about summary refs log tree commit diff
path: root/src/nm-config-data.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2021-02-11 18:11:46 +0100
committerMichael Biebl <biebl@debian.org>2021-02-11 18:11:46 +0100
commit80ec1decc49c72efec2a8b87c06245c92c0ab807 (patch)
treee3b229aa94e8dcf0590f2317664176e7b8f7607b /src/nm-config-data.c
parent65f86e8f56267192d42f2b629fc6b0c99fb9cd0c (diff)
New upstream version 1.29.90 upstream/1.29.90
Diffstat (limited to 'src/nm-config-data.c')
-rw-r--r--src/nm-config-data.c2087
1 files changed, 0 insertions, 2087 deletions
diff --git a/src/nm-config-data.c b/src/nm-config-data.c
deleted file mode 100644
index 4320e26b..00000000
--- a/src/nm-config-data.c
+++ /dev/null
@@ -1,2087 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Copyright (C) 2011 Red Hat, Inc.
- * Copyright (C) 2013 Thomas Bechtold <thomasbechtold@jpberlin.de>
- */
-
-#include "nm-default.h"
-
-#include "nm-config-data.h"
-
-#include "nm-config.h"
-#include "devices/nm-device.h"
-#include "nm-core-internal.h"
-#include "nm-keyfile/nm-keyfile-internal.h"
-#include "nm-keyfile/nm-keyfile-utils.h"
-
-/*****************************************************************************/
-
-typedef struct {
-    char *   group_name;
-    gboolean stop_match;
-    struct {
-        /* have a separate boolean field @has, because a @spec with
-         * value %NULL does not necessarily mean, that the property
-         * "match-device" was unspecified. */
-        gboolean has;
-        GSList * spec;
-    } match_device;
-} MatchSectionInfo;
-
-struct _NMGlobalDnsDomain {
-    char * name;
-    char **servers;
-    char **options;
-};
-
-struct _NMGlobalDnsConfig {
-    char **      searches;
-    char **      options;
-    GHashTable * domains;
-    const char **domain_list;
-    gboolean     internal;
-};
-
-/*****************************************************************************/
-
-NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_CONFIG_MAIN_FILE,
-                                  PROP_CONFIG_DESCRIPTION,
-                                  PROP_KEYFILE_USER,
-                                  PROP_KEYFILE_INTERN,
-                                  PROP_CONNECTIVITY_ENABLED,
-                                  PROP_CONNECTIVITY_URI,
-                                  PROP_CONNECTIVITY_INTERVAL,
-                                  PROP_CONNECTIVITY_RESPONSE,
-                                  PROP_NO_AUTO_DEFAULT, );
-
-typedef struct {
-    char *config_main_file;
-    char *config_description;
-
-    GKeyFile *keyfile;
-    GKeyFile *keyfile_user;
-    GKeyFile *keyfile_intern;
-
-    /* A zero-terminated list of pre-processed information from the
-     * [connection] sections. This is to speed up lookup. */
-    MatchSectionInfo *connection_infos;
-
-    /* A zero-terminated list of pre-processed information from the
-     * [device] sections. This is to speed up lookup. */
-    MatchSectionInfo *device_infos;
-
-    struct {
-        gboolean enabled;
-        char *   uri;
-        char *   response;
-        guint    interval;
-    } connectivity;
-
-    int autoconnect_retries_default;
-
-    struct {
-        /* from /var/lib/NetworkManager/no-auto-default.state */
-        char ** arr;
-        GSList *specs;
-
-        /* from main.no-auto-default setting in NetworkManager.conf. */
-        GSList *specs_config;
-    } no_auto_default;
-
-    GSList *ignore_carrier;
-    GSList *assume_ipv6ll_only;
-
-    char *dns_mode;
-    char *rc_manager;
-
-    NMGlobalDnsConfig *global_dns;
-
-    bool systemd_resolved : 1;
-} NMConfigDataPrivate;
-
-struct _NMConfigData {
-    GObject             parent;
-    NMConfigDataPrivate _priv;
-};
-
-struct _NMConfigDataClass {
-    GObjectClass parent;
-};
-
-G_DEFINE_TYPE(NMConfigData, nm_config_data, G_TYPE_OBJECT)
-
-#define NM_CONFIG_DATA_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMConfigData, NM_IS_CONFIG_DATA)
-
-/*****************************************************************************/
-
-const char *
-nm_config_data_get_config_main_file(const NMConfigData *self)
-{
-    g_return_val_if_fail(self, NULL);
-
-    return NM_CONFIG_DATA_GET_PRIVATE(self)->config_main_file;
-}
-
-const char *
-nm_config_data_get_config_description(const NMConfigData *self)
-{
-    g_return_val_if_fail(self, NULL);
-
-    return NM_CONFIG_DATA_GET_PRIVATE(self)->config_description;
-}
-
-gboolean
-nm_config_data_has_group(const NMConfigData *self, const char *group)
-{
-    g_return_val_if_fail(NM_IS_CONFIG_DATA(self), FALSE);
-    g_return_val_if_fail(group && *group, FALSE);
-
-    return g_key_file_has_group(NM_CONFIG_DATA_GET_PRIVATE(self)->keyfile, group);
-}
-
-char *
-nm_config_data_get_value(const NMConfigData *  self,
-                         const char *          group,
-                         const char *          key,
-                         NMConfigGetValueFlags flags)
-{
-    g_return_val_if_fail(NM_IS_CONFIG_DATA(self), NULL);
-    g_return_val_if_fail(group && *group, NULL);
-    g_return_val_if_fail(key && *key, NULL);
-
-    return nm_config_keyfile_get_value(NM_CONFIG_DATA_GET_PRIVATE(self)->keyfile,
-                                       group,
-                                       key,
-                                       flags);
-}
-
-gboolean
-nm_config_data_has_value(const NMConfigData *  self,
-                         const char *          group,
-                         const char *          key,
-                         NMConfigGetValueFlags flags)
-{
-    gs_free char *value = NULL;
-
-    g_return_val_if_fail(NM_IS_CONFIG_DATA(self), FALSE);
-    g_return_val_if_fail(group && *group, FALSE);
-    g_return_val_if_fail(key && *key, FALSE);
-
-    value =
-        nm_config_keyfile_get_value(NM_CONFIG_DATA_GET_PRIVATE(self)->keyfile, group, key, flags);
-    return !!value;
-}
-
-int
-nm_config_data_get_value_boolean(const NMConfigData *self,
-                                 const char *        group,
-                                 const char *        key,
-                                 int                 default_value)
-{
-    char *str;
-    int   value = default_value;
-
-    g_return_val_if_fail(NM_IS_CONFIG_DATA(self), default_value);
-    g_return_val_if_fail(group && *group, default_value);
-    g_return_val_if_fail(key && *key, default_value);
-
-    /* when parsing the boolean, base it on the raw value from g_key_file_get_value(). */
-    str = nm_config_keyfile_get_value(NM_CONFIG_DATA_GET_PRIVATE(self)->keyfile,
-                                      group,
-                                      key,
-                                      NM_CONFIG_GET_VALUE_RAW);
-    if (str) {
-        value = nm_config_parse_boolean(str, default_value);
-        g_free(str);
-    }
-    return value;
-}
-
-gint64
-nm_config_data_get_value_int64(const NMConfigData *self,
-                               const char *        group,
-                               const char *        key,
-                               guint               base,
-                               gint64              min,
-                               gint64              max,
-                               gint64              fallback)
-{
-    int    errsv;
-    gint64 val;
-    char * str;
-
-    g_return_val_if_fail(NM_IS_CONFIG_DATA(self), fallback);
-    g_return_val_if_fail(group && *group, fallback);
-    g_return_val_if_fail(key && *key, fallback);
-
-    str = nm_config_keyfile_get_value(NM_CONFIG_DATA_GET_PRIVATE(self)->keyfile,
-                                      group,
-                                      key,
-                                      NM_CONFIG_GET_VALUE_NONE);
-    val = _nm_utils_ascii_str_to_int64(str, base, min, max, fallback);
-    if (str) {
-        errsv = errno;
-        g_free(str);
-        errno = errsv;
-    }
-    return val;
-}
-
-char **
-nm_config_data_get_plugins(const NMConfigData *self, gboolean allow_default)
-{
-    gs_free_error GError *     error = NULL;
-    const NMConfigDataPrivate *priv;
-    char **                    list;
-
-    g_return_val_if_fail(self, NULL);
-
-    priv = NM_CONFIG_DATA_GET_PRIVATE(self);
-
-    list = g_key_file_get_string_list(priv->keyfile,
-                                      NM_CONFIG_KEYFILE_GROUP_MAIN,
-                                      "plugins",
-                                      NULL,
-                                      &error);
-    if (nm_keyfile_error_is_not_found(error) && allow_default) {
-        nm_auto_unref_keyfile GKeyFile *kf = nm_config_create_keyfile();
-
-        /* let keyfile split the default string according to its own escaping rules. */
-        g_key_file_set_value(kf,
-                             NM_CONFIG_KEYFILE_GROUP_MAIN,
-                             "plugins",
-                             NM_CONFIG_DEFAULT_MAIN_PLUGINS);
-        list = g_key_file_get_string_list(kf, NM_CONFIG_KEYFILE_GROUP_MAIN, "plugins", NULL, NULL);
-    }
-    return _nm_utils_strv_cleanup(list, TRUE, TRUE, TRUE);
-}
-
-gboolean
-nm_config_data_get_connectivity_enabled(const NMConfigData *self)
-{
-    g_return_val_if_fail(self, FALSE);
-
-    return NM_CONFIG_DATA_GET_PRIVATE(self)->connectivity.enabled;
-}
-
-const char *
-nm_config_data_get_connectivity_uri(const NMConfigData *self)
-{
-    g_return_val_if_fail(self, NULL);
-
-    return NM_CONFIG_DATA_GET_PRIVATE(self)->connectivity.uri;
-}
-
-guint
-nm_config_data_get_connectivity_interval(const NMConfigData *self)
-{
-    g_return_val_if_fail(self, 0);
-
-    return NM_CONFIG_DATA_GET_PRIVATE(self)->connectivity.interval;
-}
-
-const char *
-nm_config_data_get_connectivity_response(const NMConfigData *self)
-{
-    g_return_val_if_fail(self != NULL, NULL);
-
-    return NM_CONFIG_DATA_GET_PRIVATE(self)->connectivity.response;
-}
-
-int
-nm_config_data_get_autoconnect_retries_default(const NMConfigData *self)
-{
-    g_return_val_if_fail(self, FALSE);
-
-    return NM_CONFIG_DATA_GET_PRIVATE(self)->autoconnect_retries_default;
-}
-
-const char *const *
-nm_config_data_get_no_auto_default(const NMConfigData *self)
-{
-    g_return_val_if_fail(self, FALSE);
-
-    return (const char *const *) NM_CONFIG_DATA_GET_PRIVATE(self)->no_auto_default.arr;
-}
-
-gboolean
-nm_config_data_get_no_auto_default_for_device(const NMConfigData *self, NMDevice *device)
-{
-    const NMConfigDataPrivate *priv;
-
-    g_return_val_if_fail(NM_IS_CONFIG_DATA(self), FALSE);
-    g_return_val_if_fail(NM_IS_DEVICE(device), FALSE);
-
-    priv = NM_CONFIG_DATA_GET_PRIVATE(self);
-    return nm_device_spec_match_list(device, priv->no_auto_default.specs)
-           || nm_device_spec_match_list(device, priv->no_auto_default.specs_config);
-}
-
-const char *
-nm_config_data_get_dns_mode(const NMConfigData *self)
-{
-    g_return_val_if_fail(self, NULL);
-
-    return NM_CONFIG_DATA_GET_PRIVATE(self)->dns_mode;
-}
-
-const char *
-nm_config_data_get_rc_manager(const NMConfigData *self)
-{
-    g_return_val_if_fail(self, NULL);
-
-    return NM_CONFIG_DATA_GET_PRIVATE(self)->rc_manager;
-}
-
-gboolean
-nm_config_data_get_systemd_resolved(const NMConfigData *self)
-{
-    g_return_val_if_fail(self, FALSE);
-
-    return NM_CONFIG_DATA_GET_PRIVATE(self)->systemd_resolved;
-}
-
-gboolean
-nm_config_data_get_ignore_carrier(const NMConfigData *self, NMDevice *device)
-{
-    gs_free char *value = NULL;
-    gboolean      has_match;
-    int           m;
-
-    g_return_val_if_fail(NM_IS_CONFIG_DATA(self), FALSE);
-    g_return_val_if_fail(NM_IS_DEVICE(device), FALSE);
-
-    value = nm_config_data_get_device_config(self,
-                                             NM_CONFIG_KEYFILE_KEY_DEVICE_IGNORE_CARRIER,
-                                             device,
-                                             &has_match);
-    if (has_match)
-        m = nm_config_parse_boolean(value, -1);
-    else
-        m = nm_device_spec_match_list_full(device,
-                                           NM_CONFIG_DATA_GET_PRIVATE(self)->ignore_carrier,
-                                           -1);
-
-    if (NM_IN_SET(m, TRUE, FALSE))
-        return m;
-
-    /* if ignore-carrier is not explicitly configed, then it depends on the device (type). */
-    return nm_device_ignore_carrier_by_default(device);
-}
-
-gboolean
-nm_config_data_get_assume_ipv6ll_only(const NMConfigData *self, NMDevice *device)
-{
-    g_return_val_if_fail(NM_IS_CONFIG_DATA(self), FALSE);
-    g_return_val_if_fail(NM_IS_DEVICE(device), FALSE);
-
-    return nm_device_spec_match_list(device, NM_CONFIG_DATA_GET_PRIVATE(self)->assume_ipv6ll_only);
-}
-
-GKeyFile *
-nm_config_data_clone_keyfile_intern(const NMConfigData *self)
-{
-    const NMConfigDataPrivate *priv;
-    GKeyFile *                 keyfile;
-
-    g_return_val_if_fail(NM_IS_CONFIG_DATA(self), FALSE);
-
-    priv = NM_CONFIG_DATA_GET_PRIVATE(self);
-
-    keyfile = nm_config_create_keyfile();
-    if (priv->keyfile_intern)
-        _nm_keyfile_copy(keyfile, priv->keyfile_intern);
-    return keyfile;
-}
-
-GKeyFile *
-_nm_config_data_get_keyfile(const NMConfigData *self)
-{
-    return NM_CONFIG_DATA_GET_PRIVATE(self)->keyfile;
-}
-
-GKeyFile *
-_nm_config_data_get_keyfile_intern(const NMConfigData *self)
-{
-    return NM_CONFIG_DATA_GET_PRIVATE(self)->keyfile_intern;
-}
-
-GKeyFile *
-_nm_config_data_get_keyfile_user(const NMConfigData *self)
-{
-    return NM_CONFIG_DATA_GET_PRIVATE(self)->keyfile_user;
-}
-
-/*****************************************************************************/
-
-static NMAuthPolkitMode
-nm_auth_polkit_mode_from_string(const char *str)
-{
-    int as_bool;
-
-    if (!str)
-        return NM_AUTH_POLKIT_MODE_UNKNOWN;
-
-    if (nm_streq(str, "root-only"))
-        return NM_AUTH_POLKIT_MODE_ROOT_ONLY;
-
-    as_bool = _nm_utils_ascii_str_to_bool(str, -1);
-    if (as_bool != -1) {
-        return as_bool ? NM_AUTH_POLKIT_MODE_USE_POLKIT : NM_AUTH_POLKIT_MODE_ALLOW_ALL;
-    }
-
-    return NM_AUTH_POLKIT_MODE_UNKNOWN;
-}
-
-static NMAuthPolkitMode
-_config_data_get_main_auth_polkit(const NMConfigData *self, gboolean *out_invalid_config)
-{
-    NMAuthPolkitMode auth_polkit_mode;
-    const char *     str;
-
-    str              = nm_config_data_get_value(self,
-                                   NM_CONFIG_KEYFILE_GROUP_MAIN,
-                                   NM_CONFIG_KEYFILE_KEY_MAIN_AUTH_POLKIT,
-                                   NM_CONFIG_GET_VALUE_STRIP | NM_CONFIG_GET_VALUE_NO_EMPTY);
-    auth_polkit_mode = nm_auth_polkit_mode_from_string(str);
-    if (auth_polkit_mode == NM_AUTH_POLKIT_MODE_UNKNOWN) {
-        NM_SET_OUT(out_invalid_config, (str != NULL));
-        auth_polkit_mode = nm_auth_polkit_mode_from_string(NM_CONFIG_DEFAULT_MAIN_AUTH_POLKIT);
-        if (auth_polkit_mode == NM_AUTH_POLKIT_MODE_UNKNOWN) {
-            nm_assert_not_reached();
-            auth_polkit_mode = NM_AUTH_POLKIT_MODE_ROOT_ONLY;
-        }
-    } else
-        NM_SET_OUT(out_invalid_config, FALSE);
-
-    return auth_polkit_mode;
-}
-
-NMAuthPolkitMode
-nm_config_data_get_main_auth_polkit(const NMConfigData *self)
-{
-    return _config_data_get_main_auth_polkit(self, NULL);
-}
-
-/*****************************************************************************/
-
-/**
- * nm_config_data_get_groups:
- * @self: the #NMConfigData instance
- *
- * Returns: (transfer full): the list of groups in the configuration. The order
- * of the section is undefined, as the configuration gets merged from multiple
- * sources.
- */
-char **
-nm_config_data_get_groups(const NMConfigData *self)
-{
-    g_return_val_if_fail(NM_IS_CONFIG_DATA(self), NULL);
-
-    return g_key_file_get_groups(NM_CONFIG_DATA_GET_PRIVATE(self)->keyfile, NULL);
-}
-
-char **
-nm_config_data_get_keys(const NMConfigData *self, const char *group)
-{
-    g_return_val_if_fail(NM_IS_CONFIG_DATA(self), NULL);
-    g_return_val_if_fail(group && *group, NULL);
-
-    return g_key_file_get_keys(NM_CONFIG_DATA_GET_PRIVATE(self)->keyfile, group, NULL, NULL);
-}
-
-/**
- * nm_config_data_is_intern_atomic_group:
- * @self:
- * @group: name of the group to check.
- *
- * whether a configuration group @group exists and is entirely overwritten
- * by internal configuration, i.e. whether it is an atomic group that is
- * overwritten.
- *
- * It doesn't say, that there actually is a user setting that was overwritten. That
- * means there could be no corresponding section defined in user configuration
- * that required overwriting.
- *
- * Returns: %TRUE if @group exists and is an atomic group set via internal configuration.
- */
-gboolean
-nm_config_data_is_intern_atomic_group(const NMConfigData *self, const char *group)
-{
-    const NMConfigDataPrivate *priv;
-
-    g_return_val_if_fail(NM_IS_CONFIG_DATA(self), FALSE);
-    g_return_val_if_fail(group && *group, FALSE);
-
-    priv = NM_CONFIG_DATA_GET_PRIVATE(self);
-
-    if (!priv->keyfile_intern
-        || !g_key_file_has_key(priv->keyfile_intern,
-                               group,
-                               NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS,
-                               NULL))
-        return FALSE;
-
-    /* we have a .was entry for the section. That means that the section would be overwritten
-     * from user configuration. But it doesn't mean that the merged configuration contains this
-     * groups, because the internal setting could hide the user section.
-     * Only return TRUE, if we actually have such a group in the merged configuration.*/
-    return g_key_file_has_group(priv->keyfile, group);
-}
-
-/*****************************************************************************/
-
-static GKeyFile *
-_merge_keyfiles(GKeyFile *keyfile_user, GKeyFile *keyfile_intern)
-{
-    gs_strfreev char **groups = NULL;
-    guint              g, k;
-    GKeyFile *         keyfile;
-    gsize              ngroups;
-
-    keyfile = nm_config_create_keyfile();
-    if (keyfile_user)
-        _nm_keyfile_copy(keyfile, keyfile_user);
-    if (!keyfile_intern)
-        return keyfile;
-
-    groups = g_key_file_get_groups(keyfile_intern, &ngroups);
-    if (!groups)
-        return keyfile;
-
-    /* we must reverse the order of the connection settings so that we
-     * have lowest priority last. */
-    _nm_config_sort_groups(groups, ngroups);
-    for (g = 0; groups[g]; g++) {
-        const char *       group = groups[g];
-        gs_strfreev char **keys  = NULL;
-        gboolean           is_intern, is_atomic = FALSE;
-
-        keys = g_key_file_get_keys(keyfile_intern, group, NULL, NULL);
-        if (!keys)
-            continue;
-
-        is_intern = g_str_has_prefix(group, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN);
-        if (!is_intern
-            && g_key_file_has_key(keyfile_intern,
-                                  group,
-                                  NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS,
-                                  NULL)) {
-            /* the entire section is atomically overwritten by @keyfile_intern. */
-            g_key_file_remove_group(keyfile, group, NULL);
-            is_atomic = TRUE;
-        }
-
-        for (k = 0; keys[k]; k++) {
-            const char *  key   = keys[k];
-            gs_free char *value = NULL;
-
-            if (is_atomic && strcmp(key, NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS) == 0)
-                continue;
-
-            if (!is_intern && !is_atomic
-                && NM_STR_HAS_PREFIX_WITH_MORE(key, NM_CONFIG_KEYFILE_KEYPREFIX_WAS)) {
-                const char *key_base = &key[NM_STRLEN(NM_CONFIG_KEYFILE_KEYPREFIX_WAS)];
-
-                if (!g_key_file_has_key(keyfile_intern, group, key_base, NULL))
-                    g_key_file_remove_key(keyfile, group, key_base, NULL);
-                continue;
-            }
-            if (!is_intern && !is_atomic
-                && NM_STR_HAS_PREFIX_WITH_MORE(key, NM_CONFIG_KEYFILE_KEYPREFIX_SET))
-                continue;
-
-            value = g_key_file_get_value(keyfile_intern, group, key, NULL);
-            g_key_file_set_value(keyfile, group, key, value);
-        }
-    }
-    return keyfile;
-}
-
-/*****************************************************************************/
-
-static int
-_nm_config_data_log_sort(const char **pa, const char **pb, gpointer dummy)
-{
-    gboolean    a_is_connection, b_is_connection;
-    gboolean    a_is_device, b_is_device;
-    gboolean    a_is_intern, b_is_intern;
-    gboolean    a_is_main, b_is_main;
-    const char *a = *pa;
-    const char *b = *pb;
-
-    /* we sort intern groups to the end. */
-    a_is_intern = g_str_has_prefix(a, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN);
-    b_is_intern = g_str_has_prefix(b, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN);
-
-    if (a_is_intern && b_is_intern)
-        return 0;
-    if (a_is_intern)
-        return 1;
-    if (b_is_intern)
-        return -1;
-
-    /* we sort connection groups before intern groups (to the end). */
-    a_is_connection = a && g_str_has_prefix(a, NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION);
-    b_is_connection = b && g_str_has_prefix(b, NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION);
-
-    if (a_is_connection && b_is_connection) {
-        /* if both are connection groups, we want the explicit [connection] group first. */
-        a_is_connection = a[NM_STRLEN(NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION)] == '\0';
-        b_is_connection = b[NM_STRLEN(NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION)] == '\0';
-
-        if (a_is_connection != b_is_connection) {
-            if (a_is_connection)
-                return -1;
-            return 1;
-        }
-        /* the sections are ordered lowest-priority first. Reverse their order. */
-        return pa < pb ? 1 : -1;
-    }
-    if (a_is_connection && !b_is_connection)
-        return 1;
-    if (b_is_connection && !a_is_connection)
-        return -1;
-
-    /* we sort device groups before connection groups (to the end). */
-    a_is_device = a && g_str_has_prefix(a, NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE);
-    b_is_device = b && g_str_has_prefix(b, NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE);
-
-    if (a_is_device && b_is_device) {
-        /* if both are device groups, we want the explicit [device] group first. */
-        a_is_device = a[NM_STRLEN(NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE)] == '\0';
-        b_is_device = b[NM_STRLEN(NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE)] == '\0';
-
-        if (a_is_device != b_is_device) {
-            if (a_is_device)
-                return -1;
-            return 1;
-        }
-        /* the sections are ordered lowest-priority first. Reverse their order. */
-        return pa < pb ? 1 : -1;
-    }
-    if (a_is_device && !b_is_device)
-        return 1;
-    if (b_is_device && !a_is_device)
-        return -1;
-
-    a_is_main = nm_streq0(a, "main");
-    b_is_main = nm_streq0(b, "main");
-    if (a_is_main != b_is_main)
-        return a_is_main ? -1 : 1;
-
-    return g_strcmp0(a, b);
-}
-
-static const struct {
-    const char *group;
-    const char *key;
-    const char *value;
-} default_values[] = {
-    {NM_CONFIG_KEYFILE_GROUP_MAIN, "plugins", NM_CONFIG_DEFAULT_MAIN_PLUGINS},
-    {NM_CONFIG_KEYFILE_GROUP_MAIN, "rc-manager", NM_CONFIG_DEFAULT_MAIN_RC_MANAGER},
-    {NM_CONFIG_KEYFILE_GROUP_MAIN,
-     NM_CONFIG_KEYFILE_KEY_MAIN_AUTH_POLKIT,
-     NM_CONFIG_DEFAULT_MAIN_AUTH_POLKIT},
-    {NM_CONFIG_KEYFILE_GROUP_MAIN, NM_CONFIG_KEYFILE_KEY_MAIN_DHCP, NM_CONFIG_DEFAULT_MAIN_DHCP},
-    {NM_CONFIG_KEYFILE_GROUP_LOGGING, "backend", NM_CONFIG_DEFAULT_LOGGING_BACKEND},
-    {NM_CONFIG_KEYFILE_GROUP_LOGGING, "audit", NM_CONFIG_DEFAULT_LOGGING_AUDIT},
-};
-
-void
-nm_config_data_log(const NMConfigData * self,
-                   const char *         prefix,
-                   const char *         key_prefix,
-                   const char *         no_auto_default_file,
-                   /* FILE* */ gpointer print_stream)
-{
-    const NMConfigDataPrivate *priv;
-    gs_strfreev char **        groups = NULL;
-    gsize                      ngroups;
-    guint                      g, k, i;
-    FILE *                     stream          = print_stream;
-    gs_unref_ptrarray GPtrArray *groups_full   = NULL;
-    gboolean                     print_default = !!stream;
-
-    g_return_if_fail(NM_IS_CONFIG_DATA(self));
-
-    if (!stream && !nm_logging_enabled(LOGL_DEBUG, LOGD_CORE))
-        return;
-
-    if (!prefix)
-        prefix = "";
-    if (!key_prefix)
-        key_prefix = "";
-
-#define _LOG(stream, prefix, ...)                                \
-    G_STMT_START                                                 \
-    {                                                            \
-        if (!stream)                                             \
-            _nm_log(LOGL_DEBUG,                                  \
-                    LOGD_CORE,                                   \
-                    0,                                           \
-                    NULL,                                        \
-                    NULL,                                        \
-                    "%s"_NM_UTILS_MACRO_FIRST(__VA_ARGS__) "%s", \
-                    prefix _NM_UTILS_MACRO_REST(__VA_ARGS__),    \
-                    "");                                         \
-        else                                                     \
-            fprintf(stream,                                      \
-                    "%s"_NM_UTILS_MACRO_FIRST(__VA_ARGS__) "%s", \
-                    prefix _NM_UTILS_MACRO_REST(__VA_ARGS__),    \
-                    "\n");                                       \
-    }                                                            \
-    G_STMT_END
-
-    priv = NM_CONFIG_DATA_GET_PRIVATE(self);
-
-    groups = g_key_file_get_groups(priv->keyfile, &ngroups);
-    if (!groups)
-        ngroups = 0;
-
-    groups_full = g_ptr_array_sized_new(ngroups + 5);
-
-    if (ngroups) {
-        g_ptr_array_set_size(groups_full, ngroups);
-        memcpy(groups_full->pdata, groups, sizeof(groups[0]) * ngroups);
-        g_ptr_array_sort_with_data(groups_full, (GCompareDataFunc) _nm_config_data_log_sort, NULL);
-    }
-
-    if (print_default) {
-        for (g = 0; g < G_N_ELEMENTS(default_values); g++) {
-            const char *group = default_values[g].group;
-            gssize      idx;
-
-            idx = nm_utils_array_find_binary_search((gconstpointer *) groups_full->pdata,
-                                                    sizeof(char *),
-                                                    groups_full->len,
-                                                    &group,
-                                                    (GCompareDataFunc) _nm_config_data_log_sort,
-                                                    NULL);
-            if (idx < 0)
-                g_ptr_array_insert(groups_full, (~idx), (gpointer) group);
-        }
-    }
-
-    if (!stream)
-        _LOG(stream, prefix, "config-data[%p]: %u groups", self, groups_full->len);
-
-    for (g = 0; g < groups_full->len; g++) {
-        const char *       group = groups_full->pdata[g];
-        gs_strfreev char **keys  = NULL;
-        gboolean           is_atomic;
-
-        is_atomic = nm_config_data_is_intern_atomic_group(self, group);
-
-        _LOG(stream, prefix, "");
-        _LOG(stream, prefix, "[%s]%s", group, is_atomic && !stream ? " # atomic section" : "");
-
-        /* Print default values as comments */
-        if (print_default) {
-            for (i = 0; i < G_N_ELEMENTS(default_values); i++) {
-                if (nm_streq(default_values[i].group, group)
-                    && !g_key_file_has_key(priv->keyfile, group, default_values[i].key, NULL)) {
-                    _LOG(stream,
-                         prefix,
-                         "%s# %s=%s",
-                         key_prefix,
-                         default_values[i].key,
-                         default_values[i].value);
-                }
-            }
-        }
-
-        keys = g_key_file_get_keys(priv->keyfile, group, NULL, NULL);
-        for (k = 0; keys && keys[k]; k++) {
-            const char *  key   = keys[k];
-            gs_free char *value = NULL;
-
-            value = g_key_file_get_value(priv->keyfile, group, key, NULL);
-            _LOG(stream, prefix, "%s%s=%s", key_prefix, key, value);
-        }
-    }
-
-    _LOG(stream, prefix, "");
-    _LOG(stream, prefix, "# no-auto-default file \"%s\"", no_auto_default_file);
-    {
-        gs_free char *msg = NULL;
-
-        msg = nm_utils_g_slist_strlist_join(priv->no_auto_default.specs, ",");
-        if (msg)
-            _LOG(stream, prefix, "# no-auto-default specs \"%s\"", msg);
-    }
-
-#undef _LOG
-}
-
-/*****************************************************************************/
-
-const char *const *
-nm_global_dns_config_get_searches(const NMGlobalDnsConfig *dns_config)
-{
-    g_return_val_if_fail(dns_config, NULL);
-
-    return (const char *const *) dns_config->searches;
-}
-
-const char *const *
-nm_global_dns_config_get_options(const NMGlobalDnsConfig *dns_config)
-{
-    g_return_val_if_fail(dns_config, NULL);
-
-    return (const char *const *) dns_config->options;
-}
-
-guint
-nm_global_dns_config_get_num_domains(const NMGlobalDnsConfig *dns_config)
-{
-    g_return_val_if_fail(dns_config, 0);
-
-    return dns_config->domains ? g_hash_table_size(dns_config->domains) : 0;
-}
-
-NMGlobalDnsDomain *
-nm_global_dns_config_get_domain(const NMGlobalDnsConfig *dns_config, guint i)
-{
-    NMGlobalDnsDomain *domain;
-
-    g_return_val_if_fail(dns_config, NULL);
-    g_return_val_if_fail(dns_config->domains, NULL);
-    g_return_val_if_fail(i < g_hash_table_size(dns_config->domains), NULL);
-
-    nm_assert(NM_PTRARRAY_LEN(dns_config->domain_list) == g_hash_table_size(dns_config->domains));
-
-    domain = g_hash_table_lookup(dns_config->domains, dns_config->domain_list[i]);
-
-    nm_assert(domain);
-    return domain;
-}
-
-NMGlobalDnsDomain *
-nm_global_dns_config_lookup_domain(const NMGlobalDnsConfig *dns_config, const char *name)
-{
-    g_return_val_if_fail(dns_config, NULL);
-    g_return_val_if_fail(name, NULL);
-
-    return dns_config->domains ? g_hash_table_lookup(dns_config->domains, name) : NULL;
-}
-
-const char *
-nm_global_dns_domain_get_name(const NMGlobalDnsDomain *domain)
-{
-    g_return_val_if_fail(domain, NULL);
-
-    return (const char *) domain->name;
-}
-
-const char *const *
-nm_global_dns_domain_get_servers(const NMGlobalDnsDomain *domain)
-{
-    g_return_val_if_fail(domain, NULL);
-
-    return (const char *const *) domain->servers;
-}
-
-const char *const *
-nm_global_dns_domain_get_options(const NMGlobalDnsDomain *domain)
-{
-    g_return_val_if_fail(domain, NULL);
-
-    return (const char *const *) domain->options;
-}
-
-gboolean
-nm_global_dns_config_is_internal(const NMGlobalDnsConfig *dns_config)
-{
-    return dns_config->internal;
-}
-
-gboolean
-nm_global_dns_config_is_empty(const NMGlobalDnsConfig *dns_config)
-{
-    g_return_val_if_fail(dns_config, TRUE);
-
-    return !dns_config->searches && !dns_config->options && !dns_config->domain_list;
-}
-
-void
-nm_global_dns_config_update_checksum(const NMGlobalDnsConfig *dns_config, GChecksum *sum)
-{
-    NMGlobalDnsDomain *domain;
-    guint              i, j;
-    guint8             v8;
-
-    g_return_if_fail(dns_config);
-    g_return_if_fail(sum);
-
-    v8 = NM_HASH_COMBINE_BOOLS(guint8,
-                               !dns_config->searches,
-                               !dns_config->options,
-                               !dns_config->domain_list);
-    g_checksum_update(sum, (guchar *) &v8, 1);
-
-    if (dns_config->searches) {
-        for (i = 0; dns_config->searches[i]; i++)
-            g_checksum_update(sum,
-                              (guchar *) dns_config->searches[i],
-                              strlen(dns_config->searches[i]) + 1);
-    }
-    if (dns_config->options) {
-        for (i = 0; dns_config->options[i]; i++)
-            g_checksum_update(sum,
-                              (guchar *) dns_config->options[i],
-                              strlen(dns_config->options[i]) + 1);
-    }
-
-    if (dns_config->domain_list) {
-        for (i = 0; dns_config->domain_list[i]; i++) {
-            domain = g_hash_table_lookup(dns_config->domains, dns_config->domain_list[i]);
-            nm_assert(domain);
-
-            v8 = NM_HASH_COMBINE_BOOLS(guint8, !domain->servers, !domain->options);
-            g_checksum_update(sum, (guchar *) &v8, 1);
-
-            g_checksum_update(sum, (guchar *) domain->name, strlen(domain->name) + 1);
-
-            if (domain->servers) {
-                for (j = 0; domain->servers[j]; j++)
-                    g_checksum_update(sum,
-                                      (guchar *) domain->servers[j],
-                                      strlen(domain->servers[j]) + 1);
-            }
-            if (domain->options) {
-                for (j = 0; domain->options[j]; j++)
-                    g_checksum_update(sum,
-                                      (guchar *) domain->options[j],
-                                      strlen(domain->options[j]) + 1);
-            }
-        }
-    }
-}
-
-static void
-global_dns_domain_free(NMGlobalDnsDomain *domain)
-{
-    if (domain) {
-        g_free(domain->name);
-        g_strfreev(domain->servers);
-        g_strfreev(domain->options);
-        g_free(domain);
-    }
-}
-
-void
-nm_global_dns_config_free(NMGlobalDnsConfig *dns_config)
-{
-    if (dns_config) {
-        g_strfreev(dns_config->searches);
-        g_strfreev(dns_config->options);
-        g_free(dns_config->domain_list);
-        if (dns_config->domains)
-            g_hash_table_unref(dns_config->domains);
-        g_free(dns_config);
-    }
-}
-
-NMGlobalDnsConfig *
-nm_config_data_get_global_dns_config(const NMConfigData *self)
-{
-    g_return_val_if_fail(NM_IS_CONFIG_DATA(self), NULL);
-
-    return NM_CONFIG_DATA_GET_PRIVATE(self)->global_dns;
-}
-
-static void
-global_dns_config_seal_domains(NMGlobalDnsConfig *dns_config)
-{
-    nm_assert(dns_config);
-    nm_assert(dns_config->domains);
-    nm_assert(!dns_config->domain_list);
-
-    if (g_hash_table_size(dns_config->domains) == 0)
-        nm_clear_pointer(&dns_config->domains, g_hash_table_unref);
-    else
-        dns_config->domain_list = nm_utils_strdict_get_keys(dns_config->domains, TRUE, NULL);
-}
-
-static NMGlobalDnsConfig *
-load_global_dns(GKeyFile *keyfile, gboolean internal)
-{
-    NMGlobalDnsConfig *dns_config;
-    char *             group, *domain_prefix;
-    gs_strfreev char **groups = NULL;
-    int                g, i, j, domain_prefix_len;
-    gboolean           default_found = FALSE;
-    char **            strv;
-
-    group =
-        internal ? NM_CONFIG_KEYFILE_GROUP_INTERN_GLOBAL_DNS : NM_CONFIG_KEYFILE_GROUP_GLOBAL_DNS;
-    domain_prefix     = internal ? NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN_GLOBAL_DNS_DOMAIN
-                                 : NM_CONFIG_KEYFILE_GROUPPREFIX_GLOBAL_DNS_DOMAIN;
-    domain_prefix_len = strlen(domain_prefix);
-
-    if (!nm_config_keyfile_has_global_dns_config(keyfile, internal))
-        return NULL;
-
-    dns_config          = g_malloc0(sizeof(NMGlobalDnsConfig));
-    dns_config->domains = g_hash_table_new_full(nm_str_hash,
-                                                g_str_equal,
-                                                g_free,
-                                                (GDestroyNotify) global_dns_domain_free);
-
-    strv = g_key_file_get_string_list(keyfile,
-                                      group,
-                                      NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_SEARCHES,
-                                      NULL,
-                                      NULL);
-    if (strv) {
-        _nm_utils_strv_cleanup(strv, TRUE, TRUE, TRUE);
-        if (!strv[0])
-            g_free(strv);
-        else
-            dns_config->searches = strv;
-    }
-
-    strv = g_key_file_get_string_list(keyfile,
-                                      group,
-                                      NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_OPTIONS,
-                                      NULL,
-                                      NULL);
-    if (strv) {
-        _nm_utils_strv_cleanup(strv, TRUE, TRUE, TRUE);
-        for (i = 0, j = 0; strv[i]; i++) {
-            if (_nm_utils_dns_option_validate(strv[i], NULL, NULL, TRUE, NULL))
-                strv[j++] = strv[i];
-            else
-                g_free(strv[i]);
-        }
-        if (j == 0)
-            g_free(strv);
-        else {
-            strv[j]             = NULL;
-            dns_config->options = strv;
-        }
-    }
-
-    groups = g_key_file_get_groups(keyfile, NULL);
-    for (g = 0; groups[g]; g++) {
-        char *             name;
-        char **            servers = NULL, **options = NULL;
-        NMGlobalDnsDomain *domain;
-
-        if (!g_str_has_prefix(groups[g], domain_prefix) || !groups[g][domain_prefix_len])
-            continue;
-
-        strv = g_key_file_get_string_list(keyfile,
-                                          groups[g],
-                                          NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_DOMAIN_SERVERS,
-                                          NULL,
-                                          NULL);
-        if (strv) {
-            _nm_utils_strv_cleanup(strv, TRUE, TRUE, TRUE);
-            for (i = 0, j = 0; strv[i]; i++) {
-                if (nm_utils_ipaddr_is_valid(AF_INET, strv[i])
-                    || nm_utils_ipaddr_is_valid(AF_INET6, strv[i]))
-                    strv[j++] = strv[i];
-                else
-                    g_free(strv[i]);
-            }
-            if (j == 0)
-                g_free(strv);
-            else {
-                strv[j] = NULL;
-                servers = strv;
-            }
-        }
-
-        if (!servers)
-            continue;
-
-        strv = g_key_file_get_string_list(keyfile,
-                                          groups[g],
-                                          NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_DOMAIN_OPTIONS,
-                                          NULL,
-                                          NULL);
-        if (strv) {
-            options = _nm_utils_strv_cleanup(strv, TRUE, TRUE, TRUE);
-            if (!options[0])
-                nm_clear_g_free(&options);
-        }
-
-        name            = strdup(&groups[g][domain_prefix_len]);
-        domain          = g_malloc0(sizeof(NMGlobalDnsDomain));
-        domain->name    = name;
-        domain->servers = servers;
-        domain->options = options;
-
-        g_hash_table_insert(dns_config->domains, strdup(name), domain);
-
-        if (!strcmp(name, "*"))
-            default_found = TRUE;
-    }
-
-    if (!default_found) {
-        nm_log_dbg(LOGD_CORE,
-                   "%s global DNS configuration is missing default domain, ignore it",
-                   internal ? "internal" : "user");
-        nm_global_dns_config_free(dns_config);
-        return NULL;
-    }
-
-    dns_config->internal = internal;
-    global_dns_config_seal_domains(dns_config);
-    return dns_config;
-}
-
-void
-nm_global_dns_config_to_dbus(const NMGlobalDnsConfig *dns_config, GValue *value)
-{
-    GVariantBuilder conf_builder, domains_builder, domain_builder;
-    guint           i;
-
-    g_variant_builder_init(&conf_builder, G_VARIANT_TYPE("a{sv}"));
-    if (!dns_config)
-        goto out;
-
-    if (dns_config->searches) {
-        g_variant_builder_add(&conf_builder,
-                              "{sv}",
-                              "searches",
-                              g_variant_new_strv((const char *const *) dns_config->searches, -1));
-    }
-
-    if (dns_config->options) {
-        g_variant_builder_add(&conf_builder,
-                              "{sv}",
-                              "options",
-                              g_variant_new_strv((const char *const *) dns_config->options, -1));
-    }
-
-    g_variant_builder_init(&domains_builder, G_VARIANT_TYPE("a{sv}"));
-    if (dns_config->domain_list) {
-        for (i = 0; dns_config->domain_list[i]; i++) {
-            NMGlobalDnsDomain *domain;
-
-            domain = g_hash_table_lookup(dns_config->domains, dns_config->domain_list[i]);
-
-            g_variant_builder_init(&domain_builder, G_VARIANT_TYPE("a{sv}"));
-
-            if (domain->servers) {
-                g_variant_builder_add(
-                    &domain_builder,
-                    "{sv}",
-                    "servers",
-                    g_variant_new_strv((const char *const *) domain->servers, -1));
-            }
-            if (domain->options) {
-                g_variant_builder_add(
-                    &domain_builder,
-                    "{sv}",
-                    "options",
-                    g_variant_new_strv((const char *const *) domain->options, -1));
-            }
-
-            g_variant_builder_add(&domains_builder,
-                                  "{sv}",
-                                  domain->name,
-                                  g_variant_builder_end(&domain_builder));
-        }
-    }
-    g_variant_builder_add(&conf_builder,
-                          "{sv}",
-                          "domains",
-                          g_variant_builder_end(&domains_builder));
-
-out:
-    g_value_take_variant(value, g_variant_builder_end(&conf_builder));
-}
-
-static NMGlobalDnsDomain *
-global_dns_domain_from_dbus(char *name, GVariant *variant)
-{
-    NMGlobalDnsDomain *domain;
-    GVariantIter       iter;
-    char **            strv, *key;
-    GVariant *         val;
-    int                i, j;
-
-    if (!g_variant_is_of_type(variant, G_VARIANT_TYPE("a{sv}")))
-        return NULL;
-
-    domain       = g_malloc0(sizeof(NMGlobalDnsDomain));
-    domain->name = g_strdup(name);
-
-    g_variant_iter_init(&iter, variant);
-    while (g_variant_iter_next(&iter, "{&sv}", &key, &val)) {
-        if (!g_strcmp0(key, "servers") && g_variant_is_of_type(val, G_VARIANT_TYPE("as"))) {
-            strv = g_variant_dup_strv(val, NULL);
-            _nm_utils_strv_cleanup(strv, TRUE, TRUE, TRUE);
-            for (i = 0, j = 0; strv && strv[i]; i++) {
-                if (nm_utils_ipaddr_is_valid(AF_INET, strv[i])
-                    || nm_utils_ipaddr_is_valid(AF_INET6, strv[i]))
-                    strv[j++] = strv[i];
-                else
-                    g_free(strv[i]);
-            }
-            if (j == 0)
-                g_free(strv);
-            else {
-                strv[j] = NULL;
-                g_strfreev(domain->servers);
-                domain->servers = strv;
-            }
-        } else if (!g_strcmp0(key, "options") && g_variant_is_of_type(val, G_VARIANT_TYPE("as"))) {
-            strv = g_variant_dup_strv(val, NULL);
-            g_strfreev(domain->options);
-            domain->options = _nm_utils_strv_cleanup(strv, TRUE, TRUE, TRUE);
-            if (!domain->options[0])
-                nm_clear_g_free(&domain->options);
-        }
-
-        g_variant_unref(val);
-    }
-
-    /* At least one server is required */
-    if (!domain->servers) {
-        global_dns_domain_free(domain);
-        return NULL;
-    }
-
-    return domain;
-}
-
-NMGlobalDnsConfig *
-nm_global_dns_config_from_dbus(const GValue *value, GError **error)
-{
-    NMGlobalDnsConfig *dns_config;
-    GVariant *         variant, *val;
-    GVariantIter       iter;
-    char **            strv, *key;
-    int                i, j;
-
-    if (!G_VALUE_HOLDS_VARIANT(value)) {
-        g_set_error(error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, "invalid value type");
-        return NULL;
-    }
-
-    variant = g_value_get_variant(value);
-    if (!g_variant_is_of_type(variant, G_VARIANT_TYPE("a{sv}"))) {
-        g_set_error(error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, "invalid variant type");
-        return NULL;
-    }
-
-    dns_config          = g_malloc0(sizeof(NMGlobalDnsConfig));
-    dns_config->domains = g_hash_table_new_full(nm_str_hash,
-                                                g_str_equal,
-                                                g_free,
-                                                (GDestroyNotify) global_dns_domain_free);
-
-    g_variant_iter_init(&iter, variant);
-    while (g_variant_iter_next(&iter, "{&sv}", &key, &val)) {
-        if (!g_strcmp0(key, "searches") && g_variant_is_of_type(val, G_VARIANT_TYPE("as"))) {
-            strv                 = g_variant_dup_strv(val, NULL);
-            dns_config->searches = _nm_utils_strv_cleanup(strv, TRUE, TRUE, TRUE);
-        } else if (!g_strcmp0(key, "options") && g_variant_is_of_type(val, G_VARIANT_TYPE("as"))) {
-            strv = g_variant_dup_strv(val, NULL);
-            _nm_utils_strv_cleanup(strv, TRUE, TRUE, TRUE);
-
-            for (i = 0, j = 0; strv && strv[i]; i++) {
-                if (_nm_utils_dns_option_validate(strv[i], NULL, NULL, TRUE, NULL))
-                    strv[j++] = strv[i];
-                else
-                    g_free(strv[i]);
-            }
-            if (j == 0)
-                g_free(strv);
-            else {
-                strv[j]             = NULL;
-                dns_config->options = strv;
-            }
-        } else if (!g_strcmp0(key, "domains")
-                   && g_variant_is_of_type(val, G_VARIANT_TYPE("a{sv}"))) {
-            NMGlobalDnsDomain *domain;
-            GVariantIter       domain_iter;
-            GVariant *         v;
-            char *             k;
-
-            g_variant_iter_init(&domain_iter, val);
-            while (g_variant_iter_next(&domain_iter, "{&sv}", &k, &v)) {
-                if (k) {
-                    domain = global_dns_domain_from_dbus(k, v);
-                    if (domain)
-                        g_hash_table_insert(dns_config->domains, strdup(k), domain);
-                }
-                g_variant_unref(v);
-            }
-        }
-        g_variant_unref(val);
-    }
-
-    /* An empty value is valid and clears the internal configuration */
-    if (!nm_global_dns_config_is_empty(dns_config)
-        && !nm_global_dns_config_lookup_domain(dns_config, "*")) {
-        g_set_error_literal(error,
-                            NM_MANAGER_ERROR,
-                            NM_MANAGER_ERROR_FAILED,
-                            "Global DNS configuration is missing the default domain");
-        nm_global_dns_config_free(dns_config);
-        return NULL;
-    }
-
-    global_dns_config_seal_domains(dns_config);
-    return dns_config;
-}
-
-static gboolean
-global_dns_equal(NMGlobalDnsConfig *old, NMGlobalDnsConfig *new)
-{
-    NMGlobalDnsDomain *domain_old, *domain_new;
-    gpointer           key, value_old, value_new;
-    GHashTableIter     iter;
-
-    if (old == new)
-        return TRUE;
-
-    if (!old || !new)
-        return FALSE;
-
-    if (!_nm_utils_strv_equal(old->options, new->options)
-        || !_nm_utils_strv_equal(old->searches, new->searches))
-        return FALSE;
-
-    if ((!old->domains || !new->domains) && old->domains != new->domains)
-        return FALSE;
-
-    if (g_hash_table_size(old->domains) != g_hash_table_size(new->domains))
-        return FALSE;
-
-    g_hash_table_iter_init(&iter, old->domains);
-    while (g_hash_table_iter_next(&iter, &key, &value_old)) {
-        value_new = g_hash_table_lookup(new->domains, key);
-        if (!value_new)
-            return FALSE;
-
-        domain_old = value_old;
-        domain_new = value_new;
-
-        if (!_nm_utils_strv_equal(domain_old->options, domain_new->options)
-            || !_nm_utils_strv_equal(domain_old->servers, domain_new->servers))
-            return FALSE;
-    }
-
-    return TRUE;
-}
-
-/*****************************************************************************/
-
-static const MatchSectionInfo *
-_match_section_infos_lookup(const MatchSectionInfo *match_section_infos,
-                            GKeyFile *              keyfile,
-                            const char *            property,
-                            NMDevice *              device,
-                            const NMPlatformLink *  pllink,
-                            const char *            match_device_type,
-                            char **                 out_value)
-{
-    const char *match_dhcp_plugin;
-
-    if (!match_section_infos)
-        return NULL;
-
-    match_dhcp_plugin = nm_dhcp_manager_get_config(nm_dhcp_manager_get());
-
-    for (; match_section_infos->group_name; match_section_infos++) {
-        char *   value = NULL;
-        gboolean match;
-
-        /* FIXME: Here we use g_key_file_get_string(). This should be in sync with what keyfile-reader
-         * does.
-         *
-         * Unfortunately that is currently not possible because keyfile-reader does the two steps
-         * string_to_value(keyfile_to_string(keyfile)) in one. Optimally, keyfile library would
-         * expose both functions, and we would return here keyfile_to_string(keyfile).
-         * The caller then could convert the string to the proper value via string_to_value(value). */
-        value = g_key_file_get_string(keyfile, match_section_infos->group_name, property, NULL);
-        if (!value && !match_section_infos->stop_match)
-            continue;
-
-        if (match_section_infos->match_device.has) {
-            if (device)
-                match = nm_device_spec_match_list(device, match_section_infos->match_device.spec);
-            else if (pllink)
-                match = nm_match_spec_device_by_pllink(pllink,
-                                                       match_device_type,
-                                                       match_dhcp_plugin,
-                                                       match_section_infos->match_device.spec,
-                                                       FALSE);
-            else
-                match = FALSE;
-        } else
-            match = TRUE;
-
-        if (match) {
-            *out_value = value;
-            return match_section_infos;
-        }
-        g_free(value);
-    }
-    return NULL;
-}
-
-char *
-nm_config_data_get_device_config(const NMConfigData *self,
-                                 const char *        property,
-                                 NMDevice *          device,
-                                 gboolean *          has_match)
-{
-    const NMConfigDataPrivate *priv;
-    const MatchSectionInfo *   connection_info;
-    char *                     value = NULL;
-
-    NM_SET_OUT(has_match, FALSE);
-
-    g_return_val_if_fail(self, NULL);
-    g_return_val_if_fail(property && *property, NULL);
-
-    priv = NM_CONFIG_DATA_GET_PRIVATE(self);
-
-    connection_info = _match_section_infos_lookup(&priv->device_infos[0],
-                                                  priv->keyfile,
-                                                  property,
-                                                  device,
-                                                  NULL,
-                                                  NULL,
-                                                  &value);
-    NM_SET_OUT(has_match, !!connection_info);
-    return value;
-}
-
-char *
-nm_config_data_get_device_config_by_pllink(const NMConfigData *  self,
-                                           const char *          property,
-                                           const NMPlatformLink *pllink,
-                                           const char *          match_device_type,
-                                           gboolean *            has_match)
-{
-    const NMConfigDataPrivate *priv;
-    const MatchSectionInfo *   connection_info;
-    char *                     value = NULL;
-
-    g_return_val_if_fail(self, NULL);
-    g_return_val_if_fail(property && *property, NULL);
-
-    priv = NM_CONFIG_DATA_GET_PRIVATE(self);
-
-    connection_info = _match_section_infos_lookup(&priv->device_infos[0],
-                                                  priv->keyfile,
-                                                  property,
-                                                  NULL,
-                                                  pllink,
-                                                  match_device_type,
-                                                  &value);
-    NM_SET_OUT(has_match, !!connection_info);
-    return value;
-}
-
-gboolean
-nm_config_data_get_device_config_boolean(const NMConfigData *self,
-                                         const char *        property,
-                                         NMDevice *          device,
-                                         int                 val_no_match,
-                                         int                 val_invalid)
-{
-    gs_free char *value = NULL;
-    gboolean      has_match;
-
-    value = nm_config_data_get_device_config(self, property, device, &has_match);
-    if (!has_match)
-        return val_no_match;
-    return nm_config_parse_boolean(value, val_invalid);
-}
-
-char *
-nm_config_data_get_connection_default(const NMConfigData *self,
-                                      const char *        property,
-                                      NMDevice *          device)
-{
-    const NMConfigDataPrivate *priv;
-    char *                     value = NULL;
-
-    g_return_val_if_fail(self, NULL);
-    g_return_val_if_fail(property && *property, NULL);
-    g_return_val_if_fail(strchr(property, '.'), NULL);
-
-    priv = NM_CONFIG_DATA_GET_PRIVATE(self);
-
-#if NM_MORE_ASSERTS > 10
-    {
-        const char **ptr;
-
-        for (ptr = __start_connection_defaults; ptr < __stop_connection_defaults; ptr++) {
-            if (nm_streq(property, *ptr))
-                break;
-        }
-
-        nm_assert(ptr < __stop_connection_defaults);
-    }
-#endif
-
-    _match_section_infos_lookup(&priv->connection_infos[0],
-                                priv->keyfile,
-                                property,
-                                device,
-                                NULL,
-                                NULL,
-                                &value);
-    return value;
-}
-
-gint64
-nm_config_data_get_connection_default_int64(const NMConfigData *self,
-                                            const char *        property,
-                                            NMDevice *          device,
-                                            gint64              min,
-                                            gint64              max,
-                                            gint64              fallback)
-{
-    gs_free char *value = NULL;
-
-    value = nm_config_data_get_connection_default(self, property, device);
-    return _nm_utils_ascii_str_to_int64(value, 10, min, max, fallback);
-}
-
-static void
-_get_connection_info_init(MatchSectionInfo *connection_info, GKeyFile *keyfile, char *group)
-{
-    /* pass ownership of @group on... */
-    connection_info->group_name = group;
-
-    connection_info->match_device.spec =
-        nm_config_get_match_spec(keyfile,
-                                 group,
-                                 NM_CONFIG_KEYFILE_KEY_MATCH_DEVICE,
-                                 &connection_info->match_device.has);
-    connection_info->stop_match =
-        nm_config_keyfile_get_boolean(keyfile, group, NM_CONFIG_KEYFILE_KEY_STOP_MATCH, FALSE);
-}
-
-static void
-_match_section_infos_free(MatchSectionInfo *match_section_infos)
-{
-    guint i;
-
-    if (!match_section_infos)
-        return;
-    for (i = 0; match_section_infos[i].group_name; i++) {
-        g_free(match_section_infos[i].group_name);
-        g_slist_free_full(match_section_infos[i].match_device.spec, g_free);
-    }
-    g_free(match_section_infos);
-}
-
-static MatchSectionInfo *
-_match_section_infos_construct(GKeyFile *keyfile, const char *prefix)
-{
-    char **           groups;
-    gsize             i, j, ngroups;
-    char *            connection_tag      = NULL;
-    MatchSectionInfo *match_section_infos = NULL;
-
-    /* get the list of existing [connection.\+]/[device.\+] sections.
-     *
-     * We expect the sections in their right order, with lowest priority
-     * first. Only exception is the (literal) [connection] section, which
-     * we will always reorder to the end. */
-    groups = g_key_file_get_groups(keyfile, &ngroups);
-    if (!groups)
-        return NULL;
-
-    if (ngroups > 0) {
-        gsize l = strlen(prefix);
-
-        for (i = 0, j = 0; i < ngroups; i++) {
-            if (g_str_has_prefix(groups[i], prefix)) {
-                if (groups[i][l] == '\0')
-                    connection_tag = groups[i];
-                else
-                    groups[j++] = groups[i];
-            } else
-                g_free(groups[i]);
-        }
-        ngroups = j;
-    }
-
-    if (ngroups == 0 && !connection_tag) {
-        g_free(groups);
-        return NULL;
-    }
-
-    match_section_infos = g_new0(MatchSectionInfo, ngroups + 1 + (connection_tag ? 1 : 0));
-    for (i = 0; i < ngroups; i++) {
-        /* pass ownership of @group on... */
-        _get_connection_info_init(&match_section_infos[i], keyfile, groups[ngroups - i - 1]);
-    }
-    if (connection_tag) {
-        /* pass ownership of @connection_tag on... */
-        _get_connection_info_init(&match_section_infos[i], keyfile, connection_tag);
-    }
-    g_free(groups);
-
-    return match_section_infos;
-}
-
-/*****************************************************************************/
-
-NMConfigChangeFlags
-nm_config_data_diff(NMConfigData *old_data, NMConfigData *new_data)
-{
-    NMConfigChangeFlags  changes = NM_CONFIG_CHANGE_NONE;
-    NMConfigDataPrivate *priv_old, *priv_new;
-
-    g_return_val_if_fail(NM_IS_CONFIG_DATA(old_data), NM_CONFIG_CHANGE_NONE);
-    g_return_val_if_fail(NM_IS_CONFIG_DATA(new_data), NM_CONFIG_CHANGE_NONE);
-
-    priv_old = NM_CONFIG_DATA_GET_PRIVATE(old_data);
-    priv_new = NM_CONFIG_DATA_GET_PRIVATE(new_data);
-
-    if (!_nm_keyfile_equals(priv_old->keyfile_user, priv_new->keyfile_user, TRUE))
-        changes |= NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_USER;
-
-    if (!_nm_keyfile_equals(priv_old->keyfile_intern, priv_new->keyfile_intern, TRUE))
-        changes |= NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_INTERN;
-
-    if (g_strcmp0(nm_config_data_get_config_main_file(old_data),
-                  nm_config_data_get_config_main_file(new_data))
-            != 0
-        || g_strcmp0(nm_config_data_get_config_description(old_data),
-                     nm_config_data_get_config_description(new_data))
-               != 0)
-        changes |= NM_CONFIG_CHANGE_CONFIG_FILES;
-
-    if (nm_config_data_get_connectivity_enabled(old_data)
-            != nm_config_data_get_connectivity_enabled(new_data)
-        || nm_config_data_get_connectivity_interval(old_data)
-               != nm_config_data_get_connectivity_interval(new_data)
-        || g_strcmp0(nm_config_data_get_connectivity_uri(old_data),
-                     nm_config_data_get_connectivity_uri(new_data))
-        || g_strcmp0(nm_config_data_get_connectivity_response(old_data),
-                     nm_config_data_get_connectivity_response(new_data)))
-        changes |= NM_CONFIG_CHANGE_CONNECTIVITY;
-
-    if (nm_utils_g_slist_strlist_cmp(priv_old->no_auto_default.specs,
-                                     priv_new->no_auto_default.specs)
-            != 0
-        || nm_utils_g_slist_strlist_cmp(priv_old->no_auto_default.specs_config,
-                                        priv_new->no_auto_default.specs_config)
-               != 0)
-        changes |= NM_CONFIG_CHANGE_NO_AUTO_DEFAULT;
-
-    if (g_strcmp0(nm_config_data_get_dns_mode(old_data), nm_config_data_get_dns_mode(new_data)))
-        changes |= NM_CONFIG_CHANGE_DNS_MODE;
-
-    if (g_strcmp0(nm_config_data_get_rc_manager(old_data), nm_config_data_get_rc_manager(new_data)))
-        changes |= NM_CONFIG_CHANGE_RC_MANAGER;
-
-    if (!global_dns_equal(priv_old->global_dns, priv_new->global_dns))
-        changes |= NM_CONFIG_CHANGE_GLOBAL_DNS_CONFIG;
-
-    nm_assert(!NM_FLAGS_ANY(changes, NM_CONFIG_CHANGE_CAUSES));
-
-    return changes;
-}
-
-/*****************************************************************************/
-
-void
-nm_config_data_get_warnings(const NMConfigData *self, GPtrArray *warnings)
-{
-    gboolean invalid;
-
-    nm_assert(NM_IS_CONFIG_DATA(self));
-    nm_assert(warnings);
-
-    _config_data_get_main_auth_polkit(self, &invalid);
-    if (invalid) {
-        g_ptr_array_add(
-            warnings,
-            g_strdup_printf(
-                "invalid setting for %s.%s (should be one of \"true\", \"false\", \"root-only\")",
-                NM_CONFIG_KEYFILE_GROUP_MAIN,
-                NM_CONFIG_KEYFILE_KEY_MAIN_AUTH_POLKIT));
-    }
-}
-
-/*****************************************************************************/
-
-static void
-get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
-{
-    NMConfigData *self = NM_CONFIG_DATA(object);
-
-    switch (prop_id) {
-    case PROP_CONFIG_MAIN_FILE:
-        g_value_set_string(value, nm_config_data_get_config_main_file(self));
-        break;
-    case PROP_CONFIG_DESCRIPTION:
-        g_value_set_string(value, nm_config_data_get_config_description(self));
-        break;
-    case PROP_CONNECTIVITY_ENABLED:
-        g_value_set_boolean(value, nm_config_data_get_connectivity_enabled(self));
-        break;
-    case PROP_CONNECTIVITY_URI:
-        g_value_set_string(value, nm_config_data_get_connectivity_uri(self));
-        break;
-    case PROP_CONNECTIVITY_INTERVAL:
-        g_value_set_uint(value, nm_config_data_get_connectivity_interval(self));
-        break;
-    case PROP_CONNECTIVITY_RESPONSE:
-        g_value_set_string(value, nm_config_data_get_connectivity_response(self));
-        break;
-    default:
-        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
-        break;
-    }
-}
-
-static void
-set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
-{
-    NMConfigData *       self = NM_CONFIG_DATA(object);
-    NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE(self);
-
-    switch (prop_id) {
-    case PROP_CONFIG_MAIN_FILE:
-        /* construct-only */
-        priv->config_main_file = g_value_dup_string(value);
-        break;
-    case PROP_CONFIG_DESCRIPTION:
-        /* construct-only */
-        priv->config_description = g_value_dup_string(value);
-        break;
-    case PROP_KEYFILE_USER:
-        /* construct-only */
-        priv->keyfile_user = g_value_dup_boxed(value);
-        if (priv->keyfile_user && !_nm_keyfile_has_values(priv->keyfile_user)) {
-            g_key_file_unref(priv->keyfile_user);
-            priv->keyfile_user = NULL;
-        }
-        break;
-    case PROP_KEYFILE_INTERN:
-        /* construct-only */
-        priv->keyfile_intern = g_value_dup_boxed(value);
-        if (priv->keyfile_intern && !_nm_keyfile_has_values(priv->keyfile_intern)) {
-            g_key_file_unref(priv->keyfile_intern);
-            priv->keyfile_intern = NULL;
-        }
-        break;
-    case PROP_NO_AUTO_DEFAULT:
-        /* construct-only */
-        {
-            const char *const *  value_arr_orig = g_value_get_boxed(value);
-            gs_free const char **value_arr      = NULL;
-            GSList *             specs          = NULL;
-            gsize                i, j;
-            gsize                len;
-
-            len = NM_PTRARRAY_LEN(value_arr_orig);
-
-            /* sort entries, remove duplicates and empty words. */
-            value_arr =
-                len == 0 ? NULL : nm_memdup(value_arr_orig, sizeof(const char *) * (len + 1));
-            nm_utils_strv_sort(value_arr, len);
-            _nm_utils_strv_cleanup((char **) value_arr, FALSE, TRUE, TRUE);
-
-            len = NM_PTRARRAY_LEN(value_arr);
-            j   = 0;
-            for (i = 0; i < len; i++) {
-                const char *s = value_arr[i];
-                gboolean    is_mac;
-                char *      spec;
-
-                if (NM_STR_HAS_PREFIX(s, NM_MATCH_SPEC_INTERFACE_NAME_TAG "="))
-                    is_mac = FALSE;
-                else if (nm_utils_hwaddr_valid(s, -1))
-                    is_mac = TRUE;
-                else {
-                    /* we drop all lines that we don't understand. */
-                    continue;
-                }
-
-                value_arr[j++] = s;
-
-                spec  = is_mac ? g_strdup_printf(NM_MATCH_SPEC_MAC_TAG "%s", s) : g_strdup(s);
-                specs = g_slist_prepend(specs, spec);
-            }
-
-            priv->no_auto_default.arr   = nm_utils_strv_dup(value_arr, j, TRUE);
-            priv->no_auto_default.specs = g_slist_reverse(specs);
-        }
-        break;
-    default:
-        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
-        break;
-    }
-}
-
-/*****************************************************************************/
-
-static void
-nm_config_data_init(NMConfigData *self)
-{}
-
-static void
-constructed(GObject *object)
-{
-    NMConfigData *       self = NM_CONFIG_DATA(object);
-    NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE(self);
-    char *               str;
-
-    priv->keyfile = _merge_keyfiles(priv->keyfile_user, priv->keyfile_intern);
-
-    priv->connection_infos =
-        _match_section_infos_construct(priv->keyfile, NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION);
-    priv->device_infos =
-        _match_section_infos_construct(priv->keyfile, NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE);
-
-    priv->connectivity.enabled =
-        nm_config_keyfile_get_boolean(priv->keyfile,
-                                      NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY,
-                                      NM_CONFIG_KEYFILE_KEY_CONNECTIVITY_ENABLED,
-                                      TRUE);
-    priv->connectivity.uri =
-        nm_strstrip(g_key_file_get_string(priv->keyfile,
-                                          NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY,
-                                          NM_CONFIG_KEYFILE_KEY_CONNECTIVITY_URI,
-                                          NULL));
-    priv->connectivity.response       = g_key_file_get_string(priv->keyfile,
-                                                        NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY,
-                                                        NM_CONFIG_KEYFILE_KEY_CONNECTIVITY_RESPONSE,
-                                                        NULL);
-    str                               = nm_config_keyfile_get_value(priv->keyfile,
-                                      NM_CONFIG_KEYFILE_GROUP_MAIN,
-                                      NM_CONFIG_KEYFILE_KEY_MAIN_AUTOCONNECT_RETRIES_DEFAULT,
-                                      NM_CONFIG_GET_VALUE_NONE);
-    priv->autoconnect_retries_default = _nm_utils_ascii_str_to_int64(str, 10, 0, G_MAXINT32, 4);
-    g_free(str);
-
-    /* On missing config value, fallback to 300. On invalid value, disable connectivity checking by setting
-     * the interval to zero. */
-    str = g_key_file_get_string(priv->keyfile,
-                                NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY,
-                                NM_CONFIG_KEYFILE_KEY_CONNECTIVITY_INTERVAL,
-                                NULL);
-    priv->connectivity.interval =
-        _nm_utils_ascii_str_to_int64(str,
-                                     10,
-                                     0,
-                                     G_MAXUINT,
-                                     NM_CONFIG_DEFAULT_CONNECTIVITY_INTERVAL);
-    g_free(str);
-
-    priv->dns_mode   = nm_strstrip(g_key_file_get_string(priv->keyfile,
-                                                       NM_CONFIG_KEYFILE_GROUP_MAIN,
-                                                       NM_CONFIG_KEYFILE_KEY_MAIN_DNS,
-                                                       NULL));
-    priv->rc_manager = nm_strstrip(g_key_file_get_string(priv->keyfile,
-                                                         NM_CONFIG_KEYFILE_GROUP_MAIN,
-                                                         NM_CONFIG_KEYFILE_KEY_MAIN_RC_MANAGER,
-                                                         NULL));
-    priv->systemd_resolved =
-        nm_config_keyfile_get_boolean(priv->keyfile,
-                                      NM_CONFIG_KEYFILE_GROUP_MAIN,
-                                      NM_CONFIG_KEYFILE_KEY_MAIN_SYSTEMD_RESOLVED,
-                                      TRUE);
-    priv->ignore_carrier = nm_config_get_match_spec(priv->keyfile,
-                                                    NM_CONFIG_KEYFILE_GROUP_MAIN,
-                                                    NM_CONFIG_KEYFILE_KEY_MAIN_IGNORE_CARRIER,
-                                                    NULL);
-    priv->assume_ipv6ll_only =
-        nm_config_get_match_spec(priv->keyfile,
-                                 NM_CONFIG_KEYFILE_GROUP_MAIN,
-                                 NM_CONFIG_KEYFILE_KEY_MAIN_ASSUME_IPV6LL_ONLY,
-                                 NULL);
-    priv->no_auto_default.specs_config =
-        nm_config_get_match_spec(priv->keyfile,
-                                 NM_CONFIG_KEYFILE_GROUP_MAIN,
-                                 NM_CONFIG_KEYFILE_KEY_MAIN_NO_AUTO_DEFAULT,
-                                 NULL);
-
-    priv->global_dns = load_global_dns(priv->keyfile_user, FALSE);
-    if (!priv->global_dns)
-        priv->global_dns = load_global_dns(priv->keyfile_intern, TRUE);
-
-    G_OBJECT_CLASS(nm_config_data_parent_class)->constructed(object);
-}
-
-NMConfigData *
-nm_config_data_new(const char *       config_main_file,
-                   const char *       config_description,
-                   const char *const *no_auto_default,
-                   GKeyFile *         keyfile_user,
-                   GKeyFile *         keyfile_intern)
-{
-    return g_object_new(NM_TYPE_CONFIG_DATA,
-                        NM_CONFIG_DATA_CONFIG_MAIN_FILE,
-                        config_main_file,
-                        NM_CONFIG_DATA_CONFIG_DESCRIPTION,
-                        config_description,
-                        NM_CONFIG_DATA_KEYFILE_USER,
-                        keyfile_user,
-                        NM_CONFIG_DATA_KEYFILE_INTERN,
-                        keyfile_intern,
-                        NM_CONFIG_DATA_NO_AUTO_DEFAULT,
-                        no_auto_default,
-                        NULL);
-}
-
-NMConfigData *
-nm_config_data_new_update_keyfile_intern(const NMConfigData *base, GKeyFile *keyfile_intern)
-{
-    const NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE(base);
-
-    return g_object_new(NM_TYPE_CONFIG_DATA,
-                        NM_CONFIG_DATA_CONFIG_MAIN_FILE,
-                        priv->config_main_file,
-                        NM_CONFIG_DATA_CONFIG_DESCRIPTION,
-                        priv->config_description,
-                        NM_CONFIG_DATA_KEYFILE_USER,
-                        priv->keyfile_user, /* the keyfile is unchanged. It's safe to share it. */
-                        NM_CONFIG_DATA_KEYFILE_INTERN,
-                        keyfile_intern,
-                        NM_CONFIG_DATA_NO_AUTO_DEFAULT,
-                        priv->no_auto_default.arr,
-                        NULL);
-}
-
-NMConfigData *
-nm_config_data_new_update_no_auto_default(const NMConfigData *base,
-                                          const char *const * no_auto_default)
-{
-    const NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE(base);
-
-    return g_object_new(NM_TYPE_CONFIG_DATA,
-                        NM_CONFIG_DATA_CONFIG_MAIN_FILE,
-                        priv->config_main_file,
-                        NM_CONFIG_DATA_CONFIG_DESCRIPTION,
-                        priv->config_description,
-                        NM_CONFIG_DATA_KEYFILE_USER,
-                        priv->keyfile_user, /* the keyfile is unchanged. It's safe to share it. */
-                        NM_CONFIG_DATA_KEYFILE_INTERN,
-                        priv->keyfile_intern,
-                        NM_CONFIG_DATA_NO_AUTO_DEFAULT,
-                        no_auto_default,
-                        NULL);
-}
-
-static void
-finalize(GObject *gobject)
-{
-    NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE(gobject);
-
-    g_free(priv->config_main_file);
-    g_free(priv->config_description);
-
-    g_free(priv->connectivity.uri);
-    g_free(priv->connectivity.response);
-
-    g_slist_free_full(priv->no_auto_default.specs, g_free);
-    g_slist_free_full(priv->no_auto_default.specs_config, g_free);
-    g_strfreev(priv->no_auto_default.arr);
-
-    g_free(priv->dns_mode);
-    g_free(priv->rc_manager);
-
-    g_slist_free_full(priv->ignore_carrier, g_free);
-    g_slist_free_full(priv->assume_ipv6ll_only, g_free);
-
-    nm_global_dns_config_free(priv->global_dns);
-
-    _match_section_infos_free(priv->connection_infos);
-    _match_section_infos_free(priv->device_infos);
-
-    g_key_file_unref(priv->keyfile);
-    if (priv->keyfile_user)
-        g_key_file_unref(priv->keyfile_user);
-    if (priv->keyfile_intern)
-        g_key_file_unref(priv->keyfile_intern);
-
-    G_OBJECT_CLASS(nm_config_data_parent_class)->finalize(gobject);
-}
-
-static void
-nm_config_data_class_init(NMConfigDataClass *config_class)
-{
-    GObjectClass *object_class = G_OBJECT_CLASS(config_class);
-
-    object_class->constructed  = constructed;
-    object_class->finalize     = finalize;
-    object_class->get_property = get_property;
-    object_class->set_property = set_property;
-
-    obj_properties[PROP_CONFIG_MAIN_FILE] =
-        g_param_spec_string(NM_CONFIG_DATA_CONFIG_MAIN_FILE,
-                            "",
-                            "",
-                            NULL,
-                            G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
-
-    obj_properties[PROP_CONFIG_DESCRIPTION] =
-        g_param_spec_string(NM_CONFIG_DATA_CONFIG_DESCRIPTION,
-                            "",
-                            "",
-                            NULL,
-                            G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
-
-    obj_properties[PROP_KEYFILE_USER] =
-        g_param_spec_boxed(NM_CONFIG_DATA_KEYFILE_USER,
-                           "",
-                           "",
-                           G_TYPE_KEY_FILE,
-                           G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
-
-    obj_properties[PROP_KEYFILE_INTERN] =
-        g_param_spec_boxed(NM_CONFIG_DATA_KEYFILE_INTERN,
-                           "",
-                           "",
-                           G_TYPE_KEY_FILE,
-                           G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
-
-    obj_properties[PROP_CONNECTIVITY_ENABLED] =
-        g_param_spec_string(NM_CONFIG_DATA_CONNECTIVITY_ENABLED,
-                            "",
-                            "",
-                            NULL,
-                            G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
-
-    obj_properties[PROP_CONNECTIVITY_URI] =
-        g_param_spec_string(NM_CONFIG_DATA_CONNECTIVITY_URI,
-                            "",
-                            "",
-                            NULL,
-                            G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
-
-    obj_properties[PROP_CONNECTIVITY_INTERVAL] =
-        g_param_spec_uint(NM_CONFIG_DATA_CONNECTIVITY_INTERVAL,
-                          "",
-                          "",
-                          0,
-                          G_MAXUINT,
-                          0,
-                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
-
-    obj_properties[PROP_CONNECTIVITY_RESPONSE] =
-        g_param_spec_string(NM_CONFIG_DATA_CONNECTIVITY_RESPONSE,
-                            "",
-                            "",
-                            NULL,
-                            G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
-
-    obj_properties[PROP_NO_AUTO_DEFAULT] =
-        g_param_spec_boxed(NM_CONFIG_DATA_NO_AUTO_DEFAULT,
-                           "",
-                           "",
-                           G_TYPE_STRV,
-                           G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
-
-    g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
-}