diff options
Diffstat (limited to 'plugins/smartcard/gsd-smartcard-manager.c')
-rw-r--r-- | plugins/smartcard/gsd-smartcard-manager.c | 1372 |
1 files changed, 0 insertions, 1372 deletions
diff --git a/plugins/smartcard/gsd-smartcard-manager.c b/plugins/smartcard/gsd-smartcard-manager.c deleted file mode 100644 index ed823f4..0000000 --- a/plugins/smartcard/gsd-smartcard-manager.c +++ /dev/null @@ -1,1372 +0,0 @@ -/* msd-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 "msd-smartcard-manager.h" - -#define SMARTCARD_ENABLE_INTERNAL_API -#include "msd-smartcard.h" - -#include <dirent.h> -#include <errno.h> -#include <fcntl.h> -#include <limits.h> -#include <poll.h> -#include <signal.h> -#include <stdlib.h> -#include <string.h> -#include <sys/resource.h> -#include <sys/time.h> -#include <sys/wait.h> -#include <unistd.h> - -#include <glib.h> -#include <glib/gi18n.h> - -#include <prerror.h> -#include <nss.h> -#include <pk11func.h> -#include <secmod.h> -#include <secerr.h> - -#ifndef MSD_SMARTCARD_MANAGER_NSS_DB -#define MSD_SMARTCARD_MANAGER_NSS_DB SYSCONFDIR"/pki/nssdb" -#endif - -typedef enum _MsdSmartcardManagerState MsdSmartcardManagerState; -typedef struct _MsdSmartcardManagerWorker MsdSmartcardManagerWorker; - -enum _MsdSmartcardManagerState { - MSD_SMARTCARD_MANAGER_STATE_STOPPED = 0, - MSD_SMARTCARD_MANAGER_STATE_STARTING, - MSD_SMARTCARD_MANAGER_STATE_STARTED, - MSD_SMARTCARD_MANAGER_STATE_STOPPING, -}; - -struct _MsdSmartcardManagerPrivate { - MsdSmartcardManagerState state; - SECMODModule *module; - char *module_path; - - GSource *smartcard_event_source; - GPid smartcard_event_watcher_pid; - GHashTable *smartcards; - - GThread *worker_thread; - - guint poll_timeout_id; - - guint32 is_unstoppable : 1; - guint32 nss_is_loaded : 1; -}; - -struct _MsdSmartcardManagerWorker { - SECMODModule *module; - GHashTable *smartcards; - int write_fd; - - guint32 nss_is_loaded : 1; -}; - -static void msd_smartcard_manager_finalize (GObject *object); -static void msd_smartcard_manager_class_install_signals (MsdSmartcardManagerClass *service_class); -static void msd_smartcard_manager_class_install_properties (MsdSmartcardManagerClass *service_class); -static void msd_smartcard_manager_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void msd_smartcard_manager_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); -static void msd_smartcard_manager_set_module_path (MsdSmartcardManager *manager, - const char *module_path); -static void msd_smartcard_manager_card_removed_handler (MsdSmartcardManager *manager, - MsdSmartcard *card); -static void msd_smartcard_manager_card_inserted_handler (MsdSmartcardManager *manager_class, - MsdSmartcard *card); -static gboolean msd_smartcard_manager_stop_now (MsdSmartcardManager *manager); -static void msd_smartcard_manager_queue_stop (MsdSmartcardManager *manager); - -static gboolean msd_smartcard_manager_create_worker (MsdSmartcardManager *manager, - int *worker_fd, GThread **worker_thread); - -static MsdSmartcardManagerWorker * msd_smartcard_manager_worker_new (int write_fd); -static void msd_smartcard_manager_worker_free (MsdSmartcardManagerWorker *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 MsdSmartcard *read_smartcard (int fd, SECMODModule *module); -static gboolean write_smartcard (int fd, MsdSmartcard *card); - -enum { - PROP_0 = 0, - PROP_MODULE_PATH, - NUMBER_OF_PROPERTIES -}; - -enum { - SMARTCARD_INSERTED = 0, - SMARTCARD_REMOVED, - ERROR, - NUMBER_OF_SIGNALS -}; - -static guint msd_smartcard_manager_signals[NUMBER_OF_SIGNALS]; - -G_DEFINE_TYPE (MsdSmartcardManager, - msd_smartcard_manager, - G_TYPE_OBJECT); - -static void -msd_smartcard_manager_class_init (MsdSmartcardManagerClass *manager_class) -{ - GObjectClass *gobject_class; - - gobject_class = G_OBJECT_CLASS (manager_class); - - gobject_class->finalize = msd_smartcard_manager_finalize; - - msd_smartcard_manager_class_install_signals (manager_class); - msd_smartcard_manager_class_install_properties (manager_class); - - g_type_class_add_private (manager_class, - sizeof (MsdSmartcardManagerPrivate)); -} - -static void -msd_smartcard_manager_class_install_properties (MsdSmartcardManagerClass *card_class) -{ - GObjectClass *object_class; - GParamSpec *param_spec; - - object_class = G_OBJECT_CLASS (card_class); - object_class->set_property = msd_smartcard_manager_set_property; - object_class->get_property = msd_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 -msd_smartcard_manager_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - MsdSmartcardManager *manager = MSD_SMARTCARD_MANAGER (object); - - switch (prop_id) { - case PROP_MODULE_PATH: - msd_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 -msd_smartcard_manager_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - MsdSmartcardManager *manager = MSD_SMARTCARD_MANAGER (object); - char *module_path; - - switch (prop_id) { - case PROP_MODULE_PATH: - module_path = msd_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 * -msd_smartcard_manager_get_module_path (MsdSmartcardManager *manager) -{ - return manager->priv->module_path; -} - -static void -msd_smartcard_manager_set_module_path (MsdSmartcardManager *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 -msd_smartcard_manager_card_removed_handler (MsdSmartcardManager *manager, - MsdSmartcard *card) -{ - g_debug ("informing smartcard of its removal"); - _msd_smartcard_set_state (card, MSD_SMARTCARD_STATE_REMOVED); - g_debug ("done"); -} - -static void -msd_smartcard_manager_card_inserted_handler (MsdSmartcardManager *manager, - MsdSmartcard *card) -{ - g_debug ("informing smartcard of its insertion"); - - _msd_smartcard_set_state (card, MSD_SMARTCARD_STATE_INSERTED); - g_debug ("done"); - -} - -static void -msd_smartcard_manager_class_install_signals (MsdSmartcardManagerClass *manager_class) -{ - GObjectClass *object_class; - - object_class = G_OBJECT_CLASS (manager_class); - - msd_smartcard_manager_signals[SMARTCARD_INSERTED] = - g_signal_new ("smartcard-inserted", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (MsdSmartcardManagerClass, - smartcard_inserted), - NULL, NULL, g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_POINTER); - manager_class->smartcard_inserted = msd_smartcard_manager_card_inserted_handler; - - msd_smartcard_manager_signals[SMARTCARD_REMOVED] = - g_signal_new ("smartcard-removed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (MsdSmartcardManagerClass, - smartcard_removed), - NULL, NULL, g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_POINTER); - manager_class->smartcard_removed = msd_smartcard_manager_card_removed_handler; - - msd_smartcard_manager_signals[ERROR] = - g_signal_new ("error", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (MsdSmartcardManagerClass, 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 -msd_smartcard_manager_init (MsdSmartcardManager *manager) -{ - g_debug ("initializing smartcard manager"); - - manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager, - MSD_TYPE_SMARTCARD_MANAGER, - MsdSmartcardManagerPrivate); - manager->priv->poll_timeout_id = 0; - manager->priv->is_unstoppable = FALSE; - manager->priv->module = NULL; - - manager->priv->smartcards = - g_hash_table_new_full (g_str_hash, - g_str_equal, - (GDestroyNotify) g_free, - (GDestroyNotify) g_object_unref); - - if (!g_thread_supported ()) { - g_thread_init (NULL); - } - -} - -static void -msd_smartcard_manager_finalize (GObject *object) -{ - MsdSmartcardManager *manager; - GObjectClass *gobject_class; - - manager = MSD_SMARTCARD_MANAGER (object); - gobject_class = - G_OBJECT_CLASS (msd_smartcard_manager_parent_class); - - msd_smartcard_manager_stop_now (manager); - - g_hash_table_destroy (manager->priv->smartcards); - manager->priv->smartcards = NULL; - - gobject_class->finalize (object); -} - -GQuark -msd_smartcard_manager_error_quark (void) -{ - static GQuark error_quark = 0; - - if (error_quark == 0) { - error_quark = g_quark_from_static_string ("msd-smartcard-manager-error-quark"); - } - - return error_quark; -} - -MsdSmartcardManager * -msd_smartcard_manager_new (const char *module_path) -{ - MsdSmartcardManager *instance; - - instance = MSD_SMARTCARD_MANAGER (g_object_new (MSD_TYPE_SMARTCARD_MANAGER, - "module-path", module_path, - NULL)); - - return instance; -} - -static void -msd_smartcard_manager_emit_error (MsdSmartcardManager *manager, - GError *error) -{ - manager->priv->is_unstoppable = TRUE; - g_signal_emit (manager, msd_smartcard_manager_signals[ERROR], 0, - error); - manager->priv->is_unstoppable = FALSE; -} - -static void -msd_smartcard_manager_emit_smartcard_inserted (MsdSmartcardManager *manager, - MsdSmartcard *card) -{ - manager->priv->is_unstoppable = TRUE; - g_signal_emit (manager, msd_smartcard_manager_signals[SMARTCARD_INSERTED], 0, - card); - manager->priv->is_unstoppable = FALSE; -} - -static void -msd_smartcard_manager_emit_smartcard_removed (MsdSmartcardManager *manager, - MsdSmartcard *card) -{ - MsdSmartcardManagerState old_state; - - old_state = manager->priv->state; - manager->priv->is_unstoppable = TRUE; - g_signal_emit (manager, msd_smartcard_manager_signals[SMARTCARD_REMOVED], 0, - card); - manager->priv->is_unstoppable = FALSE; -} - -static gboolean -msd_smartcard_manager_check_for_and_process_events (GIOChannel *io_channel, - GIOCondition condition, - MsdSmartcardManager *manager) -{ - MsdSmartcard *card; - gboolean should_stop; - gchar event_type; - char *card_name; - int fd; - - 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)) { - goto out; - } - - fd = g_io_channel_unix_get_fd (io_channel); - - event_type = '\0'; - if (!read_bytes (fd, &event_type, 1)) { - should_stop = TRUE; - goto out; - } - - card = read_smartcard (fd, manager->priv->module); - - if (card == NULL) { - should_stop = TRUE; - goto out; - } - - card_name = msd_smartcard_get_name (card); - - switch (event_type) { - case 'I': - g_hash_table_replace (manager->priv->smartcards, - card_name, card); - card_name = NULL; - - msd_smartcard_manager_emit_smartcard_inserted (manager, card); - card = NULL; - break; - - case 'R': - msd_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 (MSD_SMARTCARD_MANAGER_ERROR, - MSD_SMARTCARD_MANAGER_ERROR_WATCHING_FOR_EVENTS, - "%s", (condition & G_IO_IN) ? g_strerror (errno) : _("received error or hang up from event source")); - - msd_smartcard_manager_emit_error (manager, error); - g_error_free (error); - msd_smartcard_manager_stop_now (manager); - return FALSE; - } - - return TRUE; -} - -static void -msd_smartcard_manager_event_processing_stopped_handler (MsdSmartcardManager *manager) -{ - manager->priv->smartcard_event_source = NULL; - msd_smartcard_manager_stop_now (manager); -} - -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 -msd_smartcard_manager_stop_watching_for_events (MsdSmartcardManager *manager) -{ - if (manager->priv->smartcard_event_source != NULL) { - g_source_destroy (manager->priv->smartcard_event_source); - manager->priv->smartcard_event_source = NULL; - } - - if (manager->priv->worker_thread != NULL) { - SECMOD_CancelWait (manager->priv->module); - manager->priv->worker_thread = NULL; - } -} - -static gboolean -load_nss (GError **error) -{ - SECStatus status = SECSuccess; - static const guint32 flags = - NSS_INIT_READONLY | NSS_INIT_NOCERTDB | NSS_INIT_NOMODDB | - NSS_INIT_FORCEOPEN | NSS_INIT_NOROOTINIT | - NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD; - - g_debug ("attempting to load NSS database '%s'", - MSD_SMARTCARD_MANAGER_NSS_DB); - - status = NSS_Initialize (MSD_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, - MSD_SMARTCARD_MANAGER_ERROR, - MSD_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, - MSD_SMARTCARD_MANAGER_ERROR, - MSD_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 SECMODModule * -load_driver (char *module_path, - GError **error) -{ - SECMODModule *module; - char *module_spec; - gboolean module_explicitly_specified; - - g_debug ("attempting to load driver..."); - - module = NULL; - module_explicitly_specified = module_path != NULL; - if (module_explicitly_specified) { - 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; - - } else { - SECMODModuleList *modules, *tmp; - - modules = SECMOD_GetDefaultModuleList (); - - for (tmp = modules; tmp != NULL; tmp = tmp->next) { - if (!SECMOD_HasRemovableSlots (tmp->module) || - !tmp->module->loaded) - continue; - - module = SECMOD_ReferenceModule (tmp->module); - break; - } - } - - if (!module_explicitly_specified && module == NULL) { - g_set_error (error, - MSD_SMARTCARD_MANAGER_ERROR, - MSD_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER, - _("no suitable smartcard driver could be found")); - } else if (module == NULL || !module->loaded) { - - gsize error_message_size; - char *error_message; - - if (module != NULL && !module->loaded) { - g_debug ("module found but not loaded?!"); - SECMOD_DestroyModule (module); - module = NULL; - } - - 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, - MSD_SMARTCARD_MANAGER_ERROR, - MSD_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, - MSD_SMARTCARD_MANAGER_ERROR, - MSD_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); - } - -out: - return module; -} - -static void -msd_smartcard_manager_get_all_cards (MsdSmartcardManager *manager) -{ - int i; - - for (i = 0; i < manager->priv->module->slotCount; i++) { - MsdSmartcard *card; - CK_SLOT_ID slot_id; - int slot_series; - char *card_name; - - slot_id = PK11_GetSlotID (manager->priv->module->slots[i]); - slot_series = PK11_GetSlotSeries (manager->priv->module->slots[i]); - - card = _msd_smartcard_new (manager->priv->module, - slot_id, slot_series); - - card_name = msd_smartcard_get_name (card); - - g_hash_table_replace (manager->priv->smartcards, - card_name, card); - } -} - -gboolean -msd_smartcard_manager_start (MsdSmartcardManager *manager, - GError **error) -{ - GError *watching_error; - int worker_fd; - GPid worker_pid; - GIOChannel *io_channel; - GSource *source; - GIOFlags channel_flags; - GError *nss_error; - - if (manager->priv->state == MSD_SMARTCARD_MANAGER_STATE_STARTED) { - g_debug ("smartcard manager already started"); - return TRUE; - } - - manager->priv->state = MSD_SMARTCARD_MANAGER_STATE_STARTING; - - worker_fd = -1; - worker_pid = 0; - - 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->module == NULL) { - manager->priv->module = load_driver (manager->priv->module_path, &nss_error); - } - - if (manager->priv->module == NULL) { - g_propagate_error (error, nss_error); - goto out; - } - - if (!msd_smartcard_manager_create_worker (manager, &worker_fd, &manager->priv->worker_thread)) { - - g_set_error (error, - MSD_SMARTCARD_MANAGER_ERROR, - MSD_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_fd); - - channel_flags = g_io_channel_get_flags (io_channel); - watching_error = NULL; - - source = g_io_create_watch (io_channel, G_IO_IN | G_IO_HUP); - g_io_channel_unref (io_channel); - io_channel = NULL; - - manager->priv->smartcard_event_source = source; - - g_source_set_callback (manager->priv->smartcard_event_source, - (GSourceFunc) (GIOFunc) - msd_smartcard_manager_check_for_and_process_events, - manager, - (GDestroyNotify) - msd_smartcard_manager_event_processing_stopped_handler); - g_source_attach (manager->priv->smartcard_event_source, NULL); - g_source_unref (manager->priv->smartcard_event_source); - - /* populate the hash with cards that are already inserted - */ - msd_smartcard_manager_get_all_cards (manager); - - manager->priv->state = MSD_SMARTCARD_MANAGER_STATE_STARTED; - -out: - /* don't leave it in a half started state - */ - if (manager->priv->state != MSD_SMARTCARD_MANAGER_STATE_STARTED) { - g_debug ("smartcard manager could not be completely started"); - msd_smartcard_manager_stop (manager); - } else { - g_debug ("smartcard manager started"); - } - - return manager->priv->state == MSD_SMARTCARD_MANAGER_STATE_STARTED; -} - -static gboolean -msd_smartcard_manager_stop_now (MsdSmartcardManager *manager) -{ - if (manager->priv->state == MSD_SMARTCARD_MANAGER_STATE_STOPPED) { - return FALSE; - } - - manager->priv->state = MSD_SMARTCARD_MANAGER_STATE_STOPPED; - msd_smartcard_manager_stop_watching_for_events (manager); - - if (manager->priv->module != NULL) { - SECMOD_DestroyModule (manager->priv->module); - manager->priv->module = NULL; - } - - if (manager->priv->nss_is_loaded) { - NSS_Shutdown (); - manager->priv->nss_is_loaded = FALSE; - } - - g_debug ("smartcard manager stopped"); - - return FALSE; -} - -static void -msd_smartcard_manager_queue_stop (MsdSmartcardManager *manager) -{ - - manager->priv->state = MSD_SMARTCARD_MANAGER_STATE_STOPPING; - - g_idle_add ((GSourceFunc) msd_smartcard_manager_stop_now, manager); -} - -void -msd_smartcard_manager_stop (MsdSmartcardManager *manager) -{ - if (manager->priv->state == MSD_SMARTCARD_MANAGER_STATE_STOPPED) { - return; - } - - if (manager->priv->is_unstoppable) { - msd_smartcard_manager_queue_stop (manager); - return; - } - - msd_smartcard_manager_stop_now (manager); -} - -static void -msd_smartcard_manager_check_for_login_card (CK_SLOT_ID slot_id, - MsdSmartcard *card, - gboolean *is_inserted) -{ - g_assert (is_inserted != NULL); - - if (msd_smartcard_is_login_card (card)) { - *is_inserted = TRUE; - } - -} - -gboolean -msd_smartcard_manager_login_card_is_inserted (MsdSmartcardManager *manager) - -{ - gboolean is_inserted; - - is_inserted = FALSE; - g_hash_table_foreach (manager->priv->smartcards, - (GHFunc) - msd_smartcard_manager_check_for_login_card, - &is_inserted); - return is_inserted; -} - -static MsdSmartcardManagerWorker * -msd_smartcard_manager_worker_new (int write_fd) -{ - MsdSmartcardManagerWorker *worker; - - worker = g_slice_new0 (MsdSmartcardManagerWorker); - worker->write_fd = write_fd; - worker->module = NULL; - - 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 -msd_smartcard_manager_worker_free (MsdSmartcardManagerWorker *worker) -{ - if (worker->smartcards != NULL) { - g_hash_table_destroy (worker->smartcards); - worker->smartcards = NULL; - } - - g_slice_free (MsdSmartcardManagerWorker, 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 MsdSmartcard * -read_smartcard (int fd, - SECMODModule *module) -{ - MsdSmartcard *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 = _msd_smartcard_new_from_name (module, card_name); - g_slice_free1 (card_name_size, card_name); - - return card; -} - -static gboolean -write_smartcard (int fd, - MsdSmartcard *card) -{ - gsize card_name_size; - char *card_name; - - card_name = msd_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 -msd_smartcard_manager_worker_emit_smartcard_removed (MsdSmartcardManagerWorker *worker, - MsdSmartcard *card, - GError **error) -{ - g_debug ("card '%s' removed!", msd_smartcard_get_name (card)); - - if (!write_bytes (worker->write_fd, "R", 1)) { - goto error_out; - } - - if (!write_smartcard (worker->write_fd, card)) { - goto error_out; - } - - return TRUE; - -error_out: - g_set_error (error, MSD_SMARTCARD_MANAGER_ERROR, - MSD_SMARTCARD_MANAGER_ERROR_REPORTING_EVENTS, - "%s", g_strerror (errno)); - return FALSE; -} - -static gboolean -msd_smartcard_manager_worker_emit_smartcard_inserted (MsdSmartcardManagerWorker *worker, - MsdSmartcard *card, - GError **error) -{ - GError *write_error; - - write_error = NULL; - g_debug ("card '%s' inserted!", msd_smartcard_get_name (card)); - if (!write_bytes (worker->write_fd, "I", 1)) { - goto error_out; - } - - if (!write_smartcard (worker->write_fd, card)) { - goto error_out; - } - - return TRUE; - -error_out: - g_set_error (error, MSD_SMARTCARD_MANAGER_ERROR, - MSD_SMARTCARD_MANAGER_ERROR_REPORTING_EVENTS, - "%s", g_strerror (errno)); - return FALSE; -} - -static gboolean -msd_smartcard_manager_worker_watch_for_and_process_event (MsdSmartcardManagerWorker *worker, - GError **error) -{ - PK11SlotInfo *slot; - CK_SLOT_ID slot_id, *key; - int slot_series, card_slot_series; - MsdSmartcard *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, MSD_SMARTCARD_MANAGER_ERROR, - MSD_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 = msd_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 (!msd_smartcard_manager_worker_emit_smartcard_removed (worker, card, &processing_error)) { - g_propagate_error (error, processing_error); - goto out; - } - } - - card = _msd_smartcard_new (worker->module, - slot_id, slot_series); - - g_hash_table_replace (worker->smartcards, - key, card); - key = NULL; - - if (!msd_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 (!msd_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 = _msd_smartcard_new (worker->module, - slot_id, slot_series); - g_hash_table_replace (worker->smartcards, - key, card); - key = NULL; - if (!msd_smartcard_manager_worker_emit_smartcard_inserted (worker, card, &processing_error)) { - g_propagate_error (error, processing_error); - goto out; - } - } - - if (!msd_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 -msd_smartcard_manager_worker_run (MsdSmartcardManagerWorker *worker) -{ - GError *error; - - - error = NULL; - - while (msd_smartcard_manager_worker_watch_for_and_process_event (worker, &error)); - - if (error != NULL) { - g_debug ("could not process card event - %s", error->message); - g_error_free (error); - } - - msd_smartcard_manager_worker_free (worker); -} - -static gboolean -msd_smartcard_manager_create_worker (MsdSmartcardManager *manager, - int *worker_fd, - GThread **worker_thread) -{ - MsdSmartcardManagerWorker *worker; - int write_fd, read_fd; - - write_fd = -1; - read_fd = -1; - if (!open_pipe (&write_fd, &read_fd)) { - return FALSE; - } - - worker = msd_smartcard_manager_worker_new (write_fd); - worker->module = manager->priv->module; - - *worker_thread = g_thread_create ((GThreadFunc) - msd_smartcard_manager_worker_run, - worker, FALSE, NULL); - - if (*worker_thread == NULL) { - msd_smartcard_manager_worker_free (worker); - return FALSE; - } - - if (worker_fd) { - *worker_fd = read_fd; - } - - return TRUE; -} - -#ifdef MSD_SMARTCARD_MANAGER_ENABLE_TEST -#include <glib.h> - -static GMainLoop *event_loop; -static gboolean should_exit_on_next_remove = FALSE; - -static gboolean -on_timeout (MsdSmartcardManager *manager) -{ - GError *error; - g_print ("Re-enabling manager.\n"); - - if (!msd_smartcard_manager_start (manager, &error)) { - g_warning ("could not start smartcard manager - %s", - error->message); - g_error_free (error); - return 1; - } - g_print ("Please re-insert smartcard\n"); - - should_exit_on_next_remove = TRUE; - - return FALSE; -} - -static void -on_device_inserted (MsdSmartcardManager *manager, - MsdSmartcard *card) -{ - g_print ("smartcard inserted!\n"); - g_print ("Please remove it.\n"); -} - -static void -on_device_removed (MsdSmartcardManager *manager, - MsdSmartcard *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"); - msd_smartcard_manager_stop (manager); - g_timeout_add (2000, (GSourceFunc) on_timeout, manager); - } -} - -int -main (int argc, - char *argv[]) -{ - MsdSmartcardManager *manager; - GError *error; - - g_log_set_always_fatal (G_LOG_LEVEL_ERROR - | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING); - - g_type_init (); - - g_message ("creating instance of 'smartcard manager' object..."); - manager = msd_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 (!msd_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 |