|
|
|
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
|
|
|
|
|