settings: preserve agent secrets the right way

What we want to do here is keep separate caches of system and
agent secrets.  For system secrets, we cache them because NM
periodically clears secrets using nm_connection_clear_secrets() to
ensure they don't stay around in memory, and that transient secrets
get requested again when they are needed.  For agent secrets, we
only want them during activation, but a connection read from disk
will not include agent secrets becuase by definition they aren't
stored in system settings along with the connection.  Thus we need
to keep the agent/transient secrets somewhere for the duration of
the activation to ensure they don't get deleted.

This removes the copy-back hack in update_auth_cb() which copied
agent/transient secrets back into the connection over top of the
transient secrets that had been copied back in
nm_settings_connection_replace_settings().  No reason to copy
them twice if we keep an agent/transient secrets hash and do
the right thing with it.
This commit is contained in:
Dan Williams
2011-08-16 16:19:23 -05:00
parent e2d88f59e6
commit 2b2404bbef
8 changed files with 297 additions and 170 deletions

View File

@@ -69,7 +69,7 @@ libnm_util_la_LIBADD = $(GLIB_LIBS) $(DBUS_LIBS) $(UUID_LIBS)
SYMBOL_VIS_FILE=$(srcdir)/libnm-util.ver
libnm_util_la_LDFLAGS = -Wl,--version-script=$(SYMBOL_VIS_FILE) \
-version-info "2:0:0"
-version-info "3:0:1"
if WITH_GNUTLS
libnm_util_la_SOURCES += crypto_gnutls.c

View File

@@ -2,6 +2,7 @@
global:
nm_connection_add_setting;
nm_connection_clear_secrets;
nm_connection_clear_secrets_with_flags;
nm_connection_compare;
nm_connection_create_setting;
nm_connection_diff;
@@ -162,6 +163,7 @@ global:
nm_setting_cdma_get_username;
nm_setting_cdma_new;
nm_setting_clear_secrets;
nm_setting_clear_secrets_with_flags;
nm_setting_compare;
nm_setting_connection_add_permission;
nm_setting_connection_error_get_type;

View File

