summary refs log tree commit diff
path: root/src/settings
diff options
context:
space:
mode:
Diffstat (limited to 'src/settings')
-rw-r--r--src/settings/Makefile.am1
-rw-r--r--src/settings/Makefile.in1
-rw-r--r--src/settings/nm-agent-manager.c29
-rw-r--r--src/settings/nm-polkit-helpers.h41
-rw-r--r--src/settings/nm-settings-connection.c204
-rw-r--r--src/settings/nm-settings.c64
-rw-r--r--src/settings/plugins/keyfile/writer.c33
7 files changed, 209 insertions, 164 deletions
diff --git a/src/settings/Makefile.am b/src/settings/Makefile.am
index 55b5b7ef..21dc5bb0 100644
--- a/src/settings/Makefile.am
+++ b/src/settings/Makefile.am
@@ -32,7 +32,6 @@ libsettings_la_SOURCES = \
 	nm-settings.h \
 	nm-inotify-helper.c \
 	nm-inotify-helper.h \
-	nm-polkit-helpers.h \
 	nm-settings-error.c \
 	nm-settings-error.h \
 	nm-system-config-interface.c \
diff --git a/src/settings/Makefile.in b/src/settings/Makefile.in
index 123132b7..980f35cb 100644
--- a/src/settings/Makefile.in
+++ b/src/settings/Makefile.in
@@ -396,7 +396,6 @@ libsettings_la_SOURCES = \
 	nm-settings.h \
 	nm-inotify-helper.c \
 	nm-inotify-helper.h \
-	nm-polkit-helpers.h \
 	nm-settings-error.c \
 	nm-settings-error.h \
 	nm-system-config-interface.c \
diff --git a/src/settings/nm-agent-manager.c b/src/settings/nm-agent-manager.c
index dbc29cae..8a5ea106 100644
--- a/src/settings/nm-agent-manager.c
+++ b/src/settings/nm-agent-manager.c
@@ -33,7 +33,6 @@
 #include "nm-secret-agent.h"
 #include "nm-manager-auth.h"
 #include "nm-dbus-glib-types.h"
-#include "nm-polkit-helpers.h"
 #include "nm-manager-auth.h"
 #include "nm-setting-vpn.h"
 #include "nm-setting-connection.h"
