From 0665bd86221d3c9012f0391d8e4939a2d12b6417 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
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 <secmod.h>
#include <secerr.h>
#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