From 2de3de0c28f93b2724686b65cae1cd7fce90e351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8D=C3=B1igo=20Huguet?= Date: Thu, 4 Sep 2025 16:54:21 +0200 Subject: [PATCH] core: keep empty groups from keyfile configs When reading NetworkManager.conf and NetworkManager-intern.conf we might need to know if a group is defined or not, even if it's empty. This is the case, for example, for [global-dns]. If [global-dns] is defined in NM.conf overwrites the config from NM-intern, and if it's defined in any of them they overwrite the configs from connections. Before this patch, defining it as an empty group was ignored: ``` [global-dns] ``` Instead, it was necessary to add at least one key-value to the group. Otherwise the group was silently ignored. ``` [global-dns] searches= ``` Keep empty groups so we can take better decissions about overwritting configs from other sources. (cherry picked from commit 4a46f454da5fbe6668c2eaecdeaeec35068a6ec3) --- src/core/nm-config.c | 14 ++++++++++++ src/core/tests/config/global-dns-empty.conf | 3 +++ src/core/tests/config/global-dns-not-set.conf | 5 +++++ src/core/tests/config/test-config.c | 22 ++++++++++++++++++- 4 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 src/core/tests/config/global-dns-empty.conf create mode 100644 src/core/tests/config/global-dns-not-set.conf diff --git a/src/core/nm-config.c b/src/core/nm-config.c index a55d2d1396..d1f2bbed35 100644 --- a/src/core/nm-config.c +++ b/src/core/nm-config.c @@ -18,6 +18,7 @@ #include "libnm-core-intern/nm-core-internal.h" #include "libnm-core-intern/nm-keyfile-internal.h" #include "libnm-core-intern/nm-keyfile-utils.h" +#include "libnm-glib-aux/nm-keyfile-aux.h" #define DEFAULT_CONFIG_MAIN_FILE NMCONFDIR "/NetworkManager.conf" #define DEFAULT_CONFIG_DIR NMCONFDIR "/conf.d" @@ -1046,6 +1047,10 @@ read_config(GKeyFile *keyfile, /* internal groups cannot be set by user configuration. */ continue; } + + if (!g_key_file_has_group(keyfile, group)) + nm_key_file_add_group(keyfile, group); + keys = g_key_file_get_keys(kf, group, &nkeys, NULL); if (!keys) continue; @@ -1639,6 +1644,12 @@ intern_config_read(const char *filename, ""); } + if (!g_key_file_has_group(keyfile_intern, group)) { + nm_key_file_add_group(keyfile_intern, group); + if (is_intern) + has_intern = TRUE; + } + for (k = 0; keys[k]; k++) { gs_free char *value_set = NULL; const char *key = keys[k]; @@ -1823,6 +1834,9 @@ intern_config_write(const char *filename, } } + if (!g_key_file_has_group(keyfile, group)) + nm_key_file_add_group(keyfile, group); + for (k = 0; keys[k]; k++) { const char *key = keys[k]; gs_free char *value_set = NULL; diff --git a/src/core/tests/config/global-dns-empty.conf b/src/core/tests/config/global-dns-empty.conf new file mode 100644 index 0000000000..fba823bfe4 --- /dev/null +++ b/src/core/tests/config/global-dns-empty.conf @@ -0,0 +1,3 @@ +# Good configuration, an empty global-dns section must be valid + +[global-dns] diff --git a/src/core/tests/config/global-dns-not-set.conf b/src/core/tests/config/global-dns-not-set.conf new file mode 100644 index 0000000000..133bd4ed43 --- /dev/null +++ b/src/core/tests/config/global-dns-not-set.conf @@ -0,0 +1,5 @@ +# Good configuration, an empty [global-dns] must be implicitly assumed because a domain is defined + +[global-dns-domain-*] +servers=4.5.6.7 +options=myoption1 diff --git a/src/core/tests/config/test-config.c b/src/core/tests/config/test-config.c index 2980cda7fb..78fd10571d 100644 --- a/src/core/tests/config/test-config.c +++ b/src/core/tests/config/test-config.c @@ -387,7 +387,27 @@ test_config_global_dns(void) g_assert(dns); g_object_unref(config); - /* Check that a file with a domain domain, but without a default one gives a NULL configuration */ + /* Check that a file with an empty global-dns section gives a good configuration. + * Check also that searches and options are not NULL, as this is how we expose to + * D-Bus that global-dns is defined. */ + config = + setup_config(NULL, TEST_DIR "/global-dns-empty.conf", "", NULL, "/no/such/dir", "", NULL); + dns = nm_config_data_get_global_dns_config(nm_config_get_data_orig(config)); + g_assert(dns); + g_assert(nm_global_dns_config_get_searches(dns)); + g_assert(nm_global_dns_config_get_options(dns)); + g_object_unref(config); + + /* Check that a file with a domain, but no global-dns, assumes an implicit empty global-dns */ + config = + setup_config(NULL, TEST_DIR "/global-dns-not-set.conf", "", NULL, "/no/such/dir", "", NULL); + dns = nm_config_data_get_global_dns_config(nm_config_get_data_orig(config)); + g_assert(dns); + g_assert(nm_global_dns_config_get_searches(dns)); + g_assert(nm_global_dns_config_get_options(dns)); + g_object_unref(config); + + /* Check that a file with a domain, but without a default one, gives a NULL configuration */ config = setup_config(NULL, TEST_DIR "/global-dns-invalid.conf", "", NULL, "/no/such/dir", "", NULL); dns = nm_config_data_get_global_dns_config(nm_config_get_data_orig(config));