summary refs log tree commit diff
path: root/src/settings/nm-settings.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2016-01-20 16:26:51 +0100
committerMichael Biebl <biebl@debian.org>2016-01-20 16:26:51 +0100
commit494f296a3baab08522617b24b1f126d8f9a17502 (patch)
treec8ef32fb0dd1c4ff35a0b38e787abb58692de0cd /src/settings/nm-settings.c
parent54f6333410ffd570e62717d9e77c5c987175e397 (diff)
Imported Upstream version 1.1.90 upstream/1.1.90
Diffstat (limited to 'src/settings/nm-settings.c')
-rw-r--r--src/settings/nm-settings.c1017
1 files changed, 661 insertions, 356 deletions
diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c
index f20bc71b..f6f8c374 100644
--- a/src/settings/nm-settings.c
+++ b/src/settings/nm-settings.c
@@ -31,10 +31,11 @@
 #include <string.h>
 #include <gmodule.h>
 #include <pwd.h>
-#include <dbus/dbus.h>
-#include <dbus/dbus-glib-lowlevel.h>
 
-#include "gsystem-local-alloc.h"
+#if HAVE_SELINUX
+#include <selinux/selinux.h>
+#endif
+
 #include <nm-dbus-interface.h>
 #include <nm-connection.h>
 #include <nm-setting-8021x.h>
@@ -58,12 +59,11 @@
 #include "nm-core-internal.h"
 
 #include "nm-device-ethernet.h"
-#include "nm-dbus-glib-types.h"
 #include "nm-settings.h"
 #include "nm-settings-connection.h"
-#include "nm-system-config-interface.h"
-#include "nm-logging.h"
-#include "nm-dbus-manager.h"
+#include "nm-settings-plugin.h"
+#include "nm-default.h"
+#include "nm-bus-manager.h"
 #include "nm-auth-utils.h"
 #include "nm-auth-subject.h"
 #include "nm-session-monitor.h"
@@ -71,7 +71,11 @@
 #include "nm-agent-manager.h"
 #include "nm-connection-provider.h"
 #include "nm-config.h"
+#include "nm-audit-manager.h"
 #include "NetworkManagerUtils.h"
