diff options
author | Thomas Haller <thaller@redhat.com> | 2019-01-31 08:53:32 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2019-02-04 11:00:17 +0100 |
commit | 3cd02b318e56fbb160b9f9abd2422c5ff11b6f70 (patch) | |
tree | 89e18e9a908c6678103082dbd670abe7bea8d309 | |
parent | 92ccb9de50a7f114403f1af867a9ca741a0562e0 (diff) | |
download | NetworkManager-3cd02b318e56fbb160b9f9abd2422c5ff11b6f70.tar.gz |
libnm,core: move _nm_connection_for_each_secret() from core to libnm-core
_nm_connection_for_each_secret() (formerly for_each_secret()) and
_nm_connection_find_secret() (formerly find_secret()) operate on a
GVariant of secrets. For that, they implement certain assumptions
of how to handle secrets. For example, it must special-case VPN settings,
because there is no generic abstraction to handle regular secret and VPN
secrets the same.
Such special casing should only be done in libnm-core, at one place.
Move the code to libnm-core as internal API.
-rw-r--r-- | libnm-core/nm-connection.c | 141 | ||||
-rw-r--r-- | libnm-core/nm-core-internal.h | 20 | ||||
-rw-r--r-- | src/settings/nm-settings-connection.c | 150 |
3 files changed, 164 insertions, 147 deletions
diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c index b2c109f874..1e38029dd8 100644 --- a/libnm-core/nm-connection.c +++ b/libnm-core/nm-connection.c @@ -1873,6 +1873,147 @@ nm_connection_clear_secrets_with_flags (NMConnection *connection, g_signal_emit (connection, signals[SECRETS_CLEARED], 0); } +/*****************************************************************************/ + +/* Returns always a non-NULL, non-floating variant that must + * be unrefed by the caller. */ +GVariant * +_nm_connection_for_each_secret (NMConnection *self, + GVariant *secrets, + gboolean remove_non_secrets, + NMConnectionForEachSecretFunc callback, + gpointer callback_data) +{ + GVariantBuilder secrets_builder, setting_builder; + GVariantIter secrets_iter, *setting_iter; + const char *setting_name; + + /* This function, given a dict of dicts representing new secrets of + * an NMConnection, walks through each toplevel dict (which represents a + * NMSetting), and for each setting, walks through that setting dict's + * properties. For each property that's a secret, it will check that + * secret's flags in the backing NMConnection object, and call a supplied + * callback. + * + * The one complexity is that the VPN setting's 'secrets' property is + * *also* a dict (since the key/value pairs are arbitrary and known + * only to the VPN plugin itself). That means we have three levels of + * dicts that we potentially have to traverse here. When we hit the + * VPN setting's 'secrets' property, we special-case that and iterate over + * each item in that 'secrets' dict, calling the supplied callback + * each time. + */ + + g_return_val_if_fail (callback, NULL); + + g_variant_iter_init (&secrets_iter, secrets); + g_variant_builder_init (&secrets_builder, NM_VARIANT_TYPE_CONNECTION); + while (g_variant_iter_next (&secrets_iter, "{&sa{sv}}", &setting_name, &setting_iter)) { + NMSetting *setting; + const char *secret_name; + GVariant *val; + + setting = nm_connection_get_setting_by_name (self, setting_name); + if (setting == NULL) { + g_variant_iter_free (setting_iter); + continue; + } + + g_variant_builder_init (&setting_builder, NM_VARIANT_TYPE_SETTING); + while (g_variant_iter_next (setting_iter, "{&sv}", &secret_name, &val)) { + NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE; + + /* VPN secrets need slightly different treatment here since the + * "secrets" property is actually a hash table of secrets. + */ + if (NM_IS_SETTING_VPN (setting) && !g_strcmp0 (secret_name, NM_SETTING_VPN_SECRETS)) { + GVariantBuilder vpn_secrets_builder; + GVariantIter vpn_secrets_iter; + const char *vpn_secret_name, *secret; + + if (!g_variant_is_of_type (val, G_VARIANT_TYPE ("a{ss}"))) { + /* invalid type. Silently ignore the secrets as we cannot find out the + * secret-flags. */ + g_variant_unref (val); + continue; + } + + /* Iterate through each secret from the VPN dict in the overall secrets dict */ + g_variant_builder_init (&vpn_secrets_builder, G_VARIANT_TYPE ("a{ss}")); + g_variant_iter_init (&vpn_secrets_iter, val); + while (g_variant_iter_next (&vpn_secrets_iter, "{&s&s}", &vpn_secret_name, &secret)) { + + /* we ignore the return value of get_secret_flags. The function may determine + * that this is not a secret, based on having not secret-flags and no secrets. + * But we have the secret at hand. We know it would be a valid secret, if we + * only would add it to the VPN settings. */ + nm_setting_get_secret_flags (setting, vpn_secret_name, &secret_flags, NULL); + + if (callback (secret_flags, callback_data)) + g_variant_builder_add (&vpn_secrets_builder, "{ss}", vpn_secret_name, secret); + } + + g_variant_builder_add (&setting_builder, "{sv}", + secret_name, g_variant_builder_end (&vpn_secrets_builder)); + } else { + if (!nm_setting_get_secret_flags (setting, secret_name, &secret_flags, NULL)) { + if (!remove_non_secrets) + g_variant_builder_add (&setting_builder, "{sv}", secret_name, val); + g_variant_unref (val); + continue; + } + if (callback (secret_flags, callback_data)) + g_variant_builder_add (&setting_builder, "{sv}", secret_name, val); + } + g_variant_unref (val); + } + + g_variant_iter_free (setting_iter); + g_variant_builder_add (&secrets_builder, "{sa{sv}}", setting_name, &setting_builder); + } + + return g_variant_ref_sink (g_variant_builder_end (&secrets_builder)); +} + +/*****************************************************************************/ + +typedef struct { + NMConnectionFindSecretFunc find_func; + gpointer find_func_data; + gboolean found; +} FindSecretData; + +static gboolean +find_secret_for_each_func (NMSettingSecretFlags flags, + gpointer user_data) +{ + FindSecretData *data = user_data; + + if (!data->found) + data->found = data->find_func (flags, data->find_func_data); + return FALSE; +} + +gboolean +_nm_connection_find_secret (NMConnection *self, + GVariant *secrets, + NMConnectionFindSecretFunc callback, + gpointer callback_data) +{ + FindSecretData data; + GVariant *dummy; + + data.find_func = callback; + data.find_func_data = callback_data; + data.found = FALSE; + + dummy = _nm_connection_for_each_secret (self, secrets, FALSE, find_secret_for_each_func, &data); + g_variant_unref (dummy); + return data.found; +} + +/*****************************************************************************/ + /** * nm_connection_to_dbus: * @connection: the #NMConnection diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index 9385d505e7..870ec78133 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -733,4 +733,24 @@ GBytes *_nm_setting_802_1x_cert_value_to_bytes (NMSetting8021xCKScheme scheme, /*****************************************************************************/ +/* Return TRUE to keep (copy to the result), FALSE to drop. */ +typedef gboolean (*NMConnectionForEachSecretFunc) (NMSettingSecretFlags flags, + gpointer user_data); + +GVariant *_nm_connection_for_each_secret (NMConnection *self, + GVariant *secrets, + gboolean remove_non_secrets, + NMConnectionForEachSecretFunc callback, + gpointer callback_data); + +typedef gboolean (*NMConnectionFindSecretFunc) (NMSettingSecretFlags flags, + gpointer user_data); + +gboolean _nm_connection_find_secret (NMConnection *self, + GVariant *secrets, + NMConnectionFindSecretFunc callback, + gpointer callback_data); + +/*****************************************************************************/ + #endif diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c index 9ea3253733..aa4ec0a90a 100644 --- a/src/settings/nm-settings-connection.c +++ b/src/settings/nm-settings-connection.c @@ -208,150 +208,6 @@ nm_settings_connection_get_last_secret_agent_version_id (NMSettingsConnection *s /*****************************************************************************/ -/* Return TRUE to keep, FALSE to drop */ -typedef gboolean (*ForEachSecretFunc) (NMSettingSecretFlags flags, - gpointer user_data); - -/* Returns always a non-NULL, non-floating variant that must - * be unrefed by the caller. */ -static GVariant * -for_each_secret (NMConnection *self, - GVariant *secrets, - gboolean remove_non_secrets, - ForEachSecretFunc callback, - gpointer callback_data) -{ - GVariantBuilder secrets_builder, setting_builder; - GVariantIter secrets_iter, *setting_iter; - const char *setting_name; - - /* This function, given a dict of dicts representing new secrets of - * an NMConnection, walks through each toplevel dict (which represents a - * NMSetting), and for each setting, walks through that setting dict's - * properties. For each property that's a secret, it will check that - * secret's flags in the backing NMConnection object, and call a supplied - * callback. - * - * The one complexity is that the VPN setting's 'secrets' property is - * *also* a dict (since the key/value pairs are arbitrary and known - * only to the VPN plugin itself). That means we have three levels of - * dicts that we potentially have to traverse here. When we hit the - * VPN setting's 'secrets' property, we special-case that and iterate over - * each item in that 'secrets' dict, calling the supplied callback - * each time. - */ - - g_return_val_if_fail (callback, NULL); - - g_variant_iter_init (&secrets_iter, secrets); - g_variant_builder_init (&secrets_builder, NM_VARIANT_TYPE_CONNECTION); - while (g_variant_iter_next (&secrets_iter, "{&sa{sv}}", &setting_name, &setting_iter)) { - NMSetting *setting; - const char *secret_name; - GVariant *val; - - setting = nm_connection_get_setting_by_name (self, setting_name); - if (setting == NULL) { - g_variant_iter_free (setting_iter); - continue; - } - - g_variant_builder_init (&setting_builder, NM_VARIANT_TYPE_SETTING); - while (g_variant_iter_next (setting_iter, "{&sv}", &secret_name, &val)) { - NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE; - - /* VPN secrets need slightly different treatment here since the - * "secrets" property is actually a hash table of secrets. - */ - if (NM_IS_SETTING_VPN (setting) && !g_strcmp0 (secret_name, NM_SETTING_VPN_SECRETS)) { - GVariantBuilder vpn_secrets_builder; - GVariantIter vpn_secrets_iter; - const char *vpn_secret_name, *secret; - - if (!g_variant_is_of_type (val, G_VARIANT_TYPE ("a{ss}"))) { - /* invalid type. Silently ignore the secrets as we cannot find out the - * secret-flags. */ - g_variant_unref (val); - continue; - } - - /* Iterate through each secret from the VPN dict in the overall secrets dict */ - g_variant_builder_init (&vpn_secrets_builder, G_VARIANT_TYPE ("a{ss}")); - g_variant_iter_init (&vpn_secrets_iter, val); - while (g_variant_iter_next (&vpn_secrets_iter, "{&s&s}", &vpn_secret_name, &secret)) { - - /* we ignore the return value of get_secret_flags. The function may determine - * that this is not a secret, based on having not secret-flags and no secrets. - * But we have the secret at hand. We know it would be a valid secret, if we - * only would add it to the VPN settings. */ - nm_setting_get_secret_flags (setting, vpn_secret_name, &secret_flags, NULL); - - if (callback (secret_flags, callback_data)) - g_variant_builder_add (&vpn_secrets_builder, "{ss}", vpn_secret_name, secret); - } - - g_variant_builder_add (&setting_builder, "{sv}", - secret_name, g_variant_builder_end (&vpn_secrets_builder)); - } else { - if (!nm_setting_get_secret_flags (setting, secret_name, &secret_flags, NULL)) { - if (!remove_non_secrets) - g_variant_builder_add (&setting_builder, "{sv}", secret_name, val); - g_variant_unref (val); - continue; - } - if (callback (secret_flags, callback_data)) - g_variant_builder_add (&setting_builder, "{sv}", secret_name, val); - } - g_variant_unref (val); - } - - g_variant_iter_free (setting_iter); - g_variant_builder_add (&secrets_builder, "{sa{sv}}", setting_name, &setting_builder); - } - - return g_variant_ref_sink (g_variant_builder_end (&secrets_builder)); -} - -typedef gboolean (*FindSecretFunc) (NMSettingSecretFlags flags, - gpointer user_data); - -typedef struct { - FindSecretFunc find_func; - gpointer find_func_data; - gboolean found; -} FindSecretData; - -static gboolean -find_secret_for_each_func (NMSettingSecretFlags flags, - gpointer user_data) -{ - FindSecretData *data = user_data; - - if (!data->found) - data->found = data->find_func (flags, data->find_func_data); - return FALSE; -} - -static gboolean -find_secret (NMConnection *self, - GVariant *secrets, - FindSecretFunc callback, - gpointer callback_data) -{ - FindSecretData data; - GVariant *dummy; - - data.find_func = callback; - data.find_func_data = callback_data; - data.found = FALSE; - - dummy = for_each_secret (self, secrets, FALSE, find_secret_for_each_func, &data); - g_variant_unref (dummy); - return data.found; -} - -/*****************************************************************************/ - static void set_visible (NMSettingsConnection *self, gboolean new_visible) { @@ -1001,7 +857,7 @@ get_cmp_flags (NMSettingsConnection *self, /* only needed for logging */ * save those system-owned secrets. If not, discard them and use the * existing secrets, or fail the connection. */ - *agent_had_system = find_secret (connection, secrets, secret_is_system_owned, NULL); + *agent_had_system = _nm_connection_find_secret (connection, secrets, secret_is_system_owned, NULL); if (*agent_had_system) { if (flags == NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE) { /* No user interaction was allowed when requesting secrets; the @@ -1167,7 +1023,7 @@ get_secrets_done_cb (NMAgentManager *manager, * will have been authenticated, so those secrets can replace the existing * system secrets. */ - filtered_secrets = for_each_secret (nm_settings_connection_get_connection (self), secrets, TRUE, validate_secret_flags, &cmp_flags); + filtered_secrets = _nm_connection_for_each_secret (nm_settings_connection_get_connection (self), secrets, TRUE, validate_secret_flags, &cmp_flags); if (nm_connection_update_secrets (nm_settings_connection_get_connection (self), setting_name, filtered_secrets, &local)) { /* Now that all secrets are updated, copy and cache new secrets, * then save them to backing storage. @@ -1229,7 +1085,7 @@ get_secrets_done_cb (NMAgentManager *manager, if (!dict || nm_connection_update_secrets (applied_connection, setting_name, dict, NULL)) { GVariant *filtered_secrets; - filtered_secrets = for_each_secret (applied_connection, secrets, TRUE, validate_secret_flags, &cmp_flags); + filtered_secrets = _nm_connection_for_each_secret (applied_connection, secrets, TRUE, validate_secret_flags, &cmp_flags); nm_connection_update_secrets (applied_connection, setting_name, filtered_secrets, NULL); g_variant_unref (filtered_secrets); } |