diff options
author | Ray Strode <rstrode@redhat.com> | 2013-05-28 09:22:39 -0400 |
---|---|---|
committer | Ray Strode <rstrode@redhat.com> | 2013-07-27 11:40:51 -0400 |
commit | 58320622e2480676ab85d631af287a0af9ffab6e (patch) | |
tree | ebb36adf34dd223ba849f27c25c5d71abec9caee /plugins | |
parent | 28a23b88b8487a177713ce86be564cb7e492538c (diff) | |
download | gnome-settings-daemon-58320622e2480676ab85d631af287a0af9ffab6e.tar.gz |
smartcard: add back smartcard support
This commit lands a rewrite of the smartcard plugin. It makes use
of the DBus ObjectManager interface to export tokens over the bus,
as they're inserted and removed.
https://bugzilla.gnome.org/show_bug.cgi?id=704890
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/smartcard/Makefile.am | 105 | ||||
-rw-r--r-- | plugins/smartcard/gsd-smartcard-enum-types.c.in | 42 | ||||
-rw-r--r-- | plugins/smartcard/gsd-smartcard-enum-types.h.in | 24 | ||||
-rw-r--r-- | plugins/smartcard/gsd-smartcard-manager.c | 870 | ||||
-rw-r--r-- | plugins/smartcard/gsd-smartcard-manager.h | 82 | ||||
-rw-r--r-- | plugins/smartcard/gsd-smartcard-plugin.c | 30 | ||||
-rw-r--r-- | plugins/smartcard/gsd-smartcard-service.c | 773 | ||||
-rw-r--r-- | plugins/smartcard/gsd-smartcard-service.h | 81 | ||||
-rw-r--r-- | plugins/smartcard/gsd-smartcard-utils.c | 191 | ||||
-rw-r--r-- | plugins/smartcard/gsd-smartcard-utils.h | 38 | ||||
-rw-r--r-- | plugins/smartcard/org.gnome.SettingsDaemon.Smartcard.xml | 91 | ||||
-rw-r--r-- | plugins/smartcard/test-smartcard.c | 7 |
12 files changed, 2334 insertions, 0 deletions
diff --git a/plugins/smartcard/Makefile.am b/plugins/smartcard/Makefile.am new file mode 100644 index 00000000..2d27d1c2 --- /dev/null +++ b/plugins/smartcard/Makefile.am @@ -0,0 +1,105 @@ +plugin_name = smartcard +libsmartcard_headers = gsd-smartcard-manager.h \ + gsd-smartcard-utils.h +dbus_built_sources = org.gnome.SettingsDaemon.Smartcard.c org.gnome.SettingsDaemon.Smartcard.h +enum_built_sources = gsd-smartcard-enum-types.h gsd-smartcard-enum-types.c +BUILT_SOURCES = $(dbus_built_sources) $(enum_built_sources) + +libexec_PROGRAMS = gsd-test-smartcard + +plugin_LTLIBRARIES = \ + libsmartcard.la + +$(dbus_built_sources) : Makefile.am org.gnome.SettingsDaemon.Smartcard.xml + $(AM_V_GEN) gdbus-codegen \ + --interface-prefix org.gnome.SettingsDaemon.Smartcard. \ + --c-namespace GsdSmartcardService \ + --c-generate-object-manager \ + --generate-c-code org.gnome.SettingsDaemon.Smartcard \ + org.gnome.SettingsDaemon.Smartcard.xml + +gsd-smartcard-enum-types.h: gsd-smartcard-enum-types.h.in $(libsmartcard_headers) + $(AM_V_GEN) $(GLIB_MKENUMS) --template $^ > $@ + +gsd-smartcard-enum-types.c: gsd-smartcard-enum-types.c.in $(libsmartcard_headers) + $(AM_V_GEN) $(GLIB_MKENUMS) --template $^ > $@ + +gsd_test_smartcard_SOURCES = \ + $(dbus_built_sources) \ + $(enum_built_sources) \ + gsd-smartcard-service.c \ + gsd-smartcard-manager.c \ + gsd-smartcard-utils.c \ + test-smartcard.c + +gsd_test_smartcard_CPPFLAGS = \ + -I$(top_srcdir)/data/ \ + -I$(top_srcdir)/gnome-settings-daemon \ + -I$(top_srcdir)/plugins/common \ + -DSYSCONFDIR=\""$(sysconfdir)"\" \ + -DLIBDIR=\""$(libdir)"\" \ + -DGNOME_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ + -DGSD_SMARTCARD_MANAGER_NSS_DB=\""$(NSS_DATABASE)"\" \ + $(AM_CPPFLAGS) + +gsd_test_smartcard_CFLAGS = \ + $(PLUGIN_CFLAGS) \ + $(SETTINGS_PLUGIN_CFLAGS) \ + $(MEDIA_KEYS_CFLAGS) \ + $(NSS_CFLAGS) \ + $(AM_CFLAGS) + +gsd_test_smartcard_LDADD = \ + $(top_builddir)/gnome-settings-daemon/libgsd.la \ + $(top_builddir)/plugins/common/libcommon.la \ + $(NSS_LIBS) \ + $(SETTINGS_DAEMON_LIBS) \ + $(SETTINGS_PLUGIN_LIBS) + + +libsmartcard_la_SOURCES = \ + $(libsmartcard_headers) \ + $(dbus_built_sources) \ + $(enum_built_sources) \ + gsd-smartcard-manager.c \ + gsd-smartcard-plugin.c \ + gsd-smartcard-service.c \ + gsd-smartcard-utils.c + +libsmartcard_la_CPPFLAGS = \ + -I$(top_srcdir)/gnome-settings-daemon \ + -DGNOME_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ + -I$(top_srcdir)/plugins/common \ + -DSYSCONFDIR=\""$(sysconfdir)"\" \ + -DLIBDIR=\""$(libdir)"\" \ + -DGSD_SMARTCARD_MANAGER_NSS_DB=\""$(NSS_DATABASE)"\" \ + $(AM_CPPFLAGS) + +libsmartcard_la_CFLAGS = \ + $(PLUGIN_CFLAGS) \ + $(SETTINGS_PLUGIN_CFLAGS) \ + $(NSS_CFLAGS) \ + $(AM_CFLAGS) + +libsmartcard_la_LDFLAGS = \ + $(GSD_PLUGIN_LDFLAGS) + +libsmartcard_la_LIBADD = \ + $(SETTINGS_PLUGIN_LIBS) \ + $(NSS_LIBS) + +@GSD_INTLTOOL_PLUGIN_RULE@ + +plugin_in_files = \ + smartcard.gnome-settings-plugin.in + +plugin_DATA = $(plugin_in_files:.gnome-settings-plugin.in=.gnome-settings-plugin) + +EXTRA_DIST = \ + $(plugin_in_files) + +CLEANFILES = \ + $(plugin_DATA) + +DISTCLEANFILES = \ + $(plugin_DATA) diff --git a/plugins/smartcard/gsd-smartcard-enum-types.c.in b/plugins/smartcard/gsd-smartcard-enum-types.c.in new file mode 100644 index 00000000..f281cf4e --- /dev/null +++ b/plugins/smartcard/gsd-smartcard-enum-types.c.in @@ -0,0 +1,42 @@ +/*** BEGIN file-header ***/ + +#include <glib-object.h> + +/*** END file-header ***/ + +/*** BEGIN file-production ***/ +#include "@filename@" +/* enumerations from "@filename@" */ +/*** END file-production ***/ + +/*** BEGIN value-header ***/ +GType @enum_name@_get_type (void) G_GNUC_CONST; + +GType +@enum_name@_get_type (void) +{ + static GType etype = 0; + + if (G_UNLIKELY(etype == 0)) { + static const G@Type@Value values[] = { +/*** END value-header ***/ + +/*** BEGIN value-production ***/ + { @VALUENAME@, "@VALUENAME@", "@valuenick@" }, +/*** END value-production ***/ + +/*** BEGIN value-tail ***/ + { 0, NULL, NULL } + }; + + etype = g_@type@_register_static (g_intern_static_string ("@EnumName@"), values); + } + + return etype; +} + +/*** END value-tail ***/ + +/*** BEGIN file-tail ***/ + /**/ +/*** END file-tail ***/ diff --git a/plugins/smartcard/gsd-smartcard-enum-types.h.in b/plugins/smartcard/gsd-smartcard-enum-types.h.in new file mode 100644 index 00000000..79dcc3d8 --- /dev/null +++ b/plugins/smartcard/gsd-smartcard-enum-types.h.in @@ -0,0 +1,24 @@ +/*** BEGIN file-header ***/ +#ifndef GSD_IDENTITY_ENUM_TYPES_H +#define GSD_IDENTITY_ENUM_TYPES_H + +#include <glib-object.h> + +G_BEGIN_DECLS +/*** END file-header ***/ + +/*** BEGIN file-production ***/ + +/* enumerations from "@filename@" */ +/*** END file-production ***/ + +/*** BEGIN value-header ***/ +GType @enum_name@_get_type (void) G_GNUC_CONST; +#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ()) +/*** END value-header ***/ + +/*** BEGIN file-tail ***/ +G_END_DECLS + +#endif /* GSD_IDENTITY_ENUM_TYPES_H */ +/*** END file-tail ***/ diff --git a/plugins/smartcard/gsd-smartcard-manager.c b/plugins/smartcard/gsd-smartcard-manager.c new file mode 100644 index 00000000..05f77f82 --- /dev/null +++ b/plugins/smartcard/gsd-smartcard-manager.c @@ -0,0 +1,870 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu> + * Copyright (C) 2010,2011 Red Hat, Inc. + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include "config.h" + +#include <glib.h> +#include <gio/gio.h> + +#include "gnome-settings-plugin.h" +#include "gnome-settings-profile.h" +#include "gsd-smartcard-manager.h" +#include "gsd-smartcard-service.h" +#include "gsd-smartcard-enum-types.h" +#include "gsd-smartcard-utils.h" + +#include <prerror.h> +#include <prinit.h> +#include <nss.h> +#include <pk11func.h> +#include <secmod.h> +#include <secerr.h> + +#define GSD_SMARTCARD_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_SMARTCARD_MANAGER, GsdSmartcardManagerPrivate)) + +struct GsdSmartcardManagerPrivate +{ + guint start_idle_id; + GsdSmartcardService *service; + GList *smartcards_watch_tasks; + GCancellable *cancellable; + + GSettings *settings; + + guint32 nss_is_loaded : 1; +}; + +#define CONF_SCHEMA "org.gnome.settings-daemon.peripherals.smartcard" + +static void gsd_smartcard_manager_class_init (GsdSmartcardManagerClass *klass); +static void gsd_smartcard_manager_init (GsdSmartcardManager *self); +static void gsd_smartcard_manager_finalize (GObject *object); +G_DEFINE_TYPE (GsdSmartcardManager, gsd_smartcard_manager, G_TYPE_OBJECT) +G_DEFINE_QUARK (gsd-smartcard-manager-error, gsd_smartcard_manager_error) +G_LOCK_DEFINE_STATIC (gsd_smartcards_watch_tasks); + +static gpointer manager_object = NULL; + +static void +gsd_smartcard_manager_class_init (GsdSmartcardManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gsd_smartcard_manager_finalize; + + gsd_smartcard_utils_register_error_domain (GSD_SMARTCARD_MANAGER_ERROR, + GSD_TYPE_SMARTCARD_MANAGER_ERROR); + g_type_class_add_private (klass, sizeof (GsdSmartcardManagerPrivate)); +} + +static void +gsd_smartcard_manager_init (GsdSmartcardManager *self) +{ + self->priv = GSD_SMARTCARD_MANAGER_GET_PRIVATE (self); +} + +static void +load_nss (GsdSmartcardManager *self) +{ + GsdSmartcardManagerPrivate *priv = self->priv; + SECStatus status = SECSuccess; + static const guint32 flags = NSS_INIT_READONLY + | NSS_INIT_FORCEOPEN + | NSS_INIT_NOROOTINIT + | NSS_INIT_OPTIMIZESPACE + | NSS_INIT_PK11RELOAD; + + g_debug ("attempting to load NSS database '%s'", + GSD_SMARTCARD_MANAGER_NSS_DB); + + PR_Init (PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + + status = NSS_Initialize (GSD_SMARTCARD_MANAGER_NSS_DB, + "", "", SECMOD_DB, flags); + + if (status != SECSuccess) { + gsize error_message_size; + char *error_message; + + error_message_size = PR_GetErrorTextLength (); + + if (error_message_size == 0) { + g_debug ("NSS security system could not be initialized"); + } else { + error_message = g_alloca (error_message_size); + PR_GetErrorText (error_message); + + g_debug ("NSS security system could not be initialized - %s", + error_message); + } + priv->nss_is_loaded = FALSE; + return; + + } + + g_debug ("NSS database '%s' loaded", GSD_SMARTCARD_MANAGER_NSS_DB); + priv->nss_is_loaded = TRUE; +} + +static void +unload_nss (GsdSmartcardManager *self) +{ + g_debug ("attempting to unload NSS security system with database '%s'", + GSD_SMARTCARD_MANAGER_NSS_DB); + + if (self->priv->nss_is_loaded) { + NSS_Shutdown (); + self->priv->nss_is_loaded = FALSE; + g_debug ("NSS database '%s' unloaded", GSD_SMARTCARD_MANAGER_NSS_DB); + } else { + g_debug ("NSS database '%s' already not loaded", GSD_SMARTCARD_MANAGER_NSS_DB); + } +} + +typedef struct +{ + SECMODModule *driver; + GHashTable *smartcards; +} WatchSmartcardsOperation; + +static void +on_watch_cancelled (GCancellable *cancellable, + WatchSmartcardsOperation *operation) +{ + SECMOD_CancelWait (operation->driver); +} + +static gboolean +watch_one_event_from_driver (GsdSmartcardManager *self, + WatchSmartcardsOperation *operation, + GCancellable *cancellable, + GError **error) +{ + GsdSmartcardManagerPrivate *priv = self->priv; + PK11SlotInfo *card, *old_card; + CK_SLOT_ID slot_id; + gulong handler_id; + int old_slot_series = -1, slot_series; + + handler_id = g_cancellable_connect (cancellable, + G_CALLBACK (on_watch_cancelled), + operation, + NULL); + + card = SECMOD_WaitForAnyTokenEvent (operation->driver, 0, PR_SecondsToInterval (1)); + + g_cancellable_disconnect (cancellable, handler_id); + + if (card == NULL) { + int error_code; + + error_code = PORT_GetError (); + + g_warning ("smartcard event function failed."); + + g_set_error (error, + GSD_SMARTCARD_MANAGER_ERROR, + GSD_SMARTCARD_MANAGER_ERROR_WITH_NSS, + "encountered unexpected error while " + "waiting for smartcard events (error %d)", + error_code); + return FALSE; + } + + slot_id = PK11_GetSlotID (card); + slot_series = PK11_GetSlotSeries (card); + + old_card = g_hash_table_lookup (operation->smartcards, GINT_TO_POINTER ((int) slot_id)); + + /* If there is a different card in the slot now than + * there was before, then we need to emit a removed signal + * for the old card + */ + if (old_card != NULL) { + old_slot_series = PK11_GetSlotSeries (old_card); + + if (old_slot_series != slot_series) { + /* Card registered with slot previously is + * different than this card, so update its + * exported state to track the implicit missed + * removal + */ + gsd_smartcard_service_sync_token (priv->service, old_card, cancellable); + } + + g_hash_table_remove (operation->smartcards, GINT_TO_POINTER ((int) slot_id)); + } + + if (PK11_IsPresent (card)) { + g_debug ("Detected smartcard insertion event in slot %d", (int) slot_id); + + g_hash_table_replace (operation->smartcards, + GINT_TO_POINTER ((int) slot_id), + PK11_ReferenceSlot (card)); + + gsd_smartcard_service_sync_token (priv->service, card, cancellable); + + } else if (old_card == NULL) { + /* If the just removed smartcard is not known to us then + * ignore the removal event. NSS sends a synthentic removal + * event for slots that are empty at startup + */ + g_debug ("Detected slot %d is empty in reader", (int) slot_id); + } else { + g_debug ("Detected smartcard removal event in slot %d", (int) slot_id); + + /* If the just removed smartcard is known to us then + * we need to update its exported state to reflect the + * removal + */ + if (old_slot_series == slot_series) + gsd_smartcard_service_sync_token (priv->service, card, cancellable); + } + + PK11_FreeSlot (card); + + return TRUE; +} + +static void +watch_smartcards_from_driver (GTask *task, + GsdSmartcardManager *self, + WatchSmartcardsOperation *operation, + GCancellable *cancellable) +{ + g_debug ("watching for smartcard events"); + while (!g_cancellable_is_cancelled (cancellable)) { + gboolean watch_succeeded; + GError *error = NULL; + + watch_succeeded = watch_one_event_from_driver (self, operation, cancellable, &error); + + if (!watch_succeeded) { + g_task_return_error (task, error); + break; + } + } +} + +static void +destroy_watch_smartcards_operation (WatchSmartcardsOperation *operation) +{ + SECMOD_DestroyModule (operation->driver); + g_hash_table_unref (operation->smartcards); + g_free (operation); +} + +static void +on_smartcards_watch_task_destroyed (GsdSmartcardManager *self, + GTask *freed_task) +{ + GsdSmartcardManagerPrivate *priv = self->priv; + + G_LOCK (gsd_smartcards_watch_tasks); + priv->smartcards_watch_tasks = g_list_remove (priv->smartcards_watch_tasks, + freed_task); + G_UNLOCK (gsd_smartcards_watch_tasks); +} + +static void +watch_smartcards_from_driver_async (GsdSmartcardManager *self, + SECMODModule *driver, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GsdSmartcardManagerPrivate *priv = self->priv; + GTask *task; + WatchSmartcardsOperation *operation; + + operation = g_new0 (WatchSmartcardsOperation, 1); + operation->driver = SECMOD_ReferenceModule (driver); + operation->smartcards = g_hash_table_new_full (g_direct_hash, + g_direct_equal, + NULL, + (GDestroyNotify) PK11_FreeSlot); + + task = g_task_new (self, cancellable, callback, user_data); + + g_task_set_task_data (task, + operation, + (GDestroyNotify) destroy_watch_smartcards_operation); + + G_LOCK (gsd_smartcards_watch_tasks); + priv->smartcards_watch_tasks = g_list_prepend (priv->smartcards_watch_tasks, + task); + g_object_weak_ref (G_OBJECT (task), + (GWeakNotify) on_smartcards_watch_task_destroyed, + self); + G_UNLOCK (gsd_smartcards_watch_tasks); + + g_task_run_in_thread (task, (GTaskThreadFunc) watch_smartcards_from_driver); + + g_object_unref (task); +} + +typedef struct +{ + guint driver_registered : 1; + guint smartcards_watched : 1; +} ActivateDriverOperation; + +static void +try_to_complete_driver_activation (GTask *task) +{ + ActivateDriverOperation *operation; + + operation = g_task_get_task_data (task); + + if (!operation->driver_registered) + return; + + if (!operation->smartcards_watched) + return; + + g_task_return_boolean (task, TRUE); +} + +static gboolean +register_driver_finish (GsdSmartcardManager *self, + GAsyncResult *result, + GError **error) +{ + return gsd_smartcard_utils_finish_boolean_task (G_OBJECT (self), result, error); +} + +static void +on_driver_registered (GsdSmartcardManager *self, + GAsyncResult *result, + GTask *task) +{ + ActivateDriverOperation *operation; + GError *error = NULL; + + if (!register_driver_finish (self, result, &error)) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + operation = g_task_get_task_data (task); + operation->driver_registered = TRUE; + + try_to_complete_driver_activation (task); +} + +static void +on_smartcards_from_driver_watched (GsdSmartcardManager *self, + GAsyncResult *result, + GTask *task) +{ + ActivateDriverOperation *operation; + + operation = g_task_get_task_data (task); + operation->smartcards_watched = TRUE; + + try_to_complete_driver_activation (task); +} + +typedef struct { + SECMODModule *driver; + guint idle_id; + GError *error; +} DriverRegistrationOperation; + +static void +destroy_driver_registration_operation (DriverRegistrationOperation *operation) +{ + SECMOD_DestroyModule (operation->driver); + g_free (operation); +} + +static gboolean +on_task_thread_to_complete_driver_registration (GTask *task) +{ + DriverRegistrationOperation *operation; + operation = g_task_get_task_data (task); + + if (operation->error != NULL) + g_task_return_error (task, operation->error); + else + g_task_return_boolean (task, TRUE); + + return G_SOURCE_REMOVE; +} + +static gboolean +on_main_thread_to_register_driver (GTask *task) +{ + GsdSmartcardManager *self; + GsdSmartcardManagerPrivate *priv; + DriverRegistrationOperation *operation; + GSource *source; + + self = g_task_get_source_object (task); + priv = self->priv; + operation = g_task_get_task_data (task); + + gsd_smartcard_service_register_driver (priv->service, + operation->driver); + + source = g_idle_source_new (); + g_task_attach_source (task, + source, + (GSourceFunc) on_task_thread_to_complete_driver_registration); + g_source_unref (source); + + return G_SOURCE_REMOVE; +} + +static void +register_driver (GsdSmartcardManager *self, + SECMODModule *driver, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + DriverRegistrationOperation *operation; + + task = g_task_new (self, cancellable, callback, user_data); + operation = g_new0 (DriverRegistrationOperation, 1); + operation->driver = SECMOD_ReferenceModule (driver); + g_task_set_task_data (task, + operation, + (GDestroyNotify) destroy_driver_registration_operation); + + operation->idle_id = g_idle_add ((GSourceFunc) on_main_thread_to_register_driver, task); +} + +static void +activate_driver (GsdSmartcardManager *self, + SECMODModule *driver, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + ActivateDriverOperation *operation; + GTask *task; + + g_debug ("Activating driver '%s'", driver->commonName); + + task = g_task_new (self, cancellable, callback, user_data); + operation = g_new0 (ActivateDriverOperation, 1); + g_task_set_task_data (task, operation, (GDestroyNotify) g_free); + + register_driver (self, + driver, + cancellable, + (GAsyncReadyCallback) on_driver_registered, + task); + watch_smartcards_from_driver_async (self, + driver, + cancellable, + (GAsyncReadyCallback) on_smartcards_from_driver_watched, + task); +} + +typedef struct +{ + int pending_drivers_count; + int activated_drivers_count; +} ActivateAllDriversOperation; + +static gboolean +activate_driver_async_finish (GsdSmartcardManager *self, + GAsyncResult *result, + GError **error) +{ + return gsd_smartcard_utils_finish_boolean_task (G_OBJECT (self), result, error); +} + +static void +try_to_complete_all_drivers_activation (GTask *task) +{ + ActivateAllDriversOperation *operation; + + operation = g_task_get_task_data (task); + + if (operation->pending_drivers_count >= 0) + return; + + if (operation->activated_drivers_count > 0) + g_task_return_boolean (task, TRUE); + else + g_task_return_boolean (task, FALSE); + + g_object_unref (task); +} + +static void +on_driver_activated (GsdSmartcardManager *self, + GAsyncResult *result, + GTask *task) +{ + GError *error = NULL; + gboolean driver_activated; + ActivateAllDriversOperation *operation; + + driver_activated = activate_driver_async_finish (self, result, &error); + + operation = g_task_get_task_data (task); + + if (driver_activated) + operation->activated_drivers_count++; + + operation->pending_drivers_count--; + + try_to_complete_all_drivers_activation (task); +} + +static void +activate_all_drivers_async (GsdSmartcardManager *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + SECMODListLock *lock; + SECMODModuleList *driver_list, *node; + ActivateAllDriversOperation *operation; + + task = g_task_new (self, cancellable, callback, user_data); + operation = g_new0 (ActivateAllDriversOperation, 1); + g_task_set_task_data (task, operation, (GDestroyNotify) g_free); + + lock = SECMOD_GetDefaultModuleListLock (); + + g_assert (lock != NULL); + + SECMOD_GetReadLock (lock); + driver_list = SECMOD_GetDefaultModuleList (); + for (node = driver_list; node != NULL; node = node->next) { + if (!node->module->loaded) + continue; + + if (!SECMOD_HasRemovableSlots (node->module)) + continue; + + operation->pending_drivers_count++; + + activate_driver (self, node->module, + cancellable, + (GAsyncReadyCallback) on_driver_activated, + task); + + } + SECMOD_ReleaseReadLock (lock); +} + +static gboolean +activate_all_drivers_async_finish (GsdSmartcardManager *self, + GAsyncResult *result, + GError **error) +{ + return gsd_smartcard_utils_finish_boolean_task (G_OBJECT (self), result, error); +} + +static void +on_all_drivers_activated (GsdSmartcardManager *self, + GAsyncResult *result, + GTask *task) +{ + GError *error = NULL; + gboolean driver_activated; + + driver_activated = activate_all_drivers_async_finish (self, result, &error); + + if (!driver_activated) { + g_task_return_error (task, error); + return; + } + + g_task_return_boolean (task, TRUE); +} + +static void +watch_smartcards (GTask *task, + GsdSmartcardManager *self, + gpointer data, + GCancellable *cancellable) +{ + GMainContext *context; + GMainLoop *loop; + + g_debug ("Getting list of suitable drivers"); + context = g_main_context_new (); + g_main_context_push_thread_default (context); + + activate_all_drivers_async (self, + cancellable, + (GAsyncReadyCallback) on_all_drivers_activated, + task); + + loop = g_main_loop_new (context, FALSE); + g_main_loop_run (loop); + g_main_loop_unref (loop); + + g_main_context_pop_thread_default (context); + g_main_context_unref (context); +} + +static void +watch_smartcards_async (GsdSmartcardManager *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + + task = g_task_new (self, cancellable, callback, user_data); + + g_task_run_in_thread (task, (GTaskThreadFunc) watch_smartcards); + + g_object_unref (task); +} + +static gboolean +watch_smartcards_async_finish (GsdSmartcardManager *self, + GAsyncResult *result, + GError **error) +{ + return gsd_smartcard_utils_finish_boolean_task (G_OBJECT (self), result, error); +} + +static void +on_smartcards_watched (GsdSmartcardManager *self, + GAsyncResult *result) +{ + GError *error = NULL; + + if (!watch_smartcards_async_finish (self, result, &error)) { + g_debug ("Error watching smartcards: %s", error->message); + g_error_free (error); + } +} + +static void +on_service_created (GObject *source_object, + GAsyncResult *result, + GsdSmartcardManager *self) +{ + GsdSmartcardManagerPrivate *priv = self->priv; + GsdSmartcardService *service; + GError *error = NULL; + + service = gsd_smartcard_service_new_finish (result, &error); + + if (service == NULL) { + g_warning("Couldn't create session bus service: %s", error->message); + g_error_free (error); + return; + } + + priv->service = service; + + watch_smartcards_async (self, + priv->cancellable, + (GAsyncReadyCallback) on_smartcards_watched, + NULL); + +} + +static gboolean +gsd_smartcard_manager_idle_cb (GsdSmartcardManager *self) +{ + GsdSmartcardManagerPrivate *priv = self->priv; + + gnome_settings_profile_start (NULL); + + priv->cancellable = g_cancellable_new(); + priv->settings = g_settings_new (CONF_SCHEMA); + + load_nss (self); + + gsd_smartcard_service_new_async (self, + priv->cancellable, + (GAsyncReadyCallback) on_service_created, + self); + + gnome_settings_profile_end (NULL); + + priv->start_idle_id = 0; + return FALSE; +} + +gboolean +gsd_smartcard_manager_start (GsdSmartcardManager *self, + GError **error) +{ + GsdSmartcardManagerPrivate *priv = self->priv; + + gnome_settings_profile_start (NULL); + + priv->start_idle_id = g_idle_add ((GSourceFunc) gsd_smartcard_manager_idle_cb, self); + + gnome_settings_profile_end (NULL); + + return TRUE; +} + +void +gsd_smartcard_manager_stop (GsdSmartcardManager *self) +{ + GsdSmartcardManagerPrivate *priv = self->priv; + + g_debug ("Stopping smartcard manager"); + + unload_nss (self); + + g_clear_object (&priv->settings); + g_clear_object (&priv->cancellable); +} + +static PK11SlotInfo * +get_login_token_for_operation (GsdSmartcardManager *self, + WatchSmartcardsOperation *operation) +{ + GHashTableIter iter; + gpointer key, value; + + g_hash_table_iter_init (&iter, operation->smartcards); + while (g_hash_table_iter_next (&iter, &key, &value)) { + PK11SlotInfo *card_slot; + const char *token_name; + + card_slot = (PK11SlotInfo *) value; + token_name = PK11_GetTokenName (card_slot); + + if (g_strcmp0 (g_getenv ("PKCS11_LOGIN_TOKEN_NAME"), token_name) == 0) + return card_slot; + } + + return NULL; +} + +PK11SlotInfo * +gsd_smartcard_manager_get_login_token (GsdSmartcardManager *self) +{ + GsdSmartcardManagerPrivate *priv = self->priv; + GList *node; + + G_LOCK (gsd_smartcards_watch_tasks); + node = priv->smartcards_watch_tasks; + while (node != NULL) { + PK11SlotInfo *card_slot; + + GTask *task = node->data; + WatchSmartcardsOperation *operation = g_task_get_task_data (task); + + card_slot = get_login_token_for_operation (self, operation); + + if (card_slot != NULL) + return card_slot; + + node = node->next; + } + G_UNLOCK (gsd_smartcards_watch_tasks); + + return NULL; +} + +static GList * +get_inserted_tokens_for_operation (GsdSmartcardManager *self, + WatchSmartcardsOperation *operation) +{ + GList *inserted_tokens = NULL; + GHashTableIter iter; + gpointer key, value; + + g_hash_table_iter_init (&iter, operation->smartcards); + while (g_hash_table_iter_next (&iter, &key, &value)) { + PK11SlotInfo *card_slot; + + card_slot = (PK11SlotInfo *) value; + + if (PK11_IsPresent (card_slot)) + inserted_tokens = g_list_prepend (inserted_tokens, card_slot); + } + + return inserted_tokens; +} + +GList * +gsd_smartcard_manager_get_inserted_tokens (GsdSmartcardManager *self, + gsize *num_tokens) +{ + GsdSmartcardManagerPrivate *priv = self->priv; + GList *inserted_tokens = NULL, *node; + + G_LOCK (gsd_smartcards_watch_tasks); + for (node = priv->smartcards_watch_tasks; node != NULL; node = node->next) { + GTask *task = node->data; + WatchSmartcardsOperation *operation = g_task_get_task_data (task); + GList *operation_inserted_tokens; + + operation_inserted_tokens = get_inserted_tokens_for_operation (self, operation); + + inserted_tokens = g_list_concat (inserted_tokens, operation_inserted_tokens); + } + G_UNLOCK (gsd_smartcards_watch_tasks); + + if (num_tokens != NULL) + *num_tokens = g_list_length (inserted_tokens); + + return inserted_tokens; +} + +static void +gsd_smartcard_manager_finalize (GObject *object) +{ + GsdSmartcardManager *self; + GsdSmartcardManagerPrivate *priv; + + g_return_if_fail (object != NULL); + g_return_if_fail (GSD_IS_SMARTCARD_MANAGER (object)); + + self = GSD_SMARTCARD_MANAGER (object); + priv = self->priv; + + g_return_if_fail (self->priv != NULL); + + if (priv->start_idle_id != 0) + g_source_remove (priv->start_idle_id); + + gsd_smartcard_manager_stop (self); + + G_OBJECT_CLASS (gsd_smartcard_manager_parent_class)->finalize (object); +} + +GsdSmartcardManager * +gsd_smartcard_manager_new (void) +{ + if (manager_object != NULL) { + g_object_ref (manager_object); + } else { + manager_object = g_object_new (GSD_TYPE_SMARTCARD_MANAGER, NULL); + g_object_add_weak_pointer (manager_object, + (gpointer *) &manager_object); + } + + return GSD_SMARTCARD_MANAGER (manager_object); +} diff --git a/plugins/smartcard/gsd-smartcard-manager.h b/plugins/smartcard/gsd-smartcard-manager.h new file mode 100644 index 00000000..9d3a2ce8 --- /dev/null +++ b/plugins/smartcard/gsd-smartcard-manager.h @@ -0,0 +1,82 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu> + * Copyright (C) 2010 Red Hat, Inc. + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __GSD_SMARTCARD_MANAGER_H +#define __GSD_SMARTCARD_MANAGER_H + +#include <glib-object.h> + +#include <prerror.h> +#include <prinit.h> +#include <nss.h> +#include <pk11func.h> +#include <secmod.h> +#include <secerr.h> + +G_BEGIN_DECLS + +#define GSD_TYPE_SMARTCARD_MANAGER (gsd_smartcard_manager_get_type ()) +#define GSD_SMARTCARD_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSD_TYPE_SMARTCARD_MANAGER, GsdSmartcardManager)) +#define GSD_SMARTCARD_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GSD_TYPE_SMARTCARD_MANAGER, GsdSmartcardManagerClass)) +#define GSD_IS_SMARTCARD_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSD_TYPE_SMARTCARD_MANAGER)) +#define GSD_IS_SMARTCARD_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSD_TYPE_SMARTCARD_MANAGER)) +#define GSD_SMARTCARD_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSD_TYPE_SMARTCARD_MANAGER, GsdSmartcardManagerClass)) +#define GSD_SMARTCARD_MANAGER_ERROR (gsd_smartcard_manager_error_quark ()) + +typedef struct GsdSmartcardManagerPrivate GsdSmartcardManagerPrivate; + +typedef struct +{ + GObject parent; + GsdSmartcardManagerPrivate *priv; +} GsdSmartcardManager; + +typedef struct +{ + GObjectClass parent_class; +} GsdSmartcardManagerClass; + +typedef enum +{ + GSD_SMARTCARD_MANAGER_ERROR_GENERIC = 0, + GSD_SMARTCARD_MANAGER_ERROR_WITH_NSS, + GSD_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER, + GSD_SMARTCARD_MANAGER_ERROR_WATCHING_FOR_EVENTS, + GSD_SMARTCARD_MANAGER_ERROR_REPORTING_EVENTS, + GSD_SMARTCARD_MANAGER_ERROR_FINDING_SMARTCARD +} GsdSmartcardManagerError; + +GType gsd_smartcard_manager_get_type (void); +GQuark gsd_smartcard_manager_error_quark (void); + + +GsdSmartcardManager * gsd_smartcard_manager_new (void); +gboolean gsd_smartcard_manager_start (GsdSmartcardManager *manager, + GError **error); +void gsd_smartcard_manager_stop (GsdSmartcardManager *manager); + +PK11SlotInfo * gsd_smartcard_manager_get_login_token (GsdSmartcardManager *manager); +GList * gsd_smartcard_manager_get_inserted_tokens (GsdSmartcardManager *manager, + gsize *num_tokens); + +G_END_DECLS + +#endif /* __GSD_SMARTCARD_MANAGER_H */ diff --git a/plugins/smartcard/gsd-smartcard-plugin.c b/plugins/smartcard/gsd-smartcard-plugin.c new file mode 100644 index 00000000..ea78f85f --- /dev/null +++ b/plugins/smartcard/gsd-smartcard-plugin.c @@ -0,0 +1,30 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu> + * Copyright (C) 2010 Red Hat, Inc. + * + * 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, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include "config.h" + +#include <glib/gi18n-lib.h> +#include <gmodule.h> + +#include "gnome-settings-plugin.h" +#include "gsd-smartcard-manager.h" + +GNOME_SETTINGS_PLUGIN_REGISTER (GsdSmartcard, gsd_smartcard) diff --git a/plugins/smartcard/gsd-smartcard-service.c b/plugins/smartcard/gsd-smartcard-service.c new file mode 100644 index 00000000..40350d06 --- /dev/null +++ b/plugins/smartcard/gsd-smartcard-service.c @@ -0,0 +1,773 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2012 Red Hat, Inc. + * + * 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., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: Ray Strode + */ + +#include "config.h" + +#include "gsd-smartcard-service.h" +#include "org.gnome.SettingsDaemon.Smartcard.h" +#include "gsd-smartcard-manager.h" +#include "gsd-smartcard-enum-types.h" +#include "gsd-smartcard-utils.h" + +#include "gnome-settings-plugin.h" + +#include <glib/gi18n.h> +#include <glib/gstdio.h> +#include <gio/gio.h> + +struct _GsdSmartcardServicePrivate +{ + GDBusConnection *bus_connection; + GDBusObjectManagerServer *object_manager_server; + GsdSmartcardManager *smartcard_manager; + GCancellable *cancellable; + GHashTable *tokens; + + guint name_id; +}; + +#define GSD_SMARTCARD_DBUS_NAME GSD_DBUS_NAME ".Smartcard" +#define GSD_SMARTCARD_DBUS_PATH GSD_DBUS_PATH "/Smartcard" +#define GSD_SMARTCARD_MANAGER_DBUS_PATH GSD_SMARTCARD_DBUS_PATH "/Manager" +#define GSD_SMARTCARD_MANAGER_DRIVERS_DBUS_PATH GSD_SMARTCARD_MANAGER_DBUS_PATH "/Drivers" +#define GSD_SMARTCARD_MANAGER_TOKENS_DBUS_PATH GSD_SMARTCARD_MANAGER_DBUS_PATH "/Tokens" + +enum { + PROP_0, + PROP_MANAGER, + PROP_BUS_CONNECTION +}; + +static void gsd_smartcard_service_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *param_spec); +static void gsd_smartcard_service_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *param_spec); +static void async_initable_interface_init (GAsyncInitableIface *interface); +static void smartcard_service_manager_interface_init (GsdSmartcardServiceManagerIface *interface); + +G_LOCK_DEFINE_STATIC (gsd_smartcard_tokens); + +G_DEFINE_TYPE_WITH_CODE (GsdSmartcardService, + gsd_smartcard_service, + GSD_SMARTCARD_SERVICE_TYPE_MANAGER_SKELETON, + G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, + async_initable_interface_init) + G_IMPLEMENT_INTERFACE (GSD_SMARTCARD_SERVICE_TYPE_MANAGER, + smartcard_service_manager_interface_init)); + +static void +set_bus_connection (GsdSmartcardService *self, + GDBusConnection *connection) +{ + GsdSmartcardServicePrivate *priv = self->priv; + + if (priv->bus_connection != connection) { + g_clear_object (&priv->bus_connection); + priv->bus_connection = g_object_ref (connection); + g_object_notify (G_OBJECT (self), "bus-connection"); + } +} + +static void +register_object_manager (GsdSmartcardService *self) +{ + GsdSmartcardServiceObjectSkeleton *object; + + self->priv->object_manager_server = g_dbus_object_manager_server_new (GSD_SMARTCARD_DBUS_PATH); + + object = gsd_smartcard_service_object_skeleton_new (GSD_SMARTCARD_MANAGER_DBUS_PATH); + gsd_smartcard_service_object_skeleton_set_manager (object, + GSD_SMARTCARD_SERVICE_MANAGER (self)); + + g_dbus_object_manager_server_export (self->priv->object_manager_server, + G_DBUS_OBJECT_SKELETON (object)); + g_object_unref (object); + + g_dbus_object_manager_server_set_connection (self->priv->object_manager_server, + self->priv->bus_connection); +} + +static void +on_bus_gotten (GObject *source_object, + GAsyncResult *result, + GTask *task) +{ + GsdSmartcardService *self; + GsdSmartcardServicePrivate *priv; + GDBusConnection *connection; + GError *error = NULL; + + connection = g_bus_get_finish (result, &error); + if (connection == NULL) { + g_task_return_error (task, error); + goto out; + } + + g_debug ("taking name %s on session bus", GSD_SMARTCARD_DBUS_NAME); + + self = g_task_get_source_object (task); + priv = self->priv; + + set_bus_connection (self, connection); + + register_object_manager (self); + priv->name_id = g_bus_own_name_on_connection (connection, + GSD_SMARTCARD_DBUS_NAME, + G_BUS_NAME_OWNER_FLAGS_NONE, + NULL, + NULL, + NULL, + NULL); + g_task_return_boolean (task, TRUE); + +out: + g_object_unref (task); + return; +} + +static gboolean +gsd_smartcard_service_initable_init_finish (GAsyncInitable *initable, + GAsyncResult *result, + GError **error) +{ + GTask *task; + + task = G_TASK (result); + + return g_task_propagate_boolean (task, error); +} + +static void +gsd_smartcard_service_initable_init_async (GAsyncInitable *initable, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GsdSmartcardService *self = GSD_SMARTCARD_SERVICE (initable); + GTask *task; + + task = g_task_new (G_OBJECT (self), cancellable, callback, user_data); + g_task_set_priority (task, io_priority); + + g_bus_get (G_BUS_TYPE_SESSION, cancellable, (GAsyncReadyCallback) on_bus_gotten, task); +} + +static void +async_initable_interface_init (GAsyncInitableIface *interface) +{ + interface->init_async = gsd_smartcard_service_initable_init_async; + interface->init_finish = gsd_smartcard_service_initable_init_finish; +} + +static char * +get_object_path_for_token (GsdSmartcardService *self, + PK11SlotInfo *card_slot) +{ + char *object_path; + char *escaped_library_path; + SECMODModule *driver; + CK_SLOT_ID slot_id; + + driver = PK11_GetModule (card_slot); + slot_id = PK11_GetSlotID (card_slot); + + escaped_library_path = gsd_smartcard_utils_escape_object_path (driver->dllName); + + object_path = g_strdup_printf ("%s/token_from_%s_slot_%lu", + GSD_SMARTCARD_MANAGER_TOKENS_DBUS_PATH, + escaped_library_path, + (gulong) slot_id); + g_free (escaped_library_path); + + return object_path; +} + +static gboolean +gsd_smartcard_service_handle_get_login_token (GsdSmartcardServiceManager *manager, + GDBusMethodInvocation *invocation) +{ + GsdSmartcardService *self = GSD_SMARTCARD_SERVICE (manager); + GsdSmartcardServicePrivate *priv = self->priv; + PK11SlotInfo *card_slot; + char *object_path; + + card_slot = gsd_smartcard_manager_get_login_token (priv->smartcard_manager); + + if (card_slot == NULL) { + g_dbus_method_invocation_return_error (invocation, + GSD_SMARTCARD_MANAGER_ERROR, + GSD_SMARTCARD_MANAGER_ERROR_FINDING_SMARTCARD, + _("User was not logged in with smartcard.")); + + return TRUE; + } + + object_path = get_object_path_for_token (self, card_slot); + gsd_smartcard_service_manager_complete_get_login_token (manager, + invocation, + object_path); + g_free (object_path); + + return TRUE; +} + +static gboolean +gsd_smartcard_service_handle_get_inserted_tokens (GsdSmartcardServiceManager *manager, + GDBusMethodInvocation *invocation) +{ + GsdSmartcardService *self = GSD_SMARTCARD_SERVICE (manager); + GsdSmartcardServicePrivate *priv = self->priv; + GList *inserted_tokens, *node; + GPtrArray *object_paths; + + inserted_tokens = gsd_smartcard_manager_get_inserted_tokens (priv->smartcard_manager, + NULL); + + object_paths = g_ptr_array_new (); + for (node = inserted_tokens; node != NULL; node = node->next) { + PK11SlotInfo *card_slot = node->data; + char *object_path; + + object_path = get_object_path_for_token (self, card_slot); + g_ptr_array_add (object_paths, object_path); + } + g_ptr_array_add (object_paths, NULL); + g_list_free (inserted_tokens); + + gsd_smartcard_service_manager_complete_get_inserted_tokens (manager, + invocation, + (const char * const *) object_paths->pdata); + + g_ptr_array_free (object_paths, TRUE); + + return TRUE; +} + +static void +smartcard_service_manager_interface_init (GsdSmartcardServiceManagerIface *interface) +{ + interface->handle_get_login_token = gsd_smartcard_service_handle_get_login_token; + interface->handle_get_inserted_tokens = gsd_smartcard_service_handle_get_inserted_tokens; +} + +static void +gsd_smartcard_service_init (GsdSmartcardService *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + GSD_TYPE_SMARTCARD_SERVICE, + GsdSmartcardServicePrivate); + self->priv->tokens = g_hash_table_new_full (g_str_hash, + g_str_equal, + (GDestroyNotify) g_free, + NULL); +} + +static void +gsd_smartcard_service_dispose (GObject *object) +{ + GsdSmartcardService *self = GSD_SMARTCARD_SERVICE (object); + + g_clear_object (&self->priv->bus_connection); + g_clear_object (&self->priv->object_manager_server); + g_clear_object (&self->priv->smartcard_manager); + + g_cancellable_cancel (self->priv->cancellable); + g_clear_object (&self->priv->cancellable); + g_clear_pointer (&self->priv->tokens, g_hash_table_unref); + + G_OBJECT_CLASS (gsd_smartcard_service_parent_class)->dispose (object); +} + +static void +gsd_smartcard_service_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *param_spec) +{ + GsdSmartcardService *self = GSD_SMARTCARD_SERVICE (object); + GsdSmartcardServicePrivate *priv = self->priv; + + switch (property_id) { + case PROP_MANAGER: + priv->smartcard_manager = g_value_dup_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec); + break; + } +} + +static void +gsd_smartcard_service_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *param_spec) +{ + GsdSmartcardService *self = GSD_SMARTCARD_SERVICE (object); + GsdSmartcardServicePrivate *priv = self->priv; + + switch (property_id) { + case PROP_MANAGER: + g_value_set_object (value, priv->smartcard_manager); + break; + case PROP_BUS_CONNECTION: + g_value_set_object (value, priv->bus_connection); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec); + break; + } +} + +static void +gsd_smartcard_service_class_init (GsdSmartcardServiceClass *service_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (service_class); + GParamSpec *param_spec; + + object_class->dispose = gsd_smartcard_service_dispose; + object_class->set_property = gsd_smartcard_service_set_property; + object_class->get_property = gsd_smartcard_service_get_property; + + param_spec = g_param_spec_object ("manager", + "Smartcard Manager", + "Smartcard Manager", + GSD_TYPE_SMARTCARD_MANAGER, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_property (object_class, PROP_MANAGER, param_spec); + param_spec = g_param_spec_object ("bus-connection", + "Bus Connection", + "bus connection", + G_TYPE_DBUS_CONNECTION, + G_PARAM_READABLE); + g_object_class_install_property (object_class, PROP_BUS_CONNECTION, param_spec); + + g_type_class_add_private (service_class, sizeof (GsdSmartcardServicePrivate)); +} + +static void +on_new_async_finished (GObject *source_object, + GAsyncResult *result, + GTask *task) +{ + GError *error = NULL; + GObject *object; + + object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), + result, + &error); + + if (object == NULL) { + g_task_return_error (task, error); + goto out; + } + + g_assert (GSD_IS_SMARTCARD_SERVICE (object)); + + g_task_return_pointer (task, object, g_object_unref); +out: + g_object_unref (task); + return; +} + +void +gsd_smartcard_service_new_async (GsdSmartcardManager *manager, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + + task = g_task_new (NULL, cancellable, callback, user_data); + + g_async_initable_new_async (GSD_TYPE_SMARTCARD_SERVICE, + G_PRIORITY_DEFAULT, + cancellable, + (GAsyncReadyCallback) on_new_async_finished, + task, + "manager", manager, + NULL); +} + +GsdSmartcardService * +gsd_smartcard_service_new_finish (GAsyncResult *result, + GError **error) +{ + GTask *task; + GsdSmartcardService *self = NULL; + + task = G_TASK (result); + + self = g_task_propagate_pointer (task, error); + + if (self == NULL) + return self; + + return g_object_ref (self); +} + +static char * +get_object_path_for_driver (GsdSmartcardService *self, + SECMODModule *driver) +{ + char *object_path; + char *escaped_library_path; + + escaped_library_path = gsd_smartcard_utils_escape_object_path (driver->dllName); + + object_path = g_build_path ("/", + GSD_SMARTCARD_MANAGER_DRIVERS_DBUS_PATH, + escaped_library_path, NULL); + g_free (escaped_library_path); + + return object_path; +} + +void +gsd_smartcard_service_register_driver (GsdSmartcardService *self, + SECMODModule *driver) +{ + char *object_path; + GDBusObjectSkeleton *object; + GDBusInterfaceSkeleton *interface; + + object_path = get_object_path_for_driver (self, driver); + object = G_DBUS_OBJECT_SKELETON (gsd_smartcard_service_object_skeleton_new (object_path)); + g_free (object_path); + + interface = G_DBUS_INTERFACE_SKELETON (gsd_smartcard_service_driver_skeleton_new ()); + g_dbus_object_skeleton_add_interface (object, interface); + g_object_unref (interface); + + g_object_set (G_OBJECT (interface), + "library", driver->dllName, + "description", driver->commonName, + NULL); + g_dbus_object_manager_server_export (self->priv->object_manager_server, + object); + g_object_unref (object); +} + +static void +synchronize_token_now (GsdSmartcardService *self, + PK11SlotInfo *card_slot) +{ + GsdSmartcardServicePrivate *priv = self->priv; + GDBusInterfaceSkeleton *interface; + char *object_path; + const char *token_name; + gboolean is_present, is_login_card; + + object_path = get_object_path_for_token (self, card_slot); + + G_LOCK (gsd_smartcard_tokens); + interface = g_hash_table_lookup (priv->tokens, object_path); + g_free (object_path); + + if (interface == NULL) + goto out; + + token_name = PK11_GetTokenName (card_slot); + is_present = PK11_IsPresent (card_slot); + + if (g_strcmp0 (g_getenv ("PKCS11_LOGIN_TOKEN_NAME"), token_name) == 0) + is_login_card = TRUE; + else + is_login_card = FALSE; + + g_debug ("==============================="); + g_debug (" Token '%s'", token_name); + g_debug (" Inserted: %s", is_present? "yes" : "no"); + g_debug (" Previously used to login: %s", is_login_card? "yes" : "no"); + g_debug ("===============================\n"); + + g_object_set (G_OBJECT (interface), + "used-to-login", is_login_card, + "is-inserted", is_present, + NULL); + g_object_get (G_OBJECT (interface), + "used-to-login", &is_login_card, + "is-inserted", &is_present, + NULL); + +out: + G_UNLOCK (gsd_smartcard_tokens); +} + +typedef struct +{ + PK11SlotInfo *card_slot; + char *object_path; + GSource *main_thread_source; +} RegisterNewTokenOperation; + +static void +destroy_register_new_token_operation (RegisterNewTokenOperation *operation) +{ + g_clear_pointer (&operation->main_thread_source, + (GDestroyNotify) g_source_destroy); + PK11_FreeSlot (operation->card_slot); + g_free (operation->object_path); + g_free (operation); +} + +static gboolean +on_main_thread_to_register_new_token (GTask *task) +{ + GsdSmartcardService *self; + GsdSmartcardServicePrivate *priv; + GDBusObjectSkeleton *object; + GDBusInterfaceSkeleton *interface; + RegisterNewTokenOperation *operation; + SECMODModule *driver; + char *driver_object_path; + const char *token_name; + + self = g_task_get_source_object (task); + priv = self->priv; + + operation = g_task_get_task_data (task); + operation->main_thread_source = NULL; + + object = G_DBUS_OBJECT_SKELETON (gsd_smartcard_service_object_skeleton_new (operation->object_path)); + interface = G_DBUS_INTERFACE_SKELETON (gsd_smartcard_service_token_skeleton_new ()); + + g_dbus_object_skeleton_add_interface (object, interface); + g_object_unref (interface); + + driver = PK11_GetModule (operation->card_slot); + driver_object_path = get_object_path_for_driver (self, driver); + + token_name = PK11_GetTokenName (operation->card_slot); + + g_object_set (G_OBJECT (interface), + "driver", driver_object_path, + "name", token_name, + NULL); + g_free (driver_object_path); + + g_dbus_object_manager_server_export (self->priv->object_manager_server, + object); + + G_LOCK (gsd_smartcard_tokens); + g_hash_table_insert (priv->tokens, g_strdup (operation->object_path), interface); + G_UNLOCK (gsd_smartcard_tokens); + + g_task_return_boolean (task, TRUE); + + return G_SOURCE_REMOVE; +} + +static void +create_main_thread_source (GSourceFunc callback, + gpointer user_data, + GSource **source_out) +{ + GSource *source; + + source = g_idle_source_new (); + g_source_set_callback (source, callback, user_data, NULL); + + *source_out = source; + g_source_attach (source, NULL); + g_source_unref (source); +} + +static void +register_new_token_in_main_thread (GsdSmartcardService *self, + PK11SlotInfo *card_slot, + char *object_path, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + RegisterNewTokenOperation *operation; + GTask *task; + + operation = g_new0 (RegisterNewTokenOperation, 1); + operation->card_slot = PK11_ReferenceSlot (card_slot); + operation->object_path = g_strdup (object_path); + + task = g_task_new (self, cancellable, callback, user_data); + + g_task_set_task_data (task, + operation, + (GDestroyNotify) destroy_register_new_token_operation); + + create_main_thread_source ((GSourceFunc) on_main_thread_to_register_new_token, + task, + &operation->main_thread_source); +} + +static gboolean +register_new_token_in_main_thread_finish (GsdSmartcardService *self, + GAsyncResult *result, + GError **error) +{ + return gsd_smartcard_utils_finish_boolean_task (G_OBJECT (self), result, error); +} + +static void +on_token_registered (GsdSmartcardService *self, + GAsyncResult *result, + PK11SlotInfo *card_slot) +{ + gboolean registered; + GError *error = NULL; + + registered = register_new_token_in_main_thread_finish (self, result, &error); + + if (!registered) { + g_debug ("Couldn't register token: %s", + error->message); + goto out; + } + + synchronize_token_now (self, card_slot); + +out: + PK11_FreeSlot (card_slot); +} + +typedef struct +{ + PK11SlotInfo *card_slot; + GSource *main_thread_source; +} SynchronizeTokenOperation; + +static void +destroy_synchronize_token_operation (SynchronizeTokenOperation *operation) +{ + g_clear_pointer (&operation->main_thread_source, + (GDestroyNotify) + g_source_destroy); + PK11_FreeSlot (operation->card_slot); + g_free (operation); +} + +static gboolean +on_main_thread_to_synchronize_token (GTask *task) +{ + GsdSmartcardService *self; + SynchronizeTokenOperation *operation; + + self = g_task_get_source_object (task); + + operation = g_task_get_task_data (task); + operation->main_thread_source = NULL; + + synchronize_token_now (self, operation->card_slot); + + g_task_return_boolean (task, TRUE); + + return G_SOURCE_REMOVE; +} + +static gboolean +synchronize_token_in_main_thread_finish (GsdSmartcardService *self, + GAsyncResult *result, + GError **error) +{ + return gsd_smartcard_utils_finish_boolean_task (G_OBJECT (self), result, error); +} + +static void +synchronize_token_in_main_thread (GsdSmartcardService *self, + PK11SlotInfo *card_slot, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + SynchronizeTokenOperation *operation; + GTask *task; + + operation = g_new0 (SynchronizeTokenOperation, 1); + operation->card_slot = PK11_ReferenceSlot (card_slot); + + task = g_task_new (self, cancellable, callback, user_data); + + g_task_set_task_data (task, + operation, + (GDestroyNotify) + destroy_synchronize_token_operation); + + create_main_thread_source ((GSourceFunc) + on_main_thread_to_synchronize_token, + task, + &operation->main_thread_source); +} + +static void +on_token_synchronized (GsdSmartcardService *self, + GAsyncResult *result, + PK11SlotInfo *card_slot) +{ + gboolean synchronized; + GError *error = NULL; + + synchronized = synchronize_token_in_main_thread_finish (self, result, &error); + + if (!synchronized) + g_debug ("Couldn't synchronize token: %s", error->message); + + PK11_FreeSlot (card_slot); +} + +void +gsd_smartcard_service_sync_token (GsdSmartcardService *self, + PK11SlotInfo *card_slot, + GCancellable *cancellable) +{ + GsdSmartcardServicePrivate *priv = self->priv; + char *object_path; + GDBusInterfaceSkeleton *interface; + + object_path = get_object_path_for_token (self, card_slot); + + G_LOCK (gsd_smartcard_tokens); + interface = g_hash_table_lookup (priv->tokens, object_path); + G_UNLOCK (gsd_smartcard_tokens); + + if (interface == NULL) + register_new_token_in_main_thread (self, + card_slot, + object_path, + cancellable, + (GAsyncReadyCallback) + on_token_registered, + PK11_ReferenceSlot (card_slot)); + + else + synchronize_token_in_main_thread (self, + card_slot, + cancellable, + (GAsyncReadyCallback) + on_token_synchronized, + PK11_ReferenceSlot (card_slot)); + + g_free (object_path); +} diff --git a/plugins/smartcard/gsd-smartcard-service.h b/plugins/smartcard/gsd-smartcard-service.h new file mode 100644 index 00000000..2e480014 --- /dev/null +++ b/plugins/smartcard/gsd-smartcard-service.h @@ -0,0 +1,81 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2012 Red Hat, Inc. + * + * 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., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Authors: Ray Strode + */ + +#ifndef __GSD_SMARTCARD_SERVICE_H__ +#define __GSD_SMARTCARD_SERVICE_H__ + +#include <glib.h> +#include <glib-object.h> +#include <gio/gio.h> +#include "gsd-smartcard-manager.h" + +#include "org.gnome.SettingsDaemon.Smartcard.h" + +#include <prerror.h> +#include <prinit.h> +#include <nss.h> +#include <pk11func.h> +#include <secmod.h> +#include <secerr.h> + +G_BEGIN_DECLS + +#define GSD_TYPE_SMARTCARD_SERVICE (gsd_smartcard_service_get_type ()) +#define GSD_SMARTCARD_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GSD_TYPE_SMARTCARD_SERVICE, GsdSmartcardService)) +#define GSD_SMARTCARD_SERVICE_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GSD_TYPE_SMARTCARD_SERVICE, GsdSmartcardServiceClass)) +#define GSD_IS_SMARTCARD_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GSD_TYPE_SMARTCARD_SERVICE)) +#define GSD_IS_SMARTCARD_SERVICE_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GSD_TYPE_SMARTCARD_SERVICE)) +#define GSD_SMARTCARD_SERVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSD_TYPE_SMARTCARD_SERVICE, GsdSmartcardServiceClass)) + +typedef struct _GsdSmartcardService GsdSmartcardService; +typedef struct _GsdSmartcardServiceClass GsdSmartcardServiceClass; +typedef struct _GsdSmartcardServicePrivate GsdSmartcardServicePrivate; + +struct _GsdSmartcardService +{ + GsdSmartcardServiceManagerSkeleton parent_instance; + GsdSmartcardServicePrivate *priv; +}; + +struct _GsdSmartcardServiceClass +{ + GsdSmartcardServiceManagerSkeletonClass parent_class; +}; + +GType gsd_smartcard_service_get_type (void); +void gsd_smartcard_service_new_async (GsdSmartcardManager *manager, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +GsdSmartcardService *gsd_smartcard_service_new_finish (GAsyncResult *result, + GError **error); + +void gsd_smartcard_service_register_driver (GsdSmartcardService *service, + SECMODModule *driver); +void gsd_smartcard_service_sync_token (GsdSmartcardService *service, + PK11SlotInfo *slot_info, + GCancellable *cancellable); + + +G_END_DECLS + +#endif /* __GSD_SMARTCARD_SERVICE_H__ */ diff --git a/plugins/smartcard/gsd-smartcard-utils.c b/plugins/smartcard/gsd-smartcard-utils.c new file mode 100644 index 00000000..a2511a5e --- /dev/null +++ b/plugins/smartcard/gsd-smartcard-utils.c @@ -0,0 +1,191 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2013 Red Hat, Inc. + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include "config.h" +#include "gsd-smartcard-utils.h" + +#include <string.h> + +#include <glib.h> +#include <gio/gio.h> + +static char * +dashed_string_to_studly_caps (const char *dashed_string) +{ + char *studly_string; + size_t studly_string_length; + size_t i; + + i = 0; + + studly_string = g_strdup (dashed_string); + studly_string_length = strlen (studly_string); + + studly_string[i] = g_ascii_toupper (studly_string[i]); + i++; + + while (i < studly_string_length) { + if (studly_string[i] == '-' || studly_string[i] == '_') { + memmove (studly_string + i, + studly_string + i + 1, + studly_string_length - i - 1); + studly_string_length--; + if (g_ascii_isalpha (studly_string[i])) { + studly_string[i] = g_ascii_toupper (studly_string[i]); + } + } + i++; + } + studly_string[studly_string_length] = '\0'; + + return studly_string; +} + +static char * +dashed_string_to_dbus_error_string (const char *dashed_string, + const char *old_prefix, + const char *new_prefix, + const char *suffix) +{ + char *studly_suffix; + char *dbus_error_string; + size_t dbus_error_string_length; + size_t i; + + i = 0; + + if (g_str_has_prefix (dashed_string, old_prefix) && + (dashed_string[strlen(old_prefix)] == '-' || + dashed_string[strlen(old_prefix)] == '_')) { + dashed_string += strlen (old_prefix) + 1; + } + + studly_suffix = dashed_string_to_studly_caps (suffix); + dbus_error_string = g_strdup_printf ("%s.%s.%s", new_prefix, dashed_string, studly_suffix); + g_free (studly_suffix); + i += strlen (new_prefix) + 1; + + dbus_error_string_length = strlen (dbus_error_string); + + dbus_error_string[i] = g_ascii_toupper (dbus_error_string[i]); + i++; + + while (i < dbus_error_string_length) { + if (dbus_error_string[i] == '_' || dbus_error_string[i] == '-') { + dbus_error_string[i] = '.'; + + if (g_ascii_isalpha (dbus_error_string[i + 1])) { + dbus_error_string[i + 1] = g_ascii_toupper (dbus_error_string[i + 1]); + } + } + + i++; + } + + return dbus_error_string; +} + +void +gsd_smartcard_utils_register_error_domain (GQuark error_domain, + GType error_enum) +{ + const char *error_domain_string; + char *type_name; + GType type; + GTypeClass *type_class; + GEnumClass *enum_class; + guint i; + + error_domain_string = g_quark_to_string (error_domain); + type_name = dashed_string_to_studly_caps (error_domain_string); + type = g_type_from_name (type_name); + type_class = g_type_class_ref (type); + enum_class = G_ENUM_CLASS (type_class); + + for (i = 0; i < enum_class->n_values; i++) { + char *dbus_error_string; + + dbus_error_string = dashed_string_to_dbus_error_string (error_domain_string, + "gsd", + "org.gnome.SettingsDaemon", + enum_class->values[i].value_nick); + + g_debug ("%s: Registering dbus error %s", type_name, dbus_error_string); + g_dbus_error_register_error (error_domain, + enum_class->values[i].value, + dbus_error_string); + g_free (dbus_error_string); + } + + g_type_class_unref (type_class); +} + +char * +gsd_smartcard_utils_escape_object_path (const char *unescaped_string) +{ + const char *p; + char *object_path; + GString *string; + + g_return_val_if_fail (unescaped_string != NULL, NULL); + + string = g_string_new (""); + + for (p = unescaped_string; *p != '\0'; p++) + { + guchar character; + + character = (guchar) * p; + + if (((character >= ((guchar) 'a')) && + (character <= ((guchar) 'z'))) || + ((character >= ((guchar) 'A')) && + (character <= ((guchar) 'Z'))) || + ((character >= ((guchar) '0')) && (character <= ((guchar) '9')))) + { + g_string_append_c (string, (char) character); + continue; + } + + g_string_append_printf (string, "_%x_", character); + } + + object_path = string->str; + + g_string_free (string, FALSE); + + return object_path; +} + +gboolean +gsd_smartcard_utils_finish_boolean_task (GObject *object, + GAsyncResult *result, + GError **error) +{ + gboolean return_value; + + g_return_val_if_fail (g_task_is_valid (result, object), FALSE); + + return_value = g_task_propagate_boolean (G_TASK (result), error); + + g_object_unref (G_OBJECT (result)); + + return return_value; +} diff --git a/plugins/smartcard/gsd-smartcard-utils.h b/plugins/smartcard/gsd-smartcard-utils.h new file mode 100644 index 00000000..c39b0761 --- /dev/null +++ b/plugins/smartcard/gsd-smartcard-utils.h @@ -0,0 +1,38 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2013 Red Hat, Inc. + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __GSD_SMARTCARD_UTILS_H +#define __GSD_SMARTCARD_UTILS_H + +#include <glib-object.h> +#include <gio/gio.h> + +G_BEGIN_DECLS +void gsd_smartcard_utils_register_error_domain (GQuark error_domain, + GType error_enum); +char * gsd_smartcard_utils_escape_object_path (const char *unescaped_string); + +gboolean gsd_smartcard_utils_finish_boolean_task (GObject *object, + GAsyncResult *result, + GError **error); + +G_END_DECLS + +#endif /* __GSD_SMARTCARD_MANAGER_H */ diff --git a/plugins/smartcard/org.gnome.SettingsDaemon.Smartcard.xml b/plugins/smartcard/org.gnome.SettingsDaemon.Smartcard.xml new file mode 100644 index 00000000..3daade91 --- /dev/null +++ b/plugins/smartcard/org.gnome.SettingsDaemon.Smartcard.xml @@ -0,0 +1,91 @@ +<!DOCTYPE node PUBLIC + "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" + "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> + +<!-- + Copyright (C) 2013 Red Hat, Inc. + + 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., 59 Temple Place, Suite 330, + Boston, MA 02111-1307, USA. + + Author: Ray Strode <rstrode@redhat.com> +--> + +<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd"> + <!-- + org.gnome.SettingsDaemon.Smartcard.Manager: + + An interface used for managing smartcard functionality. + --> + <interface name="org.gnome.SettingsDaemon.Smartcard.Manager"> + <method name="GetLoginToken"> + <arg name="token" type="o" direction="out"/> + </method> + + <method name="GetInsertedTokens"> + <arg name="tokens" type="ao" direction="out"/> + </method> + </interface> + + <!-- + org.gnome.SettingsDaemon.Smartcard.Driver: + + The smartcard driver interface. + --> + <interface name="org.gnome.SettingsDaemon.Smartcard.Driver"> + <!-- + Library: + Path to PKCS11 module + --> + <property name="Library" type="s" access="read"/> + + <!-- + Description: + String describing the PKCS11 module + --> + <property name="Description" type="s" access="read"/> + </interface> + + <!-- + org.gnome.SettingsDaemon.Smartcard.Token: + + The smartcard interface. + --> + <interface name="org.gnome.SettingsDaemon.Smartcard.Token"> + <!-- + Name: + Name of the token + --> + <property name="Name" type="s" access="read"/> + + <!-- + Driver: + Driver handling token + --> + <property name="Driver" type="o" access="read"/> + + <!-- + IsInserted: + Whether or not the card is inserted + --> + <property name="IsInserted" type="b" access="read"/> + + <!-- + UsedToLogin: + Whether or not the card was used to log in + --> + <property name="UsedToLogin" type="b" access="read"/> + </interface> +</node> diff --git a/plugins/smartcard/test-smartcard.c b/plugins/smartcard/test-smartcard.c new file mode 100644 index 00000000..b5ee3d50 --- /dev/null +++ b/plugins/smartcard/test-smartcard.c @@ -0,0 +1,7 @@ +#define NEW gsd_smartcard_manager_new +#define START gsd_smartcard_manager_start +#define STOP gsd_smartcard_manager_stop +#define MANAGER GsdSmartcardManager +#include "gsd-smartcard-manager.h" + +#include "test-plugin.h" |