diff --git a/libnm-core/nm-keyfile-reader.c b/libnm-core/nm-keyfile-reader.c index 078c517e8e..eb257eeb1a 100644 --- a/libnm-core/nm-keyfile-reader.c +++ b/libnm-core/nm-keyfile-reader.c @@ -35,6 +35,8 @@ #include "nm-core-internal.h" #include "nm-keyfile-utils.h" +#include "nm-setting-user.h" + typedef struct { NMConnection *connection; GKeyFile *keyfile; @@ -716,33 +718,56 @@ read_hash_of_string (GKeyFile *file, NMSetting *setting, const char *key) { gs_strfreev char **keys = NULL; const char *const*iter; - char *value; const char *setting_name = nm_setting_get_name (setting); + gboolean is_vpn; keys = nm_keyfile_plugin_kf_get_keys (file, setting_name, NULL, NULL); if (!keys || !*keys) return; - for (iter = (const char *const*) keys; *iter; iter++) { - gs_free char *to_free = NULL; - const char *name; + if ( (is_vpn = NM_IS_SETTING_VPN (setting)) + || NM_IS_SETTING_BOND (setting)) { + for (iter = (const char *const*) keys; *iter; iter++) { + gs_free char *to_free = NULL; + gs_free char *value = NULL; + const char *name; - value = nm_keyfile_plugin_kf_get_string (file, setting_name, *iter, NULL); - if (!value) - continue; + value = nm_keyfile_plugin_kf_get_string (file, setting_name, *iter, NULL); + if (!value) + continue; - name = nm_keyfile_key_decode (*iter, &to_free); + name = nm_keyfile_key_decode (*iter, &to_free); - if (NM_IS_SETTING_VPN (setting)) { - /* Add any item that's not a class property to the data hash */ - if (!g_object_class_find_property (G_OBJECT_GET_CLASS (setting), name)) - nm_setting_vpn_add_data_item (NM_SETTING_VPN (setting), name, value); + if (is_vpn) { + /* Add any item that's not a class property to the data hash */ + if (!g_object_class_find_property (G_OBJECT_GET_CLASS (setting), name)) + nm_setting_vpn_add_data_item (NM_SETTING_VPN (setting), name, value); + } else { + if (strcmp (name, "interface-name")) + nm_setting_bond_add_option (NM_SETTING_BOND (setting), name, value); + } } - if (NM_IS_SETTING_BOND (setting)) { - if (strcmp (name, "interface-name")) - nm_setting_bond_add_option (NM_SETTING_BOND (setting), name, value); + return; + } + + if (NM_IS_SETTING_USER (setting)) { + gs_unref_hashtable GHashTable *data = NULL; + + data = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + for (iter = (const char *const*) keys; *iter; iter++) { + gs_free char *to_free = NULL; + char *value = NULL; + const char *name; + + value = nm_keyfile_plugin_kf_get_string (file, setting_name, *iter, NULL); + if (!value) + continue; + name = nm_keyfile_key_decode (*iter, &to_free); + g_hash_table_insert (data, + g_steal_pointer (&to_free) ?: g_strdup (name), + value); } - g_free (value); + g_object_set (setting, NM_SETTING_USER_DATA, data, NULL); } } @@ -1460,6 +1485,9 @@ read_one_setting_value (NMSetting *setting, if (NM_IS_SETTING_VPN (setting)) check_for_key = FALSE; + if (NM_IS_SETTING_USER (setting)) + check_for_key = FALSE; + /* Bonding 'options' don't have the exact key name. The options are right under [bond] group. */ if (NM_IS_SETTING_BOND (setting)) check_for_key = FALSE; diff --git a/libnm-core/tests/test-keyfile.c b/libnm-core/tests/test-keyfile.c index f7525317a9..2dc929afd8 100644 --- a/libnm-core/tests/test-keyfile.c +++ b/libnm-core/tests/test-keyfile.c @@ -28,6 +28,7 @@ #include "nm-setting-wired.h" #include "nm-setting-8021x.h" #include "nm-setting-team.h" +#include "nm-setting-user.h" #include "nm-setting-proxy.h" #include "nm-utils/nm-test-utils.h" @@ -646,6 +647,73 @@ test_team_conf_read_invalid (void) /*****************************************************************************/ +static void +test_user_1 (void) +{ + gs_unref_keyfile GKeyFile *keyfile = NULL; + gs_unref_object NMConnection *con = NULL; + NMSettingUser *s_user; + + con = nmtst_create_connection_from_keyfile ( + "[connection]\n" + "id=t\n" + "type=ethernet\n" + "\n" + "[user]\n" + "my-value.x=value1\n" + "", + "/test_user_1/invalid", NULL); + g_assert (con); + s_user = NM_SETTING_USER (nm_connection_get_setting (con, NM_TYPE_SETTING_USER)); + g_assert (s_user); + g_assert_cmpstr (nm_setting_user_get_data (s_user, "my-value.x"), ==, "value1"); + + CLEAR (&con, &keyfile); + + con = nmtst_create_minimal_connection ("user-2", "8b85fb8d-3070-48ba-93d9-53eee231d9a2", NM_SETTING_WIRED_SETTING_NAME, NULL); + s_user = NM_SETTING_USER (nm_setting_user_new ()); + +#define _USER_SET_DATA(s_user, key, val) \ + G_STMT_START { \ + GError *_error = NULL; \ + gboolean _success; \ + \ + _success = nm_setting_user_set_data ((s_user), (key), (val), &_error); \ + nmtst_assert_success (_success, _error); \ + } G_STMT_END + +#define _USER_SET_DATA_X(s_user, key) \ + _USER_SET_DATA (s_user, key, "val="key"") + + _USER_SET_DATA (s_user, "my.val1", ""); + _USER_SET_DATA_X (s_user, "my.val2"); + _USER_SET_DATA_X (s_user, "my.v__al3"); + _USER_SET_DATA_X (s_user, "my._v"); + _USER_SET_DATA_X (s_user, "my.v+"); + _USER_SET_DATA_X (s_user, "my.Av"); + _USER_SET_DATA_X (s_user, "MY.AV"); + _USER_SET_DATA_X (s_user, "MY.8V"); + _USER_SET_DATA_X (s_user, "MY.8-V"); + _USER_SET_DATA_X (s_user, "MY.8_V"); + _USER_SET_DATA_X (s_user, "MY.8+V"); + _USER_SET_DATA_X (s_user, "MY.8/V"); + _USER_SET_DATA_X (s_user, "MY.8=V"); + _USER_SET_DATA_X (s_user, "MY.-"); + _USER_SET_DATA_X (s_user, "MY._"); + _USER_SET_DATA_X (s_user, "MY.+"); + _USER_SET_DATA_X (s_user, "MY./"); + _USER_SET_DATA_X (s_user, "MY.="); + _USER_SET_DATA_X (s_user, "my.keys.1"); + _USER_SET_DATA_X (s_user, "my.other.KEY.42"); + + nm_connection_add_setting (con, NM_SETTING (s_user)); + nmtst_connection_normalize (con); + + _keyfile_convert (&con, &keyfile, NULL, NULL, NULL, NULL, NULL, NULL, FALSE); +} + +/*****************************************************************************/ + NMTST_DEFINE (); int main (int argc, char **argv) @@ -657,6 +725,7 @@ int main (int argc, char **argv) g_test_add_func ("/core/keyfile/test_8021x_cert_read", test_8021x_cert_read); g_test_add_func ("/core/keyfile/test_team_conf_read/valid", test_team_conf_read_valid); g_test_add_func ("/core/keyfile/test_team_conf_read/invalid", test_team_conf_read_invalid); + g_test_add_func ("/core/keyfile/test_user/1", test_user_1); return g_test_run (); }