about summary refs log tree commit diff
path: root/src/nm-manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nm-manager.c')
-rw-r--r--src/nm-manager.c2357
1 files changed, 1837 insertions, 520 deletions
diff --git a/src/nm-manager.c b/src/nm-manager.c
index aad65088..e34e9014 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -25,7 +25,6 @@
 #include <string.h>
 #include <dbus/dbus-glib-lowlevel.h>
 #include <dbus/dbus-glib.h>
-#include <glib/gi18n.h>
 
 #include "nm-glib-compat.h"
 #include "nm-manager.h"
@@ -39,10 +38,8 @@
 #include "nm-device-ethernet.h"
 #include "nm-device-wifi.h"
 #include "nm-device-olpc-mesh.h"
-#if WITH_WIMAX
-#include "nm-device-wimax.h"
-#endif
-#include "nm-device-modem.h"
+#include "nm-device-cdma.h"
+#include "nm-device-gsm.h"
 #include "nm-system.h"
 #include "nm-properties-changed-signal.h"
 #include "nm-setting-bluetooth.h"
@@ -55,10 +52,11 @@
 #include "nm-hostname-provider.h"
 #include "nm-bluez-manager.h"
 #include "nm-bluez-common.h"
-#include "nm-settings.h"
-#include "nm-settings-connection.h"
+#include "nm-sysconfig-settings.h"
+#include "nm-secrets-provider-interface.h"
+#include "nm-settings-interface.h"
+#include "nm-settings-system-interface.h"
 #include "nm-manager-auth.h"
-#include "NetworkManagerUtils.h"
 
 #define NM_AUTOIP_DBUS_SERVICE "org.freedesktop.nm_avahi_autoipd"
 #define NM_AUTOIP_DBUS_IFACE   "org.freedesktop.nm_avahi_autoipd"
@@ -67,17 +65,12 @@
 
 static gboolean impl_manager_get_devices (NMManager *manager, GPtrArray **devices, GError **err);
 static void impl_manager_activate_connection (NMManager *manager,
+                                              const char *service_name,
                                               const char *connection_path,
                                               const char *device_path,
                                               const char *specific_object_path,
                                               DBusGMethodInvocation *context);
 
-static void impl_manager_add_and_activate_connection (NMManager *manager,
-                                                      GHashTable *settings,
-                                                      const char *device_path,
-                                                      const char *specific_object_path,
-                                                      DBusGMethodInvocation *context);
-
 static void impl_manager_deactivate_connection (NMManager *manager,
                                                 const char *connection_path,
                                                 DBusGMethodInvocation *context);
@@ -93,17 +86,23 @@ static void impl_manager_enable (NMManager *manager,
 static void impl_manager_get_permissions (NMManager *manager,
                                           DBusGMethodInvocation *context);
 
-static gboolean impl_manager_get_state (NMManager *manager,
-                                        guint32 *state,
-                                        GError **error);
-
 static gboolean impl_manager_set_logging (NMManager *manager,
                                           const char *level,
                                           const char *domains,
                                           GError **error);
 
+/* Legacy 0.6 compatibility interface */
+
+static void impl_manager_legacy_sleep (NMManager *manager, DBusGMethodInvocation *context);
+static void impl_manager_legacy_wake  (NMManager *manager, DBusGMethodInvocation *context);
+static gboolean impl_manager_legacy_state (NMManager *manager, guint32 *state, GError **err);
+
 #include "nm-manager-glue.h"
 
+static void connection_added_default_handler (NMManager *manager,
+									 NMConnection *connection,
+									 NMConnectionScope scope);
+
 static void udev_device_added_cb (NMUdevManager *udev_mgr,
                                   GUdevDevice *device,
                                   NMDeviceCreatorFn creator_fn,
@@ -136,7 +135,6 @@ static const char *internal_activate_device (NMManager *manager,
                                              NMConnection *connection,
                                              const char *specific_object,
                                              gboolean user_requested,
-                                             gulong sender_uid,
                                              gboolean assumed,
                                              GError **error);
 
@@ -178,14 +176,19 @@ struct PendingActivation {
 	PendingActivationFunc callback;
 	NMAuthChain *chain;
 
+	gboolean have_connection;
+	gboolean authorized;
+
+	NMConnectionScope scope;
 	char *connection_path;
-	NMConnection *connection;
 	char *specific_object_path;
 	char *device_path;
+	guint timeout_id;
 };
 
 typedef struct {
 	gboolean user_enabled;
+	gboolean daemon_enabled;
 	gboolean sw_enabled;
 	gboolean hw_enabled;
 	RfKillType rtype;
@@ -194,6 +197,7 @@ typedef struct {
 	const char *prop;
 	const char *hw_prop;
 	RfKillState (*other_enabled_func) (NMManager *);
+	RfKillState (*daemon_enabled_func) (NMManager *);
 } RadioState;
 
 typedef struct {
@@ -207,9 +211,19 @@ typedef struct {
 	NMUdevManager *udev_mgr;
 	NMBluezManager *bluez_mgr;
 
-	NMSettings *settings;
+	GHashTable *user_connections;
+	DBusGProxy *user_proxy;
+	NMAuthCallResult user_con_perm;
+	NMAuthCallResult user_net_perm;
+
+	GHashTable *system_connections;
+	NMSysconfigSettings *sys_settings;
 	char *hostname;
 
+	GSList *secrets_calls;
+
+	GSList *pending_activations;
+
 	RadioState radio_states[RFKILL_TYPE_MAX];
 	gboolean sleeping;
 	gboolean net_enabled;
@@ -248,7 +262,12 @@ enum {
 	DEVICE_ADDED,
 	DEVICE_REMOVED,
 	STATE_CHANGED,
+	STATE_CHANGE,  /* DEPRECATED */
 	PROPERTIES_CHANGED,
+	CONNECTIONS_ADDED,
+	CONNECTION_ADDED,
+	CONNECTION_UPDATED,
+	CONNECTION_REMOVED,
 	CHECK_PERMISSIONS,
 	USER_PERMISSIONS_CHANGED,
 
@@ -266,8 +285,6 @@ enum {
 	PROP_WIRELESS_HARDWARE_ENABLED,
 	PROP_WWAN_ENABLED,
 	PROP_WWAN_HARDWARE_ENABLED,
-	PROP_WIMAX_ENABLED,
-	PROP_WIMAX_HARDWARE_ENABLED,
 	PROP_ACTIVE_CONNECTIONS,
 
 	/* Not exported */
@@ -277,19 +294,17 @@ enum {
 	LAST_PROP
 };
 
-
-/************************************************************************/
-
-typedef enum {
+typedef enum
+{
 	NM_MANAGER_ERROR_UNKNOWN_CONNECTION = 0,
 	NM_MANAGER_ERROR_UNKNOWN_DEVICE,
 	NM_MANAGER_ERROR_UNMANAGED_DEVICE,
+	NM_MANAGER_ERROR_INVALID_SERVICE,
 	NM_MANAGER_ERROR_SYSTEM_CONNECTION,
 	NM_MANAGER_ERROR_PERMISSION_DENIED,
 	NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE,
 	NM_MANAGER_ERROR_ALREADY_ASLEEP_OR_AWAKE,
 	NM_MANAGER_ERROR_ALREADY_ENABLED_OR_DISABLED,
-	NM_MANAGER_ERROR_UNSUPPORTED_CONNECTION_TYPE,
 } NMManagerError;
 
 #define NM_MANAGER_ERROR (nm_manager_error_quark ())
@@ -320,6 +335,10 @@ nm_manager_error_get_type (void)
 			ENUM_ENTRY (NM_MANAGER_ERROR_UNKNOWN_DEVICE, "UnknownDevice"),
 			/* Unmanaged device. */
 			ENUM_ENTRY (NM_MANAGER_ERROR_UNMANAGED_DEVICE, "UnmanagedDevice"),
+			/* Invalid settings service (not a recognized system or user
+			 * settings service name)
+			 */
+			ENUM_ENTRY (NM_MANAGER_ERROR_INVALID_SERVICE, "InvalidService"),
 			/* Connection was superceded by a system connection. */
 			ENUM_ENTRY (NM_MANAGER_ERROR_SYSTEM_CONNECTION, "SystemConnection"),
 			/* User does not have the permission to activate this connection. */
@@ -330,8 +349,6 @@ nm_manager_error_get_type (void)
 			ENUM_ENTRY (NM_MANAGER_ERROR_ALREADY_ASLEEP_OR_AWAKE, "AlreadyAsleepOrAwake"),
 			/* The manager is already in the requested enabled/disabled state */
 			ENUM_ENTRY (NM_MANAGER_ERROR_ALREADY_ENABLED_OR_DISABLED, "AlreadyEnabledOrDisabled"),
-			/* The requested operation is unsupported for this type of connection */
-			ENUM_ENTRY (NM_MANAGER_ERROR_UNSUPPORTED_CONNECTION_TYPE, "UnsupportedConnectionType"),
 			{ 0, 0, 0 },
 		};
 		etype = g_enum_register_static ("NMManagerError", values);
@@ -339,36 +356,6 @@ nm_manager_error_get_type (void)
 	return etype;
 }
 
-/************************************************************************/
-
-static NMDevice *
-nm_manager_get_device_by_udi (NMManager *manager, const char *udi)
-{
-	GSList *iter;
-
-	g_return_val_if_fail (udi != NULL, NULL);
-
-	for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) {
-		if (!strcmp (nm_device_get_udi (NM_DEVICE (iter->data)), udi))
-			return NM_DEVICE (iter->data);
-	}
-	return NULL;
-}
-
-static NMDevice *
-nm_manager_get_device_by_path (NMManager *manager, const char *path)
-{
-	GSList *iter;
-
-	g_return_val_if_fail (path != NULL, NULL);
-
-	for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) {
-		if (!strcmp (nm_device_get_path (NM_DEVICE (iter->data)), path))
-			return NM_DEVICE (iter->data);
-	}
-	return NULL;
-}
-
 static gboolean
 manager_sleeping (NMManager *self)
 {
@@ -428,8 +415,14 @@ modem_added (NMModemManager *modem_manager,
 		return;
 	}
 
-	/* Make the new modem device */
-	device = nm_device_modem_new (modem, driver);
+	/* Otherwise make a new top-level NMDevice for it */
+	if (NM_IS_MODEM_GSM (modem))
+		device = nm_device_gsm_new (NM_MODEM_GSM (modem), driver);
+	else if (NM_IS_MODEM_CDMA (modem))
+		device = nm_device_cdma_new (NM_MODEM_CDMA (modem), driver);
+	else
+		nm_log_info (LOGD_MB, "unhandled modem '%s'", ip_iface);
+
 	if (device)
 		add_device (self, device);
 }
@@ -439,7 +432,6 @@ nm_manager_update_state (NMManager *manager)
 {
 	NMManagerPrivate *priv;
 	NMState new_state = NM_STATE_DISCONNECTED;
-	GSList *iter;
 
 	g_return_if_fail (NM_IS_MANAGER (manager));
 
@@ -448,21 +440,16 @@ nm_manager_update_state (NMManager *manager)
 	if (manager_sleeping (manager))
 		new_state = NM_STATE_ASLEEP;
 	else {
+		GSList *iter;
+
 		for (iter = priv->devices; iter; iter = iter->next) {
 			NMDevice *dev = NM_DEVICE (iter->data);
-			NMDeviceState state = nm_device_get_state (dev);
 
-			if (state == NM_DEVICE_STATE_ACTIVATED) {
-				/* FIXME: handle local-only and site too */
-				new_state = NM_STATE_CONNECTED_GLOBAL;
+			if (nm_device_get_state (dev) == NM_DEVICE_STATE_ACTIVATED) {
+				new_state = NM_STATE_CONNECTED;
 				break;
-			}
-
-			if (nm_device_is_activating (dev))
+			} else if (nm_device_is_activating (dev)) {
 				new_state = NM_STATE_CONNECTING;
-			else if (new_state != NM_STATE_CONNECTING) {
-				if (state == NM_DEVICE_STATE_DEACTIVATING)
-					new_state = NM_STATE_DISCONNECTING;
 			}
 		}
 	}
@@ -472,7 +459,72 @@ nm_manager_update_state (NMManager *manager)
 		g_object_notify (G_OBJECT (manager), NM_MANAGER_STATE);
 
 		g_signal_emit (manager, signals[STATE_CHANGED], 0, priv->state);
+
+		/* Emit StateChange too for backwards compatibility */
+		g_signal_emit (manager, signals[STATE_CHANGE], 0, priv->state);
+	}
+}
+
+static void
+update_active_connection_timestamp (NMManager *manager, NMDevice *device)
+{
+	NMActRequest *req;
+	NMConnection *connection;
+	NMSettingConnection *s_con;
+	NMManagerPrivate *priv;
+	const char *connection_uuid;
+	guint64 timestamp;
+	guint64 *ts_ptr;
+	GKeyFile *timestamps_file;
+	char *data, *tmp;
+	gsize len;
+	GError *error = NULL;
+
+	g_return_if_fail (NM_IS_DEVICE (device));
+
+	priv = NM_MANAGER_GET_PRIVATE (manager);
+	req = nm_device_get_act_request (device);
+	if (!req)
+		return;
+
+	connection = nm_act_request_get_connection (req);
+	g_assert (connection);
+
+	if (nm_connection_get_scope (connection) != NM_CONNECTION_SCOPE_SYSTEM)
+		return;
+
+	/* Update timestamp in connection's object data */
+	timestamp = (guint64) time (NULL);
+	ts_ptr = g_new (guint64, 1);
+	*ts_ptr = timestamp;
+	g_object_set_data_full (G_OBJECT (connection), NM_SYSCONFIG_SETTINGS_TIMESTAMP_TAG, ts_ptr, g_free);
+
+	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (NM_CONNECTION (connection), NM_TYPE_SETTING_CONNECTION));
+	g_assert (s_con);
+	connection_uuid = nm_setting_connection_get_uuid (s_con);
+
+	/* Save timestamp to timestamps database file */
+	timestamps_file = g_key_file_new ();
+	if (!g_key_file_load_from_file (timestamps_file, NM_SYSCONFIG_SETTINGS_TIMESTAMPS_FILE, G_KEY_FILE_KEEP_COMMENTS, &error)) {
+		if (!(error->domain == G_FILE_ERROR && error->code == G_FILE_ERROR_NOENT))
+			nm_log_warn (LOGD_SYS_SET, "error parsing timestamps file '%s': %s", NM_SYSCONFIG_SETTINGS_TIMESTAMPS_FILE, error->message);
+		g_clear_error (&error);
+	}
+
+	tmp = g_strdup_printf ("%" G_GUINT64_FORMAT, timestamp);
+	g_key_file_set_value (timestamps_file, "timestamps", connection_uuid, tmp);
+	g_free (tmp);
+
+	data = g_key_file_to_data (timestamps_file, &len, &error);
+	if (data) {
+		g_file_set_contents (NM_SYSCONFIG_SETTINGS_TIMESTAMPS_FILE, data, len, &error);
+		g_free (data);
+	}
+	if (error) {
+		nm_log_warn (LOGD_SYS_SET, "error saving timestamp: %s", error->message);
+		g_error_free (error);
 	}
+	g_key_file_free (timestamps_file);
 }
 
 static void
@@ -498,14 +550,8 @@ manager_device_state_changed (NMDevice *device,
 
 	nm_manager_update_state (manager);
 
-	if (new_state == NM_DEVICE_STATE_ACTIVATED) {
-		NMActRequest *req;
-
-		req = nm_device_get_act_request (device);
-		if (req)
-			nm_settings_connection_update_timestamp (NM_SETTINGS_CONNECTION (nm_act_request_get_connection (req)),
-			                                         (guint64) time (NULL));
-	}
+	if (new_state == NM_DEVICE_STATE_ACTIVATED)
+		update_active_connection_timestamp (manager, device);
 }
 
 /* Removes a device from a device list; returns the start of the new device list */
@@ -534,7 +580,7 @@ remove_one_device (NMManager *manager,
 
 	g_signal_handlers_disconnect_by_func (device, manager_device_state_changed, manager);
 
-	nm_settings_device_removed (priv->settings, device);
+	nm_sysconfig_settings_device_removed (priv->sys_settings, device);
 	g_signal_emit (manager, signals[DEVICE_REMOVED], 0, device);
 	g_object_unref (device);
 
@@ -624,44 +670,24 @@ nm_manager_get_state (NMManager *manager)
 	return NM_MANAGER_GET_PRIVATE (manager)->state;
 }
 
-static gboolean
-might_be_vpn (NMConnection *connection)
+static void
+emit_removed (gpointer key, gpointer value, gpointer user_data)
 {
-	NMSettingConnection *s_con;
-	const char *ctype = NULL;
-
-	if (nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN))
-		return TRUE;
-
-	/* Make sure it's not a VPN, which we can't autocomplete yet */
-	s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
-	if (s_con)
-		ctype = nm_setting_connection_get_connection_type (s_con);
+	NMManager *manager = NM_MANAGER (user_data);
+	NMConnection *connection = NM_CONNECTION (value);
 
-	return (g_strcmp0 (ctype, NM_SETTING_VPN_SETTING_NAME) == 0);
+	g_signal_emit (manager, signals[CONNECTION_REMOVED], 0,
+	               connection,
+	               nm_connection_get_scope (connection));
 }
 
-static gboolean
-try_complete_vpn (NMConnection *connection, GSList *existing, GError **error)
+static void
+nm_manager_pending_activation_remove (NMManager *self,
+                                      PendingActivation *pending)
 {
-	g_assert (might_be_vpn (connection) == TRUE);
-
-	if (!nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN)) {
-		g_set_error_literal (error,
-			                 NM_MANAGER_ERROR,
-			                 NM_MANAGER_ERROR_UNSUPPORTED_CONNECTION_TYPE,
-			                 "VPN connections require a 'vpn' setting");
-		return FALSE;
-	}
-
-	nm_utils_complete_generic (connection,
-	                           NM_SETTING_VPN_SETTING_NAME,
-	                           existing,
-	                           _("VPN connection %d"),
-	                           NULL,
-	                           FALSE); /* No IPv6 by default for now */
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
 
-	return TRUE;
+	priv->pending_activations = g_slist_remove (priv->pending_activations, pending);
 }
 
 static PendingActivation *
@@ -669,65 +695,18 @@ pending_activation_new (NMManager *manager,
                         PolkitAuthority *authority,
                         DBusGMethodInvocation *context,
                         const char *device_path,
+                        NMConnectionScope scope,
                         const char *connection_path,
-                        GHashTable *settings,
                         const char *specific_object_path,
-                        PendingActivationFunc callback,
-                        GError **error)
+                        PendingActivationFunc callback)
 {
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
 	PendingActivation *pending;
-	NMDevice *device = NULL;
-	NMConnection *connection = NULL;
-	GSList *all_connections = NULL;
-	gboolean success;
 
 	g_return_val_if_fail (manager != NULL, NULL);
 	g_return_val_if_fail (authority != NULL, NULL);
 	g_return_val_if_fail (context != NULL, NULL);
 	g_return_val_if_fail (device_path != NULL, NULL);
-
-	/* A object path of "/" means NULL */
-	if (g_strcmp0 (specific_object_path, "/") == 0)
-		specific_object_path = NULL;
-	if (g_strcmp0 (device_path, "/") == 0)
-		device_path = NULL;
-
-	/* Create the partial connection from the given settings */
-	if (settings) {
-		if (device_path)
-			device = nm_manager_get_device_by_path (manager, device_path);
-		if (!device) {
-			g_set_error_literal (error,
-				                 NM_MANAGER_ERROR,
-				                 NM_MANAGER_ERROR_UNKNOWN_DEVICE,
-				                 "Device not found");
-			return NULL;
-		}
-
-		connection = nm_connection_new ();
-		nm_connection_replace_settings (connection, settings, NULL);
-
-		all_connections = nm_settings_get_connections (priv->settings);
-
-		if (might_be_vpn (connection)) {
-			/* Try to fill the VPN's connection setting and name at least */
-			success = try_complete_vpn (connection, all_connections, error);
-		} else {
-			/* Let each device subclass complete the connection */
-			success = nm_device_complete_connection (device,
-			                                         connection,
-			                                         specific_object_path,
-			                                         all_connections,
-			                                         error);
-		}
-		g_slist_free (all_connections);
-
-		if (success == FALSE) {
-			g_object_unref (connection);
-			return NULL;
-		}
-	}
+	g_return_val_if_fail (connection_path != NULL, NULL);
 
 	pending = g_slice_new0 (PendingActivation);
 	pending->manager = manager;
@@ -736,8 +715,8 @@ pending_activation_new (NMManager *manager,
 	pending->callback = callback;
 
 	pending->device_path = g_strdup (device_path);
+	pending->scope = scope;
 	pending->connection_path = g_strdup (connection_path);
-	pending->connection = connection;
 
 	/* "/" is special-cased to NULL to get through D-Bus */
 	if (specific_object_path && strcmp (specific_object_path, "/"))
@@ -747,6 +726,39 @@ pending_activation_new (NMManager *manager,
 }
 
 static void
+pending_auth_user_done (NMAuthChain *chain,
+                        GError *error,
+                        DBusGMethodInvocation *context,
+                        gpointer user_data)
+{
+	PendingActivation *pending = user_data;
+	NMAuthCallResult result;
+
+	pending->chain = NULL;
+
+	if (error) {
+		pending->callback (pending, error);
+		goto out;
+	}
+
+	/* Caller has had a chance to obtain authorization, so we only need to
+	 * check for 'yes' here.
+	 */
+	result = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, NM_AUTH_PERMISSION_USE_USER_CONNECTIONS));
+	if (result != NM_AUTH_CALL_RESULT_YES) {
+		error = g_error_new_literal (NM_MANAGER_ERROR,
+		                             NM_MANAGER_ERROR_PERMISSION_DENIED,
+		                             "Not authorized to use user connections.");
+		pending->callback (pending, error);
+		g_error_free (error);
+	} else
+		pending->callback (pending, NULL);
+
+out:
+	nm_auth_chain_unref (chain);
+}
+
+static void
 pending_auth_net_done (NMAuthChain *chain,
                        GError *error,
                        DBusGMethodInvocation *context,
@@ -775,33 +787,86 @@ pending_auth_net_done (NMAuthChain *chain,
 		goto out;
 	}
 
-	pending->callback (pending, NULL);
+	if (pending->scope == NM_CONNECTION_SCOPE_SYSTEM) {
+		/* System connection and the user is authorized for that if they have
+		 * the network-control permission.
+		 */
+		pending->callback (pending, NULL);
+	} else {
+		g_assert (pending->scope == NM_CONNECTION_SCOPE_USER);
+
+		/* User connection, check the 'use-user-connections' permission */
+		pending->chain = nm_auth_chain_new (pending->authority,
+			                                pending->context,
+			                                NULL,
+			                                pending_auth_user_done,
+			                                pending);
+		nm_auth_chain_add_call (pending->chain,
+			                    NM_AUTH_PERMISSION_USE_USER_CONNECTIONS,
+			                    TRUE);
+	}
 
 out:
 	nm_auth_chain_unref (chain);
 }
 
