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.
This commit is contained in:
@@ -1873,6 +1873,147 @@ nm_connection_clear_secrets_with_flags (NMConnection *connection,
|
|||||||
g_signal_emit (connection, signals[SECRETS_CLEARED], 0);
|
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:
|
* nm_connection_to_dbus:
|
||||||
* @connection: the #NMConnection
|
* @connection: the #NMConnection
|
||||||
|
@@ -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
|
#endif
|
||||||
|
@@ -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
|
static void
|
||||||
set_visible (NMSettingsConnection *self, gboolean new_visible)
|
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
|
* save those system-owned secrets. If not, discard them and use the
|
||||||
* existing secrets, or fail the connection.
|
* 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 (*agent_had_system) {
|
||||||
if (flags == NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE) {
|
if (flags == NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE) {
|
||||||
/* No user interaction was allowed when requesting secrets; the
|
/* 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
|
* will have been authenticated, so those secrets can replace the existing
|
||||||
* system secrets.
|
* 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)) {
|
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,
|
/* Now that all secrets are updated, copy and cache new secrets,
|
||||||
* then save them to backing storage.
|
* 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)) {
|
if (!dict || nm_connection_update_secrets (applied_connection, setting_name, dict, NULL)) {
|
||||||
GVariant *filtered_secrets;
|
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);
|
nm_connection_update_secrets (applied_connection, setting_name, filtered_secrets, NULL);
|
||||||
g_variant_unref (filtered_secrets);
|
g_variant_unref (filtered_secrets);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user