summary refs log tree commit diff
path: root/src/nm-active-connection.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nm-active-connection.c')
-rw-r--r--src/nm-active-connection.c439
1 files changed, 260 insertions, 179 deletions
diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c
index 3a8e6cf5..ad6b08b3 100644
--- a/src/nm-active-connection.c
+++ b/src/nm-active-connection.c
@@ -20,33 +20,29 @@
 
 #include "config.h"
 
-#include <glib.h>
-
-#include "nm-types.h"
+#include "nm-default.h"
 #include "nm-active-connection.h"
 #include "nm-dbus-interface.h"
-#include "nm-logging.h"
-#include "nm-dbus-glib-types.h"
-#include "nm-dbus-manager.h"
 #include "nm-device.h"
 #include "nm-settings-connection.h"
+#include "nm-simple-connection.h"
 #include "nm-auth-utils.h"
 #include "nm-auth-subject.h"
 #include "NetworkManagerUtils.h"
-#include "gsystem-local-alloc.h"
-#include "nm-active-connection-glue.h"
-#include "nm-glib-compat.h"
+#include "nm-core-internal.h"
+
+#include "nmdbus-active-connection.h"
 
 /* Base class for anything implementing the Connection.Active D-Bus interface */
-G_DEFINE_ABSTRACT_TYPE (NMActiveConnection, nm_active_connection, G_TYPE_OBJECT)
+G_DEFINE_ABSTRACT_TYPE (NMActiveConnection, nm_active_connection, NM_TYPE_EXPORTED_OBJECT)
 
 #define NM_ACTIVE_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
                                              NM_TYPE_ACTIVE_CONNECTION, \
                                              NMActiveConnectionPrivate))
 
 typedef struct {
-	NMConnection *connection;
-	char *path;
+	NMSettingsConnection *settings_connection;
+	NMConnection *applied_connection;
 	char *specific_object;
 	NMDevice *device;
 
@@ -89,7 +85,7 @@ enum {
 	PROP_VPN,
 	PROP_MASTER,
 
-	PROP_INT_CONNECTION,
+	PROP_INT_SETTINGS_CONNECTION,
 	PROP_INT_DEVICE,
 	PROP_INT_SUBJECT,
 	PROP_INT_MASTER,
@@ -114,42 +110,27 @@ static void _device_cleanup (NMActiveConnection *self);
 #define _NMLOG_PREFIX_NAME    "active-connection"
 #define _NMLOG(level, ...) \
     G_STMT_START { \
-        const NMLogLevel __level = (level); \
+        char _sbuf[64]; \
         \
-        if (nm_logging_enabled (__level, _NMLOG_DOMAIN)) { \
-            char __prefix[128]; \
-            const char *__p_prefix = _NMLOG_PREFIX_NAME; \
-            const void *const __self = (self); \
-            \
-            if (__self) { \
-                g_snprintf (__prefix, sizeof (__prefix), "%s[%p]", _NMLOG_PREFIX_NAME, __self); \
-                __p_prefix = __prefix; \
-            } \
-            _nm_log (__level, _NMLOG_DOMAIN, 0, \
-                     "%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
-                     __p_prefix _NM_UTILS_MACRO_REST (__VA_ARGS__)); \
-        } \
+        nm_log ((level), _NMLOG_DOMAIN, \
+                "%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
+                _NMLOG_PREFIX_NAME, \
+                self ? nm_sprintf_buf (_sbuf, "[%p]", self) : "" \
+                _NM_UTILS_MACRO_REST (__VA_ARGS__)); \
     } G_STMT_END
 
 /****************************************************************/
 
-static const char *
-state_to_string (NMActiveConnectionState state)
-{
-	switch (state) {
-	case NM_ACTIVE_CONNECTION_STATE_UNKNOWN:
-		return "unknown";
-	case NM_ACTIVE_CONNECTION_STATE_ACTIVATING:
-		return "activating";
-	case NM_ACTIVE_CONNECTION_STATE_ACTIVATED:
-		return "activated";
-	case NM_ACTIVE_CONNECTION_STATE_DEACTIVATING:
-		return "deactivating";
-	case NM_ACTIVE_CONNECTION_STATE_DEACTIVATED:
-		return "deactivated";
-	}
-	return "(none)";
-}
+NM_UTILS_STRING_LOOKUP_TABLE_DEFINE_STATIC (_state_to_string, NMActiveConnectionState, NULL,
+	[NM_ACTIVE_CONNECTION_STATE_UNKNOWN]            = "unknown",
+	[NM_ACTIVE_CONNECTION_STATE_ACTIVATING]         = "activating",
+	[NM_ACTIVE_CONNECTION_STATE_ACTIVATED]          = "activated",
+	[NM_ACTIVE_CONNECTION_STATE_DEACTIVATING]       = "deactivating",
+	[NM_ACTIVE_CONNECTION_STATE_DEACTIVATED]        = "deactivated",
+);
+#define state_to_string(state) NM_UTILS_STRING_LOOKUP_TABLE (_state_to_string, state)
+
+/****************************************************************/
 
 NMActiveConnectionState
 nm_active_connection_get_state (NMActiveConnection *self)
@@ -171,6 +152,10 @@ nm_active_connection_set_state (NMActiveConnection *self,
 	if (priv->state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED)
 		g_return_if_fail (new_state != NM_ACTIVE_CONNECTION_STATE_DEACTIVATED);
 
+	_LOGD ("set state %s (was %s)",
+	       state_to_string (new_state),
+	       state_to_string (priv->state));
+
 	old_state = priv->state;
 	priv->state = new_state;
 	priv->state_set = TRUE;
@@ -180,7 +165,7 @@ nm_active_connection_set_state (NMActiveConnection *self,
 
 	if (   new_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED
 	    || old_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
-		nm_settings_connection_update_timestamp (NM_SETTINGS_CONNECTION (priv->connection),
+		nm_settings_connection_update_timestamp (priv->settings_connection,
 		                                         (guint64) time (NULL), TRUE);
 	}
 
@@ -213,59 +198,120 @@ nm_active_connection_set_state (NMActiveConnection *self,
 }
 
 const char *
-nm_active_connection_get_id (NMActiveConnection *self)
+nm_active_connection_get_settings_connection_id (NMActiveConnection *self)
 {
+	NMSettingsConnection *con;
+
 	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL);
 
-	return nm_connection_get_id (NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->connection);
+	con = NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->settings_connection;
+	return con
+	       ? nm_connection_get_id (NM_CONNECTION (con))
+	       : NULL;
 }
 
-const char *
-nm_active_connection_get_uuid (NMActiveConnection *self)
+NMSettingsConnection *
+_nm_active_connection_get_settings_connection (NMActiveConnection *self)
 {
 	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL);
 
-	return nm_connection_get_uuid (NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->connection);
+	return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->settings_connection;
 }
 
-NMConnection *
-nm_active_connection_get_connection (NMActiveConnection *self)
+NMSettingsConnection *
+nm_active_connection_get_settings_connection (NMActiveConnection *self)
 {
-	return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->connection;
+	NMSettingsConnection *con;
+
+	con = _nm_active_connection_get_settings_connection (self);
+
+	/* Only call this function on an active-connection that is already
+	 * fully set-up (i.e. that has a settings-connection). Other uses
+	 * indicate a bug. */
+	g_return_val_if_fail (con, NULL);
+	return con;
 }
 
-const char *
-nm_active_connection_get_connection_type (NMActiveConnection *self)
+NMConnection *
+nm_active_connection_get_applied_connection (NMActiveConnection *self)
 {
-	NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
+	NMConnection *con;
+
+	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL);
 
-	if (priv->connection == NULL)
-		return NULL;
+	con = NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->applied_connection;
 
-	return nm_connection_get_connection_type (priv->connection);
+	/* Only call this function on an active-connection that is already
+	 * fully set-up (i.e. that has a settings-connection). Other uses
+	 * indicate a bug. */
+	g_return_val_if_fail (con, NULL);
+	return con;
 }
 
 void
-nm_active_connection_set_connection (NMActiveConnection *self,
-                                     NMConnection *connection)
+nm_active_connection_set_settings_connection (NMActiveConnection *self,
+                                              NMSettingsConnection *connection)
 {
-	NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
+	NMActiveConnectionPrivate *priv;
+
+	g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self));
 
-	/* Can't change connection after the ActiveConnection is exported over D-Bus */
-	g_return_if_fail (priv->path == NULL);
-	g_return_if_fail (priv->connection == NULL || !NM_IS_SETTINGS_CONNECTION (priv->connection));
+	priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
 
-	if (priv->connection)
-		g_object_unref (priv->connection);
-	priv->connection = g_object_ref (connection);
+	g_return_if_fail (NM_IS_SETTINGS_CONNECTION (connection));
+	g_return_if_fail (!priv->settings_connection);
+	g_return_if_fail (!priv->applied_connection);
+
+	/* Can't change connection after the ActiveConnection is exported over D-Bus.
+	 *
+	 * Later, we want to change the settings-connection of an activated connection.
+	 * When doing that, this changes the assumption that the settings-connection
+	 * never changes (once it's set). That has effects for NMVpnConnection and
+	 * NMActivationRequest.
+	 * For example, we'd have to cancel all pending seret requests. */
+	g_return_if_fail (!nm_exported_object_is_exported (NM_EXPORTED_OBJECT (self)));
+
+	priv->settings_connection = g_object_ref (connection);
+	priv->applied_connection = nm_simple_connection_new_clone (NM_CONNECTION (priv->settings_connection));
+	nm_connection_clear_secrets (priv->applied_connection);
 }
 