+static gboolean
+check_user_authorized (NMDBusManager *dbus_mgr,
+                       DBusGProxy *user_proxy,
+                       DBusGMethodInvocation *context,
+                       NMConnectionScope scope,
+                       gulong *out_sender_uid,
+                       const char **out_error_desc)
+{
+	g_return_val_if_fail (dbus_mgr != NULL, FALSE);
+	g_return_val_if_fail (context != NULL, FALSE);
+	g_return_val_if_fail (out_sender_uid != NULL, FALSE);
+	g_return_val_if_fail (out_error_desc != NULL, FALSE);
+
+	*out_sender_uid = G_MAXULONG;
+
+	/* Get the UID */
+	if (!nm_auth_get_caller_uid (context, dbus_mgr, out_sender_uid, out_error_desc))
+		return FALSE;
+
+	/* root gets to do anything */
+	if (0 == *out_sender_uid)
+		return TRUE;
+
+	/* Check whether the UID is authorized for user connections */
+	if (   scope == NM_CONNECTION_SCOPE_USER
+	    && !nm_auth_uid_authorized (*out_sender_uid,
+	                                dbus_mgr,
+	                                user_proxy,
+	                                out_error_desc))
+		return FALSE;
+
+	return TRUE;
+}
+
 static void
 pending_activation_check_authorized (PendingActivation *pending,
-                                     NMDBusManager *dbus_mgr)
+                                     NMDBusManager *dbus_mgr,
+                                     DBusGProxy *user_proxy)
 {
-	char *error_desc = NULL;
+	const char *error_desc = NULL;
 	gulong sender_uid = G_MAXULONG;
 	GError *error;
 
 	g_return_if_fail (pending != NULL);
 	g_return_if_fail (dbus_mgr != NULL);
 
-	if (!nm_auth_get_caller_uid (pending->context, 
-		                         dbus_mgr,
-	                             &sender_uid,
-	                             &error_desc)) {
+	if (!check_user_authorized (dbus_mgr,
+	                            user_proxy,
+	                            pending->context,
+	                            pending->scope,
+	                            &sender_uid,
+	                            &error_desc)) {
 		error = g_error_new_literal (NM_MANAGER_ERROR,
 		                             NM_MANAGER_ERROR_PERMISSION_DENIED,
 		                             error_desc);
 		pending->callback (pending, error);
 		g_error_free (error);
-		g_free (error_desc);
 		return;
 	}
 
@@ -832,22 +897,16 @@ pending_activation_destroy (PendingActivation *pending,
 {
 	g_return_if_fail (pending != NULL);
 
-	if (error)
-		dbus_g_method_return_error (pending->context, error);
-	else if (ac_path) {
-		if (pending->connection) {
-			dbus_g_method_return (pending->context,
-			                      pending->connection_path,
-			                      ac_path);
-		} else
-			dbus_g_method_return (pending->context, ac_path);
-	}
-
+	if (pending->timeout_id)
+		g_source_remove (pending->timeout_id);
 	g_free (pending->connection_path);
 	g_free (pending->specific_object_path);
 	g_free (pending->device_path);
-	if (pending->connection)
-		g_object_unref (pending->connection);
+
+	if (error)
+		dbus_g_method_return_error (pending->context, error);
+	else if (ac_path)
+		dbus_g_method_return (pending->context, ac_path);
 
 	if (pending->chain)
 		nm_auth_chain_unref (pending->chain);
@@ -860,7 +919,6 @@ static GPtrArray *
 get_active_connections (NMManager *manager, NMConnection *filter)
 {
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
-	NMVPNManager *vpn_manager;
 	GPtrArray *active;
 	GSList *iter;
 
@@ -882,35 +940,582 @@ get_active_connections (NMManager *manager, NMConnection *filter)
 	}
 
 	/* Add active VPN connections */
-	vpn_manager = nm_vpn_manager_get ();
-	nm_vpn_manager_add_active_connections (vpn_manager, filter, active);
-	g_object_unref (vpn_manager);
+	nm_vpn_manager_add_active_connections (priv->vpn_manager, filter, active);
 
 	return active;
 }
 
+static void
+remove_connection (NMManager *manager,
+                   NMConnection *connection,
+                   GHashTable *hash)
+{
+	/* Destroys the connection, then associated DBusGProxy due to the
+	 * weak reference notify function placed on the connection when it
+	 * was created.
+	 */
+	g_object_ref (connection);
+	g_hash_table_remove (hash, nm_connection_get_path (connection));
+	g_signal_emit (manager, signals[CONNECTION_REMOVED], 0,
+	               connection,
+	               nm_connection_get_scope (connection));
+	g_object_unref (connection);
+
+	bluez_manager_resync_devices (manager);
+}
+
 /*******************************************************************/
-/* Settings stuff via NMSettings                                   */
+/* User settings stuff via D-Bus                                   */
 /*******************************************************************/
 
 static void
-connections_changed (NMSettings *settings,
-                     NMSettingsConnection *connection,
-                     NMManager *manager)
+user_proxy_cleanup (NMManager *self, gboolean resync_bt)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+
+	if (priv->user_connections) {
+		g_hash_table_foreach (priv->user_connections, emit_removed, self);
+		g_hash_table_remove_all (priv->user_connections);
+	}
+
+	priv->user_net_perm = NM_AUTH_CALL_RESULT_UNKNOWN;
+	priv->user_con_perm = NM_AUTH_CALL_RESULT_UNKNOWN;
+
+	if (priv->user_proxy) {
+		g_object_unref (priv->user_proxy);
+		priv->user_proxy = NULL;
+	}
+
+	if (resync_bt) {
+		/* Resync BT devices since they are generated from connections */
+		bluez_manager_resync_devices (self);
+	}
+}
+
+typedef struct GetSettingsInfo {
+	NMManager *manager;
+	NMConnection *connection;
+	DBusGProxy *proxy;
+	guint32 *calls;
+} GetSettingsInfo;
+
+static void
+free_get_settings_info (gpointer data)
+{
+	GetSettingsInfo *info = (GetSettingsInfo *) data;
+
+	/* If this was the last pending call for a batch of GetSettings calls,
+	 * send out the connections-added signal.
+	 */
+	if (info->calls) {
+		(*info->calls)--;
+		if (*info->calls == 0) {
+			g_slice_free (guint32, (gpointer) info->calls);
+			g_signal_emit (info->manager, signals[CONNECTIONS_ADDED], 0, NM_CONNECTION_SCOPE_USER);
+
+			/* Update the Bluetooth connections for all the new connections */
+			bluez_manager_resync_devices (info->manager);
+		}
+	}
+
+	if (info->manager) {
+		g_object_unref (info->manager);
+		info->manager = NULL;
+	}
+	if (info->connection) {
+		g_object_unref (info->connection);
+		info->connection = NULL;
+	}
+	if (info->proxy) {
+		g_object_unref (info->proxy);
+		info->proxy = NULL;
+	}
+
+	g_slice_free (GetSettingsInfo, data);	
+}
+
+static void
+user_connection_get_settings_cb  (DBusGProxy *proxy,
+                                  DBusGProxyCall *call_id,
+                                  gpointer user_data)
 {
+	GetSettingsInfo *info = (GetSettingsInfo *) user_data;
+	GError *err = NULL;
+	GHashTable *settings = NULL;
+	NMConnection *connection;
+	NMManager *manager;
+
+	g_return_if_fail (info != NULL);
+
+	if (!dbus_g_proxy_end_call (proxy, call_id, &err,
+	                            DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, &settings,
+	                            G_TYPE_INVALID)) {
+		nm_log_info (LOGD_USER_SET, "couldn't retrieve connection settings: %s.",
+		             err && err->message ? err->message : "(unknown)");
+		g_error_free (err);
+		goto out;
+	}
+
+	manager = info->manager;
+	connection = info->connection;
+ 	if (connection == NULL) {
+		const char *path = dbus_g_proxy_get_path (proxy);
+		NMManagerPrivate *priv;
+		GError *error = NULL;
+		NMConnection *existing = NULL;
+
+		connection = nm_connection_new_from_hash (settings, &error);
+		if (connection == NULL) {
+			nm_log_warn (LOGD_USER_SET, "invalid connection: '%s' / '%s' invalid: %d",
+			             g_type_name (nm_connection_lookup_setting_type_by_quark (error->domain)),
+			             error->message, error->code);
+			g_error_free (error);
+			goto out;
+		}
+
+		nm_connection_set_path (connection, path);
+		nm_connection_set_scope (connection, NM_CONNECTION_SCOPE_USER);
+
+		/* Add the new connection to the internal hashes only if the same
+		 * connection isn't already there.
+		 */
+		priv = NM_MANAGER_GET_PRIVATE (manager);
+
+		existing = g_hash_table_lookup (priv->user_connections, path);
+		if (!existing || !nm_connection_compare (existing, connection, NM_SETTING_COMPARE_FLAG_EXACT)) {
+			g_hash_table_insert (priv->user_connections,
+			                     g_strdup (path),
+			                     connection);
+			existing = NULL;
+
+			/* Attach the D-Bus proxy representing the remote NMConnection
+			 * to the local NMConnection object to ensure it stays alive to
+			 * continue delivering signals.  It'll be destroyed once the
+			 * NMConnection is destroyed.
+			 */
+			g_object_set_data_full (G_OBJECT (connection),
+			                        "proxy",
+			                        g_object_ref (info->proxy),
+									g_object_unref);
+		} else
+			g_object_unref (connection);
+
+		/* If the connection-added signal is supposed to be batched, don't
+		 * emit the single connection-added here.  Also, don't emit the signal
+		 * if the connection wasn't actually added to the system or user hashes.
+		 */
+		if (!info->calls && !existing) {
+			g_signal_emit (manager, signals[CONNECTION_ADDED], 0, connection, NM_CONNECTION_SCOPE_USER);
+			/* Update the Bluetooth connections for that single new connection */
+			bluez_manager_resync_devices (manager);
+		}
+	} else {
+		// FIXME: merge settings? or just replace?
+		nm_log_dbg (LOGD_USER_SET, "implement merge settings");
+	}
+
+out:
+	if (settings)
+		g_hash_table_destroy (settings);
+
+	return;
+}
+
+static void
+user_connection_removed_cb (DBusGProxy *proxy, gpointer user_data)
+{
+	NMManager *manager = NM_MANAGER (user_data);
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+	NMConnection *connection = NULL;
+	const char *path;
+
+	path = dbus_g_proxy_get_path (proxy);
+	if (path) {
+		connection = g_hash_table_lookup (priv->user_connections, path);
+		if (connection)
+			remove_connection (manager, connection, priv->user_connections);
+	}
+}
+
+static void
+user_connection_updated_cb (DBusGProxy *proxy,
+                            GHashTable *settings,
+                            gpointer user_data)
+{
+	NMManager *manager = NM_MANAGER (user_data);
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+	NMConnection *new_connection;
+	NMConnection *old_connection = NULL;
+	gboolean valid = FALSE;
+	GError *error = NULL;
+	const char *path;
+
+	path = dbus_g_proxy_get_path (proxy);
+	if (path)
+		old_connection = g_hash_table_lookup (priv->user_connections, path);
+
+	g_return_if_fail (old_connection != NULL);
+
+	new_connection = nm_connection_new_from_hash (settings, &error);
+	if (!new_connection) {
+		/* New connection invalid, remove existing connection */
+		nm_log_warn (LOGD_USER_SET, "invalid connection: '%s' / '%s' invalid: %d",
+		             g_type_name (nm_connection_lookup_setting_type_by_quark (error->domain)),
+		             error->message, error->code);
+		g_error_free (error);
+		remove_connection (manager, old_connection, priv->user_connections);
+		return;
+	}
+	g_object_unref (new_connection);
+
+	valid = nm_connection_replace_settings (old_connection, settings, NULL);
+	if (valid) {
+		g_signal_emit (manager, signals[CONNECTION_UPDATED], 0,
+		               old_connection,
+		               nm_connection_get_scope (old_connection));
+
+		bluez_manager_resync_devices (manager);
+	} else {
+		remove_connection (manager, old_connection, priv->user_connections);
+	}
+}
+
+static void
+user_internal_new_connection_cb (NMManager *manager,
+                                 const char *path,
+                                 guint32 *counter)
+{
+	GetSettingsInfo *info;
+	DBusGProxy *con_proxy;
+	DBusGConnection *g_connection;
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+
+	g_connection = nm_dbus_manager_get_connection (priv->dbus_mgr);
+	con_proxy = dbus_g_proxy_new_for_name (g_connection,
+	                                       NM_DBUS_SERVICE_USER_SETTINGS,
+	                                       path,
+	                                       NM_DBUS_IFACE_SETTINGS_CONNECTION);
+	if (!con_proxy) {
+		nm_log_err (LOGD_USER_SET, "could not init user connection proxy");
+		return;
+	}
+
+	dbus_g_proxy_add_signal (con_proxy, "Updated",
+	                         DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT,
+	                         G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (con_proxy, "Updated",
+	                             G_CALLBACK (user_connection_updated_cb),
+	                             manager,
+	                             NULL);
+
+	dbus_g_proxy_add_signal (con_proxy, "Removed", G_TYPE_INVALID, G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (con_proxy, "Removed",
+	                             G_CALLBACK (user_connection_removed_cb),
+	                             manager,
+	                             NULL);
+
+	info = g_slice_new0 (GetSettingsInfo);
+	info->manager = g_object_ref (manager);
+	info->proxy = con_proxy;
+	if (counter) {
+		info->calls = counter;
+		(*info->calls)++;
+	}
+	dbus_g_proxy_begin_call (con_proxy, "GetSettings",
+	                         user_connection_get_settings_cb,
+	                         info,
+	                         free_get_settings_info,
+	                         G_TYPE_INVALID);
+}
+
+static void
+user_list_connections_cb  (DBusGProxy *proxy,
+                           DBusGProxyCall *call_id,
+                           gpointer user_data)
+{
+	NMManager *manager = NM_MANAGER (user_data);
+	GError *err = NULL;
+	GPtrArray *ops;
+	guint32 *counter = NULL;
+	int i;
+
+	if (!dbus_g_proxy_end_call (proxy, call_id, &err,
+	                            DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH, &ops,
+	                            G_TYPE_INVALID)) {
+		nm_log_warn (LOGD_USER_SET, "couldn't retrieve connections: %s",
+		             err && err->message ? err->message : "(unknown)");
+		g_clear_error (&err);
+		return;
+	}
+
+	/* Keep track of all calls made here; don't want to emit connection-added for
+	 * each one, but emit connections-added when they are all done.
+	 */
+	counter = g_slice_new0 (guint32);
+	for (i = 0; i < ops->len; i++) {
+		char *op = g_ptr_array_index (ops, i);
+
+		user_internal_new_connection_cb (manager, op, counter);
+		g_free (op);
+	}
+	g_ptr_array_free (ops, TRUE);
+}
+
+static void
+user_proxy_destroyed_cb (DBusGProxy *proxy, NMManager *self)
+{
+	nm_log_dbg (LOGD_USER_SET, "Removing user connections...");
+
+	/* At this point the user proxy is already being disposed */
+	NM_MANAGER_GET_PRIVATE (self)->user_proxy = NULL;
+
+	/* User Settings service disappeared; throw away user connections */
+	user_proxy_cleanup (self, TRUE);
+}
+
+static void
+user_new_connection_cb (DBusGProxy *proxy, const char *path, gpointer user_data)
+{
+	user_internal_new_connection_cb (NM_MANAGER (user_data), path, NULL);
+}
+
+static gboolean
+user_settings_authorized (NMManager *self, NMAuthChain *chain)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	NMAuthCallResult old_net_perm = priv->user_net_perm;
+	NMAuthCallResult old_con_perm = priv->user_con_perm;
+
+	/* If the user could potentially get authorization to use networking and/or
+	 * to use user connections, the user settings service is authorized.
+	 */
+	priv->user_net_perm = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL));
+	priv->user_con_perm = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, NM_AUTH_PERMISSION_USE_USER_CONNECTIONS));
+
+	nm_log_dbg (LOGD_USER_SET, "User connections permissions: net %d, con %d",
+	            priv->user_net_perm, priv->user_con_perm);
+
+	if (old_net_perm != priv->user_net_perm || old_con_perm != priv->user_con_perm)
+		g_signal_emit (self, signals[USER_PERMISSIONS_CHANGED], 0);
+
+	/* If the user can't control the network they certainly aren't allowed
+	 * to provide user connections.
+	 */
+	if (   priv->user_net_perm == NM_AUTH_CALL_RESULT_UNKNOWN
+	    || priv->user_net_perm == NM_AUTH_CALL_RESULT_NO)
+		return FALSE;
+
+	/* And of course if they aren't allowed to use user connections, they can't
+	 * provide them either.
+	 */
+	if (   priv->user_con_perm == NM_AUTH_CALL_RESULT_UNKNOWN
+	    || priv->user_con_perm == NM_AUTH_CALL_RESULT_NO)
+		return FALSE;
+
+	return TRUE;
+}
+
+static void
+user_proxy_auth_done (NMAuthChain *chain,
+                      GError *error,
+                      DBusGMethodInvocation *context,
+                      gpointer user_data)
+{
+	NMManager *self = NM_MANAGER (user_data);
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	gboolean authorized = FALSE;
+
+	priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
+
+	if (error) {
+		nm_log_warn (LOGD_USER_SET, "User connections unavailable: (%d) %s",
+		             error->code, error->message ? error->message : "(unknown)");
+	} else
+		authorized = user_settings_authorized (self, chain);
+
+	if (authorized) {
+		/* If authorized, finish setting up the user settings service proxy */
+		nm_log_dbg (LOGD_USER_SET, "Requesting user connections...");
+
+		authorized = TRUE;
+
+		dbus_g_proxy_add_signal (priv->user_proxy,
+			                     "NewConnection",
+			                     DBUS_TYPE_G_OBJECT_PATH,
+			                     G_TYPE_INVALID);
+		dbus_g_proxy_connect_signal (priv->user_proxy, "NewConnection",
+			                         G_CALLBACK (user_new_connection_cb),
+			                         self,
+			                         NULL);
+
+		/* Clean up when the user settings proxy goes away */
+		g_signal_connect (priv->user_proxy, "destroy",
+			              G_CALLBACK (user_proxy_destroyed_cb),
+			              self);
+
+		/* Request user connections */
+		dbus_g_proxy_begin_call (priv->user_proxy, "ListConnections",
+			                     user_list_connections_cb,
+			                     self,
+			                     NULL,
+			                     G_TYPE_INVALID);
+	} else {
+		/* Otherwise, we ignore the user settings service completely */
+		user_proxy_cleanup (self, TRUE);
+	}
+
+	nm_auth_chain_unref (chain);
+}
+
+static void
+user_proxy_init (NMManager *self)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	DBusGConnection *bus;
+	NMAuthChain *chain;
+	GError *error = NULL;
+
+	g_return_if_fail (self != NULL);
+	g_return_if_fail (priv->user_proxy == NULL);
+
+	/* Don't try to initialize the user settings proxy if the user
+	 * settings service doesn't actually exist.
+	 */
+	if (!nm_dbus_manager_name_has_owner (priv->dbus_mgr, NM_DBUS_SERVICE_USER_SETTINGS))
+		return;
+
+	bus = nm_dbus_manager_get_connection (priv->dbus_mgr);
+	priv->user_proxy = dbus_g_proxy_new_for_name_owner (bus,
+	                                                    NM_DBUS_SERVICE_USER_SETTINGS,
+	                                                    NM_DBUS_PATH_SETTINGS,
+	                                                    NM_DBUS_IFACE_SETTINGS,
+	                                                    &error);
+	if (!priv->user_proxy) {
+		nm_log_err (LOGD_USER_SET, "could not init user settings proxy: (%d) %s",
+		            error ? error->code : -1,
+		            error && error->message ? error->message : "(unknown)");
+		g_clear_error (&error);
+		return;
+	}
+
+	/* Kick off some PolicyKit authorization requests to figure out what
+	 * permissions this user settings service has.
+	 */
+	chain = nm_auth_chain_new (priv->authority,
+	                           NULL,
+	                           priv->user_proxy,
+	                           user_proxy_auth_done,
+	                           self);
+	priv->auth_chains = g_slist_prepend (priv->auth_chains, chain);
+
+	nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_USE_USER_CONNECTIONS, FALSE);
+	nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, FALSE);
+}
+
+/*******************************************************************/
+/* System settings stuff via NMSysconfigSettings                   */
+/*******************************************************************/
+
+static void
+system_connection_updated_cb (NMSettingsConnectionInterface *connection,
+                              gpointer unused,
+                              NMManager *manager)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+	const char *path;
+	NMSettingsConnectionInterface *existing;
+	GError *error = NULL;
+
+	path = nm_connection_get_path (NM_CONNECTION (connection));
+
+	existing = g_hash_table_lookup (priv->system_connections, path);
+	if (!existing)
+		return;
+	if (existing != connection) {
+		nm_log_warn (LOGD_SYS_SET, "existing connection didn't matched updated.");
+		return;
+	}
+
+	if (!nm_connection_verify (NM_CONNECTION (existing), &error)) {
+		/* Updated connection invalid, remove existing connection */
+		nm_log_warn (LOGD_SYS_SET, "invalid connection: '%s' / '%s' invalid: %d",
+		             g_type_name (nm_connection_lookup_setting_type_by_quark (error->domain)),
+		             error->message, error->code);
+		g_error_free (error);
+		remove_connection (manager, NM_CONNECTION (existing), priv->system_connections);
+		return;
+	}
+
+	g_signal_emit (manager, signals[CONNECTION_UPDATED], 0,
+	               existing, NM_CONNECTION_SCOPE_SYSTEM);
+
 	bluez_manager_resync_devices (manager);
 }
 
 static void
