summaryrefslogtreecommitdiff
path: root/src/settings
diff options
context:
space:
mode:
authorLubomir Rintel <lkundrak@v3.sk>2015-07-14 16:53:24 +0200
committerThomas Haller <thaller@redhat.com>2015-09-18 17:32:11 +0200
commit06da3532428e3498c1e808ff8be1af48b540a6ff (patch)
tree80155896a11d61517bc7cb87df16b3f0ede16f25 /src/settings
parentc9b3617c35b3380428a1800e8aa6692ee68b4b74 (diff)
downloadNetworkManager-06da3532428e3498c1e808ff8be1af48b540a6ff.tar.gz
core: separate active and applied connection
Clone the connection upon activation. This makes it safe for the user to modify the original connection while it is activated. This involves several changes: - NMActiveConnection gets @settings_connection and @applied_connection. To support add-and-activate, we constructing a NMActiveConnection with no connection set. Previously, we would set the "connection" field to a temporary NMConnection. Now NMManager piggybacks this temporary connection as object-data (TAG_ACTIVE_CONNETION_ADD_AND_ACTIVATE). - get rid of the functions nm_active_connection_get_connection_type() and nm_active_connection_get_connection_uuid(). From their names it is unclear whether this returns the settings or applied connection. The (few) callers should figure that out themselves. - rename nm_active_connection_get_id() to nm_active_connection_get_settings_connection_id(). This function is only used internally for logging. - dispatcher calls now get two connections as well. The applied-connection is used for the connection data, while the settings-connection is used for the connection path. - needs special handling for properties that apply immediately when changed (nm_device_reapply_settings_immediately()). Co-Authored-By: Thomas Haller <thaller@redhat.com> https://bugzilla.gnome.org/show_bug.cgi?id=724041
Diffstat (limited to 'src/settings')
-rw-r--r--src/settings/nm-agent-manager.c22
-rw-r--r--src/settings/nm-agent-manager.h8
-rw-r--r--src/settings/nm-settings-connection.c559
-rw-r--r--src/settings/nm-settings-connection.h8
-rw-r--r--src/settings/nm-settings.c14
-rw-r--r--src/settings/nm-settings.h2
6 files changed, 404 insertions, 209 deletions
diff --git a/src/settings/nm-agent-manager.c b/src/settings/nm-agent-manager.c
index 2bdb41baee..c3abaac25c 100644
--- a/src/settings/nm-agent-manager.c
+++ b/src/settings/nm-agent-manager.c
@@ -474,8 +474,6 @@ struct _NMAgentManagerCallId {
NMAgentSecretsResultFunc callback;
gpointer callback_data;
- gpointer other_data2;
- gpointer other_data3;
} get;
};
} con;
@@ -564,9 +562,7 @@ req_complete_release (Request *req,
req->con.get.flags,
error ? NULL : secrets,
error,
- req->con.get.callback_data,
- req->con.get.other_data2,
- req->con.get.other_data3);
+ req->con.get.callback_data);
break;
case REQUEST_TYPE_CON_SAVE:
@@ -1167,8 +1163,6 @@ _con_get_try_complete_early (Request *req)
* @hints:
* @callback:
* @callback_data:
- * @other_data2:
- * @other_data3:
*
* Requests secrets for a connection.
*
@@ -1190,17 +1184,15 @@ nm_agent_manager_get_secrets (NMAgentManager *self,
NMSecretAgentGetSecretsFlags flags,
const char **hints,
NMAgentSecretsResultFunc callback,
- gpointer callback_data,
- gpointer other_data2,
- gpointer other_data3)
+ gpointer callback_data)
{
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self);
Request *req;
- g_return_val_if_fail (self != NULL, 0);
- g_return_val_if_fail (path && *path, 0);
- g_return_val_if_fail (NM_IS_CONNECTION (connection), 0);
- g_return_val_if_fail (callback != NULL, 0);
+ g_return_val_if_fail (self != NULL, NULL);
+ g_return_val_if_fail (path && *path, NULL);
+ g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
+ g_return_val_if_fail (callback != NULL, NULL);
nm_log_dbg (LOGD_SETTINGS,
"Secrets requested for connection %s (%s/%s)",
@@ -1227,8 +1219,6 @@ nm_agent_manager_get_secrets (NMAgentManager *self,
req->con.get.flags = flags;
req->con.get.callback = callback;
req->con.get.callback_data = callback_data;
- req->con.get.other_data2 = other_data2;
- req->con.get.other_data3 = other_data3;
if (!g_hash_table_add (priv->requests, req))
g_assert_not_reached ();
diff --git a/src/settings/nm-agent-manager.h b/src/settings/nm-agent-manager.h
index bfccabd081..2f50553724 100644
--- a/src/settings/nm-agent-manager.h
+++ b/src/settings/nm-agent-manager.h
@@ -61,9 +61,7 @@ typedef void (*NMAgentSecretsResultFunc) (NMAgentManager *manager,
NMSecretAgentGetSecretsFlags flags,
GVariant *secrets,
GError *error,
- gpointer user_data,
- gpointer other_data2,
- gpointer other_data3);
+ gpointer user_data);
NMAgentManagerCallId nm_agent_manager_get_secrets (NMAgentManager *manager,
const char *path,
@@ -74,9 +72,7 @@ NMAgentManagerCallId nm_agent_manager_get_secrets (NMAgentManager *manager,
NMSecretAgentGetSecretsFlags flags,
const char **hints,
NMAgentSecretsResultFunc callback,
- gpointer callback_data,
- gpointer other_data2,
- gpointer other_data3);
+ gpointer callback_data);
void nm_agent_manager_cancel_secrets (NMAgentManager *manager,
NMAgentManagerCallId request_id);
diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c
index e0e9a25655..9ab0bc6b30 100644
--- a/src/settings/nm-settings-connection.c
+++ b/src/settings/nm-settings-connection.c
@@ -71,18 +71,6 @@ G_DEFINE_TYPE_WITH_CODE (NMSettingsConnection, nm_settings_connection, NM_TYPE_E
NM_TYPE_SETTINGS_CONNECTION, \
NMSettingsConnectionPrivate))
-static inline NMAgentManagerCallId
-NM_AGENT_MANAGER_CALL_ID (NMSettingsConnectionCallId call_id)
-{
- return (NMAgentManagerCallId) call_id;
-}
-
-static inline NMSettingsConnectionCallId
-NM_SETTINGS_CONNECTION_CALL_ID (NMAgentManagerCallId call_id_a)
-{
- return (NMSettingsConnectionCallId) call_id_a;
-}
-
enum {
PROP_0 = 0,
PROP_VISIBLE,
@@ -115,13 +103,7 @@ typedef struct {
GSList *pending_auths; /* List of pending authentication requests */
gboolean visible; /* Is this connection is visible by some session? */
- GSList *reqs_int; /* in-progress internal secrets requests */
-
- GSList *reqs_ext; /* in-progress external secrets requests (D-Bus). Note that
- this list contains NMSettingsConnectionCallId, vs. NMAgentManagerCallId.
- So, we should for example cancel the reqs_ext with nm_settings_connection_cancel_secrets()
- instead of nm_agent_manager_cancel_secrets().
- Actually, the difference doesn't matter, because both are indeed equivalent. */
+ GSList *get_secret_requests; /* in-progress secrets requests */
/* Caches secrets from on-disk connections; were they not cached any
* call to nm_connection_clear_secrets() wipes them out and we'd have
@@ -150,6 +132,22 @@ typedef struct {
} NMSettingsConnectionPrivate;
+/*******************************************************************/
+
+gboolean
+nm_settings_connection_has_unmodified_applied_connection (NMSettingsConnection *self,
+ NMConnection *applied_connection,
+ NMSettingCompareFlags compare_flags)
+{
+ g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), FALSE);
+ g_return_val_if_fail (NM_IS_CONNECTION (applied_connection), FALSE);
+
+ /* for convenience, we *always* ignore certain settings. */
+ compare_flags |= NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS | NM_SETTING_COMPARE_FLAG_IGNORE_TIMESTAMP;
+
+ return nm_connection_compare (NM_CONNECTION (self), applied_connection, compare_flags);
+}
+
/**************************************************************/
/* Return TRUE to keep, FALSE to drop */
@@ -769,6 +767,86 @@ do_delete (NMSettingsConnection *self,
/**************************************************************/
+
+typedef enum {
+ GET_SECRETS_INFO_TYPE_REQ,
+ GET_SECRETS_INFO_TYPE_IDLE,
+} GetSecretsInfoType;
+
+struct _NMSettingsConnectionCallId {
+ NMSettingsConnection *self;
+ gboolean had_applied_connection;
+ NMConnection *applied_connection;
+ NMSettingsConnectionSecretsFunc callback;
+ gpointer callback_data;
+
+ GetSecretsInfoType type;
+ union {
+ struct {
+ NMAgentManagerCallId id;
+ } req;
+ struct {
+ guint32 id;
+ GError *error;
+ } idle;
+ } t;
+};
+
+typedef struct _NMSettingsConnectionCallId GetSecretsInfo;
+
+static GetSecretsInfo *
+_get_secrets_info_new (NMSettingsConnection *self,
+ NMConnection *applied_connection,
+ NMSettingsConnectionSecretsFunc callback,
+ gpointer callback_data)
+{
+ GetSecretsInfo *info;
+
+ info = g_slice_new0 (GetSecretsInfo);
+
+ info->self = self;
+ if (applied_connection) {
+ info->had_applied_connection = TRUE;
+ info->applied_connection = applied_connection;
+ g_object_add_weak_pointer (G_OBJECT (applied_connection), (gpointer *) &info->applied_connection);
+ }
+ info->callback = callback;
+ info->callback_data = callback_data;
+
+ return info;
+}
+
+static void
+_get_secrets_info_callback (GetSecretsInfo *info,
+ const char *agent_username,
+ const char *setting_name,
+ GError *error)
+{
+ if (info->callback) {
+ info->callback (info->self,
+ info,
+ agent_username,
+ setting_name,
+ error,
+ info->callback_data);
+ }
+}
+
+static void
+_get_secrets_info_free (GetSecretsInfo *info)
+{
+ g_return_if_fail (info && info->self);
+
+ if (info->applied_connection)
+ g_object_remove_weak_pointer (G_OBJECT (info->applied_connection), (gpointer *) &info->applied_connection);
+
+ if (info->type == GET_SECRETS_INFO_TYPE_IDLE)
+ g_clear_error (&info->t.idle.error);
+
+ memset (info, 0, sizeof (*info));
+ g_slice_free (GetSecretsInfo, info);
+}
+
static gboolean
supports_secrets (NMSettingsConnection *self, const char *setting_name)
{
@@ -813,69 +891,33 @@ new_secrets_commit_cb (NMSettingsConnection *self,
}
static void
-_callback_nop (NMSettingsConnection *self,
- NMSettingsConnectionCallId call_id,
- const char *agent_username,
- const char *setting_name,
- GError *error,
- gpointer user_data)
+get_cmp_flags (NMSettingsConnection *self, /* only needed for logging */
+ GetSecretsInfo *info, /* only needed for logging */
+ NMConnection *connection,
+ const char *agent_dbus_owner,
+ gboolean agent_has_modify,
+ const char *setting_name, /* only needed for logging */
+ NMSecretAgentGetSecretsFlags flags,
+ GVariant *secrets,
+ gboolean *agent_had_system,
+ ForEachSecretFlags *cmp_flags)
{
-}
+ gboolean is_self = (((NMConnection *) self) == connection);
-static void
-agent_secrets_done_cb (NMAgentManager *manager,
- NMAgentManagerCallId call_id_a,
- const char *agent_dbus_owner,
- const char *agent_username,
- gboolean agent_has_modify,
- const char *setting_name,
- NMSecretAgentGetSecretsFlags flags,
- GVariant *secrets,
- GError *error,
- gpointer user_data,
- gpointer other_data2,
- gpointer other_data3)
-{
- NMSettingsConnectionCallId call_id = NM_SETTINGS_CONNECTION_CALL_ID (call_id_a);
- NMSettingsConnection *self = NM_SETTINGS_CONNECTION (user_data);
- NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
- NMSettingsConnectionSecretsFunc callback = other_data2;
- gpointer callback_data = other_data3;
- GError *local = NULL;
- GVariant *dict;
- gboolean agent_had_system = FALSE;
- ForEachSecretFlags cmp_flags = { NM_SETTING_SECRET_FLAG_NONE, NM_SETTING_SECRET_FLAG_NONE };
-
- if (!callback)
- callback = _callback_nop;
-
- g_return_if_fail (g_slist_find (priv->reqs_int, call_id));
+ g_return_if_fail (secrets);
- priv->reqs_int = g_slist_remove (priv->reqs_int, call_id);
+ cmp_flags->required = NM_SETTING_SECRET_FLAG_NONE;
+ cmp_flags->forbidden = NM_SETTING_SECRET_FLAG_NONE;
- if (error) {
- _LOGD ("(%s:%p) secrets request error: %s",
- setting_name, call_id, error->message);
-
- callback (self, call_id, NULL, setting_name, error, callback_data);
- return;
- }
+ *agent_had_system = FALSE;
- if (!nm_connection_get_setting_by_name (NM_CONNECTION (self), setting_name)) {
- local = g_error_new (NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_SETTING_NOT_FOUND,
- "%s.%d - Connection didn't have requested setting '%s'.",
- __FILE__, __LINE__, setting_name);
- callback (self, call_id, NULL, setting_name, local, callback_data);
- g_clear_error (&local);
- return;
- }
-
- g_assert (secrets);
if (agent_dbus_owner) {
- _LOGD ("(%s:%p) secrets returned from agent %s",
- setting_name,
- call_id,
- agent_dbus_owner);
+ if (is_self) {
+ _LOGD ("(%s:%p) secrets returned from agent %s",
+ setting_name,
+ info,
+ agent_dbus_owner);
+ }
/* If the agent returned any system-owned secrets (initial connect and no
* secrets given when the connection was created, or something like that)
@@ -883,50 +925,134 @@ agent_secrets_done_cb (NMAgentManager *manager,
* save those system-owned secrets. If not, discard them and use the
* existing secrets, or fail the connection.
*/
- agent_had_system = find_secret (NM_CONNECTION (self), secrets, secret_is_system_owned, NULL);
- if (agent_had_system) {
+ *agent_had_system = find_secret (connection, secrets, secret_is_system_owned, NULL);
+ if (*agent_had_system) {
if (flags == NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE) {
/* No user interaction was allowed when requesting secrets; the
* agent is being bad. Remove system-owned secrets.
*/
- _LOGD ("(%s:%p) interaction forbidden but agent %s returned system secrets",
- setting_name,
- call_id,
- agent_dbus_owner);
+ if (is_self) {
+ _LOGD ("(%s:%p) interaction forbidden but agent %s returned system secrets",
+ setting_name,
+ info,
+ agent_dbus_owner);
+ }
- cmp_flags.required |= NM_SETTING_SECRET_FLAG_AGENT_OWNED;
+ cmp_flags->required |= NM_SETTING_SECRET_FLAG_AGENT_OWNED;
} else if (agent_has_modify == FALSE) {
/* Agent didn't successfully authenticate; clear system-owned secrets
* from the secrets the agent returned.
*/
- _LOGD ("(%s:%p) agent failed to authenticate but provided system secrets",
- setting_name,
- call_id);
+ if (is_self) {
+ _LOGD ("(%s:%p) agent failed to authenticate but provided system secrets",
+ setting_name,
+ info);
+ }
- cmp_flags.required |= NM_SETTING_SECRET_FLAG_AGENT_OWNED;
+ cmp_flags->required |= NM_SETTING_SECRET_FLAG_AGENT_OWNED;
}
}
} else {
- _LOGD ("(%s:%p) existing secrets returned",
- setting_name,
- call_id);
+ if (is_self) {
+ _LOGD ("(%s:%p) existing secrets returned",
+ setting_name,
+ info);
+ }
}
- _LOGD ("(%s:%p) secrets request completed",
- setting_name,
- call_id);
-
/* If no user interaction was allowed, make sure that no "unsaved" secrets
* came back. Unsaved secrets by definition require user interaction.
*/
if (flags == NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE) {
- cmp_flags.forbidden |= ( NM_SETTING_SECRET_FLAG_NOT_SAVED
- | NM_SETTING_SECRET_FLAG_NOT_REQUIRED);
+ cmp_flags->forbidden |= ( NM_SETTING_SECRET_FLAG_NOT_SAVED
+ | NM_SETTING_SECRET_FLAG_NOT_REQUIRED);
+ }
+}
+
+static void
+get_secrets_done_cb (NMAgentManager *manager,
+ NMAgentManagerCallId call_id_a,
+ const char *agent_dbus_owner,
+ const char *agent_username,
+ gboolean agent_has_modify,
+ const char *setting_name,
+ NMSecretAgentGetSecretsFlags flags,
+ GVariant *secrets,
+ GError *error,
+ gpointer user_data)
+{
+ GetSecretsInfo *info = user_data;
+ NMSettingsConnection *self;
+ NMSettingsConnectionPrivate *priv;
+ NMConnection *applied_connection;
+ gs_free_error GError *local = NULL;
+ GVariant *dict;
+ gboolean agent_had_system = FALSE;
+ ForEachSecretFlags cmp_flags = { NM_SETTING_SECRET_FLAG_NONE, NM_SETTING_SECRET_FLAG_NONE };
+
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ return;
+
+ self = info->self;
+ g_return_if_fail (NM_IS_SETTINGS_CONNECTION (self));
+
+ priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
+
+ g_return_if_fail (g_slist_find (priv->get_secret_requests, info));
+
+ priv->get_secret_requests = g_slist_remove (priv->get_secret_requests, info);
+
+ if (error) {
+ _LOGD ("(%s:%p) secrets request error: %s",
+ setting_name, info, error->message);
+
+ _get_secrets_info_callback (info, NULL, setting_name, error);
+ goto out;
}
+ if ( info->had_applied_connection
+ && !info->applied_connection) {
+ g_set_error_literal (&local, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_SETTING_NOT_FOUND,
+ "Applied connection deleted since requesting secrets");
+ _get_secrets_info_callback (info, NULL, setting_name, local);
+ goto out;
+ }
+
+ if ( info->had_applied_connection
+ && !nm_settings_connection_has_unmodified_applied_connection (self, info->applied_connection, NM_SETTING_COMPARE_FLAG_NONE)) {
+ g_set_error_literal (&local, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
+ "The connection was modified since activation");
+ _get_secrets_info_callback (info, NULL, setting_name, local);
+ goto out;
+ }
+
+ if (!nm_connection_get_setting_by_name (NM_CONNECTION (self), setting_name)) {
+ g_set_error (&local, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_SETTING_NOT_FOUND,
+ "Connection didn't have requested setting '%s'.",
+ setting_name);
+ _get_secrets_info_callback (info, NULL, setting_name, local);
+ goto out;
+ }
+
+ get_cmp_flags (self,
+ info,
+ NM_CONNECTION (self),
+ agent_dbus_owner,
+ agent_has_modify,
+ setting_name,
+ flags,
+ secrets,
+ &agent_had_system,
+ &cmp_flags);
+
+ _LOGD ("(%s:%p) secrets request completed",
+ setting_name,
+ info);
+
+ dict = nm_connection_to_dbus (priv->system_secrets, NM_CONNECTION_SERIALIZE_ONLY_SECRETS);
+
/* Update the connection with our existing secrets from backing storage */
nm_connection_clear_secrets (NM_CONNECTION (self));
- dict = nm_connection_to_dbus (priv->system_secrets, NM_CONNECTION_SERIALIZE_ONLY_SECRETS);
if (!dict || nm_connection_update_secrets (NM_CONNECTION (self), setting_name, dict, &local)) {
GVariant *filtered_secrets;
@@ -937,7 +1063,7 @@ agent_secrets_done_cb (NMAgentManager *manager,
*/
filtered_secrets = for_each_secret (NM_CONNECTION (self), secrets, TRUE, validate_secret_flags, &cmp_flags);
if (nm_connection_update_secrets (NM_CONNECTION (self), setting_name, filtered_secrets, &local)) {
- /* Now that all secrets are updated, copy and cache new secrets,
+ /* Now that all secrets are updated, copy and cache new secrets,
* then save them to backing storage.
*/
update_system_secrets_cache (self);
@@ -951,19 +1077,19 @@ agent_secrets_done_cb (NMAgentManager *manager,
if (agent_had_system) {
_LOGD ("(%s:%p) saving new secrets to backing storage",
setting_name,
- call_id);
+ info);
nm_settings_connection_commit_changes (self, NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, new_secrets_commit_cb, NULL);
} else {
_LOGD ("(%s:%p) new agent secrets processed",
setting_name,
- call_id);
+ info);
}
} else {
_LOGD ("(%s:%p) failed to update with agent secrets: (%d) %s",
setting_name,
- call_id,
+ info,
local ? local->code : -1,
(local && local->message) ? local->message : "(unknown)");
}
@@ -971,20 +1097,69 @@ agent_secrets_done_cb (NMAgentManager *manager,
} else {
_LOGD ("(%s:%p) failed to update with existing secrets: (%d) %s",
setting_name,
- call_id,
+ info,
local ? local->code : -1,
(local && local->message) ? local->message : "(unknown)");
}
- callback (self, call_id, agent_username, setting_name, local, callback_data);
+ applied_connection = info->applied_connection;
+ if (applied_connection) {
+ get_cmp_flags (self,
+ info,
+ applied_connection,
+ agent_dbus_owner,
+ agent_has_modify,
+ setting_name,
+ flags,
+ secrets,
+ &agent_had_system,
+ &cmp_flags);
+
+ nm_connection_clear_secrets (applied_connection);
+
+ if (!dict || nm_connection_update_secrets (applied_connection, setting_name, dict, NULL)) {
+ GVariant *filtered_secrets;
+
+ filtered_secrets = for_each_secret (applied_connection, secrets, TRUE, validate_secret_flags, &cmp_flags);
+ nm_connection_update_secrets (applied_connection, setting_name, filtered_secrets, NULL);
+ g_variant_unref (filtered_secrets);
+ }
+ }
+
+ _get_secrets_info_callback (info, agent_username, setting_name, local);
g_clear_error (&local);
if (dict)
g_variant_unref (dict);
+
+out:
+ _get_secrets_info_free (info);
+}
+
+static gboolean
+get_secrets_idle_cb (GetSecretsInfo *info)
+{
+ NMSettingsConnectionPrivate *priv;
+
+ g_return_val_if_fail (info && NM_IS_SETTINGS_CONNECTION (info->self), G_SOURCE_REMOVE);
+
+ priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (info->self);
+
+ g_return_val_if_fail (g_slist_find (priv->get_secret_requests, info), G_SOURCE_REMOVE);
+
+ priv->get_secret_requests = g_slist_remove (priv->get_secret_requests, info);
+
+ _get_secrets_info_callback (info, NULL, NULL, info->t.idle.error);
+
+ _get_secrets_info_free (info);
+ return G_SOURCE_REMOVE;
}
/**
* nm_settings_connection_get_secrets:
* @self: the #NMSettingsConnection
+ * @applied_connection: (allow-none): if provided, only request secrets
+ * if @self equals to @applied_connection. Also, update the secrets
+ * in the @applied_connection.
* @subject: the #NMAuthSubject originating the request
* @setting_name: the setting to return secrets for
* @flags: flags to modify the secrets request
@@ -1006,35 +1181,55 @@ agent_secrets_done_cb (NMAgentManager *manager,
**/
NMSettingsConnectionCallId
nm_settings_connection_get_secrets (NMSettingsConnection *self,
+ NMConnection *applied_connection,
NMAuthSubject *subject,
const char *setting_name,
NMSecretAgentGetSecretsFlags flags,
const char **hints,
NMSettingsConnectionSecretsFunc callback,
- gpointer callback_data,
- GError **error)
+ gpointer callback_data)
{
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
GVariant *existing_secrets;
NMAgentManagerCallId call_id_a;
gs_free char *joined_hints = NULL;
+ GetSecretsInfo *info;
+ GError *local = NULL;
+
+ g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), NULL);
+ g_return_val_if_fail ( !applied_connection
+ || ( NM_IS_CONNECTION (applied_connection)
+ && (((NMConnection *) self) != applied_connection)), NULL);
+
+ info = _get_secrets_info_new (self,
+ applied_connection,
+ callback,
+ callback_data);
+
+ priv->get_secret_requests = g_slist_append (priv->get_secret_requests, info);
/* Use priv->secrets to work around the fact that nm_connection_clear_secrets()
* will clear secrets on this object's settings.
*/
if (!priv->system_secrets) {
- g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
- "%s.%d - Internal error; secrets cache invalid.",
- __FILE__, __LINE__);
- return NULL;
+ g_set_error_literal (&local, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
+ "secrets cache invalid");
+ goto schedule_dummy;
}
/* Make sure the request actually requests something we can return */
if (!nm_connection_get_setting_by_name (NM_CONNECTION (self), setting_name)) {
- g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_SETTING_NOT_FOUND,
- "%s.%d - Connection didn't have requested setting '%s'.",
- __FILE__, __LINE__, setting_name);
- return NULL;
+ g_set_error (&local, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_SETTING_NOT_FOUND,
+ "Connection didn't have requested setting '%s'.",
+ setting_name);
+ goto schedule_dummy;
+ }
+
+ if ( applied_connection
+ && !nm_settings_connection_has_unmodified_applied_connection (self, applied_connection, NM_SETTING_COMPARE_FLAG_NONE)) {
+ g_set_error_literal (&local, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
+ "The connection was modified since activation");
+ goto schedule_dummy;
}
existing_secrets = nm_connection_to_dbus (priv->system_secrets, NM_CONNECTION_SERIALIZE_ONLY_SECRETS);
@@ -1048,10 +1243,9 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self,
setting_name,
flags,
hints,
- agent_secrets_done_cb,
- self,
- callback,
- callback_data);
+ get_secrets_done_cb,
+ info);
+ g_assert (call_id_a);
if (existing_secrets)
g_variant_unref (existing_secrets);
@@ -1061,23 +1255,61 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self,
flags,
(hints && hints[0]) ? (joined_hints = g_strjoinv (",", (char **) hints)) : "(none)");
- priv->reqs_int = g_slist_append (priv->reqs_int, call_id_a);
-
- return NM_SETTINGS_CONNECTION_CALL_ID (call_id_a);
+ if (call_id_a) {
+ info->type = GET_SECRETS_INFO_TYPE_REQ;
+ info->t.req.id = call_id_a;
+ } else {
+schedule_dummy:
+ info->type = GET_SECRETS_INFO_TYPE_IDLE;
+ g_propagate_error (&info->t.idle.error, local);
+ info->t.idle.id = g_idle_add ((GSourceFunc) get_secrets_idle_cb, info);
+ }
+ return info;
}
-void
-nm_settings_connection_cancel_secrets (NMSettingsConnection *self,
- NMSettingsConnectionCallId call_id)
+static void
+_get_secrets_cancel (NMSettingsConnection *self,
+ GetSecretsInfo *info,
+ gboolean shutdown)
{
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
- if (!g_slist_find (priv->reqs_int, call_id))
+ gs_free_error GError *error = NULL;
+
+ if (!g_slist_find (priv->get_secret_requests, info))
g_return_if_reached ();
+ priv->get_secret_requests = g_slist_remove (priv->get_secret_requests, info);
+
+ if (info->type == GET_SECRETS_INFO_TYPE_REQ)
+ nm_agent_manager_cancel_secrets (priv->agent_mgr, info->t.req.id);
+ else
+ g_source_remove (info->t.idle.id);
+
+ if (shutdown) {
+ /* Use a different error code. G_IO_ERROR_CANCELLED is only used synchronously
+ * when the user calls nm_act_request_cancel_secrets(). Disposing the instance
+ * with pending requests also cancels the requests, but with a different error
+ * code. */
+ g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Disposing NMActRequest instance");
+ } else {
+ g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_CANCELLED,
+ "Request cancelled");
+ }
+
+ _get_secrets_info_callback (info, NULL, NULL, error);
+
+ _get_secrets_info_free (info);
+}
+
+void
+nm_settings_connection_cancel_secrets (NMSettingsConnection *self,
+ NMSettingsConnectionCallId call_id)
+{
_LOGD ("(%p) secrets canceled", call_id);
- nm_agent_manager_cancel_secrets (priv->agent_mgr, NM_AGENT_MANAGER_CALL_ID (call_id));
+ _get_secrets_cancel (self, call_id, FALSE);
}
/**** User authorization **************************************/
@@ -1389,7 +1621,7 @@ update_complete (NMSettingsConnection *self,
else
g_dbus_method_invocation_return_value (info->context, NULL);
- nm_audit_log_connection_op (NM_AUDIT_OP_CONN_UPDATE, NM_CONNECTION (self), !error,
+ nm_audit_log_connection_op (NM_AUDIT_OP_CONN_UPDATE, self, !error,
info->subject, error ? error->message : NULL);
g_clear_object (&info->subject);
@@ -1555,7 +1787,7 @@ impl_settings_connection_update_helper (NMSettingsConnection *self,
return;
error:
- nm_audit_log_connection_op (NM_AUDIT_OP_CONN_UPDATE, NM_CONNECTION (self), FALSE, subject,
+ nm_audit_log_connection_op (NM_AUDIT_OP_CONN_UPDATE, self, FALSE, subject,
error->message);
g_clear_object (&tmp);
@@ -1603,7 +1835,7 @@ con_delete_cb (NMSettingsConnection *self,
else
g_dbus_method_invocation_return_value (info->context, NULL);
- nm_audit_log_connection_op (NM_AUDIT_OP_CONN_DELETE, NM_CONNECTION (self),
+ nm_audit_log_connection_op (NM_AUDIT_OP_CONN_DELETE, self,
!error, info->subject, error ? error->message : NULL);
g_free (info);
}
@@ -1618,7 +1850,7 @@ delete_auth_cb (NMSettingsConnection *self,
CallbackInfo *info;
if (error) {
- nm_audit_log_connection_op (NM_AUDIT_OP_CONN_DELETE, NM_CONNECTION (self), FALSE, subject,
+ nm_audit_log_connection_op (NM_AUDIT_OP_CONN_DELETE, self, FALSE, subject,
error->message);
g_dbus_method_invocation_return_gerror (context, error);
return;
@@ -1667,7 +1899,7 @@ impl_settings_connection_delete (NMSettingsConnection *self,
return;
out_err:
- nm_audit_log_connection_op (NM_AUDIT_OP_CONN_DELETE, NM_CONNECTION (self), FALSE, subject, error->message);
+ nm_audit_log_connection_op (NM_AUDIT_OP_CONN_DELETE, self, FALSE, subject, error->message);
g_dbus_method_invocation_take_error (context, error);
}
@@ -1681,14 +1913,9 @@ dbus_get_agent_secrets_cb (NMSettingsConnection *self,
GError *error,
gpointer user_data)
{
- NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
GDBusMethodInvocation *context = user_data;
GVariant *dict;
- g_return_if_fail (g_slist_find (priv->reqs_ext, call_id));
-
- priv->reqs_ext = g_slist_remove (priv->reqs_ext, call_id);
-
if (error)
g_dbus_method_invocation_return_gerror (context, error);
else {
@@ -1711,31 +1938,22 @@ dbus_get_secrets_auth_cb (NMSettingsConnection *self,
GError *error,
gpointer user_data)
{
- NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
char *setting_name = user_data;
- NMSettingsConnectionCallId call_id;
- GError *local = NULL;
if (!error) {
- call_id = nm_settings_connection_get_secrets (self,
- subject,
- setting_name,
- NM_SECRET_AGENT_GET_SECRETS_FLAG_USER_REQUESTED
- | NM_SECRET_AGENT_GET_SECRETS_FLAG_NO_ERRORS,
- NULL,
- dbus_get_agent_secrets_cb,
- context,
- &local);
- if (call_id) {
- /* track the request and wait for the callback */
- priv->reqs_ext = g_slist_append (priv->reqs_ext, call_id);
- }
+ nm_settings_connection_get_secrets (self,
+ NULL,
+ subject,
+ setting_name,
+ NM_SECRET_AGENT_GET_SECRETS_FLAG_USER_REQUESTED
+ | NM_SECRET_AGENT_GET_SECRETS_FLAG_NO_ERRORS,
+ NULL,
+ dbus_get_agent_secrets_cb,
+ context);
}
- if (error || local) {
- g_dbus_method_invocation_return_gerror (context, error ? error : local);
- g_clear_error (&local);
- }
+ if (error)
+ g_dbus_method_invocation_return_gerror (context, error);
g_free (setting_name);
}
@@ -1773,7 +1991,7 @@ clear_secrets_cb (NMSettingsConnection *self,
else
g_dbus_method_invocation_return_value (info->context, NULL);
- nm_audit_log_connection_op (NM_AUDIT_OP_CONN_CLEAR_SECRETS, NM_CONNECTION (self),
+ nm_audit_log_connection_op (NM_AUDIT_OP_CONN_CLEAR_SECRETS, self,
!error, info->subject, error ? error->message : NULL);
g_free (info);
}
@@ -1790,7 +2008,7 @@ dbus_clear_secrets_auth_cb (NMSettingsConnection *self,
if (error) {
g_dbus_method_invocation_return_gerror (context, error);
- nm_audit_log_connection_op (NM_AUDIT_OP_CONN_CLEAR_SECRETS, NM_CONNECTION (self),
+ nm_audit_log_connection_op (NM_AUDIT_OP_CONN_CLEAR_SECRETS, self,
FALSE, subject, error->message);
} else {
/* Clear secrets in connection and caches */
@@ -1830,7 +2048,7 @@ impl_settings_connection_clear_secrets (NMSettingsConnection *self,
NULL);
g_object_unref (subject);
} else {
- nm_audit_log_connection_op (NM_AUDIT_OP_CONN_CLEAR_SECRETS, NM_CONNECTION (self),
+ nm_audit_log_connection_op (NM_AUDIT_OP_CONN_CLEAR_SECRETS, self,
FALSE, NULL, error->message);
g_dbus_method_invocation_take_error (context, error);
}
@@ -2399,20 +2617,6 @@ constructed (GObject *object)
}
static void
-_cancel_all (NMAgentManager *agent_mgr, GSList **preqs)
-{
- while (*preqs) {
- NMAgentManagerCallId call_id_a = (*preqs)->data;
-
- /* Cancel will invoke the complete callback, which in
- * turn deletes the current call-id from the list. */
- nm_agent_manager_cancel_secrets (agent_mgr, call_id_a);
-
- g_return_if_fail (!*preqs || (call_id_a != (*preqs)->data));
- }
-}
-
-static void
dispose (GObject *object)
{
NMSettingsConnection *self = NM_SETTINGS_CONNECTION (object);
@@ -2422,11 +2626,12 @@ dispose (GObject *object)
/* Cancel in-progress secrets requests */
if (priv->agent_mgr) {
- /* although @reqs_ext theoretically contains NMSettingsConnectionCallId,
- * we still cancel it with nm_agent_manager_cancel_secrets() -- it is
- * actually correct. */
- _cancel_all (priv->agent_mgr, &priv->reqs_ext);
- _cancel_all (priv->agent_mgr, &priv->reqs_int);
+ while (priv->get_secret_requests) {
+ GetSecretsInfo *info = priv->get_secret_requests->data;
+
+ _get_secrets_cancel (self, info, TRUE);
+ g_return_if_fail (!priv->get_secret_requests || (info != priv->get_secret_requests->data));
+ }
}
if (priv->updated_idle_id) {
diff --git a/src/settings/nm-settings-connection.h b/src/settings/nm-settings-connection.h
index d7ffbecd4e..5c12a8aca7 100644
--- a/src/settings/nm-settings-connection.h
+++ b/src/settings/nm-settings-connection.h
@@ -126,6 +126,10 @@ struct _NMSettingsConnectionClass {
GType nm_settings_connection_get_type (void);
+gboolean nm_settings_connection_has_unmodified_applied_connection (NMSettingsConnection *self,
+ NMConnection *applied_connection,
+ NMSettingCompareFlags compare_flage);
+
void nm_settings_connection_commit_changes (NMSettingsConnection *self,
NMSettingsConnectionCommitReason commit_reason,
NMSettingsConnectionCommitFunc callback,
@@ -154,13 +158,13 @@ typedef void (*NMSettingsConnectionSecretsFunc) (NMSettingsConnection *self,
gpointer user_data);
NMSettingsConnectionCallId nm_settings_connection_get_secrets (NMSettingsConnection *self,
+ NMConnection *applied_connection,
NMAuthSubject *subject,
const char *setting_name,
NMSecretAgentGetSecretsFlags flags,
const char **hints,
NMSettingsConnectionSecretsFunc callback,
- gpointer callback_data,
- GError **error);
+ gpointer callback_data);
void nm_settings_connection_cancel_secrets (NMSettingsConnection *self,
NMSettingsConnectionCallId call_id);
diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c
index 71bcf67494..951f417646 100644
--- a/src/settings/nm-settings.c
+++ b/src/settings/nm-settings.c
@@ -430,7 +430,7 @@ nm_settings_get_connection_by_path (NMSettings *self, const char *path)
}
gboolean
-nm_settings_has_connection (NMSettings *self, NMConnection *connection)
+nm_settings_has_connection (NMSettings *self, NMSettingsConnection *connection)
{
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
GHashTableIter iter;
@@ -1174,7 +1174,7 @@ send_agent_owned_secrets (NMSettings *self,
secrets_filter_cb,
GUINT_TO_POINTER (NM_SETTING_SECRET_FLAG_AGENT_OWNED));
nm_agent_manager_save_secrets (priv->agent_mgr,
- nm_connection_get_path (NM_CONNECTION (for_agent)),
+ nm_connection_get_path (NM_CONNECTION (connection)),
for_agent,
subject);
g_object_unref (for_agent);
@@ -1230,7 +1230,7 @@ pk_add_cb (NMAuthChain *chain,
callback (self, added, error, context, subject, callback_data);
/* Send agent-owned secrets to the agents */
- if (!error && added && nm_settings_has_connection (self, (NMConnection *) added))
+ if (!error && added && nm_settings_has_connection (self, added))
send_agent_owned_secrets (self, added, subject);
g_clear_error (&error);
@@ -1388,9 +1388,9 @@ impl_settings_add_connection_add_cb (NMSettings *self,
nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD, NULL, FALSE, subject, error->message);
} else {
g_dbus_method_invocation_return_value (
- context,
- g_variant_new ("(o)", nm_connection_get_path (NM_CONNECTION (connection))));
- nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD, NM_CONNECTION (connection), TRUE,
+ context,
+ g_variant_new ("(o)", nm_connection_get_path (NM_CONNECTION (connection))));
+ nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD, connection, TRUE,
subject, NULL);
}
}
@@ -2046,7 +2046,7 @@ hostnamed_properties_changed (GDBusProxy *proxy,
g_free (priv->hostname.value);
priv->hostname.value = g_strdup (hostname);
g_object_notify (G_OBJECT (user_data), NM_SETTINGS_HOSTNAME);
- nm_dispatcher_call (DISPATCHER_ACTION_HOSTNAME, NULL, NULL, NULL, NULL, NULL);
+ nm_dispatcher_call (DISPATCHER_ACTION_HOSTNAME, NULL, NULL, NULL, NULL, NULL, NULL);
}
g_variant_unref (v_hostname);
diff --git a/src/settings/nm-settings.h b/src/settings/nm-settings.h
index 0801054d66..923b164b04 100644
--- a/src/settings/nm-settings.h
+++ b/src/settings/nm-settings.h
@@ -113,7 +113,7 @@ NMSettingsConnection *nm_settings_get_connection_by_path (NMSettings *settings,
NMSettingsConnection *nm_settings_get_connection_by_uuid (NMSettings *settings,
const char *uuid);
-gboolean nm_settings_has_connection (NMSettings *self, NMConnection *connection);
+gboolean nm_settings_has_connection (NMSettings *self, NMSettingsConnection *connection);
const GSList *nm_settings_get_unmanaged_specs (NMSettings *self);