diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c index b2c109f874..5bafe2d7c0 100644 --- a/libnm-core/nm-connection.c +++ b/libnm-core/nm-connection.c @@ -1873,6 +1873,108 @@ nm_connection_clear_secrets_with_flags (NMConnection *connection, g_signal_emit (connection, signals[SECRETS_CLEARED], 0); } +/*****************************************************************************/ + +/* Returns always a non-NULL, 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; + GVariantBuilder setting_builder; + GVariantIter secrets_iter; + GVariantIter *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. The differences + * are handled by the virtual for_each_secret() function. + */ + + 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)) { + _nm_unused nm_auto_free_variant_iter GVariantIter *setting_iter_free = setting_iter; + NMSetting *setting; + const char *secret_name; + GVariant *val; + + setting = nm_connection_get_setting_by_name (self, setting_name); + if (!setting) + continue; + + g_variant_builder_init (&setting_builder, NM_VARIANT_TYPE_SETTING); + while (g_variant_iter_next (setting_iter, "{&sv}", &secret_name, &val)) { + _nm_unused gs_unref_variant GVariant *val_free = val; + + NM_SETTING_GET_CLASS (setting)->for_each_secret (setting, + secret_name, + val, + remove_non_secrets, + callback, + callback_data, + &setting_builder); + } + + g_variant_builder_add (&secrets_builder, "{sa{sv}}", setting_name, &setting_builder); + } + + return 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) +{ + gs_unref_variant GVariant *dummy = NULL; + FindSecretData data = { + .find_func = callback, + .find_func_data = callback_data, + .found = FALSE, + }; + + dummy = _nm_connection_for_each_secret (self, secrets, FALSE, find_secret_for_each_func, &data); + 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 b3d664dcea..2d66eb83fb 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -614,7 +614,8 @@ gboolean _nm_setting_sriov_sort_vfs (NMSettingSriov *setting); /*****************************************************************************/ -typedef struct _NMSettInfoSetting NMSettInfoSetting; +typedef struct _NMSettInfoSetting NMSettInfoSetting; +typedef struct _NMSettInfoProperty NMSettInfoProperty; typedef GVariant *(*NMSettingPropertyGetFunc) (NMSetting *setting, const char *property); @@ -638,7 +639,7 @@ typedef GVariant *(*NMSettingPropertyTransformToFunc) (const GValue *from); typedef void (*NMSettingPropertyTransformFromFunc) (GVariant *from, GValue *to); -typedef struct { +struct _NMSettInfoProperty { const char *name; GParamSpec *param_spec; const GVariantType *dbus_type; @@ -650,7 +651,7 @@ typedef struct { NMSettingPropertyTransformToFunc to_dbus; NMSettingPropertyTransformFromFunc from_dbus; -} NMSettInfoProperty; +}; typedef struct { const GVariantType *(*get_variant_type) (const struct _NMSettInfoSetting *sett_info, @@ -732,4 +733,20 @@ GBytes *_nm_setting_802_1x_cert_value_to_bytes (NMSetting8021xCKScheme scheme, /*****************************************************************************/ +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/libnm-core/nm-setting-private.h b/libnm-core/nm-setting-private.h index 8f61b0ff9d..2af74ec4ce 100644 --- a/libnm-core/nm-setting-private.h +++ b/libnm-core/nm-setting-private.h @@ -39,6 +39,8 @@ int _nm_setting_compare_priority (gconstpointer a, gconstpointer b); /*****************************************************************************/ +void _nm_setting_emit_property_changed (NMSetting *setting); + typedef enum NMSettingUpdateSecretResult { NM_SETTING_UPDATE_SECRET_ERROR = FALSE, NM_SETTING_UPDATE_SECRET_SUCCESS_MODIFIED = TRUE, @@ -99,9 +101,6 @@ gboolean _nm_setting_verify_secret_string (const char *str, gboolean _nm_setting_aggregate (NMSetting *setting, NMConnectionAggregateType type, gpointer arg); -gboolean _nm_setting_vpn_aggregate (NMSettingVpn *setting, - NMConnectionAggregateType type, - gpointer arg); gboolean _nm_setting_slave_type_is_valid (const char *slave_type, const char **out_port_type); diff --git a/libnm-core/nm-setting-vpn.c b/libnm-core/nm-setting-vpn.c index 1371140ec4..e3612c13bd 100644 --- a/libnm-core/nm-setting-vpn.c +++ b/libnm-core/nm-setting-vpn.c @@ -449,20 +449,17 @@ nm_setting_vpn_foreach_secret (NMSettingVpn *setting, foreach_item_helper (setting, TRUE, func, user_data); } -gboolean -_nm_setting_vpn_aggregate (NMSettingVpn *setting, - NMConnectionAggregateType type, - gpointer arg) +static gboolean +aggregate (NMSetting *setting, + int type_i, + gpointer arg) { - NMSettingVpnPrivate *priv; + NMSettingVpnPrivate *priv = NM_SETTING_VPN_GET_PRIVATE (setting); + NMConnectionAggregateType type = type_i; NMSettingSecretFlags secret_flags; const char *key_name; GHashTableIter iter; - g_return_val_if_fail (NM_IS_SETTING_VPN (setting), FALSE); - - priv = NM_SETTING_VPN_GET_PRIVATE (setting); - switch (type) { case NM_CONNECTION_AGGREGATE_ANY_SECRETS: @@ -687,6 +684,57 @@ update_one_secret (NMSetting *setting, const char *key, GVariant *value, GError return success; } +static void +for_each_secret (NMSetting *setting, + const char *secret_name, + GVariant *val, + gboolean remove_non_secrets, + _NMConnectionForEachSecretFunc callback, + gpointer callback_data, + GVariantBuilder *setting_builder) +{ + GVariantBuilder vpn_secrets_builder; + GVariantIter vpn_secrets_iter; + const char *vpn_secret_name; + const char *secret; + + if (!nm_streq (secret_name, NM_SETTING_VPN_SECRETS)) { + NM_SETTING_CLASS (nm_setting_vpn_parent_class)->for_each_secret (setting, + secret_name, + val, + remove_non_secrets, + callback, + callback_data, + setting_builder); + return; + } + + 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. */ + return; + } + + /* 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)) { + NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE; + + /* 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 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)); +} + static gboolean get_secret_flags (NMSetting *setting, const char *secret_name, @@ -979,11 +1027,13 @@ nm_setting_vpn_class_init (NMSettingVpnClass *klass) setting_class->verify = verify; setting_class->update_one_secret = update_one_secret; + setting_class->for_each_secret = for_each_secret; setting_class->get_secret_flags = get_secret_flags; setting_class->set_secret_flags = set_secret_flags; setting_class->need_secrets = need_secrets; setting_class->compare_property = compare_property; setting_class->clear_secrets = clear_secrets; + setting_class->aggregate = aggregate; /** * NMSettingVpn:service-type: diff --git a/libnm-core/nm-setting.c b/libnm-core/nm-setting.c index a62e31e80d..fe6808bcdc 100644 --- a/libnm-core/nm-setting.c +++ b/libnm-core/nm-setting.c @@ -32,15 +32,6 @@ #include "nm-utils-private.h" #include "nm-property-compare.h" -#include "nm-setting-connection.h" -#include "nm-setting-bond.h" -#include "nm-setting-bridge.h" -#include "nm-setting-bridge-port.h" -#include "nm-setting-pppoe.h" -#include "nm-setting-team.h" -#include "nm-setting-team-port.h" -#include "nm-setting-vpn.h" - /** * SECTION:nm-setting * @short_description: Describes related configuration information @@ -67,7 +58,7 @@ typedef struct { NMSettingPriority priority; } SettingInfo; -NM_GOBJECT_PROPERTIES_DEFINE_BASE ( +NM_GOBJECT_PROPERTIES_DEFINE (NMSetting, PROP_NAME, ); @@ -553,6 +544,35 @@ _nm_setting_class_get_sett_info (NMSettingClass *setting_class) /*****************************************************************************/ +void +_nm_setting_emit_property_changed (NMSetting *setting) +{ + /* Some settings have "properties" that are not implemented as GObject properties. + * + * For example: + * + * - gendata-base settings like NMSettingEthtool. Here properties are just + * GVariant values in the gendata hash. + * + * - NMSettingWireGuard's peers are not backed by a GObject property. Instead + * there is C-API to access/modify peers. + * + * We still want to emit property-changed notifications for such properties, + * in particular because NMConnection registers to such signals to re-emit + * it as NM_CONNECTION_CHANGED signal. In fact, there are unlikely any other + * uses of such a property-changed signal, because generally it doesn't make + * too much sense. + * + * So, instead of adding yet another (artificial) signal "setting-changed", + * hijack the "notify" signal and just notify about changes of the "name". + * Of course, the "name" doesn't really ever change, because it's tied to + * the GObject's type. + */ + _notify (setting, PROP_NAME); +} + +/*****************************************************************************/ + gboolean _nm_setting_use_legacy_property (NMSetting *setting, GVariant *connection_dict, @@ -1082,6 +1102,8 @@ duplicate_copy_properties (const NMSettInfoSetting *sett_info, if (sett_info->detail.gendata_info) { GenData *gendata = _gendata_hash (src, FALSE); + nm_assert (!_gendata_hash (dst, FALSE)); + if ( gendata && g_hash_table_size (gendata->hash) > 0) { GHashTableIter iter; @@ -1698,6 +1720,27 @@ nm_setting_diff (NMSetting *a, } } +static void +enumerate_values (const NMSettInfoProperty *property_info, + NMSetting *setting, + NMSettingValueIterFn func, + gpointer user_data) +{ + GValue value = G_VALUE_INIT; + + if (!property_info->param_spec) + return; + + g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (property_info->param_spec)); + g_object_get_property (G_OBJECT (setting), property_info->param_spec->name, &value); + func (setting, + property_info->param_spec->name, + &value, + property_info->param_spec->flags, + user_data); + g_value_unset (&value); +} + /** * nm_setting_enumerate_values: * @setting: the #NMSetting @@ -1753,50 +1796,24 @@ nm_setting_enumerate_values (NMSetting *setting, } for (i = 0; i < sett_info->property_infos_len; i++) { - GParamSpec *prop_spec = _nm_sett_info_property_info_get_sorted (sett_info, i)->param_spec; - GValue value = G_VALUE_INIT; - - if (!prop_spec) - continue; - - g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (prop_spec)); - g_object_get_property (G_OBJECT (setting), prop_spec->name, &value); - func (setting, prop_spec->name, &value, prop_spec->flags, user_data); - g_value_unset (&value); + NM_SETTING_GET_CLASS (setting)->enumerate_values (_nm_sett_info_property_info_get_sorted (sett_info, i), + setting, + func, + user_data); } } -/** - * _nm_setting_aggregate: - * @setting: the #NMSetting to aggregate. - * @type: the #NMConnectionAggregateType aggregate type. - * @arg: the in/out arguments for aggregation. They depend on @type. - * - * This is the implementation detail of _nm_connection_aggregate(). It - * makes no sense to call this function directly outside of _nm_connection_aggregate(). - * - * Returns: %TRUE if afterwards the aggregation is complete. That means, - * the only caller _nm_connection_aggregate() will not visit other settings - * after a setting returns %TRUE (indicating that there is nothing further - * to aggregate). Note that is very different from the boolean return - * argument of _nm_connection_aggregate(), which serves a different purpose. - */ -gboolean -_nm_setting_aggregate (NMSetting *setting, - NMConnectionAggregateType type, - gpointer arg) +static gboolean +aggregate (NMSetting *setting, + int type_i, + gpointer arg) { + NMConnectionAggregateType type = type_i; const NMSettInfoSetting *sett_info; guint i; - g_return_val_if_fail (NM_IS_SETTING (setting), FALSE); - g_return_val_if_fail (arg, FALSE); - g_return_val_if_fail (NM_IN_SET (type, NM_CONNECTION_AGGREGATE_ANY_SECRETS, - NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS), - FALSE); - - if (NM_IS_SETTING_VPN (setting)) - return _nm_setting_vpn_aggregate (NM_SETTING_VPN (setting), type, arg); + nm_assert (NM_IN_SET (type, NM_CONNECTION_AGGREGATE_ANY_SECRETS, + NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS)); sett_info = _nm_setting_class_get_sett_info (NM_SETTING_GET_CLASS (setting)); for (i = 0; i < sett_info->property_infos_len; i++) { @@ -1840,6 +1857,35 @@ _nm_setting_aggregate (NMSetting *setting, return FALSE; } +/** + * _nm_setting_aggregate: + * @setting: the #NMSetting to aggregate. + * @type: the #NMConnectionAggregateType aggregate type. + * @arg: the in/out arguments for aggregation. They depend on @type. + * + * This is the implementation detail of _nm_connection_aggregate(). It + * makes no sense to call this function directly outside of _nm_connection_aggregate(). + * + * Returns: %TRUE if afterwards the aggregation is complete. That means, + * the only caller _nm_connection_aggregate() will not visit other settings + * after a setting returns %TRUE (indicating that there is nothing further + * to aggregate). Note that is very different from the boolean return + * argument of _nm_connection_aggregate(), which serves a different purpose. + */ +gboolean +_nm_setting_aggregate (NMSetting *setting, + NMConnectionAggregateType type, + gpointer arg) +{ + g_return_val_if_fail (NM_IS_SETTING (setting), FALSE); + g_return_val_if_fail (arg, FALSE); + g_return_val_if_fail (NM_IN_SET (type, NM_CONNECTION_AGGREGATE_ANY_SECRETS, + NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS), + FALSE); + + return NM_SETTING_GET_CLASS (setting)->aggregate (setting, type, arg); +} + static gboolean clear_secrets (const NMSettInfoSetting *sett_info, guint property_idx, @@ -2039,6 +2085,26 @@ _nm_setting_update_secrets (NMSetting *setting, GVariant *secrets, GError **erro return result; } +static void +for_each_secret (NMSetting *setting, + const char *secret_name, + GVariant *val, + gboolean remove_non_secrets, + _NMConnectionForEachSecretFunc callback, + gpointer callback_data, + GVariantBuilder *setting_builder) +{ + NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE; + + 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); + return; + } + if (callback (secret_flags, callback_data)) + g_variant_builder_add (setting_builder, "{sv}", secret_name, val); +} + static void _set_error_secret_property_not_found (GError **error, NMSetting *setting, @@ -2293,7 +2359,7 @@ _nm_setting_gendata_notify (NMSetting *setting, gendata = _gendata_hash (setting, FALSE); if (!gendata) - return; + goto out; nm_clear_g_free (&gendata->values); @@ -2303,7 +2369,7 @@ _nm_setting_gendata_notify (NMSetting *setting, nm_clear_g_free (&gendata->names); } - /* Note, that currently there is now way to notify the subclass when gendata changed. + /* Note, currently there is no way to notify the subclass when gendata changed. * gendata is only changed in two situations: * 1) from within NMSetting itself, for example when creating a NMSetting instance * from keyfile or a D-Bus GVariant. @@ -2316,6 +2382,9 @@ _nm_setting_gendata_notify (NMSetting *setting, * * If we ever need it, then we would need to call a virtual function to notify the subclass * that gendata changed. */ + +out: + _nm_setting_emit_property_changed (setting); } GVariant * @@ -2438,7 +2507,7 @@ nm_setting_gendata_get_all_values (NMSetting *setting) void _nm_setting_gendata_to_gvalue (NMSetting *setting, - GValue *value) + GValue *value) { GenData *gendata; GHashTable *new; @@ -2571,7 +2640,10 @@ nm_setting_class_init (NMSettingClass *setting_class) setting_class->set_secret_flags = set_secret_flags; setting_class->compare_property = compare_property; setting_class->clear_secrets = clear_secrets; + setting_class->for_each_secret = for_each_secret; setting_class->duplicate_copy_properties = duplicate_copy_properties; + setting_class->enumerate_values = enumerate_values; + setting_class->aggregate = aggregate; /** * NMSetting:name: diff --git a/libnm-core/nm-setting.h b/libnm-core/nm-setting.h index 0f0ac8f382..fdf4a4c516 100644 --- a/libnm-core/nm-setting.h +++ b/libnm-core/nm-setting.h @@ -170,6 +170,26 @@ typedef gboolean (*NMSettingClearSecretsWithFlagsFn) (NMSetting *setting, struct _NMMetaSettingInfo; struct _NMSettInfoSetting; +struct _NMSettInfoProperty; + +/** + * NMSettingValueIterFn: + * @setting: The setting for which properties are being iterated, given to + * nm_setting_enumerate_values() + * @key: The value/property name + * @value: The property's value + * @flags: The property's flags, like %NM_SETTING_PARAM_SECRET + * @user_data: User data passed to nm_setting_enumerate_values() + */ +typedef void (*NMSettingValueIterFn) (NMSetting *setting, + const char *key, + const GValue *value, + GParamFlags flags, + gpointer user_data); + +/*< private >*/ +typedef gboolean (*_NMConnectionForEachSecretFunc) (NMSettingSecretFlags flags, + gpointer user_data); typedef struct { GObjectClass parent; @@ -226,26 +246,31 @@ typedef struct { NMSetting *dst); /*< private >*/ - const struct _NMMetaSettingInfo *setting_info; + void (*enumerate_values) (const struct _NMSettInfoProperty *property_info, + NMSetting *setting, + NMSettingValueIterFn func, + gpointer user_data); /*< private >*/ - gpointer padding[5]; -} NMSettingClass; + gboolean (*aggregate) (NMSetting *setting, + int type_i, + gpointer arg); -/** - * NMSettingValueIterFn: - * @setting: The setting for which properties are being iterated, given to - * nm_setting_enumerate_values() - * @key: The value/property name - * @value: The property's value - * @flags: The property's flags, like %NM_SETTING_PARAM_SECRET - * @user_data: User data passed to nm_setting_enumerate_values() - */ -typedef void (*NMSettingValueIterFn) (NMSetting *setting, - const char *key, - const GValue *value, - GParamFlags flags, - gpointer user_data); + /*< private >*/ + void (*for_each_secret) (NMSetting *setting, + const char *secret_name, + GVariant *val, + gboolean remove_non_secrets, + _NMConnectionForEachSecretFunc callback, + gpointer callback_data, + GVariantBuilder *setting_builder); + + /*< private >*/ + gpointer padding[2]; + + /*< private >*/ + const struct _NMMetaSettingInfo *setting_info; +} NMSettingClass; GType nm_setting_get_type (void); diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c index e655a11937..25eb828bbb 100644 --- a/src/settings/nm-settings-connection.c +++ b/src/settings/nm-settings-connection.c @@ -208,141 +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; - - /* 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)) { - if (!nm_setting_get_secret_flags (setting, vpn_secret_name, &secret_flags, NULL)) { - if (!remove_non_secrets) - g_variant_builder_add (&vpn_secrets_builder, "{ss}", vpn_secret_name, secret); - continue; - } - - 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); - 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) { @@ -938,8 +803,8 @@ typedef struct { } ForEachSecretFlags; static gboolean -validate_secret_flags (NMSettingSecretFlags flags, - gpointer user_data) +validate_secret_flags_cb (NMSettingSecretFlags flags, + gpointer user_data) { ForEachSecretFlags *cmp_flags = user_data; @@ -950,6 +815,18 @@ validate_secret_flags (NMSettingSecretFlags flags, return TRUE; } +static GVariant * +validate_secret_flags (NMConnection *connection, + GVariant *secrets, + ForEachSecretFlags *cmp_flags) +{ + return g_variant_ref_sink (_nm_connection_for_each_secret (connection, + secrets, + TRUE, + validate_secret_flags_cb, + cmp_flags)); +} + static gboolean secret_is_system_owned (NMSettingSecretFlags flags, gpointer user_data) @@ -992,7 +869,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 @@ -1151,14 +1028,14 @@ get_secrets_done_cb (NMAgentManager *manager, /* Update the connection with our existing secrets from backing storage */ nm_connection_clear_secrets (nm_settings_connection_get_connection (self)); if (!dict || nm_connection_update_secrets (nm_settings_connection_get_connection (self), setting_name, dict, &local)) { - GVariant *filtered_secrets; + gs_unref_variant GVariant *filtered_secrets = NULL; /* Update the connection with the agent's secrets; by this point if any * system-owned secrets exist in 'secrets' the agent that provided them * 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 = validate_secret_flags (nm_settings_connection_get_connection (self), secrets, &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. @@ -1194,7 +1071,6 @@ get_secrets_done_cb (NMAgentManager *manager, call_id, local->message); } - g_variant_unref (filtered_secrets); } else { _LOGD ("(%s:%p) failed to update with existing secrets: %s", setting_name, @@ -1218,11 +1094,10 @@ get_secrets_done_cb (NMAgentManager *manager, nm_connection_clear_secrets (applied_connection); if (!dict || nm_connection_update_secrets (applied_connection, setting_name, dict, NULL)) { - GVariant *filtered_secrets; + gs_unref_variant GVariant *filtered_secrets = NULL; - filtered_secrets = for_each_secret (applied_connection, secrets, TRUE, validate_secret_flags, &cmp_flags); + filtered_secrets = validate_secret_flags (applied_connection, secrets, &cmp_flags); nm_connection_update_secrets (applied_connection, setting_name, filtered_secrets, NULL); - g_variant_unref (filtered_secrets); } }