summary refs log tree commit diff
path: root/libnm/nm-secret-agent-old.c
diff options
context:
space:
mode:
Diffstat (limited to 'libnm/nm-secret-agent-old.c')
-rw-r--r--libnm/nm-secret-agent-old.c1366
1 files changed, 1366 insertions, 0 deletions
diff --git a/libnm/nm-secret-agent-old.c b/libnm/nm-secret-agent-old.c
new file mode 100644
index 00000000..606c4099
--- /dev/null
+++ b/libnm/nm-secret-agent-old.c
@@ -0,0 +1,1366 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright 2010 - 2011 Red Hat, Inc.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include "nm-glib-compat.h"
+#include "nm-dbus-interface.h"
+#include "nm-secret-agent-old.h"
+#include "nm-enum-types.h"
+#include "nm-dbus-helpers.h"
+#include "nm-simple-connection.h"
+
+#include "nmdbus-secret-agent.h"
+#include "nmdbus-agent-manager.h"
+
+static void nm_secret_agent_old_initable_iface_init (GInitableIface *iface);
+static void nm_secret_agent_old_async_initable_iface_init (GAsyncInitableIface *iface);
+G_DEFINE_ABSTRACT_TYPE_WITH_CODE (NMSecretAgentOld, nm_secret_agent_old, G_TYPE_OBJECT,
+                                  G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, nm_secret_agent_old_initable_iface_init);
+                                  G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, nm_secret_agent_old_async_initable_iface_init);
+                                  )
+
+#define NM_SECRET_AGENT_OLD_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SECRET_AGENT_OLD, NMSecretAgentOldPrivate))
+
+typedef struct {
+	gboolean registered;
+	gboolean registering;
+	NMSecretAgentCapabilities capabilities;
+
+	GDBusConnection *bus;
+	gboolean private_bus;
+	gboolean session_bus;
+	NMDBusAgentManager *manager_proxy;
+	NMDBusSecretAgent *dbus_secret_agent;
+
+	/* GetSecretsInfo structs of in-flight GetSecrets requests */
+	GSList *pending_gets;
+
+	char *identifier;
+	gboolean auto_register;
+	gboolean suppress_auto;
+} NMSecretAgentOldPrivate;
+
+enum {
+	PROP_0,
+	PROP_IDENTIFIER,
+	PROP_AUTO_REGISTER,
+	PROP_REGISTERED,
+	PROP_CAPABILITIES,
+
+	LAST_PROP
+};
+
+/*************************************************************/
+
+static void
+_internal_unregister (NMSecretAgentOld *self)
+{
+	NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE (self);
+
+	if (priv->registered) {
+		g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (priv->dbus_secret_agent));
+		priv->registered = FALSE;
+		priv->registering = FALSE;
+		g_object_notify (G_OBJECT (self), NM_SECRET_AGENT_OLD_REGISTERED);
+	}
+}
+
+typedef struct {
+	char *path;
+	char *setting_name;
+	GDBusMethodInvocation *context;
+} GetSecretsInfo;
+
+static void
+get_secrets_info_finalize (NMSecretAgentOld *self, GetSecretsInfo *info)
+{
+	NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE (self);
+
+	g_return_if_fail (info != NULL);
+
+	priv->pending_gets = g_slist_remove (priv->pending_gets, info);
+
+	g_free (info->path);
+	g_free (info->setting_name);
+	memset (info, 0, sizeof (*info));
+	g_free (info);
+}
+
+static inline gboolean
+should_auto_register (NMSecretAgentOld *self)
+{
+	NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE (self);
+
+	return (   priv->auto_register
+	        && !priv->suppress_auto
+	        && !priv->registered
+	        && !priv->registering);
+}
+
+static void
+name_owner_changed (GObject *proxy,
+                    GParamSpec *pspec,
+                    gpointer user_data)
+{
+	NMSecretAgentOld *self = NM_SECRET_AGENT_OLD (user_data);
+	NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE (self);
+	GSList *iter;
+	char *owner;
+
+	owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (proxy));
+	if (owner != NULL) {
+		if (should_auto_register (self))
+			nm_secret_agent_old_register_async (self, NULL, NULL, NULL);
+		g_free (owner);
+	} else {
+		/* Cancel any pending secrets requests */
+		for (iter = priv->pending_gets; iter; iter = g_slist_next (iter)) {
+			GetSecretsInfo *info = iter->data;
+
+			NM_SECRET_AGENT_OLD_GET_CLASS (self)->cancel_get_secrets (self,
+			                                                      info->path,
+			                                                      info->setting_name);
+		}
+		g_slist_free (priv->pending_gets);
+		priv->pending_gets = NULL;
+
+		_internal_unregister (self);
+	}
+}
+
+static gboolean
+verify_sender (NMSecretAgentOld *self,
+               GDBusMethodInvocation *context,
+               GError **error)
+{
+	NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE (self);
+	char *nm_owner;
+	const char *sender;
+	guint32 sender_uid;
+	GVariant *ret;
+	GError *local = NULL;
+
+	g_return_val_if_fail (context != NULL, FALSE);
+
+	/* Private bus connection is always to NetworkManager, which is always
+	 * UID 0.
+	 */
+	if (priv->private_bus)
+		return TRUE;
+
+	/* Verify that the sender is the same as NetworkManager's bus name owner. */
+
+	nm_owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (priv->manager_proxy));
+	if (!nm_owner) {
+		g_set_error_literal (error,
+		                     NM_SECRET_AGENT_ERROR,
+		                     NM_SECRET_AGENT_ERROR_PERMISSION_DENIED,
+		                     "NetworkManager bus name owner unknown.");
+		return FALSE;
+	}
+
+	sender = g_dbus_method_invocation_get_sender (context);
+	if (!sender) {
+		g_set_error_literal (error,
+		                     NM_SECRET_AGENT_ERROR,
+		                     NM_SECRET_AGENT_ERROR_PERMISSION_DENIED,
+		                     "Failed to get request sender.");
+		g_free (nm_owner);
+		return FALSE;
+	}
+
+	/* Check that the sender matches the current NM bus name owner */
+	if (strcmp (sender, nm_owner) != 0) {
+		g_set_error_literal (error,
+		                     NM_SECRET_AGENT_ERROR,
+		                     NM_SECRET_AGENT_ERROR_PERMISSION_DENIED,
+		                     "Request sender does not match NetworkManager bus name owner.");
+		g_free (nm_owner);
+		return FALSE;
+	}
+	g_free (nm_owner);
+
+	/* If we're connected to the session bus, then this must be a test program,
+	 * so skip the UID check.
+	 */
+	if (priv->session_bus)
+		return TRUE;
+
+	/* Check the UID of the sender */
+	ret = g_dbus_connection_call_sync (priv->bus,
+	                                   DBUS_SERVICE_DBUS,
+	                                   DBUS_PATH_DBUS,
+	                                   DBUS_INTERFACE_DBUS,
+	                                   "GetConnectionUnixUser",
+	                                   g_variant_new ("(s)", sender),
+	                                   G_VARIANT_TYPE ("(u)"),
+	                                   G_DBUS_CALL_FLAGS_NONE, -1,
+	                                   NULL, &local);
+	if (!ret) {
+		char *remote_error = g_dbus_error_get_remote_error (local);
+
+		g_dbus_error_strip_remote_error (local);
+		g_set_error (error,
+		             NM_SECRET_AGENT_ERROR,
+		             NM_SECRET_AGENT_ERROR_PERMISSION_DENIED,
+		             "Failed to request unix user: (%s) %s.",
+		             remote_error ? remote_error : "",
+		             local->message);
+		g_free (remote_error);
+		g_error_free (local);
+		return FALSE;
+	}
+	g_variant_get (ret, "(u)", &sender_uid);
+	g_variant_unref (ret);
+
+	/* We only accept requests from NM, which always runs as root */
+	if (0 != sender_uid) {
+		g_set_error_literal (error,
+		                     NM_SECRET_AGENT_ERROR,
+		                     NM_SECRET_AGENT_ERROR_PERMISSION_DENIED,
+		                     "Request sender is not root.");
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static gboolean
+verify_request (NMSecretAgentOld *self,
+                GDBusMethodInvocation *context,
+                GVariant *connection_dict,
+                const char *connection_path,
+                NMConnection **out_connection,
+                GError **error)
+{
+	NMConnection *connection = NULL;
+	GError *local = NULL;
+
+	if (!verify_sender (self, context, error))
+		return FALSE;
+
+	/* No connection?  If the sender verified, then we allow the request */
+	if (connection_dict == NULL)
+		return TRUE;
+
+	/* If we have a connection dictionary, we require a path too */
+	if (connection_path == NULL) {
+		g_set_error_literal (error,
+		                     NM_SECRET_AGENT_ERROR,
+		                     NM_SECRET_AGENT_ERROR_INVALID_CONNECTION,
+		                     "Invalid connection: no connection path given.");
+		return FALSE;
+	}
+
+	/* Make sure the given connection is valid */
+	g_assert (out_connection);
+	connection = nm_simple_connection_new_from_dbus (connection_dict, &local);
+	if (connection) {
+		nm_connection_set_path (connection, connection_path);
+		*out_connection = connection;
+	} else {
+		g_set_error (error,
+		             NM_SECRET_AGENT_ERROR,
+		             NM_SECRET_AGENT_ERROR_INVALID_CONNECTION,
+		             "Invalid connection: %s", local->message);
+		g_clear_error (&local);
+	}
+
+	return !!connection;
+}
+
+static void
+get_secrets_cb (NMSecretAgentOld *self,
+                NMConnection *connection,
+                GVariant *secrets,
+                GError *error,
+                gpointer user_data)
+{
+	GetSecretsInfo *info = user_data;
+
+	if (error)
+		g_dbus_method_invocation_return_gerror (info->context, error);
+	else {
+		g_dbus_method_invocation_return_value (info->context,
+		                                       g_variant_new ("(@a{sa{sv}})", secrets));
+	}
+
+	/* Remove the request from internal tracking */
+	get_secrets_info_finalize (self, info);
+}
+
+static void
+impl_secret_agent_old_get_secrets (NMSecretAgentOld *self,
+                                   GDBusMethodInvocation *context,
+                                   GVariant *connection_dict,
+                                   const char *connection_path,
+                                   const char *setting_name,
+                                   const char * const *hints,
+                                   guint flags,
+                                   gpointer user_data)
+{
+	NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE (self);
+	GError *error = NULL;
+	NMConnection *connection = NULL;
+	GetSecretsInfo *info;
+
+	/* Make sure the request comes from NetworkManager and is valid */
+	if (!verify_request (self, context, connection_dict, connection_path, &connection, &error)) {
+		g_dbus_method_invocation_take_error (context, error);
+		return;
+	}
+
+	info = g_malloc0 (sizeof (GetSecretsInfo));
+	info->path = g_strdup (connection_path);
+	info->setting_name = g_strdup (setting_name);
+	info->context = context;
+	priv->pending_gets = g_slist_append (priv->pending_gets, info);
+
+	NM_SECRET_AGENT_OLD_GET_CLASS (self)->get_secrets (self,
+	                                               connection,
+	                                               connection_path,
+	                                               setting_name,
+	                                               (const char **) hints,
+	                                               flags,
+	                                               get_secrets_cb,
+	                                               info);
+	g_object_unref (connection);
+}
+
+static GetSecretsInfo *
+find_get_secrets_info (GSList *list, const char *path, const char *setting_name)
+{
+	GSList *iter;
+
+	for (iter = list; iter; iter = g_slist_next (iter)) {
+		GetSecretsInfo *candidate = iter->data;
+
+		if (   g_strcmp0 (path, candidate->path) == 0
+		    && g_strcmp0 (setting_name, candidate->setting_name) == 0)
+			return candidate;
+	}
+	return NULL;
+}
+
+static void
+impl_secret_agent_old_cancel_get_secrets (NMSecretAgentOld *self,
+                                          GDBusMethodInvocation *context,
+                                          const char *connection_path,
+                                          const char *setting_name,
+                                          gpointer user_data)
+{
+	NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE (self);
+	GError *error = NULL;
+	GetSecretsInfo *info;
+
+	/* Make sure the request comes from NetworkManager and is valid */
+	if (!verify_request (self, context, NULL, NULL, NULL, &error)) {
+		g_dbus_method_invocation_take_error (context, error);
+		return;
+	}
+
+	info = find_get_secrets_info (priv->pending_gets, connection_path, setting_name);
+	if (!info) {
+		g_dbus_method_invocation_return_error (context,
+		                                       NM_SECRET_AGENT_ERROR,
+		                                       NM_SECRET_AGENT_ERROR_FAILED,
+		                                       "No secrets request in progress for this connection.");
+		return;
+	}
+
+	/* Send the cancel request up to the subclass and finalize it */
+	NM_SECRET_AGENT_OLD_GET_CLASS (self)->cancel_get_secrets (self,
+	                                                      info->path,
+	                                                      info->setting_name);
+	g_dbus_method_invocation_return_value (context, NULL);
+}
+
+static void
+save_secrets_cb (NMSecretAgentOld *self,
+                 NMConnection *connection,
+                 GError *error,
+                 gpointer user_data)
+{
+	GDBusMethodInvocation *context = user_data;
+
+	if (error)
+		g_dbus_method_invocation_return_gerror (context, error);
+	else
+		g_dbus_method_invocation_return_value (context, NULL);
+}
+
+static void
+impl_secret_agent_old_save_secrets (NMSecretAgentOld *self,
+                                    GDBusMethodInvocation *context,
+                                    GVariant *connection_dict,
+                                    const char *connection_path,
+                                    gpointer user_data)
+{
+	GError *error = NULL;
+	NMConnection *connection = NULL;
+
+	/* Make sure the request comes from NetworkManager and is valid */
+	if (!verify_request (self, context, connection_dict, connection_path, &connection, &error)) {
+		g_dbus_method_invocation_take_error (context, error);
+		return;
+	}
+
+	NM_SECRET_AGENT_OLD_GET_CLASS (self)->save_secrets (self,
+	                                                connection,
+	                                                connection_path,
+	                                                save_secrets_cb,
+	                                                context);
+	g_object_unref (connection);
+}
+
+static void
+delete_secrets_cb (NMSecretAgentOld *self,
+                   NMConnection *connection,
+                   GError *error,
+                   gpointer user_data)
+{
+	GDBusMethodInvocation *context = user_data;
+
+	if (error)
+		g_dbus_method_invocation_return_gerror (context, error);
+	else
+		g_dbus_method_invocation_return_value (context, NULL);
+}
+
+static void
+impl_secret_agent_old_delete_secrets (NMSecretAgentOld *self,
+                                      GDBusMethodInvocation *context,
+                                      GVariant *connection_dict,
+                                      const char *connection_path,
+                                      gpointer user_data)
+{
+	GError *error = NULL;
+	NMConnection *connection = NULL;
+
+	/* Make sure the request comes from NetworkManager and is valid */
+	if (!verify_request (self, context, connection_dict, connection_path, &connection, &error)) {
+		g_dbus_method_invocation_take_error (context, error);
+		return;
+	}
+
+	NM_SECRET_AGENT_OLD_GET_CLASS (self)->delete_secrets (self,
+	                                                  connection,
+	                                                  connection_path,
+	                                                  delete_secrets_cb,
+	                                                  context);
+	g_object_unref (connection);
+}
+
+/**************************************************************/
+
+static gboolean
+check_nm_running (NMSecretAgentOld *self, GError **error)
+{
+	NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE (self);
+	char *owner;
+
+	if (priv->private_bus)
+		return TRUE;
+	owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (priv->manager_proxy));
+	if (owner) {
+		g_free (owner);
+		return TRUE;
+	}
+
+	g_set_error (error, NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_FAILED,
+	             "NetworkManager is not running");
+	return FALSE;
+}
+
+/**************************************************************/
+
+/**
+ * nm_secret_agent_old_register:
+ * @self: a #NMSecretAgentOld
+ * @cancellable: a #GCancellable, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Registers the #NMSecretAgentOld with the NetworkManager secret manager,
+ * indicating to NetworkManager that the agent is able to provide and save
+ * secrets for connections on behalf of its user.
+ *
+ * It is a programmer error to attempt to register an agent that is already
+ * registered, or in the process of registering.
+ *
+ * Returns: %TRUE if registration was successful, %FALSE on error.
+ **/
+gboolean
+nm_secret_agent_old_register (NMSecretAgentOld *self,
+                              GCancellable *cancellable,
+                              GError **error)
+{
+	NMSecretAgentOldPrivate *priv;
+	NMSecretAgentOldClass *class;
+
+	g_return_val_if_fail (NM_IS_SECRET_AGENT_OLD (self), FALSE);
+
+	priv = NM_SECRET_AGENT_OLD_GET_PRIVATE (self);
+
+	g_return_val_if_fail (priv->registered == FALSE, FALSE);
+	g_return_val_if_fail (priv->registering == FALSE, FALSE);
+	g_return_val_if_fail (priv->bus != NULL, FALSE);
+	g_return_val_if_fail (priv->manager_proxy != NULL, FALSE);
+
+	/* Also make sure the subclass can actually respond to secrets requests */
+	class = NM_SECRET_AGENT_OLD_GET_CLASS (self);
+	g_return_val_if_fail (class->get_secrets != NULL, FALSE);
+	g_return_val_if_fail (class->save_secrets != NULL, FALSE);
+	g_return_val_if_fail (class->delete_secrets != NULL, FALSE);
+
+	if (!check_nm_running (self, error))
+		return FALSE;
+
+	priv->suppress_auto = FALSE;
+
+	/* Export our secret agent interface before registering with the manager */
+	if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (priv->dbus_secret_agent),
+	                                       priv->bus,
+	                                       NM_DBUS_PATH_SECRET_AGENT,
+	                                       error))
+		return FALSE;
+
+	priv->registering = TRUE;
+	if (nmdbus_agent_manager_call_register_with_capabilities_sync (priv->manager_proxy,
+	                                                               priv->identifier,
+	                                                               priv->capabilities,
+	                                                               cancellable, NULL))
+		goto success;
+
+	/* Might be an old NetworkManager that doesn't support capabilities;
+	 * fall back to old Register() method instead.
+	 */
+	if (nmdbus_agent_manager_call_register_sync (priv->manager_proxy,
+	                                             priv->identifier,
+	                                             cancellable, NULL))
+		goto success;
+
+	/* Failure */
+	priv->registering = FALSE;
+	_internal_unregister (self);
+	return FALSE;
+
+success:
+	priv->registering = FALSE;
+	priv->registered = TRUE;
+	g_object_notify (G_OBJECT (self), NM_SECRET_AGENT_OLD_REGISTERED);
+	return TRUE;
+}
+
+static void
+reg_result (NMSecretAgentOld *self, GSimpleAsyncResult *simple, GError *error)
+{
+	NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE (self);
+
+	priv->registering = FALSE;
+
+	if (error) {
+		g_simple_async_result_take_error (simple, error);
+		g_simple_async_result_complete (simple);
+
+		/* If registration failed we shouldn't expose ourselves on the bus */
+		_internal_unregister (self);
+	} else {
+		priv->registered = TRUE;
+		g_object_notify (G_OBJECT (self), NM_SECRET_AGENT_OLD_REGISTERED);
+
+		g_simple_async_result_set_op_res_gboolean (simple, TRUE);
+		g_simple_async_result_complete (simple);
+	}
+
+	g_object_unref (simple);
+}
+
+static void
+reg_request_cb (GObject *proxy,
+                GAsyncResult *result,
+                gpointer user_data)
+{
+	GSimpleAsyncResult *simple = user_data;
+	NMSecretAgentOld *self;
+	NMSecretAgentOldPrivate *priv;
+	GError *error = NULL;
+
+	self = NM_SECRET_AGENT_OLD (g_async_result_get_source_object (G_ASYNC_RESULT (simple)));
+	g_object_unref (self); /* drop extra ref added by get_source_object() */
+	priv = NM_SECRET_AGENT_OLD_GET_PRIVATE (self);
+
+	if (!nmdbus_agent_manager_call_register_finish (NMDBUS_AGENT_MANAGER (proxy), result, &error))
+		g_dbus_error_strip_remote_error (error);
+	reg_result (self, simple, error);
+	g_clear_error (&error);
+}
+
+static void
+reg_with_caps_cb (GObject *proxy,
+                  GAsyncResult *result,
+                  gpointer user_data)
+{
+	GSimpleAsyncResult *simple = user_data;
+	NMSecretAgentOld *self;
+	NMSecretAgentOldPrivate *priv;
+
+	self = NM_SECRET_AGENT_OLD (g_async_result_get_source_object (G_ASYNC_RESULT (simple)));
+	g_object_unref (self); /* drop extra ref added by get_source_object() */
+	priv = NM_SECRET_AGENT_OLD_GET_PRIVATE (self);
+
+	if (nmdbus_agent_manager_call_register_with_capabilities_finish (NMDBUS_AGENT_MANAGER (proxy), result, NULL)) {
+		reg_result (self, simple, NULL);
+		return;
+	}
+
+	/* Might be an old NetworkManager that doesn't support capabilities;
+	 * fall back to old Register() method instead.
+	 */
+	nmdbus_agent_manager_call_register (priv->manager_proxy,
+	                                    priv->identifier,
+	                                    NULL, reg_request_cb, simple);
+}
+
+/**
+ * nm_secret_agent_old_register_async:
+ * @self: a #NMSecretAgentOld
+ * @cancellable: a #GCancellable, or %NULL
+ * @callback: callback to call when the agent is registered
+ * @user_data: data for @callback
+ *
+ * Asynchronously registers the #NMSecretAgentOld with the NetworkManager secret
+ * manager, indicating to NetworkManager that the agent is able to provide and
+ * save secrets for connections on behalf of its user.
+ *
+ * It is a programmer error to attempt to register an agent that is already
+ * registered, or in the process of registering.
+ **/
+void
+nm_secret_agent_old_register_async (NMSecretAgentOld *self,
+                                    GCancellable *cancellable,
+                                    GAsyncReadyCallback callback,
+                                    gpointer user_data)
+{
+	NMSecretAgentOldPrivate *priv;
+	NMSecretAgentOldClass *class;
+	GSimpleAsyncResult *simple;
+	GError *error = NULL;
+
+	g_return_if_fail (NM_IS_SECRET_AGENT_OLD (self));
+
+	priv = NM_SECRET_AGENT_OLD_GET_PRIVATE (self);
+
+	g_return_if_fail (priv->registered == FALSE);
+	g_return_if_fail (priv->registering == FALSE);
+	g_return_if_fail (priv->bus != NULL);
+	g_return_if_fail (priv->manager_proxy != NULL);
+
+	/* Also make sure the subclass can actually respond to secrets requests */
+	class = NM_SECRET_AGENT_OLD_GET_CLASS (self);
+	g_return_if_fail (class->get_secrets != NULL);
+	g_return_if_fail (class->save_secrets != NULL);
+	g_return_if_fail (class->delete_secrets != NULL);
+
+	simple = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
+	                                    nm_secret_agent_old_register_async);
+
+	if (!check_nm_running (self, &error)) {
+		g_simple_async_result_take_error (simple, error);
+		g_simple_async_result_complete_in_idle (simple);
+		g_object_unref (simple);
+		return;
+	}
+
+	/* Export our secret agent interface before registering with the manager */
+	if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (priv->dbus_secret_agent),
+	                                       priv->bus,
+	                                       NM_DBUS_PATH_SECRET_AGENT,
+	                                       &error)) {
+		g_simple_async_result_take_error (simple, error);
+		g_simple_async_result_complete_in_idle (simple);
+		g_object_unref (simple);
+		return;
+	}
+
+	priv->suppress_auto = FALSE;
+	priv->registering = TRUE;
+
+	nmdbus_agent_manager_call_register_with_capabilities (priv->manager_proxy,
+	                                                      priv->identifier,
+	                                                      priv->capabilities,
+	                                                      NULL,
+	                                                      reg_with_caps_cb, simple);
+}
+
+/**
+ * nm_secret_agent_old_register_finish:
+ * @self: a #NMSecretAgentOld
+ * @result: the result passed to the #GAsyncReadyCallback
+ * @error: return location for a #GError, or %NULL
+ *
+ * Gets the result of a call to nm_secret_agent_old_register_async().
+ *
+ * Returns: %TRUE if registration was successful, %FALSE on error.
+ **/
+gboolean
+nm_secret_agent_old_register_finish (NMSecretAgentOld *self,
+                                     GAsyncResult *result,
+                                     GError **error)
+{
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self), nm_secret_agent_old_register_async), FALSE);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return FALSE;
+	else
+		return TRUE;
+}
+
+/**
+ * nm_secret_agent_old_unregister:
+ * @self: a #NMSecretAgentOld
+ * @cancellable: a #GCancellable, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Unregisters the #NMSecretAgentOld with the NetworkManager secret manager,
+ * indicating to NetworkManager that the agent will no longer provide or
+ * store secrets on behalf of this user.
+ *
+ * It is a programmer error to attempt to unregister an agent that is not
+ * registered.
+ *
+ * Returns: %TRUE if unregistration was successful, %FALSE on error
+ **/
+gboolean
+nm_secret_agent_old_unregister (NMSecretAgentOld *self,
+                                GCancellable *cancellable,
+                                GError **error)
+{
+	NMSecretAgentOldPrivate *priv;
+	gboolean success;
+
+	g_return_val_if_fail (NM_IS_SECRET_AGENT_OLD (self), FALSE);
+
+	priv = NM_SECRET_AGENT_OLD_GET_PRIVATE (self);
+
+	g_return_val_if_fail (priv->registered == TRUE, FALSE);
+	g_return_val_if_fail (priv->bus != NULL, FALSE);
+	g_return_val_if_fail (priv->manager_proxy != NULL, FALSE);
+
+	priv->suppress_auto = TRUE;
+
+	success = nmdbus_agent_manager_call_unregister_sync (priv->manager_proxy, cancellable, error);
+	if (error && *error)
+		g_dbus_error_strip_remote_error (*error);
+	_internal_unregister (self);
+
+	return success;
+}
+
+static void
+unregister_cb (GObject *proxy, GAsyncResult *result, gpointer user_data)
+{
+	GSimpleAsyncResult *simple = user_data;
+	NMSecretAgentOld *self;
+	GError *error = NULL;
+
+	self = NM_SECRET_AGENT_OLD (g_async_result_get_source_object (G_ASYNC_RESULT (simple)));
+	g_object_unref (self); /* drop extra ref added by get_source_object() */
+
+	_internal_unregister (self);
+
+	if (nmdbus_agent_manager_call_unregister_finish (NMDBUS_AGENT_MANAGER (proxy),
+	                                                 result, &error))
+		g_simple_async_result_set_op_res_gboolean (simple, TRUE);
+	else {
+		g_dbus_error_strip_remote_error (error);
+		g_simple_async_result_take_error (simple, error);
+	}
+
+	g_simple_async_result_complete (simple);
+	g_object_unref (simple);
+}
+
+/**
+ * nm_secret_agent_old_unregister_async:
+ * @self: a #NMSecretAgentOld
+ * @cancellable: a #GCancellable, or %NULL
+ * @callback: callback to call when the agent is unregistered
+ * @user_data: data for @callback
+ *
+ * Asynchronously unregisters the #NMSecretAgentOld with the NetworkManager secret
+ * manager, indicating to NetworkManager that the agent will no longer provide
+ * or store secrets on behalf of this user.
+ *
+ * It is a programmer error to attempt to unregister an agent that is not
+ * registered.
+ **/
+void
+nm_secret_agent_old_unregister_async (NMSecretAgentOld *self,
+                                      GCancellable *cancellable,
+                                      GAsyncReadyCallback callback,
+                                      gpointer user_data)
+{
+	NMSecretAgentOldPrivate *priv;
+	GSimpleAsyncResult *simple;
+	GError *error = NULL;
+
+	g_return_if_fail (NM_IS_SECRET_AGENT_OLD (self));
+
+	priv = NM_SECRET_AGENT_OLD_GET_PRIVATE (self);
+
+	g_return_if_fail (priv->registered == TRUE);
+	g_return_if_fail (priv->bus != NULL);
+	g_return_if_fail (priv->manager_proxy != NULL);
+
+	simple = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
+	                                    nm_secret_agent_old_unregister_async);
+
+	if (!check_nm_running (self, &error)) {
+		g_simple_async_result_take_error (simple, error);
+		g_simple_async_result_complete_in_idle (simple);
+		g_object_unref (simple);
+		return;
+	}
+
+	priv->suppress_auto = TRUE;
+
+	nmdbus_agent_manager_call_unregister (priv->manager_proxy, cancellable,
+	                                      unregister_cb, simple);
+}
+
+/**
+ * nm_secret_agent_old_unregister_finish:
+ * @self: a #NMSecretAgentOld
+ * @result: the result passed to the #GAsyncReadyCallback
+ * @error: return location for a #GError, or %NULL
+ *
+ * Gets the result of a call to nm_secret_agent_old_unregister_async().
+ *
+ * Returns: %TRUE if unregistration was successful, %FALSE on error.
+ **/
+gboolean
+nm_secret_agent_old_unregister_finish (NMSecretAgentOld *self,
+                                       GAsyncResult *result,
+                                       GError **error)
+{
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self), nm_secret_agent_old_unregister_async), FALSE);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return FALSE;
+	else
+		return TRUE;
+}
+
+/**
+ * nm_secret_agent_old_get_registered:
+ * @self: a #NMSecretAgentOld
+ *
+ * Returns: a %TRUE if the agent is registered, %FALSE if it is not.
+ **/
+gboolean
+nm_secret_agent_old_get_registered (NMSecretAgentOld *self)
+{
+	g_return_val_if_fail (NM_IS_SECRET_AGENT_OLD (self), FALSE);
+
+	return NM_SECRET_AGENT_OLD_GET_PRIVATE (self)->registered;
+}
+
+/**************************************************************/
+
+/**
+ * nm_secret_agent_old_get_secrets:
+ * @self: a #NMSecretAgentOld
+ * @connection: the #NMConnection for which we're asked secrets
+ * @setting_name: the name of the secret setting
+ * @hints: (array zero-terminated=1): hints to the agent
+ * @flags: flags that modify the behavior of the request
+ * @callback: (scope async): a callback, to be invoked when the operation is done
+ * @user_data: (closure): caller-specific data to be passed to @callback
+ *
+ * Asynchronously retrieves secrets belonging to @connection for the
+ * setting @setting_name.  @flags indicate specific behavior that the secret
+ * agent should use when performing the request, for example returning only
+ * existing secrets without user interaction, or requesting entirely new
+ * secrets from the user.
+ *
+ * Virtual: get_secrets
+ */
+void
+nm_secret_agent_old_get_secrets (NMSecretAgentOld *self,
+                                 NMConnection *connection,
+                                 const char *setting_name,
+                                 const char **hints,
+                                 NMSecretAgentGetSecretsFlags flags,
+                                 NMSecretAgentOldGetSecretsFunc callback,
+                                 gpointer user_data)
+{
+	g_return_if_fail (NM_IS_SECRET_AGENT_OLD (self));
+	g_return_if_fail (NM_IS_CONNECTION (connection));
+	g_return_if_fail (nm_connection_get_path (connection));
+	g_return_if_fail (setting_name != NULL);
+	g_return_if_fail (strlen (setting_name) > 0);
+	g_return_if_fail (!(flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_ONLY_SYSTEM));
+	g_return_if_fail (!(flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_NO_ERRORS));
+	g_return_if_fail (callback != NULL);
+
+	NM_SECRET_AGENT_OLD_GET_CLASS (self)->get_secrets (self,
+	                                               connection,
+	                                               nm_connection_get_path (connection),
+	                                               setting_name,
+	                                               hints,
+	                                               flags,
+	                                               callback,
+	                                               user_data);
+}
+
+/**
+ * nm_secret_agent_old_save_secrets:
+ * @self: a #NMSecretAgentOld
+ * @connection: a #NMConnection
+ * @callback: (scope async): a callback, to be invoked when the operation is done
+ * @user_data: (closure): caller-specific data to be passed to @callback
+ *
+ * Asynchronously ensures that all secrets inside @connection are stored to
+ * disk.
+ *
+ * Virtual: save_secrets
+ */
+void
+nm_secret_agent_old_save_secrets (NMSecretAgentOld *self,
+                                  NMConnection *connection,
+                                  NMSecretAgentOldSaveSecretsFunc callback,
+                                  gpointer user_data)
+{
+	g_return_if_fail (NM_IS_SECRET_AGENT_OLD (self));
+	g_return_if_fail (NM_IS_CONNECTION (connection));
+	g_return_if_fail (nm_connection_get_path (connection));
+
+	NM_SECRET_AGENT_OLD_GET_CLASS (self)->save_secrets (self,
+	                                                connection,
+	                                                nm_connection_get_path (connection),
+	                                                callback,
+	                                                user_data);
+}
+
+/**
+ * nm_secret_agent_old_delete_secrets:
+ * @self: a #NMSecretAgentOld
+ * @connection: a #NMConnection
+ * @callback: (scope async): a callback, to be invoked when the operation is done
+ * @user_data: (closure): caller-specific data to be passed to @callback
+ *
+ * Asynchronously asks the agent to delete all saved secrets belonging to
+ * @connection.
+ *
+ * Virtual: delete_secrets
+ */
+void
+nm_secret_agent_old_delete_secrets (NMSecretAgentOld *self,
+                                    NMConnection *connection,
+                                    NMSecretAgentOldDeleteSecretsFunc callback,
+                                    gpointer user_data)
+{
+	g_return_if_fail (NM_IS_SECRET_AGENT_OLD (self));
+	g_return_if_fail (NM_IS_CONNECTION (connection));
+	g_return_if_fail (nm_connection_get_path (connection));
+
+	NM_SECRET_AGENT_OLD_GET_CLASS (self)->delete_secrets (self,
+	                                                  connection,
+	                                                  nm_connection_get_path (connection),
+	                                                  callback,
+	                                                  user_data);
+}
+
+/**************************************************************/
+
+static gboolean
+validate_identifier (const char *identifier)
+{
+	const char *p = identifier;
+	size_t id_len;
+
+	/* Length between 3 and 255 characters inclusive */
+	id_len = strlen (identifier);
+	if (id_len < 3 || id_len > 255)
+		return FALSE;
+
+	if ((identifier[0] == '.') || (identifier[id_len - 1] == '.'))
+		return FALSE;
+
+	/* FIXME: do complete validation here */
+	while (p && *p) {
+		if (!g_ascii_isalnum (*p) && (*p != '_') && (*p != '-') && (*p != '.'))
+			return FALSE;
+		if ((*p == '.') && (*(p + 1) == '.'))
+			return FALSE;
+		p++;
+	}
+
+	return TRUE;
+}
+
+static void
+nm_secret_agent_old_init (NMSecretAgentOld *self)
+{
+	NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE (self);
+
+	priv->dbus_secret_agent = nmdbus_secret_agent_skeleton_new ();
+	_nm_dbus_bind_properties (self, priv->dbus_secret_agent);
+	_nm_dbus_bind_methods (self, priv->dbus_secret_agent,
+	                       "GetSecrets", impl_secret_agent_old_get_secrets,
+	                       "CancelGetSecrets", impl_secret_agent_old_cancel_get_secrets,
+	                       "DeleteSecrets", impl_secret_agent_old_delete_secrets,
+	                       "SaveSecrets", impl_secret_agent_old_save_secrets,
+	                       NULL);
+}
+
+static void
+init_common (NMSecretAgentOld *self)
+{
+	NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE (self);
+
+	priv->private_bus = _nm_dbus_is_connection_private (priv->bus);
+
+	if (priv->private_bus == FALSE) {
+		priv->session_bus = _nm_dbus_bus_type () == G_BUS_TYPE_SESSION;
+
+		g_signal_connect (priv->manager_proxy, "notify::g-name-owner",
+		                  G_CALLBACK (name_owner_changed), self);
+	}
+}
+
+static gboolean
+init_sync (GInitable *initable, GCancellable *cancellable, GError **error)
+{
+	NMSecretAgentOld *self = NM_SECRET_AGENT_OLD (initable);
+	NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE (self);
+	GDBusProxy *proxy;
+
+	priv->bus = _nm_dbus_new_connection (cancellable, error);
+	if (!priv->bus)
+		return FALSE;
+
+	proxy = _nm_dbus_new_proxy_for_connection (priv->bus,
+	                                           NM_DBUS_PATH_AGENT_MANAGER,
+	                                           NM_DBUS_INTERFACE_AGENT_MANAGER,
+	                                           cancellable, error);
+	if (!proxy)
+		return FALSE;
+	priv->manager_proxy = NMDBUS_AGENT_MANAGER (proxy);
+
+	init_common (self);
+
+	if (priv->auto_register)
+		return nm_secret_agent_old_register (self, cancellable, error);
+	else
+		return TRUE;
+}
+
+typedef struct {
+	NMSecretAgentOld *self;
+	GCancellable *cancellable;
+	GSimpleAsyncResult *simple;
+} NMSecretAgentOldInitData;
+
+static void
+init_async_complete (NMSecretAgentOldInitData *init_data, GError *error)
+{
+	if (!error)
+		g_simple_async_result_set_op_res_gboolean (init_data->simple, TRUE);
+	else
+		g_simple_async_result_take_error (init_data->simple, error);
+
+	g_simple_async_result_complete_in_idle (init_data->simple);
+
+	g_object_unref (init_data->simple);
+	g_clear_object (&init_data->cancellable);
+	g_slice_free (NMSecretAgentOldInitData, init_data);
+}
+
+static void
+init_async_registered (GObject *object, GAsyncResult *result, gpointer user_data)
+{
+	NMSecretAgentOld *self = NM_SECRET_AGENT_OLD (object);
+	NMSecretAgentOldInitData *init_data = user_data;
+	GError *error = NULL;
+
+	nm_secret_agent_old_register_finish (self, result, &error);
+	init_async_complete (init_data, error);
+}
+
+static void
+init_async_got_proxy (GObject *object, GAsyncResult *result, gpointer user_data)
+{
+	NMSecretAgentOldInitData *init_data = user_data;
+	NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE (init_data->self);
+	GDBusProxy *proxy;
+	GError *error = NULL;
+
+	proxy = _nm_dbus_new_proxy_for_connection_finish (result, &error);
+	if (!proxy) {
+		init_async_complete (init_data, error);
+		return;
+	}
+	priv->manager_proxy = NMDBUS_AGENT_MANAGER (proxy);
+
+	init_common (init_data->self);
+
+	if (priv->auto_register) {
+		nm_secret_agent_old_register_async (init_data->self, init_data->cancellable,
+		                                init_async_registered, init_data);
+	} else
+		init_async_complete (init_data, NULL);
+}
+
+static void
+init_async_got_bus (GObject *initable, GAsyncResult *result, gpointer user_data)
+{
+	NMSecretAgentOldInitData *init_data = user_data;
+	NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE (init_data->self);
+	GError *error = NULL;
+
+	priv->bus = _nm_dbus_new_connection_finish (result, &error);
+	if (!priv->bus) {
+		init_async_complete (init_data, error);
+		return;
+	}
+
+	_nm_dbus_new_proxy_for_connection_async (priv->bus,
+	                                         NM_DBUS_PATH_AGENT_MANAGER,
+	                                         NM_DBUS_INTERFACE_AGENT_MANAGER,
+	                                         init_data->cancellable,
+	                                         init_async_got_proxy, init_data);
+}
+
+static void
+init_async (GAsyncInitable *initable, int io_priority,
+            GCancellable *cancellable, GAsyncReadyCallback callback,
+            gpointer user_data)
+{
+	NMSecretAgentOld *self = NM_SECRET_AGENT_OLD (initable);
+	NMSecretAgentOldInitData *init_data;
+
+	init_data = g_slice_new (NMSecretAgentOldInitData);
+	init_data->self = self;
+	init_data->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+
+	init_data->simple = g_simple_async_result_new (G_OBJECT (initable), callback,
+	                                               user_data, init_async);
+
+	_nm_dbus_new_connection_async (cancellable, init_async_got_bus, init_data);
+}
+
+static gboolean
+init_finish (GAsyncInitable *initable, GAsyncResult *result, GError **error)
+{
+	GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	if (g_simple_async_result_propagate_error (simple, error))
+		return FALSE;
+	else
+		return TRUE;
+}
+
+static void
+get_property (GObject *object,
+              guint prop_id,
+              GValue *value,
+              GParamSpec *pspec)
+{
+	NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_IDENTIFIER:
+		g_value_set_string (value, priv->identifier);
+		break;
+	case PROP_AUTO_REGISTER:
+		g_value_set_boolean (value, priv->auto_register);
+		break;
+	case PROP_REGISTERED:
+		g_value_set_boolean (value, priv->registered);
+		break;
+	case PROP_CAPABILITIES:
+		g_value_set_flags (value, priv->capabilities);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+set_property (GObject *object,
+              guint prop_id,
+              const GValue *value,
+              GParamSpec *pspec)
+{
+	NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE (object);
+	const char *identifier;
+
+	switch (prop_id) {
+	case PROP_IDENTIFIER:
+		identifier = g_value_get_string (value);
+
+		g_return_if_fail (validate_identifier (identifier));
+
+		g_free (priv->identifier);
+		priv->identifier = g_strdup (identifier);
+		break;
+	case PROP_AUTO_REGISTER:
+		priv->auto_register = g_value_get_boolean (value);
+		break;
+	case PROP_CAPABILITIES:
+		priv->capabilities = g_value_get_flags (value);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+dispose (GObject *object)
+{
+	NMSecretAgentOld *self = NM_SECRET_AGENT_OLD (object);
+	NMSecretAgentOldPrivate *priv = NM_SECRET_AGENT_OLD_GET_PRIVATE (self);
+
+	if (priv->registered)
+		nm_secret_agent_old_unregister_async (self, NULL, NULL, NULL);
+
+	g_clear_pointer (&priv->identifier, g_free);
+
+	while (priv->pending_gets)
+		get_secrets_info_finalize (self, priv->pending_gets->data);
+
+	g_signal_handlers_disconnect_matched (priv->dbus_secret_agent, G_SIGNAL_MATCH_DATA,
+	                                      0, 0, NULL, NULL, self);
+	g_object_unref (priv->dbus_secret_agent);
+
+	g_clear_object (&priv->manager_proxy);
+	g_clear_object (&priv->bus);
+
+	G_OBJECT_CLASS (nm_secret_agent_old_parent_class)->dispose (object);
+}
+
+static void
+nm_secret_agent_old_class_init (NMSecretAgentOldClass *class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+	g_type_class_add_private (class, sizeof (NMSecretAgentOldPrivate));
+
+	/* Virtual methods */
+	object_class->dispose = dispose;
+	object_class->get_property = get_property;
+	object_class->set_property = set_property;
+
+	/**
+	 * NMSecretAgentOld:identifier:
+	 *
+	 * Identifies this agent; only one agent in each user session may use the
+	 * same identifier.  Identifier formatting follows the same rules as
+	 * D-Bus bus names with the exception that the ':' character is not
+	 * allowed.  The valid set of characters is "[A-Z][a-z][0-9]_-." and the
+	 * identifier is limited in length to 255 characters with a minimum
+	 * of 3 characters.  An example valid identifier is 'org.gnome.nm-applet'
+	 * (without quotes).
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_IDENTIFIER,
+		 g_param_spec_string (NM_SECRET_AGENT_OLD_IDENTIFIER, "", "",
+		                      NULL,
+		                      G_PARAM_READWRITE |
+		                      G_PARAM_CONSTRUCT_ONLY |
+		                      G_PARAM_STATIC_STRINGS));
+
+	/**
+	 * NMSecretAgentOld:auto-register:
+	 *
+	 * If %TRUE (the default), the agent will always be registered when
+	 * NetworkManager is running; if NetworkManager exits and restarts, the
+	 * agent will re-register itself automatically.
+	 *
+	 * In particular, if this property is %TRUE at construct time, then the
+	 * agent will register itself with NetworkManager during
+	 * construction/initialization, and initialization will fail with an error
+	 * if the agent is unable to register itself.
+	 *
+	 * If the property is %FALSE, the agent will not automatically register with
+	 * NetworkManager, and nm_secret_agent_old_register() or
+	 * nm_secret_agent_old_register_async() must be called to register it.
+	 *
+	 * Calling nm_secret_agent_old_unregister() will suppress auto-registration
+	 * until nm_secret_agent_old_register() is called, which re-enables
+	 * auto-registration. This ensures that the agent remains un-registered when
+	 * you expect it to be unregistered.
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_AUTO_REGISTER,
+		 g_param_spec_boolean (NM_SECRET_AGENT_OLD_AUTO_REGISTER, "", "",
+		                       TRUE,
+		                       G_PARAM_READWRITE |
+		                       G_PARAM_CONSTRUCT |
+		                       G_PARAM_STATIC_STRINGS));
+
+	/**
+	 * NMSecretAgentOld:registered:
+	 *
+	 * %TRUE if the agent is registered with NetworkManager, %FALSE if not.
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_REGISTERED,
+		 g_param_spec_boolean (NM_SECRET_AGENT_OLD_REGISTERED, "", "",
+		                       FALSE,
+		                       G_PARAM_READABLE |
+		                       G_PARAM_STATIC_STRINGS));
+
+	/**
+	 * NMSecretAgentOld:capabilities:
+	 *
+	 * A bitfield of %NMSecretAgentCapabilities.
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_CAPABILITIES,
+		 g_param_spec_flags (NM_SECRET_AGENT_OLD_CAPABILITIES, "", "",
+		                     NM_TYPE_SECRET_AGENT_CAPABILITIES,
+		                     NM_SECRET_AGENT_CAPABILITY_NONE,
+		                     G_PARAM_READWRITE |
+		                     G_PARAM_CONSTRUCT |
+		                     G_PARAM_STATIC_STRINGS));
+
+	_nm_dbus_register_proxy_type (NM_DBUS_INTERFACE_AGENT_MANAGER,
+	                              NMDBUS_TYPE_AGENT_MANAGER_PROXY);
+}
+
+static void
+nm_secret_agent_old_initable_iface_init (GInitableIface *iface)
+{
+	iface->init = init_sync;
+}
+
+static void
+nm_secret_agent_old_async_initable_iface_init (GAsyncInitableIface *iface)
+{
+	iface->init_async = init_async;
+	iface->init_finish = init_finish;
+}