diff options
| author | Michael Biebl <biebl@debian.org> | 2021-10-01 23:05:04 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2021-10-01 23:05:04 +0200 |
| commit | e74c568b07b50b97873fb4ee1d776dedefbd54d6 (patch) | |
| tree | 3469f17ea9af91f7ff169b890633bda68b0cf76e /dispatcher | |
| parent | bfe522304da217296e2a61040f58e35ec5d6f3f2 (diff) | |
New upstream version 1.32.12 upstream/1.32.12
Diffstat (limited to 'dispatcher')
| -rw-r--r-- | dispatcher/meson.build | 57 | ||||
| -rw-r--r-- | dispatcher/nm-dispatcher-utils.c | 581 | ||||
| -rw-r--r-- | dispatcher/nm-dispatcher-utils.h | 26 | ||||
| -rw-r--r-- | dispatcher/nm-dispatcher.c | 1101 | ||||
| -rw-r--r-- | dispatcher/nm-dispatcher.conf | 13 | ||||
| -rw-r--r-- | dispatcher/nm-dispatcher.xml | 46 | ||||
| -rw-r--r-- | dispatcher/org.freedesktop.nm_dispatcher.service.in | 6 | ||||
| -rw-r--r-- | dispatcher/tests/dispatcher-connectivity-full | 17 | ||||
| -rw-r--r-- | dispatcher/tests/dispatcher-connectivity-unknown | 16 | ||||
| -rw-r--r-- | dispatcher/tests/dispatcher-down | 23 | ||||
| -rw-r--r-- | dispatcher/tests/dispatcher-external | 40 | ||||
| -rw-r--r-- | dispatcher/tests/dispatcher-up | 66 | ||||
| -rw-r--r-- | dispatcher/tests/dispatcher-vpn-down | 65 | ||||
| -rw-r--r-- | dispatcher/tests/dispatcher-vpn-up | 65 | ||||
| -rw-r--r-- | dispatcher/tests/meson.build | 24 | ||||
| -rw-r--r-- | dispatcher/tests/test-dispatcher-envp.c | 637 |
16 files changed, 0 insertions, 2783 deletions
diff --git a/dispatcher/meson.build b/dispatcher/meson.build deleted file mode 100644 index d12e4714..00000000 --- a/dispatcher/meson.build +++ /dev/null @@ -1,57 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later - -dispatcher_inc = include_directories('.') - -configure_file( - input: 'org.freedesktop.nm_dispatcher.service.in', - output: '@BASENAME@', - install_dir: dbus_system_bus_services_dir, - configuration: data_conf, -) - -install_data( - 'nm-dispatcher.conf', - install_dir: dbus_conf_dir, -) - -libnm_dispatcher_core = static_library( - 'nm-dispatcher-core', - sources: 'nm-dispatcher-utils.c', - dependencies: [ - libnm_dep, - libnm_nm_default_dep, - libnm_libnm_aux_dep, - ], - c_args: [ - '-DG_LOG_DOMAIN="nm-dispatcher"', - ], -) - -nmdbus_dispatcher_sources = gnome.gdbus_codegen( - 'nmdbus-dispatcher', - 'nm-dispatcher.xml', - interface_prefix: 'org.freedesktop', - namespace: 'NMDBus', -) - -executable( - 'nm-dispatcher', - 'nm-dispatcher.c', - dependencies: [ - libnm_dep, - libnm_nm_default_dep, - libnm_libnm_aux_dep, - ], - c_args: [ - '-DG_LOG_DOMAIN="nm-dispatcher"', - ], - link_with: libnm_dispatcher_core, - link_args: ldflags_linker_script_binary, - link_depends: linker_script_binary, - install: true, - install_dir: nm_libexecdir, -) - -if enable_tests - subdir('tests') -endif diff --git a/dispatcher/nm-dispatcher-utils.c b/dispatcher/nm-dispatcher-utils.c deleted file mode 100644 index f1ec979f..00000000 --- a/dispatcher/nm-dispatcher-utils.c +++ /dev/null @@ -1,581 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2008 - 2011 Red Hat, Inc. - */ - -#include "libnm/nm-default-client.h" - -#include "nm-dispatcher-utils.h" - -#include "nm-dbus-interface.h" -#include "nm-connection.h" -#include "nm-setting-ip4-config.h" -#include "nm-setting-ip6-config.h" -#include "nm-setting-connection.h" - -#include "nm-libnm-core-aux/nm-dispatcher-api.h" -#include "nm-utils.h" - -/*****************************************************************************/ - -static gboolean -_is_valid_key(const char *line, gssize len) -{ - gsize i, l; - char ch; - - if (!line) - return FALSE; - - if (len < 0) - len = strlen(line); - - if (len == 0) - return FALSE; - - ch = line[0]; - if (!(ch >= 'A' && ch <= 'Z') && !NM_IN_SET(ch, '_')) - return FALSE; - - l = (gsize) len; - - for (i = 1; i < l; i++) { - ch = line[i]; - - if (!(ch >= 'A' && ch <= 'Z') && !(ch >= '0' && ch <= '9') && !NM_IN_SET(ch, '_')) - return FALSE; - } - - return TRUE; -} - -static gboolean -_is_valid_line(const char *line) -{ - const char *d; - - if (!line) - return FALSE; - - d = strchr(line, '='); - if (!d || d == line) - return FALSE; - - return _is_valid_key(line, d - line); -} - -static char * -_sanitize_var_name(const char *key) -{ - char *sanitized; - - nm_assert(key); - - if (!key[0]) - return NULL; - - sanitized = g_ascii_strup(key, -1); - if (!NM_STRCHAR_ALL(sanitized, - ch, - (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') - || NM_IN_SET(ch, '_'))) { - g_free(sanitized); - return NULL; - } - - nm_assert(_is_valid_key(sanitized, -1)); - return sanitized; -} - -static void -_items_add_str_take(GPtrArray *items, char *line) -{ - nm_assert(items); - nm_assert(_is_valid_line(line)); - - g_ptr_array_add(items, line); -} - -static void -_items_add_str(GPtrArray *items, const char *line) -{ - _items_add_str_take(items, g_strdup(line)); -} - -static void -_items_add_key(GPtrArray *items, const char *prefix, const char *key, const char *value) -{ - nm_assert(items); - nm_assert(_is_valid_key(key, -1)); - nm_assert(value); - - _items_add_str_take(items, g_strconcat(prefix ?: "", key, "=", value, NULL)); -} - -static void -_items_add_key0(GPtrArray *items, const char *prefix, const char *key, const char *value) -{ - nm_assert(items); - nm_assert(_is_valid_key(key, -1)); - - if (!value) { - /* for convenience, allow NULL values to indicate to skip the line. */ - return; - } - - _items_add_str_take(items, g_strconcat(prefix ?: "", key, "=", value, NULL)); -} - -G_GNUC_PRINTF(2, 3) -static void -_items_add_printf(GPtrArray *items, const char *fmt, ...) -{ - va_list ap; - char * line; - - nm_assert(items); - nm_assert(fmt); - - va_start(ap, fmt); - line = g_strdup_vprintf(fmt, ap); - va_end(ap); - _items_add_str_take(items, line); -} - -static void -_items_add_strv(GPtrArray *items, const char *prefix, const char *key, const char *const *values) -{ - gboolean has; - guint i; - GString *str; - - nm_assert(items); - nm_assert(_is_valid_key(key, -1)); - - if (!values || !values[0]) { - /* Only add an item if the list of @values is not empty */ - return; - } - - str = g_string_new(NULL); - - if (prefix) - g_string_append(str, prefix); - g_string_append(str, key); - g_string_append_c(str, '='); - - has = FALSE; - for (i = 0; values[i]; i++) { - if (!values[i][0]) - continue; - if (has) - g_string_append_c(str, ' '); - else - has = TRUE; - g_string_append(str, values[i]); - } - - _items_add_str_take(items, g_string_free(str, FALSE)); -} - -/*****************************************************************************/ - -static void -construct_proxy_items(GPtrArray *items, GVariant *proxy_config, const char *prefix) -{ - GVariant *variant; - - nm_assert(items); - - if (!proxy_config) - return; - - variant = g_variant_lookup_value(proxy_config, "pac-url", G_VARIANT_TYPE_STRING); - if (variant) { - _items_add_key(items, prefix, "PROXY_PAC_URL", g_variant_get_string(variant, NULL)); - g_variant_unref(variant); - } - - variant = g_variant_lookup_value(proxy_config, "pac-script", G_VARIANT_TYPE_STRING); - if (variant) { - _items_add_key(items, prefix, "PROXY_PAC_SCRIPT", g_variant_get_string(variant, NULL)); - g_variant_unref(variant); - } -} - -static void -construct_ip_items(GPtrArray *items, int addr_family, GVariant *ip_config, const char *prefix) -{ - GVariant *val; - guint i; - guint nroutes = 0; - char four_or_six; - - if (!ip_config) - return; - - if (!prefix) - prefix = ""; - - four_or_six = nm_utils_addr_family_to_char(addr_family); - - val = g_variant_lookup_value(ip_config, - "addresses", - addr_family == AF_INET ? G_VARIANT_TYPE("aau") - : G_VARIANT_TYPE("a(ayuay)")); - if (val) { - gs_unref_ptrarray GPtrArray *addresses = NULL; - gs_free char * gateway_free = NULL; - const char * gateway; - - if (addr_family == AF_INET) - addresses = nm_utils_ip4_addresses_from_variant(val, &gateway_free); - else - addresses = nm_utils_ip6_addresses_from_variant(val, &gateway_free); - - gateway = gateway_free ?: "0.0.0.0"; - - if (addresses && addresses->len) { - for (i = 0; i < addresses->len; i++) { - NMIPAddress *addr = addresses->pdata[i]; - - _items_add_printf(items, - "%sIP%c_ADDRESS_%d=%s/%d %s", - prefix, - four_or_six, - i, - nm_ip_address_get_address(addr), - nm_ip_address_get_prefix(addr), - gateway); - } - - _items_add_printf(items, - "%sIP%c_NUM_ADDRESSES=%u", - prefix, - four_or_six, - addresses->len); - } - - _items_add_key(items, - prefix, - addr_family == AF_INET ? "IP4_GATEWAY" : "IP6_GATEWAY", - gateway); - - g_variant_unref(val); - } - - val = g_variant_lookup_value(ip_config, - "nameservers", - addr_family == AF_INET ? G_VARIANT_TYPE("au") - : G_VARIANT_TYPE("aay")); - if (val) { - gs_strfreev char **v = NULL; - - if (addr_family == AF_INET) - v = nm_utils_ip4_dns_from_variant(val); - else - v = nm_utils_ip6_dns_from_variant(val); - _items_add_strv(items, - prefix, - addr_family == AF_INET ? "IP4_NAMESERVERS" : "IP6_NAMESERVERS", - NM_CAST_STRV_CC(v)); - g_variant_unref(val); - } - - val = g_variant_lookup_value(ip_config, "domains", G_VARIANT_TYPE_STRING_ARRAY); - if (val) { - gs_free const char **v = NULL; - - v = g_variant_get_strv(val, NULL); - _items_add_strv(items, prefix, addr_family == AF_INET ? "IP4_DOMAINS" : "IP6_DOMAINS", v); - g_variant_unref(val); - } - - if (addr_family == AF_INET) { - val = g_variant_lookup_value(ip_config, "wins-servers", G_VARIANT_TYPE("au")); - if (val) { - gs_strfreev char **v = NULL; - - v = nm_utils_ip4_dns_from_variant(val); - _items_add_strv(items, prefix, "IP4_WINS_SERVERS", NM_CAST_STRV_CC(v)); - g_variant_unref(val); - } - } - - val = g_variant_lookup_value(ip_config, - "routes", - addr_family == AF_INET ? G_VARIANT_TYPE("aau") - : G_VARIANT_TYPE("a(ayuayu)")); - if (val) { - gs_unref_ptrarray GPtrArray *routes = NULL; - - if (addr_family == AF_INET) - routes = nm_utils_ip4_routes_from_variant(val); - else - routes = nm_utils_ip6_routes_from_variant(val); - - if (routes && routes->len > 0) { - const char *const DEFAULT_GW = addr_family == AF_INET ? "0.0.0.0" : "::"; - - nroutes = routes->len; - - for (i = 0; i < routes->len; i++) { - NMIPRoute *route = routes->pdata[i]; - - _items_add_printf(items, - "%sIP%c_ROUTE_%u=%s/%d %s %u", - prefix, - four_or_six, - i, - nm_ip_route_get_dest(route), - nm_ip_route_get_prefix(route), - nm_ip_route_get_next_hop(route) ?: DEFAULT_GW, - (guint) NM_MAX((gint64) 0, nm_ip_route_get_metric(route))); - } - } - - g_variant_unref(val); - } - if (nroutes > 0 || addr_family == AF_INET) { - /* we also set IP4_NUM_ROUTES=0, but don't do so for addresses and IPv6 routes. - * Historic reasons. */ - _items_add_printf(items, "%sIP%c_NUM_ROUTES=%u", prefix, four_or_six, nroutes); - } -} - -static void -construct_device_dhcp_items(GPtrArray *items, int addr_family, GVariant *dhcp_config) -{ - GVariantIter iter; - const char * key; - GVariant * val; - char four_or_six; - gboolean found_unknown_245 = FALSE; - gs_unref_variant GVariant *private_245_val = NULL; - - if (!dhcp_config) - return; - - if (!g_variant_is_of_type(dhcp_config, G_VARIANT_TYPE_VARDICT)) - return; - - four_or_six = nm_utils_addr_family_to_char(addr_family); - - g_variant_iter_init(&iter, dhcp_config); - while (g_variant_iter_next(&iter, "{&sv}", &key, &val)) { - if (g_variant_is_of_type(val, G_VARIANT_TYPE_STRING)) { - gs_free char *ucased = NULL; - - ucased = _sanitize_var_name(key); - if (ucased) { - _items_add_printf(items, - "DHCP%c_%s=%s", - four_or_six, - ucased, - g_variant_get_string(val, NULL)); - - /* MS Azure sends the server endpoint in the dhcp private - * option 245. cloud-init searches the Azure server endpoint - * value looking for the standard dhclient label used for - * that option, which is "unknown_245". - * The 11-dhclient script shipped with Fedora and RHEL dhcp - * package converts our dispatcher environment vars to the - * dhclient ones (new_<some_option>) and calls dhclient hook - * scripts. - * Let's make cloud-init happy and let's duplicate the dhcp - * option 245 with the legacy name of the default dhclient - * label also when using the internal client. - * Note however that the dhclient plugin will have unknown_ - * labels represented as ascii string when possible, falling - * back to hex string otherwise. - * private_ labels instead are always in hex string format. - * This shouldn't affect the MS Azure server endpoint value, - * as it usually belongs to the 240.0.0.0/4 network and so - * is always represented as an hex string. Moreover, cloudinit - * code checks just for an hex value in unknown_245. - */ - if (addr_family == AF_INET) { - if (nm_streq(key, "private_245")) - private_245_val = g_variant_ref(val); - else if (nm_streq(key, "unknown_245")) - found_unknown_245 = true; - } - } - } - g_variant_unref(val); - } - - if (private_245_val != NULL && !found_unknown_245) { - _items_add_printf(items, - "DHCP4_UNKNOWN_245=%s", - g_variant_get_string(private_245_val, NULL)); - } -} - -/*****************************************************************************/ - -char ** -nm_dispatcher_utils_construct_envp(const char * action, - GVariant * connection_dict, - GVariant * connection_props, - GVariant * device_props, - GVariant * device_proxy_props, - GVariant * device_ip4_props, - GVariant * device_ip6_props, - GVariant * device_dhcp4_props, - GVariant * device_dhcp6_props, - const char * connectivity_state, - const char * vpn_ip_iface, - GVariant * vpn_proxy_props, - GVariant * vpn_ip4_props, - GVariant * vpn_ip6_props, - char ** out_iface, - const char **out_error_message) -{ - const char * iface = NULL; - const char * ip_iface = NULL; - const char * uuid = NULL; - const char * id = NULL; - const char * path = NULL; - const char * filename = NULL; - gboolean external; - NMDeviceState dev_state = NM_DEVICE_STATE_UNKNOWN; - GVariant * variant; - gs_unref_ptrarray GPtrArray *items = NULL; - const char * error_message_backup; - - if (!out_error_message) - out_error_message = &error_message_backup; - - 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); - - items = g_ptr_array_new_with_free_func(g_free); - - /* Hostname and connectivity changes don't require a device nor contain a connection */ - if (NM_IN_STRSET(action, NMD_ACTION_HOSTNAME, NMD_ACTION_CONNECTIVITY_CHANGE)) - goto done; - - /* Connection properties */ - if (g_variant_lookup(connection_props, NMD_CONNECTION_PROPS_PATH, "&o", &path)) - _items_add_key(items, NULL, "CONNECTION_DBUS_PATH", path); - - if (g_variant_lookup(connection_props, NMD_CONNECTION_PROPS_EXTERNAL, "b", &external) - && external) - _items_add_str(items, "CONNECTION_EXTERNAL=1"); - - if (g_variant_lookup(connection_props, NMD_CONNECTION_PROPS_FILENAME, "&s", &filename)) - _items_add_key(items, NULL, "CONNECTION_FILENAME", filename); - - /* Canonicalize the VPN interface name; "" is used when passing it through - * D-Bus so make sure that's fixed up here. - */ - if (vpn_ip_iface && !vpn_ip_iface[0]) - vpn_ip_iface = NULL; - - if (!g_variant_lookup(device_props, NMD_DEVICE_PROPS_INTERFACE, "&s", &iface)) { - *out_error_message = "Missing or invalid required value " NMD_DEVICE_PROPS_INTERFACE "!"; - return NULL; - } - if (!*iface) - iface = NULL; - - variant = g_variant_lookup_value(device_props, NMD_DEVICE_PROPS_IP_INTERFACE, NULL); - if (variant) { - if (!g_variant_is_of_type(variant, G_VARIANT_TYPE_STRING)) { - *out_error_message = "Invalid value " NMD_DEVICE_PROPS_IP_INTERFACE "!"; - return NULL; - } - g_variant_unref(variant); - (void) g_variant_lookup(device_props, NMD_DEVICE_PROPS_IP_INTERFACE, "&s", &ip_iface); - } - - if (!g_variant_lookup(device_props, NMD_DEVICE_PROPS_TYPE, "u", NULL)) { - *out_error_message = "Missing or invalid required value " NMD_DEVICE_PROPS_TYPE "!"; - return NULL; - } - - variant = g_variant_lookup_value(device_props, NMD_DEVICE_PROPS_STATE, G_VARIANT_TYPE_UINT32); - if (!variant) { - *out_error_message = "Missing or invalid required value " NMD_DEVICE_PROPS_STATE "!"; - return NULL; - } - dev_state = g_variant_get_uint32(variant); - g_variant_unref(variant); - - if (!g_variant_lookup(device_props, NMD_DEVICE_PROPS_PATH, "o", NULL)) { - *out_error_message = "Missing or invalid required value " NMD_DEVICE_PROPS_PATH "!"; - return NULL; - } - - { - gs_unref_variant GVariant *con_setting = NULL; - - con_setting = g_variant_lookup_value(connection_dict, - NM_SETTING_CONNECTION_SETTING_NAME, - NM_VARIANT_TYPE_SETTING); - if (!con_setting) { - *out_error_message = "Failed to read connection setting"; - return NULL; - } - - if (!g_variant_lookup(con_setting, NM_SETTING_CONNECTION_UUID, "&s", &uuid)) { - *out_error_message = "Connection hash did not contain the UUID"; - return NULL; - } - - if (!g_variant_lookup(con_setting, NM_SETTING_CONNECTION_ID, "&s", &id)) { - *out_error_message = "Connection hash did not contain the ID"; - return NULL; - } - - _items_add_key0(items, NULL, "CONNECTION_UUID", uuid); - _items_add_key0(items, NULL, "CONNECTION_ID", id); - _items_add_key0(items, NULL, "DEVICE_IFACE", iface); - _items_add_key0(items, NULL, "DEVICE_IP_IFACE", ip_iface); - } - - /* Device items aren't valid if the device isn't activated */ - if (iface && dev_state == NM_DEVICE_STATE_ACTIVATED) { - construct_proxy_items(items, device_proxy_props, NULL); - construct_ip_items(items, AF_INET, device_ip4_props, NULL); - construct_ip_items(items, AF_INET6, device_ip6_props, NULL); - construct_device_dhcp_items(items, AF_INET, device_dhcp4_props); - construct_device_dhcp_items(items, AF_INET6, device_dhcp6_props); - } - - if (vpn_ip_iface) { - _items_add_key(items, NULL, "VPN_IP_IFACE", vpn_ip_iface); - construct_proxy_items(items, vpn_proxy_props, "VPN_"); - construct_ip_items(items, AF_INET, vpn_ip4_props, "VPN_"); - construct_ip_items(items, AF_INET6, vpn_ip6_props, "VPN_"); - } - - /* 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); - -done: - /* The connectivity_state value will only be meaningful for 'connectivity-change' events - * (otherwise it will be "UNKNOWN"), so we only set the environment variable in those cases. - */ - if (!NM_IN_STRSET(connectivity_state, NULL, "UNKNOWN")) - _items_add_key(items, NULL, "CONNECTIVITY_STATE", connectivity_state); - - _items_add_key0(items, NULL, "PATH", g_getenv("PATH")); - - _items_add_key(items, NULL, "NM_DISPATCHER_ACTION", action); - - *out_error_message = NULL; - g_ptr_array_add(items, NULL); - return (char **) g_ptr_array_free(g_steal_pointer(&items), FALSE); -} diff --git a/dispatcher/nm-dispatcher-utils.h b/dispatcher/nm-dispatcher-utils.h deleted file mode 100644 index cb40d146..00000000 --- a/dispatcher/nm-dispatcher-utils.h +++ /dev/null @@ -1,26 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2008 - 2011 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DISPATCHER_UTILS_H__ -#define __NETWORKMANAGER_DISPATCHER_UTILS_H__ - -char **nm_dispatcher_utils_construct_envp(const char * action, - GVariant * connection_dict, - GVariant * connection_props, - GVariant * device_props, - GVariant * device_proxy_props, - GVariant * device_ip4_props, - GVariant * device_ip6_props, - GVariant * device_dhcp4_props, - GVariant * device_dhcp6_props, - const char * connectivity_state, - const char * vpn_ip_iface, - GVariant * vpn_proxy_props, - GVariant * vpn_ip4_props, - GVariant * vpn_ip6_props, - char ** out_iface, - const char **out_error_message); - -#endif /* __NETWORKMANAGER_DISPATCHER_UTILS_H__ */ diff --git a/dispatcher/nm-dispatcher.c b/dispatcher/nm-dispatcher.c deleted file mode 100644 index 9891bf3d..00000000 --- a/dispatcher/nm-dispatcher.c +++ /dev/null @@ -1,1101 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2008 - 2012 Red Hat, Inc. - */ - -#include "libnm/nm-default-client.h" - -#include <syslog.h> -#include <stdio.h> -#include <unistd.h> -#include <stdlib.h> -#include <sys/types.h> -#include <signal.h> -#include <sys/stat.h> -#include <sys/wait.h> -#include <arpa/inet.h> -#include <glib-unix.h> - -#include "nm-libnm-core-aux/nm-dispatcher-api.h" -#include "nm-dispatcher-utils.h" - -/*****************************************************************************/ - -typedef struct Request Request; - -static struct { - GDBusConnection *dbus_connection; - GMainLoop * loop; - gboolean debug; - gboolean persist; - guint quit_id; - guint request_id_counter; - gboolean ever_acquired_name; - bool exit_with_failure; - - Request *current_request; - GQueue * requests_waiting; - int num_requests_pending; -} gl; - -typedef struct { - Request *request; - - char * script; - GPid pid; - DispatchResult result; - char * error; - gboolean wait; - gboolean dispatched; - guint watch_id; - guint timeout_id; -} ScriptInfo; - -struct Request { - guint request_id; - - GDBusMethodInvocation *context; - char * action; - char * iface; - char ** envp; - gboolean debug; - - GPtrArray *scripts; /* list of ScriptInfo */ - guint idx; - int num_scripts_done; - int num_scripts_nowait; -}; - -/*****************************************************************************/ - -#define __LOG_print(print_cmd, ...) \ - G_STMT_START \ - { \ - if (FALSE) { \ - /* g_message() alone does not warn about invalid format. Add a dummy printf() statement to - * get a compiler warning about wrong format. */ \ - printf(__VA_ARGS__); \ - } \ - print_cmd(__VA_ARGS__); \ - } \ - G_STMT_END - -#define __LOG_print_R(print_cmd, _request, ...) \ - G_STMT_START \ - { \ - __LOG_print(print_cmd, \ - "req:%u '%s'%s%s%s" _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - (_request)->request_id, \ - (_request)->action, \ - (_request)->iface ? " [" : "", \ - (_request)->iface ?: "", \ - (_request)->iface ? "]" : "" _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - G_STMT_END - -#define __LOG_print_S(print_cmd, _request, _script, ...) \ - G_STMT_START \ - { \ - __LOG_print_R(print_cmd, \ - (_request), \ - "%s%s%s" _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - (_script) ? ", \"" : "", \ - (_script) ? (_script)->script : "", \ - (_script) ? "\"" : "" _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - G_STMT_END - -#define _LOG_X_(enabled_cmd, print_cmd, ...) \ - G_STMT_START \ - { \ - if (enabled_cmd) \ - __LOG_print(print_cmd, __VA_ARGS__); \ - } \ - G_STMT_END - -#define _LOG_R_(enabled_cmd, x_request, print_cmd, ...) \ - G_STMT_START \ - { \ - const Request *const _request = (x_request); \ - \ - nm_assert(_request); \ - if (enabled_cmd) \ - __LOG_print_R(print_cmd, _request, ": "__VA_ARGS__); \ - } \ - G_STMT_END - -#define _LOG_S_(enabled_cmd, x_script, print_cmd, ...) \ - G_STMT_START \ - { \ - const ScriptInfo *const _script = (x_script); \ - const Request *const _request = _script ? _script->request : NULL; \ - \ - nm_assert(_script &&_request); \ - if (enabled_cmd) \ - __LOG_print_S(print_cmd, _request, _script, ": "__VA_ARGS__); \ - } \ - G_STMT_END - -#define _LOG_X_D_enabled() (gl.debug) -#define _LOG_X_T_enabled() _LOG_X_D_enabled() - -#define _LOG_R_D_enabled(request) (_NM_ENSURE_TYPE_CONST(Request *, request)->debug) -#define _LOG_R_T_enabled(request) _LOG_R_D_enabled(request) - -#define _LOG_X_T(...) _LOG_X_(_LOG_X_T_enabled(), g_debug, __VA_ARGS__) -#define _LOG_X_D(...) _LOG_X_(_LOG_X_D_enabled(), g_info, __VA_ARGS__) -#define _LOG_X_I(...) _LOG_X_(TRUE, g_message, __VA_ARGS__) -#define _LOG_X_W(...) _LOG_X_(TRUE, g_warning, __VA_ARGS__) - -#define _LOG_R_T(request, ...) _LOG_R_(_LOG_R_T_enabled(_request), request, g_debug, __VA_ARGS__) -#define _LOG_R_D(request, ...) _LOG_R_(_LOG_R_D_enabled(_request), request, g_info, __VA_ARGS__) -#define _LOG_R_W(request, ...) _LOG_R_(TRUE, request, g_warning, __VA_ARGS__) - -#define _LOG_S_T(script, ...) _LOG_S_(_LOG_R_T_enabled(_request), script, g_debug, __VA_ARGS__) -#define _LOG_S_D(script, ...) _LOG_S_(_LOG_R_D_enabled(_request), script, g_info, __VA_ARGS__) -#define _LOG_S_W(script, ...) _LOG_S_(TRUE, script, g_warning, __VA_ARGS__) - -/*****************************************************************************/ - -static gboolean dispatch_one_script(Request *request); - -/*****************************************************************************/ - -static void -script_info_free(gpointer ptr) -{ - ScriptInfo *info = ptr; - - g_free(info->script); - g_free(info->error); - g_slice_free(ScriptInfo, info); -} - -static void -request_free(Request *request) -{ - g_assert_cmpuint(request->num_scripts_done, ==, request->scripts->len); - g_assert_cmpuint(request->num_scripts_nowait, ==, 0); - - g_free(request->action); - g_free(request->iface); - g_strfreev(request->envp); - g_ptr_array_free(request->scripts, TRUE); - - g_slice_free(Request, request); -} - -static gboolean -quit_timeout_cb(gpointer user_data) -{ - gl.quit_id = 0; - g_main_loop_quit(gl.loop); - return G_SOURCE_REMOVE; -} - -static void -quit_timeout_reschedule(void) -{ - if (!gl.persist) { - nm_clear_g_source(&gl.quit_id); - gl.quit_id = g_timeout_add_seconds(10, quit_timeout_cb, NULL); - } -} - -/** - * next_request: - * - * @request: (allow-none): the request to set as next. If %NULL, dequeue the next - * waiting request. Otherwise, try to set the given request. - * - * Sets the currently active request (@current_request). The current request - * is a request that has at least on "wait" script, because requests that only - * consist of "no-wait" scripts are handled right away and not enqueued to - * @requests_waiting nor set as @current_request. - * - * Returns: %TRUE, if there was currently not request in process and it set - * a new request as current. - */ -static gboolean -next_request(Request *request) -{ - if (request) { - if (gl.current_request) { - g_queue_push_tail(gl.requests_waiting, request); - return FALSE; - } - } else { - /* when calling next_request() without explicit @request, we always - * forcefully clear @current_request. That one is certainly - * handled already. */ - gl.current_request = NULL; - - request = g_queue_pop_head(gl.requests_waiting); - if (!request) - return FALSE; - } - - _LOG_R_D(request, "start running ordered scripts..."); - - gl.current_request = request; - - return TRUE; -} - -/** - * complete_request: - * @request: the request - * - * Checks if all the scripts for the request have terminated and in such case - * it sends the D-Bus response and releases the request resources. - * - * It also decreases @num_requests_pending and possibly does quit_timeout_reschedule(). - */ -static void -complete_request(Request *request) -{ - GVariantBuilder results; - GVariant * ret; - guint i; - - nm_assert(request); - - /* Are there still pending scripts? Then do nothing (for now). */ - if (request->num_scripts_done < request->scripts->len) - return; - - g_variant_builder_init(&results, G_VARIANT_TYPE("a(sus)")); - for (i = 0; i < request->scripts->len; i++) { - ScriptInfo *script = g_ptr_array_index(request->scripts, i); - - g_variant_builder_add(&results, - "(sus)", - script->script, - script->result, - script->error ?: ""); - } - - ret = g_variant_new("(a(sus))", &results); - g_dbus_method_invocation_return_value(request->context, ret); - - _LOG_R_T(request, "completed (%u scripts)", request->scripts->len); - - if (gl.current_request == request) - gl.current_request = NULL; - - request_free(request); - - g_assert_cmpuint(gl.num_requests_pending, >, 0); - if (--gl.num_requests_pending <= 0) { - nm_assert(!gl.current_request && !g_queue_peek_head(gl.requests_waiting)); - quit_timeout_reschedule(); - } -} - -static void -complete_script(ScriptInfo *script) -{ - Request *request; - gboolean wait = script->wait; - - request = script->request; - - if (wait) { - /* for "wait" scripts, try to schedule the next blocking script. - * If that is successful, return (as we must wait for its completion). */ - if (dispatch_one_script(request)) - return; - } - - nm_assert(!wait || gl.current_request == request); - - /* Try to complete the request. @request will be possibly free'd, - * making @script and @request a dangling pointer. */ - complete_request(request); - - if (!wait) { - /* this was a "no-wait" script. We either completed the request, - * or there is nothing to do. Especially, there is no need to - * queue the next_request() -- because no-wait scripts don't block - * requests. However, if this was the last "no-wait" script and - * there are "wait" scripts ready to run, launch them. - */ - if (gl.current_request == request && gl.current_request->num_scripts_nowait == 0) { - if (dispatch_one_script(gl.current_request)) - return; - - complete_request(gl.current_request); - } else - return; - } else { - /* if the script is a "wait" script, we already tried above to - * dispatch the next script. As we didn't do that, it means we - * just completed the last script of @request and we can continue - * with the next request... - * - * Also, it cannot be that there is another request currently being - * processed because only requests with "wait" scripts can become - * @current_request. As there can only be one "wait" script running - * at any time, it means complete_request() above completed @request. */ - nm_assert(!gl.current_request); - } - - while (next_request(NULL)) { - request = gl.current_request; - - if (dispatch_one_script(request)) - return; - - /* Try to complete the request. It will be either completed - * now, or when all pending "no-wait" scripts return. */ - complete_request(request); - - /* We can immediately start next_request(), because our current - * @request has obviously no more "wait" scripts either. - * Repeat... */ - } -} - -static void -script_watch_cb(GPid pid, int status, gpointer user_data) -{ - ScriptInfo *script = user_data; - guint err; - - g_assert(pid == script->pid); - - script->watch_id = 0; - nm_clear_g_source(&script->timeout_id); - script->request->num_scripts_done++; - if (!script->wait) - script->request->num_scripts_nowait--; - - if (WIFEXITED(status)) { - err = WEXITSTATUS(status); - if (err == 0) - script->result = DISPATCH_RESULT_SUCCESS; - else { - script->error = - g_strdup_printf("Script '%s' exited with error status %d.", script->script, err); - } - } else if (WIFSTOPPED(status)) { - script->error = g_strdup_printf("Script '%s' stopped unexpectedly with signal %d.", - script->script, - WSTOPSIG(status)); - } else if (WIFSIGNALED(status)) { - script->error = - g_strdup_printf("Script '%s' died with signal %d", script->script, WTERMSIG(status)); - } else { - script->error = g_strdup_printf("Script '%s' died from an unknown cause", script->script); - } - - if (script->result == DISPATCH_RESULT_SUCCESS) { - _LOG_S_T(script, "complete"); - } else { - script->result = DISPATCH_RESULT_FAILED; - _LOG_S_W(script, "complete: failed with %s", script->error); - } - - g_spawn_close_pid(script->pid); - - complete_script(script); -} - -static gboolean -script_timeout_cb(gpointer user_data) -{ - ScriptInfo *script = user_data; - - script->timeout_id = 0; - nm_clear_g_source(&script->watch_id); - script->request->num_scripts_done++; - if (!script->wait) - script->request->num_scripts_nowait--; - - _LOG_S_W(script, "complete: timeout (kill script)"); - - kill(script->pid, SIGKILL); -again: - if (waitpid(script->pid, NULL, 0) == -1) { - if (errno == EINTR) - goto again; - } - - script->error = g_strdup_printf("Script '%s' timed out.", script->script); - script->result = DISPATCH_RESULT_TIMEOUT; - - g_spawn_close_pid(script->pid); - - complete_script(script); - - return FALSE; -} - -static gboolean -check_permissions(struct stat *s, const char **out_error_msg) -{ - g_return_val_if_fail(s != NULL, FALSE); - g_return_val_if_fail(out_error_msg != NULL, FALSE); - g_return_val_if_fail(*out_error_msg == NULL, FALSE); - - /* Only accept files owned by root */ - if (s->st_uid != 0) { - *out_error_msg = "not owned by root."; - return FALSE; - } - - /* Only accept files not writable by group or other, and not SUID */ - if (s->st_mode & (S_IWGRP | S_IWOTH | S_ISUID)) { - *out_error_msg = "writable by group or other, or set-UID."; - return FALSE; - } - - /* Only accept files executable by the owner */ - if (!(s->st_mode & S_IXUSR)) { - *out_error_msg = "not executable by owner."; - return FALSE; - } - - return TRUE; -} - -static gboolean -check_filename(const char *file_name) -{ - static const char *bad_suffixes[] = { - "~", - ".rpmsave", - ".rpmorig", - ".rpmnew", - ".swp", - }; - char *tmp; - guint i; - - /* File must not be a backup file, package management file, or start with '.' */ - - if (file_name[0] == '.') - return FALSE; - for (i = 0; i < G_N_ELEMENTS(bad_suffixes); i++) { - if (g_str_has_suffix(file_name, bad_suffixes[i])) - return FALSE; - } - tmp = g_strrstr(file_name, ".dpkg-"); - if (tmp && !strchr(&tmp[1], '.')) - return FALSE; - return TRUE; -} - -#define SCRIPT_TIMEOUT 600 /* 10 minutes */ - -static gboolean -script_dispatch(ScriptInfo *script) -{ - gs_free_error GError *error = NULL; - char * argv[4]; - Request * request = script->request; - - if (script->dispatched) - return FALSE; - - script->dispatched = TRUE; - - /* Only for "hostname" action we coerce the interface name to "none". We don't - * do so for "connectivity-check" action. */ - - argv[0] = script->script; - argv[1] = request->iface ?: (nm_streq(request->action, NMD_ACTION_HOSTNAME) ? "none" : ""); - argv[2] = request->action; - argv[3] = NULL; - - _LOG_S_T(script, "run script%s", script->wait ? "" : " (no-wait)"); - - if (!g_spawn_async("/", - argv, - request->envp, - G_SPAWN_DO_NOT_REAP_CHILD, - NULL, - NULL, - &script->pid, - &error)) { - _LOG_S_W(script, "complete: failed to execute script: %s", error->message); - script->result = DISPATCH_RESULT_EXEC_FAILED; - script->error = g_strdup(error->message); - request->num_scripts_done++; - return FALSE; - } - - script->watch_id = g_child_watch_add(script->pid, (GChildWatchFunc) script_watch_cb, script); - script->timeout_id = g_timeout_add_seconds(SCRIPT_TIMEOUT, script_timeout_cb, script); - if (!script->wait) - request->num_scripts_nowait++; - return TRUE; -} - -static gboolean -dispatch_one_script(Request *request) -{ - if (request->num_scripts_nowait > 0) - return TRUE; - - while (request->idx < request->scripts->len) { - ScriptInfo *script; - - script = g_ptr_array_index(request->scripts, request->idx++); - if (script_dispatch(script)) - return TRUE; - } - return FALSE; -} - -static int -_compare_basenames(gconstpointer a, gconstpointer b) -{ - const char *basename_a = strrchr(a, '/'); - const char *basename_b = strrchr(b, '/'); - int ret; - - nm_assert(basename_a); - nm_assert(basename_b); - - ret = strcmp(++basename_a, ++basename_b); - if (ret) - return ret; - - nm_assert_not_reached(); - return 0; -} - -static void -_find_scripts(Request *request, GHashTable *scripts, const char *base, const char *subdir) -{ - const char * filename; - gs_free char *dirname = NULL; - GError * error = NULL; - GDir * dir; - - dirname = g_build_filename(base, "dispatcher.d", subdir, NULL); - - if (!(dir = g_dir_open(dirname, 0, &error))) { - if (!g_error_matches(error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) { - _LOG_R_W(request, - "find-scripts: Failed to open dispatcher directory '%s': %s", - dirname, - error->message); - } - g_error_free(error); - return; - } - - while ((filename = g_dir_read_name(dir))) { - if (!check_filename(filename)) - continue; - - g_hash_table_insert(scripts, g_strdup(filename), g_build_filename(dirname, filename, NULL)); - } - - g_dir_close(dir); -} - -static GSList * -find_scripts(Request *request) -{ - gs_unref_hashtable GHashTable *scripts = NULL; - GSList * script_list = NULL; - GHashTableIter iter; - const char * subdir; - char * path; - char * filename; - - if (NM_IN_STRSET(request->action, NMD_ACTION_PRE_UP, NMD_ACTION_VPN_PRE_UP)) - subdir = "pre-up.d"; - else if (NM_IN_STRSET(request->action, NMD_ACTION_PRE_DOWN, NMD_ACTION_VPN_PRE_DOWN)) - subdir = "pre-down.d"; - else - subdir = NULL; - - scripts = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_free); - - _find_scripts(request, scripts, NMLIBDIR, subdir); - _find_scripts(request, scripts, NMCONFDIR, subdir); - - g_hash_table_iter_init(&iter, scripts); - while (g_hash_table_iter_next(&iter, (gpointer *) &filename, (gpointer *) &path)) { - gs_free char *link_target = NULL; - const char * err_msg = NULL; - struct stat st; - int err; - - link_target = g_file_read_link(path, NULL); - if (nm_streq0(link_target, "/dev/null")) - continue; - - err = stat(path, &st); - if (err) - _LOG_R_W(request, "find-scripts: Failed to stat '%s': %d", path, err); - else if (!S_ISREG(st.st_mode) || st.st_size == 0) { - /* silently skip. */ - } else if (!check_permissions(&st, &err_msg)) - _LOG_R_W(request, "find-scripts: Cannot execute '%s': %s", path, err_msg); - else { - /* success */ - script_list = g_slist_prepend(script_list, g_strdup(path)); - continue; - } - } - - return g_slist_sort(script_list, _compare_basenames); -} - -static gboolean -script_must_wait(const char *path) -{ - gs_free char *link = NULL; - - link = g_file_read_link(path, NULL); - if (link) { - gs_free char * dir = NULL; - nm_auto_free char *real = NULL; - - if (!g_path_is_absolute(link)) { - char *tmp; - - dir = g_path_get_dirname(path); - tmp = g_build_path("/", dir, link, NULL); - g_free(link); - g_free(dir); - link = tmp; - } - - dir = g_path_get_dirname(link); - real = realpath(dir, NULL); - if (NM_STR_HAS_SUFFIX(real, "/no-wait.d")) - return FALSE; - } - - return TRUE; -} - -static void -_method_call_action(GDBusMethodInvocation *invocation, GVariant *parameters) -{ - const char * action; - gs_unref_variant GVariant *connection = NULL; - gs_unref_variant GVariant *connection_properties = NULL; - gs_unref_variant GVariant *device_properties = NULL; - gs_unref_variant GVariant *device_proxy_properties = NULL; - gs_unref_variant GVariant *device_ip4_config = NULL; - gs_unref_variant GVariant *device_ip6_config = NULL; - gs_unref_variant GVariant *device_dhcp4_config = NULL; - gs_unref_variant GVariant *device_dhcp6_config = NULL; - const char * connectivity_state; - const char * vpn_ip_iface; - gs_unref_variant GVariant *vpn_proxy_properties = NULL; - gs_unref_variant GVariant *vpn_ip4_config = NULL; - gs_unref_variant GVariant *vpn_ip6_config = NULL; - gboolean debug; - GSList * sorted_scripts = NULL; - GSList * iter; - Request * request; - char ** p; - guint i, num_nowait = 0; - const char * error_message = NULL; - - g_variant_get(parameters, - "(" - "&s" /* action */ - "@a{sa{sv}}" /* connection */ - "@a{sv}" /* connection_properties */ - "@a{sv}" /* device_properties */ - "@a{sv}" /* device_proxy_properties */ - "@a{sv}" /* device_ip4_config */ - "@a{sv}" /* device_ip6_config */ - "@a{sv}" /* device_dhcp4_config */ - "@a{sv}" /* device_dhcp6_config */ - "&s" /* connectivity_state */ - "&s" /* vpn_ip_iface */ - "@a{sv}" /* vpn_proxy_properties */ - "@a{sv}" /* vpn_ip4_config */ - "@a{sv}" /* vpn_ip6_config */ - "b" /* debug */ - ")", - &action, - &connection, - &connection_properties, - &device_properties, - &device_proxy_properties, - &device_ip4_config, - &device_ip6_config, - &device_dhcp4_config, - &device_dhcp6_config, - &connectivity_state, - &vpn_ip_iface, - &vpn_proxy_properties, - &vpn_ip4_config, - &vpn_ip6_config, - &debug); - - request = g_slice_new0(Request); - request->request_id = ++gl.request_id_counter; - request->debug = debug || gl.debug; - request->context = invocation; - request->action = g_strdup(action); - - request->envp = nm_dispatcher_utils_construct_envp(action, - connection, - connection_properties, - device_properties, - device_proxy_properties, - device_ip4_config, - device_ip6_config, - device_dhcp4_config, - device_dhcp6_config, - connectivity_state, - vpn_ip_iface, - vpn_proxy_properties, - vpn_ip4_config, - vpn_ip6_config, - &request->iface, - &error_message); - - request->scripts = g_ptr_array_new_full(5, script_info_free); - - sorted_scripts = find_scripts(request); - for (iter = sorted_scripts; iter; iter = g_slist_next(iter)) { - ScriptInfo *s; - - s = g_slice_new0(ScriptInfo); - s->request = request; - s->script = iter->data; - s->wait = script_must_wait(s->script); - g_ptr_array_add(request->scripts, s); - } - g_slist_free(sorted_scripts); - - _LOG_R_D(request, "new request (%u scripts)", request->scripts->len); - if (_LOG_R_T_enabled(request) && request->envp) { - for (p = request->envp; *p; p++) - _LOG_R_T(request, "environment: %s", *p); - } - - if (error_message || request->scripts->len == 0) { - GVariant *results; - - if (error_message) - _LOG_R_W(request, "completed: invalid request: %s", error_message); - else - _LOG_R_D(request, "completed: no scripts"); - - results = g_variant_new_array(G_VARIANT_TYPE("(sus)"), NULL, 0); - g_dbus_method_invocation_return_value(invocation, g_variant_new("(@a(sus))", results)); - request->num_scripts_done = request->scripts->len; - request_free(request); - return; - } - - nm_clear_g_source(&gl.quit_id); - - gl.num_requests_pending++; - - for (i = 0; i < request->scripts->len; i++) { - ScriptInfo *s = g_ptr_array_index(request->scripts, i); - - if (!s->wait) { - script_dispatch(s); - num_nowait++; - } - } - - if (num_nowait < request->scripts->len) { - /* The request has at least one wait script. - * Try next_request() to schedule the request for - * execution. This either enqueues the request or - * sets it as gl.current_request. */ - if (next_request(request)) { - /* @request is now @current_request. Go ahead and - * schedule the first wait script. */ - if (!dispatch_one_script(request)) { - /* If that fails, we might be already finished with the - * request. Try complete_request(). */ - complete_request(request); - - if (next_request(NULL)) { - /* As @request was successfully scheduled as next_request(), there is no - * other request in queue that can be scheduled afterwards. Assert against - * that, but call next_request() to clear current_request. */ - g_assert_not_reached(); - } - } - } - } else { - /* The request contains only no-wait scripts. Try to complete - * the request right away (we might have failed to schedule any - * of the scripts). It will be either completed now, or later - * when the pending scripts return. - * We don't enqueue it to gl.requests_waiting. - * There is no need to handle next_request(), because @request is - * not the current request anyway and does not interfere with requests - * that have any "wait" scripts. */ - complete_request(request); - } -} - -static void -on_name_acquired(GDBusConnection *connection, const char *name, gpointer user_data) -{ - gl.ever_acquired_name = TRUE; -} - -static void -on_name_lost(GDBusConnection *connection, const char *name, gpointer user_data) -{ - if (!connection) { - if (!gl.ever_acquired_name) { - _LOG_X_W("Could not get the system bus. Make sure the message bus daemon is running!"); - gl.exit_with_failure = TRUE; - } else { - _LOG_X_I("System bus stopped. Exiting"); - } - } else if (!gl.ever_acquired_name) { - _LOG_X_W("Could not acquire the " NM_DISPATCHER_DBUS_SERVICE " service."); - gl.exit_with_failure = TRUE; - } else - _LOG_X_I("Lost the " NM_DISPATCHER_DBUS_SERVICE " name. Exiting"); - - g_main_loop_quit(gl.loop); -} - -static void -_method_call(GDBusConnection * connection, - const char * sender, - const char * object_path, - const char * interface_name, - const char * method_name, - GVariant * parameters, - GDBusMethodInvocation *invocation, - gpointer user_data) -{ - if (nm_streq(interface_name, NM_DISPATCHER_DBUS_INTERFACE)) { - if (nm_streq(method_name, "Action")) { - _method_call_action(invocation, parameters); - return; - } - } - g_dbus_method_invocation_return_error(invocation, - G_DBUS_ERROR, - G_DBUS_ERROR_UNKNOWN_METHOD, - "Unknown method %s", - method_name); -} - -static GDBusInterfaceInfo *const interface_info = NM_DEFINE_GDBUS_INTERFACE_INFO( - NM_DISPATCHER_DBUS_INTERFACE, - .methods = NM_DEFINE_GDBUS_METHOD_INFOS( - NM_DEFINE_GDBUS_METHOD_INFO( - "Action", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS( - NM_DEFINE_GDBUS_ARG_INFO("action", "s"), - NM_DEFINE_GDBUS_ARG_INFO("connection", "a{sa{sv}}"), - NM_DEFINE_GDBUS_ARG_INFO("connection_properties", "a{sv}"), - NM_DEFINE_GDBUS_ARG_INFO("device_properties", "a{sv}"), - NM_DEFINE_GDBUS_ARG_INFO("device_proxy_properties", "a{sv}"), - NM_DEFINE_GDBUS_ARG_INFO("device_ip4_config", "a{sv}"), - NM_DEFINE_GDBUS_ARG_INFO("device_ip6_config", "a{sv}"), - NM_DEFINE_GDBUS_ARG_INFO("device_dhcp4_config", "a{sv}"), - NM_DEFINE_GDBUS_ARG_INFO("device_dhcp6_config", "a{sv}"), - NM_DEFINE_GDBUS_ARG_INFO("connectivity_state", "s"), - NM_DEFINE_GDBUS_ARG_INFO("vpn_ip_iface", "s"), - NM_DEFINE_GDBUS_ARG_INFO("vpn_proxy_properties", "a{sv}"), - NM_DEFINE_GDBUS_ARG_INFO("vpn_ip4_config", "a{sv}"), - NM_DEFINE_GDBUS_ARG_INFO("vpn_ip6_config", "a{sv}"), - NM_DEFINE_GDBUS_ARG_INFO("debug", "b"), ), - .out_args = - NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("results", "a(sus)"), ), ), ), ); - -static const GDBusInterfaceVTable interface_vtable = { - .method_call = _method_call, -}; - -/*****************************************************************************/ - -static void -log_handler(const char *log_domain, GLogLevelFlags log_level, const char *message, gpointer ignored) -{ - int syslog_priority; - - switch (log_level) { - case G_LOG_LEVEL_ERROR: - syslog_priority = LOG_CRIT; - break; - case G_LOG_LEVEL_CRITICAL: - syslog_priority = LOG_ERR; - break; - case G_LOG_LEVEL_WARNING: - syslog_priority = LOG_WARNING; - break; - case G_LOG_LEVEL_MESSAGE: - syslog_priority = LOG_NOTICE; - break; - case G_LOG_LEVEL_DEBUG: - syslog_priority = LOG_DEBUG; - break; - case G_LOG_LEVEL_INFO: - default: - syslog_priority = LOG_INFO; - break; - } - - syslog(syslog_priority, "%s", message); -} - -static void -logging_setup(void) -{ - openlog(G_LOG_DOMAIN, LOG_CONS, LOG_DAEMON); - g_log_set_handler(G_LOG_DOMAIN, - G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, - log_handler, - NULL); -} - -static void -logging_shutdown(void) -{ - closelog(); -} - -static gboolean -signal_handler(gpointer user_data) -{ - int signo = GPOINTER_TO_INT(user_data); - - _LOG_X_I("Caught signal %d, shutting down...", signo); - g_main_loop_quit(gl.loop); - - return G_SOURCE_CONTINUE; -} - -static gboolean -parse_command_line(int *p_argc, char ***p_argv, GError **error) -{ - GOptionContext *opt_ctx; - GOptionEntry entries[] = { - {"debug", 0, 0, G_OPTION_ARG_NONE, &gl.debug, "Output to console rather than syslog", NULL}, - {"persist", 0, 0, G_OPTION_ARG_NONE, &gl.persist, "Don't quit after a short timeout", NULL}, - {NULL}}; - gboolean success; - - opt_ctx = g_option_context_new(NULL); - g_option_context_set_summary(opt_ctx, "Executes scripts upon actions by NetworkManager."); - g_option_context_add_main_entries(opt_ctx, entries, NULL); - - success = g_option_context_parse(opt_ctx, p_argc, p_argv, error); - - g_option_context_free(opt_ctx); - - return success; -} - -int -main(int argc, char **argv) -{ - gs_free_error GError *error = NULL; - guint signal_id_term = 0; - guint signal_id_int = 0; - guint dbus_regist_id = 0; - guint dbus_own_name_id = 0; - - if (!parse_command_line(&argc, &argv, &error)) { - _LOG_X_W("Error parsing command line arguments: %s", error->message); - gl.exit_with_failure = TRUE; - goto done; - } - - signal_id_term = g_unix_signal_add(SIGTERM, signal_handler, GINT_TO_POINTER(SIGTERM)); - signal_id_int = g_unix_signal_add(SIGINT, signal_handler, GINT_TO_POINTER(SIGINT)); - - if (gl.debug) { - if (!g_getenv("G_MESSAGES_DEBUG")) { - /* we log our regular messages using g_debug() and g_info(). - * When we redirect glib logging to syslog, there is no problem. - * But in "debug" mode, glib will no print these messages unless - * we set G_MESSAGES_DEBUG. */ - g_setenv("G_MESSAGES_DEBUG", "all", TRUE); - } - } else - logging_setup(); - - gl.loop = g_main_loop_new(NULL, FALSE); - - gl.dbus_connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error); - if (!gl.dbus_connection) { - _LOG_X_W("Could not get the system bus (%s). Make sure the message bus daemon is running!", - error->message); - gl.exit_with_failure = TRUE; - goto done; - } - - gl.requests_waiting = g_queue_new(); - - dbus_regist_id = - g_dbus_connection_register_object(gl.dbus_connection, - NM_DISPATCHER_DBUS_PATH, - interface_info, - NM_UNCONST_PTR(GDBusInterfaceVTable, &interface_vtable), - NULL, - NULL, - &error); - if (dbus_regist_id == 0) { - _LOG_X_W("Could not export Dispatcher D-Bus interface: %s", error->message); - gl.exit_with_failure = 1; - goto done; - } - - dbus_own_name_id = g_bus_own_name_on_connection(gl.dbus_connection, - NM_DISPATCHER_DBUS_SERVICE, - G_BUS_NAME_OWNER_FLAGS_NONE, - on_name_acquired, - on_name_lost, - NULL, - NULL); - - quit_timeout_reschedule(); - - g_main_loop_run(gl.loop); - -done: - - if (gl.num_requests_pending > 0) { - /* this only happens when we quit due to SIGTERM (not due to the idle timer). - * - * Log a warning about pending scripts. - * - * Maybe we should notify NetworkManager that these scripts are left in an unknown state. - * But this is either a bug of a dispatcher script (not terminating in time). - * - * FIXME(shutdown): Also, currently NetworkManager behaves wrongly on shutdown. - * Note that systemd would not terminate NetworkManager-dispatcher before NetworkManager. - * It's NetworkManager's responsibility to keep running long enough so that all requests - * can complete (with a watchdog timer, and a warning that user provided scripts hang). */ - _LOG_X_W("exiting but there are still %u requests pending", gl.num_requests_pending); - } - - if (dbus_own_name_id != 0) - g_bus_unown_name(nm_steal_int(&dbus_own_name_id)); - - if (dbus_regist_id != 0) - g_dbus_connection_unregister_object(gl.dbus_connection, nm_steal_int(&dbus_regist_id)); - - nm_clear_pointer(&gl.requests_waiting, g_queue_free); - - nm_clear_g_source(&signal_id_term); - nm_clear_g_source(&signal_id_int); - nm_clear_g_source(&gl.quit_id); - nm_clear_pointer(&gl.loop, g_main_loop_unref); - g_clear_object(&gl.dbus_connection); - - if (!gl.debug) - logging_shutdown(); - - return gl.exit_with_failure ? 1 : 0; -} diff --git a/dispatcher/nm-dispatcher.conf b/dispatcher/nm-dispatcher.conf deleted file mode 100644 index d6f31135..00000000 --- a/dispatcher/nm-dispatcher.conf +++ /dev/null @@ -1,13 +0,0 @@ -<!DOCTYPE busconfig PUBLIC - "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" - "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> -<busconfig> - <policy user="root"> - <allow own="org.freedesktop.nm_dispatcher"/> - <allow send_destination="org.freedesktop.nm_dispatcher"/> - </policy> - <policy context="default"> - <deny own="org.freedesktop.nm_dispatcher"/> - <deny send_destination="org.freedesktop.nm_dispatcher"/> - </policy> -</busconfig> diff --git a/dispatcher/nm-dispatcher.xml b/dispatcher/nm-dispatcher.xml deleted file mode 100644 index 0d9d28e2..00000000 --- a/dispatcher/nm-dispatcher.xml +++ /dev/null @@ -1,46 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<node name="/"> - <interface name="org.freedesktop.nm_dispatcher"> - <annotation name="org.gtk.GDBus.C.Name" value="Dispatcher"/> - - <!-- - Action: - @action: The action being performed. - @connection: The connection for which this action was triggered. - @connection_properties: Properties of the connection, including service and path. - @device_properties: Properties of the device, including type, path, interface, and state. - @device_proxy_properties: Properties of the device's proxy configuration. - @device_ip4_config: Properties of the device's IPv4 configuration. - @device_ip6_config: Properties of the device's IPv6 configuration. - @device_dhcp4_config: Properties of the device's DHCPv4 configuration. - @device_dhcp6_config: Properties of the device's DHCPv6 configuration. - @connectivity_state: Current connectivity state: unknown, none, limited, portal or full. - @vpn_ip_iface: VPN interface name. - @vpn_proxy_properties: Properties of the VPN's proxy configuration. - @vpn_ip4_config: Properties of the VPN's IPv4 configuration. - @vpn_ip6_config: Properties of the VPN's IPv6 configuration. - @debug: Whether to log debug output. - @results: Results of dispatching operations. Each element of the returned array is a struct containing the path of an executed script (s), the result of running that script (u), and a description of the result (s). - - INTERNAL; not public API. Perform an action. - --> - <method name="Action"> - <arg name="action" type="s" direction="in"/> - <arg name="connection" type="a{sa{sv}}" direction="in"/> - <arg name="connection_properties" type="a{sv}" direction="in"/> - <arg name="device_properties" type="a{sv}" direction="in"/> - <arg name="device_proxy_properties" type="a{sv}" direction="in"/> - <arg name="device_ip4_config" type="a{sv}" direction="in"/> - <arg name="device_ip6_config" type="a{sv}" direction="in"/> - <arg name="device_dhcp4_config" type="a{sv}" direction="in"/> - <arg name="device_dhcp6_config" type="a{sv}" direction="in"/> - <arg name="connectivity_state" type="s" direction="in"/> - <arg name="vpn_ip_iface" type="s" direction="in"/> - <arg name="vpn_proxy_properties" type="a{sv}" direction="in"/> - <arg name="vpn_ip4_config" type="a{sv}" direction="in"/> - <arg name="vpn_ip6_config" type="a{sv}" direction="in"/> - <arg name="debug" type="b" direction="in"/> - <arg name="results" type="a(sus)" direction="out"/> - </method> - </interface> -</node> diff --git a/dispatcher/org.freedesktop.nm_dispatcher.service.in b/dispatcher/org.freedesktop.nm_dispatcher.service.in deleted file mode 100644 index ff037cca..00000000 --- a/dispatcher/org.freedesktop.nm_dispatcher.service.in +++ /dev/null @@ -1,6 +0,0 @@ -[D-BUS Service] -Name=org.freedesktop.nm_dispatcher -Exec=@libexecdir@/nm-dispatcher -User=root -SystemdService=dbus-org.freedesktop.nm-dispatcher.service - diff --git a/dispatcher/tests/dispatcher-connectivity-full b/dispatcher/tests/dispatcher-connectivity-full deleted file mode 100644 index 937e79d7..00000000 --- a/dispatcher/tests/dispatcher-connectivity-full +++ /dev/null @@ -1,17 +0,0 @@ -[main] -action=connectivity-change -uuid=3fd2a33a-d81b-423f-ae99-e6baba742311 -id=Random Connection -connectivity-state=FULL - -[device] -state=30 -ip-interface=wlan0 -type=2 -interface=wlan0 -path=/org/freedesktop/NetworkManager/Devices/0 - -[env] -PATH= -NM_DISPATCHER_ACTION=connectivity-change -CONNECTIVITY_STATE=FULL diff --git a/dispatcher/tests/dispatcher-connectivity-unknown b/dispatcher/tests/dispatcher-connectivity-unknown deleted file mode 100644 index 9aa48e4a..00000000 --- a/dispatcher/tests/dispatcher-connectivity-unknown +++ /dev/null @@ -1,16 +0,0 @@ -[main] -action=connectivity-change -uuid=3fd2a33a-d81b-423f-ae99-e6baba742311 -id=Random Connection -connectivity-state=UNKNOWN - -[device] -state=30 -ip-interface=wlan0 -type=2 -interface=wlan0 -path=/org/freedesktop/NetworkManager/Devices/0 - -[env] -PATH= -NM_DISPATCHER_ACTION=connectivity-change diff --git a/dispatcher/tests/dispatcher-down b/dispatcher/tests/dispatcher-down deleted file mode 100644 index 8e2a2818..00000000 --- a/dispatcher/tests/dispatcher-down +++ /dev/null @@ -1,23 +0,0 @@ -[main] -action=down -expected-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] -PATH= -NM_DISPATCHER_ACTION=down -CONNECTION_UUID=3fd2a33a-d81b-423f-ae99-e6baba742311 -CONNECTION_DBUS_PATH=/org/freedesktop/NetworkManager/Connections/5 -CONNECTION_ID=Random Connection -CONNECTION_FILENAME=/dispatcher/tests/dispatcher-down -DEVICE_IFACE=wlan0 -DEVICE_IP_IFACE=wlan0 - diff --git a/dispatcher/tests/dispatcher-external b/dispatcher/tests/dispatcher-external deleted file mode 100644 index 46d6c797..00000000 --- a/dispatcher/tests/dispatcher-external +++ /dev/null @@ -1,40 +0,0 @@ -[main] -action=up -expected-iface=virbr0 -uuid=92bbc2fb-7304-46be-8ebb-6093dbe19a6a -id=virbr0 -external=1 - -[device] -state=100 -ip-interface=virbr0 -type=13 -interface=virbr0 -path=/org/freedesktop/NetworkManager/Devices/0 - -[proxy] -pac-url=http://networkmanager.com/proxy.pac -pac-script="function FindProxyForURL (url, host) {}" - -[ip4] -addresses=192.168.122.1/24 0.0.0.0 -domains= -gateway=0.0.0.0 - -[env] -PATH= -NM_DISPATCHER_ACTION=up -CONNECTION_UUID=92bbc2fb-7304-46be-8ebb-6093dbe19a6a -CONNECTION_DBUS_PATH=/org/freedesktop/NetworkManager/Connections/5 -CONNECTION_FILENAME=/dispatcher/tests/dispatcher-external -CONNECTION_ID=virbr0 -CONNECTION_EXTERNAL=1 -DEVICE_IFACE=virbr0 -DEVICE_IP_IFACE=virbr0 -PROXY_PAC_URL=http://networkmanager.com/proxy.pac -PROXY_PAC_SCRIPT="function FindProxyForURL (url, host) {}" -IP4_NUM_ADDRESSES=1 -IP4_ADDRESS_0=192.168.122.1/24 0.0.0.0 -IP4_GATEWAY=0.0.0.0 -IP4_NUM_ROUTES=0 - diff --git a/dispatcher/tests/dispatcher-up b/dispatcher/tests/dispatcher-up deleted file mode 100644 index 0a27e3de..00000000 --- a/dispatcher/tests/dispatcher-up +++ /dev/null @@ -1,66 +0,0 @@ -[main] -action=up -expected-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 - -[proxy] -pac-url=http://networkmanager.com/proxy.pac -pac-script="function FindProxyForURL (url, host) {}" - -[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] -PATH= -NM_DISPATCHER_ACTION=up -CONNECTION_UUID=3fd2a33a-d81b-423f-ae99-e6baba742311 -CONNECTION_DBUS_PATH=/org/freedesktop/NetworkManager/Connections/5 -CONNECTION_ID=Random Connection -CONNECTION_FILENAME=/dispatcher/tests/dispatcher-up -DEVICE_IFACE=wlan0 -DEVICE_IP_IFACE=wlan0 -PROXY_PAC_URL=http://networkmanager.com/proxy.pac -PROXY_PAC_SCRIPT="function FindProxyForURL (url, host) {}" -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_GATEWAY=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/dispatcher/tests/dispatcher-vpn-down b/dispatcher/tests/dispatcher-vpn-down deleted file mode 100644 index e439668f..00000000 --- a/dispatcher/tests/dispatcher-vpn-down +++ /dev/null @@ -1,65 +0,0 @@ -[main] -action=vpn-down -expected-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 - -[proxy] -pac-url=http://networkmanager.com/proxy.pac -pac-script="function FindProxyForURL (url, host) {}" - -[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] -PATH= -NM_DISPATCHER_ACTION=vpn-down -CONNECTION_UUID=355653c0-34d3-4777-ad25-f9a498b7ef8e -CONNECTION_DBUS_PATH=/org/freedesktop/NetworkManager/Connections/5 -CONNECTION_ID=Random Connection -CONNECTION_FILENAME=/dispatcher/tests/dispatcher-vpn-down -DEVICE_IFACE=wlan0 -DEVICE_IP_IFACE=tun0 -PROXY_PAC_URL=http://networkmanager.com/proxy.pac -PROXY_PAC_SCRIPT="function FindProxyForURL (url, host) {}" -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_GATEWAY=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/dispatcher/tests/dispatcher-vpn-up b/dispatcher/tests/dispatcher-vpn-up deleted file mode 100644 index 09c94c1c..00000000 --- a/dispatcher/tests/dispatcher-vpn-up +++ /dev/null @@ -1,65 +0,0 @@ -[main] -action=vpn-up -expected-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 - -[proxy] -pac-url=http://networkmanager.com/proxy.pac -pac-script="function FindProxyForURL (url, host) {}" - -[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] -PATH= -NM_DISPATCHER_ACTION=vpn-up -CONNECTION_UUID=355653c0-34d3-4777-ad25-f9a498b7ef8e -CONNECTION_DBUS_PATH=/org/freedesktop/NetworkManager/Connections/5 -CONNECTION_ID=Random Connection -CONNECTION_FILENAME=/dispatcher/tests/dispatcher-vpn-up -DEVICE_IFACE=wlan0 -DEVICE_IP_IFACE=tun0 -PROXY_PAC_URL=http://networkmanager.com/proxy.pac -PROXY_PAC_SCRIPT="function FindProxyForURL (url, host) {}" -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_GATEWAY=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/dispatcher/tests/meson.build b/dispatcher/tests/meson.build deleted file mode 100644 index 84b4b61c..00000000 --- a/dispatcher/tests/meson.build +++ /dev/null @@ -1,24 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later - -exe = executable( - 'test-dispatcher-envp', - [ - 'test-dispatcher-envp.c', - nmdbus_dispatcher_sources, - ], - include_directories: dispatcher_inc, - dependencies: [ - libnm_nm_default_dep, - libnm_glib_aux_dep, - ], - c_args: [ - '-DG_LOG_DOMAIN="test"', - ] + introspection_extra_cflags, - link_with: libnm_dispatcher_core, -) - -test( - 'dispatcher/test-dispatcher-envp', - test_script, - args: test_args + [exe.full_path()], -) diff --git a/dispatcher/tests/test-dispatcher-envp.c b/dispatcher/tests/test-dispatcher-envp.c deleted file mode 100644 index 4c37dd6c..00000000 --- a/dispatcher/tests/test-dispatcher-envp.c +++ /dev/null @@ -1,637 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2011 Red Hat, Inc. - */ - -#include "libnm/nm-default-client.h" - -#include <arpa/inet.h> -#include <stdlib.h> - -#include "nm-dispatcher-utils.h" -#include "nm-libnm-core-aux/nm-dispatcher-api.h" - -#include "nm-utils/nm-test-utils.h" - -#include "nmdbus-dispatcher.h" - -#define TEST_DIR NM_BUILD_SRCDIR "/dispatcher/tests" - -/*****************************************************************************/ - -static void -_print_env(const char *const *denv, GHashTable *expected_env) -{ - const char *const *iter; - GHashTableIter k; - const char * key; - - g_print("\n******* Generated environment:\n"); - for (iter = denv; iter && *iter; iter++) - g_print(" %s\n", *iter); - - g_print("\n******* Expected environment:\n"); - g_hash_table_iter_init(&k, expected_env); - while (g_hash_table_iter_next(&k, (gpointer) &key, NULL)) - g_print(" %s\n", key); -} - -static gboolean -parse_main(GKeyFile * kf, - const char *filename, - GVariant ** out_con_dict, - GVariant ** out_con_props, - char ** out_expected_iface, - char ** out_action, - char ** out_connectivity_state, - char ** out_vpn_ip_iface, - GError ** error) -{ - nm_auto_clear_variant_builder GVariantBuilder props = {}; - gs_free char * uuid = NULL; - gs_free char * id = NULL; - gs_unref_object NMConnection *connection = NULL; - NMSettingConnection * s_con; - - *out_expected_iface = g_key_file_get_string(kf, "main", "expected-iface", NULL); - - *out_connectivity_state = g_key_file_get_string(kf, "main", "connectivity-state", NULL); - *out_vpn_ip_iface = g_key_file_get_string(kf, "main", "vpn-ip-iface", NULL); - - *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_simple_connection_new(); - s_con = (NMSettingConnection *) nm_setting_connection_new(); - g_object_set(s_con, NM_SETTING_CONNECTION_UUID, uuid, NM_SETTING_CONNECTION_ID, id, NULL); - nm_connection_add_setting(connection, NM_SETTING(s_con)); - - *out_con_dict = nm_connection_to_dbus(connection, NM_CONNECTION_SERIALIZE_ALL); - - g_variant_builder_init(&props, G_VARIANT_TYPE("a{sv}")); - g_variant_builder_add( - &props, - "{sv}", - NMD_CONNECTION_PROPS_PATH, - g_variant_new_object_path("/org/freedesktop/NetworkManager/Connections/5")); - - /* Strip out the non-fixed portion of the filename */ - filename = strstr(filename, "/dispatcher"); - g_variant_builder_add(&props, "{sv}", "filename", g_variant_new_string(filename)); - - if (g_key_file_get_boolean(kf, "main", "external", NULL)) { - g_variant_builder_add(&props, "{sv}", "external", g_variant_new_boolean(TRUE)); - } - - *out_con_props = g_variant_builder_end(&props); - - return TRUE; -} - -static gboolean -parse_device(GKeyFile *kf, GVariant **out_device_props, GError **error) -{ - nm_auto_clear_variant_builder GVariantBuilder props = {}; - gs_free char * tmp = NULL; - int i; - - g_variant_builder_init(&props, G_VARIANT_TYPE("a{sv}")); - - i = g_key_file_get_integer(kf, "device", "state", error); - if (i == 0) - return FALSE; - g_variant_builder_add(&props, "{sv}", NMD_DEVICE_PROPS_STATE, g_variant_new_uint32(i)); - - i = g_key_file_get_integer(kf, "device", "type", error); - if (i == 0) - return FALSE; - g_variant_builder_add(&props, "{sv}", NMD_DEVICE_PROPS_TYPE, g_variant_new_uint32(i)); - - tmp = g_key_file_get_string(kf, "device", "interface", error); - if (tmp == NULL) - return FALSE; - g_variant_builder_add(&props, "{sv}", NMD_DEVICE_PROPS_INTERFACE, g_variant_new_string(tmp)); - - nm_clear_g_free(&tmp); - tmp = g_key_file_get_string(kf, "device", "ip-interface", error); - if (tmp == NULL) - return FALSE; - g_variant_builder_add(&props, "{sv}", NMD_DEVICE_PROPS_IP_INTERFACE, g_variant_new_string(tmp)); - - nm_clear_g_free(&tmp); - tmp = g_key_file_get_string(kf, "device", "path", error); - if (tmp == NULL) - return FALSE; - g_variant_builder_add(&props, "{sv}", NMD_DEVICE_PROPS_PATH, g_variant_new_object_path(tmp)); - - *out_device_props = g_variant_builder_end(&props); - return TRUE; -} - -static gboolean -add_uint_array(GKeyFile * kf, - GVariantBuilder *props, - const char * section, - const char * key, - GError ** error) -{ - gs_free char * tmp = NULL; - gs_free const char **split = NULL; - gsize i; - - tmp = g_key_file_get_string(kf, section, key, NULL); - if (tmp == NULL) - return TRUE; - - split = nm_utils_strsplit_set_with_empty(tmp, " "); - if (split) { - gs_unref_array GArray *items = NULL; - - items = g_array_sized_new(FALSE, TRUE, sizeof(guint32), NM_PTRARRAY_LEN(split)); - for (i = 0; split[i]; i++) { - const char *s; - - s = split[i]; - g_strstrip((char *) s); - if (s[0]) { - guint32 addr; - - if (inet_pton(AF_INET, s, &addr) != 1) - g_assert_not_reached(); - g_array_append_val(items, addr); - } - } - g_variant_builder_add(props, - "{sv}", - key, - g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, - items->data, - items->len, - sizeof(guint32))); - } - - return TRUE; -} - -static gboolean -parse_proxy(GKeyFile *kf, GVariant **out_props, const char *section, GError **error) -{ - nm_auto_clear_variant_builder GVariantBuilder props = {}; - gs_free char * tmp = NULL; - - g_variant_builder_init(&props, G_VARIANT_TYPE("a{sv}")); - - tmp = g_key_file_get_string(kf, section, "pac-url", error); - if (tmp == NULL) - return FALSE; - g_variant_builder_add(&props, "{sv}", "pac-url", g_variant_new_string(tmp)); - - nm_clear_g_free(&tmp); - tmp = g_key_file_get_string(kf, section, "pac-script", error); - if (tmp == NULL) - return FALSE; - g_variant_builder_add(&props, "{sv}", "pac-script", g_variant_new_string(tmp)); - - *out_props = g_variant_builder_end(&props); - return TRUE; -} - -static gboolean -parse_ip4(GKeyFile *kf, GVariant **out_props, const char *section, GError **error) -{ - nm_auto_clear_variant_builder GVariantBuilder props = {}; - gs_free char * tmp = NULL; - gs_free const char ** split = NULL; - const char ** iter; - - g_variant_builder_init(&props, G_VARIANT_TYPE("a{sv}")); - - /* search domains */ - /* Use char** for domains. (DBUS_TYPE_G_ARRAY_OF_STRING of NMIP4Config - * becomes G_TYPE_STRV when sending the value over D-Bus) - */ - tmp = g_key_file_get_string(kf, section, "domains", error); - if (tmp == NULL) - return FALSE; - split = nm_utils_strsplit_set_with_empty(tmp, " "); - if (split) { - for (iter = split; *iter; iter++) - g_strstrip((char *) *iter); - g_variant_builder_add(&props, "{sv}", "domains", g_variant_new_strv((gpointer) split, -1)); - } - nm_clear_g_free(&split); - - if (!add_uint_array(kf, &props, "ip4", "nameservers", error)) - return FALSE; - - if (!add_uint_array(kf, &props, "ip4", "wins-servers", error)) - return FALSE; - - nm_clear_g_free(&tmp); - tmp = g_key_file_get_string(kf, section, "addresses", error); - if (tmp == NULL) - return FALSE; - split = nm_utils_strsplit_set_with_empty(tmp, ","); - if (split) { - gs_unref_ptrarray GPtrArray *addresses = NULL; - const char * gateway = NULL; - - addresses = g_ptr_array_new_with_free_func((GDestroyNotify) nm_ip_address_unref); - for (iter = split; *iter; iter++) { - const char * s = *iter; - NMIPAddress *addr; - const char * ip; - const char * prefix; - - g_strstrip((char *) s); - if (s[0] == '\0') - continue; - - ip = *iter; - - prefix = strchr(ip, '/'); - g_assert(prefix); - ((char *) (prefix++))[0] = '\0'; - - if (addresses->len == 0) { - gateway = strchr(prefix, ' '); - g_assert(gateway); - gateway++; - } - - addr = nm_ip_address_new(AF_INET, ip, (guint) atoi(prefix), error); - if (!addr) - return FALSE; - - g_ptr_array_add(addresses, addr); - } - - g_variant_builder_add(&props, - "{sv}", - "addresses", - nm_utils_ip4_addresses_to_variant(addresses, gateway)); - } - nm_clear_g_free(&split); - - nm_clear_g_free(&tmp); - tmp = g_key_file_get_string(kf, section, "routes", NULL); - split = nm_utils_strsplit_set_with_empty(tmp, ","); - if (split) { - gs_unref_ptrarray GPtrArray *routes = NULL; - - routes = g_ptr_array_new_with_free_func((GDestroyNotify) nm_ip_route_unref); - for (iter = split; *iter; iter++) { - const char *s = *iter; - NMIPRoute * route; - const char *dest; - const char *prefix; - const char *next_hop; - const char *metric; - - g_strstrip((char *) s); - if (s[0] == '\0') - continue; - - dest = s; - - prefix = strchr(dest, '/'); - g_assert(prefix); - ((char *) (prefix++))[0] = '\0'; - - next_hop = strchr(prefix, ' '); - g_assert(next_hop); - ((char *) (next_hop++))[0] = '\0'; - - metric = strchr(next_hop, ' '); - g_assert(metric); - ((char *) (metric++))[0] = '\0'; - - route = nm_ip_route_new(AF_INET, - dest, - _nm_utils_ascii_str_to_int64(prefix, 10, 0, 32, 255), - next_hop, - (guint) atoi(metric), - error); - if (!route) - return FALSE; - g_ptr_array_add(routes, route); - } - - g_variant_builder_add(&props, "{sv}", "routes", nm_utils_ip4_routes_to_variant(routes)); - } - - *out_props = g_variant_builder_end(&props); - return TRUE; -} - -static gboolean -parse_dhcp(GKeyFile *kf, const char *group_name, GVariant **out_props, GError **error) -{ - nm_auto_clear_variant_builder GVariantBuilder props = {}; - gs_strfreev char ** keys = NULL; - char ** iter; - - keys = g_key_file_get_keys(kf, group_name, NULL, error); - if (!keys) - return FALSE; - - g_variant_builder_init(&props, G_VARIANT_TYPE("a{sv}")); - for (iter = keys; iter && *iter; iter++) { - gs_free char *val = NULL; - - val = g_key_file_get_string(kf, group_name, *iter, error); - if (!val) - return FALSE; - g_variant_builder_add(&props, "{sv}", *iter, g_variant_new_string(val)); - } - - *out_props = g_variant_builder_end(&props); - return TRUE; -} - -static gboolean -get_dispatcher_file(const char * file, - GVariant ** out_con_dict, - GVariant ** out_con_props, - GVariant ** out_device_props, - GVariant ** out_device_proxy_props, - GVariant ** out_device_ip4_props, - GVariant ** out_device_ip6_props, - GVariant ** out_device_dhcp4_props, - GVariant ** out_device_dhcp6_props, - char ** out_connectivity_state, - char ** out_vpn_ip_iface, - GVariant ** out_vpn_proxy_props, - GVariant ** out_vpn_ip4_props, - GVariant ** out_vpn_ip6_props, - char ** out_expected_iface, - char ** out_action, - GHashTable **out_env, - GError ** error) -{ - nm_auto_unref_keyfile GKeyFile *kf = NULL; - gs_strfreev char ** keys = NULL; - char ** iter; - - g_assert(!error || !*error); - g_assert(out_con_dict && !*out_con_dict); - g_assert(out_con_props && !*out_con_props); - g_assert(out_device_props && !*out_device_props); - g_assert(out_device_proxy_props && !*out_device_proxy_props); - g_assert(out_device_ip4_props && !*out_device_ip4_props); - g_assert(out_device_ip6_props && !*out_device_ip6_props); - g_assert(out_device_dhcp4_props && !*out_device_dhcp4_props); - g_assert(out_device_dhcp6_props && !*out_device_dhcp6_props); - g_assert(out_connectivity_state && !*out_connectivity_state); - g_assert(out_vpn_ip_iface && !*out_vpn_ip_iface); - g_assert(out_vpn_proxy_props && !*out_vpn_proxy_props); - g_assert(out_vpn_ip4_props && !*out_vpn_ip4_props); - g_assert(out_vpn_ip6_props && !*out_vpn_ip6_props); - g_assert(out_expected_iface && !*out_expected_iface); - g_assert(out_action && !*out_action); - g_assert(out_env && !*out_env); - - 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, - file, - out_con_dict, - out_con_props, - out_expected_iface, - out_action, - out_connectivity_state, - out_vpn_ip_iface, - error)) - return FALSE; - - if (!parse_device(kf, out_device_props, error)) - return FALSE; - - if (g_key_file_has_group(kf, "proxy")) { - if (!parse_proxy(kf, out_device_proxy_props, "proxy", error)) - return FALSE; - } - - if (g_key_file_has_group(kf, "ip4")) { - if (!parse_ip4(kf, out_device_ip4_props, "ip4", error)) - return FALSE; - } - - if (g_key_file_has_group(kf, "dhcp4")) { - if (!parse_dhcp(kf, "dhcp4", out_device_dhcp4_props, error)) - return FALSE; - } - - if (g_key_file_has_group(kf, "dhcp6")) { - if (!parse_dhcp(kf, "dhcp6", out_device_dhcp6_props, error)) - return FALSE; - } - - 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++) { - gs_free char *val = NULL; - - val = g_key_file_get_string(kf, "env", *iter, error); - if (!val) - return FALSE; - g_hash_table_insert(*out_env, g_strdup_printf("%s=%s", *iter, val), GUINT_TO_POINTER(1)); - } - - return TRUE; -} - -/*****************************************************************************/ - -static void -test_generic(const char *file, const char *override_vpn_ip_iface) -{ - gs_unref_variant GVariant *con_dict = NULL; - gs_unref_variant GVariant *con_props = NULL; - gs_unref_variant GVariant *device_props = NULL; - gs_unref_variant GVariant *device_proxy_props = NULL; - gs_unref_variant GVariant *device_ip4_props = NULL; - gs_unref_variant GVariant *device_ip6_props = NULL; - gs_unref_variant GVariant *device_dhcp4_props = NULL; - gs_unref_variant GVariant *device_dhcp6_props = NULL; - gs_free char * connectivity_change = NULL; - gs_free char * vpn_ip_iface = NULL; - gs_unref_variant GVariant *vpn_proxy_props = NULL; - gs_unref_variant GVariant *vpn_ip4_props = NULL; - gs_unref_variant GVariant *vpn_ip6_props = NULL; - gs_free char * expected_iface = NULL; - gs_free char * action = NULL; - gs_free char * out_iface = NULL; - const char * error_message = NULL; - gs_unref_hashtable GHashTable *expected_env = NULL; - GError * error = NULL; - gboolean success; - gs_free char * filename = NULL; - gs_strfreev char ** denv = NULL; - char ** iter; - - filename = g_build_filename(TEST_DIR, file, NULL); - success = get_dispatcher_file(filename, - &con_dict, - &con_props, - &device_props, - &device_proxy_props, - &device_ip4_props, - &device_ip6_props, - &device_dhcp4_props, - &device_dhcp6_props, - &connectivity_change, - &vpn_ip_iface, - &vpn_proxy_props, - &vpn_ip4_props, - &vpn_ip6_props, - &expected_iface, - &action, - &expected_env, - &error); - nmtst_assert_success(success, error); - - /* Get the environment from the dispatcher code */ - denv = nm_dispatcher_utils_construct_envp(action, - con_dict, - con_props, - device_props, - device_proxy_props, - device_ip4_props, - device_ip6_props, - device_dhcp4_props, - device_dhcp6_props, - connectivity_change, - override_vpn_ip_iface ?: vpn_ip_iface, - vpn_proxy_props, - vpn_ip4_props, - vpn_ip6_props, - &out_iface, - &error_message); - - g_assert((!denv && error_message) || (denv && !error_message)); - - if (error_message) - g_error("FAILED: %s", error_message); - - if (g_strv_length(denv) != g_hash_table_size(expected_env)) { - _print_env(NM_CAST_STRV_CC(denv), expected_env); - g_assert_cmpint(g_strv_length(denv), ==, g_hash_table_size(expected_env)); - } - - /* Compare dispatcher generated env and expected env */ - for (iter = denv; iter && *iter; iter++) { - gpointer foo; - const char *i_value = *iter; - - if (strstr(i_value, "PATH=") == i_value) { - g_assert_cmpstr(&i_value[strlen("PATH=")], ==, g_getenv("PATH")); - - /* The path is constructed dynamically. Ignore the actual value. */ - i_value = "PATH="; - } - - foo = g_hash_table_lookup(expected_env, i_value); - if (!foo) { - _print_env(NM_CAST_STRV_CC(denv), expected_env); - g_error("Failed to find %s in environment", i_value); - } - } - - g_assert_cmpstr(expected_iface, ==, out_iface); -} - -/*****************************************************************************/ - -static void -test_up(void) -{ - test_generic("dispatcher-up", NULL); -} - -static void -test_down(void) -{ - test_generic("dispatcher-down", NULL); -} - -static void -test_vpn_up(void) -{ - test_generic("dispatcher-vpn-up", NULL); -} - -static void -test_vpn_down(void) -{ - test_generic("dispatcher-vpn-down", NULL); -} - -static void -test_external(void) -{ - test_generic("dispatcher-external", NULL); -} - -static void -test_connectivity_changed(void) -{ - /* These tests will check that the CONNECTIVITY_STATE environment - * variable is only defined for known states, such as 'full'. */ - test_generic("dispatcher-connectivity-unknown", NULL); - test_generic("dispatcher-connectivity-full", NULL); -} - -static void -test_up_empty_vpn_iface(void) -{ - /* Test that an empty VPN iface variable, like is passed through D-Bus - * from NM, is ignored by the dispatcher environment construction code. - */ - test_generic("dispatcher-up", ""); -} - -/*****************************************************************************/ - -static void -test_gdbus_codegen(void) -{ - gs_unref_object NMDBusDispatcher *dbus_dispatcher = NULL; - - dbus_dispatcher = nmdbus_dispatcher_skeleton_new(); - g_assert(NMDBUS_IS_DISPATCHER_SKELETON(dbus_dispatcher)); -} - -/*****************************************************************************/ - -NMTST_DEFINE(); - -int -main(int argc, char **argv) -{ - nmtst_init(&argc, &argv, TRUE); - - g_test_add_func("/dispatcher/up", test_up); - g_test_add_func("/dispatcher/down", test_down); - g_test_add_func("/dispatcher/vpn_up", test_vpn_up); - g_test_add_func("/dispatcher/vpn_down", test_vpn_down); - g_test_add_func("/dispatcher/external", test_external); - g_test_add_func("/dispatcher/connectivity_changed", test_connectivity_changed); - - g_test_add_func("/dispatcher/up_empty_vpn_iface", test_up_empty_vpn_iface); - - g_test_add_func("/dispatcher/gdbus-codegen", test_gdbus_codegen); - - return g_test_run(); -} |