-system_unmanaged_devices_changed_cb (NMSettings *settings,
+system_connection_removed_cb (NMSettingsConnectionInterface *connection,
+                              NMManager *manager)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+	const char *path;
+
+	path = nm_connection_get_path (NM_CONNECTION (connection));
+
+	connection = g_hash_table_lookup (priv->system_connections, path);
+	if (connection)
+		remove_connection (manager, NM_CONNECTION (connection), priv->system_connections);
+}
+
+static void
+system_internal_new_connection (NMManager *manager,
+                                NMSettingsConnectionInterface *connection)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+	const char *path;
+
+	g_return_if_fail (connection != NULL);
+
+	g_signal_connect (connection, NM_SETTINGS_CONNECTION_INTERFACE_UPDATED,
+	                  G_CALLBACK (system_connection_updated_cb), manager);
+	g_signal_connect (connection, NM_SETTINGS_CONNECTION_INTERFACE_REMOVED,
+	                  G_CALLBACK (system_connection_removed_cb), manager);
+
+	path = nm_connection_get_path (NM_CONNECTION (connection));
+	g_hash_table_insert (priv->system_connections, g_strdup (path),
+	                     g_object_ref (connection));
+	g_signal_emit (manager, signals[CONNECTION_ADDED], 0, connection, NM_CONNECTION_SCOPE_SYSTEM);
+}
+
+static void
+system_new_connection_cb (NMSysconfigSettings *settings,
+                          NMSettingsConnectionInterface *connection,
+                          NMManager *manager)
+{
+	system_internal_new_connection (manager, connection);
+}
+
+static void
+system_query_connections (NMManager *manager)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+	GSList *system_connections, *iter;
+
+	system_connections = nm_settings_interface_list_connections (NM_SETTINGS_INTERFACE (priv->sys_settings));
+	for (iter = system_connections; iter; iter = g_slist_next (iter))
+		system_internal_new_connection (manager, NM_SETTINGS_CONNECTION_INTERFACE (iter->data));
+	g_slist_free (system_connections);
+}
+
+static void
+system_unmanaged_devices_changed_cb (NMSysconfigSettings *sys_settings,
                                      GParamSpec *pspec,
                                      gpointer user_data)
 {
-	NMManager *self = NM_MANAGER (user_data);
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	NMManager *manager = NM_MANAGER (user_data);
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
 	const GSList *unmanaged_specs, *iter;
 
-	unmanaged_specs = nm_settings_get_unmanaged_specs (priv->settings);
+	unmanaged_specs = nm_sysconfig_settings_get_unmanaged_specs (sys_settings);
 	for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
 		NMDevice *device = NM_DEVICE (iter->data);
 		gboolean managed;
@@ -919,28 +1524,30 @@ system_unmanaged_devices_changed_cb (NMSettings *settings,
 		nm_device_set_managed (device,
 		                       managed,
 		                       managed ? NM_DEVICE_STATE_REASON_NOW_MANAGED :
-		                                 NM_DEVICE_STATE_REASON_NOW_UNMANAGED);
+		                                   NM_DEVICE_STATE_REASON_NOW_UNMANAGED);
 	}
 }
 
 static void
