/* * Copyright 2013 Canonical Ltd. * * This program 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; version 3. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authors: * Alberto Ruiz * Renato Araujo Oliveira Filho */ #include #include #include #include "secret-agent.h" #define UNITY_SETTINGS_TYPE_SECRET_AGENT (unity_settings_secret_agent_get_type ()) #define UNITY_SETTINGS_SECRET_AGENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UNITY_SETTINGS_TYPE_SECRET_AGENT, UnitySettingsSecretAgent)) #define UNITY_SETTINGS_SECRET_AGENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UNITY_SETTINGS_TYPE_SECRET_AGENT, UnitySettingsSecretAgentClass)) #define UNITY_SETTINGS_IS_SECRET_AGENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UNITY_SETTINGS_TYPE_SECRET_AGENT)) #define UNITY_SETTINGS_IS_SECRET_AGENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UNITY_SETTINGS_TYPE_SECRET_AGENT)) #define UNITY_SETTINGS_SECRET_AGENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UNITY_SETTINGS_TYPE_SECRET_AGENT, UnitySettingsSecretAgentClass)) #define UNITY_SETTINGS_SECRET_AGENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), UNITY_SETTINGS_TYPE_SECRET_AGENT, UnitySettingsSecretAgentPrivate)) #define AGENT_ID "com.canonical.settings.network.nm-agent" static gpointer unity_settings_secret_agent_parent_class = NULL; typedef struct _UnitySettingsSecretAgentPrivate UnitySettingsSecretAgentPrivate; struct _UnitySettingsSecretAgentPrivate { GQueue *requests; }; typedef struct _SecretRequest { gint id; NMSecretAgent *agent; NMConnection *connection; const char *connection_path; const char *setting_name; const char **hints; NMSecretAgentGetSecretsFlags flags; NMSecretAgentGetSecretsFunc callback; gpointer callback_data; } SecretRequest; GType unity_settings_secret_agent_get_type (void) G_GNUC_CONST; enum { UNITY_SETTINGS_SECRET_AGENT_DUMMY_PROPERTY }; enum { SECRET_REQUESTED, REQUEST_CANCELLED, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; UnitySettingsSecretAgent* unity_settings_secret_agent_new (void); UnitySettingsSecretAgent* unity_settings_secret_agent_construct (GType object_type); int secret_request_find (SecretRequest *req, guint *id) { if (req->id > *id) return -1; if (req->id < *id) return 1; return 0; } void unity_settings_secret_agent_provide_secret (UnitySettingsSecretAgent *agent, guint request, GHashTable *secrets) { GList *iter; SecretRequest *req; UnitySettingsSecretAgentPrivate *priv = agent->priv; iter = g_queue_find_custom (priv->requests, &request, (GCompareFunc)secret_request_find); if (iter == NULL || iter->data == NULL) { g_warning ("Secret request with id <%d> was not found", (int)request); return; } req = iter->data; req->callback (NM_SECRET_AGENT (agent), req->connection, secrets, NULL, req->callback_data); g_queue_remove_all (priv->requests, req); g_free (req); return; } void free_request (SecretRequest *req) { g_object_unref (req->connection); g_free (req); } void unity_settings_secret_agent_cancel_request (UnitySettingsSecretAgent *agent, guint request) { GList *iter; SecretRequest *req; UnitySettingsSecretAgentPrivate *priv = agent->priv; GError *error; iter = g_queue_find_custom (priv->requests, &request, (GCompareFunc)secret_request_find); if (iter == NULL || iter->data == NULL) { g_warning ("Secret request with id <%d> was not found", (int)request); return; } req = iter->data; error = g_error_new (NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_INTERNAL_ERROR, "This secret request was canceled by the user."); req->callback (NM_SECRET_AGENT (agent), req->connection, NULL, error, req->callback_data); g_queue_remove_all (priv->requests, req); free_request (req); return; } static void delete_secrets (NMSecretAgent *agent, NMConnection *connection, const char *connection_path, NMSecretAgentDeleteSecretsFunc callback, gpointer callback_data) { g_debug ("delete secrets"); } /* If it returns G_MAXUINT it's considered an error */ static guint find_available_id (UnitySettingsSecretAgentPrivate *priv) { guint i = 0; guint candidate = 0; if (g_queue_get_length (priv->requests) == G_MAXUINT) return G_MAXUINT; while (i < g_queue_get_length (priv->requests)) { SecretRequest *req = (SecretRequest*)g_queue_peek_nth (priv->requests, i); if (req->id == candidate) { candidate++; i = 0; } else { i++; } } return i; } static void get_secrets (NMSecretAgent *agent, NMConnection *connection, const char *connection_path, const char *setting_name, const char **hints, NMSecretAgentGetSecretsFlags flags, NMSecretAgentGetSecretsFunc callback, gpointer callback_data) { guint id; UnitySettingsSecretAgentPrivate *priv = UNITY_SETTINGS_SECRET_AGENT_GET_PRIVATE (agent); SecretRequest *req = NULL; if (flags == NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE) { GError *error = g_error_new (NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_INTERNAL_ERROR, "No password found for this connection."); callback (agent, connection, NULL, error, callback_data); g_error_free (error); return; } id = find_available_id (priv); if (id == G_MAXUINT) { GError *error = g_error_new (NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_INTERNAL_ERROR, "Reached maximum number of requests."); callback (agent, connection, NULL, error, callback_data); g_error_free (error); return; } /* Adding a request */ req = (SecretRequest*) g_malloc0 (sizeof (SecretRequest)); *req = ((SecretRequest) { id, agent, connection, connection_path, setting_name, hints, flags, callback, callback_data }); g_object_ref (connection); g_queue_push_tail (priv->requests, req); g_signal_emit_by_name (agent, UNITY_SETTINGS_SECRET_AGENT_SECRET_REQUESTED, id, connection, setting_name, hints, flags); } static void save_secrets (NMSecretAgent *agent, NMConnection *connection, const char *connection_path, NMSecretAgentSaveSecretsFunc callback, gpointer callback_data) { g_debug ("save secrets"); } static void cancel_get_secrets (NMSecretAgent *agent, const char *connection_path, const char *setting_name) { g_debug ("cancel get secrets"); } UnitySettingsSecretAgent* unity_settings_secret_agent_construct (GType object_type) { UnitySettingsSecretAgent * self = NULL; self = (UnitySettingsSecretAgent*) g_object_new (object_type, NM_SECRET_AGENT_IDENTIFIER, AGENT_ID, NULL); return self; } UnitySettingsSecretAgent* unity_settings_secret_agent_new (void) { return unity_settings_secret_agent_construct (UNITY_SETTINGS_TYPE_SECRET_AGENT); } static void destroy_pending_request (gpointer data) { SecretRequest* req = (SecretRequest*)data; /* Reporting the cancellation of all pending requests */ g_signal_emit_by_name (req->agent, UNITY_SETTINGS_SECRET_AGENT_REQUEST_CANCELLED, req->id); free_request (req); } static void unity_settings_secret_agent_finalize (GObject *agent) { UnitySettingsSecretAgentPrivate *priv = UNITY_SETTINGS_SECRET_AGENT_GET_PRIVATE (agent); g_queue_free_full (priv->requests, destroy_pending_request); } static void unity_settings_secret_agent_class_init (UnitySettingsSecretAgentClass *klass) { unity_settings_secret_agent_parent_class = g_type_class_peek_parent (klass); NMSecretAgentClass *parent_class = NM_SECRET_AGENT_CLASS (klass); parent_class->get_secrets = get_secrets; parent_class->save_secrets = save_secrets; parent_class->delete_secrets = delete_secrets; parent_class->cancel_get_secrets = cancel_get_secrets; g_type_class_add_private (klass, sizeof(UnitySettingsSecretAgentPrivate)); G_OBJECT_CLASS (klass)->finalize = unity_settings_secret_agent_finalize; signals[SECRET_REQUESTED] = g_signal_new (UNITY_SETTINGS_SECRET_AGENT_SECRET_REQUESTED, G_OBJECT_CLASS_TYPE (G_OBJECT_CLASS (klass)), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (UnitySettingsSecretAgentClass, secret_requested), NULL, NULL, NULL, G_TYPE_NONE, 5, G_TYPE_UINT, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_UINT); signals[REQUEST_CANCELLED] = g_signal_new (UNITY_SETTINGS_SECRET_AGENT_REQUEST_CANCELLED, G_OBJECT_CLASS_TYPE (G_OBJECT_CLASS (klass)), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (UnitySettingsSecretAgentClass, request_cancelled), NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_UINT); } static void unity_settings_secret_agent_instance_init (UnitySettingsSecretAgent *self) { self->priv = UNITY_SETTINGS_SECRET_AGENT_GET_PRIVATE (self); self->priv->requests = g_queue_new (); } GType unity_settings_secret_agent_get_type (void) { static volatile gsize unity_settings_secret_agent_type_id__volatile = 0; if (g_once_init_enter (&unity_settings_secret_agent_type_id__volatile)) { static const GTypeInfo g_define_type_info = { sizeof (UnitySettingsSecretAgentClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) unity_settings_secret_agent_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (UnitySettingsSecretAgent), 0, (GInstanceInitFunc) unity_settings_secret_agent_instance_init, NULL }; GType unity_settings_secret_agent_type_id; unity_settings_secret_agent_type_id = g_type_register_static (NM_TYPE_SECRET_AGENT, "UnitySettingsSecretAgent", &g_define_type_info, 0); g_once_init_leave (&unity_settings_secret_agent_type_id__volatile, unity_settings_secret_agent_type_id); } return unity_settings_secret_agent_type_id__volatile; }