diff --git a/include/nm-macros-internal.h b/include/nm-macros-internal.h index 291dc0742a..7ae08bf727 100644 --- a/include/nm-macros-internal.h +++ b/include/nm-macros-internal.h @@ -175,6 +175,7 @@ (cond) ? (prefix) : "", \ (cond) ? (str) : (str_else), \ (cond) ? (suffix) : "" +#define NM_PRINT_FMT_QUOTE_STRING(arg) NM_PRINT_FMT_QUOTED((arg), "\"", (arg), "\"", "(null)") /*****************************************************************************/ diff --git a/libnm-core/nm-dbus-utils.c b/libnm-core/nm-dbus-utils.c index 730a0eb3ec..8627278623 100644 --- a/libnm-core/nm-dbus-utils.c +++ b/libnm-core/nm-dbus-utils.c @@ -269,6 +269,11 @@ _nm_dbus_proxy_call_sync (GDBusProxy *proxy, * * Checks if @error is set and corresponds to the D-Bus error @dbus_error_name. * + * This should only be used for "foreign" D-Bus errors (eg, errors + * from BlueZ or wpa_supplicant). All NetworkManager D-Bus errors + * should be properly mapped by gdbus to one of the domains/codes in + * nm-errors.h. + * * Returns: %TRUE or %FALSE */ gboolean diff --git a/src/nm-bus-manager.c b/src/nm-bus-manager.c index 584db5e8a6..5f528a6f0e 100644 --- a/src/nm-bus-manager.c +++ b/src/nm-bus-manager.c @@ -847,10 +847,38 @@ nm_bus_manager_unregister_object (NMBusManager *self, gpointer object) g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (object)); } +gboolean +nm_bus_manager_connection_is_private (NMBusManager *self, + GDBusConnection *connection) +{ + NMBusManagerPrivate *priv; + GSList *iter; + + g_return_val_if_fail (NM_IS_BUS_MANAGER (self), FALSE); + g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE); + + if (g_dbus_connection_get_unique_name (connection)) + return FALSE; + + /* Assert that we still track the private connection. The caller + * of nm_bus_manager_connection_is_private() want's to subscribe + * to NM_BUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED, thus the signal + * never comes if we don't track the connection. */ + priv = NM_BUS_MANAGER_GET_PRIVATE (self); + for (iter = priv->private_servers; iter; iter = g_slist_next (iter)) { + PrivateServer *s = iter->data; + + if (g_hash_table_contains (s->connections, + connection)) + return TRUE; + } + g_return_val_if_reached (TRUE); +} + /** * nm_bus_manager_new_proxy: * @self: the #NMBusManager - * @context: the method call context this proxy should be created + * @connection: the GDBusConnection for which this connection should be created * @proxy_type: the type of #GDBusProxy to create * @name: any name on the message bus * @path: name of the object instance to call methods on @@ -865,23 +893,20 @@ nm_bus_manager_unregister_object (NMBusManager *self, gpointer object) */ GDBusProxy * nm_bus_manager_new_proxy (NMBusManager *self, - GDBusMethodInvocation *context, + GDBusConnection *connection, GType proxy_type, const char *name, const char *path, const char *iface) { NMBusManagerPrivate *priv = NM_BUS_MANAGER_GET_PRIVATE (self); - GDBusConnection *connection; GSList *iter; const char *owner; GDBusProxy *proxy; GError *error = NULL; g_return_val_if_fail (g_type_is_a (proxy_type, G_TYPE_DBUS_PROXY), NULL); - - connection = g_dbus_method_invocation_get_connection (context); - g_assert (connection); + g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL); /* Might be a private connection, for which @name is fake */ for (iter = priv->private_servers; iter; iter = g_slist_next (iter)) { diff --git a/src/nm-bus-manager.h b/src/nm-bus-manager.h index cf6a701f1a..86aa5df6eb 100644 --- a/src/nm-bus-manager.h +++ b/src/nm-bus-manager.h @@ -72,6 +72,9 @@ gboolean nm_bus_manager_get_caller_info (NMBusManager *self, gulong *out_uid, gulong *out_pid); +gboolean nm_bus_manager_connection_is_private (NMBusManager *self, + GDBusConnection *connection); + gboolean nm_bus_manager_get_unix_user (NMBusManager *self, const char *sender, gulong *out_uid); @@ -97,7 +100,7 @@ void nm_bus_manager_private_server_register (NMBusManager *self, const char *tag); GDBusProxy *nm_bus_manager_new_proxy (NMBusManager *self, - GDBusMethodInvocation *context, + GDBusConnection *connection, GType proxy_type, const char *name, const char *path, diff --git a/src/settings/nm-agent-manager.c b/src/settings/nm-agent-manager.c index 34c2fecce1..b3f2f675b0 100644 --- a/src/settings/nm-agent-manager.c +++ b/src/settings/nm-agent-manager.c @@ -40,6 +40,42 @@ #include "nmdbus-agent-manager.h" +NM_DEFINE_SINGLETON_INSTANCE (NMAgentManager); + +#define _NMLOG_PREFIX_NAME "agent-manager" +#define _NMLOG_DOMAIN LOGD_AGENTS +#define _NMLOG(level, agent, ...) \ + G_STMT_START { \ + if (nm_logging_enabled ((level), (_NMLOG_DOMAIN))) { \ + char __prefix1[32]; \ + char __prefix2[128]; \ + NMSecretAgent *__agent = (agent); \ + \ + if (!(self)) \ + g_snprintf (__prefix1, sizeof (__prefix1), "%s%s", ""_NMLOG_PREFIX_NAME"", "[]"); \ + else if ((self) != singleton_instance) \ + g_snprintf (__prefix1, sizeof (__prefix1), "%s[%p]", ""_NMLOG_PREFIX_NAME"", (self)); \ + else \ + g_strlcpy (__prefix1, _NMLOG_PREFIX_NAME, sizeof (__prefix1)); \ + if (__agent) { \ + g_snprintf (__prefix2, sizeof (__prefix2), \ + ": req[%p, %s]", \ + __agent, \ + nm_secret_agent_get_description (__agent)); \ + } else \ + __prefix2[0] = '\0'; \ + _nm_log ((level), (_NMLOG_DOMAIN), 0, \ + "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + __prefix1, __prefix2 _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } \ + } G_STMT_END + +#define LOG_REQ_FMT "[%p/%s%s%s]" +#define LOG_REQ_ARG(req) (req), NM_PRINT_FMT_QUOTE_STRING ((req)->detail) + +#define LOG_REQ2_FMT "[%p/%s%s%s/%s%s%s]" +#define LOG_REQ2_ARG(req) (req), NM_PRINT_FMT_QUOTE_STRING ((req)->parent.detail), NM_PRINT_FMT_QUOTE_STRING ((req)->setting_name) + G_DEFINE_TYPE (NMAgentManager, nm_agent_manager, NM_TYPE_EXPORTED_OBJECT) #define NM_AGENT_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ @@ -94,8 +130,7 @@ remove_agent (NMAgentManager *self, const char *owner) if (!agent) return FALSE; - nm_log_dbg (LOGD_AGENTS, "(%s) agent unregistered or disappeared", - nm_secret_agent_get_description (agent)); + _LOGD (agent, "agent unregistered or disappeared"); /* Remove this agent from any in-progress secrets requests */ g_hash_table_iter_init (&iter, priv->requests); @@ -221,8 +256,7 @@ agent_register_permissions_done (NMAuthChain *chain, sender = nm_secret_agent_get_dbus_owner (agent); g_hash_table_insert (priv->agents, g_strdup (sender), agent); - nm_log_dbg (LOGD_AGENTS, "(%s) agent registered", - nm_secret_agent_get_description (agent)); + _LOGD (agent, "agent registered"); g_dbus_method_invocation_return_value (context, NULL); /* Signal an agent was registered */ @@ -308,8 +342,7 @@ impl_agent_manager_register_with_capabilities (NMAgentManager *self, g_signal_connect (agent, NM_SECRET_AGENT_DISCONNECTED, G_CALLBACK (agent_disconnected_cb), self); - nm_log_dbg (LOGD_AGENTS, "(%s) requesting permissions", - nm_secret_agent_get_description (agent)); + _LOGD (agent, "requesting permissions"); /* Kick off permissions requests for this agent */ chain = nm_auth_chain_new_subject (subject, context, agent_register_permissions_done, self); @@ -388,6 +421,8 @@ typedef void (*RequestCancelFunc) (Request *req); /* Basic secrets request structure */ struct _Request { + NMAgentManager *self; + guint32 reqid; char *detail; char *verb; @@ -396,17 +431,11 @@ struct _Request { /* Current agent being asked for secrets */ NMSecretAgent *current; - gconstpointer current_call_id; + NMSecretAgentCallId current_call_id; /* Stores the sorted list of NMSecretAgents which will be asked for secrets */ GSList *pending; - /* Stores the list of NMSecretAgent hashes that we've already - * asked for secrets, so that we don't ask the same agent twice - * if it quits and re-registers during this secrets request. - */ - GSList *asked; - guint32 idle_id; RequestAddAgentFunc add_agent_callback; @@ -423,6 +452,7 @@ static guint32 next_req_id = 1; static Request * request_new (gsize struct_size, + NMAgentManager *self, const char *detail, const char *verb, NMAuthSubject *subject, @@ -436,6 +466,7 @@ request_new (gsize struct_size, Request *req; req = g_malloc0 (struct_size); + req->self = g_object_ref (self); req->reqid = next_req_id++; req->detail = g_strdup (detail); req->verb = g_strdup (verb); @@ -466,7 +497,12 @@ request_free (Request *req) 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->self); + + if (req->current) + g_object_unref (req->current); + memset (req, 0, sizeof (Request)); g_free (req); } @@ -532,11 +568,12 @@ agent_compare_func (gconstpointer aa, gconstpointer bb, gpointer user_data) static void request_add_agent (Request *req, NMSecretAgent *agent) { + NMAgentManager *self; + 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; + self = req->self; if (req->add_agent_callback && !req->add_agent_callback (req, agent)) return; @@ -548,18 +585,16 @@ request_add_agent (Request *req, NMSecretAgent *agent) agent_uid = nm_secret_agent_get_owner_uid (agent); subject_uid = nm_auth_subject_get_unix_process_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); + _LOGD (agent, "agent ignored for secrets request "LOG_REQ_FMT" " + "(uid %ld not required %ld)", + LOG_REQ_ARG (req), + (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->detail); + _LOGD (agent, "agent allowed for secrets request "LOG_REQ_FMT, + LOG_REQ_ARG (req)); /* Add this agent to the list, sorted appropriately */ req->pending = g_slist_insert_sorted_with_data (req->pending, @@ -583,25 +618,28 @@ request_add_agents (NMAgentManager *self, Request *req) static void request_next_agent (Request *req) { + NMAgentManager *self; GError *error = NULL; - req->current_call_id = NULL; - if (req->current) - g_object_unref (req->current); + self = req->self; + + if (req->current) { + if (req->current_call_id) + nm_secret_agent_cancel_secrets (req->current, req->current_call_id); + g_clear_object (&req->current); + } + g_warn_if_fail (!req->current_call_id); if (req->pending) { /* Send the request to the next agent */ 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), - req->verb, req, req->detail); + _LOGD (req->current, "agent %s secrets for request "LOG_REQ_FMT, + req->verb, LOG_REQ_ARG (req)); req->next_callback (req); } else { - req->current = 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, @@ -614,18 +652,26 @@ request_next_agent (Request *req) static void request_remove_agent (Request *req, NMSecretAgent *agent, GSList **pending_reqs) { + NMAgentManager *self; + g_return_if_fail (req != NULL); g_return_if_fail (agent != NULL); - req->pending = g_slist_remove (req->pending, agent); + self = req->self; 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); + nm_assert (!g_slist_find (req->pending, agent)); + + _LOGD (agent, "current agent removed from secrets request "LOG_REQ_FMT, + LOG_REQ_ARG (req)); *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); + req->pending = g_slist_remove (req->pending, agent); + + _LOGD (agent, "agent removed from secrets request "LOG_REQ_FMT, + LOG_REQ_ARG (req)); + + g_object_unref (agent); } } @@ -682,16 +728,18 @@ connection_request_free (gpointer data) static gboolean connection_request_add_agent (Request *parent, NMSecretAgent *agent) { + NMAgentManager *self; ConnectionRequest *req = (ConnectionRequest *) parent; NMAuthSubject *subject = nm_secret_agent_get_subject(agent); + self = parent->self; + /* Ensure the caller's username exists in the connection's permissions, * or that the permissions is empty (ie, visible by everyone). */ if (!nm_auth_is_subject_in_acl (req->connection, subject, 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); + _LOGD (agent, "agent ignored for secrets request "LOG_REQ_FMT" (not in ACL)", + LOG_REQ_ARG (parent)); /* Connection not visible to this agent's user */ return FALSE; } @@ -700,7 +748,8 @@ connection_request_add_agent (Request *parent, NMSecretAgent *agent) } static ConnectionRequest * -connection_request_new_get (NMConnection *connection, +connection_request_new_get (NMAgentManager *self, + NMConnection *connection, NMAuthSubject *subject, GVariant *existing_secrets, const char *setting_name, @@ -719,6 +768,7 @@ connection_request_new_get (NMConnection *connection, ConnectionRequest *req; req = (ConnectionRequest *) request_new (sizeof (ConnectionRequest), + self, nm_connection_get_id (connection), verb, subject, @@ -744,7 +794,8 @@ connection_request_new_get (NMConnection *connection, } static ConnectionRequest * -connection_request_new_other (NMConnection *connection, +connection_request_new_other (NMAgentManager *self, + NMConnection *connection, NMAuthSubject *subject, const char *verb, RequestCompleteFunc complete_callback, @@ -754,6 +805,7 @@ connection_request_new_other (NMConnection *connection, ConnectionRequest *req; req = (ConnectionRequest *) request_new (sizeof (ConnectionRequest), + self, nm_connection_get_id (connection), verb, subject, @@ -770,11 +822,12 @@ connection_request_new_other (NMConnection *connection, static void get_done_cb (NMSecretAgent *agent, - gconstpointer call_id, + NMSecretAgentCallId call_id, GVariant *secrets, GError *error, gpointer user_data) { + NMAgentManager *self; Request *parent = user_data; ConnectionRequest *req = user_data; GVariant *setting_secrets; @@ -783,15 +836,24 @@ get_done_cb (NMSecretAgent *agent, char *agent_uname = NULL; g_return_if_fail (call_id == parent->current_call_id); + g_return_if_fail (agent == parent->current); + + self = parent->self; + + parent->current_call_id = NULL; if (error) { - nm_log_dbg (LOGD_AGENTS, "(%s) agent failed secrets request %p/%s/%s: (%d) %s", - nm_secret_agent_get_description (agent), - req, parent->detail, req->setting_name, - error ? error->code : -1, - (error && error->message) ? error->message : "(unknown)"); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + _LOGD (agent, "get secrets request cancelled: "LOG_REQ2_FMT, + LOG_REQ2_ARG (req)); + return; + } - if (_nm_dbus_error_has_name (error, NM_DBUS_INTERFACE_SECRET_AGENT ".UserCanceled")) { + _LOGD (agent, "agent failed secrets request "LOG_REQ2_FMT": %s", + LOG_REQ2_ARG (req), + error->message); + + if (g_error_matches (error, NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_USER_CANCELED)) { error = g_error_new_literal (NM_AGENT_MANAGER_ERROR, NM_AGENT_MANAGER_ERROR_USER_CANCELED, "User canceled the secrets request."); @@ -808,17 +870,15 @@ get_done_cb (NMSecretAgent *agent, /* Ensure the setting we wanted secrets for got returned and has something in it */ setting_secrets = g_variant_lookup_value (secrets, req->setting_name, NM_VARIANT_TYPE_SETTING); if (!setting_secrets || !g_variant_n_children (setting_secrets)) { - nm_log_dbg (LOGD_AGENTS, "(%s) agent returned no secrets for request %p/%s/%s", - nm_secret_agent_get_description (agent), - req, parent->detail, req->setting_name); + _LOGD (agent, "agent returned no secrets for request "LOG_REQ2_FMT, + LOG_REQ2_ARG (req)); /* Try the next agent */ request_next_agent (parent); return; } - nm_log_dbg (LOGD_AGENTS, "(%s) agent returned secrets for request %p/%s/%s", - nm_secret_agent_get_description (agent), - req, parent->detail, req->setting_name); + _LOGD (agent, "agent returned secrets for request "LOG_REQ2_FMT, + LOG_REQ2_ARG (req)); /* Get the agent's username */ pw = getpwuid (nm_secret_agent_get_owner_uid (agent)); @@ -900,9 +960,8 @@ get_agent_request_secrets (ConnectionRequest *req, gboolean include_system_secre req->flags, get_done_cb, req); - if (parent->current_call_id == NULL) { - /* Shouldn't hit this, but handle it anyway */ - g_warn_if_fail (parent->current_call_id != NULL); + if (!parent->current_call_id) { + g_warn_if_reached (); request_next_agent (parent); } @@ -915,17 +974,19 @@ get_agent_modify_auth_cb (NMAuthChain *chain, GDBusMethodInvocation *context, gpointer user_data) { + NMAgentManager *self; Request *parent = user_data; ConnectionRequest *req = user_data; const char *perm; + self = parent->self; + req->chain = NULL; if (error) { - 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)"); + _LOGD (parent->current, "agent "LOG_REQ2_FMT" MODIFY check error: (%d) %s", + LOG_REQ2_ARG (req), + error->code, error->message ? error->message : "(unknown)"); /* Try the next agent */ request_next_agent (parent); } else { @@ -938,10 +999,9 @@ get_agent_modify_auth_cb (NMAuthChain *chain, if (nm_auth_chain_get_result (chain, perm) == NM_AUTH_CALL_RESULT_YES) req->current_has_modify = TRUE; - 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"); + _LOGD (parent->current, "agent "LOG_REQ2_FMT" MODIFY check result %s", + LOG_REQ2_ARG (req), + req->current_has_modify ? "YES" : "NO"); get_agent_request_secrets (req, req->current_has_modify); } @@ -995,10 +1055,13 @@ has_system_secrets (NMConnection *connection) static void get_next_cb (Request *parent) { + NMAgentManager *self; ConnectionRequest *req = (ConnectionRequest *) parent; NMSettingConnection *s_con; const char *agent_dbus_owner, *perm; + self = parent->self; + req->current_has_modify = FALSE; agent_dbus_owner = nm_secret_agent_get_dbus_owner (parent->current); @@ -1011,8 +1074,8 @@ get_next_cb (Request *parent) */ if ( (req->flags != NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE) && (req->existing_secrets || has_system_secrets (req->connection))) { - 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); + _LOGD (NULL, "("LOG_REQ2_FMT") request has system secrets; checking agent %s for MODIFY", + LOG_REQ2_ARG (req), agent_dbus_owner); req->chain = nm_auth_chain_new_subject (nm_secret_agent_get_subject (parent->current), NULL, @@ -1034,8 +1097,8 @@ get_next_cb (Request *parent) nm_auth_chain_add_call (req->chain, perm, TRUE); } else { - nm_log_dbg (LOGD_AGENTS, "(%p/%s/%s) requesting user-owned secrets from agent %s", - req, parent->detail, req->setting_name, agent_dbus_owner); + _LOGD (NULL, "("LOG_REQ2_FMT") requesting user-owned secrets from agent %s", + LOG_REQ2_ARG (req), agent_dbus_owner); get_agent_request_secrets (req, FALSE); } @@ -1044,10 +1107,13 @@ get_next_cb (Request *parent) static gboolean get_start (gpointer user_data) { + NMAgentManager *self; Request *parent = user_data; ConnectionRequest *req = user_data; GVariant *setting_secrets = NULL; + self = parent->self; + parent->idle_id = 0; /* Check if there are any existing secrets */ @@ -1074,14 +1140,14 @@ get_start (gpointer user_data) /* Do we have everything we need? */ if ( (req->flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_ONLY_SYSTEM) || ((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); + _LOGD (NULL, "("LOG_REQ2_FMT") system settings secrets sufficient", + LOG_REQ2_ARG (req)); /* Got everything, we're done */ req_complete_success (parent, req->existing_secrets, NULL, NULL); } else { - nm_log_dbg (LOGD_AGENTS, "(%p/%s/%s) system settings secrets insufficient, asking agents", - req, parent->detail, req->setting_name); + _LOGD (NULL, "("LOG_REQ2_FMT") system settings secrets insufficient, asking agents", + LOG_REQ2_ARG (req)); /* We don't, so ask some agents for additional secrets */ if ( req->flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_NO_ERRORS @@ -1180,7 +1246,8 @@ nm_agent_manager_get_secrets (NMAgentManager *self, * both returning NULL if they didn't hash anything. */ - req = connection_request_new_get (connection, + req = connection_request_new_get (self, + connection, subject, existing_secrets, setting_name, @@ -1220,32 +1287,40 @@ nm_agent_manager_cancel_secrets (NMAgentManager *self, static void save_done_cb (NMSecretAgent *agent, - gconstpointer call_id, + NMSecretAgentCallId call_id, GVariant *secrets, GError *error, gpointer user_data) { - Request *parent = user_data; + NMAgentManager *self; ConnectionRequest *req = user_data; + Request *parent = (Request *) req; const char *agent_dbus_owner; g_return_if_fail (call_id == parent->current_call_id); + g_return_if_fail (agent == parent->current); + + self = parent->self; + + parent->current_call_id = NULL; if (error) { - nm_log_dbg (LOGD_AGENTS, "(%s) agent failed save secrets request %p/%s: (%d) %s", - nm_secret_agent_get_description (agent), - req, parent->detail, - error ? error->code : -1, - (error && error->message) ? error->message : "(unknown)"); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + _LOGD (agent, "save secrets request cancelled: "LOG_REQ_FMT, + LOG_REQ_ARG (parent)); + return; + } + + _LOGD (agent, "agent failed save secrets request "LOG_REQ_FMT": %s", + LOG_REQ_ARG (parent), error->message); /* Try the next agent */ request_next_agent (parent); maybe_remove_agent_on_error (agent, error); return; } - nm_log_dbg (LOGD_AGENTS, "(%s) agent saved secrets for request %p/%s", - nm_secret_agent_get_description (agent), - req, parent->detail); + _LOGD (agent, "agent saved secrets for request "LOG_REQ_FMT, + LOG_REQ_ARG (parent)); agent_dbus_owner = nm_secret_agent_get_dbus_owner (agent); req_complete_success (parent, NULL, NULL, agent_dbus_owner); @@ -1260,9 +1335,8 @@ save_next_cb (Request *parent) req->connection, save_done_cb, req); - if (parent->current_call_id == NULL) { - /* Shouldn't hit this, but handle it anyway */ - g_warn_if_fail (parent->current_call_id != NULL); + if (!parent->current_call_id) { + g_warn_if_reached (); request_next_agent (parent); } } @@ -1296,7 +1370,8 @@ nm_agent_manager_save_secrets (NMAgentManager *self, nm_connection_get_path (connection), nm_connection_get_id (connection)); - req = connection_request_new_other (connection, + req = connection_request_new_other (self, + connection, subject, "saving", save_complete_cb, @@ -1315,23 +1390,33 @@ nm_agent_manager_save_secrets (NMAgentManager *self, static void delete_done_cb (NMSecretAgent *agent, - gconstpointer call_id, - GVariant *secrets, - GError *error, - gpointer user_data) + NMSecretAgentCallId call_id, + GVariant *secrets, + GError *error, + gpointer user_data) { + NMAgentManager *self; Request *req = user_data; g_return_if_fail (call_id == req->current_call_id); + g_return_if_fail (agent == req->current); + + self = req->self; + + 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->detail, - error ? error->code : -1, - (error && error->message) ? error->message : "(unknown)"); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + _LOGD (agent, "delete secrets request cancelled: "LOG_REQ_FMT, + LOG_REQ_ARG (req)); + return; + } + + _LOGD (agent, "agent failed delete secrets request "LOG_REQ_FMT": %s", + LOG_REQ_ARG (req), error->message); } else { - nm_log_dbg (LOGD_AGENTS, "(%s) agent deleted secrets for request %p/%s", - nm_secret_agent_get_description (agent), req, req->detail); + _LOGD (agent, "agent deleted secrets for request "LOG_REQ_FMT, + LOG_REQ_ARG (req)); } /* Tell the next agent to delete secrets */ @@ -1349,9 +1434,8 @@ delete_next_cb (Request *parent) req->connection, delete_done_cb, req); - if (parent->current_call_id == NULL) { - /* Shouldn't hit this, but handle it anyway */ - g_warn_if_fail (parent->current_call_id != NULL); + if (!parent->current_call_id) { + g_warn_if_reached (); request_next_agent (parent); } } @@ -1386,7 +1470,8 @@ nm_agent_manager_delete_secrets (NMAgentManager *self, nm_connection_get_id (connection)); subject = nm_auth_subject_new_internal (); - req = connection_request_new_other (connection, + req = connection_request_new_other (self, + connection, subject, "deleting", delete_complete_cb, @@ -1464,12 +1549,10 @@ agent_permissions_changed_done (NMAuthChain *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)); - } else { - nm_log_dbg (LOGD_AGENTS, "(%s) updated agent permissions", - nm_secret_agent_get_description (agent)); + if (error) + _LOGD (agent, "failed to request updated agent permissions"); + else { + _LOGD (agent, "updated agent permissions"); if (nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED) == NM_AUTH_CALL_RESULT_YES) share_protected = TRUE; diff --git a/src/settings/nm-secret-agent.c b/src/settings/nm-secret-agent.c index c2c220fd41..d77f5e0e29 100644 --- a/src/settings/nm-secret-agent.c +++ b/src/settings/nm-secret-agent.c @@ -32,6 +32,26 @@ #include "nmdbus-secret-agent.h" +#define _NMLOG_PREFIX_NAME "secret-agent" +#define _NMLOG_DOMAIN LOGD_AGENTS +#define _NMLOG(level, ...) \ + G_STMT_START { \ + if (nm_logging_enabled ((level), (_NMLOG_DOMAIN))) { \ + char __prefix[32]; \ + \ + if ((self)) \ + g_snprintf (__prefix, sizeof (__prefix), "%s[%p]", ""_NMLOG_PREFIX_NAME"", (self)); \ + else \ + g_strlcpy (__prefix, _NMLOG_PREFIX_NAME, sizeof (__prefix)); \ + _nm_log ((level), (_NMLOG_DOMAIN), 0, \ + "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + __prefix _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } \ + } G_STMT_END + +#define LOG_REQ_FMT "req[%p,%s,%s%s%s%s]" +#define LOG_REQ_ARG(req) (req), (req)->dbus_command, NM_PRINT_FMT_QUOTE_STRING ((req)->path), ((req)->cancellable ? "" : " (cancelled)") + G_DEFINE_TYPE (NMSecretAgent, nm_secret_agent, G_TYPE_OBJECT) #define NM_SECRET_AGENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ @@ -45,11 +65,14 @@ typedef struct { char *owner_username; char *dbus_owner; NMSecretAgentCapabilities capabilities; - guint32 hash; GSList *permissions; NMDBusSecretAgent *proxy; + NMBusManager *bus_mgr; + GDBusConnection *connection; + gboolean connection_is_private; + guint on_disconnected_id; GHashTable *requests; } NMSecretAgentPrivate; @@ -63,17 +86,22 @@ static guint signals[LAST_SIGNAL] = { 0 }; /*************************************************************/ -typedef struct { +struct _NMSecretAgentCallId { NMSecretAgent *agent; GCancellable *cancellable; char *path; + const char *dbus_command; char *setting_name; + gboolean is_get_secrets; NMSecretAgentCallback callback; gpointer callback_data; -} Request; +}; + +typedef struct _NMSecretAgentCallId Request; static Request * -request_new (NMSecretAgent *agent, +request_new (NMSecretAgent *self, + const char *dbus_command, /* this must be a static string. */ const char *path, const char *setting_name, NMSecretAgentCallback callback, @@ -82,26 +110,60 @@ request_new (NMSecretAgent *agent, Request *r; r = g_slice_new0 (Request); - r->agent = agent; + r->agent = self; r->path = g_strdup (path); r->setting_name = g_strdup (setting_name); + r->dbus_command = dbus_command, r->callback = callback; r->callback_data = callback_data; r->cancellable = g_cancellable_new (); + _LOGT ("request "LOG_REQ_FMT": created", LOG_REQ_ARG (r)); return r; } +#define request_new(self,dbus_command,path,setting_name,callback,callback_data) request_new(self,""dbus_command"",path,setting_name,callback,callback_data) static void request_free (Request *r) { + NMSecretAgent *self = r->agent; + + _LOGT ("request "LOG_REQ_FMT": destroyed", LOG_REQ_ARG (r)); g_free (r->path); g_free (r->setting_name); - g_object_unref (r->cancellable); + if (r->cancellable) + g_object_unref (r->cancellable); g_slice_free (Request, r); } +static gboolean +request_check_return (Request *r) +{ + NMSecretAgentPrivate *priv; + + if (!r->cancellable) + return FALSE; + + g_return_val_if_fail (NM_IS_SECRET_AGENT (r->agent), FALSE); + + priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent); + + if (!g_hash_table_remove (priv->requests, r)) + g_return_val_if_reached (FALSE); + + return TRUE; +} + /*************************************************************/ +static char * +_create_description (const char *dbus_owner, const char *identifier, gulong uid) +{ + return g_strdup_printf ("%s/%s/%lu", + dbus_owner, + identifier, + uid); +} + const char * nm_secret_agent_get_description (NMSecretAgent *agent) { @@ -111,10 +173,9 @@ nm_secret_agent_get_description (NMSecretAgent *agent) priv = NM_SECRET_AGENT_GET_PRIVATE (agent); if (!priv->description) { - priv->description = g_strdup_printf ("%s/%s/%lu", - priv->dbus_owner, - priv->identifier, - nm_auth_subject_get_unix_process_uid (priv->subject)); + priv->description = _create_description (priv->dbus_owner, + priv->identifier, + nm_auth_subject_get_unix_process_uid (priv->subject)); } return priv->description; @@ -168,14 +229,6 @@ nm_secret_agent_get_capabilities (NMSecretAgent *agent) return NM_SECRET_AGENT_GET_PRIVATE (agent)->capabilities; } -guint32 -nm_secret_agent_get_hash (NMSecretAgent *agent) -{ - g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), 0); - - return NM_SECRET_AGENT_GET_PRIVATE (agent)->hash; -} - NMAuthSubject * nm_secret_agent_get_subject (NMSecretAgent *agent) { @@ -262,24 +315,22 @@ get_callback (GObject *proxy, gpointer user_data) { Request *r = user_data; - NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent); - GVariant *secrets = NULL; - GError *error = NULL; - if (!g_cancellable_is_cancelled (r->cancellable)) { + if (request_check_return (r)) { + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent); + gs_free_error GError *error = NULL; + gs_unref_variant GVariant *secrets = NULL; + nmdbus_secret_agent_call_get_secrets_finish (priv->proxy, &secrets, result, &error); if (error) g_dbus_error_strip_remote_error (error); - r->callback (r->agent, r, secrets, error, r->callback_data); - g_clear_pointer (&secrets, g_variant_unref); - g_clear_error (&error); } - g_hash_table_remove (priv->requests, r); + request_free (r); } -gconstpointer +NMSecretAgentCallId nm_secret_agent_get_secrets (NMSecretAgent *self, NMConnection *connection, const char *setting_name, @@ -306,7 +357,9 @@ nm_secret_agent_get_secrets (NMSecretAgent *self, flags &= ~NM_SECRET_AGENT_GET_SECRETS_FLAG_ONLY_SYSTEM; flags &= ~NM_SECRET_AGENT_GET_SECRETS_FLAG_NO_ERRORS; - r = request_new (self, nm_connection_get_path (connection), setting_name, callback, callback_data); + r = request_new (self, "GetSecrets", nm_connection_get_path (connection), setting_name, callback, callback_data); + r->is_get_secrets = TRUE; + g_hash_table_add (priv->requests, r); nmdbus_secret_agent_call_get_secrets (priv->proxy, dict, nm_connection_get_path (connection), @@ -315,11 +368,12 @@ nm_secret_agent_get_secrets (NMSecretAgent *self, flags, r->cancellable, get_callback, r); - g_hash_table_insert (priv->requests, r, r); return r; } +/*************************************************************/ + static void cancel_done (GObject *proxy, GAsyncResult *result, gpointer user_data) { @@ -327,33 +381,85 @@ cancel_done (GObject *proxy, GAsyncResult *result, gpointer user_data) GError *error = NULL; if (!nmdbus_secret_agent_call_cancel_get_secrets_finish (NMDBUS_SECRET_AGENT (proxy), result, &error)) { - g_dbus_error_strip_remote_error (error); - nm_log_dbg (LOGD_AGENTS, "(%s): agent failed to cancel secrets: %s", - description, error->message); + nm_log_dbg (LOGD_AGENTS, "%s%s%s: agent failed to cancel secrets: %s", + NM_PRINT_FMT_QUOTED (description, "(", description, ")", "???"), + error->message); g_clear_error (&error); } g_free (description); } +static void +do_cancel_secrets (NMSecretAgent *self, Request *r, gboolean disposing) +{ + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); + GCancellable *cancellable; + NMSecretAgentCallback callback; + gpointer callback_data; + + g_return_if_fail (r->agent == self); + g_return_if_fail (r->cancellable); + + if ( r->is_get_secrets + && priv->proxy) { + /* for GetSecrets call, we must cancel the request. */ + nmdbus_secret_agent_call_cancel_get_secrets (priv->proxy, + r->path, r->setting_name, + NULL, + cancel_done, + g_strdup (nm_secret_agent_get_description (self))); + } + + cancellable = r->cancellable; + callback = r->callback; + callback_data = r->callback_data; + + /* During g_cancellable_cancel() the d-bus method might return synchronously. + * Clear r->cancellable first, so that it doesn't actually do anything. + * After that, @r might be already freed. */ + r->cancellable = NULL; + g_cancellable_cancel (cancellable); + g_object_unref (cancellable); + + /* Don't free the request @r. It will be freed when the d-bus call returns. + * Only clear r->cancellable to indicate that the request was cancelled. */ + + if (callback) { + GError *error = NULL; + + if (disposing) { + /* hijack an error code. G_IO_ERROR_CANCELLED is only used synchronously + * when the user calls nm_act_request_cancel_secrets(). + * When the user disposes the instance, we also invoke the callback synchronously, + * but with a different error-reason. */ + g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Disposing NMSecretAgent instance"); + } else { + g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_CANCELLED, + "Request cancelled"); + } + /* @r might be a dangling pointer at this point. However, that is no problem + * to pass it as (opaque) call_id. */ + callback (self, r, NULL, error, callback_data); + g_error_free (error); + } +} + void -nm_secret_agent_cancel_secrets (NMSecretAgent *self, gconstpointer call) +nm_secret_agent_cancel_secrets (NMSecretAgent *self, NMSecretAgentCallId call_id) { NMSecretAgentPrivate *priv; - Request *r = (gpointer) call; + Request *r = call_id; + + g_return_if_fail (NM_IS_SECRET_AGENT (self)); + g_return_if_fail (r); - g_return_if_fail (self != NULL); priv = NM_SECRET_AGENT_GET_PRIVATE (self); - g_return_if_fail (priv->proxy != NULL); - g_return_if_fail (r != NULL); + if (!g_hash_table_remove (priv->requests, r)) + g_return_if_reached (); - g_cancellable_cancel (r->cancellable); - - nmdbus_secret_agent_call_cancel_get_secrets (priv->proxy, - r->path, r->setting_name, - NULL, - cancel_done, - g_strdup (nm_secret_agent_get_description (self))); + do_cancel_secrets (self, r, FALSE); } /*************************************************************/ @@ -364,21 +470,21 @@ agent_save_cb (GObject *proxy, gpointer user_data) { Request *r = user_data; - NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent); - GError *error = NULL; - if (!g_cancellable_is_cancelled (r->cancellable)) { + if (request_check_return (r)) { + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent); + gs_free_error GError *error = NULL; + nmdbus_secret_agent_call_save_secrets_finish (priv->proxy, result, &error); if (error) g_dbus_error_strip_remote_error (error); r->callback (r->agent, r, NULL, error, r->callback_data); - g_clear_error (&error); } - g_hash_table_remove (priv->requests, r); + request_free (r); } -gconstpointer +NMSecretAgentCallId nm_secret_agent_save_secrets (NMSecretAgent *self, NMConnection *connection, NMSecretAgentCallback callback, @@ -398,35 +504,39 @@ nm_secret_agent_save_secrets (NMSecretAgent *self, /* Caller should have ensured that only agent-owned secrets exist in 'connection' */ dict = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL); - r = request_new (self, cpath, NULL, callback, callback_data); + r = request_new (self, "SaveSecrets", cpath, NULL, callback, callback_data); + g_hash_table_add (priv->requests, r); nmdbus_secret_agent_call_save_secrets (priv->proxy, dict, cpath, - NULL, + NULL, /* cancelling the request does *not* cancel the D-Bus call. */ agent_save_cb, r); - g_hash_table_insert (priv->requests, r, r); return r; } +/*************************************************************/ + static void agent_delete_cb (GObject *proxy, GAsyncResult *result, gpointer user_data) { Request *r = user_data; - NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent); - GError *error = NULL; - if (!g_cancellable_is_cancelled (r->cancellable)) { + if (request_check_return (r)) { + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent); + gs_free_error GError *error = NULL; + nmdbus_secret_agent_call_delete_secrets_finish (priv->proxy, result, &error); + if (error) + g_dbus_error_strip_remote_error (error); r->callback (r->agent, r, NULL, error, r->callback_data); - g_clear_error (&error); } - g_hash_table_remove (priv->requests, r); + request_free (r); } -gconstpointer +NMSecretAgentCallId nm_secret_agent_delete_secrets (NMSecretAgent *self, NMConnection *connection, NMSecretAgentCallback callback, @@ -446,34 +556,80 @@ nm_secret_agent_delete_secrets (NMSecretAgent *self, /* No secrets sent; agents must be smart enough to track secrets using the UUID or something */ dict = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_NO_SECRETS); - r = request_new (self, cpath, NULL, callback, callback_data); + r = request_new (self, "DeleteSecrets", cpath, NULL, callback, callback_data); + g_hash_table_add (priv->requests, r); nmdbus_secret_agent_call_delete_secrets (priv->proxy, dict, cpath, - NULL, + NULL, /* cancelling the request does *not* cancel the D-Bus call. */ agent_delete_cb, r); - g_hash_table_insert (priv->requests, r, r); return r; } +/*************************************************************/ + static void -name_owner_changed_cb (GObject *proxy, - GParamSpec *pspec, - gpointer user_data) +_on_disconnected_cleanup (NMSecretAgentPrivate *priv) +{ + if (priv->on_disconnected_id) { + if (priv->connection_is_private) { + g_signal_handler_disconnect (priv->bus_mgr, + priv->on_disconnected_id); + } else { + g_dbus_connection_signal_unsubscribe (priv->connection, + priv->on_disconnected_id); + } + priv->on_disconnected_id = 0; + } + + g_clear_object (&priv->connection); + g_clear_object (&priv->proxy); + g_clear_object (&priv->bus_mgr); +} + +static void +_on_disconnected_private_connection (NMBusManager *mgr, + GDBusConnection *connection, + NMSecretAgent *self) +{ + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); + + if (priv->connection != connection) + return; + + _LOGT ("private connection disconnected"); + + _on_disconnected_cleanup (priv); + g_signal_emit (self, signals[DISCONNECTED], 0); +} + +static void +_on_disconnected_name_owner_changed (GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) { NMSecretAgent *self = NM_SECRET_AGENT (user_data); NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); - char *owner; + const char *old_owner, *new_owner; - owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (proxy)); - if (!owner) { - g_signal_handlers_disconnect_by_func (priv->proxy, name_owner_changed_cb, self); - g_clear_object (&priv->proxy); + g_variant_get (parameters, + "(&s&s&s)", + NULL, + &old_owner, + &new_owner); + + _LOGT ("name-owner-changed: %s%s%s => %s%s%s", + NM_PRINT_FMT_QUOTE_STRING (old_owner), + NM_PRINT_FMT_QUOTE_STRING (new_owner)); + + if (!*new_owner) { + _on_disconnected_cleanup (priv); g_signal_emit (self, signals[DISCONNECTED], 0); - - g_clear_pointer (&priv->dbus_owner, g_free); - } else - g_free (owner); + } } /*************************************************************/ @@ -486,44 +642,83 @@ nm_secret_agent_new (GDBusMethodInvocation *context, { NMSecretAgent *self; NMSecretAgentPrivate *priv; - char *hash_str; + const char *dbus_owner; struct passwd *pw; GDBusProxy *proxy; + char *owner_username = NULL; + char *description = NULL; + char buf_subject[64]; + gulong uid; + GDBusConnection *connection; g_return_val_if_fail (context != NULL, NULL); g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL); g_return_val_if_fail (nm_auth_subject_is_unix_process (subject), NULL); g_return_val_if_fail (identifier != NULL, NULL); - pw = getpwuid (nm_auth_subject_get_unix_process_uid (subject)); - g_return_val_if_fail (pw != NULL, NULL); - g_return_val_if_fail (pw->pw_name[0] != '\0', NULL); + connection = g_dbus_method_invocation_get_connection (context); + + g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL); + + uid = nm_auth_subject_get_unix_process_uid (subject); + + pw = getpwuid (uid); + if (pw && pw->pw_name && pw->pw_name[0]) + owner_username = g_strdup (pw->pw_name); + + dbus_owner = nm_auth_subject_get_unix_process_dbus_sender (subject); self = (NMSecretAgent *) g_object_new (NM_TYPE_SECRET_AGENT, NULL); + priv = NM_SECRET_AGENT_GET_PRIVATE (self); + priv->bus_mgr = g_object_ref (nm_bus_manager_get ()); + priv->connection = g_object_ref (connection); + priv->connection_is_private = nm_bus_manager_connection_is_private (priv->bus_mgr, connection); + + _LOGT ("constructed: %s, owner=%s%s%s (%s), private-connection=%d, unique-name=%s%s%s", + (description = _create_description (dbus_owner, identifier, uid)), + NM_PRINT_FMT_QUOTE_STRING (owner_username), + nm_auth_subject_to_string (subject, buf_subject, sizeof (buf_subject)), + priv->connection_is_private, + NM_PRINT_FMT_QUOTE_STRING (g_dbus_connection_get_unique_name (priv->connection))); + priv->identifier = g_strdup (identifier); - priv->owner_username = g_strdup (pw->pw_name); - priv->dbus_owner = g_strdup (nm_auth_subject_get_unix_process_dbus_sender (subject)); + priv->owner_username = owner_username; + priv->dbus_owner = g_strdup (dbus_owner); + priv->description = description; priv->capabilities = capabilities; priv->subject = g_object_ref (subject); - hash_str = g_strdup_printf ("%16lu%s", nm_auth_subject_get_unix_process_uid (subject), identifier); - priv->hash = g_str_hash (hash_str); - g_free (hash_str); - - proxy = nm_bus_manager_new_proxy (nm_bus_manager_get (), - context, + proxy = nm_bus_manager_new_proxy (priv->bus_mgr, + priv->connection, NMDBUS_TYPE_SECRET_AGENT_PROXY, priv->dbus_owner, NM_DBUS_PATH_SECRET_AGENT, NM_DBUS_INTERFACE_SECRET_AGENT); g_assert (proxy); - g_signal_connect (proxy, "notify::g-name-owner", - G_CALLBACK (name_owner_changed_cb), - self); priv->proxy = NMDBUS_SECRET_AGENT (proxy); + /* we cannot subscribe to notify::g-name-owner because that doesn't work + * for unique names and it doesn't work for private connections. */ + if (priv->connection_is_private) { + priv->on_disconnected_id = g_signal_connect (priv->bus_mgr, + NM_BUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED, + G_CALLBACK (_on_disconnected_private_connection), + self); + } else { + priv->on_disconnected_id = g_dbus_connection_signal_subscribe (priv->connection, + "org.freedesktop.DBus", /* name */ + "org.freedesktop.DBus", /* interface */ + "NameOwnerChanged", /* signal name */ + "/org/freedesktop/DBus", /* path */ + priv->dbus_owner, /* arg0 */ + G_DBUS_SIGNAL_FLAGS_NONE, + _on_disconnected_name_owner_changed, + self, + NULL); + } + return self; } @@ -532,16 +727,25 @@ nm_secret_agent_init (NMSecretAgent *self) { NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); - priv->requests = g_hash_table_new_full (g_direct_hash, g_direct_equal, - NULL, (GDestroyNotify) request_free); + priv->requests = g_hash_table_new (g_direct_hash, g_direct_equal); } static void dispose (GObject *object) { - NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (object); + NMSecretAgent *self = NM_SECRET_AGENT (object); + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); + GHashTableIter iter; + Request *r; + + g_hash_table_iter_init (&iter, priv->requests); + while (g_hash_table_iter_next (&iter, (gpointer *) &r, NULL)) { + g_hash_table_iter_remove (&iter); + do_cancel_secrets (self, r, TRUE); + } + + _on_disconnected_cleanup (priv); - g_clear_object (&priv->proxy); g_clear_object (&priv->subject); G_OBJECT_CLASS (nm_secret_agent_parent_class)->dispose (object); @@ -550,16 +754,20 @@ dispose (GObject *object) static void finalize (GObject *object) { - NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (object); + NMSecretAgent *self = NM_SECRET_AGENT (object); + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); g_free (priv->description); g_free (priv->identifier); g_free (priv->owner_username); + g_free (priv->dbus_owner); g_slist_free_full (priv->permissions, g_free); g_hash_table_destroy (priv->requests); G_OBJECT_CLASS (nm_secret_agent_parent_class)->finalize (object); + + _LOGT ("finalized"); } static void diff --git a/src/settings/nm-secret-agent.h b/src/settings/nm-secret-agent.h index 7883979d5b..b220dfd53f 100644 --- a/src/settings/nm-secret-agent.h +++ b/src/settings/nm-secret-agent.h @@ -43,6 +43,8 @@ typedef struct { void (*disconnected) (NMSecretAgent *self); } NMSecretAgentClass; +typedef struct _NMSecretAgentCallId *NMSecretAgentCallId; + GType nm_secret_agent_get_type (void); NMSecretAgent *nm_secret_agent_new (GDBusMethodInvocation *context, @@ -64,8 +66,6 @@ gulong nm_secret_agent_get_pid (NMSecretAgent *agent); NMSecretAgentCapabilities nm_secret_agent_get_capabilities (NMSecretAgent *agent); -guint32 nm_secret_agent_get_hash (NMSecretAgent *agent); - NMAuthSubject *nm_secret_agent_get_subject (NMSecretAgent *agent); void nm_secret_agent_add_permission (NMSecretAgent *agent, @@ -76,30 +76,30 @@ gboolean nm_secret_agent_has_permission (NMSecretAgent *agent, const char *permission); typedef void (*NMSecretAgentCallback) (NMSecretAgent *agent, - gconstpointer call, + NMSecretAgentCallId call_id, GVariant *new_secrets, /* NULL for save & delete */ GError *error, gpointer user_data); -gconstpointer nm_secret_agent_get_secrets (NMSecretAgent *agent, - NMConnection *connection, - const char *setting_name, - const char **hints, - NMSecretAgentGetSecretsFlags flags, - NMSecretAgentCallback callback, - gpointer callback_data); +NMSecretAgentCallId nm_secret_agent_get_secrets (NMSecretAgent *agent, + NMConnection *connection, + const char *setting_name, + const char **hints, + NMSecretAgentGetSecretsFlags flags, + NMSecretAgentCallback callback, + gpointer callback_data); void nm_secret_agent_cancel_secrets (NMSecretAgent *agent, - gconstpointer call_id); + NMSecretAgentCallId call_id); -gconstpointer nm_secret_agent_save_secrets (NMSecretAgent *agent, - NMConnection *connection, - NMSecretAgentCallback callback, - gpointer callback_data); +NMSecretAgentCallId nm_secret_agent_save_secrets (NMSecretAgent *agent, + NMConnection *connection, + NMSecretAgentCallback callback, + gpointer callback_data); -gconstpointer nm_secret_agent_delete_secrets (NMSecretAgent *agent, - NMConnection *connection, - NMSecretAgentCallback callback, - gpointer callback_data); +NMSecretAgentCallId nm_secret_agent_delete_secrets (NMSecretAgent *agent, + NMConnection *connection, + NMSecretAgentCallback callback, + gpointer callback_data); #endif /* __NETWORKMANAGER_SECRET_AGENT_H__ */