+#include "nm-dispatcher.h"
+
+#include "nmdbus-settings.h"
 
 #define LOG(level, ...) \
 	G_STMT_START { \
@@ -94,52 +98,39 @@ EXPORT(nm_settings_connection_replace_settings)
 EXPORT(nm_settings_connection_replace_and_commit)
 /* END LINKER CRACKROCK */
 
-#define PLUGIN_MODULE_PATH      "plugin-module-path"
-
-static void claim_connection (NMSettings *self,
-                              NMSettingsConnection *connection);
-
-static gboolean impl_settings_list_connections (NMSettings *self,
-                                                GPtrArray **connections,
-                                                GError **error);
-
-static void impl_settings_get_connection_by_uuid (NMSettings *self,
-                                                  const char *uuid,
-                                                  DBusGMethodInvocation *context);
+#define HOSTNAMED_SERVICE_NAME      "org.freedesktop.hostname1"
+#define HOSTNAMED_SERVICE_PATH      "/org/freedesktop/hostname1"
+#define HOSTNAMED_SERVICE_INTERFACE "org.freedesktop.hostname1"
 
-static void impl_settings_add_connection (NMSettings *self,
-                                          GHashTable *settings,
-                                          DBusGMethodInvocation *context);
+#define HOSTNAME_FILE_DEFAULT   "/etc/hostname"
+#define HOSTNAME_FILE_SUSE      "/etc/HOSTNAME"
+#define HOSTNAME_FILE_GENTOO    "/etc/conf.d/hostname"
+#define IFCFG_DIR               SYSCONFDIR "/sysconfig/network"
+#define CONF_DHCP               IFCFG_DIR "/dhcp"
 
-static void impl_settings_add_connection_unsaved (NMSettings *self,
-                                                  GHashTable *settings,
-                                                  DBusGMethodInvocation *context);
-
-static void impl_settings_load_connections (NMSettings *self,
-                                            char **filenames,
-                                            DBusGMethodInvocation *context);
-
-static void impl_settings_reload_connections (NMSettings *self,
-                                              DBusGMethodInvocation *context);
+#define PLUGIN_MODULE_PATH      "plugin-module-path"
 
-static void impl_settings_save_hostname (NMSettings *self,
-                                         const char *hostname,
-                                         DBusGMethodInvocation *context);
+#if defined(HOSTNAME_PERSIST_SUSE)
+#define HOSTNAME_FILE           HOSTNAME_FILE_SUSE
+#elif defined(HOSTNAME_PERSIST_GENTOO)
+#define HOSTNAME_FILE           HOSTNAME_FILE_GENTOO
+#else
+#define HOSTNAME_FILE           HOSTNAME_FILE_DEFAULT
+#endif
 
-#include "nm-settings-glue.h"
+static void claim_connection (NMSettings *self,
+                              NMSettingsConnection *connection);
 
-static void unmanaged_specs_changed (NMSystemConfigInterface *config, gpointer user_data);
-static void unrecognized_specs_changed (NMSystemConfigInterface *config, gpointer user_data);
+static void unmanaged_specs_changed (NMSettingsPlugin *config, gpointer user_data);
+static void unrecognized_specs_changed (NMSettingsPlugin *config, gpointer user_data);
 
-static void connection_provider_init (NMConnectionProvider *cp_class);
+static void connection_provider_iface_init (NMConnectionProviderInterface *cp_iface);
 
-G_DEFINE_TYPE_EXTENDED (NMSettings, nm_settings, G_TYPE_OBJECT, 0,
-                        G_IMPLEMENT_INTERFACE (NM_TYPE_CONNECTION_PROVIDER, connection_provider_init))
+G_DEFINE_TYPE_EXTENDED (NMSettings, nm_settings, NM_TYPE_EXPORTED_OBJECT, 0,
+                        G_IMPLEMENT_INTERFACE (NM_TYPE_CONNECTION_PROVIDER, connection_provider_iface_init))
 
 
 typedef struct {
-	NMDBusManager *dbus_mgr;
-
 	NMAgentManager *agent_mgr;
 
 	NMConfig *config;
@@ -153,13 +144,23 @@ typedef struct {
 	GSList *unrecognized_specs;
 	GSList *get_connections_cache;
 
+	gboolean started;
 	gboolean startup_complete;
+
+	struct {
+		char *value;
+		char *file;
+		GFileMonitor *monitor;
+		GFileMonitor *dhcp_monitor;
+		gulong monitor_id;
+		gulong dhcp_monitor_id;
+		GDBusProxy *hostnamed_proxy;
+	} hostname;
 } NMSettingsPrivate;
 
 #define NM_SETTINGS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTINGS, NMSettingsPrivate))
 
 enum {
-	PROPERTIES_CHANGED,
 	CONNECTION_ADDED,
 	CONNECTION_UPDATED,
 	CONNECTION_UPDATED_BY_USER,
@@ -215,7 +216,7 @@ connection_ready_changed (NMSettingsConnection *conn,
 }
 
 static void
-plugin_connection_added (NMSystemConfigInterface *config,
+plugin_connection_added (NMSettingsPlugin *config,
                          NMSettingsConnection *connection,
                          gpointer user_data)
 {
@@ -229,11 +230,11 @@ load_connections (NMSettings *self)
 	GSList *iter;
 
 	for (iter = priv->plugins; iter; iter = g_slist_next (iter)) {
-		NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (iter->data);
+		NMSettingsPlugin *plugin = NM_SETTINGS_PLUGIN (iter->data);
 		GSList *plugin_connections;
 		GSList *elt;
 
-		plugin_connections = nm_system_config_interface_get_connections (plugin);
+		plugin_connections = nm_settings_plugin_get_connections (plugin);
 
 		// FIXME: ensure connections from plugins loaded with a lower priority
 		// get rejected when they conflict with connections from a higher
@@ -244,11 +245,11 @@ load_connections (NMSettings *self)
 
 		g_slist_free (plugin_connections);
 
-		g_signal_connect (plugin, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED,
+		g_signal_connect (plugin, NM_SETTINGS_PLUGIN_CONNECTION_ADDED,
 		                  G_CALLBACK (plugin_connection_added), self);
-		g_signal_connect (plugin, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED,
+		g_signal_connect (plugin, NM_SETTINGS_PLUGIN_UNMANAGED_SPECS_CHANGED,
 		                  G_CALLBACK (unmanaged_specs_changed), self);
-		g_signal_connect (plugin, NM_SYSTEM_CONFIG_INTERFACE_UNRECOGNIZED_SPECS_CHANGED,
+		g_signal_connect (plugin, NM_SETTINGS_PLUGIN_UNRECOGNIZED_SPECS_CHANGED,
 		                  G_CALLBACK (unrecognized_specs_changed), self);
 	}
 
@@ -277,20 +278,24 @@ nm_settings_for_each_connection (NMSettings *self,
 		for_each_func (self, NM_SETTINGS_CONNECTION (data), user_data);
 }
 
-static gboolean
+static void
 impl_settings_list_connections (NMSettings *self,
-                                GPtrArray **connections,
-                                GError **error)
+                                GDBusMethodInvocation *context)
 {
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
+	GPtrArray *connections;
 	GHashTableIter iter;
 	gpointer key;
 
-	*connections = g_ptr_array_sized_new (g_hash_table_size (priv->connections) + 1);
+	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, g_strdup ((const char *) key));
-	return TRUE;
+		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 *
@@ -307,7 +312,7 @@ nm_settings_get_connection_by_uuid (NMSettings *self, const char *uuid)
 
 	g_hash_table_iter_init (&iter, priv->connections);
 	while (g_hash_table_iter_next (&iter, NULL, (gpointer) &candidate)) {
-		if (g_strcmp0 (uuid, nm_connection_get_uuid (NM_CONNECTION (candidate))) == 0)
+		if (g_strcmp0 (uuid, nm_settings_connection_get_uuid (candidate)) == 0)
 			return candidate;
 	}
 
@@ -316,8 +321,8 @@ nm_settings_get_connection_by_uuid (NMSettings *self, const char *uuid)
 
 static void
 impl_settings_get_connection_by_uuid (NMSettings *self,
-                                      const char *uuid,
-                                      DBusGMethodInvocation *context)
+                                      GDBusMethodInvocation *context,
+                                      const char *uuid)
 {
 	NMSettingsConnection *connection = NULL;
 	NMAuthSubject *subject = NULL;
@@ -341,7 +346,6 @@ impl_settings_get_connection_by_uuid (NMSettings *self,
 	}
 
 	if (!nm_auth_is_subject_in_acl (NM_CONNECTION (connection),
-	                                nm_session_monitor_get (),
 	                                subject,
 	                                &error_desc)) {
 		error = g_error_new_literal (NM_SETTINGS_ERROR,
@@ -352,13 +356,14 @@ impl_settings_get_connection_by_uuid (NMSettings *self,
 	}
 
 	g_clear_object (&subject);
-	dbus_g_method_return (context, nm_connection_get_path (NM_CONNECTION (connection)));
+	g_dbus_method_invocation_return_value (
+		context,
+		g_variant_new ("(o)", nm_connection_get_path (NM_CONNECTION (connection))));
 	return;
 
 error:
 	g_assert (error);
-	dbus_g_method_return_error (context, error);
-	g_error_free (error);
+	g_dbus_method_invocation_take_error (context, error);
 	g_clear_object (&subject);
 }
 
@@ -424,53 +429,8 @@ nm_settings_get_connection_by_path (NMSettings *self, const char *path)
 	return (NMSettingsConnection *) g_hash_table_lookup (priv->connections, path);
 }
 
-static char*
-uscore_to_wincaps (const char *uscore)
-{
-	const char *p;
-	GString *str;
-	gboolean last_was_uscore;
-
-	last_was_uscore = TRUE;
-  
-	str = g_string_new (NULL);
-	p = uscore;
-	while (p && *p) {
-		if (*p == '-' || *p == '_')
-			last_was_uscore = TRUE;
-		else {
-			if (last_was_uscore) {
-				g_string_append_c (str, g_ascii_toupper (*p));
-				last_was_uscore = FALSE;
-			} else
-				g_string_append_c (str, *p);
-		}
-		++p;
-	}
-
-	return g_string_free (str, FALSE);
-}
-
-static void
-notify (GObject *object, GParamSpec *pspec)
-{
-	GValue *value;
-	GHashTable *hash;
-
-	value = g_slice_new0 (GValue);
-	hash = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL);
-
-	g_value_init (value, pspec->value_type);
-	g_object_get_property (object, pspec->name, value);
-	g_hash_table_insert (hash, uscore_to_wincaps (pspec->name), value);
-	g_signal_emit (object, signals[PROPERTIES_CHANGED], 0, hash);
-	g_hash_table_destroy (hash);
-	g_value_unset (value);
-	g_slice_free (GValue, value);
-}
-
 gboolean
-nm_settings_has_connection (NMSettings *self, NMConnection *connection)
+nm_settings_has_connection (NMSettings *self, NMSettingsConnection *connection)
 {
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
 	GHashTableIter iter;
@@ -492,7 +452,7 @@ nm_settings_get_unmanaged_specs (NMSettings *self)
 	return priv->unmanaged_specs;
 }
 
-static NMSystemConfigInterface *
+static NMSettingsPlugin *
 get_plugin (NMSettings *self, guint32 capability)
 {
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
@@ -500,42 +460,109 @@ get_plugin (NMSettings *self, guint32 capability)
 
 	g_return_val_if_fail (self != NULL, NULL);
 
-	/* Do any of the plugins support setting the hostname? */
+	/* Do any of the plugins support the given capability? */
 	for (iter = priv->plugins; iter; iter = iter->next) {
-		NMSystemConfigInterfaceCapabilities caps = NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE;
+		NMSettingsPluginCapabilities caps = NM_SETTINGS_PLUGIN_CAP_NONE;
 
-		g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES, &caps, NULL);
+		g_object_get (G_OBJECT (iter->data), NM_SETTINGS_PLUGIN_CAPABILITIES, &caps, NULL);
 		if (NM_FLAGS_ALL (caps, capability))
-			return NM_SYSTEM_CONFIG_INTERFACE (iter->data);
+			return NM_SETTINGS_PLUGIN (iter->data);
 	}
 
 	return NULL;
 }
 
+#if defined(HOSTNAME_PERSIST_GENTOO)
+static gchar *
+read_hostname_gentoo (const char *path)
+{
+	gchar *contents = NULL, *result = NULL, *tmp;
+	gchar **all_lines = NULL;
+	guint line_num, i;
+
+	if (!g_file_get_contents (path, &contents, NULL, NULL))
+		return NULL;
+	all_lines = g_strsplit (contents, "\n", 0);
+	line_num = g_strv_length (all_lines);
+	for (i = 0; i < line_num; i++) {
+		g_strstrip (all_lines[i]);
+		if (all_lines[i][0] == '#' || all_lines[i][0] == '\0')
+			continue;
+		if (g_str_has_prefix (all_lines[i], "hostname=")) {
+			tmp = &all_lines[i][STRLEN ("hostname=")];
+			result = g_shell_unquote (tmp, NULL);
+			break;
+		}
+	}
+	g_strfreev (all_lines);
+	g_free (contents);
+	return result;
+}
+#endif
+
+#if defined(HOSTNAME_PERSIST_SUSE)
+static gboolean
+hostname_is_dynamic (void)
+{
+	GIOChannel *channel;
+	char *str = NULL;
+	gboolean dynamic = FALSE;
+
+	channel = g_io_channel_new_file (CONF_DHCP, "r", NULL);
+	if (!channel)
+		return dynamic;
+
+	while (g_io_channel_read_line (channel, &str, NULL, NULL, NULL) != G_IO_STATUS_EOF) {
+		if (str) {
+			g_strstrip (str);
+			if (g_str_has_prefix (str, "DHCLIENT_SET_HOSTNAME="))
+				dynamic = strcmp (&str[STRLEN ("DHCLIENT_SET_HOSTNAME=")], "\"yes\"") == 0;
+			g_free (str);
+		}
+	}
+
+	g_io_channel_shutdown (channel, FALSE, NULL);
+	g_io_channel_unref (channel);
+
+	return dynamic;
+}
+#endif
+
 /* Returns an allocated string which the caller owns and must eventually free */
 char *
 nm_settings_get_hostname (NMSettings *self)
 {
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
-	GSList *iter;
 	char *hostname = NULL;
 
-	/* Hostname returned is the hostname returned from the first plugin
-	 * that provides one.
-	 */
-	for (iter = priv->plugins; iter; iter = iter->next) {
-		NMSystemConfigInterfaceCapabilities caps = NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE;
-
-		g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES, &caps, NULL);
-		if (caps & NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME) {
-			g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME, &hostname, NULL);
-			if (hostname && strlen (hostname))
-				return hostname;
-			g_free (hostname);
-		}
+	if (!priv->started)
+		return NULL;
+
+	if (priv->hostname.hostnamed_proxy) {
+		hostname = g_strdup (priv->hostname.value);
+		goto out;
 	}
 
-	return NULL;
+#if defined(HOSTNAME_PERSIST_GENTOO)
+	hostname = read_hostname_gentoo (priv->hostname.file);
+#else
+
+#if defined(HOSTNAME_PERSIST_SUSE)
+	if (priv->hostname.dhcp_monitor_id && hostname_is_dynamic ())
+		return NULL;
+#endif
+	if (g_file_get_contents (priv->hostname.file, &hostname, NULL, NULL))
+		g_strchomp (hostname);
+
+#endif /* HOSTNAME_PERSIST_GENTOO */
+
+out:
+	if (hostname && !hostname[0]) {
+		g_free (hostname);
+		hostname = NULL;
+	}
+
+	return hostname;
 }
 
 static gboolean
@@ -552,7 +579,7 @@ find_spec (GSList *spec_list, const char *spec)
 
 static void
 update_specs (NMSettings *self, GSList **specs_ptr,
-              GSList * (*get_specs_func) (NMSystemConfigInterface *))
+              GSList * (*get_specs_func) (NMSettingsPlugin *))
 {
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
 	GSList *iter;
@@ -563,7 +590,7 @@ update_specs (NMSettings *self, GSList **specs_ptr,
 	for (iter = priv->plugins; iter; iter = g_slist_next (iter)) {
 		GSList *specs, *specs_iter;
 
-		specs = get_specs_func (NM_SYSTEM_CONFIG_INTERFACE (iter->data));
+		specs = get_specs_func (NM_SETTINGS_PLUGIN (iter->data));
 		for (specs_iter = specs; specs_iter; specs_iter = specs_iter->next) {
 			if (!find_spec (*specs_ptr, (const char *) specs_iter->data)) {
 				*specs_ptr = g_slist_prepend (*specs_ptr, specs_iter->data);
@@ -576,58 +603,52 @@ update_specs (NMSettings *self, GSList **specs_ptr,
 }
 
 static void
-unmanaged_specs_changed (NMSystemConfigInterface *config,
+unmanaged_specs_changed (NMSettingsPlugin *config,
                          gpointer user_data)
 {
 	NMSettings *self = NM_SETTINGS (user_data);
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
 
 	update_specs (self, &priv->unmanaged_specs,
-	              nm_system_config_interface_get_unmanaged_specs);
+	              nm_settings_plugin_get_unmanaged_specs);
 	g_object_notify (G_OBJECT (self), NM_SETTINGS_UNMANAGED_SPECS);
 }
 
 static void
-unrecognized_specs_changed (NMSystemConfigInterface *config,
+unrecognized_specs_changed (NMSettingsPlugin *config,
                                gpointer user_data)
 {
 	NMSettings *self = NM_SETTINGS (user_data);
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
 
 	update_specs (self, &priv->unrecognized_specs,
-	              nm_system_config_interface_get_unrecognized_specs);
-}
-
-static void
-hostname_changed (NMSystemConfigInterface *config,
-                  GParamSpec *pspec,
-                  gpointer user_data)
-{
-	g_object_notify (G_OBJECT (user_data), NM_SETTINGS_HOSTNAME);
+	              nm_settings_plugin_get_unrecognized_specs);
 }
 
-static void
-add_plugin (NMSettings *self, NMSystemConfigInterface *plugin)
+static gboolean
+add_plugin (NMSettings *self, NMSettingsPlugin *plugin)
 {
 	NMSettingsPrivate *priv;
 	char *pname = NULL;
 	char *pinfo = NULL;
 	const char *path;
 
-	g_return_if_fail (NM_IS_SETTINGS (self));
-	g_return_if_fail (NM_IS_SYSTEM_CONFIG_INTERFACE (plugin));
+	g_return_val_if_fail (NM_IS_SETTINGS (self), FALSE);
+	g_return_val_if_fail (NM_IS_SETTINGS_PLUGIN (plugin), FALSE);
 
 	priv = NM_SETTINGS_GET_PRIVATE (self);
 
-	priv->plugins = g_slist_append (priv->plugins, g_object_ref (plugin));
-
-	g_signal_connect (plugin, "notify::hostname", G_CALLBACK (hostname_changed), self);
+	if (g_slist_find (priv->plugins, plugin)) {
+		/* don't add duplicates. */
+		return FALSE;
+	}
 
-	nm_system_config_interface_init (plugin, NULL);
+	priv->plugins = g_slist_append (priv->plugins, g_object_ref (plugin));
+	nm_settings_plugin_init (plugin);
 
 	g_object_get (G_OBJECT (plugin),
-	              NM_SYSTEM_CONFIG_INTERFACE_NAME, &pname,
-	              NM_SYSTEM_CONFIG_INTERFACE_INFO, &pinfo,
+	              NM_SETTINGS_PLUGIN_NAME, &pname,
+	              NM_SETTINGS_PLUGIN_INFO, &pinfo,
 	              NULL);
 
 	path = g_object_get_data (G_OBJECT (plugin), PLUGIN_MODULE_PATH);
@@ -636,6 +657,8 @@ add_plugin (NMSettings *self, NMSystemConfigInterface *plugin)
 	             NM_PRINT_FMT_QUOTED (path, " (", path, ")", ""));
 	g_free (pname);
 	g_free (pinfo);
+
+	return TRUE;
 }
 
 static GObject *
@@ -647,11 +670,11 @@ find_plugin (GSList *list, const char *pname)
 	g_return_val_if_fail (pname != NULL, NULL);
 
 	for (iter = list; iter && !obj; iter = g_slist_next (iter)) {
-		NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (iter->data);
+		NMSettingsPlugin *plugin = NM_SETTINGS_PLUGIN (iter->data);
 		char *list_pname = NULL;
 
 		g_object_get (G_OBJECT (plugin),
-		              NM_SYSTEM_CONFIG_INTERFACE_NAME,
+		              NM_SETTINGS_PLUGIN_NAME,
 		              &list_pname,
 		              NULL);
 		if (list_pname && !strcmp (pname, list_pname))
@@ -666,11 +689,12 @@ find_plugin (GSList *list, const char *pname)
 static void
 add_keyfile_plugin (NMSettings *self)
 {
-	GObject *keyfile_plugin;
+	gs_unref_object GObject *keyfile_plugin = NULL;
 
 	keyfile_plugin = nm_settings_keyfile_plugin_new ();
 	g_assert (keyfile_plugin);
-	add_plugin (self, NM_SYSTEM_CONFIG_INTERFACE (keyfile_plugin));
+	if (!add_plugin (self, NM_SETTINGS_PLUGIN (keyfile_plugin)))
+		g_return_if_reached ();
 }
 
 static gboolean
@@ -680,26 +704,34 @@ load_plugins (NMSettings *self, const char **plugins, GError **error)
 	const char **iter;
 	gboolean keyfile_added = FALSE;
 	gboolean success = TRUE;
+	gboolean add_ibft = FALSE;
+	gboolean has_no_ibft;
+	gssize idx_no_ibft, idx_ibft;
+
+	idx_ibft    = _nm_utils_strv_find_first ((char **) plugins, -1, "ibft");
+	idx_no_ibft = _nm_utils_strv_find_first ((char **) plugins, -1, "no-ibft");
+	has_no_ibft = idx_no_ibft >= 0 && idx_no_ibft > idx_ibft;
+#if WITH_SETTINGS_PLUGIN_IBFT
+	add_ibft = idx_no_ibft < 0 && idx_ibft < 0;
+#endif
 
 	for (iter = plugins; iter && *iter; iter++) {
-		GModule *plugin;
-		gs_free char *full_name = NULL;
-		gs_free char *path = NULL;
-		const char *pname;
+		const char *pname = *iter;
 		GObject *obj;
-		GObject * (*factory_func) (void);
-		struct stat st;
-		int errsv;
-
-		pname = *iter;
 
 		if (!*pname || strchr (pname, '/')) {
 			LOG (LOGL_WARN, "ignore invalid plugin \"%s\"", pname);
 			continue;
 		}
 
-		obj = find_plugin (list, pname);
-		if (obj)
+		if (!strcmp (pname, "ifcfg-suse")) {
+			LOG (LOGL_WARN, "skipping deprecated plugin ifcfg-suse");
+			continue;
+		}
+
+		if (!strcmp (pname, "no-ibft"))
+			continue;
+		if (has_no_ibft && !strcmp (pname, "ibft"))
 			continue;
 
 		/* keyfile plugin is built-in now */
@@ -711,61 +743,92 @@ load_plugins (NMSettings *self, const char **plugins, GError **error)
 			continue;
 		}
 
-		full_name = g_strdup_printf ("nm-settings-plugin-%s", pname);
-		path = g_module_build_path (NMPLUGINDIR, full_name);
-
-		if (stat (path, &st) != 0) {
-			errsv = errno;
-			LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': %s", pname, path, strerror (errsv));
-			continue;
-		}
-		if (!S_ISREG (st.st_mode)) {
-			LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': not a file", pname, path);
-			continue;
-		}
-		if (st.st_uid != 0) {
-			LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': file must be owned by root", pname, path);
-			continue;
-		}
-		if (st.st_mode & (S_IWGRP | S_IWOTH | S_ISUID)) {
-			LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': invalid file permissions", pname, path);
+		if (_nm_utils_strv_find_first ((char **) plugins,
+		                               iter - plugins,
+		                               pname) >= 0) {
+			/* the plugin is already mentioned in the list previously.
+			 * Don't load a duplicate. */
 			continue;
 		}
 
-		plugin = g_module_open (path, G_MODULE_BIND_LOCAL);
-		if (!plugin) {
-			LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': %s",
-			     pname, path, g_module_error ());
+		if (find_plugin (list, pname))
 			continue;
-		}
 
-		/* errors after this point are fatal, because we loaded the shared library already. */
+load_plugin:
+		{
+			GModule *plugin;
+			gs_free char *full_name = NULL;
+			gs_free char *path = NULL;
+			GObject * (*factory_func) (void);
+			struct stat st;
+			int errsv;
+
+			full_name = g_strdup_printf ("nm-settings-plugin-%s", pname);
+			path = g_module_build_path (NMPLUGINDIR, full_name);
+
+			if (stat (path, &st) != 0) {
+				errsv = errno;
+				LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': %s", pname, path, strerror (errsv));
+				goto next;
+			}
+			if (!S_ISREG (st.st_mode)) {
+				LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': not a file", pname, path);
+				goto next;
+			}
+			if (st.st_uid != 0) {
+				LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': file must be owned by root", pname, path);
+				goto next;
+			}
+			if (st.st_mode & (S_IWGRP | S_IWOTH | S_ISUID)) {
+				LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': invalid file permissions", pname, path);
+				goto next;
+			}
 
-		if (!g_module_symbol (plugin, "nm_system_config_factory", (gpointer) (&factory_func))) {
-			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
-			             "Could not find plugin '%s' factory function.",
-			             pname);
-			success = FALSE;
-			g_module_close (plugin);
-			break;
-		}
+			plugin = g_module_open (path, G_MODULE_BIND_LOCAL);
+			if (!plugin) {
+				LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': %s",
+				     pname, path, g_module_error ());
+				goto next;
+			}
 
-		obj = (*factory_func) ();
-		if (!obj || !NM_IS_SYSTEM_CONFIG_INTERFACE (obj)) {
-			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
-			             "Plugin '%s' returned invalid system config object.",
-			             pname);
-			success = FALSE;
-			g_module_close (plugin);
-			break;
-		}
+			/* errors after this point are fatal, because we loaded the shared library already. */
 
-		g_module_make_resident (plugin);
-		g_object_weak_ref (obj, (GWeakNotify) g_module_close, plugin);
-		g_object_set_data_full (obj, PLUGIN_MODULE_PATH, path, g_free);
-		path = NULL;
-		add_plugin (self, NM_SYSTEM_CONFIG_INTERFACE (obj));
-		list = g_slist_append (list, obj);
+			if (!g_module_symbol (plugin, "nm_settings_plugin_factory", (gpointer) (&factory_func))) {
+				g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
+				             "Could not find plugin '%s' factory function.",
+				             pname);
+				success = FALSE;
+				g_module_close (plugin);
+				break;
+			}
+
+			obj = (*factory_func) ();
+			if (!obj || !NM_IS_SETTINGS_PLUGIN (obj)) {
+				g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
+				             "Plugin '%s' returned invalid system config object.",
+				             pname);
+				success = FALSE;
+				g_module_close (plugin);
+				break;
+			}
+
+			g_module_make_resident (plugin);
+			g_object_weak_ref (obj, (GWeakNotify) g_module_close, plugin);
+			g_object_set_data_full (obj, PLUGIN_MODULE_PATH, path, g_free);
+			path = NULL;
+			if (add_plugin (self, NM_SETTINGS_PLUGIN (obj)))
+				list = g_slist_append (list, obj);
+			else
+				g_object_unref (obj);
+		}
+next:
+		if (add_ibft && !strcmp (pname, "ifcfg-rh")) {
+			/* The plugin ibft is not explicitly mentioned but we just enabled "ifcfg-rh".
+			 * Enable "ibft" by default after "ifcfg-rh". */
+			pname = "ibft";
+			add_ibft = FALSE;
+			goto load_plugin;
+		}
 	}
 
 	/* If keyfile plugin was not among configured plugins, add it as the last one */
@@ -819,7 +882,6 @@ connection_removed (NMSettingsConnection *connection, gpointer user_data)
 
 	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
@@ -832,6 +894,7 @@ connection_removed (NMSettingsConnection *connection, gpointer user_data)
 	g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_updated_by_user), self);
 	g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_visibility_changed), self);
 	g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_ready_changed), self);