@@ -127,7 +127,7 @@ enum {
enum {
SECRETS_UPDATED,
SECRETS_CLEARED,
LAST_SIGNAL
};
@@ -950,12 +950,6 @@ nm_connection_need_secrets (NMConnection *connection,
return name;
}
static void
clear_setting_secrets (gpointer key, gpointer data, gpointer user_data)
{
nm_setting_clear_secrets (NM_SETTING (data));
}
/**
* nm_connection_clear_secrets:
* @connection: the #NMConnection
@@ -966,12 +960,42 @@ clear_setting_secrets (gpointer key, gpointer data, gpointer user_data)
void
nm_connection_clear_secrets (NMConnection *connection)
{
NMConnectionPrivate *priv;
GHashTableIter iter;
NMSetting *setting;
g_return_if_fail (NM_IS_CONNECTION (connection));
priv = NM_CONNECTION_GET_PRIVATE (connection);
g_hash_table_foreach (priv->settings, clear_setting_secrets, NULL);
g_hash_table_iter_init (&iter, NM_CONNECTION_GET_PRIVATE (connection)->settings);
while (g_hash_table_iter_next (&iter, NULL, (gpointer) &setting))
nm_setting_clear_secrets (setting);
g_signal_emit (connection, signals[SECRETS_CLEARED], 0);
}
/**
* nm_connection_clear_secrets_with_flags:
* @connection: the #NMConnection
* @func: function to be called to determine whether a specific secret should be
* cleared or not
* @user_data: caller-supplied data passed to @func
*
* Clears and frees secrets determined by @func.
**/
void
nm_connection_clear_secrets_with_flags (NMConnection *connection,
NMSettingClearSecretsWithFlagsFn func,
gpointer user_data)
{
GHashTableIter iter;
NMSetting *setting;
g_return_if_fail (NM_IS_CONNECTION (connection));
g_hash_table_iter_init (&iter, NM_CONNECTION_GET_PRIVATE (connection)->settings);
while (g_hash_table_iter_next (&iter, NULL, (gpointer) &setting))
nm_setting_clear_secrets_with_flags (setting, func, user_data);
g_signal_emit (connection, signals[SECRETS_CLEARED], 0);
}
/**
@@ -1609,5 +1633,20 @@ nm_connection_class_init (NMConnectionClass *klass)
g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE, 1,
G_TYPE_STRING);
/**
* NMConnection::secrets-cleared:
* @connection: the object on which the signal is emitted
*
* The ::secrets-cleared signal is emitted when the secrets of a connection
* are cleared.
*/
signals[SECRETS_CLEARED] =
g_signal_new ("secrets-cleared",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
0, NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}

View File

@@ -147,6 +147,10 @@ const char * nm_connection_need_secrets (NMConnection *connection,
void nm_connection_clear_secrets (NMConnection *connection);
void nm_connection_clear_secrets_with_flags (NMConnection *connection,
NMSettingClearSecretsWithFlagsFn func,
gpointer user_data);
gboolean nm_connection_update_secrets (NMConnection *connection,
const char *setting_name,
GHashTable *setting_secrets,

View File

@@ -611,6 +611,30 @@ compare_property (NMSetting *setting,
return same;
}
static void
clear_secrets_with_flags (NMSetting *setting,
GParamSpec *pspec,
NMSettingClearSecretsWithFlagsFn func,
gpointer user_data)
{
NMSettingVPNPrivate *priv = NM_SETTING_VPN_GET_PRIVATE (setting);
GHashTableIter iter;
const char *secret;
if (priv->secrets == NULL)
return;
/* Iterate through secrets hash and check each entry */
g_hash_table_iter_init (&iter, priv->secrets);
while (g_hash_table_iter_next (&iter, (gpointer) &secret, NULL)) {
NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
nm_setting_get_secret_flags (setting, secret, &flags, NULL);
if (func (setting, pspec->name, flags, user_data) == TRUE)
g_hash_table_iter_remove (&iter);
}
}
static void
destroy_one_secret (gpointer data)
{
@@ -733,6 +757,7 @@ nm_setting_vpn_class_init (NMSettingVPNClass *setting_class)
parent_class->set_secret_flags = set_secret_flags;
parent_class->need_secrets = need_secrets;
parent_class->compare_property = compare_property;
parent_class->clear_secrets_with_flags = clear_secrets_with_flags;
/* Properties */
/**

View File

@@ -648,6 +648,60 @@ nm_setting_clear_secrets (NMSetting *setting)
g_free (property_specs);
}
static void
clear_secrets_with_flags (NMSetting *setting,
GParamSpec *pspec,
NMSettingClearSecretsWithFlagsFn func,
gpointer user_data)
{
GValue value = { 0 };
NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
/* Clear the secret if the user function says to do so */
nm_setting_get_secret_flags (setting, pspec->name, &flags, NULL);
if (func (setting, pspec->name, flags, user_data) == TRUE) {
g_value_init (&value, pspec->value_type);
g_param_value_set_default (pspec, &value);
g_object_set_property (G_OBJECT (setting), pspec->name, &value);
g_value_unset (&value);
}
}
/**
* nm_setting_clear_secrets_with_flags:
* @setting: the #NMSetting
* @func: function to be called to determine whether a specific secret should be
* cleared or not
* @user_data: caller-supplied data passed to @func
*
* Clears and frees secrets determined by @func.
**/
void
nm_setting_clear_secrets_with_flags (NMSetting *setting,
NMSettingClearSecretsWithFlagsFn func,
gpointer user_data)
{
GParamSpec **property_specs;
guint n_property_specs;
guint i;
g_return_if_fail (setting);
g_return_if_fail (NM_IS_SETTING (setting));
g_return_if_fail (func != NULL);
property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (setting), &n_property_specs);
for (i = 0; i < n_property_specs; i++) {
if (property_specs[i]->flags & NM_SETTING_PARAM_SECRET) {
NM_SETTING_GET_CLASS (setting)->clear_secrets_with_flags (setting,
property_specs[i],
func,
user_data);
}
}
g_free (property_specs);
}
/**
* nm_setting_need_secrets:
* @setting: the #NMSetting
@@ -1029,6 +1083,7 @@ nm_setting_class_init (NMSettingClass *setting_class)
setting_class->get_secret_flags = get_secret_flags;
setting_class->set_secret_flags = set_secret_flags;
setting_class->compare_property = compare_property;
setting_class->clear_secrets_with_flags = clear_secrets_with_flags;
/* Properties */

View File

@@ -150,6 +150,21 @@ typedef struct {
GObject parent;
} NMSetting;
/**
* NMSettingClearSecretsWithFlagsFn:
* @setting: The setting for which secrets are being iterated
* @secret: The secret's name
* @flags: The secret's flags, eg %NM_SETTING_SECRET_FLAG_AGENT_OWNED
* @user_data: User data passed to nm_connection_clear_secrets_with_flags()
*
* Returns: %TRUE to clear the secret, %FALSE to not clear the secret
*/
typedef gboolean (*NMSettingClearSecretsWithFlagsFn) (NMSetting *setting,
const char *secret,
NMSettingSecretFlags flags,
gpointer user_data);
typedef struct {
GObjectClass parent;
@@ -183,10 +198,14 @@ typedef struct {
const GParamSpec *prop_spec,
NMSettingCompareFlags flags);
void (*clear_secrets_with_flags) (NMSetting *setting,
GParamSpec *pspec,
NMSettingClearSecretsWithFlagsFn func,
gpointer user_data);
/* Padding for future expansion */
void (*_reserved1) (void);
void (*_reserved2) (void);
void (*_reserved3) (void);
} NMSettingClass;
/**
@@ -269,6 +288,11 @@ char *nm_setting_to_string (NMSetting *setting);
/* Secrets */
void nm_setting_clear_secrets (NMSetting *setting);
void nm_setting_clear_secrets_with_flags (NMSetting *setting,
NMSettingClearSecretsWithFlagsFn func,
gpointer user_data);
GPtrArray *nm_setting_need_secrets (NMSetting *setting);
gboolean nm_setting_update_secrets (NMSetting *setting,
GHashTable *secrets,

View File

@@ -84,16 +84,28 @@ typedef struct {
NMDBusManager *dbus_mgr;
NMAgentManager *agent_mgr;
GSList *pending_auths; /* List of pending authentication requests */
NMConnection *secrets;
gboolean visible; /* Is this connection is visible by some session? */
GSList *reqs; /* in-progress secrets requests */
NMSessionMonitor *session_monitor;
guint session_changed_id;
GSList *pending_auths; /* List of pending authentication requests */
gboolean visible; /* Is this connection is visible by some session? */
GSList *reqs; /* in-progress secrets requests */
/* Caches secrets from on-disk connections; were they not cached any
* call to nm_connection_clear_secrets() wipes them out and we'd have
* to re-read them from disk which defeats the purpose of having the
* connection in-memory at all.
*/
NMConnection *system_secrets;
/* Caches secrets from agents during the activation process; if new system
* secrets are returned from an agent, they get written out to disk,
* triggering a re-read of the connection, which reads only system
* secrets, and would wipe out any agent-owned or not-saved secrets the
* agent also returned.
*/
NMConnection *agent_secrets;
guint64 timestamp; /* Up-to-date timestamp of connection use */
GHashTable *seen_bssids; /* Up-to-date BSSIDs that's been seen for the connection */
} NMSettingsConnectionPrivate;
@@ -294,57 +306,67 @@ nm_settings_connection_check_permission (NMSettingsConnection *self,
/**************************************************************/
static void
only_system_secrets_cb (NMSetting *setting,
const char *key,
const GValue *value,
GParamFlags flags,
gpointer user_data)
static gboolean
secrets_filter_cb (NMSetting *setting,
const char *secret,
NMSettingSecretFlags flags,
gpointer user_data)
{
if (flags & NM_SETTING_PARAM_SECRET) {
NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE;
NMSettingSecretFlags filter_flags = GPOINTER_TO_UINT (user_data);
/* VPNs are special; need to handle each secret separately */
if (NM_IS_SETTING_VPN (setting) && !strcmp (key, NM_SETTING_VPN_SECRETS)) {
GHashTableIter iter;
const char *secret_name = NULL;
/* Returns TRUE to remove the secret */
g_hash_table_iter_init (&iter, (GHashTable *) g_value_get_boxed (value));
while (g_hash_table_iter_next (&iter, (gpointer *) &secret_name, NULL)) {
secret_flags = NM_SETTING_SECRET_FLAG_NONE;
nm_setting_get_secret_flags (setting, secret_name, &secret_flags, NULL);
if (secret_flags != NM_SETTING_SECRET_FLAG_NONE)
nm_setting_vpn_remove_secret (NM_SETTING_VPN (setting), secret_name);
}
} else {
nm_setting_get_secret_flags (setting, key, &secret_flags, NULL);
if (secret_flags != NM_SETTING_SECRET_FLAG_NONE)
g_object_set (G_OBJECT (setting), key, NULL, NULL);
}
}
/* Can't use bitops with SECRET_FLAG_NONE so handle that specifically */
if ( (flags == NM_SETTING_SECRET_FLAG_NONE)
&& (filter_flags == NM_SETTING_SECRET_FLAG_NONE))
return FALSE;
/* Otherwise if the secret has at least one of the desired flags keep it */
return (flags & filter_flags) ? FALSE : TRUE;
}
static void
update_secrets_cache (NMSettingsConnection *self)
update_system_secrets_cache (NMSettingsConnection *self)
{
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
if (priv->secrets)
g_object_unref (priv->secrets);
priv->secrets = nm_connection_duplicate (NM_CONNECTION (self));
if (priv->system_secrets)
g_object_unref (priv->system_secrets);
priv->system_secrets = nm_connection_duplicate (NM_CONNECTION (self));
/* Clear out non-system-owned and not-saved secrets */
nm_connection_for_each_setting_value (priv->secrets, only_system_secrets_cb, NULL);
nm_connection_clear_secrets_with_flags (priv->system_secrets,
secrets_filter_cb,
GUINT_TO_POINTER (NM_SETTING_SECRET_FLAG_NONE));
}
static gboolean
clear_system_secrets (GHashTableIter *iter,
NMSettingSecretFlags flags,
gpointer user_data)
static void
update_agent_secrets_cache (NMSettingsConnection *self, NMConnection *new)
{
if (flags == NM_SETTING_SECRET_FLAG_NONE)
g_hash_table_iter_remove (iter);
return TRUE;
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
NMSettingSecretFlags filter_flags = NM_SETTING_SECRET_FLAG_NOT_SAVED | NM_SETTING_SECRET_FLAG_AGENT_OWNED;
if (priv->agent_secrets)
g_object_unref (priv->agent_secrets);
priv->agent_secrets = nm_connection_duplicate (new ? new : NM_CONNECTION (self));
/* Clear out non-system-owned secrets */
nm_connection_clear_secrets_with_flags (priv->agent_secrets,
secrets_filter_cb,
GUINT_TO_POINTER (filter_flags));
}
static void
secrets_cleared_cb (NMSettingsConnection *self)
{
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
/* Clear agent secrets when connection's secrets are cleared since agent
* secrets are transient.
*/
if (priv->agent_secrets)
g_object_unref (priv->agent_secrets);
priv->agent_secrets = NULL;
}
/* Update the settings of this connection to match that of 'new', taking care to
@@ -356,7 +378,7 @@ nm_settings_connection_replace_settings (NMSettingsConnection *self,
GError **error)
{
NMSettingsConnectionPrivate *priv;
GHashTable *new_settings, *transient_secrets;
GHashTable *new_settings, *hash = NULL;
gboolean success = FALSE;
g_return_val_if_fail (self != NULL, FALSE);
@@ -366,37 +388,29 @@ nm_settings_connection_replace_settings (NMSettingsConnection *self,
priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
/* Replacing the settings might replace transient secrets, such as when
* a user agent returns secrets, which might trigger the connection to be
* written out, which triggers an inotify event to re-read and update the
* connection, which, if we're not careful, could wipe out the transient
* secrets the user agent just sent us. Basically, only
* nm_connection_clear_secrets() should wipe out transient secrets but
* re-reading a connection from on-disk and updating our in-memory copy
* should not. Thus we preserve non-system-owned secrets here.
*/
transient_secrets = nm_connection_to_hash (NM_CONNECTION (self), NM_SETTING_HASH_FLAG_ONLY_SECRETS);
if (transient_secrets)
for_each_secret (NM_CONNECTION (self), transient_secrets, clear_system_secrets, NULL);
new_settings = nm_connection_to_hash (new, NM_SETTING_HASH_FLAG_ALL);
g_assert (new_settings);
if (nm_connection_replace_settings (NM_CONNECTION (self), new_settings, error)) {
/* Copy the connection to keep its secrets around even if NM
* calls nm_connection_clear_secrets().
/* Cache the just-updated system secrets in case something calls
* nm_connection_clear_secrets() and clears them.
*/
update_secrets_cache (self);
update_system_secrets_cache (self);
success = TRUE;
/* And add the transient secrets back */
if (transient_secrets)
nm_connection_update_secrets (NM_CONNECTION (self), NULL, transient_secrets, NULL);
/* Add agent and always-ask secrets back; they won't necessarily be
* in the replacement connection data if it was eg reread from disk.
*/
if (priv->agent_secrets) {
hash = nm_connection_to_hash (priv->agent_secrets, NM_SETTING_HASH_FLAG_ONLY_SECRETS);
if (hash) {
success = nm_connection_update_secrets (NM_CONNECTION (self), NULL, hash, error);
g_hash_table_destroy (hash);
}
}
nm_settings_connection_recheck_visibility (self);
success = TRUE;
}
g_hash_table_destroy (new_settings);
if (transient_secrets)
g_hash_table_destroy (transient_secrets);
return success;
}
@@ -719,7 +733,7 @@ agent_secrets_done_cb (NMAgentManager *manager,
/* Update the connection with our existing secrets from backing storage */
nm_connection_clear_secrets (NM_CONNECTION (self));
hash = nm_connection_to_hash (priv->secrets, NM_SETTING_HASH_FLAG_ONLY_SECRETS);
hash = nm_connection_to_hash (priv->system_secrets, NM_SETTING_HASH_FLAG_ONLY_SECRETS);
if (!hash || nm_connection_update_secrets (NM_CONNECTION (self), setting_name, hash, &local)) {
/* Update the connection with the agent's secrets; by this point if any
* system-owned secrets exist in 'secrets' the agent that provided them
@@ -730,7 +744,8 @@ agent_secrets_done_cb (NMAgentManager *manager,
/* Now that all secrets are updated, copy and cache new secrets,
* then save them to backing storage.
*/
update_secrets_cache (self);
update_system_secrets_cache (self);
update_agent_secrets_cache (self, NULL);
/* Only save secrets to backing storage if the agent returned any
* new system secrets. If it didn't, then the secrets are agent-
@@ -807,11 +822,9 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self,
guint32 call_id = 0;
/* Use priv->secrets to work around the fact that nm_connection_clear_secrets()
* will clear secrets on this object's settings. priv->secrets should be
* a complete copy of this object and kept in sync by
* nm_settings_connection_replace_settings().
* will clear secrets on this object's settings.
*/
if (!priv->secrets) {
if (!priv->system_secrets) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"%s.%d - Internal error; secrets cache invalid.",
__FILE__, __LINE__);
@@ -826,7 +839,7 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self,
return 0;
}
existing_secrets = nm_connection_to_hash (priv->secrets, NM_SETTING_HASH_FLAG_ONLY_SECRETS);
existing_secrets = nm_connection_to_hash (priv->system_secrets, NM_SETTING_HASH_FLAG_ONLY_SECRETS);
call_id = nm_agent_manager_get_secrets (priv->agent_mgr,
NM_CONNECTION (self),
filter_by_uid,
@@ -1084,47 +1097,40 @@ impl_settings_connection_get_settings (NMSettingsConnection *self,
auth_start (self, context, NULL, get_settings_auth_cb, NULL);
}
typedef struct {
DBusGMethodInvocation *context;
NMAgentManager *agent_mgr;
gulong sender_uid;
} UpdateInfo;
static void
con_update_cb (NMSettingsConnection *connection,
con_update_cb (NMSettingsConnection *self,
GError *error,
gpointer user_data)
{
DBusGMethodInvocation *context = user_data;
UpdateInfo *info = user_data;
NMConnection *for_agent;
if (error)
dbus_g_method_return_error (context, error);
else
dbus_g_method_return (context);
}
dbus_g_method_return_error (info->context, error);
else {
/* Dupe the connection so we can clear out non-agent-owned secrets,
* as agent-owned secrets are the only ones we send back be saved.
* Only send secrets to agents of the same UID that called update too.
*/
for_agent = nm_connection_duplicate (NM_CONNECTION (self));
nm_connection_clear_secrets_with_flags (for_agent,
secrets_filter_cb,
GUINT_TO_POINTER (NM_SETTING_SECRET_FLAG_AGENT_OWNED));
nm_agent_manager_save_secrets (info->agent_mgr, for_agent, TRUE, info->sender_uid);
g_object_unref (for_agent);
static void
secrets_filter_cb (NMSetting *setting,
const char *key,
const GValue *value,
GParamFlags flags,
gpointer user_data)
{
NMSettingSecretFlags filter_flags = GPOINTER_TO_UINT (user_data);
NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE;
const char *secret_name = NULL;
GHashTableIter iter;
if (flags & NM_SETTING_PARAM_SECRET) {
if (NM_IS_SETTING_VPN (setting) && !strcmp (key, NM_SETTING_VPN_SECRETS)) {
/* VPNs are special; need to handle each secret separately */
g_hash_table_iter_init (&iter, (GHashTable *) g_value_get_boxed (value));
while (g_hash_table_iter_next (&iter, (gpointer) &secret_name, NULL)) {
secret_flags = NM_SETTING_SECRET_FLAG_NONE;
nm_setting_get_secret_flags (setting, secret_name, &secret_flags, NULL);
if (!(secret_flags & filter_flags))
nm_setting_vpn_remove_secret (NM_SETTING_VPN (setting), secret_name);
}
} else {
nm_setting_get_secret_flags (setting, key, &secret_flags, NULL);
if (!(secret_flags & filter_flags))
g_object_set (G_OBJECT (setting), key, NULL, NULL);
}
dbus_g_method_return (info->context);
}
g_object_unref (info->agent_mgr);
memset (info, 0, sizeof (*info));
g_free (info);
}
static void
@@ -1136,54 +1142,27 @@ update_auth_cb (NMSettingsConnection *self,
{
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
NMConnection *new_settings = data;
NMConnection *for_agent, *dup;
NMSettingSecretFlags filter_flags;
GHashTable *hash;
GError *local = NULL;
UpdateInfo *info;
if (error)
dbus_g_method_return_error (context, error);
else {
/* Cache the new secrets since they may get overwritten by the replace
* when transient secrets are copied back.
info = g_malloc0 (sizeof (*info));
info->context = context;
info->agent_mgr = g_object_ref (priv->agent_mgr);
info->sender_uid = sender_uid;
/* Cache the new secrets from the agent, as stuff like inotify-triggered
* changes to connection's backing config files will blow them away if
* they're in the main connection.
*/
dup = nm_connection_duplicate (new_settings);
update_agent_secrets_cache (self, new_settings);
/* Update and commit our settings. */
nm_settings_connection_replace_and_commit (self,
new_settings,
con_update_cb,
context);
/* Copy new agent secrets back to the connection */
filter_flags = NM_SETTING_SECRET_FLAG_AGENT_OWNED | NM_SETTING_SECRET_FLAG_NOT_SAVED;
nm_connection_for_each_setting_value (dup,
secrets_filter_cb,
GUINT_TO_POINTER (filter_flags));
hash = nm_connection_to_hash (dup, NM_SETTING_HASH_FLAG_ONLY_SECRETS);
g_object_unref (dup);
if (hash) {
if (!nm_connection_update_secrets (NM_CONNECTION (self), NULL, hash, &local)) {
nm_log_warn (LOGD_SETTINGS, "Failed to update connection secrets: (%d) %s",
local ? local->code : -1,
local && local->message ? local->message : "(unknown)");
g_clear_error (&local);
}
g_hash_table_destroy (hash);
}
/* Dupe the connection and clear out non-agent-owned secrets so we can
* send the agent-owned ones to agents to be saved. Only send them to
* agents of the same UID as the Update() request sender.
*/
for_agent = nm_connection_duplicate (NM_CONNECTION (self));
filter_flags = NM_SETTING_SECRET_FLAG_AGENT_OWNED;
nm_connection_for_each_setting_value (for_agent,
secrets_filter_cb,
GUINT_TO_POINTER (filter_flags));
nm_agent_manager_save_secrets (priv->agent_mgr, for_agent, TRUE, sender_uid);
g_object_unref (for_agent);
new_settings,
con_update_cb,
info);
}
g_object_unref (new_settings);
@@ -1345,16 +1324,11 @@ dbus_get_agent_secrets_cb (NMSettingsConnection *self,
if (error)
dbus_g_method_return_error (context, error);
else {
/* The connection's secrets will have been updated by the agent manager,
* so we want to refresh the secrets cache. Note that we will never save
* new secrets to backing storage here because D-Bus initated requests will
* never ask for completely new secrets from agents. Thus system-owned
* secrets should not have changed from backing storage. We also don't
* send agent-owned secrets back out to be saved since we assume the agent
* that provided the secrets saved them itself.
/* Return secrets from agent and backing storage to the D-Bus caller;
* nm_settings_connection_get_secrets() will have updated itself with
* secrets from backing storage and those returned from the agent
* by the time we get here.
*/
update_secrets_cache (self);
hash = nm_connection_to_hash (NM_CONNECTION (self), NM_SETTING_HASH_FLAG_ONLY_SECRETS);
if (!hash)
hash = g_hash_table_new (NULL, NULL);
@@ -1726,6 +1700,8 @@ nm_settings_connection_init (NMSettingsConnection *self)
priv->agent_mgr = nm_agent_manager_get ();
priv->seen_bssids = g_hash_table_new_full (mac_hash, mac_equal, g_free, g_free);
g_signal_connect (self, "secrets-cleared", G_CALLBACK (secrets_cleared_cb), NULL);
}
static void
@@ -1739,8 +1715,10 @@ dispose (GObject *object)
goto out;
priv->disposed = TRUE;
if (priv->secrets)
g_object_unref (priv->secrets);
if (priv->system_secrets)
g_object_unref (priv->system_secrets);
if (priv->agent_secrets)
g_object_unref (priv->agent_secrets);
/* Cancel PolicyKit requests */
for (iter = priv->pending_auths; iter; iter = g_slist_next (iter))