-const char *
-nm_active_connection_get_path (NMActiveConnection *self)
+gboolean
+nm_active_connection_has_unmodified_applied_connection (NMActiveConnection *self, NMSettingCompareFlags compare_flags)
+{
+	NMActiveConnectionPrivate *priv;
+
+	g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE);
+
+	priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
+
+	g_return_val_if_fail (priv->settings_connection, FALSE);
+
+	return nm_settings_connection_has_unmodified_applied_connection (priv->settings_connection,
+	                                                                 priv->applied_connection,
+	                                                                 compare_flags);
+}
+
+/*******************************************************************/
+
+void
+nm_active_connection_clear_secrets (NMActiveConnection *self)
 {
-	return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->path;
+	NMActiveConnectionPrivate *priv;
+
+	g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self));
+
+	priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
+
+	if (nm_settings_connection_has_unmodified_applied_connection (priv->settings_connection,
+	                                                              priv->applied_connection,
+	                                                              NM_SETTING_COMPARE_FLAG_NONE))
+		nm_connection_clear_secrets ((NMConnection *) priv->settings_connection);
+	nm_connection_clear_secrets (priv->applied_connection);
 }
 
+/*******************************************************************/
+
 const char *
 nm_active_connection_get_specific_object (NMActiveConnection *self)
 {
@@ -341,18 +387,6 @@ nm_active_connection_get_default6 (NMActiveConnection *self)
 	return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->is_default6;
 }
 