-system_hostname_changed_cb (NMSettings *settings,
+system_hostname_changed_cb (NMSysconfigSettings *sys_settings,
                             GParamSpec *pspec,
                             gpointer user_data)
 {
-	NMManager *self = NM_MANAGER (user_data);
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	NMManager *manager = NM_MANAGER (user_data);
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
 	char *hostname;
 
-	hostname = nm_settings_get_hostname (priv->settings);
+	hostname = nm_sysconfig_settings_get_hostname (sys_settings);
+
 	if (!hostname && !priv->hostname)
 		return;
+
 	if (hostname && priv->hostname && !strcmp (hostname, priv->hostname))
 		return;
 
 	g_free (priv->hostname);
 	priv->hostname = (hostname && strlen (hostname)) ? g_strdup (hostname) : NULL;
-	g_object_notify (G_OBJECT (self), NM_MANAGER_HOSTNAME);
+	g_object_notify (G_OBJECT (manager), NM_MANAGER_HOSTNAME);
 
 	g_free (hostname);
 }
@@ -949,6 +1556,49 @@ system_hostname_changed_cb (NMSettings *settings,
 /* General NMManager stuff                                         */
 /*******************************************************************/
 
+static NMDevice *
+nm_manager_get_device_by_udi (NMManager *manager, const char *udi)
+{
+	GSList *iter;
+
+	for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) {
+		if (!strcmp (nm_device_get_udi (NM_DEVICE (iter->data)), udi))
+			return NM_DEVICE (iter->data);
+	}
+	return NULL;
+}
+
+static NMDevice *
+nm_manager_get_device_by_path (NMManager *manager, const char *path)
+{
+	GSList *iter;
+
+	for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) {
+		if (!strcmp (nm_device_get_path (NM_DEVICE (iter->data)), path))
+			return NM_DEVICE (iter->data);
+	}
+	return NULL;
+}
+
+static void
+nm_manager_name_owner_changed (NMDBusManager *mgr,
+                               const char *name,
+                               const char *old,
+                               const char *new,
+                               gpointer user_data)
+{
+	NMManager *manager = NM_MANAGER (user_data);
+	gboolean old_owner_good = (old && (strlen (old) > 0));
+	gboolean new_owner_good = (new && (strlen (new) > 0));
+
+	if (strcmp (name, NM_DBUS_SERVICE_USER_SETTINGS) == 0) {
+		if (!old_owner_good && new_owner_good)
+			user_proxy_init (manager);
+		else
+			user_proxy_cleanup (manager, TRUE);
+	}
+}
+
 /* Store value into key-file; supported types: boolean, int, string */
 static gboolean
 write_value_to_state_file (const char *filename,
@@ -1000,21 +1650,28 @@ write_value_to_state_file (const char *filename,
 }
 
 static gboolean
-radio_enabled_for_rstate (RadioState *rstate)
+radio_enabled_for_rstate (RadioState *rstate, gboolean check_daemon_enabled)
 {
-	return rstate->user_enabled && rstate->sw_enabled && rstate->hw_enabled;
+	gboolean enabled;
+
+	enabled = rstate->user_enabled && rstate->sw_enabled && rstate->hw_enabled;
+	if (rstate->daemon_enabled_func && check_daemon_enabled)
+		enabled &= rstate->daemon_enabled;
+	return enabled;
 }
 
 static gboolean
-radio_enabled_for_type (NMManager *self, RfKillType rtype)
+radio_enabled_for_type (NMManager *self, RfKillType rtype, gboolean check_daemon_enabled)
 {
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
 
-	return radio_enabled_for_rstate (&priv->radio_states[rtype]);
+	return radio_enabled_for_rstate (&priv->radio_states[rtype], check_daemon_enabled);
 }
 
 static void
-manager_update_radio_enabled (NMManager *self, RadioState *rstate)
+manager_update_radio_enabled (NMManager *self,
+                              RadioState *rstate,
+                              gboolean enabled)
 {
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
 	GSList *iter;
@@ -1032,7 +1689,6 @@ manager_update_radio_enabled (NMManager *self, RadioState *rstate)
 	/* enable/disable wireless devices as required */
 	for (iter = priv->devices; iter; iter = iter->next) {
 		RfKillType devtype = RFKILL_TYPE_UNKNOWN;
-		gboolean enabled = radio_enabled_for_rstate (rstate);
 
 		g_object_get (G_OBJECT (iter->data), NM_DEVICE_INTERFACE_RFKILL_TYPE, &devtype, NULL);
 		if (devtype == rstate->rtype) {
@@ -1050,7 +1706,6 @@ manager_hidden_ap_found (NMDeviceInterface *device,
                          gpointer user_data)
 {
 	NMManager *manager = NM_MANAGER (user_data);
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
 	const struct ether_addr *ap_addr;
 	const GByteArray *ap_ssid;
 	GSList *iter;
@@ -1066,7 +1721,8 @@ manager_hidden_ap_found (NMDeviceInterface *device,
 
 	/* Look for this AP's BSSID in the seen-bssids list of a connection,
 	 * and if a match is found, copy over the SSID */
-	connections = nm_settings_get_connections (priv->settings);
+	connections = nm_manager_get_connections (manager, NM_CONNECTION_SCOPE_SYSTEM);
+	connections = g_slist_concat (connections,  nm_manager_get_connections (manager, NM_CONNECTION_SCOPE_USER));
 
 	for (iter = connections; iter && !done; iter = g_slist_next (iter)) {
 		NMConnection *connection = NM_CONNECTION (iter->data);
@@ -1077,27 +1733,32 @@ manager_hidden_ap_found (NMDeviceInterface *device,
 
 		s_wireless = (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS);
 		if (!s_wireless)
-			continue;
+			goto next;
 
 		num_bssids = nm_setting_wireless_get_num_seen_bssids (s_wireless);
 		if (num_bssids < 1)
-			continue;
+			goto next;
 
 		ssid = nm_setting_wireless_get_ssid (s_wireless);
 		g_assert (ssid);
 
-		for (i = 0; i < num_bssids && !done; i++) {
+		for (i = 0; i < num_bssids; i++) {
 			const char *seen_bssid = nm_setting_wireless_get_seen_bssid (s_wireless, i);
 			struct ether_addr seen_addr;
 
-			if (ether_aton_r (seen_bssid, &seen_addr)) {
-				if (memcmp (ap_addr, &seen_addr, sizeof (struct ether_addr))) {
-					/* Copy the SSID from the connection to the AP */
-					nm_ap_set_ssid (ap, ssid);
-					done = TRUE;
-				}
-			}
+			if (!ether_aton_r (seen_bssid, &seen_addr))
+				continue;
+
+			if (memcmp (ap_addr, &seen_addr, sizeof (struct ether_addr)))
+				continue;
+
+			/* Copy the SSID from the connection to the AP */
+			nm_ap_set_ssid (ap, ssid);
+			done = TRUE;
 		}
+
+next:
+		g_object_unref (connection);
 	}
 	g_slist_free (connections);
 }
@@ -1174,9 +1835,9 @@ manager_rfkill_update_one_type (NMManager *self,
 	RfKillState other_state = RFKILL_UNBLOCKED;
 	RfKillState composite;
 	gboolean old_enabled, new_enabled, old_rfkilled, new_rfkilled;
-	gboolean old_hwe;
+	gboolean old_hwe, old_daemon_enabled = FALSE;
 
-	old_enabled = radio_enabled_for_rstate (rstate);
+	old_enabled = radio_enabled_for_rstate (rstate, TRUE);
 	old_rfkilled = rstate->hw_enabled && rstate->sw_enabled;
 	old_hwe = rstate->hw_enabled;
 
@@ -1195,9 +1856,26 @@ manager_rfkill_update_one_type (NMManager *self,
 
 	update_rstate_from_rfkill (rstate, composite);
 
+	/* If the device has a management daemon that can affect enabled state, check that now */
+	if (rstate->daemon_enabled_func) {
+		old_daemon_enabled = rstate->daemon_enabled;
+		rstate->daemon_enabled = (rstate->daemon_enabled_func (self) == RFKILL_UNBLOCKED);
+		if (old_daemon_enabled != rstate->daemon_enabled) {
+			nm_log_info (LOGD_RFKILL, "%s now %s by management service",
+				         rstate->desc,
+				         rstate->daemon_enabled ? "enabled" : "disabled");
+		}
+	}
+
+	/* Print out all states affecting device enablement */
 	if (rstate->desc) {
-		nm_log_dbg (LOGD_RFKILL, "%s hw-enabled %d sw-enabled %d",
-		            rstate->desc, rstate->hw_enabled, rstate->sw_enabled);
+		if (rstate->daemon_enabled_func) {
+			nm_log_dbg (LOGD_RFKILL, "%s hw-enabled %d sw-enabled %d daemon-enabled %d",
+			            rstate->desc, rstate->hw_enabled, rstate->sw_enabled, rstate->daemon_enabled);
+		} else {
+			nm_log_dbg (LOGD_RFKILL, "%s hw-enabled %d sw-enabled %d",
+			            rstate->desc, rstate->hw_enabled, rstate->sw_enabled);
+		}
 	}
 
 	/* Log new killswitch state */
@@ -1214,10 +1892,14 @@ manager_rfkill_update_one_type (NMManager *self,
 			g_object_notify (G_OBJECT (self), rstate->hw_prop);
 	}
 
-	/* And finally update the actual device radio state itself */
-	new_enabled = radio_enabled_for_rstate (rstate);
+	/* And finally update the actual device radio state itself; respect the
+	 * daemon state here because this is never called from user-triggered
+	 * radio changes and we only want to ignore the daemon enabled state when
+	 * handling user radio change requests.
+	 */
+	new_enabled = radio_enabled_for_rstate (rstate, TRUE);
 	if (new_enabled != old_enabled)
-		manager_update_radio_enabled (self, rstate);
+		manager_update_radio_enabled (self, rstate, new_enabled);
 }
 
 static void
@@ -1226,14 +1908,13 @@ nm_manager_rfkill_update (NMManager *self, RfKillType rtype)
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
 	guint i;
 
-	if (rtype != RFKILL_TYPE_UNKNOWN) {
+	if (rtype != RFKILL_TYPE_UNKNOWN)
 		manager_rfkill_update_one_type (self, &priv->radio_states[rtype], rtype);
-		return;
+	else {
+		/* Otherwise sync all radio types */
+		for (i = 0; i < RFKILL_TYPE_MAX; i++)
+			manager_rfkill_update_one_type (self, &priv->radio_states[i], i);
 	}
-
-	/* Otherwise sync all radio types */
-	for (i = 0; i < RFKILL_TYPE_MAX; i++)
-		manager_rfkill_update_one_type (self, &priv->radio_states[i], i);
 }
 
 static void
@@ -1264,40 +1945,90 @@ deactivate_disconnect_check_error (GError *auth_error,
 	} else if (result != NM_AUTH_CALL_RESULT_YES) {
 		return g_error_new (NM_MANAGER_ERROR,
 		                    NM_MANAGER_ERROR_PERMISSION_DENIED,
-		                    "Not authorized to %s connections",
+		                    "Not authorized to %s user connections",
 		                    detail);
 	}
 	return NULL;
 }
 
 static void
+disconnect_user_auth_done_cb (NMAuthChain *chain,
+                              GError *error,
+                              DBusGMethodInvocation *context,
+                              gpointer user_data)
+{
+	NMManager *self = NM_MANAGER (user_data);
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	GError *ret_error = NULL;
+	NMAuthCallResult result;
+	NMDevice *device;
+
+	priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
+
+	result = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, NM_AUTH_PERMISSION_USE_USER_CONNECTIONS));
+	ret_error = deactivate_disconnect_check_error (error, result, "Disconnect");
+	if (!ret_error) {
+		/* Everything authorized, deactivate the connection */
+		device = nm_auth_chain_get_data (chain, "device");
+		if (nm_device_interface_disconnect (NM_DEVICE_INTERFACE (device), &ret_error))
+			dbus_g_method_return (context);
+	}
+
+	if (ret_error)
+		dbus_g_method_return_error (context, ret_error);
+	g_clear_error (&ret_error);
+
+	nm_auth_chain_unref (chain);
+}
+
+static void
 disconnect_net_auth_done_cb (NMAuthChain *chain,
-                             GError *auth_error,
+                             GError *error,
                              DBusGMethodInvocation *context,
                              gpointer user_data)
 {
 	NMManager *self = NM_MANAGER (user_data);
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
-	GError *error = NULL;
+	GError *ret_error = NULL;
 	NMAuthCallResult result;
+	NMConnectionScope scope;
 	NMDevice *device;
 
 	priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
 
 	result = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL));
-	error = deactivate_disconnect_check_error (auth_error, result, "Disconnect");
-	if (!error) {
-		device = nm_auth_chain_get_data (chain, "device");
-		if (!nm_device_interface_disconnect (NM_DEVICE_INTERFACE (device), &error))
-			g_assert (error);
+	ret_error = deactivate_disconnect_check_error (error, result, "Disconnect");
+	if (ret_error) {
+		dbus_g_method_return_error (context, ret_error);
+		g_error_free (ret_error);
+		goto done;
 	}
 
-	if (error)
-		dbus_g_method_return_error (context, error);
-	else
-		dbus_g_method_return (context);
+	/* If it's a system connection, we're done */
+	device = nm_auth_chain_get_data (chain, "device");
+	scope = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, "scope"));
+	if (scope == NM_CONNECTION_SCOPE_USER) {
+		NMAuthChain *user_chain;
 
-	g_clear_error (&error);
+		/* It's a user connection, so we need to ensure the caller is
+		 * authorized to manipulate user connections.
+		 */
+		user_chain = nm_auth_chain_new (priv->authority, context, NULL, disconnect_user_auth_done_cb, self);
+		g_assert (user_chain);
+		priv->auth_chains = g_slist_append (priv->auth_chains, user_chain);
+
+		nm_auth_chain_set_data (user_chain, "device", g_object_ref (device), g_object_unref);
+		nm_auth_chain_set_data (user_chain, "scope", GUINT_TO_POINTER (scope), NULL);
+		nm_auth_chain_add_call (user_chain, NM_AUTH_PERMISSION_USE_USER_CONNECTIONS, TRUE);
+	} else {
+		if (!nm_device_interface_disconnect (NM_DEVICE_INTERFACE (device), &ret_error)) {
+			dbus_g_method_return_error (context, ret_error);
+			g_clear_error (&ret_error);
+		} else
+			dbus_g_method_return (context);
+	}
+
+done:
 	nm_auth_chain_unref (chain);
 }
 
@@ -1308,9 +2039,11 @@ manager_device_disconnect_request (NMDevice *device,
 {
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
 	NMActRequest *req;
+	NMConnection *connection;
 	GError *error = NULL;
+	NMConnectionScope scope;
 	gulong sender_uid = G_MAXULONG;
-	char *error_desc = NULL;
+	const char *error_desc = NULL;
 
 	req = nm_device_get_act_request (device);
 	if (!req) {
@@ -1322,19 +2055,24 @@ manager_device_disconnect_request (NMDevice *device,
 		return;
 	}
 
+	connection = nm_act_request_get_connection (req);
+	g_assert (connection);
+
 	/* Need to check the caller's permissions and stuff before we can
 	 * deactivate the connection.
 	 */
-	if (!nm_auth_get_caller_uid (context,
-		                         priv->dbus_mgr,
-	                             &sender_uid,
-	                             &error_desc)) {
+	scope = nm_connection_get_scope (connection);
+	if (!check_user_authorized (priv->dbus_mgr,
+	                            priv->user_proxy,
+	                            context,
+	                            scope,
+	                            &sender_uid,
+	                            &error_desc)) {
 		error = g_error_new_literal (NM_MANAGER_ERROR,
 		                             NM_MANAGER_ERROR_PERMISSION_DENIED,
 		                             error_desc);
 		dbus_g_method_return_error (context, error);
 		g_error_free (error);
-		g_free (error_desc);
 		return;
 	}
 
@@ -1354,6 +2092,7 @@ manager_device_disconnect_request (NMDevice *device,
 		priv->auth_chains = g_slist_append (priv->auth_chains, chain);
 
 		nm_auth_chain_set_data (chain, "device", g_object_ref (device), g_object_unref);
+		nm_auth_chain_set_data (chain, "scope", GUINT_TO_POINTER (scope), NULL);
 		nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE);
 	}
 }
@@ -1367,7 +2106,10 @@ add_device (NMManager *self, NMDevice *device)
 	static guint32 devcount = 0;
 	const GSList *unmanaged_specs;
 	NMConnection *existing = NULL;
+	GHashTableIter iter;
+	gpointer value;
 	gboolean managed = FALSE, enabled = FALSE;
+	RfKillType rtype = RFKILL_TYPE_UNKNOWN;
 
 	iface = nm_device_get_ip_iface (device);
 	g_assert (iface);
@@ -1401,32 +2143,21 @@ add_device (NMManager *self, NMDevice *device)
 		g_signal_connect (device, "notify::" NM_DEVICE_WIFI_IPW_RFKILL_STATE,
 		                  G_CALLBACK (manager_ipw_rfkill_state_changed),
 		                  self);
-
-		/* Update global rfkill state with this device's rfkill state, and
-		 * then set this device's rfkill state based on the global state.
-		 */
-		nm_manager_rfkill_update (self, RFKILL_TYPE_WLAN);
-		enabled = radio_enabled_for_type (self, RFKILL_TYPE_WLAN);
-		nm_device_interface_set_enabled (NM_DEVICE_INTERFACE (device), enabled);
+		rtype = RFKILL_TYPE_WLAN;
 	} else if (NM_IS_DEVICE_MODEM (device)) {
 		g_signal_connect (device, NM_DEVICE_MODEM_ENABLE_CHANGED,
 		                  G_CALLBACK (manager_modem_enabled_changed),
 		                  self);
+		rtype = RFKILL_TYPE_WWAN;
+	}
 
-		nm_manager_rfkill_update (self, RFKILL_TYPE_WWAN);
-		enabled = radio_enabled_for_type (self, RFKILL_TYPE_WWAN);
-		/* Until we start respecting WWAN rfkill switches the modem itself
-		 * is the source of the enabled/disabled state, so the manager shouldn't
-		 * touch it here.
-		nm_device_interface_set_enabled (NM_DEVICE_INTERFACE (device),
-		                                 priv->radio_states[RFKILL_TYPE_WWAN].enabled);
-		*/
-#if WITH_WIMAX
-	} else if (NM_IS_DEVICE_WIMAX (device)) {
-		nm_manager_rfkill_update (self, RFKILL_TYPE_WIMAX);
-		enabled = radio_enabled_for_type (self, RFKILL_TYPE_WIMAX);
+	if (rtype != RFKILL_TYPE_UNKNOWN) {
+		/* Update global rfkill state with this device's rfkill state, and
+		 * then set this device's rfkill state based on the global state.
+		 */
+		nm_manager_rfkill_update (self, rtype);
+		enabled = radio_enabled_for_type (self, rtype, TRUE);
 		nm_device_interface_set_enabled (NM_DEVICE_INTERFACE (device), enabled);
-#endif
 	}
 
 	type_desc = nm_device_get_type_desc (device);
@@ -1451,19 +2182,25 @@ add_device (NMManager *self, NMDevice *device)
 	if (nm_device_interface_can_assume_connections (NM_DEVICE_INTERFACE (device))) {
 		GSList *connections = NULL;
 
-		connections = nm_settings_get_connections (priv->settings);
+		g_hash_table_iter_init (&iter, priv->system_connections);
+		while (g_hash_table_iter_next (&iter, NULL, &value))
+			connections = g_slist_append (connections, value);
 		existing = nm_device_interface_connection_match_config (NM_DEVICE_INTERFACE (device),
 		                                                        (const GSList *) connections);
 		g_slist_free (connections);
 
-		if (existing)
+		if (existing) {
+			NMSettingConnection *s_con;
+
+			s_con = (NMSettingConnection *) nm_connection_get_setting (existing, NM_TYPE_SETTING_CONNECTION);
 			nm_log_dbg (LOGD_DEVICE, "(%s): found existing device connection '%s'",
 			            nm_device_get_iface (device),
-			            nm_connection_get_id (existing));
+			            nm_setting_connection_get_id (s_con));
+		}
 	}
 
 	/* Start the device if it's supposed to be managed */
-	unmanaged_specs = nm_settings_get_unmanaged_specs (priv->settings);
+	unmanaged_specs = nm_sysconfig_settings_get_unmanaged_specs (priv->sys_settings);
 	if (   !manager_sleeping (self)
 	    && !nm_device_interface_spec_match_list (NM_DEVICE_INTERFACE (device), unmanaged_specs)) {
 		nm_device_set_managed (device,
@@ -1473,7 +2210,7 @@ add_device (NMManager *self, NMDevice *device)
 		managed = TRUE;
 	}
 
-	nm_settings_device_added (priv->settings, device);
+	nm_sysconfig_settings_device_added (priv->sys_settings, device);
 	g_signal_emit (self, signals[DEVICE_ADDED], 0, device);
 
 	/* If the device has a connection it can assume, do that now */
@@ -1484,11 +2221,12 @@ add_device (NMManager *self, NMDevice *device)
 		nm_log_dbg (LOGD_DEVICE, "(%s): will attempt to assume existing connection",
 		            nm_device_get_iface (device));
 
-		ac_path = internal_activate_device (self, device, existing, NULL, FALSE, 0, TRUE, &error);
+		ac_path = internal_activate_device (self, device, existing, NULL, FALSE, TRUE, &error);
 		if (ac_path)
 			g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS);
 		else {
-			nm_log_warn (LOGD_DEVICE, "assumed connection %s failed to activate: (%d) %s",
+			nm_log_warn (LOGD_DEVICE, "assumed connection (%d) %s failed to activate: (%d) %s",
+			             nm_connection_get_scope (existing),
 			             nm_connection_get_path (existing),
 			             error ? error->code : -1,
 			             error && error->message ? error->message : "(unknown)");
@@ -1528,11 +2266,11 @@ bluez_manager_find_connection (NMManager *manager,
                                const char *bdaddr,
                                guint32 capabilities)
 {
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
 	NMConnection *found = NULL;
 	GSList *connections, *l;
 
-	connections = nm_settings_get_connections (priv->settings);
+	connections = nm_manager_get_connections (manager, NM_CONNECTION_SCOPE_SYSTEM);
+	connections = g_slist_concat (connections, nm_manager_get_connections (manager, NM_CONNECTION_SCOPE_USER));
 
 	for (l = connections; l != NULL; l = l->next) {
 		NMConnection *candidate = NM_CONNECTION (l->data);
@@ -1812,13 +2550,312 @@ nm_manager_get_act_request_by_path (NMManager *manager,
 	return NULL;
 }
 
+typedef struct GetSecretsInfo {
+	NMManager *manager;
+	NMSecretsProviderInterface *provider;
+
+	char *setting_name;
+	RequestSecretsCaller caller;
+	gboolean request_new;
+
+	/* User connection bits */
+	DBusGProxy *proxy;
+	DBusGProxyCall *call;
+
+	/* System connection bits */
+	guint32 idle_id;
+	char *hint1;
+	char *hint2;
+	char *connection_path;
+} GetSecretsInfo;
+
+static void
+free_get_secrets_info (gpointer data)
+{
+	GetSecretsInfo *info = data;
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (info->manager);
+
+	g_object_weak_unref (G_OBJECT (info->provider), (GWeakNotify) free_get_secrets_info, info);
+
+	priv->secrets_calls = g_slist_remove (priv->secrets_calls, info);
+
+	if (info->proxy) {
+		if (info->call)
+			dbus_g_proxy_cancel_call (info->proxy, info->call);
+		g_object_unref (info->proxy);
+	}
+
+	if (info->idle_id)
+		g_source_remove (info->idle_id);
+
+	g_free (info->hint1);
+	g_free (info->hint2);
+	g_free (info->setting_name);
+	g_free (info->connection_path);
+	memset (info, 0, sizeof (GetSecretsInfo));
+	g_free (info);
+}
+
+static void
+provider_cancel_secrets (NMSecretsProviderInterface *provider, gpointer user_data)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (user_data);
+	GSList *iter;
+
+	for (iter = priv->secrets_calls; iter; iter = g_slist_next (iter)) {
+		GetSecretsInfo *candidate = iter->data;
+
+		if (candidate->provider == provider) {
+			free_get_secrets_info (candidate);
+			break;
+		}
+	}
+}
+
+static void
+user_get_secrets_cb (DBusGProxy *proxy,
+                     DBusGProxyCall *call,
+                     gpointer user_data)
+{
+	GetSecretsInfo *info = (GetSecretsInfo *) user_data;
+	NMManagerPrivate *priv;
+	GHashTable *settings = NULL;
+	GError *error = NULL;
+	GObject *provider;
+
+	g_return_if_fail (info != NULL);
+	g_return_if_fail (info->provider);
+	g_return_if_fail (info->setting_name);
+
+	/* Remove the GetSecretsInfo from our internal list just in case
+	 * calling the secrets provider's get_secrets_result() function tries
+	 * to cancel the secrets request, which would cause us to double-free
+	 * the GetSecretsInfo.  We know we're going to free it at the end here,
+	 * so there's no need to track it anymore.
+	 */
+	priv = NM_MANAGER_GET_PRIVATE (info->manager);
+	priv->secrets_calls = g_slist_remove (priv->secrets_calls, info);
+
+	provider = g_object_ref (info->provider);
+
+	if (dbus_g_proxy_end_call (proxy, call, &error,
+	                           DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, &settings,
+	                           G_TYPE_INVALID)) {
+		nm_secrets_provider_interface_get_secrets_result (info->provider,
+		                                                  info->setting_name,
+		                                                  info->caller,
+		                                                  settings,
+		                                                  NULL);
+		g_hash_table_destroy (settings);
+	} else {
+		nm_secrets_provider_interface_get_secrets_result (info->provider,
+		                                                  info->setting_name,
+		                                                  info->caller,
+		                                                  NULL,
+		                                                  error);
+		g_clear_error (&error);
+	}
+
+	info->call = NULL;
+	free_get_secrets_info (info);
+
+	g_object_unref (provider);
+}
+
+static GetSecretsInfo *
+user_get_secrets (NMManager *self,
+                  NMSecretsProviderInterface *provider,
+                  NMConnection *connection,
+                  const char *setting_name,
+                  gboolean request_new,
+                  RequestSecretsCaller caller_id,
+                  const char *hint1,
+                  const char *hint2)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	DBusGConnection *g_connection;
+	GetSecretsInfo *info = NULL;
+	GPtrArray *hints = NULL;
+
+	info = g_malloc0 (sizeof (GetSecretsInfo));
+
+	g_connection = nm_dbus_manager_get_connection (priv->dbus_mgr);
+	info->proxy = dbus_g_proxy_new_for_name (g_connection,
+	                                         NM_DBUS_SERVICE_USER_SETTINGS,
+	                                         nm_connection_get_path (connection),
+	                                         NM_DBUS_IFACE_SETTINGS_CONNECTION_SECRETS);
+	if (!info->proxy) {
+		nm_log_warn (LOGD_USER_SET, "could not create user connection secrets proxy");
+		g_free (info);
+		return NULL;
+	}
+
+	info->manager = self;
+	info->provider = provider;
+	info->caller = caller_id;
+	info->setting_name = g_strdup (setting_name);
+
+	g_object_weak_ref (G_OBJECT (provider), (GWeakNotify) free_get_secrets_info, info);
+
+	hints = g_ptr_array_sized_new (2);
+	if (hint1)
+		g_ptr_array_add (hints, (char *) hint1);
+	if (hint2)
+		g_ptr_array_add (hints, (char *) hint2);
+
+	info->call = dbus_g_proxy_begin_call_with_timeout (info->proxy, "GetSecrets",
+	                                                   user_get_secrets_cb,
+	                                                   info,
+	                                                   NULL,
+	                                                   G_MAXINT32,
+	                                                   G_TYPE_STRING, setting_name,
+	                                                   DBUS_TYPE_G_ARRAY_OF_STRING, hints,
+	                                                   G_TYPE_BOOLEAN, request_new,
+	                                                   G_TYPE_INVALID);
+	g_ptr_array_free (hints, TRUE);
+	return info;
+}
+
+static void
+system_get_secrets_reply_cb (NMSettingsConnectionInterface *connection,
+                             GHashTable *secrets,
+                             GError *error,
+                             gpointer user_data)
+{
+	GetSecretsInfo *info = user_data;
+	GObject *provider;
+
+	provider = g_object_ref (info->provider);
+
+	nm_secrets_provider_interface_get_secrets_result (info->provider,
+	                                                  info->setting_name,
+	                                                  info->caller,
+	                                                  error ? NULL : secrets,
+	                                                  error);
+	free_get_secrets_info (info);
+	g_object_unref (provider);
+}
+
+static gboolean
+system_get_secrets_idle_cb (gpointer user_data)
+{
+	GetSecretsInfo *info = user_data;
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (info->manager);
+	NMSettingsConnectionInterface *connection;
+	GError *error = NULL;
+	const char *hints[3] = { NULL, NULL, NULL };
+
+	info->idle_id = 0;
+
+	connection = nm_settings_interface_get_connection_by_path (NM_SETTINGS_INTERFACE (priv->sys_settings), 
+	                                                           info->connection_path);
+	if (!connection) {
+		error = g_error_new_literal (NM_MANAGER_ERROR,
+		                             NM_MANAGER_ERROR_UNKNOWN_CONNECTION,
+		                             "unknown connection (not exported by system settings)");
+		nm_secrets_provider_interface_get_secrets_result (info->provider,
+		                                                  info->setting_name,
+		                                                  info->caller,
+		                                                  NULL,
+		                                                  error);
+		g_error_free (error);
+		free_get_secrets_info (info);
+		return FALSE;
+	}
+
+	hints[0] = info->hint1;
+	hints[1] = info->hint2;
+	nm_settings_connection_interface_get_secrets (connection,
+	                                              info->setting_name,
+	                                              hints,
+	                                              info->request_new,
+	                                              system_get_secrets_reply_cb,
+	                                              info);
+	return FALSE;
+}
+
+static GetSecretsInfo *
+system_get_secrets (NMManager *self,
+                    NMSecretsProviderInterface *provider,
+                    NMConnection *connection,
+                    const char *setting_name,
+                    gboolean request_new,
+                    RequestSecretsCaller caller_id,
+                    const char *hint1,
+                    const char *hint2)
+{
+	GetSecretsInfo *info;
+
+	info = g_malloc0 (sizeof (GetSecretsInfo));
+	info->manager = self;
+	info->provider = provider;
+	info->caller = caller_id;
+	info->setting_name = g_strdup (setting_name);
+	info->hint1 = hint1 ? g_strdup (hint1) : NULL;
+	info->hint2 = hint2 ? g_strdup (hint2) : NULL;
+	info->connection_path = g_strdup (nm_connection_get_path (connection));
+	info->request_new = request_new;
+
+	g_object_weak_ref (G_OBJECT (provider), (GWeakNotify) free_get_secrets_info, info);
+
+	info->idle_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
+	                                 system_get_secrets_idle_cb,
+	                                 info,
+	                                 NULL);
+	return info;
+}
+
+static gboolean
+provider_get_secrets (NMSecretsProviderInterface *provider,
+                      NMConnection *connection,
+                      const char *setting_name,
+                      gboolean request_new,
+                      RequestSecretsCaller caller_id,
+                      const char *hint1,
+                      const char *hint2,
+                      gpointer user_data)
+{
+	NMManager *self = NM_MANAGER (user_data);
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	GetSecretsInfo *info = NULL;
+	NMConnectionScope scope;
+	GSList *iter;
+
+	g_return_val_if_fail (connection != NULL, FALSE);
+	g_return_val_if_fail (setting_name != NULL, FALSE);
+
+	/* Tear down any pending secrets requests for this secrets provider */
+	for (iter = priv->secrets_calls; iter; iter = g_slist_next (iter)) {
+		GetSecretsInfo *candidate = iter->data;
+
+		if (provider == candidate->provider) {
+			free_get_secrets_info (candidate);
+			break;
+		}
+	}
+
+	/* Build up the new secrets request */
+	scope = nm_connection_get_scope (connection);
+	if (scope == NM_CONNECTION_SCOPE_SYSTEM) {
+		info = system_get_secrets (self, provider, connection, setting_name,
+		                           request_new, caller_id, hint1, hint2);
+	} else if (scope == NM_CONNECTION_SCOPE_USER) {
+		info = user_get_secrets (self, provider, connection, setting_name,
+		                         request_new, caller_id, hint1, hint2);
+	}
+
+	if (info)
+		priv->secrets_calls = g_slist_append (priv->secrets_calls, info);
+
+	return !!info;
+}
+
 static const char *
 internal_activate_device (NMManager *manager,
                           NMDevice *device,
                           NMConnection *connection,
                           const char *specific_object,
                           gboolean user_requested,
-                          gulong sender_uid,
                           gboolean assumed,
                           GError **error)
 {
@@ -1843,24 +2880,42 @@ internal_activate_device (NMManager *manager,
 		                         NM_DEVICE_STATE_REASON_NONE);
 	}
 
-	req = nm_act_request_new (connection,
-	                          specific_object,
-	                          user_requested,
-	                          sender_uid,
-	                          assumed,
-	                          (gpointer) device);
+	req = nm_act_request_new (connection, specific_object, user_requested, assumed, (gpointer) device);
+	g_signal_connect (req, "manager-get-secrets", G_CALLBACK (provider_get_secrets), manager);
+	g_signal_connect (req, "manager-cancel-secrets", G_CALLBACK (provider_cancel_secrets), manager);
 	success = nm_device_interface_activate (dev_iface, req, error);
 	g_object_unref (req);
 
 	return success ? nm_act_request_get_active_connection_path (req) : NULL;
 }
 
+static gboolean
+wait_for_connection_expired (gpointer data)
+{
+	PendingActivation *pending = data;
+	GError *error = NULL;
+
+	g_return_val_if_fail (pending != NULL, FALSE);
+
+	nm_log_warn (LOGD_CORE, "connection %s (scope %d) failed to activate (timeout)",
+	             pending->connection_path, pending->scope);
+
+	nm_manager_pending_activation_remove (pending->manager, pending);
+
+	error = g_error_new_literal (NM_MANAGER_ERROR,
+	                             NM_MANAGER_ERROR_UNKNOWN_CONNECTION,
+	                             "Connection was not provided by any settings service");
+	pending_activation_destroy (pending, error, NULL);
+	g_error_free (error);
+	return FALSE;
+}
+
 const char *
 nm_manager_activate_connection (NMManager *manager,
                                 NMConnection *connection,
                                 const char *specific_object,
                                 const char *device_path,
-                                const char *dbus_sender,
+                                gboolean user_requested,
                                 GError **error)
 {
 	NMManagerPrivate *priv;
@@ -1868,8 +2923,6 @@ nm_manager_activate_connection (NMManager *manager,
 	NMSettingConnection *s_con;
 	NMVPNConnection *vpn_connection;
 	const char *path = NULL;
-	gulong sender_uid = 0;
-	DBusError dbus_error;
 
 	g_return_val_if_fail (manager != NULL, NULL);
 	g_return_val_if_fail (connection != NULL, NULL);
@@ -1878,34 +2931,17 @@ nm_manager_activate_connection (NMManager *manager,
 
 	priv = NM_MANAGER_GET_PRIVATE (manager);
 
-	/* Get the UID of the user that originated the request, if any */
-	if (dbus_sender) {
-		dbus_error_init (&dbus_error);
-		sender_uid = dbus_bus_get_unix_user (nm_dbus_manager_get_dbus_connection (priv->dbus_mgr),
-		                                     dbus_sender,
-		                                     &dbus_error);
-		if (dbus_error_is_set (&dbus_error)) {
-			g_set_error_literal (error,
-			                     NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED,
-			                     "Failed to get unix user for dbus sender");
-			dbus_error_free (&dbus_error);
-			return NULL;
-		}
-	}
-
 	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
 	g_assert (s_con);
 
 	if (!strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_VPN_SETTING_NAME)) {
-		NMActRequest *parent_req = NULL;
-		NMVPNManager *vpn_manager;
+		NMActRequest *req = NULL;
 
 		/* VPN connection */
-
 		if (specific_object) {
 			/* Find the specifc connection the client requested we use */
-			parent_req = nm_manager_get_act_request_by_path (manager, specific_object, &device);
-			if (!parent_req) {
+			req = nm_manager_get_act_request_by_path (manager, specific_object, &device);
+			if (!req) {
 				g_set_error (error,
 				             NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE,
 				             "%s", "Base connection for VPN connection not active.");
@@ -1922,30 +2958,30 @@ nm_manager_activate_connection (NMManager *manager,
 				candidate_req = nm_device_get_act_request (candidate);
 				if (candidate_req && nm_act_request_get_default (candidate_req)) {
 					device = candidate;
-					parent_req = candidate_req;
+					req = candidate_req;
 					break;
 				}
 			}
 		}
 
-		if (!device || !parent_req) {
+		if (!device || !req) {
 			g_set_error (error,
 			             NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
 			             "%s", "Could not find source connection, or the source connection had no active device.");
 			return NULL;
 		}
 
-		vpn_manager = nm_vpn_manager_get ();
-		vpn_connection = nm_vpn_manager_activate_connection (vpn_manager,
+		vpn_connection = nm_vpn_manager_activate_connection (priv->vpn_manager,
 		                                                     connection,
-		                                                     parent_req,
 		                                                     device,
-		                                                     TRUE,
-		                                                     sender_uid,
 		                                                     error);
-		if (vpn_connection)
+		if (vpn_connection) {
+			g_signal_connect (vpn_connection, "manager-get-secrets",
+			                  G_CALLBACK (provider_get_secrets), manager);
+			g_signal_connect (vpn_connection, "manager-cancel-secrets",
+			                  G_CALLBACK (provider_cancel_secrets), manager);
 			path = nm_vpn_connection_get_active_connection_path (vpn_connection);
-		g_object_unref (vpn_manager);
+		}
 	} else {
 		NMDeviceState state;
 
@@ -1970,8 +3006,7 @@ nm_manager_activate_connection (NMManager *manager,
 		                                 device,
 		                                 connection,
 		                                 specific_object,
-		                                 dbus_sender ? TRUE : FALSE,
-		                                 dbus_sender ? sender_uid : 0,
+		                                 user_requested,
 		                                 FALSE,
 		                                 error);
 	}
@@ -1979,24 +3014,40 @@ nm_manager_activate_connection (NMManager *manager,
 	return path;
 }
 
-/* 
- * TODO this function was created and named in the era of user settings, where
- * we could get activation requests for a connection before we got the settings
- * data of that connection. Now that user settings are gone, flatten or rename
- * it.
- */
-static void
-pending_activate (NMManager *self, PendingActivation *pending)
+static PendingActivation *
+nm_manager_pending_activation_find (NMManager *self,
+                                    const char *path,
+                                    NMConnectionScope scope)
 {
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
-	NMSettingsConnection *connection;
+	GSList *iter;
+
+	for (iter = priv->pending_activations; iter; iter = g_slist_next (iter)) {
+		PendingActivation *pending = iter->data;
+
+		if (!strcmp (pending->connection_path, path) && (pending->scope == scope))
+			return pending;
+	}
+	return NULL;
+}
+
+static void
+check_pending_ready (NMManager *self, PendingActivation *pending)
+{
+	NMConnection *connection;
 	const char *path = NULL;
 	GError *error = NULL;
-	char *sender;
 
-	/* Ok, we're authorized */
+	if (!pending->have_connection || !pending->authorized)
+		return;
+
+	/* Ok, we're authorized and the connection is available */
 
-	connection = nm_settings_get_connection_by_path (priv->settings, pending->connection_path);
+	nm_manager_pending_activation_remove (self, pending);
+
+	connection = nm_manager_get_connection_by_object_path (self,
+	                                                       pending->scope,
+	                                                       pending->connection_path);
 	if (!connection) {
 		error = g_error_new_literal (NM_MANAGER_ERROR,
 		                             NM_MANAGER_ERROR_UNKNOWN_CONNECTION,
@@ -2004,19 +3055,15 @@ pending_activate (NMManager *self, PendingActivation *pending)
 		goto out;
 	}
 
-	sender = dbus_g_method_get_sender (pending->context);
-	g_assert (sender);
 	path = nm_manager_activate_connection (self,
-	                                       NM_CONNECTION (connection),
+	                                       connection,
 	                                       pending->specific_object_path,
 	                                       pending->device_path,
-	                                       sender,
+	                                       TRUE,
 	                                       &error);
-	g_free (sender);
-
 	if (!path) {
-		nm_log_warn (LOGD_CORE, "connection %s failed to activate: (%d) %s",
-		             pending->connection_path, error->code, error->message);
+		nm_log_warn (LOGD_CORE, "connection (%d) %s failed to activate: (%d) %s",
+		             pending->scope, pending->connection_path, error->code, error->message);
 	} else
 		g_object_notify (G_OBJECT (pending->manager), NM_MANAGER_ACTIVE_CONNECTIONS);
 
@@ -2026,93 +3073,68 @@ out:
 }
 
 static void
+connection_added_default_handler (NMManager *self,
+                                  NMConnection *connection,
+                                  NMConnectionScope scope)
+{
+	PendingActivation *pending;
+
+	pending = nm_manager_pending_activation_find (self,
+	                                              nm_connection_get_path (connection),
+	                                              scope);
+	if (pending) {
+		pending->have_connection = TRUE;
+		check_pending_ready (self, pending);
+	}
+}
+
+static void
 activation_auth_done (PendingActivation *pending, GError *error)
 {
-	if (error)
+	if (error) {
+		nm_manager_pending_activation_remove (pending->manager, pending);
 		pending_activation_destroy (pending, error, NULL);
-	else
-		pending_activate (pending->manager, pending);
+		return;
+	} else {
+		pending->authorized = TRUE;
+
+		/* Now that we're authorized, if the connection hasn't shown up yet,
+		 * start a timer and wait for it.
+		 */
+		if (!pending->have_connection && !pending->timeout_id)
+			pending->timeout_id = g_timeout_add_seconds (5, wait_for_connection_expired, pending);
+
+		check_pending_ready (pending->manager, pending);
+	}
 }
 
 static void
 impl_manager_activate_connection (NMManager *self,
+                                  const char *service_name,
                                   const char *connection_path,
                                   const char *device_path,
                                   const char *specific_object_path,
                                   DBusGMethodInvocation *context)
 {
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	NMConnectionScope scope = NM_CONNECTION_SCOPE_UNKNOWN;
 	PendingActivation *pending;
 	GError *error = NULL;
 
-	/* Need to check the caller's permissions and stuff before we can
-	 * activate the connection.
-	 */
-	pending = pending_activation_new (self,
-	                                  priv->authority,
-	                                  context,
-	                                  device_path,
-	                                  connection_path,
-	                                  NULL,
-	                                  specific_object_path,
-	                                  activation_auth_done,
-	                                  &error);
-	if (pending)
-		pending_activation_check_authorized (pending, priv->dbus_mgr);
+	if (!strcmp (service_name, NM_DBUS_SERVICE_USER_SETTINGS))
+		scope = NM_CONNECTION_SCOPE_USER;
+	else if (!strcmp (service_name, NM_DBUS_SERVICE_SYSTEM_SETTINGS))
+		scope = NM_CONNECTION_SCOPE_SYSTEM;
 	else {
-		g_assert (error);
+		error = g_error_new_literal (NM_MANAGER_ERROR,
+		                             NM_MANAGER_ERROR_INVALID_SERVICE,
+		                             "Invalid settings service name");
 		dbus_g_method_return_error (context, error);
+		nm_log_warn (LOGD_CORE, "connection (%d) %s failed to activate: (%d) %s",
+		             scope, connection_path, error->code, error->message);
 		g_error_free (error);
+		return;
 	}
-}
-
-static void
-activation_add_done (NMSettings *self,
-                     NMSettingsConnection *connection,
-                     GError *error,
-                     DBusGMethodInvocation *context,
-                     gpointer user_data)
-{
-	PendingActivation *pending = user_data;
-
-	if (error)
-		pending_activation_destroy (pending, error, NULL);
-	else {
-		/* Save the new connection's D-Bus path */
-		pending->connection_path = g_strdup (nm_connection_get_path (NM_CONNECTION (connection)));
-
-		/* And activate it */
-		pending_activate (pending->manager, pending);
-	}
-}
-
-static void
-add_and_activate_auth_done (PendingActivation *pending, GError *error)
-{
-	if (error)
-		pending_activation_destroy (pending, error, NULL);
-	else {
-		NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (pending->manager);
-
-		/* Basic sender auth checks performed; try to add the connection */
-		nm_settings_add_connection (priv->settings,
-                                    pending->connection,
-                                    pending->context,
-                                    activation_add_done,
-                                    pending);
-	}
-}
-
-static void
-impl_manager_add_and_activate_connection (NMManager *self,
-                                          GHashTable *settings,
-                                          const char *device_path,
-                                          const char *specific_object_path,
-                                          DBusGMethodInvocation *context)
-{
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
-	PendingActivation *pending;
-	GError *error = NULL;
 
 	/* Need to check the caller's permissions and stuff before we can
 	 * activate the connection.
@@ -2121,18 +3143,16 @@ impl_manager_add_and_activate_connection (NMManager *self,
 	                                  priv->authority,
 	                                  context,
 	                                  device_path,
-	                                  NULL,
-	                                  settings,
+	                                  scope,
+	                                  connection_path,
 	                                  specific_object_path,
-	                                  add_and_activate_auth_done,
-	                                  &error);
-	if (pending)
-		pending_activation_check_authorized (pending, priv->dbus_mgr);
-	else {
-		g_assert (error);
-		dbus_g_method_return_error (context, error);
-		g_error_free (error);
-	}
+	                                  activation_auth_done);
+	priv->pending_activations = g_slist_prepend (priv->pending_activations, pending);
+
+	if (nm_manager_get_connection_by_object_path (self, scope, connection_path))
+		pending->have_connection = TRUE;
+
+	pending_activation_check_authorized (pending, priv->dbus_mgr, priv->user_proxy);
 }
 
 gboolean
@@ -2142,7 +3162,6 @@ nm_manager_deactivate_connection (NMManager *manager,
                                   GError **error)
 {
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
-	NMVPNManager *vpn_manager;
 	GSList *iter;
 	gboolean success = FALSE;
 	NMVPNConnectionStateReason vpn_reason = NM_VPN_CONNECTION_STATE_REASON_USER_DISCONNECTED;
@@ -2166,17 +3185,15 @@ nm_manager_deactivate_connection (NMManager *manager,
 	}
 
 	/* Check for VPN connections next */
-	vpn_manager = nm_vpn_manager_get ();
 	if (reason == NM_DEVICE_STATE_REASON_CONNECTION_REMOVED)
 		vpn_reason = NM_VPN_CONNECTION_STATE_REASON_CONNECTION_REMOVED;
-	if (nm_vpn_manager_deactivate_connection (vpn_manager, connection_path, vpn_reason)) {
+	if (nm_vpn_manager_deactivate_connection (priv->vpn_manager, connection_path, vpn_reason)) {
 		success = TRUE;
 	} else {
 		g_set_error (error,
 		             NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE,
 		             "%s", "The connection was not active.");
 	}
-	g_object_unref (vpn_manager);
 
 done:
 	g_object_notify (G_OBJECT (manager), NM_MANAGER_ACTIVE_CONNECTIONS);
@@ -2184,6 +3201,37 @@ done:
 }
 
 static void
+deactivate_user_auth_done_cb (NMAuthChain *chain,
+                              GError *error,
+                              DBusGMethodInvocation *context,
+                              gpointer user_data)
+{
+	NMManager *self = NM_MANAGER (user_data);
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	GError *ret_error = NULL;
+	NMAuthCallResult result;
+
+	priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
+
+	result = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, NM_AUTH_PERMISSION_USE_USER_CONNECTIONS));
+	ret_error = deactivate_disconnect_check_error (error, result, "Deactivate");
+	if (!ret_error) {
+		/* Everything authorized, deactivate the connection */
+		if (nm_manager_deactivate_connection (self,
+		                                      nm_auth_chain_get_data (chain, "path"),
+		                                      NM_DEVICE_STATE_REASON_USER_REQUESTED,
+		                                      &ret_error))
+			dbus_g_method_return (context);
+	}
+
+	if (ret_error)
+		dbus_g_method_return_error (context, ret_error);
+	g_clear_error (&ret_error);
+
+	nm_auth_chain_unref (chain);
+}
+
+static void
 deactivate_net_auth_done_cb (NMAuthChain *chain,
                              GError *error,
                              DBusGMethodInvocation *context,
@@ -2194,6 +3242,7 @@ deactivate_net_auth_done_cb (NMAuthChain *chain,
 	GError *ret_error = NULL;
 	NMAuthCallResult result;
 	const char *active_path;
+	NMConnectionScope scope;
 
 	priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
 
@@ -2205,15 +3254,32 @@ deactivate_net_auth_done_cb (NMAuthChain *chain,
 		goto done;
 	}
 
+	/* If it's a system connection, we're done */
 	active_path = nm_auth_chain_get_data (chain, "path");
-	if (!nm_manager_deactivate_connection (self,
-	                                       active_path,
-	                                       NM_DEVICE_STATE_REASON_USER_REQUESTED,
-	                                       &ret_error)) {
-		dbus_g_method_return_error (context, ret_error);
-		g_clear_error (&ret_error);
-	} else
-		dbus_g_method_return (context);
+	scope = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, "scope"));
+	if (scope == NM_CONNECTION_SCOPE_USER) {
+		NMAuthChain *user_chain;
+
+		/* It's a user connection, so we need to ensure the caller is
+		 * authorized to manipulate user connections.
+		 */
+		user_chain = nm_auth_chain_new (priv->authority, context, NULL, deactivate_user_auth_done_cb, self);
+		g_assert (user_chain);
+		priv->auth_chains = g_slist_append (priv->auth_chains, user_chain);
+
+		nm_auth_chain_set_data (user_chain, "path", g_strdup (active_path), g_free);
+		nm_auth_chain_set_data (user_chain, "scope", GUINT_TO_POINTER (scope), NULL);
+		nm_auth_chain_add_call (user_chain, NM_AUTH_PERMISSION_USE_USER_CONNECTIONS, TRUE);
+	} else {
+		if (!nm_manager_deactivate_connection (self,
+		                                       active_path,
+		                                       NM_DEVICE_STATE_REASON_USER_REQUESTED,
+		                                       &ret_error)) {
+			dbus_g_method_return_error (context, ret_error);
+			g_clear_error (&ret_error);
+		} else
+			dbus_g_method_return (context);
+	}
 
 done:
 	nm_auth_chain_unref (chain);
@@ -2230,7 +3296,8 @@ impl_manager_deactivate_connection (NMManager *self,
 	GSList *iter;
 	NMAuthChain *chain;
 	gulong sender_uid = G_MAXULONG;
-	char *error_desc = NULL;
+	NMConnectionScope scope;
+	const char *error_desc = NULL;
 
 	/* Check for device connections first */
 	for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
@@ -2263,16 +3330,18 @@ impl_manager_deactivate_connection (NMManager *self,
 	/* Need to check the caller's permissions and stuff before we can
 	 * deactivate the connection.
 	 */
-	if (!nm_auth_get_caller_uid (context, 
-		                         priv->dbus_mgr,
-	                             &sender_uid,
-	                             &error_desc)) {
+	scope = nm_connection_get_scope (connection);
+	if (!check_user_authorized (priv->dbus_mgr,
+	                            priv->user_proxy,
+	                            context,
+	                            scope,
+	                            &sender_uid,
+	                            &error_desc)) {
 		error = g_error_new_literal (NM_MANAGER_ERROR,
 		                             NM_MANAGER_ERROR_PERMISSION_DENIED,
 		                             error_desc);
 		dbus_g_method_return_error (context, error);
 		g_error_free (error);
-		g_free (error_desc);
 		return;
 	}
 
@@ -2296,6 +3365,7 @@ impl_manager_deactivate_connection (NMManager *self,
 	priv->auth_chains = g_slist_append (priv->auth_chains, chain);
 
 	nm_auth_chain_set_data (chain, "path", g_strdup (active_path), g_free);
+	nm_auth_chain_set_data (chain, "scope", GUINT_TO_POINTER (scope), NULL);
 	nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE);
 }
 
@@ -2319,7 +3389,7 @@ do_sleep_wake (NMManager *self)
 	} else {
 		nm_log_info (LOGD_SUSPEND, "waking up and re-enabling...");
 
-		unmanaged_specs = nm_settings_get_unmanaged_specs (priv->settings);
+		unmanaged_specs = nm_sysconfig_settings_get_unmanaged_specs (priv->sys_settings);
 
 		/* Ensure rfkill state is up-to-date since we don't respond to state
 		 * changes during sleep.
@@ -2336,7 +3406,7 @@ do_sleep_wake (NMManager *self)
 			 */
 			for (i = 0; i < RFKILL_TYPE_MAX; i++) {
 				RadioState *rstate = &priv->radio_states[i];
-				gboolean enabled = radio_enabled_for_rstate (rstate);
+				gboolean enabled = radio_enabled_for_rstate (rstate, TRUE);
 				RfKillType devtype = RFKILL_TYPE_UNKNOWN;
 
 				if (rstate->desc) {
@@ -2605,7 +3675,7 @@ impl_manager_enable (NMManager *self,
 	NMAuthChain *chain;
 	GError *error = NULL;
 	gulong sender_uid = G_MAXULONG;
-	char *error_desc = NULL;
+	const char *error_desc = NULL;
 
 	g_return_if_fail (NM_IS_MANAGER (self));
 
@@ -2626,7 +3696,6 @@ impl_manager_enable (NMManager *self,
 		                             error_desc);
 		dbus_g_method_return_error (context, error);
 		g_error_free (error);
-		g_free (error_desc);
 		return;
 	}
 
@@ -2651,8 +3720,60 @@ impl_manager_enable (NMManager *self,
 /* Permissions */
 
 static void
+user_proxy_permissions_changed_done (NMAuthChain *chain,
+                                     GError *error,
+                                     DBusGMethodInvocation *context,
+                                     gpointer user_data)
+{
+	NMManager *self = NM_MANAGER (user_data);
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	gboolean authorized = FALSE;
+
+	priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
+
+	if (error) {
+		nm_log_warn (LOGD_USER_SET, "User connections unavailable: (%d) %s",
+		             error->code, error->message ? error->message : "(unknown)");
+	} else
+		authorized = user_settings_authorized (self, chain);
+
+	if (authorized) {
+		/* User connections are authorized */
+		if (!priv->user_proxy)
+			user_proxy_init (self);
+	} else
+		user_proxy_cleanup (self, TRUE);
+
+	nm_auth_chain_unref (chain);
+}
+
+static void
 pk_authority_changed_cb (GObject *object, gpointer user_data)
 {
+	NMManager *self = NM_MANAGER (user_data);
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+	NMAuthChain *chain;
+
+	/* If the user settings service wasn't previously authorized, we wouldn't
+	 * care about it.  But it might be authorized now, so lets check.
+	 */
+	if (!priv->user_proxy)
+		user_proxy_init (self);
+	else {
+		/* Otherwise the user settings permissions could have changed so we
+		 * need to recheck them.
+		 */
+		chain = nm_auth_chain_new (priv->authority,
+		                           NULL,
+		                           priv->user_proxy,
+		                           user_proxy_permissions_changed_done,
+		                           self);
+		priv->auth_chains = g_slist_prepend (priv->auth_chains, chain);
+
+		nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_USE_USER_CONNECTIONS, FALSE);
+		nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, FALSE);
+	}
+
 	/* Let clients know they should re-check their authorization */
 	g_signal_emit (NM_MANAGER (user_data), signals[CHECK_PERMISSIONS], 0);
 }
@@ -2700,13 +3821,8 @@ get_permissions_done_cb (NMAuthChain *chain,
 		get_perm_add_result (chain, results, NM_AUTH_PERMISSION_SLEEP_WAKE);
 		get_perm_add_result (chain, results, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI);
 		get_perm_add_result (chain, results, NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN);
-		get_perm_add_result (chain, results, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX);
+		get_perm_add_result (chain, results, NM_AUTH_PERMISSION_USE_USER_CONNECTIONS);
 		get_perm_add_result (chain, results, NM_AUTH_PERMISSION_NETWORK_CONTROL);
-		get_perm_add_result (chain, results, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED);
-		get_perm_add_result (chain, results, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN);
-		get_perm_add_result (chain, results, NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM);
-		get_perm_add_result (chain, results, NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN);
-		get_perm_add_result (chain, results, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME);
 		dbus_g_method_return (context, results);
 		g_hash_table_destroy (results);
 	}
@@ -2732,20 +3848,31 @@ impl_manager_get_permissions (NMManager *self,
 	nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SLEEP_WAKE, FALSE);
 	nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI, FALSE);
 	nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN, FALSE);
-	nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX, FALSE);
+	nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_USE_USER_CONNECTIONS, FALSE);
 	nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, FALSE);
-	nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED, FALSE);
-	nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, FALSE);
-	nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM, FALSE);
-	nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN, FALSE);
-	nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME, FALSE);
+}
+
+/* Legacy 0.6 compatibility interface */
+
+static void
+impl_manager_legacy_sleep (NMManager *manager, DBusGMethodInvocation *context)
+{
+	return impl_manager_sleep (manager, TRUE, context);
+}
+
+static void
+impl_manager_legacy_wake  (NMManager *manager, DBusGMethodInvocation *context)
+{
+	return impl_manager_sleep (manager, FALSE, context);
 }
 
 static gboolean
