summary refs log tree commit diff
path: root/src/settings/nm-settings.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/settings/nm-settings.c')
-rw-r--r--src/settings/nm-settings.c769
1 files changed, 320 insertions, 449 deletions
diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c
index 2c6b7101..8e3fc582 100644
--- a/src/settings/nm-settings.c
+++ b/src/settings/nm-settings.c
@@ -62,12 +62,10 @@
 #include "nm-utils.h"
 #include "nm-core-internal.h"
 
-#include "nm-utils/nm-c-list.h"
-#include "nm-dbus-object.h"
 #include "devices/nm-device-ethernet.h"
 #include "nm-settings-connection.h"
 #include "nm-settings-plugin.h"
-#include "nm-dbus-manager.h"
+#include "nm-bus-manager.h"
 #include "nm-auth-utils.h"
 #include "nm-auth-subject.h"
 #include "nm-session-monitor.h"
@@ -79,6 +77,8 @@
 #include "nm-dispatcher.h"
 #include "nm-hostname-manager.h"
 
+#include "introspection/org.freedesktop.NetworkManager.Settings.h"
+
 /*****************************************************************************/
 
 #define EXPORT(sym) void * __export_##sym = &sym;
@@ -107,6 +107,7 @@ enum {
 	CONNECTION_UPDATED,
 	CONNECTION_REMOVED,
 	CONNECTION_FLAGS_CHANGED,
+	NEW_CONNECTION, /* exported, not used internally */
 	LAST_SIGNAL
 };
 
@@ -120,33 +121,29 @@ typedef struct {
 	GSList *auths;
 
 	GSList *plugins;
-
-	CList connections_lst_head;
-
+	gboolean connections_loaded;
+	GHashTable *connections;
 	NMSettingsConnection **connections_cached_list;
 	GSList *unmanaged_specs;
 	GSList *unrecognized_specs;
 
-	NMHostnameManager *hostname_manager;
-
-	guint connections_len;
+	gboolean started;
+	gboolean startup_complete;
 
-	bool started:1;
-	bool startup_complete:1;
-	bool connections_loaded:1;
+	NMHostnameManager *hostname_manager;
 
 } NMSettingsPrivate;
 
 struct _NMSettings {
-	NMDBusObject parent;
+	NMExportedObject parent;
 	NMSettingsPrivate _priv;
 };
 
 struct _NMSettingsClass {
-	NMDBusObjectClass parent;
+	NMExportedObjectClass parent;
 };
 
-G_DEFINE_TYPE (NMSettings, nm_settings, NM_TYPE_DBUS_OBJECT);
+G_DEFINE_TYPE (NMSettings, nm_settings, NM_TYPE_EXPORTED_OBJECT);
 
 #define NM_SETTINGS_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMSettings, NM_IS_SETTINGS)
 
@@ -157,10 +154,6 @@ G_DEFINE_TYPE (NMSettings, nm_settings, NM_TYPE_DBUS_OBJECT);
 
 /*****************************************************************************/
 
-static const NMDBusInterfaceInfoExtended interface_info_settings;
-static const GDBusSignalInfo signal_info_new_connection;
-static const GDBusSignalInfo signal_info_connection_removed;
-
 static void claim_connection (NMSettings *self,
                               NMSettingsConnection *connection);
 
@@ -171,29 +164,27 @@ static void connection_ready_changed (NMSettingsConnection *conn,
                                       GParamSpec *pspec,
                                       gpointer user_data);
 
-static void default_wired_clear_tag (NMSettings *self,
-                                     NMDevice *device,
-                                     NMSettingsConnection *connection,
-                                     gboolean add_to_no_auto_default);
-
 /*****************************************************************************/
 
 static void
 check_startup_complete (NMSettings *self)
 {
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
+	GHashTableIter iter;
 	NMSettingsConnection *conn;
 
 	if (priv->startup_complete)
 		return;
 
-	c_list_for_each_entry (conn, &priv->connections_lst_head, _connections_lst) {
+	g_hash_table_iter_init (&iter, priv->connections);
+	while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &conn)) {
 		if (!nm_settings_connection_get_ready (conn))
 			return;
 	}
 
 	/* the connection_ready_changed signal handler is no longer needed. */
-	c_list_for_each_entry (conn, &priv->connections_lst_head, _connections_lst)
+	g_hash_table_iter_init (&iter, priv->connections);
+	while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &conn))
 		g_signal_handlers_disconnect_by_func (conn, G_CALLBACK (connection_ready_changed), self);
 
 	priv->startup_complete = TRUE;
@@ -256,25 +247,43 @@ load_connections (NMSettings *self)
 	unrecognized_specs_changed (NULL, self);
 }
 
+void
+nm_settings_for_each_connection (NMSettings *self,
+                                 NMSettingsForEachFunc for_each_func,
+                                 gpointer user_data)
+{
+	NMSettingsPrivate *priv;
+	GHashTableIter iter;
+	gpointer data;
+
+	g_return_if_fail (NM_IS_SETTINGS (self));
+	g_return_if_fail (for_each_func != NULL);
+
+	priv = NM_SETTINGS_GET_PRIVATE (self);
+
+	g_hash_table_iter_init (&iter, priv->connections);
+	while (g_hash_table_iter_next (&iter, NULL, &data))
+		for_each_func (self, NM_SETTINGS_CONNECTION (data), user_data);
+}
+
 static void
-impl_settings_list_connections (NMDBusObject *obj,
-                                const NMDBusInterfaceInfoExtended *interface_info,
-                                const NMDBusMethodInfoExtended *method_info,
-                                GDBusConnection *dbus_connection,
-                                const char *sender,
-                                GDBusMethodInvocation *invocation,
-                                GVariant *parameters)
+impl_settings_list_connections (NMSettings *self,
+                                GDBusMethodInvocation *context)
 {
-	NMSettings *self = NM_SETTINGS (obj);
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
-	gs_free const char **strv = NULL;
-
-	strv = nm_dbus_utils_get_paths_for_clist (&priv->connections_lst_head,
-	                                          priv->connections_len,
-	                                          G_STRUCT_OFFSET (NMSettingsConnection, _connections_lst),
-	                                          TRUE);
-	g_dbus_method_invocation_return_value (invocation,
-	                                       g_variant_new ("(^ao)", strv));
+	GPtrArray *connections;
+	GHashTableIter iter;
+	gpointer key;
+
+	connections = g_ptr_array_sized_new (g_hash_table_size (priv->connections) + 1);
+	g_hash_table_iter_init (&iter, priv->connections);
+	while (g_hash_table_iter_next (&iter, &key, NULL))
+		g_ptr_array_add (connections, key);
+	g_ptr_array_add (connections, NULL);
+
+	g_dbus_method_invocation_return_value (context,
+	                                       g_variant_new ("(^ao)", connections->pdata));
+	g_ptr_array_unref (connections);
 }
 
 NMSettingsConnection *