+	g_object_unref (self);
 
 	/* Forget about the connection internally */
 	g_hash_table_remove (priv->connections, (gpointer) cpath);
@@ -842,6 +905,8 @@ connection_removed (NMSettingsConnection *connection, gpointer user_data)
 	/* Re-emit for listeners like NMPolicy */
 	g_signal_emit_by_name (self, NM_CP_SIGNAL_CONNECTION_REMOVED, connection);
 	g_object_notify (G_OBJECT (self), NM_SETTINGS_CONNECTIONS);
+	if (nm_exported_object_is_exported (NM_EXPORTED_OBJECT (connection)))
+		nm_exported_object_unexport (NM_EXPORTED_OBJECT (connection));
 
 	check_startup_complete (self);
 
@@ -904,11 +969,10 @@ static void
 claim_connection (NMSettings *self, NMSettingsConnection *connection)
 {
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
-	static guint32 ec_counter = 0;
 	GError *error = NULL;
 	GHashTableIter iter;
 	gpointer data;
-	char *path;
+	const char *path;
 	NMSettingsConnection *existing;
 
 	g_return_if_fail (NM_IS_SETTINGS_CONNECTION (connection));
@@ -928,7 +992,7 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection)
 		return;
 	}
 
-	existing = nm_settings_get_connection_by_uuid (self, nm_connection_get_uuid (NM_CONNECTION (connection)));
+	existing = nm_settings_get_connection_by_uuid (self, nm_settings_connection_get_uuid (connection));
 	if (existing) {
 		/* Cannot add duplicate connections per UUID. Just return without action and
 		 * log a warning.
@@ -941,7 +1005,7 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection)
 		 * error out. That should not happen unless the admin misconfigured the system
 		 * to create conflicting connections. */
 		nm_log_warn (LOGD_SETTINGS, "plugin provided duplicate connection with UUID %s",
-		             nm_connection_get_uuid (NM_CONNECTION (connection)));
+		             nm_settings_connection_get_uuid (connection));
 		return;
 	}
 
