summaryrefslogtreecommitdiff
path: root/src/settings/nm-settings-connection.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/settings/nm-settings-connection.c')
-rw-r--r--src/settings/nm-settings-connection.c204
1 files changed, 138 insertions, 66 deletions
diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c
index 22aef7161..60de6b068 100644
--- a/src/settings/nm-settings-connection.c
+++ b/src/settings/nm-settings-connection.c
@@ -34,7 +34,6 @@
#include "nm-dbus-manager.h"
#include "nm-settings-error.h"
#include "nm-dbus-glib-types.h"
-#include "nm-polkit-helpers.h"
#include "nm-logging.h"
#include "nm-manager-auth.h"
#include "nm-marshal.h"
@@ -83,7 +82,6 @@ typedef struct {
NMDBusManager *dbus_mgr;
NMAgentManager *agent_mgr;
- PolkitAuthority *authority;
GSList *pending_auths; /* List of pending authentication requests */
NMConnection *secrets;
gboolean visible; /* Is this connection is visible by some session? */
@@ -98,6 +96,83 @@ typedef struct {
/**************************************************************/
+/* Return TRUE to continue, FALSE to stop */
+typedef gboolean (*ForEachSecretFunc) (GHashTableIter *iter,
+ NMSettingSecretFlags flags,
+ gpointer user_data);
+
+static void
+for_each_secret (NMConnection *connection,
+ GHashTable *secrets,
+ ForEachSecretFunc callback,
+ gpointer callback_data)
+{
+ GHashTableIter iter;
+ const char *setting_name;
+ GHashTable *setting_hash;
+
+ /* This function, given a hash of hashes representing new secrets of
+ * an NMConnection, walks through each toplevel hash (which represents a
+ * NMSetting), and for each setting, walks through that setting hash'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 hash table (since the key/value pairs are arbitrary and known
+ * only to the VPN plugin itself). That means we have three levels of
+ * GHashTables 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' hash table, calling the supplied callback
+ * each time.
+ */
+
+ /* Walk through the list of setting hashes */
+ g_hash_table_iter_init (&iter, secrets);
+ while (g_hash_table_iter_next (&iter, (gpointer) &setting_name, (gpointer) &setting_hash)) {
+ NMSetting *setting;
+ GHashTableIter secret_iter;
+ const char *secret_name;
+ GValue *val;
+
+ /* Get the actual NMSetting from the connection so we can get secret flags
+ * from the connection data, since flags aren't secrets. What we're
+ * iterating here is just the secrets, not a whole connection.
+ */
+ setting = nm_connection_get_setting_by_name (connection, setting_name);
+ if (setting == NULL)
+ continue;
+
+ /* Walk through the list of keys in each setting hash */
+ g_hash_table_iter_init (&secret_iter, setting_hash);
+ while (g_hash_table_iter_next (&secret_iter, (gpointer) &secret_name, (gpointer) &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) == 0)) {
+ GHashTableIter vpn_secrets_iter;
+
+ /* Iterate through each secret from the VPN hash in the overall secrets hash */
+ g_hash_table_iter_init (&vpn_secrets_iter, g_value_get_boxed (val));
+ while (g_hash_table_iter_next (&vpn_secrets_iter, (gpointer) &secret_name, NULL)) {
+ secret_flags = NM_SETTING_SECRET_FLAG_NONE;
+ nm_setting_get_secret_flags (setting, secret_name, &secret_flags, NULL);
+ if (callback (&vpn_secrets_iter, secret_flags, callback_data) == FALSE)
+ return;
+ }
+ } else {
+ nm_setting_get_secret_flags (setting, secret_name, &secret_flags, NULL);
+ if (callback (&secret_iter, secret_flags, callback_data) == FALSE)
+ return;
+ }
+ }
+ }
+}
+
+/**************************************************************/
+
static void
set_visible (NMSettingsConnection *self, gboolean new_visible)
{
@@ -112,7 +187,8 @@ set_visible (NMSettingsConnection *self, gboolean new_visible)
gboolean
nm_settings_connection_is_visible (NMSettingsConnection *self)
{
- g_return_val_if_fail (NM_SETTINGS_CONNECTION (self), FALSE);
+ g_return_val_if_fail (self != NULL, FALSE);
+ g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), FALSE);
return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->visible;
}
@@ -124,7 +200,8 @@ nm_settings_connection_recheck_visibility (NMSettingsConnection *self)
NMSettingConnection *s_con;
guint32 num, i;
- g_return_if_fail (NM_SETTINGS_CONNECTION (self));
+ g_return_if_fail (self != NULL);
+ g_return_if_fail (NM_IS_SETTINGS_CONNECTION (self));
priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
@@ -178,10 +255,10 @@ only_system_secrets_cb (NMSetting *setting,
g_hash_table_iter_init (&iter, (GHashTable *) g_value_get_boxed (value));
while (g_hash_table_iter_next (&iter, (gpointer *) &secret_name, NULL)) {
- if (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);
- }
+ 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);
@@ -204,15 +281,26 @@ update_secrets_cache (NMSettingsConnection *self)
nm_connection_for_each_setting_value (priv->secrets, only_system_secrets_cb, NULL);
}
+static gboolean
+clear_system_secrets (GHashTableIter *iter,
+ NMSettingSecretFlags flags,
+ gpointer user_data)
+{
+ if (flags == NM_SETTING_SECRET_FLAG_NONE)
+ g_hash_table_iter_remove (iter);
+ return TRUE;
+}
+
/* Update the settings of this connection to match that of 'new', taking care to
- * make a private copy of secrets. */
+ * make a private copy of secrets.
+ */
gboolean
nm_settings_connection_replace_settings (NMSettingsConnection *self,
NMConnection *new,
GError **error)
{
NMSettingsConnectionPrivate *priv;
- GHashTable *new_settings;
+ GHashTable *new_settings, *transient_secrets;
gboolean success = FALSE;
g_return_val_if_fail (self != NULL, FALSE);
@@ -222,18 +310,48 @@ 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)) {
+ GHashTableIter iter;
+ NMSetting *setting;
+ const char *setting_name;
+ GHashTable *setting_hash;
+
/* Copy the connection to keep its secrets around even if NM
* calls nm_connection_clear_secrets().
*/
update_secrets_cache (self);
+ /* And add the transient secrets back */
+ if (transient_secrets) {
+ g_hash_table_iter_init (&iter, transient_secrets);
+ while (g_hash_table_iter_next (&iter, (gpointer) &setting_name, (gpointer) &setting_hash)) {
+ setting = nm_connection_get_setting_by_name (NM_CONNECTION (self), setting_name);
+ if (setting)
+ nm_setting_update_secrets (setting, setting_hash, NULL);
+ }
+ }
+
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;
}
@@ -398,11 +516,6 @@ supports_secrets (NMSettingsConnection *connection, const char *setting_name)
return TRUE;
}
-/* Return TRUE to continue, FALSE to stop */
-typedef gboolean (*ForEachSecretFunc) (GHashTableIter *iter,
- NMSettingSecretFlags flags,
- gpointer user_data);
-
static gboolean
clear_nonagent_secrets (GHashTableIter *iter,
NMSettingSecretFlags flags,
@@ -430,7 +543,7 @@ has_system_owned_secrets (GHashTableIter *iter,
{
gboolean *has_system_owned = user_data;
- if (!(flags & NM_SETTING_SECRET_FLAG_AGENT_OWNED)) {
+ if (flags == NM_SETTING_SECRET_FLAG_NONE) {
*has_system_owned = TRUE;
return FALSE;
}
@@ -438,40 +551,6 @@ has_system_owned_secrets (GHashTableIter *iter,
}
static void
-for_each_secret (NMConnection *connection,
- GHashTable *secrets,
- ForEachSecretFunc callback,
- gpointer callback_data)
-{
- GHashTableIter iter;
- const char *setting_name;
- GHashTable *setting_hash;
-
- /* Walk through the list of setting hashes */
- g_hash_table_iter_init (&iter, secrets);
- while (g_hash_table_iter_next (&iter,
- (gpointer *) &setting_name,
- (gpointer *) &setting_hash)) {
- GHashTableIter setting_iter;
- const char *secret_name;
-
- /* Walk through the list of keys in each setting hash */
- g_hash_table_iter_init (&setting_iter, setting_hash);
- while (g_hash_table_iter_next (&setting_iter, (gpointer *) &secret_name, NULL)) {
- NMSetting *setting;
- NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
-
- /* Get the actual NMSetting from the connection so we can get secret flags */
- setting = nm_connection_get_setting_by_name (connection, setting_name);
- if (setting && nm_setting_get_secret_flags (setting, secret_name, &flags, NULL)) {
- if (callback (&setting_iter, flags, callback_data) == FALSE)
- return;
- }
- }
- }
-}
-
-static void
new_secrets_commit_cb (NMSettingsConnection *connection,
GError *error,
gpointer user_data)
@@ -850,7 +929,7 @@ auth_start (NMSettingsConnection *self,
}
if (check_permission) {
- chain = nm_auth_chain_new (priv->authority, context, NULL, pk_auth_cb, self);
+ chain = nm_auth_chain_new (context, NULL, pk_auth_cb, self);
g_assert (chain);
nm_auth_chain_set_data (chain, "perm", (gpointer) check_permission, NULL);
nm_auth_chain_set_data (chain, "callback", callback, NULL);
@@ -980,10 +1059,10 @@ only_agent_secrets_cb (NMSetting *setting,
/* 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)) {
- if (nm_setting_get_secret_flags (setting, secret_name, &secret_flags, NULL)) {
- if (secret_flags != NM_SETTING_SECRET_FLAG_AGENT_OWNED)
- nm_setting_vpn_remove_secret (NM_SETTING_VPN (setting), secret_name);
- }
+ 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_AGENT_OWNED)
+ nm_setting_vpn_remove_secret (NM_SETTING_VPN (setting), secret_name);
}
} else {
nm_setting_get_secret_flags (setting, key, &secret_flags, NULL);
@@ -1271,7 +1350,8 @@ nm_settings_connection_signal_remove (NMSettingsConnection *self)
guint64
nm_settings_connection_get_timestamp (NMSettingsConnection *connection)
{
- g_return_val_if_fail (NM_SETTINGS_CONNECTION (connection), 0);
+ g_return_val_if_fail (connection != NULL, 0);
+ g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (connection), 0);
return NM_SETTINGS_CONNECTION_GET_PRIVATE (connection)->timestamp;
}
@@ -1368,18 +1448,9 @@ nm_settings_connection_init (NMSettingsConnection *self)
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
static guint32 dbus_counter = 0;
char *dbus_path;
- GError *error = NULL;
priv->dbus_mgr = nm_dbus_manager_get ();
- priv->authority = polkit_authority_get_sync (NULL, &error);
- if (!priv->authority) {
- nm_log_warn (LOGD_SETTINGS, "failed to create PolicyKit authority: (%d) %s",
- error ? error->code : -1,
- error && error->message ? error->message : "(unknown)");
- g_clear_error (&error);
- }
-
dbus_path = g_strdup_printf ("%s/%u", NM_DBUS_PATH_SETTINGS, dbus_counter++);
nm_connection_set_path (NM_CONNECTION (self), dbus_path);
g_free (dbus_path);
@@ -1421,10 +1492,11 @@ dispose (GObject *object)
set_visible (self, FALSE);
+ if (priv->session_changed_id)
+ g_signal_handler_disconnect (priv->session_monitor, priv->session_changed_id);
g_object_unref (priv->session_monitor);
g_object_unref (priv->agent_mgr);
g_object_unref (priv->dbus_mgr);
- g_object_unref (priv->authority);
out:
G_OBJECT_CLASS (nm_settings_connection_parent_class)->dispose (object);