@@ -282,14 +291,16 @@ nm_settings_get_connection_by_uuid (NMSettings *self, const char *uuid)
 {
 	NMSettingsPrivate *priv;
 	NMSettingsConnection *candidate;
+	GHashTableIter iter;
 
 	g_return_val_if_fail (NM_IS_SETTINGS (self), NULL);
 	g_return_val_if_fail (uuid != NULL, NULL);
 
 	priv = NM_SETTINGS_GET_PRIVATE (self);
 
-	c_list_for_each_entry (candidate, &priv->connections_lst_head, _connections_lst) {
-		if (nm_streq (uuid, nm_settings_connection_get_uuid (candidate)))
+	g_hash_table_iter_init (&iter, priv->connections);
+	while (g_hash_table_iter_next (&iter, NULL, (gpointer) &candidate)) {
+		if (g_strcmp0 (uuid, nm_settings_connection_get_uuid (candidate)) == 0)
 			return candidate;
 	}
 
@@ -297,21 +308,14 @@ nm_settings_get_connection_by_uuid (NMSettings *self, const char *uuid)
 }
 
 static void
-impl_settings_get_connection_by_uuid (NMDBusObject *obj,
-                                      const NMDBusInterfaceInfoExtended *interface_info,
-                                      const NMDBusMethodInfoExtended *method_info,
-                                      GDBusConnection *dbus_connection,
-                                      const char *sender,
-                                      GDBusMethodInvocation *invocation,
-                                      GVariant *parameters)
+impl_settings_get_connection_by_uuid (NMSettings *self,
+                                      GDBusMethodInvocation *context,
+                                      const char *uuid)
 {
-	NMSettings *self = NM_SETTINGS (obj);
 	NMSettingsConnection *connection = NULL;
-	gs_unref_object NMAuthSubject *subject = NULL;
+	NMAuthSubject *subject = NULL;
 	GError *error = NULL;
-	const char *uuid;
-
-	g_variant_get (parameters, "(&s)", &uuid);
+	char *error_desc = NULL;
 
 	connection = nm_settings_get_connection_by_uuid (self, uuid);
 	if (!connection) {
@@ -321,7 +325,7 @@ impl_settings_get_connection_by_uuid (NMDBusObject *obj,
 		goto error;
 	}
 
-	subject = nm_auth_subject_new_unix_process_from_context (invocation);
+	subject = nm_auth_subject_new_unix_process_from_context (context);
 	if (!subject) {
 		error = g_error_new_literal (NM_SETTINGS_ERROR,
 		                             NM_SETTINGS_ERROR_PERMISSION_DENIED,
@@ -329,40 +333,26 @@ impl_settings_get_connection_by_uuid (NMDBusObject *obj,
 		goto error;
 	}
 
-	if (!nm_auth_is_subject_in_acl_set_error (NM_CONNECTION (connection),
-	                                          subject,
-	                                          NM_SETTINGS_ERROR,
-	                                          NM_SETTINGS_ERROR_PERMISSION_DENIED,
-	                                          &error))
+	if (!nm_auth_is_subject_in_acl (NM_CONNECTION (connection),
+	                                subject,
+	                                &error_desc)) {
+		error = g_error_new_literal (NM_SETTINGS_ERROR,
+		                             NM_SETTINGS_ERROR_PERMISSION_DENIED,
+		                             error_desc);
+		g_free (error_desc);
 		goto error;
+	}
 
-	g_dbus_method_invocation_return_value (invocation,
-	                                       g_variant_new ("(o)",
-	                                                      nm_dbus_object_get_path (NM_DBUS_OBJECT (connection))));
+	g_clear_object (&subject);
+	g_dbus_method_invocation_return_value (
+		context,
+		g_variant_new ("(o)", nm_connection_get_path (NM_CONNECTION (connection))));
 	return;
 
 error:
-	g_dbus_method_invocation_take_error (invocation, error);
-}
-
-static void
-_clear_connections_cached_list (NMSettingsPrivate *priv)
-{
-	if (!priv->connections_cached_list)
-		return;
-
-	nm_assert (priv->connections_len == NM_PTRARRAY_LEN (priv->connections_cached_list));
-
-#if NM_MORE_ASSERTS
-	/* set the pointer to a bogus value. This makes it more apparent
-	 * if somebody has a reference to the cached list and still uses
-	 * it. That is a bug, this code just tries to make it blow up
-	 * more eagerly. */
-	memset (priv->connections_cached_list,
-	        0xdeaddead,
-	        sizeof (NMSettingsConnection *) * (priv->connections_len + 1));
-#endif
-	nm_clear_g_free (&priv->connections_cached_list);
+	g_assert (error);
+	g_dbus_method_invocation_take_error (context, error);
+	g_clear_object (&subject);
 }
 
 /**
@@ -380,33 +370,37 @@ _clear_connections_cached_list (NMSettingsPrivate *priv)
 NMSettingsConnection *const*
 nm_settings_get_connections (NMSettings *self, guint *out_len)
 {
+	GHashTableIter iter;
 	NMSettingsPrivate *priv;
+	guint l, i;
 	NMSettingsConnection **v;
 	NMSettingsConnection *con;
-	guint i;
 
 	g_return_val_if_fail (NM_IS_SETTINGS (self), NULL);
 
 	priv = NM_SETTINGS_GET_PRIVATE (self);
 
-	nm_assert (priv->connections_len == c_list_length (&priv->connections_lst_head));
+	if (G_LIKELY (priv->connections_cached_list)) {
+		NM_SET_OUT (out_len, g_hash_table_size (priv->connections));
+		return priv->connections_cached_list;
+	}
 
-	if (G_UNLIKELY (!priv->connections_cached_list)) {
-		v = g_new (NMSettingsConnection *, priv->connections_len + 1);
+	l = g_hash_table_size (priv->connections);
 
-		i = 0;
-		c_list_for_each_entry (con, &priv->connections_lst_head, _connections_lst) {
-			nm_assert (i < priv->connections_len);
-			v[i++] = con;
-		}
-		nm_assert (i == priv->connections_len);
-		v[i] = NULL;
+	v = g_new (NMSettingsConnection *, (gsize) l + 1);
 
-		priv->connections_cached_list = v;
+	i = 0;
+	g_hash_table_iter_init (&iter, priv->connections);
+	while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &con)) {
+		nm_assert (i < l);
+		v[i++] = con;
 	}
+	nm_assert (i == l);
+	v[i] = NULL;
 
-	NM_SET_OUT (out_len, priv->connections_len);
-	return priv->connections_cached_list;
+	NM_SET_OUT (out_len, l);
+	priv->connections_cached_list = v;
+	return v;
 }
 
 /**
@@ -473,41 +467,28 @@ NMSettingsConnection *
 nm_settings_get_connection_by_path (NMSettings *self, const char *path)
 {
 	NMSettingsPrivate *priv;
-	NMSettingsConnection *connection;
 
 	g_return_val_if_fail (NM_IS_SETTINGS (self), NULL);
-	g_return_val_if_fail (path, NULL);
+	g_return_val_if_fail (path != NULL, NULL);
 
 	priv = NM_SETTINGS_GET_PRIVATE (self);
 
-	connection = (NMSettingsConnection *) nm_dbus_manager_lookup_object (nm_dbus_object_get_manager (NM_DBUS_OBJECT (self)),
-	                                                                     path);
-	if (   !connection
-	    || !NM_IS_SETTINGS_CONNECTION (connection))
-		return NULL;
-
-	nm_assert (c_list_contains (&priv->connections_lst_head, &connection->_connections_lst));
-	return connection;
+	return (NMSettingsConnection *) g_hash_table_lookup (priv->connections, path);
 }
 
 gboolean
 nm_settings_has_connection (NMSettings *self, NMSettingsConnection *connection)
 {
-	NMSettingsConnection *candidate = NULL;
-	const char *path;
-
-	g_return_val_if_fail (NM_IS_SETTINGS (self), FALSE);
-	g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (connection), FALSE);
+	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
+	GHashTableIter iter;
+	gpointer data;
 
-	path = nm_dbus_object_get_path (NM_DBUS_OBJECT (connection));
-	if (path)
-		candidate = nm_settings_get_connection_by_path (self, path);
+	g_hash_table_iter_init (&iter, priv->connections);
+	while (g_hash_table_iter_next (&iter, NULL, &data))
+		if (data == connection)
+			return TRUE;
 
-	nm_assert (!candidate || candidate == connection);
-	nm_assert (!!candidate == nm_c_list_contains_entry (&NM_SETTINGS_GET_PRIVATE (self)->connections_lst_head,
-	                                                    connection,
-	                                                    _connections_lst));
-	return !!candidate;
+	return FALSE;
 }
 
 const GSList *
@@ -519,7 +500,7 @@ nm_settings_get_unmanaged_specs (NMSettings *self)
 }
 
 static NMSettingsPlugin *
-get_plugin (NMSettings *self, NMSettingsPluginCapabilities capability)
+get_plugin (NMSettings *self, guint32 capability)
 {
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
 	GSList *iter;
@@ -696,8 +677,8 @@ load_plugins (NMSettings *self, const char **plugins, GError **error)
 			continue;
 		}
 
-		if (NM_IN_STRSET (pname, "ifcfg-suse", "ifnet")) {
-			_LOGW ("skipping deprecated plugin %s", pname);
+		if (!strcmp (pname, "ifcfg-suse")) {
+			_LOGW ("skipping deprecated plugin ifcfg-suse");
 			continue;
 		}
 
@@ -825,6 +806,7 @@ connection_updated (NMSettingsConnection *connection, gboolean by_user, gpointer
 
 static void
 connection_flags_changed (NMSettingsConnection *connection,
+                          GParamSpec *pspec,
                           gpointer user_data)
 {
 	g_signal_emit (NM_SETTINGS (user_data),
@@ -838,20 +820,11 @@ connection_removed (NMSettingsConnection *connection, gpointer user_data)
 {
 	NMSettings *self = NM_SETTINGS (user_data);
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
-	NMDevice *device;
+	const char *cpath = nm_connection_get_path (NM_CONNECTION (connection));
 
-	g_return_if_fail (NM_IS_SETTINGS_CONNECTION (connection));
-	g_return_if_fail (!c_list_is_empty (&connection->_connections_lst));
-	nm_assert (c_list_contains (&priv->connections_lst_head, &connection->_connections_lst));
-
-	/* When the default wired connection is removed (either deleted or saved to
-	 * a new persistent connection by a plugin), write the MAC address of the
-	 * wired device to the config file and don't create a new default wired
-	 * connection for that device again.
-	 */
-	device = g_object_get_qdata (G_OBJECT (connection), _default_wired_device_quark ());
-	if (device)
-		default_wired_clear_tag (self, device, connection, TRUE);
+	if (!g_hash_table_lookup (priv->connections, cpath))
+		g_return_if_reached ();
+	g_object_ref (connection);
 
 	/* Disconnect signal handlers, as plugins might still keep references
 	 * to the connection (and thus the signal handlers would still be live)
@@ -863,30 +836,23 @@ connection_removed (NMSettingsConnection *connection, gpointer user_data)
 	g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_flags_changed), self);
 	if (!priv->startup_complete)
 		g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_ready_changed), self);
+	g_object_unref (self);
 
 	/* Forget about the connection internally */
-	_clear_connections_cached_list (priv);
-	priv->connections_len--;
-	c_list_unlink (&connection->_connections_lst);
-
-	if (priv->connections_loaded) {
-		_notify (self, PROP_CONNECTIONS);
+	g_hash_table_remove (priv->connections, (gpointer) cpath);
+	g_clear_pointer (&priv->connections_cached_list, g_free);
 
-		nm_dbus_object_emit_signal (NM_DBUS_OBJECT (self),
-		                            &interface_info_settings,
-		                            &signal_info_connection_removed,
-		                            "(o)",
-		                            nm_dbus_object_get_path (NM_DBUS_OBJECT (connection)));
-	}
+	/* Notify D-Bus */
+	g_signal_emit (self, signals[CONNECTION_REMOVED], 0, connection);
 
-	nm_dbus_object_unexport (NM_DBUS_OBJECT (connection));
+	/* Re-emit for listeners like NMPolicy */
+	_notify (self, PROP_CONNECTIONS);
+	if (nm_exported_object_is_exported (NM_EXPORTED_OBJECT (connection)))
+		nm_exported_object_unexport (NM_EXPORTED_OBJECT (connection));
 
-	if (priv->connections_loaded)
-		g_signal_emit (self, signals[CONNECTION_REMOVED], 0, connection);
+	check_startup_complete (self);
 
 	g_object_unref (connection);
-
-	check_startup_complete (self);
 }
 
 #define NM_DBUS_SERVICE_OPENCONNECT    "org.freedesktop.NetworkManager.openconnect"
@@ -934,16 +900,19 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection)
 {
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
 	GError *error = NULL;
+	GHashTableIter iter;
+	gpointer data;
 	const char *path;
 	NMSettingsConnection *existing;
 
 	g_return_if_fail (NM_IS_SETTINGS_CONNECTION (connection));
-	g_return_if_fail (!nm_dbus_object_is_exported (NM_DBUS_OBJECT (connection)));
+	g_return_if_fail (nm_connection_get_path (NM_CONNECTION (connection)) == NULL);
 
-	/* prevent duplicates */
-	if (!c_list_is_empty (&connection->_connections_lst)) {
-		nm_assert (c_list_contains (&priv->connections_lst_head, &connection->_connections_lst));
-		return;
+	g_hash_table_iter_init (&iter, priv->connections);
+	while (g_hash_table_iter_next (&iter, NULL, &data)) {
+		/* prevent duplicates */
+		if (data == connection)
+			return;
 	}
 
 	if (!nm_connection_normalize (NM_CONNECTION (connection), NULL, NULL, &error)) {
@@ -975,19 +944,20 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection)
 	/* Read seen-bssids from look-aside file and put it into the connection's data */
 	nm_settings_connection_read_and_fill_seen_bssids (connection);
 
-	/* Ensure its initial visibility is up-to-date */
+	/* Ensure it's initial visibility is up-to-date */
 	nm_settings_connection_recheck_visibility (connection);
 
 	/* Evil openconnect migration hack */
 	openconnect_migrate_hack (NM_CONNECTION (connection));
 
+	g_object_ref (self);
 	/* This one unexports the connection, it needs to run late to give the active
 	 * connection a chance to deal with its reference to this settings connection. */
 	g_signal_connect_after (connection, NM_SETTINGS_CONNECTION_REMOVED,
 	                        G_CALLBACK (connection_removed), self);
 	g_signal_connect (connection, NM_SETTINGS_CONNECTION_UPDATED_INTERNAL,
 	                  G_CALLBACK (connection_updated), self);
-	g_signal_connect (connection, NM_SETTINGS_CONNECTION_FLAGS_CHANGED,
+	g_signal_connect (connection, "notify::" NM_SETTINGS_CONNECTION_FLAGS,
 	                  G_CALLBACK (connection_flags_changed),
 	                  self);
 	if (!priv->startup_complete) {
@@ -996,29 +966,28 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection)
 		                  self);
 	}
 
-	_clear_connections_cached_list (priv);
+	/* Export the connection over D-Bus */
+	g_warn_if_fail (nm_connection_get_path (NM_CONNECTION (connection)) == NULL);
+	path = nm_exported_object_export (NM_EXPORTED_OBJECT (connection));
+	nm_connection_set_path (NM_CONNECTION (connection), path);
 
-	g_object_ref (connection);
-	priv->connections_len++;
-	c_list_link_tail (&priv->connections_lst_head, &connection->_connections_lst);
-
-	path = nm_dbus_object_export (NM_DBUS_OBJECT (connection));
+	g_hash_table_insert (priv->connections,
+	                     (gpointer) nm_connection_get_path (NM_CONNECTION (connection)),
+	                     g_object_ref (connection));
+	g_clear_pointer (&priv->connections_cached_list, g_free);
 
-	nm_utils_log_connection_diff (NM_CONNECTION (connection), NULL, LOGL_DEBUG, LOGD_CORE, "new connection", "++ ",
-	                              path);
+	nm_utils_log_connection_diff (NM_CONNECTION (connection), NULL, LOGL_DEBUG, LOGD_CORE, "new connection", "++ ");
 
 	/* Only emit the individual connection-added signal after connections
 	 * have been initially loaded.
 	 */
 	if (priv->connections_loaded) {
-		nm_dbus_object_emit_signal (NM_DBUS_OBJECT (self),
-		                            &interface_info_settings,
-		                            &signal_info_new_connection,
-		                            "(o)",
-		                            nm_dbus_object_get_path (NM_DBUS_OBJECT (connection)));
-
+		/* Internal added signal */
 		g_signal_emit (self, signals[CONNECTION_ADDED], 0, connection);
 		_notify (self, PROP_CONNECTIONS);
+
+		/* Exported D-Bus signal */
+		g_signal_emit (self, signals[NEW_CONNECTION], 0, connection);
 	}
 
 	nm_settings_connection_added (connection);
@@ -1066,14 +1035,14 @@ nm_settings_add_connection (NMSettings *self,
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
 	GSList *iter;
 	NMSettingsConnection *added = NULL;
-	NMSettingsConnection *candidate = NULL;
-	const char *uuid;
-
-	uuid = nm_connection_get_uuid (connection);
+	GHashTableIter citer;
+	NMConnection *candidate = NULL;
 
 	/* Make sure a connection with this UUID doesn't already exist */
-	c_list_for_each_entry (candidate, &priv->connections_lst_head, _connections_lst) {
-		if (nm_streq0 (uuid, nm_connection_get_uuid (NM_CONNECTION (candidate)))) {
+	g_hash_table_iter_init (&citer, priv->connections);
+	while (g_hash_table_iter_next (&citer, NULL, (gpointer *) &candidate)) {
+		if (g_strcmp0 (nm_connection_get_uuid (connection),
+		               nm_connection_get_uuid (candidate)) == 0) {
 			g_set_error_literal (error,
 			                     NM_SETTINGS_ERROR,
 			                     NM_SETTINGS_ERROR_UUID_EXISTS,
@@ -1130,7 +1099,7 @@ send_agent_owned_secrets (NMSettings *self,
                           NMAuthSubject *subject)
 {
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
-	gs_unref_object NMConnection *for_agent = NULL;
+	NMConnection *for_agent;
 
 	/* Dupe the connection so we can clear out non-agent-owned secrets,
 	 * as agent-owned secrets are the only ones we send back to be saved.
@@ -1141,9 +1110,10 @@ send_agent_owned_secrets (NMSettings *self,
 	                                        secrets_filter_cb,
 	                                        GUINT_TO_POINTER (NM_SETTING_SECRET_FLAG_AGENT_OWNED));
 	nm_agent_manager_save_secrets (priv->agent_mgr,
-	                               nm_dbus_object_get_path (NM_DBUS_OBJECT (connection)),
+	                               nm_connection_get_path (NM_CONNECTION (connection)),
 	                               for_agent,
 	                               subject);
+	g_object_unref (for_agent);
 }
 
 static void
@@ -1200,7 +1170,7 @@ pk_add_cb (NMAuthChain *chain,
 		send_agent_owned_secrets (self, added, subject);
 
 	g_clear_error (&error);
-	nm_auth_chain_destroy (chain);
+	nm_auth_chain_unref (chain);
 }
 
 /* FIXME: remove if/when kernel supports adhoc wpa */
@@ -1248,6 +1218,7 @@ nm_settings_add_connection_dbus (NMSettings *self,
 	NMAuthSubject *subject = NULL;
 	NMAuthChain *chain;
 	GError *error = NULL, *tmp_error = NULL;
+	char *error_desc = NULL;
 	const char *perm;
 
 	g_return_if_fail (connection != NULL);
@@ -1290,12 +1261,18 @@ nm_settings_add_connection_dbus (NMSettings *self,
 		goto done;
 	}
 
-	if (!nm_auth_is_subject_in_acl_set_error (connection,
-	                                          subject,
-	                                          NM_SETTINGS_ERROR,
-	                                          NM_SETTINGS_ERROR_PERMISSION_DENIED,
-	                                          &error))
+	/* Ensure the caller's username exists in the connection's permissions,
+	 * or that the permissions is empty (ie, visible by everyone).
+	 */
+	if (!nm_auth_is_subject_in_acl (connection,
+	                                subject,
+	                                &error_desc)) {
+		error = g_error_new_literal (NM_SETTINGS_ERROR,
+		                             NM_SETTINGS_ERROR_PERMISSION_DENIED,
+		                             error_desc);
+		g_free (error_desc);
 		goto done;
+	}
 
 	/* If the caller is the only user in the connection's permissions, then
 	 * we use the 'modify.own' permission instead of 'modify.system'.  If the
@@ -1335,30 +1312,30 @@ done:
 }
 
 static void
-settings_add_connection_add_cb (NMSettings *self,
-                                NMSettingsConnection *connection,
-                                GError *error,
-                                GDBusMethodInvocation *context,
-                                NMAuthSubject *subject,
-                                gpointer user_data)
+impl_settings_add_connection_add_cb (NMSettings *self,
+                                     NMSettingsConnection *connection,
+                                     GError *error,
+                                     GDBusMethodInvocation *context,
+                                     NMAuthSubject *subject,
+                                     gpointer user_data)
 {
 	if (error) {
 		g_dbus_method_invocation_return_gerror (context, error);
 		nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD, NULL, FALSE, NULL, subject, error->message);
 	} else {
-		g_dbus_method_invocation_return_value (context,
-		                                       g_variant_new ("(o)",
-		                                                      nm_dbus_object_get_path (NM_DBUS_OBJECT (connection))));
+		g_dbus_method_invocation_return_value (
+		    context,
+		    g_variant_new ("(o)", nm_connection_get_path (NM_CONNECTION (connection))));
 		nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD, connection, TRUE, NULL,
 		                            subject, NULL);
 	}
 }
 
 static void
-settings_add_connection_helper (NMSettings *self,
-                                GDBusMethodInvocation *context,
-                                GVariant *settings,
-                                gboolean save_to_disk)
+impl_settings_add_connection_helper (NMSettings *self,
+                                     GDBusMethodInvocation *context,
+                                     GVariant *settings,
+                                     gboolean save_to_disk)
 {
 	gs_unref_object NMConnection *connection = NULL;
 	GError *error = NULL;
@@ -1378,111 +1355,77 @@ settings_add_connection_helper (NMSettings *self,
 	                                 connection,
 	                                 save_to_disk,
 	                                 context,
-	                                 settings_add_connection_add_cb,
+	                                 impl_settings_add_connection_add_cb,
 	                                 NULL);
 }
 
 static void
-impl_settings_add_connection (NMDBusObject *obj,
-                              const NMDBusInterfaceInfoExtended *interface_info,
-                              const NMDBusMethodInfoExtended *method_info,
-                              GDBusConnection *connection,
-                              const char *sender,
-                              GDBusMethodInvocation *invocation,
-                              GVariant *parameters)
+impl_settings_add_connection (NMSettings *self,
+                              GDBusMethodInvocation *context,
+                              GVariant *settings)
 {
-	NMSettings *self = NM_SETTINGS (obj);
-	gs_unref_variant GVariant *settings = NULL;
-
-	g_variant_get (parameters, "(@a{sa{sv}})", &settings);
-	settings_add_connection_helper (self, invocation, settings, TRUE);
+	impl_settings_add_connection_helper (self, context, settings, TRUE);
 }
 
 static void
-impl_settings_add_connection_unsaved (NMDBusObject *obj,
-                                      const NMDBusInterfaceInfoExtended *interface_info,
-                                      const NMDBusMethodInfoExtended *method_info,
-                                      GDBusConnection *connection,
-                                      const char *sender,
-                                      GDBusMethodInvocation *invocation,
-                                      GVariant *parameters)
+impl_settings_add_connection_unsaved (NMSettings *self,
+                                      GDBusMethodInvocation *context,
+                                      GVariant *settings)
 {
-	NMSettings *self = NM_SETTINGS (obj);
-	gs_unref_variant GVariant *settings = NULL;
-
-	g_variant_get (parameters, "(@a{sa{sv}})", &settings);
-	settings_add_connection_helper (self, invocation, settings, FALSE);
+	impl_settings_add_connection_helper (self, context, settings, FALSE);
 }
 
 static void
-impl_settings_load_connections (NMDBusObject *obj,
-                                const NMDBusInterfaceInfoExtended *interface_info,
-                                const NMDBusMethodInfoExtended *method_info,
-                                GDBusConnection *connection,
-                                const char *sender,
-                                GDBusMethodInvocation *invocation,
-                                GVariant *parameters)
+impl_settings_load_connections (NMSettings *self,
+                                GDBusMethodInvocation *context,
+                                char **filenames)
 {
-	NMSettings *self = NM_SETTINGS (obj);
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
-	gs_unref_ptrarray GPtrArray *failures = NULL;
+	GPtrArray *failures;
 	GSList *iter;
-	guint i;
-	gs_free const char **filenames = NULL;
-
-	g_variant_get (parameters, "(^a&s)", &filenames);
+	int i;
 
 	/* The permission is already enforced by the D-Bus daemon, but we ensure
 	 * that the caller is still alive so that clients are forced to wait and
 	 * we'll be able to switch to polkit without breaking behavior.
 	 */
-	if (!nm_dbus_manager_ensure_uid (nm_dbus_object_get_manager (obj),
-	                                 invocation,
-	                                 G_MAXULONG,
-	                                 NM_SETTINGS_ERROR,
-	                                 NM_SETTINGS_ERROR_PERMISSION_DENIED))
+	if (!nm_bus_manager_ensure_uid (nm_bus_manager_get (),
+	                                context,
+	                                G_MAXULONG,
+	                                NM_SETTINGS_ERROR,
+	                                NM_SETTINGS_ERROR_PERMISSION_DENIED))
 		return;
 
-	if (filenames) {
-		for (i = 0; filenames[i]; i++) {
-			for (iter = priv->plugins; iter; iter = g_slist_next (iter)) {
-				NMSettingsPlugin *plugin = NM_SETTINGS_PLUGIN (iter->data);
+	failures = g_ptr_array_new ();
 
-				if (nm_settings_plugin_load_connection (plugin, filenames[i]))
-					break;
-			}
+	for (i = 0; filenames[i]; i++) {
+		for (iter = priv->plugins; iter; iter = g_slist_next (iter)) {
+			NMSettingsPlugin *plugin = NM_SETTINGS_PLUGIN (iter->data);
 
-			if (!iter) {
-				if (!g_path_is_absolute (filenames[i]))
-					_LOGW ("connection filename '%s' is not an absolute path", filenames[i]);
-				if (!failures)
-					failures = g_ptr_array_new ();
-				g_ptr_array_add (failures, (char *) filenames[i]);
-			}
+			if (nm_settings_plugin_load_connection (plugin, filenames[i]))
+				break;
 		}
-	}
 
-	if (failures)
-		g_ptr_array_add (failures, NULL);
+		if (!iter) {
+			if (!g_path_is_absolute (filenames[i]))
+				_LOGW ("connection filename '%s' is not an absolute path", filenames[i]);
+			g_ptr_array_add (failures, (char *) filenames[i]);
+		}
+	}
 
-	g_dbus_method_invocation_return_value (invocation,
-	                                       g_variant_new ("(b^as)",
-	                                                      (gboolean) (!!failures),
-	                                                      failures
-	                                                        ? (const char **) failures->pdata
-	                                                        : NM_PTRARRAY_EMPTY (const char *)));
+	g_ptr_array_add (failures, NULL);
+	g_dbus_method_invocation_return_value (
+		context,
+		g_variant_new ("(b^as)",
+		               failures->len == 1,
+		               failures->pdata));
+	g_ptr_array_unref (failures);
 }
 
 static void
-impl_settings_reload_connections (NMDBusObject *obj,
-                                  const NMDBusInterfaceInfoExtended *interface_info,
-                                  const NMDBusMethodInfoExtended *method_info,
-                                  GDBusConnection *connection,
-                                  const char *sender,
-                                  GDBusMethodInvocation *invocation,
-                                  GVariant *parameters)
+impl_settings_reload_connections (NMSettings *self,
+                                  GDBusMethodInvocation *context)
 {
-	NMSettings *self = NM_SETTINGS (obj);
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
 	GSList *iter;
 
@@ -1490,11 +1433,11 @@ impl_settings_reload_connections (NMDBusObject *obj,
 	 * that the caller is still alive so that clients are forced to wait and
 	 * we'll be able to switch to polkit without breaking behavior.
 	 */
-	if (!nm_dbus_manager_ensure_uid (nm_dbus_object_get_manager (obj),
-	                                 invocation,
-	                                 G_MAXULONG,
-	                                 NM_SETTINGS_ERROR,
-	                                 NM_SETTINGS_ERROR_PERMISSION_DENIED))
+	if (!nm_bus_manager_ensure_uid (nm_bus_manager_get (),
+	                                context,
+	                                G_MAXULONG,
+	                                NM_SETTINGS_ERROR,
+	                                NM_SETTINGS_ERROR_PERMISSION_DENIED))
 		return;
 
 	for (iter = priv->plugins; iter; iter = g_slist_next (iter)) {
@@ -1503,7 +1446,7 @@ impl_settings_reload_connections (NMDBusObject *obj,
 		nm_settings_plugin_reload_connections (plugin);
 	}
 
-	g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
+	g_dbus_method_invocation_return_value (context, g_variant_new ("(b)", TRUE));
 }
 
 /*****************************************************************************/
@@ -1551,46 +1494,41 @@ pk_hostname_cb (NMAuthChain *chain,
 	else
 		g_dbus_method_invocation_return_value (context, NULL);
 
-	nm_auth_chain_destroy (chain);
+	nm_auth_chain_unref (chain);
 }
 
 static void
-impl_settings_save_hostname (NMDBusObject *obj,
-                             const NMDBusInterfaceInfoExtended *interface_info,
-                             const NMDBusMethodInfoExtended *method_info,
-                             GDBusConnection *connection,
-                             const char *sender,
-                             GDBusMethodInvocation *invocation,
-                             GVariant *parameters)
+impl_settings_save_hostname (NMSettings *self,
+                             GDBusMethodInvocation *context,
+                             const char *hostname)
 {
-	NMSettings *self = NM_SETTINGS (obj);
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
 	NMAuthChain *chain;
-	const char *hostname;
-
-	g_variant_get (parameters, "(&s)", &hostname);
+	GError *error = NULL;
 
 	/* Minimal validation of the hostname */
 	if (!nm_hostname_manager_validate_hostname (hostname)) {
-		g_dbus_method_invocation_return_error_literal (invocation,
-		                                               NM_SETTINGS_ERROR,
-		                                               NM_SETTINGS_ERROR_INVALID_HOSTNAME,
-		                                               "The hostname was too long or contained invalid characters.");
-		return;
+		error = g_error_new_literal (NM_SETTINGS_ERROR,
+		                             NM_SETTINGS_ERROR_INVALID_HOSTNAME,
+		                             "The hostname was too long or contained invalid characters.");
+		goto done;
 	}
 
-	chain = nm_auth_chain_new_context (invocation, pk_hostname_cb, self);
+	chain = nm_auth_chain_new_context (context, pk_hostname_cb, self);
 	if (!chain) {
-		g_dbus_method_invocation_return_error_literal (invocation,
-		                                               NM_SETTINGS_ERROR,
-		                                               NM_SETTINGS_ERROR_PERMISSION_DENIED,
-		                                               "Unable to authenticate the request.");
-		return;
+		error = g_error_new_literal (NM_SETTINGS_ERROR,
+		                             NM_SETTINGS_ERROR_PERMISSION_DENIED,
+		                             "Unable to authenticate the request.");
+		goto done;
 	}
 
 	priv->auths = g_slist_append (priv->auths, chain);
 	nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME, TRUE);
 	nm_auth_chain_set_data (chain, "hostname", g_strdup (hostname), g_free);
+
+done:
+	if (error)
+		g_dbus_method_invocation_take_error (context, error);
 }
 
 /*****************************************************************************/
@@ -1599,24 +1537,27 @@ static gboolean
 have_connection_for_device (NMSettings *self, NMDevice *device)
 {
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
+	GHashTableIter iter;
+	gpointer data;
 	NMSettingConnection *s_con;
 	NMSettingWired *s_wired;
 	const char *setting_hwaddr;
 	const char *perm_hw_addr;
-	NMSettingsConnection *connection;
 
 	g_return_val_if_fail (NM_IS_SETTINGS (self), FALSE);
 
 	perm_hw_addr = nm_device_get_permanent_hw_address (device);
 
 	/* Find a wired connection locked to the given MAC address, if any */
-	c_list_for_each_entry (connection, &priv->connections_lst_head, _connections_lst) {
+	g_hash_table_iter_init (&iter, priv->connections);
+	while (g_hash_table_iter_next (&iter, NULL, &data)) {
+		NMConnection *connection = NM_CONNECTION (data);
 		const char *ctype, *iface;
 
-		if (!nm_device_check_connection_compatible (device, NM_CONNECTION (connection)))
+		if (!nm_device_check_connection_compatible (device, connection))
 			continue;
 
-		s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection));
+		s_con = nm_connection_get_setting_connection (connection);
 
 		iface = nm_setting_connection_get_interface_name (s_con);
 		if (iface && strcmp (iface, nm_device_get_iface (device)) != 0)
@@ -1627,7 +1568,7 @@ have_connection_for_device (NMSettings *self, NMDevice *device)
 		    && strcmp (ctype, NM_SETTING_PPPOE_SETTING_NAME))
 			continue;
 
-		s_wired = nm_connection_get_setting_wired (NM_CONNECTION (connection));
+		s_wired = nm_connection_get_setting_wired (connection);
 
 		if (!s_wired && !strcmp (ctype, NM_SETTING_PPPOE_SETTING_NAME)) {
 			/* No wired setting; therefore the PPPoE connection applies to any device */
@@ -1655,6 +1596,26 @@ have_connection_for_device (NMSettings *self, NMDevice *device)
 	return FALSE;
 }
 
+static void default_wired_clear_tag (NMSettings *self,
+                                     NMDevice *device,
+                                     NMSettingsConnection *connection,
+                                     gboolean add_to_no_auto_default);
+
+static void
+default_wired_connection_removed_cb (NMSettingsConnection *connection, NMSettings *self)
+{
+	NMDevice *device;
+
+	/* When the default wired connection is removed (either deleted or saved to
+	 * a new persistent connection by a plugin), write the MAC address of the
+	 * wired device to the config file and don't create a new default wired
+	 * connection for that device again.
+	 */
+	device = g_object_get_qdata (G_OBJECT (connection), _default_wired_device_quark ());
+	if (device)
+		default_wired_clear_tag (self, device, connection, TRUE);
+}
+
 static void
 default_wired_connection_updated_by_user_cb (NMSettingsConnection *connection, gboolean by_user, NMSettings *self)
 {
@@ -1687,6 +1648,7 @@ default_wired_clear_tag (NMSettings *self,
 	g_object_set_qdata (G_OBJECT (connection), _default_wired_device_quark (), NULL);
 	g_object_set_qdata (G_OBJECT (device), _default_wired_connection_quark (), NULL);
 
+	g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (default_wired_connection_removed_cb), self);
 	g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (default_wired_connection_updated_by_user_cb), self);
 
 	if (add_to_no_auto_default)
@@ -1738,6 +1700,8 @@ device_realized (NMDevice *device, GParamSpec *pspec, NMSettings *self)
 
 	g_signal_connect (added, NM_SETTINGS_CONNECTION_UPDATED_INTERNAL,
 	                  G_CALLBACK (default_wired_connection_updated_by_user_cb), self);
+	g_signal_connect (added, NM_SETTINGS_CONNECTION_REMOVED,
+	                  G_CALLBACK (default_wired_connection_removed_cb), self);
 
 	_LOGI ("(%s): created default wired connection '%s'",
 	       nm_device_get_iface (device),
@@ -1810,8 +1774,10 @@ nm_settings_start (NMSettings *self, GError **error)
 	/* Load the plugins; fail if a plugin is not found. */
 	plugins = nm_config_data_get_plugins (nm_config_get_data_orig (priv->config), TRUE);
 
-	if (!load_plugins (self, (const char **) plugins, error))
+	if (!load_plugins (self, (const char **) plugins, error)) {
+		g_object_unref (self);
 		return FALSE;
+	}
 
 	load_connections (self);
 	check_startup_complete (self);
@@ -1836,19 +1802,18 @@ get_property (GObject *object, guint prop_id,
 	NMSettings *self = NM_SETTINGS (object);
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
 	const GSList *specs, *iter;
-	guint i;
-	char **strvs;
-	const char **strv;
+	GHashTableIter citer;
+	GPtrArray *array;
+	const char *path;
 
 	switch (prop_id) {
 	case PROP_UNMANAGED_SPECS:
+		array = g_ptr_array_new ();
 		specs = nm_settings_get_unmanaged_specs (self);
-		strvs = g_new (char *, g_slist_length ((GSList *) specs) + 1);
-		i = 0;
-		for (iter = specs; iter; iter = iter->next)
-			strvs[i++] = g_strdup (iter->data);
-		strvs[i] = NULL;
-		g_value_take_boxed (value, strvs);
+		for (iter = specs; iter; iter = g_slist_next (iter))
+			g_ptr_array_add (array, g_strdup (iter->data));
+		g_ptr_array_add (array, NULL);
+		g_value_take_boxed (value, (char **) g_ptr_array_free (array, FALSE));
 		break;
 	case PROP_HOSTNAME:
 		g_value_set_string (value,
@@ -1860,14 +1825,12 @@ get_property (GObject *object, guint prop_id,
 		g_value_set_boolean (value, !!get_plugin (self, NM_SETTINGS_PLUGIN_CAP_MODIFY_CONNECTIONS));
 		break;
 	case PROP_CONNECTIONS:
-		if (priv->connections_loaded) {
-			strv = nm_dbus_utils_get_paths_for_clist (&priv->connections_lst_head,
-			                                          priv->connections_len,
-			                                          G_STRUCT_OFFSET (NMSettingsConnection, _connections_lst),
-			                                          TRUE);
-			g_value_take_boxed (value, nm_utils_strv_make_deep_copied (strv));
-		} else
-			g_value_set_boxed (value, NULL);
+		array = g_ptr_array_sized_new (g_hash_table_size (priv->connections) + 1);
+		g_hash_table_iter_init (&citer, priv->connections);
+		while (g_hash_table_iter_next (&citer, (gpointer) &path, NULL))
+			g_ptr_array_add (array, g_strdup (path));
+		g_ptr_array_add (array, NULL);
+		g_value_take_boxed (value, (char **) g_ptr_array_free (array, FALSE));
 		break;
 	case PROP_STARTUP_COMPLETE:
 		g_value_set_boolean (value, nm_settings_get_startup_complete (self));
@@ -1885,7 +1848,7 @@ nm_settings_init (NMSettings *self)
 {
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
 
-	c_list_init (&priv->connections_lst_head);
+	priv->connections = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, g_object_unref);
 
 	priv->agent_mgr = g_object_ref (nm_agent_manager_get ());
 	priv->config = g_object_ref (nm_config_get ());
@@ -1903,9 +1866,11 @@ dispose (GObject *object)
 	NMSettings *self = NM_SETTINGS (object);
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
 
-	g_slist_free_full (priv->auths, (GDestroyNotify) nm_auth_chain_destroy);
+	g_slist_free_full (priv->auths, (GDestroyNotify) nm_auth_chain_unref);
 	priv->auths = NULL;
 
+	g_object_unref (priv->agent_mgr);
+
 	if (priv->hostname_manager) {
 		g_signal_handlers_disconnect_by_func (priv->hostname_manager,
 		                                      G_CALLBACK (_hostname_changed_cb),
@@ -1922,139 +1887,26 @@ finalize (GObject *object)
 	NMSettings *self = NM_SETTINGS (object);
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
 
-	_clear_connections_cached_list (priv);
-
-	nm_assert (c_list_is_empty (&priv->connections_lst_head));
+	g_hash_table_destroy (priv->connections);
+	g_clear_pointer (&priv->connections_cached_list, g_free);
 
 	g_slist_free_full (priv->unmanaged_specs, g_free);
 	g_slist_free_full (priv->unrecognized_specs, g_free);
 
 	g_slist_free_full (priv->plugins, g_object_unref);
 
-	g_clear_object (&priv->agent_mgr);
-
 	g_clear_object (&priv->config);
 
 	G_OBJECT_CLASS (nm_settings_parent_class)->finalize (object);
 }
 
-static const GDBusSignalInfo signal_info_new_connection = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT (
-	"NewConnection",
-	.args = NM_DEFINE_GDBUS_ARG_INFOS (
-		NM_DEFINE_GDBUS_ARG_INFO ("connection", "o"),
-	),
-);
-
-static const GDBusSignalInfo signal_info_connection_removed = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT (
-	"ConnectionRemoved",
-	.args = NM_DEFINE_GDBUS_ARG_INFOS (
-		NM_DEFINE_GDBUS_ARG_INFO ("connection", "o"),
-	),
-);
-
-static const NMDBusInterfaceInfoExtended interface_info_settings = {
-	.parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT (
-		NM_DBUS_INTERFACE_SETTINGS,
-		.methods = NM_DEFINE_GDBUS_METHOD_INFOS (
-			NM_DEFINE_DBUS_METHOD_INFO_EXTENDED (
-				NM_DEFINE_GDBUS_METHOD_INFO_INIT (
-					"ListConnections",
-					.out_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("connections", "ao"),
-					),
-				),
-				.handle = impl_settings_list_connections,
-			),
-			NM_DEFINE_DBUS_METHOD_INFO_EXTENDED (
-				NM_DEFINE_GDBUS_METHOD_INFO_INIT (
-					"GetConnectionByUuid",
-					.in_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("uuid", "s"),
-					),
-					.out_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("connection", "o"),
-					),
-				),
-				.handle = impl_settings_get_connection_by_uuid,
-			),
-			NM_DEFINE_DBUS_METHOD_INFO_EXTENDED (
-				NM_DEFINE_GDBUS_METHOD_INFO_INIT (
-					"AddConnection",
-					.in_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("connection", "a{sa{sv}}"),
-					),
-					.out_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("path", "o"),
-					),
-				),
-				.handle = impl_settings_add_connection,
-			),
-			NM_DEFINE_DBUS_METHOD_INFO_EXTENDED (
-				NM_DEFINE_GDBUS_METHOD_INFO_INIT (
-					"AddConnectionUnsaved",
-					.in_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("connection", "a{sa{sv}}"),
-					),
-					.out_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("path", "o"),
-					),
-				),
-				.handle = impl_settings_add_connection_unsaved,
-			),
-			NM_DEFINE_DBUS_METHOD_INFO_EXTENDED (
-				NM_DEFINE_GDBUS_METHOD_INFO_INIT (
-					"LoadConnections",
-					.in_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("filenames", "as"),
-					),
-					.out_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("status", "b"),
-						NM_DEFINE_GDBUS_ARG_INFO ("failures", "as"),
-					),
-				),
-				.handle = impl_settings_load_connections,
-			),
-			NM_DEFINE_DBUS_METHOD_INFO_EXTENDED (
-				NM_DEFINE_GDBUS_METHOD_INFO_INIT (
-					"ReloadConnections",
-					.out_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("status", "b"),
-					),
-				),
-				.handle = impl_settings_reload_connections,
-			),
-			NM_DEFINE_DBUS_METHOD_INFO_EXTENDED (
-				NM_DEFINE_GDBUS_METHOD_INFO_INIT (
-					"SaveHostname",
-					.in_args = NM_DEFINE_GDBUS_ARG_INFOS (
-						NM_DEFINE_GDBUS_ARG_INFO ("hostname", "s"),
-					),
-				),
-				.handle = impl_settings_save_hostname,
-			),
-		),
-		.signals = NM_DEFINE_GDBUS_SIGNAL_INFOS (
-			&nm_signal_info_property_changed_legacy,
-			&signal_info_new_connection,
-			&signal_info_connection_removed,
-		),
-		.properties = NM_DEFINE_GDBUS_PROPERTY_INFOS (
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Connections", "ao", NM_SETTINGS_CONNECTIONS),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Hostname",    "s",  NM_SETTINGS_HOSTNAME),
-			NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("CanModify",   "b",  NM_SETTINGS_CAN_MODIFY),
-		),
-	),
-	.legacy_property_changed = TRUE,
-};
-
 static void
 nm_settings_class_init (NMSettingsClass *class)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (class);
-	NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (class);
+	NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (class);
 
-	dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_STATIC (NM_DBUS_PATH_SETTINGS);
-	dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_settings);
+	exported_object_class->export_path = NM_DBUS_PATH_SETTINGS;
 
 	object_class->get_property = get_property;
 	object_class->dispose = dispose;
@@ -2123,4 +1975,23 @@ nm_settings_class_init (NMSettingsClass *class)
 	                  0, NULL, NULL,
 	                  g_cclosure_marshal_VOID__OBJECT,
 	                  G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION);
+
+	signals[NEW_CONNECTION] =
+	    g_signal_new ("new-connection",
+	                  G_OBJECT_CLASS_TYPE (object_class),
+	                  G_SIGNAL_RUN_FIRST, 0, NULL, NULL,
+	                  g_cclosure_marshal_VOID__OBJECT,
+	                  G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION);
+
+	nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (class),
+	                                        NMDBUS_TYPE_SETTINGS_SKELETON,
+	                                        "ListConnections", impl_settings_list_connections,
+	                                        "GetConnectionByUuid", impl_settings_get_connection_by_uuid,
+	                                        "AddConnection", impl_settings_add_connection,
+	                                        "AddConnectionUnsaved", impl_settings_add_connection_unsaved,
+	                                        "LoadConnections", impl_settings_load_connections,
+	                                        "ReloadConnections", impl_settings_reload_connections,
+	                                        "SaveHostname", impl_settings_save_hostname,
+	                                        NULL);
 }
+