about summary refs log tree commit diff
path: root/dispatcher
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2021-10-01 23:05:04 +0200
committerMichael Biebl <biebl@debian.org>2021-10-01 23:05:04 +0200
commite74c568b07b50b97873fb4ee1d776dedefbd54d6 (patch)
tree3469f17ea9af91f7ff169b890633bda68b0cf76e /dispatcher
parentbfe522304da217296e2a61040f58e35ec5d6f3f2 (diff)
New upstream version 1.32.12 upstream/1.32.12
Diffstat (limited to 'dispatcher')
-rw-r--r--dispatcher/meson.build57
-rw-r--r--dispatcher/nm-dispatcher-utils.c581
-rw-r--r--dispatcher/nm-dispatcher-utils.h26
-rw-r--r--dispatcher/nm-dispatcher.c1101
-rw-r--r--dispatcher/nm-dispatcher.conf13
-rw-r--r--dispatcher/nm-dispatcher.xml46
-rw-r--r--dispatcher/org.freedesktop.nm_dispatcher.service.in6
-rw-r--r--dispatcher/tests/dispatcher-connectivity-full17
-rw-r--r--dispatcher/tests/dispatcher-connectivity-unknown16
-rw-r--r--dispatcher/tests/dispatcher-down23
-rw-r--r--dispatcher/tests/dispatcher-external40
-rw-r--r--dispatcher/tests/dispatcher-up66
-rw-r--r--dispatcher/tests/dispatcher-vpn-down65
-rw-r--r--dispatcher/tests/dispatcher-vpn-up65
-rw-r--r--dispatcher/tests/meson.build24
-rw-r--r--dispatcher/tests/test-dispatcher-envp.c637
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();
-}