Merge remote branch 'origin/master' into gsoc

This commit is contained in:
Dan Williams 2010-08-26 09:18:37 -05:00
commit 022d8e665c
94 changed files with 15551 additions and 3684 deletions

4
.gitignore vendored
View file

@ -99,6 +99,7 @@ system-settings/plugins/ifcfg-rh/tests/test-ifcfg-rh
system-settings/plugins/ifcfg-rh/tests/test-ifcfg-rh-utils
system-settings/plugins/ifcfg-rh/tests/network-scripts/Test_Write_*
system-settings/plugins/ifcfg-rh/tests/network-scripts/*-Test_Write_*
system-settings/plugins/ifupdown/tests/test-ifupdown
m4/gtk-doc.m4
m4/intltool.m4
@ -108,4 +109,7 @@ m4/lt*.m4
policy/org.freedesktop.network-manager-settings.system.policy
policy/org.freedesktop.NetworkManager.policy
data/NetworkManager.service
data/org.freedesktop.NetworkManager.service
cli/src/nmcli

View file

@ -10,6 +10,7 @@ SUBDIRS = \
cli \
tools \
policy \
data \
initscript \
test \
po \
@ -24,7 +25,11 @@ EXTRA_DIST = \
intltool-merge.in \
intltool-update.in
DISTCHECK_CONFIGURE_FLAGS = --with-tests=yes --with-docs=yes --with-udev-dir=$$dc_install_base/lib/udev
DISTCHECK_CONFIGURE_FLAGS = \
--with-tests=yes \
--with-docs=yes \
--with-udev-dir=$$dc_install_base/lib/udev \
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
DISTCLEANFILES = intltool-extract intltool-merge intltool-update

View file

@ -203,6 +203,12 @@ dnl
AC_CHECK_LIB([dl], [dladdr], LIBDL="-ldl", LIBDL="")
AC_SUBST(LIBDL)
dnl
dnl Checks for new dbus-glib property access function
dnl
AC_CHECK_LIB([dbus-glib-1], [dbus_glib_global_set_disable_legacy_property_access], ac_have_dg_prop="1", ac_have_dg_prop="0")
AC_DEFINE_UNQUOTED(HAVE_DBUS_GLIB_DISABLE_LEGACY_PROP_ACCESS, $ac_have_dg_prop, [Define if you have a dbus-glib with dbus_glib_global_set_disable_legacy_property_access()])
PKG_CHECK_MODULES(DBUS, dbus-1 >= 1.1 dbus-glib-1 >= 0.75)
AC_SUBST(DBUS_CFLAGS)
AC_SUBST(DBUS_LIBS)
@ -231,6 +237,14 @@ else
fi
AC_SUBST(UDEV_BASE_DIR)
# systemd
AC_ARG_WITH([systemdsystemunitdir],
AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files]),
[],
[with_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)])
AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])
AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$with_systemdsystemunitdir"])
PKG_CHECK_MODULES(LIBNL, libnl-1 >= 1.0-pre8)
AC_SUBST(LIBNL_CFLAGS)
AC_SUBST(LIBNL_LIBS)
@ -241,9 +255,12 @@ AC_SUBST(UUID_CFLAGS)
AC_SUBST(UUID_LIBS)
PKG_CHECK_MODULES(POLKIT, polkit-gobject-1)
AC_SUBST(POLKIT_CFLAGS)
# Check for polkit_authority_get_sync()
AC_CHECK_LIB([polkit-gobject-1], [polkit_authority_get_sync], ac_have_pk_auth_get_sync="1", ac_have_pk_auth_get_sync="0")
AC_DEFINE_UNQUOTED(HAVE_POLKIT_AUTHORITY_GET_SYNC, $ac_have_pk_auth_get_sync, [Define if you have a polkit with polkit_authority_get_sync()])
AC_ARG_WITH(crypto, AS_HELP_STRING([--with-crypto=nss | gnutls], [Cryptography library to use for certificate and key operations]),ac_crypto=$withval, ac_crypto=nss)
with_nss=no
@ -305,21 +322,30 @@ AC_SUBST(PPPD_PLUGIN_DIR)
AC_ARG_WITH([dhclient], AS_HELP_STRING([--with-dhclient=yes|no|path], [Enable dhclient 4.x support]))
# If a full path is given, use that and do not test if it works or not.
case "${with_dhclient}" in
# NM only works with ISC dhclient - other derivatives don't have
# the same userland. dhclient 4.x is required for IPv6 support;
# with older versions NM won't be able to use DHCPv6.
/*)
DHCLIENT_PATH="${with_dhclient}"
DHCLIENT_VERSION=4
if test -x "${with_dhclient}"; then
case `"${with_dhclient}" --version 2>&1` in
"isc-dhclient-4"*) DHCLIENT_VERSION=4; break;;
"isc-dhclient-V3"*) DHCLIENT_VERSION=3; break;;
esac
fi
AC_MSG_NOTICE(using dhclient at ${DHCLIENT_PATH})
;;
no) AC_MSG_NOTICE(dhclient support disabled)
;;
*)
AC_MSG_CHECKING(for dhclient)
# NM only works with ISC dhclient - other derivatives don't have
# the same userland. NM also requires dhclient 4.x since older
# versions do not have IPv6 support.
for path in /sbin /usr/sbin /usr/pkg/sbin /usr/local/sbin; do
test -x "${path}/dhclient" || continue
case `"$path/dhclient" --version 2>&1` in
"isc-dhclient-4"*) DHCLIENT_PATH="$path/dhclient"; break;;
"isc-dhclient-4"*) DHCLIENT_PATH="$path/dhclient"; DHCLIENT_VERSION=4; break;;
"isc-dhclient-V3"*) DHCLIENT_PATH="$path/dhclient"; DHCLIENT_VERSION=3; break;;
esac
done
if test -n "${DHCLIENT_PATH}"; then
@ -367,6 +393,7 @@ if test -z "$DHCPCD_PATH" -a -z "$DHCLIENT_PATH"; then
AC_MSG_WARN([Falling back to ISC dhclient, ${DHCLIENT_PATH}])
fi
AC_SUBST(DHCLIENT_PATH)
AC_SUBST(DHCLIENT_VERSION)
AC_SUBST(DHCPCD_PATH)
# resolvconf support
@ -484,6 +511,9 @@ tools/Makefile
system-settings/Makefile
system-settings/plugins/Makefile
system-settings/plugins/ifupdown/Makefile
system-settings/plugins/ifupdown/tests/Makefile
system-settings/plugins/ifnet/Makefile
system-settings/plugins/ifnet/tests/Makefile
system-settings/plugins/ifcfg-rh/Makefile
system-settings/plugins/ifcfg-rh/tests/Makefile
system-settings/plugins/ifcfg-rh/tests/network-scripts/Makefile
@ -522,6 +552,7 @@ man/nm-online.1
man/nmcli.1
po/Makefile.in
policy/Makefile
data/Makefile
docs/Makefile
docs/libnm-glib/Makefile
docs/libnm-util/Makefile
@ -539,6 +570,7 @@ echo
if test -n "${DHCLIENT_PATH}"; then
echo ISC dhclient support: ${DHCLIENT_PATH}
echo ISC dhclient version: ${DHCLIENT_VERSION}
else
echo ISC dhclient support: no
fi
@ -549,6 +581,12 @@ else
echo dhcpcd support: no
fi
if test -n "${with_systemdsystemunitdir}"; then
echo systemd support: ${with_systemdsystemunitdir}
else
echo systemd support: no
fi
echo
echo Building documentation: ${with_docs}
echo Building tests: ${with_tests}

26
data/Makefile.am Normal file
View file

@ -0,0 +1,26 @@
if HAVE_SYSTEMD
systemdsystemunit_DATA = NetworkManager.service
NetworkManager.service: NetworkManager.service.in
$(edit) $< >$@
servicedir = $(datadir)/dbus-1/system-services
service_in_files = org.freedesktop.NetworkManager.service.in
service_DATA = $(service_in_files:.service.in=.service)
$(service_DATA): $(service_in_files) Makefile
$(edit) $< >$@
endif
edit = sed \
-e 's|@sbindir[@]|$(sbindir)|g' \
-e 's|@sysconfdir[@]|$(sysconfdir)|g' \
-e 's|@localstatedir[@]|$(localstatedir)|g'
EXTRA_DIST = \
NetworkManager.service.in \
org.freedesktop.NetworkManager.service.in
CLEANFILES = NetworkManager.service org.freedesktop.NetworkManager.service

View file

@ -0,0 +1,12 @@
[Unit]
Description=Network Manager
After=syslog.target
[Service]
Type=dbus
BusName=org.freedesktop.NetworkManager
ExecStart=@sbindir@/NetworkManager --no-daemon
[Install]
WantedBy=network.target multi-user.target
Alias=dbus-org.freedesktop.NetworkManager.service

View file

@ -0,0 +1,11 @@
# This D-Bus service activation file is only for systemd support since
# an auto-activated NetworkManager would be quite surprising for those people
# who have NM installed but turned off. Thus the Exec path available to
# D-Bus is /bin/false, but systemd knows the real Exec path due to the NM
# systemd .service file.
[D-BUS Service]
Name=org.freedesktop.NetworkManager
Exec=/bin/false
User=root
SystemdService=dbus-org.freedesktop.NetworkManager.service

View file

@ -166,6 +166,9 @@ typedef enum {
*/
#define NM_VPN_PLUGIN_IP4_CONFIG_ROUTES "routes"
/* boolean: prevent this VPN connection from ever getting the default route */
#define NM_VPN_PLUGIN_IP4_CONFIG_NEVER_DEFAULT "never-default"
/* Deprecated */
#define NM_VPN_PLUGIN_IP4_CONFIG_GATEWAY NM_VPN_PLUGIN_IP4_CONFIG_EXT_GATEWAY

View file

@ -319,12 +319,8 @@ nm_permission_result_to_client (const char *nm)
}
static void
get_permissions_reply (DBusGProxy *proxy,
GHashTable *permissions,
GError *error,
gpointer user_data)
update_permissions (NMClient *self, GHashTable *permissions)
{
NMClient *self = NM_CLIENT (user_data);
NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (self);
GHashTableIter iter;
gpointer key, value;
@ -332,13 +328,11 @@ get_permissions_reply (DBusGProxy *proxy,
NMClientPermissionResult perm_result;
GList *keys, *keys_iter;
priv->perm_call = NULL;
/* get list of old permissions for change notification */
keys = g_hash_table_get_keys (priv->permissions);
g_hash_table_remove_all (priv->permissions);
if (!error) {
if (permissions) {
/* Process new permissions */
g_hash_table_iter_init (&iter, permissions);
while (g_hash_table_iter_next (&iter, &key, &value)) {
@ -377,12 +371,31 @@ get_permissions_reply (DBusGProxy *proxy,
g_list_free (keys);
}
static DBusGProxyCall *
get_permissions (NMClient *self)
static void
get_permissions_sync (NMClient *self)
{
return org_freedesktop_NetworkManager_get_permissions_async (NM_CLIENT_GET_PRIVATE (self)->client_proxy,
get_permissions_reply,
self);
gboolean success;
GHashTable *permissions = NULL;
success = dbus_g_proxy_call_with_timeout (NM_CLIENT_GET_PRIVATE (self)->client_proxy,
"GetPermissions", 3000, NULL,
G_TYPE_INVALID,
DBUS_TYPE_G_MAP_OF_STRING, &permissions, G_TYPE_INVALID);
update_permissions (self, success ? permissions : NULL);
if (permissions)
g_hash_table_destroy (permissions);
}
static void
get_permissions_reply (DBusGProxy *proxy,
GHashTable *permissions,
GError *error,
gpointer user_data)
{
NMClient *self = NM_CLIENT (user_data);
NM_CLIENT_GET_PRIVATE (self)->perm_call = NULL;
update_permissions (NM_CLIENT (user_data), error ? NULL : permissions);
}
static void
@ -391,8 +404,11 @@ client_recheck_permissions (DBusGProxy *proxy, gpointer user_data)
NMClient *self = NM_CLIENT (user_data);
NMClientPrivate *priv = NM_CLIENT_GET_PRIVATE (self);
if (!priv->perm_call)
priv->perm_call = get_permissions (self);
if (!priv->perm_call) {
priv->perm_call = org_freedesktop_NetworkManager_get_permissions_async (NM_CLIENT_GET_PRIVATE (self)->client_proxy,
get_permissions_reply,
self);
}
}
static GObject*
@ -442,7 +458,7 @@ constructor (GType type,
G_CALLBACK (client_recheck_permissions),
object,
NULL);
priv->perm_call = get_permissions (NM_CLIENT (object));
get_permissions_sync (NM_CLIENT (object));
priv->bus_proxy = dbus_g_proxy_new_for_name (connection,
"org.freedesktop.DBus",

View file

@ -192,11 +192,18 @@ fetch_connections_done (DBusGProxy *proxy,
int i;
if (error) {
g_warning ("%s: error fetching connections: (%d) %s.",
__func__,
error->code,
error->message ? error->message : "(unknown)");
/* Ignore settings service spawn errors */
if ( !g_error_matches (error, DBUS_GERROR, DBUS_GERROR_SERVICE_UNKNOWN)
&& !g_error_matches (error, DBUS_GERROR, DBUS_GERROR_NAME_HAS_NO_OWNER)) {
g_warning ("%s: error fetching connections: (%d) %s.",
__func__,
error->code,
error->message ? error->message : "(unknown)");
}
g_clear_error (&error);
/* We tried to read connections and failed */
g_signal_emit (self, signals[CONNECTIONS_READ], 0);
return;
}

View file

@ -20,4 +20,5 @@ src/logging/nm-logging.c
src/named-manager/nm-named-manager.c
src/system-settings/nm-default-wired-connection.c
system-settings/plugins/ifcfg-rh/reader.c
system-settings/plugins/ifnet/connection_parser.c

407
po/es.po

File diff suppressed because it is too large Load diff

1748
po/gl.po

File diff suppressed because it is too large Load diff

134
po/hi.po
View file

@ -5,12 +5,12 @@
# Rajesh Ranjan <rranjan@redhat.com>, 2010.
msgid ""
msgstr ""
"Project-Id-Version: NetworkManager.master\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=NetworkManager&component=general\n"
"POT-Creation-Date: 2010-05-06 14:31+0530\n"
"PO-Revision-Date: 2010-05-07 15:23+0530\n"
"Project-Id-Version: hi\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-07-20 12:39+0530\n"
"PO-Revision-Date: 2010-07-26 13:05+0530\n"
"Last-Translator: Rajesh Ranjan <rranjan@redhat.com>\n"
"Language-Team: Hindi <Red Hat>\n"
"Language-Team: Hindi <fedora-trans-hi@redhat.com>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@ -499,6 +499,16 @@ msgstr "IP4-SETTINGS"
msgid "IP4-DNS"
msgstr "IP4-DNS"
#. 6
#: ../cli/src/devices.c:79
msgid "IP6-SETTINGS"
msgstr "IP6-SETTINGS"
#. 7
#: ../cli/src/devices.c:80
msgid "IP6-DNS"
msgstr "IP6-DNS"
#. 2
#: ../cli/src/devices.c:88
msgid "DRIVER"
@ -1501,6 +1511,88 @@ msgstr "गोपित कुंजी को PEM फाइल में लि
msgid "Could not allocate memory for PEM file data."
msgstr "PEM फाइल आँकड़ा के लिए स्मृति नहीं आबंटित कर सका."
#: ../policy/org.freedesktop.network-manager-settings.system.policy.in.h:1
msgid "Connection sharing via a protected WiFi network"
msgstr "किसी संरक्षित WiFi संजाल के द्वारा कनेक्शन साझा"
#: ../policy/org.freedesktop.network-manager-settings.system.policy.in.h:2
msgid "Connection sharing via an open WiFi network"
msgstr "किसी खुले WiFi संजाल के द्वारा कनेक्शन साझा"
#: ../policy/org.freedesktop.network-manager-settings.system.policy.in.h:3
msgid "Modify persistent system hostname"
msgstr "स्थिर सिस्टम होस्टनेम को सुधारें"
#: ../policy/org.freedesktop.network-manager-settings.system.policy.in.h:4
msgid "Modify system connections"
msgstr "सिस्टम कनेक्शन सुधारें"
#: ../policy/org.freedesktop.network-manager-settings.system.policy.in.h:5
msgid "System policy prevents modification of system settings"
msgstr "सिस्टम नीति सिस्टम सेटिंग के रूपांतरण को रोकता है."
#: ../policy/org.freedesktop.network-manager-settings.system.policy.in.h:6
msgid "System policy prevents modification of the persistent system hostname"
msgstr "सिस्टम नीति स्थिर सिस्टम होस्टनेम के रूपांतरण को रोकता है."
#: ../policy/org.freedesktop.network-manager-settings.system.policy.in.h:7
msgid "System policy prevents sharing connections via a protected WiFi network"
msgstr "किसी संरक्षित WiFi संजाल के द्वारा साझा कनेक्शन को सिस्टम नीति रोकता है"
#: ../policy/org.freedesktop.network-manager-settings.system.policy.in.h:8
msgid "System policy prevents sharing connections via an open WiFi network"
msgstr "किसी खुले WiFi संजाल के द्वारा साझा कनेक्शन को सिस्टम नीति रोकता है"
#: ../policy/org.freedesktop.NetworkManager.policy.in.h:1
msgid "Allow control of network connections"
msgstr "संजाल कनेक्शन के नियंत्रण स्वीकार करें"
#: ../policy/org.freedesktop.NetworkManager.policy.in.h:2
msgid "Allow use of user-specific connections"
msgstr "उपयोक्ता विशिष्ट कनेक्शन के उपयोग की स्वीकृति दें"
#: ../policy/org.freedesktop.NetworkManager.policy.in.h:3
msgid "Enable or disable WiFi devices"
msgstr "WiFi युक्तियाँ सक्रिय या निष्क्रिय करें"
#: ../policy/org.freedesktop.NetworkManager.policy.in.h:4
msgid "Enable or disable mobile broadband devices"
msgstr "मोबाइल ब्राडबैंड युक्तियाँ सक्रिय या निष्क्रिय करें"
#: ../policy/org.freedesktop.NetworkManager.policy.in.h:5
msgid "Enable or disable system networking"
msgstr "तंत्र संजालन सक्रिय या निष्क्रिय करें"
#: ../policy/org.freedesktop.NetworkManager.policy.in.h:6
msgid ""
"Put NetworkManager to sleep or wake it up (should only be used by system "
"power management)"
msgstr " NetworkManager को स्लीप स्थिति या वेकअप स्थिति में रखें (केवल सिस्टम पावर मैनेजमेंट के द्वारा प्रयोग किया जाएगा)"
#: ../policy/org.freedesktop.NetworkManager.policy.in.h:7
msgid "System policy prevents control of network connections"
msgstr "सिस्टम कनेक्शन के नियंत्रण को सिस्टम नीति रोकता है"
#: ../policy/org.freedesktop.NetworkManager.policy.in.h:8
msgid "System policy prevents enabling or disabling WiFi devices"
msgstr "WiFi युक्ति के सक्रियण या निष्क्रियण को तंत्र नीति रोकता है"
#: ../policy/org.freedesktop.NetworkManager.policy.in.h:9
msgid "System policy prevents enabling or disabling mobile broadband devices"
msgstr "मोबाइल ब्रॉडबैंड युक्ति के सक्रियण या निष्क्रियण को तंत्र नीति रोकता है"
#: ../policy/org.freedesktop.NetworkManager.policy.in.h:10
msgid "System policy prevents enabling or disabling system networking"
msgstr "तंत्र संजालन के युक्ति के सक्रियण या निष्क्रियण को तंत्र नीति रोकता है"
#: ../policy/org.freedesktop.NetworkManager.policy.in.h:11
msgid "System policy prevents putting NetworkManager to sleep or waking it up"
msgstr "NetworkManager को स्लीप या वेकअप स्थिति में लाने के लिए नेटवर्कमैनेजर रोकता है"
#: ../policy/org.freedesktop.NetworkManager.policy.in.h:12
msgid "System policy prevents use of user-specific connections"
msgstr "सिस्टम नीति उपयोक्ता विशेष कनेक्शन के उपयोग को रोकता है"
#: ../src/nm-netlink-monitor.c:100 ../src/nm-netlink-monitor.c:231
#: ../src/nm-netlink-monitor.c:653
#, c-format
@ -1608,35 +1700,3 @@ msgstr "स्वतः %s"
msgid "System"
msgstr "तंत्र"
#: ../policy/org.freedesktop.network-manager-settings.system.policy.in.h:1
msgid "Connection sharing via a protected WiFi network"
msgstr "किसी संरक्षित WiFi संजाल के द्वारा कनेक्शन साझा"
#: ../policy/org.freedesktop.network-manager-settings.system.policy.in.h:2
msgid "Connection sharing via an open WiFi network"
msgstr "किसी खुले WiFi संजाल के द्वारा कनेक्शन साझा"
#: ../policy/org.freedesktop.network-manager-settings.system.policy.in.h:3
msgid "Modify persistent system hostname"
msgstr "स्थिर सिस्टम होस्टनेम को सुधारें"
#: ../policy/org.freedesktop.network-manager-settings.system.policy.in.h:4
msgid "Modify system connections"
msgstr "सिस्टम कनेक्शन सुधारें"
#: ../policy/org.freedesktop.network-manager-settings.system.policy.in.h:5
msgid "System policy prevents modification of system settings"
msgstr "सिस्टम नीति सिस्टम सेटिंग के रूपांतरण को रोकता है."
#: ../policy/org.freedesktop.network-manager-settings.system.policy.in.h:6
msgid "System policy prevents modification of the persistent system hostname"
msgstr "सिस्टम नीति स्थिर सिस्टम होस्टनेम के रूपांतरण को रोकता है."
#: ../policy/org.freedesktop.network-manager-settings.system.policy.in.h:7
msgid "System policy prevents sharing connections via a protected WiFi network"
msgstr "किसी संरक्षित WiFi संजाल के द्वारा साझा कनेक्शन को सिस्टम नीति रोकता है"
#: ../policy/org.freedesktop.network-manager-settings.system.policy.in.h:8
msgid "System policy prevents sharing connections via an open WiFi network"
msgstr "किसी खुले WiFi संजाल के द्वारा साझा कनेक्शन को सिस्टम नीति रोकता है"

2509
po/id.po

File diff suppressed because it is too large Load diff

411
po/or.po

File diff suppressed because it is too large Load diff

1917
po/sv.po

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -29,6 +29,7 @@ libdhcp_manager_la_CPPFLAGS = \
-DLIBEXECDIR=\"$(libexecdir)\" \
-DLOCALSTATEDIR=\"$(localstatedir)\" \
-DDHCLIENT_PATH=\"$(DHCLIENT_PATH)\" \
-DDHCLIENT_V$(DHCLIENT_VERSION) \
-DDHCPCD_PATH=\"$(DHCPCD_PATH)\"
libdhcp_manager_la_LIBADD = \

View file

@ -45,7 +45,11 @@ G_DEFINE_TYPE (NMDHCPDhclient, nm_dhcp_dhclient, NM_TYPE_DHCP_CLIENT)
#define NM_DHCP_DHCLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DHCP_DHCLIENT, NMDHCPDhclientPrivate))
#if defined(TARGET_DEBIAN) || defined(TARGET_SUSE) || defined(TARGET_MANDRIVA)
#if defined(DHCLIENT_V3)
#define NM_DHCLIENT_LEASE_DIR LOCALSTATEDIR "/lib/dhcp3"
#else
#define NM_DHCLIENT_LEASE_DIR LOCALSTATEDIR "/lib/dhcp"
#endif
#else
#define NM_DHCLIENT_LEASE_DIR LOCALSTATEDIR "/lib/dhclient"
#endif
@ -437,7 +441,11 @@ create_dhclient_config (const char *iface,
#if defined(TARGET_SUSE)
orig = g_strdup (SYSCONFDIR "/dhclient.conf");
#elif defined(TARGET_DEBIAN) || defined(TARGET_GENTOO)
#if defined(DHCLIENT_V3)
orig = g_strdup (SYSCONFDIR "/dhcp3/dhclient.conf");
#else
orig = g_strdup (SYSCONFDIR "/dhcp/dhclient.conf");
#endif
#else
orig = g_strdup_printf (SYSCONFDIR "/dhclient-%s.conf", iface);
#endif
@ -499,12 +507,20 @@ dhclient_start (NMDHCPClient *client,
guint log_domain;
g_return_val_if_fail (priv->pid_file == NULL, -1);
g_return_val_if_fail (ip_opt != NULL, -1);
iface = nm_dhcp_client_get_iface (client);
uuid = nm_dhcp_client_get_uuid (client);
ipv6 = nm_dhcp_client_get_ipv6 (client);
#if defined(DHCLIENT_V3)
if (ipv6) {
nm_log_warn (log_domain, "(%s): ISC dhcp3 does not support IPv6", iface);
return -1;
}
#else
g_return_val_if_fail (ip_opt != NULL, -1);
#endif
log_domain = ipv6 ? LOGD_DHCP6 : LOGD_DHCP4;
priv->pid_file = g_strdup_printf (LOCALSTATEDIR "/run/dhclient%s-%s.pid",
@ -536,10 +552,11 @@ dhclient_start (NMDHCPClient *client,
g_ptr_array_add (argv, (gpointer) "-d");
#if !defined(DHCLIENT_V3)
g_ptr_array_add (argv, (gpointer) ip_opt);
if (mode_opt)
g_ptr_array_add (argv, (gpointer) mode_opt);
#endif
g_ptr_array_add (argv, (gpointer) "-sf"); /* Set script file */
g_ptr_array_add (argv, (gpointer) ACTION_SCRIPT_PATH );

View file

@ -209,6 +209,12 @@ nm_logging_domains_to_string (void)
return g_string_free (str, FALSE);
}
gboolean
nm_logging_level_enabled (guint32 level)
{
return !!(log_level & level);
}
void _nm_log (const char *loc,
const char *func,
guint32 domain,

View file

@ -90,6 +90,7 @@ void _nm_log (const char *loc, const char *func,
const char *nm_logging_level_to_string (void);
char *nm_logging_domains_to_string (void);
gboolean nm_logging_level_enabled (guint32 level);
/* Undefine the nm-utils.h logging stuff to ensure errors */
#undef nm_print_backtrace

View file

@ -19,10 +19,7 @@
* Copyright (C) 2005 - 2008 Novell, Inc.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <config.h>
#include <glib.h>
#include <dbus/dbus.h>
#include <dbus/dbus-glib-lowlevel.h>
@ -627,6 +624,17 @@ main (int argc, char *argv[])
g_thread_init (NULL);
dbus_g_thread_init ();
#ifndef HAVE_DBUS_GLIB_DISABLE_LEGACY_PROP_ACCESS
#error HAVE_DBUS_GLIB_DISABLE_LEGACY_PROP_ACCESS not defined
#endif
#if HAVE_DBUS_GLIB_DISABLE_LEGACY_PROP_ACCESS
/* Ensure that non-exported properties don't leak out, and that the
* introspection 'access' permissions are respected.
*/
dbus_glib_global_set_disable_legacy_property_access ();
#endif
setup_signals ();
nm_logging_start (become_daemon);

View file

@ -785,6 +785,39 @@ real_is_available (NMDevice *dev)
return TRUE;
}
static gboolean
match_subchans (NMDeviceEthernet *self, NMSettingWired *s_wired, gboolean *try_mac)
{
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
const GPtrArray *subchans;
int i;
*try_mac = TRUE;
subchans = nm_setting_wired_get_s390_subchannels (s_wired);
if (!subchans)
return TRUE;
/* connection requires subchannels but the device has none */
if (!priv->subchannels)
return FALSE;
/* Make sure each subchannel in the connection is a subchannel of this device */
for (i = 0; i < subchans->len; i++) {
const char *candidate = g_ptr_array_index (subchans, i);
if ( (priv->subchan1 && !strcmp (priv->subchan1, candidate))
|| (priv->subchan2 && !strcmp (priv->subchan2, candidate))
|| (priv->subchan3 && !strcmp (priv->subchan3, candidate)))
continue;
return FALSE; /* a subchannel was not found */
}
*try_mac = FALSE;
return TRUE;
}
static NMConnection *
real_get_best_auto_connection (NMDevice *dev,
GSList *connections,
@ -820,9 +853,13 @@ real_get_best_auto_connection (NMDevice *dev,
if (s_wired) {
const GByteArray *mac;
gboolean try_mac = TRUE;
if (!match_subchans (self, s_wired, &try_mac))
continue;
mac = nm_setting_wired_get_mac_address (s_wired);
if (mac && memcmp (mac->data, &priv->perm_hw_addr, ETH_ALEN))
if (try_mac && mac && memcmp (mac->data, &priv->perm_hw_addr, ETH_ALEN))
continue;
}
@ -1702,41 +1739,6 @@ real_deactivate_quickly (NMDevice *device)
_set_hw_addr (self, priv->perm_hw_addr, "reset");
}
static gboolean
match_subchans (NMDeviceEthernet *self, NMSettingWired *s_wired, gboolean *try_mac)
{
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
const GPtrArray *subchans;
int i;
*try_mac = TRUE;
subchans = nm_setting_wired_get_s390_subchannels (s_wired);
if (!subchans)
return TRUE;
/* connection requires subchannels but the device has none */
if (!priv->subchannels)
return FALSE;
/* Make sure each subchannel in the connection is a subchannel of this device */
for (i = 0; i < subchans->len; i++) {
const char *candidate = g_ptr_array_index (subchans, i);
gboolean found = FALSE;
if ( (priv->subchan1 && !strcmp (priv->subchan1, candidate))
|| (priv->subchan2 && !strcmp (priv->subchan2, candidate))
|| (priv->subchan3 && !strcmp (priv->subchan3, candidate)))
found = TRUE;
if (!found)
return FALSE;
}
*try_mac = FALSE;
return TRUE;
}
static gboolean
real_check_connection_compatible (NMDevice *device,
NMConnection *connection,

View file

@ -398,11 +398,13 @@ nm_device_interface_connection_match_config (NMDeviceInterface *device,
}
gboolean
nm_device_interface_can_assume_connection (NMDeviceInterface *device)
nm_device_interface_can_assume_connections (NMDeviceInterface *device)
{
g_return_val_if_fail (NM_IS_DEVICE_INTERFACE (device), FALSE);
return !!NM_DEVICE_INTERFACE_GET_INTERFACE (device)->connection_match_config;
if (NM_DEVICE_INTERFACE_GET_INTERFACE (device)->can_assume_connections)
return NM_DEVICE_INTERFACE_GET_INTERFACE (device)->can_assume_connections (device);
return FALSE;
}
void

View file

@ -109,6 +109,8 @@ struct _NMDeviceInterface {
NMConnection * (*connection_match_config) (NMDeviceInterface *device, const GSList *specs);
gboolean (*can_assume_connections) (NMDeviceInterface *device);
void (*set_enabled) (NMDeviceInterface *device, gboolean enabled);
gboolean (*get_enabled) (NMDeviceInterface *device);
@ -145,7 +147,7 @@ gboolean nm_device_interface_spec_match_list (NMDeviceInterface *device,
NMConnection * nm_device_interface_connection_match_config (NMDeviceInterface *device,
const GSList *connections);
gboolean nm_device_interface_can_assume_connection (NMDeviceInterface *device);
gboolean nm_device_interface_can_assume_connections (NMDeviceInterface *device);
gboolean nm_device_interface_get_enabled (NMDeviceInterface *device);

View file

@ -159,6 +159,7 @@ static void nm_device_deactivate (NMDeviceInterface *device, NMDeviceStateReason
static gboolean device_disconnect (NMDeviceInterface *device, GError **error);
static gboolean spec_match_list (NMDeviceInterface *device, const GSList *specs);
static NMConnection *connection_match_config (NMDeviceInterface *device, const GSList *connections);
static gboolean can_assume_connections (NMDeviceInterface *device);
static void nm_device_activate_schedule_stage5_ip_config_commit (NMDevice *self, int family);
@ -196,6 +197,7 @@ device_interface_init (NMDeviceInterface *device_interface_class)
device_interface_class->disconnect = device_disconnect;
device_interface_class->spec_match_list = spec_match_list;
device_interface_class->connection_match_config = connection_match_config;
device_interface_class->can_assume_connections = can_assume_connections;
}
@ -1237,7 +1239,7 @@ static gboolean
aipd_exec (NMDevice *self, GError **error)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
char *argv[5];
char *argv[6], *cmdline;
gboolean success = FALSE;
const char **aipd_binary = NULL;
static const char *aipd_paths[] = {
@ -1245,6 +1247,7 @@ aipd_exec (NMDevice *self, GError **error)
"/usr/local/sbin/avahi-autoipd",
NULL
};
int i = 0;
aipd_cleanup (self);
@ -1261,11 +1264,17 @@ aipd_exec (NMDevice *self, GError **error)
return FALSE;
}
argv[0] = (char *) (*aipd_binary);
argv[1] = "--script";
argv[2] = LIBEXECDIR "/nm-avahi-autoipd.action";
argv[3] = (char *) nm_device_get_ip_iface (self);
argv[4] = NULL;
argv[i++] = (char *) (*aipd_binary);
argv[i++] = "--script";
argv[i++] = LIBEXECDIR "/nm-avahi-autoipd.action";
if (nm_logging_level_enabled (LOGL_DEBUG))
argv[i++] = "--debug";
argv[i++] = (char *) nm_device_get_ip_iface (self);
argv[i++] = NULL;
cmdline = g_strjoinv (" ", argv);
nm_log_dbg(LOGD_AUTOIP4, "running: %s", cmdline);
g_free (cmdline);
success = g_spawn_async ("/", argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD,
&aipd_child_setup, NULL, &(priv->aipd_pid), error);
@ -1572,6 +1581,8 @@ dhcp6_start (NMDevice *self,
NMSettingConnection *s_con;
const char *uuid;
const char *ip_iface;
const struct in6_addr dest = { { { 0xFF,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } };
int err;
if (!connection) {
NMActRequest *req;
@ -1592,6 +1603,18 @@ dhcp6_start (NMDevice *self,
g_object_unref (priv->dhcp6_config);
priv->dhcp6_config = nm_dhcp6_config_new ();
/* DHCPv6 communicates with the DHCPv6 server via two multicast addresses,
* ff02::1:2 (link-scope) and ff05::1:3 (site-scope). Make sure we have
* a multicast route (ff00::/8) for client <-> server communication.
*/
err = nm_system_set_ip6_route (priv->ip_iface ? priv->ip_ifindex : priv->ifindex,
&dest, 8, NULL, 256, 0, RTPROT_BOOT, RT_TABLE_LOCAL, NULL);
if (err) {
nm_log_err (LOGD_DEVICE | LOGD_IP6,
"(%s): failed to add IPv6 multicast route: %s",
priv->ip_iface ? priv->ip_iface : priv->iface, nl_geterror ());
}
s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
g_assert (s_con);
uuid = nm_setting_connection_get_uuid (s_con);
@ -3289,7 +3312,7 @@ dispose (GObject *object)
/* Don't down can-assume-connection capable devices that are activated with
* a connection that can be assumed.
*/
if ( nm_device_interface_can_assume_connection (NM_DEVICE_INTERFACE (self))
if ( nm_device_interface_can_assume_connections (NM_DEVICE_INTERFACE (self))
&& (nm_device_get_state (self) == NM_DEVICE_STATE_ACTIVATED)) {
NMConnection *connection;
NMSettingIP4Config *s_ip4;
@ -3352,7 +3375,8 @@ finalize (GObject *object)
NMDevice *self = NM_DEVICE (object);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
g_object_unref (priv->dhcp_manager);
if (priv->dhcp_manager)
g_object_unref (priv->dhcp_manager);
g_free (priv->udi);
g_free (priv->iface);
@ -3844,6 +3868,14 @@ connection_match_config (NMDeviceInterface *device, const GSList *connections)
return NULL;
}
static gboolean
can_assume_connections (NMDeviceInterface *device)
{
g_return_val_if_fail (device != NULL, FALSE);
return !!NM_DEVICE_GET_CLASS (device)->connection_match_config;
}
void
nm_device_set_dhcp_timeout (NMDevice *device, guint32 timeout)
{

View file

@ -73,16 +73,17 @@ default_call_func (NMAuthChain *chain,
nm_auth_chain_set_data (chain, permission, GUINT_TO_POINTER (result), NULL);
}
NMAuthChain *
nm_auth_chain_new (PolkitAuthority *authority,
DBusGMethodInvocation *context,
DBusGProxy *proxy,
NMAuthChainResultFunc done_func,
gpointer user_data)
static NMAuthChain *
_auth_chain_new (PolkitAuthority *authority,
DBusGMethodInvocation *context,
DBusGProxy *proxy,
DBusMessage *message,
NMAuthChainResultFunc done_func,
gpointer user_data)
{
NMAuthChain *self;
g_return_val_if_fail (context || proxy, NULL);
g_return_val_if_fail (context || proxy || message, NULL);
self = g_malloc0 (sizeof (NMAuthChain));
self->refcount = 1;
@ -97,6 +98,8 @@ nm_auth_chain_new (PolkitAuthority *authority,
self->owner = g_strdup (dbus_g_proxy_get_bus_name (proxy));
else if (context)
self->owner = dbus_g_method_get_sender (context);
else if (message)
self->owner = g_strdup (dbus_message_get_sender (message));
if (!self->owner) {
/* Need an owner */
@ -108,6 +111,25 @@ nm_auth_chain_new (PolkitAuthority *authority,
return self;
}
NMAuthChain *
nm_auth_chain_new (PolkitAuthority *authority,
DBusGMethodInvocation *context,
DBusGProxy *proxy,
NMAuthChainResultFunc done_func,
gpointer user_data)
{
return _auth_chain_new (authority, context, proxy, NULL, done_func, user_data);
}
NMAuthChain *
nm_auth_chain_new_raw_message (PolkitAuthority *authority,
DBusMessage *message,
NMAuthChainResultFunc done_func,
gpointer user_data)
{
return _auth_chain_new (authority, NULL, NULL, message, done_func, user_data);
}
gpointer
nm_auth_chain_get_data (NMAuthChain *self, const char *tag)
{

View file

@ -60,6 +60,11 @@ NMAuthChain *nm_auth_chain_new (PolkitAuthority *authority,
NMAuthChainResultFunc done_func,
gpointer user_data);
NMAuthChain *nm_auth_chain_new_raw_message (PolkitAuthority *authority,
DBusMessage *message,
NMAuthChainResultFunc done_func,
gpointer user_data);
gpointer nm_auth_chain_get_data (NMAuthChain *chain, const char *tag);
void nm_auth_chain_set_data (NMAuthChain *chain,

View file

@ -19,6 +19,8 @@
* Copyright (C) 2007 - 2010 Red Hat, Inc.
*/
#include <config.h>
#include <netinet/ether.h>
#include <string.h>
#include <dbus/dbus-glib-lowlevel.h>
@ -133,11 +135,24 @@ static NMDevice *find_device_by_iface (NMManager *self, const gchar *iface);
static GSList * remove_one_device (NMManager *manager,
GSList *list,
NMDevice *device,
gboolean quitting,
gboolean force_unmanage);
gboolean quitting);
static NMDevice *nm_manager_get_device_by_udi (NMManager *manager, const char *udi);
/* Fix for polkit 0.97 and later */
#if !HAVE_POLKIT_AUTHORITY_GET_SYNC
static inline PolkitAuthority *
polkit_authority_get_sync (GCancellable *cancellable, GError **error)
{
PolkitAuthority *authority;
authority = polkit_authority_get ();
if (!authority)
g_set_error (error, 0, 0, "failed to get the PolicyKit authority");
return authority;
}
#endif
#define SSD_POKE_INTERVAL 120
#define ORIGDEV_TAG "originating-device"
@ -350,8 +365,7 @@ modem_added (NMModemManager *modem_manager,
priv->devices = remove_one_device (NM_MANAGER (user_data),
priv->devices,
replace_device,
FALSE,
TRUE);
FALSE);
}
/* Give Bluetooth DUN devices first chance to claim the modem */
@ -450,20 +464,22 @@ static GSList *
remove_one_device (NMManager *manager,
GSList *list,
NMDevice *device,
gboolean quitting,
gboolean force_unmanage)
gboolean quitting)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
if (nm_device_get_managed (device)) {
gboolean unmanage = !quitting;
/* When quitting, we want to leave up interfaces & connections
* that can be taken over again (ie, "assumed") when NM restarts
* so that '/etc/init.d/NetworkManager restart' will not distrupt
* networking for interfaces that support connection assumption.
* All other devices get unmanaged when NM quits so that their
* connections get torn down and the interface is deactivated.
*/
/* Don't unmanage active assume-connection-capable devices at shutdown */
if ( nm_device_interface_can_assume_connection (NM_DEVICE_INTERFACE (device))
&& nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED)
unmanage = FALSE;
if (unmanage || force_unmanage)
if ( !nm_device_interface_can_assume_connections (NM_DEVICE_INTERFACE (device))
|| (nm_device_get_state (device) != NM_DEVICE_STATE_ACTIVATED)
|| !quitting)
nm_device_set_managed (device, FALSE, NM_DEVICE_STATE_REASON_REMOVED);
}
@ -497,7 +513,7 @@ modem_removed (NMModemManager *modem_manager,
/* Otherwise remove the standalone modem */
found = nm_manager_get_device_by_udi (self, nm_modem_get_path (modem));
if (found)
priv->devices = remove_one_device (self, priv->devices, found, FALSE, TRUE);
priv->devices = remove_one_device (self, priv->devices, found, FALSE);
}
static void
@ -822,6 +838,7 @@ system_internal_new_connection (NMManager *manager,
path = nm_connection_get_path (NM_CONNECTION (connection));
g_hash_table_insert (priv->system_connections, g_strdup (path),
g_object_ref (connection));
g_signal_emit (manager, signals[CONNECTION_ADDED], 0, connection);
}
static void
@ -1414,7 +1431,7 @@ add_device (NMManager *self, NMDevice *device)
/* Check if we should assume the device's active connection by matching its
* config with an existing system connection.
*/
if (nm_device_interface_can_assume_connection (NM_DEVICE_INTERFACE (device))) {
if (nm_device_interface_can_assume_connections (NM_DEVICE_INTERFACE (device))) {
GSList *connections = NULL;
g_hash_table_iter_init (&iter, priv->system_connections);
@ -1572,7 +1589,7 @@ bluez_manager_resync_devices (NMManager *self)
priv->devices = keep;
while (g_slist_length (gone))
gone = remove_one_device (self, gone, NM_DEVICE (gone->data), FALSE, TRUE);
gone = remove_one_device (self, gone, NM_DEVICE (gone->data), FALSE);
} else {
g_slist_free (keep);
g_slist_free (gone);
@ -1641,7 +1658,7 @@ bluez_manager_bdaddr_removed_cb (NMBluezManager *bluez_mgr,
NMDevice *device = NM_DEVICE (iter->data);
if (!strcmp (nm_device_get_udi (device), object_path)) {
priv->devices = remove_one_device (self, priv->devices, device, FALSE, TRUE);
priv->devices = remove_one_device (self, priv->devices, device, FALSE);
break;
}
}
@ -1710,7 +1727,7 @@ udev_device_removed_cb (NMUdevManager *manager,
ifindex = g_udev_device_get_property_as_int (udev_device, "IFINDEX");
device = find_device_by_ifindex (self, ifindex);
if (device)
priv->devices = remove_one_device (self, priv->devices, device, FALSE, TRUE);
priv->devices = remove_one_device (self, priv->devices, device, FALSE);
}
static void
@ -2015,7 +2032,7 @@ nm_manager_activate_connection (NMManager *manager,
NMDevice *device = NULL;
NMSettingConnection *s_con;
NMVPNConnection *vpn_connection;
const char *path;
const char *path = NULL;
g_return_val_if_fail (manager != NULL, NULL);
g_return_val_if_fail (connection != NULL, NULL);
@ -2072,11 +2089,13 @@ nm_manager_activate_connection (NMManager *manager,
req,
device,
error);
g_signal_connect (vpn_connection, "manager-get-secrets",
G_CALLBACK (provider_get_secrets), manager);
g_signal_connect (vpn_connection, "manager-cancel-secrets",
G_CALLBACK (provider_cancel_secrets), manager);
path = nm_vpn_connection_get_active_connection_path (vpn_connection);
if (vpn_connection) {
g_signal_connect (vpn_connection, "manager-get-secrets",
G_CALLBACK (provider_get_secrets), manager);
g_signal_connect (vpn_connection, "manager-cancel-secrets",
G_CALLBACK (provider_cancel_secrets), manager);
path = nm_vpn_connection_get_active_connection_path (vpn_connection);
}
g_object_unref (vpn_manager);
} else {
NMDeviceState state;
@ -2972,6 +2991,159 @@ firmware_dir_changed (GFileMonitor *monitor,
}
}
#define PERM_DENIED_ERROR "org.freedesktop.NetworkManager.PermissionDenied"
static void
prop_set_auth_done_cb (NMAuthChain *chain,
GError *error,
DBusGMethodInvocation *context,
gpointer user_data)
{
NMManager *self = NM_MANAGER (user_data);
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
DBusGConnection *bus;
DBusConnection *dbus_connection;
NMAuthCallResult result;
DBusMessage *reply, *request;
const char *permission, *prop;
gboolean set_enabled = TRUE;
priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
request = nm_auth_chain_get_data (chain, "message");
permission = nm_auth_chain_get_data (chain, "permission");
prop = nm_auth_chain_get_data (chain, "prop");
set_enabled = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, "enabled"));
if (error) {
reply = dbus_message_new_error (request, PERM_DENIED_ERROR,
"Not authorized to perform this operation");
} else {
/* Caller has had a chance to obtain authorization, so we only need to
* check for 'yes' here.
*/
result = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, permission));
if (result != NM_AUTH_CALL_RESULT_YES) {
reply = dbus_message_new_error (request, PERM_DENIED_ERROR,
"Not authorized to perform this operation");
} else {
g_object_set (self, prop, set_enabled, NULL);
reply = dbus_message_new_method_return (request);
}
}
if (reply) {
bus = nm_dbus_manager_get_connection (priv->dbus_mgr);
g_assert (bus);
dbus_connection = dbus_g_connection_get_connection (bus);
g_assert (dbus_connection);
dbus_connection_send (dbus_connection, reply, NULL);
dbus_message_unref (reply);
}
nm_auth_chain_unref (chain);
}
static DBusHandlerResult
prop_filter (DBusConnection *connection,
DBusMessage *message,
void *user_data)
{
NMManager *self = NM_MANAGER (user_data);
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
DBusMessageIter iter;
DBusMessageIter sub;
const char *propiface = NULL;
const char *propname = NULL;
const char *sender = NULL;
const char *glib_propname = NULL, *permission = NULL;
DBusError dbus_error;
gulong uid = G_MAXULONG;
DBusMessage *reply = NULL;
gboolean set_enabled = FALSE;
NMAuthChain *chain;
/* The sole purpose of this function is to validate property accesses
* on the NMManager object since dbus-glib doesn't yet give us this
* functionality.
*/
if (!dbus_message_is_method_call (message, DBUS_INTERFACE_PROPERTIES, "Set"))
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
dbus_message_iter_init (message, &iter);
/* Get the D-Bus interface of the property to set */
if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
dbus_message_iter_get_basic (&iter, &propiface);
if (!propiface || strcmp (propiface, NM_DBUS_INTERFACE))
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
dbus_message_iter_next (&iter);
/* Get the property name that's going to be set */
if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
dbus_message_iter_get_basic (&iter, &propname);
dbus_message_iter_next (&iter);
if (!strcmp (propname, "WirelessEnabled")) {
glib_propname = NM_MANAGER_WIRELESS_ENABLED;
permission = NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI;
} else if (!strcmp (propname, "WwanEnabled")) {
glib_propname = NM_MANAGER_WWAN_ENABLED;
permission = NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN;
} else
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
/* Get the new value for the property */
if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_VARIANT)
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
dbus_message_iter_recurse (&iter, &sub);
if (dbus_message_iter_get_arg_type (&sub) != DBUS_TYPE_BOOLEAN)
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
dbus_message_iter_get_basic (&sub, &set_enabled);
sender = dbus_message_get_sender (message);
if (!sender) {
reply = dbus_message_new_error (message, PERM_DENIED_ERROR,
"Could not determine D-Bus requestor");
goto out;
}
dbus_error_init (&dbus_error);
uid = dbus_bus_get_unix_user (connection, sender, &dbus_error);
if (dbus_error_is_set (&dbus_error)) {
reply = dbus_message_new_error (message, PERM_DENIED_ERROR,
"Could not determine the user ID of the requestor");
dbus_error_free (&dbus_error);
goto out;
}
if (uid > 0) {
/* Otherwise validate the user request */
chain = nm_auth_chain_new_raw_message (priv->authority, message, prop_set_auth_done_cb, self);
g_assert (chain);
priv->auth_chains = g_slist_append (priv->auth_chains, chain);
nm_auth_chain_set_data (chain, "prop", g_strdup (glib_propname), g_free);
nm_auth_chain_set_data (chain, "permission", g_strdup (permission), g_free);
nm_auth_chain_set_data (chain, "enabled", GUINT_TO_POINTER (set_enabled), NULL);
nm_auth_chain_set_data (chain, "message", dbus_message_ref (message), (GDestroyNotify) dbus_message_unref);
nm_auth_chain_add_call (chain, permission, TRUE);
} else {
/* Yay for root */
g_object_set (self, glib_propname, set_enabled, NULL);
reply = dbus_message_new_method_return (message);
}
out:
if (reply) {
dbus_connection_send (connection, reply, NULL);
dbus_message_unref (reply);
}
return DBUS_HANDLER_RESULT_HANDLED;
}
NMManager *
nm_manager_get (const char *config_file,
const char *plugins,
@ -2983,6 +3155,8 @@ nm_manager_get (const char *config_file,
{
static NMManager *singleton = NULL;
NMManagerPrivate *priv;
DBusGConnection *bus;
DBusConnection *dbus_connection;
if (singleton)
return g_object_ref (singleton);
@ -2992,6 +3166,17 @@ nm_manager_get (const char *config_file,
priv = NM_MANAGER_GET_PRIVATE (singleton);
bus = nm_dbus_manager_get_connection (priv->dbus_mgr);
g_assert (bus);
dbus_connection = dbus_g_connection_get_connection (bus);
g_assert (dbus_connection);
if (!dbus_connection_add_filter (dbus_connection, prop_filter, singleton, NULL)) {
nm_log_err (LOGD_CORE, "failed to register DBus connection filter");
g_object_unref (singleton);
return NULL;
}
priv->sys_settings = nm_sysconfig_settings_new (config_file, plugins, error);
if (!priv->sys_settings) {
g_object_unref (singleton);
@ -3052,6 +3237,8 @@ dispose (GObject *object)
{
NMManager *manager = NM_MANAGER (object);
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
DBusGConnection *bus;
DBusConnection *dbus_connection;
if (priv->disposed) {
G_OBJECT_CLASS (nm_manager_parent_class)->dispose (object);
@ -3070,8 +3257,7 @@ dispose (GObject *object)
priv->devices = remove_one_device (manager,
priv->devices,
NM_DEVICE (priv->devices->data),
TRUE,
FALSE);
TRUE);
}
g_hash_table_foreach (priv->system_connections, emit_removed, manager);
@ -3103,7 +3289,14 @@ dispose (GObject *object)
}
g_object_unref (priv->modem_manager);
/* Unregister property filter */
bus = nm_dbus_manager_get_connection (priv->dbus_mgr);
g_assert (bus);
dbus_connection = dbus_g_connection_get_connection (bus);
g_assert (dbus_connection);
dbus_connection_remove_filter (dbus_connection, prop_filter, manager);
g_object_unref (priv->dbus_mgr);
if (priv->bluez_mgr)
g_object_unref (priv->bluez_mgr);
@ -3198,6 +3391,7 @@ nm_manager_init (NMManager *manager)
DBusGConnection *g_connection;
guint id, i;
GFile *file;
GError *error = NULL;
/* Initialize rfkill structures and states */
memset (priv->radio_states, 0, sizeof (priv->radio_states));
@ -3275,14 +3469,18 @@ nm_manager_init (NMManager *manager)
} else
nm_log_warn (LOGD_AUTOIP4, "could not initialize avahi-autoipd D-Bus proxy");
priv->authority = polkit_authority_get ();
priv->authority = polkit_authority_get_sync (NULL, &error);
if (priv->authority) {
priv->auth_changed_id = g_signal_connect (priv->authority,
"changed",
G_CALLBACK (pk_authority_changed_cb),
manager);
} else
nm_log_warn (LOGD_CORE, "failed to create PolicyKit authority.");
} else {
nm_log_warn (LOGD_CORE, "failed to create PolicyKit authority: (%d) %s",
error ? error->code : -1,
error && error->message ? error->message : "(unknown)");
g_clear_error (&error);
}
/* Monitor the firmware directory */
if (strlen (KERNEL_FIRMWARE_DIR)) {

View file

@ -133,6 +133,7 @@ nm_policy_get_etc_hosts (const char **lines,
gboolean hostname6_is_fallback;
gboolean host4_before = FALSE;
gboolean host6_before = FALSE;
char *short_hostname = NULL;
g_return_val_if_fail (lines != NULL, FALSE);
g_return_val_if_fail (hostname != NULL, FALSE);
@ -206,6 +207,24 @@ nm_policy_get_etc_hosts (const char **lines,
return NULL;
}
/* Find the short hostname, like 'foo' from 'foo.bar.baz'; we want to
* make sure that the entries we add for this host also include the short
* hostname too so that if the resolver does not answer queries for the
* machine's actual hostname/domain, that stuff like 'ping foo' still works.
*/
if (!hostname4_is_fallback || !hostname6_is_fallback) {
char *dot;
short_hostname = g_strdup (hostname);
dot = strchr (short_hostname, '.');
if (dot && *(dot+1))
*dot = '\0';
else {
g_free (short_hostname);
short_hostname = NULL;
}
}
/* Construct the new hosts file; replace any 127.0.0.1/::1 entry that is
* at the beginning of the file or right after initial comments and contains
* the string 'localhost' (for IPv4) or 'localhost6' (for IPv6). If there
@ -229,21 +248,35 @@ nm_policy_get_etc_hosts (const char **lines,
*/
/* Add the address mappings first so they take precedence */
if (!hostname4_is_fallback && ip4_addr && !found_user_host4)
g_string_append_printf (contents, "%s\t%s\t%s\n", ip4_addr, hostname, ADDED_TAG);
if (!hostname6_is_fallback && ip6_addr && !found_user_host6)
g_string_append_printf (contents, "%s\t%s\t%s\n", ip6_addr, hostname, ADDED_TAG);
if (!hostname4_is_fallback && ip4_addr && !found_user_host4) {
g_string_append_printf (contents, "%s\t%s", ip4_addr, hostname);
if (short_hostname)
g_string_append_printf (contents, "\t%s", short_hostname);
g_string_append_printf (contents, "\t%s\n", ADDED_TAG);
}
if (!hostname6_is_fallback && ip6_addr && !found_user_host6) {
g_string_append_printf (contents, "%s\t%s", ip6_addr, hostname);
if (short_hostname)
g_string_append_printf (contents, "\t%s", short_hostname);
g_string_append_printf (contents, "\t%s\n", ADDED_TAG);
}
/* IPv4 localhost line */
g_string_append (contents, "127.0.0.1");
if (!hostname4_is_fallback && !ip4_addr && !found_user_host4)
if (!hostname4_is_fallback && !ip4_addr && !found_user_host4) {
g_string_append_printf (contents, "\t%s", hostname);
if (short_hostname)
g_string_append_printf (contents, "\t%s", short_hostname);
}
g_string_append_printf (contents, "\t%s\tlocalhost\n", fallback_hostname4);
/* IPv6 localhost line */
g_string_append (contents, "::1");
if (!hostname6_is_fallback && !hostname4_is_fallback && !ip6_addr && !found_user_host6)
if (!hostname6_is_fallback && !hostname4_is_fallback && !ip6_addr && !found_user_host6) {
g_string_append_printf (contents, "\t%s", hostname);
if (short_hostname)
g_string_append_printf (contents, "\t%s", short_hostname);
}
g_string_append_printf (contents, "\t%s\tlocalhost6\n", fallback_hostname6);
added = TRUE;
@ -277,15 +310,24 @@ nm_policy_get_etc_hosts (const char **lines,
g_string_append (contents, "# that require network functionality will fail.\n");
/* Add the address mappings first so they take precedence */
if (!hostname4_is_fallback && ip4_addr)
g_string_append_printf (contents, "%s\t%s\t%s\n", ip4_addr, hostname, ADDED_TAG);
if (!hostname6_is_fallback && ip6_addr)
g_string_append_printf (contents, "%s\t%s\t%s\n", ip6_addr, hostname, ADDED_TAG);
if (!hostname4_is_fallback && ip4_addr) {
g_string_append_printf (contents, "%s\t%s", ip4_addr, hostname);
if (short_hostname)
g_string_append_printf (contents, "\t%s", short_hostname);
g_string_append_printf (contents, "\t%s\n", ADDED_TAG);
}
if (!hostname6_is_fallback && ip6_addr) {
g_string_append_printf (contents, "%s\t%s", ip6_addr, hostname);
if (short_hostname)
g_string_append_printf (contents, "\t%s", short_hostname);
g_string_append_printf (contents, "\t%s\n", ADDED_TAG);
}
g_string_append_printf (contents, "127.0.0.1\t%s\tlocalhost\n", fallback_hostname4);
g_string_append_printf (contents, "::1\t%s\tlocalhost6\n", fallback_hostname6);
}
g_free (short_hostname);
return contents;
}

View file

@ -138,7 +138,8 @@ get_best_ip4_device (NMManager *manager, NMActRequest **out_req)
continue;
/* 'never-default' devices can't ever be the default */
if (s_ip4 && nm_setting_ip4_config_get_never_default (s_ip4))
if ( (s_ip4 && nm_setting_ip4_config_get_never_default (s_ip4))
|| nm_ip4_config_get_never_default (ip4_config))
continue;
prio = nm_device_get_priority (dev);
@ -482,6 +483,13 @@ update_ip4_routing_and_dns (NMPolicy *policy, gboolean force_update)
/* If it's marked 'never-default', don't make it default */
vpn_connection = nm_vpn_connection_get_connection (candidate);
g_assert (vpn_connection);
/* Check the active IP4 config from the VPN service daemon */
ip4_config = nm_vpn_connection_get_ip4_config (candidate);
if (ip4_config && nm_ip4_config_get_never_default (ip4_config))
can_default = FALSE;
/* Check the user's preference from the NMConnection */
s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (vpn_connection, NM_TYPE_SETTING_IP4_CONFIG);
if (s_ip4 && nm_setting_ip4_config_get_never_default (s_ip4))
can_default = FALSE;
@ -493,7 +501,6 @@ update_ip4_routing_and_dns (NMPolicy *policy, gboolean force_update)
ip_iface = nm_vpn_connection_get_ip_iface (candidate);
connection = nm_vpn_connection_get_connection (candidate);
ip4_config = nm_vpn_connection_get_ip4_config (candidate);
addr = nm_ip4_config_get_address (ip4_config, 0);
parent = nm_vpn_connection_get_parent_device (candidate);
@ -1205,6 +1212,7 @@ nm_policy_destroy (NMPolicy *policy)
g_signal_handler_disconnect (policy->vpn_manager, policy->vpn_activated_id);
g_signal_handler_disconnect (policy->vpn_manager, policy->vpn_deactivated_id);
g_object_unref (policy->vpn_manager);
for (iter = policy->signal_ids; iter; iter = g_slist_next (iter))
g_signal_handler_disconnect (policy->manager, (gulong) iter->data);

View file

@ -481,32 +481,34 @@ nm_system_apply_ip4_config (const char *iface,
return TRUE;
}
static struct rtnl_route *
nm_system_device_set_ip6_route (const char *iface,
const struct in6_addr *ip6_dest,
guint32 ip6_prefix,
const struct in6_addr *ip6_gateway,
guint32 metric,
int mss)
int
nm_system_set_ip6_route (int ifindex,
const struct in6_addr *ip6_dest,
guint32 ip6_prefix,
const struct in6_addr *ip6_gateway,
guint32 metric,
int mss,
int protocol,
int table,
struct rtnl_route **out_route)
{
struct nl_handle *nlh;
struct rtnl_route *route;
struct nl_addr *dest_addr;
struct nl_addr *gw_addr = NULL;
int err, iface_idx;
int err = 0;
g_return_val_if_fail (ifindex >= 0, -1);
nlh = nm_netlink_get_default_handle ();
g_return_val_if_fail (nlh != NULL, NULL);
g_return_val_if_fail (nlh != NULL, -1);
iface_idx = nm_netlink_iface_to_index (iface);
g_return_val_if_fail (iface_idx >= 0, NULL);
route = create_route (iface_idx, mss);
g_return_val_if_fail (route != NULL, NULL);
route = create_route (ifindex, mss);
g_return_val_if_fail (route != NULL, -1);
/* Destination */
dest_addr = nl_addr_build (AF_INET6, (struct in6_addr *) ip6_dest, sizeof (*ip6_dest));
g_return_val_if_fail (dest_addr != NULL, NULL);
g_return_val_if_fail (dest_addr != NULL, -1);
nl_addr_set_prefixlen (dest_addr, (int) ip6_prefix);
rtnl_route_set_dst (route, dest_addr);
@ -521,7 +523,7 @@ nm_system_device_set_ip6_route (const char *iface,
} else {
nm_log_warn (LOGD_DEVICE | LOGD_IP6, "Invalid gateway");
rtnl_route_put (route);
return NULL;
return -1;
}
}
@ -529,13 +531,19 @@ nm_system_device_set_ip6_route (const char *iface,
if (metric)
rtnl_route_set_prio (route, metric);
if (protocol)
rtnl_route_set_protocol (route, protocol);
if (table)
rtnl_route_set_table (route, table);
/* Add the route */
err = rtnl_route_add (nlh, route, 0);
if (err == -ESRCH && ip6_gateway) {
/* Gateway might be over a bridge; try adding a route to gateway first */
struct rtnl_route *route2;
route2 = create_route (iface_idx, mss);
route2 = create_route (ifindex, mss);
if (route2) {
/* Add route to gateway over bridge */
rtnl_route_set_dst (route2, gw_addr);
@ -553,15 +561,12 @@ nm_system_device_set_ip6_route (const char *iface,
if (gw_addr)
nl_addr_put (gw_addr);
if (err) {
nm_log_err (LOGD_DEVICE | LOGD_IP6,
"(%s): failed to set IPv6 route: %s",
iface, nl_geterror ());
if (out_route)
*out_route = route;
else
rtnl_route_put (route);
route = NULL;
}
return route;
return err;
}
static gboolean
@ -618,24 +623,33 @@ nm_system_apply_ip6_config (const char *iface,
}
if (flags & NM_IP6_COMPARE_FLAG_ROUTES) {
int ifindex = nm_netlink_iface_to_index (iface);
for (i = 0; i < nm_ip6_config_get_num_routes (config); i++) {
NMIP6Route *route = nm_ip6_config_get_route (config, i);
struct rtnl_route *tmp;
int err;
/* Don't add the route if it doesn't have a gateway and the connection
* is never supposed to be the default connection.
*/
if ( nm_ip6_config_get_never_default (config)
&& IN6_IS_ADDR_UNSPECIFIED(nm_ip6_route_get_dest (route)))
&& IN6_IS_ADDR_UNSPECIFIED (nm_ip6_route_get_dest (route)))
continue;
tmp = nm_system_device_set_ip6_route (iface,
nm_ip6_route_get_dest (route),
nm_ip6_route_get_prefix (route),
nm_ip6_route_get_next_hop (route),
nm_ip6_route_get_metric (route),
nm_ip6_config_get_mss (config));
rtnl_route_put (tmp);
err = nm_system_set_ip6_route (ifindex,
nm_ip6_route_get_dest (route),
nm_ip6_route_get_prefix (route),
nm_ip6_route_get_next_hop (route),
nm_ip6_route_get_metric (route),
nm_ip6_config_get_mss (config),
RTPROT_UNSPEC,
RT_TABLE_UNSPEC,
NULL);
if (err) {
nm_log_err (LOGD_DEVICE | LOGD_IP6,
"(%s): failed to set IPv6 route: %s",
iface, nl_geterror ());
}
}
}
@ -1225,6 +1239,45 @@ foreach_route (void (*callback)(struct nl_object *, gpointer),
nl_cache_free (route_cache);
}
static void
dump_route (struct rtnl_route *route)
{
char buf6[INET6_ADDRSTRLEN];
char buf4[INET_ADDRSTRLEN];
struct nl_addr *nl;
struct in6_addr *addr6 = NULL;
struct in_addr *addr4 = NULL;
int prefixlen = 0;
const char *sf = "UNSPEC";
int family = rtnl_route_get_family (route);
memset (buf6, 0, sizeof (buf6));
memset (buf4, 0, sizeof (buf4));
nl = rtnl_route_get_dst (route);
if (nl) {
if (rtnl_route_get_family (route) == AF_INET) {
addr4 = nl_addr_get_binary_addr (nl);
if (addr4)
inet_ntop (AF_INET, addr4, &buf4[0], sizeof (buf4));
} else if (rtnl_route_get_family (route) == AF_INET6) {
addr6 = nl_addr_get_binary_addr (nl);
if (addr6)
inet_ntop (AF_INET6, addr6, &buf6[0], sizeof (buf6));
}
prefixlen = nl_addr_get_prefixlen (nl);
}
if (family == AF_INET)
sf = "INET";
else if (family == AF_INET6)
sf = "INET6";
nm_log_dbg (LOGD_IP4 | LOGD_IP6, " route idx %d family %s (%d) addr %s/%d",
rtnl_route_get_oif (route),
sf, family,
strlen (buf4) ? buf4 : (strlen (buf6) ? buf6 : "<unknown>"),
prefixlen);
}
typedef struct {
const char *iface;
@ -1238,6 +1291,10 @@ check_one_route (struct nl_object *object, void *user_data)
RouteCheckData *data = (RouteCheckData *) user_data;
struct rtnl_route *route = (struct rtnl_route *) object;
int err;
guint32 log_level = LOGD_IP4 | LOGD_IP6;
if (nm_logging_level_enabled (LOGL_DEBUG))
dump_route (route);
/* Delete all routes from this interface */
if (rtnl_route_get_oif (route) != data->iface_idx)
@ -1259,11 +1316,19 @@ check_one_route (struct nl_object *object, void *user_data)
addr = nl_addr_get_binary_addr (nl);
if (addr) {
if (IN6_IS_ADDR_LINKLOCAL (addr) || IN6_IS_ADDR_MC_LINKLOCAL (addr))
if ( IN6_IS_ADDR_LINKLOCAL (addr)
|| IN6_IS_ADDR_MC_LINKLOCAL (addr)
|| (IN6_IS_ADDR_MULTICAST (addr) && (nl_addr_get_prefixlen (nl) == 8)))
return;
}
}
if (data->family == AF_INET)
log_level = LOGD_IP4;
else if (data->family == AF_INET6)
log_level = LOGD_IP6;
nm_log_dbg (log_level, " deleting route");
err = rtnl_route_del (nm_netlink_get_default_handle (), route, 0);
if (err < 0 && (err != -ERANGE)) {
nm_log_err (LOGD_DEVICE,
@ -1275,6 +1340,8 @@ check_one_route (struct nl_object *object, void *user_data)
static void flush_routes (int ifindex, const char *iface, int family)
{
RouteCheckData check_data;
guint32 log_level = LOGD_IP4 | LOGD_IP6;
const char *sf = "UNSPEC";
g_return_if_fail (iface != NULL);
@ -1286,6 +1353,16 @@ static void flush_routes (int ifindex, const char *iface, int family)
}
}
if (family == AF_INET) {
log_level = LOGD_IP4;
sf = "INET";
} else if (family == AF_INET6) {
log_level = LOGD_IP6;
sf = "INET6";
}
nm_log_dbg (log_level, "(%s): flushing routes ifindex %d family %s (%d)",
iface, ifindex, sf, family);
memset (&check_data, 0, sizeof (check_data));
check_data.iface = iface;
check_data.iface_idx = ifindex;

View file

@ -66,6 +66,16 @@ gboolean nm_system_apply_ip4_config (const char *iface,
int priority,
NMIP4ConfigCompareFlags flags);
int nm_system_set_ip6_route (int ifindex,
const struct in6_addr *ip6_dest,
guint32 ip6_prefix,
const struct in6_addr *ip6_gateway,
guint32 metric,
int mss,
int protocol,
int table,
struct rtnl_route **out_route);
gboolean nm_system_apply_ip6_config (const char *iface,
NMIP6Config *config,
int priority,

View file

@ -153,6 +153,8 @@ set_property (GObject *object, guint prop_id,
case PROP_STRENGTH:
nm_ap_set_strength (ap, g_value_get_char (value));
break;
case PROP_HW_ADDRESS:
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -242,7 +244,7 @@ nm_ap_class_init (NMAccessPointClass *ap_class)
NM_802_11_AP_FLAGS_NONE,
NM_802_11_AP_FLAGS_PRIVACY,
NM_802_11_AP_FLAGS_NONE,
G_PARAM_READWRITE));
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property
(object_class, PROP_WPA_FLAGS,
@ -252,7 +254,7 @@ nm_ap_class_init (NMAccessPointClass *ap_class)
NM_802_11_AP_SEC_NONE,
all_sec_flags,
NM_802_11_AP_SEC_NONE,
G_PARAM_READWRITE));
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property
(object_class, PROP_RSN_FLAGS,
@ -262,7 +264,7 @@ nm_ap_class_init (NMAccessPointClass *ap_class)
NM_802_11_AP_SEC_NONE,
all_sec_flags,
NM_802_11_AP_SEC_NONE,
G_PARAM_READWRITE));
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property
(object_class, PROP_SSID,
@ -270,7 +272,7 @@ nm_ap_class_init (NMAccessPointClass *ap_class)
"SSID",
"SSID",
DBUS_TYPE_G_UCHAR_ARRAY,
G_PARAM_READWRITE));
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property
(object_class, PROP_FREQUENCY,
@ -278,7 +280,7 @@ nm_ap_class_init (NMAccessPointClass *ap_class)
"Frequency",
"Frequency",
0, 10000, 0,
G_PARAM_READWRITE));
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property
(object_class, PROP_HW_ADDRESS,
@ -286,7 +288,7 @@ nm_ap_class_init (NMAccessPointClass *ap_class)
"MAC Address",
"Hardware MAC address",
NULL,
G_PARAM_READABLE));
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property
(object_class, PROP_MODE,
@ -294,7 +296,7 @@ nm_ap_class_init (NMAccessPointClass *ap_class)
"Mode",
"Mode",
NM_802_11_MODE_ADHOC, NM_802_11_MODE_INFRA, NM_802_11_MODE_INFRA,
G_PARAM_READWRITE));
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property
(object_class, PROP_MAX_BITRATE,
@ -302,7 +304,7 @@ nm_ap_class_init (NMAccessPointClass *ap_class)
"Max Bitrate",
"Max Bitrate",
0, G_MAXUINT16, 0,
G_PARAM_READWRITE));
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property
(object_class, PROP_STRENGTH,
@ -310,7 +312,7 @@ nm_ap_class_init (NMAccessPointClass *ap_class)
"Strength",
"Strength",
G_MININT8, G_MAXINT8, 0,
G_PARAM_READWRITE));
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
/* Signals */
signals[PROPERTIES_CHANGED] =

View file

@ -16,12 +16,13 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* (C) Copyright 2008 Novell, Inc.
* (C) Copyright 2008 Red Hat, Inc.
* (C) Copyright 2008 - 2010 Red Hat, Inc.
*/
#ifndef NM_POLKIT_HELPERS_H
#define NM_POLKIT_HELPERS_H
#include <config.h>
#include <polkit/polkit.h>
#define NM_SYSCONFIG_POLICY_ACTION_CONNECTION_MODIFY "org.freedesktop.NetworkManager.settings.modify"
@ -29,4 +30,18 @@
#define NM_SYSCONFIG_POLICY_ACTION_WIFI_SHARE_OPEN "org.freedesktop.NetworkManager.settings.wifi.share.open"
#define NM_SYSCONFIG_POLICY_ACTION_HOSTNAME_MODIFY "org.freedesktop.NetworkManager.settings.hostname.modify"
/* Fix for polkit 0.97 and later */
#if !HAVE_POLKIT_AUTHORITY_GET_SYNC
static inline PolkitAuthority *
polkit_authority_get_sync (GCancellable *cancellable, GError **error)
{
PolkitAuthority *authority;
authority = polkit_authority_get ();
if (!authority)
g_set_error (error, 0, 0, "failed to get the PolicyKit authority");
return authority;
}
#endif
#endif /* NM_POLKIT_HELPERS_H */

View file

@ -162,7 +162,7 @@ get_unix_user_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data
guint user_id;
struct passwd *pw_info = NULL;
int ngroups;
guint group_ids_size;
guint group_ids_size = 0;
gid_t *group_ids = NULL;
GSList *group_names = NULL;
NMSessionInfo *session = NULL;
@ -196,7 +196,7 @@ get_unix_user_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data
// Get the list of group IDs
// FIXME what happens if the group list changes in the window between the
// two getgrouplist calls?
group_ids_size = ngroups * sizeof(gid_t);
group_ids_size = ngroups * sizeof (gid_t);
group_ids = g_slice_alloc (group_ids_size);
if (getgrouplist (pw_info->pw_name, pw_info->pw_gid, group_ids, &ngroups) == -1) {
error = g_error_new (NM_SESSION_MANAGER_ERROR,

View file

@ -16,7 +16,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* (C) Copyright 2008 Novell, Inc.
* (C) Copyright 2008 - 2009 Red Hat, Inc.
* (C) Copyright 2008 - 2010 Red Hat, Inc.
*/
#include <NetworkManager.h>
@ -1004,10 +1004,14 @@ nm_sysconfig_connection_init (NMSysconfigConnection *self)
NMSessionManager *session_manager;
static guint32 dbus_counter = 0;
char *dbus_path;
GError *error = NULL;
priv->authority = polkit_authority_get ();
priv->authority = polkit_authority_get_sync (NULL, NULL);
if (!priv->authority) {
nm_log_err (LOGD_SYS_SET, "%s:error creating PolicyKit authority");
nm_log_warn (LOGD_SYS_SET, "failed to create PolicyKit authority: (%d) %s",
error ? error->code : -1,
error && error->message ? error->message : "(unknown)");
g_clear_error (&error);
}
dbus_path = g_strdup_printf ("%s/%u", NM_DBUS_PATH_SETTINGS, dbus_counter++);

View file

@ -1601,17 +1601,22 @@ static void
nm_sysconfig_settings_init (NMSysconfigSettings *self)
{
NMSysconfigSettingsPrivate *priv = NM_SYSCONFIG_SETTINGS_GET_PRIVATE (self);
GError *error = NULL;
priv->visible_connections = g_hash_table_new (g_direct_hash, g_direct_equal);
priv->all_connections = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL);
priv->authority = polkit_authority_get ();
priv->authority = polkit_authority_get_sync (NULL, &error);
if (priv->authority) {
priv->auth_changed_id = g_signal_connect (priv->authority,
"changed",
G_CALLBACK (pk_authority_changed_cb),
self);
} else
nm_log_warn (LOGD_SYS_SET, "failed to create PolicyKit authority.");
} else {
nm_log_warn (LOGD_SYS_SET, "failed to create PolicyKit authority: (%d) %s",
error ? error->code : -1,
error && error->message ? error->message : "(unknown)");
g_clear_error (&error);
}
}

View file

@ -375,6 +375,24 @@ test_hosts_named46_non127 (void)
/*******************************************/
static const char *named46_non127_long_before = \
"# Do not remove the following line, or various programs\n"
"# that require network functionality will fail.\n"
"127.0.0.1 localhost.localdomain localhost\n"
"::1 localhost6.localdomain6 localhost6\n"
"192.168.1.2 comet.space comet\n"
"3001:abba::3234 comet.space comet\n"
"\n"
"127.0.0.1 lcmd.us.intellitxt.com\n";
static void
test_hosts_named46_non127_long (void)
{
test_generic (named46_non127_long_before, NULL, "comet.space", "192.168.1.2", "3001:abba::3234", FALSE);
}
/*******************************************/
static const char *named46_non127_other4_before = \
"# Do not remove the following line, or various programs\n"
"# that require network functionality will fail.\n"
@ -404,6 +422,35 @@ test_hosts_named46_non127_other4 (void)
/*******************************************/
static const char *named46_non127_other4_long_before = \
"# Do not remove the following line, or various programs\n"
"# that require network functionality will fail.\n"
"127.0.0.1 localhost.localdomain localhost\n"
"::1 localhost6.localdomain6 localhost6\n"
"192.168.1.3 comet.space\n"
"3001:abba::3234 comet.space\n"
"\n"
"127.0.0.1 lcmd.us.intellitxt.com\n";
static const char *named46_non127_other4_long_after = \
"# Do not remove the following line, or various programs\n"
"# that require network functionality will fail.\n"
"192.168.1.2 comet.space comet # Added by NetworkManager\n"
"127.0.0.1 localhost.localdomain localhost\n"
"::1 localhost6.localdomain6 localhost6\n"
"192.168.1.3 comet.space\n"
"3001:abba::3234 comet.space\n"
"\n"
"127.0.0.1 lcmd.us.intellitxt.com\n";
static void
test_hosts_named46_non127_other4_long (void)
{
test_generic (named46_non127_other4_long_before, named46_non127_other4_long_after, "comet.space", "192.168.1.2", "3001:abba::3234", FALSE);
}
/*******************************************/
static const char *named46_non127_other6_before = \
"# Do not remove the following line, or various programs\n"
"# that require network functionality will fail.\n"
@ -433,6 +480,35 @@ test_hosts_named46_non127_other6 (void)
/*******************************************/
static const char *named46_non127_other6_long_before = \
"# Do not remove the following line, or various programs\n"
"# that require network functionality will fail.\n"
"127.0.0.1 localhost.localdomain localhost\n"
"::1 localhost6.localdomain6 localhost6\n"
"192.168.1.2 comet.space\n"
"3001:abba::9675 comet.space\n"
"\n"
"127.0.0.1 lcmd.us.intellitxt.com\n";
static const char *named46_non127_other6_long_after = \
"# Do not remove the following line, or various programs\n"
"# that require network functionality will fail.\n"
"3001:abba::3234 comet.space comet # Added by NetworkManager\n"
"127.0.0.1 localhost.localdomain localhost\n"
"::1 localhost6.localdomain6 localhost6\n"
"192.168.1.2 comet.space\n"
"3001:abba::9675 comet.space\n"
"\n"
"127.0.0.1 lcmd.us.intellitxt.com\n";
static void
test_hosts_named46_non127_other6_long (void)
{
test_generic (named46_non127_other6_long_before, named46_non127_other6_long_after, "comet.space", "192.168.1.2", "3001:abba::3234", FALSE);
}
/*******************************************/
static const char *unnamed46_non127_before = \
"# Do not remove the following line, or various programs\n"
"# that require network functionality will fail.\n"
@ -459,6 +535,32 @@ test_hosts_unnamed46_non127 (void)
/*******************************************/
static const char *unnamed46_non127_long_before = \
"# Do not remove the following line, or various programs\n"
"# that require network functionality will fail.\n"
"127.0.0.1 localhost.localdomain localhost\n"
"::1 localhost6.localdomain6 localhost6\n"
"\n"
"127.0.0.1 lcmd.us.intellitxt.com\n";
static const char *unnamed46_non127_long_after = \
"# Do not remove the following line, or various programs\n"
"# that require network functionality will fail.\n"
"192.168.1.2 comet.space comet # Added by NetworkManager\n"
"3001:abba::3234 comet.space comet # Added by NetworkManager\n"
"127.0.0.1 localhost.localdomain localhost\n"
"::1 localhost6.localdomain6 localhost6\n"
"\n"
"127.0.0.1 lcmd.us.intellitxt.com\n";
static void
test_hosts_unnamed46_non127_long (void)
{
test_generic (unnamed46_non127_long_before, unnamed46_non127_long_after, "comet.space", "192.168.1.2", "3001:abba::3234", FALSE);
}
/*******************************************/
static const char *named46_non127_wrong_before = \
"# Do not remove the following line, or various programs\n"
"# that require network functionality will fail.\n"
@ -569,7 +671,11 @@ test_find_token (void)
}
}
#if GLIB_CHECK_VERSION(2,25,12)
typedef GTestFixtureFunc TCFunc;
#else
typedef void (*TCFunc)(void);
#endif
#define TESTCASE(t, d) g_test_create_case (#t, 0, d, NULL, (TCFunc) t, NULL)
@ -592,10 +698,14 @@ int main (int argc, char **argv)
g_test_suite_add (suite, TESTCASE (test_hosts_named4_non127_more, NULL));
g_test_suite_add (suite, TESTCASE (test_hosts_named6_non127_more, NULL));
g_test_suite_add (suite, TESTCASE (test_hosts_named46_non127, NULL));
g_test_suite_add (suite, TESTCASE (test_hosts_named46_non127_long, NULL));
g_test_suite_add (suite, TESTCASE (test_hosts_named46_non127_other4, NULL));
g_test_suite_add (suite, TESTCASE (test_hosts_named46_non127_other4_long, NULL));
g_test_suite_add (suite, TESTCASE (test_hosts_named46_non127_other6, NULL));
g_test_suite_add (suite, TESTCASE (test_hosts_named46_non127_other6_long, NULL));
g_test_suite_add (suite, TESTCASE (test_hosts_named46_non127_wrong, NULL));
g_test_suite_add (suite, TESTCASE (test_hosts_unnamed46_non127, NULL));
g_test_suite_add (suite, TESTCASE (test_hosts_unnamed46_non127_long, NULL));
g_test_suite_add (suite, TESTCASE (test_hosts_named_no_localhost, NULL));
g_test_suite_add (suite, TESTCASE (test_hosts_no_localhost, NULL));
g_test_suite_add (suite, TESTCASE (test_hosts_named_last, NULL));

View file

@ -381,6 +381,9 @@ print_vpn_config (NMIP4Config *config,
ip_address_to_string (nm_ip4_route_get_next_hop (route)));
}
nm_log_info (LOGD_VPN, "Forbid Default Route: %s",
nm_ip4_config_get_never_default (config) ? "yes" : "no");
num = nm_ip4_config_get_num_nameservers (config);
for (i = 0; i < num; i++) {
nm_log_info (LOGD_VPN, "Internal IP4 DNS: %s",
@ -526,6 +529,10 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
g_slist_free (routes);
}
val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_NEVER_DEFAULT);
if (val && G_VALUE_HOLDS_BOOLEAN (val))
nm_ip4_config_set_never_default (config, g_value_get_boolean (val));
print_vpn_config (config, priv->ip4_internal_gw, priv->ip_iface, priv->banner);
/* Merge in user overrides from the NMConnection's IPv4 setting */

View file

@ -15,11 +15,12 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2005 - 2008 Red Hat, Inc.
* Copyright (C) 2005 - 2010 Red Hat, Inc.
* Copyright (C) 2006 - 2008 Novell, Inc.
*/
#include <string.h>
#include <gio/gio.h>
#include "nm-vpn-manager.h"
#include "nm-vpn-service.h"
@ -28,13 +29,18 @@
#include "nm-dbus-manager.h"
#include "NetworkManagerVPN.h"
#include "nm-marshal.h"
#include "nm-logging.h"
G_DEFINE_TYPE (NMVPNManager, nm_vpn_manager, G_TYPE_OBJECT)
#define NM_VPN_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_VPN_MANAGER, NMVPNManagerPrivate))
typedef struct {
GSList *services;
gboolean disposed;
GHashTable *services;
GFileMonitor *monitor;
guint monitor_id;
} NMVPNManagerPrivate;
enum {
@ -81,53 +87,42 @@ nm_vpn_manager_error_get_type (void)
}
static NMVPNService *
nm_vpn_manager_get_service (NMVPNManager *manager, const char *service_name)
get_service_by_namefile (NMVPNManager *self, const char *namefile)
{
GSList *iter;
NMVPNManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (self);
GHashTableIter iter;
gpointer data;
for (iter = NM_VPN_MANAGER_GET_PRIVATE (manager)->services; iter; iter = iter->next) {
NMVPNService *service = NM_VPN_SERVICE (iter->data);
g_return_val_if_fail (namefile, NULL);
g_return_val_if_fail (g_path_is_absolute (namefile), NULL);
if (!strcmp (service_name, nm_vpn_service_get_name (service)))
return g_object_ref (service);
g_hash_table_iter_init (&iter, priv->services);
while (g_hash_table_iter_next (&iter, NULL, &data)) {
NMVPNService *candidate = NM_VPN_SERVICE (data);
const char *service_namefile;
service_namefile = nm_vpn_service_get_name_file (candidate);
if (!strcmp (namefile, service_namefile))
return candidate;
}
return NULL;
}
static void
remove_service (gpointer data, GObject *service)
{
NMVPNManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (data);
priv->services = g_slist_remove (priv->services, service);
}
static void
nm_vpn_manager_add_service (NMVPNManager *manager, NMVPNService *service)
{
NMVPNManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (manager);
priv->services = g_slist_prepend (priv->services, service);
g_object_weak_ref (G_OBJECT (service), remove_service, manager);
}
static NMVPNConnection *
find_active_vpn_connection_by_connection (NMVPNManager *manager, NMConnection *connection)
find_active_vpn_connection_by_connection (NMVPNManager *self, NMConnection *connection)
{
NMVPNManagerPrivate *priv;
GSList *iter;
NMVPNManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (self);
GHashTableIter iter;
gpointer data;
GSList *connections, *elt;
g_return_val_if_fail (NM_IS_VPN_MANAGER (manager), NULL);
g_return_val_if_fail (connection, NULL);
g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
priv = NM_VPN_MANAGER_GET_PRIVATE (manager);
for (iter = priv->services; iter; iter = g_slist_next (iter)) {
GSList *connections, *elt;
connections = nm_vpn_service_get_active_connections (NM_VPN_SERVICE (iter->data));
g_hash_table_iter_init (&iter, priv->services);
while (g_hash_table_iter_next (&iter, NULL, &data)) {
connections = nm_vpn_service_get_active_connections (NM_VPN_SERVICE (data));
for (elt = connections; elt; elt = g_slist_next (elt)) {
NMVPNConnection *vpn = NM_VPN_CONNECTION (elt->data);
@ -169,7 +164,7 @@ nm_vpn_manager_activate_connection (NMVPNManager *manager,
NMSettingVPN *vpn_setting;
NMVPNService *service;
NMVPNConnection *vpn = NULL;
const char *service_type;
const char *service_name;
g_return_val_if_fail (NM_IS_VPN_MANAGER (manager), NULL);
g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
@ -199,78 +194,78 @@ nm_vpn_manager_activate_connection (NMVPNManager *manager,
vpn = NULL;
}
service_type = nm_setting_vpn_get_service_type (vpn_setting);
service = nm_vpn_manager_get_service (manager, service_type);
service_name = nm_setting_vpn_get_service_type (vpn_setting);
g_assert (service_name);
service = g_hash_table_lookup (NM_VPN_MANAGER_GET_PRIVATE (manager)->services, service_name);
if (!service) {
service = nm_vpn_service_new (service_type);
if (service)
nm_vpn_manager_add_service (manager, service);
}
if (service) {
vpn = nm_vpn_service_activate (service, connection, act_request, device, error);
if (vpn) {
g_signal_connect (vpn, "vpn-state-changed",
G_CALLBACK (connection_vpn_state_changed),
manager);
}
} else {
g_set_error (error,
NM_VPN_MANAGER_ERROR, NM_VPN_MANAGER_ERROR_SERVICE_INVALID,
"%s", "The VPN service was invalid.");
"The VPN service '%s' was not installed.",
service_name);
return NULL;
}
vpn = nm_vpn_service_activate (service, connection, act_request, device, error);
if (vpn) {
g_signal_connect (vpn, "vpn-state-changed",
G_CALLBACK (connection_vpn_state_changed),
manager);
}
return vpn;
}
gboolean
nm_vpn_manager_deactivate_connection (NMVPNManager *manager,
nm_vpn_manager_deactivate_connection (NMVPNManager *self,
const char *path,
NMVPNConnectionStateReason reason)
{
NMVPNManagerPrivate *priv;
GSList *iter;
gboolean found = FALSE;
GHashTableIter iter;
gpointer data;
GSList *active, *elt;
g_return_val_if_fail (NM_IS_VPN_MANAGER (manager), FALSE);
g_return_val_if_fail (self, FALSE);
g_return_val_if_fail (NM_IS_VPN_MANAGER (self), FALSE);
g_return_val_if_fail (path != NULL, FALSE);
priv = NM_VPN_MANAGER_GET_PRIVATE (manager);
for (iter = priv->services; iter; iter = g_slist_next (iter)) {
GSList *connections, *elt;
connections = nm_vpn_service_get_active_connections (NM_VPN_SERVICE (iter->data));
for (elt = connections; elt; elt = g_slist_next (elt)) {
priv = NM_VPN_MANAGER_GET_PRIVATE (self);
g_hash_table_iter_init (&iter, priv->services);
while (g_hash_table_iter_next (&iter, NULL, &data)) {
active = nm_vpn_service_get_active_connections (NM_VPN_SERVICE (data));
for (elt = active; elt; elt = g_slist_next (elt)) {
NMVPNConnection *vpn = NM_VPN_CONNECTION (elt->data);
const char *vpn_path;
vpn_path = nm_vpn_connection_get_active_connection_path (vpn);
if (!strcmp (path, vpn_path)) {
nm_vpn_connection_disconnect (vpn, reason);
found = TRUE;
return TRUE;
}
}
}
return found ? TRUE : FALSE;
return FALSE;
}
void
nm_vpn_manager_add_active_connections (NMVPNManager *manager,
nm_vpn_manager_add_active_connections (NMVPNManager *self,
NMConnection *filter,
GPtrArray *array)
{
NMVPNManagerPrivate *priv;
GSList *iter;
GHashTableIter iter;
gpointer data;
GSList *active, *elt;
g_return_if_fail (NM_IS_VPN_MANAGER (manager));
g_return_if_fail (self);
g_return_if_fail (NM_IS_VPN_MANAGER (self));
g_return_if_fail (array != NULL);
priv = NM_VPN_MANAGER_GET_PRIVATE (manager);
for (iter = priv->services; iter; iter = g_slist_next (iter)) {
GSList *active, *elt;
active = nm_vpn_service_get_active_connections (NM_VPN_SERVICE (iter->data));
priv = NM_VPN_MANAGER_GET_PRIVATE (self);
g_hash_table_iter_init (&iter, priv->services);
while (g_hash_table_iter_next (&iter, NULL, &data)) {
active = nm_vpn_service_get_active_connections (NM_VPN_SERVICE (data));
for (elt = active; elt; elt = g_slist_next (elt)) {
NMVPNConnection *vpn = NM_VPN_CONNECTION (elt->data);
const char *path;
@ -284,23 +279,23 @@ nm_vpn_manager_add_active_connections (NMVPNManager *manager,
}
GSList *
nm_vpn_manager_get_active_connections (NMVPNManager *manager)
nm_vpn_manager_get_active_connections (NMVPNManager *self)
{
NMVPNManagerPrivate *priv;
GSList *iter;
GSList *list = NULL;
GHashTableIter iter;
gpointer data;
GSList *list = NULL, *active, *elt;
g_return_val_if_fail (NM_IS_VPN_MANAGER (manager), NULL);
g_return_val_if_fail (self, NULL);
g_return_val_if_fail (NM_IS_VPN_MANAGER (self), NULL);
priv = NM_VPN_MANAGER_GET_PRIVATE (manager);
for (iter = priv->services; iter; iter = g_slist_next (iter)) {
GSList *active, *elt;
active = nm_vpn_service_get_active_connections (NM_VPN_SERVICE (iter->data));
priv = NM_VPN_MANAGER_GET_PRIVATE (self);
g_hash_table_iter_init (&iter, priv->services);
while (g_hash_table_iter_next (&iter, NULL, &data)) {
active = nm_vpn_service_get_active_connections (NM_VPN_SERVICE (data));
for (elt = active; elt; elt = g_slist_next (elt))
list = g_slist_append (list, g_object_ref (NM_VPN_CONNECTION (elt->data)));
list = g_slist_append (list, g_object_ref (G_OBJECT (elt->data)));
}
return list;
}
@ -309,28 +304,130 @@ nm_vpn_manager_get_connection_for_active (NMVPNManager *manager,
const char *active_path)
{
NMVPNManagerPrivate *priv;
GSList *iter;
GHashTableIter iter;
gpointer data;
GSList *active, *elt;
g_return_val_if_fail (NM_IS_VPN_MANAGER (manager), NULL);
priv = NM_VPN_MANAGER_GET_PRIVATE (manager);
for (iter = priv->services; iter; iter = g_slist_next (iter)) {
GSList *active, *elt;
active = nm_vpn_service_get_active_connections (NM_VPN_SERVICE (iter->data));
g_hash_table_iter_init (&iter, priv->services);
while (g_hash_table_iter_next (&iter, NULL, &data)) {
active = nm_vpn_service_get_active_connections (NM_VPN_SERVICE (data));
for (elt = active; elt; elt = g_slist_next (elt)) {
NMVPNConnection *candidate = NM_VPN_CONNECTION (elt->data);
NMVPNConnection *vpn = NM_VPN_CONNECTION (elt->data);
const char *ac_path;
ac_path = nm_vpn_connection_get_active_connection_path (candidate);
ac_path = nm_vpn_connection_get_active_connection_path (vpn);
if (ac_path && !strcmp (ac_path, active_path))
return nm_vpn_connection_get_connection (candidate);
return nm_vpn_connection_get_connection (vpn);
}
}
return NULL;
}
static char *
service_name_from_file (const char *path)
{
GKeyFile *kf = NULL;
char *service_name = NULL;
g_return_val_if_fail (g_path_is_absolute (path), NULL);
if (!g_str_has_suffix (path, ".name"))
return NULL;
kf = g_key_file_new ();
if (g_key_file_load_from_file (kf, path, G_KEY_FILE_NONE, NULL))
service_name = g_key_file_get_string (kf, VPN_CONNECTION_GROUP, "service", NULL);
g_key_file_free (kf);
return service_name;
}
static void
try_add_service (NMVPNManager *self, const char *namefile)
{
NMVPNManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (self);
NMVPNService *service = NULL;
GError *error = NULL;
const char *service_name;
char *tmp;
g_return_if_fail (g_path_is_absolute (namefile));
/* Make sure we don't add dupes */
tmp = service_name_from_file (namefile);
if (tmp)
service = g_hash_table_lookup (priv->services, tmp);
g_free (tmp);
if (service)
return;
/* New service, add it */
service = nm_vpn_service_new (namefile, &error);
if (!service) {
nm_log_warn (LOGD_VPN, "failed to load VPN service file %s: (%d) %s",
error ? error->code : -1,
error && error->message ? error->message : "(unknown)");
g_clear_error (&error);
return;
}
service_name = nm_vpn_service_get_dbus_service (service);
g_hash_table_insert (priv->services, (char *) service_name, service);
nm_log_info (LOGD_VPN, "VPN: loaded %s", service_name, service);
}
static void
vpn_dir_changed (GFileMonitor *monitor,
GFile *file,
GFile *other_file,
GFileMonitorEvent event_type,
gpointer user_data)
{
NMVPNManager *self = NM_VPN_MANAGER (user_data);
NMVPNManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (self);
NMVPNService *service;
char *path;
path = g_file_get_path (file);
if (!g_str_has_suffix (path, ".name")) {
g_free (path);
return;
}
switch (event_type) {
case G_FILE_MONITOR_EVENT_DELETED:
nm_log_dbg (LOGD_VPN, "service file %s deleted", path);
service = get_service_by_namefile (self, path);
if (service) {
const char *service_name = nm_vpn_service_get_dbus_service (service);
/* Stop active VPN connections and destroy the service */
nm_vpn_service_connections_stop (service, TRUE,
NM_VPN_CONNECTION_STATE_REASON_SERVICE_STOPPED);
nm_log_info (LOGD_VPN, "VPN: unloaded %s", service_name, service);
g_hash_table_remove (priv->services, service_name);
}
break;
case G_FILE_MONITOR_EVENT_CREATED:
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
nm_log_dbg (LOGD_VPN, "service file %s created or modified", path);
try_add_service (self, path);
break;
default:
nm_log_dbg (LOGD_VPN, "service file %s change event %d", path, event_type);
break;
}
g_free (path);
}
/******************************************************************************/
NMVPNManager *
nm_vpn_manager_get (void)
{
@ -345,21 +442,61 @@ nm_vpn_manager_get (void)
return singleton;
}
/******************************************************************************/
static void
nm_vpn_manager_init (NMVPNManager *manager)
nm_vpn_manager_init (NMVPNManager *self)
{
NMVPNManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (self);
GFile *file;
GDir *dir;
const char *fn;
char *path;
priv->services = g_hash_table_new_full (g_str_hash, g_str_equal,
NULL, g_object_unref);
/* Watch the VPN directory for changes */
file = g_file_new_for_path (VPN_NAME_FILES_DIR "/");
priv->monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL);
g_object_unref (file);
if (priv->monitor) {
priv->monitor_id = g_signal_connect (priv->monitor, "changed",
G_CALLBACK (vpn_dir_changed), self);
}
/* Load VPN service files */
dir = g_dir_open (VPN_NAME_FILES_DIR, 0, NULL);
if (dir) {
while ((fn = g_dir_read_name (dir))) {
/* only parse filenames that end with .name */
if (g_str_has_suffix (fn, ".name")) {
path = g_build_filename (VPN_NAME_FILES_DIR, fn, NULL);
try_add_service (self, path);
g_free (path);
}
}
g_dir_close (dir);
}
}
static void
finalize (GObject *object)
dispose (GObject *object)
{
NMVPNManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (object);
g_slist_foreach (priv->services, (GFunc) g_object_unref, NULL);
if (!priv->disposed) {
priv->disposed = TRUE;
G_OBJECT_CLASS (nm_vpn_manager_parent_class)->finalize (object);
if (priv->monitor) {
if (priv->monitor_id)
g_signal_handler_disconnect (priv->monitor, priv->monitor_id);
g_file_monitor_cancel (priv->monitor);
g_object_unref (priv->monitor);
}
g_hash_table_destroy (priv->services);
}
G_OBJECT_CLASS (nm_vpn_manager_parent_class)->dispose (object);
}
static void
@ -370,7 +507,7 @@ nm_vpn_manager_class_init (NMVPNManagerClass *manager_class)
g_type_class_add_private (manager_class, sizeof (NMVPNManagerPrivate));
/* virtual methods */
object_class->finalize = finalize;
object_class->dispose = dispose;
/* signals */
signals[CONNECTION_ACTIVATED] =

View file

@ -15,7 +15,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2005 - 2008 Red Hat, Inc.
* Copyright (C) 2005 - 2010 Red Hat, Inc.
* Copyright (C) 2005 - 2008 Novell, Inc.
*/
@ -36,125 +36,94 @@
G_DEFINE_TYPE (NMVPNService, nm_vpn_service, G_TYPE_OBJECT)
typedef struct {
gboolean disposed;
NMDBusManager *dbus_mgr;
char *name;
char *dbus_service;
char *program;
char *namefile;
GPid pid;
GSList *connections;
guint service_start_timeout;
guint service_child_watch;
guint start_timeout;
guint quit_timeout;
guint child_watch;
gulong name_owner_id;
} NMVPNServicePrivate;
#define NM_VPN_SERVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_VPN_SERVICE, NMVPNServicePrivate))
#define VPN_CONNECTION_GROUP "VPN Connection"
static GKeyFile *
find_service_file (const char *name)
NMVPNService *
nm_vpn_service_new (const char *namefile, GError **error)
{
GDir *dir;
const char *fn;
GKeyFile *key_file = NULL;
NMVPNService *self = NULL;
GKeyFile *kf;
char *dbus_service = NULL, *program = NULL, *name = NULL;
dir = g_dir_open (VPN_NAME_FILES_DIR, 0, NULL);
if (!dir)
g_return_val_if_fail (namefile != NULL, NULL);
g_return_val_if_fail (g_path_is_absolute (namefile), NULL);
kf = g_key_file_new ();
if (!g_key_file_load_from_file (kf, namefile, G_KEY_FILE_NONE, error)) {
g_key_file_free (kf);
return NULL;
while ((fn = g_dir_read_name (dir))) {
char *path;
gboolean found = FALSE;
/* only parse filenames that end with .name */
if (!g_str_has_suffix (fn, ".name"))
continue;
key_file = g_key_file_new ();
path = g_build_filename (VPN_NAME_FILES_DIR, fn, NULL);
if (g_key_file_load_from_file (key_file, path, G_KEY_FILE_NONE, NULL)) {
gchar *val;
val = g_key_file_get_string (key_file, VPN_CONNECTION_GROUP, "service", NULL);
if (val) {
if (!strcmp (val, name))
found = TRUE;
g_free (val);
}
}
g_free (path);
if (found)
break;
g_key_file_free (key_file);
key_file = NULL;
}
g_dir_close (dir);
return key_file;
}
NMVPNService *
nm_vpn_service_new (const char *name)
{
GKeyFile *key_file;
NMVPNService *service = NULL;
NMVPNServicePrivate *priv;
char *dbus_service = NULL;
char *program = NULL;
gboolean success = FALSE;
g_return_val_if_fail (name != NULL, NULL);
key_file = find_service_file (name);
if (!key_file)
return NULL;
dbus_service = g_key_file_get_string (key_file, VPN_CONNECTION_GROUP, "service", NULL);
if (!dbus_service)
dbus_service = g_key_file_get_string (kf, VPN_CONNECTION_GROUP, "service", NULL);
if (!dbus_service) {
g_set_error (error, 0, 0, "VPN service file %s had no 'service' key", namefile);
goto out;
}
program = g_key_file_get_string (key_file, VPN_CONNECTION_GROUP, "program", NULL);
if (!program)
program = g_key_file_get_string (kf, VPN_CONNECTION_GROUP, "program", NULL);
if (!program) {
g_set_error (error, 0, 0, "VPN service file %s had no 'program' key", namefile);
goto out;
}
service = (NMVPNService *) g_object_new (NM_TYPE_VPN_SERVICE, NULL);
if (!service)
name = g_key_file_get_string (kf, VPN_CONNECTION_GROUP, "name", NULL);
if (!name) {
g_set_error (error, 0, 0, "VPN service file %s had no 'name' key", namefile);
goto out;
}
priv = NM_VPN_SERVICE_GET_PRIVATE (service);
self = (NMVPNService *) g_object_new (NM_TYPE_VPN_SERVICE, NULL);
if (!self) {
g_set_error (error, 0, 0, "out of memory creating VPN service object");
goto out;
}
priv->name = g_strdup (name);
priv->dbus_service = dbus_service;
priv->program = program;
success = TRUE;
NM_VPN_SERVICE_GET_PRIVATE (self)->name = g_strdup (name);
NM_VPN_SERVICE_GET_PRIVATE (self)->dbus_service = g_strdup (dbus_service);
NM_VPN_SERVICE_GET_PRIVATE (self)->program = g_strdup (program);
NM_VPN_SERVICE_GET_PRIVATE (self)->namefile = g_strdup (namefile);
out:
g_key_file_free (key_file);
if (!success) {
g_free (dbus_service);
g_free (program);
}
return service;
g_key_file_free (kf);
g_free (dbus_service);
g_free (program);
g_free (name);
return self;
}
const char *
nm_vpn_service_get_name (NMVPNService *service)
nm_vpn_service_get_dbus_service (NMVPNService *service)
{
g_return_val_if_fail (NM_IS_VPN_SERVICE (service), NULL);
return NM_VPN_SERVICE_GET_PRIVATE (service)->name;
return NM_VPN_SERVICE_GET_PRIVATE (service)->dbus_service;
}
static void
const char *
nm_vpn_service_get_name_file (NMVPNService *service)
{
g_return_val_if_fail (NM_IS_VPN_SERVICE (service), NULL);
return NM_VPN_SERVICE_GET_PRIVATE (service)->namefile;
}
void
nm_vpn_service_connections_stop (NMVPNService *service,
gboolean fail,
NMVPNConnectionStateReason reason)
@ -175,6 +144,17 @@ nm_vpn_service_connections_stop (NMVPNService *service,
g_slist_free (copy);
}
static void
clear_quit_timeout (NMVPNService *self)
{
NMVPNServicePrivate *priv = NM_VPN_SERVICE_GET_PRIVATE (self);
if (priv->quit_timeout) {
g_source_remove (priv->quit_timeout);
priv->quit_timeout = 0;
}
}
/*
* nm_vpn_service_child_setup
*
@ -200,21 +180,22 @@ vpn_service_watch_cb (GPid pid, gint status, gpointer user_data)
if (err != 0) {
nm_log_warn (LOGD_VPN, "VPN service '%s' exited with error: %d",
nm_vpn_service_get_name (service), WSTOPSIG (status));
priv->name, WSTOPSIG (status));
}
} else if (WIFSTOPPED (status)) {
nm_log_warn (LOGD_VPN, "VPN service '%s' stopped unexpectedly with signal %d",
nm_vpn_service_get_name (service), WSTOPSIG (status));
priv->name, WSTOPSIG (status));
} else if (WIFSIGNALED (status)) {
nm_log_warn (LOGD_VPN, "VPN service '%s' died with signal %d",
nm_vpn_service_get_name (service), WTERMSIG (status));
priv->name, WTERMSIG (status));
} else {
nm_log_warn (LOGD_VPN, "VPN service '%s' died from an unknown cause",
nm_vpn_service_get_name (service));
priv->name);
}
priv->pid = 0;
priv->service_child_watch = 0;
priv->child_watch = 0;
clear_quit_timeout (service);
nm_vpn_service_connections_stop (service, TRUE, NM_VPN_CONNECTION_STATE_REASON_SERVICE_STOPPED);
}
@ -222,14 +203,12 @@ vpn_service_watch_cb (GPid pid, gint status, gpointer user_data)
static gboolean
nm_vpn_service_timeout (gpointer data)
{
NMVPNService *service = NM_VPN_SERVICE (data);
nm_log_warn (LOGD_VPN, "VPN service '%s' did not start in time, cancelling connections",
nm_vpn_service_get_name (service));
NM_VPN_SERVICE_GET_PRIVATE (service)->service_start_timeout = 0;
nm_vpn_service_connections_stop (service, TRUE, NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_TIMEOUT);
NMVPNService *self = NM_VPN_SERVICE (data);
NMVPNServicePrivate *priv = NM_VPN_SERVICE_GET_PRIVATE (self);
nm_log_warn (LOGD_VPN, "VPN service '%s' start timed out", priv->name);
priv->start_timeout = 0;
nm_vpn_service_connections_stop (self, TRUE, NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_TIMEOUT);
return FALSE;
}
@ -253,13 +232,15 @@ nm_vpn_service_daemon_exec (NMVPNService *service, GError **error)
&spawn_error);
if (success) {
nm_log_info (LOGD_VPN, "VPN service '%s' started (%s), PID %d",
nm_vpn_service_get_name (service), priv->dbus_service, priv->pid);
priv->name, priv->dbus_service, priv->pid);
priv->service_child_watch = g_child_watch_add (priv->pid, vpn_service_watch_cb, service);
priv->service_start_timeout = g_timeout_add_seconds (5, nm_vpn_service_timeout, service);
priv->child_watch = g_child_watch_add (priv->pid, vpn_service_watch_cb, service);
priv->start_timeout = g_timeout_add_seconds (5, nm_vpn_service_timeout, service);
} else {
nm_log_warn (LOGD_VPN, "VPN service '%s': could not launch the VPN service. error: (%d) %s.",
nm_vpn_service_get_name (service), spawn_error->code, spawn_error->message);
priv->name,
spawn_error ? spawn_error->code : -1,
spawn_error && spawn_error->message ? spawn_error->message : "(unknown)");
g_set_error (error,
NM_VPN_MANAGER_ERROR, NM_VPN_MANAGER_ERROR_SERVICE_START_FAILED,
@ -274,9 +255,40 @@ nm_vpn_service_daemon_exec (NMVPNService *service, GError **error)
}
static gboolean
destroy_service (gpointer data)
ensure_killed (gpointer data)
{
g_object_unref (data);
int pid = GPOINTER_TO_INT (data);
if (kill (pid, 0) == 0)
kill (pid, SIGKILL);
/* ensure the child is reaped */
nm_log_dbg (LOGD_VPN, "waiting for VPN service pid %d to exit", pid);
waitpid (pid, NULL, 0);
nm_log_dbg (LOGD_VPN, "VPN service pid %d cleaned up", pid);
return FALSE;
}
static gboolean
service_quit (gpointer user_data)
{
NMVPNServicePrivate *priv = NM_VPN_SERVICE_GET_PRIVATE (user_data);
if (priv->pid) {
if (kill (priv->pid, SIGTERM) == 0)
g_timeout_add_seconds (2, ensure_killed, GINT_TO_POINTER (priv->pid));
else {
kill (priv->pid, SIGKILL);
/* ensure the child is reaped */
nm_log_dbg (LOGD_VPN, "waiting for VPN service pid %d to exit", priv->pid);
waitpid (priv->pid, NULL, 0);
nm_log_dbg (LOGD_VPN, "VPN service pid %d cleaned up", priv->pid);
}
priv->pid = 0;
}
priv->quit_timeout = 0;
return FALSE;
}
@ -297,8 +309,9 @@ connection_vpn_state_changed (NMVPNConnection *connection,
g_object_unref (connection);
if (priv->connections == NULL) {
/* schedule a timeout (10 seconds) to destroy the service */
g_timeout_add_seconds (10, destroy_service, user_data);
/* Tell the service to quit in a few seconds */
if (!priv->quit_timeout)
priv->quit_timeout = g_timeout_add_seconds (5, service_quit, user_data);
}
break;
default:
@ -325,6 +338,8 @@ nm_vpn_service_activate (NMVPNService *service,
priv = NM_VPN_SERVICE_GET_PRIVATE (service);
clear_quit_timeout (service);
vpn = nm_vpn_connection_new (connection, act_request, device);
g_signal_connect (vpn, "vpn-state-changed",
G_CALLBACK (connection_vpn_state_changed),
@ -335,9 +350,8 @@ nm_vpn_service_activate (NMVPNService *service,
if (nm_dbus_manager_name_has_owner (priv->dbus_mgr, priv->dbus_service)) {
// FIXME: fill in error when errors happen
nm_vpn_connection_activate (vpn);
} else if (priv->service_start_timeout == 0) {
nm_log_info (LOGD_VPN, "Starting VPN service '%s'...",
nm_vpn_service_get_name (service));
} else if (priv->start_timeout == 0) {
nm_log_info (LOGD_VPN, "Starting VPN service '%s'...", priv->name);
if (!nm_vpn_service_daemon_exec (service, error))
vpn = NULL;
}
@ -364,14 +378,15 @@ nm_vpn_service_name_owner_changed (NMDBusManager *mgr,
NMVPNServicePrivate *priv = NM_VPN_SERVICE_GET_PRIVATE (service);
gboolean old_owner_good;
gboolean new_owner_good;
GSList *iter;
if (strcmp (name, priv->dbus_service))
return;
/* Service changed, no need to wait for the timeout any longer */
if (priv->service_start_timeout) {
g_source_remove (priv->service_start_timeout);
priv->service_start_timeout = 0;
if (priv->start_timeout) {
g_source_remove (priv->start_timeout);
priv->start_timeout = 0;
}
old_owner_good = (old && (strlen (old) > 0));
@ -379,18 +394,14 @@ nm_vpn_service_name_owner_changed (NMDBusManager *mgr,
if (!old_owner_good && new_owner_good) {
/* service just appeared */
GSList *iter;
nm_log_info (LOGD_VPN, "VPN service '%s' appeared, activating connections",
nm_vpn_service_get_name (service));
nm_log_info (LOGD_VPN, "VPN service '%s' appeared; activating connections", priv->name);
clear_quit_timeout (service);
for (iter = priv->connections; iter; iter = iter->next)
nm_vpn_connection_activate (NM_VPN_CONNECTION (iter->data));
} else if (old_owner_good && !new_owner_good) {
/* service went away */
nm_log_info (LOGD_VPN, "VPN service '%s' disappeared, cancelling connections",
nm_vpn_service_get_name (service));
nm_log_info (LOGD_VPN, "VPN service '%s' disappeared", priv->name);
nm_vpn_service_connections_stop (service, TRUE, NM_VPN_CONNECTION_STATE_REASON_SERVICE_STOPPED);
}
}
@ -398,40 +409,28 @@ nm_vpn_service_name_owner_changed (NMDBusManager *mgr,
/******************************************************************************/
static void
nm_vpn_service_init (NMVPNService *service)
nm_vpn_service_init (NMVPNService *self)
{
NMVPNServicePrivate *priv = NM_VPN_SERVICE_GET_PRIVATE (service);
NMVPNServicePrivate *priv = NM_VPN_SERVICE_GET_PRIVATE (self);
priv->dbus_mgr = nm_dbus_manager_get ();
priv->name_owner_id = g_signal_connect (priv->dbus_mgr, "name-owner-changed",
G_CALLBACK (nm_vpn_service_name_owner_changed),
service);
}
static gboolean
ensure_killed (gpointer data)
{
int pid = GPOINTER_TO_INT (data);
if (kill (pid, 0) == 0)
kill (pid, SIGKILL);
/* ensure the child is reaped */
nm_log_dbg (LOGD_VPN, "waiting for VPN service pid %d to exit", pid);
waitpid (pid, NULL, 0);
nm_log_dbg (LOGD_VPN, "VPN service pid %d cleaned up", pid);
return FALSE;
G_CALLBACK (nm_vpn_service_name_owner_changed),
self);
}
static void
finalize (GObject *object)
dispose (GObject *object)
{
NMVPNServicePrivate *priv = NM_VPN_SERVICE_GET_PRIVATE (object);
NMVPNService *self = NM_VPN_SERVICE (object);
NMVPNServicePrivate *priv = NM_VPN_SERVICE_GET_PRIVATE (self);
if (priv->service_start_timeout)
g_source_remove (priv->service_start_timeout);
if (priv->disposed)
goto out;
priv->disposed = TRUE;
if (priv->start_timeout)
g_source_remove (priv->start_timeout);
nm_vpn_service_connections_stop (NM_VPN_SERVICE (object),
FALSE,
@ -439,31 +438,21 @@ finalize (GObject *object)
g_signal_handler_disconnect (priv->dbus_mgr, priv->name_owner_id);
if (priv->service_child_watch)
g_source_remove (priv->service_child_watch);
if (priv->child_watch)
g_source_remove (priv->child_watch);
if (priv->pid) {
if (kill (priv->pid, SIGTERM) == 0)
g_timeout_add_seconds (2, ensure_killed, GINT_TO_POINTER (priv->pid));
else {
kill (priv->pid, SIGKILL);
/* ensure the child is reaped */
nm_log_dbg (LOGD_VPN, "waiting for VPN service pid %d to exit", priv->pid);
waitpid (priv->pid, NULL, 0);
nm_log_dbg (LOGD_VPN, "VPN service pid %d cleaned up", priv->pid);
}
priv->pid = 0;
}
clear_quit_timeout (self);
service_quit (self);
g_object_unref (priv->dbus_mgr);
g_free (priv->name);
g_free (priv->dbus_service);
g_free (priv->program);
g_free (priv->namefile);
G_OBJECT_CLASS (nm_vpn_service_parent_class)->finalize (object);
out:
G_OBJECT_CLASS (nm_vpn_service_parent_class)->dispose (object);
}
static void
@ -474,5 +463,5 @@ nm_vpn_service_class_init (NMVPNServiceClass *service_class)
g_type_class_add_private (service_class, sizeof (NMVPNServicePrivate));
/* virtual methods */
object_class->finalize = finalize;
object_class->dispose = dispose;
}

View file

@ -35,6 +35,8 @@
#define NM_IS_VPN_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_VPN_SERVICE))
#define NM_VPN_SERVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_VPN_SERVICE, NMVPNServiceClass))
#define VPN_CONNECTION_GROUP "VPN Connection"
typedef struct {
GObject parent;
} NMVPNService;
@ -45,9 +47,13 @@ typedef struct {
GType nm_vpn_service_get_type (void);
NMVPNService * nm_vpn_service_new (const char *service_name);
NMVPNService * nm_vpn_service_new (const char *namefile, GError **error);
const char * nm_vpn_service_get_name (NMVPNService *service);
/* Returns the VPN service's D-Bus service name */
const char *nm_vpn_service_get_dbus_service (NMVPNService *service);
/* Returns the path of the VPN service's .name file */
const char *nm_vpn_service_get_name_file (NMVPNService *service);
NMVPNConnection * nm_vpn_service_activate (NMVPNService *service,
NMConnection *connection,
@ -57,4 +63,8 @@ NMVPNConnection * nm_vpn_service_activate (NMVPNService *service,
GSList * nm_vpn_service_get_active_connections (NMVPNService *service);
void nm_vpn_service_connections_stop (NMVPNService *service,
gboolean fail,
NMVPNConnectionStateReason reason);
#endif /* NM_VPN_VPN_SERVICE_H */

View file

@ -15,3 +15,7 @@ endif
if TARGET_DEBIAN
SUBDIRS+=ifupdown
endif
if TARGET_GENTOO
SUBDIRS+=ifnet
endif

View file

@ -33,6 +33,8 @@
#define ORIG_TAG ".orig"
#define REJ_TAG ".rej"
#define RPMNEW_TAG ".rpmnew"
#define AUGNEW_TAG ".augnew"
#define AUGTMP_TAG ".augtmp"
#define IFCFG_DIR SYSCONFDIR"/sysconfig/network-scripts"

View file

@ -165,7 +165,7 @@ read_one_connection (SCPluginIfcfg *plugin, const char *filename)
PLUGIN_PRINT (IFCFG_PLUGIN_NAME, " error: %s",
(error && error->message) ? error->message : "(unknown)");
}
g_error_free (error);
g_clear_error (&error);
}
return connection;
@ -341,25 +341,25 @@ dir_changed (GFileMonitor *monitor,
g_free (path);
connection = g_hash_table_lookup (priv->connections, name);
if (!connection) {
do_new = TRUE;
} else {
switch (event_type) {
case G_FILE_MONITOR_EVENT_DELETED:
PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "removed %s.", name);
do_remove = TRUE;
break;
case G_FILE_MONITOR_EVENT_CREATED:
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
/* Update */
switch (event_type) {
case G_FILE_MONITOR_EVENT_DELETED:
PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "removed %s.", name);
if (connection)
handle_connection_remove_or_new (plugin, name, connection, TRUE, FALSE);
break;
case G_FILE_MONITOR_EVENT_CREATED:
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
/* Update */
if (!connection)
do_new = TRUE;
else
connection_changed_handler (plugin, name, connection, &do_remove, &do_new);
break;
default:
break;
}
}
handle_connection_remove_or_new (plugin, name, connection, do_remove, do_new);
handle_connection_remove_or_new (plugin, name, connection, do_remove, do_new);
break;
default:
break;
}
g_free (name);
}
@ -551,7 +551,7 @@ impl_ifcfgrh_get_ifcfg_details (SCPluginIfcfg *plugin,
}
connection = g_hash_table_lookup (priv->connections, in_ifcfg);
if (!connection) {
if (!connection || nm_ifcfg_connection_get_unmanaged_spec (connection)) {
g_set_error (error,
NM_SYSCONFIG_SETTINGS_ERROR,
NM_SYSCONFIG_SETTINGS_ERROR_INVALID_CONNECTION,

View file

@ -3183,6 +3183,12 @@ is_wireless_device (const char *iface)
return is_wireless;
}
enum {
IGNORE_REASON_NONE = 0x00,
IGNORE_REASON_BRIDGE = 0x01,
IGNORE_REASON_VLAN = 0x02,
};
NMConnection *
connection_from_file (const char *filename,
const char *network_file, /* for unit tests only */
@ -3203,7 +3209,7 @@ connection_from_file (const char *filename,
gboolean nm_controlled = TRUE;
gboolean ip6_used = FALSE;
GError *error = NULL;
gboolean ignore_connection = FALSE;
guint32 ignore_reason = IGNORE_REASON_NONE;
g_return_val_if_fail (filename != NULL, NULL);
g_return_val_if_fail (unmanaged != NULL, NULL);
@ -3293,7 +3299,7 @@ connection_from_file (const char *filename,
if (tmp) {
g_free (tmp);
nm_controlled = FALSE;
ignore_connection = TRUE;
ignore_reason = IGNORE_REASON_BRIDGE;
}
if (nm_controlled) {
@ -3301,7 +3307,7 @@ connection_from_file (const char *filename,
if (tmp) {
g_free (tmp);
nm_controlled = FALSE;
ignore_connection = TRUE;
ignore_reason = IGNORE_REASON_VLAN;
}
}
@ -3325,14 +3331,22 @@ connection_from_file (const char *filename,
g_free (type);
/* Don't bother reading the connection fully if it's unmanaged. As a
* special-case, BRIDGE= and VLAN= connections are completely ignored so
* that ifup gets an error when it tries to ask NM about them.
*/
if (!connection || *unmanaged || ignore_connection) {
if (connection && ignore_connection) {
g_object_unref (connection);
connection = NULL;
/* Don't bother reading the connection fully if it's unmanaged or ignored */
if (!connection || *unmanaged || ignore_reason) {
if (connection && !*unmanaged) {
/* However,BRIDGE and VLAN connections that don't have HWADDR won't
* be unmanaged because the unmanaged state is keyed off HWADDR.
* They willl still be tagged 'ignore' from code that checks BRIDGE
* and VLAN above. Since they aren't marked unmanaged, kill them
* completely.
*/
if (ignore_reason) {
g_object_unref (connection);
connection = NULL;
g_set_error (&error, IFCFG_PLUGIN_ERROR, 0,
"%s connections are not yet supported",
ignore_reason == IGNORE_REASON_BRIDGE ? "Bridge" : "VLAN");
}
}
goto done;
}

View file

@ -4,6 +4,7 @@ EXTRA_DIST = \
ifcfg-test-wired-static \
ifcfg-test-wired-static-bootproto \
ifcfg-test-wired-dhcp \
ifcfg-test-wired-dhcp6-only \
ifcfg-test-wired-global-gateway \
network-test-wired-global-gateway \
ifcfg-test-wired-never-default \

View file

@ -1,5 +1,4 @@
DEVICE=eth1.43
HWADDR=00:22:15:59:62:97
VLAN=yes
ONBOOT=yes
BOOTPROTO=none

View file

@ -0,0 +1,11 @@
DEVICE="eth0"
ONBOOT=no
TYPE=Ethernet
DEFROUTE=yes
PEERDNS=yes
PEERROUTES=yes
IPV6INIT=yes
IPV6_AUTOCONF=no
DHCPV6C=yes
HWADDR=00:13:20:F5:F5:E4

View file

@ -153,6 +153,8 @@ int main (int argc, char **argv)
test_ignored ("ignored-orig", "ifcfg-FooBar" ORIG_TAG, TRUE);
test_ignored ("ignored-rej", "ifcfg-FooBar" REJ_TAG, TRUE);
test_ignored ("ignored-rpmnew", "ifcfg-FooBar" RPMNEW_TAG, TRUE);
test_ignored ("ignored-augnew", "ifcfg-FooBar" AUGNEW_TAG, TRUE);
test_ignored ("ignored-augtmp", "ifcfg-FooBar" AUGTMP_TAG, TRUE);
base = g_path_get_basename (argv[0]);
fprintf (stdout, "%s: SUCCESS\n", base);

View file

@ -2319,6 +2319,111 @@ test_read_wired_ipv6_only (void)
g_object_unref (connection);
}
#define TEST_IFCFG_WIRED_DHCP6_ONLY TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-dhcp6-only"
static void
test_read_wired_dhcp6_only (void)
{
NMConnection *connection;
NMSettingConnection *s_con;
NMSettingWired *s_wired;
NMSettingIP4Config *s_ip4;
NMSettingIP6Config *s_ip6;
char *unmanaged = NULL;
char *keyfile = NULL;
char *routefile = NULL;
char *route6file = NULL;
gboolean ignore_error = FALSE;
GError *error = NULL;
const char *tmp;
const char *expected_id = "System test-wired-dhcp6-only";
const char *method;
connection = connection_from_file (TEST_IFCFG_WIRED_DHCP6_ONLY,
NULL,
TYPE_ETHERNET,
NULL,
&unmanaged,
&keyfile,
&routefile,
&route6file,
&error,
&ignore_error);
ASSERT (connection != NULL,
"wired-dhcp6-only-read", "failed to read %s: %s", TEST_IFCFG_WIRED_DHCP6_ONLY, error->message);
ASSERT (nm_connection_verify (connection, &error),
"wired-dhcp6-only-verify", "failed to verify %s: %s", TEST_IFCFG_WIRED_DHCP6_ONLY, error->message);
ASSERT (unmanaged == FALSE,
"wired-dhcp6-only-verify", "failed to verify %s: unexpected unmanaged value", TEST_IFCFG_WIRED_DHCP6_ONLY);
/* ===== CONNECTION SETTING ===== */
s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
ASSERT (s_con != NULL,
"wired-dhcp6-only-verify-connection", "failed to verify %s: missing %s setting",
TEST_IFCFG_WIRED_DHCP6_ONLY,
NM_SETTING_CONNECTION_SETTING_NAME);
/* ID */
tmp = nm_setting_connection_get_id (s_con);
ASSERT (tmp != NULL,
"wired-dhcp6-only-verify-connection", "failed to verify %s: missing %s / %s key",
TEST_IFCFG_WIRED_DHCP6_ONLY,
NM_SETTING_CONNECTION_SETTING_NAME,
NM_SETTING_CONNECTION_ID);
ASSERT (strcmp (tmp, expected_id) == 0,
"wired-dhcp6-only-verify-connection", "failed to verify %s: unexpected %s / %s key value",
TEST_IFCFG_WIRED_DHCP6_ONLY,
NM_SETTING_CONNECTION_SETTING_NAME,
NM_SETTING_CONNECTION_ID);
/* ===== WIRED SETTING ===== */
s_wired = NM_SETTING_WIRED (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED));
ASSERT (s_wired != NULL,
"wired-dhcp6-only-verify-wired", "failed to verify %s: missing %s setting",
TEST_IFCFG_WIRED_DHCP6_ONLY,
NM_SETTING_WIRED_SETTING_NAME);
/* ===== IPv4 SETTING ===== */
s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
ASSERT (s_ip4 != NULL,
"wired-dhcp6-only-verify-ip4", "failed to verify %s: missing %s setting",
TEST_IFCFG_WIRED_DHCP6_ONLY,
NM_SETTING_IP4_CONFIG_SETTING_NAME);
method = nm_setting_ip4_config_get_method (s_ip4);
ASSERT (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0,
"wired-dhcp6-only-verify-ip4", "failed to verify %s: unexpected %s / %s key value",
TEST_IFCFG_WIRED_DHCP6_ONLY,
NM_SETTING_IP4_CONFIG_SETTING_NAME,
NM_SETTING_IP4_CONFIG_METHOD);
/* ===== IPv6 SETTING ===== */
s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG));
ASSERT (s_ip6 != NULL,
"wired-dhcp6-only-verify-ip6", "failed to verify %s: missing %s setting",
TEST_IFCFG_WIRED_DHCP6_ONLY,
NM_SETTING_IP6_CONFIG_SETTING_NAME);
/* Method */
tmp = nm_setting_ip6_config_get_method (s_ip6);
ASSERT (strcmp (tmp, NM_SETTING_IP6_CONFIG_METHOD_DHCP) == 0,
"wired-dhcp6-only-verify-ip6", "failed to verify %s: unexpected %s / %s key value",
TEST_IFCFG_WIRED_DHCP6_ONLY,
NM_SETTING_IP6_CONFIG_SETTING_NAME,
NM_SETTING_IP6_CONFIG_METHOD);
g_free (keyfile);
g_free (routefile);
g_free (route6file);
g_object_unref (connection);
}
#define TEST_IFCFG_ONBOOT_NO TEST_IFCFG_DIR"/network-scripts/ifcfg-test-onboot-no"
static void
@ -9334,10 +9439,15 @@ test_read_bridge_component (void)
&ignore_error);
ASSERT (connection != NULL,
"bridge-component-read", "unexpected failure reading %s", TEST_IFCFG_BRIDGE_COMPONENT);
ASSERT (unmanaged != NULL,
"bridge-component-read", "unexpected managed device reading %s", TEST_IFCFG_BRIDGE_COMPONENT);
ASSERT (strcmp (unmanaged, "mac:00:22:15:59:62:97") == 0,
"bridge-component-read", "expected unmanaged device reading %s", TEST_IFCFG_BRIDGE_COMPONENT);
"bridge-component-read", "missing unmanaged spec from %s", TEST_IFCFG_BRIDGE_COMPONENT);
ASSERT (g_strcmp0 (unmanaged, "mac:00:22:15:59:62:97") == 0,
"bridge-component-read", "unexpected unmanaged spec from %s", TEST_IFCFG_BRIDGE_COMPONENT);
g_object_unref (connection);
g_free (unmanaged);
}
#define TEST_IFCFG_VLAN_INTERFACE TEST_IFCFG_DIR"/network-scripts/ifcfg-test-vlan-interface"
@ -9363,14 +9473,8 @@ test_read_vlan_interface (void)
&route6file,
&error,
&ignore_error);
ASSERT (connection != NULL,
"vlan-interface-read", "unexpected failure reading %s", TEST_IFCFG_VLAN_INTERFACE);
ASSERT (unmanaged != NULL,
"vlan-interface-read", "unexpected managed device reading %s", TEST_IFCFG_VLAN_INTERFACE);
ASSERT (strcmp (unmanaged, "mac:00:22:15:59:62:97") == 0,
"vlan-interface-read", "expected unmanaged device reading %s", TEST_IFCFG_VLAN_INTERFACE);
g_object_unref (connection);
ASSERT (connection == NULL,
"vlan-interface-read", "unexpected success reading %s", TEST_IFCFG_VLAN_INTERFACE);
}
#define TEST_IFCFG_WIFI_OPEN_SSID_BAD_HEX TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wifi-open-ssid-bad-hex"
@ -9412,6 +9516,7 @@ int main (int argc, char **argv)
test_read_wired_static_routes_legacy ();
test_read_wired_ipv6_manual ();
test_read_wired_ipv6_only ();
test_read_wired_dhcp6_only ();
test_read_onboot_no ();
test_read_wired_8021x_peap_mschapv2 ();
test_read_wifi_open ();

View file

@ -160,7 +160,9 @@ utils_should_ignore_file (const char *filename, gboolean only_ifcfg)
&& !check_suffix (base, TILDE_TAG)
&& !check_suffix (base, ORIG_TAG)
&& !check_suffix (base, REJ_TAG)
&& !check_suffix (base, RPMNEW_TAG))
&& !check_suffix (base, RPMNEW_TAG)
&& !check_suffix (base, AUGNEW_TAG)
&& !check_suffix (base, AUGTMP_TAG))
ignore = FALSE;
g_free (base);

View file

@ -0,0 +1,61 @@
SUBDIRS = . tests
INCLUDES = \
-I$(top_srcdir)/src/system-settings \
-I$(top_srcdir)/include \
-I$(top_srcdir)/libnm-glib \
-I$(top_srcdir)/libnm-util
pkglib_LTLIBRARIES = libnm-settings-plugin-ifnet.la
noinst_LTLIBRARIES = lib-ifnet-io.la
libnm_settings_plugin_ifnet_la_SOURCES = \
nm-ifnet-connection.c \
nm-ifnet-connection.h \
plugin.c \
plugin.h
libnm_settings_plugin_ifnet_la_CPPFLAGS = \
$(GLIB_CFLAGS) \
$(GMODULE_CFLAGS) \
$(DBUS_CFLAGS) \
$(GUDEV_CFLAGS) \
-DG_DISABLE_DEPRECATED \
-DSYSCONFDIR=\"$(sysconfdir)\"\
-g
libnm_settings_plugin_ifnet_la_LDFLAGS = -module -avoid-version
libnm_settings_plugin_ifnet_la_LIBADD = \
$(top_builddir)/libnm-util/libnm-util.la \
$(top_builddir)/libnm-glib/libnm-glib.la \
lib-ifnet-io.la\
$(GLIB_LIBS) \
$(GMODULE_LIBS) \
$(GUDEV_LIBS) \
$(GIO_LIBS)
lib_ifnet_io_la_SOURCES = \
net_parser.c\
net_parser.h\
connection_parser.c \
connection_parser.h \
net_utils.h\
net_utils.c\
wpa_parser.h\
wpa_parser.c
lib_ifnet_io_la_CPPFLAGS = \
$(GLIB_CFLAGS) \
$(DBUS_CFLAGS) \
-DG_DISABLE_DEPRECATED \
-DSYSCONFDIR=\"$(sysconfdir)\" \
-DSBINDIR=\"$(sbindir)\"\
-g
lib_ifnet_io_la_LIBADD = \
$(top_builddir)/libnm-util/libnm-util.la \
$(GLIB_LIBS)\
$(GIO_LIBS)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,43 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
* Mu Qiao <qiaomuf@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 1999-2010 Gentoo Foundation, Inc.
*/
#ifndef _CONNECTION_PARSER_H
#define _CONNECTION_PARSER_H
#include <nm-connection.h>
#include "net_parser.h"
NMConnection *ifnet_update_connection_from_config_block (gchar * conn_name,
GError ** error);
/* nm_conn_name is used to update nm_ifnet_connection's priv data */
gboolean ifnet_update_parsers_by_connection (NMConnection * connection,
gchar * conn_name,
gchar ** nm_conn_name,
gchar * config_file,
gchar * wpa_file, GError ** error);
gboolean ifnet_delete_connection_in_parsers (gchar * conn_name,
gchar * config_file,
gchar * wpa_file);
gboolean ifnet_add_new_connection (NMConnection * connection,
gchar * config_file, gchar * wpa_file,
GError ** error);
#endif

View file

@ -0,0 +1,635 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
* Mu Qiao <qiaomuf@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 1999-2010 Gentoo Foundation, Inc.
*/
#include <string.h>
#include <nm-system-config-interface.h>
#include <stdio.h>
#include "net_parser.h"
#include "net_utils.h"
/* Save all the connection information */
static GHashTable *conn_table;
/* Save global settings which are used for writing*/
static GHashTable *global_settings_table;
/* Save functions */
static GList *functions_list;
/* Used to decide whether to write changes to file*/
static gboolean net_parser_data_changed = FALSE;
static GHashTable *
add_new_connection_config (const gchar * type, const gchar * name)
{
GHashTable *new_conn;
gchar *new_name;
if (!name)
return NULL;
/* Return existing connection */
if ((new_conn = g_hash_table_lookup (conn_table, name)) != NULL)
return new_conn;
new_conn = g_hash_table_new (g_str_hash, g_str_equal);
new_name = g_strdup (name);
g_hash_table_insert (new_conn, g_strdup ("name"), new_name);
g_hash_table_insert (new_conn, g_strdup ("type"), g_strdup (type));
g_hash_table_insert (conn_table, new_name, new_conn);
return new_conn;
}
gboolean
ifnet_add_connection (gchar * name, gchar * type)
{
if (add_new_connection_config (type, name)) {
PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Adding network for %s", name);
net_parser_data_changed = TRUE;
return TRUE;
} else
return FALSE;
}
gboolean
ifnet_has_connection (gchar * conn_name)
{
return g_hash_table_lookup (conn_table, conn_name) != NULL;
}
static GHashTable *
get_connection_config (gchar * name)
{
return g_hash_table_lookup (conn_table, name);
}
/* Ignored name won't be treated as wireless ssid */
static gchar *ignore_name[] = {
"vlan", "bond", "atm", "ath", "ippp", "vpn", "tap", "tun", "1",
"br", "nas", "6to4", "timeout", "kvm", "force", NULL
};
static gboolean
ignore_connection_name (gchar * name)
{
gboolean result = FALSE;
guint i = 0;
/* check ignore_name list */
while (ignore_name[i] != NULL) {
if (g_ascii_strncasecmp
(name, ignore_name[i], strlen (ignore_name[i])) == 0) {
return TRUE;
}
i++;
}
/* Ignore mac address based configuration */
if (strlen (name) == 12 && is_hex (name))
result = TRUE;
return result;
}
static gboolean
is_global_setting (char *key)
{
static gchar *global_settings[] = { "wpa_supplicant_", NULL };
int i;
for (i = 0; global_settings[i] != NULL; i++) {
if (strstr (key, global_settings[i]))
return 1;
}
return 0;
}
/* Parse a complete line */
/* Connection type is determined here */
static void
init_block_by_line (gchar * buf)
{
gchar **key_value;
gchar *pos;
gchar *data;
gchar *tmp;
GHashTable *conn;
key_value = g_strsplit (buf, "=", 2);
if (g_strv_length (key_value) != 2) {
PLUGIN_WARN (IFNET_PLUGIN_NAME, "Can't handle this line: %s\n",
buf);
g_strfreev (key_value);
return;
}
pos = g_strrstr (key_value[0], "_");
if (pos == NULL || is_global_setting (key_value[0])) {
/* global data */
PLUGIN_PRINT (IFNET_PLUGIN_NAME, "global:%s-%s\n", key_value[0],
key_value[1]);
g_hash_table_insert (global_settings_table,
g_strdup (key_value[0]),
g_strdup (key_value[1]));
g_strfreev (key_value);
return;
}
*pos++ = '\0';
if ((conn = get_connection_config (pos)) == NULL) {
if (g_ascii_strncasecmp (pos, "eth", 3) == 0
&& strlen (pos) == 4)
/* wired connection */
conn = add_new_connection_config ("wired", pos);
else if (g_ascii_strncasecmp (pos, "ppp", 3) == 0
&& strlen (pos) == 4)
/* pppoe connection */
conn = add_new_connection_config ("ppp", pos);
else if (ignore_connection_name (pos)) {
/* ignored connection */
conn = add_new_connection_config ("ignore", pos);
} else
/* wireless connection */
conn = add_new_connection_config ("wireless", pos);
}
data = g_strdup (key_value[1]);
tmp = strip_string (data, '(');
tmp = strip_string (tmp, ')');
strip_string (tmp, '"');
strip_string (tmp, '\'');
if (conn)
g_hash_table_insert (conn, g_strdup (key_value[0]),
g_strdup (tmp));
g_free (data);
g_strfreev (key_value);
}
static void
destroy_connection_config (GHashTable * conn)
{
gpointer key, value;
GHashTableIter iter;
g_hash_table_iter_init (&iter, conn);
while (g_hash_table_iter_next (&iter, &key, &value)) {
g_free (key);
g_free (value);
}
g_hash_table_destroy (conn);
}
// read settings from /etc/NetworkManager/nm-system-settings.conf
gchar *
ifnet_get_global_setting (gchar * group, gchar * key)
{
GError *error = NULL;
GKeyFile *keyfile = g_key_file_new ();
gchar *result = NULL;
if (!g_key_file_load_from_file (keyfile,
IFNET_SYSTEM_SETTINGS_KEY_FILE,
G_KEY_FILE_NONE, &error)) {
PLUGIN_WARN (IFNET_PLUGIN_NAME,
"loading system config file (%s) caused error: (%d) %s",
IFNET_SYSTEM_SETTINGS_KEY_FILE,
error ? error->code : -1, error
&& error->message ? error->message : "(unknown)");
} else {
result = g_key_file_get_string (keyfile, group, key, &error);
}
g_key_file_free (keyfile);
return result;
}
static void
strip_function (GIOChannel * channel, gchar * line)
{
int counter = 0;
gchar *p, *tmp;
gboolean begin = FALSE;
GString *function_str = g_string_new (line);
g_string_append (function_str, "\n");
while (1) {
p = line;
while (*p != '\0') {
if (*p == '{') {
counter++;
begin = TRUE;
} else if (*p == '}')
counter--;
p++;
}
if (begin && counter == 0) {
g_free (line);
goto done;
}
while (1) {
g_free (line);
if (g_io_channel_read_line
(channel, &line, NULL, NULL,
NULL) == G_IO_STATUS_EOF)
goto done;
g_string_append (function_str, line);
tmp = g_strdup (line);
g_strstrip (tmp);
if (tmp[0] != '#' && tmp[0] != '\0') {
g_free (tmp);
break;
} else
g_free (tmp);
}
}
done:
functions_list =
g_list_append (functions_list, g_strdup (function_str->str));
g_string_free (function_str, TRUE);
}
static gboolean
is_function (gchar * line)
{
static gchar *func_names[] =
{ "preup", "predown", "postup", "postdown", "failup", "faildown",
NULL,
};
int i;
for (i = 0; func_names[i]; i++) {
if (g_str_has_prefix (line, func_names[i])) {
PLUGIN_PRINT (IFNET_PLUGIN_NAME,
"Ignoring function: %s", func_names[i]);
return TRUE;
}
}
return FALSE;
}
gboolean
ifnet_init (gchar * config_file)
{
GIOChannel *channel = NULL;
gchar *line;
/* Handle multiple lines with brackets */
gboolean complete = TRUE;
/* line buffer */
GString *buf;
net_parser_data_changed = FALSE;
conn_table = g_hash_table_new (g_str_hash, g_str_equal);
global_settings_table = g_hash_table_new (g_str_hash, g_str_equal);
functions_list = NULL;
if (g_file_test (config_file, G_FILE_TEST_IS_REGULAR))
channel = g_io_channel_new_file (config_file, "r", NULL);
if (channel == NULL) {
PLUGIN_WARN (IFNET_PLUGIN_NAME,
"Error: Can't open %s\n", config_file);
return FALSE;
}
buf = g_string_new (NULL);
while (g_io_channel_read_line
(channel, &line, NULL, NULL, NULL) != G_IO_STATUS_EOF) {
g_strstrip (line);
/* convert multiple lines to a complete line and
* pass it to init_block_by_line() */
if (is_function (line)) {
strip_function (channel, line);
continue;
}
if (line[0] != '#' && line[0] != '\0') {
gchar *pos = NULL;
if (!complete) {
complete =
g_strrstr (line,
")") == NULL ? FALSE : TRUE;
if ((pos = strchr (line, '#')) != NULL)
*pos = '\0';
g_strstrip (line);
if (line[0] != '\0') {
g_string_append_printf (buf,
" %s", line);
}
g_free (line);
if (!complete)
continue;
} else {
complete =
(g_strrstr (line, "(") != NULL
&& g_strrstr (line, ")") != NULL)
|| g_strrstr (line, "(") == NULL;
if ((pos = strchr (line, '#')) != NULL)
*pos = '\0';
g_strstrip (line);
if (line[0] != '\0')
g_string_append (buf, line);
g_free (line);
if (!complete)
continue;
}
init_block_by_line (buf->str);
g_string_free (buf, TRUE);
buf = g_string_new (NULL);
} else
/* Blank line or comment line */
g_free (line);
}
g_string_free (buf, TRUE);
g_io_channel_shutdown (channel, FALSE, NULL);
g_io_channel_unref (channel);
return TRUE;
}
gchar *
ifnet_get_data (gchar * conn_name, const gchar * key)
{
GHashTable *conn = g_hash_table_lookup (conn_table, conn_name);
if (conn)
return g_hash_table_lookup (conn, key);
return NULL;
}
void
ifnet_set_data (gchar * conn_name, gchar * key, gchar * value)
{
gpointer orin_key = NULL, orin_value = NULL;
GHashTable *conn = g_hash_table_lookup (conn_table, conn_name);
if (!conn) {
PLUGIN_WARN (IFNET_PLUGIN_NAME,
"%s does not exsit!", conn_name);
return;
}
/* Remove existing key value pair */
if (g_hash_table_lookup_extended (conn, key, &orin_key, &orin_value)) {
g_hash_table_remove (conn, orin_key);
g_free (orin_key);
g_free (orin_value);
}
if (value)
g_hash_table_insert (conn, g_strdup (key),
strip_string (g_strdup (value), '"'));
net_parser_data_changed = TRUE;
}
// Remember to free return value
gchar *
ifnet_get_global_data (const gchar * key)
{
gchar *result = g_hash_table_lookup (global_settings_table, key);
if (result)
result = g_strdup (result);
else
return NULL;
strip_string (result, '"');
return result;
}
// Return names of legal connections
GList *
ifnet_get_connection_names ()
{
GList *names = g_hash_table_get_keys (conn_table);
GList *result = NULL;
while (names) {
if (!ignore_connection_name (names->data))
result = g_list_append (result, names->data);
names = names->next;
}
return result;
}
/* format IP and route for writing */
static void
format_ips (gchar * value, gchar ** out_line, gchar * key, gchar * name)
{
gchar **ipset;
guint length, i;
GString *formated_string = g_string_new (NULL);
strip_string (value, '"');
ipset = g_strsplit (value, "\" \"", 0);
length = g_strv_length (ipset);
//only one line
if (length < 2) {
*out_line =
g_strdup_printf ("%s_%s=( \"%s\" )\n", key, name, value);
goto done;
}
// Multiple lines
g_string_append_printf (formated_string, "%s_%s=(\n", key, name);
for (i = 0; i < length; i++)
g_string_append_printf (formated_string,
"\t\"%s\"\n", ipset[i]);
g_string_append (formated_string, ")\n");
*out_line = g_strdup (formated_string->str);
done:
g_string_free (formated_string, TRUE);
g_strfreev (ipset);
}
gboolean
ifnet_flush_to_file (gchar * config_file)
{
GIOChannel *channel;
GError **error = NULL;
gpointer key, value, name, network;
GHashTableIter iter, iter_network;
GList *list_iter;
gchar *out_line;
gsize bytes_written;
gboolean result = FALSE;
if (!net_parser_data_changed)
return FALSE;
if (!conn_table || !global_settings_table)
return FALSE;
channel = g_io_channel_new_file (config_file, "w", NULL);
if (!channel) {
PLUGIN_WARN (IFNET_PLUGIN_NAME,
"Can't open file %s for writing", config_file);
return FALSE;
}
g_hash_table_iter_init (&iter, global_settings_table);
PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Writing to %s", config_file);
g_io_channel_write_chars (channel,
"#Generated by NetworkManager\n"
"###### Global Configuration ######\n",
-1, &bytes_written, error);
/* Writing global data */
while (g_hash_table_iter_next (&iter, &key, &value)) {
out_line =
g_strdup_printf ("%s=%s\n", (gchar *) key, (gchar *) value);
g_io_channel_write_chars (channel, out_line, -1,
&bytes_written, error);
if (bytes_written == 0 || (error && *error))
break;
g_free (out_line);
}
if (error && *error) {
PLUGIN_WARN (IFNET_PLUGIN_NAME,
"Found error: %s", (*error)->message);
goto done;
}
/* Writing connection data */
g_io_channel_write_chars (channel,
"\n###### Connection Configuration ######\n",
-1, &bytes_written, error);
g_hash_table_iter_init (&iter, conn_table);
while (g_hash_table_iter_next (&iter, &name, &network)) {
g_hash_table_iter_init (&iter_network, (GHashTable *) network);
g_io_channel_write_chars (channel,
"#----------------------------------\n",
-1, &bytes_written, error);
while (g_hash_table_iter_next (&iter_network, &key, &value)) {
if (!g_str_has_prefix ((gchar *) key, "name")
&& !g_str_has_prefix ((gchar *) key, "type")) {
/* These keys contain brackets */
if (strcmp
((gchar *) key,
"config") == 0
|| strcmp ((gchar *) key,
"routes") == 0
|| strcmp ((gchar *) key,
"pppd") == 0
|| strcmp ((gchar *) key, "chat") == 0)
format_ips (value, &out_line, (gchar *)
key, (gchar *)
name);
else
out_line =
g_strdup_printf
("%s_%s=\"%s\"\n",
(gchar *) key,
(gchar *) name, (gchar *) value);
g_io_channel_write_chars
(channel, out_line, -1,
&bytes_written, error);
if (bytes_written == 0 || (error && *error))
break;
g_free (out_line);
}
}
}
if (error && *error) {
PLUGIN_WARN (IFNET_PLUGIN_NAME,
"Found error: %s", (*error)->message);
goto done;
}
/* Writing reserved functions */
if (functions_list) {
g_io_channel_write_chars (channel,
"\n###### Reserved Functions ######\n",
-1, &bytes_written, error);
/* Writing functions */
for (list_iter = functions_list; list_iter;
list_iter = g_list_next (list_iter)) {
out_line =
g_strdup_printf ("%s\n", (gchar *) list_iter->data);
g_io_channel_write_chars (channel, out_line, -1,
&bytes_written, error);
if (bytes_written == 0 || (error && *error))
break;
g_free (out_line);
}
if (error && *error) {
PLUGIN_WARN (IFNET_PLUGIN_NAME,
"Found error: %s", (*error)->message);
goto done;
}
}
g_io_channel_flush (channel, error);
if (error && *error) {
PLUGIN_WARN (IFNET_PLUGIN_NAME,
"Found error: %s", (*error)->message);
goto done;
}
result = TRUE;
net_parser_data_changed = FALSE;
done:
g_io_channel_shutdown (channel, FALSE, NULL);
g_io_channel_unref (channel);
return result;
}
gboolean
ifnet_delete_network (gchar * conn_name)
{
GHashTable *network = NULL;
g_return_val_if_fail (conn_table != NULL && conn_name != NULL, FALSE);
PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Deleting network for %s", conn_name);
network = g_hash_table_lookup (conn_table, conn_name);
if (!network)
return FALSE;
g_hash_table_remove (conn_table, conn_name);
destroy_connection_config (network);
net_parser_data_changed = TRUE;
return TRUE;
}
void
ifnet_destroy (void)
{
GHashTableIter iter;
gpointer key;
gpointer value;
GList *list_iter;
/* Destroy connection setting */
if (conn_table) {
g_hash_table_iter_init (&iter, conn_table);
while (g_hash_table_iter_next (&iter, &key, &value)) {
destroy_connection_config ((GHashTable *)
value);
}
g_hash_table_destroy (conn_table);
conn_table = NULL;
}
/* Destroy global data */
if (global_settings_table) {
g_hash_table_iter_init (&iter, global_settings_table);
while (g_hash_table_iter_next (&iter, &key, &value)) {
g_free (key);
g_free (value);
}
g_hash_table_destroy (global_settings_table);
global_settings_table = NULL;
}
for (list_iter = functions_list; list_iter;
list_iter = g_list_next (list_iter))
g_free (list_iter->data);
g_list_free (functions_list);
}

View file

@ -0,0 +1,46 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
* Mu Qiao <qiaomuf@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 1999-2010 Gentoo Foundation, Inc.
*/
#ifndef _NET_PARSER_H
#define _NET_PARSER_H
#include <glib.h>
#define CONF_NET_FILE "/etc/conf.d/net"
#define IFNET_SYSTEM_SETTINGS_KEY_FILE "/etc/NetworkManager/nm-system-settings.conf"
#define IFNET_KEY_FILE_GROUP "ifnet"
gboolean ifnet_init (gchar * config_file);
void ifnet_destroy (void);
/* Reader functions */
GList *ifnet_get_connection_names (void);
gchar *ifnet_get_data (gchar * conn_name, const gchar * key);
gchar *ifnet_get_global_data (const gchar * key);
gchar *ifnet_get_global_setting (gchar * group, gchar * key);
gboolean ifnet_has_connection (gchar * conn_name);
/* Writer functions */
gboolean ifnet_flush_to_file (gchar * config_file);
void ifnet_set_data (gchar * conn_name, gchar * key, gchar * value);
gboolean ifnet_add_connection (gchar * name, gchar * type);
gboolean ifnet_delete_network (gchar * conn_name);
#endif

View file

@ -0,0 +1,931 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
* Mu Qiao <qiaomuf@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 1999-2010 Gentoo Foundation, Inc.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <nm-utils.h>
#include <nm-system-config-interface.h>
#include "net_utils.h"
#include "wpa_parser.h"
#include "net_parser.h"
/* emit heading and tailing blank space, tab, character t */
gchar *
strip_string (gchar * str, gchar t)
{
gchar *ret = str;
gint length = 0;
guint i = 0;
while (ret[i] != '\0'
&& (ret[i] == '\t' || ret[i] == ' ' || ret[i] == t)) {
length++;
i++;
}
i = 0;
while (ret[i + length] != '\0') {
ret[i] = ret[i + length];
i++;
}
ret[i] = '\0';
length = strlen (ret);
while ((length - 1) >= 0
&& (ret[length - 1] == ' ' || ret[length - 1] == '\n'
|| ret[length - 1] == '\t' || ret[length - 1] == t))
length--;
ret[length] = '\0';
return ret;
}
gboolean
is_hex (gchar * value)
{
gchar *p;
if (!value)
return FALSE;
p = value;
while (*p) {
if (!isxdigit (*p)) {
return FALSE;
}
p++;
}
return TRUE;
}
gboolean
is_ascii (gchar * value)
{
gchar *p;
p = value;
while (*p) {
if (!isascii (*p)) {
return FALSE;
}
p++;
}
return TRUE;
}
gboolean
is_true (char *str)
{
if (!g_ascii_strcasecmp (str, "yes")
|| !g_ascii_strcasecmp (str, "true"))
return TRUE;
return FALSE;
}
static int
hex2num (char c)
{
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
return -1;
}
static int
hex2byte (const char *hex)
{
int a, b;
a = hex2num (*hex++);
if (a < 0)
return -1;
b = hex2num (*hex++);
if (b < 0)
return -1;
return (a << 4) | b;
}
/* free return value by caller */
gchar *
utils_hexstr2bin (const gchar * hex, size_t len)
{
size_t i;
int a;
const gchar *ipos = hex;
gchar *buf = NULL;
gchar *opos;
/* Length must be a multiple of 2 */
if ((len % 2) != 0)
return NULL;
opos = buf = g_malloc0 ((len / 2) + 1);
for (i = 0; i < len; i += 2) {
a = hex2byte (ipos);
if (a < 0) {
g_free (buf);
return NULL;
}
*opos++ = a;
ipos += 2;
}
return buf;
}
/* free return value by caller */
gchar *
utils_bin2hexstr (const gchar * bytes, int len, int final_len)
{
static gchar hex_digits[] = "0123456789abcdef";
gchar *result;
int i;
gsize buflen = (len * 2) + 1;
g_return_val_if_fail (bytes != NULL, NULL);
g_return_val_if_fail (len > 0, NULL);
g_return_val_if_fail (len < 4096, NULL); /* Arbitrary limit */
if (final_len > -1)
g_return_val_if_fail (final_len < buflen, NULL);
result = g_malloc0 (buflen);
for (i = 0; i < len; i++) {
result[2 * i] = hex_digits[(bytes[i] >> 4) & 0xf];
result[2 * i + 1] = hex_digits[bytes[i] & 0xf];
}
/* Cut converted key off at the correct length for this cipher type */
if (final_len > -1)
result[final_len] = '\0';
else
result[buflen - 1] = '\0';
return result;
}
GQuark
ifnet_plugin_error_quark (void)
{
static GQuark error_quark = 0;
if (G_UNLIKELY (error_quark == 0))
error_quark =
g_quark_from_static_string ("ifnet-plugin-error-quark");
return error_quark;
}
gboolean
reload_parsers ()
{
ifnet_destroy ();
wpa_parser_destroy ();
if (!ifnet_init (CONF_NET_FILE))
return FALSE;
wpa_parser_init (WPA_SUPPLICANT_CONF);
return TRUE;
}
gchar *
read_hostname (gchar * path)
{
gchar *contents = NULL, *result = NULL, *tmp;
gchar **all_lines = NULL;
guint line_num, i;
if (!g_file_get_contents (path, &contents, NULL, NULL))
return NULL;
all_lines = g_strsplit (contents, "\n", 0);
line_num = g_strv_length (all_lines);
for (i = 0; i < line_num; i++) {
g_strstrip (all_lines[i]);
if (all_lines[i][0] == '#' || all_lines[i][0] == '\0')
continue;
if (g_str_has_prefix (all_lines[i], "hostname")) {
tmp = strstr (all_lines[i], "=");
tmp++;
tmp = strip_string (tmp, '"');
result = g_strdup (tmp);
break;
}
}
g_strfreev (all_lines);
g_free (contents);
return result;
}
gboolean
write_hostname (const gchar * hostname, gchar * path)
{
gchar *contents = g_strdup_printf ("#Generated by NetworkManager\n"
"hostname=\"%s\"\n", hostname);
gboolean result = g_file_set_contents (path, contents, -1, NULL);
g_free (contents);
return result;
}
gboolean
is_static_ip4 (gchar * conn_name)
{
gchar *data = ifnet_get_data (conn_name, "config");
gchar *dhcp6;
if (!data)
return FALSE;
dhcp6 = strstr (data, "dhcp6");
if (dhcp6) {
gchar *dhcp4;
if (strstr (data, "dhcp "))
return FALSE;
dhcp4 = strstr (data, "dhcp");
if (!dhcp4)
return TRUE;
if (dhcp4[4] == '\0')
return FALSE;
return TRUE;
}
return strstr (data, "dhcp") == NULL ? TRUE : FALSE;
}
gboolean
is_static_ip6 (gchar * conn_name)
{
gchar *data = ifnet_get_data (conn_name, "config");
if (!data)
return TRUE;
return strstr (data, "dhcp6") == NULL ? TRUE : FALSE;
}
gboolean
is_ip4_address (gchar * in_address)
{
gchar *pattern =
"\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.((\\{\\d{1,3}\\.\\.\\d{1,3}\\})|\\d{1,3})$";
gchar *address = g_strdup (in_address);
gboolean result = FALSE;
gchar *tmp;
GRegex *regex = g_regex_new (pattern, 0, 0, NULL);
GMatchInfo *match_info;
if (!address)
goto done;
g_strstrip (address);
if ((tmp = strstr (address, "/")) != NULL)
*tmp = '\0';
if ((tmp = strstr (address, " ")) != NULL)
*tmp = '\0';
g_regex_match (regex, address, 0, &match_info);
result = g_match_info_matches (match_info);
done:
if (match_info)
g_match_info_free (match_info);
g_regex_unref (regex);
g_free (address);
return result;
}
gboolean
is_ip6_address (gchar * in_address)
{
struct in6_addr tmp_ip6_addr;
gchar *tmp;
gchar *address = g_strdup (in_address);
gboolean result = FALSE;
if (!address) {
g_free (address);
return FALSE;
}
g_strstrip (address);
if ((tmp = strchr (address, '/')) != NULL)
*tmp = '\0';
if (inet_pton (AF_INET6, address, &tmp_ip6_addr))
result = TRUE;
g_free (address);
return result;
}
gboolean
has_ip6_address (gchar * conn_name)
{
gchar **ipset;
guint length;
guint i;
g_return_val_if_fail (conn_name != NULL, FALSE);
ipset = g_strsplit (ifnet_get_data (conn_name, "config"), "\" \"", 0);
length = g_strv_length (ipset);
for (i = 0; i < length; i++) {
if (!is_ip6_address (ipset[i]))
continue;
else {
g_strfreev (ipset);
return TRUE;
}
}
g_strfreev (ipset);
return FALSE;
}
gboolean
has_default_route (gchar * conn_name, gboolean (*check_fn) (gchar *))
{
gchar *routes = NULL, *tmp, *end;
g_return_val_if_fail (conn_name != NULL, FALSE);
tmp = ifnet_get_data (conn_name, "routes");
if (!tmp)
return FALSE;
routes = g_strdup (tmp);
tmp = strstr (routes, "default via ");
if (!tmp) {
goto error;
}
tmp += strlen ("default via ");
g_strstrip (tmp);
if ((end = strstr (tmp, "\"")) != NULL)
*end = '\0';
if (check_fn (tmp)) {
g_free (routes);
return TRUE;
}
error:
g_free (routes);
return FALSE;
}
static ip_block *
create_ip4_block (gchar * ip)
{
ip_block *iblock = g_slice_new0 (ip_block);
struct in_addr tmp_ip4_addr;
int i;
guint length;
gchar **ip_mask;
/* prefix format */
if (strstr (ip, "/")) {
gchar *prefix;
ip_mask = g_strsplit (ip, "/", 0);
length = g_strv_length (ip_mask);
if (!inet_pton (AF_INET, ip_mask[0], &tmp_ip4_addr))
goto error;
iblock->ip = tmp_ip4_addr.s_addr;
prefix = ip_mask[1];
i = 0;
while (i < length && isdigit (prefix[i]))
i++;
prefix[i] = '\0';
iblock->netmask = nm_utils_ip4_prefix_to_netmask ((guint32)
atoi (ip_mask
[1]));
} else if (strstr (ip, "netmask")) {
ip_mask = g_strsplit (ip, " ", 0);
length = g_strv_length (ip_mask);
if (!inet_pton (AF_INET, ip_mask[0], &tmp_ip4_addr))
goto error;
iblock->ip = tmp_ip4_addr.s_addr;
i = 0;
while (i < length && !strstr (ip_mask[++i], "netmask")) ;
while (i < length && ip_mask[++i][0] == '\0') ;
if (i >= length)
goto error;
if (!inet_pton (AF_INET, ip_mask[i], &tmp_ip4_addr))
goto error;
iblock->netmask = tmp_ip4_addr.s_addr;
} else {
g_slice_free (ip_block, iblock);
if (!is_ip6_address (ip) && !strstr (ip, "dhcp"))
PLUGIN_WARN (IFNET_PLUGIN_NAME,
"Can't handle ipv4 address: %s, missing netmask or prefix",
ip);
return NULL;
}
g_strfreev (ip_mask);
return iblock;
error:
if (!is_ip6_address (ip))
PLUGIN_WARN (IFNET_PLUGIN_NAME, "Can't handle IPv4 address: %s",
ip);
g_strfreev (ip_mask);
g_slice_free (ip_block, iblock);
return NULL;
}
static ip6_block *
create_ip6_block (gchar * ip)
{
ip6_block *iblock = g_slice_new0 (ip6_block);
gchar *dup_ip = g_strdup (ip);
struct in6_addr *tmp_ip6_addr = g_slice_new0 (struct in6_addr);
gchar *prefix = NULL;
if ((prefix = strstr (dup_ip, "/")) != NULL) {
*prefix = '\0';
prefix++;
}
if (!inet_pton (AF_INET6, dup_ip, tmp_ip6_addr)) {
goto error;
}
iblock->ip = tmp_ip6_addr;
if (prefix) {
errno = 0;
iblock->prefix = strtol (prefix, NULL, 10);
if (errno || iblock->prefix <= 0 || iblock->prefix > 128) {
goto error;
}
} else
iblock->prefix = 64;
g_free (dup_ip);
return iblock;
error:
if (!is_ip4_address (ip))
PLUGIN_WARN (IFNET_PLUGIN_NAME, "Can't handle IPv6 address: %s",
ip);
g_slice_free (ip6_block, iblock);
g_slice_free (struct in6_addr, tmp_ip6_addr);
g_free (dup_ip);
return NULL;
}
static guint32
get_ip4_gateway (gchar * gateway)
{
gchar *tmp, *split;
struct in_addr tmp_ip4_addr;
if (!gateway)
return 0;
tmp = strstr (gateway, "via ");
tmp = g_strdup (tmp + strlen ("via "));
strip_string (tmp, ' ');
strip_string (tmp, '"');
if ((split = strstr (tmp, "\"")) != NULL)
*split = '\0';
if (!inet_pton (AF_INET, tmp, &tmp_ip4_addr))
goto error;
g_free (tmp);
return tmp_ip4_addr.s_addr;
error:
if (!is_ip6_address (tmp))
PLUGIN_WARN (IFNET_PLUGIN_NAME, "Can't handle IPv4 gateway: %s",
tmp);
g_free (tmp);
return 0;
}
static struct in6_addr *
get_ip6_next_hop (gchar * next_hop)
{
gchar *tmp;
struct in6_addr *tmp_ip6_addr = g_slice_new0 (struct in6_addr);
if (!next_hop)
return 0;
tmp = strstr (next_hop, "via ");
tmp = g_strdup (tmp + strlen ("via "));
strip_string (tmp, ' ');
strip_string (tmp, '"');
g_strstrip (tmp);
if (!inet_pton (AF_INET6, tmp, tmp_ip6_addr))
goto error;
g_free (tmp);
return tmp_ip6_addr;
error:
if (!is_ip4_address (tmp))
PLUGIN_WARN (IFNET_PLUGIN_NAME,
"Can't handle IPv6 next_hop: %s", tmp);
g_free (tmp);
g_slice_free (struct in6_addr, tmp_ip6_addr);
return NULL;
}
ip_block *
convert_ip4_config_block (gchar * conn_name)
{
gchar **ipset;
guint length;
guint i;
gchar *ip;
guint32 def_gateway;
gchar *routes;
gchar *pos;
ip_block *start = NULL, *current = NULL, *iblock = NULL;
gchar *pattern =
"((\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.)\\{(\\d{1,3})\\.\\.(\\d{1,3})\\}(/\\d{1,2}))";
GRegex *regex = g_regex_new (pattern, 0, 0, NULL);
g_return_val_if_fail (conn_name != NULL, NULL);
ipset = g_strsplit (ifnet_get_data (conn_name, "config"), "\" \"", 0);
length = g_strv_length (ipset);
routes = ifnet_get_data (conn_name, "routes");
if (routes)
def_gateway = get_ip4_gateway (strstr (routes, "default"));
else
def_gateway = 0;
for (i = 0; i < length; i++) {
ip = ipset[i];
ip = strip_string (ip, '"');
//Handle ip like 192.168.4.{1..3}
if ((pos = strchr (ip, '{')) != NULL) {
gchar *ip_start, *ip_prefix;
gchar *begin_str, *end_str;
int begin, end, j;
GMatchInfo *match_info;
g_regex_match (regex, ip, 0, &match_info);
if (!g_match_info_matches (match_info)) {
g_match_info_free (match_info);
continue;
}
begin_str = g_match_info_fetch (match_info, 3);
end_str = g_match_info_fetch (match_info, 4);
begin = atoi (begin_str);
end = atoi (end_str);
ip_start = g_match_info_fetch (match_info, 2);
ip_prefix = g_match_info_fetch (match_info, 5);
if (end < begin || begin < 1 || end > 254) {
g_match_info_free (match_info);
continue;
}
for (j = begin; j <= end; j++) {
char suf[4];
gchar *newip;
sprintf (suf, "%d", j);
newip =
g_strconcat (ip_start, suf, ip_prefix,
NULL);
iblock = create_ip4_block (newip);
if (iblock == NULL) {
g_free (newip);
continue;
}
if (!iblock->gateway && def_gateway != 0)
iblock->gateway = def_gateway;
if (start == NULL)
start = current = iblock;
else {
current->next = iblock;
current = iblock;
}
g_free (newip);
}
g_free (begin_str);
g_free (end_str);
g_free (ip_start);
g_free (ip_prefix);
g_match_info_free (match_info);
} else {
iblock = create_ip4_block (ip);
if (iblock == NULL)
continue;
if (!iblock->gateway && def_gateway != 0)
iblock->gateway = def_gateway;
if (start == NULL)
start = current = iblock;
else {
current->next = iblock;
current = iblock;
}
}
}
g_strfreev (ipset);
g_regex_unref (regex);
return start;
}
ip6_block *
convert_ip6_config_block (gchar * conn_name)
{
gchar **ipset;
guint length;
guint i;
gchar *ip;
ip6_block *start = NULL, *current = NULL, *iblock = NULL;
g_return_val_if_fail (conn_name != NULL, NULL);
ipset = g_strsplit (ifnet_get_data (conn_name, "config"), "\" \"", 0);
length = g_strv_length (ipset);
for (i = 0; i < length; i++) {
ip = ipset[i];
ip = strip_string (ip, '"');
iblock = create_ip6_block (ip);
if (iblock == NULL)
continue;
if (start == NULL)
start = current = iblock;
else {
current->next = iblock;
current = iblock;
}
}
g_strfreev (ipset);
return start;
}
ip_block *
convert_ip4_routes_block (gchar * conn_name)
{
gchar **ipset;
guint length;
guint i;
gchar *ip;
gchar *routes;
ip_block *start = NULL, *current = NULL, *iblock = NULL;
g_return_val_if_fail (conn_name != NULL, NULL);
routes = ifnet_get_data (conn_name, "routes");
if (!routes)
return NULL;
ipset = g_strsplit (routes, "\" \"", 0);
length = g_strv_length (ipset);
for (i = 0; i < length; i++) {
ip = ipset[i];
if (strstr (ip, "default via ") || strstr (ip, "::")
|| !strstr (ip, "via"))
continue;
ip = strip_string (ip, '"');
iblock = create_ip4_block (ip);
if (iblock == NULL)
continue;
iblock->gateway = get_ip4_gateway (ip);
if (start == NULL)
start = current = iblock;
else {
current->next = iblock;
current = iblock;
}
}
g_strfreev (ipset);
return start;
}
ip6_block *
convert_ip6_routes_block (gchar * conn_name)
{
gchar **ipset;
guint length;
guint i;
gchar *ip, *tmp_addr;
gchar *routes;
ip6_block *start = NULL, *current = NULL, *iblock = NULL;
struct in6_addr *tmp_ip6_addr;
g_return_val_if_fail (conn_name != NULL, NULL);
routes = ifnet_get_data (conn_name, "routes");
if (!routes)
return NULL;
ipset = g_strsplit (routes, "\" \"", 0);
length = g_strv_length (ipset);
for (i = 0; i < length; i++) {
ip = ipset[i];
ip = strip_string (ip, '"');
if (ip[0] == '\0')
continue;
printf ("ip:%s\n", ip);
if ((tmp_addr = strstr (ip, "default via ")) != NULL) {
tmp_addr += strlen ("default via ");
if (!is_ip6_address (tmp_addr))
continue;
else {
tmp_ip6_addr = g_slice_new0 (struct in6_addr);
if (inet_pton (AF_INET6, "::", tmp_ip6_addr)) {
iblock = g_slice_new0 (ip6_block);
iblock->ip = tmp_ip6_addr;
iblock->prefix = 128;
} else {
g_slice_free (struct in6_addr,
tmp_ip6_addr);
continue;
}
}
} else
iblock = create_ip6_block (ip);
if (iblock == NULL)
continue;
iblock->next_hop = get_ip6_next_hop (ip);
if (iblock->next_hop == NULL) {
destroy_ip6_block (iblock);
continue;
}
if (start == NULL)
start = current = iblock;
else {
current->next = iblock;
current = iblock;
}
}
g_strfreev (ipset);
return start;
}
void
destroy_ip_block (ip_block * iblock)
{
g_slice_free (ip_block, iblock);
}
void
destroy_ip6_block (ip6_block * iblock)
{
g_slice_free (struct in6_addr, iblock->ip);
g_slice_free (struct in6_addr, iblock->next_hop);
g_slice_free (ip6_block, iblock);
}
void
set_ip4_dns_servers (NMSettingIP4Config * s_ip4, gchar * conn_name)
{
gchar *dns_servers = ifnet_get_data (conn_name, "dns_servers");
gchar **server_list;
guint length, i;
struct in_addr tmp_ip4_addr;
guint32 new_dns;
if (!dns_servers)
return;
strip_string (dns_servers, '"');
server_list = g_strsplit (dns_servers, " ", 0);
length = g_strv_length (server_list);
if (length)
g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_IGNORE_AUTO_DNS,
TRUE, NULL);
for (i = 0; i < length; i++) {
g_strstrip (server_list[i]);
if (server_list[i][0] == '\0')
continue;
if (!inet_pton (AF_INET, server_list[i], &tmp_ip4_addr)) {
if (!is_ip6_address (server_list[i]))
PLUGIN_WARN (IFNET_PLUGIN_NAME,
"ignored dns: %s\n",
server_list[i]);
continue;
}
new_dns = tmp_ip4_addr.s_addr;
if (new_dns && !nm_setting_ip4_config_add_dns (s_ip4, new_dns))
PLUGIN_WARN (IFNET_PLUGIN_NAME,
"warning: duplicate DNS server %s",
server_list[i]);
}
g_strfreev (server_list);
}
void
set_ip6_dns_servers (NMSettingIP6Config * s_ip6, gchar * conn_name)
{
gchar *dns_servers = ifnet_get_data (conn_name, "dns_servers");
gchar **server_list;
guint length, i;
struct in6_addr tmp_ip6_addr;
if (!dns_servers)
return;
strip_string (dns_servers, '"');
server_list = g_strsplit (dns_servers, " ", 0);
length = g_strv_length (server_list);
if (length)
g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_IGNORE_AUTO_DNS,
TRUE, NULL);
for (i = 0; i < length; i++) {
g_strstrip (server_list[i]);
if (server_list[i][0] == '\0')
continue;
if (!inet_pton (AF_INET6, server_list[i], &tmp_ip6_addr)) {
if (is_ip6_address (server_list[i]))
PLUGIN_WARN (IFNET_PLUGIN_NAME,
"ignored dns: %s\n",
server_list[i]);
continue;
}
if (!IN6_IS_ADDR_UNSPECIFIED (&tmp_ip6_addr)
&& !nm_setting_ip6_config_add_dns (s_ip6, &tmp_ip6_addr))
PLUGIN_WARN (IFNET_PLUGIN_NAME,
"warning: duplicate DNS server %s",
server_list[i]);
}
g_strfreev (server_list);
}
gboolean
is_managed (gchar * conn_name)
{
gchar *config;
g_return_val_if_fail (conn_name != NULL, FALSE);
config = (gchar *) ifnet_get_data (conn_name, "managed");
if (!config)
return TRUE;
if (strcmp (config, "false") == 0)
return FALSE;
return TRUE;
}
void
get_dhcp_hostname_and_client_id (char **hostname, char **client_id)
{
gchar *dhcp_client = ifnet_get_global_setting ("main", "dhcp");
const gchar *dhcpcd_conf = "/etc/dhcpcd.conf";
const gchar *dhclient_conf = "/etc/dhcp/dhclient.conf";
gchar *line = NULL, *tmp = NULL, *contents = NULL;
gchar **all_lines;
guint line_num, i;
*hostname = NULL;
*client_id = NULL;
if (dhcp_client) {
if (!strcmp (dhcp_client, "dhclient"))
g_file_get_contents (dhclient_conf, &contents, NULL,
NULL);
else if (!strcmp (dhcp_client, "dhcpcd"))
g_file_get_contents (dhcpcd_conf, &contents, NULL,
NULL);
} else {
if (g_file_test (dhclient_conf, G_FILE_TEST_IS_REGULAR))
g_file_get_contents (dhclient_conf, &contents, NULL,
NULL);
else if (g_file_test (dhcpcd_conf, G_FILE_TEST_IS_REGULAR))
g_file_get_contents (dhcpcd_conf, &contents, NULL,
NULL);
}
if (!contents)
return;
all_lines = g_strsplit (contents, "\n", 0);
line_num = g_strv_length (all_lines);
for (i = 0; i < line_num; i++) {
line = all_lines[i];
// dhcpcd.conf
g_strstrip (line);
if (g_str_has_prefix (line, "hostname")) {
tmp = line + strlen ("hostname");
g_strstrip (tmp);
if (tmp[0] != '\0')
*hostname = g_strdup (tmp);
else
PLUGIN_PRINT (IFNET_PLUGIN_NAME,
"dhcpcd hostname not defined, ignoring");
} else if (g_str_has_prefix (line, "clientid")) {
tmp = line + strlen ("clientid");
g_strstrip (tmp);
if (tmp[0] != '\0')
*client_id = g_strdup (tmp);
else
PLUGIN_PRINT (IFNET_PLUGIN_NAME,
"dhcpcd clientid not defined, ignoring");
}
// dhclient.conf
else if ((tmp = strstr (line, "send host-name")) != NULL) {
tmp += strlen ("send host-name");
g_strstrip (tmp);
strip_string (tmp, '"');
strip_string (tmp, ';');
if (tmp[0] != '\0')
*hostname = g_strdup (tmp);
else
PLUGIN_PRINT (IFNET_PLUGIN_NAME,
"dhclient hostname not defined, ignoring");
} else if ((tmp = strstr (line, "send dhcp-client-identifier"))
!= NULL) {
tmp += strlen ("send dhcp-client-identifier");
g_strstrip (tmp);
strip_string (tmp, ';');
if (tmp[0] != '\0')
*client_id = g_strdup (tmp);
else
PLUGIN_PRINT (IFNET_PLUGIN_NAME,
"dhclient clientid not defined, ignoring");
}
}
g_strfreev (all_lines);
g_free (contents);
}

View file

@ -0,0 +1,80 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
* Mu Qiao <qiaomuf@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 1999-2010 Gentoo Foundation, Inc.
*/
#ifndef _IFNET_UTILS_H
#define _IFNET_UTILS_H
#define IFNET_PLUGIN_NAME "SCPlugin-Ifnet"
#include <glib.h>
#include <arpa/inet.h>
#include <nm-setting-ip6-config.h>
#include <nm-setting-ip4-config.h>
#include "net_parser.h"
#define has_default_ip4_route(conn_name) has_default_route((conn_name),&is_ip4_address)
#define has_default_ip6_route(conn_name) has_default_route((conn_name),&is_ip6_address)
typedef struct _ip_block {
guint32 ip;
guint32 netmask;
guint32 gateway;
struct _ip_block *next;
} ip_block;
typedef struct _ip6_block {
struct in6_addr *ip;
long int prefix;
struct in6_addr *next_hop;
struct _ip6_block *next;
} ip6_block;
gchar *read_hostname (gchar * path);
gboolean write_hostname (const gchar * hostname, gchar * path);
gboolean is_static_ip4 (gchar * conn_name);
gboolean is_static_ip6 (gchar * conn_name);
gboolean is_ip4_address (gchar * in_address);
gboolean is_ip6_address (gchar * in_address);
gboolean has_ip6_address (gchar * conn_name);
gboolean has_default_route (gchar * conn_name, gboolean (*check_fn) (gchar *));
gboolean reload_parsers (void);
ip_block *convert_ip4_config_block (gchar * conn_name);
ip6_block *convert_ip6_config_block (gchar * conn_name);
ip_block *convert_ip4_routes_block (gchar * conn_name);
ip6_block *convert_ip6_routes_block (gchar * conn_name);
void destroy_ip_block (ip_block * iblock);
void destroy_ip6_block (ip6_block * iblock);
void set_ip4_dns_servers (NMSettingIP4Config * s_ip4, gchar * conn_name);
void set_ip6_dns_servers (NMSettingIP6Config * s_ip6, gchar * conn_name);
gchar *strip_string (gchar * str, gchar t);
gboolean is_managed (gchar * conn_name);
GQuark ifnet_plugin_error_quark (void);
gchar *utils_hexstr2bin (const gchar * hex, size_t len);
gchar *utils_bin2hexstr (const gchar * bytes, int len, int final_len);
gboolean is_hex (gchar * value);
gboolean is_ascii (gchar * value);
gboolean is_true (gchar * str);
void get_dhcp_hostname_and_client_id (char **hostname, char **client_id);
#endif

View file

@ -0,0 +1,251 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
* Mu Qiao <qiaomuf@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 1999-2010 Gentoo Foundation, Inc.
*/
#include <string.h>
#include <glib/gstdio.h>
#include <NetworkManager.h>
#include <nm-utils.h>
#include <nm-setting-wireless-security.h>
#include <nm-sysconfig-connection.h>
#include <nm-system-config-interface.h>
#include <nm-system-config-error.h>
#include "nm-ifnet-connection.h"
#include "connection_parser.h"
#include "net_parser.h"
#include "net_utils.h"
#include "wpa_parser.h"
#include "plugin.h"
static NMSettingsConnectionInterface *parent_settings_connection_iface;
static void settings_connection_interface_init (NMSettingsConnectionInterface *
klass);
G_DEFINE_TYPE_EXTENDED (NMIfnetConnection, nm_ifnet_connection,
NM_TYPE_SYSCONFIG_CONNECTION, 0,
G_IMPLEMENT_INTERFACE
(NM_TYPE_SETTINGS_CONNECTION_INTERFACE,
settings_connection_interface_init))
// G_DEFINE_TYPE(NMIfnetConnection, nm_ifnet_connection,
// NM_TYPE_SYSCONFIG_CONNECTION)
#define NM_IFNET_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_IFNET_CONNECTION, NMIfnetConnectionPrivate))
enum {
PROP_ZERO,
PROP_CONN_NAME,
_PROP_END,
};
enum {
IFNET_SETUP_MONITORS,
IFNET_CANCEL_MONITORS,
IFNET_LAST_SIGNAL
};
static guint signals[IFNET_LAST_SIGNAL] = { 0 };
typedef struct {
gchar *conn_name;
NMSystemConfigInterface *config;
} NMIfnetConnectionPrivate;
NMIfnetConnection *
nm_ifnet_connection_new (gchar * conn_name)
{
NMConnection *tmp;
GObject *object;
GError **error = NULL;
g_return_val_if_fail (conn_name != NULL, NULL);
tmp = ifnet_update_connection_from_config_block (conn_name, error);
if (!tmp)
return NULL;
object = (GObject *) g_object_new (NM_TYPE_IFNET_CONNECTION,
NM_IFNET_CONNECTION_CONN_NAME,
conn_name, NULL);
if (!object) {
g_object_unref (tmp);
return NULL;
}
nm_sysconfig_connection_update (NM_SYSCONFIG_CONNECTION (object), tmp,
FALSE, NULL);
g_object_unref (tmp);
return NM_IFNET_CONNECTION (object);
}
static void
nm_ifnet_connection_init (NMIfnetConnection * connection)
{
}
static gboolean
update (NMSettingsConnectionInterface * connection,
NMSettingsConnectionInterfaceUpdateFunc callback, gpointer user_data)
{
GError *error = NULL;
gchar *new_conn_name = NULL;
gboolean result;
NMIfnetConnectionPrivate *priv =
NM_IFNET_CONNECTION_GET_PRIVATE (connection);
g_signal_emit (connection, signals[IFNET_CANCEL_MONITORS], 0);
if (!ifnet_update_parsers_by_connection
(NM_CONNECTION (connection), priv->conn_name, &new_conn_name,
CONF_NET_FILE, WPA_SUPPLICANT_CONF, &error)) {
if (new_conn_name)
g_free (new_conn_name);
PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Failed to update %s",
priv->conn_name);
reload_parsers ();
callback (connection, error, user_data);
g_error_free (error);
g_signal_emit (connection, signals[IFNET_SETUP_MONITORS], 0);
return FALSE;
}
g_free (priv->conn_name);
priv->conn_name = new_conn_name;
result =
parent_settings_connection_iface->update (connection, callback,
user_data);
if (result)
PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Successfully updated %s",
priv->conn_name);
g_signal_emit (connection, signals[IFNET_SETUP_MONITORS], 0);
return result;
}
static gboolean
do_delete (NMSettingsConnectionInterface * connection,
NMSettingsConnectionInterfaceDeleteFunc callback, gpointer user_data)
{
GError *error = NULL;
gboolean result;
NMIfnetConnectionPrivate *priv =
NM_IFNET_CONNECTION_GET_PRIVATE (connection);
g_signal_emit (connection, signals[IFNET_CANCEL_MONITORS], 0);
if (!ifnet_delete_connection_in_parsers
(priv->conn_name, CONF_NET_FILE, WPA_SUPPLICANT_CONF)) {
PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Failed to delete %s",
priv->conn_name);
reload_parsers ();
callback (connection, error, user_data);
g_error_free (error);
g_signal_emit (connection, signals[IFNET_SETUP_MONITORS], 0);
return FALSE;
}
result =
parent_settings_connection_iface->delete (connection, callback,
user_data);
if (result)
PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Successfully deleted %s",
priv->conn_name);
g_signal_emit (connection, signals[IFNET_SETUP_MONITORS], 0);
return result;
}
static void
settings_connection_interface_init (NMSettingsConnectionInterface * iface)
{
parent_settings_connection_iface = g_type_interface_peek_parent (iface);
iface->update = update;
iface->delete = do_delete;
}
static void
set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
NMIfnetConnectionPrivate *priv =
NM_IFNET_CONNECTION_GET_PRIVATE (object);
g_return_if_fail (priv);
switch (prop_id) {
case PROP_CONN_NAME:
if (priv->conn_name)
g_free (priv->conn_name);
priv->conn_name = g_strdup (g_value_get_pointer (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
NMIfnetConnectionPrivate *priv =
NM_IFNET_CONNECTION_GET_PRIVATE (object);
g_return_if_fail (priv);
switch (prop_id) {
case PROP_CONN_NAME:
g_value_set_pointer (value, priv->conn_name);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
finalize (GObject * object)
{
NMIfnetConnectionPrivate *priv =
NM_IFNET_CONNECTION_GET_PRIVATE (object);
g_return_if_fail (priv);
if (priv->conn_name)
g_free (priv->conn_name);
G_OBJECT_CLASS (nm_ifnet_connection_parent_class)->finalize (object);
}
static void
nm_ifnet_connection_class_init (NMIfnetConnectionClass * ifnet_connection_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (ifnet_connection_class);
g_type_class_add_private (ifnet_connection_class,
sizeof (NMIfnetConnectionPrivate));
object_class->set_property = set_property;
object_class->get_property = get_property;
object_class->finalize = finalize;
/* Properties */
g_object_class_install_property
(object_class, PROP_CONN_NAME,
g_param_spec_pointer (NM_IFNET_CONNECTION_CONN_NAME,
"config_block",
"",
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
signals[IFNET_SETUP_MONITORS] =
g_signal_new ("ifnet_setup_monitors",
G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST,
0, NULL, NULL, g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
signals[IFNET_CANCEL_MONITORS] =
g_signal_new ("ifnet_cancel_monitors",
G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST,
0, NULL, NULL, g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}

View file

@ -0,0 +1,49 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
* Mu Qiao <qiaomuf@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 1999-2010 Gentoo Foundation, Inc.
*/
#ifndef NM_IFNET_CONNECTION_H
#define NM_IFNET_CONNECTION_H
#include <nm-sysconfig-connection.h>
#include "net_parser.h"
G_BEGIN_DECLS
#define NM_TYPE_IFNET_CONNECTION (nm_ifnet_connection_get_type ())
#define NM_IFNET_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_IFNET_CONNECTION, NMIfnetConnection))
#define NM_IFNET_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_IFNET_CONNECTION, NMIfnetConnectionClass))
#define NM_IS_IFNET_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_IFNET_CONNECTION))
#define NM_IS_IFNET_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_IFNET_CONNECTION))
#define NM_IFNET_CONNECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_IFNET_CONNECTION, NMIfnetConnectionClass))
#define NM_IFNET_CONNECTION_CONN_NAME "connection_name"
typedef struct {
NMSysconfigConnection parent;
} NMIfnetConnection;
typedef struct {
NMSysconfigConnectionClass parent;
} NMIfnetConnectionClass;
GType nm_ifnet_connection_get_type (void);
NMIfnetConnection *nm_ifnet_connection_new (gchar * conn_name);
G_END_DECLS
#endif /* NM_IFNET_CONNECTION_H */

View file

@ -0,0 +1,585 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager system settings service (ifnet)
*
* Mu Qiao <qiaomuf@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 1999-2010 Gentoo Foundation, Inc.
*/
#include <string.h>
#include <gmodule.h>
#include <glib.h>
#include <gio/gio.h>
#include <nm-utils.h>
#include <nm-setting-connection.h>
#include "NetworkManager.h"
#include "nm-system-config-interface.h"
#include "nm-ifnet-connection.h"
#include "plugin.h"
#include "net_utils.h"
#include "net_parser.h"
#include "wpa_parser.h"
#include "connection_parser.h"
#define IFNET_PLUGIN_NAME_PRINT "ifnet"
#define IFNET_PLUGIN_INFO "(C) 1999-2010 Gentoo Foundation, Inc. To report bugs please use bugs.gentoo.org with [networkmanager] or [dagger] prefix."
#define IFNET_SYSTEM_HOSTNAME_FILE "/etc/conf.d/hostname"
#define IFNET_MANAGE_WELL_KNOWN_DEFAULT TRUE
#define IFNET_KEY_FILE_KEY_MANAGED "managed"
typedef struct {
GHashTable *config_connections;
gchar *hostname;
gboolean unmanaged_well_known;
GFileMonitor *hostname_monitor;
GFileMonitor *net_monitor;
GFileMonitor *wpa_monitor;
} SCPluginIfnetPrivate;
typedef void (*FileChangedFn) (gpointer user_data);
typedef struct {
FileChangedFn callback;
gpointer user_data;
} FileMonitorInfo;
static void system_config_interface_init (NMSystemConfigInterface *
system_config_interface_class);
static void
reload_connections (gpointer config);
G_DEFINE_TYPE_EXTENDED (SCPluginIfnet, sc_plugin_ifnet, G_TYPE_OBJECT, 0,
G_IMPLEMENT_INTERFACE (NM_TYPE_SYSTEM_CONFIG_INTERFACE,
system_config_interface_init))
#define SC_PLUGIN_IFNET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SC_TYPE_PLUGIN_IFNET, SCPluginIfnetPrivate))
/*
static void
ignore_cb(NMSettingsConnectionInterface * connection,
GError * error, gpointer user_data)
{
}
*/
static const char *
get_hostname (NMSystemConfigInterface * config)
{
return SC_PLUGIN_IFNET_GET_PRIVATE (config)->hostname;
}
static void
update_system_hostname (gpointer config)
{
SCPluginIfnetPrivate *priv = SC_PLUGIN_IFNET_GET_PRIVATE (config);
PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Updating hostname");
if (priv->hostname)
g_free (priv->hostname);
priv->hostname = read_hostname (IFNET_SYSTEM_HOSTNAME_FILE);
g_object_notify (G_OBJECT (config),
NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME);
PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Hostname updated to: %s",
priv->hostname);
}
static void
write_system_hostname (NMSystemConfigInterface * config,
const gchar * newhostname)
{
SCPluginIfnetPrivate *priv = SC_PLUGIN_IFNET_GET_PRIVATE (config);
g_return_if_fail (newhostname);
PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Write system hostname: %s",
newhostname);
if (write_hostname (newhostname, IFNET_SYSTEM_HOSTNAME_FILE)) {
if (priv->hostname)
g_free (priv->hostname);
priv->hostname = g_strdup (newhostname);
g_object_notify (G_OBJECT (config),
NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME);
} else
PLUGIN_WARN (IFNET_PLUGIN_NAME,
"Write system hostname: %s failed", newhostname);
}
static gboolean
is_managed_plugin ()
{
gchar *result = NULL;
result =
ifnet_get_global_setting (IFNET_KEY_FILE_GROUP,
IFNET_KEY_FILE_KEY_MANAGED);
if (result) {
if (is_true (result)) {
g_free (result);
return TRUE;
} else {
g_free (result);
return FALSE;
}
}
return IFNET_MANAGE_WELL_KNOWN_DEFAULT;
}
static void
file_changed (GFileMonitor * monitor,
GFile * file,
GFile * other_file,
GFileMonitorEvent event_type, gpointer user_data)
{
FileMonitorInfo *info;
switch (event_type) {
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
info = (FileMonitorInfo *) user_data;
info->callback (info->user_data);
break;
default:
break;
}
}
static GFileMonitor *
monitor_file_changes (const char *filename,
FileChangedFn callback, gpointer user_data)
{
GFile *file;
GFileMonitor *monitor;
FileMonitorInfo *info;
GError **error = NULL;
if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR))
return NULL;
file = g_file_new_for_path (filename);
monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, error);
g_object_unref (file);
if (monitor) {
info = g_new0 (FileMonitorInfo, 1);
info->callback = callback;
info->user_data = user_data;
g_object_weak_ref (G_OBJECT (monitor), (GWeakNotify) g_free,
info);
g_signal_connect (monitor, "changed", G_CALLBACK (file_changed),
info);
PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Monitoring %s", filename);
} else
PLUGIN_WARN (IFNET_PLUGIN_NAME,
"Monitoring %s failed, error: %s", filename,
error == NULL ? "nothing" : (*error)->message);
return monitor;
}
static void
update_old_connection (gchar * conn_name,
NMIfnetConnection * old_conn,
NMIfnetConnection * new_conn,
SCPluginIfnetPrivate * priv)
{
GError **error = NULL;
if (!nm_sysconfig_connection_update (NM_SYSCONFIG_CONNECTION (old_conn),
NM_CONNECTION (new_conn), TRUE,
error)) {
PLUGIN_WARN (IFNET_PLUGIN_NAME, "error updating: %s",
(error
&& (*error)) ? (*error)->message : "(unknown)");
} else
PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Connection %s updated",
conn_name);
g_object_unref (new_conn);
}
static void
setup_monitors (NMIfnetConnection * connection, gpointer user_data)
{
SCPluginIfnet *self = SC_PLUGIN_IFNET (user_data);
SCPluginIfnetPrivate *priv = SC_PLUGIN_IFNET_GET_PRIVATE (self);
priv->hostname_monitor =
monitor_file_changes (IFNET_SYSTEM_HOSTNAME_FILE,
update_system_hostname, user_data);
priv->net_monitor =
monitor_file_changes (CONF_NET_FILE, reload_connections, user_data);
priv->wpa_monitor =
monitor_file_changes (WPA_SUPPLICANT_CONF, reload_connections,
user_data);
}
static void
cancel_monitors (NMIfnetConnection * connection, gpointer user_data)
{
SCPluginIfnet *self = SC_PLUGIN_IFNET (user_data);
SCPluginIfnetPrivate *priv = SC_PLUGIN_IFNET_GET_PRIVATE (self);
if (priv->hostname_monitor) {
g_file_monitor_cancel (priv->hostname_monitor);
g_object_unref (priv->hostname_monitor);
}
if (priv->net_monitor) {
g_file_monitor_cancel (priv->net_monitor);
g_object_unref (priv->net_monitor);
}
if (priv->wpa_monitor) {
g_file_monitor_cancel (priv->wpa_monitor);
g_object_unref (priv->wpa_monitor);
}
}
static void
reload_connections (gpointer config)
{
SCPluginIfnet *self = SC_PLUGIN_IFNET (config);
SCPluginIfnetPrivate *priv = SC_PLUGIN_IFNET_GET_PRIVATE (self);
GList *conn_names = NULL, *n_iter = NULL;
/* save names for removing unused connections */
GHashTable *new_conn_names = NULL;
GHashTableIter iter;
gpointer key;
gpointer value;
if (priv->unmanaged_well_known)
return;
if (!reload_parsers ())
return;
PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Loading connections");
conn_names = ifnet_get_connection_names ();
new_conn_names =
g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
for (n_iter = conn_names; n_iter; n_iter = g_list_next (n_iter)) {
NMIfnetConnection *exported;
NMIfnetConnection *old;
gchar *conn_name = g_strdup (n_iter->data);
/* add the new connection */
exported = nm_ifnet_connection_new (conn_name);
if (!exported) {
g_free (conn_name);
continue;
}
g_signal_connect (G_OBJECT (exported), "ifnet_setup_monitors",
G_CALLBACK (setup_monitors), config);
g_signal_connect (G_OBJECT (exported), "ifnet_cancel_monitors",
G_CALLBACK (cancel_monitors), config);
old = g_hash_table_lookup (priv->config_connections, conn_name);
if (old && exported) {
gchar *auto_refresh =
ifnet_get_global_setting (IFNET_KEY_FILE_GROUP,
"auto_refresh");
if (auto_refresh && is_true (auto_refresh)) {
if (!nm_connection_compare (NM_CONNECTION (old),
NM_CONNECTION
(exported),
NM_SETTING_COMPARE_FLAG_EXACT))
{
PLUGIN_PRINT (IFNET_PLUGIN_NAME,
"Auto refreshing %s",
conn_name);
g_signal_emit_by_name (old,
NM_SETTINGS_CONNECTION_INTERFACE_REMOVED);
g_hash_table_remove
(priv->config_connections,
conn_name);
g_hash_table_insert
(priv->config_connections,
g_strdup (conn_name), exported);
if (is_managed (conn_name))
g_signal_emit_by_name (self,
NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED,
exported);
}
} else
update_old_connection (conn_name, old,
exported, priv);
g_signal_emit_by_name (self,
NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED);
} else if (exported) {
g_hash_table_insert (priv->config_connections,
g_strdup (conn_name), exported);
if (is_managed (conn_name))
g_signal_emit_by_name (self,
NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED,
exported);
}
g_hash_table_insert (new_conn_names, conn_name, conn_name);
}
/* remove unused connections */
g_hash_table_iter_init (&iter, priv->config_connections);
while (g_hash_table_iter_next (&iter, &key, &value)) {
if (!g_hash_table_lookup (new_conn_names, key)) {
g_signal_emit_by_name (value,
NM_SETTINGS_CONNECTION_INTERFACE_REMOVED);
g_hash_table_remove (priv->config_connections, key);
}
}
g_hash_table_remove_all (new_conn_names);
g_hash_table_destroy (new_conn_names);
g_list_free (conn_names);
}
static gboolean
add_connection (NMSystemConfigInterface * config,
NMConnection * connection, GError ** error)
{
gboolean result;
result = ifnet_add_new_connection (connection, CONF_NET_FILE,
WPA_SUPPLICANT_CONF, error);
reload_connections (config);
return result;
}
static void
check_unmanaged (gpointer key, gpointer data, gpointer user_data)
{
GSList **list = (GSList **) user_data;
gchar *conn_name = (gchar *) key;
const char *unmanaged_spec;
GSList *iter;
if (is_managed (conn_name))
return;
PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Checking unmanaged: %s", conn_name);
unmanaged_spec = ifnet_get_data (conn_name, "mac");
if (!unmanaged_spec)
return;
/* Just return if the unmanaged spec is already in the list */
for (iter = *list; iter; iter = g_slist_next (iter)) {
if (!strcmp ((char *) iter->data, unmanaged_spec))
return;
}
PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Add unmanaged: %s", unmanaged_spec);
*list =
g_slist_prepend (*list, g_strdup_printf ("mac:%s", unmanaged_spec));
}
static GSList *
get_unmanaged_specs (NMSystemConfigInterface * config)
{
SCPluginIfnetPrivate *priv = SC_PLUGIN_IFNET_GET_PRIVATE (config);
GSList *list = NULL;
g_return_val_if_fail (priv->config_connections != NULL, NULL);
PLUGIN_PRINT (IFNET_PLUGIN_NAME, "getting unmanaged specs...");
g_hash_table_foreach (priv->config_connections, check_unmanaged, &list);
return list;
}
static void
SCPluginIfnet_init (NMSystemConfigInterface * config)
{
SCPluginIfnet *self = SC_PLUGIN_IFNET (config);
SCPluginIfnetPrivate *priv = SC_PLUGIN_IFNET_GET_PRIVATE (self);
PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Initializing!");
if (!priv->config_connections)
priv->config_connections =
g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
g_object_unref);
priv->unmanaged_well_known = !is_managed_plugin ();
PLUGIN_PRINT (IFNET_PLUGIN_NAME, "management mode: %s",
priv->unmanaged_well_known ? "unmanaged" : "managed");
// GFileMonitor setup
setup_monitors (NULL, config);
reload_connections (config);
/* Now if we're running in managed mode, let NM know there are new connections */
if (!priv->unmanaged_well_known) {
GHashTableIter iter;
gpointer key;
gpointer value;
g_hash_table_iter_init (&iter, priv->config_connections);
while (g_hash_table_iter_next (&iter, &key, &value)) {
if (is_managed ((gchar *) key))
g_signal_emit_by_name
(self,
NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED,
NM_EXPORTED_CONNECTION (value));
}
}
/* Read hostname */
update_system_hostname (self);
PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Initialzation complete!");
}
static GSList *
SCPluginIfnet_get_connections (NMSystemConfigInterface * config)
{
SCPluginIfnetPrivate *priv = SC_PLUGIN_IFNET_GET_PRIVATE (config);
GSList *connections = NULL;
GHashTableIter iter;
gpointer key, value;
PLUGIN_PRINT (IFNET_PLUGIN_NAME, "(%d) ... get_connections.",
GPOINTER_TO_UINT (config));
if (priv->unmanaged_well_known) {
PLUGIN_PRINT (IFNET_PLUGIN_NAME,
"(%d) ... get_connections (managed=false): return empty list.",
GPOINTER_TO_UINT (config));
return NULL;
}
g_hash_table_iter_init (&iter, priv->config_connections);
while (g_hash_table_iter_next (&iter, &key, &value))
if (is_managed ((gchar *) key))
connections = g_slist_prepend (connections, value);
PLUGIN_PRINT (IFNET_PLUGIN_NAME, "(%d) connections count: %d",
GPOINTER_TO_UINT (config), g_slist_length (connections));
return connections;
}
static void
system_config_interface_init (NMSystemConfigInterface *
system_config_interface_class)
{
system_config_interface_class->init = SCPluginIfnet_init;
system_config_interface_class->get_connections =
SCPluginIfnet_get_connections;
system_config_interface_class->get_unmanaged_specs =
get_unmanaged_specs;
system_config_interface_class->add_connection = add_connection;
}
static void
sc_plugin_ifnet_init (SCPluginIfnet * plugin)
{
}
static void
get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
NMSystemConfigInterface *self = NM_SYSTEM_CONFIG_INTERFACE (object);
switch (prop_id) {
case NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME:
g_value_set_string (value, IFNET_PLUGIN_NAME_PRINT);
break;
case NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO:
g_value_set_string (value, IFNET_PLUGIN_INFO);
break;
case NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES:
g_value_set_uint (value,
NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS
|
NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME);
break;
case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME:
g_value_set_string (value, get_hostname (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
set_property (GObject * object, guint prop_id, const GValue * value,
GParamSpec * pspec)
{
switch (prop_id) {
case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME:{
const gchar *hostname = g_value_get_string (value);
if (hostname && strlen (hostname) < 1)
hostname = NULL;
write_system_hostname (NM_SYSTEM_CONFIG_INTERFACE
(object), hostname);
break;
}
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
dispose (GObject * object)
{
SCPluginIfnet *plugin = SC_PLUGIN_IFNET (object);
SCPluginIfnetPrivate *priv = SC_PLUGIN_IFNET_GET_PRIVATE (plugin);
cancel_monitors (NULL, object);
if (priv->config_connections) {
g_hash_table_remove_all (priv->config_connections);
g_hash_table_destroy (priv->config_connections);
}
if (priv->hostname)
g_free (priv->hostname);
ifnet_destroy ();
wpa_parser_destroy ();
G_OBJECT_CLASS (sc_plugin_ifnet_parent_class)->dispose (object);
}
static void
sc_plugin_ifnet_class_init (SCPluginIfnetClass * req_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (req_class);
g_type_class_add_private (req_class, sizeof (SCPluginIfnetPrivate));
object_class->dispose = dispose;
object_class->get_property = get_property;
object_class->set_property = set_property;
g_object_class_override_property (object_class,
NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME,
NM_SYSTEM_CONFIG_INTERFACE_NAME);
g_object_class_override_property (object_class,
NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO,
NM_SYSTEM_CONFIG_INTERFACE_INFO);
g_object_class_override_property (object_class,
NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES,
NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES);
g_object_class_override_property (object_class,
NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME,
NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME);
}
G_MODULE_EXPORT GObject *
nm_system_config_factory (void)
{
static SCPluginIfnet *singleton = NULL;
if (!singleton)
singleton
=
SC_PLUGIN_IFNET (g_object_new (SC_TYPE_PLUGIN_IFNET, NULL));
else
g_object_ref (singleton);
return G_OBJECT (singleton);
}

View file

@ -0,0 +1,47 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager system settings service (ifnet)
*
* Mu Qiao <qiaomuf@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 1999-2010 Gentoo Foundation, Inc.
*/
#ifndef _PLUGIN_H_
#define _PLUGIN_H_
#include <glib-object.h>
#define SC_TYPE_PLUGIN_IFNET (sc_plugin_ifnet_get_type ())
#define SC_PLUGIN_IFNET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SC_TYPE_PLUGIN_IFNET, SCPluginIfnet))
#define SC_PLUGIN_IFNET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SC_TYPE_PLUGIN_IFNET, SCPluginIfnetClass))
#define SC_IS_PLUGIN_IFNET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SC_TYPE_PLUGIN_IFNET))
#define SC_IS_PLUGIN_IFNET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), SC_TYPE_PLUGIN_IFNET))
#define SC_PLUGIN_IFNET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SC_TYPE_PLUGIN_IFNET, SCPluginIfnetClass))
typedef struct _SCPluginIfnet SCPluginIfnet;
typedef struct _SCPluginIfnetClass SCPluginIfnetClass;
struct _SCPluginIfnet {
GObject parent;
};
struct _SCPluginIfnetClass {
GObjectClass parent;
};
GType sc_plugin_ifnet_get_type (void);
#endif

View file

@ -0,0 +1,14 @@
INCLUDES=-I$(top_srcdir)/system-settings/plugins/ifnet\
-I$(top_srcdir)/libnm-glib \
-I$(top_srcdir)/libnm-util \
-I$(top_srcdir)/include \
-I$(top_srcdir)/src/system-settings
TESTS = check_ifnet
check_PROGRAMS = check_ifnet
check_ifnet_SOURCES = test_all.c
check_ifnet_LDFLAGS = -g
check_ifnet_CPPFLAGS = $(CHECK_CFLAGS) $(GLIB_CFLAGS) -g
check_ifnet_LDADD = $(top_srcdir)/libnm-util/libnm-util.la\
$(top_srcdir)/system-settings/plugins/ifnet/lib-ifnet-io.la\
$(CHECK_LIBS)\
$(GLIB_LIBS)

View file

@ -0,0 +1,2 @@
#Generated by NetworkManager
hostname="gentoo"

View file

@ -0,0 +1,147 @@
# This blank configuration will automatically use DHCP for any net.*
# scripts in /etc/init.d. To create a more complete configuration,
# please review /etc/conf.d/net.example and save your configuration
# in /etc/conf.d/net (this file :]!).
config_eth0=(
"202.117.16.121 netmask 255.255.255.0 brd 202.117.16.255"
"192.168.4.121/24"
"dhcp6"
)
routes_eth0=( "default via 202.117.16.1"
"192.168.4.0/24 via 192.168.4.1")
dns_servers_eth0="202.117.0.20 202.117.0.21"
dns_search_eth0="p12.edu.cn p13.edu.cn"
config_eth1=(
"dhcp"
)
enable_ipv6_eth1="true"
routes_eth1=( "default via 202.117.16.1" )
dns_servers_eth1="202.117.0.20 202.117.0.21"
config_eth2=(
"202.117.16.1211 netmask 255.255.255.0 brd 202.117.16.255"
"192.168.4.121/24"
"4321:0:1:2:3:4:567:89ab/64"
)
routes_eth2=("default via 4321:0:1:2:3:4:567:89ab")
enable_ipv6_eth2="true"
config_eth3=("nufjlsjlll")
managed_eth4=("false")
routes_eth4=("default via 4321:0:1:2:3:4:567:89ab")
config_eth5=("dhcp")
config_eth6=("192.168.4.{1..101}/24")
config_eth7=( "dhcp" )
auto_eth7="true"
config_myxjtu2=("202.117.16.121/24 brd 202.117.16.255")
routes_myxjtu2=("default via 202.117.16.1")
dns_servers_myxjtu2="202.117.0.20 202.117.0.21"
#key_myxjtu2="[1] s:xjtud key [1] enc restricted"
#key_eth6="[1] aaaa-4444-3d [2] s:xjtudlc key [1] enc open"
username_ppp0='user'
password_ppp0='password'
config_qiaomuf=("dhcp")
config_1xtest=("dhcp")
config_0xab3ace=("dhcp")
modules=( "iproute2" )
config_kvm0=( "null" )
config_kvm1=( "null" )
tuntap_kvm0="tap"
tuntap_kvm1="tap"
tunctl_kvm0="-u user"
tunctl_kvm1="-u user"
bridge_br0="eth0 kvm0 kvm1"
config_br0=( "192.168.1.10/24" )
brctl_br0=( "setfd 0")
dhcp_eth1="nosendhost nontp -I"
predown() {
# The default in the script is to test for NFS root and disallow
# downing interfaces in that case. Note that if you specify a
# predown() function you will override that logic. Here it is, in
# case you still want it...
if is_net_fs /; then
eerror "root filesystem is network mounted -- can't stop ${IFACE}"
return 1
fi
# Remember to return 0 on success
return 0
}
postup() {
# This function could be used, for example, to register with a
# dynamic DNS service. Another possibility would be to
# send/receive mail once the interface is brought up.
# Here is an example that allows the use of iproute rules
# which have been configured using the rules_eth0 variable.
#rules_eth0=" \
# 'from 24.80.102.112/32 to 192.168.1.0/24 table localnet priority 100' \
# 'from 216.113.223.51/32 to 192.168.1.0/24 table localnet priority 100' \
#"
eval set -- \$rules_${IFVAR}
if [ $# != 0 ]; then
einfo "Adding IP policy routing rules"
eindent
# Ensure that the kernel supports policy routing
if ! ip rule list | grep -q "^"; then
eerror "You need to enable IP Policy Routing (CONFIG_IP_MULTIPLE_TABLES)"
eerror "in your kernel to use ip rules"
else
for x; do
ebegin "${x}"
ip rule add ${x}
eend $?
done
fi
eoutdent
# Flush the cache
ip route flush cache dev "${IFACE}"
fi
}
postdown() {
# Enable Wake-On-LAN for every interface except for lo
# Probably a good idea to set ifdown="no" in /etc/conf.d/net
# as well ;)
[ "${IFACE}" != "lo" ] && ethtool -s "${IFACE}" wol g
Automatically erase any ip rules created in the example postup above
if interface_exists "${IFACE}"; then
# Remove any rules for this interface
local rule
ip rule list | grep " iif ${IFACE}[ ]*" | {
while read rule; do
rule="${rule#*:}"
ip rule del ${rule}
done
}
# Flush the route cache
ip route flush cache dev "${IFACE}"
fi
# Return 0 always
return 0
}
failup() {
# This function is mostly here for completeness... I haven't
# thought of anything nifty to do with it yet ;-)
}
faildown()
{}

View file

@ -0,0 +1,864 @@
##############################################################################
# QUICK-START
#
# The quickest start is if you want to use DHCP.
# In that case, everything should work out of the box, no configuration
# necessary, though the startup script will warn you that you haven't
# specified anything.
# WARNING :- some examples have a mixture of IPv4 (ie 192.168.0.1) and IPv6
# (ie 4321:0:1:2:3:4:567:89ab) internet addresses. They only work if you have
# the relevant kernel option enabled. So if you don't have an IPv6 enabled
# kernel then remove the IPv6 address from your config.
# If you want to use a static address or use DHCP explicitly, jump
# down to the section labelled INTERFACE HANDLERS.
#
# If you want to do anything more fancy, you should take the time to
# read through the rest of this file.
##############################################################################
# MODULES
#
# We now support modular networking scripts which means we can easily
# add support for new interface types and modules while keeping
# compatability with existing ones.
#
# Modules load by default if the package they need is installed. If
# you specify a module here that doesn't have it's package installed
# then you get an error stating which package you need to install.
# Ideally, you only use the modules setting when you have two or more
# packages installed that supply the same service.
#
# In other words, you probably should DO NOTHING HERE...
# Prefer ifconfig over iproute2
modules=( "ifconfig" )
# You can also specify other modules for an interface
# In this case we prefer udhcpc over dhcpcd
modules_eth0=( "udhcpc" )
# You can also specify which modules not to use - for example you may be
# using a supplicant or linux-wlan-ng to control wireless configuration but
# you still want to configure network settings per ESSID associated with.
modules=( "!iwconfig" "!wpa_supplicant" )
# IMPORTANT: If you need the above, please disable modules in that order
##############################################################################
# INTERFACE HANDLERS
#
# We provide two interface handlers presently: ifconfig and iproute2.
# You need one of these to do any kind of network configuration.
# For ifconfig support, emerge sys-apps/net-tools
# For iproute2 support, emerge sys-apps/iproute2
# If you don't specify an interface then we prefer iproute2 if it's installed
# To prefer ifconfig over iproute2
modules=( "ifconfig" )
# For a static configuration, use something like this
# (They all do exactly the same thing btw)
config_eth0=( "192.168.0.2/24" )
config_eth0=( "192.168.0.2 netmask 255.255.255.0" )
# We can also specify a broadcast
config_eth0=( "192.168.0.2/24 brd 192.168.0.255" )
config_eth0=( "192.168.0.2 netmask 255.255.255.0 broadcast 192.168.0.255" )
# If you need more than one address, you can use something like this
# NOTE: ifconfig creates an aliased device for each extra IPv4 address
# (eth0:1, eth0:2, etc)
# iproute2 does not do this as there is no need to
config_eth0=(
"192.168.0.2/24"
"192.168.0.3/24"
"192.168.0.4/24"
)
# Or you can use sequence expressions
config_eth0=( "192.168.0.{2..4}/24" )
# which does the same as above. Be careful though as if you use this and
# fallbacks, you have to ensure that both end up with the same number of
# values otherwise your fallback won't work correctly.
# You can also use IPv6 addresses
# (you should always specify a prefix length with IPv6 here)
config_eth0=(
"192.168.0.2/24"
"4321:0:1:2:3:4:567:89ab/64"
"4321:0:1:2:3:4:567:89ac/64"
)
# If you wish to keep existing addresses + routing and the interface is up,
# you can specify a noop (no operation). If the interface is down or there
# are no addresses assigned, then we move onto the next step (default dhcp)
# This is useful when configuring your interface with a kernel command line
# or similar
config_eth0=( "noop" "192.168.0.2/24" )
# If you don't want ANY address (only useful when calling for advanced stuff)
config_eth0=( "null" )
# Here's how to do routing if you need it
routes_eth0=(
"default via 192.168.0.1" # IPv4 default route
"10.0.0.0/8 via 192.168.0.1" # IPv4 subnet route
"::/0" # IPv6 unicast
)
# If a specified module fails (like dhcp - see below), you can specify a
# fallback like so
fallback_eth0=( "192.168.0.2 netmask 255.255.255.0" )
fallback_route_eth0=( "default via 192.168.0.1" )
# NOTE: fallback entry must match the entry location in config_eth0
# As such you can only have one fallback route.
# Some users may need to alter the MTU - here's how
mtu_eth0="1500"
# Each module described below can set a default base metric, lower is
# preferred over higher. This is so we can prefer a wired route over a
# wireless route automaticaly. You can override this by setting
metric_eth0="100"
# or on a global basis
metric="100"
# The only downside of the global setting is that you have to ensure that
# there are no conflicting routes yourself. For users with large routing
# tables you may have to set a global metric as the due to a simple read of
# the routing table taking over a minute at a time.
##############################################################################
# OPTIONAL MODULES
# INTERFACE RENAMING
# There is no consistent device renaming scheme for Linux.
# The preferred way of naming devices is via the kernel module directly or
# by using udev (http://www.reactivated.net/udevrules.php)
# If you are unable to write udev rules, then we do provide a way of renaming
# the interface based on it's MAC address, but it is not optimal.
# Here is how to rename an interface whose MAC address is 00:11:22:33:44:55
# to foo1
rename_001122334455="foo1"
# You can also do this based on current device name - although this is not
# recommended. Here we rename eth1 to foo2.
rename_eth1="foo2"
#-----------------------------------------------------------------------------
# WIRELESS (802.11 support)
# Wireless can be provided by iwconfig or wpa_supplicant
# iwconfig
# emerge net-wireless/wireless-tools
# Wireless options are held in /etc/conf.d/wireless - but could be here too
# Consult the sample file /etc/conf.d/wireless.example for instructions
# iwconfig is the default
# wpa_supplicant
# emerge net-wireless/wpa-supplicant
# Wireless options are held in /etc/wpa_supplicant.conf
# Consult the sample file /etc/wpa_supplicant.conf.example for instructions
# To choose wpa_supplicant over iwconfig
modules=( "wpa_supplicant" )
# To configure wpa_supplicant
wpa_supplicant_eth0="-Dwext" # For generic wireless
wpa_supplicant_ath0="-Dmadwifi" # For Atheros based cards
# Consult wpa_supplicant for more drivers
# By default don't wait for wpa_suppliant to associate and authenticate.
# If you would like to, so can specify how long in seconds
associate_timeout_eth0=60
# A value of 0 means wait forever.
# GENERIC WIRELESS OPTIONS
# PLEASE READ THE INSTRUCTIONS IN /etc/conf.d/wireless.example FOR
# HOW TO USE THIS ESSID VARIABLE
# You can also override any settings found here per ESSID - which is very
# handy if you use different networks a lot
config_ESSID=( "dhcp" )
dhcpcd_ESSID="-t 5"
# Setting name/domain server causes /etc/resolv.conf to be overwritten
# Note that if DHCP is used, and you want this to take precedence then
set dhcp_ESSID="nodns"
dns_servers_ESSID=( "192.168.0.1" "192.168.0.2" )
dns_domain_ESSID="some.domain"
dns_search_ESSID="search.this.domain search.that.domain"
# Please check the man page for resolv.conf for more information
# as domain and search are mutually exclusive.
# You can also override any settings found here per MAC address of the AP
# in case you use Access Points with the same ESSID but need different
# networking configs. Below is an example - of course you use the same
# method with other variables
mac_config_001122334455=( "dhcp" )
mac_dhcpcd_001122334455="-t 10"
mac_dns_servers_001122334455=( "192.168.0.1" "192.168.0.2" )
# When an interface has been associated with an Access Point, a global
# variable called ESSID is set to the Access Point's ESSID for use in the
# pre/post user functions below (although it's not available in preup as you
# won't have associated then)
# If you're using anything else to configure wireless on your interface AND
# you have installed any of the above packages, you need to disable them
modules=( "!iwconfig" "!wpa_supplicant" )
#-----------------------------------------------------------------------------
# DHCP
# DHCP can be provided by dhclient, dhcpcd, pump or udhcpc.
#
# dhclient: emerge net-misc/dhcp
# dhcpcd: emerge net-misc/dhcpcd
# pump: emerge net-misc/pump
# udhcpc: emerge net-misc/udhcp
# If you have more than one DHCP client installed, you need to specify which
# one to use - otherwise we default to dhcpcd if available.
modules=( "dhclient" ) # to select dhclient over dhcpcd
#
# Notes:
# - All clients send the current hostname to the DHCP server by default
# - dhcpcd does not daemonize when the lease time is infinite
# - udhcp-0.9.3-r3 and earlier do not support getting NTP servers
# - pump does not support getting NIS servers
# - DHCP tends to erase any existing device information - so add
# static addresses after dhcp if you need them
# - dhclient and udhcpc can set other resolv.conf options such as "option"
# and "sortlist"- see the System module for more details
# Regardless of which DHCP client you prefer, you configure them the
# same way using one of following depending on which interface modules
# you're using.
config_eth0=( "dhcp" )
# For passing custom options to dhcpcd use something like the following. This
# example reduces the timeout for retrieving an address from 60 seconds (the
# default) to 10 seconds.
dhcpcd_eth0="-t 10"
# dhclient, udhcpc and pump don't have many runtime options
# You can pass options to them in a similar manner to dhcpcd though
dhclient_eth0="..."
udhcpc_eth0="..."
pump_eth0="..."
# GENERIC DHCP OPTIONS
# Set generic DHCP options like so
dhcp_eth0="release nodns nontp nonis nogateway nosendhost"
# This tells the dhcp client to release it's lease when it stops, not to
# overwrite dns, ntp and nis settings, not to set a default route and not to
# send the current hostname to the dhcp server and when it starts.
# You can use any combination of the above options - the default is not to
# use any of them.
#-----------------------------------------------------------------------------
# For APIPA support, emerge net-misc/iputils or net-analyzer/arping
# APIPA is a module that tries to find a free address in the range
# 169.254.0.0-169.254.255.255 by arping a random address in that range on the
# interface. If no reply is found then we assign that address to the interface
# This is only useful for LANs where there is no DHCP server and you don't
# connect directly to the internet.
config_eth0=( "dhcp" )
fallback_eth0=( "apipa" )
#-----------------------------------------------------------------------------
# ARPING Gateway configuration
# and
# Automatic Private IP Addressing (APIPA)
# For arpingnet / apipa support, emerge net-misc/iputils or net-analyzer/arping
#
# This is a module that tries to find a gateway IP. If it exists then we use
# that gateways configuration for our own. For the configuration variables
# simply ensure that each octet is zero padded and the dots are removed.
# Below is an example.
#
gateways_eth0="192.168.0.1 10.0.0.1"
config_192168000001=( "192.168.0.2/24" )
routes_192168000001=( "default via 192.168.0.1" )
dns_servers_192168000001=( "192.168.0.1" )
config_010000000001=( "10.0.0.254/8" )
routes_010000000001=( "default via 10.0.0.1" )
dns_servers_010000000001=( "10.0.0.1" )
# We can also specify a specific MAC address for each gateway if different
# networks have the same gateway.
gateways_eth0="192.168.0.1,00:11:22:AA:BB:CC 10.0.0.1,33:44:55:DD:EE:FF"
config_192168000001_001122AABBCC=( "192.168.0.2/24" )
routes_192168000001_001122AABBCC=( "default via 192.168.0.1" )
dns_servers_192168000001_001122AABBCC=( "192.168.0.1" )
config_010000000001_334455DDEEFF=( "10.0.0.254/8" )
routes_010000000001_334455DDEEFF=( "default via 10.0.0.1" )
dns_servers_010000000001_334455DDEEFF=( "10.0.0.1" )
# If we don't find any gateways (or there are none configured) then we try and
# use APIPA to find a free address in the range 169.254.0.0-169.254.255.255
# by arping a random address in that range on the interface. If no reply is
# found then we assign that address to the interface.
# This is only useful for LANs where there is no DHCP server.
config_eth0=( "arping" )
# or if no DHCP server can be found
config_eth0=( "dhcp" )
fallback_eth0=( "arping" )
# NOTE: We default to sleeping for 1 second the first time we attempt an
# arping to give the interface time to settle on the LAN. This appears to
# be a good default for most instances, but if not you can alter it here.
arping_sleep=5
arping_sleep_lan=7
# NOTE: We default to waiting 3 seconds to get an arping response. You can
# change the default wait like so.
arping_wait=3
arping_wait_lan=2
#-----------------------------------------------------------------------------
# VLAN (802.1q support)
# For VLAN support, emerge net-misc/vconfig
# Specify the VLAN numbers for the interface like so
# Please ensure your VLAN IDs are NOT zero-padded
vlans_eth0="1 2"
# You may not want to assign an IP the the physical interface, but we still
# need it up.
config_eth0=( "null" )
# You can also configure the VLAN - see for vconfig man page for more details
vconfig_eth0=( "set_name_type VLAN_PLUS_VID_NO_PAD" )
vconfig_vlan1=( "set_flag 1" "set_egress_map 2 6" )
config_vlan1=( "172.16.3.1 netmask 255.255.254.0" )
config_vlan2=( "172.16.2.1 netmask 255.255.254.0" )
# NOTE: Vlans can be configured with a . in their interface names
# When configuring vlans with this name type, you need to replace . with a _
config_eth0.1=( "dhcp" ) - does not work
config_eth0_1=( "dhcp" ) - does work
# NOTE: Vlans are controlled by their physical interface and not per vlan
# This means you do not need to create init scripts in /etc/init.d for each
# vlan, you must need to create one for the physical interface.
# If you wish to control the configuration of each vlan through a separate
# script, or wish to rename the vlan interface to something that vconfig
# cannot then you need to do this.
vlan_start_eth0="no"
# If you do the above then you may want to depend on eth0 like so
RC_NEED_vlan1="net.eth0"
# NOTE: depend functions only work in /etc/conf.d/net
# and not in profile configs such as /etc/conf.d/net.foo
#-----------------------------------------------------------------------------
# Bonding
# For link bonding/trunking emerge net-misc/ifenslave
# To bond interfaces together
slaves_bond0="eth0 eth1 eth2"
config_bond0=( "null" ) # You may not want to assign an IP the the bond
# If any of the slaves require extra configuration - for example wireless or
# ppp devices - we need to depend function on the bonded interfaces
RC_NEED_bond0="net.eth0 net.eth1"
#-----------------------------------------------------------------------------
# Classical IP over ATM
# For CLIP support emerge net-dialup/linux-atm
# Ensure that you have /etc/atmsigd.conf setup correctly
# Now setup each clip interface like so
clip_atm0=( "peer_ip [if.]vpi.vci [opts]" ... )
# where "peer_ip" is the IP address of a PVC peer (in case of an ATM connection
# with your ISP, your only peer is usually the ISP gateway closest to you),
# "if" is the number of the ATM interface which will carry the PVC, "vpi.vci"
# is the ATM VC address, and "opts" may optionally specify VC parameters like
# qos, pcr, and the like (see "atmarp -s" for further reference). Please also
# note quoting: it is meant to distinguish the VCs you want to create. You may,
# in example, create an atm0 interface to more peers, like this:
clip_atm0=( "1.1.1.254 0.8.35" "1.1.1.253 1.8.35" )
# By default, the PVC will use the LLC/SNAP encapsulation. If you rather need a
# null encapsulation (aka "VC mode"), please add the keyword "null" to opts.
#-----------------------------------------------------------------------------
# PPP
# For PPP support, emerge net-dialup/ppp
# PPP is used for most dialup connections, including ADSL.
# The older ADSL module is documented below, but you are encouraged to try
# this module first.
#
# You need to create the PPP net script yourself. Make it like so
#ln -s net.lo /etc/init.d/net.ppp0
#
# We have to instruct ppp0 to actually use ppp
config_ppp0=( "ppp" )
#
# Each PPP interface requires an interface to use as a "Link"
link_ppp0="/dev/ttyS0" # Most PPP links will use a serial port
link_ppp0="eth0" # PPPoE requires an ethernet interface
link_ppp0="[itf.]vpi.vci" # PPPoA requires the ATM VC's address
link_ppp0="/dev/null" # ISDN links should have this
link_ppp0="pty 'your_link_command'" # PPP links over ssh, rsh, etc
#
# Here you should specify what pppd plugins you want to use
# Available plugins are: pppoe, pppoa, capi, dhcpc, minconn, radius,
# radattr, radrealms and winbind
plugins_ppp0=(
"pppoe" # Required plugin for PPPoE
"pppoa vc-encaps" # Required plugin for PPPoA with an option
"capi" # Required plugin for ISDN
)
#
# PPP requires at least a username. You can optionally set a password here too
# If you don't, then it will use the password specified in /etc/ppp/*-secrets
# against the specified username
username_ppp0='user'
password_ppp0='password'
# NOTE: You can set a blank password like so
password_ppp0=
#
# The PPP daemon has many options you can specify - although there are many
# and may seem daunting, it is recommended that you read the pppd man page
# before enabling any of them
pppd_ppp0=(
"maxfail 0" # WARNING: It's not recommended you use this
# if you don't specify maxfail then we assume 0
"updetach" # If not set, "/etc/init.d/net.ppp0 start" will return
# immediately, without waiting the link to come up
# for the first time.
# Do not use it for dial-on-demand links!
"debug" # Enables syslog debugging
"noauth" # Do not require the peer to authenticate itself
"defaultroute" # Make this PPP interface the default route
"usepeerdns" # Use the DNS settings provided by PPP
# On demand options
"demand" # Enable dial on demand
"idle 30" # Link goes down after 30 seconds of inactivity
"10.112.112.112:10.112.112.113" # Phony IP addresses
"ipcp-accept-remote" # Accept the peers idea of remote address
"ipcp-accept-local" # Accept the peers idea of local address
"holdoff 3" # Wait 3 seconds after link dies before re-starting
# Dead peer detection
"lcp-echo-interval 15" # Send a LCP echo every 15 seconds
"lcp-echo-failure 3" # Make peer dead after 3 consective
# echo-requests
# Compression options - use these to completely disable compression
# noaccomp noccp nobsdcomp nodeflate nopcomp novj novjccomp
# Dial-up settings
"lock" # Lock serial port
"115200" # Set the serial port baud rate
"modem crtscts" # Enable hardware flow control
"192.168.0.1:192.168.0.2" # Local and remote IP addresses
)
#
# Dial-up PPP users need to specify at least one telephone number
phone_number_ppp0=( "12345689" ) # Maximum 2 phone numbers are supported
# They will also need a chat script - here's a good one
chat_ppp0=(
# 'ABORT' 'BUSY'
# 'ABORT' 'ERROR'
# 'ABORT' 'NO ANSWER'
# 'ABORT' 'NO CARRIER'
# 'ABORT' 'NO DIALTONE'
# 'ABORT' 'Invalid Login'
# 'ABORT' 'Login incorrect'
# 'TIMEOUT' '5'
# '' 'ATZ'
# 'OK' 'AT' # Put your modem initialization string here
# 'OK' 'ATDT\T'
# 'TIMEOUT' '60'
# 'CONNECT' ''
# 'TIMEOUT' '5'
# '~--' ''
)
# If the link require extra configuration - for example wireless or
# RFC 268 bridge - we need to depend on the bridge so they get
# configured correctly.
RC_NEED_ppp0="net.nas0"
#WARNING: if MTU of the PPP interface is less than 1500 and you use this
#machine as a router, you should add the following rule to your firewall
#
#iptables -I FORWARD 1 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
#-----------------------------------------------------------------------------
# ADSL
# For ADSL support, emerge net-dialup/rp-pppoe
# WARNING: This ADSL module is being deprecated in favour of the PPP module
# above.
# You should make the following settings and also put your
# username/password information in /etc/ppp/pap-secrets
# Configure the interface to use ADSL
config_eth0=( "adsl" )
# You probably won't need to edit /etc/ppp/pppoe.conf if you set this
adsl_user_eth0="my-adsl-username"
#-----------------------------------------------------------------------------
# ISDN
# For ISDN support, emerge net-dialup/isdn4k-utils
# You should make the following settings and also put your
# username/password information in /etc/ppp/pap-secrets
# Configure the interface to use ISDN
config_ippp0=( "dhcp" )
# It's important to specify dhcp if you need it!
config_ippp0=( "192.168.0.1/24" )
# Otherwise, you can use a static IP
# NOTE: The interface name must be either ippp or isdn followed by a number
# You may need this option to set the default route
ipppd_eth0="defaultroute"
#-----------------------------------------------------------------------------
# MAC changer
# To set a specific MAC address
mac_eth0="00:11:22:33:44:55"
# For changing MAC addresses using the below, emerge net-analyzer/macchanger
# - to randomize the last 3 bytes only
mac_eth0="random-ending"
# - to randomize between the same physical type of connection (e.g. fibre,
# copper, wireless) , all vendors
mac_eth0="random-samekind"
# - to randomize between any physical type of connection (e.g. fibre, copper,
# wireless) , all vendors
mac_eth0="random-anykind"
# - full randomization - WARNING: some MAC addresses generated by this may NOT
# act as expected
mac_eth0="random-full"
# custom - passes all parameters directly to net-analyzer/macchanger
mac_eth0="some custom set of parameters"
# You can also set other options based on the MAC address of your network card
# Handy if you use different docking stations with laptops
config_001122334455=( "dhcp" )
#-----------------------------------------------------------------------------
# TUN/TAP
# For TUN/TAP support emerge net-misc/openvpn or sys-apps/usermode-utilities
#
# You must specify if we're a tun or tap device. Then you can give it any
# name you like - such as vpn
tuntap_vpn="tun"
config_vpn=( "192.168.0.1/24")
# Or stick wit the generic names - like tap0
tuntap_tap0="tap"
config_tap0=( "192.168.0.1/24")
# For passing custom options to tunctl use something like the following. This
# example sets the owner to adm
tunctl_tun1="-u adm"
# When using openvpn, there are no options
#-----------------------------------------------------------------------------
# Bridging (802.1d)
# For bridging support emerge net-misc/bridge-utils
# To add ports to bridge br0
bridge_br0="eth0 eth1"
# or dynamically add them when the interface comes up
bridge_add_eth0="br0"
bridge_add_eth1="br0"
# You need to configure the ports to null values so dhcp does not get started
config_eth0=( "null" )
config_eth1=( "null" )
# Finally give the bridge an address - dhcp or a static IP
config_br0=( "dhcp" ) # may not work when adding ports dynamically
config_br0=( "192.168.0.1/24" )
# If any of the ports require extra configuration - for example wireless or
# ppp devices - we need to depend on them like so.
RC_NEED_br0="net.eth0 net.eth1"
# Below is an example of configuring the bridge
# Consult "man brctl" for more details
brctl_br0=( "setfd 0" "sethello 0" "stp off" )
#-----------------------------------------------------------------------------
# RFC 2684 Bridge Support
# For RFC 2684 bridge support emerge net-misc/br2684ctl
# Interface names have to be of the form nas0, nas1, nas2, etc.
# You have to specify a VPI and VCI for the interface like so
br2684ctl_nas0="-a 0.38" # UK VPI and VCI
# You may want to configure the encapsulation method as well by adding the -e
# option to the command above (may need to be before the -a command)
# -e 0 # LLC (default)
# -e 1 # VC mux
# Then you can configure the interface as normal
config_nas0=( "192.168.0.1/24" )
#-----------------------------------------------------------------------------
# Tunnelling
# WARNING: For tunnelling it is highly recommended that you
# emerge sys-apps/iproute2
#
# For GRE tunnels
iptunnel_vpn0="mode gre remote 207.170.82.1 key 0xffffffff ttl 255"
# For IPIP tunnels
iptunnel_vpn0="mode ipip remote 207.170.82.2 ttl 255"
# To configure the interface
config_vpn0=( "192.168.0.2 pointopoint 192.168.1.2" ) # ifconfig style
config_vpn0=( "192.168.0.2 peer 192.168.1.1" ) # iproute2 style
# 6to4 Tunnels allow IPv6 to work over IPv4 addresses, provided you
# have a non-private address configured on an interface.
link_6to4="eth0" # Interface to base it's addresses on
config_6to4=( "ip6to4" )
# You may want to depend on eth0 like so
RC_NEED_6to4="net.eth0"
# To ensure that eth0 is configured before 6to4. Of course, the tunnel could be
# any name and this also works for any configured interface.
# NOTE: If you're not using iproute2 then your 6to4 tunnel has to be called
# sit0 - otherwise use a different name like 6to4 in the example above.
#-----------------------------------------------------------------------------
# System
# For configuring system specifics such as domain, dns, ntp and nis servers
# It's rare that you would need todo this, but you can anyway.
# This is most benefit to wireless users who don't use DHCP so they can change
# their configs based on ESSID. See wireless.example for more details
# To use dns settings such as these, dns_servers_eth0 must be set!
# If you omit the _eth0 suffix, then it applies to all interfaces unless
# overridden by the interface suffix.
dns_domain_eth0="your.domain"
dns_servers_eth0="192.168.0.2 192.168.0.3"
dns_search_eth0="this.domain that.domain"
dns_options_eth0=( "timeout 1" "rotate" )
dns_sortlist_eth0="130.155.160.0/255.255.240.0 130.155.0.0"
# See the man page for resolv.conf for details about the options and sortlist
# directives
ntp_servers_eth0="192.168.0.2 192.168.0.3"
nis_domain_eth0="domain"
nis_servers_eth0="192.168.0.2 192.168.0.3"
# NOTE: Setting any of these will stamp on the files in question. So if you
# don't specify dns_servers but you do specify dns_domain then no nameservers
# will be listed in /etc/resolv.conf even if there were any there to start
# with.
# If this is an issue for you then maybe you should look into a resolv.conf
# manager like resolvconf-gentoo to manage this file for you. All packages
# that baselayout supports use resolvconf-gentoo if installed.
#-----------------------------------------------------------------------------
# Cable in/out detection
# Sometimes the cable is in, others it's out. Obviously you don't want to
# restart net.eth0 every time when you plug it in either.
#
# netplug is a package that detects this and requires no extra configuration
# on your part.
# emerge sys-apps/netplug
# or
# emerge sys-apps/ifplugd
# and you're done :)
# By default we don't wait for netplug/ifplugd to configure the interface.
# If you would like it to wait so that other services now that network is up
# then you can specify a timeout here.
plug_timeout="10"
# A value of 0 means wait forever.
# If you don't want to use netplug on a specific interface but you have it
# installed, you can disable it for that interface via the modules statement
modules_eth0=( "!netplug" )
# You can do the same for ifplugd
#
# You can disable them both with the generic plug
modules_eth0=( "!plug" )
# To use specific ifplugd options, fex specifying wireless mode
ifplugd_eth0="--api-mode=wlan"
# man ifplugd for more options
##############################################################################
# ADVANCED CONFIGURATION
#
# Four functions can be defined which will be called surrounding the
# start/stop operations. The functions are called with the interface
# name first so that one function can control multiple adapters. An extra two
# functions can be defined when an interface fails to start or stop.
#
# The return values for the preup and predown functions should be 0
# (success) to indicate that configuration or deconfiguration of the
# interface can continue. If preup returns a non-zero value, then
# interface configuration will be aborted. If predown returns a
# non-zero value, then the interface will not be allowed to continue
# deconfiguration.
#
# The return values for the postup, postdown, failup and faildown functions are
# ignored since there's nothing to do if they indicate failure.
#
# ${IFACE} is set to the interface being brought up/down
# ${IFVAR} is ${IFACE} converted to variable name bash allows
#preup() {
# # Test for link on the interface prior to bringing it up. This
# # only works on some network adapters and requires the mii-diag
# # package to be installed.
# if mii-tool "${IFACE}" 2> /dev/null | grep -q 'no link'; then
# ewarn "No link on ${IFACE}, aborting configuration"
# return 1
# fi
#
# # Test for link on the interface prior to bringing it up. This
# # only works on some network adapters and requires the ethtool
# # package to be installed.
# if ethtool "${IFACE}" | grep -q 'Link detected: no'; then
# ewarn "No link on ${IFACE}, aborting configuration"
# return 1
# fi
#
#
# # Remember to return 0 on success
# return 0
#}
#predown() {
# # The default in the script is to test for NFS root and disallow
# # downing interfaces in that case. Note that if you specify a
# # predown() function you will override that logic. Here it is, in
# # case you still want it...
# if is_net_fs /; then
# eerror "root filesystem is network mounted -- can't stop ${IFACE}"
# return 1
# fi
#
# # Remember to return 0 on success
# return 0
#}
#postup() {
# # This function could be used, for example, to register with a
# # dynamic DNS service. Another possibility would be to
# # send/receive mail once the interface is brought up.
# # Here is an example that allows the use of iproute rules
# # which have been configured using the rules_eth0 variable.
# #rules_eth0=(
# # "from 24.80.102.112/32 to 192.168.1.0/24 table localnet priority 100"
# # "from 216.113.223.51/32 to 192.168.1.0/24 table localnet priority 100"
# #)
# local x="rules_${IFVAR}[@]"
# local -a rules=( "${!x}" )
# if [[ -n ${rules} ]] ; then
# einfo "Adding IP policy routing rules"
# eindent
# # Ensure that the kernel supports policy routing
# if ! ip rule list | grep -q "^" ; then
# eerror "You need to enable IP Policy Routing (CONFIG_IP_MULTIPLE_TABLES)"
# eerror "in your kernel to use ip rules"
# else
# for x in "${rules[@]}" ; do
# ebegin "${x}"
# ip rule add ${x} dev "${IFACE}"
# eend $?
# done
# fi
# eoutdent
# # Flush the cache
# ip route flush cache dev "${IFACE}"
# fi
#}
#postdown() {
# # Enable Wake-On-LAN for every interface except for lo
# # Probably a good idea to set RC_DOWN_INTERFACE="no" in /etc/conf.d/rc
# # as well ;)
# [[ ${IFACE} != "lo" ]] && ethtool -s "${IFACE}" wol g
# Automatically erase any ip rules created in the example postup above
# if interface_exists "${IFACE}" ; then
# # Remove any rules for this interface
# local rule
# ip rule list | grep " iif ${IFACE}[ ]*" | {
# while read rule ; do
# rule="${rule#*:}"
# ip rule del ${rule}
# done
# }
# # Flush the route cache
# ip route flush cache dev "${IFACE}"
# fi
# # Return 0 always
# return 0
#}
#failup() {
# # This function is mostly here for completeness... I haven't
# # thought of anything nifty to do with it yet ;-)
#}
#faildown() {
# # This function is mostly here for completeness... I haven't
# # thought of anything nifty to do with it yet ;-)
#}
##############################################################################
# FORCING MODULES
# The Big Fat Warning :- If you use module forcing do not complain to us or
# file bugs about it not working!
#
# Loading modules is a slow affair - we have to check each one for the following
# 1) Code sanity
# 2) Has the required package been emerged?
# 3) Has it modified anything?
# 4) Have all the dependant modules been loaded?
# Then we have to strip out the conflicting modules based on user preference
# and default configuration and sort them into the correct order.
# Finally we check the end result for dependencies.
# This, of course, takes valuable CPU time so we provide module forcing as a
# means to speed things up. We still do *some* checking but not much.
# It is essential that you force modules in the correct order and supply all
# the modules you need. You must always supply an interface module - we
# supply ifconfig or iproute2.
# The Big Fat Warning :- If you use module forcing do not complain to us or
# file bugs about it not working!
# Now that we've warned you twice, here's how to do it
modules_force=( "ifconfig" )
modules_force=( "iproute2" "dhcpcd" )
# We can also apply this to a specific interface
modules_force_eth1=( "iproute2" )
# The below will not work
modules_force=( "dhcpcd" )
# No interface (ifconfig/iproute2)
modules_force=( "ifconfig" "essidnet" "iwconfig" )
# Although it will not crash, essidnet will not work as it has to come after
# iwconfig
modules_force=( "iproute2" "ifconfig" )
# The interface will be setup twice which will cause problems

View file

@ -0,0 +1,5 @@
[main]
plugins=ifnet,keyfile
[ifnet]
managed=false

View file

@ -0,0 +1,379 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager system settings service (ifnet)
*
* Mu Qiao <qiaomuf@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 1999-2010 Gentoo Foundation, Inc.
*/
#include <stdio.h>
#include <string.h>
#include <glib.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <nm-utils.h>
#include "net_parser.h"
#include "nm-test-helpers.h"
#include "net_utils.h"
#include "wpa_parser.h"
#include "connection_parser.h"
static void
test_getdata ()
{
ASSERT (ifnet_get_data ("eth1", "config")
&& strcmp (ifnet_get_data ("eth1", "config"), "dhcp") == 0,
"get data", "config_eth1 is not correct");
ASSERT (ifnet_get_data ("ppp0", "username")
&& strcmp (ifnet_get_data ("ppp0", "username"), "user") == 0,
"get data", "config_ppp0 username is not correctly read");
ASSERT (ifnet_get_data ("ppp0", "password")
&& strcmp (ifnet_get_data ("ppp0", "password"),
"password") == 0, "get data",
"config_ppp0 password is not correctly read");
}
static void
test_read_hostname ()
{
gchar *hostname = read_hostname ("hostname");
ASSERT (hostname != NULL, "get hostname", "hostname is NULL");
ASSERT (strcmp ("gentoo", hostname) == 0,
"get hostname",
"hostname is not correctly read, read:%s, expected: gentoo",
hostname);
}
static void
test_write_hostname ()
{
gchar *hostname = read_hostname ("hostname");
write_hostname ("gentoo-nm", "hostname");
ASSERT (strcmp (read_hostname ("hostname"), "gentoo-nm") == 0,
"write hostname", "write hostname error");
write_hostname (hostname, "hostname");
}
static void
test_is_static ()
{
ASSERT (is_static_ip4 ("eth1") == FALSE, "is static",
"a dhcp interface is recognized as static");
ASSERT (is_static_ip4 ("eth0") == TRUE, "is static",
"a static interface is recognized as dhcp");
ASSERT (!is_static_ip6 ("eth0") == TRUE, "is static",
"a static interface is recognized as dhcp");
}
static void
test_has_default_route ()
{
ASSERT (has_default_ip4_route ("eth0"), "has default route",
"eth0 should have a default ipv4 route");
ASSERT (has_default_ip6_route ("eth4"), "has default route",
"eth4 should have a default ipv6 route");
ASSERT (!has_default_ip4_route ("eth5")
&& !has_default_ip6_route ("eth5"), "has default route",
"eth5 shouldn't have a default route");
}
static void
test_has_ip6_address ()
{
ASSERT (has_ip6_address ("eth2"), "has ip6 address",
"eth2 should have a ipv6 address");
ASSERT (!has_ip6_address ("eth0"), "has ip6 address",
"eth0 shouldn't have a ipv6 address")
}
static void
test_is_ip4_address ()
{
gchar *address1 = "192.168.4.232/24";
gchar *address2 = "192.168.100.{1..254}/24";
gchar *address3 = "192.168.4.2555/24";
ASSERT (is_ip4_address (address1), "is ip4 address",
"%s should be a valid address", address1);
ASSERT (is_ip4_address (address2), "is ip4 address",
"%s should be a valid address", address2);
ASSERT (!is_ip4_address (address3), "is ip4 address",
"%s should be an invalid address", address3);
}
static void
test_is_ip6_address ()
{
gchar *address1 = "4321:0:1:2:3:4:567:89ac/24";
ASSERT (is_ip6_address (address1), "is ip6 address",
"%s should be a valid address", address1);
}
static void
check_ip_block (ip_block * iblock, gchar * ip, gchar * netmask, gchar * gateway)
{
char *str;
struct in_addr tmp_ip4_addr;
str = malloc (INET_ADDRSTRLEN);
tmp_ip4_addr.s_addr = iblock->ip;
inet_ntop (AF_INET, &tmp_ip4_addr, str, INET_ADDRSTRLEN);
ASSERT (strcmp (ip, str) == 0, "check ip", "ip expected:%s, find:%s",
ip, str);
tmp_ip4_addr.s_addr = iblock->netmask;
inet_ntop (AF_INET, &tmp_ip4_addr, str, INET_ADDRSTRLEN);
ASSERT (strcmp (netmask, str) == 0, "check netmask",
"netmask expected:%s, find:%s", netmask, str);
tmp_ip4_addr.s_addr = iblock->gateway;
inet_ntop (AF_INET, &tmp_ip4_addr, str, INET_ADDRSTRLEN);
ASSERT (strcmp (gateway, str) == 0, "check gateway",
"gateway expected:%s, find:%s", gateway, str);
free (str);
}
static void
test_convert_ipv4_config_block ()
{
ip_block *iblock = convert_ip4_config_block ("eth0");
ip_block *tmp = iblock;
ASSERT (iblock != NULL, "convert ipv4 block",
"block eth0 should not be NULL");
check_ip_block (iblock, "202.117.16.121", "255.255.255.0",
"202.117.16.1");
iblock = iblock->next;
destroy_ip_block (tmp);
ASSERT (iblock != NULL, "convert ipv4 block",
"block eth0 should have a second IP address");
check_ip_block (iblock, "192.168.4.121", "255.255.255.0",
"202.117.16.1");
destroy_ip_block (iblock);
iblock = convert_ip4_config_block ("eth2");
ASSERT (iblock != NULL
&& iblock->next == NULL, "convert error IPv4 address",
"should only get one address");
check_ip_block (iblock, "192.168.4.121", "255.255.255.0", "0.0.0.0");
destroy_ip_block (iblock);
iblock = convert_ip4_config_block ("eth3");
ASSERT (iblock == NULL, "convert config_block",
"convert error configuration");
destroy_ip_block (iblock);
iblock = convert_ip4_config_block ("eth6");
ASSERT (iblock != NULL, "convert config_block",
"convert error configuration");
destroy_ip_block (iblock);
}
static void
test_convert_ipv4_routes_block ()
{
ip_block *iblock = convert_ip4_routes_block ("eth0");
ip_block *tmp = iblock;
ASSERT (iblock != NULL, "convert ip4 routes", "should get one route");
check_ip_block (iblock, "192.168.4.0", "255.255.255.0", "192.168.4.1");
iblock = iblock->next;
destroy_ip_block (tmp);
ASSERT (iblock == NULL, "convert ip4 routes",
"should only get one route");
}
static void
test_wpa_parser ()
{
gchar *value;
ASSERT (exist_ssid ("example"), "get wsec",
"ssid myxjtu2 is not found");
ASSERT (exist_ssid ("static-wep-test"), "exist_ssid",
"ssid static-wep-test is not found");
value = wpa_get_value ("static-wep-test", "key_mgmt");
ASSERT (value && strcmp (value, "NONE") == 0, "get wpa data",
"key_mgmt of static-wep-test should be NONE, find %s", value);
value = wpa_get_value ("static-wep-test", "wep_key0");
ASSERT (value && strcmp (value, "\"abcde\"") == 0, "get wpa data",
"wep_key0 of static-wep-test should be abcde, find %s", value);
ASSERT (exist_ssid ("leap-example"), "get wsec",
"ssid leap-example is not found");
}
static void
test_strip_string ()
{
gchar *str = "( \"default via 202.117.16.1\" )";
gchar *result = g_strdup (str);
gchar *result_b = result;
result = strip_string (result, '(');
result = strip_string (result, ')');
result = strip_string (result, '"');
ASSERT (strcmp (result, "default via 202.117.16.1") == 0,
"strip_string", "string isn't stripped, result is: %s", result);
g_free (result_b);
}
static void
test_is_unmanaged ()
{
ASSERT (is_managed ("eth0"), "test_is_unmanaged",
"eth0 should be managed");
ASSERT (!is_managed ("eth4"), "test_is_unmanaged",
"eth4 should be unmanaged");
}
static void
test_new_connection ()
{
GError **error = NULL;
NMConnection *connection;
connection = ifnet_update_connection_from_config_block ("eth2", error);
ASSERT (connection != NULL, "new connection",
"new connection failed: %s",
error == NULL ? "None" : (*error)->message);
g_object_unref (connection);
connection =
ifnet_update_connection_from_config_block ("qiaomuf", error);
ASSERT (connection != NULL, "new connection",
"new connection failed: %s", error
&& (*error) ? (*error)->message : "NONE");
g_object_unref (connection);
connection =
ifnet_update_connection_from_config_block ("myxjtu2", error);
ASSERT (connection != NULL, "new connection",
"new connection failed: %s", error
&& (*error) ? (*error)->message : "NONE");
g_object_unref (connection);
}
static void
test_update_connection ()
{
GError **error = NULL;
NMConnection *connection;
connection = ifnet_update_connection_from_config_block ("eth0", error);
ASSERT (connection != NULL, "get connection",
"get connection failed: %s",
error == NULL ? "None" : (*error)->message);
ASSERT (ifnet_update_parsers_by_connection
(connection, "eth0", NULL, "net.generate",
"wpa_supplicant.conf.generate", error), "update connection",
"update connection failed %s", "eth0");
connection =
ifnet_update_connection_from_config_block ("0xab3ace", error);
ASSERT (connection != NULL, "get connection",
"get connection failed: %s",
error == NULL ? "None" : (*error)->message);
ASSERT (ifnet_update_parsers_by_connection
(connection, "0xab3ace", NULL, "net.generate",
"wpa_supplicant.conf.generate", error), "update connection",
"update connection failed %s", "0xab3ace");
}
static void
test_add_connection ()
{
GError **error = NULL;
NMConnection *connection;
connection = ifnet_update_connection_from_config_block ("eth0", error);
ASSERT (ifnet_add_new_connection
(connection, "net.generate", "wpa_supplicant.conf.generate",
error), "add connection", "add connection failed: %s", "eth0");
connection =
ifnet_update_connection_from_config_block ("myxjtu2", error);
ASSERT (ifnet_add_new_connection
(connection, "net.generate", "wpa_supplicant.conf.generate",
error), "add connection", "add connection failed: %s",
"myxjtu2");
}
static void
test_delete_connection ()
{
GError **error = NULL;
NMConnection *connection;
connection = ifnet_update_connection_from_config_block ("eth7", error);
ASSERT (connection != NULL, "get connection",
"get connection failed: %s",
error == NULL ? "None" : (*error)->message);
ASSERT (ifnet_delete_connection_in_parsers
("eth7", "net.generate", "wpa_supplicant.conf.generate"),
"delete connection", "delete connection failed: %s", "eth7");
connection =
ifnet_update_connection_from_config_block ("qiaomuf", error);
ASSERT (connection != NULL, "get connection",
"get connection failed: %s",
error == NULL ? "None" : (*error)->message);
ASSERT (ifnet_delete_connection_in_parsers
("qiaomuf", "net.generate", "wpa_supplicant.conf.generate"),
"delete connection", "delete connection failed: %s", "qiaomuf");
}
static void
run_all (gboolean run)
{
if (run) {
test_strip_string ();
test_is_static ();
test_has_ip6_address ();
test_has_default_route ();
test_getdata ();
test_read_hostname ();
test_write_hostname ();
test_is_ip4_address ();
test_is_ip6_address ();
test_convert_ipv4_config_block ();
test_convert_ipv4_routes_block ();
test_is_unmanaged ();
test_wpa_parser ();
test_convert_ipv4_routes_block ();
test_new_connection ();
test_update_connection ();
test_add_connection ();
test_delete_connection ();
}
}
int
main (void)
{
// g_mem_set_vtable(glib_mem_profiler_table);
// g_atexit(g_mem_profile);
g_type_init ();
ifnet_destroy ();
wpa_parser_destroy ();
ifnet_init ("net");
wpa_parser_init ("wpa_supplicant.conf");
printf("Initialization complete\n");
run_all (TRUE);
ifnet_destroy ();
wpa_parser_destroy ();
return 0;
}

View file

@ -0,0 +1,876 @@
##### Example wpa_supplicant configuration file ###############################
#
# This file describes configuration file format and lists all available option.
# Please also take a look at simpler configuration examples in 'examples'
# subdirectory.
#
# Empty lines and lines starting with # are ignored
# NOTE! This file may contain password information and should probably be made
# readable only by root user on multiuser systems.
# Note: All file paths in this configuration file should use full (absolute,
# not relative to working directory) path in order to allow working directory
# to be changed. This can happen if wpa_supplicant is run in the background.
# Whether to allow wpa_supplicant to update (overwrite) configuration
#
# This option can be used to allow wpa_supplicant to overwrite configuration
# file whenever configuration is changed (e.g., new network block is added with
# wpa_cli or wpa_gui, or a password is changed). This is required for
# wpa_cli/wpa_gui to be able to store the configuration changes permanently.
# Please note that overwriting configuration file will remove the comments from
# it.
#update_config=1
# global configuration (shared by all network blocks)
#
# Parameters for the control interface. If this is specified, wpa_supplicant
# will open a control interface that is available for external programs to
# manage wpa_supplicant. The meaning of this string depends on which control
# interface mechanism is used. For all cases, the existance of this parameter
# in configuration is used to determine whether the control interface is
# enabled.
#
# For UNIX domain sockets (default on Linux and BSD): This is a directory that
# will be created for UNIX domain sockets for listening to requests from
# external programs (CLI/GUI, etc.) for status information and configuration.
# The socket file will be named based on the interface name, so multiple
# wpa_supplicant processes can be run at the same time if more than one
# interface is used.
# /var/run/wpa_supplicant is the recommended directory for sockets and by
# default, wpa_cli will use it when trying to connect with wpa_supplicant.
#
# Access control for the control interface can be configured by setting the
# directory to allow only members of a group to use sockets. This way, it is
# possible to run wpa_supplicant as root (since it needs to change network
# configuration and open raw sockets) and still allow GUI/CLI components to be
# run as non-root users. However, since the control interface can be used to
# change the network configuration, this access needs to be protected in many
# cases. By default, wpa_supplicant is configured to use gid 0 (root). If you
# want to allow non-root users to use the control interface, add a new group
# and change this value to match with that group. Add users that should have
# control interface access to this group. If this variable is commented out or
# not included in the configuration file, group will not be changed from the
# value it got by default when the directory or socket was created.
#
# When configuring both the directory and group, use following format:
# DIR=/var/run/wpa_supplicant GROUP=wheel
# DIR=/var/run/wpa_supplicant GROUP=0
# (group can be either group name or gid)
#
# For UDP connections (default on Windows): The value will be ignored. This
# variable is just used to select that the control interface is to be created.
# The value can be set to, e.g., udp (ctrl_interface=udp)
#
# For Windows Named Pipe: This value can be used to set the security descriptor
# for controlling access to the control interface. Security descriptor can be
# set using Security Descriptor String Format (see http://msdn.microsoft.com/
# library/default.asp?url=/library/en-us/secauthz/security/
# security_descriptor_string_format.asp). The descriptor string needs to be
# prefixed with SDDL=. For example, ctrl_interface=SDDL=D: would set an empty
# DACL (which will reject all connections). See README-Windows.txt for more
# information about SDDL string format.
#
ctrl_interface=/var/run/wpa_supplicant
# IEEE 802.1X/EAPOL version
# wpa_supplicant is implemented based on IEEE Std 802.1X-2004 which defines
# EAPOL version 2. However, there are many APs that do not handle the new
# version number correctly (they seem to drop the frames completely). In order
# to make wpa_supplicant interoperate with these APs, the version number is set
# to 1 by default. This configuration value can be used to set it to the new
# version (2).
eapol_version=1
# AP scanning/selection
# By default, wpa_supplicant requests driver to perform AP scanning and then
# uses the scan results to select a suitable AP. Another alternative is to
# allow the driver to take care of AP scanning and selection and use
# wpa_supplicant just to process EAPOL frames based on IEEE 802.11 association
# information from the driver.
# 1: wpa_supplicant initiates scanning and AP selection
# 0: driver takes care of scanning, AP selection, and IEEE 802.11 association
# parameters (e.g., WPA IE generation); this mode can also be used with
# non-WPA drivers when using IEEE 802.1X mode; do not try to associate with
# APs (i.e., external program needs to control association). This mode must
# also be used when using wired Ethernet drivers.
# 2: like 0, but associate with APs using security policy and SSID (but not
# BSSID); this can be used, e.g., with ndiswrapper and NDIS drivers to
# enable operation with hidden SSIDs and optimized roaming; in this mode,
# the network blocks in the configuration file are tried one by one until
# the driver reports successful association; each network block should have
# explicit security policy (i.e., only one option in the lists) for
# key_mgmt, pairwise, group, proto variables
ap_scan=1
# EAP fast re-authentication
# By default, fast re-authentication is enabled for all EAP methods that
# support it. This variable can be used to disable fast re-authentication.
# Normally, there is no need to disable this.
fast_reauth=1
# OpenSSL Engine support
# These options can be used to load OpenSSL engines.
# The two engines that are supported currently are shown below:
# They are both from the opensc project (http://www.opensc.org/)
# By default no engines are loaded.
# make the opensc engine available
#opensc_engine_path=/usr/lib64/engine_opensc.so
# make the pkcs11 engine available
#pkcs11_engine_path=/usr/lib64/engine_pkcs11.so
# configure the path to the pkcs11 module required by the pkcs11 engine
#pkcs11_module_path=/usr/lib64/opensc-pkcs11.so
# Dynamic EAP methods
# If EAP methods were built dynamically as shared object files, they need to be
# loaded here before being used in the network blocks. By default, EAP methods
# are included statically in the build, so these lines are not needed
#load_dynamic_eap=/usr/lib/wpa_supplicant/eap_tls.so
#load_dynamic_eap=/usr/lib/wpa_supplicant/eap_md5.so
# Driver interface parameters
# This field can be used to configure arbitrary driver interace parameters. The
# format is specific to the selected driver interface. This field is not used
# in most cases.
#driver_param="field=value"
# Country code
# The ISO/IEC alpha2 country code for the country in which this device is
# currently operating.
#country=US
# Maximum lifetime for PMKSA in seconds; default 43200
#dot11RSNAConfigPMKLifetime=43200
# Threshold for reauthentication (percentage of PMK lifetime); default 70
#dot11RSNAConfigPMKReauthThreshold=70
# Timeout for security association negotiation in seconds; default 60
#dot11RSNAConfigSATimeout=60
# Wi-Fi Protected Setup (WPS) parameters
# Universally Unique IDentifier (UUID; see RFC 4122) of the device
# If not configured, UUID will be generated based on the local MAC address.
#uuid=12345678-9abc-def0-1234-56789abcdef0
# Device Name
# User-friendly description of device; up to 32 octets encoded in UTF-8
#device_name=Wireless Client
# Manufacturer
# The manufacturer of the device (up to 64 ASCII characters)
#manufacturer=Company
# Model Name
# Model of the device (up to 32 ASCII characters)
#model_name=cmodel
# Model Number
# Additional device description (up to 32 ASCII characters)
#model_number=123
# Serial Number
# Serial number of the device (up to 32 characters)
#serial_number=12345
# Primary Device Type
# Used format: <categ>-<OUI>-<subcateg>
# categ = Category as an integer value
# OUI = OUI and type octet as a 4-octet hex-encoded value; 0050F204 for
# default WPS OUI
# subcateg = OUI-specific Sub Category as an integer value
# Examples:
# 1-0050F204-1 (Computer / PC)
# 1-0050F204-2 (Computer / Server)
# 5-0050F204-1 (Storage / NAS)
# 6-0050F204-1 (Network Infrastructure / AP)
#device_type=1-0050F204-1
# OS Version
# 4-octet operating system version number (hex string)
#os_version=01020300
# Credential processing
# 0 = process received credentials internally (default)
# 1 = do not process received credentials; just pass them over ctrl_iface to
# external program(s)
# 2 = process received credentials internally and pass them over ctrl_iface
# to external program(s)
#wps_cred_processing=0
# network block
#
# Each network (usually AP's sharing the same SSID) is configured as a separate
# block in this configuration file. The network blocks are in preference order
# (the first match is used).
#
# network block fields:
#
# disabled:
# 0 = this network can be used (default)
# 1 = this network block is disabled (can be enabled through ctrl_iface,
# e.g., with wpa_cli or wpa_gui)
#
# id_str: Network identifier string for external scripts. This value is passed
# to external action script through wpa_cli as WPA_ID_STR environment
# variable to make it easier to do network specific configuration.
#
# ssid: SSID (mandatory); either as an ASCII string with double quotation or
# as hex string; network name
#
# scan_ssid:
# 0 = do not scan this SSID with specific Probe Request frames (default)
# 1 = scan with SSID-specific Probe Request frames (this can be used to
# find APs that do not accept broadcast SSID or use multiple SSIDs;
# this will add latency to scanning, so enable this only when needed)
#
# bssid: BSSID (optional); if set, this network block is used only when
# associating with the AP using the configured BSSID
#
# priority: priority group (integer)
# By default, all networks will get same priority group (0). If some of the
# networks are more desirable, this field can be used to change the order in
# which wpa_supplicant goes through the networks when selecting a BSS. The
# priority groups will be iterated in decreasing priority (i.e., the larger the
# priority value, the sooner the network is matched against the scan results).
# Within each priority group, networks will be selected based on security
# policy, signal strength, etc.
# Please note that AP scanning with scan_ssid=1 and ap_scan=2 mode are not
# using this priority to select the order for scanning. Instead, they try the
# networks in the order that used in the configuration file.
#
# mode: IEEE 802.11 operation mode
# 0 = infrastructure (Managed) mode, i.e., associate with an AP (default)
# 1 = IBSS (ad-hoc, peer-to-peer)
# Note: IBSS can only be used with key_mgmt NONE (plaintext and static WEP)
# and key_mgmt=WPA-NONE (fixed group key TKIP/CCMP). In addition, ap_scan has
# to be set to 2 for IBSS. WPA-None requires following network block options:
# proto=WPA, key_mgmt=WPA-NONE, pairwise=NONE, group=TKIP (or CCMP, but not
# both), and psk must also be set.
#
# frequency: Channel frequency in megahertz (MHz) for IBSS, e.g.,
# 2412 = IEEE 802.11b/g channel 1. This value is used to configure the initial
# channel for IBSS (adhoc) networks. It is ignored in the infrastructure mode.
# In addition, this value is only used by the station that creates the IBSS. If
# an IBSS network with the configured SSID is already present, the frequency of
# the network will be used instead of this configured value.
#
# proto: list of accepted protocols
# WPA = WPA/IEEE 802.11i/D3.0
# RSN = WPA2/IEEE 802.11i (also WPA2 can be used as an alias for RSN)
# If not set, this defaults to: WPA RSN
#
# key_mgmt: list of accepted authenticated key management protocols
# WPA-PSK = WPA pre-shared key (this requires 'psk' field)
# WPA-EAP = WPA using EAP authentication
# IEEE8021X = IEEE 802.1X using EAP authentication and (optionally) dynamically
# generated WEP keys
# NONE = WPA is not used; plaintext or static WEP could be used
# WPA-PSK-SHA256 = Like WPA-PSK but using stronger SHA256-based algorithms
# WPA-EAP-SHA256 = Like WPA-EAP but using stronger SHA256-based algorithms
# If not set, this defaults to: WPA-PSK WPA-EAP
#
# auth_alg: list of allowed IEEE 802.11 authentication algorithms
# OPEN = Open System authentication (required for WPA/WPA2)
# SHARED = Shared Key authentication (requires static WEP keys)
# LEAP = LEAP/Network EAP (only used with LEAP)
# If not set, automatic selection is used (Open System with LEAP enabled if
# LEAP is allowed as one of the EAP methods).
#
# pairwise: list of accepted pairwise (unicast) ciphers for WPA
# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0]
# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0]
# NONE = Use only Group Keys (deprecated, should not be included if APs support
# pairwise keys)
# If not set, this defaults to: CCMP TKIP
#
# group: list of accepted group (broadcast/multicast) ciphers for WPA
# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0]
# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0]
# WEP104 = WEP (Wired Equivalent Privacy) with 104-bit key
# WEP40 = WEP (Wired Equivalent Privacy) with 40-bit key [IEEE 802.11]
# If not set, this defaults to: CCMP TKIP WEP104 WEP40
#
# psk: WPA preshared key; 256-bit pre-shared key
# The key used in WPA-PSK mode can be entered either as 64 hex-digits, i.e.,
# 32 bytes or as an ASCII passphrase (in which case, the real PSK will be
# generated using the passphrase and SSID). ASCII passphrase must be between
# 8 and 63 characters (inclusive).
# This field is not needed, if WPA-EAP is used.
# Note: Separate tool, wpa_passphrase, can be used to generate 256-bit keys
# from ASCII passphrase. This process uses lot of CPU and wpa_supplicant
# startup and reconfiguration time can be optimized by generating the PSK only
# only when the passphrase or SSID has actually changed.
#
# eapol_flags: IEEE 802.1X/EAPOL options (bit field)
# Dynamic WEP key required for non-WPA mode
# bit0 (1): require dynamically generated unicast WEP key
# bit1 (2): require dynamically generated broadcast WEP key
# (3 = require both keys; default)
# Note: When using wired authentication, eapol_flags must be set to 0 for the
# authentication to be completed successfully.
#
# mixed_cell: This option can be used to configure whether so called mixed
# cells, i.e., networks that use both plaintext and encryption in the same
# SSID, are allowed when selecting a BSS form scan results.
# 0 = disabled (default)
# 1 = enabled
#
# proactive_key_caching:
# Enable/disable opportunistic PMKSA caching for WPA2.
# 0 = disabled (default)
# 1 = enabled
#
# wep_key0..3: Static WEP key (ASCII in double quotation, e.g. "abcde" or
# hex without quotation, e.g., 0102030405)
# wep_tx_keyidx: Default WEP key index (TX) (0..3)
#
# peerkey: Whether PeerKey negotiation for direct links (IEEE 802.11e DLS) is
# allowed. This is only used with RSN/WPA2.
# 0 = disabled (default)
# 1 = enabled
#peerkey=1
#
# wpa_ptk_rekey: Maximum lifetime for PTK in seconds. This can be used to
# enforce rekeying of PTK to mitigate some attacks against TKIP deficiencies.
#
# Following fields are only used with internal EAP implementation.
# eap: space-separated list of accepted EAP methods
# MD5 = EAP-MD5 (unsecure and does not generate keying material ->
# cannot be used with WPA; to be used as a Phase 2 method
# with EAP-PEAP or EAP-TTLS)
# MSCHAPV2 = EAP-MSCHAPv2 (cannot be used separately with WPA; to be used
# as a Phase 2 method with EAP-PEAP or EAP-TTLS)
# OTP = EAP-OTP (cannot be used separately with WPA; to be used
# as a Phase 2 method with EAP-PEAP or EAP-TTLS)
# GTC = EAP-GTC (cannot be used separately with WPA; to be used
# as a Phase 2 method with EAP-PEAP or EAP-TTLS)
# TLS = EAP-TLS (client and server certificate)
# PEAP = EAP-PEAP (with tunnelled EAP authentication)
# TTLS = EAP-TTLS (with tunnelled EAP or PAP/CHAP/MSCHAP/MSCHAPV2
# authentication)
# If not set, all compiled in methods are allowed.
#
# identity: Identity string for EAP
# This field is also used to configure user NAI for
# EAP-PSK/PAX/SAKE/GPSK.
# anonymous_identity: Anonymous identity string for EAP (to be used as the
# unencrypted identity with EAP types that support different tunnelled
# identity, e.g., EAP-TTLS)
# password: Password string for EAP. This field can include either the
# plaintext password (using ASCII or hex string) or a NtPasswordHash
# (16-byte MD4 hash of password) in hash:<32 hex digits> format.
# NtPasswordHash can only be used when the password is for MSCHAPv2 or
# MSCHAP (EAP-MSCHAPv2, EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP).
# EAP-PSK (128-bit PSK), EAP-PAX (128-bit PSK), and EAP-SAKE (256-bit
# PSK) is also configured using this field. For EAP-GPSK, this is a
# variable length PSK.
# ca_cert: File path to CA certificate file (PEM/DER). This file can have one
# or more trusted CA certificates. If ca_cert and ca_path are not
# included, server certificate will not be verified. This is insecure and
# a trusted CA certificate should always be configured when using
# EAP-TLS/TTLS/PEAP. Full path should be used since working directory may
# change when wpa_supplicant is run in the background.
# On Windows, trusted CA certificates can be loaded from the system
# certificate store by setting this to cert_store://<name>, e.g.,
# ca_cert="cert_store://CA" or ca_cert="cert_store://ROOT".
# Note that when running wpa_supplicant as an application, the user
# certificate store (My user account) is used, whereas computer store
# (Computer account) is used when running wpasvc as a service.
# ca_path: Directory path for CA certificate files (PEM). This path may
# contain multiple CA certificates in OpenSSL format. Common use for this
# is to point to system trusted CA list which is often installed into
# directory like /etc/ssl/certs. If configured, these certificates are
# added to the list of trusted CAs. ca_cert may also be included in that
# case, but it is not required.
# client_cert: File path to client certificate file (PEM/DER)
# Full path should be used since working directory may change when
# wpa_supplicant is run in the background.
# Alternatively, a named configuration blob can be used by setting this
# to blob://<blob name>.
# private_key: File path to client private key file (PEM/DER/PFX)
# When PKCS#12/PFX file (.p12/.pfx) is used, client_cert should be
# commented out. Both the private key and certificate will be read from
# the PKCS#12 file in this case. Full path should be used since working
# directory may change when wpa_supplicant is run in the background.
# Windows certificate store can be used by leaving client_cert out and
# configuring private_key in one of the following formats:
# cert://substring_to_match
# hash://certificate_thumbprint_in_hex
# for example: private_key="hash://63093aa9c47f56ae88334c7b65a4"
# Note that when running wpa_supplicant as an application, the user
# certificate store (My user account) is used, whereas computer store
# (Computer account) is used when running wpasvc as a service.
# Alternatively, a named configuration blob can be used by setting this
# to blob://<blob name>.
# private_key_passwd: Password for private key file (if left out, this will be
# asked through control interface)
# dh_file: File path to DH/DSA parameters file (in PEM format)
# This is an optional configuration file for setting parameters for an
# ephemeral DH key exchange. In most cases, the default RSA
# authentication does not use this configuration. However, it is possible
# setup RSA to use ephemeral DH key exchange. In addition, ciphers with
# DSA keys always use ephemeral DH keys. This can be used to achieve
# forward secrecy. If the file is in DSA parameters format, it will be
# automatically converted into DH params.
# subject_match: Substring to be matched against the subject of the
# authentication server certificate. If this string is set, the server
# sertificate is only accepted if it contains this string in the subject.
# The subject string is in following format:
# /C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as@example.com
# altsubject_match: Semicolon separated string of entries to be matched against
# the alternative subject name of the authentication server certificate.
# If this string is set, the server sertificate is only accepted if it
# contains one of the entries in an alternative subject name extension.
# altSubjectName string is in following format: TYPE:VALUE
# Example: EMAIL:server@example.com
# Example: DNS:server.example.com;DNS:server2.example.com
# Following types are supported: EMAIL, DNS, URI
# phase1: Phase1 (outer authentication, i.e., TLS tunnel) parameters
# (string with field-value pairs, e.g., "peapver=0" or
# "peapver=1 peaplabel=1")
# 'peapver' can be used to force which PEAP version (0 or 1) is used.
# 'peaplabel=1' can be used to force new label, "client PEAP encryption",
# to be used during key derivation when PEAPv1 or newer. Most existing
# PEAPv1 implementation seem to be using the old label, "client EAP
# encryption", and wpa_supplicant is now using that as the default value.
# Some servers, e.g., Radiator, may require peaplabel=1 configuration to
# interoperate with PEAPv1; see eap_testing.txt for more details.
# 'peap_outer_success=0' can be used to terminate PEAP authentication on
# tunneled EAP-Success. This is required with some RADIUS servers that
# implement draft-josefsson-pppext-eap-tls-eap-05.txt (e.g.,
# Lucent NavisRadius v4.4.0 with PEAP in "IETF Draft 5" mode)
# include_tls_length=1 can be used to force wpa_supplicant to include
# TLS Message Length field in all TLS messages even if they are not
# fragmented.
# sim_min_num_chal=3 can be used to configure EAP-SIM to require three
# challenges (by default, it accepts 2 or 3)
# result_ind=1 can be used to enable EAP-SIM and EAP-AKA to use
# protected result indication.
# 'crypto_binding' option can be used to control PEAPv0 cryptobinding
# behavior:
# * 0 = do not use cryptobinding (default)
# * 1 = use cryptobinding if server supports it
# * 2 = require cryptobinding
# EAP-WSC (WPS) uses following options: pin=<Device Password> or
# pbc=1.
# phase2: Phase2 (inner authentication with TLS tunnel) parameters
# (string with field-value pairs, e.g., "auth=MSCHAPV2" for EAP-PEAP or
# "autheap=MSCHAPV2 autheap=MD5" for EAP-TTLS)
# Following certificate/private key fields are used in inner Phase2
# authentication when using EAP-TTLS or EAP-PEAP.
# ca_cert2: File path to CA certificate file. This file can have one or more
# trusted CA certificates. If ca_cert2 and ca_path2 are not included,
# server certificate will not be verified. This is insecure and a trusted
# CA certificate should always be configured.
# ca_path2: Directory path for CA certificate files (PEM)
# client_cert2: File path to client certificate file
# private_key2: File path to client private key file
# private_key2_passwd: Password for private key file
# dh_file2: File path to DH/DSA parameters file (in PEM format)
# subject_match2: Substring to be matched against the subject of the
# authentication server certificate.
# altsubject_match2: Substring to be matched against the alternative subject
# name of the authentication server certificate.
#
# fragment_size: Maximum EAP fragment size in bytes (default 1398).
# This value limits the fragment size for EAP methods that support
# fragmentation (e.g., EAP-TLS and EAP-PEAP). This value should be set
# small enough to make the EAP messages fit in MTU of the network
# interface used for EAPOL. The default value is suitable for most
# cases.
#
# EAP-FAST variables:
# pac_file: File path for the PAC entries. wpa_supplicant will need to be able
# to create this file and write updates to it when PAC is being
# provisioned or refreshed. Full path to the file should be used since
# working directory may change when wpa_supplicant is run in the
# background. Alternatively, a named configuration blob can be used by
# setting this to blob://<blob name>
# phase1: fast_provisioning option can be used to enable in-line provisioning
# of EAP-FAST credentials (PAC):
# 0 = disabled,
# 1 = allow unauthenticated provisioning,
# 2 = allow authenticated provisioning,
# 3 = allow both unauthenticated and authenticated provisioning
# fast_max_pac_list_len=<num> option can be used to set the maximum
# number of PAC entries to store in a PAC list (default: 10)
# fast_pac_format=binary option can be used to select binary format for
# storing PAC entries in order to save some space (the default
# text format uses about 2.5 times the size of minimal binary
# format)
#
# wpa_supplicant supports number of "EAP workarounds" to work around
# interoperability issues with incorrectly behaving authentication servers.
# These are enabled by default because some of the issues are present in large
# number of authentication servers. Strict EAP conformance mode can be
# configured by disabling workarounds with eap_workaround=0.
# Example blocks:
# Simple case: WPA-PSK, PSK as an ASCII passphrase, allow all valid ciphers
network={
ssid="simple"
psk="very secret passphrase"
priority=5
}
# Same as previous, but request SSID-specific scanning (for APs that reject
# broadcast SSID)
network={
ssid="second ssid"
scan_ssid=1
psk="very secret passphrase"
priority=2
}
# Only WPA-PSK is used. Any valid cipher combination is accepted.
network={
ssid="example"
proto=WPA
key_mgmt=WPA-PSK
pairwise=CCMP TKIP
group=CCMP TKIP WEP104 WEP40
psk=06b4be19da289f475aa46a33cb793029d4ab3db7a23ee92382eb0106c72ac7bb
priority=2
}
# WPA-Personal(PSK) with TKIP and enforcement for frequent PTK rekeying
network={
ssid="example"
proto=WPA
key_mgmt=WPA-PSK
pairwise=TKIP
group=TKIP
psk="not so secure passphrase"
wpa_ptk_rekey=600
}
# Only WPA-EAP is used. Both CCMP and TKIP is accepted. An AP that used WEP104
# or WEP40 as the group cipher will not be accepted.
network={
ssid="example"
proto=RSN
key_mgmt=WPA-EAP
pairwise=CCMP TKIP
group=CCMP TKIP
eap=TLS
identity="user@example.com"
ca_cert="/etc/cert/ca.pem"
client_cert="/etc/cert/user.pem"
private_key="/etc/cert/user.prv"
private_key_passwd="password"
priority=1
}
# EAP-PEAP/MSCHAPv2 configuration for RADIUS servers that use the new peaplabel
# (e.g., Radiator)
network={
ssid="example"
key_mgmt=WPA-EAP
eap=PEAP
identity="user@example.com"
password="foobar"
ca_cert="/etc/cert/ca.pem"
phase1="peaplabel=1"
phase2="auth=MSCHAPV2"
priority=10
}
# EAP-TTLS/EAP-MD5-Challenge configuration with anonymous identity for the
# unencrypted use. Real identity is sent only within an encrypted TLS tunnel.
network={
ssid="example"
key_mgmt=WPA-EAP
eap=TTLS
identity="user@example.com"
anonymous_identity="anonymous@example.com"
password="foobar"
ca_cert="/etc/cert/ca.pem"
priority=2
}
# EAP-TTLS/MSCHAPv2 configuration with anonymous identity for the unencrypted
# use. Real identity is sent only within an encrypted TLS tunnel.
network={
ssid="example"
key_mgmt=WPA-EAP
eap=TTLS
identity="user@example.com"
anonymous_identity="anonymous@example.com"
password="foobar"
ca_cert="/etc/cert/ca.pem"
phase2="auth=MSCHAPV2"
}
# WPA-EAP, EAP-TTLS with different CA certificate used for outer and inner
# authentication.
network={
ssid="example"
key_mgmt=WPA-EAP
eap=TTLS
# Phase1 / outer authentication
anonymous_identity="anonymous@example.com"
ca_cert="/etc/cert/ca.pem"
# Phase 2 / inner authentication
phase2="autheap=TLS"
ca_cert2="/etc/cert/ca2.pem"
client_cert2="/etc/cer/user.pem"
private_key2="/etc/cer/user.prv"
private_key2_passwd="password"
priority=2
}
# Both WPA-PSK and WPA-EAP is accepted. Only CCMP is accepted as pairwise and
# group cipher.
network={
ssid="example"
bssid=00:11:22:33:44:55
proto=WPA RSN
key_mgmt=WPA-PSK WPA-EAP
pairwise=CCMP
group=CCMP
psk=06b4be19da289f475aa46a33cb793029d4ab3db7a23ee92382eb0106c72ac7bb
}
# Special characters in SSID, so use hex string. Default to WPA-PSK, WPA-EAP
# and all valid ciphers.
network={
ssid=00010203
psk=000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
}
# EAP-SIM with a GSM SIM or USIM
network={
ssid="eap-sim-test"
key_mgmt=WPA-EAP
eap=SIM
pin="1234"
pcsc=""
}
# EAP-PSK
network={
ssid="eap-psk-test"
key_mgmt=WPA-EAP
eap=PSK
anonymous_identity="eap_psk_user"
password=06b4be19da289f475aa46a33cb793029
identity="eap_psk_user@example.com"
}
# IEEE 802.1X/EAPOL with dynamically generated WEP keys (i.e., no WPA) using
# EAP-TLS for authentication and key generation; require both unicast and
# broadcast WEP keys.
network={
ssid="1xtest"
key_mgmt=IEEE8021X
eap=TLS
identity="user@example.com"
ca_cert="/etc/cert/ca.pem"
client_cert="/etc/cert/user.pem"
private_key="/etc/cert/user.prv"
private_key_passwd="password"
eapol_flags=3
}
# LEAP with dynamic WEP keys
network={
ssid="leap-example"
key_mgmt=IEEE8021X
eap=LEAP
identity="user"
password="foobar"
}
# EAP-IKEv2 using shared secrets for both server and peer authentication
network={
ssid="ikev2-example"
key_mgmt=WPA-EAP
eap=IKEV2
identity="user"
password="foobar"
}
# EAP-FAST with WPA (WPA or WPA2)
network={
ssid="eap-fast-test"
key_mgmt=WPA-EAP
eap=FAST
anonymous_identity="FAST-000102030405"
identity="username"
password="password"
phase1="fast_provisioning=1"
pac_file="/etc/wpa_supplicant.eap-fast-pac"
}
network={
ssid="eap-fast-test"
key_mgmt=WPA-EAP
eap=FAST
anonymous_identity="FAST-000102030405"
identity="username"
password="password"
phase1="fast_provisioning=1"
pac_file="blob://eap-fast-pac"
}
# Plaintext connection (no WPA, no IEEE 802.1X)
network={
ssid="plaintext-test"
key_mgmt=NONE
}
# Shared WEP key connection (no WPA, no IEEE 802.1X)
network={
ssid="static-wep-test"
key_mgmt=NONE
wep_key0="abcde"
wep_key1=0102030405
wep_key2="1234567890123"
wep_tx_keyidx=0
priority=5
}
# Shared WEP key connection (no WPA, no IEEE 802.1X) using Shared Key
# IEEE 802.11 authentication
network={
ssid="static-wep-test2"
key_mgmt=NONE
wep_key0="abcde"
wep_key1=0102030405
wep_key2="1234567890123"
wep_tx_keyidx=0
priority=5
auth_alg=SHARED
}
# IBSS/ad-hoc network with WPA-None/TKIP.
network={
ssid="test adhoc"
mode=1
frequency=2412
proto=WPA
key_mgmt=WPA-NONE
pairwise=NONE
group=TKIP
psk="secret passphrase"
}
# Catch all example that allows more or less all configuration modes
network={
ssid="example"
scan_ssid=1
key_mgmt=WPA-EAP WPA-PSK IEEE8021X NONE
pairwise=CCMP TKIP
group=CCMP TKIP WEP104 WEP40
psk="very secret passphrase"
eap=TTLS PEAP TLS
identity="user@example.com"
password="foobar"
ca_cert="/etc/cert/ca.pem"
client_cert="/etc/cert/user.pem"
private_key="/etc/cert/user.prv"
private_key_passwd="password"
phase1="peaplabel=0"
}
# Example of EAP-TLS with smartcard (openssl engine)
network={
ssid="example"
key_mgmt=WPA-EAP
eap=TLS
proto=RSN
pairwise=CCMP TKIP
group=CCMP TKIP
identity="user@example.com"
ca_cert="/etc/cert/ca.pem"
client_cert="/etc/cert/user.pem"
engine=1
# The engine configured here must be available. Look at
# OpenSSL engine support in the global section.
# The key available through the engine must be the private key
# matching the client certificate configured above.
# use the opensc engine
#engine_id="opensc"
#key_id="45"
# use the pkcs11 engine
engine_id="pkcs11"
key_id="id_45"
# Optional PIN configuration; this can be left out and PIN will be
# asked through the control interface
pin="1234"
}
# Example configuration showing how to use an inlined blob as a CA certificate
# data instead of using external file
network={
ssid="example"
key_mgmt=WPA-EAP
eap=TTLS
identity="user@example.com"
anonymous_identity="anonymous@example.com"
password="foobar"
ca_cert="blob://exampleblob"
priority=20
}
blob-base64-exampleblob={
SGVsbG8gV29ybGQhCg==
}
# Wildcard match for SSID (plaintext APs only). This example select any
# open AP regardless of its SSID.
network={
key_mgmt=NONE
}
network={
ssid="qiaomuf"
key_mgmt=WPA-EAP
eap=TLS
identity="user@example.com"
ca_cert="/home/gentoo/temp/ca.pem"
client_cert="/home/gentoo/temp/client.pem"
private_key="/home/gentoo/temp/client.p12"
private_key_passwd="whatever"
# phase2="auth=MSCHAPV2"
priority=10
}
network={
ssid="myxjtu2"
scan_ssid=1
key_mgmt=WPA-PSK
psk="xjtudlc3731"
disabled=0
key_mgmt=NONE
wep_key0="12345"
wep_key1=1234567890
wep_key2="zxcvb"
wep_tx_keyidx=1
auth_alg=OPEN
mode=1
}
network={
ssid=ab3ace
key_mgmt=WPA-EAP
eap=TTLS
identity="user@example.com"
anonymous_identity="anonymous@example.com"
password="foobar"
ca_cert="blob://exampleblob"
priority=20
}

View file

@ -0,0 +1,558 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
* Mu Qiao <qiaomuf@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 1999-2010 Gentoo Foundation, Inc.
*/
#include <string.h>
#include <stdlib.h>
#include <nm-system-config-interface.h>
#include "wpa_parser.h"
#include "net_parser.h"
#include "net_utils.h"
/* Security information */
static GHashTable *wsec_table = NULL;
/* Global information used for writing */
static GHashTable *wsec_global_table = NULL;
static gboolean wpa_parser_data_changed = FALSE;
static long
wpa_get_long (GHashTable * table, gchar * key)
{
return atol (g_hash_table_lookup (table, key));
}
static void
destroy_security (GHashTable * network)
{
gpointer key, value;
GHashTableIter iter;
g_return_if_fail (network);
g_hash_table_iter_init (&iter, network);
while (g_hash_table_iter_next (&iter, &key, &value)) {
g_free (key);
g_free (value);
}
g_hash_table_destroy (network);
}
static GHashTable *
add_security (GHashTable * security)
{
GHashTable *oldsecurity;
gchar *ssid = g_hash_table_lookup (security, "ssid"), *ssid_key;
gchar *value;
gboolean is_hex_ssid;
/* Every security information should have a ssid */
if (!ssid) {
destroy_security (security);
return NULL;
}
/* Hex format begins with " */
is_hex_ssid = (ssid[0] != '"');
if ((value = g_hash_table_lookup (security, "disabled")) != NULL) {
if (strcmp (value, "1") == 0)
return NULL;
}
/* Default priority is 1 */
if (g_hash_table_lookup (security, "priority") == NULL)
g_hash_table_insert (security, g_strdup ("priority"),
g_strdup ("1"));
oldsecurity = g_hash_table_lookup (wsec_table, ssid);
/* Security with lower priority will be ignored */
if (oldsecurity != NULL) {
if (wpa_get_long (oldsecurity, "priority") >=
wpa_get_long (security, "priority")) {
destroy_security (security);
return NULL;
} else {
g_hash_table_remove (wsec_table, ssid);
destroy_security (oldsecurity);
}
}
/* format ssid */
ssid_key =
is_hex_ssid ? g_strdup_printf ("0x%s",
ssid) :
strip_string (g_strdup (ssid), '"');
g_hash_table_insert (wsec_table, ssid_key, security);
return security;
}
static void
add_key_value (GHashTable * network, gchar * line)
{
gchar **key_value;
if (g_str_has_prefix (line, "network={"))
line += 9;
strip_string (line, '{');
strip_string (line, '}');
if (line[0] == '\0')
return;
key_value = g_strsplit (line, "=", 2);
if (g_strv_length (key_value) != 2) {
g_strfreev (key_value);
return;
}
g_strstrip (key_value[0]);
g_strstrip (key_value[1]);
/* Reserve quotes for psk, wep_key, ssid
* Quotes will determine whether they are hex format */
if (strcmp (key_value[0], "psk") != 0
&& !g_str_has_prefix (key_value[0], "wep_key")
&& strcmp (key_value[0], "ssid") != 0)
strip_string (key_value[1], '"');
g_hash_table_insert (network, g_strdup (key_value[0]),
g_strdup (key_value[1]));
g_strfreev (key_value);
}
static void
add_one_wep_key (GHashTable * table, int key_num, gchar * one_wep_key)
{
if (one_wep_key[0] == 's') {
//asc key
g_hash_table_insert (table,
g_strdup_printf ("wep_key%d", key_num - 1),
g_strdup_printf ("\"%s\"",
one_wep_key + 2));
} else {
gchar buf[30];
int i = 0, j = 0;
//hex key
while (one_wep_key[i] != '\0') {
if (one_wep_key[i] != '-')
buf[j++] = one_wep_key[i];
i++;
}
buf[j] = '\0';
g_hash_table_insert (table,
g_strdup_printf ("wep_key%d", key_num - 1),
g_strdup (buf));
}
}
/* Reading wep security information from /etc/conf.d/net.
* This should not be used in futre, use wpa_supplicant instead. */
static void
add_keys_from_net ()
{
GList *names = ifnet_get_connection_names ();
GList *iter = names;
gchar *wep_keys = "(\\[([1-4])\\]\\s+(s:\\w{5}|s:\\w{13}|"
"([\\da-fA-F]{4}\\-){2}[\\da-fA-F]{2}|"
"([\\da-fA-F]{4}\\-){6}[\\da-fA-F]{2})\\s+)";
gchar *key_method =
"\\s+key\\s+\\[([1-4])\\]\\s+enc\\s+(open|restricted)";
GRegex *regex_keys = g_regex_new (wep_keys, 0, 0, NULL);
GRegex *regex_method = g_regex_new (key_method, 0, 0, NULL);
GMatchInfo *keys_info;
GMatchInfo *method_info;
while (iter) {
gchar *conn_name = iter->data;
GHashTable *table;
gchar *key_str;
if ((key_str = ifnet_get_data (conn_name, "key")) == NULL) {
iter = g_list_next (iter);
continue;
}
wpa_add_security (conn_name);
table = _get_hash_table (conn_name);
/* Give lowest priority */
wpa_set_data (conn_name, "priority", "0");
g_regex_match (regex_keys, key_str, 0, &keys_info);
/* add wep keys */
while (g_match_info_matches (keys_info)) {
gchar *key_num = g_match_info_fetch (keys_info, 2);
gchar *one_wep_key = g_match_info_fetch (keys_info, 3);
add_one_wep_key (table, atoi (key_num), one_wep_key);
g_free (key_num);
g_free (one_wep_key);
g_match_info_next (keys_info, NULL);
}
g_match_info_free (keys_info);
g_regex_match (regex_method, key_str, 0, &method_info);
/* set default key index and auth alg */
if (g_match_info_matches (method_info)) {
gchar *default_idx =
g_match_info_fetch (method_info, 1);
gchar *method = g_match_info_fetch (method_info, 2);
default_idx[0]--;
g_hash_table_insert (table, g_strdup ("wep_tx_keyidx"),
default_idx);
g_hash_table_insert (table, g_strdup ("auth_alg"),
g_ascii_strup (method, -1));
}
g_match_info_free (method_info);
add_security (table);
iter = g_list_next (iter);
}
g_list_free (names);
g_regex_unref (regex_keys);
g_regex_unref (regex_method);
}
static void
add_global_data (gchar * line)
{
gchar **key_value;
g_strstrip (line);
key_value = g_strsplit (line, "=", 2);
if (g_strv_length (key_value) != 2) {
PLUGIN_WARN (IFNET_PLUGIN_NAME, "Can't handle this line: %s\n",
line);
g_strfreev (key_value);
return;
}
g_hash_table_insert (wsec_global_table,
g_strdup (g_strstrip (key_value[0])),
g_strdup (g_strstrip (key_value[1])));
g_strfreev (key_value);
}
void
wpa_parser_init (gchar * wpa_supplicant_conf)
{
GIOChannel *channel = NULL;
gchar *line;
gboolean complete = FALSE;
wpa_parser_data_changed = FALSE;
wsec_table = g_hash_table_new (g_str_hash, g_str_equal);
wsec_global_table = g_hash_table_new (g_str_hash, g_str_equal);
if (g_file_test (wpa_supplicant_conf, G_FILE_TEST_IS_REGULAR))
channel =
g_io_channel_new_file (wpa_supplicant_conf, "r", NULL);
if (channel == NULL) {
PLUGIN_WARN (IFNET_PLUGIN_NAME,
"Can't open %s for wireless security",
wpa_supplicant_conf);
return;
}
while (g_io_channel_read_line (channel, &line, NULL, NULL, NULL)
!= G_IO_STATUS_EOF) {
g_strstrip (line);
if (line[0] != '#' && line[0] != '\0') {
if (strstr (line, "network={") == NULL) {
add_global_data (line);
g_free (line);
continue;
} else {
GHashTable *network =
g_hash_table_new (g_str_hash, g_str_equal);
gchar *tmp;
do {
if (line[0] == '#' || line[0] == '\0') {
g_free (line);
continue;
}
/* ignore inline comments */
if ((tmp = strchr (line, '#')) != NULL)
*tmp = '\0';
if (strstr (line, "}") != NULL)
complete = TRUE;
add_key_value (network, line);
g_free (line);
} while (complete == FALSE
&&
g_io_channel_read_line
(channel, &line, NULL,
NULL, NULL) != G_IO_STATUS_EOF);
add_security (network);
//EOF in inner loop
if (complete == FALSE) {
g_free (line);
break;
}
complete = FALSE;
}
} else
g_free (line);
}
g_io_channel_shutdown (channel, FALSE, NULL);
g_io_channel_unref (channel);
add_keys_from_net ();
}
gchar *
wpa_get_value (gchar * ssid, gchar * key)
{
GHashTable *target = g_hash_table_lookup (wsec_table, ssid);
if (target)
return g_hash_table_lookup (target, key);
return NULL;
}
gboolean
exist_ssid (gchar * ssid)
{
return g_hash_table_lookup (wsec_table, ssid) != NULL;
}
GHashTable *
_get_hash_table (gchar * ssid)
{
return g_hash_table_lookup (wsec_table, ssid);
}
static gchar *quoted_keys[] =
{ "identity", "cert", "private", "phase", "password", NULL };
/* tell whether the key needs quotes when writing is performed */
static gboolean
need_quote (gchar * key)
{
int i = 0;
while (quoted_keys[i] != NULL) {
if (strstr (key, quoted_keys[i]))
return TRUE;
i++;
}
return FALSE;
}
gboolean
wpa_flush_to_file (gchar * config_file)
{
GIOChannel *channel;
GError **error = NULL;
gpointer key, value, ssid, security;
GHashTableIter iter, iter_security;
gchar *out_line;
gsize bytes_written;
gboolean result = FALSE;
if (!wpa_parser_data_changed)
return FALSE;
if (!wsec_table || !wsec_global_table)
return FALSE;
channel = g_io_channel_new_file (config_file, "w", NULL);
if (!channel) {
PLUGIN_WARN (IFNET_PLUGIN_NAME,
"Can't open file %s for writing", config_file);
return FALSE;
}
g_hash_table_iter_init (&iter, wsec_global_table);
PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Writing to %s", config_file);
g_io_channel_write_chars (channel,
"#Generated by NetworkManager\n"
"###### Global Configuration ######\n",
-1, &bytes_written, error);
/* Writing global information */
while (g_hash_table_iter_next (&iter, &key, &value)) {
out_line =
g_strdup_printf ("%s=%s\n", (gchar *) key, (gchar *) value);
g_io_channel_write_chars (channel, out_line, -1, &bytes_written,
error);
if (bytes_written == 0 || (error && *error))
break;
g_free (out_line);
}
if (error && *error) {
PLUGIN_WARN (IFNET_PLUGIN_NAME, "Found error: %s",
(*error)->message);
goto done;
}
g_io_channel_write_chars (channel,
"\n###### Security Configuration ######\n",
-1, &bytes_written, error);
g_hash_table_iter_init (&iter, wsec_table);
/* Writing security */
while (g_hash_table_iter_next (&iter, &ssid, &security)) {
g_hash_table_iter_init (&iter_security,
(GHashTable *) security);
g_io_channel_write_chars (channel, "network={\n", -1,
&bytes_written, error);
while (g_hash_table_iter_next (&iter_security, &key, &value)) {
out_line =
g_strdup_printf (need_quote ((gchar *) key) ?
"\t%s=\"%s\"\n" : "\t%s=%s\n",
(gchar *) key, (gchar *) value);
g_io_channel_write_chars (channel, out_line, -1,
&bytes_written, error);
if (bytes_written == 0 || (error && *error))
break;
g_free (out_line);
}
g_io_channel_write_chars (channel,
"}\n\n", -1, &bytes_written, error);
}
if (error && *error) {
PLUGIN_WARN (IFNET_PLUGIN_NAME, "Found error: %s",
(*error)->message);
goto done;
}
g_io_channel_flush (channel, error);
if (error && *error) {
PLUGIN_WARN (IFNET_PLUGIN_NAME, "Found error: %s",
(*error)->message);
goto done;
}
wpa_parser_data_changed = FALSE;
result = TRUE;
done:
g_io_channel_shutdown (channel, FALSE, NULL);
g_io_channel_unref (channel);
return result;
}
/* If value is NULL, this method will delete old key value pair */
void
wpa_set_data (gchar * ssid, gchar * key, gchar * value)
{
gpointer orig_key = NULL, orig_value = NULL;
GHashTable *security = g_hash_table_lookup (wsec_table, ssid);
g_return_if_fail (security != NULL);
/* Remove old key value pairs */
if (g_hash_table_lookup_extended
(security, key, &orig_key, &orig_value)) {
g_hash_table_remove (security, orig_key);
g_free (orig_key);
g_free (orig_value);
}
/* Add new key value */
if (value) {
gchar *new_value = g_strdup (value);
if (strcmp (key, "ssid") != 0 && strcmp (key, "psk") != 0
&& !g_str_has_prefix (key, "wep_key"))
strip_string (new_value, '"');
g_hash_table_insert (security, g_strdup (key), new_value);
}
wpa_parser_data_changed = TRUE;
}
gboolean
wpa_has_security (gchar * ssid)
{
return g_hash_table_lookup (wsec_table, ssid) != NULL;
}
gboolean
wpa_add_security (gchar * ssid)
{
if (wpa_has_security (ssid))
return FALSE;
else {
GHashTable *security =
g_hash_table_new (g_str_hash, g_str_equal);
gchar *ssid_i;
PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Adding security for %s",
ssid);
if (g_str_has_prefix (ssid, "0x")) {
/* hex ssid */
ssid_i = g_strdup (ssid + 2);
} else {
/* ascii ssid requires quotes */
ssid_i = g_strdup_printf ("\"%s\"", ssid);
}
g_hash_table_insert (security, strdup ("ssid"), ssid_i);
g_hash_table_insert (security, strdup ("priority"),
strdup ("1"));
g_hash_table_insert (wsec_table, g_strdup (ssid), security);
wpa_parser_data_changed = TRUE;
return TRUE;
}
}
gboolean
wpa_delete_security (gchar * ssid)
{
gpointer orig_key, orig_value;
g_return_val_if_fail (wsec_table != NULL && ssid != NULL, FALSE);
PLUGIN_PRINT (IFNET_PLUGIN_NAME, "Deleting security for %s", ssid);
if (!g_hash_table_lookup_extended
(wsec_table, ssid, &orig_key, &orig_value))
return FALSE;
g_hash_table_remove (wsec_table, orig_key);
g_free (orig_key);
destroy_security ((GHashTable *) orig_value);
wpa_parser_data_changed = TRUE;
return TRUE;
}
void
wpa_parser_destroy (void)
{
GHashTableIter iter;
gpointer key;
gpointer value;
/* Destroy security */
if (wsec_table) {
g_hash_table_iter_init (&iter, wsec_table);
while (g_hash_table_iter_next (&iter, &key, &value)) {
destroy_security ((GHashTable *) value);
g_free (key);
}
g_hash_table_destroy (wsec_table);
wsec_table = NULL;
}
/* Destroy global data */
if (wsec_global_table) {
g_hash_table_iter_init (&iter, wsec_global_table);
while (g_hash_table_iter_next (&iter, &key, &value)) {
g_free (key);
g_free (value);
}
g_hash_table_destroy (wsec_global_table);
wsec_global_table = NULL;
}
}

View file

@ -0,0 +1,40 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
* Mu Qiao <qiaomuf@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 1999-2010 Gentoo Foundation, Inc.
*/
#ifndef _WPA_PARSER_H
#define _WPA_PARSER_H
#define WPA_SUPPLICANT_CONF "/etc/wpa_supplicant/wpa_supplicant.conf"
#include <glib.h>
void wpa_parser_init (gchar * wpa_supplicant_conf);
void wpa_parser_destroy (void);
/* reader functions */
gchar *wpa_get_value (gchar * ssid, gchar * key);
gboolean exist_ssid (gchar * ssid);
GHashTable *_get_hash_table (gchar * ssid);
gboolean wpa_has_security (gchar * ssid);
/* writer functions */
gboolean wpa_flush_to_file (gchar * config_file);
void wpa_set_data (gchar * ssid, gchar * key, gchar * value);
gboolean wpa_add_security (gchar * ssid);
gboolean wpa_delete_security (gchar * ssid);
#endif

View file

@ -1,3 +1,4 @@
SUBDIRS=. tests
INCLUDES = \
-I$(top_srcdir)/src/system-settings \
@ -5,15 +6,30 @@ INCLUDES = \
-I$(top_srcdir)/libnm-glib \
-I$(top_srcdir)/libnm-util
noinst_LTLIBRARIES = libifupdown-io.la
libifupdown_io_la_SOURCES = \
interface_parser.c \
interface_parser.h \
parser.c \
parser.h
libifupdown_io_la_CPPFLAGS = \
$(GLIB_CFLAGS) \
$(DBUS_CFLAGS) \
-DG_DISABLE_DEPRECATED \
-DSYSCONFDIR=\"$(sysconfdir)\"
libifupdown_io_la_LIBADD = \
$(top_builddir)/libnm-util/libnm-util.la \
$(GLIB_LIBS) \
$(GMODULE_LIBS)
pkglib_LTLIBRARIES = libnm-settings-plugin-ifupdown.la
libnm_settings_plugin_ifupdown_la_SOURCES = \
interface_parser.c \
interface_parser.h \
nm-ifupdown-connection.c \
nm-ifupdown-connection.h \
parser.c \
parser.h \
plugin.c \
plugin.h
@ -28,6 +44,7 @@ libnm_settings_plugin_ifupdown_la_CPPFLAGS = \
libnm_settings_plugin_ifupdown_la_LDFLAGS = -module -avoid-version
libnm_settings_plugin_ifupdown_la_LIBADD = \
$(top_builddir)/libnm-util/libnm-util.la \
libifupdown-io.la \
$(GLIB_LIBS) \
$(GMODULE_LIBS) \
$(GUDEV_LIBS)

View file

@ -73,85 +73,147 @@ void add_data(const char *key,const char *data)
//printf("added data '%s' with key '%s'\n",data,key);
}
#define SPACE_OR_TAB(string,ret) {ret = strchr(string,' ');ret=(ret == NULL?strchr(string,'\t'):ret);}
void ifparser_init(void)
// join values in src with spaces into dst; dst needs to be large enough
static char *join_values_with_spaces(char *dst, char **src)
{
FILE *inp = fopen(ENI_INTERFACES_FILE, "r");
int ret = 0;
char *line;
char *space;
char rline[255];
if (dst != NULL) {
*dst = '\0';
if (src != NULL && *src != NULL) {
strcat(dst, *src);
if (inp == NULL)
{
nm_warning ("Error: Can't open %s\n", ENI_INTERFACES_FILE);
for (src++; *src != NULL; src++) {
strcat(dst, " ");
strcat(dst, *src);
}
}
}
return(dst);
}
void ifparser_init (const char *eni_file, int quiet)
{
FILE *inp = fopen (eni_file, "r");
char line[255];
int skip_to_block = 1;
int skip_long_line = 0;
int offs = 0;
if (inp == NULL) {
if (!quiet)
g_warning ("Error: Can't open %s\n", eni_file);
return;
}
first = last = NULL;
while(1)
{
line = space = NULL;
ret = fscanf(inp,"%255[^\n]\n",rline);
if (ret == EOF)
break;
// If the line did not match, skip it
if (ret == 0) {
char *ignored;
ignored = fgets(rline, 255, inp);
first = last = NULL;
while (!feof(inp))
{
char *token[128]; // 255 chars can only be split into 127 tokens
char value[255]; // large enough to join previously split tokens
char *safeptr;
int toknum;
int len = 0;
char *ptr = fgets(line+offs, 255-offs, inp);
if (ptr == NULL)
break;
len = strlen(line);
// skip over-long lines
if (!feof(inp) && len > 0 && line[len-1] != '\n') {
if (!skip_long_line) {
if (!quiet)
g_message ("Error: Skipping over-long-line '%s...'\n", line);
}
skip_long_line = 1;
continue;
}
line = rline;
while(line[0] == ' ')
line++;
if (line[0]=='#' || line[0]=='\0')
// trailing '\n' found: remove it & reset offset to 0
if (len > 0 && line[len-1] == '\n') {
line[--len] = '\0';
offs = 0;
}
// if we're in long_line_skip mode, terminate it for real next line
if (skip_long_line) {
if (len == 0 || line[len-1] != '\\')
skip_long_line = 0;
continue;
}
// unwrap wrapped lines
if (len > 0 && line[len-1] == '\\') {
offs = len - 1;
continue;
}
//printf(">>%s<<\n", line);
#define SPACES " \t"
// tokenize input;
for (toknum = 0, token[toknum] = strtok_r(line, SPACES, &safeptr);
token[toknum] != NULL;
toknum++, token[toknum] = strtok_r(NULL, SPACES, &safeptr))
;
// ignore comments and empty lines
if (toknum == 0 || *token[0]=='#')
continue;
SPACE_OR_TAB(line,space)
if (space == NULL)
{
nm_warning ("Error: Can't parse interface line '%s'\n",line);
continue;
if (toknum < 2) {
if (!quiet) {
g_message ("Error: Can't parse interface line '%s'\n",
join_values_with_spaces(value, token));
}
space[0] = '\0';
skip_to_block = 1;
continue;
}
// There are four different stanzas:
// iface, mapping, auto and allow-*. Create a block for each of them.
if (strcmp(line,"iface")==0)
{
char *space2 = strchr(space+1,' ');
if (space2 == NULL)
{
nm_warning ("Error: Can't parse iface line '%s'\n",space+1);
// iface stanza takes at least 3 parameters
if (strcmp(token[0], "iface") == 0) {
if (toknum < 4) {
if (!quiet) {
g_message ("Error: Can't parse iface line '%s'\n",
join_values_with_spaces(value, token));
}
continue;
}
space2[0]='\0';
add_block(line,space+1);
if (space2[1]!='\0')
{
space = strchr(space2+1,' ');
if (space == NULL)
{
nm_warning ("Error: Can't parse data '%s'\n",space2+1);
continue;
}
space[0] = '\0';
add_data(space2+1,space+1);
}
add_block(token[0], token[1]);
skip_to_block = 0;
add_data(token[2], join_values_with_spaces(value, token + 3));
}
// auto and allow-auto stanzas are equivalent,
// both can take multiple interfaces as parameters: add one block for each
else if (strcmp(token[0], "auto") == 0 ||
strcmp(token[0], "allow-auto") == 0) {
int i;
for (i = 1; i < toknum; i++)
add_block("auto", token[i]);
skip_to_block = 0;
}
else if (strcmp(token[0], "mapping") == 0) {
add_block(token[0], join_values_with_spaces(value, token + 1));
skip_to_block = 0;
}
// allow-* can take multiple interfaces as parameters: add one block for each
else if (strncmp(token[0],"allow-",6) == 0) {
int i;
for (i = 1; i < toknum; i++)
add_block(token[0], token[i]);
skip_to_block = 0;
}
else {
if (skip_to_block) {
if (!quiet) {
g_message ("Error: ignoring out-of-block data '%s'\n",
join_values_with_spaces(value, token));
}
} else
add_data(token[0], join_values_with_spaces(value, token + 1));
}
else if (strcmp(line,"auto")==0)
add_block(line,space+1);
else if (strcmp(line,"mapping")==0)
add_block(line,space+1);
else if (strncmp(line,"allow-",6)==0)
add_block(line,space+1);
else
add_data(line,space+1);
//printf("line: '%s' ret=%d\n",rline,ret);
}
fclose(inp);
}
@ -190,6 +252,18 @@ if_block *ifparser_getfirst(void)
return first;
}
int ifparser_get_num_blocks(void)
{
int i = 0;
if_block *iter = first;
while (iter) {
i++;
iter = iter->next;
}
return i;
}
if_block *ifparser_getif(const char* iface)
{
if_block *curr = first;
@ -213,3 +287,15 @@ const char *ifparser_getkey(if_block* iface, const char *key)
}
return NULL;
}
int ifparser_get_num_info(if_block* iface)
{
int i = 0;
if_data *iter = iface->info;
while (iter) {
i++;
iter = iter->next;
}
return i;
}

View file

@ -26,8 +26,6 @@
#include "config.h"
#define ENI_INTERFACES_FILE "/etc/network/interfaces"
typedef struct _if_data
{
char *key;
@ -43,12 +41,14 @@ typedef struct _if_block
struct _if_block *next;
} if_block;
void ifparser_init(void);
void ifparser_init(const char *eni_file, int quiet);
void ifparser_destroy(void);
if_block *ifparser_getif(const char* iface);
if_block *ifparser_getfirst(void);
const char *ifparser_getkey(if_block* iface, const char *key);
int ifparser_get_num_blocks(void);
int ifparser_get_num_info(if_block* iface);
void add_block(const char *type, const char* name);
void add_data(const char *key,const char *data);

View file

@ -55,6 +55,8 @@
#define G_UDEV_API_IS_SUBJECT_TO_CHANGE
#include <gudev/gudev.h>
#define ENI_INTERFACES_FILE "/etc/network/interfaces"
#define IFUPDOWN_PLUGIN_NAME "ifupdown"
#define IFUPDOWN_PLUGIN_INFO "(C) 2008 Canonical Ltd. To report bugs please use the NetworkManager mailing list."
#define IFUPDOWN_SYSTEM_HOSTNAME_FILE "/etc/hostname"
@ -355,7 +357,7 @@ SCPluginIfupdown_init (NMSystemConfigInterface *config)
update_system_hostname (inotify_helper, NULL, NULL, config);
/* Read in all the interfaces */
ifparser_init ();
ifparser_init (ENI_INTERFACES_FILE, 0);
block = ifparser_getfirst ();
while (block) {
if(!strcmp ("auto", block->type) || !strcmp ("allow-hotplug", block->type))

View file

@ -0,0 +1,32 @@
INCLUDES = \
-I$(top_srcdir)/include \
-I$(top_srcdir)/libnm-util \
-I$(top_srcdir)/libnm-glib \
-I$(top_srcdir)/system-settings/plugins/ifupdown
noinst_PROGRAMS = test-ifupdown
test_ifupdown_SOURCES = \
test-ifupdown.c
test_ifupdown_CPPFLAGS = \
$(GLIB_CFLAGS) \
$(DBUS_CFLAGS) \
-DTEST_ENI_DIR=\"$(abs_srcdir)\"
test_ifupdown_LDADD = \
$(top_builddir)/libnm-glib/libnm-glib.la \
$(top_builddir)/libnm-util/libnm-util.la \
$(top_builddir)/system-settings/plugins/ifupdown/libifupdown-io.la \
$(DBUS_LIBS)
if WITH_TESTS
check-local: test-ifupdown
$(abs_builddir)/test-ifupdown
endif
EXTRA_DIST = \
test1 test2 test3 test4 test5 test6 test7 test8 test9 test11 test12 \
test13 test14 test15 test16

View file

@ -0,0 +1,496 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2010 Red Hat, Inc.
*
*/
#include <glib.h>
#include <string.h>
#include "interface_parser.h"
#include "parser.h"
typedef struct {
char *key;
char *data;
} ExpectedKey;
typedef struct {
char *type;
char *name;
GSList *keys;
} ExpectedBlock;
typedef struct {
GSList *blocks;
} Expected;
static ExpectedKey *
expected_key_new (const char *key, const char *data)
{
ExpectedKey *k;
k = g_malloc0 (sizeof (ExpectedKey));
g_assert (k);
k->key = g_strdup (key);
g_assert (k->key);
k->data = g_strdup (data);
g_assert (k->data);
return k;
}
static void
expected_key_free (ExpectedKey *k)
{
g_assert (k);
g_free (k->key);
g_free (k->data);
memset (k, 0, sizeof (ExpectedKey));
g_free (k);
}
static ExpectedBlock *
expected_block_new (const char *type, const char *name)
{
ExpectedBlock *b;
g_assert (type);
g_assert (name);
b = g_malloc0 (sizeof (ExpectedBlock));
g_assert (b);
b->type = g_strdup (type);
b->name = g_strdup (name);
return b;
}
static void
expected_block_free (ExpectedBlock *b)
{
g_assert (b);
g_slist_foreach (b->keys, (GFunc) expected_key_free, NULL);
g_slist_free (b->keys);
g_free (b->type);
g_free (b->name);
memset (b, 0, sizeof (ExpectedBlock));
g_free (b);
}
static void
expected_block_add_key (ExpectedBlock *b, ExpectedKey *k)
{
g_assert (b);
g_assert (k);
b->keys = g_slist_append (b->keys, k);
}
static Expected *
expected_new (void)
{
Expected *e;
e = g_malloc0 (sizeof (Expected));
g_assert (e);
return e;
}
static void
expected_add_block (Expected *e, ExpectedBlock *b)
{
g_assert (e);
g_assert (b);
e->blocks = g_slist_append (e->blocks, b);
}
static void
expected_free (Expected *e)
{
g_assert (e);
g_slist_foreach (e->blocks, (GFunc) expected_block_free, NULL);
g_slist_free (e->blocks);
memset (e, 0, sizeof (Expected));
g_free (e);
}
static void
compare_expected_to_ifparser (Expected *e)
{
if_block *n;
GSList *biter, *kiter;
g_assert_cmpint (g_slist_length (e->blocks), ==, ifparser_get_num_blocks ());
for (n = ifparser_getfirst (), biter = e->blocks;
n && biter;
n = n->next, biter = g_slist_next (biter)) {
if_data *m;
ExpectedBlock *b = biter->data;
g_assert (b->type && n->type);
g_assert_cmpstr (b->type, ==, n->type);
g_assert (b->name && n->name);
g_assert_cmpstr (b->name, ==, n->name);
g_assert_cmpint (g_slist_length (b->keys), ==, ifparser_get_num_info (n));
for (m = n->info, kiter = b->keys;
m && kiter;
m = m->next, kiter = g_slist_next (kiter)) {
ExpectedKey *k = kiter->data;
g_assert (k->key && m->key);
g_assert_cmpstr (k->key, ==, m->key);
g_assert (k->data && m->data);
g_assert_cmpstr (k->data, ==, m->data);
}
}
}
static void
dump_blocks (void)
{
if_block *n;
g_message ("\n***************************************************");
for (n = ifparser_getfirst (); n != NULL; n = n->next) {
if_data *m;
// each block start with its type & name
// (single quotes used to show typ & name baoundaries)
g_print("'%s' '%s'\n", n->type, n->name);
// each key-value pair within a block is indented & separated by a tab
// (single quotes used to show typ & name baoundaries)
for (m = n->info; m != NULL; m = m->next)
g_print("\t'%s'\t'%s'\n", m->key, m->data);
// blocks are separated by an empty line
g_print("\n");
}
g_message ("##################################################\n");
}
static void
init_ifparser_with_file (const char *path, const char *file)
{
char *tmp;
tmp = g_strdup_printf ("%s/%s", path, file);
ifparser_init (tmp, 1);
g_free (tmp);
}
static void
test1_ignore_line_before_first_block (const char *path)
{
Expected *e;
ExpectedBlock *b;
e = expected_new ();
b = expected_block_new ("auto", "eth0");
expected_add_block (e, b);
b = expected_block_new ("iface", "eth0");
expected_add_block (e, b);
expected_block_add_key (b, expected_key_new ("inet", "dhcp"));
init_ifparser_with_file (path, "test1");
compare_expected_to_ifparser (e);
ifparser_destroy ();
expected_free (e);
}
static void
test2_wrapped_line (const char *path)
{
Expected *e;
ExpectedBlock *b;
e = expected_new ();
b = expected_block_new ("auto", "lo");
expected_add_block (e, b);
init_ifparser_with_file (path, "test2");
compare_expected_to_ifparser (e);
ifparser_destroy ();
expected_free (e);
}
static void
test3_wrapped_multiline_multiarg (const char *path)
{
Expected *e;
ExpectedBlock *b;
e = expected_new ();
b = expected_block_new ("allow-hotplug", "eth0");
expected_add_block (e, b);
b = expected_block_new ("allow-hotplug", "wlan0");
expected_add_block (e, b);
b = expected_block_new ("allow-hotplug", "bnep0");
expected_add_block (e, b);
init_ifparser_with_file (path, "test3");
compare_expected_to_ifparser (e);
ifparser_destroy ();
expected_free (e);
}
static void
test4_allow_auto_is_auto (const char *path)
{
Expected *e;
ExpectedBlock *b;
e = expected_new ();
b = expected_block_new ("auto", "eth0");
expected_add_block (e, b);
init_ifparser_with_file (path, "test4");
compare_expected_to_ifparser (e);
ifparser_destroy ();
expected_free (e);
}
static void
test5_allow_auto_multiarg (const char *path)
{
Expected *e;
ExpectedBlock *b;
e = expected_new ();
b = expected_block_new ("allow-hotplug", "eth0");
expected_add_block (e, b);
b = expected_block_new ("allow-hotplug", "wlan0");
expected_add_block (e, b);
init_ifparser_with_file (path, "test5");
compare_expected_to_ifparser (e);
ifparser_destroy ();
expected_free (e);
}
static void
test6_mixed_whitespace (const char *path)
{
Expected *e;
ExpectedBlock *b;
e = expected_new ();
b = expected_block_new ("iface", "lo");
expected_block_add_key (b, expected_key_new ("inet", "loopback"));
expected_add_block (e, b);
init_ifparser_with_file (path, "test6");
compare_expected_to_ifparser (e);
ifparser_destroy ();
expected_free (e);
}
static void
test7_long_line (const char *path)
{
init_ifparser_with_file (path, "test7");
g_assert_cmpint (ifparser_get_num_blocks (), ==, 0);
ifparser_destroy ();
}
static void
test8_long_line_wrapped (const char *path)
{
init_ifparser_with_file (path, "test8");
g_assert_cmpint (ifparser_get_num_blocks (), ==, 0);
ifparser_destroy ();
}
static void
test9_wrapped_lines_in_block (const char *path)
{
Expected *e;
ExpectedBlock *b;
e = expected_new ();
b = expected_block_new ("iface", "eth0");
expected_add_block (e, b);
expected_block_add_key (b, expected_key_new ("inet", "static"));
expected_block_add_key (b, expected_key_new ("address", "10.250.2.3"));
expected_block_add_key (b, expected_key_new ("netmask", "255.255.255.192"));
expected_block_add_key (b, expected_key_new ("broadcast", "10.250.2.63"));
expected_block_add_key (b, expected_key_new ("gateway", "10.250.2.50"));
init_ifparser_with_file (path, "test9");
compare_expected_to_ifparser (e);
ifparser_destroy ();
expected_free (e);
}
static void
test11_complex_wrap (const char *path)
{
Expected *e;
ExpectedBlock *b;
e = expected_new ();
b = expected_block_new ("iface", "pppoe");
expected_add_block (e, b);
expected_block_add_key (b, expected_key_new ("inet", "manual"));
expected_block_add_key (b, expected_key_new ("pre-up", "/sbin/ifconfig eth0 up"));
init_ifparser_with_file (path, "test11");
compare_expected_to_ifparser (e);
ifparser_destroy ();
expected_free (e);
}
static void
test12_complex_wrap_split_word (const char *path)
{
Expected *e;
ExpectedBlock *b;
e = expected_new ();
b = expected_block_new ("iface", "pppoe");
expected_add_block (e, b);
expected_block_add_key (b, expected_key_new ("inet", "manual"));
expected_block_add_key (b, expected_key_new ("up", "ifup ppp0=dsl"));
init_ifparser_with_file (path, "test12");
compare_expected_to_ifparser (e);
ifparser_destroy ();
expected_free (e);
}
static void
test13_more_mixed_whitespace (const char *path)
{
Expected *e;
ExpectedBlock *b;
e = expected_new ();
b = expected_block_new ("iface", "dsl");
expected_block_add_key (b, expected_key_new ("inet", "ppp"));
expected_add_block (e, b);
init_ifparser_with_file (path, "test13");
compare_expected_to_ifparser (e);
ifparser_destroy ();
expected_free (e);
}
static void
test14_mixed_whitespace_block_start (const char *path)
{
Expected *e;
ExpectedBlock *b;
e = expected_new ();
b = expected_block_new ("iface", "wlan0");
expected_block_add_key (b, expected_key_new ("inet", "manual"));
expected_add_block (e, b);
b = expected_block_new ("iface", "wlan-adpm");
expected_block_add_key (b, expected_key_new ("inet", "dhcp"));
expected_add_block (e, b);
b = expected_block_new ("iface", "wlan-default");
expected_block_add_key (b, expected_key_new ("inet", "dhcp"));
expected_add_block (e, b);
init_ifparser_with_file (path, "test14");
compare_expected_to_ifparser (e);
ifparser_destroy ();
expected_free (e);
}
static void
test15_trailing_space (const char *path)
{
Expected *e;
ExpectedBlock *b;
e = expected_new ();
b = expected_block_new ("iface", "bnep0");
expected_block_add_key (b, expected_key_new ("inet", "static"));
expected_add_block (e, b);
init_ifparser_with_file (path, "test15");
compare_expected_to_ifparser (e);
ifparser_destroy ();
expected_free (e);
}
static void
test16_missing_newline (const char *path)
{
Expected *e;
e = expected_new ();
expected_add_block (e, expected_block_new ("mapping", "eth0"));
init_ifparser_with_file (path, "test16");
compare_expected_to_ifparser (e);
ifparser_destroy ();
expected_free (e);
}
#if GLIB_CHECK_VERSION(2,25,12)
typedef GTestFixtureFunc TCFunc;
#else
typedef void (*TCFunc)(void);
#endif
#define TESTCASE(t, d) g_test_create_case (#t, 0, d, NULL, (TCFunc) t, NULL)
int main (int argc, char **argv)
{
GTestSuite *suite;
g_test_init (&argc, &argv, NULL);
suite = g_test_get_root ();
if (0)
dump_blocks ();
g_test_suite_add (suite, TESTCASE (test1_ignore_line_before_first_block, TEST_ENI_DIR));
g_test_suite_add (suite, TESTCASE (test2_wrapped_line, TEST_ENI_DIR));
g_test_suite_add (suite, TESTCASE (test3_wrapped_multiline_multiarg, TEST_ENI_DIR));
g_test_suite_add (suite, TESTCASE (test4_allow_auto_is_auto, TEST_ENI_DIR));
g_test_suite_add (suite, TESTCASE (test5_allow_auto_multiarg, TEST_ENI_DIR));
g_test_suite_add (suite, TESTCASE (test6_mixed_whitespace, TEST_ENI_DIR));
g_test_suite_add (suite, TESTCASE (test7_long_line, TEST_ENI_DIR));
g_test_suite_add (suite, TESTCASE (test8_long_line_wrapped, TEST_ENI_DIR));
g_test_suite_add (suite, TESTCASE (test9_wrapped_lines_in_block, TEST_ENI_DIR));
g_test_suite_add (suite, TESTCASE (test11_complex_wrap, TEST_ENI_DIR));
g_test_suite_add (suite, TESTCASE (test12_complex_wrap_split_word, TEST_ENI_DIR));
g_test_suite_add (suite, TESTCASE (test13_more_mixed_whitespace, TEST_ENI_DIR));
g_test_suite_add (suite, TESTCASE (test14_mixed_whitespace_block_start, TEST_ENI_DIR));
g_test_suite_add (suite, TESTCASE (test15_trailing_space, TEST_ENI_DIR));
g_test_suite_add (suite, TESTCASE (test16_missing_newline, TEST_ENI_DIR));
return g_test_run ();
}

View file

@ -0,0 +1,6 @@
# case 1: line before 1st block (must be ignored)
address 10.250.2.3
auto eth0
iface eth0 inet dhcp

View file

@ -0,0 +1,5 @@
iface pppoe inet manual
# case 11: wrapped line (without leading space on the wrapped part, wrap within a multi-word value)
pre-up /sbin/ifconfig \
eth0 up

View file

@ -0,0 +1,5 @@
iface pppoe inet manual
# case 12: wrapped line, splitting a word (must be joined again)
up ifup ppp0\
=dsl

View file

@ -0,0 +1,3 @@
# case 13: variations of tabs & spaces
iface dsl inet ppp

View file

@ -0,0 +1,5 @@
# case 14: variations of tabs and spaces (all must be recognized as lines starting an iface block)
iface wlan0 inet manual
iface wlan-adpm inet dhcp
iface wlan-default inet dhcp

View file

@ -0,0 +1,3 @@
# case 15: trailing space (must be ignored)
iface bnep0 inet static

View file

@ -0,0 +1,2 @@
# case 16: last line that is not followed by LF (added with 'echo -n "mapping eth0" >> /e/n/i')
mapping eth0

View file

@ -0,0 +1,4 @@
# case 2: wrapped line
auto \
lo

View file

@ -0,0 +1,5 @@
# case 3: line wrapped over multiple lines & multi-argument allow-*
allow-hotplug eth0 \
wlan0 \
bnep0

View file

@ -0,0 +1,3 @@
# case 4: 'allow-auto' is synonymous to 'auto'
allow-auto eth0

View file

@ -0,0 +1,3 @@
# case 5: multi-argument allow-* (even worse: trailing space)
allow-hotplug eth0 wlan0

View file

@ -0,0 +1,3 @@
# case 6: mix between tabs and spaces
iface lo inet loopback

View file

@ -0,0 +1,3 @@
# case 7: over-long line (must be ignored completely)
123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789

View file

@ -0,0 +1,5 @@
# case 8: over-long line that wraps to consecutive lines (must be ignored completely)
123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 \
allow-test eth0 \
eth0

View file

@ -0,0 +1,10 @@
iface eth0 inet static
# case 9: wrapped lines inside a block (to be on the safe side)
address \
10.250.2.3
netmask \
255.255.255.192
broadcast 10.250.2.63
gateway 10.250.2.50