-impl_manager_get_state (NMManager *manager, guint32 *state, GError **error)
+impl_manager_legacy_state (NMManager *manager, guint32 *state, GError **err)
 {
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+
 	nm_manager_update_state (manager);
-	*state = NM_MANAGER_GET_PRIVATE (manager)->state;
+	*state = priv->state;
 	return TRUE;
 }
 
@@ -2767,6 +3894,115 @@ impl_manager_set_logging (NMManager *manager,
 	return FALSE;
 }
 
+/* Connections */
+
+gboolean
+nm_manager_auto_user_connections_allowed (NMManager *self)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+
+	return    priv->user_net_perm == NM_AUTH_CALL_RESULT_YES
+	       && priv->user_con_perm == NM_AUTH_CALL_RESULT_YES;
+}
+
+static guint64
+get_connection_timestamp (NMConnection *connection)
+{
+	if (nm_connection_get_scope (connection) == NM_CONNECTION_SCOPE_SYSTEM) {
+		guint64 *ts_p;
+
+		ts_p = (guint64 *) g_object_get_data (G_OBJECT (connection), NM_SYSCONFIG_SETTINGS_TIMESTAMP_TAG);
+		return ts_p != NULL ? *ts_p : 0;
+	} else {
+		NMSettingConnection *s_con;
+
+		s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
+		g_assert (s_con);
+		return nm_setting_connection_get_timestamp (s_con);
+	}
+}
+
+static int
+connection_sort (gconstpointer pa, gconstpointer pb)
+{
+	NMConnection *a = NM_CONNECTION (pa);
+	NMSettingConnection *con_a;
+	NMConnection *b = NM_CONNECTION (pb);
+	NMSettingConnection *con_b;
+	guint64 ts_a, ts_b;
+
+	con_a = (NMSettingConnection *) nm_connection_get_setting (a, NM_TYPE_SETTING_CONNECTION);
+	g_assert (con_a);
+	con_b = (NMSettingConnection *) nm_connection_get_setting (b, NM_TYPE_SETTING_CONNECTION);
+	g_assert (con_b);
+
+	if (nm_setting_connection_get_autoconnect (con_a) != nm_setting_connection_get_autoconnect (con_b)) {
+		if (nm_setting_connection_get_autoconnect (con_a))
+			return -1;
+		return 1;
+	}
+
+	ts_a = get_connection_timestamp (a);
+	ts_b = get_connection_timestamp (b);
+	if (ts_a > ts_b)
+		return -1;
+	else if (ts_a == ts_b)
+		return 0;
+
+	return 1;
+}
+
+static void
+connections_to_slist (gpointer key, gpointer value, gpointer user_data)
+{
+	GSList **list = (GSList **) user_data;
+
+	*list = g_slist_insert_sorted (*list, g_object_ref (value), connection_sort);
+}
+
+/* Returns a GSList of referenced NMConnection objects, caller must
+ * unref the connections in the list and destroy the list.
+ */
+GSList *
+nm_manager_get_connections (NMManager *manager,
+                            NMConnectionScope scope)
+{
+	NMManagerPrivate *priv;
+	GSList *list = NULL;
+
+	g_return_val_if_fail (NM_IS_MANAGER (manager), NULL);
+
+	priv = NM_MANAGER_GET_PRIVATE (manager);
+	if (scope == NM_CONNECTION_SCOPE_USER)
+		g_hash_table_foreach (priv->user_connections, connections_to_slist, &list);
+	else if (scope == NM_CONNECTION_SCOPE_SYSTEM)
+		g_hash_table_foreach (priv->system_connections, connections_to_slist, &list);
+	else
+		nm_log_err (LOGD_CORE, "unknown NMConnectionScope %d", scope);
+	return list;
+}
+
+NMConnection *
+nm_manager_get_connection_by_object_path (NMManager *manager,
+                                          NMConnectionScope scope,
+                                          const char *path)
+{
+	NMManagerPrivate *priv;
+	NMConnection *connection = NULL;
+
+	g_return_val_if_fail (NM_IS_MANAGER (manager), NULL);
+	g_return_val_if_fail (path != NULL, NULL);
+
+	priv = NM_MANAGER_GET_PRIVATE (manager);
+	if (scope == NM_CONNECTION_SCOPE_USER)
+		connection = (NMConnection *) g_hash_table_lookup (priv->user_connections, path);
+	else if (scope == NM_CONNECTION_SCOPE_SYSTEM)
+		connection = (NMConnection *) g_hash_table_lookup (priv->system_connections, path);
+	else
+		nm_log_err (LOGD_CORE, "unknown NMConnectionScope %d", scope);
+	return connection;
+}
+
 GPtrArray *
 nm_manager_get_active_connections_by_connection (NMManager *manager,
                                                  NMConnection *connection)
