diff --git a/include/NetworkManager.h b/include/NetworkManager.h index ea05c1f49..558eb3e40 100644 --- a/include/NetworkManager.h +++ b/include/NetworkManager.h @@ -55,6 +55,9 @@ #define NM_DBUS_INTERFACE_AGENT_MANAGER NM_DBUS_INTERFACE ".AgentManager" #define NM_DBUS_PATH_AGENT_MANAGER "/org/freedesktop/NetworkManager/AgentManager" +#define NM_DBUS_INTERFACE_SECRET_AGENT NM_DBUS_INTERFACE ".SecretAgent" +#define NM_DBUS_PATH_SECRET_AGENT "/org/freedesktop/NetworkManager/SecretAgent" + /* * Types of NetworkManager states */ diff --git a/introspection/nm-secret-agent.xml b/introspection/nm-secret-agent.xml new file mode 100644 index 000000000..bfab5852c --- /dev/null +++ b/introspection/nm-secret-agent.xml @@ -0,0 +1,106 @@ + + + + + + + Private D-Bus interface used by secret agents that store and provide + secrets to NetworkManager. + + + + + Retrieve and return stored secrets, if any, or request new + secrets from the agent's user. + + + + + + Nested settings maps containing the connection for which + secrets are being requested. + + + + + Object path of the connection for which secrets are being + requested. + + + + + Setting name for which secrets are being requested. + + + + + Array of strings of key names in the requested setting for + which NetworkManager thinks a secrets may be required. The + Agent should return any secrets it has, or that it thinks + are required, regardless of what hints NetworkManager sends + in this request. + + + + + If true, new secrets are assumed to be invalid or incorrect, + and the agent should ask the user for new secrets. If false, + existing secrets should be retrieved from storage and + returned without interrupting the user. + + + + + + Nested settings maps containing secrets. Each setting MUST + contain at least the 'name' field, containing the name of + the setting, and one or more secrets. + + + + + + + Save given secrets to backing storage. + + + + + + Nested settings maps containing the entire connection + (including secrets), for which the agent should save the + secrets to backing storage. + + + + + Object path of the connection for which the agent should + save secrets to backing storage. + + + + + + + Delete secrets from backing storage. + + + + + + Nested settings maps containing the entire connection + (including secrets), for which the agent should delete the + secrets from backing storage. + + + + + Object path of the connection for which the agent should + delete secrets from backing storage. + + + + + + + diff --git a/libnm-glib/Makefile.am b/libnm-glib/Makefile.am index aa6f95960..5a6045ebc 100644 --- a/libnm-glib/Makefile.am +++ b/libnm-glib/Makefile.am @@ -18,7 +18,8 @@ BUILT_SOURCES = \ nm-ip4-config-bindings.h \ nm-dhcp4-config-bindings.h \ nm-ip6-config-bindings.h \ - nm-dhcp6-config-bindings.h + nm-dhcp6-config-bindings.h \ + nm-secret-agent-glue.h ##################################################### # Deprecated original libnm_glib bits @@ -76,7 +77,8 @@ libnminclude_HEADERS = \ nm-ip6-config.h \ nm-dhcp6-config.h \ nm-remote-connection.h \ - nm-remote-settings.h + nm-remote-settings.h \ + nm-secret-agent.h libnm_glib_la_SOURCES = \ nm-object.c \ @@ -105,7 +107,8 @@ libnm_glib_la_SOURCES = \ nm-dhcp6-config.c \ nm-remote-connection.c \ nm-remote-connection-private.h \ - nm-remote-settings.c + nm-remote-settings.c \ + nm-secret-agent.c libnm_glib_la_LIBADD = \ $(top_builddir)/libnm-util/libnm-util.la \ @@ -178,6 +181,9 @@ nm-ip6-config-bindings.h: $(top_srcdir)/introspection/nm-ip6-config.xml nm-dhcp6-config-bindings.h: $(top_srcdir)/introspection/nm-dhcp6-config.xml $(AM_V_GEN) dbus-binding-tool --prefix=nm_dhcp6_config --mode=glib-client --output=$@ $< +nm-secret-agent-glue.h: $(top_srcdir)/introspection/nm-secret-agent.xml + $(AM_V_GEN) dbus-binding-tool --prefix=nm_secret_agent --mode=glib-server --output=$@ $< + pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libnm-glib.pc libnm-glib-vpn.pc diff --git a/libnm-glib/nm-secret-agent.c b/libnm-glib/nm-secret-agent.c new file mode 100644 index 000000000..68d6af9cf --- /dev/null +++ b/libnm-glib/nm-secret-agent.c @@ -0,0 +1,638 @@ +/* -*- 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. + * + * (C) Copyright 2010 Red Hat, Inc. + */ + +#include +#include +#include +#include +#include + +#include "nm-secret-agent.h" +#include "nm-marshal.h" +#include "NetworkManager.h" + +static void impl_secret_agent_get_secrets (NMSecretAgent *self, + GHashTable *connection_hash, + const char *connection_path, + const char *setting_name, + const char **hints, + gboolean request_new, + DBusGMethodInvocation *context); + +static void impl_secret_agent_save_secrets (NMSecretAgent *self, + GHashTable *connection_hash, + const char *connection_path, + DBusGMethodInvocation *context); + +static void impl_secret_agent_delete_secrets (NMSecretAgent *self, + GHashTable *connection_hash, + const char *connection_path, + DBusGMethodInvocation *context); + +#include "nm-secret-agent-glue.h" + +G_DEFINE_TYPE (NMSecretAgent, nm_secret_agent, G_TYPE_OBJECT) + +#define NM_SECRET_AGENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ + NM_TYPE_SECRET_AGENT, \ + NMSecretAgentPrivate)) + +typedef struct { + gboolean registered; + + DBusGConnection *bus; + DBusGProxy *dbus_proxy; + DBusGProxy *manager_proxy; + DBusGProxyCall *reg_call; + + char *nm_owner; + + char *identifier; + + gboolean disposed; +} NMSecretAgentPrivate; + +enum { + PROP_0, + PROP_IDENTIFIER, + + LAST_PROP +}; + +enum { + REGISTRATION_RESULT, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + + +/********************************************************************/ + +GQuark +nm_secret_agent_error_quark (void) +{ + static GQuark ret = 0; + + if (G_UNLIKELY (ret == 0)) + ret = g_quark_from_static_string ("nm-secret-agent-error"); + return ret; +} + +#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } + +GType +nm_secret_agent_error_get_type (void) +{ + static GType etype = 0; + + if (etype == 0) { + static const GEnumValue values[] = { + /* Sender is not authorized to make this request */ + ENUM_ENTRY (NM_SECRET_AGENT_ERROR_NOT_AUTHORIZED, "NotAuthorized"), + /* Given connection details do not make a valid connection */ + ENUM_ENTRY (NM_SECRET_AGENT_ERROR_INVALID_CONNECTION, "InvalidConnection"), + /* The request was canceled explicitly by the user */ + ENUM_ENTRY (NM_SECRET_AGENT_ERROR_USER_CANCELED, "UserCanceled"), + /* The request was canceled, but not by the user */ + ENUM_ENTRY (NM_SECRET_AGENT_ERROR_AGENT_CANCELED, "AgentCanceled"), + { 0, 0, 0 } + }; + etype = g_enum_register_static ("NMSecretAgentError", values); + } + return etype; +} + +/*************************************************************/ + +static const char * +get_nm_owner (NMSecretAgent *self) +{ + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); + GError *error = NULL; + char *owner; + + if (!priv->nm_owner) { + if (!dbus_g_proxy_call_with_timeout (priv->dbus_proxy, + "GetNameOwner", 2000, &error, + G_TYPE_STRING, NM_DBUS_SERVICE, + G_TYPE_INVALID, + G_TYPE_STRING, &owner, + G_TYPE_INVALID)) + return NULL; + + priv->nm_owner = g_strdup (owner); + g_free (owner); + } + + return priv->nm_owner; +} + +static void +name_owner_changed (DBusGProxy *proxy, + const char *name, + const char *old_owner, + const char *new_owner, + gpointer user_data) +{ + NMSecretAgent *self = NM_SECRET_AGENT (user_data); + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); + + if (strcmp (name, NM_DBUS_SERVICE) == 0) { + g_free (priv->nm_owner); + priv->nm_owner = g_strdup (new_owner); + } +} + +static NMConnection * +verify_request (NMSecretAgent *self, + DBusGMethodInvocation *context, + GHashTable *connection_hash, + GError **error) +{ + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); + NMConnection *connection = NULL; + DBusConnection *bus; + char *sender; + const char *nm_owner; + DBusError dbus_error; + uid_t sender_uid = G_MAXUINT; + GError *local = NULL; + + g_return_val_if_fail (context != NULL, NULL); + g_return_val_if_fail (connection_hash != NULL, NULL); + + /* Verify the sender's UID is 0, and that the sender is the same as + * NetworkManager's bus name owner. + */ + + nm_owner = get_nm_owner (self); + if (!nm_owner) { + g_set_error_literal (error, + NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_NOT_AUTHORIZED, + "NetworkManager bus name owner unknown."); + return FALSE; + } + + bus = dbus_g_connection_get_connection (priv->bus); + if (!bus) { + g_set_error_literal (error, + NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_NOT_AUTHORIZED, + "Failed to get DBus connection."); + return FALSE; + } + + sender = dbus_g_method_get_sender (context); + if (!sender) { + g_set_error_literal (error, + NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_NOT_AUTHORIZED, + "Failed to get request sender."); + 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_NOT_AUTHORIZED, + "Request sender does not match NetworkManager bus name owner."); + goto out; + } + + dbus_error_init (&dbus_error); + sender_uid = dbus_bus_get_unix_user (bus, sender, &dbus_error); + if (dbus_error_is_set (&dbus_error)) { + g_set_error (error, + NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_NOT_AUTHORIZED, + "Failed to get request unix user: (%s) %s.", + dbus_error.name, dbus_error.message); + dbus_error_free (&dbus_error); + goto out; + } + + if (0 != sender_uid) { + g_set_error_literal (error, + NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_NOT_AUTHORIZED, + "Request sender is not root."); + goto out; + } + + /* And make sure the connection is actually valid */ + connection = nm_connection_new_from_hash (connection_hash, &local); + if (!connection) { + g_set_error (error, + NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_INVALID_CONNECTION, + "Invalid connection: (%d) %s", + local ? local->code : -1, + (local && local->message) ? local->message : "(unknown)"); + g_clear_error (&local); + } + + +out: + g_free (sender); + return connection; +} + +static void +impl_secret_agent_get_secrets (NMSecretAgent *self, + GHashTable *connection_hash, + const char *connection_path, + const char *setting_name, + const char **hints, + gboolean request_new, + DBusGMethodInvocation *context) +{ + GError *error = NULL; + NMConnection *connection; + + /* Make sure the request comes from NetworkManager and is valid */ + connection = verify_request (self, context, connection_hash, &error); + if (!connection) { + dbus_g_method_return_error (context, error); + g_clear_error (&error); + return; + } + + NM_SECRET_AGENT_GET_CLASS (self)->get_secrets (self, + connection, + connection_path, + setting_name, + hints, + request_new, + context); + g_object_unref (connection); +} + +static void +impl_secret_agent_save_secrets (NMSecretAgent *self, + GHashTable *connection_hash, + const char *connection_path, + DBusGMethodInvocation *context) +{ + GError *error = NULL; + NMConnection *connection; + + /* Make sure the request comes from NetworkManager and is valid */ + connection = verify_request (self, context, connection_hash, &error); + if (!connection) { + dbus_g_method_return_error (context, error); + g_clear_error (&error); + return; + } + + NM_SECRET_AGENT_GET_CLASS (self)->save_secrets (self, + connection, + connection_path, + context); + g_object_unref (connection); +} + +static void +impl_secret_agent_delete_secrets (NMSecretAgent *self, + GHashTable *connection_hash, + const char *connection_path, + DBusGMethodInvocation *context) +{ + GError *error = NULL; + NMConnection *connection; + + /* Make sure the request comes from NetworkManager and is valid */ + connection = verify_request (self, context, connection_hash, &error); + if (!connection) { + dbus_g_method_return_error (context, error); + g_clear_error (&error); + return; + } + + NM_SECRET_AGENT_GET_CLASS (self)->delete_secrets (self, + connection, + connection_path, + context); + g_object_unref (connection); +} + +/**************************************************************/ + +static void +reg_request_cb (DBusGProxy *proxy, + DBusGProxyCall *call, + gpointer user_data) +{ + NMSecretAgent *self = NM_SECRET_AGENT (user_data); + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); + GError *error = NULL; + + priv->reg_call = NULL; + + if (dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID)) + priv->registered = TRUE; + else { + /* If registration failed we shouldn't expose ourselves on the bus */ + dbus_g_connection_unregister_g_object (priv->bus, G_OBJECT (self)); + } + + g_signal_emit (self, signals[REGISTRATION_RESULT], 0, error); + g_clear_error (&error); +} + +/** + * nm_secret_agent_register: + * + * Registers the #NMSecretAgent 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. Registration is an + * asynchronous operation and its success or failure is indicated via the + * 'registration-result' signal. + * + * Returns: a new %TRUE if registration was successfully requested (this does + * not mean registration itself was successful), %FALSE if registration was not + * successfully requested. + **/ +gboolean +nm_secret_agent_register (NMSecretAgent *self) +{ + NMSecretAgentPrivate *priv; + NMSecretAgentClass *class; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (NM_IS_SECRET_AGENT (self), FALSE); + + priv = NM_SECRET_AGENT_GET_PRIVATE (self); + + g_return_val_if_fail (priv->registered == FALSE, FALSE); + g_return_val_if_fail (priv->reg_call == NULL, 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_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); + + /* Export our secret agent interface before registering with the manager */ + dbus_g_connection_register_g_object (priv->bus, + NM_DBUS_PATH_SECRET_AGENT, + G_OBJECT (self)); + + priv->reg_call = dbus_g_proxy_begin_call_with_timeout (priv->manager_proxy, + "Register", + reg_request_cb, + self, + NULL, + G_USEC_PER_SEC * 5, + G_TYPE_STRING, priv->identifier, + G_TYPE_INVALID); + + return TRUE; +} + +/** + * nm_secret_agent_unregister: + * + * Unregisters the #NMSecretAgent with the NetworkManager secret manager, + * indicating to NetworkManager that the agent is will no longer provide or + * store secrets on behalf of this user. + * + * Returns: a new %TRUE if unregistration was successful, %FALSE if it was not. + **/ +gboolean +nm_secret_agent_unregister (NMSecretAgent *self) +{ + NMSecretAgentPrivate *priv; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (NM_IS_SECRET_AGENT (self), FALSE); + + priv = NM_SECRET_AGENT_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); + + dbus_g_proxy_call_no_reply (priv->manager_proxy, "Unregister", G_TYPE_INVALID); + + return TRUE; +} + +/**************************************************************/ + +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 (!isalnum (*p) && (*p != '_') && (*p != '-')) + return FALSE; + if ((*p == '.') && (*(p + 1) == '.')) + return FALSE; + } + + return TRUE; +} + +static void +nm_secret_agent_init (NMSecretAgent *self) +{ + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); + GError *error = NULL; + + priv->bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); + if (!priv->bus) { + g_warning ("Couldn't connect to system bus: %s", error->message); + g_error_free (error); + return; + } + + priv->dbus_proxy = dbus_g_proxy_new_for_name (priv->bus, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS); + if (!priv->dbus_proxy) { + g_warning ("Couldn't create messagebus proxy."); + return; + } + + dbus_g_object_register_marshaller (_nm_marshal_VOID__STRING_STRING_STRING, + G_TYPE_NONE, + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_INVALID); + dbus_g_proxy_add_signal (priv->dbus_proxy, "NameOwnerChanged", + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_INVALID); + dbus_g_proxy_connect_signal (priv->dbus_proxy, + "NameOwnerChanged", + G_CALLBACK (name_owner_changed), + self, NULL); + + priv->manager_proxy = dbus_g_proxy_new_for_name (priv->bus, + NM_DBUS_SERVICE, + NM_DBUS_PATH_AGENT_MANAGER, + NM_DBUS_INTERFACE_AGENT_MANAGER); + if (!priv->manager_proxy) { + g_warning ("Couldn't create NM agent manager proxy."); + return; + } +} + +static void +get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_IDENTIFIER: + g_value_set_string (value, priv->identifier); + 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) +{ + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_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; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +dispose (GObject *object) +{ + NMSecretAgent *self = NM_SECRET_AGENT (object); + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); + + if (!priv->disposed) { + priv->disposed = TRUE; + + if (priv->registered) + nm_secret_agent_unregister (self); + + g_free (priv->identifier); + g_free (priv->nm_owner); + + if (priv->dbus_proxy) + g_object_unref (priv->dbus_proxy); + + if (priv->manager_proxy) + g_object_unref (priv->manager_proxy); + + if (priv->bus) + dbus_g_connection_unref (priv->bus); + } + + G_OBJECT_CLASS (nm_secret_agent_parent_class)->dispose (object); +} + +static void +nm_secret_agent_class_init (NMSecretAgentClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + g_type_class_add_private (class, sizeof (NMSecretAgentPrivate)); + + /* Virtual methods */ + object_class->dispose = dispose; + object_class->get_property = get_property; + object_class->set_property = set_property; + + /** + * NMSecretAgent: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_IDENTIFIER, + "Identifier", + "Identifier", + NULL, + G_PARAM_READABLE | G_PARAM_CONSTRUCT_ONLY)); + + /** + * NMSecretAgent::registration-result: + * @agent: the agent that received the signal + * @error: the error, if any, that occured while registering + * + * Indicates the result of a registration request; if @error is NULL the + * request was successful. + **/ + signals[REGISTRATION_RESULT] = + g_signal_new (REGISTRATION_RESULT, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); + + dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (class), + &dbus_glib_nm_secret_agent_object_info); + + dbus_g_error_domain_register (NM_SECRET_AGENT_ERROR, + NM_DBUS_INTERFACE_SECRET_AGENT, + NM_TYPE_SECRET_AGENT_ERROR); +} + diff --git a/libnm-glib/nm-secret-agent.h b/libnm-glib/nm-secret-agent.h new file mode 100644 index 000000000..b9f0fd727 --- /dev/null +++ b/libnm-glib/nm-secret-agent.h @@ -0,0 +1,119 @@ +/* -*- 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. + * + * (C) Copyright 2010 Red Hat, Inc. + */ + +#ifndef NM_SECRET_AGENT_H +#define NM_SECRET_AGENT_H + +#include +#include +#include + +G_BEGIN_DECLS + +#define NM_SECRET_AGENT_ERROR (nm_secret_agent_error_quark ()) +#define NM_TYPE_SECRET_AGENT_ERROR (nm_secret_agent_error_get_type ()) + +GQuark nm_secret_agent_error_quark (void); +GType nm_secret_agent_error_get_type (void); + +typedef enum { + NM_SECRET_AGENT_ERROR_NOT_AUTHORIZED = 0, + NM_SECRET_AGENT_ERROR_INVALID_CONNECTION, + NM_SECRET_AGENT_ERROR_USER_CANCELED, + NM_SECRET_AGENT_ERROR_AGENT_CANCELED +} NMSecretAgentError; + + +#define NM_TYPE_SECRET_AGENT (nm_secret_agent_get_type ()) +#define NM_SECRET_AGENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SECRET_AGENT, NMSecretAgent)) +#define NM_SECRET_AGENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SECRET_AGENT, NMSecretAgentClass)) +#define NM_IS_SECRET_AGENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SECRET_AGENT)) +#define NM_IS_SECRET_AGENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_SECRET_AGENT)) +#define NM_SECRET_AGENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SECRET_AGENT, NMSecretAgentClass)) + +#define NM_SECRET_AGENT_IDENTIFIER "identifier" + +#define NM_SECRET_AGENT_REGISTRATION_RESULT "registration-result" + +typedef struct { + GObject parent; +} NMSecretAgent; + +typedef struct { + GObjectClass parent; + + /* Virtual methods for subclasses */ + + /* Called when the subclass should retrieve and return secrets. Subclass + * must copy or reference any arguments it may require after returning from + * this method, as the arguments will freed (except for 'agent' and + * 'context' of course). + */ + void (*get_secrets) (NMSecretAgent *agent, + NMConnection *connection, + const char *connection_path, + const char *setting_name, + const char **hints, + gboolean request_new, + DBusGMethodInvocation *context); + + /* Called when the subclass should save the secrets contained in the + * connection to backing storage. Subclass must copy or reference any + * arguments it may require after returning from this method, as the + * arguments will freed (except for 'agent' and 'context' of course). + */ + void (*save_secrets) (NMSecretAgent *agent, + NMConnection *connection, + const char *connection_path, + DBusGMethodInvocation *context); + + /* Called when the subclass should delete the secrets contained in the + * connection from backing storage. Subclass must copy or reference any + * arguments it may require after returning from this method, as the + * arguments will freed (except for 'agent' and 'context' of course). + */ + void (*delete_secrets) (NMSecretAgent *agent, + NMConnection *connection, + const char *connection_path, + DBusGMethodInvocation *context); + + /* Signals */ + void (*registration_result) (NMSecretAgent *agent, GError *error); + + /* Padding for future expansion */ + void (*_reserved1) (void); + void (*_reserved2) (void); + void (*_reserved3) (void); + void (*_reserved4) (void); + void (*_reserved5) (void); + void (*_reserved6) (void); +} NMSecretAgentClass; + +GType nm_secret_agent_get_type (void); + +NMSecretAgent *nm_secret_agent_new (const char *identifier); + +gboolean nm_secret_agent_register (NMSecretAgent *self); + +gboolean nm_secret_agent_unregister (NMSecretAgent *self); + +G_END_DECLS + +#endif /* NM_SECRET_AGENT_H */