Thu, 23 Aug 2012 01:27:48 -0400
Add a Secret Service password plugin.
No, not *that* Secret Service... The password storing one:
http://developer.gnome.org/libsecret/
--- a/configure.ac Wed Aug 22 18:19:53 2012 -0400 +++ b/configure.ac Thu Aug 23 01:27:48 2012 -0400 @@ -1447,6 +1447,29 @@ fi dnl ####################################################################### +dnl # Check for Secret Service headers +dnl ####################################################################### + +AC_ARG_ENABLE(libsecret, [AC_HELP_STRING([--disable-secret-service], [disable Secret Service support])], enable_secret_service=$enableval, enable_secret_service=yes) + +dnl Check for libsecret; if we don't have it, oh well +if test "x$enable_secret_service" = "xyes" ; then + PKG_CHECK_MODULES(SECRETSERVICE, [libsecret-1], [ + AC_SUBST(SECRETSERVICE_CFLAGS) + AC_SUBST(SECRETSERVICE_LIBS) + AC_DEFINE(HAVE_SECRETSERVICE, 1, [Define if we have Secret Service.]) + ], [ + if test "x$force_deps" = "xyes" ; then + AC_MSG_ERROR([ +Secret Service development headers not found. +Use --disable-secret-service if you do not need Secret Service support. +]) + fi]) +fi + +AM_CONDITIONAL(ENABLE_SECRETSERVICE, test "x$enable_secret_service" = "xyes") + +dnl ####################################################################### dnl # Check for GNOME Keyring headers dnl ####################################################################### @@ -2806,6 +2829,7 @@ fi echo Build with GNU Libidn......... : $enable_idn echo Build with NetworkManager..... : $enable_nm +echo Build with Secret Service..... : $enable_secret_service echo Build with GNOME Keyring...... : $enable_gnome_keyring echo Build with KWallet............ : $enable_kwallet echo SSL Library/Libraries......... : $msg_ssl
--- a/libpurple/plugins/keyrings/Makefile.am Wed Aug 22 18:19:53 2012 -0400 +++ b/libpurple/plugins/keyrings/Makefile.am Thu Aug 23 01:27:48 2012 -0400 @@ -8,6 +8,15 @@ internalkeyring_la_SOURCES = internalkeyring.c internalkeyring_la_LIBADD = $(GLIB_LIBS) +if ENABLE_SECRETSERVICE + +secretservice_la_CFLAGS = $(AM_CPPFLAGS) $(SECRETSERVICE_CFLAGS) +secretservice_la_LDFLAGS = -module -avoid-version +secretservice_la_SOURCES = secretservice.c +secretservice_la_LIBADD = $(GLIB_LIBS) $(SECRETSERVICE_LIBS) + +endif + if ENABLE_GNOMEKEYRING gnomekeyring_la_CFLAGS = $(AM_CPPFLAGS) $(GNOMEKEYRING_CFLAGS) @@ -35,6 +44,11 @@ plugin_LTLIBRARIES = \ internalkeyring.la +if ENABLE_SECRETSERVICE +plugin_LTLIBRARIES += \ + secretservice.la +endif + if ENABLE_GNOMEKEYRING plugin_LTLIBRARIES += \ gnomekeyring.la
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/plugins/keyrings/secretservice.c Thu Aug 23 01:27:48 2012 -0400 @@ -0,0 +1,360 @@ +/* purple + * @file secretservice.c Secret Service password storage + * @ingroup plugins + * + * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * 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 02111-1301 USA + */ + +#include "internal.h" +#include "account.h" +#include "debug.h" +#include "keyring.h" +#include "plugin.h" +#include "version.h" + +#include <libsecret/secret.h> + +#define SECRETSERVICE_NAME N_("Secret Service") +#define SECRETSERVICE_ID "keyring-libsecret" + +#define ERR_SECRETSERVICEPLUGIN (ss_error_domain()) + +static PurpleKeyring *keyring_handler = NULL; + +static const SecretSchema purple_schema = { + "im.pidgin.Purple", SECRET_SCHEMA_NONE, + { + {"user", SECRET_SCHEMA_ATTRIBUTE_STRING}, + {"protocol", SECRET_SCHEMA_ATTRIBUTE_STRING}, + {"NULL", 0} + }, + /* Reserved fields */ + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +typedef struct _InfoStorage InfoStorage; + +struct _InfoStorage +{ + PurpleAccount *account; + gpointer cb; + gpointer user_data; +}; + +static GQuark +ss_error_domain(void) +{ + return g_quark_from_static_string("SecretService plugin"); +} + + +/***********************************************/ +/* Keyring interface */ +/***********************************************/ +static void +ss_read_continue(GObject *object, GAsyncResult *result, gpointer data) +{ + InfoStorage *storage = data; + PurpleAccount *account = storage->account; + PurpleKeyringReadCallback cb = storage->cb; + char *password; + GError *error = NULL; + + password = secret_password_lookup_finish(result, &error); + + if (error != NULL) { + int code = error->code; + g_error_free(error); + + switch (code) { + case G_DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND: + case G_DBUS_ERROR_IO_ERROR: + error = g_error_new(ERR_SECRETSERVICEPLUGIN, + PURPLE_KEYRING_ERROR_NOCHANNEL, + "Failed to communicate with Secret Service (account : %s).", + purple_account_get_username(account)); + if (cb != NULL) + cb(account, NULL, error, storage->user_data); + g_error_free(error); + break; + + default: + error = g_error_new(ERR_SECRETSERVICEPLUGIN, + PURPLE_KEYRING_ERROR_NOCHANNEL, + "Unknown error (account : %s).", + purple_account_get_username(account)); + if (cb != NULL) + cb(account, NULL, error, storage->user_data); + g_error_free(error); + break; + } + + } else if (password == NULL) { + error = g_error_new(ERR_SECRETSERVICEPLUGIN, + PURPLE_KEYRING_ERROR_NOPASSWD, + "No password found for account: %s", + purple_account_get_username(account)); + if (cb != NULL) + cb(account, NULL, error, storage->user_data); + g_error_free(error); + + } else { + if (cb != NULL) + cb(account, password, NULL, storage->user_data); + } + + g_free(storage); +} + +static void +ss_read(PurpleAccount *account, PurpleKeyringReadCallback cb, gpointer data) +{ + InfoStorage *storage = g_new0(InfoStorage, 1); + + storage->account = account; + storage->cb = cb; + storage->user_data = data; + + secret_password_lookup(&purple_schema, + NULL, ss_read_continue, storage, + "user", purple_account_get_username(account), + "protocol", purple_account_get_protocol_id(account), + NULL); +} + +static void +ss_save_continue(GObject *object, GAsyncResult *result, gpointer data) +{ + InfoStorage *storage = data; + PurpleKeyringSaveCallback cb; + GError *error = NULL; + PurpleAccount *account; + + account = storage->account; + cb = storage->cb; + + secret_password_store_finish(result, &error); + + if (error != NULL) { + int code = error->code; + g_error_free(error); + + switch (code) { + case G_DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND: + case G_DBUS_ERROR_IO_ERROR: + purple_debug_info("keyring-libsecret", + "Failed to communicate with Secret Service (account : %s (%s)).\n", + purple_account_get_username(account), + purple_account_get_protocol_id(account)); + error = g_error_new(ERR_SECRETSERVICEPLUGIN, + PURPLE_KEYRING_ERROR_NOCHANNEL, + "Failed to communicate with Secret Service (account : %s).", + purple_account_get_username(account)); + if (cb != NULL) + cb(account, error, storage->user_data); + g_error_free(error); + break; + + default: + purple_debug_info("keyring-libsecret", + "Unknown error (account : %s (%s)).\n", + purple_account_get_username(account), + purple_account_get_protocol_id(account)); + error = g_error_new(ERR_SECRETSERVICEPLUGIN, + PURPLE_KEYRING_ERROR_NOCHANNEL, + "Unknown error (account : %s).", + purple_account_get_username(account)); + if (cb != NULL) + cb(account, error, storage->user_data); + g_error_free(error); + break; + } + + } else { + purple_debug_info("keyring-libsecret", "Password for %s updated.\n", + purple_account_get_username(account)); + + if (cb != NULL) + cb(account, NULL, storage->user_data); + } + + g_free(storage); +} + +static void +ss_save(PurpleAccount *account, + const gchar *password, + PurpleKeyringSaveCallback cb, + gpointer data) +{ + InfoStorage *storage = g_new0(InfoStorage, 1); + + storage->account = account; + storage->cb = cb; + storage->user_data = data; + + if (password != NULL && *password != '\0') { + const char *username = purple_account_get_username(account); + char *label; + + purple_debug_info("keyring-libsecret", + "Updating password for account %s (%s).\n", + username, purple_account_get_protocol_id(account)); + + label = g_strdup_printf(_("Pidgin IM password for account %s"), username); + secret_password_store(&purple_schema, SECRET_COLLECTION_DEFAULT, + label, password, + NULL, ss_save_continue, storage, + "user", username, + "protocol", purple_account_get_protocol_id(account), + NULL); + g_free(label); + + } else { /* password == NULL, delete password. */ + purple_debug_info("keyring-libsecret", + "Forgetting password for account %s (%s).\n", + purple_account_get_username(account), + purple_account_get_protocol_id(account)); + + secret_password_clear(&purple_schema, NULL, ss_save_continue, storage, + "user", purple_account_get_username(account), + "protocol", purple_account_get_protocol_id(account), + NULL); + } +} + +static void +ss_close(GError **error) +{ +} + +static gboolean +ss_import_password(PurpleAccount *account, + const char *mode, + const char *data, + GError **error) +{ + purple_debug_info("keyring-libsecret", "Importing password.\n"); + return TRUE; +} + +static gboolean +ss_export_password(PurpleAccount *account, + const char **mode, + char **data, + GError **error, + GDestroyNotify *destroy) +{ + purple_debug_info("keyring-libsecret", "Exporting password.\n"); + *data = NULL; + *mode = NULL; + *destroy = NULL; + + return TRUE; +} + +static gboolean +ss_init(void) +{ + purple_debug_info("keyring-libsecret", "Init.\n"); + + keyring_handler = purple_keyring_new(); + + purple_keyring_set_name(keyring_handler, SECRETSERVICE_NAME); + purple_keyring_set_id(keyring_handler, SECRETSERVICE_ID); + purple_keyring_set_read_password(keyring_handler, ss_read); + purple_keyring_set_save_password(keyring_handler, ss_save); + purple_keyring_set_close_keyring(keyring_handler, ss_close); + purple_keyring_set_import_password(keyring_handler, ss_import_password); + purple_keyring_set_export_password(keyring_handler, ss_export_password); + + purple_keyring_register(keyring_handler); + + return TRUE; +} + +static void +ss_uninit(void) +{ + purple_debug_info("keyring-libsecret", "Uninit.\n"); + ss_close(NULL); + purple_keyring_unregister(keyring_handler); + purple_keyring_free(keyring_handler); + keyring_handler = NULL; +} + +/***********************************************/ +/* Plugin interface */ +/***********************************************/ + +static gboolean +ss_load(PurplePlugin *plugin) +{ + return ss_init(); +} + +static gboolean +ss_unload(PurplePlugin *plugin) +{ + if (purple_keyring_get_inuse() == keyring_handler) + return FALSE; + + ss_uninit(); + + return TRUE; +} + +PurplePluginInfo plugininfo = +{ + PURPLE_PLUGIN_MAGIC, /* magic */ + PURPLE_MAJOR_VERSION, /* major_version */ + PURPLE_MINOR_VERSION, /* minor_version */ + PURPLE_PLUGIN_STANDARD, /* type */ + NULL, /* ui_requirement */ + PURPLE_PLUGIN_FLAG_INVISIBLE|PURPLE_PLUGIN_FLAG_AUTOLOAD, /* flags */ + NULL, /* dependencies */ + PURPLE_PRIORITY_DEFAULT, /* priority */ + SECRETSERVICE_ID, /* id */ + SECRETSERVICE_NAME, /* name */ + DISPLAY_VERSION, /* version */ + "Secret Service Plugin", /* summary */ + N_("This plugin will store passwords in Secret Service."), /* description */ + "Elliott Sales de Andrade (qulogic[at]pidgin.im)", /* author */ + PURPLE_WEBSITE, /* homepage */ + ss_load, /* load */ + ss_unload, /* unload */ + NULL, /* destroy */ + NULL, /* ui_info */ + NULL, /* extra_info */ + NULL, /* prefs_info */ + NULL, /* actions */ + NULL, /* padding... */ + NULL, + NULL, + NULL, +}; + +static void +init_plugin(PurplePlugin *plugin) +{ + purple_debug_info("keyring-libsecret", "Init plugin called.\n"); +} + +PURPLE_INIT_PLUGIN(secret_service, init_plugin, plugininfo) +