@@ -2784,6 +4020,7 @@ nm_manager_start (NMManager *self)
 	for (i = 0; i < RFKILL_TYPE_MAX; i++) {
 		RadioState *rstate = &priv->radio_states[i];
 		RfKillState udev_state;
+		gboolean enabled;
 
 		if (!rstate->desc)
 			continue;
@@ -2797,15 +4034,23 @@ nm_manager_start (NMManager *self)
 				         (rstate->hw_enabled && rstate->sw_enabled) ? "enabled" : "disabled",
 				         rstate->user_enabled ? "enabled" : "disabled");
 		}
-		manager_update_radio_enabled (self, rstate);
+		enabled = radio_enabled_for_rstate (rstate, TRUE);
+		manager_update_radio_enabled (self, rstate, enabled);
 	}
 
 	/* Log overall networking status - enabled/disabled */
 	nm_log_info (LOGD_CORE, "Networking is %s by state file",
 	             priv->net_enabled ? "enabled" : "disabled");
 
-	system_unmanaged_devices_changed_cb (priv->settings, NULL, self);
-	system_hostname_changed_cb (priv->settings, NULL, self);
+	system_unmanaged_devices_changed_cb (priv->sys_settings, NULL, self);
+	system_hostname_changed_cb (priv->sys_settings, NULL, self);
+	system_query_connections (self);
+
+	/* Get user connections if the user settings service is around, otherwise
+	 * they will be queried when the user settings service shows up on the
+	 * bus in nm_manager_name_owner_changed().
+	 */
+	user_proxy_init (self);
 
 	nm_udev_manager_query_devices (priv->udev_mgr);
 	bluez_manager_resync_devices (self);