@@ -957,6 +1021,7 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection)
 	/* Evil openconnect migration hack */
 	openconnect_migrate_hack (NM_CONNECTION (connection));
 
+	g_object_ref (self);
 	g_signal_connect (connection, NM_SETTINGS_CONNECTION_REMOVED,
 	                  G_CALLBACK (connection_removed), self);
 	g_signal_connect (connection, NM_SETTINGS_CONNECTION_UPDATED,
@@ -974,10 +1039,8 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection)
 
 	/* Export the connection over D-Bus */
 	g_warn_if_fail (nm_connection_get_path (NM_CONNECTION (connection)) == NULL);
-	path = g_strdup_printf ("%s/%u", NM_DBUS_PATH_SETTINGS, ec_counter++);
+	path = nm_exported_object_export (NM_EXPORTED_OBJECT (connection));
 	nm_connection_set_path (NM_CONNECTION (connection), path);
-	nm_dbus_manager_register_object (priv->dbus_mgr, path, G_OBJECT (connection));
-	g_free (path);
 
 	g_hash_table_insert (priv->connections,
 	                     (gpointer) nm_connection_get_path (NM_CONNECTION (connection)),
@@ -1047,10 +1110,10 @@ nm_settings_add_connection (NMSettings *self,
 	 *     contain the same data as the connection it already knows about
 	 */
 	for (iter = priv->plugins; iter; iter = g_slist_next (iter)) {
-		NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (iter->data);
+		NMSettingsPlugin *plugin = NM_SETTINGS_PLUGIN (iter->data);
 		GError *add_error = NULL;
 
-		added = nm_system_config_interface_add_connection (plugin, connection, save_to_disk, &add_error);
+		added = nm_settings_plugin_add_connection (plugin, connection, save_to_disk, &add_error);
 		if (added) {
 			claim_connection (self, added);
 			return added;
@@ -1112,21 +1175,24 @@ send_agent_owned_secrets (NMSettings *self,
 	nm_connection_clear_secrets_with_flags (for_agent,
 	                                        secrets_filter_cb,
 	                                        GUINT_TO_POINTER (NM_SETTING_SECRET_FLAG_AGENT_OWNED));
-	nm_agent_manager_save_secrets (priv->agent_mgr, for_agent, subject);
+	nm_agent_manager_save_secrets (priv->agent_mgr,
+	                               nm_connection_get_path (NM_CONNECTION (connection)),
+	                               for_agent,
+	                               subject);
 	g_object_unref (for_agent);
 }
 
 static void
 pk_add_cb (NMAuthChain *chain,
            GError *chain_error,
-           DBusGMethodInvocation *context,
+           GDBusMethodInvocation *context,
            gpointer user_data)
 {
 	NMSettings *self = NM_SETTINGS (user_data);
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
 	NMAuthCallResult result;
 	GError *error = NULL;
-	NMConnection *connection;
+	NMConnection *connection = NULL;
 	NMSettingsConnection *added = NULL;
 	NMSettingsAddCallback callback;
 	gpointer callback_data;
@@ -1163,10 +1229,10 @@ pk_add_cb (NMAuthChain *chain,
 	callback_data = nm_auth_chain_get_data (chain, "callback-data");
 	subject = nm_auth_chain_get_data (chain, "subject");
 
-	callback (self, added, error, context, callback_data);
+	callback (self, added, error, context, subject, callback_data);
 
 	/* Send agent-owned secrets to the agents */
-	if (!error && added)
+	if (!error && added && nm_settings_has_connection (self, added))
 		send_agent_owned_secrets (self, added, subject);
 
 	g_clear_error (&error);
@@ -1207,11 +1273,11 @@ is_adhoc_wpa (NMConnection *connection)
 
 void
 nm_settings_add_connection_dbus (NMSettings *self,
-                            NMConnection *connection,
-                            gboolean save_to_disk,
-                            DBusGMethodInvocation *context,
-                            NMSettingsAddCallback callback,
-                            gpointer user_data)
+                                 NMConnection *connection,
+                                 gboolean save_to_disk,
+                                 GDBusMethodInvocation *context,
+                                 NMSettingsAddCallback callback,
+                                 gpointer user_data)
 {
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
 	NMSettingConnection *s_con;
@@ -1246,7 +1312,7 @@ nm_settings_add_connection_dbus (NMSettings *self,
 	}
 
 	/* Do any of the plugins support adding? */
-	if (!get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS)) {
+	if (!get_plugin (self, NM_SETTINGS_PLUGIN_CAP_MODIFY_CONNECTIONS)) {
 		error = g_error_new_literal (NM_SETTINGS_ERROR,
 		                             NM_SETTINGS_ERROR_NOT_SUPPORTED,
 		                             "None of the registered plugins support add.");
@@ -1265,7 +1331,6 @@ nm_settings_add_connection_dbus (NMSettings *self,
 	 * or that the permissions is empty (ie, visible by everyone).
 	 */
 	if (!nm_auth_is_subject_in_acl (connection,
-	                                nm_session_monitor_get (),
 	                                subject,
 	                                &error_desc)) {
 		error = g_error_new_literal (NM_SETTINGS_ERROR,
@@ -1306,7 +1371,7 @@ nm_settings_add_connection_dbus (NMSettings *self,
 
 done:
 	if (error)
-		callback (self, NULL, error, context, user_data);
+		callback (self, NULL, error, context, subject, user_data);
 
 	g_clear_error (&error);
 	g_clear_object (&subject);
@@ -1316,29 +1381,37 @@ static void
 impl_settings_add_connection_add_cb (NMSettings *self,
                                      NMSettingsConnection *connection,
                                      GError *error,
-                                     DBusGMethodInvocation *context,
+                                     GDBusMethodInvocation *context,
+                                     NMAuthSubject *subject,
                                      gpointer user_data)
 {
-	if (error)
-		dbus_g_method_return_error (context, error);
-	else
-		dbus_g_method_return (context, nm_connection_get_path (NM_CONNECTION (connection)));
+	if (error) {
+		g_dbus_method_invocation_return_gerror (context, error);
+		nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD, NULL, FALSE, subject, error->message);
+	} else {
+		g_dbus_method_invocation_return_value (
+		    context,
+		    g_variant_new ("(o)", nm_connection_get_path (NM_CONNECTION (connection))));
+		nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD, connection, TRUE,
+		                            subject, NULL);
+	}
 }
 
 static void
 impl_settings_add_connection_helper (NMSettings *self,
-                                     GHashTable *settings,
-                                     gboolean save_to_disk,
-                                     DBusGMethodInvocation *context)
+                                     GDBusMethodInvocation *context,
+                                     GVariant *settings,
+                                     gboolean save_to_disk)
 {
 	NMConnection *connection;
-	GVariant *dict;
 	GError *error = NULL;
 
-	dict = nm_utils_connection_hash_to_dict (settings);
-	connection = nm_simple_connection_new_from_dbus (dict, &error);
-	g_variant_unref (dict);
+	connection = nm_simple_connection_new_from_dbus (settings, &error);
+
 	if (connection) {
+		if (!nm_connection_verify_secrets (connection, &error))
+			goto failure;
+
 		nm_settings_add_connection_dbus (self,
 		                                 connection,
 		                                 save_to_disk,
@@ -1346,50 +1419,49 @@ impl_settings_add_connection_helper (NMSettings *self,
 		                                 impl_settings_add_connection_add_cb,
 		                                 NULL);
 		g_object_unref (connection);
-	} else {
-		g_assert (error);
-		dbus_g_method_return_error (context, error);
-		g_error_free (error);
+		return;
 	}
+
+failure:
+	g_assert (error);
+	g_dbus_method_invocation_take_error (context, error);
 }
 
 static void
 impl_settings_add_connection (NMSettings *self,
-                              GHashTable *settings,
-                              DBusGMethodInvocation *context)
+                              GDBusMethodInvocation *context,
+                              GVariant *settings)
 {
-	impl_settings_add_connection_helper (self, settings, TRUE, context);
+	impl_settings_add_connection_helper (self, context, settings, TRUE);
 }
 
 static void
 impl_settings_add_connection_unsaved (NMSettings *self,
-                                      GHashTable *settings,
-                                      DBusGMethodInvocation *context)
+                                      GDBusMethodInvocation *context,
+                                      GVariant *settings)
 {
-	impl_settings_add_connection_helper (self, settings, FALSE, context);
+	impl_settings_add_connection_helper (self, context, settings, FALSE);
 }
 
 static gboolean
-ensure_root (NMDBusManager         *dbus_mgr,
-             DBusGMethodInvocation *context)
+ensure_root (NMBusManager          *dbus_mgr,
+             GDBusMethodInvocation *context)
 {
 	gulong caller_uid;
 	GError *error = NULL;
 
-	if (!nm_dbus_manager_get_caller_info (dbus_mgr, context, NULL, &caller_uid, NULL)) {
+	if (!nm_bus_manager_get_caller_info (dbus_mgr, context, NULL, &caller_uid, NULL)) {
 		error = g_error_new_literal (NM_SETTINGS_ERROR,
 		                             NM_SETTINGS_ERROR_PERMISSION_DENIED,
 		                             "Unable to determine request UID.");
-		dbus_g_method_return_error (context, error);
-		g_error_free (error);
+		g_dbus_method_invocation_take_error (context, error);
 		return FALSE;
 	}
 	if (caller_uid != 0) {
 		error = g_error_new_literal (NM_SETTINGS_ERROR,
 		                             NM_SETTINGS_ERROR_PERMISSION_DENIED,
 		                             "Permission denied");
-		dbus_g_method_return_error (context, error);
-		g_error_free (error);
+		g_dbus_method_invocation_take_error (context, error);
 		return FALSE;
 	}
 
@@ -1398,24 +1470,24 @@ ensure_root (NMDBusManager         *dbus_mgr,
 
 static void
 impl_settings_load_connections (NMSettings *self,
-                                char **filenames,
-                                DBusGMethodInvocation *context)
+                                GDBusMethodInvocation *context,
+                                char **filenames)
 {
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
 	GPtrArray *failures;
 	GSList *iter;
 	int i;
 
-	if (!ensure_root (priv->dbus_mgr, context))
+	if (!ensure_root (nm_bus_manager_get (), context))
 		return;
 
 	failures = g_ptr_array_new ();
 
 	for (i = 0; filenames[i]; i++) {
 		for (iter = priv->plugins; iter; iter = g_slist_next (iter)) {
-			NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (iter->data);
+			NMSettingsPlugin *plugin = NM_SETTINGS_PLUGIN (iter->data);
 
-			if (nm_system_config_interface_load_connection (plugin, filenames[i]))
+			if (nm_settings_plugin_load_connection (plugin, filenames[i]))
 				break;
 		}
 
@@ -1427,40 +1499,110 @@ impl_settings_load_connections (NMSettings *self,
 	}
 
 	g_ptr_array_add (failures, NULL);
-	dbus_g_method_return (context, failures->len == 1, failures->pdata);
+	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 (NMSettings *self,
-                                  DBusGMethodInvocation *context)
+                                  GDBusMethodInvocation *context)
 {
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
 	GSList *iter;
 
-	if (!ensure_root (priv->dbus_mgr, context))
+	if (!ensure_root (nm_bus_manager_get (), context))
 		return;
 
 	for (iter = priv->plugins; iter; iter = g_slist_next (iter)) {
-		NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (iter->data);
+		NMSettingsPlugin *plugin = NM_SETTINGS_PLUGIN (iter->data);
 
-		nm_system_config_interface_reload_connections (plugin);
+		nm_settings_plugin_reload_connections (plugin);
 	}
 
-	dbus_g_method_return (context, TRUE);
+	g_dbus_method_invocation_return_value (context, g_variant_new ("(b)", TRUE));
+}
+
+static gboolean
+write_hostname (NMSettingsPrivate *priv, const char *hostname)
+{
+	char *hostname_eol;
+	gboolean ret;
+	gs_free_error GError *error = NULL;
+	const char *file = priv->hostname.file;
+	gs_unref_variant GVariant *var = NULL;
+#if HAVE_SELINUX
+	security_context_t se_ctx_prev = NULL, se_ctx = NULL;
+	struct stat file_stat = { .st_mode = 0 };
+	mode_t st_mode = 0;
+#endif
+
+	if (priv->hostname.hostnamed_proxy) {
+		var = g_dbus_proxy_call_sync (priv->hostname.hostnamed_proxy,
+		                              "SetStaticHostname",
+		                              g_variant_new ("(sb)", hostname, FALSE),
+		                              G_DBUS_CALL_FLAGS_NONE,
+		                              -1,
+		                              NULL,
+		                              &error);
+		if (error)
+			nm_log_warn (LOGD_SETTINGS, "Could not set hostname: %s", error->message);
+
+		return !error;
+	}
+
+#if HAVE_SELINUX
+	/* Get default context for hostname file and set it for fscreate */
+	if (stat (file, &file_stat) == 0)
+		st_mode = file_stat.st_mode;
+	matchpathcon (file, st_mode, &se_ctx);
+	matchpathcon_fini ();
+	getfscreatecon (&se_ctx_prev);
+	setfscreatecon (se_ctx);
+#endif
+
+#if defined (HOSTNAME_PERSIST_GENTOO)
+	hostname_eol = g_strdup_printf ("#Generated by NetworkManager\n"
+	                                "hostname=\"%s\"\n", hostname);
+#else
+	hostname_eol = g_strdup_printf ("%s\n", hostname);
+#endif
+
+	/* FIXME: g_file_set_contents() writes first to a temporary file
+	 * and renames it atomically. We should hack g_file_set_contents()
+	 * to set the SELINUX labels before renaming the file. */
+	ret = g_file_set_contents (file, hostname_eol, -1, &error);
+
+#if HAVE_SELINUX
+	/* Restore previous context and cleanup */
+	setfscreatecon (se_ctx_prev);
+	freecon (se_ctx);
+	freecon (se_ctx_prev);
+#endif
+
+	g_free (hostname_eol);
+
+	if (!ret) {
+		nm_log_warn (LOGD_SETTINGS, "Could not save hostname to %s: %s", file, error->message);
+		return FALSE;
+	}
+
+	return TRUE;
 }
 
 static void
 pk_hostname_cb (NMAuthChain *chain,
                 GError *chain_error,
-                DBusGMethodInvocation *context,
+                GDBusMethodInvocation *context,
                 gpointer user_data)
 {
 	NMSettings *self = NM_SETTINGS (user_data);
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
 	NMAuthCallResult result;
 	GError *error = NULL;
-	GSList *iter;
 	const char *hostname;
 
 	g_assert (context);
@@ -1480,30 +1622,20 @@ pk_hostname_cb (NMAuthChain *chain,
 		                             NM_SETTINGS_ERROR_PERMISSION_DENIED,
 		                             "Insufficient privileges.");
 	} else {
-		/* Set the hostname in all plugins */
 		hostname = nm_auth_chain_get_data (chain, "hostname");
-		for (iter = priv->plugins; iter; iter = iter->next) {
-			NMSystemConfigInterfaceCapabilities caps = NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE;
 
-			/* error will be cleared if any plugin supports saving the hostname */
+		if (!write_hostname (priv, hostname)) {
 			error = g_error_new_literal (NM_SETTINGS_ERROR,
 			                             NM_SETTINGS_ERROR_FAILED,
 			                             "Saving the hostname failed.");
-
-			g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES, &caps, NULL);
-			if (caps & NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME) {
-				g_object_set (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME, hostname, NULL);
-				g_clear_error (&error);
-			}
 		}
 	}
 
 	if (error)
-		dbus_g_method_return_error (context, error);
+		g_dbus_method_invocation_take_error (context, error);
 	else
-		dbus_g_method_return (context);
+		g_dbus_method_invocation_return_value (context, NULL);
 
-	g_clear_error (&error);
 	nm_auth_chain_unref (chain);
 }
 
@@ -1536,8 +1668,8 @@ validate_hostname (const char *hostname)
 
 static void
 impl_settings_save_hostname (NMSettings *self,
-                             const char *hostname,
-                             DBusGMethodInvocation *context)
+                             GDBusMethodInvocation *context,
+                             const char *hostname)
 {
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
 	NMAuthChain *chain;
@@ -1551,14 +1683,6 @@ impl_settings_save_hostname (NMSettings *self,
 		goto done;
 	}
 
-	/* Do any of the plugins support setting the hostname? */
-	if (!get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME)) {
-		error = g_error_new_literal (NM_SETTINGS_ERROR,
-		                             NM_SETTINGS_ERROR_NOT_SUPPORTED,
-		                             "None of the registered plugins support setting the hostname.");
-		goto done;
-	}
-
 	chain = nm_auth_chain_new_context (context, pk_hostname_cb, self);
 	if (!chain) {
 		error = g_error_new_literal (NM_SETTINGS_ERROR,
@@ -1573,8 +1697,39 @@ impl_settings_save_hostname (NMSettings *self,
 
 done:
 	if (error)
-		dbus_g_method_return_error (context, error);
-	g_clear_error (&error);
+		g_dbus_method_invocation_take_error (context, error);
+}
+
+static void
+hostname_maybe_changed (NMSettings *settings)
+{
+	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (settings);
+	char *new_hostname;
+
+	new_hostname = nm_settings_get_hostname (settings);
+
+	if (   (new_hostname && !priv->hostname.value)
+	    || (!new_hostname && priv->hostname.value)
+	    || (priv->hostname.value && new_hostname && strcmp (priv->hostname.value, new_hostname))) {
+
+		nm_log_info (LOGD_SETTINGS, "hostname changed from %s%s%s to %s%s%s",
+		             NM_PRINT_FMT_QUOTED (priv->hostname.value, "\"", priv->hostname.value, "\"", "(none)"),
+		             NM_PRINT_FMT_QUOTED (new_hostname, "\"", new_hostname, "\"", "(none)"));
+		g_free (priv->hostname.value);
+		priv->hostname.value = new_hostname;
+		g_object_notify (G_OBJECT (settings), NM_SETTINGS_HOSTNAME);
+	} else
+		g_free (new_hostname);
+}
+
+static void
+hostname_file_changed_cb (GFileMonitor *monitor,
+                          GFile *file,
+                          GFile *other_file,
+                          GFileMonitorEvent event_type,
+                          gpointer user_data)
+{
+	hostname_maybe_changed (user_data);
 }
 
 static gboolean
@@ -1699,13 +1854,20 @@ default_wired_clear_tag (NMSettings *self,
 		nm_config_set_no_auto_default_for_device (NM_SETTINGS_GET_PRIVATE (self)->config, device);
 }
 
-void
-nm_settings_device_added (NMSettings *self, NMDevice *device)
+static void
+device_realized (NMDevice *device, GParamSpec *pspec, NMSettings *self)
 {
 	NMConnection *connection;
 	NMSettingsConnection *added;
 	GError *error = NULL;
 
+	if (!nm_device_is_real (device))
+		return;
+
+	g_signal_handlers_disconnect_by_func (device,
+	                                      G_CALLBACK (device_realized),
+	                                      self);
+
 	/* If the device isn't managed or it already has a default wired connection,
 	 * ignore it.
 	 */
@@ -1740,7 +1902,19 @@ nm_settings_device_added (NMSettings *self, NMDevice *device)
 
 	nm_log_info (LOGD_SETTINGS, "(%s): created default wired connection '%s'",
 	             nm_device_get_iface (device),
-	             nm_connection_get_id (NM_CONNECTION (added)));
+	             nm_settings_connection_get_id (added));
+}
+
+void
+nm_settings_device_added (NMSettings *self, NMDevice *device)
+{
+	if (nm_device_is_real (device))
+		device_realized (device, NULL, self);
+	else {
+		g_signal_connect_after (device, "notify::" NM_DEVICE_REAL,
+		                        G_CALLBACK (device_realized),
+		                        self);
+	}
 }
 
 void
@@ -1748,6 +1922,10 @@ nm_settings_device_removed (NMSettings *self, NMDevice *device, gboolean quittin
 {
 	NMSettingsConnection *connection;
 
+	g_signal_handlers_disconnect_by_func (device,
+	                                      G_CALLBACK (device_realized),
+	                                      self);
+
 	connection = g_object_get_data (G_OBJECT (device), DEFAULT_WIRED_CONNECTION_TAG);
 	if (connection) {
 		default_wired_clear_tag (self, device, connection, FALSE);
@@ -1875,8 +2053,75 @@ nm_settings_get_startup_complete (NMSettings *self)
 
 /***************************************************************/
 
+static void
+hostnamed_properties_changed (GDBusProxy *proxy,
+                              GVariant *changed_properties,
+                              char **invalidated_properties,
+                              gpointer user_data)
+{
+	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (user_data);
+	GVariant *v_hostname;
+	const char *hostname;
+
+	v_hostname = g_dbus_proxy_get_cached_property (priv->hostname.hostnamed_proxy,
+	                                               "StaticHostname");
+	if (!v_hostname)
+		return;
+
+	hostname = g_variant_get_string (v_hostname, NULL);
+
+	if (g_strcmp0 (priv->hostname.value, hostname) != 0) {
+		nm_log_info (LOGD_SETTINGS, "hostname changed from %s%s%s to %s%s%s",
+		             NM_PRINT_FMT_QUOTED (priv->hostname.value, "\"", priv->hostname.value, "\"", "(none)"),
+		             NM_PRINT_FMT_QUOTED (hostname, "\"", hostname, "\"", "(none)"));
+		g_free (priv->hostname.value);
+		priv->hostname.value = g_strdup (hostname);
+		g_object_notify (G_OBJECT (user_data), NM_SETTINGS_HOSTNAME);
+		nm_dispatcher_call (DISPATCHER_ACTION_HOSTNAME, NULL, NULL, NULL, NULL, NULL, NULL);
+	}
+
+	g_variant_unref (v_hostname);
+}
+
+static void
+setup_hostname_file_monitors (NMSettings *self)
+{
+	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
+	GFileMonitor *monitor;
+	GFile *file;
+
+	priv->hostname.file = HOSTNAME_FILE;
+	priv->hostname.value = nm_settings_get_hostname (self);
+
+	/* monitor changes to hostname file */
+	file = g_file_new_for_path (priv->hostname.file);
+	monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL);
+	g_object_unref (file);
+	if (monitor) {
+		priv->hostname.monitor_id = g_signal_connect (monitor, "changed",
+		                                              G_CALLBACK (hostname_file_changed_cb),
+		                                              self);
+		priv->hostname.monitor = monitor;
+	}
+
+#if defined (HOSTNAME_PERSIST_SUSE)
+	/* monitor changes to dhcp file to know whether the hostname is valid */
+	file = g_file_new_for_path (CONF_DHCP);
+	monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL);
+	g_object_unref (file);
+	if (monitor) {
+		priv->hostname.dhcp_monitor_id = g_signal_connect (monitor, "changed",
+		                                                   G_CALLBACK (hostname_file_changed_cb),
+		                                                   self);
+		priv->hostname.dhcp_monitor = monitor;
+	}
+#endif
+
+	hostname_maybe_changed (self);
+}
+
 NMSettings *
-nm_settings_new (GError **error)
+nm_settings_new (void)
 {
 	NMSettings *self;
 	NMSettingsPrivate *priv;
@@ -1886,28 +2131,67 @@ nm_settings_new (GError **error)
 	priv = NM_SETTINGS_GET_PRIVATE (self);
 
 	priv->config = nm_config_get ();
-	priv->dbus_mgr = nm_dbus_manager_get ();
+
+	nm_exported_object_export (NM_EXPORTED_OBJECT (self));
+	return self;
+}
+
+gboolean
+nm_settings_start (NMSettings *self, GError **error)
+{
+	NMSettingsPrivate *priv;
+	GDBusProxy *proxy;
+	GVariant *variant;
+	GError *local_error = NULL;
+
+	priv = NM_SETTINGS_GET_PRIVATE (self);
 
 	/* Load the plugins; fail if a plugin is not found. */
 	if (!load_plugins (self, nm_config_get_plugins (priv->config), error)) {
 		g_object_unref (self);
-		return NULL;
+		return FALSE;
 	}
 
 	load_connections (self);
 	check_startup_complete (self);
 
-	nm_dbus_manager_register_object (priv->dbus_mgr, NM_DBUS_PATH_SETTINGS, self);
-	return self;
+	proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, 0, NULL,
+	                                       HOSTNAMED_SERVICE_NAME, HOSTNAMED_SERVICE_PATH,
+	                                       HOSTNAMED_SERVICE_INTERFACE, NULL, &local_error);
+	if (proxy) {
+		variant = g_dbus_proxy_get_cached_property (proxy, "StaticHostname");
+		if (variant) {
+			nm_log_info (LOGD_SETTINGS, "hostname: using hostnamed");
+			priv->hostname.hostnamed_proxy = proxy;
+			g_signal_connect (proxy, "g-properties-changed",
+			                  G_CALLBACK (hostnamed_properties_changed), self);
+			hostnamed_properties_changed (proxy, NULL, NULL, self);
+			g_variant_unref (variant);
+		} else {
+			nm_log_info (LOGD_SETTINGS, "hostname: couldn't get property from hostnamed");
+			g_object_unref (proxy);
+		}
+	} else {
+		nm_log_info (LOGD_SETTINGS, "hostname: hostnamed not used as proxy creation failed with: %s",
+		             local_error->message);
+		g_clear_error (&local_error);
+	}
+
+	if (!priv->hostname.hostnamed_proxy)
+		setup_hostname_file_monitors (self);
+
+	priv->started = TRUE;
+	g_object_notify (G_OBJECT (self), NM_SETTINGS_HOSTNAME);
+	return TRUE;
 }
 
 static void
-connection_provider_init (NMConnectionProvider *cp_class)
+connection_provider_iface_init (NMConnectionProviderInterface *cp_iface)
 {
-    cp_class->get_best_connections = get_best_connections;
-    cp_class->get_connections = get_connections;
-    cp_class->add_connection = _nm_connection_provider_add_connection;
-    cp_class->get_connection_by_uuid = cp_get_connection_by_uuid;
+    cp_iface->get_best_connections = get_best_connections;
+    cp_iface->get_connections = get_connections;
+    cp_iface->add_connection = _nm_connection_provider_add_connection;
+    cp_iface->get_connection_by_uuid = cp_get_connection_by_uuid;
 }
 
 static void
@@ -1936,10 +2220,34 @@ dispose (GObject *object)
 	g_slist_free_full (priv->auths, (GDestroyNotify) nm_auth_chain_unref);
 	priv->auths = NULL;
 
-	priv->dbus_mgr = NULL;
-
 	g_object_unref (priv->agent_mgr);
 
+	if (priv->hostname.hostnamed_proxy) {
+		g_signal_handlers_disconnect_by_func (priv->hostname.hostnamed_proxy,
+		                                      G_CALLBACK (hostnamed_properties_changed),
+		                                      self);
+		g_clear_object (&priv->hostname.hostnamed_proxy);
+	}
+
+	if (priv->hostname.monitor) {
+		if (priv->hostname.monitor_id)
+			g_signal_handler_disconnect (priv->hostname.monitor, priv->hostname.monitor_id);
+
+		g_file_monitor_cancel (priv->hostname.monitor);
+		g_clear_object (&priv->hostname.monitor);
+	}
+
+	if (priv->hostname.dhcp_monitor) {
+		if (priv->hostname.dhcp_monitor_id)
+			g_signal_handler_disconnect (priv->hostname.dhcp_monitor,
+			                             priv->hostname.dhcp_monitor_id);
+
+		g_file_monitor_cancel (priv->hostname.dhcp_monitor);
+		g_clear_object (&priv->hostname.dhcp_monitor);
+	}
+
+	g_clear_pointer (&priv->hostname.value, g_free);
+
 	G_OBJECT_CLASS (nm_settings_parent_class)->dispose (object);
 }
 
@@ -1962,22 +2270,23 @@ finalize (GObject *object)
 
 static void
 get_property (GObject *object, guint prop_id,
-			  GValue *value, GParamSpec *pspec)
+              GValue *value, GParamSpec *pspec)
 {
 	NMSettings *self = NM_SETTINGS (object);
 	NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
 	const GSList *specs, *iter;
-	GSList *copy = NULL;
 	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);
 		for (iter = specs; iter; iter = g_slist_next (iter))
-			copy = g_slist_append (copy, g_strdup (iter->data));
-		g_value_take_boxed (value, copy);
+			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_take_string (value, nm_settings_get_hostname (self));
@@ -1987,14 +2296,15 @@ get_property (GObject *object, guint prop_id,
 			g_value_set_static_string (value, "");
 		break;
 	case PROP_CAN_MODIFY:
-		g_value_set_boolean (value, !!get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS));
+		g_value_set_boolean (value, !!get_plugin (self, NM_SETTINGS_PLUGIN_CAP_MODIFY_CONNECTIONS));
 		break;
 	case PROP_CONNECTIONS:
-		array = g_ptr_array_sized_new (g_hash_table_size (priv->connections));
+		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_value_take_boxed (value, array);
+		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));
@@ -2009,11 +2319,13 @@ static void
 nm_settings_class_init (NMSettingsClass *class)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (class);
-	
+	NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (class);
+
 	g_type_class_add_private (class, sizeof (NMSettingsPrivate));
 
+	exported_object_class->export_path = NM_DBUS_PATH_SETTINGS;
+
 	/* virtual methods */
-	object_class->notify = notify;
 	object_class->get_property = get_property;
 	object_class->dispose = dispose;
 	object_class->finalize = finalize;
@@ -2023,7 +2335,7 @@ nm_settings_class_init (NMSettingsClass *class)
 	g_object_class_install_property
 		(object_class, PROP_UNMANAGED_SPECS,
 		 g_param_spec_boxed (NM_SETTINGS_UNMANAGED_SPECS, "", "",
-		                     DBUS_TYPE_G_LIST_OF_STRING,
+		                     G_TYPE_STRV,
 		                     G_PARAM_READABLE |
 		                     G_PARAM_STATIC_STRINGS));
 
@@ -2044,19 +2356,11 @@ nm_settings_class_init (NMSettingsClass *class)
 	g_object_class_install_property
 		(object_class, PROP_CONNECTIONS,
 		 g_param_spec_boxed (NM_SETTINGS_CONNECTIONS, "", "",
-		                     DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH,
+		                     G_TYPE_STRV,
 		                     G_PARAM_READABLE |
 		                     G_PARAM_STATIC_STRINGS));
 
 	/* signals */
-	signals[PROPERTIES_CHANGED] = 
-	                g_signal_new ("properties-changed",
-	                              G_OBJECT_CLASS_TYPE (object_class),
-	                              G_SIGNAL_RUN_FIRST,
-	                              G_STRUCT_OFFSET (NMSettingsClass, properties_changed),
-	                              NULL, NULL,
-	                              g_cclosure_marshal_VOID__BOXED,
-	                              G_TYPE_NONE, 1, DBUS_TYPE_G_MAP_OF_VARIANT);
 	signals[CONNECTION_ADDED] = 
 	                g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_ADDED,
 	                              G_OBJECT_CLASS_TYPE (object_class),
@@ -2064,7 +2368,7 @@ nm_settings_class_init (NMSettingsClass *class)
 	                              G_STRUCT_OFFSET (NMSettingsClass, connection_added),
 	                              NULL, NULL,
 	                              g_cclosure_marshal_VOID__OBJECT,
-	                              G_TYPE_NONE, 1, G_TYPE_OBJECT);
+	                              G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION);
 
 	signals[CONNECTION_UPDATED] = 
 	                g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_UPDATED,
@@ -2073,7 +2377,7 @@ nm_settings_class_init (NMSettingsClass *class)
 	                              G_STRUCT_OFFSET (NMSettingsClass, connection_updated),
 	                              NULL, NULL,
 	                              g_cclosure_marshal_VOID__OBJECT,
-	                              G_TYPE_NONE, 1, G_TYPE_OBJECT);
+	                              G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION);
 
 	signals[CONNECTION_UPDATED_BY_USER] =
 	                g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_UPDATED_BY_USER,
@@ -2082,7 +2386,7 @@ nm_settings_class_init (NMSettingsClass *class)
 	                              0,
 	                              NULL, NULL,
 	                              g_cclosure_marshal_VOID__OBJECT,
-	                              G_TYPE_NONE, 1, G_TYPE_OBJECT);
+	                              G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION);
 
 	signals[CONNECTION_REMOVED] = 
 	                g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_REMOVED,
