From f898dbf1a9cb657c3970fc9044d99dc46455f690 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 2 May 2011 22:38:51 -0500 Subject: [PATCH] dispatcher: enhance dispatcher script environment (bgo #648382) For VPN connections, the interface name would be that of the VPN's IP interface, but the script environment would be the that of the VPN's parent device. Enhance the environment by adding any VPN specific details as additional environment variables prefixed by "VPN_". Leave the existing environment setup intact for backwards compatiblity. Additionally, the dispatcher never got updated for IPv6 support, so push IPv6 configuration and DHCPv6 configuration into the environment too. Even better, push everything the dispatcher needs to it instead of making the dispatcher make D-Bus requests back to NM, which sometimes fails if NM has already torn down the device or the connection which the device was using. And add some testcases to ensure that we don't break backwards compat, the testcases here were grabbed from a 0.8.4 machine with a hacked up dispatcher to dump everything it was given from NM. --- .gitignore | 1 + callouts/Makefile.am | 35 +- callouts/nm-dispatcher-action.c | 327 ++----------- callouts/nm-dispatcher-utils.c | 509 ++++++++++++++++++++ callouts/nm-dispatcher-utils.h | 41 ++ callouts/nm-dispatcher.xml | 40 ++ callouts/tests/Makefile.am | 38 ++ callouts/tests/dispatcher-old-down | 19 + callouts/tests/dispatcher-old-up | 55 +++ callouts/tests/dispatcher-old-vpn-down | 54 +++ callouts/tests/dispatcher-old-vpn-up | 54 +++ callouts/tests/test-dispatcher-envp.c | 615 +++++++++++++++++++++++++ configure.ac | 1 + src/NetworkManagerUtils.c | 147 +++++- src/NetworkManagerUtils.h | 10 +- src/nm-device.c | 8 +- src/nm-policy.c | 2 +- src/vpn-manager/nm-vpn-connection.c | 10 +- 18 files changed, 1646 insertions(+), 320 deletions(-) create mode 100644 callouts/nm-dispatcher-utils.c create mode 100644 callouts/nm-dispatcher-utils.h create mode 100644 callouts/tests/Makefile.am create mode 100644 callouts/tests/dispatcher-old-down create mode 100644 callouts/tests/dispatcher-old-up create mode 100644 callouts/tests/dispatcher-old-vpn-down create mode 100644 callouts/tests/dispatcher-old-vpn-up create mode 100644 callouts/tests/test-dispatcher-envp.c 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: