diff options
Diffstat (limited to 'src/settings/nm-secret-agent.c')
| -rw-r--r-- | src/settings/nm-secret-agent.c | 398 |
1 files changed, 398 insertions, 0 deletions
diff --git a/src/settings/nm-secret-agent.c b/src/settings/nm-secret-agent.c new file mode 100644 index 00000000..2b1156cb --- /dev/null +++ b/src/settings/nm-secret-agent.c @@ -0,0 +1,398 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2010 - 2011 Red Hat, Inc. + */ + +#include <config.h> + +#include <glib.h> +#include <dbus/dbus-glib.h> +#include <dbus/dbus-glib-lowlevel.h> + +#include "NetworkManager.h" +#include "nm-secret-agent.h" +#include "nm-dbus-glib-types.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 disposed; + + char *description; + char *owner; + char *identifier; + uid_t owner_uid; + guint32 hash; + + NMDBusManager *dbus_mgr; + DBusGProxy *proxy; + + GHashTable *requests; +} NMSecretAgentPrivate; + +/*************************************************************/ + +typedef struct { + NMSecretAgent *agent; + DBusGProxyCall *call; + char *path; + char *setting_name; + NMSecretAgentCallback callback; + gpointer callback_data; +} Request; + +static Request * +request_new (NMSecretAgent *agent, + const char *path, + const char *setting_name, + NMSecretAgentCallback callback, + gpointer callback_data) +{ + Request *r; + + r = g_slice_new0 (Request); + r->agent = agent; + r->path = g_strdup (path); + r->setting_name = g_strdup (setting_name); + r->callback = callback; + r->callback_data = callback_data; + return r; +} + +static void +request_free (Request *r) +{ + g_free (r->path); + g_free (r->setting_name); + g_slice_free (Request, r); +} + +/*************************************************************/ + +const char * +nm_secret_agent_get_description (NMSecretAgent *agent) +{ + NMSecretAgentPrivate *priv; + + g_return_val_if_fail (agent != NULL, NULL); + g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), NULL); + + priv = NM_SECRET_AGENT_GET_PRIVATE (agent); + if (!priv->description) { + priv->description = g_strdup_printf ("%s/%s/%u", + priv->owner, + priv->identifier, + priv->owner_uid); + } + + return priv->description; +} + +const char * +nm_secret_agent_get_dbus_owner (NMSecretAgent *agent) +{ + g_return_val_if_fail (agent != NULL, NULL); + g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), NULL); + + return NM_SECRET_AGENT_GET_PRIVATE (agent)->owner; +} + +const char * +nm_secret_agent_get_identifier (NMSecretAgent *agent) +{ + g_return_val_if_fail (agent != NULL, NULL); + g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), NULL); + + return NM_SECRET_AGENT_GET_PRIVATE (agent)->identifier; +} + +uid_t +nm_secret_agent_get_owner_uid (NMSecretAgent *agent) +{ + g_return_val_if_fail (agent != NULL, G_MAXUINT); + g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), G_MAXUINT); + + return NM_SECRET_AGENT_GET_PRIVATE (agent)->owner_uid; +} + +guint32 +nm_secret_agent_get_hash (NMSecretAgent *agent) +{ + g_return_val_if_fail (agent != NULL, 0); + g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), 0); + + return NM_SECRET_AGENT_GET_PRIVATE (agent)->hash; +} + +/*************************************************************/ + +static void +get_callback (DBusGProxy *proxy, + DBusGProxyCall *call, + void *user_data) +{ + Request *r = user_data; + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent); + GError *error = NULL; + GHashTable *secrets = NULL; + + g_return_if_fail (call == r->call); + + dbus_g_proxy_end_call (proxy, call, &error, + DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, &secrets, + G_TYPE_INVALID); + r->callback (r->agent, r->call, secrets, error, r->callback_data); + if (secrets) + g_hash_table_unref (secrets); + g_clear_error (&error); + g_hash_table_remove (priv->requests, call); +} + +gconstpointer +nm_secret_agent_get_secrets (NMSecretAgent *self, + NMConnection *connection, + const char *setting_name, + const char *hint, + NMSettingsGetSecretsFlags flags, + NMSecretAgentCallback callback, + gpointer callback_data) +{ + NMSecretAgentPrivate *priv; + GHashTable *hash; + const char *hints[2] = { hint, NULL }; + Request *r; + + g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail (connection != NULL, NULL); + g_return_val_if_fail (setting_name != NULL, NULL); + + priv = NM_SECRET_AGENT_GET_PRIVATE (self); + + hash = nm_connection_to_hash (connection, NM_SETTING_HASH_FLAG_ALL); + + r = request_new (self, nm_connection_get_path (connection), setting_name, callback, callback_data); + r->call = dbus_g_proxy_begin_call_with_timeout (priv->proxy, + "GetSecrets", + get_callback, + r, + NULL, + 120000, /* 120 seconds */ + DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, hash, + DBUS_TYPE_G_OBJECT_PATH, nm_connection_get_path (connection), + G_TYPE_STRING, setting_name, + G_TYPE_STRV, hints, + G_TYPE_UINT, flags, + G_TYPE_INVALID); + g_hash_table_insert (priv->requests, r->call, r); + + g_hash_table_destroy (hash); + return r->call; +} + +void +nm_secret_agent_cancel_secrets (NMSecretAgent *self, gconstpointer call) +{ + NMSecretAgentPrivate *priv; + Request *r; + + g_return_if_fail (self != NULL); + priv = NM_SECRET_AGENT_GET_PRIVATE (self); + + r = g_hash_table_lookup (priv->requests, call); + g_return_if_fail (r != NULL); + + dbus_g_proxy_cancel_call (NM_SECRET_AGENT_GET_PRIVATE (self)->proxy, (gpointer) call); + + dbus_g_proxy_call_no_reply (priv->proxy, + "CancelGetSecrets", + G_TYPE_STRING, r->path, + G_TYPE_STRING, r->setting_name, + G_TYPE_INVALID); + g_hash_table_remove (priv->requests, call); +} + +/*************************************************************/ + +static void +agent_save_delete_cb (DBusGProxy *proxy, + DBusGProxyCall *call, + void *user_data) +{ + Request *r = user_data; + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent); + GError *error = NULL; + + g_return_if_fail (call == r->call); + + dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID); + r->callback (r->agent, r->call, NULL, error, r->callback_data); + g_clear_error (&error); + g_hash_table_remove (priv->requests, call); +} + +static gpointer +agent_new_save_delete (NMSecretAgent *self, + NMConnection *connection, + NMSettingHashFlags hash_flags, + const char *method, + NMSecretAgentCallback callback, + gpointer callback_data) +{ + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); + GHashTable *hash; + Request *r; + const char *cpath = nm_connection_get_path (connection); + + hash = nm_connection_to_hash (connection, hash_flags); + + r = request_new (self, cpath, NULL, callback, callback_data); + r->call = dbus_g_proxy_begin_call_with_timeout (priv->proxy, + method, + agent_save_delete_cb, + r, + NULL, + 10000, /* 10 seconds */ + DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, hash, + DBUS_TYPE_G_OBJECT_PATH, cpath, + G_TYPE_INVALID); + g_hash_table_insert (priv->requests, r->call, r); + + g_hash_table_destroy (hash); + return r->call; +} + +gconstpointer +nm_secret_agent_save_secrets (NMSecretAgent *self, + NMConnection *connection, + NMSecretAgentCallback callback, + gpointer callback_data) +{ + g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail (connection != NULL, NULL); + + /* Caller should have ensured that only agent-owned secrets exist in 'connection' */ + return agent_new_save_delete (self, + connection, + NM_SETTING_HASH_FLAG_ALL, + "SaveSecrets", + callback, + callback_data); +} + +gconstpointer +nm_secret_agent_delete_secrets (NMSecretAgent *self, + NMConnection *connection, + NMSecretAgentCallback callback, + gpointer callback_data) +{ + g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail (connection != NULL, NULL); + + /* No secrets sent; agents must be smart enough to track secrets using the UUID or something */ + return agent_new_save_delete (self, + connection, + NM_SETTING_HASH_FLAG_NO_SECRETS, + "DeleteSecrets", + callback, + callback_data); +} + +/*************************************************************/ + +NMSecretAgent * +nm_secret_agent_new (NMDBusManager *dbus_mgr, + const char *owner, + const char *identifier, + uid_t owner_uid) +{ + NMSecretAgent *self; + NMSecretAgentPrivate *priv; + DBusGConnection *bus; + char *hash_str; + + g_return_val_if_fail (owner != NULL, NULL); + g_return_val_if_fail (identifier != NULL, NULL); + + self = (NMSecretAgent *) g_object_new (NM_TYPE_SECRET_AGENT, NULL); + if (self) { + priv = NM_SECRET_AGENT_GET_PRIVATE (self); + + priv->owner = g_strdup (owner); + priv->identifier = g_strdup (identifier); + priv->owner_uid = owner_uid; + + hash_str = g_strdup_printf ("%08u%s", owner_uid, identifier); + priv->hash = g_str_hash (hash_str); + g_free (hash_str); + + priv->dbus_mgr = g_object_ref (dbus_mgr); + bus = nm_dbus_manager_get_connection (priv->dbus_mgr); + priv->proxy = dbus_g_proxy_new_for_name (bus, + owner, + NM_DBUS_PATH_SECRET_AGENT, + NM_DBUS_INTERFACE_SECRET_AGENT); + g_assert (priv->proxy); + } + + return self; +} + +static void +nm_secret_agent_init (NMSecretAgent *self) +{ + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); + + priv->requests = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, (GDestroyNotify) request_free); +} + +static void +dispose (GObject *object) +{ + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (object); + + if (!priv->disposed) { + priv->disposed = TRUE; + + g_free (priv->description); + g_free (priv->owner); + g_free (priv->identifier); + + g_hash_table_destroy (priv->requests); + g_object_unref (priv->proxy); + g_object_unref (priv->dbus_mgr); + } + + G_OBJECT_CLASS (nm_secret_agent_parent_class)->dispose (object); +} + +static void +nm_secret_agent_class_init (NMSecretAgentClass *config_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (config_class); + + g_type_class_add_private (config_class, sizeof (NMSecretAgentPrivate)); + + /* virtual methods */ + object_class->dispose = dispose; +} + |