@@ -2091,7 +2395,7 @@ nm_settings_class_init (NMSettingsClass *class)
 	                              G_STRUCT_OFFSET (NMSettingsClass, connection_removed),
 	                              NULL, NULL,
 	                              g_cclosure_marshal_VOID__OBJECT,
-	                              G_TYPE_NONE, 1, G_TYPE_OBJECT);
+	                              G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION);
 
 	signals[CONNECTION_VISIBILITY_CHANGED] = 
 	                g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_VISIBILITY_CHANGED,
@@ -2100,7 +2404,7 @@ nm_settings_class_init (NMSettingsClass *class)
 	                              G_STRUCT_OFFSET (NMSettingsClass, connection_visibility_changed),
 	                              NULL, NULL,
 	                              g_cclosure_marshal_VOID__OBJECT,
-	                              G_TYPE_NONE, 1, G_TYPE_OBJECT);
+	                              G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION);
 
 	signals[AGENT_REGISTERED] =
 		g_signal_new (NM_SETTINGS_SIGNAL_AGENT_REGISTERED,
@@ -2109,7 +2413,7 @@ nm_settings_class_init (NMSettingsClass *class)
 		              G_STRUCT_OFFSET (NMSettingsClass, agent_registered),
 		              NULL, NULL,
 		              g_cclosure_marshal_VOID__OBJECT,
-		              G_TYPE_NONE, 1, G_TYPE_OBJECT);
+		              G_TYPE_NONE, 1, NM_TYPE_SECRET_AGENT);
 
 
 	signals[NEW_CONNECTION] = 
@@ -2117,16 +2421,17 @@ nm_settings_class_init (NMSettingsClass *class)
 	                              G_OBJECT_CLASS_TYPE (object_class),
 	                              G_SIGNAL_RUN_FIRST, 0, NULL, NULL,
 	                              g_cclosure_marshal_VOID__OBJECT,
-	                              G_TYPE_NONE, 1, G_TYPE_OBJECT);
-
-	dbus_g_error_domain_register (NM_SETTINGS_ERROR,
-	                              NM_DBUS_INTERFACE_SETTINGS,
-	                              NM_TYPE_SETTINGS_ERROR);
-	dbus_g_error_domain_register (NM_CONNECTION_ERROR,
-	                              NM_DBUS_INTERFACE_SETTINGS_CONNECTION,
-	                              NM_TYPE_CONNECTION_ERROR);
-
-	dbus_g_object_type_install_info (NM_TYPE_SETTINGS, &dbus_glib_nm_settings_object_info);
-
+	                              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);
 }