diff --git a/.gitignore b/.gitignore index 0f9c390b34..6c014d92f2 100644 --- a/.gitignore +++ b/.gitignore @@ -141,6 +141,7 @@ initscript/*/[Nn]etwork[Mm]anager *-glue.h *-bindings.h nm-marshal.[ch] +callouts/tests/test-dispatcher-envp libnm-glib/libnm-glib-test src/NetworkManager src/nm-crash-logger diff --git a/callouts/Makefile.am b/callouts/Makefile.am index 9fcdd6c7c0..4a1ea7ca55 100644 --- a/callouts/Makefile.am +++ b/callouts/Makefile.am @@ -1,3 +1,13 @@ +SUBDIRS=. tests + +########################################### +# Test libraries +########################################### + +noinst_LTLIBRARIES = \ + libtest-dispatcher-envp.la + + dbusservicedir = $(DBUS_SYS_DIR) dbusservice_DATA = \ nm-dhcp-client.conf \ @@ -41,7 +51,9 @@ nm_avahi_autoipd_action_LDADD = \ nm_dispatcher_action_SOURCES = \ nm-dispatcher-action.c \ - nm-dispatcher-action.h + nm-dispatcher-action.h \ + nm-dispatcher-utils.c \ + nm-dispatcher-utils.h nm_dispatcher_action_CPPFLAGS = \ -I${top_srcdir} \ @@ -54,7 +66,6 @@ nm_dispatcher_action_CPPFLAGS = \ -DLIBEXECDIR=\"$(libexecdir)\" nm_dispatcher_action_LDADD = \ - $(top_builddir)/libnm-glib/libnm-glib.la \ $(top_builddir)/libnm-util/libnm-util.la \ $(DBUS_LIBS) \ $(GLIB_LIBS) @@ -62,6 +73,26 @@ nm_dispatcher_action_LDADD = \ nm-dispatcher-glue.h: nm-dispatcher.xml $(AM_V_GEN) dbus-binding-tool --prefix=nm_dispatcher --mode=glib-server --output=$@ $< +########################################### +# dispatcher envp +########################################### + +libtest_dispatcher_envp_la_SOURCES = \ + nm-dispatcher-utils.c \ + nm-dispatcher-utils.h + +libtest_dispatcher_envp_la_CPPFLAGS = \ + -I${top_srcdir}/include \ + -I${top_srcdir}/libnm-util \ + $(GLIB_CFLAGS) \ + $(DBUS_CFLAGS) + +libtest_dispatcher_envp_la_LIBADD = \ + $(top_builddir)/libnm-util/libnm-util.la \ + $(GLIB_LIBS) \ + $(DBUS_LIBS) + + udevrulesdir = $(UDEV_BASE_DIR)/rules.d udevrules_DATA = 77-nm-olpc-mesh.rules diff --git a/callouts/nm-dispatcher-action.c b/callouts/nm-dispatcher-action.c index ed9cb00c1e..54186a98a1 100644 --- a/callouts/nm-dispatcher-action.c +++ b/callouts/nm-dispatcher-action.c @@ -35,15 +35,9 @@ #include #include -#include -#include "nm-glib-compat.h" -#include -#include -#include -#include -#include #include "nm-dispatcher-action.h" +#include "nm-dispatcher-utils.h" #define NMD_SCRIPT_DIR SYSCONFDIR "/NetworkManager/dispatcher.d" @@ -84,11 +78,18 @@ typedef struct { } Dispatcher; static gboolean -nm_dispatcher_action (Handler *obj, +nm_dispatcher_action (Handler *h, const char *action, - GHashTable *connection, + GHashTable *connection_hash, GHashTable *connection_props, GHashTable *device_props, + GHashTable *device_ip4_props, + GHashTable *device_ip6_props, + GHashTable *device_dhcp4_props, + GHashTable *device_dhcp6_props, + const char *vpn_ip_iface, + GHashTable *vpn_ip4_props, + GHashTable *vpn_ip6_props, GError **error); #include "nm-dispatcher-glue.h" @@ -220,207 +221,13 @@ child_setup (gpointer user_data G_GNUC_UNUSED) setpgid (pid, pid); } -typedef struct { - char **envp; - guint32 i; -} EnvAddInfo; - static void -add_one_option_to_envp (gpointer key, gpointer value, gpointer user_data) -{ - EnvAddInfo *info = (EnvAddInfo *) user_data; - char *ucased; - - ucased = g_ascii_strup (key, -1); - info->envp[info->i++] = g_strdup_printf ("DHCP4_%s=%s", ucased, (char *) value); - g_free (ucased); -} - -static char ** -construct_envp (const char *uuid, - const char *id, - NMIP4Config *ip4_config, - NMDHCP4Config *dhcp4_config) -{ - guint32 env_size = 0; - char **envp; - guint32 envp_idx = 0; - GHashTable *options = NULL; - GSList *addresses, *routes, *iter; - GArray *nameservers, *wins; - GPtrArray *domains; - guint32 num, i; - GString *tmp; - - if (!ip4_config) - return g_new0 (char *, 1); - - addresses = (GSList *) nm_ip4_config_get_addresses (ip4_config); - nameservers = (GArray *) nm_ip4_config_get_nameservers (ip4_config); - domains = (GPtrArray *) nm_ip4_config_get_domains (ip4_config); - wins = (GArray *) nm_ip4_config_get_wins_servers (ip4_config); - routes = (GSList *) nm_ip4_config_get_routes (ip4_config); - - env_size = g_slist_length (addresses) - + 1 /* addresses length */ - + 1 /* nameservers */ - + 1 /* domains */ - + 1 /* WINS servers */ - + g_slist_length (routes) - + 1 /* routes length */ - + 1 /* connection UUID */ - + 1 /* connection ID */; - - if (dhcp4_config) { - options = nm_dhcp4_config_get_options (dhcp4_config); - env_size += g_hash_table_size (options); - } - - envp = g_new0 (char *, env_size + 1); - - if (uuid) - envp[envp_idx++] = g_strdup_printf ("CONNECTION_UUID=%s", uuid); - if (id) - envp[envp_idx++] = g_strdup_printf ("CONNECTION_ID=%s", id); - - /* IP4 config stuff */ - for (iter = addresses, num = 0; iter; iter = g_slist_next (iter)) { - NMIP4Address *addr = (NMIP4Address *) iter->data; - char str_addr[INET_ADDRSTRLEN + 1]; - char str_gw[INET_ADDRSTRLEN + 1]; - struct in_addr tmp_addr; - guint32 prefix = nm_ip4_address_get_prefix (addr); - - memset (str_addr, 0, sizeof (str_addr)); - tmp_addr.s_addr = nm_ip4_address_get_address (addr); - if (!inet_ntop (AF_INET, &tmp_addr, str_addr, sizeof (str_addr))) - continue; - - memset (str_gw, 0, sizeof (str_gw)); - tmp_addr.s_addr = nm_ip4_address_get_gateway (addr); - inet_ntop (AF_INET, &tmp_addr, str_gw, sizeof (str_gw)); - - tmp = g_string_sized_new (25 + strlen (str_addr) + strlen (str_gw)); - g_string_append_printf (tmp, "IP4_ADDRESS_%d=%s/%d %s", num++, str_addr, prefix, str_gw); - envp[envp_idx++] = tmp->str; - g_string_free (tmp, FALSE); - } - if (num) - envp[envp_idx++] = g_strdup_printf ("IP4_NUM_ADDRESSES=%d", num); - - if (nameservers && nameservers->len) { - gboolean first = TRUE; - - tmp = g_string_new ("IP4_NAMESERVERS="); - for (i = 0; i < nameservers->len; i++) { - struct in_addr addr; - char buf[INET_ADDRSTRLEN + 1]; - - addr.s_addr = g_array_index (nameservers, guint32, i); - memset (buf, 0, sizeof (buf)); - if (inet_ntop (AF_INET, &addr, buf, sizeof (buf))) { - if (!first) - g_string_append_c (tmp, ' '); - g_string_append (tmp, buf); - first = FALSE; - } - } - envp[envp_idx++] = tmp->str; - g_string_free (tmp, FALSE); - } - - if (domains && domains->len) { - tmp = g_string_new ("IP4_DOMAINS="); - for (i = 0; i < domains->len; i++) { - if (i > 0) - g_string_append_c (tmp, ' '); - g_string_append (tmp, (char *) g_ptr_array_index (domains, i)); - } - envp[envp_idx++] = tmp->str; - g_string_free (tmp, FALSE); - } - - if (wins && wins->len) { - gboolean first = TRUE; - - tmp = g_string_new ("IP4_WINS_SERVERS="); - for (i = 0; i < wins->len; i++) { - struct in_addr addr; - char buf[INET_ADDRSTRLEN + 1]; - - addr.s_addr = g_array_index (wins, guint32, i); - memset (buf, 0, sizeof (buf)); - if (inet_ntop (AF_INET, &addr, buf, sizeof (buf))) { - if (!first) - g_string_append_c (tmp, ' '); - g_string_append (tmp, buf); - first = FALSE; - } - } - envp[envp_idx++] = tmp->str; - g_string_free (tmp, FALSE); - } - - for (iter = routes, num = 0; iter; iter = g_slist_next (iter)) { - NMIP4Route *route = (NMIP4Route *) iter->data; - char str_addr[INET_ADDRSTRLEN + 1]; - char str_nh[INET_ADDRSTRLEN + 1]; - struct in_addr tmp_addr; - guint32 prefix = nm_ip4_route_get_prefix (route); - guint32 metric = nm_ip4_route_get_metric (route); - - memset (str_addr, 0, sizeof (str_addr)); - tmp_addr.s_addr = nm_ip4_route_get_dest (route); - if (!inet_ntop (AF_INET, &tmp_addr, str_addr, sizeof (str_addr))) - continue; - - memset (str_nh, 0, sizeof (str_nh)); - tmp_addr.s_addr = nm_ip4_route_get_next_hop (route); - inet_ntop (AF_INET, &tmp_addr, str_nh, sizeof (str_nh)); - - tmp = g_string_sized_new (30 + strlen (str_addr) + strlen (str_nh)); - g_string_append_printf (tmp, "IP4_ROUTE_%d=%s/%d %s %d", num++, str_addr, prefix, str_nh, metric); - envp[envp_idx++] = tmp->str; - g_string_free (tmp, FALSE); - } - envp[envp_idx++] = g_strdup_printf ("IP4_NUM_ROUTES=%d", num); - - /* DHCP stuff */ - if (dhcp4_config && options) { - EnvAddInfo info; - - info.envp = envp; - info.i = envp_idx; - g_hash_table_foreach (options, add_one_option_to_envp, &info); - } - - if (debug) { - char **p; - - g_message ("------------ Script Environment ------------"); - for (p = envp; *p; p++) - g_message (" %s", *p); - g_message ("\n"); - } - - return envp; -} - -static void -dispatch_scripts (const char *action, - const char *iface, - const char *parent_iface, - NMDeviceType type, - const char *uuid, - const char *id, - NMIP4Config *ip4_config, - NMDHCP4Config *dhcp4_config) +dispatch_scripts (const char *action, const char *iface, char **envp) { GDir *dir; const char *filename; GSList *scripts = NULL, *iter; GError *error = NULL; - char **envp = NULL; if (!(dir = g_dir_open (NMD_SCRIPT_DIR, 0, &error))) { g_warning ("g_dir_open() could not open '" NMD_SCRIPT_DIR "'. '%s'", @@ -458,8 +265,6 @@ dispatch_scripts (const char *action, } g_dir_close (dir); - envp = construct_envp (uuid, id, ip4_config, dhcp4_config); - for (iter = scripts; iter; iter = g_slist_next (iter)) { gchar *argv[4]; gint status = -1; @@ -487,8 +292,6 @@ dispatch_scripts (const char *action, } } - g_strfreev (envp); - g_slist_foreach (scripts, (GFunc) g_free, NULL); g_slist_free (scripts); } @@ -499,18 +302,18 @@ nm_dispatcher_action (Handler *h, GHashTable *connection_hash, GHashTable *connection_props, GHashTable *device_props, + GHashTable *device_ip4_props, + GHashTable *device_ip6_props, + GHashTable *device_dhcp4_props, + GHashTable *device_dhcp6_props, + const char *vpn_ip_iface, + GHashTable *vpn_ip4_props, + GHashTable *vpn_ip6_props, GError **error) { Dispatcher *d = g_object_get_data (G_OBJECT (h), "dispatcher"); - NMConnection *connection; - char *iface = NULL, *parent_iface = NULL; - const char *uuid = NULL, *id = NULL; - NMDeviceType type = NM_DEVICE_TYPE_UNKNOWN; - NMDeviceState dev_state = NM_DEVICE_STATE_UNKNOWN; - NMDevice *device = NULL; - NMDHCP4Config *dhcp4_config = NULL; - NMIP4Config *ip4_config = NULL; - GValue *value; + char **envp, **p; + char *iface = NULL; /* Back off the quit timeout */ if (d->quit_timeout) @@ -518,80 +321,30 @@ nm_dispatcher_action (Handler *h, if (!d->persist) d->quit_timeout = g_timeout_add_seconds (10, quit_timeout_cb, NULL); - /* Hostname changes don't require a device nor contain a connection */ - if (!strcmp (action, "hostname")) - goto dispatch; + envp = nm_dispatcher_utils_construct_envp (action, + connection_hash, + connection_props, + device_props, + device_ip4_props, + device_ip6_props, + device_dhcp4_props, + device_dhcp6_props, + vpn_ip_iface, + vpn_ip4_props, + vpn_ip6_props, + &iface); - connection = nm_connection_new_from_hash (connection_hash, error); - if (connection) { - uuid = nm_connection_get_uuid (connection); - id = nm_connection_get_id (connection); - } else { - g_warning ("%s: Invalid connection: '%s' / '%s' invalid: %d", - __func__, - g_type_name (nm_connection_lookup_setting_type_by_quark ((*error)->domain)), - (*error)->message, (*error)->code); - /* Don't fail on this error yet */ - g_error_free (*error); - *error = NULL; + if (debug) { + g_message ("------------ Script Environment ------------"); + for (p = envp; *p; p++) + g_message (" %s", *p); + g_message ("\n"); } - /* interface name */ - value = g_hash_table_lookup (device_props, NMD_DEVICE_PROPS_INTERFACE); - if (!value || !G_VALUE_HOLDS_STRING (value)) { - g_warning ("Missing or invalid required value " NMD_DEVICE_PROPS_INTERFACE "!"); - goto out; - } - iface = (char *) g_value_get_string (value); + dispatch_scripts (action, iface, envp); + g_strfreev (envp); + g_free (iface); - /* IP interface name */ - value = g_hash_table_lookup (device_props, NMD_DEVICE_PROPS_IP_INTERFACE); - if (value) { - if (!G_VALUE_HOLDS_STRING (value)) { - g_warning ("Invalid required value " NMD_DEVICE_PROPS_IP_INTERFACE "!"); - goto out; - } - parent_iface = iface; - iface = (char *) g_value_get_string (value); - } - - /* Device type */ - value = g_hash_table_lookup (device_props, NMD_DEVICE_PROPS_TYPE); - if (!value || !G_VALUE_HOLDS_UINT (value)) { - g_warning ("Missing or invalid required value " NMD_DEVICE_PROPS_TYPE "!"); - goto out; - } - type = g_value_get_uint (value); - - /* Device state */ - value = g_hash_table_lookup (device_props, NMD_DEVICE_PROPS_STATE); - if (!value || !G_VALUE_HOLDS_UINT (value)) { - g_warning ("Missing or invalid required value " NMD_DEVICE_PROPS_STATE "!"); - goto out; - } - dev_state = g_value_get_uint (value); - - /* device itself */ - value = g_hash_table_lookup (device_props, NMD_DEVICE_PROPS_PATH); - if (!value || (G_VALUE_TYPE (value) != DBUS_TYPE_G_OBJECT_PATH)) { - g_warning ("Missing or invalid required value " NMD_DEVICE_PROPS_PATH "!"); - goto out; - } - device = NM_DEVICE (nm_device_new (d->g_connection, (const char *) g_value_get_boxed (value))); - - /* Get the DHCP4 config */ - if (device && (dev_state == NM_DEVICE_STATE_ACTIVATED)) { - dhcp4_config = nm_device_get_dhcp4_config (device); - ip4_config = nm_device_get_ip4_config (device); - } - -dispatch: - dispatch_scripts (action, iface, parent_iface, type, uuid, id, ip4_config, dhcp4_config); - - if (device) - g_object_unref (device); - -out: return TRUE; } diff --git a/callouts/nm-dispatcher-utils.c b/callouts/nm-dispatcher-utils.c new file mode 100644 index 0000000000..97ee1a4bef --- /dev/null +++ b/callouts/nm-dispatcher-utils.c @@ -0,0 +1,509 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * 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) 2008 - 2011 Red Hat, Inc. + */ + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "nm-dispatcher-action.h" +#include "nm-utils.h" + +#include "nm-dispatcher-utils.h" + +static GSList * +construct_basic_items (GSList *list, + const char *uuid, + const char *id, + const char *iface, + const char *ip_iface) +{ + if (uuid) + list = g_slist_prepend (list, g_strdup_printf ("CONNECTION_UUID=%s", uuid)); + if (id) + list = g_slist_prepend (list, g_strdup_printf ("CONNECTION_ID=%s", id)); + if (iface) + list = g_slist_prepend (list, g_strdup_printf ("DEVICE_IFACE=%s", iface)); + if (ip_iface) + list = g_slist_prepend (list, g_strdup_printf ("DEVICE_IP_IFACE=%s", ip_iface)); + return list; +} + +static GSList * +add_domains (GSList *items, + GHashTable *hash, + const char *prefix, + const char four_or_six) +{ + GValue *val; + GPtrArray *domains = NULL; + GString *tmp; + guint i; + + /* Search domains */ + val = g_hash_table_lookup (hash, "domains"); + if (!val || !G_VALUE_HOLDS (val, DBUS_TYPE_G_ARRAY_OF_STRING)) + return items; + + domains = (GPtrArray *) g_value_get_boxed (val); + if (!domains || (domains->len == 0)) + return items; + + tmp = g_string_new (NULL); + g_string_append_printf (tmp, "%sIP%c_DOMAINS=", prefix, four_or_six); + for (i = 0; i < domains->len; i++) { + if (i > 0) + g_string_append_c (tmp, ' '); + g_string_append (tmp, (char *) g_ptr_array_index (domains, i)); + } + items = g_slist_prepend (items, tmp->str); + g_string_free (tmp, FALSE); + + return items; +} + +static GSList * +construct_ip4_items (GSList *items, GHashTable *ip4_config, const char *prefix) +{ + GSList *addresses = NULL, *routes = NULL, *iter; + GArray *dns = NULL, *wins = NULL; + guint32 num, i; + GString *tmp; + GValue *val; + + if (ip4_config == NULL) + return items; + + if (prefix == NULL) + prefix = ""; + + /* IP addresses */ + val = g_hash_table_lookup (ip4_config, "addresses"); + if (val) + addresses = nm_utils_ip4_addresses_from_gvalue (val); + + for (iter = addresses, num = 0; iter; iter = g_slist_next (iter)) { + NMIP4Address *addr = (NMIP4Address *) iter->data; + char str_addr[INET_ADDRSTRLEN + 1]; + char str_gw[INET_ADDRSTRLEN + 1]; + struct in_addr tmp_addr; + guint32 ip_prefix = nm_ip4_address_get_prefix (addr); + char *addrtmp; + + memset (str_addr, 0, sizeof (str_addr)); + tmp_addr.s_addr = nm_ip4_address_get_address (addr); + if (!inet_ntop (AF_INET, &tmp_addr, str_addr, sizeof (str_addr))) + continue; + + memset (str_gw, 0, sizeof (str_gw)); + tmp_addr.s_addr = nm_ip4_address_get_gateway (addr); + inet_ntop (AF_INET, &tmp_addr, str_gw, sizeof (str_gw)); + + addrtmp = g_strdup_printf ("%sIP4_ADDRESS_%d=%s/%d %s", prefix, num++, str_addr, ip_prefix, str_gw); + items = g_slist_prepend (items, addrtmp); + } + if (num) + items = g_slist_prepend (items, g_strdup_printf ("%sIP4_NUM_ADDRESSES=%d", prefix, num)); + if (addresses) { + g_slist_foreach (addresses, (GFunc) nm_ip4_address_unref, NULL); + g_slist_free (addresses); + } + + /* DNS servers */ + val = g_hash_table_lookup (ip4_config, "nameservers"); + if (val && G_VALUE_HOLDS (val, DBUS_TYPE_G_UINT_ARRAY)) + dns = (GArray *) g_value_get_boxed (val); + + if (dns && (dns->len > 0)) { + gboolean first = TRUE; + + tmp = g_string_new (NULL); + g_string_append_printf (tmp, "%sIP4_NAMESERVERS=", prefix); + for (i = 0; i < dns->len; i++) { + struct in_addr addr; + char buf[INET_ADDRSTRLEN + 1]; + + addr.s_addr = g_array_index (dns, guint32, i); + memset (buf, 0, sizeof (buf)); + if (inet_ntop (AF_INET, &addr, buf, sizeof (buf))) { + if (!first) + g_string_append_c (tmp, ' '); + g_string_append (tmp, buf); + first = FALSE; + } + } + items = g_slist_prepend (items, tmp->str); + g_string_free (tmp, FALSE); + } + + /* Search domains */ + items = add_domains (items, ip4_config, prefix, '4'); + + /* WINS servers */ + val = g_hash_table_lookup (ip4_config, "wins-servers"); + if (val && G_VALUE_HOLDS (val, DBUS_TYPE_G_UINT_ARRAY)) + wins = (GArray *) g_value_get_boxed (val); + + if (wins && wins->len) { + gboolean first = TRUE; + + tmp = g_string_new (NULL); + g_string_append_printf (tmp, "%sIP4_WINS_SERVERS=", prefix); + for (i = 0; i < wins->len; i++) { + struct in_addr addr; + char buf[INET_ADDRSTRLEN + 1]; + + addr.s_addr = g_array_index (wins, guint32, i); + memset (buf, 0, sizeof (buf)); + if (inet_ntop (AF_INET, &addr, buf, sizeof (buf))) { + if (!first) + g_string_append_c (tmp, ' '); + g_string_append (tmp, buf); + first = FALSE; + } + } + items = g_slist_prepend (items, tmp->str); + g_string_free (tmp, FALSE); + } + + /* Static routes */ + val = g_hash_table_lookup (ip4_config, "routes"); + if (val) + routes = nm_utils_ip4_routes_from_gvalue (val); + + for (iter = routes, num = 0; iter; iter = g_slist_next (iter)) { + NMIP4Route *route = (NMIP4Route *) iter->data; + char str_addr[INET_ADDRSTRLEN + 1]; + char str_nh[INET_ADDRSTRLEN + 1]; + struct in_addr tmp_addr; + guint32 ip_prefix = nm_ip4_route_get_prefix (route); + guint32 metric = nm_ip4_route_get_metric (route); + char *routetmp; + + memset (str_addr, 0, sizeof (str_addr)); + tmp_addr.s_addr = nm_ip4_route_get_dest (route); + if (!inet_ntop (AF_INET, &tmp_addr, str_addr, sizeof (str_addr))) + continue; + + memset (str_nh, 0, sizeof (str_nh)); + tmp_addr.s_addr = nm_ip4_route_get_next_hop (route); + inet_ntop (AF_INET, &tmp_addr, str_nh, sizeof (str_nh)); + + routetmp = g_strdup_printf ("%sIP4_ROUTE_%d=%s/%d %s %d", prefix, num++, str_addr, ip_prefix, str_nh, metric); + items = g_slist_prepend (items, routetmp); + } + items = g_slist_prepend (items, g_strdup_printf ("%sIP4_NUM_ROUTES=%d", prefix, num)); + if (routes) { + g_slist_foreach (routes, (GFunc) nm_ip4_route_unref, NULL); + g_slist_free (routes); + } + + return items; +} + +static GSList * +construct_device_dhcp4_items (GSList *items, GHashTable *dhcp4_config) +{ + GHashTableIter iter; + const char *key, *tmp; + GValue *val; + char *ucased; + + if (dhcp4_config == NULL) + return items; + + g_hash_table_iter_init (&iter, dhcp4_config); + while (g_hash_table_iter_next (&iter, (gpointer) &key, (gpointer) &val)) { + ucased = g_ascii_strup (key, -1); + tmp = g_value_get_string (val); + items = g_slist_prepend (items, g_strdup_printf ("DHCP4_%s=%s", ucased, tmp)); + g_free (ucased); + } + return items; +} + +static GSList * +construct_ip6_items (GSList *items, GHashTable *ip6_config, const char *prefix) +{ + GSList *addresses = NULL, *routes = NULL, *dns = NULL, *iter; + guint32 num; + GString *tmp; + GValue *val; + + if (ip6_config == NULL) + return items; + + if (prefix == NULL) + prefix = ""; + + /* IP addresses */ + val = g_hash_table_lookup (ip6_config, "addresses"); + if (val) + addresses = nm_utils_ip6_addresses_from_gvalue (val); + + for (iter = addresses, num = 0; iter; iter = g_slist_next (iter)) { + NMIP6Address *addr = (NMIP6Address *) iter->data; + char str_addr[INET6_ADDRSTRLEN + 1]; + char str_gw[INET6_ADDRSTRLEN + 1]; + const struct in6_addr *tmp_addr; + guint32 ip_prefix = nm_ip6_address_get_prefix (addr); + char *addrtmp; + + memset (str_addr, 0, sizeof (str_addr)); + tmp_addr = nm_ip6_address_get_address (addr); + if (!inet_ntop (AF_INET6, &tmp_addr, str_addr, sizeof (str_addr))) + continue; + + memset (str_gw, 0, sizeof (str_gw)); + tmp_addr = nm_ip6_address_get_gateway (addr); + inet_ntop (AF_INET6, &tmp_addr, str_gw, sizeof (str_gw)); + + addrtmp = g_strdup_printf ("%sIP6_ADDRESS_%d=%s/%d %s", prefix, num++, str_addr, ip_prefix, str_gw); + items = g_slist_prepend (items, addrtmp); + } + if (num) + items = g_slist_prepend (items, g_strdup_printf ("%sIP6_NUM_ADDRESSES=%d", prefix, num)); + if (addresses) { + g_slist_foreach (addresses, (GFunc) nm_ip6_address_unref, NULL); + g_slist_free (addresses); + } + + /* DNS servers */ + val = g_hash_table_lookup (ip6_config, "nameservers"); + if (val) + dns = nm_utils_ip6_dns_from_gvalue (val); + + if (g_slist_length (dns)) { + tmp = g_string_new (NULL); + g_string_append_printf (tmp, "%sIP6_NAMESERVERS=", prefix); + + for (iter = dns; iter; iter = g_slist_next (iter)) { + const struct in6_addr *addr = iter->data; + gboolean first = TRUE; + char buf[INET6_ADDRSTRLEN + 1]; + + memset (buf, 0, sizeof (buf)); + if (inet_ntop (AF_INET6, addr, buf, sizeof (buf))) { + if (!first) + g_string_append_c (tmp, ' '); + g_string_append (tmp, buf); + first = FALSE; + } + } + + items = g_slist_prepend (items, tmp->str); + g_string_free (tmp, FALSE); + } + + /* Search domains */ + items = add_domains (items, ip6_config, prefix, '6'); + + /* Static routes */ + val = g_hash_table_lookup (ip6_config, "routes"); + if (val) + routes = nm_utils_ip6_routes_from_gvalue (val); + + for (iter = routes, num = 0; iter; iter = g_slist_next (iter)) { + NMIP6Route *route = (NMIP6Route *) iter->data; + char str_addr[INET6_ADDRSTRLEN + 1]; + char str_nh[INET6_ADDRSTRLEN + 1]; + const struct in6_addr *tmp_addr; + guint32 ip_prefix = nm_ip6_route_get_prefix (route); + guint32 metric = nm_ip6_route_get_metric (route); + char *routetmp; + + memset (str_addr, 0, sizeof (str_addr)); + tmp_addr = nm_ip6_route_get_dest (route); + if (!inet_ntop (AF_INET6, &tmp_addr, str_addr, sizeof (str_addr))) + continue; + + memset (str_nh, 0, sizeof (str_nh)); + tmp_addr = nm_ip6_route_get_next_hop (route); + inet_ntop (AF_INET6, &tmp_addr, str_nh, sizeof (str_nh)); + + routetmp = g_strdup_printf ("%sIP6_ROUTE_%d=%s/%d %s %d", prefix, num++, str_addr, ip_prefix, str_nh, metric); + items = g_slist_prepend (items, routetmp); + } + if (num) + items = g_slist_prepend (items, g_strdup_printf ("%sIP6_NUM_ROUTES=%d", prefix, num)); + if (routes) { + g_slist_foreach (routes, (GFunc) nm_ip6_route_unref, NULL); + g_slist_free (routes); + } + + return items; +} + +static GSList * +construct_device_dhcp6_items (GSList *items, GHashTable *dhcp6_config) +{ + GHashTableIter iter; + const char *key, *tmp; + GValue *val; + char *ucased; + + if (dhcp6_config == NULL) + return items; + + g_hash_table_iter_init (&iter, dhcp6_config); + while (g_hash_table_iter_next (&iter, (gpointer) &key, (gpointer) &val)) { + ucased = g_ascii_strup (key, -1); + tmp = g_value_get_string (val); + items = g_slist_prepend (items, g_strdup_printf ("DHCP6_%s=%s", ucased, tmp)); + g_free (ucased); + } + return items; +} + +char ** +nm_dispatcher_utils_construct_envp (const char *action, + GHashTable *connection_hash, + GHashTable *connection_props, + GHashTable *device_props, + GHashTable *device_ip4_props, + GHashTable *device_ip6_props, + GHashTable *device_dhcp4_props, + GHashTable *device_dhcp6_props, + const char *vpn_ip_iface, + GHashTable *vpn_ip4_props, + GHashTable *vpn_ip6_props, + char **out_iface) +{ + const char *iface = NULL, *ip_iface = NULL; + const char *uuid = NULL, *id = NULL; + NMDeviceState dev_state = NM_DEVICE_STATE_UNKNOWN; + GValue *value; + char **envp = NULL; + GSList *items = NULL, *iter; + guint i; + GHashTable *con_setting_hash; + + g_return_val_if_fail (action != NULL, NULL); + g_return_val_if_fail (out_iface != NULL, NULL); + g_return_val_if_fail (*out_iface == NULL, NULL); + + /* Hostname changes don't require a device nor contain a connection */ + if (!strcmp (action, "hostname")) + return g_new0 (char *, 1); + + con_setting_hash = g_hash_table_lookup (connection_hash, NM_SETTING_CONNECTION_SETTING_NAME); + if (!con_setting_hash) { + g_warning ("Failed to read connection setting"); + return NULL; + } + + value = g_hash_table_lookup (con_setting_hash, NM_SETTING_CONNECTION_UUID); + if (!value || !G_VALUE_HOLDS (value, G_TYPE_STRING)) { + g_warning ("Connection hash did not contain the UUID"); + return NULL; + } + uuid = g_value_get_string (value); + + value = g_hash_table_lookup (con_setting_hash, NM_SETTING_CONNECTION_ID); + if (!value || !G_VALUE_HOLDS (value, G_TYPE_STRING)) { + g_warning ("Connection hash did not contain the ID"); + return NULL; + } + id = g_value_get_string (value); + + /* interface name */ + value = g_hash_table_lookup (device_props, NMD_DEVICE_PROPS_INTERFACE); + if (!value || !G_VALUE_HOLDS_STRING (value)) { + g_warning ("Missing or invalid required value " NMD_DEVICE_PROPS_INTERFACE "!"); + return NULL; + } + iface = g_value_get_string (value); + + /* IP interface name */ + value = g_hash_table_lookup (device_props, NMD_DEVICE_PROPS_IP_INTERFACE); + if (value) { + if (!G_VALUE_HOLDS_STRING (value)) { + g_warning ("Invalid required value " NMD_DEVICE_PROPS_IP_INTERFACE "!"); + return NULL; + } + ip_iface = g_value_get_string (value); + } + + /* Device type */ + value = g_hash_table_lookup (device_props, NMD_DEVICE_PROPS_TYPE); + if (!value || !G_VALUE_HOLDS_UINT (value)) { + g_warning ("Missing or invalid required value " NMD_DEVICE_PROPS_TYPE "!"); + return NULL; + } + + /* Device state */ + value = g_hash_table_lookup (device_props, NMD_DEVICE_PROPS_STATE); + if (!value || !G_VALUE_HOLDS_UINT (value)) { + g_warning ("Missing or invalid required value " NMD_DEVICE_PROPS_STATE "!"); + return NULL; + } + dev_state = g_value_get_uint (value); + + /* device itself */ + value = g_hash_table_lookup (device_props, NMD_DEVICE_PROPS_PATH); + if (!value || (G_VALUE_TYPE (value) != DBUS_TYPE_G_OBJECT_PATH)) { + g_warning ("Missing or invalid required value " NMD_DEVICE_PROPS_PATH "!"); + return NULL; + } + + items = construct_basic_items (items, uuid, id, iface, ip_iface); + + /* Device it's aren't valid if the device isn't activated */ + if (iface && (dev_state == NM_DEVICE_STATE_ACTIVATED)) { + items = construct_ip4_items (items, device_ip4_props, NULL); + items = construct_ip6_items (items, device_ip6_props, NULL); + items = construct_device_dhcp4_items (items, device_dhcp4_props); + items = construct_device_dhcp6_items (items, device_dhcp6_props); + } + + if (vpn_ip_iface) { + items = g_slist_prepend (items, g_strdup_printf ("VPN_IP_IFACE=%s", vpn_ip_iface)); + items = construct_ip4_items (items, vpn_ip4_props, "VPN_"); + items = construct_ip6_items (items, vpn_ip6_props, "VPN_"); + } + + /* Convert the list to an environment pointer */ + envp = g_new0 (char *, g_slist_length (items) + 1); + for (iter = items, i = 0; iter; iter = g_slist_next (iter), i++) + envp[i] = (char *) iter->data; + g_slist_free (items); + + /* Backwards compat: 'iface' is set in this order: + * 1) VPN interface name + * 2) Device IP interface name + * 3) Device interface anme + */ + if (vpn_ip_iface) + *out_iface = g_strdup (vpn_ip_iface); + else if (ip_iface) + *out_iface = g_strdup (ip_iface); + else + *out_iface = g_strdup (iface); + + return envp; +} + diff --git a/callouts/nm-dispatcher-utils.h b/callouts/nm-dispatcher-utils.h new file mode 100644 index 0000000000..33202e0ebe --- /dev/null +++ b/callouts/nm-dispatcher-utils.h @@ -0,0 +1,41 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * 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) 2008 - 2011 Red Hat, Inc. + */ + +#ifndef NM_DISPATCHER_UTILS_H +#define NM_DISPATCHER_UTILS_H + +#include + +char ** +nm_dispatcher_utils_construct_envp (const char *action, + GHashTable *connection_hash, + GHashTable *connection_props, + GHashTable *device_props, + GHashTable *device_ip4_props, + GHashTable *device_ip6_props, + GHashTable *device_dhcp4_props, + GHashTable *device_dhcp6_props, + const char *vpn_ip_iface, + GHashTable *vpn_ip4_props, + GHashTable *vpn_ip6_props, + char **out_iface); + +#endif /* NM_DISPATCHER_UTILS_H */ + diff --git a/callouts/nm-dispatcher.xml b/callouts/nm-dispatcher.xml index 532ae9f313..92780b1790 100644 --- a/callouts/nm-dispatcher.xml +++ b/callouts/nm-dispatcher.xml @@ -32,6 +32,46 @@ + + + Properties of the device's IPv4 configuration. + + + + + + Properties of the device's IPv6 configuration. + + + + + + Properties of the device's DHCPv4 configuration. + + + + + + Properties of the device's DHCPv6 configuration. + + + + + VPN interface name. + + + + + Properties of the VPN's IPv4 configuration. + + + + + + Properties of the VPN's IPv6 configuration. + + + diff --git a/callouts/tests/Makefile.am b/callouts/tests/Makefile.am new file mode 100644 index 0000000000..6a46b629f1 --- /dev/null +++ b/callouts/tests/Makefile.am @@ -0,0 +1,38 @@ +INCLUDES = \ + -I$(top_srcdir)/include \ + -I$(top_srcdir)/libnm-util \ + -I$(top_srcdir)/callouts + +noinst_PROGRAMS = \ + test-dispatcher-envp + +####### dispatcher envp ####### + +test_dispatcher_envp_SOURCES = \ + test-dispatcher-envp.c + +test_dispatcher_envp_CPPFLAGS = \ + $(GLIB_CFLAGS) \ + $(DBUS_CFLAGS) + +test_dispatcher_envp_LDADD = \ + $(top_builddir)/libnm-util/libnm-util.la \ + $(top_builddir)/callouts/libtest-dispatcher-envp.la \ + $(GLIB_LIBS) \ + $(DBUS_LIBS) + +########################################### + +if WITH_TESTS + +check-local: test-dispatcher-envp + $(abs_builddir)/test-dispatcher-envp $(abs_srcdir) + +endif + +EXTRA_DIST= \ + dispatcher-old-down \ + dispatcher-old-up \ + dispatcher-old-vpn-down \ + dispatcher-old-vpn-up + diff --git a/callouts/tests/dispatcher-old-down b/callouts/tests/dispatcher-old-down new file mode 100644 index 0000000000..4210921d38 --- /dev/null +++ b/callouts/tests/dispatcher-old-down @@ -0,0 +1,19 @@ +[main] +action=down +iface=wlan0 +uuid=3fd2a33a-d81b-423f-ae99-e6baba742311 +id=Random Connection + +[device] +state=30 +ip-interface=wlan0 +type=2 +interface=wlan0 +path=/org/freedesktop/NetworkManager/Devices/0 + +[env] +CONNECTION_UUID=3fd2a33a-d81b-423f-ae99-e6baba742311 +CONNECTION_ID=Random Connection +DEVICE_IFACE=wlan0 +DEVICE_IP_IFACE=wlan0 + diff --git a/callouts/tests/dispatcher-old-up b/callouts/tests/dispatcher-old-up new file mode 100644 index 0000000000..ed15fef541 --- /dev/null +++ b/callouts/tests/dispatcher-old-up @@ -0,0 +1,55 @@ +[main] +action=up +iface=wlan0 +uuid=3fd2a33a-d81b-423f-ae99-e6baba742311 +id=Random Connection + +[device] +state=100 +ip-interface=wlan0 +type=2 +interface=wlan0 +path=/org/freedesktop/NetworkManager/Devices/0 + +[dhcp4] +netbios_name_servers=0.0.0.0 +domain_name_servers=68.87.77.134 68.87.72.134 192.168.1.1 +dhcp_lease_time=86400 +network_number=192.168.1.0 +domain_name=hsd1.mn.comcast.net. +ip_address=192.168.1.119 +dhcp_message_type=5 +dhcp_server_identifier=192.168.1.1 +routers=192.168.1.1 +broadcast_address=192.168.1.255 +subnet_mask=255.255.255.0 +expiry=1304300446 + +[ip4] +addresses=192.168.1.119/24 192.168.1.1 +nameservers=68.87.77.134 68.87.72.134 192.168.1.1 +domains=hsd1.mn.comcast.net. + +[env] +CONNECTION_UUID=3fd2a33a-d81b-423f-ae99-e6baba742311 +CONNECTION_ID=Random Connection +DEVICE_IFACE=wlan0 +DEVICE_IP_IFACE=wlan0 +IP4_ADDRESS_0=192.168.1.119/24 192.168.1.1 +IP4_NUM_ADDRESSES=1 +IP4_NAMESERVERS=68.87.77.134 68.87.72.134 192.168.1.1 +IP4_DOMAINS=hsd1.mn.comcast.net. +IP4_NUM_ROUTES=0 +DHCP4_NETBIOS_NAME_SERVERS=0.0.0.0 +DHCP4_DOMAIN_NAME_SERVERS=68.87.77.134 68.87.72.134 192.168.1.1 +DHCP4_DHCP_LEASE_TIME=86400 +DHCP4_NETWORK_NUMBER=192.168.1.0 +DHCP4_DOMAIN_NAME=hsd1.mn.comcast.net. +DHCP4_IP_ADDRESS=192.168.1.119 +DHCP4_DHCP_MESSAGE_TYPE=5 +DHCP4_DHCP_SERVER_IDENTIFIER=192.168.1.1 +DHCP4_ROUTERS=192.168.1.1 +DHCP4_BROADCAST_ADDRESS=192.168.1.255 +DHCP4_SUBNET_MASK=255.255.255.0 +DHCP4_EXPIRY=1304300446 + diff --git a/callouts/tests/dispatcher-old-vpn-down b/callouts/tests/dispatcher-old-vpn-down new file mode 100644 index 0000000000..b45d8ea85a --- /dev/null +++ b/callouts/tests/dispatcher-old-vpn-down @@ -0,0 +1,54 @@ +[main] +action=vpn-down +iface=tun0 +uuid=355653c0-34d3-4777-ad25-f9a498b7ef8e +id=Random Connection + +[device] +state=100 +ip-interface=tun0 +type=2 +interface=wlan0 +path=/org/freedesktop/NetworkManager/Devices/0 + +[dhcp4] +netbios_name_servers=0.0.0.0 +domain_name_servers=68.87.77.134 68.87.72.134 192.168.1.1 +dhcp_lease_time=86400 +network_number=192.168.1.0 +domain_name=hsd1.mn.comcast.net. +ip_address=192.168.1.119 +dhcp_message_type=5 +dhcp_server_identifier=192.168.1.1 +routers=192.168.1.1 +broadcast_address=192.168.1.255 +subnet_mask=255.255.255.0 +expiry=1304349405 + +[ip4] +addresses=192.168.1.119/24 192.168.1.1 +nameservers=68.87.77.134 68.87.72.134 192.168.1.1 +domains=hsd1.mn.comcast.net. + +[env] +CONNECTION_UUID=355653c0-34d3-4777-ad25-f9a498b7ef8e +CONNECTION_ID=Random Connection +DEVICE_IFACE=wlan0 +DEVICE_IP_IFACE=tun0 +IP4_ADDRESS_0=192.168.1.119/24 192.168.1.1 +IP4_NUM_ADDRESSES=1 +IP4_NAMESERVERS=68.87.77.134 68.87.72.134 192.168.1.1 +IP4_DOMAINS=hsd1.mn.comcast.net. +IP4_NUM_ROUTES=0 +DHCP4_NETBIOS_NAME_SERVERS=0.0.0.0 +DHCP4_DOMAIN_NAME_SERVERS=68.87.77.134 68.87.72.134 192.168.1.1 +DHCP4_DHCP_LEASE_TIME=86400 +DHCP4_NETWORK_NUMBER=192.168.1.0 +DHCP4_DOMAIN_NAME=hsd1.mn.comcast.net. +DHCP4_IP_ADDRESS=192.168.1.119 +DHCP4_DHCP_MESSAGE_TYPE=5 +DHCP4_DHCP_SERVER_IDENTIFIER=192.168.1.1 +DHCP4_ROUTERS=192.168.1.1 +DHCP4_BROADCAST_ADDRESS=192.168.1.255 +DHCP4_SUBNET_MASK=255.255.255.0 +DHCP4_EXPIRY=1304349405 diff --git a/callouts/tests/dispatcher-old-vpn-up b/callouts/tests/dispatcher-old-vpn-up new file mode 100644 index 0000000000..f3b502defe --- /dev/null +++ b/callouts/tests/dispatcher-old-vpn-up @@ -0,0 +1,54 @@ +[main] +action=vpn-up +iface=tun0 +uuid=355653c0-34d3-4777-ad25-f9a498b7ef8e +id=Random Connection + +[device] +state=100 +ip-interface=tun0 +type=2 +interface=wlan0 +path=/org/freedesktop/NetworkManager/Devices/0 + +[dhcp4] +netbios_name_servers=0.0.0.0 +domain_name_servers=68.87.77.134 68.87.72.134 192.168.1.1 +dhcp_lease_time=86400 +network_number=192.168.1.0 +domain_name=hsd1.mn.comcast.net. +ip_address=192.168.1.119 +dhcp_message_type=5 +dhcp_server_identifier=192.168.1.1 +routers=192.168.1.1 +broadcast_address=192.168.1.255 +subnet_mask=255.255.255.0 +expiry=1304349405 + +[ip4] +addresses=192.168.1.119/24 192.168.1.1 +nameservers=68.87.77.134 68.87.72.134 192.168.1.1 +domains=hsd1.mn.comcast.net. + +[env] +CONNECTION_UUID=355653c0-34d3-4777-ad25-f9a498b7ef8e +CONNECTION_ID=Random Connection +DEVICE_IFACE=wlan0 +DEVICE_IP_IFACE=tun0 +IP4_ADDRESS_0=192.168.1.119/24 192.168.1.1 +IP4_NUM_ADDRESSES=1 +IP4_NAMESERVERS=68.87.77.134 68.87.72.134 192.168.1.1 +IP4_DOMAINS=hsd1.mn.comcast.net. +IP4_NUM_ROUTES=0 +DHCP4_NETBIOS_NAME_SERVERS=0.0.0.0 +DHCP4_DOMAIN_NAME_SERVERS=68.87.77.134 68.87.72.134 192.168.1.1 +DHCP4_DHCP_LEASE_TIME=86400 +DHCP4_NETWORK_NUMBER=192.168.1.0 +DHCP4_DOMAIN_NAME=hsd1.mn.comcast.net. +DHCP4_IP_ADDRESS=192.168.1.119 +DHCP4_DHCP_MESSAGE_TYPE=5 +DHCP4_DHCP_SERVER_IDENTIFIER=192.168.1.1 +DHCP4_ROUTERS=192.168.1.1 +DHCP4_BROADCAST_ADDRESS=192.168.1.255 +DHCP4_SUBNET_MASK=255.255.255.0 +DHCP4_EXPIRY=1304349405 diff --git a/callouts/tests/test-dispatcher-envp.c b/callouts/tests/test-dispatcher-envp.c new file mode 100644 index 0000000000..b4dbd784a9 --- /dev/null +++ b/callouts/tests/test-dispatcher-envp.c @@ -0,0 +1,615 @@ +/* -*- 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) 2011 Red Hat, Inc. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "nm-connection.h" +#include "nm-setting-connection.h" +#include "nm-dispatcher-utils.h" +#include "nm-dbus-glib-types.h" +#include "nm-dispatcher-action.h" +#include "nm-utils.h" + +/*******************************************/ + +static void +value_destroy (gpointer data) +{ + GValue *value = (GValue *) data; + + g_value_unset (value); + g_slice_free (GValue, value); +} + +static GHashTable * +value_hash_create (void) +{ + return g_hash_table_new_full (g_str_hash, g_str_equal, g_free, value_destroy); +} + +static void +value_hash_add (GHashTable *hash, + const char *key, + GValue *value) +{ + g_hash_table_insert (hash, g_strdup (key), value); +} + +static void +value_hash_add_string (GHashTable *hash, + const char *key, + const char *str) +{ + GValue *value; + + value = g_slice_new0 (GValue); + g_value_init (value, G_TYPE_STRING); + g_value_set_string (value, str); + + value_hash_add (hash, key, value); +} + +static void +value_hash_add_object_path (GHashTable *hash, + const char *key, + const char *op) +{ + GValue *value; + + value = g_slice_new0 (GValue); + g_value_init (value, DBUS_TYPE_G_OBJECT_PATH); + g_value_set_boxed (value, op); + + value_hash_add (hash, key, value); +} + +static void +value_hash_add_uint (GHashTable *hash, + const char *key, + guint32 val) +{ + GValue *value; + + value = g_slice_new0 (GValue); + g_value_init (value, G_TYPE_UINT); + g_value_set_uint (value, val); + + value_hash_add (hash, key, value); +} + +static void +value_hash_add_strv (GHashTable *hash, + const char *key, + GPtrArray *array) +{ + GValue *value; + + value = g_slice_new0 (GValue); + g_value_init (value, DBUS_TYPE_G_ARRAY_OF_STRING); + g_value_take_boxed (value, array); + value_hash_add (hash, key, value); +} + +static void +value_hash_add_uint_array (GHashTable *hash, + const char *key, + GArray *array) +{ + GValue *value; + + value = g_slice_new0 (GValue); + g_value_init (value, DBUS_TYPE_G_UINT_ARRAY); + g_value_take_boxed (value, array); + value_hash_add (hash, key, value); +} + +static gboolean +parse_main (GKeyFile *kf, + GHashTable **out_con_hash, + GHashTable **out_con_props, + char **out_iface, + char **out_action, + GError **error) +{ + char *uuid, *id; + NMConnection *connection; + NMSettingConnection *s_con; + + *out_iface = g_key_file_get_string (kf, "main", "iface", error); + if (*out_iface == NULL) + return FALSE; + + *out_action = g_key_file_get_string (kf, "main", "action", error); + if (*out_action == NULL) + return FALSE; + + uuid = g_key_file_get_string (kf, "main", "uuid", error); + if (uuid == NULL) + return FALSE; + id = g_key_file_get_string (kf, "main", "id", error); + if (id == NULL) + return FALSE; + + connection = nm_connection_new (); + g_assert (connection); + s_con = (NMSettingConnection *) nm_setting_connection_new (); + g_assert (s_con); + g_object_set (s_con, + NM_SETTING_CONNECTION_UUID, uuid, + NM_SETTING_CONNECTION_ID, id, + NULL); + g_free (uuid); + g_free (id); + nm_connection_add_setting (connection, NM_SETTING (s_con)); + + *out_con_hash = nm_connection_to_hash (connection, NM_SETTING_HASH_FLAG_ALL); + g_object_unref (connection); + + *out_con_props = value_hash_create (); + value_hash_add_object_path (*out_con_props, "connection-path", "/org/freedesktop/NetworkManager/Connections/5"); + + return TRUE; +} + +static gboolean +parse_device (GKeyFile *kf, GHashTable **out_device_props, GError **error) +{ + char *tmp; + gint i; + + *out_device_props = value_hash_create (); + + i = g_key_file_get_integer (kf, "device", "state", error); + if (i == 0) + return FALSE; + value_hash_add_uint (*out_device_props, NMD_DEVICE_PROPS_STATE, (guint) i); + + i = g_key_file_get_integer (kf, "device", "type", error); + if (i == 0) + return FALSE; + value_hash_add_uint (*out_device_props, NMD_DEVICE_PROPS_TYPE, (guint) i); + + tmp = g_key_file_get_string (kf, "device", "interface", error); + if (tmp == NULL) + return FALSE; + value_hash_add_string (*out_device_props, NMD_DEVICE_PROPS_INTERFACE, tmp); + g_free (tmp); + + tmp = g_key_file_get_string (kf, "device", "ip-interface", error); + if (tmp == NULL) + return FALSE; + value_hash_add_string (*out_device_props, NMD_DEVICE_PROPS_IP_INTERFACE, tmp); + g_free (tmp); + + tmp = g_key_file_get_string (kf, "device", "path", error); + if (tmp == NULL) + return FALSE; + value_hash_add_object_path (*out_device_props, NMD_DEVICE_PROPS_PATH, tmp); + g_free (tmp); + + return TRUE; +} + +static gboolean +add_uint_array (GKeyFile *kf, + GHashTable *props, + const char *section, + const char *key, + GError **error) +{ + char *tmp; + char **split, **iter; + GArray *items; + + tmp = g_key_file_get_string (kf, section, key, error); + if (tmp == NULL) { + g_clear_error (error); + return TRUE; + } + split = g_strsplit_set (tmp, " ", -1); + g_free (tmp); + + if (g_strv_length (split) > 0) { + items = g_array_sized_new (FALSE, TRUE, sizeof (guint32), g_strv_length (split)); + for (iter = split; iter && *iter; iter++) { + if (strlen (g_strstrip (*iter))) { + struct in_addr addr; + + g_assert_cmpint (inet_pton (AF_INET, *iter, &addr), ==, 1); + g_array_append_val (items, addr.s_addr); + } + } + value_hash_add_uint_array (props, key, items); + } + g_strfreev (split); + return TRUE; +} + +static gboolean +parse_ip4 (GKeyFile *kf, GHashTable **out_props, const char *section, GError **error) +{ + char *tmp; + char **split, **iter; + GPtrArray *domains; + GSList *list; + GValue *val; + + *out_props = value_hash_create (); + + /* search domains */ + tmp = g_key_file_get_string (kf, section, "domains", error); + if (tmp == NULL) + return FALSE; + split = g_strsplit_set (tmp, " ", -1); + g_free (tmp); + + if (g_strv_length (split) > 0) { + domains = g_ptr_array_sized_new (g_strv_length (split)); + for (iter = split; iter && *iter; iter++) { + if (strlen (g_strstrip (*iter))) + g_ptr_array_add (domains, g_strdup (*iter)); + } + value_hash_add_strv (*out_props, "domains", domains); + } + g_strfreev (split); + + /* nameservers */ + if (!add_uint_array (kf, *out_props, "ip4", "nameservers", error)) + return FALSE; + /* wins-servers */ + if (!add_uint_array (kf, *out_props, "ip4", "wins-servers", error)) + return FALSE; + + /* Addresses */ + tmp = g_key_file_get_string (kf, section, "addresses", error); + if (tmp == NULL) + return FALSE; + split = g_strsplit_set (tmp, ",", -1); + g_free (tmp); + + if (g_strv_length (split) > 0) { + list = NULL; + for (iter = split; iter && *iter; iter++) { + NMIP4Address *addr; + struct in_addr a; + char *p; + + if (strlen (g_strstrip (*iter)) == 0) + continue; + + addr = nm_ip4_address_new (); + + p = strchr (*iter, '/'); + g_assert (p); + *p++ = '\0'; + + g_assert_cmpint (inet_pton (AF_INET, *iter, &a), ==, 1); + nm_ip4_address_set_address (addr, a.s_addr); + nm_ip4_address_set_prefix (addr, (guint) atoi (p)); + + p = strchr (p, ' '); + g_assert (p); + p++; + + g_assert_cmpint (inet_pton (AF_INET, p, &a), ==, 1); + nm_ip4_address_set_gateway (addr, a.s_addr); + + list = g_slist_append (list, addr); + } + + val = g_slice_new0 (GValue); + g_value_init (val, DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT); + nm_utils_ip4_addresses_to_gvalue (list, val); + value_hash_add (*out_props, "addresses", val); + } + g_strfreev (split); + + /* Routes */ + tmp = g_key_file_get_string (kf, section, "routes", error); + g_clear_error (error); + if (tmp) { + split = g_strsplit_set (tmp, ",", -1); + g_free (tmp); + + if (g_strv_length (split) > 0) { + list = NULL; + for (iter = split; iter && *iter; iter++) { + NMIP4Route *route; + struct in_addr a; + char *p; + + if (strlen (g_strstrip (*iter)) == 0) + continue; + + route = nm_ip4_route_new (); + + p = strchr (*iter, '/'); + g_assert (p); + *p++ = '\0'; + + g_assert_cmpint (inet_pton (AF_INET, *iter, &a), ==, 1); + nm_ip4_route_set_dest (route, a.s_addr); + nm_ip4_route_set_prefix (route, (guint) atoi (p)); + + p = strchr (p, ' '); + g_assert (p); + p++; + + g_assert_cmpint (inet_pton (AF_INET, p, &a), ==, 1); + nm_ip4_route_set_next_hop (route, a.s_addr); + + p = strchr (p, ' '); + g_assert (p); + p++; + nm_ip4_route_set_metric (route, (guint) atoi (p)); + + list = g_slist_append (list, route); + } + + val = g_slice_new0 (GValue); + g_value_init (val, DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT); + nm_utils_ip4_routes_to_gvalue (list, val); + value_hash_add (*out_props, "routes", val); + } + g_strfreev (split); + } + + return TRUE; +} + +static gboolean +parse_dhcp (GKeyFile *kf, + const char *group_name, + GHashTable **out_props, + GError **error) +{ + char **keys, **iter, *val; + + keys = g_key_file_get_keys (kf, group_name, NULL, error); + if (!keys) + return FALSE; + + *out_props = value_hash_create (); + for (iter = keys; iter && *iter; iter++) { + val = g_key_file_get_string (kf, group_name, *iter, error); + if (!val) + return FALSE; + value_hash_add_string (*out_props, *iter, val); + g_free (val); + } + + return TRUE; +} + +static gboolean +get_dispatcher_file (const char *file, + GHashTable **out_con_hash, + GHashTable **out_con_props, + GHashTable **out_device_props, + GHashTable **out_device_ip4_props, + GHashTable **out_device_ip6_props, + GHashTable **out_device_dhcp4_props, + GHashTable **out_device_dhcp6_props, + const char **out_vpn_ip_iface, + GHashTable **out_vpn_ip4_props, + GHashTable **out_vpn_ip6_props, + char **out_expected_iface, + char **out_action, + GHashTable **out_env, + GError **error) +{ + GKeyFile *kf; + gboolean success = FALSE; + char **keys, **iter, *val; + + kf = g_key_file_new (); + if (!g_key_file_load_from_file (kf, file, G_KEY_FILE_NONE, error)) + return FALSE; + + if (!parse_main (kf, out_con_hash, out_con_props, out_expected_iface, out_action, error)) + goto out; + + if (!parse_device (kf, out_device_props, error)) + goto out; + + if (g_key_file_has_group (kf, "ip4")) { + if (!parse_ip4 (kf, out_device_ip4_props, "ip4", error)) + goto out; + } + + if (g_key_file_has_group (kf, "dhcp4")) { + if (!parse_dhcp (kf, "dhcp4", out_device_dhcp4_props, error)) + goto out; + } + + if (g_key_file_has_group (kf, "dhcp6")) { + if (!parse_dhcp (kf, "dhcp6", out_device_dhcp4_props, error)) + goto out; + } + + g_assert (g_key_file_has_group (kf, "env")); + keys = g_key_file_get_keys (kf, "env", NULL, error); + *out_env = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + for (iter = keys; iter && *iter; iter++) { + val = g_key_file_get_string (kf, "env", *iter, error); + if (!val) + goto out; + g_hash_table_insert (*out_env, + g_strdup_printf ("%s=%s", *iter, val), + GUINT_TO_POINTER (1)); + g_free (val); + } + g_strfreev (keys); + + success = TRUE; + +out: + g_key_file_free (kf); + return success; +} + +/*******************************************/ + +static void +test_generic (const char *path, const char *file) +{ + GHashTable *con_hash = NULL; + GHashTable *con_props = NULL; + GHashTable *device_props = NULL; + GHashTable *device_ip4_props = NULL; + GHashTable *device_ip6_props = NULL; + GHashTable *device_dhcp4_props = NULL; + GHashTable *device_dhcp6_props = NULL; + const char *vpn_ip_iface = NULL; + GHashTable *vpn_ip4_props = NULL; + GHashTable *vpn_ip6_props = NULL; + char *expected_iface = NULL; + char *action = NULL; + char *out_iface = NULL; + GHashTable *expected_env = NULL; + GError *error = NULL; + gboolean success; + char *p; + char **denv, **iter; + + /* Read in the test file */ + p = g_strdup_printf ("%s/%s", path, file); + success = get_dispatcher_file (p, + &con_hash, + &con_props, + &device_props, + &device_ip4_props, + &device_ip6_props, + &device_dhcp4_props, + &device_dhcp6_props, + &vpn_ip_iface, + &vpn_ip4_props, + &vpn_ip6_props, + &expected_iface, + &action, + &expected_env, + &error); + g_free (p); + g_assert_no_error (error); + g_assert (success); + + /* Get the environment from the dispatcher code */ + denv = nm_dispatcher_utils_construct_envp (action, + con_hash, + con_props, + device_props, + device_ip4_props, + device_ip6_props, + device_dhcp4_props, + device_dhcp6_props, + vpn_ip_iface, + vpn_ip4_props, + vpn_ip6_props, + &out_iface); + + /* Print out environment for now */ + g_message ("\n"); + for (iter = denv; iter && *iter; iter++) + g_message (" %s", *iter); + + g_assert_cmpint (g_strv_length (denv), ==, g_hash_table_size (expected_env)); + + { + GHashTableIter k; + const char *key; + g_hash_table_iter_init (&k, expected_env); + while (g_hash_table_iter_next (&k, (gpointer) &key, NULL)) + g_message (" %s", key); + } + + /* Compare dispatcher generated env and expected env */ + for (iter = denv; iter && *iter; iter++) { + gpointer foo; + + foo = g_hash_table_lookup (expected_env, *iter); + if (!foo) + g_warning ("Failed to find %s in environment", *iter); + g_assert (foo); + } + + g_assert_cmpstr (expected_iface, ==, out_iface); +} + +/*******************************************/ + +static void +test_old_up (const char *path) +{ + test_generic (path, "dispatcher-old-up"); +} + +static void +test_old_down (const char *path) +{ + test_generic (path, "dispatcher-old-down"); +} + +static void +test_old_vpn_up (const char *path) +{ + test_generic (path, "dispatcher-old-vpn-up"); +} + +static void +test_old_vpn_down (const char *path) +{ + test_generic (path, "dispatcher-old-vpn-down"); +} + +/*******************************************/ + +#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_assert (argc > 1); + + g_test_init (&argc, &argv, NULL); + g_type_init (); + + suite = g_test_get_root (); + + g_test_suite_add (suite, TESTCASE (test_old_up, argv[1])); + g_test_suite_add (suite, TESTCASE (test_old_down, argv[1])); + g_test_suite_add (suite, TESTCASE (test_old_vpn_up, argv[1])); + g_test_suite_add (suite, TESTCASE (test_old_vpn_down, argv[1])); + + return g_test_run (); +} + diff --git a/configure.ac b/configure.ac index 427029cf8b..72f113395a 100644 --- a/configure.ac +++ b/configure.ac @@ -631,6 +631,7 @@ libnm-glib/libnm-glib-vpn.pc libnm-glib/Makefile libnm-glib/tests/Makefile callouts/Makefile +callouts/tests/Makefile tools/Makefile cli/Makefile cli/src/Makefile diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index 3981a1db39..d069eca75d 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -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) 2004 - 2010 Red Hat, Inc. + * Copyright (C) 2004 - 2011 Red Hat, Inc. * Copyright (C) 2005 - 2008 Novell, Inc. */ @@ -373,6 +373,72 @@ nm_utils_merge_ip6_config (NMIP6Config *ip6_config, NMSettingIP6Config *setting) nm_ip6_config_set_never_default (ip6_config, TRUE); } +static void +dump_object_to_props (GObject *object, GHashTable *hash) +{ + GParamSpec **pspecs; + guint len = 0, i; + + pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (object), &len); + for (i = 0; i < len; i++) { + value_hash_add_object_property (hash, + pspecs[i]->name, + object, + pspecs[i]->name, + pspecs[i]->value_type); + } + g_free (pspecs); +} + +static void +fill_device_props (NMDevice *device, + GHashTable *dev_hash, + GHashTable *ip4_hash, + GHashTable *ip6_hash, + GHashTable *dhcp4_hash, + GHashTable *dhcp6_hash) +{ + NMIP4Config *ip4_config; + NMIP6Config *ip6_config; + NMDHCP4Config *dhcp4_config; + NMDHCP6Config *dhcp6_config; + + /* If the action is for a VPN, send the VPN's IP interface instead of the device's */ + value_hash_add_str (dev_hash, NMD_DEVICE_PROPS_IP_INTERFACE, nm_device_get_ip_iface (device)); + value_hash_add_str (dev_hash, NMD_DEVICE_PROPS_INTERFACE, nm_device_get_iface (device)); + value_hash_add_uint (dev_hash, NMD_DEVICE_PROPS_TYPE, nm_device_get_device_type (device)); + value_hash_add_uint (dev_hash, NMD_DEVICE_PROPS_STATE, nm_device_get_state (device)); + value_hash_add_object_path (dev_hash, NMD_DEVICE_PROPS_PATH, nm_device_get_path (device)); + + ip4_config = nm_device_get_ip4_config (device); + if (ip4_config) + dump_object_to_props (G_OBJECT (ip4_config), ip4_hash); + + ip6_config = nm_device_get_ip6_config (device); + if (ip6_config) + dump_object_to_props (G_OBJECT (ip6_config), ip6_hash); + + dhcp4_config = nm_device_get_dhcp4_config (device); + if (dhcp4_config) + dump_object_to_props (G_OBJECT (dhcp4_config), dhcp4_hash); + + dhcp6_config = nm_device_get_dhcp6_config (device); + if (dhcp6_config) + dump_object_to_props (G_OBJECT (dhcp6_config), dhcp6_hash); +} + +static void +fill_vpn_props (NMIP4Config *ip4_config, + NMIP6Config *ip6_config, + GHashTable *ip4_hash, + GHashTable *ip6_hash) +{ + if (ip4_config) + dump_object_to_props (G_OBJECT (ip4_config), ip4_hash); + if (ip6_config) + dump_object_to_props (G_OBJECT (ip6_config), ip6_hash); +} + static void dispatcher_done_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data) { @@ -384,7 +450,9 @@ void nm_utils_call_dispatcher (const char *action, NMConnection *connection, NMDevice *device, - const char *vpn_iface) + const char *vpn_iface, + NMIP4Config *vpn_ip4_config, + NMIP6Config *vpn_ip6_config) { NMDBusManager *dbus_mgr; DBusGProxy *proxy; @@ -392,12 +460,21 @@ nm_utils_call_dispatcher (const char *action, GHashTable *connection_hash; GHashTable *connection_props; GHashTable *device_props; + GHashTable *device_ip4_props; + GHashTable *device_ip6_props; + GHashTable *device_dhcp4_props; + GHashTable *device_dhcp6_props; + GHashTable *vpn_ip4_props; + GHashTable *vpn_ip6_props; g_return_if_fail (action != NULL); /* All actions except 'hostname' require a device */ - if (strcmp (action, "hostname")) + if (strcmp (action, "hostname") != 0) g_return_if_fail (NM_IS_DEVICE (device)); + /* VPN actions require at least an IPv4 config (for now) */ + if (strcmp (action, "vpn-up") == 0) + g_return_if_fail (vpn_ip4_config != NULL); dbus_mgr = nm_dbus_manager_get (); g_connection = nm_dbus_manager_get_connection (dbus_mgr); @@ -426,25 +503,23 @@ nm_utils_call_dispatcher (const char *action, } device_props = value_hash_create (); + device_ip4_props = value_hash_create (); + device_ip6_props = value_hash_create (); + device_dhcp4_props = value_hash_create (); + device_dhcp6_props = value_hash_create (); + vpn_ip4_props = value_hash_create (); + vpn_ip6_props = value_hash_create (); - /* Hostname actions do not require a device */ - if (strcmp (action, "hostname")) { - /* interface */ - value_hash_add_str (device_props, NMD_DEVICE_PROPS_INTERFACE, nm_device_get_iface (device)); - - /* IP interface */ - if (vpn_iface) { - value_hash_add_str (device_props, NMD_DEVICE_PROPS_IP_INTERFACE, vpn_iface); - } else if (nm_device_get_ip_iface (device)) { - value_hash_add_str (device_props, NMD_DEVICE_PROPS_IP_INTERFACE, nm_device_get_ip_iface (device)); - } - - /* type */ - value_hash_add_uint (device_props, NMD_DEVICE_PROPS_TYPE, nm_device_get_device_type (device)); - - /* state */ - value_hash_add_uint (device_props, NMD_DEVICE_PROPS_STATE, nm_device_get_state (device)); - value_hash_add_object_path (device_props, NMD_DEVICE_PROPS_PATH, nm_device_get_path (device)); + /* hostname actions only send the hostname */ + if (strcmp (action, "hostname") != 0) { + fill_device_props (device, + device_props, + device_ip4_props, + device_ip6_props, + device_dhcp4_props, + device_dhcp6_props); + if (vpn_iface) + fill_vpn_props (vpn_ip4_config, NULL, vpn_ip4_props, vpn_ip6_props); } /* Do a non-blocking call, but wait for the reply, because dbus-glib @@ -455,17 +530,30 @@ nm_utils_call_dispatcher (const char *action, */ dbus_g_proxy_begin_call_with_timeout (proxy, "Action", dispatcher_done_cb, - dbus_mgr, + dbus_mgr, /* automatically unref the dbus mgr when call is done */ g_object_unref, 5000, G_TYPE_STRING, action, DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, connection_hash, DBUS_TYPE_G_MAP_OF_VARIANT, connection_props, DBUS_TYPE_G_MAP_OF_VARIANT, device_props, + DBUS_TYPE_G_MAP_OF_VARIANT, device_ip4_props, + DBUS_TYPE_G_MAP_OF_VARIANT, device_ip6_props, + DBUS_TYPE_G_MAP_OF_VARIANT, device_dhcp4_props, + DBUS_TYPE_G_MAP_OF_VARIANT, device_dhcp6_props, + G_TYPE_STRING, vpn_iface ? vpn_iface : "", + DBUS_TYPE_G_MAP_OF_VARIANT, vpn_ip4_props, + DBUS_TYPE_G_MAP_OF_VARIANT, vpn_ip6_props, G_TYPE_INVALID); g_hash_table_destroy (connection_hash); g_hash_table_destroy (connection_props); g_hash_table_destroy (device_props); + g_hash_table_destroy (device_ip4_props); + g_hash_table_destroy (device_ip6_props); + g_hash_table_destroy (device_dhcp4_props); + g_hash_table_destroy (device_dhcp6_props); + g_hash_table_destroy (vpn_ip4_props); + g_hash_table_destroy (vpn_ip6_props); } gboolean @@ -670,6 +758,21 @@ value_hash_add_bool (GHashTable *hash, value_hash_add (hash, key, value); } +void +value_hash_add_object_property (GHashTable *hash, + const char *key, + GObject *object, + const char *prop, + GType val_type) +{ + GValue *value; + + value = g_slice_new0 (GValue); + g_value_init (value, val_type); + g_object_get_property (object, prop, value); + value_hash_add (hash, key, value); +} + gboolean nm_utils_do_sysctl (const char *path, const char *value) { diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h index 6f48a78823..aaa267fb0f 100644 --- a/src/NetworkManagerUtils.h +++ b/src/NetworkManagerUtils.h @@ -45,7 +45,9 @@ void nm_utils_merge_ip6_config (NMIP6Config *ip6_config, NMSettingIP6Config *set void nm_utils_call_dispatcher (const char *action, NMConnection *connection, NMDevice *device, - const char *vpn_iface); + const char *vpn_iface, + NMIP4Config *vpn_ip4_config, + NMIP6Config *vpn_ip6_config); gboolean nm_match_spec_hwaddr (const GSList *specs, const char *hwaddr); gboolean nm_match_spec_s390_subchannels (const GSList *specs, const char *subchannels); @@ -72,6 +74,12 @@ void value_hash_add_bool (GHashTable *hash, const char *key, gboolean val); +void value_hash_add_object_property (GHashTable *hash, + const char *key, + GObject *object, + const char *prop, + GType val_type); + gboolean nm_utils_do_sysctl (const char *path, const char *value); gboolean nm_utils_get_proc_sys_net_value (const char *path, diff --git a/src/nm-device.c b/src/nm-device.c index ff9aab77af..b13172e10a 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -1384,7 +1384,7 @@ handle_dhcp_lease_change (NMDevice *device, gboolean ipv6) nm_dhcp_client_foreach_option (priv->dhcp6_client, dhcp6_add_option_cb, priv->dhcp6_config); - nm_utils_call_dispatcher ("dhcp6-change", connection, device, NULL); + nm_utils_call_dispatcher ("dhcp6-change", connection, device, NULL, NULL, NULL); } else { nm_log_warn (LOGD_DHCP6, "(%s): failed to update IPv6 config in response to DHCP event.", nm_device_get_ip_iface (device)); @@ -1409,7 +1409,7 @@ handle_dhcp_lease_change (NMDevice *device, gboolean ipv6) nm_dhcp_client_foreach_option (priv->dhcp4_client, dhcp4_add_option_cb, priv->dhcp4_config); - nm_utils_call_dispatcher ("dhcp4-change", connection, device, NULL); + nm_utils_call_dispatcher ("dhcp4-change", connection, device, NULL, NULL, NULL); } else { nm_log_warn (LOGD_DHCP6, "(%s): failed to update IPv4 config in response to DHCP event.", nm_device_get_ip_iface (device)); @@ -3781,7 +3781,7 @@ nm_device_state_changed (NMDevice *device, case NM_DEVICE_STATE_ACTIVATED: nm_log_info (LOGD_DEVICE, "Activation (%s) successful, device activated.", nm_device_get_iface (device)); - nm_utils_call_dispatcher ("up", nm_act_request_get_connection (req), device, NULL); + nm_utils_call_dispatcher ("up", nm_act_request_get_connection (req), device, NULL, NULL, NULL); break; case NM_DEVICE_STATE_FAILED: nm_log_warn (LOGD_DEVICE, "Activation (%s) failed.", nm_device_get_iface (device)); @@ -3796,7 +3796,7 @@ nm_device_state_changed (NMDevice *device, } if (old_state == NM_DEVICE_STATE_ACTIVATED) - nm_utils_call_dispatcher ("down", nm_act_request_get_connection (req), device, NULL); + nm_utils_call_dispatcher ("down", nm_act_request_get_connection (req), device, NULL, NULL, NULL); /* Dispose of the cached activation request */ if (req) diff --git a/src/nm-policy.c b/src/nm-policy.c index 0e7897cbd9..5c30828b2d 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -238,7 +238,7 @@ _set_hostname (NMPolicy *policy, } if (nm_policy_set_system_hostname (policy->cur_hostname, msg)) - nm_utils_call_dispatcher ("hostname", NULL, NULL, NULL); + nm_utils_call_dispatcher ("hostname", NULL, NULL, NULL, NULL, NULL); } static void diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c index 503fc190da..cf6135a684 100644 --- a/src/vpn-manager/nm-vpn-connection.c +++ b/src/vpn-manager/nm-vpn-connection.c @@ -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 - 2010 Red Hat, Inc. + * Copyright (C) 2005 - 2011 Red Hat, Inc. * Copyright (C) 2006 - 2008 Novell, Inc. */ @@ -140,7 +140,9 @@ nm_vpn_connection_set_vpn_state (NMVPNConnection *connection, nm_utils_call_dispatcher ("vpn-up", priv->connection, priv->parent_dev, - ip_iface); + ip_iface, + priv->ip4_config, + NULL); break; case NM_VPN_CONNECTION_STATE_FAILED: case NM_VPN_CONNECTION_STATE_DISCONNECTED: @@ -148,7 +150,9 @@ nm_vpn_connection_set_vpn_state (NMVPNConnection *connection, nm_utils_call_dispatcher ("vpn-down", priv->connection, priv->parent_dev, - ip_iface); + ip_iface, + NULL, + NULL); } break; default: