From 0665bd86221d3c9012f0391d8e4939a2d12b6417 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 9 Feb 2018 16:39:12 -0500 Subject: [PATCH 1/2] smartcard: Wait until smartcards are inspected before locking screen There's a race condition in the code where we check if the screen should be locked (because the smartcard is removed) before we necessarly check the smartcard's insertion status. This commit fixes the race by iterating through all smartcards at startup and checking their status explicitly. --- plugins/smartcard/gsd-smartcard-manager.c | 61 ++++++++++++++++++----- 1 file changed, 49 insertions(+), 12 deletions(-) diff --git a/plugins/smartcard/gsd-smartcard-manager.c b/plugins/smartcard/gsd-smartcard-manager.c index a6245425..94ffdd90 100644 --- a/plugins/smartcard/gsd-smartcard-manager.c +++ b/plugins/smartcard/gsd-smartcard-manager.c @@ -37,64 +37,73 @@ #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; NSSInitContext *nss_context; }; #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); +static void on_smartcards_from_driver_watched (GsdSmartcardManager *self, + GAsyncResult *result, + GTask *task); 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); +typedef struct { + SECMODModule *driver; + guint idle_id; + GError *error; +} DriverRegistrationOperation; + 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; NSSInitContext *context = NULL; /* The first field in the NSSInitParameters structure * is the size of the structure. NSS requires this, so * that it can change the size of the structure in future * versions of NSS in a detectable way @@ -291,135 +300,168 @@ watch_smartcards_from_driver (GTask *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 +sync_initial_tokens_from_driver (GsdSmartcardManager *self, + SECMODModule *driver, + GHashTable *smartcards, + GCancellable *cancellable) +{ + GsdSmartcardManagerPrivate *priv = self->priv; + int i; + + for (i = 0; i < driver->slotCount; i++) { + PK11SlotInfo *card; + + card = driver->slots[i]; + + if (PK11_IsPresent (card)) { + CK_SLOT_ID slot_id; + slot_id = PK11_GetSlotID (card); + + g_debug ("Detected smartcard in slot %d at start up", (int) slot_id); + + g_hash_table_replace (smartcards, + GINT_TO_POINTER ((int) slot_id), + PK11_ReferenceSlot (card)); + gsd_smartcard_service_sync_token (priv->service, card, cancellable); + } + } +} + 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); + sync_initial_tokens_from_driver (self, driver, operation->smartcards, cancellable); + g_task_run_in_thread (task, (GTaskThreadFunc) watch_smartcards_from_driver); } static gboolean register_driver_finish (GsdSmartcardManager *self, GAsyncResult *result, GError **error) { return g_task_propagate_boolean (G_TASK (result), error); } static void on_driver_registered (GsdSmartcardManager *self, GAsyncResult *result, GTask *task) { GError *error = NULL; + DriverRegistrationOperation *operation; + GsdSmartcardManagerPrivate *priv = self->priv; + + operation = g_task_get_task_data (G_TASK (result)); if (!register_driver_finish (self, result, &error)) { g_task_return_error (task, error); g_object_unref (task); return; } - g_task_return_boolean (task, TRUE); + watch_smartcards_from_driver_async (self, + operation->driver, + priv->cancellable, + (GAsyncReadyCallback) on_smartcards_from_driver_watched, + task); + g_task_return_boolean (task, TRUE); g_object_unref (task); } static void on_smartcards_from_driver_watched (GsdSmartcardManager *self, GAsyncResult *result, GTask *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 on_main_thread_to_register_driver (GTask *task) { GsdSmartcardManager *self; GsdSmartcardManagerPrivate *priv; DriverRegistrationOperation *operation; GSource *source; self = g_task_get_source_object (task); @@ -450,65 +492,60 @@ register_driver (GsdSmartcardManager *self, 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); g_source_set_name_by_id (operation->idle_id, "[gnome-settings-daemon] on_main_thread_to_register_driver"); } static void activate_driver (GsdSmartcardManager *self, SECMODModule *driver, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; g_debug ("Activating driver '%s'", driver->commonName); task = g_task_new (self, cancellable, callback, user_data); 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 g_task_propagate_boolean (G_TASK (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_new_error (task, GSD_SMARTCARD_MANAGER_ERROR, -- 2.17.0