@@ -2974,9 +4219,6 @@ prop_filter (DBusConnection *connection,
 	} else if (!strcmp (propname, "WwanEnabled")) {
 		glib_propname = NM_MANAGER_WWAN_ENABLED;
 		permission = NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN;
-	} else if (!strcmp (propname, "WimaxEnabled")) {
-		glib_propname = NM_MANAGER_WIMAX_ENABLED;
-		permission = NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX;
 	} else
 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
@@ -3029,14 +4271,12 @@ out:
 }
 
 NMManager *
-nm_manager_get (NMSettings *settings,
-                const char *config_file,
+nm_manager_get (const char *config_file,
                 const char *plugins,
                 const char *state_file,
                 gboolean initial_net_enabled,
                 gboolean initial_wifi_enabled,
                 gboolean initial_wwan_enabled,
-                gboolean initial_wimax_enabled,
                 GError **error)
 {
 	static NMManager *singleton = NULL;
@@ -3047,8 +4287,6 @@ nm_manager_get (NMSettings *settings,
 	if (singleton)
 		return g_object_ref (singleton);
 
-	g_assert (settings);
-
 	singleton = (NMManager *) g_object_new (NM_TYPE_MANAGER, NULL);
 	g_assert (singleton);
 
@@ -3065,31 +4303,37 @@ nm_manager_get (NMSettings *settings,
 		return NULL;
     }
 
-	priv->settings = g_object_ref (settings);
+	priv->sys_settings = nm_sysconfig_settings_new (config_file, plugins, bus, error);
+	if (!priv->sys_settings) {
+		g_object_unref (singleton);
+		return NULL;
+	}
+	nm_settings_service_export (NM_SETTINGS_SERVICE (priv->sys_settings));
 
 	priv->config_file = g_strdup (config_file);
+
 	priv->state_file = g_strdup (state_file);
 
 	priv->net_enabled = initial_net_enabled;
 
 	priv->radio_states[RFKILL_TYPE_WLAN].user_enabled = initial_wifi_enabled;
 	priv->radio_states[RFKILL_TYPE_WWAN].user_enabled = initial_wwan_enabled;
-	priv->radio_states[RFKILL_TYPE_WIMAX].user_enabled = initial_wimax_enabled;
 
-	g_signal_connect (priv->settings, "notify::" NM_SETTINGS_UNMANAGED_SPECS,
+	g_signal_connect (priv->sys_settings, "notify::" NM_SYSCONFIG_SETTINGS_UNMANAGED_SPECS,
 	                  G_CALLBACK (system_unmanaged_devices_changed_cb), singleton);
-	g_signal_connect (priv->settings, "notify::" NM_SETTINGS_HOSTNAME,
+	g_signal_connect (priv->sys_settings, "notify::" NM_SETTINGS_SYSTEM_INTERFACE_HOSTNAME,
 	                  G_CALLBACK (system_hostname_changed_cb), singleton);
-	g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_ADDED,
-	                  G_CALLBACK (connections_changed), singleton);
-	g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_UPDATED,
-	                  G_CALLBACK (connections_changed), singleton);
-	g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_REMOVED,
-	                  G_CALLBACK (connections_changed), singleton);
-	g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_VISIBILITY_CHANGED,
-	                  G_CALLBACK (connections_changed), singleton);
+	g_signal_connect (priv->sys_settings, "new-connection",
+	                  G_CALLBACK (system_new_connection_cb), singleton);
 
-	dbus_g_connection_register_g_object (bus, NM_DBUS_PATH, G_OBJECT (singleton));
+	dbus_g_connection_register_g_object (nm_dbus_manager_get_connection (priv->dbus_mgr),
+	                                     NM_DBUS_PATH,
+	                                     G_OBJECT (singleton));
+
+	g_signal_connect (priv->dbus_mgr,
+	                  "name-owner-changed",
+	                  G_CALLBACK (nm_manager_name_owner_changed),
+	                  singleton);
 
 	priv->udev_mgr = nm_udev_manager_new ();
 	g_signal_connect (priv->udev_mgr,
@@ -3125,6 +4369,7 @@ dispose (GObject *object)
 {
 	NMManager *manager = NM_MANAGER (object);
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+	GSList *iter, *list;
 	DBusGConnection *bus;
 	DBusConnection *dbus_connection;
 
@@ -3134,10 +4379,18 @@ dispose (GObject *object)
 	}
 	priv->disposed = TRUE;
 
+	for (iter = priv->pending_activations; iter; iter = g_slist_next (iter))
+		pending_activation_destroy ((PendingActivation *) iter->data, NULL, NULL);
+	g_slist_free (priv->pending_activations);
+	priv->pending_activations = NULL;
+
 	g_slist_foreach (priv->auth_chains, (GFunc) nm_auth_chain_unref, NULL);
 	g_slist_free (priv->auth_chains);
 	g_object_unref (priv->authority);
 
+	while (g_slist_length (priv->secrets_calls))
+		free_get_secrets_info ((GetSecretsInfo *) priv->secrets_calls->data);
+
 	while (g_slist_length (priv->devices)) {
 		priv->devices = remove_one_device (manager,
 		                                   priv->devices,
@@ -3145,11 +4398,37 @@ dispose (GObject *object)
 		                                   TRUE);
 	}
 
+	user_proxy_cleanup (manager, FALSE);
+	g_hash_table_destroy (priv->user_connections);
+	priv->user_connections = NULL;
+
+	g_hash_table_foreach (priv->system_connections, emit_removed, manager);
+	g_hash_table_remove_all (priv->system_connections);
+	g_hash_table_destroy (priv->system_connections);
+	priv->system_connections = NULL;
+
 	g_free (priv->hostname);
 	g_free (priv->config_file);
 
-	g_object_unref (priv->settings);
+	if (priv->sys_settings) {
+		g_object_unref (priv->sys_settings);
+		priv->sys_settings = NULL;
+	}
 
+	/* Make sure we disconnect signal handlers from VPN connections that
+	 * might still be alive when the manager dies.
+	 */
+	list = nm_vpn_manager_get_active_connections (priv->vpn_manager);
+	for (iter = list; iter; iter = g_slist_next (iter)) {
+		g_signal_handlers_disconnect_by_func (G_OBJECT (iter->data),
+						      G_CALLBACK (provider_get_secrets),
+						      manager);
+		g_signal_handlers_disconnect_by_func (G_OBJECT (iter->data),
+						      G_CALLBACK (provider_cancel_secrets),
+						      manager);
+		/* unref to balance returned objects from the VPN manager */
+		g_object_unref (iter->data);
+	}
 	if (priv->vpn_manager_id) {
 		g_source_remove (priv->vpn_manager_id);
 		priv->vpn_manager_id = 0;
@@ -3232,11 +4511,20 @@ manager_radio_user_toggled (NMManager *self,
 		}
 	}
 
-	old_enabled = radio_enabled_for_rstate (rstate);
+	/* When the user toggles the radio, their request should override any
+	 * daemon (like ModemManager) enabled state that can be changed.  For WWAN
+	 * for example, we want the WwanEnabled property to reflect the daemon state
+	 * too so that users can toggle the modem powered, but we don't want that
+	 * daemon state to affect whether or not the user *can* turn it on, which is
+	 * what the kernel rfkill state does.  So we ignore daemon enabled state
+	 * when determining what the new state should be since it shouldn't block
+	 * the user's request.
+	 */
+	old_enabled = radio_enabled_for_rstate (rstate, TRUE);
 	rstate->user_enabled = enabled;
-	new_enabled = radio_enabled_for_rstate (rstate);
+	new_enabled = radio_enabled_for_rstate (rstate, FALSE);
 	if (new_enabled != old_enabled)
-		manager_update_radio_enabled (self, rstate);
+		manager_update_radio_enabled (self, rstate, new_enabled);
 }
 
 static void
@@ -3261,11 +4549,6 @@ set_property (GObject *object, guint prop_id,
 		                            &priv->radio_states[RFKILL_TYPE_WWAN],
 		                            g_value_get_boolean (value));
 		break;
-	case PROP_WIMAX_ENABLED:
-		manager_radio_user_toggled (NM_MANAGER (object),
-		                            &priv->radio_states[RFKILL_TYPE_WIMAX],
-		                            g_value_get_boolean (value));
-		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -3291,23 +4574,17 @@ get_property (GObject *object, guint prop_id,
 		g_value_set_boolean (value, priv->net_enabled);
 		break;
 	case PROP_WIRELESS_ENABLED:
-		g_value_set_boolean (value, radio_enabled_for_type (self, RFKILL_TYPE_WLAN));
+		g_value_set_boolean (value, radio_enabled_for_type (self, RFKILL_TYPE_WLAN, TRUE));
 		break;
 	case PROP_WIRELESS_HARDWARE_ENABLED:
 		g_value_set_boolean (value, priv->radio_states[RFKILL_TYPE_WLAN].hw_enabled);
 		break;
 	case PROP_WWAN_ENABLED:
-		g_value_set_boolean (value, radio_enabled_for_type (self, RFKILL_TYPE_WWAN));
+		g_value_set_boolean (value, radio_enabled_for_type (self, RFKILL_TYPE_WWAN, TRUE));
 		break;
 	case PROP_WWAN_HARDWARE_ENABLED:
 		g_value_set_boolean (value, priv->radio_states[RFKILL_TYPE_WWAN].hw_enabled);
 		break;
-	case PROP_WIMAX_ENABLED:
-		g_value_set_boolean (value, radio_enabled_for_type (self, RFKILL_TYPE_WIMAX));
-		break;
-	case PROP_WIMAX_HARDWARE_ENABLED:
-		g_value_set_boolean (value, priv->radio_states[RFKILL_TYPE_WIMAX].hw_enabled);
-		break;
 	case PROP_ACTIVE_CONNECTIONS:
 		g_value_take_boxed (value, get_active_connections (self, NULL));
 		break;
@@ -3339,8 +4616,7 @@ periodic_update_active_connection_timestamps (gpointer user_data)
 
 		req = nm_manager_get_act_request_by_path (manager, active_path, &device);
 		if (device && nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED)
-			nm_settings_connection_update_timestamp (NM_SETTINGS_CONNECTION (nm_act_request_get_connection (req)),
-			                                         (guint64) time (NULL));
+			update_active_connection_timestamp (manager, device);
 	}
 
 	return TRUE;
@@ -3371,13 +4647,13 @@ nm_manager_init (NMManager *manager)
 	priv->radio_states[RFKILL_TYPE_WWAN].prop = NM_MANAGER_WWAN_ENABLED;
 	priv->radio_states[RFKILL_TYPE_WWAN].hw_prop = NM_MANAGER_WWAN_HARDWARE_ENABLED;
 	priv->radio_states[RFKILL_TYPE_WWAN].desc = "WWAN";
-	priv->radio_states[RFKILL_TYPE_WWAN].other_enabled_func = nm_manager_get_modem_enabled_state;
+	priv->radio_states[RFKILL_TYPE_WWAN].daemon_enabled_func = nm_manager_get_modem_enabled_state;
 	priv->radio_states[RFKILL_TYPE_WWAN].rtype = RFKILL_TYPE_WWAN;
 
 	priv->radio_states[RFKILL_TYPE_WIMAX].user_enabled = TRUE;
 	priv->radio_states[RFKILL_TYPE_WIMAX].key = "WiMAXEnabled";
-	priv->radio_states[RFKILL_TYPE_WIMAX].prop = NM_MANAGER_WIMAX_ENABLED;
-	priv->radio_states[RFKILL_TYPE_WIMAX].hw_prop = NM_MANAGER_WIMAX_HARDWARE_ENABLED;
+	priv->radio_states[RFKILL_TYPE_WIMAX].prop = NULL;
+	priv->radio_states[RFKILL_TYPE_WIMAX].hw_prop = NULL;
 	priv->radio_states[RFKILL_TYPE_WIMAX].desc = "WiMAX";
 	priv->radio_states[RFKILL_TYPE_WIMAX].other_enabled_func = NULL;
 	priv->radio_states[RFKILL_TYPE_WIMAX].rtype = RFKILL_TYPE_WIMAX;
@@ -3390,6 +4666,16 @@ nm_manager_init (NMManager *manager)
 
 	priv->dbus_mgr = nm_dbus_manager_get ();
 
+	priv->user_connections = g_hash_table_new_full (g_str_hash,
+	                                                g_str_equal,
+	                                                g_free,
+	                                                g_object_unref);
+
+	priv->system_connections = g_hash_table_new_full (g_str_hash,
+	                                                  g_str_equal,
+	                                                  g_free,
+	                                                  g_object_unref);
+
 	priv->modem_manager = nm_modem_manager_get ();
 	priv->modem_added_id = g_signal_connect (priv->modem_manager, "modem-added",
 	                                         G_CALLBACK (modem_added), manager);
@@ -3487,6 +4773,8 @@ nm_manager_class_init (NMManagerClass *manager_class)
 	g_type_class_add_private (manager_class, sizeof (NMManagerPrivate));
 
 	/* virtual methods */
+	manager_class->connection_added = connection_added_default_handler;
+
 	object_class->set_property = set_property;
 	object_class->get_property = get_property;
 	object_class->dispose = dispose;
@@ -3549,22 +4837,6 @@ nm_manager_class_init (NMManagerClass *manager_class)
 		                       G_PARAM_READABLE));
 
 	g_object_class_install_property