-void
-nm_active_connection_export (NMActiveConnection *self)
-{
-	NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
-	static guint32 counter = 0;
-
-	g_assert (priv->device || priv->vpn);
-
-	priv->path = g_strdup_printf (NM_DBUS_PATH "/ActiveConnection/%d", counter++);
-	nm_dbus_manager_register_object (nm_dbus_manager_get (), priv->path, self);
-}
-
 NMAuthSubject *
 nm_active_connection_get_subject (NMActiveConnection *self)
 {
@@ -450,6 +484,14 @@ nm_active_connection_set_device (NMActiveConnection *self, NMDevice *device)
 	if (device == priv->device)
 		return TRUE;
 
+	_LOGD ("set device %s%s%s [%p]",
+	       NM_PRINT_FMT_QUOTED (device && nm_device_get_iface (device),
+	                            "\"",
+	                            nm_device_get_iface (device),
+	                            "\"",
+	                            device ? "(unknown)" : "(null)"),
+	       device);
+
 	old_device = priv->device ? g_object_ref (priv->device) : NULL;
 	_device_cleanup (self);
 
@@ -459,7 +501,7 @@ nm_active_connection_set_device (NMActiveConnection *self, NMDevice *device)
 
 		priv->device = g_object_ref (device);
 
-		g_signal_connect (device, "state-changed",
+		g_signal_connect (device, NM_DEVICE_STATE_CHANGED,
 		                  G_CALLBACK (device_state_changed), self);
 		g_signal_connect (device, "notify::master",
 		                  G_CALLBACK (device_master_changed), self);
@@ -470,8 +512,13 @@ nm_active_connection_set_device (NMActiveConnection *self, NMDevice *device)
 			priv->pending_activation_id = g_strdup_printf ("activation::%p", (void *)self);
 			nm_device_add_pending_action (device, priv->pending_activation_id, TRUE);
 		}
-	} else
+	} else {
+		/* The ActiveConnection's device can only be cleared after the
+		 * connection is activated.
+		 */
+		g_warn_if_fail (priv->state > NM_ACTIVE_CONNECTION_STATE_UNKNOWN);
 		priv->device = NULL;
+	}
 	g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_INT_DEVICE);
 
 	g_signal_emit (self, signals[DEVICE_CHANGED], 0, priv->device, old_device);
