Commit 2b2404bb authored by Dan Williams's avatar Dan Williams

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.
parent e2d88f59
......@@ -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
......
......@@ -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;
......
......@@ -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);
}
......@@ -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,
......
......@@ -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 */
/**
......
......@@ -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 */
......
......@@ -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,
......
This diff is collapsed.
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