-		(object_class, PROP_WIMAX_ENABLED,
-		 g_param_spec_boolean (NM_MANAGER_WIMAX_ENABLED,
-		                       "WimaxEnabled",
-		                       "Is WiMAX enabled",
-		                       TRUE,
-		                       G_PARAM_READWRITE));
-
-	g_object_class_install_property
-		(object_class, PROP_WIMAX_HARDWARE_ENABLED,
-		 g_param_spec_boolean (NM_MANAGER_WIMAX_HARDWARE_ENABLED,
-		                       "WimaxHardwareEnabled",
-		                       "Whether WiMAX is disabled by a hardware switch or not",
-		                       TRUE,
-		                       G_PARAM_READABLE));
-
-	g_object_class_install_property
 		(object_class, PROP_ACTIVE_CONNECTIONS,
 		 g_param_spec_boxed (NM_MANAGER_ACTIVE_CONNECTIONS,
 		                     "Active connections",
@@ -3622,6 +4894,42 @@ nm_manager_class_init (NMManagerClass *manager_class)
 		nm_properties_changed_signal_new (object_class,
 		                                  G_STRUCT_OFFSET (NMManagerClass, properties_changed));
 
+	signals[CONNECTIONS_ADDED] =
+		g_signal_new ("connections-added",
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              G_STRUCT_OFFSET (NMManagerClass, connections_added),
+		              NULL, NULL,
+		              g_cclosure_marshal_VOID__UINT,
+		              G_TYPE_NONE, 1, G_TYPE_UINT);
+
+	signals[CONNECTION_ADDED] =
+		g_signal_new ("connection-added",
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              G_STRUCT_OFFSET (NMManagerClass, connection_added),
+		              NULL, NULL,
+		              _nm_marshal_VOID__OBJECT_UINT,
+		              G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_UINT);
+
+	signals[CONNECTION_UPDATED] =
+		g_signal_new ("connection-updated",
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              G_STRUCT_OFFSET (NMManagerClass, connection_updated),
+		              NULL, NULL,
+		              _nm_marshal_VOID__OBJECT_UINT,
+		              G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_UINT);
+
+	signals[CONNECTION_REMOVED] =
+		g_signal_new ("connection-removed",
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              G_STRUCT_OFFSET (NMManagerClass, connection_removed),
+		              NULL, NULL,
+		              _nm_marshal_VOID__OBJECT_UINT,
+		              G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_UINT);
+
 	signals[CHECK_PERMISSIONS] =
 		g_signal_new ("check-permissions",
 		              G_OBJECT_CLASS_TYPE (object_class),
@@ -3638,6 +4946,15 @@ nm_manager_class_init (NMManagerClass *manager_class)
 		              g_cclosure_marshal_VOID__VOID,
 		              G_TYPE_NONE, 0);
 
+	/* StateChange is DEPRECATED */
+	signals[STATE_CHANGE] =
+		g_signal_new ("state-change",
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              0, NULL, NULL,
+		              g_cclosure_marshal_VOID__UINT,
+		              G_TYPE_NONE, 1, G_TYPE_UINT);
+
 	dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (manager_class),
 	                                 &dbus_glib_nm_manager_object_info);