diff --git a/introspection/nm-secret-agent.xml b/introspection/nm-secret-agent.xml
index 8a651dd66c..9655c2b9df 100644
--- a/introspection/nm-secret-agent.xml
+++ b/introspection/nm-secret-agent.xml
@@ -18,7 +18,10 @@
Nested settings maps containing the connection for which
- secrets are being requested.
+ secrets are being requested. This may contain system-owned
+ secrets if the agent has successfully authenticated to
+ modify system network settings and the GetSecrets request
+ flags allow user interaction.
diff --git a/src/settings/nm-agent-manager.c b/src/settings/nm-agent-manager.c
index 9979c4e889..9f10dc7b4f 100644
--- a/src/settings/nm-agent-manager.c
+++ b/src/settings/nm-agent-manager.c
@@ -32,6 +32,8 @@
#include "nm-secret-agent.h"
#include "nm-manager-auth.h"
#include "nm-dbus-glib-types.h"
+#include "nm-polkit-helpers.h"
+#include "nm-manager-auth.h"
G_DEFINE_TYPE (NMAgentManager, nm_agent_manager, G_TYPE_OBJECT)
@@ -44,6 +46,7 @@ typedef struct {
NMDBusManager *dbus_mgr;
NMSessionMonitor *session_monitor;
+ PolkitAuthority *authority;
/* Hashed by owner name, not identifier, since two agents in different
* sessions can use the same identifier.
@@ -323,6 +326,7 @@ done:
typedef void (*RequestCompleteFunc) (Request *req,
GHashTable *secrets,
const char *agent_dbus_owner,
+ gboolean agent_has_modify,
GError *error,
gpointer user_data);
typedef void (*RequestNextFunc) (Request *req);
@@ -330,6 +334,8 @@ typedef void (*RequestCancelFunc) (Request *req);
struct _Request {
guint32 reqid;
+ PolkitAuthority *authority;
+ NMAuthChain *chain;
NMConnection *connection;
gboolean filter_by_uid;
@@ -341,6 +347,7 @@ struct _Request {
/* Current agent being asked for secrets */
NMSecretAgent *current;
gconstpointer current_call_id;
+ gboolean current_has_modify;
/* Stores the sorted list of NMSecretAgents which will be asked for secrets */
GSList *pending;
@@ -370,6 +377,7 @@ static guint32 next_req_id = 1;
static Request *
request_new_get (NMConnection *connection,
+ PolkitAuthority *authority,
gboolean filter_by_uid,
gulong uid_filter,
GHashTable *existing_secrets,
@@ -390,6 +398,7 @@ request_new_get (NMConnection *connection,
req = g_malloc0 (sizeof (Request));
req->reqid = next_req_id++;
req->connection = g_object_ref (connection);
+ req->authority = g_object_ref (authority);
req->filter_by_uid = filter_by_uid;
req->uid_filter = uid_filter;
if (existing_secrets)
@@ -446,6 +455,9 @@ request_free (Request *req)
g_free (req->hint);
if (req->existing_secrets)
g_hash_table_unref (req->existing_secrets);
+ if (req->chain)
+ nm_auth_chain_unref (req->chain);
+ g_object_unref (req->authority);
memset (req, 0, sizeof (Request));
g_free (req);
}
@@ -552,6 +564,7 @@ request_remove_agent (Request *req, NMSecretAgent *agent)
/* If this agent is being asked right now, cancel the request */
if (agent == req->current) {
req->cancel_callback (req);
+ req->current_has_modify = FALSE;
req->current = NULL;
req->current_call_id = NULL;
try_next = TRUE;
@@ -583,10 +596,11 @@ next_generic (Request *req, const char *detail)
error = g_error_new_literal (NM_AGENT_MANAGER_ERROR,
NM_AGENT_MANAGER_ERROR_NO_SECRETS,
"No agents were available for this request.");
- req->complete_callback (req, NULL, NULL, error, req->complete_callback_data);
+ req->complete_callback (req, NULL, NULL, FALSE, error, req->complete_callback_data);
g_error_free (error);
} else {
/* Send a secrets request to the next agent */
+ req->current_has_modify = FALSE;
req->current = req->pending->data;
req->pending = g_slist_remove (req->pending, req->current);
@@ -622,18 +636,21 @@ get_done_cb (NMSecretAgent *agent,
Request *req = user_data;
GHashTable *setting_secrets;
const char *agent_dbus_owner;
+ gboolean agent_has_modify;
g_return_if_fail (call_id == req->current_call_id);
+ agent_has_modify = req->current_has_modify;
+ req->current_has_modify = FALSE;
req->current = NULL;
req->current_call_id = NULL;
if (error) {
nm_log_dbg (LOGD_AGENTS, "(%s) agent failed secrets request %p/%s: (%d) %s",
- nm_secret_agent_get_description (agent),
- req, req->setting_name,
- error ? error->code : -1,
- (error && error->message) ? error->message : "(unknown)");
+ nm_secret_agent_get_description (agent),
+ req, req->setting_name,
+ error ? error->code : -1,
+ (error && error->message) ? error->message : "(unknown)");
/* Try the next agent */
req->next_callback (req);
@@ -644,8 +661,8 @@ get_done_cb (NMSecretAgent *agent,
setting_secrets = g_hash_table_lookup (secrets, req->setting_name);
if (!setting_secrets || !g_hash_table_size (setting_secrets)) {
nm_log_dbg (LOGD_AGENTS, "(%s) agent returned no secrets for request %p/%s",
- nm_secret_agent_get_description (agent),
- req, req->setting_name);
+ nm_secret_agent_get_description (agent),
+ req, req->setting_name);
/* Try the next agent */
req->next_callback (req);
@@ -653,21 +670,25 @@ get_done_cb (NMSecretAgent *agent,
}
nm_log_dbg (LOGD_AGENTS, "(%s) agent returned secrets for request %p/%s",
- nm_secret_agent_get_description (agent),
- req, req->setting_name);
+ nm_secret_agent_get_description (agent),
+ req, req->setting_name);
agent_dbus_owner = nm_secret_agent_get_dbus_owner (agent);
- req->complete_callback (req, secrets, agent_dbus_owner, NULL, req->complete_callback_data);
+ req->complete_callback (req, secrets, agent_dbus_owner, agent_has_modify, NULL, req->complete_callback_data);
}
static void
-get_next_cb (Request *req)
+get_agent_request_secrets (Request *req, gboolean include_system_secrets)
{
- if (!next_generic (req, "getting"))
- return;
+ NMConnection *tmp;
+
+ tmp = nm_connection_duplicate (req->connection);
+ nm_connection_clear_secrets (tmp);
+ if (include_system_secrets)
+ nm_connection_update_secrets (tmp, req->setting_name, req->existing_secrets, NULL);
req->current_call_id = nm_secret_agent_get_secrets (NM_SECRET_AGENT (req->current),
- req->connection,
+ tmp,
req->setting_name,
req->hint,
req->flags,
@@ -676,9 +697,103 @@ get_next_cb (Request *req)
if (req->current_call_id == NULL) {
/* Shouldn't hit this, but handle it anyway */
g_warn_if_fail (req->current_call_id != NULL);
+ req->current_has_modify = FALSE;
req->current = NULL;
req->next_callback (req);
}
+
+ g_object_unref (tmp);
+}
+
+static void
+get_agent_modify_auth_cb (NMAuthChain *chain,
+ GError *error,
+ DBusGMethodInvocation *context,
+ gpointer user_data)
+{
+ Request *req = user_data;
+ NMAuthCallResult result;
+
+ req->chain = NULL;
+ nm_auth_chain_unref (chain);
+
+ if (error) {
+ nm_log_dbg (LOGD_AGENTS, "(%p/%s) agent MODIFY check error: (%d) %s",
+ req, req->setting_name,
+ error->code, error->message ? error->message : "(unknown)");
+
+ /* Try the next agent */
+ req->next_callback (req);
+ } else {
+
+ /* If the agent obtained the 'modify' permission, we send all system secrets
+ * to it. If it didn't, we still ask it for secrets, but we don't send
+ * any system secrets.
+ */
+ result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_SETTINGS_CONNECTION_MODIFY);
+ if (result == NM_AUTH_CALL_RESULT_YES)
+ req->current_has_modify = TRUE;
+
+ nm_log_dbg (LOGD_AGENTS, "(%p/%s) agent MODIFY check result %d",
+ req, req->setting_name, result);
+
+ get_agent_request_secrets (req, req->current_has_modify);
+ }
+}
+
+static void
+has_system_secrets (NMSetting *setting,
+ const char *key,
+ const GValue *value,
+ GParamFlags flags,
+ gpointer user_data)
+{
+ NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_SYSTEM_OWNED;
+ gboolean *has_system = user_data;
+
+ if (flags & NM_SETTING_PARAM_SECRET) {
+ nm_setting_get_secret_flags (setting, key, &secret_flags, NULL);
+ if (secret_flags == NM_SETTING_SECRET_FLAG_SYSTEM_OWNED)
+ *has_system = TRUE;
+ }
+}
+
+static void
+get_next_cb (Request *req)
+{
+ const char *agent_dbus_owner;
+
+ if (!next_generic (req, "getting"))
+ return;
+
+ agent_dbus_owner = nm_secret_agent_get_dbus_owner (NM_SECRET_AGENT (req->current));
+
+ if (req->flags != 0) {
+ gboolean has_system = FALSE;
+
+ /* Interaction with the user is allowed; if there are any system secrets,
+ * check whether the agent has the 'modify' permission before sending those
+ * secrets to the agent.
+ */
+ nm_connection_for_each_setting_value (req->connection, has_system_secrets, &has_system);
+ if (has_system) {
+ nm_log_dbg (LOGD_AGENTS, "(%p/%s) request has system secrets; checking agent %s for MODIFY",
+ req, req->setting_name, agent_dbus_owner);
+
+ req->chain = nm_auth_chain_new_dbus_sender (req->authority,
+ agent_dbus_owner,
+ get_agent_modify_auth_cb,
+ req);
+ g_assert (req->chain);
+ nm_auth_chain_add_call (req->chain, NM_AUTH_PERMISSION_SETTINGS_CONNECTION_MODIFY, TRUE);
+ return;
+ }
+ }
+
+ nm_log_dbg (LOGD_AGENTS, "(%p/%s) requesting user-owned secrets from agent %s",
+ req, req->setting_name, agent_dbus_owner);
+
+ get_agent_request_secrets (req, FALSE);
}
static gboolean
@@ -706,20 +821,20 @@ get_start (gpointer user_data)
g_assert (tmp);
if (!nm_connection_update_secrets (tmp, req->setting_name, req->existing_secrets, &error)) {
- req->complete_callback (req, NULL, NULL, error, req->complete_callback_data);
+ req->complete_callback (req, NULL, NULL, FALSE, error, req->complete_callback_data);
g_clear_error (&error);
} else {
/* Do we have everything we need? */
/* FIXME: handle second check for VPN connections */
if (nm_connection_need_secrets (tmp, NULL) == NULL) {
nm_log_dbg (LOGD_AGENTS, "(%p/%s) system settings secrets sufficient",
- req, req->setting_name);
+ req, req->setting_name);
/* Got everything, we're done */
- req->complete_callback (req, req->existing_secrets, NULL, NULL, req->complete_callback_data);
+ req->complete_callback (req, req->existing_secrets, NULL, FALSE, NULL, req->complete_callback_data);
} else {
nm_log_dbg (LOGD_AGENTS, "(%p/%s) system settings secrets insufficient, asking agents",
- req, req->setting_name);
+ req, req->setting_name);
/* We don't, so ask some agents for additional secrets */
req->next_callback (req);
@@ -741,6 +856,7 @@ static void
get_complete_cb (Request *req,
GHashTable *secrets,
const char *agent_dbus_owner,
+ gboolean agent_has_modify,
GError *error,
gpointer user_data)
{
@@ -751,6 +867,7 @@ get_complete_cb (Request *req,
req->callback (self,
req->reqid,
agent_dbus_owner,
+ agent_has_modify,
req->setting_name,
req->flags,
error ? NULL : secrets,
@@ -797,6 +914,7 @@ nm_agent_manager_get_secrets (NMAgentManager *self,
setting_name);
req = request_new_get (connection,
+ priv->authority,
filter_by_uid,
uid_filter,
existing_secrets,
@@ -850,10 +968,10 @@ save_done_cb (NMSecretAgent *agent,
if (error) {
nm_log_dbg (LOGD_AGENTS, "(%s) agent failed save secrets request %p/%s: (%d) %s",
- nm_secret_agent_get_description (agent),
- req, req->setting_name,
- error ? error->code : -1,
- (error && error->message) ? error->message : "(unknown)");
+ nm_secret_agent_get_description (agent),
+ req, req->setting_name,
+ error ? error->code : -1,
+ (error && error->message) ? error->message : "(unknown)");
/* Try the next agent */
req->next_callback (req);
@@ -861,11 +979,11 @@ save_done_cb (NMSecretAgent *agent,
}
nm_log_dbg (LOGD_AGENTS, "(%s) agent saved secrets for request %p/%s",
- nm_secret_agent_get_description (agent),
- req, req->setting_name);
+ nm_secret_agent_get_description (agent),
+ req, req->setting_name);
agent_dbus_owner = nm_secret_agent_get_dbus_owner (agent);
- req->complete_callback (req, NULL, agent_dbus_owner, NULL, req->complete_callback_data);
+ req->complete_callback (req, NULL, agent_dbus_owner, FALSE, NULL, req->complete_callback_data);
}
static void
@@ -890,6 +1008,7 @@ static void
save_complete_cb (Request *req,
GHashTable *secrets,
const char *agent_dbus_owner,
+ gboolean agent_has_modify,
GError *error,
gpointer user_data)
{
@@ -949,14 +1068,14 @@ delete_done_cb (NMSecretAgent *agent,
if (error) {
nm_log_dbg (LOGD_AGENTS, "(%s) agent failed delete secrets request %p/%s: (%d) %s",
- nm_secret_agent_get_description (agent),
- req, req->setting_name,
- error ? error->code : -1,
- (error && error->message) ? error->message : "(unknown)");
+ nm_secret_agent_get_description (agent),
+ req, req->setting_name,
+ error ? error->code : -1,
+ (error && error->message) ? error->message : "(unknown)");
} else {
nm_log_dbg (LOGD_AGENTS, "(%s) agent deleted secrets for request %p/%s",
- nm_secret_agent_get_description (agent),
- req, req->setting_name);
+ nm_secret_agent_get_description (agent),
+ req, req->setting_name);
}
/* Tell the next agent to delete secrets */
@@ -985,6 +1104,7 @@ static void
delete_complete_cb (Request *req,
GHashTable *secrets,
const char *agent_dbus_owner,
+ gboolean agent_has_modify,
GError *error,
gpointer user_data)
{
@@ -1077,6 +1197,15 @@ static void
nm_agent_manager_init (NMAgentManager *self)
{
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self);
+ GError *error = NULL;
+
+ 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);
+ }
priv->agents = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
priv->requests = g_hash_table_new_full (g_direct_hash,
@@ -1090,15 +1219,16 @@ dispose (GObject *object)
{
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (object);
- if (priv->disposed)
- return;
- priv->disposed = TRUE;
+ if (!priv->disposed) {
+ priv->disposed = TRUE;
- g_object_unref (priv->session_monitor);
- g_object_unref (priv->dbus_mgr);
+ g_hash_table_destroy (priv->agents);
+ g_hash_table_destroy (priv->requests);
- g_hash_table_destroy (priv->agents);
- g_hash_table_destroy (priv->requests);
+ g_object_unref (priv->session_monitor);
+ g_object_unref (priv->dbus_mgr);
+ g_object_unref (priv->authority);
+ }
G_OBJECT_CLASS (nm_agent_manager_parent_class)->dispose (object);
}
diff --git a/src/settings/nm-agent-manager.h b/src/settings/nm-agent-manager.h
index 6771f943a9..5e5dca42f6 100644
--- a/src/settings/nm-agent-manager.h
+++ b/src/settings/nm-agent-manager.h
@@ -48,6 +48,7 @@ NMAgentManager *nm_agent_manager_get (void);
typedef void (*NMAgentSecretsResultFunc) (NMAgentManager *manager,
guint32 call_id,
const char *agent_dbus_owner,
+ gboolean agent_has_modify,
const char *setting_name,
guint32 flags,
GHashTable *secrets,
diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c
index d82bb4414e..d3e1bada8c 100644
--- a/src/settings/nm-settings-connection.c
+++ b/src/settings/nm-settings-connection.c
@@ -426,140 +426,11 @@ new_secrets_commit_cb (NMSettingsConnection *connection,
}
}
-static void
-get_secrets_done (NMSettingsConnection *self,
- guint32 call_id,
- const char *setting_name,
- GHashTable *secrets,
- GError *error,
- NMSettingsConnectionSecretsFunc callback,
- gpointer callback_data)
-{
- NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
- NMSettingConnection *s_con;
- GError *local = NULL;
- GHashTable *hash = NULL;
-
- s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (self), NM_TYPE_SETTING_CONNECTION);
- g_assert (s_con);
-
- if (error) {
- nm_log_dbg (LOGD_SETTINGS, "(%s/%s:%u) secrets request completed; error: (%d) %s",
- nm_setting_connection_get_uuid (s_con),
- setting_name,
- call_id,
- error->code,
- error->message ? error->message : "(unknown)");
- callback (self, call_id, setting_name, error, callback_data);
- return;
- }
-
- nm_log_dbg (LOGD_SETTINGS, "(%s/%s:%u) secrets request completed successfully",
- nm_setting_connection_get_uuid (s_con),
- setting_name,
- call_id);
-
- /* 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);
- if (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
- * will have been authenticated, so those secrets can replace the existing
- * system secrets.
- */
- if (nm_connection_update_secrets (NM_CONNECTION (self), setting_name, secrets, &local)) {
- /* Now that all secrets are updated, copy and cache new secrets,
- * then save them to backing storage.
- */
- if (priv->secrets)
- g_object_unref (priv->secrets);
- priv->secrets = nm_connection_duplicate (NM_CONNECTION (self));
-
- nm_log_dbg (LOGD_SETTINGS, "(%s/%s:%u) saving new secrets to backing storage",
- nm_setting_connection_get_uuid (s_con),
- setting_name,
- call_id);
-
- nm_settings_connection_commit_changes (self, new_secrets_commit_cb, NULL);
- } else {
- nm_log_dbg (LOGD_SETTINGS, "(%s/%s:%u) failed to update with agent secrets: (%d) %s",
- nm_setting_connection_get_uuid (s_con),
- setting_name,
- call_id,
- local->code,
- local->message ? local->message : "(unknown)");
- }
- } else {
- nm_log_dbg (LOGD_SETTINGS, "(%s/%s:%u) failed to update with existing secrets: (%d) %s",
- nm_setting_connection_get_uuid (s_con),
- setting_name,
- call_id,
- local->code,
- local->message ? local->message : "(unknown)");
- }
-
- callback (self, call_id, setting_name, local, callback_data);
- g_clear_error (&local);
- if (hash)
- g_hash_table_destroy (hash);
-}
-
-static void
-agent_secrets_modify_auth_cb (NMAuthChain *chain,
- GError *error,
- DBusGMethodInvocation *context,
- gpointer user_data)
-{
- NMSettingsConnection *self = NM_SETTINGS_CONNECTION (user_data);
- NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
- NMSettingConnection *s_con;
- NMAuthCallResult result;
- GHashTable *secrets = nm_auth_chain_get_data (chain, "secrets");
- const char *setting_name = nm_auth_chain_get_data (chain, "setting-name");
- guint32 call_id = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, "call-id"));
-
- s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (self), NM_TYPE_SETTING_CONNECTION);
- g_assert (s_con);
-
- priv->pending_auths = g_slist_remove (priv->pending_auths, chain);
-
- result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_SETTINGS_CONNECTION_MODIFY);
-
- nm_log_dbg (LOGD_SETTINGS, "(%s/%s:%u) agent MODIFY check result %d",
- nm_setting_connection_get_uuid (s_con),
- setting_name,
- call_id,
- result);
-
- if (result == NM_AUTH_CALL_RESULT_YES) {
- /* Agent can modify system connections; system-owned secrets it returned
- * replace any secrets in backing storage.
- */
- } else {
- /* Agent didn't successfully authenticate; clear system-owned secrets
- * from the secrets the agent returned.
- */
- nm_log_dbg (LOGD_SETTINGS, "(%s/%s:%u) agent failed to authenticate after providing system secrets",
- nm_setting_connection_get_uuid (s_con),
- setting_name,
- call_id);
- for_each_secret (NM_CONNECTION (self), secrets, clear_system_owned_secrets, NULL);
- }
-
- get_secrets_done (self,
- call_id,
- setting_name,
- secrets,
- error,
- nm_auth_chain_get_data (chain, "callback"),
- nm_auth_chain_get_data (chain, "callback_data"));
-}
-
static void
agent_secrets_done_cb (NMAgentManager *manager,
guint32 call_id,
const char *agent_dbus_owner,
+ gboolean agent_has_modify,
const char *setting_name,
guint32 flags,
GHashTable *secrets,
@@ -574,17 +445,18 @@ agent_secrets_done_cb (NMAgentManager *manager,
gpointer callback_data = other_data3;
NMSettingConnection *s_con;
GError *local = NULL;
+ GHashTable *hash;
s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (self), NM_TYPE_SETTING_CONNECTION);
g_assert (s_con);
if (error) {
nm_log_dbg (LOGD_SETTINGS, "(%s/%s:%u) secrets request error: (%d) %s",
- nm_setting_connection_get_uuid (s_con),
- setting_name,
- call_id,
- error->code,
- error->message ? error->message : "(unknown)");
+ nm_setting_connection_get_uuid (s_con),
+ setting_name,
+ call_id,
+ error->code,
+ error->message ? error->message : "(unknown)");
callback (self, call_id, setting_name, error, callback_data);
return;
@@ -604,10 +476,10 @@ agent_secrets_done_cb (NMAgentManager *manager,
gboolean has_system = FALSE;
nm_log_dbg (LOGD_SETTINGS, "(%s/%s:%u) secrets returned from agent %s",
- nm_setting_connection_get_uuid (s_con),
- setting_name,
- call_id,
- agent_dbus_owner);
+ nm_setting_connection_get_uuid (s_con),
+ setting_name,
+ call_id,
+ agent_dbus_owner);
/* If the agent returned any system-owned secrets (initial connect and no
* secrets given when the connection was created, or something like that)
@@ -621,51 +493,81 @@ agent_secrets_done_cb (NMAgentManager *manager,
/* No user interaction was allowed when requesting secrets; the
* agent is being bad. Remove system-owned secrets.
*/
- for_each_secret (NM_CONNECTION (self), secrets, clear_system_owned_secrets, NULL);
-
nm_log_dbg (LOGD_SETTINGS, "(%s/%s:%u) interaction forbidden but agent %s returned system secrets",
- nm_setting_connection_get_uuid (s_con),
- setting_name,
- call_id,
- agent_dbus_owner);
- } else {
- NMAuthChain *chain;
+ nm_setting_connection_get_uuid (s_con),
+ setting_name,
+ call_id,
+ agent_dbus_owner);
- nm_log_dbg (LOGD_SETTINGS, "(%s/%s:%u) agent %s returned system secrets; checking for MODIFY",
- nm_setting_connection_get_uuid (s_con),
- setting_name,
- call_id,
- agent_dbus_owner);
-
- /* User interaction was allowed, check whether the agent's UID
- * has the 'modify' privilege before using the system-owned
- * secrets supplied by the agent.
+ for_each_secret (NM_CONNECTION (self), secrets, clear_system_owned_secrets, NULL);
+ } else if (agent_has_modify == FALSE) {
+ /* Agent didn't successfully authenticate; clear system-owned secrets
+ * from the secrets the agent returned.
*/
- chain = nm_auth_chain_new_dbus_sender (priv->authority,
- agent_dbus_owner,
- agent_secrets_modify_auth_cb,
- self);
- g_assert (chain);
+ nm_log_dbg (LOGD_SETTINGS, "(%s/%s:%u) agent failed to authenticate but provided system secrets",
+ nm_setting_connection_get_uuid (s_con),
+ setting_name,
+ call_id);
- nm_auth_chain_set_data (chain, "call-id", GUINT_TO_POINTER (call_id), NULL);
- nm_auth_chain_set_data (chain, "setting-name", g_strdup (setting_name), g_free);
- nm_auth_chain_set_data (chain, "secrets", g_hash_table_ref (secrets), (GDestroyNotify) g_hash_table_unref);
- nm_auth_chain_set_data (chain, "callback", callback, NULL);
- nm_auth_chain_set_data (chain, "callback-data", callback_data, NULL);
-
- nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_CONNECTION_MODIFY, TRUE);
- priv->pending_auths = g_slist_append (priv->pending_auths, chain);
- return;
+ for_each_secret (NM_CONNECTION (self), secrets, clear_system_owned_secrets, NULL);
}
}
} else {
nm_log_dbg (LOGD_SETTINGS, "(%s/%s:%u) existing secrets returned",
- nm_setting_connection_get_uuid (s_con),
- setting_name,
- call_id);
+ nm_setting_connection_get_uuid (s_con),
+ setting_name,
+ call_id);
}
- get_secrets_done (self, call_id, setting_name, secrets, error, callback, callback_data);
+ nm_log_dbg (LOGD_SETTINGS, "(%s/%s:%u) secrets request completed",
+ nm_setting_connection_get_uuid (s_con),
+ setting_name,
+ call_id);
+
+ /* 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);
+ if (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
+ * will have been authenticated, so those secrets can replace the existing
+ * system secrets.
+ */
+ if (nm_connection_update_secrets (NM_CONNECTION (self), setting_name, secrets, &local)) {
+ /* Now that all secrets are updated, copy and cache new secrets,
+ * then save them to backing storage.
+ */
+ if (priv->secrets)
+ g_object_unref (priv->secrets);
+ priv->secrets = nm_connection_duplicate (NM_CONNECTION (self));
+
+ nm_log_dbg (LOGD_SETTINGS, "(%s/%s:%u) saving new secrets to backing storage",
+ nm_setting_connection_get_uuid (s_con),
+ setting_name,
+ call_id);
+
+ nm_settings_connection_commit_changes (self, new_secrets_commit_cb, NULL);
+ } else {
+ nm_log_dbg (LOGD_SETTINGS, "(%s/%s:%u) failed to update with agent secrets: (%d) %s",
+ nm_setting_connection_get_uuid (s_con),
+ setting_name,
+ call_id,
+ local->code,
+ local->message ? local->message : "(unknown)");
+ }
+ } else {
+ nm_log_dbg (LOGD_SETTINGS, "(%s/%s:%u) failed to update with existing secrets: (%d) %s",
+ nm_setting_connection_get_uuid (s_con),
+ setting_name,
+ call_id,
+ local->code,
+ local->message ? local->message : "(unknown)");
+ }
+
+ callback (self, call_id, setting_name, local, callback_data);
+ g_clear_error (&local);
+ if (hash)
+ g_hash_table_destroy (hash);
}
/**
@@ -1170,7 +1072,7 @@ nm_settings_connection_init (NMSettingsConnection *self)
priv->dbus_mgr = nm_dbus_manager_get ();
- priv->authority = polkit_authority_get_sync (NULL, NULL);
+ 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,
@@ -1222,6 +1124,7 @@ dispose (GObject *object)
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);