From 92b5f8d3ca7b83fa5f10c16b8e876cfde23e4377 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Tue, 28 May 2013 09:20:57 -0400 Subject: [PATCH 1/11] smartcard: drop old implementation It's going to be substantially rewritten, so drop the old code to avoid a confusing diff when the new stuff lands. https://bugzilla.gnome.org/show_bug.cgi?id=704890 --- plugins/smartcard/Makefile.am | 75 -- plugins/smartcard/gsd-smartcard-manager.c | 1519 ----------------------------- plugins/smartcard/gsd-smartcard-manager.h | 88 -- plugins/smartcard/gsd-smartcard-plugin.c | 337 ------- plugins/smartcard/gsd-smartcard-plugin.h | 59 -- plugins/smartcard/gsd-smartcard.c | 556 ----------- plugins/smartcard/gsd-smartcard.h | 94 -- plugins/smartcard/test-smartcard.c | 7 - 8 files changed, 2735 deletions(-) delete mode 100644 plugins/smartcard/Makefile.am delete mode 100644 plugins/smartcard/gsd-smartcard-manager.c delete mode 100644 plugins/smartcard/gsd-smartcard-manager.h delete mode 100644 plugins/smartcard/gsd-smartcard-plugin.c delete mode 100644 plugins/smartcard/gsd-smartcard-plugin.h delete mode 100644 plugins/smartcard/gsd-smartcard.c delete mode 100644 plugins/smartcard/gsd-smartcard.h delete mode 100644 plugins/smartcard/test-smartcard.c diff --git a/plugins/smartcard/Makefile.am b/plugins/smartcard/Makefile.am deleted file mode 100644 index e2a0add..0000000 --- a/plugins/smartcard/Makefile.am +++ /dev/null @@ -1,75 +0,0 @@ -plugin_name = smartcard - -libexec_PROGRAMS = gsd-test-smartcard - -gsd_test_smartcard_SOURCES = \ - gsd-smartcard-manager.h \ - gsd-smartcard-manager.c \ - gsd-smartcard.h \ - gsd-smartcard.c \ - test-smartcard.c - -gsd_test_smartcard_CFLAGS = \ - -I$(top_srcdir)/gnome-settings-daemon \ - -I$(top_srcdir)/plugins/common \ - -DSYSCONFDIR=\""$(sysconfdir)"\" \ - -DLIBDIR=\""$(libdir)"\" \ - -DGNOME_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ - $(NSS_CFLAGS) \ - $(PLUGIN_CFLAGS) \ - $(SETTINGS_PLUGIN_CFLAGS) \ - $(AM_CFLAGS) - -gsd_test_smartcard_LDADD = \ - $(top_builddir)/gnome-settings-daemon/libgsd.la \ - $(top_builddir)/plugins/common/libcommon.la \ - $(NSS_LIBS) \ - $(SETTINGS_PLUGIN_LIBS) - -plugin_LTLIBRARIES = \ - libsmartcard.la - -libsmartcard_la_SOURCES = \ - gsd-smartcard-plugin.h \ - gsd-smartcard-plugin.c \ - gsd-smartcard.h \ - gsd-smartcard.c \ - gsd-smartcard-manager.h \ - gsd-smartcard-manager.c - -libsmartcard_la_CPPFLAGS = \ - -I$(top_srcdir)/gnome-settings-daemon \ - -DGNOME_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ - -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-manager.c b/plugins/smartcard/gsd-smartcard-manager.c deleted file mode 100644 index 3acef0e..0000000 --- a/plugins/smartcard/gsd-smartcard-manager.c +++ /dev/null @@ -1,1519 +0,0 @@ -/* gsd-smartcard-manager.c - object for monitoring smartcard insertion and - * removal events - * - * Copyright (C) 2006, 2009 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. - * - * Written By: Ray Strode - */ -#include "config.h" - -#include "gsd-smartcard-manager.h" - -#define SMARTCARD_ENABLE_INTERNAL_API -#include "gsd-smartcard.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - -#ifndef GSD_SMARTCARD_MANAGER_DRIVER -#define GSD_SMARTCARD_MANAGER_DRIVER LIBDIR"/pkcs11/libcoolkeypk11.so" -#endif - -#ifndef GSD_SMARTCARD_MANAGER_NSS_DB -#define GSD_SMARTCARD_MANAGER_NSS_DB SYSCONFDIR"/pki/nssdb" -#endif - -#ifndef GSD_MAX_OPEN_FILE_DESCRIPTORS -#define GSD_MAX_OPEN_FILE_DESCRIPTORS 1024 -#endif - -#ifndef GSD_OPEN_FILE_DESCRIPTORS_DIR -#define GSD_OPEN_FILE_DESCRIPTORS_DIR "/proc/self/fd" -#endif - -typedef enum _GsdSmartcardManagerState GsdSmartcardManagerState; -typedef struct _GsdSmartcardManagerWorker GsdSmartcardManagerWorker; - -enum _GsdSmartcardManagerState { - GSD_SMARTCARD_MANAGER_STATE_STOPPED = 0, - GSD_SMARTCARD_MANAGER_STATE_STARTING, - GSD_SMARTCARD_MANAGER_STATE_STARTED, - GSD_SMARTCARD_MANAGER_STATE_STOPPING, -}; - -struct _GsdSmartcardManagerPrivate { - GsdSmartcardManagerState state; - GList *modules; - char *module_path; - - GList *workers; - - GPid smartcard_event_watcher_pid; - GHashTable *smartcards; - - guint poll_timeout_id; - - guint32 is_unstoppable : 1; - guint32 nss_is_loaded : 1; -}; - -struct _GsdSmartcardManagerWorker { - GsdSmartcardManager *manager; - int manager_fd; - - GThread *thread; - SECMODModule *module; - GHashTable *smartcards; - int fd; - GSource *event_source; - - guint32 nss_is_loaded : 1; -}; - -static void gsd_smartcard_manager_finalize (GObject *object); -static void gsd_smartcard_manager_class_install_signals (GsdSmartcardManagerClass *service_class); -static void gsd_smartcard_manager_class_install_properties (GsdSmartcardManagerClass *service_class); -static void gsd_smartcard_manager_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void gsd_smartcard_manager_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); -static void gsd_smartcard_manager_set_module_path (GsdSmartcardManager *manager, - const char *module_path); -static void gsd_smartcard_manager_card_removed_handler (GsdSmartcardManager *manager, - GsdSmartcard *card); -static void gsd_smartcard_manager_card_inserted_handler (GsdSmartcardManager *manager_class, - GsdSmartcard *card); -static gboolean gsd_smartcard_manager_stop_now (GsdSmartcardManager *manager); -static void gsd_smartcard_manager_queue_stop (GsdSmartcardManager *manager); - -static GsdSmartcardManagerWorker *gsd_smartcard_manager_create_worker (GsdSmartcardManager *manager, - SECMODModule *module); - -static GsdSmartcardManagerWorker * gsd_smartcard_manager_worker_new (GsdSmartcardManager *manager, - int worker_fd, - int manager_fd, - SECMODModule *module); -static void gsd_smartcard_manager_worker_free (GsdSmartcardManagerWorker *worker); -static gboolean open_pipe (int *write_fd, int *read_fd); -static gboolean read_bytes (int fd, gpointer bytes, gsize num_bytes); -static gboolean write_bytes (int fd, gconstpointer bytes, gsize num_bytes); -static GsdSmartcard *read_smartcard (int fd, SECMODModule *module); -static gboolean write_smartcard (int fd, GsdSmartcard *card); - -enum { - PROP_0 = 0, - PROP_MODULE_PATH, - NUMBER_OF_PROPERTIES -}; - -enum { - SMARTCARD_INSERTED = 0, - SMARTCARD_REMOVED, - ERROR, - NUMBER_OF_SIGNALS -}; - -static guint gsd_smartcard_manager_signals[NUMBER_OF_SIGNALS]; - -G_DEFINE_TYPE (GsdSmartcardManager, - gsd_smartcard_manager, - G_TYPE_OBJECT); - -static void -gsd_smartcard_manager_class_init (GsdSmartcardManagerClass *manager_class) -{ - GObjectClass *gobject_class; - - gobject_class = G_OBJECT_CLASS (manager_class); - - gobject_class->finalize = gsd_smartcard_manager_finalize; - - gsd_smartcard_manager_class_install_signals (manager_class); - gsd_smartcard_manager_class_install_properties (manager_class); - - g_type_class_add_private (manager_class, - sizeof (GsdSmartcardManagerPrivate)); -} - -static void -gsd_smartcard_manager_class_install_properties (GsdSmartcardManagerClass *card_class) -{ - GObjectClass *object_class; - GParamSpec *param_spec; - - object_class = G_OBJECT_CLASS (card_class); - object_class->set_property = gsd_smartcard_manager_set_property; - object_class->get_property = gsd_smartcard_manager_get_property; - - param_spec = g_param_spec_string ("module-path", "Module Path", - "path to smartcard PKCS #11 driver", - NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); - g_object_class_install_property (object_class, PROP_MODULE_PATH, param_spec); -} - -static void -gsd_smartcard_manager_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GsdSmartcardManager *manager = GSD_SMARTCARD_MANAGER (object); - - switch (prop_id) { - case PROP_MODULE_PATH: - gsd_smartcard_manager_set_module_path (manager, - g_value_get_string (value)); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gsd_smartcard_manager_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GsdSmartcardManager *manager = GSD_SMARTCARD_MANAGER (object); - char *module_path; - - switch (prop_id) { - case PROP_MODULE_PATH: - module_path = gsd_smartcard_manager_get_module_path (manager); - g_value_set_string (value, module_path); - g_free (module_path); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -char * -gsd_smartcard_manager_get_module_path (GsdSmartcardManager *manager) -{ - return manager->priv->module_path; -} - -static void -gsd_smartcard_manager_set_module_path (GsdSmartcardManager *manager, - const char *module_path) -{ - if ((manager->priv->module_path == NULL) && (module_path == NULL)) { - return; - } - - if (((manager->priv->module_path == NULL) || - (module_path == NULL) || - (strcmp (manager->priv->module_path, module_path) != 0))) { - g_free (manager->priv->module_path); - manager->priv->module_path = g_strdup (module_path); - g_object_notify (G_OBJECT (manager), "module-path"); - } -} - -static void -gsd_smartcard_manager_card_removed_handler (GsdSmartcardManager *manager, - GsdSmartcard *card) -{ - g_debug ("informing smartcard of its removal"); - _gsd_smartcard_set_state (card, GSD_SMARTCARD_STATE_REMOVED); - g_debug ("done"); -} - -static void -gsd_smartcard_manager_card_inserted_handler (GsdSmartcardManager *manager, - GsdSmartcard *card) -{ - g_debug ("informing smartcard of its insertion"); - - _gsd_smartcard_set_state (card, GSD_SMARTCARD_STATE_INSERTED); - g_debug ("done"); - -} - -static void -gsd_smartcard_manager_class_install_signals (GsdSmartcardManagerClass *manager_class) -{ - GObjectClass *object_class; - - object_class = G_OBJECT_CLASS (manager_class); - - gsd_smartcard_manager_signals[SMARTCARD_INSERTED] = - g_signal_new ("smartcard-inserted", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GsdSmartcardManagerClass, - smartcard_inserted), - NULL, NULL, g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_POINTER); - manager_class->smartcard_inserted = gsd_smartcard_manager_card_inserted_handler; - - gsd_smartcard_manager_signals[SMARTCARD_REMOVED] = - g_signal_new ("smartcard-removed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GsdSmartcardManagerClass, - smartcard_removed), - NULL, NULL, g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_POINTER); - manager_class->smartcard_removed = gsd_smartcard_manager_card_removed_handler; - - gsd_smartcard_manager_signals[ERROR] = - g_signal_new ("error", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GsdSmartcardManagerClass, error), - NULL, NULL, g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_POINTER); - manager_class->error = NULL; -} - -static gboolean -slot_id_equal (CK_SLOT_ID *slot_id_1, - CK_SLOT_ID *slot_id_2) -{ - g_assert (slot_id_1 != NULL); - g_assert (slot_id_2 != NULL); - - return *slot_id_1 == *slot_id_2; -} - -static gboolean -slot_id_hash (CK_SLOT_ID *slot_id) -{ - guint32 upper_bits, lower_bits; - int temp; - - if (sizeof (CK_SLOT_ID) == sizeof (int)) { - return g_int_hash (slot_id); - } - - upper_bits = ((*slot_id) >> 31) - 1; - lower_bits = (*slot_id) & 0xffffffff; - - /* The upper bits are almost certainly always zero, - * so let's degenerate to g_int_hash for the - * (very) common case - */ - temp = lower_bits + upper_bits; - return upper_bits + g_int_hash (&temp); -} - -static void -gsd_smartcard_manager_init (GsdSmartcardManager *manager) -{ - g_debug ("initializing smartcard manager"); - - manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager, - GSD_TYPE_SMARTCARD_MANAGER, - GsdSmartcardManagerPrivate); - manager->priv->poll_timeout_id = 0; - manager->priv->is_unstoppable = FALSE; - - manager->priv->smartcards = - g_hash_table_new_full (g_str_hash, - g_str_equal, - (GDestroyNotify) g_free, - (GDestroyNotify) g_object_unref); -} - -static void -gsd_smartcard_manager_finalize (GObject *object) -{ - GsdSmartcardManager *manager; - GObjectClass *gobject_class; - - manager = GSD_SMARTCARD_MANAGER (object); - gobject_class = - G_OBJECT_CLASS (gsd_smartcard_manager_parent_class); - - gsd_smartcard_manager_stop_now (manager); - - g_hash_table_destroy (manager->priv->smartcards); - manager->priv->smartcards = NULL; - - gobject_class->finalize (object); -} - -GQuark -gsd_smartcard_manager_error_quark (void) -{ - static GQuark error_quark = 0; - - if (error_quark == 0) { - error_quark = g_quark_from_static_string ("gsd-smartcard-manager-error-quark"); - } - - return error_quark; -} - -GsdSmartcardManager * -gsd_smartcard_manager_new_default (void) -{ - return gsd_smartcard_manager_new (NULL); -} - -GsdSmartcardManager * -gsd_smartcard_manager_new (const char *module_path) -{ - GsdSmartcardManager *instance; - - instance = GSD_SMARTCARD_MANAGER (g_object_new (GSD_TYPE_SMARTCARD_MANAGER, - "module-path", module_path, - NULL)); - - return instance; -} - -static void -gsd_smartcard_manager_emit_error (GsdSmartcardManager *manager, - GError *error) -{ - manager->priv->is_unstoppable = TRUE; - g_signal_emit (manager, gsd_smartcard_manager_signals[ERROR], 0, - error); - manager->priv->is_unstoppable = FALSE; -} - -static void -gsd_smartcard_manager_emit_smartcard_inserted (GsdSmartcardManager *manager, - GsdSmartcard *card) -{ - manager->priv->is_unstoppable = TRUE; - g_signal_emit (manager, gsd_smartcard_manager_signals[SMARTCARD_INSERTED], 0, - card); - manager->priv->is_unstoppable = FALSE; -} - -static void -gsd_smartcard_manager_emit_smartcard_removed (GsdSmartcardManager *manager, - GsdSmartcard *card) -{ - manager->priv->is_unstoppable = TRUE; - g_signal_emit (manager, gsd_smartcard_manager_signals[SMARTCARD_REMOVED], 0, - card); - manager->priv->is_unstoppable = FALSE; -} - -static gboolean -gsd_smartcard_manager_check_for_and_process_events (GIOChannel *io_channel, - GIOCondition condition, - GsdSmartcardManagerWorker *worker) -{ - GsdSmartcard *card; - GsdSmartcardManager *manager; - gboolean should_stop; - guchar event_type; - char *card_name; - int fd; - - manager = worker->manager; - - g_debug ("event!"); - card = NULL; - should_stop = (condition & G_IO_HUP) || (condition & G_IO_ERR); - - if (should_stop) { - g_debug ("received %s on event socket, stopping " - "manager...", - (condition & G_IO_HUP) && (condition & G_IO_ERR)? - "error and hangup" : - (condition & G_IO_HUP)? - "hangup" : "error"); - } - - if (!(condition & G_IO_IN)) { - g_debug ("nevermind outta here!"); - goto out; - } - - fd = g_io_channel_unix_get_fd (io_channel); - - event_type = '\0'; - if (!read_bytes (fd, &event_type, 1)) { - g_debug ("could not read event type, stopping"); - should_stop = TRUE; - goto out; - } - - card = read_smartcard (fd, worker->module); - - if (card == NULL) { - g_debug ("could not read card, stopping"); - should_stop = TRUE; - goto out; - } - - card_name = gsd_smartcard_get_name (card); - g_debug ("card '%s' had event %c", card_name, event_type); - - switch (event_type) { - case 'I': - g_hash_table_replace (manager->priv->smartcards, - card_name, card); - card_name = NULL; - - gsd_smartcard_manager_emit_smartcard_inserted (manager, card); - card = NULL; - break; - - case 'R': - gsd_smartcard_manager_emit_smartcard_removed (manager, card); - if (!g_hash_table_remove (manager->priv->smartcards, card_name)) { - g_debug ("got removal event of unknown card!"); - } - g_free (card_name); - card_name = NULL; - card = NULL; - break; - - default: - g_free (card_name); - card_name = NULL; - g_object_unref (card); - - should_stop = TRUE; - break; - } - -out: - if (should_stop) { - GError *error; - - error = g_error_new (GSD_SMARTCARD_MANAGER_ERROR, - GSD_SMARTCARD_MANAGER_ERROR_WATCHING_FOR_EVENTS, - "%s", (condition & G_IO_IN) ? g_strerror (errno) : _("received error or hang up from event source")); - - gsd_smartcard_manager_emit_error (manager, error); - g_error_free (error); - gsd_smartcard_manager_stop_now (manager); - return FALSE; - } - - return TRUE; -} - -static void -stop_manager (GsdSmartcardManager *manager) -{ - manager->priv->state = GSD_SMARTCARD_MANAGER_STATE_STOPPED; - - if (manager->priv->nss_is_loaded) { - NSS_Shutdown (); - manager->priv->nss_is_loaded = FALSE; - } - g_debug ("smartcard manager stopped"); -} - -static void -stop_worker (GsdSmartcardManagerWorker *worker) -{ - GsdSmartcardManager *manager; - - manager = worker->manager; - - if (worker->event_source != NULL) { - g_source_destroy (worker->event_source); - worker->event_source = NULL; - } - - if (worker->thread != NULL) { - SECMOD_CancelWait (worker->module); - worker->thread = NULL; - } - - SECMOD_DestroyModule (worker->module); - manager->priv->workers = g_list_remove (manager->priv->workers, worker); - - if (manager->priv->workers == NULL && manager->priv->state != GSD_SMARTCARD_MANAGER_STATE_STOPPED) { - stop_manager (manager); - } -} - -static void -gsd_smartcard_manager_event_processing_stopped_handler (GsdSmartcardManagerWorker *worker) -{ - worker->event_source = NULL; - - stop_worker (worker); -} - -static gboolean -open_pipe (int *write_fd, - int *read_fd) -{ - int pipe_fds[2] = { -1, -1 }; - - g_assert (write_fd != NULL); - g_assert (read_fd != NULL); - - if (pipe (pipe_fds) < 0) { - return FALSE; - } - - if (fcntl (pipe_fds[0], F_SETFD, FD_CLOEXEC) < 0) { - close (pipe_fds[0]); - close (pipe_fds[1]); - return FALSE; - } - - if (fcntl (pipe_fds[1], F_SETFD, FD_CLOEXEC) < 0) { - close (pipe_fds[0]); - close (pipe_fds[1]); - return FALSE; - } - - *read_fd = pipe_fds[0]; - *write_fd = pipe_fds[1]; - - return TRUE; -} - -static void -gsd_smartcard_manager_stop_watching_for_events (GsdSmartcardManager *manager) -{ - GList *node; - - node = manager->priv->workers; - while (node != NULL) { - GsdSmartcardManagerWorker *worker; - GList *next_node; - - worker = (GsdSmartcardManagerWorker *) node->data; - next_node = node->next; - - stop_worker (worker); - - node = next_node; - } -} - -static gboolean -load_nss (GError **error) -{ - 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"); - g_set_error (error, - GSD_SMARTCARD_MANAGER_ERROR, - GSD_SMARTCARD_MANAGER_ERROR_WITH_NSS, - _("NSS security system could not be initialized")); - goto out; - } - - error_message = g_slice_alloc0 (error_message_size); - PR_GetErrorText (error_message); - - g_set_error (error, - GSD_SMARTCARD_MANAGER_ERROR, - GSD_SMARTCARD_MANAGER_ERROR_WITH_NSS, - "%s", error_message); - g_debug ("NSS security system could not be initialized - %s", - error_message); - - g_slice_free1 (error_message_size, error_message); - - goto out; - } - - g_debug ("NSS database sucessfully loaded"); - return TRUE; - -out: - g_debug ("NSS database couldn't be sucessfully loaded"); - return FALSE; -} - -static GList * -get_available_modules (GsdSmartcardManager *manager) -{ - SECMODModuleList *module_list, *tmp; - GList *modules; - - g_debug ("Getting list of suitable modules"); - - module_list = SECMOD_GetDefaultModuleList (); - modules = NULL; - for (tmp = module_list; tmp != NULL; tmp = tmp->next) { - if (!SECMOD_HasRemovableSlots (tmp->module) || - !tmp->module->loaded) - continue; - - g_debug ("Using module '%s'", tmp->module->commonName); - - modules = g_list_prepend (modules, - SECMOD_ReferenceModule (tmp->module)); - } - - return modules; -} - -static gboolean -load_driver (GsdSmartcardManager *manager, - char *module_path, - GError **error) -{ - GList *modules; - char *module_spec; - gboolean module_explicitly_specified; - - g_debug ("attempting to load driver..."); - - modules = NULL; - module_explicitly_specified = module_path != NULL; - if (module_explicitly_specified) { - SECMODModule *module; - - module_spec = g_strdup_printf ("library=\"%s\"", module_path); - g_debug ("loading smartcard driver using spec '%s'", - module_spec); - - module = SECMOD_LoadUserModule (module_spec, - NULL /* parent */, - FALSE /* recurse */); - g_free (module_spec); - module_spec = NULL; - - if (SECMOD_HasRemovableSlots (module) && - module->loaded) { - modules = g_list_prepend (modules, module); - } else { - g_debug ("fallback module found but not %s", - SECMOD_HasRemovableSlots (module)? - "removable" : "loaded"); - SECMOD_DestroyModule (module); - } - - } else { - SECMODListLock *lock; - - lock = SECMOD_GetDefaultModuleListLock (); - - if (lock != NULL) { - SECMOD_GetReadLock (lock); - modules = get_available_modules (manager); - SECMOD_ReleaseReadLock (lock); - } - - /* fallback to compiled in driver path - */ - if (modules == NULL) { - SECMODModule *module; - module_path = GSD_SMARTCARD_MANAGER_DRIVER; - module_spec = g_strdup_printf ("library=\"%s\"", module_path); - g_debug ("loading smartcard driver using spec '%s'", - module_spec); - - module = SECMOD_LoadUserModule (module_spec, - NULL /* parent */, - FALSE /* recurse */); - g_free (module_spec); - module_spec = NULL; - - if (SECMOD_HasRemovableSlots (module) && - module->loaded) { - modules = g_list_prepend (modules, module); - } else { - g_debug ("fallback module found but not loaded"); - SECMOD_DestroyModule (module); - } - } - - } - - if (!module_explicitly_specified && modules == NULL) { - g_set_error (error, - GSD_SMARTCARD_MANAGER_ERROR, - GSD_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER, - _("no suitable smartcard driver could be found")); - } else if (modules == NULL) { - - gsize error_message_size; - char *error_message; - - error_message_size = PR_GetErrorTextLength (); - - if (error_message_size == 0) { - g_debug ("smartcard driver '%s' could not be loaded", - module_path); - g_set_error (error, - GSD_SMARTCARD_MANAGER_ERROR, - GSD_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER, - _("smartcard driver '%s' could not be " - "loaded"), module_path); - goto out; - } - - error_message = g_slice_alloc0 (error_message_size); - PR_GetErrorText (error_message); - - g_set_error (error, - GSD_SMARTCARD_MANAGER_ERROR, - GSD_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER, - "%s", error_message); - - g_debug ("smartcard driver '%s' could not be loaded - %s", - module_path, error_message); - g_slice_free1 (error_message_size, error_message); - } - - manager->priv->modules = modules; -out: - return manager->priv->modules != NULL; -} - -static void -gsd_smartcard_manager_get_all_cards (GsdSmartcardManager *manager) -{ - GList *node; - int i; - - node = manager->priv->workers; - while (node != NULL) { - - GsdSmartcardManagerWorker *worker; - - worker = (GsdSmartcardManagerWorker *) node->data; - - for (i = 0; i < worker->module->slotCount; i++) { - GsdSmartcard *card; - CK_SLOT_ID slot_id; - int slot_series; - char *card_name; - - slot_id = PK11_GetSlotID (worker->module->slots[i]); - slot_series = PK11_GetSlotSeries (worker->module->slots[i]); - - card = _gsd_smartcard_new (worker->module, - slot_id, slot_series); - - card_name = gsd_smartcard_get_name (card); - - g_hash_table_replace (manager->priv->smartcards, - card_name, card); - } - node = node->next; - } -} - -static GsdSmartcardManagerWorker * -start_worker (GsdSmartcardManager *manager, - SECMODModule *module, - GError **error) -{ - GIOChannel *io_channel; - GSource *source; - GsdSmartcardManagerWorker *worker; - - worker = gsd_smartcard_manager_create_worker (manager, module); - - if (worker == NULL) { - g_set_error (error, - GSD_SMARTCARD_MANAGER_ERROR, - GSD_SMARTCARD_MANAGER_ERROR_WATCHING_FOR_EVENTS, - _("could not watch for incoming card events - %s"), - g_strerror (errno)); - - goto out; - } - - io_channel = g_io_channel_unix_new (worker->manager_fd); - - source = g_io_create_watch (io_channel, G_IO_IN | G_IO_HUP); - g_io_channel_unref (io_channel); - io_channel = NULL; - - worker->event_source = source; - - g_source_set_callback (worker->event_source, - (GSourceFunc) (GIOFunc) - gsd_smartcard_manager_check_for_and_process_events, - worker, - (GDestroyNotify) - gsd_smartcard_manager_event_processing_stopped_handler); - g_source_attach (worker->event_source, NULL); - g_source_unref (worker->event_source); -out: - return worker; -} - -static void -start_workers (GsdSmartcardManager *manager) -{ - GList *node; - - node = manager->priv->modules; - while (node != NULL) { - SECMODModule *module; - GsdSmartcardManagerWorker *worker; - GError *error; - - module = (SECMODModule *) node->data; - - error = NULL; - worker = start_worker (manager, module, &error); - if (worker == NULL) { - g_warning ("%s", error->message); - g_error_free (error); - } else { - manager->priv->workers = g_list_prepend (manager->priv->workers, - worker); - } - node = node->next; - } -} - -gboolean -gsd_smartcard_manager_start (GsdSmartcardManager *manager, - GError **error) -{ - GError *nss_error; - - if (manager->priv->state == GSD_SMARTCARD_MANAGER_STATE_STARTED) { - g_debug ("smartcard manager already started"); - return TRUE; - } - - manager->priv->state = GSD_SMARTCARD_MANAGER_STATE_STARTING; - - nss_error = NULL; - if (!manager->priv->nss_is_loaded && !load_nss (&nss_error)) { - g_propagate_error (error, nss_error); - goto out; - } - manager->priv->nss_is_loaded = TRUE; - - if (manager->priv->modules == NULL) { - if (!load_driver (manager, manager->priv->module_path, &nss_error)) { - g_propagate_error (error, nss_error); - goto out; - } - } - - start_workers (manager); - - /* populate the hash with cards that are already inserted - */ - gsd_smartcard_manager_get_all_cards (manager); - - manager->priv->state = GSD_SMARTCARD_MANAGER_STATE_STARTED; - -out: - /* don't leave it in a half started state - */ - if (manager->priv->state != GSD_SMARTCARD_MANAGER_STATE_STARTED) { - g_debug ("smartcard manager could not be completely started"); - gsd_smartcard_manager_stop (manager); - } else { - g_debug ("smartcard manager started"); - } - - return manager->priv->state == GSD_SMARTCARD_MANAGER_STATE_STARTED; -} - -static gboolean -gsd_smartcard_manager_stop_now (GsdSmartcardManager *manager) -{ - if (manager->priv->state == GSD_SMARTCARD_MANAGER_STATE_STOPPED) { - return FALSE; - } - - gsd_smartcard_manager_stop_watching_for_events (manager); - - return FALSE; -} - -static void -gsd_smartcard_manager_queue_stop (GsdSmartcardManager *manager) -{ - - manager->priv->state = GSD_SMARTCARD_MANAGER_STATE_STOPPING; - - g_idle_add ((GSourceFunc) gsd_smartcard_manager_stop_now, manager); -} - -void -gsd_smartcard_manager_stop (GsdSmartcardManager *manager) -{ - if (manager->priv->state == GSD_SMARTCARD_MANAGER_STATE_STOPPED) { - return; - } - - if (manager->priv->is_unstoppable) { - gsd_smartcard_manager_queue_stop (manager); - return; - } - - gsd_smartcard_manager_stop_now (manager); -} - -static void -gsd_smartcard_manager_check_for_login_card (CK_SLOT_ID slot_id, - GsdSmartcard *card, - gboolean *is_inserted) -{ - g_assert (is_inserted != NULL); - - if (gsd_smartcard_is_login_card (card)) { - *is_inserted = TRUE; - } - -} - -gboolean -gsd_smartcard_manager_login_card_is_inserted (GsdSmartcardManager *manager) - -{ - gboolean is_inserted; - - is_inserted = FALSE; - g_hash_table_foreach (manager->priv->smartcards, - (GHFunc) - gsd_smartcard_manager_check_for_login_card, - &is_inserted); - return is_inserted; -} - -static GsdSmartcardManagerWorker * -gsd_smartcard_manager_worker_new (GsdSmartcardManager *manager, - int worker_fd, - int manager_fd, - SECMODModule *module) -{ - GsdSmartcardManagerWorker *worker; - - worker = g_slice_new0 (GsdSmartcardManagerWorker); - worker->manager = manager; - worker->fd = worker_fd; - worker->manager_fd = manager_fd; - worker->module = module; - - worker->smartcards = - g_hash_table_new_full ((GHashFunc) slot_id_hash, - (GEqualFunc) slot_id_equal, - (GDestroyNotify) g_free, - (GDestroyNotify) g_object_unref); - - return worker; -} - -static void -gsd_smartcard_manager_worker_free (GsdSmartcardManagerWorker *worker) -{ - if (worker->smartcards != NULL) { - g_hash_table_destroy (worker->smartcards); - worker->smartcards = NULL; - } - - g_slice_free (GsdSmartcardManagerWorker, worker); -} - -static gboolean -read_bytes (int fd, - gpointer bytes, - gsize num_bytes) -{ - size_t bytes_left; - size_t total_bytes_read; - ssize_t bytes_read; - - bytes_left = (size_t) num_bytes; - total_bytes_read = 0; - - do { - bytes_read = read (fd, - (char *) bytes + total_bytes_read, - bytes_left); - g_assert (bytes_read <= (ssize_t) bytes_left); - - if (bytes_read <= 0) { - if ((bytes_read < 0) && (errno == EINTR || errno == EAGAIN)) { - continue; - } - - bytes_left = 0; - } else { - bytes_left -= bytes_read; - total_bytes_read += bytes_read; - } - } while (bytes_left > 0); - - if (total_bytes_read < (size_t) num_bytes) { - return FALSE; - } - - return TRUE; -} - -static gboolean -write_bytes (int fd, - gconstpointer bytes, - gsize num_bytes) -{ - size_t bytes_left; - size_t total_bytes_written; - ssize_t bytes_written; - - bytes_left = (size_t) num_bytes; - total_bytes_written = 0; - - do { - bytes_written = write (fd, - (char *) bytes + total_bytes_written, - bytes_left); - g_assert (bytes_written <= (ssize_t) bytes_left); - - if (bytes_written <= 0) { - if ((bytes_written < 0) && (errno == EINTR || errno == EAGAIN)) { - continue; - } - - bytes_left = 0; - } else { - bytes_left -= bytes_written; - total_bytes_written += bytes_written; - } - } while (bytes_left > 0); - - if (total_bytes_written < (size_t) num_bytes) { - return FALSE; - } - - return TRUE; -} - -static GsdSmartcard * -read_smartcard (int fd, - SECMODModule *module) -{ - GsdSmartcard *card; - char *card_name; - gsize card_name_size; - - card_name_size = 0; - if (!read_bytes (fd, &card_name_size, sizeof (card_name_size))) { - return NULL; - } - - card_name = g_slice_alloc0 (card_name_size); - if (!read_bytes (fd, card_name, card_name_size)) { - g_slice_free1 (card_name_size, card_name); - return NULL; - } - card = _gsd_smartcard_new_from_name (module, card_name); - g_slice_free1 (card_name_size, card_name); - - return card; -} - -static gboolean -write_smartcard (int fd, - GsdSmartcard *card) -{ - gsize card_name_size; - char *card_name; - - card_name = gsd_smartcard_get_name (card); - card_name_size = strlen (card_name) + 1; - - if (!write_bytes (fd, &card_name_size, sizeof (card_name_size))) { - g_free (card_name); - return FALSE; - } - - if (!write_bytes (fd, card_name, card_name_size)) { - g_free (card_name); - return FALSE; - } - g_free (card_name); - - return TRUE; -} - -static gboolean -gsd_smartcard_manager_worker_emit_smartcard_removed (GsdSmartcardManagerWorker *worker, - GsdSmartcard *card, - GError **error) -{ - g_debug ("card '%s' removed!", gsd_smartcard_get_name (card)); - - if (!write_bytes (worker->fd, "R", 1)) { - goto error_out; - } - - if (!write_smartcard (worker->fd, card)) { - goto error_out; - } - - return TRUE; - -error_out: - g_set_error (error, GSD_SMARTCARD_MANAGER_ERROR, - GSD_SMARTCARD_MANAGER_ERROR_REPORTING_EVENTS, - "%s", g_strerror (errno)); - return FALSE; -} - -static gboolean -gsd_smartcard_manager_worker_emit_smartcard_inserted (GsdSmartcardManagerWorker *worker, - GsdSmartcard *card, - GError **error) -{ - g_debug ("card '%s' inserted!", gsd_smartcard_get_name (card)); - if (!write_bytes (worker->fd, "I", 1)) { - goto error_out; - } - - if (!write_smartcard (worker->fd, card)) { - goto error_out; - } - - return TRUE; - -error_out: - g_set_error (error, GSD_SMARTCARD_MANAGER_ERROR, - GSD_SMARTCARD_MANAGER_ERROR_REPORTING_EVENTS, - "%s", g_strerror (errno)); - return FALSE; -} - -static gboolean -gsd_smartcard_manager_worker_watch_for_and_process_event (GsdSmartcardManagerWorker *worker, - GError **error) -{ - PK11SlotInfo *slot; - CK_SLOT_ID slot_id, *key = NULL; - int slot_series, card_slot_series; - GsdSmartcard *card; - GError *processing_error; - gboolean ret; - - g_debug ("waiting for card event"); - ret = FALSE; - - slot = SECMOD_WaitForAnyTokenEvent (worker->module, 0, PR_SecondsToInterval (1)); - - processing_error = NULL; - - if (slot == NULL) { - int error_code; - - error_code = PORT_GetError (); - if ((error_code == 0) || (error_code == SEC_ERROR_NO_EVENT)) { - g_debug ("spurrious event occurred"); - return TRUE; - } - - /* FIXME: is there a function to convert from a PORT error - * code to a translated string? - */ - g_set_error (error, GSD_SMARTCARD_MANAGER_ERROR, - GSD_SMARTCARD_MANAGER_ERROR_WITH_NSS, - _("encountered unexpected error while " - "waiting for smartcard events")); - goto out; - } - - /* the slot id and series together uniquely identify a card. - * You can never have two cards with the same slot id at the - * same time, however (I think), so we can key off of it. - */ - slot_id = PK11_GetSlotID (slot); - slot_series = PK11_GetSlotSeries (slot); - - /* First check to see if there is a card that we're currently - * tracking in the slot. - */ - key = g_new (CK_SLOT_ID, 1); - *key = slot_id; - card = g_hash_table_lookup (worker->smartcards, key); - - if (card != NULL) { - card_slot_series = gsd_smartcard_get_slot_series (card); - } else { - card_slot_series = -1; - } - - if (PK11_IsPresent (slot)) { - /* Now, check to see if their is a new card in the slot. - * If there was a different card in the slot now than - * there was before, then we need to emit a removed signal - * for the old card (we don't want unpaired insertion events). - */ - if ((card != NULL) && - card_slot_series != slot_series) { - if (!gsd_smartcard_manager_worker_emit_smartcard_removed (worker, card, &processing_error)) { - g_propagate_error (error, processing_error); - goto out; - } - } - - card = _gsd_smartcard_new (worker->module, - slot_id, slot_series); - - g_hash_table_replace (worker->smartcards, - key, card); - key = NULL; - - if (!gsd_smartcard_manager_worker_emit_smartcard_inserted (worker, card, &processing_error)) { - g_propagate_error (error, processing_error); - goto out; - } - } else { - /* if we aren't tracking the card, just discard the event. - * We don't want unpaired remove events. Note on startup - * NSS will generate an "insertion" event if a card is - * already inserted in the slot. - */ - if ((card != NULL)) { - /* FIXME: i'm not sure about this code. Maybe we - * shouldn't do this at all, or maybe we should do it - * n times (where n = slot_series - card_slot_series + 1) - * - * Right now, i'm just doing it once. - */ - if ((slot_series - card_slot_series) > 1) { - - if (!gsd_smartcard_manager_worker_emit_smartcard_removed (worker, card, &processing_error)) { - g_propagate_error (error, processing_error); - goto out; - } - g_hash_table_remove (worker->smartcards, key); - - card = _gsd_smartcard_new (worker->module, - slot_id, slot_series); - g_hash_table_replace (worker->smartcards, - key, card); - key = NULL; - if (!gsd_smartcard_manager_worker_emit_smartcard_inserted (worker, card, &processing_error)) { - g_propagate_error (error, processing_error); - goto out; - } - } - - if (!gsd_smartcard_manager_worker_emit_smartcard_removed (worker, card, &processing_error)) { - g_propagate_error (error, processing_error); - goto out; - } - - g_hash_table_remove (worker->smartcards, key); - card = NULL; - } else { - g_debug ("got spurious remove event"); - } - } - - ret = TRUE; - -out: - g_free (key); - PK11_FreeSlot (slot); - - return ret; -} - -static void -gsd_smartcard_manager_worker_run (GsdSmartcardManagerWorker *worker) -{ - GError *error; - gboolean should_continue; - - do - { - error = NULL; - should_continue = gsd_smartcard_manager_worker_watch_for_and_process_event (worker, &error); - } - while (should_continue); - - if (error != NULL) { - g_debug ("could not process card event - %s", error->message); - g_error_free (error); - } - - gsd_smartcard_manager_worker_free (worker); -} - -static GsdSmartcardManagerWorker * -gsd_smartcard_manager_create_worker (GsdSmartcardManager *manager, - SECMODModule *module) -{ - GsdSmartcardManagerWorker *worker; - int write_fd, read_fd; - - write_fd = -1; - read_fd = -1; - if (!open_pipe (&write_fd, &read_fd)) { - return NULL; - } - - worker = gsd_smartcard_manager_worker_new (manager, - write_fd, - read_fd, - module); - - worker->thread = g_thread_create ((GThreadFunc) - gsd_smartcard_manager_worker_run, - worker, FALSE, NULL); - - if (worker->thread == NULL) { - gsd_smartcard_manager_worker_free (worker); - return NULL; - } - - return worker; -} - -#ifdef GSD_SMARTCARD_MANAGER_ENABLE_TEST -#include - -static GMainLoop *event_loop; -static gboolean should_exit_on_next_remove = FALSE; - -static gboolean -on_timeout (GsdSmartcardManager *manager) -{ - GError *error; - g_print ("Re-enabling manager.\n"); - - if (!gsd_smartcard_manager_start (manager, &error)) { - g_warning ("could not start smartcard manager - %s", - error->message); - g_error_free (error); - return TRUE; - } - g_print ("Please re-insert smartcard\n"); - - should_exit_on_next_remove = TRUE; - - return FALSE; -} - -static void -on_device_inserted (GsdSmartcardManager *manager, - GsdSmartcard *card) -{ - g_print ("smartcard inserted!\n"); - g_print ("Please remove it.\n"); -} - -static void -on_device_removed (GsdSmartcardManager *manager, - GsdSmartcard *card) -{ - g_print ("smartcard removed!\n"); - - if (should_exit_on_next_remove) { - g_main_loop_quit (event_loop); - } else { - g_print ("disabling manager for 2 seconds\n"); - gsd_smartcard_manager_stop (manager); - g_timeout_add_seconds (2, (GSourceFunc) on_timeout, manager); - } -} - -int -main (int argc, - char *argv[]) -{ - GsdSmartcardManager *manager; - GError *error; - - g_log_set_always_fatal (G_LOG_LEVEL_ERROR - | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING); - - g_message ("creating instance of 'smartcard manager' object..."); - manager = gsd_smartcard_manager_new (NULL); - g_message ("'smartcard manager' object created successfully"); - - g_signal_connect (manager, "smartcard-inserted", - G_CALLBACK (on_device_inserted), NULL); - - g_signal_connect (manager, "smartcard-removed", - G_CALLBACK (on_device_removed), NULL); - - g_message ("starting listener..."); - - error = NULL; - if (!gsd_smartcard_manager_start (manager, &error)) { - g_warning ("could not start smartcard manager - %s", - error->message); - g_error_free (error); - return 1; - } - - event_loop = g_main_loop_new (NULL, FALSE); - g_main_loop_run (event_loop); - g_main_loop_unref (event_loop); - event_loop = NULL; - - g_message ("destroying previously created 'smartcard manager' object..."); - g_object_unref (manager); - manager = NULL; - g_message ("'smartcard manager' object destroyed successfully"); - - return 0; -} -#endif diff --git a/plugins/smartcard/gsd-smartcard-manager.h b/plugins/smartcard/gsd-smartcard-manager.h deleted file mode 100644 index 949f194..0000000 --- a/plugins/smartcard/gsd-smartcard-manager.h +++ /dev/null @@ -1,88 +0,0 @@ -/* gsd-smartcard-manager.h - object for monitoring smartcard insertion and - * removal events - * - * Copyright (C) 2006, 2009 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. - * - * Written by: Ray Strode - */ -#ifndef GSD_SMARTCARD_MANAGER_H -#define GSD_SMARTCARD_MANAGER_H - -#define GSD_SMARTCARD_ENABLE_INTERNAL_API -#include "gsd-smartcard.h" - -#include -#include - -G_BEGIN_DECLS -#define GSD_TYPE_SMARTCARD_MANAGER (gsd_smartcard_manager_get_type ()) -#define GSD_SMARTCARD_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSD_TYPE_SMARTCARD_MANAGER, GsdSmartcardManager)) -#define GSD_SMARTCARD_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSD_TYPE_SMARTCARD_MANAGER, GsdSmartcardManagerClass)) -#define GSD_IS_SMARTCARD_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SC_TYPE_SMARTCARD_MANAGER)) -#define GSD_IS_SMARTCARD_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SC_TYPE_SMARTCARD_MANAGER)) -#define GSD_SMARTCARD_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GSD_TYPE_SMARTCARD_MANAGER, GsdSmartcardManagerClass)) -#define GSD_SMARTCARD_MANAGER_ERROR (gsd_smartcard_manager_error_quark ()) -typedef struct _GsdSmartcardManager GsdSmartcardManager; -typedef struct _GsdSmartcardManagerClass GsdSmartcardManagerClass; -typedef struct _GsdSmartcardManagerPrivate GsdSmartcardManagerPrivate; -typedef enum _GsdSmartcardManagerError GsdSmartcardManagerError; - -struct _GsdSmartcardManager { - GObject parent; - - /*< private > */ - GsdSmartcardManagerPrivate *priv; -}; - -struct _GsdSmartcardManagerClass { - GObjectClass parent_class; - - /* Signals */ - void (*smartcard_inserted) (GsdSmartcardManager *manager, - GsdSmartcard *token); - void (*smartcard_removed) (GsdSmartcardManager *manager, - GsdSmartcard *token); - void (*error) (GsdSmartcardManager *manager, - GError *error); -}; - -enum _GsdSmartcardManagerError { - 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 -}; - -GType gsd_smartcard_manager_get_type (void) G_GNUC_CONST; -GQuark gsd_smartcard_manager_error_quark (void) G_GNUC_CONST; - -GsdSmartcardManager *gsd_smartcard_manager_new_default (void); - -GsdSmartcardManager *gsd_smartcard_manager_new (const char *module); - -gboolean gsd_smartcard_manager_start (GsdSmartcardManager *manager, - GError **error); - -void gsd_smartcard_manager_stop (GsdSmartcardManager *manager); - -char *gsd_smartcard_manager_get_module_path (GsdSmartcardManager *manager); -gboolean gsd_smartcard_manager_login_card_is_inserted (GsdSmartcardManager *manager); - -G_END_DECLS -#endif /* GSD_SMARTCARD_MANAGER_H */ diff --git a/plugins/smartcard/gsd-smartcard-plugin.c b/plugins/smartcard/gsd-smartcard-plugin.c deleted file mode 100644 index df1a8c8..0000000 --- a/plugins/smartcard/gsd-smartcard-plugin.c +++ /dev/null @@ -1,337 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- - * - * 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 -#include - -#include -#include -#include - -#include "gnome-settings-plugin.h" -#include "gnome-settings-session.h" -#include "gsd-smartcard-plugin.h" -#include "gsd-smartcard-manager.h" - -struct GsdSmartcardPluginPrivate { - GsdSmartcardManager *manager; - GDBusConnection *bus_connection; - - guint32 is_active : 1; -}; - -typedef enum -{ - GSD_SMARTCARD_REMOVE_ACTION_NONE, - GSD_SMARTCARD_REMOVE_ACTION_LOCK_SCREEN, - GSD_SMARTCARD_REMOVE_ACTION_FORCE_LOGOUT, -} GsdSmartcardRemoveAction; - -#define SCREENSAVER_DBUS_NAME "org.gnome.ScreenSaver" -#define SCREENSAVER_DBUS_PATH "/" -#define SCREENSAVER_DBUS_INTERFACE "org.gnome.ScreenSaver" - -#define SM_LOGOUT_MODE_FORCE 2 - -#define KEY_REMOVE_ACTION "removal-action" - -#define GSD_SMARTCARD_PLUGIN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), GSD_TYPE_SMARTCARD_PLUGIN, GsdSmartcardPluginPrivate)) - -GNOME_SETTINGS_PLUGIN_REGISTER (GsdSmartcardPlugin, gsd_smartcard_plugin); - -static void -simulate_user_activity (GsdSmartcardPlugin *plugin) -{ - GDBusProxy *screensaver_proxy; - - g_debug ("GsdSmartcardPlugin telling screensaver about smart card insertion"); - screensaver_proxy = g_dbus_proxy_new_sync (plugin->priv->bus_connection, - 0, NULL, - SCREENSAVER_DBUS_NAME, - SCREENSAVER_DBUS_PATH, - SCREENSAVER_DBUS_INTERFACE, - NULL, NULL); - - g_dbus_proxy_call (screensaver_proxy, - "SimulateUserActivity", - NULL, G_DBUS_CALL_FLAGS_NONE, - -1, NULL, NULL, NULL); - - g_object_unref (screensaver_proxy); -} - -static void -lock_screen (GsdSmartcardPlugin *plugin) -{ - GDBusProxy *screensaver_proxy; - - g_debug ("GsdSmartcardPlugin telling screensaver to lock screen"); - screensaver_proxy = g_dbus_proxy_new_sync (plugin->priv->bus_connection, - 0, NULL, - SCREENSAVER_DBUS_NAME, - SCREENSAVER_DBUS_PATH, - SCREENSAVER_DBUS_INTERFACE, - NULL, NULL); - - g_dbus_proxy_call (screensaver_proxy, - "Lock", - NULL, G_DBUS_CALL_FLAGS_NONE, - -1, NULL, NULL, NULL); - - g_object_unref (screensaver_proxy); -} - -static void -force_logout (GsdSmartcardPlugin *plugin) -{ - GDBusProxy *sm_proxy; - GError *error; - GVariant *res; - - g_debug ("GsdSmartcardPlugin telling session manager to force logout"); - sm_proxy = gnome_settings_session_get_session_proxy (); - - error = NULL; - res = g_dbus_proxy_call_sync (sm_proxy, - "Logout", - g_variant_new ("(i)", SM_LOGOUT_MODE_FORCE), - G_DBUS_CALL_FLAGS_NONE, - -1, NULL, &error); - - if (! res) { - g_warning ("GsdSmartcardPlugin Unable to force logout: %s", error->message); - g_error_free (error); - } else - g_variant_unref (res); - - g_object_unref (sm_proxy); -} - -static void -gsd_smartcard_plugin_init (GsdSmartcardPlugin *plugin) -{ - plugin->priv = GSD_SMARTCARD_PLUGIN_GET_PRIVATE (plugin); - - g_debug ("GsdSmartcardPlugin initializing"); - - plugin->priv->manager = gsd_smartcard_manager_new (NULL); -} - -static void -gsd_smartcard_plugin_finalize (GObject *object) -{ - GsdSmartcardPlugin *plugin; - - g_return_if_fail (object != NULL); - g_return_if_fail (GSD_IS_SMARTCARD_PLUGIN (object)); - - g_debug ("GsdSmartcardPlugin finalizing"); - - plugin = GSD_SMARTCARD_PLUGIN (object); - - g_return_if_fail (plugin->priv != NULL); - - if (plugin->priv->manager != NULL) { - g_object_unref (plugin->priv->manager); - } - - G_OBJECT_CLASS (gsd_smartcard_plugin_parent_class)->finalize (object); -} - -static void -smartcard_inserted_cb (GsdSmartcardManager *card_monitor, - GsdSmartcard *card, - GsdSmartcardPlugin *plugin) -{ - char *name; - - name = gsd_smartcard_get_name (card); - g_debug ("GsdSmartcardPlugin smart card '%s' inserted", name); - g_free (name); - - simulate_user_activity (plugin); -} - -static gboolean -user_logged_in_with_smartcard (void) -{ - return g_getenv ("PKCS11_LOGIN_TOKEN_NAME") != NULL; -} - -static GsdSmartcardRemoveAction -get_configured_remove_action (GsdSmartcardPlugin *plugin) -{ - GSettings *settings; - char *remove_action_string; - GsdSmartcardRemoveAction remove_action; - - settings = g_settings_new ("org.gnome.settings-daemon.peripherals.smartcard"); - remove_action_string = g_settings_get_string (settings, KEY_REMOVE_ACTION); - - if (remove_action_string == NULL) { - g_warning ("GsdSmartcardPlugin unable to get smartcard remove action"); - remove_action = GSD_SMARTCARD_REMOVE_ACTION_NONE; - } else if (strcmp (remove_action_string, "none") == 0) { - remove_action = GSD_SMARTCARD_REMOVE_ACTION_NONE; - } else if (strcmp (remove_action_string, "lock_screen") == 0) { - remove_action = GSD_SMARTCARD_REMOVE_ACTION_LOCK_SCREEN; - } else if (strcmp (remove_action_string, "force_logout") == 0) { - remove_action = GSD_SMARTCARD_REMOVE_ACTION_FORCE_LOGOUT; - } else { - g_warning ("GsdSmartcardPlugin unknown smartcard remove action"); - remove_action = GSD_SMARTCARD_REMOVE_ACTION_NONE; - } - - g_object_unref (settings); - - return remove_action; -} - -static void -process_smartcard_removal (GsdSmartcardPlugin *plugin) -{ - GsdSmartcardRemoveAction remove_action; - - g_debug ("GsdSmartcardPlugin processing smartcard removal"); - remove_action = get_configured_remove_action (plugin); - - switch (remove_action) - { - case GSD_SMARTCARD_REMOVE_ACTION_NONE: - return; - case GSD_SMARTCARD_REMOVE_ACTION_LOCK_SCREEN: - lock_screen (plugin); - break; - case GSD_SMARTCARD_REMOVE_ACTION_FORCE_LOGOUT: - force_logout (plugin); - break; - } -} - -static void -smartcard_removed_cb (GsdSmartcardManager *card_monitor, - GsdSmartcard *card, - GsdSmartcardPlugin *plugin) -{ - - char *name; - - name = gsd_smartcard_get_name (card); - g_debug ("GsdSmartcardPlugin smart card '%s' removed", name); - g_free (name); - - if (!gsd_smartcard_is_login_card (card)) { - g_debug ("GsdSmartcardPlugin removed smart card was not used to login"); - return; - } - - process_smartcard_removal (plugin); -} - -static void -impl_activate (GnomeSettingsPlugin *plugin) -{ - GError *error; - GsdSmartcardPlugin *smartcard_plugin = GSD_SMARTCARD_PLUGIN (plugin); - - if (smartcard_plugin->priv->is_active) { - g_debug ("GsdSmartcardPlugin Not activating smartcard plugin, because it's " - "already active"); - return; - } - - if (!user_logged_in_with_smartcard ()) { - g_debug ("GsdSmartcardPlugin Not activating smartcard plugin, because user didn't use " - " smartcard to log in"); - smartcard_plugin->priv->is_active = FALSE; - return; - } - - g_debug ("GsdSmartcardPlugin Activating smartcard plugin"); - - error = NULL; - smartcard_plugin->priv->bus_connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); - - if (smartcard_plugin->priv->bus_connection == NULL) { - g_warning ("GsdSmartcardPlugin Unable to connect to session bus: %s", error->message); - return; - } - - if (!gsd_smartcard_manager_start (smartcard_plugin->priv->manager, &error)) { - g_warning ("GsdSmartcardPlugin Unable to start smartcard manager: %s", error->message); - g_error_free (error); - } - - g_signal_connect (smartcard_plugin->priv->manager, - "smartcard-removed", - G_CALLBACK (smartcard_removed_cb), smartcard_plugin); - - g_signal_connect (smartcard_plugin->priv->manager, - "smartcard-inserted", - G_CALLBACK (smartcard_inserted_cb), smartcard_plugin); - - if (!gsd_smartcard_manager_login_card_is_inserted (smartcard_plugin->priv->manager)) { - g_debug ("GsdSmartcardPlugin processing smartcard removal immediately user logged in with smartcard " - "and it's not inserted"); - process_smartcard_removal (smartcard_plugin); - } - - smartcard_plugin->priv->is_active = TRUE; -} - -static void -impl_deactivate (GnomeSettingsPlugin *plugin) -{ - GsdSmartcardPlugin *smartcard_plugin = GSD_SMARTCARD_PLUGIN (plugin); - - if (!smartcard_plugin->priv->is_active) { - g_debug ("GsdSmartcardPlugin Not deactivating smartcard plugin, " - "because it's already inactive"); - return; - } - - g_debug ("GsdSmartcardPlugin Deactivating smartcard plugin"); - - gsd_smartcard_manager_stop (smartcard_plugin->priv->manager); - - g_signal_handlers_disconnect_by_func (smartcard_plugin->priv->manager, - smartcard_removed_cb, smartcard_plugin); - - g_signal_handlers_disconnect_by_func (smartcard_plugin->priv->manager, - smartcard_inserted_cb, smartcard_plugin); - smartcard_plugin->priv->bus_connection = NULL; - smartcard_plugin->priv->is_active = FALSE; -} - -static void -gsd_smartcard_plugin_class_init (GsdSmartcardPluginClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GnomeSettingsPluginClass *plugin_class = GNOME_SETTINGS_PLUGIN_CLASS (klass); - - object_class->finalize = gsd_smartcard_plugin_finalize; - - plugin_class->activate = impl_activate; - plugin_class->deactivate = impl_deactivate; - - g_type_class_add_private (klass, sizeof (GsdSmartcardPluginPrivate)); -} diff --git a/plugins/smartcard/gsd-smartcard-plugin.h b/plugins/smartcard/gsd-smartcard-plugin.h deleted file mode 100644 index f1458d1..0000000 --- a/plugins/smartcard/gsd-smartcard-plugin.h +++ /dev/null @@ -1,59 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- - * - * 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. - * - */ - -#ifndef __GSD_SMARTCARD_PLUGIN_H__ -#define __GSD_SMARTCARD_PLUGIN_H__ - -#include -#include -#include - -#include "gnome-settings-plugin.h" - -G_BEGIN_DECLS - -#define GSD_TYPE_SMARTCARD_PLUGIN (gsd_smartcard_plugin_get_type ()) -#define GSD_SMARTCARD_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSD_TYPE_SMARTCARD_PLUGIN, GsdSmartcardPlugin)) -#define GSD_SMARTCARD_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GSD_TYPE_SMARTCARD_PLUGIN, GsdSmartcardPluginClass)) -#define GSD_IS_SMARTCARD_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSD_TYPE_SMARTCARD_PLUGIN)) -#define GSD_IS_SMARTCARD_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSD_TYPE_SMARTCARD_PLUGIN)) -#define GSD_SMARTCARD_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSD_TYPE_SMARTCARD_PLUGIN, GsdSmartcardPluginClass)) - -typedef struct GsdSmartcardPluginPrivate GsdSmartcardPluginPrivate; - -typedef struct -{ - GnomeSettingsPlugin parent; - GsdSmartcardPluginPrivate *priv; -} GsdSmartcardPlugin; - -typedef struct -{ - GnomeSettingsPluginClass parent_class; -} GsdSmartcardPluginClass; - -GType gsd_smartcard_plugin_get_type (void) G_GNUC_CONST; - -/* All the plugins must implement this function */ -G_MODULE_EXPORT GType register_gnome_settings_plugin (GTypeModule *module); - -G_END_DECLS - -#endif /* __GSD_SMARTCARD_PLUGIN_H__ */ diff --git a/plugins/smartcard/gsd-smartcard.c b/plugins/smartcard/gsd-smartcard.c deleted file mode 100644 index a926df1..0000000 --- a/plugins/smartcard/gsd-smartcard.c +++ /dev/null @@ -1,556 +0,0 @@ -/* gsd-smartcard.c - smartcard object - * - * Copyright (C) 2006 Ray Strode - * - * 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" - -#define GSD_SMARTCARD_ENABLE_INTERNAL_API -#include "gsd-smartcard.h" - -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - -struct _GsdSmartcardPrivate { - SECMODModule *module; - GsdSmartcardState state; - - CK_SLOT_ID slot_id; - int slot_series; - - PK11SlotInfo *slot; - char *name; - - CERTCertificate *signing_certificate; - CERTCertificate *encryption_certificate; -}; - -static void gsd_smartcard_finalize (GObject *object); -static void gsd_smartcard_class_install_signals (GsdSmartcardClass *card_class); -static void gsd_smartcard_class_install_properties (GsdSmartcardClass *card_class); -static void gsd_smartcard_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void gsd_smartcard_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); -static void gsd_smartcard_set_name (GsdSmartcard *card, const char *name); -static void gsd_smartcard_set_slot_id (GsdSmartcard *card, - int slot_id); -static void gsd_smartcard_set_slot_series (GsdSmartcard *card, - int slot_series); -static void gsd_smartcard_set_module (GsdSmartcard *card, - SECMODModule *module); - -static PK11SlotInfo *gsd_smartcard_find_slot_from_id (GsdSmartcard *card, - int slot_id); - -static PK11SlotInfo *gsd_smartcard_find_slot_from_card_name (GsdSmartcard *card, - const char *card_name); - -#ifndef GSD_SMARTCARD_DEFAULT_SLOT_ID -#define GSD_SMARTCARD_DEFAULT_SLOT_ID ((gulong) -1) -#endif - -#ifndef GSD_SMARTCARD_DEFAULT_SLOT_SERIES -#define GSD_SMARTCARD_DEFAULT_SLOT_SERIES -1 -#endif - -enum { - PROP_0 = 0, - PROP_NAME, - PROP_SLOT_ID, - PROP_SLOT_SERIES, - PROP_MODULE, - NUMBER_OF_PROPERTIES -}; - -enum { - INSERTED, - REMOVED, - NUMBER_OF_SIGNALS -}; - -static guint gsd_smartcard_signals[NUMBER_OF_SIGNALS]; - -G_DEFINE_TYPE (GsdSmartcard, gsd_smartcard, G_TYPE_OBJECT); - -static void -gsd_smartcard_class_init (GsdSmartcardClass *card_class) -{ - GObjectClass *gobject_class; - - gobject_class = G_OBJECT_CLASS (card_class); - - gobject_class->finalize = gsd_smartcard_finalize; - - gsd_smartcard_class_install_signals (card_class); - gsd_smartcard_class_install_properties (card_class); - - g_type_class_add_private (card_class, - sizeof (GsdSmartcardPrivate)); -} - -static void -gsd_smartcard_class_install_signals (GsdSmartcardClass *card_class) -{ - GObjectClass *object_class; - - object_class = G_OBJECT_CLASS (card_class); - - gsd_smartcard_signals[INSERTED] = - g_signal_new ("inserted", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GsdSmartcardClass, - inserted), - NULL, NULL, g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gsd_smartcard_signals[REMOVED] = - g_signal_new ("removed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GsdSmartcardClass, - removed), - NULL, NULL, g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); -} - -static void -gsd_smartcard_class_install_properties (GsdSmartcardClass *card_class) -{ - GObjectClass *object_class; - GParamSpec *param_spec; - - object_class = G_OBJECT_CLASS (card_class); - object_class->set_property = gsd_smartcard_set_property; - object_class->get_property = gsd_smartcard_get_property; - - param_spec = g_param_spec_ulong ("slot-id", "Slot ID", - "The slot the card is in", - 1, G_MAXULONG, - GSD_SMARTCARD_DEFAULT_SLOT_ID, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); - g_object_class_install_property (object_class, PROP_SLOT_ID, param_spec); - - param_spec = g_param_spec_int ("slot-series", "Slot Series", - "per-slot card identifier", - -1, G_MAXINT, - GSD_SMARTCARD_DEFAULT_SLOT_SERIES, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); - g_object_class_install_property (object_class, PROP_SLOT_SERIES, param_spec); - - param_spec = g_param_spec_string ("name", "name", - "name", NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); - g_object_class_install_property (object_class, PROP_NAME, param_spec); - - param_spec = g_param_spec_pointer ("module", "Module", - "smartcard driver", - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); - g_object_class_install_property (object_class, PROP_MODULE, param_spec); -} - -static void -gsd_smartcard_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GsdSmartcard *card = GSD_SMARTCARD (object); - - switch (prop_id) { - case PROP_NAME: - gsd_smartcard_set_name (card, g_value_get_string (value)); - break; - - case PROP_SLOT_ID: - gsd_smartcard_set_slot_id (card, - g_value_get_ulong (value)); - break; - - case PROP_SLOT_SERIES: - gsd_smartcard_set_slot_series (card, - g_value_get_int (value)); - break; - - case PROP_MODULE: - gsd_smartcard_set_module (card, - (SECMODModule *) - g_value_get_pointer (value)); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -CK_SLOT_ID -gsd_smartcard_get_slot_id (GsdSmartcard *card) -{ - return card->priv->slot_id; -} - -GsdSmartcardState -gsd_smartcard_get_state (GsdSmartcard *card) -{ - return card->priv->state; -} - -char * -gsd_smartcard_get_name (GsdSmartcard *card) -{ - return g_strdup (card->priv->name); -} - -gboolean -gsd_smartcard_is_login_card (GsdSmartcard *card) -{ - const char *login_card_name; - login_card_name = g_getenv ("PKCS11_LOGIN_TOKEN_NAME"); - - if ((login_card_name == NULL) || (card->priv->name == NULL)) { - return FALSE; - } - - if (strcmp (card->priv->name, login_card_name) == 0) { - return TRUE; - } - - return FALSE; -} - -static void -gsd_smartcard_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GsdSmartcard *card = GSD_SMARTCARD (object); - - switch (prop_id) { - case PROP_NAME: - g_value_take_string (value, - gsd_smartcard_get_name (card)); - break; - - case PROP_SLOT_ID: - g_value_set_ulong (value, - (gulong) gsd_smartcard_get_slot_id (card)); - break; - - case PROP_SLOT_SERIES: - g_value_set_int (value, - gsd_smartcard_get_slot_series (card)); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void -gsd_smartcard_set_name (GsdSmartcard *card, - const char *name) -{ - if (name == NULL) { - return; - } - - if ((card->priv->name == NULL) || - (strcmp (card->priv->name, name) != 0)) { - g_free (card->priv->name); - card->priv->name = g_strdup (name); - - if (card->priv->slot == NULL) { - card->priv->slot = gsd_smartcard_find_slot_from_card_name (card, - card->priv->name); - - if (card->priv->slot != NULL) { - int slot_id, slot_series; - - slot_id = PK11_GetSlotID (card->priv->slot); - if (slot_id != card->priv->slot_id) { - gsd_smartcard_set_slot_id (card, slot_id); - } - - slot_series = PK11_GetSlotSeries (card->priv->slot); - if (slot_series != card->priv->slot_series) { - gsd_smartcard_set_slot_series (card, slot_series); - } - - _gsd_smartcard_set_state (card, GSD_SMARTCARD_STATE_INSERTED); - } else { - _gsd_smartcard_set_state (card, GSD_SMARTCARD_STATE_REMOVED); - } - } - - g_object_notify (G_OBJECT (card), "name"); - } -} - -static void -gsd_smartcard_set_slot_id (GsdSmartcard *card, - int slot_id) -{ - if (card->priv->slot_id != slot_id) { - card->priv->slot_id = slot_id; - - if (card->priv->slot == NULL) { - card->priv->slot = gsd_smartcard_find_slot_from_id (card, - card->priv->slot_id); - - if (card->priv->slot != NULL) { - const char *card_name; - - card_name = PK11_GetTokenName (card->priv->slot); - if ((card->priv->name == NULL) || - ((card_name != NULL) && - (strcmp (card_name, card->priv->name) != 0))) { - gsd_smartcard_set_name (card, card_name); - } - - _gsd_smartcard_set_state (card, GSD_SMARTCARD_STATE_INSERTED); - } else { - _gsd_smartcard_set_state (card, GSD_SMARTCARD_STATE_REMOVED); - } - } - - g_object_notify (G_OBJECT (card), "slot-id"); - } -} - -static void -gsd_smartcard_set_slot_series (GsdSmartcard *card, - int slot_series) -{ - if (card->priv->slot_series != slot_series) { - card->priv->slot_series = slot_series; - g_object_notify (G_OBJECT (card), "slot-series"); - } -} - -static void -gsd_smartcard_set_module (GsdSmartcard *card, - SECMODModule *module) -{ - gboolean should_notify; - - if (card->priv->module != module) { - should_notify = TRUE; - } else { - should_notify = FALSE; - } - - if (card->priv->module != NULL) { - SECMOD_DestroyModule (card->priv->module); - card->priv->module = NULL; - } - - if (module != NULL) { - card->priv->module = SECMOD_ReferenceModule (module); - } - - if (should_notify) { - g_object_notify (G_OBJECT (card), "module"); - } -} - -int -gsd_smartcard_get_slot_series (GsdSmartcard *card) -{ - return card->priv->slot_series; -} - -static void -gsd_smartcard_init (GsdSmartcard *card) -{ - - g_debug ("initializing smartcard "); - - card->priv = G_TYPE_INSTANCE_GET_PRIVATE (card, - GSD_TYPE_SMARTCARD, - GsdSmartcardPrivate); -} - -static void gsd_smartcard_finalize (GObject *object) -{ - GsdSmartcard *card; - GObjectClass *gobject_class; - - card = GSD_SMARTCARD (object); - - g_free (card->priv->name); - - gsd_smartcard_set_module (card, NULL); - - gobject_class = G_OBJECT_CLASS (gsd_smartcard_parent_class); - - gobject_class->finalize (object); -} - -GQuark gsd_smartcard_error_quark (void) -{ - static GQuark error_quark = 0; - - if (error_quark == 0) { - error_quark = g_quark_from_static_string ("gsd-smartcard-error-quark"); - } - - return error_quark; -} - -GsdSmartcard * -_gsd_smartcard_new (SECMODModule *module, - CK_SLOT_ID slot_id, - int slot_series) -{ - GsdSmartcard *card; - - g_return_val_if_fail (module != NULL, NULL); - g_return_val_if_fail (slot_id >= 1, NULL); - g_return_val_if_fail (slot_series > 0, NULL); - g_return_val_if_fail (sizeof (gulong) == sizeof (slot_id), NULL); - - card = GSD_SMARTCARD (g_object_new (GSD_TYPE_SMARTCARD, - "module", module, - "slot-id", (gulong) slot_id, - "slot-series", slot_series, - NULL)); - return card; -} - -GsdSmartcard * -_gsd_smartcard_new_from_name (SECMODModule *module, - const char *name) -{ - GsdSmartcard *card; - - g_return_val_if_fail (module != NULL, NULL); - g_return_val_if_fail (name != NULL, NULL); - - card = GSD_SMARTCARD (g_object_new (GSD_TYPE_SMARTCARD, - "module", module, - "name", name, - NULL)); - return card; -} - -void -_gsd_smartcard_set_state (GsdSmartcard *card, - GsdSmartcardState state) -{ - /* gsd_smartcard_fetch_certificates (card); */ - if (card->priv->state != state) { - card->priv->state = state; - - if (state == GSD_SMARTCARD_STATE_INSERTED) { - g_signal_emit (card, gsd_smartcard_signals[INSERTED], 0); - } else if (state == GSD_SMARTCARD_STATE_REMOVED) { - g_signal_emit (card, gsd_smartcard_signals[REMOVED], 0); - } else { - g_assert_not_reached (); - } - } -} - -/* So we could conceivably make the closure data a pointer to the card - * or something similiar and then emit signals when we want passwords, - * but it's probably easier to just get the password up front and use - * it. So we just take the passed in g_malloc'd (well probably, who knows) - * and strdup it using NSPR's memory allocation routines. - */ -static char * -gsd_smartcard_password_handler (PK11SlotInfo *slot, - PRBool is_retrying, - const char *password) -{ - if (is_retrying) { - return NULL; - } - - return password != NULL? PL_strdup (password): NULL; -} - -gboolean -gsd_smartcard_unlock (GsdSmartcard *card, - const char *password) -{ - SECStatus status; - - PK11_SetPasswordFunc ((PK11PasswordFunc) gsd_smartcard_password_handler); - - /* we pass PR_TRUE to load certificates - */ - status = PK11_Authenticate (card->priv->slot, PR_TRUE, (gpointer) password); - - if (status != SECSuccess) { - g_debug ("could not unlock card - %d", status); - return FALSE; - } - return TRUE; -} - -static PK11SlotInfo * -gsd_smartcard_find_slot_from_card_name (GsdSmartcard *card, - const char *card_name) -{ - int i; - - for (i = 0; i < card->priv->module->slotCount; i++) { - const char *slot_card_name; - - slot_card_name = PK11_GetTokenName (card->priv->module->slots[i]); - - if ((slot_card_name != NULL) && - (strcmp (slot_card_name, card_name) == 0)) { - return card->priv->module->slots[i]; - } - } - - return NULL; -} - -static PK11SlotInfo * -gsd_smartcard_find_slot_from_id (GsdSmartcard *card, - int slot_id) -{ - int i; - - for (i = 0; i < card->priv->module->slotCount; i++) { - if (PK11_GetSlotID (card->priv->module->slots[i]) == slot_id) { - return card->priv->module->slots[i]; - } - } - - return NULL; -} diff --git a/plugins/smartcard/gsd-smartcard.h b/plugins/smartcard/gsd-smartcard.h deleted file mode 100644 index c99b5fa..0000000 --- a/plugins/smartcard/gsd-smartcard.h +++ /dev/null @@ -1,94 +0,0 @@ -/* securitycard.h - api for reading and writing data to a security card - * - * Copyright (C) 2006 Ray Strode - * - * 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. - */ -#ifndef GSD_SMARTCARD_H -#define GSD_SMARTCARD_H - -#include -#include - -#include - -G_BEGIN_DECLS -#define GSD_TYPE_SMARTCARD (gsd_smartcard_get_type ()) -#define GSD_SMARTCARD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSD_TYPE_SMARTCARD, GsdSmartcard)) -#define GSD_SMARTCARD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSD_TYPE_SMARTCARD, GsdSmartcardClass)) -#define GSD_IS_SMARTCARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSD_TYPE_SMARTCARD)) -#define GSD_IS_SMARTCARD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSD_TYPE_SMARTCARD)) -#define GSD_SMARTCARD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GSD_TYPE_SMARTCARD, GsdSmartcardClass)) -#define GSD_SMARTCARD_ERROR (gsd_smartcard_error_quark ()) -typedef struct _GsdSmartcardClass GsdSmartcardClass; -typedef struct _GsdSmartcard GsdSmartcard; -typedef struct _GsdSmartcardPrivate GsdSmartcardPrivate; -typedef enum _GsdSmartcardError GsdSmartcardError; -typedef enum _GsdSmartcardState GsdSmartcardState; - -typedef struct _GsdSmartcardRequest GsdSmartcardRequest; - -struct _GsdSmartcard { - GObject parent; - - /*< private > */ - GsdSmartcardPrivate *priv; -}; - -struct _GsdSmartcardClass { - GObjectClass parent_class; - - void (* inserted) (GsdSmartcard *card); - void (* removed) (GsdSmartcard *card); -}; - -enum _GsdSmartcardError { - GSD_SMARTCARD_ERROR_GENERIC = 0, -}; - -enum _GsdSmartcardState { - GSD_SMARTCARD_STATE_INSERTED = 0, - GSD_SMARTCARD_STATE_REMOVED, -}; - -GType gsd_smartcard_get_type (void) G_GNUC_CONST; -GQuark gsd_smartcard_error_quark (void) G_GNUC_CONST; - -CK_SLOT_ID gsd_smartcard_get_slot_id (GsdSmartcard *card); -gint gsd_smartcard_get_slot_series (GsdSmartcard *card); -GsdSmartcardState gsd_smartcard_get_state (GsdSmartcard *card); - -char *gsd_smartcard_get_name (GsdSmartcard *card); -gboolean gsd_smartcard_is_login_card (GsdSmartcard *card); - -gboolean gsd_smartcard_unlock (GsdSmartcard *card, - const char *password); - -/* don't under any circumstances call these functions */ -#ifdef GSD_SMARTCARD_ENABLE_INTERNAL_API - -GsdSmartcard *_gsd_smartcard_new (SECMODModule *module, - CK_SLOT_ID slot_id, - gint slot_series); -GsdSmartcard *_gsd_smartcard_new_from_name (SECMODModule *module, - const char *name); - -void _gsd_smartcard_set_state (GsdSmartcard *card, - GsdSmartcardState state); -#endif - -G_END_DECLS -#endif /* GSD_SMARTCARD_H */ diff --git a/plugins/smartcard/test-smartcard.c b/plugins/smartcard/test-smartcard.c deleted file mode 100644 index b57d908..0000000 --- a/plugins/smartcard/test-smartcard.c +++ /dev/null @@ -1,7 +0,0 @@ -#define NEW gsd_smartcard_manager_new_default -#define START gsd_smartcard_manager_start -#define STOP gsd_smartcard_manager_stop -#define MANAGER GsdSmartcardManager -#include "gsd-smartcard-manager.h" - -#include "test-plugin.h" -- 1.8.3.1 From f2afbc595d58cd54a586a1145879051161adb10c Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Tue, 28 May 2013 09:22:39 -0400 Subject: [PATCH 2/11] 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 --- plugins/smartcard/Makefile.am | 105 +++ plugins/smartcard/gsd-smartcard-enum-types.c.in | 42 + plugins/smartcard/gsd-smartcard-enum-types.h.in | 24 + plugins/smartcard/gsd-smartcard-manager.c | 870 +++++++++++++++++++++ plugins/smartcard/gsd-smartcard-manager.h | 82 ++ plugins/smartcard/gsd-smartcard-plugin.c | 30 + plugins/smartcard/gsd-smartcard-service.c | 773 ++++++++++++++++++ plugins/smartcard/gsd-smartcard-service.h | 81 ++ plugins/smartcard/gsd-smartcard-utils.c | 191 +++++ plugins/smartcard/gsd-smartcard-utils.h | 38 + .../org.gnome.SettingsDaemon.Smartcard.xml | 91 +++ plugins/smartcard/test-smartcard.c | 7 + 13 files changed, 2340 insertions(+) create mode 100644 plugins/smartcard/Makefile.am create mode 100644 plugins/smartcard/gsd-smartcard-enum-types.c.in create mode 100644 plugins/smartcard/gsd-smartcard-enum-types.h.in create mode 100644 plugins/smartcard/gsd-smartcard-manager.c create mode 100644 plugins/smartcard/gsd-smartcard-manager.h create mode 100644 plugins/smartcard/gsd-smartcard-plugin.c create mode 100644 plugins/smartcard/gsd-smartcard-service.c create mode 100644 plugins/smartcard/gsd-smartcard-service.h create mode 100644 plugins/smartcard/gsd-smartcard-utils.c create mode 100644 plugins/smartcard/gsd-smartcard-utils.h create mode 100644 plugins/smartcard/org.gnome.SettingsDaemon.Smartcard.xml create mode 100644 plugins/smartcard/test-smartcard.c diff --git a/plugins/smartcard/Makefile.am b/plugins/smartcard/Makefile.am new file mode 100644 index 0000000..2d27d1c --- /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 0000000..f281cf4 --- /dev/null +++ b/plugins/smartcard/gsd-smartcard-enum-types.c.in @@ -0,0 +1,42 @@ +/*** BEGIN file-header ***/ + +#include + +/*** 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 0000000..79dcc3d --- /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 + +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 0000000..05f77f8 --- /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 + * 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 +#include + +#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 +#include +#include +#include +#include +#include + +#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 0000000..9d3a2ce --- /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 + * 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 + +#include +#include +#include +#include +#include +#include + +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 0000000..ea78f85 --- /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 + * 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 +#include + +#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 0000000..40350d0 --- /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 +#include +#include + +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 0000000..2e48001 --- /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 +#include +#include +#include "gsd-smartcard-manager.h" + +#include "org.gnome.SettingsDaemon.Smartcard.h" + +#include +#include +#include +#include +#include +#include + +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 0000000..a2511a5 --- /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 + +#include +#include + +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 0000000..c39b076 --- /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 +#include + +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 0000000..3daade9 --- /dev/null +++ b/plugins/smartcard/org.gnome.SettingsDaemon.Smartcard.xml @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/smartcard/test-smartcard.c b/plugins/smartcard/test-smartcard.c new file mode 100644 index 0000000..b5ee3d5 --- /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" -- 1.8.3.1 From 7ad29294bcc95806b36bee3639c51901f44f8fc8 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Sat, 27 Jul 2013 10:35:55 -0400 Subject: [PATCH 3/11] Revert "build: Disable smartcard plugin for now" This reverts commit e2998b46a9d5eaa9ec2812867efac1eff8b3937f. Now that smartcard plugin is freshly revamped we can revert the commit that disables it. https://bugzilla.gnome.org/show_bug.cgi?id=704890 --- configure.ac | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index d7a9ead..c8a35f0 100644 --- a/configure.ac +++ b/configure.ac @@ -278,64 +278,63 @@ AC_ARG_ENABLE(packagekit, yes) WANT_PACKAGEKIT=yes ;; no) WANT_PACKAGEKIT=no ;; *) AC_MSG_ERROR(bad value ${enableval} for --disable-packagekit) ;; esac], [WANT_PACKAGEKIT=yes]) dnl Default value if test x$WANT_PACKAGEKIT = xyes ; then PK_REQUIRED_VERSION=0.7.4 PKG_CHECK_MODULES(PACKAGEKIT, glib-2.0 packagekit-glib2 >= $PK_REQUIRED_VERSION upower-glib >= $UPOWER_REQUIRED_VERSION gudev-1.0 libnotify >= $LIBNOTIFY_REQUIRED_VERSION, [have_packagekit=true AC_DEFINE(HAVE_PACKAGEKIT, 1, [Define if PackageKit should be used])], [have_packagekit=false]) fi AM_CONDITIONAL(HAVE_PACKAGEKIT, test "x$have_packagekit" = "xtrue") AC_SUBST(PACKAGEKIT_CFLAGS) AC_SUBST(PACKAGEKIT_LIBS) dnl ============================================== dnl smartcard section dnl ============================================== have_smartcard_support=false AC_ARG_ENABLE(smartcard-support, AC_HELP_STRING([--disable-smartcard-support], [turn off smartcard support]), [case "${enableval}" in yes) WANT_SMARTCARD_SUPPORT=yes ;; no) WANT_SMARTCARD_SUPPORT=no ;; *) AC_MSG_ERROR(bad value ${enableval} for --disable-smartcard-support) ;; esac], - [WANT_SMARTCARD_SUPPORT=no]) + [WANT_SMARTCARD_SUPPORT=yes]) if test x$WANT_SMARTCARD_SUPPORT = xyes ; then - AC_MSG_ERROR(Smartcard support is broken in this version) NSS_REQUIRED_VERSION=3.11.2 PKG_CHECK_MODULES(NSS, nss >= $NSS_REQUIRED_VERSION, [have_smartcard_support=true AC_DEFINE(SMARTCARD_SUPPORT, 1, [Define if smartcard support should be enabled])], [have_smartcard_support=false]) fi AM_CONDITIONAL(SMARTCARD_SUPPORT, test "x$have_smartcard_support" = "xtrue") AC_SUBST(NSS_CFLAGS) AC_SUBST(NSS_LIBS) AC_ARG_WITH(nssdb, AC_HELP_STRING([--with-nssdb], [where system NSS database is])) NSS_DATABASE="" if test "x$have_smartcard_support" = "xtrue"; then if ! test -z "$with_nssdb" ; then NSS_DATABASE="$with_nssdb" else NSS_DATABASE="${sysconfdir}/pki/nssdb" fi else if ! test -z "$with_nssdb" ; then AC_MSG_WARN([nssdb specified when smartcard support is disabled]) fi fi AC_SUBST(NSS_DATABASE) -- 1.8.3.1 From 667d9edf568556d9e840245ceed1a3723e8d352c Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Sat, 27 Jul 2013 13:46:29 -0400 Subject: [PATCH 4/11] build: Fix smartcard plugin with srcdir != builddir --- plugins/smartcard/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/smartcard/Makefile.am b/plugins/smartcard/Makefile.am index 2d27d1c..3ba5abd 100644 --- a/plugins/smartcard/Makefile.am +++ b/plugins/smartcard/Makefile.am @@ -1,49 +1,49 @@ 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 + $(srcdir)/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) \ -- 1.8.3.1 From bbf3aa7fbc268fff449d4cf0c2f3ee7f9bf791c0 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Sun, 28 Jul 2013 23:54:59 -0400 Subject: [PATCH 5/11] smartcard: fix driver activation notification g-s-d fails to notice when it's finished loading all the smartcard drivers. This is because the code was waiting for the driver worker threads to finish instead of to start (and also a fault >= instead > 0 check for pending drivers) The commit fixes that. --- plugins/smartcard/gsd-smartcard-manager.c | 40 +++---------------------------- 1 file changed, 3 insertions(+), 37 deletions(-) diff --git a/plugins/smartcard/gsd-smartcard-manager.c b/plugins/smartcard/gsd-smartcard-manager.c index 05f77f8..14c2f71 100644 --- a/plugins/smartcard/gsd-smartcard-manager.c +++ b/plugins/smartcard/gsd-smartcard-manager.c @@ -294,121 +294,90 @@ watch_smartcards_from_driver_async (GsdSmartcardManager *self, 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); + g_task_return_boolean (task, TRUE); } 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); + g_debug ("Done watching smartcards from driver"); } 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 @@ -435,103 +404,100 @@ on_main_thread_to_register_driver (GTask *task) 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) + 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); } -- 1.8.3.1 From 94f03e52bd1863d16e1df9a4a5634235f7532dff Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Sun, 28 Jul 2013 22:19:18 -0400 Subject: [PATCH 6/11] smartcard: add screensaver proxy We're going to need to be able to lock the screen in some cases when a user removes their smartcard. This commit adds the goo needed to get access to the lock screen. --- plugins/smartcard/Makefile.am | 14 ++++++++- plugins/smartcard/org.gnome.ScreenSaver.xml | 45 +++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 plugins/smartcard/org.gnome.ScreenSaver.xml diff --git a/plugins/smartcard/Makefile.am b/plugins/smartcard/Makefile.am index 3ba5abd..62f85e7 100644 --- a/plugins/smartcard/Makefile.am +++ b/plugins/smartcard/Makefile.am @@ -1,92 +1,104 @@ 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 +screensaver_dbus_built_sources = org.gnome.ScreenSaver.c org.gnome.ScreenSaver.h enum_built_sources = gsd-smartcard-enum-types.h gsd-smartcard-enum-types.c -BUILT_SOURCES = $(dbus_built_sources) $(enum_built_sources) +BUILT_SOURCES = $(dbus_built_sources) $(screensaver_dbus_built_sources) $(enum_built_sourcs) 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 \ $(srcdir)/org.gnome.SettingsDaemon.Smartcard.xml +$(screensaver_dbus_built_sources) : Makefile.am org.gnome.ScreenSaver.xml + gdbus-codegen \ + --interface-prefix org.gnome.ScreenSaver. \ + --generate-c-code org.gnome.ScreenSaver \ + --c-namespace Gsd \ + --annotate "org.gnome.ScreenSaver" \ + "org.gtk.GDBus.C.Name" ScreenSaver \ + $(srcdir)/org.gnome.ScreenSaver.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) \ + $(screensaver_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) \ + $(screensaver_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@ diff --git a/plugins/smartcard/org.gnome.ScreenSaver.xml b/plugins/smartcard/org.gnome.ScreenSaver.xml new file mode 100644 index 0000000..7a6cf86 --- /dev/null +++ b/plugins/smartcard/org.gnome.ScreenSaver.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + -- 1.8.3.1 From 6ac958091b6f2742bcc504f29b716028fe0cb37b Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Sun, 28 Jul 2013 22:19:18 -0400 Subject: [PATCH 7/11] smartcard: add session manager proxy We're going to need to be able to log the user out in some cases when they remove their smartcard. This commit adds the makefile goo and the xml file stolen from gnome-session source tree to get access to the session manager to log out. --- plugins/smartcard/Makefile.am | 14 +- plugins/smartcard/org.gnome.SessionManager.xml | 451 +++++++++++++++++++++++++ 2 files changed, 464 insertions(+), 1 deletion(-) create mode 100644 plugins/smartcard/org.gnome.SessionManager.xml diff --git a/plugins/smartcard/Makefile.am b/plugins/smartcard/Makefile.am index 62f85e7..098bb47 100644 --- a/plugins/smartcard/Makefile.am +++ b/plugins/smartcard/Makefile.am @@ -1,104 +1,116 @@ 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 screensaver_dbus_built_sources = org.gnome.ScreenSaver.c org.gnome.ScreenSaver.h +session_manager_dbus_built_sources = org.gnome.SessionManager.c org.gnome.SessionManager.h enum_built_sources = gsd-smartcard-enum-types.h gsd-smartcard-enum-types.c -BUILT_SOURCES = $(dbus_built_sources) $(screensaver_dbus_built_sources) $(enum_built_sourcs) +BUILT_SOURCES = $(dbus_built_sources) $(screensaver_dbus_built_sources) $(session_manager_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 \ $(srcdir)/org.gnome.SettingsDaemon.Smartcard.xml $(screensaver_dbus_built_sources) : Makefile.am org.gnome.ScreenSaver.xml gdbus-codegen \ --interface-prefix org.gnome.ScreenSaver. \ --generate-c-code org.gnome.ScreenSaver \ --c-namespace Gsd \ --annotate "org.gnome.ScreenSaver" \ "org.gtk.GDBus.C.Name" ScreenSaver \ $(srcdir)/org.gnome.ScreenSaver.xml +$(session_manager_dbus_built_sources) : Makefile.am org.gnome.SessionManager.xml + gdbus-codegen \ + --interface-prefix org.gnome.SessionManager. \ + --generate-c-code org.gnome.SessionManager \ + --c-namespace Gsd \ + --annotate "org.gnome.SessionManager" \ + "org.gtk.GDBus.C.Name" SessionManager \ + $(srcdir)/org.gnome.SessionManager.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) \ $(screensaver_dbus_built_sources) \ + $(session_manager_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) \ $(screensaver_dbus_built_sources) \ + $(session_manager_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@ diff --git a/plugins/smartcard/org.gnome.SessionManager.xml b/plugins/smartcard/org.gnome.SessionManager.xml new file mode 100644 index 0000000..eb69180 --- /dev/null +++ b/plugins/smartcard/org.gnome.SessionManager.xml @@ -0,0 +1,451 @@ + + + + + + + + + + + The variable name + + + + + The value + + + + + Adds the variable name to the application launch environment with the specified value. May only be used during the Session Manager initialization phase. + + + + + + + + The locale category + + + + + The value + + + + + Reads the current state of the specific locale category. + + + + + + + + The error message + + + + + Whether the error should be treated as fatal + + + + + May be used by applications launched during the Session Manager initialization phase to indicate there was a problem. + + + + + + + + + + + The application identifier + + + + + Client startup identifier + + + + + The object path of the newly registered client + + + + + Register the caller as a Session Management client. + + + + + + + + + The object path of the client + + + + + Unregister the specified client from Session Management. + + + + + + + + + The application identifier + + + + + The toplevel X window identifier + + + + + The reason for the inhibit + + + + + Flags that specify what should be inhibited + + + + + The cookie + + + + + Proactively indicates that the calling application is performing an action that should not be interrupted and sets a reason to be displayed to the user when an interruption is about to take placea. + + + Applications should invoke this method when they begin an operation that + should not be interrupted, such as creating a CD or DVD. The types of actions + that may be blocked are specified by the flags parameter. When the application + completes the operation it should call Uninhibit() + or disconnect from the session bus. + + + Applications should not expect that they will always be able to block the + action. In most cases, users will be given the option to force the action + to take place. + + + Reasons should be short and to the point. + + + The flags parameter must include at least one of the following: + + + 1 + Inhibit logging out + + + 2 + Inhibit user switching + + + 4 + Inhibit suspending the session or computer + + + 8 + Inhibit the session being marked as idle + + + 16 + Inhibit auto-mounting removable media for the session + + + Values for flags may be bitwise or'ed together. + + + The returned cookie is used to uniquely identify this request. It should be used + as an argument to Uninhibit() in + order to remove the request. + + + + + + + + + + The cookie + + + + + Cancel a previous call to Inhibit() identified by the cookie. + + + + + + + + Flags that spefify what should be inhibited + + + + + Returns TRUE if any of the operations in the bitfield flags are inhibited + + + + + Determine if operation(s) specified by the flags + are currently inhibited. Flags are same as those accepted + by the + Inhibit() + method. + + + + + + + + an array of client IDs + + + + + This gets a list of all the Clients + that are currently known to the session manager. + Each Client ID is an D-Bus object path for the object that implements the + Client interface. + + org.gnome.SessionManager.Client + + + + + + + an array of inhibitor IDs + + + + + This gets a list of all the Inhibitors + that are currently known to the session manager. + Each Inhibitor ID is an D-Bus object path for the object that implements the + Inhibitor interface. + + org.gnome.SessionManager.Inhibitor + + + + + + + + The autostart condition string + + + + + True if condition is handled, false otherwise + + + + + Allows the caller to determine whether the session manager is + handling changes to the specified autostart condition. + + + + + + + + Request a shutdown dialog. + + + + + + + + Request a reboot dialog. + + + + + + + + True if shutdown is available to the user, false otherwise + + + + + Allows the caller to determine whether or not it's okay to show + a shutdown option in the UI + + + + + + + + The type of logout that is being requested + + + + + Request a logout dialog + + Allowed values for the mode parameter are: + + + 0 + Normal. + + + 1 + No confirmation inferface should be shown. + + + 2 + Forcefully logout. No confirmation will be shown and any inhibitors will be ignored. + + + Values for flags may be bitwise or'ed together. + + + + + + + + + True if the session has entered the Running phase, false otherwise + + + + + Allows the caller to determine whether the session manager + has entered the Running phase, in case the client missed the + SessionRunning signal. + + + + + + + + + + The object path for the added client + + + + + Emitted when a client has been added to the session manager. + + + + + + + + The object path for the removed client + + + + + Emitted when a client has been removed from the session manager. + + + + + + + + + The object path for the added inhibitor + + + + + Emitted when an inhibitor has been added to the session manager. + + + + + + + + The object path for the removed inhibitor + + + + + Emitted when an inhibitor has been removed from the session manager. + + + + + + + + + Indicates the session has entered the Running phase. + + + + + + + + Indicates the session is about to end. + + + + + + + + + + The name of the session that has been loaded. + + + + + + + + If true, the session is currently in the + foreground and available for user input. + + + + + + + + A bitmask of flags to indicate which actions + are inhibited. See the Inhibit() function's description + for a list of possible values. + + + + + + -- 1.8.3.1 From 69d86f2acb2a5cd632fc2c6b4e6beff431e06846 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Mon, 29 Jul 2013 00:02:04 -0400 Subject: [PATCH 8/11] smartcard: support old card removal actions The old smartcard plugin supported a feature where the screen would lock or the session would get logged out if a user yanked their login token. This commit adds that feature back. --- plugins/smartcard/gsd-smartcard-manager.c | 170 +++++++++++++++++++++++++++++- plugins/smartcard/gsd-smartcard-manager.h | 1 + plugins/smartcard/gsd-smartcard-service.c | 11 ++ 3 files changed, 181 insertions(+), 1 deletion(-) diff --git a/plugins/smartcard/gsd-smartcard-manager.c b/plugins/smartcard/gsd-smartcard-manager.c index 14c2f71..4ac31ae 100644 --- a/plugins/smartcard/gsd-smartcard-manager.c +++ b/plugins/smartcard/gsd-smartcard-manager.c @@ -4,86 +4,97 @@ * 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 #include #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 "org.gnome.ScreenSaver.h" +#include "org.gnome.SessionManager.h" + #include #include #include #include #include #include #define GSD_SMARTCARD_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_SMARTCARD_MANAGER, GsdSmartcardManagerPrivate)) +#define GSD_SESSION_MANAGER_LOGOUT_MODE_FORCE 2 + struct GsdSmartcardManagerPrivate { guint start_idle_id; GsdSmartcardService *service; GList *smartcards_watch_tasks; GCancellable *cancellable; + GsdSessionManager *session_manager; + GsdScreenSaver *screen_saver; + GSettings *settings; guint32 nss_is_loaded : 1; }; #define CONF_SCHEMA "org.gnome.settings-daemon.peripherals.smartcard" +#define KEY_REMOVE_ACTION "removal-action" 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); +static void lock_screen (GsdSmartcardManager *self); +static void log_out (GsdSmartcardManager *self); 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 @@ -194,61 +205,60 @@ watch_one_event_from_driver (GsdSmartcardManager *self, 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)) { @@ -529,68 +539,79 @@ activate_all_drivers_async (GsdSmartcardManager *self, 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; + PK11SlotInfo *login_token; driver_activated = activate_all_drivers_async_finish (self, result, &error); if (!driver_activated) { g_task_return_error (task, error); return; } + login_token = gsd_smartcard_manager_get_login_token (self); + + if (login_token || g_getenv ("PKCS11_LOGIN_TOKEN_NAME") != NULL) { + /* The card used to log in was removed before login completed. + * Do removal action immediately + */ + if (!login_token || !PK11_IsPresent (login_token)) + gsd_smartcard_manager_do_remove_action (self); + } + 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 @@ -676,60 +697,207 @@ gsd_smartcard_manager_idle_cb (GsdSmartcardManager *self) 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); + g_clear_object (&priv->session_manager); + g_clear_object (&priv->screen_saver); +} + +static void +on_got_screen_saver_to_lock_screen (GObject *object, + GAsyncResult *result, + GsdSmartcardManager *self) +{ + GsdSmartcardManagerPrivate *priv = self->priv; + GsdScreenSaver *screen_saver; + GError *error = NULL; + + screen_saver = gsd_screen_saver_proxy_new_for_bus_finish (result, &error); + + if (screen_saver == NULL) { + g_warning ("Couldn't find screen saver service to lock screen: %s", + error->message); + g_error_free (error); + return; + } + + if (priv->screen_saver != NULL) + g_object_unref (screen_saver); + + priv->screen_saver = screen_saver; + + lock_screen (self); +} + +static void +on_screen_locked (GsdScreenSaver *screen_saver, + GAsyncResult *result, + GsdSmartcardManager *self) +{ + gboolean is_locked; + GError *error = NULL; + + is_locked = gsd_screen_saver_call_lock_finish (screen_saver, result, &error); + + if (!is_locked) { + g_warning ("Couldn't lock screen: %s", error->message); + g_error_free (error); + return; + } +} + +static void +lock_screen (GsdSmartcardManager *self) +{ + GsdSmartcardManagerPrivate *priv = self->priv; + + if (priv->screen_saver == NULL) { + gsd_screen_saver_proxy_new_for_bus (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_NONE, + "org.gnome.ScreenSaver", + "/org/gnome/ScreenSaver", + priv->cancellable, + (GAsyncReadyCallback) on_got_screen_saver_to_lock_screen, + self); + return; + } + + gsd_screen_saver_call_lock (priv->screen_saver, + priv->cancellable, + (GAsyncReadyCallback) on_screen_locked, + self); +} + +static void +on_got_session_manager_to_log_out (GObject *object, + GAsyncResult *result, + GsdSmartcardManager *self) +{ + GsdSmartcardManagerPrivate *priv = self->priv; + GsdSessionManager *session_manager; + GError *error = NULL; + + session_manager = gsd_session_manager_proxy_new_for_bus_finish (result, &error); + + if (session_manager == NULL) { + g_warning ("Couldn't find session manager service to log out: %s", + error->message); + g_error_free (error); + return; + } + + if (priv->session_manager != NULL) + g_object_unref (session_manager); + + priv->session_manager = session_manager; + + log_out (self); +} + +static void +on_logged_out (GsdSessionManager *session_manager, + GAsyncResult *result, + GsdSmartcardManager *self) +{ + gboolean is_logged_out; + GError *error = NULL; + + is_logged_out = gsd_session_manager_call_logout_finish (session_manager, result, &error); + + if (!is_logged_out) { + g_warning ("Couldn't log out: %s", error->message); + g_error_free (error); + return; + } +} + +static void +log_out (GsdSmartcardManager *self) +{ + GsdSmartcardManagerPrivate *priv = self->priv; + + if (priv->session_manager == NULL) { + gsd_session_manager_proxy_new_for_bus (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_NONE, + "org.gnome.SessionManager", + "/org/gnome/SessionManager", + priv->cancellable, + (GAsyncReadyCallback) on_got_session_manager_to_log_out, + self); + return; + } + + gsd_session_manager_call_logout (priv->session_manager, + GSD_SESSION_MANAGER_LOGOUT_MODE_FORCE, + priv->cancellable, + (GAsyncReadyCallback) on_logged_out, + self); +} + +void +gsd_smartcard_manager_do_remove_action (GsdSmartcardManager *self) +{ + GsdSmartcardManagerPrivate *priv = self->priv; + char *remove_action; + + remove_action = g_settings_get_string (priv->settings, KEY_REMOVE_ACTION); + + if (strcmp (remove_action, "lock-screen") == 0) + lock_screen (self); + else if (strcmp (remove_action, "force-logout") == 0) + log_out (self); } 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; diff --git a/plugins/smartcard/gsd-smartcard-manager.h b/plugins/smartcard/gsd-smartcard-manager.h index 9d3a2ce..7876fc1 100644 --- a/plugins/smartcard/gsd-smartcard-manager.h +++ b/plugins/smartcard/gsd-smartcard-manager.h @@ -49,34 +49,35 @@ typedef struct 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); +void gsd_smartcard_manager_do_remove_action (GsdSmartcardManager *manager); G_END_DECLS #endif /* __GSD_SMARTCARD_MANAGER_H */ diff --git a/plugins/smartcard/gsd-smartcard-service.c b/plugins/smartcard/gsd-smartcard-service.c index 40350d0..cc20f4c 100644 --- a/plugins/smartcard/gsd-smartcard-service.c +++ b/plugins/smartcard/gsd-smartcard-service.c @@ -478,60 +478,71 @@ synchronize_token_now (GsdSmartcardService *self, { 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"); + if (!is_present && is_login_card) { + gboolean was_present; + + g_object_get (G_OBJECT (interface), + "is-inserted", &was_present, + NULL); + + if (was_present) + gsd_smartcard_manager_do_remove_action (priv->smartcard_manager); + } + 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); } -- 1.8.3.1 From 73526df53a92aa2829e7043f7dec0e51cf7b0dee Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Thu, 22 Aug 2013 17:52:35 -0400 Subject: [PATCH 9/11] smartcard: ignore softtoken For some reason that I haven't fully fleshed out, sometimes the soft token gets into the "will load list" and then havoc ensues. This commit fixes that by explicitly ignoring built-in modules. https://bugzilla.gnome.org/show_bug.cgi?id=706620 --- plugins/smartcard/gsd-smartcard-manager.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/smartcard/gsd-smartcard-manager.c b/plugins/smartcard/gsd-smartcard-manager.c index 4ac31ae..eb22cb2 100644 --- a/plugins/smartcard/gsd-smartcard-manager.c +++ b/plugins/smartcard/gsd-smartcard-manager.c @@ -513,60 +513,63 @@ on_driver_activated (GsdSmartcardManager *self, } 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; + if (node->module->dllName == NULL) + 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; PK11SlotInfo *login_token; driver_activated = activate_all_drivers_async_finish (self, result, &error); -- 1.8.3.1 From 3f3914ef025aecb85cd737746c5629b656d7d21c Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Mon, 10 Feb 2014 12:33:21 -0500 Subject: [PATCH 10/11] smartcard: detect explicit cancelation explicitly If the the smartcard function has been cancelled (because, say, g-s-d is shutting down), handle that case explicitly, so the right error message is propagated. https://bugzilla.gnome.org/show_bug.cgi?id=724122 --- plugins/smartcard/gsd-smartcard-manager.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/plugins/smartcard/gsd-smartcard-manager.c b/plugins/smartcard/gsd-smartcard-manager.c index eb22cb2..a6eb144 100644 --- a/plugins/smartcard/gsd-smartcard-manager.c +++ b/plugins/smartcard/gsd-smartcard-manager.c @@ -157,60 +157,65 @@ typedef struct } 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 (g_cancellable_is_cancelled (cancellable)) { + g_warning ("smartcard event function cancelled"); + return FALSE; + } + 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 @@ -240,60 +245,64 @@ watch_one_event_from_driver (GsdSmartcardManager *self, 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 (g_task_return_error_if_cancelled (task)) { + break; + } + 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, -- 1.8.3.1 From a36d72a776767b401a29dd8b10c17f365643d9e6 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Tue, 11 Feb 2014 10:11:51 -0500 Subject: [PATCH 11/11] smartcard: filter out spurious errors Some PKCS11 modules send spurious errors when the card is first powered on. This commit works around that problem by adding retries. This brings us back to status quo with the old smartcard plugin. https://bugzilla.gnome.org/show_bug.cgi?id=724122 --- plugins/smartcard/gsd-smartcard-manager.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/plugins/smartcard/gsd-smartcard-manager.c b/plugins/smartcard/gsd-smartcard-manager.c index a6eb144..3fc4823 100644 --- a/plugins/smartcard/gsd-smartcard-manager.c +++ b/plugins/smartcard/gsd-smartcard-manager.c @@ -127,110 +127,121 @@ load_nss (GsdSmartcardManager *self) 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; + int number_of_consecutive_errors; } 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 (g_cancellable_is_cancelled (cancellable)) { g_warning ("smartcard event function cancelled"); return FALSE; } if (card == NULL) { int error_code; error_code = PORT_GetError (); - g_warning ("smartcard event function failed."); + operation->number_of_consecutive_errors++; + if (operation->number_of_consecutive_errors > 10) { + g_warning ("Got %d consecutive smartcard errors, so giving up.", + operation->number_of_consecutive_errors); + + g_set_error (error, + GSD_SMARTCARD_MANAGER_ERROR, + GSD_SMARTCARD_MANAGER_ERROR_WITH_NSS, + "encountered unexpected error while " + "waiting for smartcard events (error %x)", + error_code); + return FALSE; + } - 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; + g_warning ("Got potentially spurious smartcard event error: %x.", error_code); + + g_usleep (0.5 * G_USEC_PER_SEC); + return TRUE; } + operation->number_of_consecutive_errors = 0; 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), -- 1.8.3.1