@@ -49,7 +48,6 @@ typedef struct {
 
 	NMDBusManager *dbus_mgr;
 	NMSessionMonitor *session_monitor;
-	PolkitAuthority *authority;
 
 	/* Hashed by owner name, not identifier, since two agents in different
 	 * sessions can use the same identifier.
@@ -338,7 +336,6 @@ typedef void (*RequestCancelFunc) (Request *req);
 
 struct _Request {
 	guint32 reqid;
-	PolkitAuthority *authority;
 	NMAuthChain *chain;
 
 	NMConnection *connection;
@@ -381,7 +378,6 @@ static guint32 next_req_id = 1;
 
 static Request *
 request_new_get (NMConnection *connection,
-                 PolkitAuthority *authority,
                  gboolean filter_by_uid,
                  gulong uid_filter,
                  GHashTable *existing_secrets,
@@ -402,7 +398,6 @@ request_new_get (NMConnection *connection,
 	req = g_malloc0 (sizeof (Request));
 	req->reqid = next_req_id++;
 	req->connection = g_object_ref (connection);
-	req->authority = g_object_ref (authority);
 	req->filter_by_uid = filter_by_uid;
 	req->uid_filter = uid_filter;
 	if (existing_secrets)
@@ -462,8 +457,6 @@ request_free (Request *req)
 		g_hash_table_unref (req->existing_secrets);
 	if (req->chain)
 		nm_auth_chain_unref (req->chain);
-	if (req->authority)
-		g_object_unref (req->authority);
 	memset (req, 0, sizeof (Request));
 	g_free (req);
 }
@@ -853,10 +846,10 @@ check_system_secrets_cb (NMSetting *setting,
 		/* VPNs are special; need to handle each secret separately */
 		g_hash_table_iter_init (&iter, (GHashTable *) g_value_get_boxed (value));
 		while (g_hash_table_iter_next (&iter, (gpointer *) &secret_name, NULL)) {
-			if (nm_setting_get_secret_flags (setting, secret_name, &secret_flags, NULL)) {
-				if (secret_flags == NM_SETTING_SECRET_FLAG_NONE)
-					*has_system = TRUE;
-			}
+			secret_flags = NM_SETTING_SECRET_FLAG_NONE;
+			nm_setting_get_secret_flags (setting, secret_name, &secret_flags, NULL);
+			if (secret_flags == NM_SETTING_SECRET_FLAG_NONE)
+				*has_system = TRUE;
 		}
 	} else {
 		nm_setting_get_secret_flags (setting, key, &secret_flags, NULL);
@@ -896,8 +889,7 @@ get_next_cb (Request *req)
 		nm_log_dbg (LOGD_AGENTS, "(%p/%s) request has system secrets; checking agent %s for MODIFY",
 		            req, req->setting_name, agent_dbus_owner);
 
-		req->chain = nm_auth_chain_new_dbus_sender (req->authority,
-		                                            agent_dbus_owner,
+		req->chain = nm_auth_chain_new_dbus_sender (agent_dbus_owner,
 		                                            get_agent_modify_auth_cb,
 		                                            req);
 		g_assert (req->chain);
@@ -1050,7 +1042,6 @@ nm_agent_manager_get_secrets (NMAgentManager *self,
 	 */
 
 	req = request_new_get (connection,
-	                       priv->authority,
 	                       filter_by_uid,
 	                       uid_filter,
 	                       existing_secrets,
@@ -1335,15 +1326,6 @@ static void
 nm_agent_manager_init (NMAgentManager *self)
 {
 	NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self);
-	GError *error = NULL;
-
-	priv->authority = polkit_authority_get_sync (NULL, &error);
-	if (!priv->authority) {
-		nm_log_warn (LOGD_SETTINGS, "failed to create PolicyKit authority: (%d) %s",
-		             error ? error->code : -1,
-		             error && error->message ? error->message : "(unknown)");
-		g_clear_error (&error);
-	}
 
 	priv->agents = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
 	priv->requests = g_hash_table_new_full (g_direct_hash,
@@ -1365,7 +1347,6 @@ dispose (GObject *object)
 
 		g_object_unref (priv->session_monitor);
 		g_object_unref (priv->dbus_mgr);
-		g_object_unref (priv->authority);
 	}
 
 	G_OBJECT_CLASS (nm_agent_manager_parent_class)->dispose (object);
diff --git a/src/settings/nm-polkit-helpers.h b/src/settings/nm-polkit-helpers.h
deleted file mode 100644
index d812e944..00000000
--- a/src/settings/nm-polkit-helpers.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/* NetworkManager system settings service
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * (C) Copyright 2008 Novell, Inc.
- * (C) Copyright 2008 - 2010 Red Hat, Inc.
- */
-
-#ifndef NM_POLKIT_HELPERS_H
-#define NM_POLKIT_HELPERS_H
-
-#include <polkit/polkit.h>
-
-/* Fix for polkit 0.97 and later */
-#if !HAVE_POLKIT_AUTHORITY_GET_SYNC
-static inline PolkitAuthority *
-polkit_authority_get_sync (GCancellable *cancellable, GError **error)
-{
-	PolkitAuthority *authority;
-
-	authority = polkit_authority_get ();
-	if (!authority)
-		g_set_error (error, 0, 0, "failed to get the PolicyKit authority");
-	return authority;
-}
-#endif
-
-#endif /* NM_POLKIT_HELPERS_H */
diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c
index 22aef716..60de6b06 100644
--- a/src/settings/nm-settings-connection.c
+++ b/src/settings/nm-settings-connection.c
@@ -34,7 +34,6 @@
 #include "nm-dbus-manager.h"
 #include "nm-settings-error.h"
 #include "nm-dbus-glib-types.h"
-#include "nm-polkit-helpers.h"
 #include "nm-logging.h"
 #include "nm-manager-auth.h"
 #include "nm-marshal.h"
@@ -83,7 +82,6 @@ typedef struct {
 	NMDBusManager *dbus_mgr;
 	NMAgentManager *agent_mgr;
 
-	PolkitAuthority *authority;
 	GSList *pending_auths; /* List of pending authentication requests */
 	NMConnection *secrets;
 	gboolean visible; /* Is this connection is visible by some session? */
@@ -98,6 +96,83 @@ typedef struct {
 
 /**************************************************************/
 
+/* Return TRUE to continue, FALSE to stop */
+typedef gboolean (*ForEachSecretFunc) (GHashTableIter *iter,
+                                       NMSettingSecretFlags flags,
+                                       gpointer user_data);
+
+static void
+for_each_secret (NMConnection *connection,
+                 GHashTable *secrets,
+                 ForEachSecretFunc callback,
+                 gpointer callback_data)
+{
+	GHashTableIter iter;
+	const char *setting_name;
+	GHashTable *setting_hash;
+
+	/* This function, given a hash of hashes representing new secrets of
+	 * an NMConnection, walks through each toplevel hash (which represents a
+	 * NMSetting), and for each setting, walks through that setting hash's
+	 * properties.  For each property that's a secret, it will check that
+	 * secret's flags in the backing NMConnection object, and call a supplied
+	 * callback.
+	 *
+	 * The one complexity is that the VPN setting's 'secrets' property is
+	 * *also* a hash table (since the key/value pairs are arbitrary and known
+	 * only to the VPN plugin itself).  That means we have three levels of
+	 * GHashTables that we potentially have to traverse here.  When we hit the
+	 * VPN setting's 'secrets' property, we special-case that and iterate over
+	 * each item in that 'secrets' hash table, calling the supplied callback
+	 * each time.
+	 */
+
+	/* Walk through the list of setting hashes */
+	g_hash_table_iter_init (&iter, secrets);
+	while (g_hash_table_iter_next (&iter, (gpointer) &setting_name, (gpointer) &setting_hash)) {
+		NMSetting *setting;
+		GHashTableIter secret_iter;
+		const char *secret_name;
+		GValue *val;
+
+		/* Get the actual NMSetting from the connection so we can get secret flags
+		 * from the connection data, since flags aren't secrets.  What we're
+		 * iterating here is just the secrets, not a whole connection.
+		 */
+		setting = nm_connection_get_setting_by_name (connection, setting_name);
+		if (setting == NULL)
+			continue;
+
+		/* Walk through the list of keys in each setting hash */
+		g_hash_table_iter_init (&secret_iter, setting_hash);
+		while (g_hash_table_iter_next (&secret_iter, (gpointer) &secret_name, (gpointer) &val)) {
+			NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE;
+
+			/* VPN secrets need slightly different treatment here since the
+			 * "secrets" property is actually a hash table of secrets.
+			 */
+			if (NM_IS_SETTING_VPN (setting) && (g_strcmp0 (secret_name, NM_SETTING_VPN_SECRETS) == 0)) {
+				GHashTableIter vpn_secrets_iter;
+
+				/* Iterate through each secret from the VPN hash in the overall secrets hash */
+				g_hash_table_iter_init (&vpn_secrets_iter, g_value_get_boxed (val));
+				while (g_hash_table_iter_next (&vpn_secrets_iter, (gpointer) &secret_name, NULL)) {
+					secret_flags = NM_SETTING_SECRET_FLAG_NONE;
+					nm_setting_get_secret_flags (setting, secret_name, &secret_flags, NULL);
+					if (callback (&vpn_secrets_iter, secret_flags, callback_data) == FALSE)
+						return;
+				}
+			} else {
+				nm_setting_get_secret_flags (setting, secret_name, &secret_flags, NULL);
+				if (callback (&secret_iter, secret_flags, callback_data) == FALSE)
+					return;
+			}
+		}
+	}
+}
+
+/**************************************************************/
+
 static void
 set_visible (NMSettingsConnection *self, gboolean new_visible)
 {
@@ -112,7 +187,8 @@ set_visible (NMSettingsConnection *self, gboolean new_visible)
 gboolean
 nm_settings_connection_is_visible (NMSettingsConnection *self)
 {
-	g_return_val_if_fail (NM_SETTINGS_CONNECTION (self), FALSE);
+	g_return_val_if_fail (self != NULL, FALSE);
+	g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), FALSE);
 
 	return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->visible;
 }
@@ -124,7 +200,8 @@ nm_settings_connection_recheck_visibility (NMSettingsConnection *self)
 	NMSettingConnection *s_con;
 	guint32 num, i;
 
-	g_return_if_fail (NM_SETTINGS_CONNECTION (self));
+	g_return_if_fail (self != NULL);
+	g_return_if_fail (NM_IS_SETTINGS_CONNECTION (self));
 
 	priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
 
@@ -178,10 +255,10 @@ only_system_secrets_cb (NMSetting *setting,
 
 			g_hash_table_iter_init (&iter, (GHashTable *) g_value_get_boxed (value));
 			while (g_hash_table_iter_next (&iter, (gpointer *) &secret_name, NULL)) {
-				if (nm_setting_get_secret_flags (setting, secret_name, &secret_flags, NULL)) {
-					if (secret_flags != NM_SETTING_SECRET_FLAG_NONE)
-						nm_setting_vpn_remove_secret (NM_SETTING_VPN (setting), secret_name);
-				}
+				secret_flags = NM_SETTING_SECRET_FLAG_NONE;
+				nm_setting_get_secret_flags (setting, secret_name, &secret_flags, NULL);
+				if (secret_flags != NM_SETTING_SECRET_FLAG_NONE)
+					nm_setting_vpn_remove_secret (NM_SETTING_VPN (setting), secret_name);
 			}
 		} else {
 			nm_setting_get_secret_flags (setting, key, &secret_flags, NULL);
@@ -204,15 +281,26 @@ update_secrets_cache (NMSettingsConnection *self)
 	nm_connection_for_each_setting_value (priv->secrets, only_system_secrets_cb, NULL);
 }
 
+static gboolean
+clear_system_secrets (GHashTableIter *iter,
+                      NMSettingSecretFlags flags,
+                      gpointer user_data)
+{
+	if (flags == NM_SETTING_SECRET_FLAG_NONE)
+		g_hash_table_iter_remove (iter);
+	return TRUE;
+}
+
 /* Update the settings of this connection to match that of 'new', taking care to
- * make a private copy of secrets. */
+ * make a private copy of secrets.
+ */
 gboolean
 nm_settings_connection_replace_settings (NMSettingsConnection *self,
                                          NMConnection *new,
                                          GError **error)
 {
 	NMSettingsConnectionPrivate *priv;
-	GHashTable *new_settings;
+	GHashTable *new_settings, *transient_secrets;
 	gboolean success = FALSE;
 
 	g_return_val_if_fail (self != NULL, FALSE);
@@ -222,18 +310,48 @@ nm_settings_connection_replace_settings (NMSettingsConnection *self,
 
 	priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
 
+	/* Replacing the settings might replace transient secrets, such as when
+	 * a user agent returns secrets, which might trigger the connection to be
+	 * written out, which triggers an inotify event to re-read and update the
+	 * connection, which, if we're not careful, could wipe out the transient
+	 * secrets the user agent just sent us.  Basically, only
+	 * nm_connection_clear_secrets() should wipe out transient secrets but
+	 * re-reading a connection from on-disk and updating our in-memory copy
+	 * should not.  Thus we preserve non-system-owned secrets here.
+	 */
+	transient_secrets = nm_connection_to_hash (NM_CONNECTION (self), NM_SETTING_HASH_FLAG_ONLY_SECRETS);
+	if (transient_secrets)
+		for_each_secret (NM_CONNECTION (self), transient_secrets, clear_system_secrets, NULL);
+
 	new_settings = nm_connection_to_hash (new, NM_SETTING_HASH_FLAG_ALL);
 	g_assert (new_settings);
 	if (nm_connection_replace_settings (NM_CONNECTION (self), new_settings, error)) {
+		GHashTableIter iter;
+		NMSetting *setting;
+		const char *setting_name;
+		GHashTable *setting_hash;
+
 		/* Copy the connection to keep its secrets around even if NM
 		 * calls nm_connection_clear_secrets().
 		 */
 		update_secrets_cache (self);
 
+		/* And add the transient secrets back */
+		if (transient_secrets) {
+			g_hash_table_iter_init (&iter, transient_secrets);
+			while (g_hash_table_iter_next (&iter, (gpointer) &setting_name, (gpointer) &setting_hash)) {
+				setting = nm_connection_get_setting_by_name (NM_CONNECTION (self), setting_name);
+				if (setting)
+					nm_setting_update_secrets (setting, setting_hash, NULL);
+			}
+		}
+
 		nm_settings_connection_recheck_visibility (self);
 		success = TRUE;
 	}
 	g_hash_table_destroy (new_settings);
+	if (transient_secrets)
+		g_hash_table_destroy (transient_secrets);
 	return success;
 }
 
@@ -398,11 +516,6 @@ supports_secrets (NMSettingsConnection *connection, const char *setting_name)
 	return TRUE;
 }
 
-/* Return TRUE to continue, FALSE to stop */
-typedef gboolean (*ForEachSecretFunc) (GHashTableIter *iter,
-                                       NMSettingSecretFlags flags,
-                                       gpointer user_data);
-
 static gboolean
 clear_nonagent_secrets (GHashTableIter *iter,
                         NMSettingSecretFlags flags,
@@ -430,7 +543,7 @@ has_system_owned_secrets (GHashTableIter *iter,
 {
 	gboolean *has_system_owned = user_data;
 
-	if (!(flags & NM_SETTING_SECRET_FLAG_AGENT_OWNED)) {
+	if (flags == NM_SETTING_SECRET_FLAG_NONE) {
 		*has_system_owned = TRUE;
 		return FALSE;
 	}
@@ -438,40 +551,6 @@ has_system_owned_secrets (GHashTableIter *iter,
 }
 
 static void
-for_each_secret (NMConnection *connection,
-                 GHashTable *secrets,
-                 ForEachSecretFunc callback,
-                 gpointer callback_data)
-{
-	GHashTableIter iter;
-	const char *setting_name;
-	GHashTable *setting_hash;
-
-	/* Walk through the list of setting hashes */
-	g_hash_table_iter_init (&iter, secrets);
-	while (g_hash_table_iter_next (&iter,
-	                               (gpointer *) &setting_name,
-	                               (gpointer *) &setting_hash)) {
-		GHashTableIter setting_iter;
-		const char *secret_name;
-
-		/* Walk through the list of keys in each setting hash */
-		g_hash_table_iter_init (&setting_iter, setting_hash);
-		while (g_hash_table_iter_next (&setting_iter, (gpointer *) &secret_name, NULL)) {
-			NMSetting *setting;
-			NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
-
-			/* Get the actual NMSetting from the connection so we can get secret flags */
-			setting = nm_connection_get_setting_by_name (connection, setting_name);
-			if (setting && nm_setting_get_secret_flags (setting, secret_name, &flags, NULL)) {
-				if (callback (&setting_iter, flags, callback_data) == FALSE)
-					return;
-			}
-		}
-	}
-}
-
-static void
 new_secrets_commit_cb (NMSettingsConnection *connection,
                        GError *error,
                        gpointer user_data)
@@ -850,7 +929,7 @@ auth_start (NMSettingsConnection *self,
 	}
 
 	if (check_permission) {
-		chain = nm_auth_chain_new (priv->authority, context, NULL, pk_auth_cb, self);
+		chain = nm_auth_chain_new (context, NULL, pk_auth_cb, self);
 		g_assert (chain);
 		nm_auth_chain_set_data (chain, "perm", (gpointer) check_permission, NULL);
 		nm_auth_chain_set_data (chain, "callback", callback, NULL);
@@ -980,10 +1059,10 @@ only_agent_secrets_cb (NMSetting *setting,
 			/* VPNs are special; need to handle each secret separately */
 			g_hash_table_iter_init (&iter, (GHashTable *) g_value_get_boxed (value));
 			while (g_hash_table_iter_next (&iter, (gpointer *) &secret_name, NULL)) {
-				if (nm_setting_get_secret_flags (setting, secret_name, &secret_flags, NULL)) {
-					if (secret_flags != NM_SETTING_SECRET_FLAG_AGENT_OWNED)
-						nm_setting_vpn_remove_secret (NM_SETTING_VPN (setting), secret_name);
-				}
+				secret_flags = NM_SETTING_SECRET_FLAG_NONE;
+				nm_setting_get_secret_flags (setting, secret_name, &secret_flags, NULL);
+				if (secret_flags != NM_SETTING_SECRET_FLAG_AGENT_OWNED)
+					nm_setting_vpn_remove_secret (NM_SETTING_VPN (setting), secret_name);
 			}
 		} else {
 			nm_setting_get_secret_flags (setting, key, &secret_flags, NULL);
@@ -1271,7 +1350,8 @@ nm_settings_connection_signal_remove (NMSettingsConnection *self)
 guint64
 nm_settings_connection_get_timestamp (NMSettingsConnection *connection)
 {
-	g_return_val_if_fail (NM_SETTINGS_CONNECTION (connection), 0);
+	g_return_val_if_fail (connection != NULL, 0);
+	g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (connection), 0);
 
 	return NM_SETTINGS_CONNECTION_GET_PRIVATE (connection)->timestamp;
 }
@@ -1368,18 +1448,9 @@ nm_settings_connection_init (NMSettingsConnection *self)
 	NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
 	static guint32 dbus_counter = 0;
 	char *dbus_path;
-	GError *error = NULL;
 
 	priv->dbus_mgr = nm_dbus_manager_get ();
 
-	priv->authority = polkit_authority_get_sync (NULL, &error);
-	if (!priv->authority) {
-		nm_log_warn (LOGD_SETTINGS, "failed to create PolicyKit authority: (%d) %s",
-		             error ? error->code : -1,
-		             error && error->message ? error->message : "(unknown)");
-		g_clear_error (&error);
-	}
-
 	dbus_path = g_strdup_printf ("%s/%u", NM_DBUS_PATH_SETTINGS, dbus_counter++);
 	nm_connection_set_path (NM_CONNECTION (self), dbus_path);
 	g_free (dbus_path);
@@ -1421,10 +1492,11 @@ dispose (GObject *object)
 
 	set_visible (self, FALSE);
 
+	if (priv->session_changed_id)
+		g_signal_handler_disconnect (priv->session_monitor, priv->session_changed_id);
 	g_object_unref (priv->session_monitor);
 	g_object_unref (priv->agent_mgr);
 	g_object_unref (priv->dbus_mgr);
-	g_object_unref (priv->authority);
 
 out:
 	G_OBJECT_CLASS (nm_settings_connection_parent_class)->dispose (object);
diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c
index 87fa4b6c..e23e8d13 100644
--- a/src/settings/nm-settings.c
+++ b/src/settings/nm-settings.c
@@ -56,7 +56,6 @@
 #include "nm-dbus-glib-types.h"
 #include "nm-settings.h"
 #include "nm-settings-connection.h"
-#include "nm-polkit-helpers.h"
 #include "nm-settings-error.h"
 #include "nm-default-wired-connection.h"
 #include "nm-logging.h"
@@ -114,8 +113,6 @@ typedef struct {
 
 	NMAgentManager *agent_mgr;
 
-	PolkitAuthority *authority;
-	guint auth_changed_id;
 	char *config_file;
 
 	NMSessionMonitor *session_monitor;
@@ -702,6 +699,46 @@ connection_visibility_changed (NMSettingsConnection *connection,
 	               connection);
 }
 
+#define NM_DBUS_SERVICE_OPENCONNECT    "org.freedesktop.NetworkManager.openconnect"
+#define NM_OPENCONNECT_KEY_GATEWAY "gateway"
+#define NM_OPENCONNECT_KEY_COOKIE "cookie"
+#define NM_OPENCONNECT_KEY_GWCERT "gwcert"
+#define NM_OPENCONNECT_KEY_XMLCONFIG "xmlconfig"
+#define NM_OPENCONNECT_KEY_LASTHOST "lasthost"
+#define NM_OPENCONNECT_KEY_AUTOCONNECT "autoconnect"
+#define NM_OPENCONNECT_KEY_CERTSIGS "certsigs"
+
+static void
+openconnect_migrate_hack (NMConnection *connection)
+{
+	NMSettingVPN *s_vpn;
+	NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NOT_SAVED;
+
+	/* Huge hack.  There were some openconnect changes that needed to happen
+	 * pretty late, too late to get into distros.  Migration has already
+	 * happened for many people, and their secret flags are wrong.  But we
+	 * don't want to requrie re-migration, so we have to fix it up here. Ugh.
+	 */
+
+	s_vpn = nm_connection_get_setting_vpn (connection);
+	if (s_vpn == NULL)
+		return;
+
+	if (g_strcmp0 (nm_setting_vpn_get_service_type (s_vpn), NM_DBUS_SERVICE_OPENCONNECT) == 0) {
+		/* These are different for every login session, and should not be stored */
+		nm_setting_set_secret_flags (NM_SETTING (s_vpn), NM_OPENCONNECT_KEY_GATEWAY, flags, NULL);
+		nm_setting_set_secret_flags (NM_SETTING (s_vpn), NM_OPENCONNECT_KEY_COOKIE, flags, NULL);
+		nm_setting_set_secret_flags (NM_SETTING (s_vpn), NM_OPENCONNECT_KEY_GWCERT, flags, NULL);
+
+		/* These are purely internal data for the auth-dialog, and should be stored */
+		flags = 0;
+		nm_setting_set_secret_flags (NM_SETTING (s_vpn), NM_OPENCONNECT_KEY_XMLCONFIG, flags, NULL);
+		nm_setting_set_secret_flags (NM_SETTING (s_vpn), NM_OPENCONNECT_KEY_LASTHOST, flags, NULL);
+		nm_setting_set_secret_flags (NM_SETTING (s_vpn), NM_OPENCONNECT_KEY_AUTOCONNECT, flags, NULL);
+		nm_setting_set_secret_flags (NM_SETTING (s_vpn), NM_OPENCONNECT_KEY_CERTSIGS, flags, NULL);
+	}
+}
+
 static void
 claim_connection (NMSettings *self,
                   NMSettingsConnection *connection,
@@ -739,6 +776,9 @@ claim_connection (NMSettings *self,
 	/* Ensure it's initial visibility is up-to-date */
 	nm_settings_connection_recheck_visibility (connection);
 
+	/* Evil openconnect migration hack */
+	openconnect_migrate_hack (NM_CONNECTION (connection));
+
 	id = g_signal_connect (connection, NM_SETTINGS_CONNECTION_REMOVED,
 	                       G_CALLBACK (connection_removed),
 	                       self);
@@ -999,7 +1039,7 @@ nm_settings_add_connection (NMSettings *self,
 		perm = NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM;
 
 	/* Otherwise validate the user request */
-	chain = nm_auth_chain_new (priv->authority, context, NULL, pk_add_cb, self);
+	chain = nm_auth_chain_new (context, NULL, pk_add_cb, self);
 	g_assert (chain);
 	priv->auths = g_slist_append (priv->auths, chain);
 	nm_auth_chain_add_call (chain, perm, TRUE);
@@ -1111,7 +1151,7 @@ impl_settings_save_hostname (NMSettings *self,
 	}
 
 	/* Otherwise validate the user request */
-	chain = nm_auth_chain_new (priv->authority, context, NULL, pk_hostname_cb, self);
+	chain = nm_auth_chain_new (context, NULL, pk_hostname_cb, self);
 	g_assert (chain);
 	priv->auths = g_slist_append (priv->auths, chain);
 	nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME, TRUE);
@@ -1476,18 +1516,9 @@ static void
 nm_settings_init (NMSettings *self)
 {
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
-	GError *error = NULL;
 
 	priv->connections = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
 
-	priv->authority = polkit_authority_get_sync (NULL, &error);
-	if (!priv->authority) {
-		nm_log_warn (LOGD_SETTINGS, "failed to create PolicyKit authority: (%d) %s",
-		             error ? error->code : -1,
-		             error && error->message ? error->message : "(unknown)");
-		g_clear_error (&error);
-	}
-
 	priv->session_monitor = nm_session_monitor_get ();
 
 	/* Hold a reference to the agent manager so it stays alive; the only
@@ -1505,11 +1536,6 @@ dispose (GObject *object)
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
 	GSList *iter;
 
-	if (priv->auth_changed_id) {
-		g_signal_handler_disconnect (priv->authority, priv->auth_changed_id);
-		priv->auth_changed_id = 0;
-	}
-
 	for (iter = priv->auths; iter; iter = g_slist_next (iter))
 		nm_auth_chain_unref ((NMAuthChain *) iter->data);
 	g_slist_free (priv->auths);
diff --git a/src/settings/plugins/keyfile/writer.c b/src/settings/plugins/keyfile/writer.c
index 5ecf5891..eeb14556 100644
--- a/src/settings/plugins/keyfile/writer.c
+++ b/src/settings/plugins/keyfile/writer.c
@@ -453,17 +453,22 @@ write_hash_of_string (GKeyFile *file,
 
 	g_hash_table_iter_init (&iter, (GHashTable *) g_value_get_boxed (value));
 	while (g_hash_table_iter_next (&iter, (gpointer *) &property, (gpointer *) &data)) {
-		NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
+		gboolean write_item = TRUE;
 
 		/* Handle VPN secrets specially; they are nested in the property's hash;
-		 * we don't want to write them if the secret is not saved or not required.
+		 * we don't want to write them if the secret is not saved, not required,
+		 * or owned by a user's secret agent.
 		 */
-		if (vpn_secrets && nm_setting_get_secret_flags (setting, property, &flags, NULL)) {
-			if (flags & (NM_SETTING_SECRET_FLAG_NOT_SAVED | NM_SETTING_SECRET_FLAG_NOT_REQUIRED))
-				continue;
+		if (vpn_secrets) {
+			NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE;
+
+			nm_setting_get_secret_flags (setting, property, &secret_flags, NULL);
+			if (secret_flags != NM_SETTING_SECRET_FLAG_NONE)
+				write_item = FALSE;
 		}
 
-		g_key_file_set_string (file, group_name, property, data);
+		if (write_item)
+			g_key_file_set_string (file, group_name, property, data);
 	}
 }
 
@@ -799,7 +804,6 @@ write_setting_value (NMSetting *setting,
 	GType type = G_VALUE_TYPE (value);
 	KeyWriter *writer = &key_writers[0];
 	GParamSpec *pspec;
-	NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
 
 	/* Setting name gets picked up from the keyfile's section name instead */
 	if (!strcmp (key, NM_SETTING_NAME))
@@ -822,12 +826,17 @@ write_setting_value (NMSetting *setting,
 	}
 
 	/* Don't write secrets that are owned by user secret agents or aren't
-	 * supposed to be saved.
+	 * supposed to be saved.  VPN secrets are handled specially though since
+	 * the secret flags there are in a third-level hash in the 'secrets'
+	 * property.
 	 */
-	if (   (pspec->flags & NM_SETTING_PARAM_SECRET)
-	    && nm_setting_get_secret_flags (setting, key, &flags, NULL)
-	    && (flags != NM_SETTING_SECRET_FLAG_NONE))
-		return;
+	if (pspec->flags & NM_SETTING_PARAM_SECRET && !NM_IS_SETTING_VPN (setting)) {
+		NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE;
+
+		nm_setting_get_secret_flags (setting, key, &secret_flags, NULL);
+		if (secret_flags != NM_SETTING_SECRET_FLAG_NONE)
+			return;
+	}
 
 	/* Look through the list of handlers for non-standard format key values */
 	while (writer->setting_name) {