@@ -508,34 +555,34 @@ static void
 check_master_ready (NMActiveConnection *self)
 {
 	NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
-	NMActiveConnectionState master_state = NM_ACTIVE_CONNECTION_STATE_UNKNOWN;
-
-	if (priv->state != NM_ACTIVE_CONNECTION_STATE_ACTIVATING) {
-		_LOGD ("not signalling master-ready (not activating)");
-		return;
-	}
-	if (!priv->master) {
-		_LOGD ("not signalling master-ready (no master)");
-		return;
-	}
-	if (priv->master_ready) {
-		_LOGD ("not signalling master-ready (already signaled)");
-		return;
-	}
+	gboolean signalling = FALSE;
 
 	/* ActiveConnetions don't enter the ACTIVATING state until they have a
 	 * NMDevice in PREPARE or higher states, so the master active connection's
 	 * device will be ready to accept slaves when the master is in ACTIVATING
 	 * or higher states.
 	 */
-	master_state = nm_active_connection_get_state (priv->master);
-	_LOGD ("master ActiveConnection [%p] state now '%s' (%d)",
-	       priv->master, state_to_string (master_state), master_state);
-
-	if (   master_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATING
-	    || master_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
-		_LOGD ("signalling master-ready");
+	if (   !priv->master_ready
+	    && priv->master
+	    && priv->state == NM_ACTIVE_CONNECTION_STATE_ACTIVATING
+	    && NM_IN_SET (nm_active_connection_get_state (priv->master),
+	                  NM_ACTIVE_CONNECTION_STATE_ACTIVATING,
+	                  NM_ACTIVE_CONNECTION_STATE_ACTIVATED)) {
+		signalling = TRUE;
+	}
 
+	_LOGD ("check-master-ready: %s (state %s, %s)",
+	       signalling
+	           ? "signal"
+	           : (priv->master_ready ? "already signalled" : "not signalling"),
+	       state_to_string (priv->state),
+	       priv->master
+	           ? nm_sprintf_bufa (128, "master %p is in state %s",
+	                              priv->master,
+	                              state_to_string (nm_active_connection_get_state (priv->master)))
+	           : "no master");
+
+	if (signalling) {
 		priv->master_ready = TRUE;
 		g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_INT_MASTER_READY);
 
@@ -553,17 +600,14 @@ master_state_cb (NMActiveConnection *master,
                  gpointer user_data)
 {
 	NMActiveConnection *self = NM_ACTIVE_CONNECTION (user_data);
-	NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
 	NMActiveConnectionState master_state = nm_active_connection_get_state (master);
+	NMDevice *master_device = nm_active_connection_get_device (master);
 
 	check_master_ready (self);
 
-	_LOGD ("master ActiveConnection [%p] state now '%s' (%d)",
-	       master, state_to_string (master_state), master_state);
-
-	if (   master_state >= NM_ACTIVE_CONNECTION_STATE_DEACTIVATING
-	    && !priv->master_ready) {
-		/* Master failed without ever creating its device */
+	if (   master_state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATING
+	    && (!master_device || !nm_device_is_real (master_device))) {
+		/* Master failed without ever creating or realizing its device */
 		if (NM_ACTIVE_CONNECTION_GET_CLASS (self)->master_failed)
 			NM_ACTIVE_CONNECTION_GET_CLASS (self)->master_failed (self);
 	}
@@ -590,14 +634,16 @@ nm_active_connection_set_master (NMActiveConnection *self, NMActiveConnection *m
 
 	/* Master is write-once, and must be set before exporting the object */
 	g_return_if_fail (priv->master == NULL);
-	g_return_if_fail (priv->path == NULL);
+	g_return_if_fail (!nm_exported_object_is_exported (NM_EXPORTED_OBJECT (self)));
 	if (priv->device) {
 		/* Note, the master ActiveConnection may not yet have a device */
 		g_return_if_fail (priv->device != nm_active_connection_get_device (master));
 	}
 
-	_LOGD ("master ActiveConnection is [%p] %s",
-	       master, nm_active_connection_get_id (master));
+	_LOGD ("set master %p, %s, state %s",
+	       master,
+	       nm_active_connection_get_settings_connection_id (master),
+	       state_to_string (nm_active_connection_get_state (master)));
 
 	priv->master = g_object_ref (master);
 	g_signal_connect (priv->master,
@@ -633,7 +679,7 @@ nm_active_connection_get_assumed (NMActiveConnection *self)
 static void
 auth_done (NMAuthChain *chain,
            GError *error,
-           DBusGMethodInvocation *unused,
+           GDBusMethodInvocation *unused,
            gpointer user_data)
 {
 	NMActiveConnection *self = NM_ACTIVE_CONNECTION (user_data);
@@ -692,6 +738,9 @@ done:
 /**
  * nm_active_connection_authorize:
  * @self: the #NMActiveConnection
+ * @initial_connection: (allow-none): for add-and-activate, there
+ *   is no @settings_connection available when creating the active connection.
+ *   Instead pass an alternative connection.
  * @result_func: function to be called on success or error
  * @user_data1: pointer passed to @result_func
  * @user_data2: additional pointer passed to @result_func
@@ -702,16 +751,29 @@ done:
  */
 void
 nm_active_connection_authorize (NMActiveConnection *self,
+                                NMConnection *initial_connection,
                                 NMActiveConnectionAuthResultFunc result_func,
                                 gpointer user_data1,
                                 gpointer user_data2)
 {
 	NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
 	const char *wifi_permission = NULL;
+	NMConnection *con;
 
 	g_return_if_fail (result_func != NULL);
 	g_return_if_fail (priv->chain == NULL);
 
+	if (initial_connection) {
+		g_return_if_fail (NM_IS_CONNECTION (initial_connection));
+		g_return_if_fail (!priv->settings_connection);
+		g_return_if_fail (!priv->applied_connection);
+		con = initial_connection;
+	} else {
+		g_return_if_fail (NM_IS_SETTINGS_CONNECTION (priv->settings_connection));
+		g_return_if_fail (NM_IS_CONNECTION (priv->applied_connection));
+		con = priv->applied_connection;
+	}
+
 	priv->chain = nm_auth_chain_new_subject (priv->subject, NULL, auth_done, self);
 	g_assert (priv->chain);
 
@@ -719,7 +781,7 @@ nm_active_connection_authorize (NMActiveConnection *self,
 	nm_auth_chain_add_call (priv->chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE);
 
 	/* Shared wifi connections require special permissions too */
-	wifi_permission = nm_utils_get_shared_wifi_permission (priv->connection);
+	wifi_permission = nm_utils_get_shared_wifi_permission (con);
 	if (wifi_permission) {
 		priv->wifi_shared_permission = wifi_permission;
 		nm_auth_chain_add_call (priv->chain, wifi_permission, TRUE);
@@ -736,28 +798,42 @@ nm_active_connection_authorize (NMActiveConnection *self,
 static void
 nm_active_connection_init (NMActiveConnection *self)
 {
+	_LOGT ("creating");
 }
 
 static void
 constructed (GObject *object)
 {
+	NMActiveConnection *self = (NMActiveConnection *) object;
+	NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
+
 	G_OBJECT_CLASS (nm_active_connection_parent_class)->constructed (object);
-	g_assert (NM_ACTIVE_CONNECTION_GET_PRIVATE (object)->subject);
+
+	_LOGD ("constructed (%s)", G_OBJECT_TYPE_NAME (self));
+
+	g_return_if_fail (priv->subject);
 }
 
 static void
 set_property (GObject *object, guint prop_id,
-			  const GValue *value, GParamSpec *pspec)
+              const GValue *value, GParamSpec *pspec)
 {
 	NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object);
 	const char *tmp;
+	NMSettingsConnection *con;
 
 	switch (prop_id) {
-	case PROP_INT_CONNECTION:
-		g_warn_if_fail (priv->connection == NULL);
-		priv->connection = g_value_dup_object (value);
+	case PROP_INT_SETTINGS_CONNECTION:
+		/* construct-only */
+		con = g_value_get_object (value);
+		if (con) {
+			priv->settings_connection = g_object_ref (con);
+			priv->applied_connection = nm_simple_connection_new_clone (NM_CONNECTION (con));
+			nm_connection_clear_secrets (priv->applied_connection);
+		}
 		break;
 	case PROP_INT_DEVICE:
+		/* construct-only */
 		nm_active_connection_set_device (NM_ACTIVE_CONNECTION (object), g_value_get_object (value));
 		break;
 	case PROP_INT_SUBJECT:
@@ -767,10 +843,10 @@ set_property (GObject *object, guint prop_id,
 		nm_active_connection_set_master (NM_ACTIVE_CONNECTION (object), g_value_get_object (value));
 		break;
 	case PROP_SPECIFIC_OBJECT:
-		tmp = g_value_get_boxed (value);
+		tmp = g_value_get_string (value);
 		/* NM uses "/" to mean NULL */
 		if (g_strcmp0 (tmp, "/") != 0)
-			priv->specific_object = g_value_dup_boxed (value);
+			priv->specific_object = g_strdup (tmp);
 		break;
 	case PROP_DEFAULT:
 		priv->is_default = !!g_value_get_boolean (value);
@@ -791,7 +867,7 @@ set_property (GObject *object, guint prop_id,
 
 static void
 get_property (GObject *object, guint prop_id,
-			  GValue *value, GParamSpec *pspec)
+              GValue *value, GParamSpec *pspec)
 {
 	NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object);
 	GPtrArray *devices;
@@ -799,25 +875,26 @@ get_property (GObject *object, guint prop_id,
 
 	switch (prop_id) {
 	case PROP_CONNECTION:
-		g_value_set_boxed (value, nm_connection_get_path (priv->connection));
+		g_value_set_string (value, nm_connection_get_path (NM_CONNECTION (priv->settings_connection)));
 		break;
 	case PROP_ID:
-		g_value_set_string (value, nm_connection_get_id (priv->connection));
+		g_value_set_string (value, nm_connection_get_id (NM_CONNECTION (priv->settings_connection)));
 		break;
 	case PROP_UUID:
-		g_value_set_string (value, nm_connection_get_uuid (priv->connection));
+		g_value_set_string (value, nm_connection_get_uuid (NM_CONNECTION (priv->settings_connection)));
 		break;
 	case PROP_TYPE:
-		g_value_set_string (value, nm_connection_get_connection_type (priv->connection));
+		g_value_set_string (value, nm_connection_get_connection_type (NM_CONNECTION (priv->settings_connection)));
 		break;
 	case PROP_SPECIFIC_OBJECT:
-		g_value_set_boxed (value, priv->specific_object ? priv->specific_object : "/");
+		g_value_set_string (value, priv->specific_object ? priv->specific_object : "/");
 		break;
 	case PROP_DEVICES:
-		devices = g_ptr_array_sized_new (1);
+		devices = g_ptr_array_sized_new (2);
 		if (priv->device && priv->state < NM_ACTIVE_CONNECTION_STATE_DEACTIVATED)
-			g_ptr_array_add (devices, g_strdup (nm_device_get_path (priv->device)));
-		g_value_take_boxed (value, devices);
+			g_ptr_array_add (devices, g_strdup (nm_exported_object_get_path (NM_EXPORTED_OBJECT (priv->device))));
+		g_ptr_array_add (devices, NULL);
+		g_value_take_boxed (value, (char **) g_ptr_array_free (devices, FALSE));
 		break;
 	case PROP_STATE:
 		if (priv->state_set)
@@ -834,19 +911,19 @@ get_property (GObject *object, guint prop_id,
 		break;
 	case PROP_IP4_CONFIG:
 		/* The IP and DHCP config properties may be overridden by a subclass */
-		g_value_set_boxed (value, "/");
+		g_value_set_string (value, "/");
 		break;
 	case PROP_DHCP4_CONFIG:
-		g_value_set_boxed (value, "/");
+		g_value_set_string (value, "/");
 		break;
 	case PROP_DEFAULT6:
 		g_value_set_boolean (value, priv->is_default6);
 		break;
 	case PROP_IP6_CONFIG:
-		g_value_set_boxed (value, "/");
+		g_value_set_string (value, "/");
 		break;
 	case PROP_DHCP6_CONFIG:
-		g_value_set_boxed (value, "/");
+		g_value_set_string (value, "/");
 		break;
 	case PROP_VPN:
 		g_value_set_boolean (value, priv->vpn);
@@ -854,7 +931,7 @@ get_property (GObject *object, guint prop_id,
 	case PROP_MASTER:
 		if (priv->master)
 			master_device = nm_active_connection_get_device (priv->master);
-		g_value_set_boxed (value, master_device ? nm_device_get_path (master_device) : "/");
+		nm_utils_g_value_set_object_path (value, master_device);
 		break;
 	case PROP_INT_SUBJECT:
 		g_value_set_object (value, priv->subject);
@@ -893,17 +970,18 @@ dispose (GObject *object)
 	NMActiveConnection *self = NM_ACTIVE_CONNECTION (object);
 	NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
 
+	_LOGD ("disposing");
+
 	if (priv->chain) {
 		nm_auth_chain_unref (priv->chain);
 		priv->chain = NULL;
 	}
 
-	g_free (priv->path);
-	priv->path = NULL;
 	g_free (priv->specific_object);
 	priv->specific_object = NULL;
 
-	g_clear_object (&priv->connection);
+	g_clear_object (&priv->settings_connection);
+	g_clear_object (&priv->applied_connection);
 
 	_device_cleanup (self);
 
@@ -922,9 +1000,12 @@ static void
 nm_active_connection_class_init (NMActiveConnectionClass *ac_class)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (ac_class);
+	NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (ac_class);
 
 	g_type_class_add_private (ac_class, sizeof (NMActiveConnectionPrivate));
 
+	exported_object_class->export_path = NM_DBUS_PATH "/ActiveConnection/%u";
+
 	/* virtual methods */
 	object_class->get_property = get_property;
 	object_class->set_property = set_property;
@@ -934,10 +1015,10 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class)
 	/* D-Bus exported properties */
 	g_object_class_install_property
 		(object_class, PROP_CONNECTION,
-		 g_param_spec_boxed (NM_ACTIVE_CONNECTION_CONNECTION, "", "",
-		                     DBUS_TYPE_G_OBJECT_PATH,
-		                     G_PARAM_READABLE |
-		                     G_PARAM_STATIC_STRINGS));
+		 g_param_spec_string (NM_ACTIVE_CONNECTION_CONNECTION, "", "",
+		                      NULL,
+		                      G_PARAM_READABLE |
+		                      G_PARAM_STATIC_STRINGS));
 
 	g_object_class_install_property
 		(object_class, PROP_ID,
@@ -962,15 +1043,15 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class)
 
 	g_object_class_install_property
 		(object_class, PROP_SPECIFIC_OBJECT,
-		 g_param_spec_boxed (NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, "", "",
-		                     DBUS_TYPE_G_OBJECT_PATH,
-		                     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
-		                     G_PARAM_STATIC_STRINGS));
+		 g_param_spec_string (NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, "", "",
+		                      NULL,
+		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+		                      G_PARAM_STATIC_STRINGS));
 
 	g_object_class_install_property
 		(object_class, PROP_DEVICES,
 		 g_param_spec_boxed (NM_ACTIVE_CONNECTION_DEVICES, "", "",
-		                     DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH,
+		                     G_TYPE_STRV,
 		                     G_PARAM_READABLE |
 		                     G_PARAM_STATIC_STRINGS));
 
@@ -992,17 +1073,17 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class)
 
 	g_object_class_install_property
 		(object_class, PROP_IP4_CONFIG,
-		 g_param_spec_boxed (NM_ACTIVE_CONNECTION_IP4_CONFIG, "", "",
-		                     DBUS_TYPE_G_OBJECT_PATH,
-		                     G_PARAM_READABLE |
-		                     G_PARAM_STATIC_STRINGS));
+		 g_param_spec_string (NM_ACTIVE_CONNECTION_IP4_CONFIG, "", "",
+		                      NULL,
+		                      G_PARAM_READABLE |
+		                      G_PARAM_STATIC_STRINGS));
 
 	g_object_class_install_property
 		(object_class, PROP_DHCP4_CONFIG,
-		 g_param_spec_boxed (NM_ACTIVE_CONNECTION_DHCP4_CONFIG, "", "",
-		                     DBUS_TYPE_G_OBJECT_PATH,
-		                     G_PARAM_READABLE |
-		                     G_PARAM_STATIC_STRINGS));
+		 g_param_spec_string (NM_ACTIVE_CONNECTION_DHCP4_CONFIG, "", "",
+		                      NULL,
+		                      G_PARAM_READABLE |
+		                      G_PARAM_STATIC_STRINGS));
 
 	g_object_class_install_property
 		(object_class, PROP_DEFAULT6,
@@ -1013,17 +1094,17 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class)
 
 	g_object_class_install_property
 		(object_class, PROP_IP6_CONFIG,
-		 g_param_spec_boxed (NM_ACTIVE_CONNECTION_IP6_CONFIG, "", "",
-		                     DBUS_TYPE_G_OBJECT_PATH,
-		                     G_PARAM_READABLE |
-		                     G_PARAM_STATIC_STRINGS));
+		 g_param_spec_string (NM_ACTIVE_CONNECTION_IP6_CONFIG, "", "",
+		                      NULL,
+		                      G_PARAM_READABLE |
+		                      G_PARAM_STATIC_STRINGS));
 
 	g_object_class_install_property
 		(object_class, PROP_DHCP6_CONFIG,
-		 g_param_spec_boxed (NM_ACTIVE_CONNECTION_DHCP6_CONFIG, "", "",
-		                     DBUS_TYPE_G_OBJECT_PATH,
-		                     G_PARAM_READABLE |
-		                     G_PARAM_STATIC_STRINGS));
+		 g_param_spec_string (NM_ACTIVE_CONNECTION_DHCP6_CONFIG, "", "",
+		                      NULL,
+		                      G_PARAM_READABLE |
+		                      G_PARAM_STATIC_STRINGS));
 
 	g_object_class_install_property
 		(object_class, PROP_VPN,
@@ -1034,24 +1115,24 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class)
 
 	g_object_class_install_property
 		(object_class, PROP_MASTER,
-		 g_param_spec_boxed (NM_ACTIVE_CONNECTION_MASTER, "", "",
-		                     DBUS_TYPE_G_OBJECT_PATH,
-		                     G_PARAM_READABLE |
-		                     G_PARAM_STATIC_STRINGS));
+		 g_param_spec_string (NM_ACTIVE_CONNECTION_MASTER, "", "",
+		                      NULL,
+		                      G_PARAM_READABLE |
+		                      G_PARAM_STATIC_STRINGS));
 
 	/* Internal properties */
 	g_object_class_install_property
-		(object_class, PROP_INT_CONNECTION,
-		 g_param_spec_object (NM_ACTIVE_CONNECTION_INT_CONNECTION, "", "",
-		                      NM_TYPE_CONNECTION,
-		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+		(object_class, PROP_INT_SETTINGS_CONNECTION,
+		 g_param_spec_object (NM_ACTIVE_CONNECTION_INT_SETTINGS_CONNECTION, "", "",
+		                      NM_TYPE_SETTINGS_CONNECTION,
+		                      G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
 		                      G_PARAM_STATIC_STRINGS));
 
 	g_object_class_install_property
 		(object_class, PROP_INT_DEVICE,
 		 g_param_spec_object (NM_ACTIVE_CONNECTION_INT_DEVICE, "", "",
 		                      NM_TYPE_DEVICE,
-		                      G_PARAM_READWRITE |
+		                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
 		                      G_PARAM_STATIC_STRINGS));
 
 	g_object_class_install_property
@@ -1090,8 +1171,8 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class)
 		              NULL, NULL, NULL,
 		              G_TYPE_NONE, 1, G_TYPE_UINT);
 
-	nm_dbus_manager_register_exported_type (nm_dbus_manager_get (),
-	                                        G_TYPE_FROM_CLASS (ac_class),
-	                                        &dbus_glib_nm_active_connection_object_info);
+	nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (ac_class),
+	                                        NMDBUS_TYPE_ACTIVE_CONNECTION_SKELETON,
+	                                        NULL);
 }