Commit 79a0238c authored by Thomas Haller's avatar Thomas Haller

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.
parent 4ea6c83e
......@@ -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
......
......@@ -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
......@@ -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);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment