summary refs log tree commit diff
path: root/libnm-glib/nm-remote-settings.c
diff options
context:
space:
mode:
Diffstat (limited to 'libnm-glib/nm-remote-settings.c')
-rw-r--r--libnm-glib/nm-remote-settings.c550
1 files changed, 421 insertions, 129 deletions
diff --git a/libnm-glib/nm-remote-settings.c b/libnm-glib/nm-remote-settings.c
index 34817e2c..3a2a3e68 100644
--- a/libnm-glib/nm-remote-settings.c
+++ b/libnm-glib/nm-remote-settings.c
@@ -25,11 +25,100 @@
 #include <NetworkManager.h>
 #include <nm-connection.h>
 
-#include "nm-glib-marshal.h"
 #include "nm-dbus-glib-types.h"
 #include "nm-remote-settings.h"
 #include "nm-remote-connection-private.h"
+#include "nm-object-private.h"
+#include "nm-dbus-helpers-private.h"
 #include "nm-glib-compat.h"
+#include "nm-object-private.h"
+
+/**
+ * SECTION:nm-remote-settings
+ * @Short_description: A helper for NetworkManager's settings API
+ * @Title: NMRemoteSettings
+ * @See_also:#NMRemoteConnection, #NMClient
+ *
+ * The #NMRemoteSettings object represents NetworkManager's "settings" service,
+ * which stores network configuration and allows authenticated clients to
+ * add, delete, and modify that configuration.  The data required to connect
+ * to a specific network is called a "connection" and encapsulated by the
+ * #NMConnection object.  Once a connection is known to NetworkManager, having
+ * either been added by a user or read from on-disk storage, the
+ * #NMRemoteSettings object creates a #NMRemoteConnection object which
+ * represents this stored connection.  Use the #NMRemoteConnection object to
+ * perform any operations like modification or deletion.
+ *
+ * To add a new network connection to the NetworkManager settings service, first
+ * build up a template #NMConnection object.  Since this connection is not yet
+ * added to NetworkManager, it is known only to your program and is not yet
+ * an #NMRemoteConnection.  Then ask #NMRemoteSettings to add your connection.
+ * When the connection is added successfully, the supplied callback is called
+ * and returns to your program the new #NMRemoteConnection which represents
+ * the stored object known to NetworkManager.
+ *
+ * |[<!-- language="C" -->
+ * static void
+ * added_cb (NMRemoteSettings *settings,
+ *           NMRemoteConnection *remote,
+ *           GError *error,
+ *           gpointer user_data)
+ * {
+ *    if (error)
+ *        g_print ("Error adding connection: %s", error->message);
+ *    else {
+ *        g_print ("Added: %s\n", nm_connection_get_path (NM_CONNECTION (remote)));
+ *        /&ast; Use 'remote' with nm_remote_connection_commit_changes() to save
+ *         * changes and nm_remote_connection_delete() to delete the connection &ast;/
+ *    }
+ * }
+ *
+ * static gboolean
+ * add_wired_connection (const char *human_name)
+ * {
+ *    NMConnection *connection;
+ *    NMSettingConnection *s_con;
+ *    NMSettingWired *s_wired;
+ *    char *uuid;
+ *    gboolean success;
+ *
+ *    connection = nm_connection_new ();
+ *
+ *    /&ast; Build up the 'connection' setting &ast;/
+ *    s_con = (NMSettingConnection *) nm_setting_connection_new ();
+ *    uuid = nm_utils_uuid_generate ();
+ *    g_object_set (G_OBJECT (s_con),
+ *                  NM_SETTING_CONNECTION_UUID, uuid,
+ *                  NM_SETTING_CONNECTION_ID, human_name,
+ *                  NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME,
+ *                  NULL);
+ *    g_free (uuid);
+ *    nm_connection_add_setting (connection, NM_SETTING (s_con));
+ *
+ *    /&ast; Add the required 'wired' setting as this is a wired connection &ast;/
+ *    nm_connection_add_setting (connection, nm_setting_wired_new ());
+ *
+ *    /&ast; Add an 'ipv4' setting using AUTO configuration (eg DHCP) &ast;/
+ *    s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new ();
+ *    g_object_set (G_OBJECT (s_ip4),
+ *                  NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO,
+ *                  NULL);
+ *    nm_connection_add_setting (connection, NM_SETTING (s_ip4));
+ *
+ *    /&ast; Ask NetworkManager to store the connection &ast;/
+ *    success = nm_remote_settings_add_connection (settings, connection, added_cb, loop);
+ *
+ *    /&ast; Release the template connection; the actual stored connection will
+ *     * be returned in added_cb() &ast;/
+ *    g_object_unref (connection);
+ *
+ *    /&ast; Let glib event loop run and added_cb() will be called when NetworkManager
+ *     * is done adding the new connection. &ast;/
+ *
+ *    return success;
+ * }
+ * ]|
+ */
 
 static void nm_remote_settings_initable_iface_init (GInitableIface *iface);
 static void nm_remote_settings_async_initable_iface_init (GAsyncInitableIface *iface);
@@ -43,6 +132,7 @@ G_DEFINE_TYPE_WITH_CODE (NMRemoteSettings, nm_remote_settings, G_TYPE_OBJECT,
 
 typedef struct {
 	DBusGConnection *bus;
+	gboolean private_bus;
 	gboolean inited;
 
 	DBusGProxy *proxy;
@@ -60,8 +150,7 @@ typedef struct {
 
 	DBusGProxy *dbus_proxy;
 
-	guint fetch_id;
-	gboolean fetching;
+	DBusGProxyCall *listcon_call;
 } NMRemoteSettingsPrivate;
 
 enum {
@@ -172,6 +261,45 @@ add_connection_info_complete (NMRemoteSettings *self,
 }
 
 /**
+ * nm_remote_settings_get_connection_by_id:
+ * @settings: the %NMRemoteSettings
+ * @id: the id of the remote connection
+ *
+ * Returns the first matching %NMRemoteConnection matching a given @id.
+ *
+ * Returns: (transfer none): the remote connection object on success, or %NULL if no
+ *  matching object was found.
+ *
+ * Since: 0.9.10
+ **/
+NMRemoteConnection *
+nm_remote_settings_get_connection_by_id (NMRemoteSettings *settings, const char *id)
+{
+	NMRemoteSettingsPrivate *priv;
+
+	g_return_val_if_fail (NM_IS_REMOTE_SETTINGS (settings), NULL);
+	g_return_val_if_fail (id != NULL, NULL);
+
+	priv = NM_REMOTE_SETTINGS_GET_PRIVATE (settings);
+
+	_nm_remote_settings_ensure_inited (settings);
+
+	if (priv->service_running) {
+		GHashTableIter iter;
+		NMConnection *candidate;
+
+		g_hash_table_iter_init (&iter, priv->connections);
+		while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &candidate)) {
+
+			if (!strcmp (id, nm_connection_get_id (candidate)))
+				return NM_REMOTE_CONNECTION (candidate);
+		}
+	}
+
+	return NULL;
+}
+
+/**
  * nm_remote_settings_get_connection_by_path:
  * @settings: the %NMRemoteSettings
  * @path: the D-Bus object path of the remote connection
@@ -186,7 +314,6 @@ nm_remote_settings_get_connection_by_path (NMRemoteSettings *settings, const cha
 {
 	NMRemoteSettingsPrivate *priv;
 
-	g_return_val_if_fail (settings != NULL, NULL);
 	g_return_val_if_fail (NM_IS_REMOTE_SETTINGS (settings), NULL);
 	g_return_val_if_fail (path != NULL, NULL);
 
@@ -214,7 +341,6 @@ nm_remote_settings_get_connection_by_uuid (NMRemoteSettings *settings, const cha
 	GHashTableIter iter;
 	NMRemoteConnection *candidate;
 
-	g_return_val_if_fail (settings != NULL, NULL);
 	g_return_val_if_fail (NM_IS_REMOTE_SETTINGS (settings), NULL);
 	g_return_val_if_fail (uuid != NULL, NULL);
 
@@ -363,9 +489,10 @@ connection_inited (GObject *source, GAsyncResult *result, gpointer user_data)
 		g_signal_emit (self, signals[NEW_CONNECTION], 0, remote);
 	} else {
 		if (addinfo) {
-			local = g_error_new_literal (NM_REMOTE_SETTINGS_ERROR,
-			                             NM_REMOTE_SETTINGS_ERROR_CONNECTION_UNAVAILABLE,
-			                             "Connection not visible or not available");
+			local = g_error_new (NM_REMOTE_SETTINGS_ERROR,
+			                     NM_REMOTE_SETTINGS_ERROR_CONNECTION_UNAVAILABLE,
+			                     "Connection not visible or not available: %s",
+			                     error ? error->message : "(unknown)");
 			add_connection_info_complete (self, addinfo, local);
 			g_error_free (local);
 		}
@@ -382,10 +509,8 @@ connection_inited (GObject *source, GAsyncResult *result, gpointer user_data)
 
 	/* Let listeners know that all connections have been found */
 	priv->init_left--;
-	if (priv->init_left == 0) {
-		priv->fetching = FALSE;
+	if (priv->init_left == 0)
 		g_signal_emit (self, signals[CONNECTIONS_READ], 0);
-	}
 }
 
 static NMRemoteConnection *
@@ -431,12 +556,15 @@ fetch_connections_done (DBusGProxy *proxy,
 	GError *error = NULL;
 	int i;
 
+	g_warn_if_fail (priv->listcon_call == call);
+	priv->listcon_call = NULL;
+
 	if (!dbus_g_proxy_end_call (proxy, call, &error, 
 	                            DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH, &connections,
 	                            G_TYPE_INVALID)) {
-		/* Ignore settings service spawn errors */
 		if (   !g_error_matches (error, DBUS_GERROR, DBUS_GERROR_SERVICE_UNKNOWN)
-		    && !g_error_matches (error, DBUS_GERROR, DBUS_GERROR_NAME_HAS_NO_OWNER)) {
+		    && !g_error_matches (error, DBUS_GERROR, DBUS_GERROR_NAME_HAS_NO_OWNER)
+		    && priv->service_running) {
 			g_warning ("%s: error fetching connections: (%d) %s.",
 			           __func__,
 				       error->code,
@@ -445,16 +573,14 @@ fetch_connections_done (DBusGProxy *proxy,
 		g_clear_error (&error);
 
 		/* We tried to read connections and failed */
-		priv->fetching = FALSE;
 		g_signal_emit (self, signals[CONNECTIONS_READ], 0);
 		return;
 	}
 
 	/* Let listeners know we are done getting connections */
-	if (connections->len == 0) {
-		priv->fetching = FALSE;
+	if (connections->len == 0)
 		g_signal_emit (self, signals[CONNECTIONS_READ], 0);
-	} else {
+	else {
 		priv->init_left = connections->len;
 		for (i = 0; i < connections->len; i++) {
 			char *path = g_ptr_array_index (connections, i);
@@ -467,20 +593,6 @@ fetch_connections_done (DBusGProxy *proxy,
 	g_ptr_array_free (connections, TRUE);
 }
 
-static gboolean
-fetch_connections (gpointer user_data)
-{
-	NMRemoteSettings *self = NM_REMOTE_SETTINGS (user_data);
-	NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self);
-
-	priv->fetch_id = 0;
-
-	dbus_g_proxy_begin_call (priv->proxy, "ListConnections",
-	                         fetch_connections_done, self, NULL,
-	                         G_TYPE_INVALID);
-	return FALSE;
-}
-
 /**
  * nm_remote_settings_list_connections:
  * @settings: the %NMRemoteSettings
@@ -500,7 +612,6 @@ nm_remote_settings_list_connections (NMRemoteSettings *settings)
 	GHashTableIter iter;
 	gpointer value;
 
-	g_return_val_if_fail (settings != NULL, NULL);
 	g_return_val_if_fail (NM_IS_REMOTE_SETTINGS (settings), NULL);
 
 	priv = NM_REMOTE_SETTINGS_GET_PRIVATE (settings);
@@ -543,7 +654,14 @@ add_connection_done (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data
  * @user_data: (closure): caller-specific data passed to @callback
  *
  * Requests that the remote settings service add the given settings to a new
- * connection.
+ * connection.  The connection is immediately written to disk.  @connection is
+ * untouched by this function and only serves as a template of the settings to
+ * add.  The #NMRemoteConnection object that represents what NetworkManager
+ * actually added is returned to @callback when the addition operation is complete.
+ *
+ * Note that the #NMRemoteConnection returned in @callback may not contain
+ * identical settings to @connection as NetworkManager may perform automatic
+ * completion and/or normalization of connection properties.
  *
  * Returns: %TRUE if the request was successful, %FALSE if it failed
  **/
@@ -557,9 +675,7 @@ nm_remote_settings_add_connection (NMRemoteSettings *settings,
 	AddConnectionInfo *info;
 	GHashTable *new_settings;
 
-	g_return_val_if_fail (settings != NULL, FALSE);
 	g_return_val_if_fail (NM_IS_REMOTE_SETTINGS (settings), FALSE);
-	g_return_val_if_fail (connection != NULL, FALSE);
 	g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
 	g_return_val_if_fail (callback != NULL, FALSE);
 
@@ -567,6 +683,9 @@ nm_remote_settings_add_connection (NMRemoteSettings *settings,
 
 	_nm_remote_settings_ensure_inited (settings);
 
+	if (!priv->service_running)
+		return FALSE;
+
 	info = g_malloc0 (sizeof (AddConnectionInfo));
 	info->self = settings;
 	info->callback = callback;
@@ -586,6 +705,171 @@ nm_remote_settings_add_connection (NMRemoteSettings *settings,
 	return TRUE;
 }
 
+/**
+ * nm_remote_settings_add_connection_unsaved:
+ * @settings: the %NMRemoteSettings
+ * @connection: the connection to add. Note that this object's settings will be
+ *   added, not the object itself
+ * @callback: (scope async): callback to be called when the add operation completes
+ * @user_data: (closure): caller-specific data passed to @callback
+ *
+ * Requests that the remote settings service add the given settings to a new
+ * connection.  The connection is not written to disk, which may be done at
+ * a later time by calling the connection's nm_remote_connection_commit_changes()
+ * method.
+ *
+ * Returns: %TRUE if the request was successful, %FALSE if it failed
+ *
+ * Since: 0.9.10
+ **/
+gboolean
+nm_remote_settings_add_connection_unsaved (NMRemoteSettings *settings,
+                                           NMConnection *connection,
+                                           NMRemoteSettingsAddConnectionFunc callback,
+                                           gpointer user_data)
+{
+	NMRemoteSettingsPrivate *priv;
+	AddConnectionInfo *info;
+	GHashTable *new_settings;
+
+	g_return_val_if_fail (NM_IS_REMOTE_SETTINGS (settings), FALSE);
+	g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
+	g_return_val_if_fail (callback != NULL, FALSE);
+
+	priv = NM_REMOTE_SETTINGS_GET_PRIVATE (settings);
+
+	_nm_remote_settings_ensure_inited (settings);
+
+	if (!priv->service_running)
+		return FALSE;
+
+	info = g_malloc0 (sizeof (AddConnectionInfo));
+	info->self = settings;
+	info->callback = callback;
+	info->callback_data = user_data;
+
+	new_settings = nm_connection_to_hash (connection, NM_SETTING_HASH_FLAG_ALL);
+	dbus_g_proxy_begin_call (priv->proxy, "AddConnectionUnsaved",
+	                         add_connection_done,
+	                         info,
+	                         NULL,
+	                         DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, new_settings,
+	                         G_TYPE_INVALID);
+	g_hash_table_destroy (new_settings);
+
+	priv->add_list = g_slist_append (priv->add_list, info);
+
+	return TRUE;
+}
+
+/**
+ * nm_remote_settings_load_connections:
+ * @settings: the %NMRemoteSettings
+ * @filenames: %NULL-terminated array of filenames to load
+ * @failures: (out) (transfer full): on return, a %NULL-terminated array of
+ *   filenames that failed to load
+ * @error: return location for #GError
+ *
+ * Requests that the remote settings service load or reload the given files,
+ * adding or updating the connections described within.
+ *
+ * The changes to the indicated files will not yet be reflected in
+ * @settings's connections array when the function returns.
+ *
+ * If all of the indicated files were successfully loaded, the
+ * function will return %TRUE, and @failures will be set to %NULL. If
+ * NetworkManager tried to load the files, but some (or all) failed,
+ * then @failures will be set to a %NULL-terminated array of the
+ * filenames that failed to load.
+
+ * Returns: %TRUE if NetworkManager at least tried to load @filenames,
+ * %FALSE if an error occurred (eg, permission denied).
+ *
+ * Since: 0.9.10
+ **/
+gboolean
+nm_remote_settings_load_connections (NMRemoteSettings *settings,
+                                     char **filenames,
+                                     char ***failures,
+                                     GError **error)
+{
+	NMRemoteSettingsPrivate *priv;
+	char **my_failures = NULL;
+	gboolean ret;
+
+	g_return_val_if_fail (NM_IS_REMOTE_SETTINGS (settings), FALSE);
+	g_return_val_if_fail (filenames != NULL, FALSE);
+
+	priv = NM_REMOTE_SETTINGS_GET_PRIVATE (settings);
+
+	_nm_remote_settings_ensure_inited (settings);
+
+	if (!priv->service_running) {
+		g_set_error_literal (error, NM_REMOTE_SETTINGS_ERROR,
+		                     NM_REMOTE_SETTINGS_ERROR_SERVICE_UNAVAILABLE,
+		                     "NetworkManager is not running.");
+		return FALSE;
+	}
+
+	if (!dbus_g_proxy_call (priv->proxy, "LoadConnections", error,
+	                        G_TYPE_STRV, filenames,
+	                        G_TYPE_INVALID,
+	                        G_TYPE_BOOLEAN, &ret,
+	                        G_TYPE_STRV, &my_failures,
+	                        G_TYPE_INVALID))
+		ret = FALSE;
+
+	if (failures) {
+		if (my_failures && !*my_failures)
+			g_clear_pointer (&my_failures, g_free);
+		*failures = my_failures;
+	} else
+		g_strfreev (my_failures);
+
+	return ret;
+}
+
+/**
+ * nm_remote_settings_reload_connections:
+ * @settings: the #NMRemoteSettings
+ * @error: return location for #GError
+ *
+ * Requests that the remote settings service reload all connection
+ * files from disk, adding, updating, and removing connections until
+ * the in-memory state matches the on-disk state.
+ *
+ * Return value: %TRUE on success, %FALSE on failure
+ *
+ * Since: 0.9.10
+ **/
+gboolean
+nm_remote_settings_reload_connections (NMRemoteSettings *settings,
+                                       GError **error)
+{
+	NMRemoteSettingsPrivate *priv;
+	gboolean success;
+
+	g_return_val_if_fail (NM_IS_REMOTE_SETTINGS (settings), FALSE);
+
+	priv = NM_REMOTE_SETTINGS_GET_PRIVATE (settings);
+
+	_nm_remote_settings_ensure_inited (settings);
+
+	if (!priv->service_running) {
+		g_set_error_literal (error, NM_REMOTE_SETTINGS_ERROR,
+		                     NM_REMOTE_SETTINGS_ERROR_SERVICE_UNAVAILABLE,
+		                     "NetworkManager is not running.");
+		return FALSE;
+	}
+
+	if (!dbus_g_proxy_call (priv->proxy, "ReloadConnections", error,
+	                        G_TYPE_INVALID,
+	                        G_TYPE_BOOLEAN, &success,
+	                        G_TYPE_INVALID))
+		return FALSE;
+	return success;
+}
+
 static void
 clear_one_hash (GHashTable *table)
 {
@@ -595,7 +879,7 @@ clear_one_hash (GHashTable *table)
 
 	/* Build up the list of connections; we can't emit "removed" during hash
 	 * table iteration because emission of the "removed" signal may trigger code
-	 * that explicitly removes the the connection from the hash table somewhere
+	 * that explicitly removes the connection from the hash table somewhere
 	 * else.
 	 */
 	g_hash_table_iter_init (&iter, table);
@@ -609,17 +893,6 @@ clear_one_hash (GHashTable *table)
 	g_hash_table_remove_all (table);
 }
 
-static gboolean
-remove_connections (gpointer user_data)
-{
-	NMRemoteSettings *self = NM_REMOTE_SETTINGS (user_data);
-	NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self);
-
-	clear_one_hash (priv->pending);
-	clear_one_hash (priv->connections);
-	return FALSE;
-}
-
 typedef struct {
 	NMRemoteSettings *settings;
 	NMRemoteSettingsSaveHostnameFunc callback;
@@ -663,7 +936,6 @@ nm_remote_settings_save_hostname (NMRemoteSettings *settings,
 	NMRemoteSettingsPrivate *priv;
 	SaveHostnameInfo *info;
 
-	g_return_val_if_fail (settings != NULL, FALSE);
 	g_return_val_if_fail (NM_IS_REMOTE_SETTINGS (settings), FALSE);
 	g_return_val_if_fail (hostname != NULL, FALSE);
 	g_return_val_if_fail (callback != NULL, FALSE);
@@ -672,6 +944,9 @@ nm_remote_settings_save_hostname (NMRemoteSettings *settings,
 
 	_nm_remote_settings_ensure_inited (settings);
 
+	if (!priv->service_running)
+		return FALSE;
+
 	info = g_malloc0 (sizeof (SaveHostnameInfo));
 	info->settings = settings;
 	info->callback = callback;
@@ -740,21 +1015,23 @@ name_owner_changed (DBusGProxy *proxy,
 	const char *sname = NM_DBUS_SERVICE;
 
 	if (!strcmp (name, sname)) {
-		if (priv->fetch_id)
-			g_source_remove (priv->fetch_id);
-
 		if (new_owner && strlen (new_owner) > 0) {
-			priv->fetch_id = g_idle_add (fetch_connections, self);
 			priv->service_running = TRUE;
 
+			priv->listcon_call = dbus_g_proxy_begin_call (priv->proxy, "ListConnections",
+			                                              fetch_connections_done, self, NULL,
+			                                              G_TYPE_INVALID);
+
 			dbus_g_proxy_begin_call (priv->props_proxy, "GetAll",
 			                         nm_appeared_got_properties, self, NULL,
 			                         G_TYPE_STRING, NM_DBUS_IFACE_SETTINGS,
 			                         G_TYPE_INVALID);
 		} else {
-			priv->fetch_id = g_idle_add (remove_connections, self);
 			priv->service_running = FALSE;
 
+			clear_one_hash (priv->pending);
+			clear_one_hash (priv->connections);
+
 			/* Clear properties */
 			g_free (priv->hostname);
 			priv->hostname = NULL;
@@ -762,6 +1039,11 @@ name_owner_changed (DBusGProxy *proxy,
 
 			priv->can_modify = FALSE;
 			g_object_notify (G_OBJECT (self), NM_REMOTE_SETTINGS_CAN_MODIFY);
+
+			if (priv->listcon_call) {
+				dbus_g_proxy_cancel_call (priv->proxy, priv->listcon_call);
+				priv->listcon_call = NULL;
+			}
 		}
 		g_object_notify (G_OBJECT (self), NM_REMOTE_SETTINGS_SERVICE_RUNNING);
 	}
@@ -784,7 +1066,11 @@ name_owner_changed (DBusGProxy *proxy,
 NMRemoteSettings *
 nm_remote_settings_new (DBusGConnection *bus)
 {
-	return g_object_new (NM_TYPE_REMOTE_SETTINGS, NM_REMOTE_SETTINGS_BUS, bus, NULL);
+	NMRemoteSettings *self;
+
+	self = g_object_new (NM_TYPE_REMOTE_SETTINGS, NM_REMOTE_SETTINGS_BUS, bus, NULL);
+	_nm_remote_settings_ensure_inited (self);
+	return self;
 }
 
 static void
@@ -880,29 +1166,30 @@ constructed (GObject *object)
 
 	priv = NM_REMOTE_SETTINGS_GET_PRIVATE (object);
 
-	/* D-Bus proxy for clearing connections on NameOwnerChanged */
-	priv->dbus_proxy = dbus_g_proxy_new_for_name (priv->bus,
-	                                              "org.freedesktop.DBus",
-	                                              "/org/freedesktop/DBus",
-	                                              "org.freedesktop.DBus");
-	g_assert (priv->dbus_proxy);
+	if (priv->private_bus == FALSE) {
+		/* D-Bus proxy for clearing connections on NameOwnerChanged */
+		priv->dbus_proxy = dbus_g_proxy_new_for_name (priv->bus,
+		                                              DBUS_SERVICE_DBUS,
+		                                              DBUS_PATH_DBUS,
+		                                              DBUS_INTERFACE_DBUS);
+		g_assert (priv->dbus_proxy);
+
+		dbus_g_object_register_marshaller (g_cclosure_marshal_generic,
+		                                   G_TYPE_NONE,
+		                                   G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
+		                                   G_TYPE_INVALID);
+		dbus_g_proxy_add_signal (priv->dbus_proxy, "NameOwnerChanged",
+		                         G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
+		                         G_TYPE_INVALID);
+		dbus_g_proxy_connect_signal (priv->dbus_proxy,
+		                             "NameOwnerChanged",
+		                             G_CALLBACK (name_owner_changed),
+		                             object, NULL);
+	}
 
-	dbus_g_object_register_marshaller (_nm_glib_marshal_VOID__STRING_STRING_STRING,
-	                                   G_TYPE_NONE,
-	                                   G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
-	                                   G_TYPE_INVALID);
-	dbus_g_proxy_add_signal (priv->dbus_proxy, "NameOwnerChanged",
-	                         G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
-	                         G_TYPE_INVALID);
-	dbus_g_proxy_connect_signal (priv->dbus_proxy,
-	                             "NameOwnerChanged",
-	                             G_CALLBACK (name_owner_changed),
-	                             object, NULL);
-
-	priv->proxy = dbus_g_proxy_new_for_name (priv->bus,
-	                                         NM_DBUS_SERVICE,
-	                                         NM_DBUS_PATH_SETTINGS,
-	                                         NM_DBUS_IFACE_SETTINGS);
+	priv->proxy = _nm_dbus_new_proxy_for_connection (priv->bus,
+	                                                 NM_DBUS_PATH_SETTINGS,
+	                                                 NM_DBUS_IFACE_SETTINGS);
 	g_assert (priv->proxy);
 	dbus_g_proxy_set_default_timeout (priv->proxy, G_MAXINT);
 
@@ -914,19 +1201,14 @@ constructed (GObject *object)
 	                             object,
 	                             NULL);
 
-	priv->fetching = TRUE;
-	priv->fetch_id = g_idle_add (fetch_connections, object);
-
-
 	/* D-Bus properties proxy */
-	priv->props_proxy = dbus_g_proxy_new_for_name (priv->bus,
-	                                               NM_DBUS_SERVICE,
-	                                               NM_DBUS_PATH_SETTINGS,
-	                                               "org.freedesktop.DBus.Properties");
+	priv->props_proxy = _nm_dbus_new_proxy_for_connection (priv->bus,
+	                                                       NM_DBUS_PATH_SETTINGS,
+	                                                       "org.freedesktop.DBus.Properties");
 	g_assert (priv->props_proxy);
 
 	/* Monitor properties */
-	dbus_g_object_register_marshaller (g_cclosure_marshal_VOID__BOXED,
+	dbus_g_object_register_marshaller (g_cclosure_marshal_generic,
 	                                   G_TYPE_NONE,
 	                                   DBUS_TYPE_G_MAP_OF_VARIANT,
 	                                   G_TYPE_INVALID);
@@ -946,20 +1228,27 @@ init_sync (GInitable *initable, GCancellable *cancellable, GError **error)
 	NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (settings);
 	GHashTable *props;
 
-	if (!dbus_g_proxy_call (priv->dbus_proxy, "NameHasOwner", error,
-	                        G_TYPE_STRING, NM_DBUS_SERVICE,
-	                        G_TYPE_INVALID,
-	                        G_TYPE_BOOLEAN, &priv->service_running,
-	                        G_TYPE_INVALID)) {
-		priv->service_running = FALSE;
-		return FALSE;
-	}
+	if (priv->private_bus == FALSE) {
+		if (!dbus_g_proxy_call (priv->dbus_proxy, "NameHasOwner", error,
+		                        G_TYPE_STRING, NM_DBUS_SERVICE,
+		                        G_TYPE_INVALID,
+		                        G_TYPE_BOOLEAN, &priv->service_running,
+		                        G_TYPE_INVALID)) {
+			priv->service_running = FALSE;
+			return FALSE;
+		}
 
-	/* If NM isn't running we'll grab properties from name_owner_changed()
-	 * when it starts.
-	 */
-	if (!priv->service_running)
-		return TRUE;
+		/* If NM isn't running we'll grab properties from name_owner_changed()
+		 * when it starts.
+		 */
+		if (!priv->service_running)
+			return TRUE;
+	} else
+		priv->service_running = TRUE;
+
+	priv->listcon_call = dbus_g_proxy_begin_call (priv->proxy, "ListConnections",
+	                                              fetch_connections_done, NM_REMOTE_SETTINGS (initable), NULL,
+	                                              G_TYPE_INVALID);
 
 	/* Get properties */
 	if (!dbus_g_proxy_call (priv->props_proxy, "GetAll", error,
@@ -1019,14 +1308,23 @@ init_async_got_properties (DBusGProxy *proxy, DBusGProxyCall *call,
 	} else
 		g_simple_async_result_take_error (init_data->result, error);
 
-	if (priv->fetching) {
-		/* Still creating initial connections; wait for that to complete */
-		g_signal_connect (init_data->settings, "connections-read",
-		                  G_CALLBACK (init_read_connections), init_data);
-		return;
-	}
+	/* Read connections and wait for the result */
+	priv->listcon_call = dbus_g_proxy_begin_call (priv->proxy, "ListConnections",
+	                                              fetch_connections_done, init_data->settings, NULL,
+	                                              G_TYPE_INVALID);
+	g_signal_connect (init_data->settings, "connections-read",
+	                  G_CALLBACK (init_read_connections), init_data);
+}
 
-	init_async_complete (init_data);
+static void
+init_get_properties (NMRemoteSettingsInitData *init_data)
+{
+	NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (init_data->settings);
+
+	dbus_g_proxy_begin_call (priv->props_proxy, "GetAll",
+	                         init_async_got_properties, init_data, NULL,
+	                         G_TYPE_STRING, NM_DBUS_IFACE_SETTINGS,
+	                         G_TYPE_INVALID);
 }
 
 static void
@@ -1051,10 +1349,7 @@ init_async_got_manager_running (DBusGProxy *proxy, DBusGProxyCall *call,
 		return;
 	}
 
-	dbus_g_proxy_begin_call (priv->props_proxy, "GetAll",
-	                         init_async_got_properties, init_data, NULL,
-	                         G_TYPE_STRING, NM_DBUS_IFACE_SETTINGS,
-	                         G_TYPE_INVALID);
+	init_get_properties (init_data);
 }
 
 static void
@@ -1070,12 +1365,16 @@ init_async (GAsyncInitable *initable, int io_priority,
 	init_data->result = g_simple_async_result_new (G_OBJECT (initable), callback,
 	                                               user_data, init_async);
 
-	/* Check if NM is running */
-	dbus_g_proxy_begin_call (priv->dbus_proxy, "NameHasOwner",
-	                         init_async_got_manager_running,
-	                         init_data, NULL,
-	                         G_TYPE_STRING, NM_DBUS_SERVICE,
-	                         G_TYPE_INVALID);
+	if (priv->private_bus)
+		init_get_properties (init_data);
+	else {
+		/* Check if NM is running */
+		dbus_g_proxy_begin_call (priv->dbus_proxy, "NameHasOwner",
+		                         init_async_got_manager_running,
+		                         init_data, NULL,
+		                         G_TYPE_STRING, NM_DBUS_SERVICE,
+		                         G_TYPE_INVALID);
+	}
 }
 
 static gboolean
@@ -1095,11 +1394,6 @@ dispose (GObject *object)
 	NMRemoteSettings *self = NM_REMOTE_SETTINGS (object);
 	NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (self);
 
-	if (priv->fetch_id) {
-		g_source_remove (priv->fetch_id);
-		priv->fetch_id = 0;
-	}
-
 	while (g_slist_length (priv->add_list))
 		add_connection_info_dispose (self, (AddConnectionInfo *) priv->add_list->data);
 
@@ -1133,15 +1427,15 @@ set_property (GObject *object, guint prop_id,
               const GValue *value, GParamSpec *pspec)
 {
 	NMRemoteSettingsPrivate *priv = NM_REMOTE_SETTINGS_GET_PRIVATE (object);
-	DBusGConnection *connection;
 
 	switch (prop_id) {
 	case PROP_BUS:
 		/* Construct only */
-		connection = (DBusGConnection *) g_value_get_boxed (value);
-		if (!connection)
-			connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, NULL);
-		priv->bus = dbus_g_connection_ref (connection);
+		priv->bus = g_value_dup_boxed (value);
+		if (!priv->bus) {
+			priv->bus = _nm_dbus_new_connection (NULL);
+			priv->private_bus = _nm_dbus_is_connection_private (priv->bus);
+		}
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -1228,8 +1522,7 @@ nm_remote_settings_class_init (NMRemoteSettingsClass *class)
 	                              G_OBJECT_CLASS_TYPE (object_class),
 	                              G_SIGNAL_RUN_FIRST,
 	                              G_STRUCT_OFFSET (NMRemoteSettingsClass, new_connection),
-	                              NULL, NULL,
-	                              g_cclosure_marshal_VOID__OBJECT,
+	                              NULL, NULL, NULL,
 	                              G_TYPE_NONE, 1, G_TYPE_OBJECT);
 
 	signals[CONNECTIONS_READ] = 
@@ -1237,8 +1530,7 @@ nm_remote_settings_class_init (NMRemoteSettingsClass *class)
 	                              G_OBJECT_CLASS_TYPE (object_class),
 	                              G_SIGNAL_RUN_FIRST,
 	                              G_STRUCT_OFFSET (NMRemoteSettingsClass, connections_read),
-	                              NULL, NULL,
-	                              g_cclosure_marshal_VOID__VOID,
+	                              NULL, NULL, NULL,
 	                              G_TYPE_NONE, 0);
 }