Blob Blame History Raw
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, &parameters, 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