From 991df804086c4a1cee393d6d7182fa40cbba5dd7 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Thu, 13 Nov 2014 20:22:04 +0100 Subject: [PATCH] cli: Process secret agent request for a connection only if we know its path If we're activating the device without knowing the connection in advance, defer servicing the requests for the secrets until we set the path. [lkundrak@fedora20-2 ~]$ nmcli --ask c ifname wlan0 (process:18405): libnm-CRITICAL **: nm_object_get_path: assertion 'NM_IS_OBJECT (object)' failed Error: Connection activation failed: The device has no connections available. [lkundrak@fedora20-2 ~]$ --- clients/cli/agent.c | 3 +- clients/cli/connections.c | 19 ++++++- clients/common/nm-secret-agent-simple.c | 76 ++++++++++++++++++++----- clients/common/nm-secret-agent-simple.h | 5 +- clients/tui/nmtui-connect.c | 21 ++++++- 5 files changed, 103 insertions(+), 21 deletions(-) diff --git a/clients/cli/agent.c b/clients/cli/agent.c index 2b606a7fca..0434e009a2 100644 --- a/clients/cli/agent.c +++ b/clients/cli/agent.c @@ -142,11 +142,12 @@ static NMCResultCode do_agent_secret (NmCli *nmc, int argc, char **argv) { /* Create secret agent */ - nmc->secret_agent = nm_secret_agent_simple_new ("nmcli-agent", NULL); + nmc->secret_agent = nm_secret_agent_simple_new ("nmcli-agent"); if (nmc->secret_agent) { /* We keep running */ nmc->should_wait = TRUE; + nm_secret_agent_simple_enable (nmc->secret_agent); g_signal_connect (nmc->secret_agent, "request-secrets", G_CALLBACK (secrets_requested), nmc); g_print (_("nmcli successfully registered as a NetworkManager's secret agent.\n")); } else { diff --git a/clients/cli/connections.c b/clients/cli/connections.c index 6b823fcd58..49af70f6d4 100644 --- a/clients/cli/connections.c +++ b/clients/cli/connections.c @@ -1780,6 +1780,14 @@ active_connection_state_cb (NMActiveConnection *active, GParamSpec *pspec, gpoin const GPtrArray *devices; NMDevice *device; + if (nmc->secret_agent) { + NMRemoteConnection *connection = nm_active_connection_get_connection (active); + const gchar *path = nm_connection_get_path (NM_CONNECTION (connection)); + + nm_secret_agent_simple_set_connection_path (nmc->secret_agent, path); + nm_secret_agent_simple_enable (nmc->secret_agent); + } + devices = nm_active_connection_get_devices (active); device = devices->len ? g_ptr_array_index (devices, 0) : NULL; if ( device @@ -2164,9 +2172,16 @@ nmc_activate_connection (NmCli *nmc, nmc->pwds_hash = pwds_hash; /* Create secret agent */ - nmc->secret_agent = nm_secret_agent_simple_new ("nmcli-connect", nm_object_get_path (NM_OBJECT (connection))); - if (nmc->secret_agent) + nmc->secret_agent = nm_secret_agent_simple_new ("nmcli-connect"); + if (nmc->secret_agent) { g_signal_connect (nmc->secret_agent, "request-secrets", G_CALLBACK (secrets_requested), nmc); + if (connection) { + const gchar *path = nm_object_get_path (NM_OBJECT (connection)); + + nm_secret_agent_simple_set_connection_path (nmc->secret_agent, path); + nm_secret_agent_simple_enable (nmc->secret_agent); + } + } info = g_malloc0 (sizeof (ActivateConnectionInfo)); info->nmc = nmc; diff --git a/clients/common/nm-secret-agent-simple.c b/clients/common/nm-secret-agent-simple.c index 3848bf9302..24f2b76a5a 100644 --- a/clients/common/nm-secret-agent-simple.c +++ b/clients/common/nm-secret-agent-simple.c @@ -63,6 +63,7 @@ typedef struct { GHashTable *requests; char *path; + gboolean enabled; } NMSecretAgentSimplePrivate; static void @@ -451,14 +452,6 @@ nm_secret_agent_simple_get_secrets (NMSecretAgent *agent, return; } - if (priv->path && g_strcmp0 (priv->path, connection_path) != 0) { - /* We only handle requests for connection with @path if set. */ - error = g_error_new (NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_FAILED, - "Request for %s secrets doesn't match path %s", - request_id, priv->path); - goto nope; - } - s_con = nm_connection_get_setting_connection (connection); connection_type = nm_setting_connection_get_connection_type (s_con); @@ -485,7 +478,8 @@ nm_secret_agent_simple_get_secrets (NMSecretAgent *agent, request->request_id = request_id; g_hash_table_replace (priv->requests, request->request_id, request); - request_secrets_from_ui (request); + if (priv->enabled) + request_secrets_from_ui (request); } /** @@ -588,6 +582,59 @@ nm_secret_agent_simple_delete_secrets (NMSecretAgent *agent, callback (agent, connection, NULL, callback_data); } +/** + * nm_secret_agent_simple_set_connection_path: + * @agent: the #NMSecretAgentSimple + * @path: the path of the connection the agent handle secrets for + * + * Sets the path for a new #NMSecretAgentSimple. + */ +void +nm_secret_agent_simple_set_connection_path (NMSecretAgent *agent, const char *path) +{ + NMSecretAgentSimplePrivate *priv = NM_SECRET_AGENT_SIMPLE_GET_PRIVATE (agent); + + g_free (priv->path); + priv->path = g_strdup (path); +} + +/** + * nm_secret_agent_simple_enable: + * @agent: the #NMSecretAgentSimple + * + * Enables servicing the requests including the already queued ones. + */ +void +nm_secret_agent_simple_enable (NMSecretAgent *agent) +{ + NMSecretAgentSimplePrivate *priv = NM_SECRET_AGENT_SIMPLE_GET_PRIVATE (agent); + GList *requests, *iter; + GError *error; + + if (priv->enabled) + return; + priv->enabled = TRUE; + + /* Service pending secret requests. */ + requests = g_hash_table_get_values (priv->requests); + for (iter = requests; iter; iter = g_list_next (iter)) { + NMSecretAgentSimpleRequest *request = iter->data; + + if (!g_str_has_prefix (request->request_id, priv->path)) { + request_secrets_from_ui (request); + } else { + /* We only handle requests for connection with @path if set. */ + error = g_error_new (NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_FAILED, + "Request for %s secrets doesn't match path %s", + request->request_id, priv->path); + request->callback (agent, request->connection, NULL, error, request->callback_data); + g_hash_table_remove (priv->requests, request->request_id); + g_error_free (error); + } + } + g_list_free (requests); +} + void nm_secret_agent_simple_class_init (NMSecretAgentSimpleClass *klass) { @@ -639,22 +686,21 @@ nm_secret_agent_simple_class_init (NMSecretAgentSimpleClass *klass) /** * nm_secret_agent_simple_new: * @name: the identifier of secret agent - * @path: (allow-none): the path of the connection the agent handle secrets for, - * or %NULL to handle requests for all connections * - * Creates a new #NMSecretAgentSimple. + * Creates a new #NMSecretAgentSimple. It does not serve any requests until + * nm_secret_agent_simple_enable() is called. * - * Returns: a new #NMSecretAgentSimple + * Returns: a new #NMSecretAgentSimple if the agent creation is successful + * or %NULL in case of a failure. */ NMSecretAgent * -nm_secret_agent_simple_new (const char *name, const char *path) +nm_secret_agent_simple_new (const char *name) { NMSecretAgent *agent; agent = g_initable_new (NM_TYPE_SECRET_AGENT_SIMPLE, NULL, NULL, NM_SECRET_AGENT_IDENTIFIER, name, NULL); - NM_SECRET_AGENT_SIMPLE_GET_PRIVATE (agent)->path = g_strdup (path); return agent; } diff --git a/clients/common/nm-secret-agent-simple.h b/clients/common/nm-secret-agent-simple.h index b1cc304492..5d4278bdfa 100644 --- a/clients/common/nm-secret-agent-simple.h +++ b/clients/common/nm-secret-agent-simple.h @@ -47,10 +47,13 @@ typedef struct { GType nm_secret_agent_simple_get_type (void); -NMSecretAgent *nm_secret_agent_simple_new (const char *name, const char *path); +NMSecretAgent *nm_secret_agent_simple_new (const char *name); void nm_secret_agent_simple_response (NMSecretAgentSimple *self, const char *request_id, GPtrArray *secrets); +void nm_secret_agent_simple_set_connection_path (NMSecretAgent *agent, + const char *path); +void nm_secret_agent_simple_enable (NMSecretAgent *agent); G_END_DECLS diff --git a/clients/tui/nmtui-connect.c b/clients/tui/nmtui-connect.c index 26f7296a66..77c7ff0798 100644 --- a/clients/tui/nmtui-connect.c +++ b/clients/tui/nmtui-connect.c @@ -145,8 +145,15 @@ activate_connection (NMConnection *connection, label = nmt_newt_label_new (_("Connecting...")); nmt_newt_form_set_content (form, label); - agent = nm_secret_agent_simple_new ("nmtui", nm_object_get_path (NM_OBJECT (connection))); - g_signal_connect (agent, "request-secrets", G_CALLBACK (secrets_requested), NULL); + agent = nm_secret_agent_simple_new ("nmtui"); + if (agent) { + if (connection) { + nm_secret_agent_simple_set_connection_path (agent, + nm_object_get_path (NM_OBJECT (connection))); + nm_secret_agent_simple_enable (agent); + } + g_signal_connect (agent, "request-secrets", G_CALLBACK (secrets_requested), NULL); + } specific_object_path = specific_object ? nm_object_get_path (specific_object) : NULL; @@ -182,6 +189,16 @@ activate_connection (NMConnection *connection, goto done; } + if (!connection) { + connection = NM_CONNECTION (nm_active_connection_get_connection (ac)); + if (connection) { + const gchar *path = nm_object_get_path (NM_OBJECT (connection)); + + nm_secret_agent_simple_set_connection_path (agent, path); + nm_secret_agent_simple_enable (agent); + } + } + /* Now wait for the connection to actually reach the ACTIVATED state, * allowing the user to cancel if it takes too long. */