From 2273e9d04010d2c37c5995f8505c047ca1764232 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 16 Jun 2015 09:45:46 -0400
Subject: [PATCH] smartcard: use NSS_InitContext instead of NSS_Initialize
NSS_Initialize is a noop if called multiple times. We
currently call NSS_Initialize twice in gnome-settings-daemon.
Once by NMClient and once by the smartcard plugin. NMClient
does it first, and it does it without initializing the secmod
database. When the smartcard plugin tries to initialize NSS
with the secmod database later, it's call is turned to a noop.
This commit changes the smartcard plugin to use NSS_InitContext
instead, which can properly handle being initialized multiple
times with different configurations. See:
https://wiki.mozilla.org/NSS_Library_Init
https://bugzilla.gnome.org/show_bug.cgi?id=751040
---
plugins/smartcard/gsd-smartcard-manager.c | 28 ++++++++++++++++++----------
1 file changed, 18 insertions(+), 10 deletions(-)
diff --git a/plugins/smartcard/gsd-smartcard-manager.c b/plugins/smartcard/gsd-smartcard-manager.c
index e81ace2..2564acd 100644
--- a/plugins/smartcard/gsd-smartcard-manager.c
+++ b/plugins/smartcard/gsd-smartcard-manager.c
@@ -27,147 +27,155 @@
#include "gnome-settings-profile.h"
#include "gnome-settings-bus.h"
#include "gsd-smartcard-manager.h"
#include "gsd-smartcard-service.h"
#include "gsd-smartcard-enum-types.h"
#include "gsd-smartcard-utils.h"
#include <prerror.h>
#include <prinit.h>
#include <nss.h>
#include <pk11func.h>
#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;
- guint32 nss_is_loaded : 1;
+ 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);
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;
+ 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
+ */
+ NSSInitParameters parameters = { sizeof (parameters), };
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);
+ context = NSS_InitContext (GSD_SMARTCARD_MANAGER_NSS_DB,
+ "", "", SECMOD_DB, ¶meters, flags);
- if (status != SECSuccess) {
+ if (context == NULL) {
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;
+
+ priv->nss_context = NULL;
return;
}
g_debug ("NSS database '%s' loaded", GSD_SMARTCARD_MANAGER_NSS_DB);
- priv->nss_is_loaded = TRUE;
+ priv->nss_context = context;
}
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;
+ if (self->priv->nss_context != NULL) {
+ g_clear_pointer (&self->priv->nss_context,
+ NSS_ShutdownContext);
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;
--
2.5.0