diff options
Diffstat (limited to 'src/settings/nm-agent-manager.c')
| -rw-r--r-- | src/settings/nm-agent-manager.c | 1022 |
1 files changed, 550 insertions, 472 deletions
diff --git a/src/settings/nm-agent-manager.c b/src/settings/nm-agent-manager.c index d3635706..ae930692 100644 --- a/src/settings/nm-agent-manager.c +++ b/src/settings/nm-agent-manager.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2010 - 2011 Red Hat, Inc. + * Copyright (C) 2010 - 2013 Red Hat, Inc. */ #include <config.h> @@ -47,7 +47,6 @@ typedef struct { gboolean disposed; NMDBusManager *dbus_mgr; - NMSessionMonitor *session_monitor; /* Auth chains for checking agent permissions */ GSList *chains; @@ -70,16 +69,21 @@ static guint signals[LAST_SIGNAL] = { 0 }; typedef struct _Request Request; -static void request_add_agent (Request *req, - NMSecretAgent *agent, - NMSessionMonitor *session_monitor); +static void request_add_agent (Request *req, NMSecretAgent *agent); -static void request_remove_agent (gpointer key, gpointer value, gpointer user_data); +static void request_remove_agent (Request *req, NMSecretAgent *agent, GSList **pending_reqs); + +static void request_next_agent (Request *req); static void impl_agent_manager_register (NMAgentManager *self, const char *identifier, DBusGMethodInvocation *context); +static void impl_agent_manager_register_with_capabilities (NMAgentManager *self, + const char *identifier, + NMSecretAgentCapabilities capabilities, + DBusGMethodInvocation *context); + static void impl_agent_manager_unregister (NMAgentManager *self, DBusGMethodInvocation *context); @@ -101,60 +105,14 @@ nm_agent_manager_error_quark (void) /*************************************************************/ -/*----------------------------------------------------------------------------*/ -/* GHashTable safe iterating function: x_g_hash_table_safe_for_each() - * GHashTable can't be modified while iterating, the common solution for that is - * to flatten the hash table first and iterate over list. - * Taken from https://github.com/linuxmint/nemo/blob/master/eel/eel-glib-extensions.c - */ -typedef struct { - GList *keys; - GList *values; -} FlattenedHashTable; - -static void -flatten_hash_table_element (gpointer key, gpointer value, gpointer callback_data) -{ - FlattenedHashTable *flattened_table; - - flattened_table = callback_data; - flattened_table->keys = g_list_prepend - (flattened_table->keys, key); - flattened_table->values = g_list_prepend - (flattened_table->values, value); -} - -static void -x_g_hash_table_safe_for_each (GHashTable *hash_table, - GHFunc callback, - gpointer callback_data) -{ - FlattenedHashTable flattened; - GList *p, *q; - - flattened.keys = NULL; - flattened.values = NULL; - - g_hash_table_foreach (hash_table, - flatten_hash_table_element, - &flattened); - - for (p = flattened.keys, q = flattened.values; - p != NULL; - p = p->next, q = q->next) { - (* callback) (p->data, q->data, callback_data); - } - - g_list_free (flattened.keys); - g_list_free (flattened.values); -} -/*----------------------------------------------------------------------------*/ - static gboolean remove_agent (NMAgentManager *self, const char *owner) { NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); NMSecretAgent *agent; + GHashTableIter iter; + gpointer data; + GSList *pending_reqs = NULL; g_return_val_if_fail (owner != NULL, FALSE); @@ -163,11 +121,20 @@ remove_agent (NMAgentManager *self, const char *owner) if (!agent) return FALSE; - nm_log_dbg (LOGD_AGENTS, "(%s) agent unregistered", + nm_log_dbg (LOGD_AGENTS, "(%s) agent unregistered or disappeared", nm_secret_agent_get_description (agent)); /* Remove this agent from any in-progress secrets requests */ - x_g_hash_table_safe_for_each (priv->requests, request_remove_agent, agent); + g_hash_table_iter_init (&iter, priv->requests); + while (g_hash_table_iter_next (&iter, NULL, &data)) + request_remove_agent ((Request *) data, agent, &pending_reqs); + + /* We cannot call request_next_agent() from from within hash iterating loop, + * because it may remove the request from the hash table, which invalidates + * the iterator. So, only remove the agent from requests. And store the requests + * that should be sent to other agent to a temporary list to proceed afterwards. + */ + g_slist_free_full (pending_reqs, (GDestroyNotify) request_next_agent); /* And dispose of the agent */ g_hash_table_remove (priv->agents, owner); @@ -246,6 +213,8 @@ agent_register_permissions_done (NMAuthChain *chain, GHashTableIter iter; Request *req; + g_assert (context); + priv->chains = g_slist_remove (priv->chains, chain); if (error) { @@ -257,6 +226,7 @@ agent_register_permissions_done (NMAuthChain *chain, g_error_free (local); } else { agent = nm_auth_chain_steal_data (chain, "agent"); + g_assert (agent); result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED); if (result == NM_AUTH_CALL_RESULT_YES) @@ -278,37 +248,54 @@ agent_register_permissions_done (NMAuthChain *chain, /* Add this agent to any in-progress secrets requests */ g_hash_table_iter_init (&iter, priv->requests); while (g_hash_table_iter_next (&iter, NULL, (gpointer) &req)) - request_add_agent (req, agent, priv->session_monitor); + request_add_agent (req, agent); } nm_auth_chain_unref (chain); } +static NMSecretAgent * +find_agent_by_identifier_and_uid (NMAgentManager *self, + const char *identifier, + gulong sender_uid) +{ + NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); + GHashTableIter iter; + NMSecretAgent *agent; + + g_hash_table_iter_init (&iter, priv->agents); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &agent)) { + if ( g_strcmp0 (nm_secret_agent_get_identifier (agent), identifier) == 0 + && nm_secret_agent_get_owner_uid (agent) == sender_uid) + return agent; + } + return NULL; +} + static void -impl_agent_manager_register (NMAgentManager *self, - const char *identifier, - DBusGMethodInvocation *context) +impl_agent_manager_register_with_capabilities (NMAgentManager *self, + const char *identifier, + NMSecretAgentCapabilities capabilities, + DBusGMethodInvocation *context) { NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); - char *error_desc = NULL, *sender = NULL; + NMAuthSubject *subject; gulong sender_uid = G_MAXULONG; GError *error = NULL, *local = NULL; NMSecretAgent *agent; NMAuthChain *chain; - if (!nm_auth_get_caller_uid (context, - priv->dbus_mgr, - &sender_uid, - &error_desc)) { + subject = nm_auth_subject_new_from_context (context); + if (!subject) { error = g_error_new_literal (NM_AGENT_MANAGER_ERROR, NM_AGENT_MANAGER_ERROR_SENDER_UNKNOWN, - error_desc); - g_free (error_desc); + "Unable to determine request sender and UID."); goto done; } + sender_uid = nm_auth_subject_get_uid (subject); if ( 0 != sender_uid - && !nm_session_monitor_uid_has_session (priv->session_monitor, + && !nm_session_monitor_uid_has_session (nm_session_monitor_get (), sender_uid, NULL, &local)) { @@ -318,20 +305,20 @@ impl_agent_manager_register (NMAgentManager *self, goto done; } - sender = dbus_g_method_get_sender (context); - if (!sender) { - error = g_error_new_literal (NM_AGENT_MANAGER_ERROR, - NM_AGENT_MANAGER_ERROR_SENDER_UNKNOWN, - "Failed to get D-Bus request sender"); - goto done; - } - /* Validate the identifier */ if (!validate_identifier (identifier, &error)) goto done; + /* Only one agent for each identifier is allowed per user */ + if (find_agent_by_identifier_and_uid (self, identifier, sender_uid)) { + error = g_error_new_literal (NM_AGENT_MANAGER_ERROR, + NM_AGENT_MANAGER_ERROR_PERMISSION_DENIED, + "An agent with this ID is already registered for this user."); + goto done; + } + /* Success, add the new agent */ - agent = nm_secret_agent_new (priv->dbus_mgr, sender, identifier, sender_uid); + agent = nm_secret_agent_new (context, subject, identifier, capabilities); if (!agent) { error = g_error_new_literal (NM_AGENT_MANAGER_ERROR, NM_AGENT_MANAGER_ERROR_INTERNAL_ERROR, @@ -343,33 +330,51 @@ impl_agent_manager_register (NMAgentManager *self, nm_secret_agent_get_description (agent)); /* Kick off permissions requests for this agent */ - chain = nm_auth_chain_new (context, NULL, agent_register_permissions_done, self); - nm_auth_chain_set_data (chain, "agent", agent, g_object_unref); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED, FALSE); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, FALSE); + chain = nm_auth_chain_new_subject (subject, context, agent_register_permissions_done, self); + if (chain) { + nm_auth_chain_set_data (chain, "agent", agent, g_object_unref); + nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED, FALSE); + nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, FALSE); - priv->chains = g_slist_append (priv->chains, chain); + priv->chains = g_slist_append (priv->chains, chain); + } else { + error = g_error_new_literal (NM_AGENT_MANAGER_ERROR, + NM_AGENT_MANAGER_ERROR_SENDER_UNKNOWN, + "Unable to start agent authentication."); + } done: if (error) dbus_g_method_return_error (context, error); g_clear_error (&error); g_clear_error (&local); - g_free (sender); + g_clear_object (&subject); +} + +static void +impl_agent_manager_register (NMAgentManager *self, + const char *identifier, + DBusGMethodInvocation *context) +{ + impl_agent_manager_register_with_capabilities (self, identifier, 0, context); } static void impl_agent_manager_unregister (NMAgentManager *self, DBusGMethodInvocation *context) { + NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); GError *error = NULL; char *sender = NULL; - sender = dbus_g_method_get_sender (context); - if (!sender) { + if (!nm_dbus_manager_get_caller_info (priv->dbus_mgr, + context, + &sender, + NULL, + NULL)) { error = g_error_new_literal (NM_AGENT_MANAGER_ERROR, NM_AGENT_MANAGER_ERROR_SENDER_UNKNOWN, - "Failed to get D-Bus request sender"); + "Unable to determine request sender."); goto done; } @@ -396,27 +401,23 @@ typedef void (*RequestCompleteFunc) (Request *req, GHashTable *secrets, const char *agent_dbus_owner, const char *agent_username, - gboolean agent_has_modify, GError *error, gpointer user_data); +typedef gboolean (*RequestAddAgentFunc) (Request *req, NMSecretAgent *agent); typedef void (*RequestNextFunc) (Request *req); typedef void (*RequestCancelFunc) (Request *req); +/* Basic secrets request structure */ struct _Request { guint32 reqid; - NMAuthChain *chain; + char *detail; + char *verb; - NMConnection *connection; - gboolean filter_by_uid; - gulong uid_filter; - char *setting_name; - NMSettingsGetSecretsFlags flags; - char *hint; + NMAuthSubject *subject; /* 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; @@ -429,102 +430,64 @@ struct _Request { guint32 idle_id; - GHashTable *existing_secrets; - - NMAgentSecretsResultFunc callback; - gpointer callback_data; - gpointer other_data2; - gpointer other_data3; - + RequestAddAgentFunc add_agent_callback; RequestCancelFunc cancel_callback; RequestNextFunc next_callback; RequestCompleteFunc complete_callback; gpointer complete_callback_data; + gboolean completed; + + GDestroyNotify free_func; }; static guint32 next_req_id = 1; static Request * -request_new_get (NMConnection *connection, - gboolean filter_by_uid, - gulong uid_filter, - GHashTable *existing_secrets, - const char *setting_name, - NMSettingsGetSecretsFlags flags, - const char *hint, - NMAgentSecretsResultFunc callback, - gpointer callback_data, - gpointer other_data2, - gpointer other_data3, - RequestCompleteFunc complete_callback, - gpointer complete_callback_data, - RequestNextFunc next_callback, - RequestCancelFunc cancel_callback) +request_new (gsize struct_size, + const char *detail, + const char *verb, + NMAuthSubject *subject, + RequestCompleteFunc complete_callback, + gpointer complete_callback_data, + RequestAddAgentFunc add_agent_callback, + RequestNextFunc next_callback, + RequestCancelFunc cancel_callback, + GDestroyNotify free_func) { Request *req; - req = g_malloc0 (sizeof (Request)); + req = g_malloc0 (struct_size); req->reqid = next_req_id++; - req->connection = g_object_ref (connection); - req->filter_by_uid = filter_by_uid; - req->uid_filter = uid_filter; - if (existing_secrets) - req->existing_secrets = g_hash_table_ref (existing_secrets); - req->setting_name = g_strdup (setting_name); - req->flags = flags; - req->hint = g_strdup (hint); - req->callback = callback; - req->callback_data = callback_data; - req->other_data2 = other_data2; - req->other_data3 = other_data3; + req->detail = g_strdup (detail); + req->verb = g_strdup (verb); + req->subject = g_object_ref (subject); req->complete_callback = complete_callback; req->complete_callback_data = complete_callback_data; + req->add_agent_callback = add_agent_callback, req->next_callback = next_callback; req->cancel_callback = cancel_callback; - - return req; -} - -static Request * -request_new_other (NMConnection *connection, - gboolean filter_by_uid, - gulong uid_filter, - RequestCompleteFunc complete_callback, - gpointer complete_callback_data, - RequestNextFunc next_callback) -{ - Request *req; - - req = g_malloc0 (sizeof (Request)); - req->reqid = next_req_id++; - req->connection = g_object_ref (connection); - req->filter_by_uid = filter_by_uid; - req->uid_filter = uid_filter; - req->complete_callback = complete_callback; - req->complete_callback_data = complete_callback_data; - req->next_callback = next_callback; - + req->free_func = free_func; return req; } static void request_free (Request *req) { + if (req->free_func) + req->free_func ((gpointer) req); + if (req->idle_id) g_source_remove (req->idle_id); - if (req->cancel_callback) + if (!req->completed && req->cancel_callback) req->cancel_callback (req); + g_object_unref (req->subject); + + g_free (req->detail); + g_free (req->verb); g_slist_free_full (req->pending, g_object_unref); g_slist_free (req->asked); - g_object_unref (req->connection); - g_free (req->setting_name); - g_free (req->hint); - if (req->existing_secrets) - g_hash_table_unref (req->existing_secrets); - if (req->chain) - nm_auth_chain_unref (req->chain); memset (req, 0, sizeof (Request)); g_free (req); } @@ -533,14 +496,13 @@ static void req_complete_success (Request *req, GHashTable *secrets, const char *agent_dbus_owner, - const char *agent_uname, - gboolean agent_has_modify) + const char *agent_uname) { + req->completed = TRUE; req->complete_callback (req, secrets, agent_dbus_owner, agent_uname, - agent_has_modify, NULL, req->complete_callback_data); } @@ -548,27 +510,38 @@ req_complete_success (Request *req, static void req_complete_error (Request *req, GError *error) { - req->complete_callback (req, NULL, NULL, NULL, FALSE, error, req->complete_callback_data); + req->completed = TRUE; + req->complete_callback (req, NULL, NULL, NULL, error, req->complete_callback_data); } static gint -agent_compare_func (NMSecretAgent *a, NMSecretAgent *b, gpointer user_data) +agent_compare_func (gconstpointer aa, gconstpointer bb, gpointer user_data) { - NMSessionMonitor *session_monitor = NM_SESSION_MONITOR (user_data); + NMSecretAgent *a = (NMSecretAgent *)aa; + NMSecretAgent *b = (NMSecretAgent *)bb; + Request *req = user_data; gboolean a_active, b_active; - - if (a && !b) - return -1; - else if (a == b) - return 0; - else if (!a && b) - return 1; + gulong a_pid, b_pid, requester; + + /* Prefer agents in the process the request came from */ + requester = nm_auth_subject_get_pid (req->subject); + if (requester != G_MAXULONG) { + a_pid = nm_secret_agent_get_pid (a); + b_pid = nm_secret_agent_get_pid (b); + + if (a_pid != b_pid) { + if (a_pid == requester) + return -1; + else if (b_pid == requester) + return 1; + } + } /* Prefer agents in active sessions */ - a_active = nm_session_monitor_uid_active (session_monitor, + a_active = nm_session_monitor_uid_active (nm_session_monitor_get (), nm_secret_agent_get_owner_uid (a), NULL); - b_active = nm_session_monitor_uid_active (session_monitor, + b_active = nm_session_monitor_uid_active (nm_session_monitor_get (), nm_secret_agent_get_owner_uid (b), NULL); if (a_active && !b_active) @@ -582,48 +555,42 @@ agent_compare_func (NMSecretAgent *a, NMSecretAgent *b, gpointer user_data) } static void -request_add_agent (Request *req, - NMSecretAgent *agent, - NMSessionMonitor *session_monitor) +request_add_agent (Request *req, NMSecretAgent *agent) { - uid_t agent_uid; - g_return_if_fail (req != NULL); g_return_if_fail (agent != NULL); if (g_slist_find (req->asked, GUINT_TO_POINTER (nm_secret_agent_get_hash (agent)))) return; - /* Ensure the caller's username exists in the connection's permissions, - * or that the permissions is empty (ie, visible by everyone). - */ - agent_uid = nm_secret_agent_get_owner_uid (agent); - if (!nm_auth_uid_in_acl (req->connection, session_monitor, agent_uid, NULL)) { - nm_log_dbg (LOGD_AGENTS, "(%s) agent ignored for secrets request %p/%s (not in ACL)", - nm_secret_agent_get_description (agent), - req, req->setting_name); - /* Connection not visible to this agent's user */ + if (req->add_agent_callback && !req->add_agent_callback (req, agent)) return; - } /* If the request should filter agents by UID, do that now */ - if (req->filter_by_uid && (agent_uid != req->uid_filter)) { - nm_log_dbg (LOGD_AGENTS, "(%s) agent ignored for secrets request %p/%s " - "(uid %d not required %ld)", - nm_secret_agent_get_description (agent), - req, req->setting_name, agent_uid, req->uid_filter); - return; + if (!nm_auth_subject_get_internal (req->subject)) { + uid_t agent_uid, subject_uid; + + agent_uid = nm_secret_agent_get_owner_uid (agent); + subject_uid = nm_auth_subject_get_uid (req->subject); + if (agent_uid != subject_uid) { + nm_log_dbg (LOGD_AGENTS, "(%s) agent ignored for secrets request %p/%s " + "(uid %ld not required %ld)", + nm_secret_agent_get_description (agent), + req, req->detail, + (long)agent_uid, (long)subject_uid); + return; + } } nm_log_dbg (LOGD_AGENTS, "(%s) agent allowed for secrets request %p/%s", - nm_secret_agent_get_description (agent), - req, req->setting_name); + nm_secret_agent_get_description (agent), + req, req->detail); - /* Add this agent to the list, preferring active sessions */ + /* Add this agent to the list, sorted appropriately */ req->pending = g_slist_insert_sorted_with_data (req->pending, g_object_ref (agent), - (GCompareDataFunc) agent_compare_func, - session_monitor); + agent_compare_func, + req); } static void @@ -635,94 +602,197 @@ request_add_agents (NMAgentManager *self, Request *req) g_hash_table_iter_init (&iter, priv->agents); while (g_hash_table_iter_next (&iter, NULL, &data)) - request_add_agent (req, NM_SECRET_AGENT (data), priv->session_monitor); + request_add_agent (req, NM_SECRET_AGENT (data)); } static void -request_remove_agent (gpointer key, gpointer value, gpointer user_data) +request_next_agent (Request *req) { - Request *req = (Request *) value; - NMSecretAgent *agent = (NMSecretAgent *) user_data; - gboolean try_next = FALSE; - const char *detail = ""; - GSList *found; - - g_return_if_fail (req != NULL); - g_return_if_fail (agent != NULL); + GError *error = NULL; - /* If this agent is being asked right now, cancel the request */ - if (agent == req->current) { - if (req->cancel_callback) - req->cancel_callback (req); - req->current_has_modify = FALSE; - req->current = NULL; + if (req->pending) { + /* Send the request to the next agent */ req->current_call_id = NULL; - try_next = TRUE; - detail = " current"; - } - - nm_log_dbg (LOGD_AGENTS, "(%s)%s agent removed from secrets request %p/%s", - nm_secret_agent_get_description (agent), - detail, req, req->setting_name); + if (req->current) + g_object_unref (req->current); + req->current = req->pending->data; + req->pending = g_slist_remove (req->pending, req->current); - found = g_slist_find (req->pending, agent); - if (found) { - req->pending = g_slist_remove_link (req->pending, found); - g_object_unref (found->data); - g_slist_free_1 (found); - } + nm_log_dbg (LOGD_AGENTS, "(%s) agent %s secrets for request %p/%s", + nm_secret_agent_get_description (req->current), + req->verb, req, req->detail); - if (try_next) { - /* If the agent serving the in-progress secrets request went away then - * we need to send the request to the next agent. - */ req->next_callback (req); - } -} - -static gboolean -next_generic (Request *req, const char *detail) -{ - GError *error = NULL; - gboolean success = FALSE; + } else { + req->current_call_id = NULL; + req->current = NULL; - if (req->pending == NULL) { /* No more secret agents are available to fulfill this secrets request */ error = g_error_new_literal (NM_AGENT_MANAGER_ERROR, NM_AGENT_MANAGER_ERROR_NO_SECRETS, "No agents were available for this request."); req_complete_error (req, error); g_error_free (error); - } else { - /* Send a secrets request to the next agent */ - req->current_has_modify = FALSE; - if (req->current) - g_object_unref (req->current); - req->current = req->pending->data; - req->pending = g_slist_remove (req->pending, req->current); - - nm_log_dbg (LOGD_AGENTS, "(%s) agent %s secrets for request %p/%s", - nm_secret_agent_get_description (req->current), - detail, req, req->setting_name); - success = TRUE; } +} + +static void +request_remove_agent (Request *req, NMSecretAgent *agent, GSList **pending_reqs) +{ + g_return_if_fail (req != NULL); + g_return_if_fail (agent != NULL); - return success; + req->pending = g_slist_remove (req->pending, agent); + + if (agent == req->current) { + nm_log_dbg (LOGD_AGENTS, "(%s) current agent removed from secrets request %p/%s", + nm_secret_agent_get_description (agent), req, req->detail); + *pending_reqs = g_slist_prepend (*pending_reqs, req); + } else { + nm_log_dbg (LOGD_AGENTS, "(%s) agent removed from secrets request %p/%s", + nm_secret_agent_get_description (agent), req, req->detail); + } } static gboolean -start_generic (gpointer user_data) +request_start (gpointer user_data) { Request *req = user_data; req->idle_id = 0; - req->next_callback (req); + request_next_agent (req); return FALSE; } - /*************************************************************/ +/* Request subclass for connection secrets */ +typedef struct { + Request parent; + + NMSettingsGetSecretsFlags flags; + NMConnection *connection; + char *setting_name; + char **hints; + + GHashTable *existing_secrets; + + NMAgentSecretsResultFunc callback; + gpointer callback_data; + gpointer other_data2; + gpointer other_data3; + + NMAuthChain *chain; + + /* Whether the agent currently being asked for secrets + * has the system.modify privilege. + */ + gboolean current_has_modify; +} ConnectionRequest; + +static void +connection_request_free (gpointer data) +{ + ConnectionRequest *req = data; + + g_object_unref (req->connection); + g_free (req->setting_name); + g_strfreev (req->hints); + if (req->existing_secrets) + g_hash_table_unref (req->existing_secrets); + if (req->chain) + nm_auth_chain_unref (req->chain); +} + +static gboolean +connection_request_add_agent (Request *parent, NMSecretAgent *agent) +{ + ConnectionRequest *req = (ConnectionRequest *) parent; + uid_t agent_uid = nm_secret_agent_get_owner_uid (agent); + + /* Ensure the caller's username exists in the connection's permissions, + * or that the permissions is empty (ie, visible by everyone). + */ + if (!nm_auth_uid_in_acl (req->connection, nm_session_monitor_get (), agent_uid, NULL)) { + nm_log_dbg (LOGD_AGENTS, "(%s) agent ignored for secrets request %p/%s (not in ACL)", + nm_secret_agent_get_description (agent), + parent, parent->detail); + /* Connection not visible to this agent's user */ + return FALSE; + } + + return TRUE; +} + +static ConnectionRequest * +connection_request_new_get (NMConnection *connection, + NMAuthSubject *subject, + GHashTable *existing_secrets, + const char *setting_name, + const char *verb, + NMSettingsGetSecretsFlags flags, + const char **hints, + NMAgentSecretsResultFunc callback, + gpointer callback_data, + gpointer other_data2, + gpointer other_data3, + RequestCompleteFunc complete_callback, + gpointer complete_callback_data, + RequestNextFunc next_callback, + RequestCancelFunc cancel_callback) +{ + ConnectionRequest *req; + + req = (ConnectionRequest *) request_new (sizeof (ConnectionRequest), + nm_connection_get_id (connection), + verb, + subject, + complete_callback, + complete_callback_data, + connection_request_add_agent, + next_callback, + cancel_callback, + connection_request_free); + g_assert (req); + + req->connection = g_object_ref (connection); + if (existing_secrets) + req->existing_secrets = g_hash_table_ref (existing_secrets); + req->setting_name = g_strdup (setting_name); + req->hints = g_strdupv ((char **) hints); + req->flags = flags; + req->callback = callback; + req->callback_data = callback_data; + req->other_data2 = other_data2; + req->other_data3 = other_data3; + return req; +} + +static ConnectionRequest * +connection_request_new_other (NMConnection *connection, + NMAuthSubject *subject, + const char *verb, + RequestCompleteFunc complete_callback, + gpointer complete_callback_data, + RequestNextFunc next_callback) +{ + ConnectionRequest *req; + + req = (ConnectionRequest *) request_new (sizeof (ConnectionRequest), + nm_connection_get_id (connection), + verb, + subject, + complete_callback, + complete_callback_data, + NULL, + next_callback, + NULL, + connection_request_free); + g_assert (req); + req->connection = g_object_ref (connection); + return req; +} + static void get_done_cb (NMSecretAgent *agent, gconstpointer call_id, @@ -730,47 +800,49 @@ get_done_cb (NMSecretAgent *agent, GError *error, gpointer user_data) { - Request *req = user_data; + Request *parent = user_data; + ConnectionRequest *req = user_data; GHashTable *setting_secrets; const char *agent_dbus_owner; - gboolean agent_has_modify; struct passwd *pw; char *agent_uname = NULL; - 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; + g_return_if_fail (call_id == parent->current_call_id); if (error) { - nm_log_dbg (LOGD_AGENTS, "(%s) agent failed secrets request %p/%s: (%d) %s", + nm_log_dbg (LOGD_AGENTS, "(%s) agent failed secrets request %p/%s/%s: (%d) %s", nm_secret_agent_get_description (agent), - req, req->setting_name, + req, parent->detail, req->setting_name, error ? error->code : -1, (error && error->message) ? error->message : "(unknown)"); - /* Try the next agent */ - req->next_callback (req); + if (dbus_g_error_has_name (error, NM_DBUS_INTERFACE_SECRET_AGENT ".UserCanceled")) { + error = g_error_new_literal (NM_AGENT_MANAGER_ERROR, + NM_AGENT_MANAGER_ERROR_USER_CANCELED, + "User canceled the secrets request."); + req_complete_error (parent, error); + g_error_free (error); + } else { + /* Try the next agent */ + request_next_agent (parent); + } return; } /* Ensure the setting we wanted secrets for got returned and has something in it */ 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_log_dbg (LOGD_AGENTS, "(%s) agent returned no secrets for request %p/%s/%s", nm_secret_agent_get_description (agent), - req, req->setting_name); - + req, parent->detail, req->setting_name); /* Try the next agent */ - req->next_callback (req); + request_next_agent (parent); return; } - nm_log_dbg (LOGD_AGENTS, "(%s) agent returned secrets for request %p/%s", + nm_log_dbg (LOGD_AGENTS, "(%s) agent returned secrets for request %p/%s/%s", nm_secret_agent_get_description (agent), - req, req->setting_name); + req, parent->detail, req->setting_name); /* Get the agent's username */ pw = getpwuid (nm_secret_agent_get_owner_uid (agent)); @@ -781,7 +853,7 @@ get_done_cb (NMSecretAgent *agent, } agent_dbus_owner = nm_secret_agent_get_dbus_owner (agent); - req_complete_success (req, secrets, agent_dbus_owner, agent_uname, agent_has_modify); + req_complete_success (parent, secrets, agent_dbus_owner, agent_uname); g_free (agent_uname); } @@ -827,15 +899,16 @@ set_secrets_not_required (NMConnection *connection, GHashTable *hash) } static void -get_agent_request_secrets (Request *req, gboolean include_system_secrets) +get_agent_request_secrets (ConnectionRequest *req, gboolean include_system_secrets) { + Request *parent = (Request *) req; NMConnection *tmp; tmp = nm_connection_duplicate (req->connection); nm_connection_clear_secrets (tmp); if (include_system_secrets) { if (req->existing_secrets) - nm_connection_update_secrets (tmp, req->setting_name, req->existing_secrets, NULL); + (void) nm_connection_update_secrets (tmp, req->setting_name, req->existing_secrets, NULL); } else { /* Update secret flags in the temporary connection to indicate that * the system secrets we're not sending to the agent aren't required, @@ -845,19 +918,17 @@ get_agent_request_secrets (Request *req, gboolean include_system_secrets) set_secrets_not_required (tmp, req->existing_secrets); } - req->current_call_id = nm_secret_agent_get_secrets (NM_SECRET_AGENT (req->current), - tmp, - req->setting_name, - req->hint, - req->flags, - get_done_cb, - req); - if (req->current_call_id == NULL) { + parent->current_call_id = nm_secret_agent_get_secrets (parent->current, + tmp, + req->setting_name, + (const char **) req->hints, + req->flags, + get_done_cb, + req); + if (parent->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_warn_if_fail (parent->current_call_id != NULL); + request_next_agent (parent); } g_object_unref (tmp); @@ -869,19 +940,19 @@ get_agent_modify_auth_cb (NMAuthChain *chain, DBusGMethodInvocation *context, gpointer user_data) { - Request *req = user_data; - NMAuthCallResult result; + Request *parent = user_data; + ConnectionRequest *req = user_data; const char *perm; req->chain = NULL; if (error) { - nm_log_dbg (LOGD_AGENTS, "(%p/%s) agent MODIFY check error: (%d) %s", - req, req->setting_name, + nm_log_dbg (LOGD_AGENTS, "(%s) agent %p/%s/%s MODIFY check error: (%d) %s", + nm_secret_agent_get_description (parent->current), + req, parent->detail, req->setting_name, error->code, error->message ? error->message : "(unknown)"); - /* Try the next agent */ - req->next_callback (req); + request_next_agent (parent); } 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 @@ -889,15 +960,17 @@ get_agent_modify_auth_cb (NMAuthChain *chain, */ perm = nm_auth_chain_get_data (chain, "perm"); g_assert (perm); - result = nm_auth_chain_get_result (chain, perm); - if (result == NM_AUTH_CALL_RESULT_YES) + if (nm_auth_chain_get_result (chain, perm) == 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); + nm_log_dbg (LOGD_AGENTS, "(%s) agent %p/%s/%s MODIFY check result %s", + nm_secret_agent_get_description (parent->current), + req, parent->detail, req->setting_name, + req->current_has_modify ? "YES" : "NO"); get_agent_request_secrets (req, req->current_has_modify); } + nm_auth_chain_unref (chain); } @@ -944,15 +1017,15 @@ has_system_secrets (NMConnection *connection) } static void -get_next_cb (Request *req) +get_next_cb (Request *parent) { + ConnectionRequest *req = (ConnectionRequest *) parent; NMSettingConnection *s_con; const char *agent_dbus_owner, *perm; - if (!next_generic (req, "getting")) - return; + req->current_has_modify = FALSE; - agent_dbus_owner = nm_secret_agent_get_dbus_owner (NM_SECRET_AGENT (req->current)); + agent_dbus_owner = nm_secret_agent_get_dbus_owner (parent->current); /* If the request flags allow user interaction, and there are existing * system secrets (or blank secrets that are supposed to be system-owned), @@ -962,12 +1035,13 @@ get_next_cb (Request *req) */ if ( (req->flags != NM_SETTINGS_GET_SECRETS_FLAG_NONE) && (req->existing_secrets || has_system_secrets (req->connection))) { - nm_log_dbg (LOGD_AGENTS, "(%p/%s) request has system secrets; checking agent %s for MODIFY", - req, req->setting_name, agent_dbus_owner); + nm_log_dbg (LOGD_AGENTS, "(%p/%s/%s) request has system secrets; checking agent %s for MODIFY", + req, parent->detail, req->setting_name, agent_dbus_owner); - req->chain = nm_auth_chain_new_dbus_sender (agent_dbus_owner, - get_agent_modify_auth_cb, - req); + req->chain = nm_auth_chain_new_subject (nm_secret_agent_get_subject (parent->current), + NULL, + get_agent_modify_auth_cb, + req); g_assert (req->chain); /* If the caller is the only user in the connection's permissions, then @@ -984,8 +1058,8 @@ get_next_cb (Request *req) nm_auth_chain_add_call (req->chain, perm, TRUE); } else { - nm_log_dbg (LOGD_AGENTS, "(%p/%s) requesting user-owned secrets from agent %s", - req, req->setting_name, agent_dbus_owner); + nm_log_dbg (LOGD_AGENTS, "(%p/%s/%s) requesting user-owned secrets from agent %s", + req, parent->detail, req->setting_name, agent_dbus_owner); get_agent_request_secrets (req, FALSE); } @@ -994,10 +1068,11 @@ get_next_cb (Request *req) static gboolean get_start (gpointer user_data) { - Request *req = user_data; + Request *parent = user_data; + ConnectionRequest *req = user_data; GHashTable *setting_secrets = NULL; - req->idle_id = 0; + parent->idle_id = 0; /* Check if there are any existing secrets */ if (req->existing_secrets) @@ -1006,7 +1081,7 @@ get_start (gpointer user_data) if (setting_secrets && g_hash_table_size (setting_secrets)) { NMConnection *tmp; GError *error = NULL; - gboolean request_new = (req->flags & NM_SETTINGS_GET_SECRETS_FLAG_REQUEST_NEW); + gboolean new_secrets = (req->flags & NM_SETTINGS_GET_SECRETS_FLAG_REQUEST_NEW); /* The connection already had secrets; check if any more are required. * If no more are required, we're done. If secrets are still needed, @@ -1017,23 +1092,23 @@ get_start (gpointer user_data) g_assert (tmp); if (!nm_connection_update_secrets (tmp, req->setting_name, req->existing_secrets, &error)) { - req_complete_error (req, error); + req_complete_error (parent, error); g_clear_error (&error); } else { /* Do we have everything we need? */ if ( (req->flags & NM_SETTINGS_GET_SECRETS_FLAG_ONLY_SYSTEM) - || ((nm_connection_need_secrets (tmp, NULL) == NULL) && (request_new == FALSE))) { - nm_log_dbg (LOGD_AGENTS, "(%p/%s) system settings secrets sufficient", - req, req->setting_name); + || ((nm_connection_need_secrets (tmp, NULL) == NULL) && (new_secrets == FALSE))) { + nm_log_dbg (LOGD_AGENTS, "(%p/%s/%s) system settings secrets sufficient", + req, parent->detail, req->setting_name); /* Got everything, we're done */ - req_complete_success (req, req->existing_secrets, NULL, NULL, FALSE); + req_complete_success (parent, req->existing_secrets, NULL, NULL); } else { - nm_log_dbg (LOGD_AGENTS, "(%p/%s) system settings secrets insufficient, asking agents", - req, req->setting_name); + nm_log_dbg (LOGD_AGENTS, "(%p/%s/%s) system settings secrets insufficient, asking agents", + req, parent->detail, req->setting_name); /* We don't, so ask some agents for additional secrets */ - req->next_callback (req); + request_next_agent (parent); } } g_object_unref (tmp); @@ -1042,30 +1117,30 @@ get_start (gpointer user_data) * agents for secrets. Let the Agent Manager handle which agents * we'll ask and in which order. */ - req->next_callback (req); + request_next_agent (parent); } return FALSE; } static void -get_complete_cb (Request *req, +get_complete_cb (Request *parent, GHashTable *secrets, const char *agent_dbus_owner, const char *agent_username, - gboolean agent_has_modify, GError *error, gpointer user_data) { NMAgentManager *self = NM_AGENT_MANAGER (user_data); NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); + ConnectionRequest *req = (ConnectionRequest *) parent; /* Send secrets back to the requesting object */ req->callback (self, - req->reqid, + parent->reqid, agent_dbus_owner, agent_username, - agent_has_modify, + req->current_has_modify, req->setting_name, req->flags, error ? NULL : secrets, @@ -1074,41 +1149,44 @@ get_complete_cb (Request *req, req->other_data2, req->other_data3); - g_hash_table_remove (priv->requests, GUINT_TO_POINTER (req->reqid)); + g_hash_table_remove (priv->requests, GUINT_TO_POINTER (parent->reqid)); } static void -get_cancel_cb (Request *req) +get_cancel_cb (Request *parent) { - if (req->current && req->current_call_id) - nm_secret_agent_cancel_secrets (req->current, req->current_call_id); + ConnectionRequest *req = (ConnectionRequest *) parent; + + req->current_has_modify = FALSE; + if (parent->current && parent->current_call_id) + nm_secret_agent_cancel_secrets (parent->current, parent->current_call_id); } guint32 nm_agent_manager_get_secrets (NMAgentManager *self, NMConnection *connection, - gboolean filter_by_uid, - gulong uid_filter, + NMAuthSubject *subject, GHashTable *existing_secrets, const char *setting_name, NMSettingsGetSecretsFlags flags, - const char *hint, + const char **hints, NMAgentSecretsResultFunc callback, gpointer callback_data, gpointer other_data2, gpointer other_data3) { NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); - Request *req; + Request *parent; + ConnectionRequest *req; g_return_val_if_fail (self != NULL, 0); - g_return_val_if_fail (connection != NULL, 0); g_return_val_if_fail (NM_IS_CONNECTION (connection), 0); g_return_val_if_fail (callback != NULL, 0); nm_log_dbg (LOGD_SETTINGS, - "Secrets requested for connection %s (%s)", + "Secrets requested for connection %s (%s/%s)", nm_connection_get_path (connection), + nm_connection_get_id (connection), setting_name); /* NOTE: a few things in the Request handling depend on existing_secrets @@ -1117,29 +1195,29 @@ nm_agent_manager_get_secrets (NMAgentManager *self, * both returning NULL if they didn't hash anything. */ - req = request_new_get (connection, - filter_by_uid, - uid_filter, - existing_secrets, - setting_name, - flags, - hint, - callback, - callback_data, - other_data2, - other_data3, - get_complete_cb, - self, - get_next_cb, - get_cancel_cb); - g_hash_table_insert (priv->requests, GUINT_TO_POINTER (req->reqid), req); + req = connection_request_new_get (connection, + subject, + existing_secrets, + setting_name, + "getting", + flags, + hints, + callback, + callback_data, + other_data2, + other_data3, + get_complete_cb, + self, + get_next_cb, + get_cancel_cb); + parent = (Request *) req; + g_hash_table_insert (priv->requests, GUINT_TO_POINTER (parent->reqid), req); /* Kick off the request */ if (!(req->flags & NM_SETTINGS_GET_SECRETS_FLAG_ONLY_SYSTEM)) - request_add_agents (self, req); - req->idle_id = g_idle_add (get_start, req); - - return req->reqid; + request_add_agents (self, parent); + parent->idle_id = g_idle_add (get_start, req); + return parent->reqid; } void @@ -1162,49 +1240,44 @@ save_done_cb (NMSecretAgent *agent, GError *error, gpointer user_data) { - Request *req = user_data; + Request *parent = user_data; + ConnectionRequest *req = user_data; const char *agent_dbus_owner; - g_return_if_fail (call_id == req->current_call_id); - - req->current = NULL; - req->current_call_id = NULL; + g_return_if_fail (call_id == parent->current_call_id); 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, + req, parent->detail, error ? error->code : -1, (error && error->message) ? error->message : "(unknown)"); - /* Try the next agent */ - req->next_callback (req); + request_next_agent (parent); return; } nm_log_dbg (LOGD_AGENTS, "(%s) agent saved secrets for request %p/%s", nm_secret_agent_get_description (agent), - req, req->setting_name); + req, parent->detail); agent_dbus_owner = nm_secret_agent_get_dbus_owner (agent); - req_complete_success (req, NULL, NULL, agent_dbus_owner, FALSE); + req_complete_success (parent, NULL, NULL, agent_dbus_owner); } static void -save_next_cb (Request *req) +save_next_cb (Request *parent) { - if (!next_generic (req, "saving")) - return; + ConnectionRequest *req = (ConnectionRequest *) parent; - req->current_call_id = nm_secret_agent_save_secrets (NM_SECRET_AGENT (req->current), - req->connection, - save_done_cb, - req); - if (req->current_call_id == NULL) { + parent->current_call_id = nm_secret_agent_save_secrets (parent->current, + req->connection, + save_done_cb, + req); + if (parent->current_call_id == NULL) { /* Shouldn't hit this, but handle it anyway */ - g_warn_if_fail (req->current_call_id != NULL); - req->current = NULL; - req->next_callback (req); + g_warn_if_fail (parent->current_call_id != NULL); + request_next_agent (parent); } } @@ -1213,46 +1286,43 @@ save_complete_cb (Request *req, GHashTable *secrets, const char *agent_dbus_owner, const char *agent_username, - gboolean agent_has_modify, GError *error, gpointer user_data) { - NMAgentManager *self = NM_AGENT_MANAGER (user_data); - NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); - - g_hash_table_remove (priv->requests, GUINT_TO_POINTER (req->reqid)); + g_hash_table_remove (NM_AGENT_MANAGER_GET_PRIVATE (user_data)->requests, + GUINT_TO_POINTER (req->reqid)); } guint32 nm_agent_manager_save_secrets (NMAgentManager *self, NMConnection *connection, - gboolean filter_by_uid, - gulong uid_filter) + NMAuthSubject *subject) { NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); - Request *req; + ConnectionRequest *req; + Request *parent; g_return_val_if_fail (self != NULL, 0); - g_return_val_if_fail (connection != NULL, 0); g_return_val_if_fail (NM_IS_CONNECTION (connection), 0); nm_log_dbg (LOGD_SETTINGS, - "Saving secrets for connection %s", - nm_connection_get_path (connection)); + "Saving secrets for connection %s (%s)", + nm_connection_get_path (connection), + nm_connection_get_id (connection)); - req = request_new_other (connection, - filter_by_uid, - uid_filter, - save_complete_cb, - self, - save_next_cb); - g_hash_table_insert (priv->requests, GUINT_TO_POINTER (req->reqid), req); + req = connection_request_new_other (connection, + subject, + "saving", + save_complete_cb, + self, + save_next_cb); + parent = (Request *) req; + g_hash_table_insert (priv->requests, GUINT_TO_POINTER (parent->reqid), req); /* Kick off the request */ - request_add_agents (self, req); - req->idle_id = g_idle_add (start_generic, req); - - return req->reqid; + request_add_agents (self, parent); + parent->idle_id = g_idle_add (request_start, req); + return parent->reqid; } /*************************************************************/ @@ -1268,40 +1338,33 @@ delete_done_cb (NMSecretAgent *agent, g_return_if_fail (call_id == req->current_call_id); - req->current = NULL; - req->current_call_id = NULL; - 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, + nm_secret_agent_get_description (agent), req, req->detail, 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->detail); } /* Tell the next agent to delete secrets */ - req->next_callback (req); + request_next_agent (req); } static void -delete_next_cb (Request *req) +delete_next_cb (Request *parent) { - if (!next_generic (req, "deleting")) - return; + ConnectionRequest *req = (ConnectionRequest *) parent; - req->current_call_id = nm_secret_agent_delete_secrets (NM_SECRET_AGENT (req->current), - req->connection, - delete_done_cb, - req); - if (req->current_call_id == NULL) { + parent->current_call_id = nm_secret_agent_delete_secrets (parent->current, + req->connection, + delete_done_cb, + req); + if (parent->current_call_id == NULL) { /* Shouldn't hit this, but handle it anyway */ - g_warn_if_fail (req->current_call_id != NULL); - req->current = NULL; - req->next_callback (req); + g_warn_if_fail (parent->current_call_id != NULL); + request_next_agent (parent); } } @@ -1310,46 +1373,45 @@ delete_complete_cb (Request *req, GHashTable *secrets, const char *agent_dbus_owner, const char *agent_username, - gboolean agent_has_modify, GError *error, gpointer user_data) { - NMAgentManager *self = NM_AGENT_MANAGER (user_data); - NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); - - g_hash_table_remove (priv->requests, GUINT_TO_POINTER (req->reqid)); + g_hash_table_remove (NM_AGENT_MANAGER_GET_PRIVATE (user_data)->requests, + GUINT_TO_POINTER (req->reqid)); } guint32 nm_agent_manager_delete_secrets (NMAgentManager *self, - NMConnection *connection, - gboolean filter_by_uid, - gulong uid_filter) + NMConnection *connection) { NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); - Request *req; + NMAuthSubject *subject; + ConnectionRequest *req; + Request *parent; g_return_val_if_fail (self != NULL, 0); - g_return_val_if_fail (connection != NULL, 0); g_return_val_if_fail (NM_IS_CONNECTION (connection), 0); nm_log_dbg (LOGD_SETTINGS, - "Deleting secrets for connection %s", - nm_connection_get_path (connection)); - - req = request_new_other (connection, - filter_by_uid, - uid_filter, - delete_complete_cb, - self, - delete_next_cb); - g_hash_table_insert (priv->requests, GUINT_TO_POINTER (req->reqid), req); + "Deleting secrets for connection %s (%s)", + nm_connection_get_path (connection), + nm_connection_get_id (connection)); + + subject = nm_auth_subject_new_internal (); + req = connection_request_new_other (connection, + subject, + "deleting", + delete_complete_cb, + self, + delete_next_cb); + g_object_unref (subject); + parent = (Request *) req; + g_hash_table_insert (priv->requests, GUINT_TO_POINTER (parent->reqid), req); /* Kick off the request */ - request_add_agents (self, req); - req->idle_id = g_idle_add (start_generic, req); - - return req->reqid; + request_add_agents (self, parent); + parent->idle_id = g_idle_add (request_start, req); + return parent->reqid; } /*************************************************************/ @@ -1372,6 +1434,30 @@ nm_agent_manager_get_agent_by_user (NMAgentManager *self, const char *username) /*************************************************************/ +gboolean +nm_agent_manager_all_agents_have_capability (NMAgentManager *manager, + NMAuthSubject *subject, + NMSecretAgentCapabilities capability) +{ + NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (manager); + GHashTableIter iter; + NMSecretAgent *agent; + + g_hash_table_iter_init (&iter, priv->agents); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &agent)) { + if ( !nm_auth_subject_get_internal (subject) + && nm_secret_agent_get_owner_uid (agent) != nm_auth_subject_get_uid (subject)) + continue; + + if (!(nm_secret_agent_get_capabilities (agent) & capability)) + return FALSE; + } + + return TRUE; +} + +/*************************************************************/ + static void name_owner_changed_cb (NMDBusManager *dbus_mgr, const char *name, @@ -1394,32 +1480,29 @@ agent_permissions_changed_done (NMAuthChain *chain, NMAgentManager *self = NM_AGENT_MANAGER (user_data); NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); NMSecretAgent *agent; - NMAuthCallResult result; + gboolean share_protected = FALSE, share_open = FALSE; priv->chains = g_slist_remove (priv->chains, chain); agent = nm_auth_chain_get_data (chain, "agent"); + g_assert (agent); if (error) { nm_log_dbg (LOGD_AGENTS, "(%s) failed to request updated agent permissions", nm_secret_agent_get_description (agent)); - nm_secret_agent_add_permission (agent, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED, FALSE); - nm_secret_agent_add_permission (agent, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, FALSE); } else { nm_log_dbg (LOGD_AGENTS, "(%s) updated agent permissions", nm_secret_agent_get_description (agent)); - result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED); - nm_secret_agent_add_permission (agent, - NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED, - (result == NM_AUTH_CALL_RESULT_YES)); - - result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN); - nm_secret_agent_add_permission (agent, - NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, - (result == NM_AUTH_CALL_RESULT_YES)); + if (nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED) == NM_AUTH_CALL_RESULT_YES) + share_protected = TRUE; + if (nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN) == NM_AUTH_CALL_RESULT_YES) + share_open = TRUE; } + nm_secret_agent_add_permission (agent, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED, share_protected); + nm_secret_agent_add_permission (agent, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, share_open); + nm_auth_chain_unref (chain); } @@ -1435,11 +1518,14 @@ authority_changed_cb (gpointer user_data) g_hash_table_iter_init (&iter, priv->agents); while (g_hash_table_iter_next (&iter, NULL, (gpointer) &agent)) { NMAuthChain *chain; - const char *sender; /* Kick off permissions requests for this agent */ - sender = nm_secret_agent_get_dbus_owner (agent); - chain = nm_auth_chain_new_dbus_sender (sender, agent_permissions_changed_done, self); + chain = nm_auth_chain_new_subject (nm_secret_agent_get_subject (agent), + NULL, + agent_permissions_changed_done, + self); + g_assert (chain); + priv->chains = g_slist_append (priv->chains, chain); /* Make sure if the agent quits while the permissions call is in progress * that the object sticks around until our callback. @@ -1447,8 +1533,6 @@ authority_changed_cb (gpointer user_data) nm_auth_chain_set_data (chain, "agent", g_object_ref (agent), g_object_unref); nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED, FALSE); nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, FALSE); - - priv->chains = g_slist_append (priv->chains, chain); } } @@ -1459,7 +1543,6 @@ nm_agent_manager_get (void) { static NMAgentManager *singleton = NULL; NMAgentManagerPrivate *priv; - DBusGConnection *connection; if (singleton) return g_object_ref (singleton); @@ -1468,13 +1551,9 @@ nm_agent_manager_get (void) g_assert (singleton); priv = NM_AGENT_MANAGER_GET_PRIVATE (singleton); - priv->session_monitor = nm_session_monitor_get (); priv->dbus_mgr = nm_dbus_manager_get (); - connection = nm_dbus_manager_get_connection (priv->dbus_mgr); - dbus_g_connection_register_g_object (connection, - NM_DBUS_PATH_AGENT_MANAGER, - G_OBJECT (singleton)); + nm_dbus_manager_register_object (priv->dbus_mgr, NM_DBUS_PATH_AGENT_MANAGER, singleton); g_signal_connect (priv->dbus_mgr, NM_DBUS_MANAGER_NAME_OWNER_CHANGED, @@ -1513,8 +1592,7 @@ dispose (GObject *object) g_hash_table_destroy (priv->agents); g_hash_table_destroy (priv->requests); - g_object_unref (priv->session_monitor); - g_object_unref (priv->dbus_mgr); + priv->dbus_mgr = NULL; } G_OBJECT_CLASS (nm_agent_manager_parent_class)->dispose (object); |