aa06693
diff -up gnome-screensaver-2.26.0/configure.ac.securitytoken gnome-screensaver-2.26.0/configure.ac
aa06693
--- gnome-screensaver-2.26.0/configure.ac.securitytoken	2009-03-18 13:20:20.000000000 -0400
6d5f864
+++ gnome-screensaver-2.26.0/configure.ac	2009-03-19 00:20:36.625194934 -0400
aa06693
@@ -45,6 +45,7 @@ GNOME_DESKTOP_REQUIRED_VERSION=2.23.2
aa06693
 
aa06693
 GLADE_REQUIRED_VERSION=2.5.0
aa06693
 LIBGNOMEKBDUI_REQUIRED_VERSION=0.1
aa06693
+NSS_REQUIRED_VERSION=3.11.2
aa06693
 
aa06693
 AC_CHECK_HEADERS(unistd.h)
aa06693
 AC_CHECK_HEADERS(crypt.h sys/select.h)
aa06693
@@ -59,7 +60,8 @@ PKG_CHECK_MODULES(GNOME_SCREENSAVER,
aa06693
         dbus-glib-1 >= $DBUS_REQUIRED_VERSION
aa06693
         gconf-2.0 >= $GCONF_REQUIRED_VERSION
aa06693
         gnome-desktop-2.0 >= $GNOME_DESKTOP_REQUIRED_VERSION
aa06693
-        libgnome-menu >= $LIBGNOME_MENU_REQUIRED_VERSION)
aa06693
+        libgnome-menu >= $LIBGNOME_MENU_REQUIRED_VERSION
aa06693
+        nss >= $NSS_REQUIRED_VERSION)
aa06693
 AC_SUBST(GNOME_SCREENSAVER_CFLAGS)
aa06693
 AC_SUBST(GNOME_SCREENSAVER_LIBS)
aa06693
 
aa06693
@@ -96,8 +98,6 @@ AC_PATH_PROG(GCONFTOOL, gconftool-2)
aa06693
 
aa06693
 AM_GCONF_SOURCE_2
aa06693
 
aa06693
-GNOME_COMPILE_WARNINGS(yes)
aa06693
-
aa06693
 # Solaris requires libresolv for daemon()
aa06693
 case "$host" in
aa06693
 	*-*-solaris*)
aa06693
@@ -171,6 +171,13 @@ PKG_CHECK_MODULES(LIB_GNOME_MENU,
aa06693
 AC_SUBST(LIB_GNOME_MENU_CFLAGS)
aa06693
 AC_SUBST(LIB_GNOME_MENU_LIBS)
aa06693
 
aa06693
+# security token support
aa06693
+PKG_CHECK_MODULES(SECURITY_TOKEN,
aa06693
+        gobject-2.0 >= $GLIB_REQUIRED_VERSION
aa06693
+        nss >= $NSS_REQUIRED_VERSION)
aa06693
+AC_SUBST(SECURITY_TOKEN_CFLAGS)
aa06693
+AC_SUBST(SECURITY_TOKEN_LIBS)
aa06693
+
aa06693
 dnl ---------------------------------------------------------------------------
aa06693
 dnl - Where should we put documentation ?
aa06693
 dnl ---------------------------------------------------------------------------
aa06693
diff -up gnome-screensaver-2.26.0/src/gs-auth-pam.c.securitytoken gnome-screensaver-2.26.0/src/gs-auth-pam.c
aa06693
--- gnome-screensaver-2.26.0/src/gs-auth-pam.c.securitytoken	2009-03-18 11:39:58.000000000 -0400
6d5f864
+++ gnome-screensaver-2.26.0/src/gs-auth-pam.c	2009-03-19 00:20:36.632207149 -0400
aa06693
@@ -354,6 +354,13 @@ close_pam_handle (int status)
aa06693
                                    status2,
aa06693
                                    (status2 == PAM_SUCCESS ? "Success" : "Failure"));
aa06693
                 }
aa06693
+
aa06693
+		/* iterate the glib event loop inbetween processing pam
aa06693
+		 * messages so that the user interface can be updated
aa06693
+		 * to reflect changes that are a result of the pam
aa06693
+		 * messages
aa06693
+		 */
aa06693
+		while (g_main_context_iteration (NULL, FALSE));
aa06693
         }
aa06693
 
aa06693
         if (message_handled_condition != NULL) {
aa06693
diff -up gnome-screensaver-2.26.0/src/gs-monitor.c.securitytoken gnome-screensaver-2.26.0/src/gs-monitor.c
aa06693
--- gnome-screensaver-2.26.0/src/gs-monitor.c.securitytoken	2009-03-18 11:39:58.000000000 -0400
6d5f864
+++ gnome-screensaver-2.26.0/src/gs-monitor.c	2009-03-19 00:46:39.466197461 -0400
aa06693
@@ -41,10 +41,15 @@
aa06693
 #include "gs-prefs.h"
aa06693
 #include "gs-debug.h"
aa06693
 
aa06693
+#include "securitytokenmonitor.h"
aa06693
+
aa06693
 static void     gs_monitor_class_init (GSMonitorClass *klass);
aa06693
 static void     gs_monitor_init       (GSMonitor      *monitor);
aa06693
 static void     gs_monitor_finalize   (GObject        *object);
aa06693
 
aa06693
+static void     gs_monitor_simulate_user_activity (GSMonitor *monitor);
aa06693
+static void     gs_monitor_lock_screen (GSMonitor *monitor);
aa06693
+
aa06693
 #define GS_MONITOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GS_TYPE_MONITOR, GSMonitorPrivate))
aa06693
 
aa06693
 struct GSMonitorPrivate
aa06693
@@ -56,6 +61,7 @@ struct GSMonitorPrivate
aa06693
         GSFade         *fade;
aa06693
         GSGrab         *grab;
aa06693
         guint           release_grab_id;
aa06693
+        ScSecurityTokenMonitor *security_token_monitor;
aa06693
 };
aa06693
 
aa06693
 #define FADE_TIMEOUT 10000
aa06693
@@ -85,6 +91,36 @@ manager_deactivated_cb (GSManager *manag
aa06693
         gs_listener_set_active (monitor->priv->listener, FALSE);
aa06693
 }
aa06693
 
aa06693
+static void
aa06693
+security_token_inserted_cb (ScSecurityTokenMonitor *token_monitor,
aa06693
+                            ScSecurityToken        *token,
aa06693
+                            GSMonitor              *monitor)
aa06693
+{
aa06693
+        gs_monitor_simulate_user_activity (monitor);
aa06693
+}
aa06693
+
aa06693
+static gboolean
aa06693
+gs_monitor_should_lock_on_login_security_token_removal (void)
aa06693
+{
aa06693
+        /* FIXME: lame hack
aa06693
+         */
aa06693
+        return system ("pkcs11_setup rm_action | grep -q lock") == 0;
aa06693
+}
aa06693
+
aa06693
+static void
aa06693
+security_token_removed_cb (ScSecurityTokenMonitor *token_monitor,
aa06693
+                           ScSecurityToken        *token,
aa06693
+                           GSMonitor              *monitor)
aa06693
+{
aa06693
+        if (gs_monitor_should_lock_on_login_security_token_removal () &&
aa06693
+            sc_security_token_is_login_token (token))
aa06693
+                gs_monitor_lock_screen (monitor);
aa06693
+
aa06693
+        /* If we're already locked and the lock dialog is up, kill it.
aa06693
+         */
aa06693
+        gs_manager_cancel_unlock_request (monitor->priv->manager);
aa06693
+}
aa06693
+
aa06693
 static gboolean
aa06693
 watcher_idle_cb (GSWatcher *watcher,
aa06693
                  gboolean   is_idle,
aa06693
@@ -165,35 +201,6 @@ watcher_idle_notice_cb (GSWatcher *watch
aa06693
 }
aa06693
 
aa06693
 static void
aa06693
-gs_monitor_lock_screen (GSMonitor *monitor)
aa06693
-{
aa06693
-        gboolean res;
aa06693
-        gboolean locked;
aa06693
-
aa06693
-        /* set lock flag before trying to activate screensaver
aa06693
-           in case something tries to react to the ActiveChanged signal */
aa06693
-
aa06693
-        gs_manager_get_lock_active (monitor->priv->manager, &locked);
aa06693
-        gs_manager_set_lock_active (monitor->priv->manager, TRUE);
aa06693
-        res = gs_listener_set_active (monitor->priv->listener, TRUE);
aa06693
-        if (! res) {
aa06693
-                /* If we've failed then restore lock status */
aa06693
-                gs_manager_set_lock_active (monitor->priv->manager, locked);
aa06693
-                gs_debug ("Unable to lock the screen");
aa06693
-        }
aa06693
-}
aa06693
-
aa06693
-static void
aa06693
-gs_monitor_simulate_user_activity (GSMonitor *monitor)
aa06693
-{
aa06693
-        /* FIXME: reset the xsync timer? */
aa06693
-
aa06693
-        /* request that the manager unlock -
aa06693
-           will pop up a dialog if necessary */
aa06693
-        gs_manager_request_unlock (monitor->priv->manager);
aa06693
-}
aa06693
-
aa06693
-static void
aa06693
 listener_lock_cb (GSListener *listener,
aa06693
                   GSMonitor  *monitor)
aa06693
 {
aa06693
@@ -401,6 +408,27 @@ connect_manager_signals (GSMonitor *moni
aa06693
 }
aa06693
 
aa06693
 static void
aa06693
+disconnect_security_token_monitor_signals (GSMonitor *monitor)
aa06693
+{
aa06693
+        g_signal_handlers_disconnect_by_func (monitor->priv->security_token_monitor,
aa06693
+					      security_token_removed_cb, monitor);
aa06693
+
aa06693
+        g_signal_handlers_disconnect_by_func (monitor->priv->security_token_monitor,
aa06693
+					      security_token_inserted_cb, monitor);
aa06693
+}
aa06693
+
aa06693
+static void
aa06693
+connect_security_token_monitor_signals (GSMonitor *monitor)
aa06693
+{
aa06693
+	g_signal_connect (monitor->priv->security_token_monitor, 
aa06693
+			  "security-token-removed",
aa06693
+			  G_CALLBACK (security_token_removed_cb), monitor);
aa06693
+	g_signal_connect (monitor->priv->security_token_monitor, 
aa06693
+			  "security-token-inserted",
aa06693
+			  G_CALLBACK (security_token_inserted_cb), monitor);
aa06693
+}
aa06693
+
aa06693
+static void
aa06693
 disconnect_prefs_signals (GSMonitor *monitor)
aa06693
 {
aa06693
         g_signal_handlers_disconnect_by_func (monitor->priv->prefs, _gs_monitor_update_from_prefs, monitor);
aa06693
@@ -434,6 +462,26 @@ gs_monitor_init (GSMonitor *monitor)
aa06693
         monitor->priv->manager = gs_manager_new ();
aa06693
         connect_manager_signals (monitor);
aa06693
 
aa06693
+	/* PKCS11_LOGIN_TOKEN_NAME is set if the user logged in with a
aa06693
+	 * security token.
aa06693
+	 */
aa06693
+	if (g_getenv ("PKCS11_LOGIN_TOKEN_NAME") != NULL) {
aa06693
+		monitor->priv->security_token_monitor = sc_security_token_monitor_new (NULL);
aa06693
+		sc_security_token_monitor_start (monitor->priv->security_token_monitor,
aa06693
+						 NULL);
aa06693
+		connect_security_token_monitor_signals (monitor);
aa06693
+
aa06693
+		/* if the user logged in with a security token but it's
aa06693
+		 * not currently inserted, then they must have yanked it
aa06693
+		 * before we started.  lock the screen immediately
aa06693
+		 */
aa06693
+		if (gs_monitor_should_lock_on_login_security_token_removal () &&
aa06693
+		    !sc_security_token_monitor_login_token_is_inserted (monitor->priv->security_token_monitor))
aa06693
+			gs_monitor_lock_screen (monitor);
aa06693
+	} else {
aa06693
+		monitor->priv->security_token_monitor = NULL;
aa06693
+	}
aa06693
+
aa06693
         _gs_monitor_update_from_prefs (monitor, monitor->priv->prefs);
aa06693
 }
aa06693
 
aa06693
@@ -449,6 +497,12 @@ gs_monitor_finalize (GObject *object)
aa06693
 
aa06693
         g_return_if_fail (monitor->priv != NULL);
aa06693
 
aa06693
+	if (monitor->priv->security_token_monitor != NULL) {
aa06693
+		sc_security_token_monitor_stop (monitor->priv->security_token_monitor);
aa06693
+		disconnect_security_token_monitor_signals (monitor);
aa06693
+		g_object_unref (monitor->priv->security_token_monitor);
aa06693
+	}
aa06693
+
aa06693
         disconnect_watcher_signals (monitor);
aa06693
         disconnect_listener_signals (monitor);
aa06693
         disconnect_manager_signals (monitor);
6d5f864
@@ -486,3 +540,30 @@ gs_monitor_start (GSMonitor *monitor,
aa06693
 
aa06693
         return TRUE;
aa06693
 }
aa06693
+
aa06693
+static void     
aa06693
+gs_monitor_simulate_user_activity (GSMonitor *monitor)
aa06693
+{
aa06693
+        /* request that the manager unlock -
aa06693
+           will pop up a dialog if necessary */
aa06693
+        gs_manager_request_unlock (monitor->priv->manager);
aa06693
+}
aa06693
+
aa06693
+static void     
aa06693
+gs_monitor_lock_screen (GSMonitor *monitor)
aa06693
+{
aa06693
+        gboolean res;
aa06693
+        gboolean locked;
aa06693
+
aa06693
+        /* set lock flag before trying to activate screensaver
aa06693
+           in case something tries to react to the ActiveChanged signal */
aa06693
+
aa06693
+        gs_manager_get_lock_active (monitor->priv->manager, &locked);
aa06693
+        gs_manager_set_lock_active (monitor->priv->manager, TRUE);
aa06693
+        res = gs_listener_set_active (monitor->priv->listener, TRUE);
aa06693
+        if (! res) {
aa06693
+                /* If we've failed then restore lock status */
aa06693
+                gs_manager_set_lock_active (monitor->priv->manager, locked);
aa06693
+                gs_debug ("Unable to lock the screen");
aa06693
+        }
aa06693
+}
aa06693
diff -up gnome-screensaver-2.26.0/src/Makefile.am.securitytoken gnome-screensaver-2.26.0/src/Makefile.am
aa06693
--- gnome-screensaver-2.26.0/src/Makefile.am.securitytoken	2009-03-18 11:39:58.000000000 -0400
6d5f864
+++ gnome-screensaver-2.26.0/src/Makefile.am	2009-03-19 00:20:36.635194085 -0400
aa06693
@@ -51,6 +51,18 @@ noinst_PROGRAMS = 	\
aa06693
 	test-window	\
aa06693
 	$(NULL)
aa06693
 
aa06693
+noinst_LIBRARIES = libsecuritytoken.a
aa06693
+ 
aa06693
+libsecuritytoken_a_SOURCES = \
aa06693
+	securitytoken.h \
aa06693
+	securitytoken.c \
aa06693
+	securitytokenmonitor.h \
aa06693
+	securitytokenmonitor.c
aa06693
+
aa06693
+libsecuritytoken_a_CFLAGS = $(SECURITY_TOKEN_CFLAGS) \
aa06693
+			-DLIBDIR=\""$(libdir)"\"  \
aa06693
+			-DSYSCONFDIR=\""$(sysconfdir)"\"
aa06693
+
aa06693
 gnome_screensaver_command_SOURCES = 	\
aa06693
 	gnome-screensaver-command.c	\
aa06693
 	$(NULL)
aa06693
@@ -208,6 +220,7 @@ gnome_screensaver_gl_helper_SOURCES =	\
aa06693
 gnome_screensaver_LDADD =		\
aa06693
 	$(GNOME_SCREENSAVER_LIBS)	\
aa06693
 	$(SAVER_LIBS)			\
aa06693
+ 	$(top_builddir)/src/libsecuritytoken.a \
aa06693
 	$(NULL)
aa06693
 
aa06693
 gnome_screensaver_LDFLAGS = -export-dynamic
aa06693
diff -up /dev/null gnome-screensaver-2.26.0/src/securitytoken.c
aa06693
--- /dev/null	2009-03-18 22:51:48.055015100 -0400
6d5f864
+++ gnome-screensaver-2.26.0/src/securitytoken.c	2009-03-19 00:20:36.637204629 -0400
aa06693
@@ -0,0 +1,680 @@
aa06693
+/* securitytoken.c - security token
aa06693
+ * 
aa06693
+ * Copyright (C) 2006 Ray Strode <rstrode@redhat.com>
aa06693
+ * 
aa06693
+ * This program is free software; you can redistribute it and/or modify
aa06693
+ * it under the terms of the GNU General Public License as published by
aa06693
+ * the Free Software Foundation; either version 2, or (at your option)
aa06693
+ * any later version.
aa06693
+ * 
aa06693
+ * This program is distributed in the hope that it will be useful,
aa06693
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
aa06693
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
aa06693
+ * GNU General Public License for more details.
aa06693
+ * 
aa06693
+ * You should have received a copy of the GNU General Public License
aa06693
+ * along with this program; if not, write to the Free Software
aa06693
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
aa06693
+ * 02111-1307, USA.  
aa06693
+ *
aa06693
+ * TODO:     - doing this per project is a bad idea i think.
aa06693
+ *             We should probably make this a system service 
aa06693
+ *             and use dbus.
aa06693
+ *
aa06693
+ *           - We hardcode a driver right now.  We should probably
aa06693
+ *             look up the default list and go from there. 
aa06693
+ */
aa06693
+#define SC_SECURITY_TOKEN_ENABLE_INTERNAL_API
aa06693
+#include "securitytoken.h"
aa06693
+
aa06693
+#include <errno.h>
aa06693
+#include <string.h>
aa06693
+#include <unistd.h>
aa06693
+
aa06693
+#include <glib.h>
aa06693
+#include <glib/gi18n.h>
aa06693
+
aa06693
+#include <cert.h>
aa06693
+#include <nss.h>
aa06693
+#include <pk11func.h>
aa06693
+#include <prerror.h>
aa06693
+#include <secmod.h>
aa06693
+#include <secerr.h>
aa06693
+
aa06693
+#if defined (SC_SECURITY_TOKEN_ENABLE_TEST) || defined (SC_SECURITY_TOKEN_MONITOR_ENABLE_TEST)
aa06693
+#define sc_debug(format, args...) g_printerr (format "\n", ##args)
aa06693
+#define sc_warning(format, args...) g_printerr (format "\n", ##args)
aa06693
+#else
aa06693
+#define sc_debug(format, args...) 
aa06693
+#define sc_warning(format, args...) 
aa06693
+#endif
aa06693
+
aa06693
+struct _ScSecurityTokenPrivate {
aa06693
+	SECMODModule *module;
aa06693
+	ScSecurityTokenState state;
aa06693
+
aa06693
+	CK_SLOT_ID slot_id;
aa06693
+	gint slot_series;
aa06693
+
aa06693
+	PK11SlotInfo *slot;
aa06693
+	gchar *name;
aa06693
+
aa06693
+	CERTCertificate *signing_certificate;
aa06693
+	CERTCertificate *encryption_certificate;
aa06693
+};
aa06693
+
aa06693
+static void sc_security_token_finalize (GObject *object);
aa06693
+static void sc_security_token_class_install_signals (ScSecurityTokenClass *token_class);
aa06693
+static void sc_security_token_class_install_properties (ScSecurityTokenClass *token_class);
aa06693
+static void sc_security_token_set_property (GObject       *object,
aa06693
+					    guint          prop_id,
aa06693
+					    const GValue  *value,
aa06693
+					    GParamSpec    *pspec);
aa06693
+static void sc_security_token_get_property (GObject     *object,
aa06693
+					    guint        prop_id,
aa06693
+					    GValue      *value,
aa06693
+					    GParamSpec  *pspec);
aa06693
+static void sc_security_token_set_name (ScSecurityToken *token, const gchar *name);
aa06693
+static void sc_security_token_set_slot_id (ScSecurityToken *token, 
aa06693
+					   gint             slot_id);
aa06693
+static void sc_security_token_set_slot_series (ScSecurityToken *token, 
aa06693
+					       gint             slot_series);
aa06693
+static void sc_security_token_set_module (ScSecurityToken *token,
aa06693
+					  SECMODModule    *module);
aa06693
+
aa06693
+static PK11SlotInfo *sc_security_token_find_slot_from_id (ScSecurityToken *token,
aa06693
+							  gint slot_id);
aa06693
+
aa06693
+static PK11SlotInfo *sc_security_token_find_slot_from_token_name (ScSecurityToken *token,
aa06693
+								  const gchar     *token_name);
aa06693
+static gboolean sc_security_token_fetch_certificates (ScSecurityToken *token);
aa06693
+
aa06693
+
aa06693
+#ifndef SC_SECURITY_TOKEN_DEFAULT_SLOT_ID 
aa06693
+#define SC_SECURITY_TOKEN_DEFAULT_SLOT_ID ((gulong) -1)
aa06693
+#endif
aa06693
+
aa06693
+#ifndef SC_SECURITY_TOKEN_DEFAULT_SLOT_SERIES
aa06693
+#define SC_SECURITY_TOKEN_DEFAULT_SLOT_SERIES -1
aa06693
+#endif
aa06693
+
aa06693
+enum {
aa06693
+	PROP_0 = 0,
aa06693
+	PROP_NAME,
aa06693
+	PROP_SLOT_ID,
aa06693
+	PROP_SLOT_SERIES,
aa06693
+	PROP_MODULE,
aa06693
+	NUMBER_OF_PROPERTIES
aa06693
+};
aa06693
+
aa06693
+enum {
aa06693
+	INSERTED,
aa06693
+	REMOVED,
aa06693
+	NUMBER_OF_SIGNALS
aa06693
+};
aa06693
+
aa06693
+static guint sc_security_token_signals[NUMBER_OF_SIGNALS];
aa06693
+
aa06693
+G_DEFINE_TYPE (ScSecurityToken, sc_security_token, G_TYPE_OBJECT);
aa06693
+
aa06693
+static void
aa06693
+sc_security_token_class_init (ScSecurityTokenClass *token_class)
aa06693
+{
aa06693
+    GObjectClass *gobject_class;
aa06693
+
aa06693
+    gobject_class = G_OBJECT_CLASS (token_class);
aa06693
+
aa06693
+    gobject_class->finalize = sc_security_token_finalize;
aa06693
+
aa06693
+    sc_security_token_class_install_signals (token_class);
aa06693
+    sc_security_token_class_install_properties (token_class);
aa06693
+
aa06693
+    g_type_class_add_private (token_class,
aa06693
+			      sizeof (ScSecurityTokenPrivate));
aa06693
+}
aa06693
+
aa06693
+static void
aa06693
+sc_security_token_class_install_signals (ScSecurityTokenClass *token_class)
aa06693
+{
aa06693
+    GObjectClass *object_class;
aa06693
+
aa06693
+    object_class = G_OBJECT_CLASS (token_class);
aa06693
+
aa06693
+    sc_security_token_signals[INSERTED] =
aa06693
+	    g_signal_new ("inserted",
aa06693
+			  G_OBJECT_CLASS_TYPE (object_class),
aa06693
+			  G_SIGNAL_RUN_LAST,
aa06693
+			  G_STRUCT_OFFSET (ScSecurityTokenClass,
aa06693
+					   inserted), 
aa06693
+			  NULL, NULL, g_cclosure_marshal_VOID__VOID, 
aa06693
+			  G_TYPE_NONE, 0);
aa06693
+    token_class->inserted = NULL;
aa06693
+
aa06693
+    sc_security_token_signals[REMOVED] =
aa06693
+	    g_signal_new ("removed",
aa06693
+			  G_OBJECT_CLASS_TYPE (object_class),
aa06693
+			  G_SIGNAL_RUN_LAST,
aa06693
+			  G_STRUCT_OFFSET (ScSecurityTokenClass,
aa06693
+					   removed), 
aa06693
+			  NULL, NULL, g_cclosure_marshal_VOID__VOID, 
aa06693
+			  G_TYPE_NONE, 0);
aa06693
+    token_class->removed = NULL;
aa06693
+}
aa06693
+
aa06693
+static void
aa06693
+sc_security_token_class_install_properties (ScSecurityTokenClass *token_class)
aa06693
+{
aa06693
+    GObjectClass *object_class;
aa06693
+    GParamSpec *param_spec;
aa06693
+
aa06693
+    object_class = G_OBJECT_CLASS (token_class);
aa06693
+    object_class->set_property = sc_security_token_set_property;
aa06693
+    object_class->get_property = sc_security_token_get_property;
aa06693
+
aa06693
+    param_spec = g_param_spec_ulong ("slot-id", _("Slot ID"),
aa06693
+				   _("The slot the token is in"),
aa06693
+				   1, G_MAXULONG,
aa06693
+				   SC_SECURITY_TOKEN_DEFAULT_SLOT_ID,
aa06693
+				   G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
aa06693
+    g_object_class_install_property (object_class, PROP_SLOT_ID, param_spec);
aa06693
+
aa06693
+    param_spec = g_param_spec_int ("slot-series", _("Slot Series"),
aa06693
+				   _("per-slot token identifier"),
aa06693
+				   -1, G_MAXINT,
aa06693
+				   SC_SECURITY_TOKEN_DEFAULT_SLOT_SERIES,
aa06693
+				   G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
aa06693
+    g_object_class_install_property (object_class, PROP_SLOT_SERIES, param_spec);
aa06693
+
aa06693
+    param_spec = g_param_spec_string ("name", _("name"),
aa06693
+				      _("name"), NULL,
aa06693
+				      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
aa06693
+    g_object_class_install_property (object_class, PROP_NAME, param_spec);
aa06693
+
aa06693
+    param_spec = g_param_spec_pointer ("module", _("Module"),
aa06693
+				       _("security token driver"),
aa06693
+				       G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
aa06693
+    g_object_class_install_property (object_class, PROP_MODULE, param_spec);
aa06693
+}
aa06693
+
aa06693
+static void 
aa06693
+sc_security_token_set_property (GObject       *object,
aa06693
+				guint          prop_id,
aa06693
+				const GValue  *value,
aa06693
+				GParamSpec    *pspec)
aa06693
+{
aa06693
+    ScSecurityToken *token = SC_SECURITY_TOKEN (object);
aa06693
+
aa06693
+    switch (prop_id)
aa06693
+    {
aa06693
+	    case PROP_NAME:
aa06693
+		    sc_security_token_set_name (token, g_value_get_string (value));
aa06693
+		    break;
aa06693
+
aa06693
+	    case PROP_SLOT_ID:
aa06693
+		    sc_security_token_set_slot_id (token, 
aa06693
+						   g_value_get_ulong (value));
aa06693
+		    break;
aa06693
+
aa06693
+	    case PROP_SLOT_SERIES:
aa06693
+		    sc_security_token_set_slot_series (token, 
aa06693
+						       g_value_get_int (value));
aa06693
+		    break;
aa06693
+
aa06693
+	    case PROP_MODULE:
aa06693
+		    sc_security_token_set_module (token, 
aa06693
+						  (SECMODModule *)
aa06693
+						  g_value_get_pointer (value));
aa06693
+		    break;
aa06693
+
aa06693
+	    default:
aa06693
+		    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
aa06693
+    }
aa06693
+}
aa06693
+
aa06693
+CK_SLOT_ID
aa06693
+sc_security_token_get_slot_id (ScSecurityToken *token)
aa06693
+{
aa06693
+    return token->priv->slot_id;
aa06693
+}
aa06693
+
aa06693
+ScSecurityTokenState 
aa06693
+sc_security_token_get_state (ScSecurityToken *token)
aa06693
+{
aa06693
+    return token->priv->state;
aa06693
+}
aa06693
+
aa06693
+gchar *
aa06693
+sc_security_token_get_name (ScSecurityToken *token)
aa06693
+{
aa06693
+    return g_strdup (token->priv->name);
aa06693
+}
aa06693
+
aa06693
+gboolean
aa06693
+sc_security_token_is_login_token (ScSecurityToken *token)
aa06693
+{
aa06693
+    const gchar *login_token_name;
aa06693
+    login_token_name = g_getenv ("PKCS11_LOGIN_TOKEN_NAME");
aa06693
+
aa06693
+    if ((login_token_name == NULL) || (token->priv->name == NULL))
aa06693
+	    return FALSE;
aa06693
+
aa06693
+    if (strcmp (token->priv->name, login_token_name) == 0)
aa06693
+	    return TRUE;
aa06693
+
aa06693
+    return FALSE;
aa06693
+}
aa06693
+
aa06693
+static void 
aa06693
+sc_security_token_get_property (GObject    *object,
aa06693
+				guint        prop_id,
aa06693
+				GValue      *value,
aa06693
+				GParamSpec  *pspec)
aa06693
+{
aa06693
+    ScSecurityToken *token = SC_SECURITY_TOKEN (object);
aa06693
+
aa06693
+    switch (prop_id)
aa06693
+    {
aa06693
+	    case PROP_NAME:
aa06693
+		    g_value_take_string (value, 
aa06693
+					 sc_security_token_get_name (token));
aa06693
+		    break;
aa06693
+
aa06693
+	    case PROP_SLOT_ID:
aa06693
+		    g_value_set_ulong (value, 
aa06693
+				       (gulong) sc_security_token_get_slot_id (token));
aa06693
+		    break;
aa06693
+
aa06693
+	    case PROP_SLOT_SERIES:
aa06693
+		    g_value_set_int (value, 
aa06693
+				     sc_security_token_get_slot_series (token));
aa06693
+		    break;
aa06693
+
aa06693
+	    default:
aa06693
+		    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
aa06693
+    }
aa06693
+}
aa06693
+
aa06693
+static void
aa06693
+sc_security_token_set_name (ScSecurityToken *token,
aa06693
+			    const gchar     *name)
aa06693
+{
aa06693
+    if (name == NULL)
aa06693
+	    return;
aa06693
+
aa06693
+    if ((token->priv->name == NULL) ||
aa06693
+	(strcmp (token->priv->name, name) != 0)) {
aa06693
+	    g_free (token->priv->name);
aa06693
+	    token->priv->name = g_strdup (name);
aa06693
+
aa06693
+	    if (token->priv->slot == NULL) {
aa06693
+		    token->priv->slot = sc_security_token_find_slot_from_token_name (token,
aa06693
+										     token->priv->name);
aa06693
+
aa06693
+		    if (token->priv->slot != NULL) {
aa06693
+			    gint slot_id, slot_series;
aa06693
+
aa06693
+			    slot_id = PK11_GetSlotID (token->priv->slot);
aa06693
+			    if (slot_id != token->priv->slot_id)
aa06693
+				    sc_security_token_set_slot_id (token, slot_id);
aa06693
+
aa06693
+			    slot_series = PK11_GetSlotSeries (token->priv->slot);
aa06693
+			    if (slot_series != token->priv->slot_series)
aa06693
+				    sc_security_token_set_slot_series (token, slot_series);
aa06693
+
aa06693
+			    _sc_security_token_set_state (token, SC_SECURITY_TOKEN_STATE_INSERTED);
aa06693
+		    } else {
aa06693
+			    _sc_security_token_set_state (token, SC_SECURITY_TOKEN_STATE_REMOVED);
aa06693
+		    }
aa06693
+	    }
aa06693
+
aa06693
+
aa06693
+	    g_object_notify (G_OBJECT (token), "name");
aa06693
+    }
aa06693
+}
aa06693
+
aa06693
+static void
aa06693
+sc_security_token_set_slot_id (ScSecurityToken *token,
aa06693
+			       gint             slot_id)
aa06693
+{
aa06693
+    if (token->priv->slot_id != slot_id)
aa06693
+    {
aa06693
+	    token->priv->slot_id = slot_id;
aa06693
+
aa06693
+	    if (token->priv->slot == NULL) {
aa06693
+		    token->priv->slot = sc_security_token_find_slot_from_id (token,
aa06693
+									     token->priv->slot_id);
aa06693
+
aa06693
+		    if (token->priv->slot != NULL) {
aa06693
+			    const gchar *token_name;
aa06693
+
aa06693
+			    token_name = PK11_GetTokenName (token->priv->slot);
aa06693
+			    if ((token->priv->name == NULL) || 
aa06693
+				((token_name != NULL) &&
aa06693
+				(strcmp (token_name, token->priv->name) != 0)))
aa06693
+				    sc_security_token_set_name (token, token_name);
aa06693
+
aa06693
+			    _sc_security_token_set_state (token, SC_SECURITY_TOKEN_STATE_INSERTED);
aa06693
+		    } else {
aa06693
+			    _sc_security_token_set_state (token, SC_SECURITY_TOKEN_STATE_REMOVED);
aa06693
+		    }
aa06693
+	    }
aa06693
+
aa06693
+	    g_object_notify (G_OBJECT (token), "slot-id");
aa06693
+    }
aa06693
+}
aa06693
+
aa06693
+static void
aa06693
+sc_security_token_set_slot_series (ScSecurityToken *token,
aa06693
+				   gint             slot_series)
aa06693
+{
aa06693
+    if (token->priv->slot_series != slot_series)
aa06693
+    {
aa06693
+	    token->priv->slot_series = slot_series;
aa06693
+	    g_object_notify (G_OBJECT (token), "slot-series");
aa06693
+    }
aa06693
+}
aa06693
+
aa06693
+static void
aa06693
+sc_security_token_set_module (ScSecurityToken *token,
aa06693
+			      SECMODModule    *module)
aa06693
+{
aa06693
+    gboolean should_notify;
aa06693
+
aa06693
+    if (token->priv->module != module)
aa06693
+	    should_notify = TRUE;
aa06693
+    else
aa06693
+	    should_notify = FALSE;
aa06693
+
aa06693
+    if (token->priv->module != NULL) {
aa06693
+	    SECMOD_DestroyModule (token->priv->module);
aa06693
+	    token->priv->module = NULL;
aa06693
+    }
aa06693
+
aa06693
+    if (module != NULL)
aa06693
+	    token->priv->module = SECMOD_ReferenceModule (module);
aa06693
+
aa06693
+    if (should_notify)
aa06693
+	    g_object_notify (G_OBJECT (token), "module");
aa06693
+}
aa06693
+
aa06693
+gint 
aa06693
+sc_security_token_get_slot_series (ScSecurityToken *token)
aa06693
+{
aa06693
+    return token->priv->slot_series;
aa06693
+}
aa06693
+
aa06693
+static void
aa06693
+sc_security_token_init (ScSecurityToken *token)
aa06693
+{
aa06693
+
aa06693
+    sc_debug ("initializing security token ");
aa06693
+
aa06693
+    token->priv = G_TYPE_INSTANCE_GET_PRIVATE (token,
aa06693
+					       SC_TYPE_SECURITY_TOKEN,
aa06693
+					       ScSecurityTokenPrivate);
aa06693
+
aa06693
+    if (token->priv->slot != NULL)
aa06693
+	    token->priv->name = g_strdup (PK11_GetTokenName (token->priv->slot));
aa06693
+}
aa06693
+
aa06693
+static void sc_security_token_finalize (GObject *object)
aa06693
+{
aa06693
+    ScSecurityToken *token;
aa06693
+    GObjectClass *gobject_class;
aa06693
+
aa06693
+    token = SC_SECURITY_TOKEN (object);
aa06693
+
aa06693
+    g_free (token->priv->name);
aa06693
+
aa06693
+    sc_security_token_set_module (token, NULL);
aa06693
+
aa06693
+    gobject_class =
aa06693
+	    G_OBJECT_CLASS (sc_security_token_parent_class);
aa06693
+
aa06693
+    gobject_class->finalize (object);
aa06693
+}
aa06693
+
aa06693
+GQuark sc_security_token_error_quark (void)
aa06693
+{
aa06693
+    static GQuark error_quark = 0;
aa06693
+
aa06693
+    if (error_quark == 0)
aa06693
+	    error_quark = g_quark_from_static_string ("sc-security-token-error-quark");
aa06693
+
aa06693
+    return error_quark;
aa06693
+}
aa06693
+
aa06693
+ScSecurityToken *
aa06693
+_sc_security_token_new (SECMODModule *module,
aa06693
+			CK_SLOT_ID    slot_id,
aa06693
+			gint          slot_series)
aa06693
+{
aa06693
+    ScSecurityToken *token;
aa06693
+
aa06693
+    g_return_val_if_fail (module != NULL, NULL);
aa06693
+    g_return_val_if_fail (slot_id >= 1, NULL);
aa06693
+    g_return_val_if_fail (slot_series > 0, NULL);
aa06693
+    g_return_val_if_fail (sizeof (gulong) == sizeof (slot_id), NULL);
aa06693
+
aa06693
+    token = SC_SECURITY_TOKEN (g_object_new (SC_TYPE_SECURITY_TOKEN,
aa06693
+					     "module", module,
aa06693
+					     "slot-id", (gulong) slot_id,
aa06693
+					     "slot-series", slot_series,
aa06693
+					     NULL));
aa06693
+    return token;
aa06693
+}
aa06693
+
aa06693
+ScSecurityToken *
aa06693
+_sc_security_token_new_from_name (SECMODModule *module,
aa06693
+				  const gchar  *name)
aa06693
+{
aa06693
+    ScSecurityToken *token;
aa06693
+
aa06693
+    g_return_val_if_fail (module != NULL, NULL);
aa06693
+    g_return_val_if_fail (name != NULL, NULL);
aa06693
+
aa06693
+    token = SC_SECURITY_TOKEN (g_object_new (SC_TYPE_SECURITY_TOKEN,
aa06693
+					     "module", module,
aa06693
+					     "name", name,
aa06693
+					     NULL));
aa06693
+    return token;
aa06693
+}
aa06693
+
aa06693
+void 
aa06693
+_sc_security_token_set_state (ScSecurityToken      *token,
aa06693
+			      ScSecurityTokenState  state)
aa06693
+{
aa06693
+    /* sc_security_token_fetch_certificates (token); */
aa06693
+    if (token->priv->state != state)
aa06693
+    {
aa06693
+	    token->priv->state = state;
aa06693
+
aa06693
+	    if (state == SC_SECURITY_TOKEN_STATE_INSERTED) {
aa06693
+		    g_signal_emit (token, sc_security_token_signals[INSERTED], 0);
aa06693
+	    } else if (state == SC_SECURITY_TOKEN_STATE_REMOVED)
aa06693
+		    g_signal_emit (token, sc_security_token_signals[REMOVED], 0);
aa06693
+	    else
aa06693
+		    g_assert_not_reached ();
aa06693
+    }
aa06693
+}
aa06693
+
aa06693
+/* So we could conceivably make the closure data a pointer to the token
aa06693
+ * or something similiar and then emit signals when we want passwords,
aa06693
+ * but it's probably easier to just get the password up front and use
aa06693
+ * it.  So we just take the passed in g_malloc'd (well probably, who knows)
aa06693
+ * and strdup it using NSPR's memory allocation routines.
aa06693
+ */
aa06693
+static char *
aa06693
+sc_security_token_password_handler (PK11SlotInfo *slot, 
aa06693
+				    PRBool        is_retrying, 
aa06693
+				    const gchar  *password)
aa06693
+{
aa06693
+    if (is_retrying)
aa06693
+	    return NULL;
aa06693
+
aa06693
+    return password != NULL? PL_strdup (password): NULL;
aa06693
+}
aa06693
+
aa06693
+gboolean
aa06693
+sc_security_token_unlock (ScSecurityToken *token,
aa06693
+			  const gchar     *password)
aa06693
+{   
aa06693
+    SECStatus status;
aa06693
+
aa06693
+    PK11_SetPasswordFunc ((PK11PasswordFunc) sc_security_token_password_handler);
aa06693
+
aa06693
+    /* we pass PR_TRUE to load certificates
aa06693
+     */
aa06693
+    status = PK11_Authenticate (token->priv->slot, PR_TRUE, (gpointer) password);
aa06693
+
aa06693
+    if (status != SECSuccess) {
aa06693
+	    sc_debug ("could not unlock token - %d", status);
aa06693
+	    return FALSE;
aa06693
+    }
aa06693
+    return TRUE;
aa06693
+}
aa06693
+
aa06693
+static PK11SlotInfo *
aa06693
+sc_security_token_find_slot_from_token_name (ScSecurityToken *token,
aa06693
+					     const gchar     *token_name)
aa06693
+{
aa06693
+    int i;
aa06693
+
aa06693
+    for (i = 0; i < token->priv->module->slotCount; i++) {
aa06693
+	    const gchar *slot_token_name;
aa06693
+
aa06693
+	    slot_token_name = PK11_GetTokenName (token->priv->module->slots[i]);
aa06693
+
aa06693
+	    if ((slot_token_name != NULL) &&
aa06693
+		(strcmp (slot_token_name, token_name) == 0))
aa06693
+		    return token->priv->module->slots[i];
aa06693
+    }
aa06693
+
aa06693
+    return NULL;
aa06693
+}
aa06693
+
aa06693
+static PK11SlotInfo *
aa06693
+sc_security_token_find_slot_from_id (ScSecurityToken *token,
aa06693
+                                     gint slot_id)
aa06693
+{
aa06693
+    int i;
aa06693
+
aa06693
+    for (i = 0; i < token->priv->module->slotCount; i++)
aa06693
+	    if (PK11_GetSlotID (token->priv->module->slots[i]) == slot_id)
aa06693
+		    return token->priv->module->slots[i];
aa06693
+
aa06693
+    return NULL;
aa06693
+}
aa06693
+
aa06693
+static gboolean
aa06693
+sc_security_token_fetch_certificates (ScSecurityToken *token)
aa06693
+{
aa06693
+    PK11SlotInfo *slot;
aa06693
+    CERTCertList *certificates;
aa06693
+    CERTCertListNode *node;
aa06693
+    SECStatus status;
aa06693
+    int i;
aa06693
+
aa06693
+    sc_security_token_unlock (token, "0000");
aa06693
+
aa06693
+    sc_debug ("fetching certificates for token in slot %lu",
aa06693
+	      token->priv->slot_id);
aa06693
+
aa06693
+    slot = sc_security_token_find_slot_from_id (token,
aa06693
+						token->priv->slot_id);
aa06693
+
aa06693
+    g_assert (PK11_GetSlotID (slot) == token->priv->slot_id);
aa06693
+
aa06693
+    if (i == token->priv->module->slotCount) {
aa06693
+	    sc_debug ("could not find slot %lu", token->priv->slot_id);
aa06693
+	    return FALSE;
aa06693
+    }
aa06693
+
aa06693
+    certificates = PK11_ListCertsInSlot (slot);
aa06693
+
aa06693
+    sc_debug ("filtering out non-user certificates");
aa06693
+    if (CERT_FilterCertListForUserCerts (certificates) != SECSuccess) {
aa06693
+	    CERT_DestroyCertList (certificates);
aa06693
+	    sc_debug ("could not filter out non-user certificates");
aa06693
+	    return FALSE;
aa06693
+    }
aa06693
+
aa06693
+    for (node = CERT_LIST_HEAD (certificates); 
aa06693
+	 !CERT_LIST_END (node, certificates);
aa06693
+	 node = CERT_LIST_NEXT(node)) {
aa06693
+
aa06693
+	    SECCertificateUsage cert_usages;
aa06693
+
aa06693
+	    sc_debug ("verifying certificate for use");
aa06693
+	    status = CERT_VerifyCertificateNow (NULL, node->cert, TRUE, 
aa06693
+						0, NULL, &cert_usages);
aa06693
+
aa06693
+	    if (status != SECSuccess) {
aa06693
+		    sc_debug ("could not be verified, skipping...");
aa06693
+		    continue;
aa06693
+	    }
aa06693
+
aa06693
+	    sc_debug ("got cert with usages 0x%lx", (gulong) cert_usages);
aa06693
+
aa06693
+	    if (token->priv->encryption_certificate == NULL) {
aa06693
+
aa06693
+		    sc_debug ("checking if certificate can be used for data "
aa06693
+			      "encryption");
aa06693
+		    status = CERT_CheckCertUsage (node->cert, 
aa06693
+						  KU_DATA_ENCIPHERMENT);
aa06693
+
aa06693
+		    if (status == SECSuccess) {
aa06693
+			    token->priv->encryption_certificate = 
aa06693
+				    CERT_DupCertificate (node->cert);
aa06693
+		    } else {
aa06693
+			    sc_debug ("certificate can not be used for encryption");
aa06693
+		    }
aa06693
+	    }
aa06693
+
aa06693
+	    if (token->priv->signing_certificate == NULL) {
aa06693
+
aa06693
+		    sc_debug ("checking if certificate can be used for data "
aa06693
+			      "signing");
aa06693
+		    status = CERT_CheckCertUsage (node->cert, 
aa06693
+						  KU_DIGITAL_SIGNATURE);
aa06693
+
aa06693
+		    if (status == SECSuccess) {
aa06693
+			    token->priv->signing_certificate = 
aa06693
+				    CERT_DupCertificate (node->cert);
aa06693
+		    } else {
aa06693
+			    sc_debug ("certificate can not be used for signing things");
aa06693
+		    }
aa06693
+	    }
aa06693
+    }
aa06693
+    return TRUE;
aa06693
+}
aa06693
+
aa06693
+#ifdef SC_SECURITY_TOKEN_ENABLE_TEST
aa06693
+#include <glib.h>
aa06693
+
aa06693
+static GMainLoop *event_loop;
aa06693
+
aa06693
+int 
aa06693
+main (int   argc, 
aa06693
+      char *argv[])
aa06693
+{
aa06693
+    ScSecurityToken *token;
aa06693
+    GError *error;
aa06693
+
aa06693
+    g_log_set_always_fatal (G_LOG_LEVEL_ERROR
aa06693
+			    | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING);
aa06693
+
aa06693
+    g_type_init ();
aa06693
+
aa06693
+    g_message ("creating instance of 'security token' object...");
aa06693
+    token = _sc_security_token_new (NULL, 1, 1);
aa06693
+    g_message ("'security token' object created successfully");
aa06693
+
aa06693
+    g_message ("destroying previously created 'security token' object...");
aa06693
+    g_object_unref (token);
aa06693
+    token = NULL;
aa06693
+    g_message ("'security token' object destroyed successfully");
aa06693
+
aa06693
+    return 0;
aa06693
+}
aa06693
+#endif
aa06693
diff -up /dev/null gnome-screensaver-2.26.0/src/securitytoken.h
aa06693
--- /dev/null	2009-03-18 22:51:48.055015100 -0400
6d5f864
+++ gnome-screensaver-2.26.0/src/securitytoken.h	2009-03-19 00:20:36.638249327 -0400
aa06693
@@ -0,0 +1,94 @@
aa06693
+/* securitytoken.h - api for reading and writing data to a security token 
aa06693
+ *
aa06693
+ * Copyright (C) 2006 Ray Strode
aa06693
+ *
aa06693
+ * This program is free software; you can redistribute it and/or modify
aa06693
+ * it under the terms of the GNU General Public License as published by
aa06693
+ * the Free Software Foundation; either version 2, or (at your option)
aa06693
+ * any later version.
aa06693
+ *
aa06693
+ * This program is distributed in the hope that it will be useful,
aa06693
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
aa06693
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
aa06693
+ * GNU General Public License for more details.
aa06693
+ *
aa06693
+ * You should have received a copy of the GNU General Public License
aa06693
+ * along with this program; if not, write to the Free Software
aa06693
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
aa06693
+ * 02111-1307, USA.  
aa06693
+ */
aa06693
+#ifndef SC_SECURITY_TOKEN_H
aa06693
+#define SC_SECURITY_TOKEN_H
aa06693
+
aa06693
+#include <glib.h>
aa06693
+#include <glib-object.h>
aa06693
+
aa06693
+#include <secmod.h>
aa06693
+
aa06693
+G_BEGIN_DECLS
aa06693
+#define SC_TYPE_SECURITY_TOKEN            (sc_security_token_get_type ())
aa06693
+#define SC_SECURITY_TOKEN(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), SC_TYPE_SECURITY_TOKEN, ScSecurityToken))
aa06693
+#define SC_SECURITY_TOKEN_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), SC_TYPE_SECURITY_TOKEN, ScSecurityTokenClass))
aa06693
+#define SC_IS_SECURITY_TOKEN(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SC_TYPE_SECURITY_TOKEN))
aa06693
+#define SC_IS_SECURITY_TOKEN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SC_TYPE_SECURITY_TOKEN))
aa06693
+#define SC_SECURITY_TOKEN_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), SC_TYPE_SECURITY_TOKEN, ScSecurityTokenClass))
aa06693
+#define SC_SECURITY_TOKEN_ERROR           (sc_security_token_error_quark ())
aa06693
+typedef struct _ScSecurityTokenClass ScSecurityTokenClass;
aa06693
+typedef struct _ScSecurityToken ScSecurityToken;
aa06693
+typedef struct _ScSecurityTokenPrivate ScSecurityTokenPrivate;
aa06693
+typedef enum _ScSecurityTokenError ScSecurityTokenError;
aa06693
+typedef enum _ScSecurityTokenState ScSecurityTokenState;
aa06693
+
aa06693
+typedef struct _ScSecurityTokenRequest ScSecurityTokenRequest;
aa06693
+
aa06693
+struct _ScSecurityToken {
aa06693
+    GObject parent;
aa06693
+
aa06693
+    /*< private > */
aa06693
+    ScSecurityTokenPrivate *priv;
aa06693
+};
aa06693
+
aa06693
+struct _ScSecurityTokenClass {
aa06693
+    GObjectClass parent_class;
aa06693
+
aa06693
+    void (* inserted) (ScSecurityToken *token);
aa06693
+    void (* removed) (ScSecurityToken *token);
aa06693
+};
aa06693
+
aa06693
+enum _ScSecurityTokenError {
aa06693
+    SC_SECURITY_TOKEN_ERROR_GENERIC = 0,
aa06693
+};
aa06693
+
aa06693
+enum _ScSecurityTokenState {
aa06693
+    SC_SECURITY_TOKEN_STATE_INSERTED = 0,
aa06693
+    SC_SECURITY_TOKEN_STATE_REMOVED,
aa06693
+};
aa06693
+
aa06693
+GType sc_security_token_get_type (void) G_GNUC_CONST;
aa06693
+GQuark sc_security_token_error_quark (void) G_GNUC_CONST;
aa06693
+
aa06693
+CK_SLOT_ID sc_security_token_get_slot_id (ScSecurityToken *token);
aa06693
+gint sc_security_token_get_slot_series (ScSecurityToken *token);
aa06693
+ScSecurityTokenState sc_security_token_get_state (ScSecurityToken *token);
aa06693
+
aa06693
+gchar *sc_security_token_get_name (ScSecurityToken *token);
aa06693
+gboolean sc_security_token_is_login_token (ScSecurityToken *token);
aa06693
+
aa06693
+gboolean sc_security_token_unlock (ScSecurityToken *token,
aa06693
+				   const gchar     *password);
aa06693
+
aa06693
+/* don't under any circumstances call these functions */
aa06693
+#ifdef SC_SECURITY_TOKEN_ENABLE_INTERNAL_API
aa06693
+
aa06693
+ScSecurityToken *_sc_security_token_new (SECMODModule *module,
aa06693
+					 CK_SLOT_ID slot_id, 
aa06693
+					 gint slot_series);
aa06693
+ScSecurityToken *_sc_security_token_new_from_name (SECMODModule *module,
aa06693
+						   const gchar *name);
aa06693
+
aa06693
+void _sc_security_token_set_state (ScSecurityToken      *token,
aa06693
+				   ScSecurityTokenState  state);
aa06693
+#endif 
aa06693
+
aa06693
+G_END_DECLS
aa06693
+#endif				/* SC_SECURITY_TOKEN_H */
aa06693
diff -up /dev/null gnome-screensaver-2.26.0/src/securitytokenmonitor.c
aa06693
--- /dev/null	2009-03-18 22:51:48.055015100 -0400
6d5f864
+++ gnome-screensaver-2.26.0/src/securitytokenmonitor.c	2009-03-19 00:20:36.641220270 -0400
aa06693
@@ -0,0 +1,1743 @@
aa06693
+/* securitytokenmonitor.c - monitor for security token insertion and
aa06693
+ *                          removal events
aa06693
+ * 
aa06693
+ * Copyright (C) 2006 Ray Strode <rstrode@redhat.com>
aa06693
+ * 
aa06693
+ * This program is free software; you can redistribute it and/or modify
aa06693
+ * it under the terms of the GNU General Public License as published by
aa06693
+ * the Free Software Foundation; either version 2, or (at your option)
aa06693
+ * any later version.
aa06693
+ * 
aa06693
+ * This program is distributed in the hope that it will be useful,
aa06693
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
aa06693
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
aa06693
+ * GNU General Public License for more details.
aa06693
+ * 
aa06693
+ * You should have received a copy of the GNU General Public License
aa06693
+ * along with this program; if not, write to the Free Software
aa06693
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
aa06693
+ * 02111-1307, USA.  
aa06693
+ *
aa06693
+ * TODO:     - doing this per project is a bad idea i think.
aa06693
+ *             We should probably make this a system service 
aa06693
+ *             and use dbus.
aa06693
+ */
aa06693
+#define _GNU_SOURCE
aa06693
+#include "securitytokenmonitor.h"
aa06693
+
aa06693
+#define SC_SECURITY_TOKEN_ENABLE_INTERNAL_API
aa06693
+#include "securitytoken.h"
aa06693
+
aa06693
+#include <dirent.h>
aa06693
+#include <errno.h>
aa06693
+#include <fcntl.h>
aa06693
+#include <limits.h>
aa06693
+#include <poll.h>
aa06693
+#include <signal.h>
aa06693
+#include <stdlib.h>
aa06693
+#include <string.h>
aa06693
+#include <sys/resource.h>
aa06693
+#include <sys/time.h>
aa06693
+#include <sys/wait.h>
aa06693
+#include <unistd.h>
aa06693
+
aa06693
+#include <glib.h>
aa06693
+#include <glib/gi18n.h>
aa06693
+
aa06693
+#include <prerror.h>
aa06693
+#include <nss.h>
aa06693
+#include <pk11func.h>
aa06693
+#include <secmod.h>
aa06693
+#include <secerr.h>
aa06693
+
aa06693
+#ifndef SC_SECURITY_TOKEN_MONITOR_DRIVER
aa06693
+#define SC_SECURITY_TOKEN_MONITOR_DRIVER LIBDIR"/pkcs11/libcoolkeypk11.so"
aa06693
+#endif
aa06693
+
aa06693
+#ifndef SC_SECURITY_TOKEN_MONITOR_NSS_DB
aa06693
+#define SC_SECURITY_TOKEN_MONITOR_NSS_DB SYSCONFDIR"/pki/nssdb"
aa06693
+#endif 
aa06693
+
aa06693
+#ifndef SC_MAX_OPEN_FILE_DESCRIPTORS
aa06693
+#define SC_MAX_OPEN_FILE_DESCRIPTORS 1024
aa06693
+#endif
aa06693
+
aa06693
+#ifndef SC_OPEN_FILE_DESCRIPTORS_DIR
aa06693
+#define SC_OPEN_FILE_DESCRIPTORS_DIR "/proc/self/fd"
aa06693
+#endif
aa06693
+
aa06693
+#ifndef sc_debug
aa06693
+#if defined (SC_SECURITY_TOKEN_MONITOR_ENABLE_TEST)
aa06693
+#define sc_debug(fmt, args...) g_printerr("[%u] " fmt " \n", getpid(), ##args)
aa06693
+#else
aa06693
+#define sc_debug(fmt, args...) 
aa06693
+#endif
aa06693
+#endif
aa06693
+
aa06693
+typedef enum _ScSecurityTokenMonitorState ScSecurityTokenMonitorState;
aa06693
+typedef struct _ScSecurityTokenMonitorWorker ScSecurityTokenMonitorWorker;
aa06693
+
aa06693
+enum _ScSecurityTokenMonitorState {
aa06693
+	SC_SECURITY_TOKEN_MONITOR_STATE_STOPPED = 0,
aa06693
+	SC_SECURITY_TOKEN_MONITOR_STATE_STARTING,
aa06693
+	SC_SECURITY_TOKEN_MONITOR_STATE_STARTED,
aa06693
+	SC_SECURITY_TOKEN_MONITOR_STATE_STOPPING,
aa06693
+};
aa06693
+
aa06693
+struct _ScSecurityTokenMonitorPrivate {
aa06693
+	ScSecurityTokenMonitorState state;
aa06693
+	SECMODModule *module;
aa06693
+	gchar        *module_path;
aa06693
+
aa06693
+	GSource *security_token_event_source;
aa06693
+	GPid security_token_event_watcher_pid;
aa06693
+	GHashTable *security_tokens;
aa06693
+
aa06693
+	guint poll_timeout_id;
aa06693
+
aa06693
+	guint32 is_unstoppable : 1;
aa06693
+	guint32 nss_is_loaded : 1;
aa06693
+
aa06693
+#ifndef SC_SECURITY_TOKEN_MONITOR_DRIVER_CAN_BE_RELOADED_AFTER_BEING_DESTROYED
aa06693
+	GArray *fds_to_close_on_fork;
aa06693
+#endif 
aa06693
+};
aa06693
+
aa06693
+struct _ScSecurityTokenMonitorWorker {
aa06693
+	SECMODModule *module;
aa06693
+	GHashTable *security_tokens;
aa06693
+	gint write_fd;
aa06693
+
aa06693
+	guint32 nss_is_loaded : 1;
aa06693
+};
aa06693
+
aa06693
+static void sc_security_token_monitor_finalize (GObject *object);
aa06693
+static void sc_security_token_monitor_class_install_signals (ScSecurityTokenMonitorClass *service_class);
aa06693
+static void sc_security_token_monitor_class_install_properties (ScSecurityTokenMonitorClass *service_class);
aa06693
+static void sc_security_token_monitor_set_property (GObject       *object,
aa06693
+						    guint          prop_id,
aa06693
+						    const GValue  *value,
aa06693
+						    GParamSpec    *pspec);
aa06693
+static void sc_security_token_monitor_get_property (GObject    *object,
aa06693
+						    guint       prop_id,
aa06693
+						    GValue     *value,
aa06693
+						    GParamSpec *pspec);
aa06693
+static void sc_security_token_monitor_set_module_path (ScSecurityTokenMonitor *monitor,
aa06693
+						       const gchar            *module_path);
aa06693
+static void sc_security_token_monitor_token_removed_handler (ScSecurityTokenMonitor *monitor,
aa06693
+							     ScSecurityToken        *token);
aa06693
+static void sc_security_token_monitor_token_inserted_handler (ScSecurityTokenMonitor *monitor_class,
aa06693
+							      ScSecurityToken        *token);
aa06693
+static gboolean sc_security_token_monitor_stop_now (ScSecurityTokenMonitor *monitor);
aa06693
+static void sc_security_token_monitor_queue_stop (ScSecurityTokenMonitor *monitor);
aa06693
+
aa06693
+static gboolean sc_security_token_monitor_create_worker (ScSecurityTokenMonitor *monitor,
aa06693
+							 gint *worker_fd, GPid *worker_pid);
aa06693
+
aa06693
+static ScSecurityTokenMonitorWorker * sc_security_token_monitor_worker_new (gint write_fd);
aa06693
+static void sc_security_token_monitor_worker_free (ScSecurityTokenMonitorWorker *worker);
aa06693
+static void sc_security_token_monitor_worker_die_with_parent (ScSecurityTokenMonitorWorker *worker);
aa06693
+static gboolean sc_open_pipe (gint *write_fd, gint *read_fd);
aa06693
+static gboolean sc_read_bytes (gint fd, gpointer bytes, gsize num_bytes);
aa06693
+static gboolean sc_write_bytes (gint fd, gconstpointer bytes, gsize num_bytes);
aa06693
+static ScSecurityToken *sc_read_security_token (gint fd, SECMODModule *module);
aa06693
+static gboolean sc_write_security_token (gint fd, ScSecurityToken *token);
aa06693
+
aa06693
+enum {
aa06693
+	PROP_0 = 0,
aa06693
+	PROP_MODULE_PATH,
aa06693
+	NUMBER_OF_PROPERTIES
aa06693
+};
aa06693
+
aa06693
+enum {
aa06693
+	SECURITY_TOKEN_INSERTED = 0,
aa06693
+	SECURITY_TOKEN_REMOVED,
aa06693
+	ERROR,
aa06693
+	NUMBER_OF_SIGNALS
aa06693
+};
aa06693
+
aa06693
+static guint sc_security_token_monitor_signals[NUMBER_OF_SIGNALS];
aa06693
+
aa06693
+G_DEFINE_TYPE (ScSecurityTokenMonitor, 
aa06693
+	       sc_security_token_monitor, 
aa06693
+	       G_TYPE_OBJECT);
aa06693
+
aa06693
+static void
aa06693
+sc_security_token_monitor_class_init (ScSecurityTokenMonitorClass *monitor_class)
aa06693
+{
aa06693
+    GObjectClass *gobject_class;
aa06693
+
aa06693
+    gobject_class = G_OBJECT_CLASS (monitor_class);
aa06693
+
aa06693
+    gobject_class->finalize = sc_security_token_monitor_finalize;
aa06693
+
aa06693
+    sc_security_token_monitor_class_install_signals (monitor_class);
aa06693
+    sc_security_token_monitor_class_install_properties (monitor_class);
aa06693
+
aa06693
+    g_type_class_add_private (monitor_class,
aa06693
+			      sizeof (ScSecurityTokenMonitorPrivate));
aa06693
+}
aa06693
+
aa06693
+static void
aa06693
+sc_security_token_monitor_class_install_properties (ScSecurityTokenMonitorClass *token_class)
aa06693
+{
aa06693
+    GObjectClass *object_class;
aa06693
+    GParamSpec *param_spec;
aa06693
+
aa06693
+    object_class = G_OBJECT_CLASS (token_class);
aa06693
+    object_class->set_property = sc_security_token_monitor_set_property;
aa06693
+    object_class->get_property = sc_security_token_monitor_get_property;
aa06693
+
aa06693
+    param_spec = g_param_spec_string ("module-path", _("Module Path"),
aa06693
+				      _("path to security token PKCS #11 driver"),
aa06693
+				      NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
aa06693
+    g_object_class_install_property (object_class, PROP_MODULE_PATH, param_spec);
aa06693
+}
aa06693
+
aa06693
+static void 
aa06693
+sc_security_token_monitor_set_property (GObject       *object,
aa06693
+					guint          prop_id,
aa06693
+					const GValue  *value,
aa06693
+					GParamSpec    *pspec)
aa06693
+{
aa06693
+    ScSecurityTokenMonitor *monitor = SC_SECURITY_TOKEN_MONITOR (object);
aa06693
+
aa06693
+    switch (prop_id)
aa06693
+    {
aa06693
+	    case PROP_MODULE_PATH:
aa06693
+		    sc_security_token_monitor_set_module_path (monitor, 
aa06693
+							       g_value_get_string (value));
aa06693
+		    break;
aa06693
+
aa06693
+	    default:
aa06693
+		    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
aa06693
+		    break;
aa06693
+    }
aa06693
+}
aa06693
+
aa06693
+static void 
aa06693
+sc_security_token_monitor_get_property (GObject    *object,
aa06693
+					guint       prop_id,
aa06693
+					GValue     *value,
aa06693
+					GParamSpec *pspec)
aa06693
+{
aa06693
+    ScSecurityTokenMonitor *monitor = SC_SECURITY_TOKEN_MONITOR (object);
aa06693
+    gchar *module_path;
aa06693
+
aa06693
+    switch (prop_id)
aa06693
+    {
aa06693
+	    case PROP_MODULE_PATH:
aa06693
+		    module_path = sc_security_token_monitor_get_module_path (monitor);
aa06693
+		    g_value_set_string (value, module_path);
aa06693
+		    g_free (module_path);
aa06693
+		    break;
aa06693
+
aa06693
+	    default:
aa06693
+		    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
aa06693
+		    break;
aa06693
+    }
aa06693
+}
aa06693
+
aa06693
+gchar *
aa06693
+sc_security_token_monitor_get_module_path (ScSecurityTokenMonitor *monitor)
aa06693
+{
aa06693
+    return monitor->priv->module_path;
aa06693
+}
aa06693
+
aa06693
+static void
aa06693
+sc_security_token_monitor_set_module_path (ScSecurityTokenMonitor *monitor,
aa06693
+					   const gchar            *module_path)
aa06693
+{
aa06693
+    if ((monitor->priv->module_path == NULL) && (module_path == NULL))
aa06693
+	    return;
aa06693
+
aa06693
+    if (((monitor->priv->module_path == NULL) ||
aa06693
+	 (module_path == NULL) ||
aa06693
+	 (strcmp (monitor->priv->module_path, module_path) != 0))) {
aa06693
+	    g_free (monitor->priv->module_path);
aa06693
+	    monitor->priv->module_path = g_strdup (module_path);
aa06693
+	    g_object_notify (G_OBJECT (monitor), "module-path");
aa06693
+    }
aa06693
+}
aa06693
+
aa06693
+static void
aa06693
+sc_security_token_monitor_token_removed_handler (ScSecurityTokenMonitor *monitor,
aa06693
+						 ScSecurityToken        *token)
aa06693
+{
aa06693
+    sc_debug ("informing security token of its removal");
aa06693
+    _sc_security_token_set_state (token, SC_SECURITY_TOKEN_STATE_REMOVED);
aa06693
+    sc_debug ("done");
aa06693
+}
aa06693
+
aa06693
+static void
aa06693
+sc_security_token_monitor_token_inserted_handler (ScSecurityTokenMonitor *monitor,
aa06693
+						  ScSecurityToken        *token)
aa06693
+{
aa06693
+    sc_debug ("informing security token of its insertion");
aa06693
+
aa06693
+    _sc_security_token_set_state (token, SC_SECURITY_TOKEN_STATE_INSERTED);
aa06693
+    sc_debug ("done");
aa06693
+
aa06693
+}
aa06693
+
aa06693
+static void
aa06693
+sc_security_token_monitor_class_install_signals (ScSecurityTokenMonitorClass *monitor_class)
aa06693
+{
aa06693
+    GObjectClass *object_class;
aa06693
+
aa06693
+    object_class = G_OBJECT_CLASS (monitor_class);
aa06693
+
aa06693
+    sc_security_token_monitor_signals[SECURITY_TOKEN_INSERTED] =
aa06693
+	    g_signal_new ("security-token-inserted",
aa06693
+			  G_OBJECT_CLASS_TYPE (object_class),
aa06693
+			  G_SIGNAL_RUN_FIRST,
aa06693
+			  G_STRUCT_OFFSET (ScSecurityTokenMonitorClass,
aa06693
+					   security_token_inserted), 
aa06693
+			  NULL, NULL, g_cclosure_marshal_VOID__POINTER, 
aa06693
+			  G_TYPE_NONE, 1, G_TYPE_POINTER);
aa06693
+    monitor_class->security_token_inserted = sc_security_token_monitor_token_inserted_handler;
aa06693
+
aa06693
+    sc_security_token_monitor_signals[SECURITY_TOKEN_REMOVED] =
aa06693
+	    g_signal_new ("security-token-removed",
aa06693
+			  G_OBJECT_CLASS_TYPE (object_class),
aa06693
+			  G_SIGNAL_RUN_FIRST,
aa06693
+			  G_STRUCT_OFFSET (ScSecurityTokenMonitorClass,
aa06693
+					   security_token_removed), 
aa06693
+			  NULL, NULL, g_cclosure_marshal_VOID__POINTER, 
aa06693
+			  G_TYPE_NONE, 1, G_TYPE_POINTER);
aa06693
+    monitor_class->security_token_removed = sc_security_token_monitor_token_removed_handler;
aa06693
+
aa06693
+    sc_security_token_monitor_signals[ERROR] =
aa06693
+	    g_signal_new ("error",
aa06693
+			  G_OBJECT_CLASS_TYPE (object_class),
aa06693
+			  G_SIGNAL_RUN_LAST,
aa06693
+			  G_STRUCT_OFFSET (ScSecurityTokenMonitorClass, error),
aa06693
+			  NULL, NULL, g_cclosure_marshal_VOID__POINTER,
aa06693
+			  G_TYPE_NONE, 1, G_TYPE_POINTER);
aa06693
+    monitor_class->error = NULL;
aa06693
+}
aa06693
+
aa06693
+static gboolean
aa06693
+sc_slot_id_equal (CK_SLOT_ID *slot_id_1, 
aa06693
+		  CK_SLOT_ID *slot_id_2)
aa06693
+{
aa06693
+    g_assert (slot_id_1 != NULL);
aa06693
+    g_assert (slot_id_2 != NULL);
aa06693
+
aa06693
+    return *slot_id_1 == *slot_id_2;
aa06693
+}
aa06693
+
aa06693
+static gboolean
aa06693
+sc_slot_id_hash (CK_SLOT_ID *slot_id) 
aa06693
+{
aa06693
+    guint32 upper_bits, lower_bits;
aa06693
+    gint temp;
aa06693
+
aa06693
+    if (sizeof (CK_SLOT_ID) == sizeof (gint))
aa06693
+	    return g_int_hash (slot_id);
aa06693
+
aa06693
+    upper_bits = ((*slot_id) >> 31) - 1;
aa06693
+    lower_bits = (*slot_id) & 0xffffffff;
aa06693
+
aa06693
+    /* The upper bits are almost certainly always zero,
aa06693
+     * so let's degenerate to g_int_hash for the 
aa06693
+     * (very) common case
aa06693
+     */
aa06693
+    temp = lower_bits + upper_bits;
aa06693
+    return upper_bits + g_int_hash (&temp);
aa06693
+}
aa06693
+
aa06693
+static void
aa06693
+sc_security_token_monitor_init (ScSecurityTokenMonitor *monitor)
aa06693
+{
aa06693
+    sc_debug ("initializing security token monitor");
aa06693
+
aa06693
+    monitor->priv = G_TYPE_INSTANCE_GET_PRIVATE (monitor,
aa06693
+						 SC_TYPE_SECURITY_TOKEN_MONITOR,
aa06693
+						 ScSecurityTokenMonitorPrivate);
aa06693
+    monitor->priv->poll_timeout_id = 0;
aa06693
+    monitor->priv->is_unstoppable = FALSE;
aa06693
+    monitor->priv->module = NULL;
aa06693
+
aa06693
+    monitor->priv->security_tokens = 
aa06693
+	    g_hash_table_new_full (g_str_hash, 
aa06693
+				   g_str_equal,
aa06693
+				   (GDestroyNotify) g_free, 
aa06693
+				   (GDestroyNotify) g_object_unref);
aa06693
+
aa06693
+#ifndef SC_SECURITY_TOKEN_MONITOR_DRIVER_CAN_BE_RELOADED_AFTER_BEING_DESTROYED
aa06693
+    monitor->priv->fds_to_close_on_fork = g_array_new (FALSE, FALSE, sizeof (gint));
aa06693
+#endif
aa06693
+
aa06693
+}
aa06693
+
aa06693
+static void 
aa06693
+sc_security_token_monitor_finalize (GObject *object)
aa06693
+{
aa06693
+    ScSecurityTokenMonitor *monitor;
aa06693
+    GObjectClass *gobject_class;
aa06693
+
aa06693
+    monitor = SC_SECURITY_TOKEN_MONITOR (object);
aa06693
+    gobject_class =
aa06693
+	    G_OBJECT_CLASS (sc_security_token_monitor_parent_class);
aa06693
+
aa06693
+    sc_security_token_monitor_stop_now (monitor);
aa06693
+
aa06693
+    g_hash_table_destroy (monitor->priv->security_tokens);
aa06693
+    monitor->priv->security_tokens = NULL;
aa06693
+
aa06693
+#ifndef SC_SECURITY_TOKEN_MONITOR_DRIVER_CAN_BE_RELOADED_AFTER_BEING_DESTROYED
aa06693
+    g_array_free (monitor->priv->fds_to_close_on_fork, TRUE);
aa06693
+#endif 
aa06693
+
aa06693
+    gobject_class->finalize (object);
aa06693
+}
aa06693
+
aa06693
+GQuark 
aa06693
+sc_security_token_monitor_error_quark (void)
aa06693
+{
aa06693
+    static GQuark error_quark = 0;
aa06693
+
aa06693
+    if (error_quark == 0)
aa06693
+	    error_quark = g_quark_from_static_string ("sc-security-token-monitor-error-quark");
aa06693
+
aa06693
+    return error_quark;
aa06693
+}
aa06693
+
aa06693
+ScSecurityTokenMonitor *
aa06693
+sc_security_token_monitor_new (const gchar *module_path)
aa06693
+{
aa06693
+    ScSecurityTokenMonitor *instance;
aa06693
+
aa06693
+    instance = SC_SECURITY_TOKEN_MONITOR (g_object_new (SC_TYPE_SECURITY_TOKEN_MONITOR, 
aa06693
+							"module-path", module_path,
aa06693
+							NULL));
aa06693
+
aa06693
+    return instance;
aa06693
+}
aa06693
+
aa06693
+static void 
aa06693
+sc_security_token_monitor_emit_error (ScSecurityTokenMonitor *monitor,
aa06693
+				      GError                 *error)
aa06693
+{
aa06693
+    monitor->priv->is_unstoppable = TRUE;
aa06693
+    g_signal_emit (monitor, sc_security_token_monitor_signals[ERROR], 0,
aa06693
+		   error);
aa06693
+    monitor->priv->is_unstoppable = FALSE;
aa06693
+}
aa06693
+
aa06693
+static void 
aa06693
+sc_security_token_monitor_emit_security_token_inserted (ScSecurityTokenMonitor *monitor,
aa06693
+							ScSecurityToken        *token)
aa06693
+{
aa06693
+    monitor->priv->is_unstoppable = TRUE;
aa06693
+    g_signal_emit (monitor, sc_security_token_monitor_signals[SECURITY_TOKEN_INSERTED], 0,
aa06693
+		   token);
aa06693
+    monitor->priv->is_unstoppable = FALSE;
aa06693
+}
aa06693
+
aa06693
+static void 
aa06693
+sc_security_token_monitor_emit_security_token_removed (ScSecurityTokenMonitor *monitor,
aa06693
+							ScSecurityToken        *token)
aa06693
+{
aa06693
+    ScSecurityTokenMonitorState old_state;
aa06693
+
aa06693
+    old_state = monitor->priv->state;
aa06693
+    monitor->priv->is_unstoppable = TRUE;
aa06693
+    g_signal_emit (monitor, sc_security_token_monitor_signals[SECURITY_TOKEN_REMOVED], 0,
aa06693
+		   token);
aa06693
+    monitor->priv->is_unstoppable = FALSE;
aa06693
+}
aa06693
+
aa06693
+static gboolean
aa06693
+sc_security_token_monitor_check_for_and_process_events (GIOChannel *io_channel,
aa06693
+							GIOCondition condition,
aa06693
+							ScSecurityTokenMonitor *monitor)
aa06693
+{
aa06693
+    ScSecurityToken *token;
aa06693
+    gboolean should_stop;
aa06693
+    guchar event_type;
aa06693
+    gchar *token_name;
aa06693
+    gint fd;
aa06693
+
aa06693
+    token = NULL;
aa06693
+    should_stop = (condition & G_IO_HUP) || (condition & G_IO_ERR);
aa06693
+
aa06693
+    if (should_stop)
aa06693
+	    sc_debug ("received %s on event socket, stopping "
aa06693
+		      "monitor...", 
aa06693
+		      (condition & G_IO_HUP) && (condition & G_IO_ERR)? 
aa06693
+		      "error and hangup" : 
aa06693
+		      (condition & G_IO_HUP)? 
aa06693
+		      "hangup" : "error");
aa06693
+
aa06693
+    if (!(condition & G_IO_IN))
aa06693
+	    goto out;
aa06693
+
aa06693
+    fd = g_io_channel_unix_get_fd (io_channel);
aa06693
+
aa06693
+    event_type = '\0';
aa06693
+    if (!sc_read_bytes (fd, &event_type, 1)) {
aa06693
+	    should_stop = TRUE;
aa06693
+	    goto out;
aa06693
+    }
aa06693
+
aa06693
+    token = sc_read_security_token (fd, monitor->priv->module);
aa06693
+
aa06693
+    if (token == NULL) {
aa06693
+	    should_stop = TRUE;
aa06693
+	    goto out;
aa06693
+    }
aa06693
+
aa06693
+    token_name = sc_security_token_get_name (token);
aa06693
+
aa06693
+    switch (event_type) {
aa06693
+	    case 'I':
aa06693
+		    g_hash_table_replace (monitor->priv->security_tokens,
aa06693
+					  token_name, token);
aa06693
+		    token_name = NULL;
aa06693
+
aa06693
+		    sc_security_token_monitor_emit_security_token_inserted (monitor, token);
aa06693
+		    token = NULL;
aa06693
+		    break;
aa06693
+
aa06693
+	    case 'R':
aa06693
+		    sc_security_token_monitor_emit_security_token_removed (monitor, token);
aa06693
+		    if (!g_hash_table_remove (monitor->priv->security_tokens, token_name))
aa06693
+			    sc_debug ("got removal event of unknown token!");
aa06693
+		    g_free (token_name);
aa06693
+		    token_name = NULL;
aa06693
+		    token = NULL;
aa06693
+		    break;
aa06693
+
aa06693
+	    default: 
aa06693
+		    g_free (token_name);
aa06693
+		    token_name = NULL;
aa06693
+		    g_object_unref (token);
aa06693
+
aa06693
+		    should_stop = TRUE;
aa06693
+		    break;
aa06693
+    }
aa06693
+
aa06693
+out:
aa06693
+    if (should_stop) {
aa06693
+	    GError *error;
aa06693
+
aa06693
+	    error = g_error_new (SC_SECURITY_TOKEN_MONITOR_ERROR,
aa06693
+				 SC_SECURITY_TOKEN_MONITOR_ERROR_WATCHING_FOR_EVENTS,
aa06693
+				 "%s", (condition & G_IO_IN) ? g_strerror (errno) : _("received error or hang up from event source"));
aa06693
+
aa06693
+	    sc_security_token_monitor_emit_error (monitor, error);
aa06693
+	    g_error_free (error);
aa06693
+	    sc_security_token_monitor_stop_now (monitor);
aa06693
+	    return FALSE;
aa06693
+    }
aa06693
+
aa06693
+    return TRUE;
aa06693
+}
aa06693
+
aa06693
+static void
aa06693
+sc_security_token_monitor_event_processing_stopped_handler (ScSecurityTokenMonitor *monitor)
aa06693
+{
aa06693
+    monitor->priv->security_token_event_source = NULL;
aa06693
+    sc_security_token_monitor_stop_now (monitor);
aa06693
+}
aa06693
+
aa06693
+/* sorta complex function that is nothing more than fork() without having
aa06693
+ * to worry about reaping the child later with waitpid
aa06693
+ */
aa06693
+static GPid
aa06693
+sc_fork_and_disown (void)
aa06693
+{
aa06693
+    pid_t child_pid;
aa06693
+    GPid grandchild_pid;
aa06693
+    gint write_fd, read_fd;
aa06693
+    gint saved_errno;
aa06693
+
aa06693
+    write_fd = -1;
aa06693
+    read_fd = -1;
aa06693
+    if (!sc_open_pipe (&write_fd, &read_fd))
aa06693
+	    return (GPid) -1;
aa06693
+
aa06693
+    child_pid = fork ();
aa06693
+
aa06693
+    if (child_pid < 0) {
aa06693
+	    close (write_fd);
aa06693
+	    close (read_fd);
aa06693
+	    return (GPid) child_pid;
aa06693
+    }
aa06693
+
aa06693
+    if (child_pid == 0) {
aa06693
+
aa06693
+	    /* close the end of the pipe we're not going to use
aa06693
+	     */
aa06693
+	    close (read_fd);
aa06693
+
aa06693
+	    /* fork again 
aa06693
+	     */
aa06693
+	    child_pid = fork ();
aa06693
+
aa06693
+	    /* in the event of error, write out negative errno
aa06693
+	     */
aa06693
+	    if (child_pid < 0) {
aa06693
+		    child_pid = -1 * errno;
aa06693
+
aa06693
+		    sc_write_bytes (write_fd, &child_pid, sizeof (child_pid));
aa06693
+		    close (write_fd);
aa06693
+		    _exit (1);
aa06693
+	    }
aa06693
+
aa06693
+	    /* otherwise write out the pid of the child and exit
aa06693
+	     */
aa06693
+	    if (child_pid != 0) {
aa06693
+
aa06693
+		    signal (SIGPIPE, SIG_IGN);
aa06693
+
aa06693
+		    if (!sc_write_bytes (write_fd, &child_pid, sizeof (child_pid))) {
aa06693
+			    kill (SIGKILL, child_pid);
aa06693
+			    _exit (2);
aa06693
+		    }
aa06693
+		    close (write_fd);
aa06693
+		    _exit (0);
aa06693
+	    }
aa06693
+	    close (write_fd);
aa06693
+
aa06693
+	    /* we're done, we've forked without having to worry about
aa06693
+	     * reaping the child later
aa06693
+	     */
aa06693
+	    g_assert (child_pid == 0);
aa06693
+	    return (GPid) 0;
aa06693
+    }
aa06693
+
aa06693
+    /* close the end of the pipe we're not going to use
aa06693
+     */
aa06693
+    close (write_fd);
aa06693
+
aa06693
+    grandchild_pid = -1;
aa06693
+    if (!sc_read_bytes (read_fd, &grandchild_pid, sizeof (grandchild_pid))) {
aa06693
+	    grandchild_pid = -1;
aa06693
+    }
aa06693
+
aa06693
+    saved_errno = errno;
aa06693
+
aa06693
+    /* close the other end of the pipe since we're done with it
aa06693
+     */
aa06693
+    close (read_fd);
aa06693
+
aa06693
+    /* wait for child to die (and emancipate the grandchild)
aa06693
+     */
aa06693
+    waitpid (child_pid, NULL, 0);
aa06693
+    
aa06693
+    errno = saved_errno;
aa06693
+    return (GPid) grandchild_pid;
aa06693
+}
aa06693
+
aa06693
+static gboolean
aa06693
+sc_open_pipe (gint *write_fd,
aa06693
+	      gint *read_fd)
aa06693
+{
aa06693
+    gint pipe_fds[2] = { -1, -1 };
aa06693
+
aa06693
+    g_assert (write_fd != NULL);
aa06693
+    g_assert (read_fd != NULL);
aa06693
+
aa06693
+    if (pipe (pipe_fds) < 0)
aa06693
+	    return FALSE;
aa06693
+
aa06693
+    if (fcntl (pipe_fds[0], F_SETFD, FD_CLOEXEC) < 0) {
aa06693
+	    close (pipe_fds[0]);
aa06693
+	    close (pipe_fds[1]);
aa06693
+	    return FALSE;
aa06693
+    }
aa06693
+
aa06693
+    if (fcntl (pipe_fds[1], F_SETFD, FD_CLOEXEC) < 0) {
aa06693
+	    close (pipe_fds[0]);
aa06693
+	    close (pipe_fds[1]);
aa06693
+	    return FALSE;
aa06693
+    }
aa06693
+
aa06693
+    *read_fd = pipe_fds[0];
aa06693
+    *write_fd = pipe_fds[1];
aa06693
+ 
aa06693
+    return TRUE;
aa06693
+}
aa06693
+
aa06693
+static void
aa06693
+sc_security_token_monitor_stop_watching_for_events (ScSecurityTokenMonitor  *monitor)
aa06693
+{
aa06693
+    if (monitor->priv->security_token_event_source != NULL) {
aa06693
+	    g_source_destroy (monitor->priv->security_token_event_source);
aa06693
+	    monitor->priv->security_token_event_source = NULL;
aa06693
+    }
aa06693
+
aa06693
+    if (monitor->priv->security_token_event_watcher_pid > 0) {
aa06693
+	    kill (monitor->priv->security_token_event_watcher_pid, SIGKILL);
aa06693
+	    monitor->priv->security_token_event_watcher_pid = 0;
aa06693
+    }
aa06693
+}
aa06693
+
aa06693
+static gboolean
aa06693
+sc_load_nss (GError **error)
aa06693
+{
aa06693
+    SECStatus status = SECSuccess;
aa06693
+    static const guint32 flags = 
aa06693
+	NSS_INIT_READONLY| NSS_INIT_NOCERTDB | NSS_INIT_NOMODDB | 
aa06693
+	NSS_INIT_FORCEOPEN | NSS_INIT_NOROOTINIT | 
aa06693
+	NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD;
aa06693
+
aa06693
+    sc_debug ("attempting to load NSS database '%s'",
aa06693
+	      SC_SECURITY_TOKEN_MONITOR_NSS_DB);
aa06693
+
aa06693
+    status = NSS_Initialize (SC_SECURITY_TOKEN_MONITOR_NSS_DB,
aa06693
+			     "", "", SECMOD_DB, flags);
aa06693
+
aa06693
+    if (status != SECSuccess) {
aa06693
+	    gsize error_message_size;
aa06693
+	    gchar *error_message;
aa06693
+
aa06693
+	    error_message_size = PR_GetErrorTextLength ();
aa06693
+
aa06693
+	    if (error_message_size == 0) {
aa06693
+		    sc_debug ("NSS security system could not be initialized");
aa06693
+		    g_set_error (error,
aa06693
+				 SC_SECURITY_TOKEN_MONITOR_ERROR,
aa06693
+				 SC_SECURITY_TOKEN_MONITOR_ERROR_WITH_NSS,
aa06693
+				 _("NSS security system could not be initialized"));
aa06693
+		    goto out;
aa06693
+	    }
aa06693
+
aa06693
+	    error_message = g_slice_alloc0 (error_message_size);
aa06693
+	    PR_GetErrorText (error_message);
aa06693
+
aa06693
+	    g_set_error (error,
aa06693
+			 SC_SECURITY_TOKEN_MONITOR_ERROR,
aa06693
+			 SC_SECURITY_TOKEN_MONITOR_ERROR_WITH_NSS,
aa06693
+			 "%s", error_message);
aa06693
+	    sc_debug ("NSS security system could not be initialized - %s",
aa06693
+		      error_message);
aa06693
+
aa06693
+	    g_slice_free1 (error_message_size, error_message);
aa06693
+
aa06693
+	    goto out;
aa06693
+    }
aa06693
+
aa06693
+    sc_debug ("NSS database sucessfully loaded");
aa06693
+    return TRUE;
aa06693
+
aa06693
+out:
aa06693
+    sc_debug ("NSS database couldn't be sucessfully loaded");
aa06693
+    return FALSE;
aa06693
+}
aa06693
+
aa06693
+static SECMODModule *
aa06693
+sc_load_driver (gchar   *module_path,
aa06693
+		GError **error)
aa06693
+{
aa06693
+    SECMODModule *module;
aa06693
+    gchar *module_spec;
aa06693
+    gboolean module_explicitly_specified;
aa06693
+
aa06693
+    sc_debug ("attempting to load driver...");
aa06693
+
aa06693
+    module = NULL;
aa06693
+    module_explicitly_specified = module_path != NULL;
aa06693
+    if (module_explicitly_specified) {
aa06693
+	    module_spec = g_strdup_printf ("library=\"%s\"", module_path);
aa06693
+	    sc_debug ("loading security token driver using spec '%s'",
aa06693
+		      module_spec);
aa06693
+
aa06693
+	    module = SECMOD_LoadUserModule (module_spec, 
aa06693
+					    NULL /* parent */, 
aa06693
+					    FALSE /* recurse */);
aa06693
+	    g_free (module_spec);
aa06693
+	    module_spec = NULL;
aa06693
+
aa06693
+    } else {
aa06693
+	    SECMODModuleList *modules, *tmp;
aa06693
+
aa06693
+	    modules = SECMOD_GetDefaultModuleList ();
aa06693
+
aa06693
+	    for (tmp = modules; tmp != NULL; tmp = tmp->next) {
aa06693
+		    if (!SECMOD_HasRemovableSlots (tmp->module) ||
aa06693
+			!tmp->module->loaded)
aa06693
+			    continue;
aa06693
+
aa06693
+		    module = SECMOD_ReferenceModule (tmp->module);
aa06693
+		    break;
aa06693
+	    }
aa06693
+
aa06693
+	    /* fallback to compiled in driver path
aa06693
+	     */
aa06693
+	    if (module == NULL) {
aa06693
+		    if (g_file_test (SC_SECURITY_TOKEN_MONITOR_DRIVER,
aa06693
+				     G_FILE_TEST_IS_REGULAR)) {
aa06693
+
aa06693
+			    module_spec = g_strdup_printf ("library=\"%s\"", module_path);
aa06693
+			    sc_debug ("loading security token driver using spec '%s'",
aa06693
+				      module_spec);
aa06693
+
aa06693
+			    module = SECMOD_LoadUserModule (module_spec, 
aa06693
+							    NULL /* parent */, 
aa06693
+							    FALSE /* recurse */);
aa06693
+			    g_free (module_spec);
aa06693
+			    module_spec = NULL;
aa06693
+
aa06693
+		    }
aa06693
+	    }
aa06693
+
aa06693
+    }
aa06693
+
aa06693
+    if (!module_explicitly_specified && module == NULL) {
aa06693
+	    g_set_error (error,
aa06693
+			 SC_SECURITY_TOKEN_MONITOR_ERROR,
aa06693
+			 SC_SECURITY_TOKEN_MONITOR_ERROR_LOADING_DRIVER,
aa06693
+			 _("no suitable security token driver could be found"));
aa06693
+    } else if (module == NULL || !module->loaded) {
aa06693
+
aa06693
+	    gsize error_message_size;
aa06693
+	    gchar *error_message;
aa06693
+            
aa06693
+	    if (module != NULL && !module->loaded) {
aa06693
+		    sc_debug ("module found but not loaded?!");
aa06693
+		    SECMOD_DestroyModule (module);
aa06693
+		    module = NULL;
aa06693
+	    }
aa06693
+
aa06693
+	    error_message_size = PR_GetErrorTextLength ();
aa06693
+
aa06693
+	    if (error_message_size == 0) {
aa06693
+		    sc_debug ("security token driver '%s' could not be loaded",
aa06693
+			      module_path);
aa06693
+		    g_set_error (error,
aa06693
+				 SC_SECURITY_TOKEN_MONITOR_ERROR,
aa06693
+				 SC_SECURITY_TOKEN_MONITOR_ERROR_LOADING_DRIVER,
aa06693
+				 _("security token driver '%s' could not be "
aa06693
+				   "loaded"), module_path);
aa06693
+		    goto out;
aa06693
+	    }
aa06693
+
aa06693
+	    error_message = g_slice_alloc0 (error_message_size);
aa06693
+	    PR_GetErrorText (error_message);
aa06693
+
aa06693
+	    g_set_error (error,
aa06693
+			 SC_SECURITY_TOKEN_MONITOR_ERROR,
aa06693
+			 SC_SECURITY_TOKEN_MONITOR_ERROR_LOADING_DRIVER,
aa06693
+			 "%s", error_message);
aa06693
+
aa06693
+	    sc_debug ("security token driver '%s' could not be loaded - %s",
aa06693
+		      module_path, error_message);
aa06693
+	    g_slice_free1 (error_message_size, error_message);
aa06693
+    }
aa06693
+
aa06693
+out:
aa06693
+    return module;
aa06693
+}
aa06693
+
aa06693
+static void
aa06693
+sc_security_token_monitor_get_all_tokens (ScSecurityTokenMonitor *monitor)
aa06693
+{
aa06693
+    int i;
aa06693
+
aa06693
+    for (i = 0; i < monitor->priv->module->slotCount; i++) {
aa06693
+	    ScSecurityToken *token;
aa06693
+	    CK_SLOT_ID    slot_id;
aa06693
+	    gint          slot_series;
aa06693
+	    gchar *token_name;
aa06693
+
aa06693
+	    slot_id = PK11_GetSlotID (monitor->priv->module->slots[i]);
aa06693
+	    slot_series = PK11_GetSlotSeries (monitor->priv->module->slots[i]);
aa06693
+
aa06693
+	    token = _sc_security_token_new (monitor->priv->module, 
aa06693
+					    slot_id, slot_series);
aa06693
+
aa06693
+	    token_name = sc_security_token_get_name (token);
aa06693
+
aa06693
+	    g_hash_table_replace (monitor->priv->security_tokens,
aa06693
+				  token_name, token);
aa06693
+    }
aa06693
+}
aa06693
+
aa06693
+gboolean
aa06693
+sc_security_token_monitor_start (ScSecurityTokenMonitor  *monitor,
aa06693
+				 GError                 **error)
aa06693
+{
aa06693
+    GError *watching_error;
aa06693
+    gint worker_fd;
aa06693
+    GPid worker_pid;
aa06693
+    GIOChannel *io_channel;
aa06693
+    GSource *source;
aa06693
+    GIOFlags channel_flags;
aa06693
+    GError *nss_error;
aa06693
+
aa06693
+    if (monitor->priv->state == SC_SECURITY_TOKEN_MONITOR_STATE_STARTED) {
aa06693
+	    sc_debug ("security token monitor already started");
aa06693
+	    return TRUE;
aa06693
+    }
aa06693
+
aa06693
+    monitor->priv->state = SC_SECURITY_TOKEN_MONITOR_STATE_STARTING;
aa06693
+
aa06693
+    worker_fd = -1;
aa06693
+    worker_pid = 0;
aa06693
+
aa06693
+    nss_error = NULL;
aa06693
+    if (!monitor->priv->nss_is_loaded && !sc_load_nss (&nss_error)) {
aa06693
+	    g_propagate_error (error, nss_error);
aa06693
+	    goto out;
aa06693
+    }
aa06693
+    monitor->priv->nss_is_loaded = TRUE;
aa06693
+
aa06693
+    if (monitor->priv->module == NULL)
aa06693
+	    monitor->priv->module = sc_load_driver (monitor->priv->module_path, &nss_error);
aa06693
+
aa06693
+    if (monitor->priv->module == NULL) {
aa06693
+	    g_propagate_error (error, nss_error);
aa06693
+	    goto out;
aa06693
+    }
aa06693
+
aa06693
+    if (!sc_security_token_monitor_create_worker (monitor, &worker_fd, &worker_pid)) {
aa06693
+
aa06693
+	    g_set_error (error,
aa06693
+			 SC_SECURITY_TOKEN_MONITOR_ERROR,
aa06693
+			 SC_SECURITY_TOKEN_MONITOR_ERROR_WATCHING_FOR_EVENTS,
aa06693
+			 _("could not watch for incoming token events - %s"),
aa06693
+			 g_strerror (errno));
aa06693
+
aa06693
+	    goto out;
aa06693
+    }
aa06693
+
aa06693
+    monitor->priv->security_token_event_watcher_pid = worker_pid;
aa06693
+
aa06693
+    io_channel = g_io_channel_unix_new (worker_fd);
aa06693
+
aa06693
+    channel_flags = g_io_channel_get_flags (io_channel);
aa06693
+    watching_error = NULL;
aa06693
+
aa06693
+    source = g_io_create_watch (io_channel, G_IO_IN | G_IO_HUP);
aa06693
+    g_io_channel_unref (io_channel);
aa06693
+    io_channel = NULL;
aa06693
+
aa06693
+    monitor->priv->security_token_event_source = source;
aa06693
+
aa06693
+    g_source_set_callback (monitor->priv->security_token_event_source,
aa06693
+			   (GSourceFunc) (GIOFunc)
aa06693
+			   sc_security_token_monitor_check_for_and_process_events,
aa06693
+			   monitor,
aa06693
+			   (GDestroyNotify)
aa06693
+			   sc_security_token_monitor_event_processing_stopped_handler);
aa06693
+    g_source_attach (monitor->priv->security_token_event_source, NULL);
aa06693
+    g_source_unref (monitor->priv->security_token_event_source);
aa06693
+
aa06693
+    /* populate the hash with tokens that are already inserted
aa06693
+     */
aa06693
+    sc_security_token_monitor_get_all_tokens (monitor);
aa06693
+
aa06693
+    monitor->priv->state = SC_SECURITY_TOKEN_MONITOR_STATE_STARTED;
aa06693
+
aa06693
+out:
aa06693
+    /* don't leave it in a half started state
aa06693
+     */
aa06693
+    if (monitor->priv->state != SC_SECURITY_TOKEN_MONITOR_STATE_STARTED) {
aa06693
+	    sc_debug ("security token monitor could not be completely started");
aa06693
+	    sc_security_token_monitor_stop (monitor);
aa06693
+    } else
aa06693
+	    sc_debug ("security token monitor started");
aa06693
+
aa06693
+    return monitor->priv->state == SC_SECURITY_TOKEN_MONITOR_STATE_STARTED;
aa06693
+}
aa06693
+
aa06693
+static gboolean
aa06693
+sc_security_token_monitor_stop_now (ScSecurityTokenMonitor *monitor)
aa06693
+{
aa06693
+    if (monitor->priv->state == SC_SECURITY_TOKEN_MONITOR_STATE_STOPPED)
aa06693
+	    return FALSE;
aa06693
+
aa06693
+    monitor->priv->state = SC_SECURITY_TOKEN_MONITOR_STATE_STOPPED;
aa06693
+    sc_security_token_monitor_stop_watching_for_events (monitor);
aa06693
+#ifdef SC_SECURITY_TOKEN_MONITOR_DRIVER_CAN_BE_RELOADED_AFTER_BEING_DESTROYED
aa06693
+    if (monitor->priv->module != NULL) {
aa06693
+	    SECMOD_DestroyModule (monitor->priv->module);
aa06693
+	    monitor->priv->module = NULL;
aa06693
+    }
aa06693
+
aa06693
+    if (monitor->priv->nss_is_loaded) {
aa06693
+	    NSS_Shutdown ();
aa06693
+	    monitor->priv->nss_is_loaded = FALSE;
aa06693
+    }
aa06693
+#endif
aa06693
+    sc_debug ("security token monitor stopped");
aa06693
+    
aa06693
+    return FALSE;
aa06693
+}
aa06693
+
aa06693
+static void
aa06693
+sc_security_token_monitor_queue_stop (ScSecurityTokenMonitor *monitor)
aa06693
+{
aa06693
+
aa06693
+    monitor->priv->state = SC_SECURITY_TOKEN_MONITOR_STATE_STOPPING;
aa06693
+
aa06693
+    g_idle_add ((GSourceFunc) sc_security_token_monitor_stop_now, monitor);
aa06693
+}
aa06693
+
aa06693
+void 
aa06693
+sc_security_token_monitor_stop (ScSecurityTokenMonitor *monitor)
aa06693
+{
aa06693
+    if (monitor->priv->state == SC_SECURITY_TOKEN_MONITOR_STATE_STOPPED)
aa06693
+	    return;
aa06693
+
aa06693
+    if (monitor->priv->is_unstoppable) {
aa06693
+	    sc_security_token_monitor_queue_stop (monitor);
aa06693
+	    return;
aa06693
+    } 
aa06693
+
aa06693
+    sc_security_token_monitor_stop_now (monitor);
aa06693
+}
aa06693
+
aa06693
+static void
aa06693
+sc_security_token_monitor_check_for_login_token (CK_SLOT_ID       slot_id,
aa06693
+						 ScSecurityToken *token,
aa06693
+						 gboolean        *is_inserted)
aa06693
+{
aa06693
+    g_assert (is_inserted != NULL);
aa06693
+
aa06693
+    if (sc_security_token_is_login_token (token))
aa06693
+	    *is_inserted = TRUE;
aa06693
+
aa06693
+}
aa06693
+
aa06693
+gboolean 
aa06693
+sc_security_token_monitor_login_token_is_inserted (ScSecurityTokenMonitor *monitor) 
aa06693
+
aa06693
+{
aa06693
+    gboolean is_inserted;
aa06693
+
aa06693
+    is_inserted = FALSE;
aa06693
+    g_hash_table_foreach (monitor->priv->security_tokens, 
aa06693
+			  (GHFunc)
aa06693
+			  sc_security_token_monitor_check_for_login_token,
aa06693
+			  &is_inserted);
aa06693
+    return is_inserted;
aa06693
+}
aa06693
+
aa06693
+static gint
aa06693
+sc_get_max_open_fds (void)
aa06693
+{
aa06693
+  struct rlimit open_fd_limit;
aa06693
+  const gint fallback_limit = SC_MAX_OPEN_FILE_DESCRIPTORS;
aa06693
+
aa06693
+  if (getrlimit (RLIMIT_NOFILE, &open_fd_limit) < 0) {
aa06693
+	  sc_debug ("could not get file descriptor limit: %s",
aa06693
+		    g_strerror (errno));
aa06693
+	  sc_debug ("returning fallback file descriptor limit of %d",
aa06693
+		    fallback_limit);
aa06693
+	  return fallback_limit;
aa06693
+  }
aa06693
+
aa06693
+  if (open_fd_limit.rlim_cur == RLIM_INFINITY) {
aa06693
+	  sc_debug ("currently no file descriptor limit, returning fallback limit of %d",
aa06693
+		    fallback_limit);
aa06693
+	  return fallback_limit;
aa06693
+  }
aa06693
+
aa06693
+  return (gint) open_fd_limit.rlim_cur;
aa06693
+}
aa06693
+
aa06693
+static void
aa06693
+sc_close_all_fds (int *fds_to_keep_open)
aa06693
+{
aa06693
+    int max_open_fds, fd;
aa06693
+
aa06693
+    sc_debug ("closing all file descriptors");
aa06693
+    max_open_fds = sc_get_max_open_fds ();
aa06693
+
aa06693
+    for (fd = 0; fd < max_open_fds; fd++) {
aa06693
+	    int i;
aa06693
+	    gboolean should_close_fd;
aa06693
+
aa06693
+	    should_close_fd = TRUE;
aa06693
+
aa06693
+	    if (fds_to_keep_open != NULL) {
aa06693
+		    for (i = 0; fds_to_keep_open[i] >= 0; i++) {
aa06693
+			    if (fd == fds_to_keep_open[i]) {
aa06693
+				    should_close_fd = FALSE;
aa06693
+				    break;
aa06693
+			    }
aa06693
+		    }
aa06693
+	    } 
aa06693
+
aa06693
+	    if (should_close_fd) {
aa06693
+		    sc_debug ("closing file descriptor '%d'", fd);
aa06693
+		    close (fd);
aa06693
+	    }
aa06693
+    }
aa06693
+}
aa06693
+
aa06693
+static void
aa06693
+sc_close_open_fds (int *fds_to_keep_open)
aa06693
+{
aa06693
+    /* using DIR instead of GDir because we need access to dirfd so
aa06693
+     * that we can iterate through the fds and close them in one sweep.
aa06693
+     * (if we just closed all of them then we would close the one we're using
aa06693
+     * for reading the directory!)
aa06693
+     */
aa06693
+    DIR *dir;
aa06693
+    struct dirent *entry;
aa06693
+    gint fd, opendir_fd;
aa06693
+    gboolean should_use_fallback;
aa06693
+
aa06693
+    should_use_fallback = FALSE;
aa06693
+    opendir_fd = -1;
aa06693
+
aa06693
+    dir = opendir (SC_OPEN_FILE_DESCRIPTORS_DIR);
aa06693
+
aa06693
+    if (dir != NULL)
aa06693
+	    opendir_fd = dirfd (dir);
aa06693
+
aa06693
+    if ((dir == NULL) || (opendir_fd < 0)) {
aa06693
+	    sc_debug ("could not open "SC_OPEN_FILE_DESCRIPTORS_DIR": %s", g_strerror (errno));
aa06693
+	    should_use_fallback = TRUE;
aa06693
+    } else {
aa06693
+	    sc_debug ("reading files in '"SC_OPEN_FILE_DESCRIPTORS_DIR"'");
aa06693
+	    while ((entry = readdir (dir)) != NULL) {
aa06693
+		    gint i;
aa06693
+		    glong filename_as_number;
aa06693
+		    gchar *byte_after_number;
aa06693
+		    gboolean should_close_fd;
aa06693
+
aa06693
+		    errno = 0;
aa06693
+		    if (entry->d_name[0] == '.')
aa06693
+			    continue;
aa06693
+
aa06693
+		    sc_debug ("scanning filename '%s' for file descriptor number",
aa06693
+			       entry->d_name);
aa06693
+		    fd = -1;
aa06693
+		    filename_as_number = strtol (entry->d_name, &byte_after_number, 10);
aa06693
+
aa06693
+		    g_assert (byte_after_number != NULL);
aa06693
+
aa06693
+		    if ((*byte_after_number != '\0') ||
aa06693
+			(filename_as_number < 0) ||
aa06693
+			(filename_as_number >= G_MAXINT)) {
aa06693
+			    sc_debug ("filename '%s' does not appear to represent a "
aa06693
+				       "file descriptor: %s",
aa06693
+				       entry->d_name, strerror (errno));
aa06693
+			    should_use_fallback = TRUE;
aa06693
+		    } else {
aa06693
+			    fd = (gint) filename_as_number;
aa06693
+			    sc_debug ("filename '%s' represents file descriptor '%d'",
aa06693
+				       entry->d_name, fd);
aa06693
+			    should_use_fallback = FALSE;
aa06693
+		    }
aa06693
+
aa06693
+		    if (fd == opendir_fd) {
aa06693
+			    should_close_fd = FALSE;
aa06693
+		    } else {
aa06693
+			    should_close_fd = TRUE;
aa06693
+			    if (fds_to_keep_open != NULL)
aa06693
+				    for (i = 0; fds_to_keep_open[i] >= 0; i++) {
aa06693
+					    if (fd == fds_to_keep_open[i]) {
aa06693
+						    should_close_fd = FALSE;
aa06693
+						    break;
aa06693
+					    }
aa06693
+				    }
aa06693
+		    }
aa06693
+
aa06693
+		    if (should_close_fd) {
aa06693
+			    sc_debug ("closing file descriptor '%d'", fd);
aa06693
+			    close (fd);
aa06693
+		    } else {
aa06693
+			    sc_debug ("will not close file descriptor '%d' because it "
aa06693
+				      "is still needed", fd);
aa06693
+		    }
aa06693
+	    }
aa06693
+	    
aa06693
+	    if (entry != NULL)
aa06693
+		    should_use_fallback = TRUE;
aa06693
+
aa06693
+	    sc_debug ("closing directory '"SC_OPEN_FILE_DESCRIPTORS_DIR"'");
aa06693
+	    closedir (dir);
aa06693
+    }
aa06693
+
aa06693
+    /* if /proc isn't mounted or something else is screwy,
aa06693
+     * fall back to closing everything
aa06693
+     */
aa06693
+    if (should_use_fallback)
aa06693
+	    sc_close_all_fds (fds_to_keep_open);
aa06693
+}
aa06693
+
aa06693
+static void
aa06693
+sc_close_fds (gint *fds, 
aa06693
+	      gint  num_fds)
aa06693
+{
aa06693
+    gint i;
aa06693
+
aa06693
+    for (i = 0; i < num_fds; i++)
aa06693
+	    close (fds[i]);
aa06693
+}
aa06693
+
aa06693
+static ScSecurityTokenMonitorWorker *
aa06693
+sc_security_token_monitor_worker_new (gint write_fd)
aa06693
+{
aa06693
+    ScSecurityTokenMonitorWorker *worker;
aa06693
+
aa06693
+    worker = g_slice_new0 (ScSecurityTokenMonitorWorker);
aa06693
+    worker->write_fd = write_fd;
aa06693
+    worker->module = NULL;
aa06693
+
aa06693
+    worker->security_tokens =
aa06693
+	    g_hash_table_new_full ((GHashFunc) sc_slot_id_hash, 
aa06693
+				   (GEqualFunc) sc_slot_id_equal, 
aa06693
+				   (GDestroyNotify) g_free, 
aa06693
+				   (GDestroyNotify) g_object_unref);
aa06693
+
aa06693
+    return worker;
aa06693
+}
aa06693
+
aa06693
+static void 
aa06693
+sc_security_token_monitor_worker_free (ScSecurityTokenMonitorWorker *worker)
aa06693
+{
aa06693
+    if (worker->security_tokens != NULL) {
aa06693
+	    g_hash_table_destroy (worker->security_tokens);
aa06693
+	    worker->security_tokens = NULL;
aa06693
+    }
aa06693
+
aa06693
+    g_slice_free (ScSecurityTokenMonitorWorker, worker);
aa06693
+}
aa06693
+
aa06693
+/* This function checks to see if the helper's connection to the
aa06693
+ * parent process has been closed.  If it has, we assume the
aa06693
+ * parent has died (or is otherwise done with the connection)
aa06693
+ * and so we die, too.  We do this from a signal handler (yuck!)
aa06693
+ * because there isn't a nice way to cancel the 
aa06693
+ * SECMOD_WaitForAnyTokenEvent call, which just sits and blocks
aa06693
+ * indefinitely.  There is a SECMOD_CancelWait wait function
aa06693
+ * that we could call if we would have gone multithreaded like
aa06693
+ * NSS really wants us to do, but that call isn't signal handler
aa06693
+ * safe, so we just _exit() instead (eww).
aa06693
+ */
aa06693
+static void
aa06693
+worker_io_signal_handler (int        signal_number, 
aa06693
+			  siginfo_t *signal_info,
aa06693
+			  void      *data)
aa06693
+{
aa06693
+    int number_of_events;
aa06693
+    int old_errno;
aa06693
+    struct pollfd poll_fds[1] = { { 0 } };
aa06693
+    int parent_fd;
aa06693
+
aa06693
+    old_errno = errno;
aa06693
+
aa06693
+    /* pipe fd set up to talk to the parent */
aa06693
+    parent_fd = signal_info->si_fd;
aa06693
+
aa06693
+    /* We only care about disconnection events
aa06693
+     * (which get unmasked implicitly), so we just
aa06693
+     * pass 0 for the event mask
aa06693
+     */
aa06693
+    poll_fds[0].events = 0;
aa06693
+    poll_fds[0].fd = parent_fd;
aa06693
+    
aa06693
+    do {
aa06693
+	    number_of_events = poll (poll_fds, G_N_ELEMENTS (poll_fds), 0);
aa06693
+    } while ((number_of_events < 0) && (errno == EINTR));
aa06693
+
aa06693
+    g_assert (number_of_events <= G_N_ELEMENTS (poll_fds));
aa06693
+
aa06693
+    if (number_of_events < 0)
aa06693
+	    _exit (errno);
aa06693
+
aa06693
+    /* pipe disconnected; parent died
aa06693
+     */
aa06693
+    if (number_of_events > 0) {
aa06693
+	    g_assert (!(poll_fds[0].revents & POLLNVAL));
aa06693
+
aa06693
+	    if ((poll_fds[0].revents & POLLHUP) ||
aa06693
+		(poll_fds[0].revents & POLLERR)) {
aa06693
+		    _exit (poll_fds[0].revents);
aa06693
+	    }
aa06693
+    } 
aa06693
+
aa06693
+    errno = old_errno;
aa06693
+}
aa06693
+
aa06693
+static void
aa06693
+sc_security_token_monitor_worker_die_with_parent (ScSecurityTokenMonitorWorker *worker)
aa06693
+{
aa06693
+    struct sigaction action = { { 0 } };
aa06693
+    gint flags;
aa06693
+
aa06693
+    /* dirty hack to clean up worker if parent goes away
aa06693
+     */
aa06693
+    sigemptyset (&action.sa_mask);
aa06693
+    action.sa_sigaction = worker_io_signal_handler;
aa06693
+    action.sa_flags = SA_SIGINFO;
aa06693
+    sigaction (SIGIO, &action, NULL);
aa06693
+
aa06693
+    flags = fcntl (worker->write_fd, F_GETFL, 0);
aa06693
+
aa06693
+    fcntl (worker->write_fd, F_SETOWN, getpid ());
aa06693
+    fcntl (worker->write_fd, F_SETFL, flags | O_ASYNC);
aa06693
+    fcntl (worker->write_fd, F_SETSIG, SIGIO);
aa06693
+}
aa06693
+
aa06693
+static gboolean
aa06693
+sc_read_bytes (gint fd, gpointer bytes, gsize num_bytes)
aa06693
+{
aa06693
+    size_t bytes_left;
aa06693
+    size_t total_bytes_read;
aa06693
+    ssize_t bytes_read;
aa06693
+
aa06693
+    bytes_left = (size_t) num_bytes;
aa06693
+    total_bytes_read = 0;
aa06693
+
aa06693
+    do {
aa06693
+	    bytes_read = read (fd, bytes + total_bytes_read, bytes_left);
aa06693
+	    g_assert (bytes_read <= (ssize_t) bytes_left);
aa06693
+
aa06693
+	    if (bytes_read <= 0) {
aa06693
+		    if ((bytes_read < 0) && (errno == EINTR || errno == EAGAIN))
aa06693
+			    continue;
aa06693
+
aa06693
+		    bytes_left = 0;
aa06693
+	    } else {
aa06693
+		    bytes_left -= bytes_read;
aa06693
+		    total_bytes_read += bytes_read;
aa06693
+	    }
aa06693
+    } while (bytes_left > 0);
aa06693
+
aa06693
+    if (total_bytes_read <  (size_t) num_bytes)
aa06693
+	    return FALSE;
aa06693
+
aa06693
+    return TRUE;
aa06693
+}
aa06693
+
aa06693
+static gboolean
aa06693
+sc_write_bytes (gint fd, gconstpointer bytes, gsize num_bytes)
aa06693
+{
aa06693
+    size_t bytes_left;
aa06693
+    size_t total_bytes_written;
aa06693
+    ssize_t bytes_written;
aa06693
+
aa06693
+    bytes_left = (size_t) num_bytes;
aa06693
+    total_bytes_written = 0;
aa06693
+
aa06693
+    do {
aa06693
+	    bytes_written = write (fd, bytes + total_bytes_written, bytes_left);
aa06693
+	    g_assert (bytes_written <= (ssize_t) bytes_left);
aa06693
+
aa06693
+	    if (bytes_written <= 0) {
aa06693
+		    if ((bytes_written < 0) && (errno == EINTR || errno == EAGAIN))
aa06693
+			    continue;
aa06693
+
aa06693
+		    bytes_left = 0;
aa06693
+	    } else {
aa06693
+		    bytes_left -= bytes_written;
aa06693
+		    total_bytes_written += bytes_written;
aa06693
+	    }
aa06693
+    } while (bytes_left > 0);
aa06693
+
aa06693
+    if (total_bytes_written <  (size_t) num_bytes)
aa06693
+	    return FALSE;
aa06693
+
aa06693
+    return TRUE;
aa06693
+}
aa06693
+
aa06693
+static ScSecurityToken *
aa06693
+sc_read_security_token (gint fd, SECMODModule *module)
aa06693
+{
aa06693
+    ScSecurityToken *token;
aa06693
+    gchar *token_name;
aa06693
+    gsize token_name_size;
aa06693
+
aa06693
+    token_name_size = 0;
aa06693
+    if (!sc_read_bytes (fd, &token_name_size, sizeof (token_name_size)))
aa06693
+	return NULL;
aa06693
+
aa06693
+    token_name = g_slice_alloc0 (token_name_size);
aa06693
+    if (!sc_read_bytes (fd, token_name, token_name_size)) {
aa06693
+	    g_slice_free1 (token_name_size, token_name);
aa06693
+	    return NULL;
aa06693
+    }
aa06693
+    token = _sc_security_token_new_from_name (module, token_name);
aa06693
+    g_slice_free1 (token_name_size, token_name);
aa06693
+
aa06693
+    return token;
aa06693
+}
aa06693
+
aa06693
+static gboolean
aa06693
+sc_write_security_token (gint             fd, 
aa06693
+			 ScSecurityToken *token)
aa06693
+{
aa06693
+    gsize token_name_size;
aa06693
+    gchar *token_name;
aa06693
+
aa06693
+    token_name = sc_security_token_get_name (token);
aa06693
+    token_name_size = strlen (token_name) + 1;
aa06693
+
aa06693
+    if (!sc_write_bytes (fd, &token_name_size, sizeof (token_name_size))) {
aa06693
+	g_free (token_name);
aa06693
+	return FALSE;
aa06693
+    }
aa06693
+
aa06693
+    if (!sc_write_bytes (fd, token_name, token_name_size)) {
aa06693
+	g_free (token_name);
aa06693
+	return FALSE;
aa06693
+    }
aa06693
+    g_free (token_name);
aa06693
+
aa06693
+    return TRUE;
aa06693
+}
aa06693
+
aa06693
+static gboolean
aa06693
+sc_security_token_monitor_worker_emit_security_token_removed (ScSecurityTokenMonitorWorker  *worker, 
aa06693
+							      ScSecurityToken               *token, 
aa06693
+							      GError                       **error)
aa06693
+{
aa06693
+    sc_debug ("token '%s' removed!", sc_security_token_get_name (token));
aa06693
+
aa06693
+    if (!sc_write_bytes (worker->write_fd, "R", 1)) 
aa06693
+	    goto error_out;
aa06693
+
aa06693
+    if (!sc_write_security_token (worker->write_fd, token))
aa06693
+	    goto error_out;
aa06693
+
aa06693
+    return TRUE;
aa06693
+
aa06693
+error_out:
aa06693
+    g_set_error (error, SC_SECURITY_TOKEN_MONITOR_ERROR,
aa06693
+		 SC_SECURITY_TOKEN_MONITOR_ERROR_REPORTING_EVENTS, 
aa06693
+		 "%s", g_strerror (errno));
aa06693
+    return FALSE;
aa06693
+}
aa06693
+
aa06693
+static gboolean
aa06693
+sc_security_token_monitor_worker_emit_security_token_inserted (ScSecurityTokenMonitorWorker  *worker, 
aa06693
+							       ScSecurityToken               *token,
aa06693
+							       GError                       **error)
aa06693
+{
aa06693
+    GError *write_error;
aa06693
+
aa06693
+    write_error = NULL;
aa06693
+    sc_debug ("token '%s' inserted!", sc_security_token_get_name (token));
aa06693
+    if (!sc_write_bytes (worker->write_fd, "I", 1)) 
aa06693
+	    goto error_out;
aa06693
+
aa06693
+    if (!sc_write_security_token (worker->write_fd, token))
aa06693
+	    goto error_out;
aa06693
+
aa06693
+    return TRUE;
aa06693
+
aa06693
+error_out:
aa06693
+    g_set_error (error, SC_SECURITY_TOKEN_MONITOR_ERROR,
aa06693
+		 SC_SECURITY_TOKEN_MONITOR_ERROR_REPORTING_EVENTS, 
aa06693
+		 "%s", g_strerror (errno));
aa06693
+    return FALSE;
aa06693
+}
aa06693
+
aa06693
+static gboolean
aa06693
+sc_security_token_monitor_worker_watch_for_and_process_event (ScSecurityTokenMonitorWorker *worker,
aa06693
+							      GError                      **error)
aa06693
+{
aa06693
+    PK11SlotInfo *slot;
aa06693
+    CK_SLOT_ID slot_id, *key;
aa06693
+    gint slot_series, token_slot_series;
aa06693
+    ScSecurityToken *token;
aa06693
+    GError *processing_error;
aa06693
+
aa06693
+    sc_debug ("waiting for token event");
aa06693
+
aa06693
+    /* FIXME: we return FALSE quite a bit in this function without cleaning up
aa06693
+     * resources.  By returning FALSE we're going to ultimately exit anyway, but
aa06693
+     * we should still be tidier about things.
aa06693
+     */
aa06693
+
aa06693
+    slot = SECMOD_WaitForAnyTokenEvent (worker->module, 0, PR_SecondsToInterval (1)); 
aa06693
+    processing_error = NULL;
aa06693
+
aa06693
+    if (slot == NULL) {
aa06693
+	    int error_code;
aa06693
+
aa06693
+	    error_code = PORT_GetError ();
aa06693
+	    if ((error_code == 0) || (error_code == SEC_ERROR_NO_EVENT)) {
aa06693
+		    sc_debug ("spurrious event occurred");
aa06693
+		    return TRUE;
aa06693
+	    }
aa06693
+
aa06693
+	    /* FIXME: is there a function to convert from a PORT error
aa06693
+	     * code to a translated string?
aa06693
+	     */
aa06693
+	    g_set_error (error, SC_SECURITY_TOKEN_MONITOR_ERROR,
aa06693
+			 SC_SECURITY_TOKEN_MONITOR_ERROR_WITH_NSS,
aa06693
+			 _("encountered unexpected error while "
aa06693
+			   "waiting for security token events"));
aa06693
+	    return FALSE;
aa06693
+    }
aa06693
+
aa06693
+    /* the slot id and series together uniquely identify a token.
aa06693
+     * You can never have two tokens with the same slot id at the
aa06693
+     * same time, however (I think), so we can key off of it.
aa06693
+     */
aa06693
+    slot_id = PK11_GetSlotID (slot);
aa06693
+    slot_series = PK11_GetSlotSeries (slot);
aa06693
+
aa06693
+    /* First check to see if there is a token that we're currently
aa06693
+     * tracking in the slot.
aa06693
+     */
aa06693
+    key = g_new (CK_SLOT_ID, 1);
aa06693
+    *key = slot_id;
aa06693
+    token = g_hash_table_lookup (worker->security_tokens, key);
aa06693
+
aa06693
+    if (token != NULL)
aa06693
+	    token_slot_series = sc_security_token_get_slot_series (token);
aa06693
+
aa06693
+    if (PK11_IsPresent (slot)) {
aa06693
+	    /* Now, check to see if their is a new token in the slot.
aa06693
+	     * If there was a different token in the slot now than
aa06693
+	     * there was before, then we need to emit a removed signal
aa06693
+	     * for the old token (we don't want unpaired insertion events).
aa06693
+	     */
aa06693
+	    if ((token != NULL) && 
aa06693
+		token_slot_series != slot_series) {
aa06693
+		    if (!sc_security_token_monitor_worker_emit_security_token_removed (worker, token, &processing_error)) {
aa06693
+			    g_propagate_error (error, processing_error);
aa06693
+			    return FALSE;
aa06693
+		    }
aa06693
+	    }
aa06693
+
aa06693
+	    token = _sc_security_token_new (worker->module, 
aa06693
+					    slot_id, slot_series);
aa06693
+
aa06693
+	    g_hash_table_replace (worker->security_tokens,
aa06693
+				  key, token);
aa06693
+	    key = NULL;
aa06693
+
aa06693
+	    if (!sc_security_token_monitor_worker_emit_security_token_inserted (worker, token, &processing_error)) {
aa06693
+		    g_propagate_error (error, processing_error);
aa06693
+		    return FALSE;
aa06693
+	    }
aa06693
+    } else {
aa06693
+	    /* if we aren't tracking the token, just discard the event.
aa06693
+	     * We don't want unpaired remove events.  Note on startup
aa06693
+	     * NSS will generate an "insertion" event if a token is
aa06693
+	     * already inserted in the slot.
aa06693
+	     */
aa06693
+	    if ((token != NULL)) {
aa06693
+		    /* FIXME: i'm not sure about this code.  Maybe we
aa06693
+		     * shouldn't do this at all, or maybe we should do it
aa06693
+		     * n times (where n = slot_series - token_slot_series + 1)
aa06693
+		     * 
aa06693
+		     * Right now, i'm just doing it once.  
aa06693
+		     */
aa06693
+		    if ((slot_series - token_slot_series) > 1) {
aa06693
+
aa06693
+			    if (!sc_security_token_monitor_worker_emit_security_token_removed (worker, token, &processing_error)) {
aa06693
+				    g_propagate_error (error, processing_error);
aa06693
+				    return FALSE;
aa06693
+			    }
aa06693
+			    g_hash_table_remove (worker->security_tokens, key);
aa06693
+
aa06693
+			    token = _sc_security_token_new (worker->module, 
aa06693
+							    slot_id, slot_series);
aa06693
+			    g_hash_table_replace (worker->security_tokens,
aa06693
+						  key, token);
aa06693
+			    key = NULL;
aa06693
+			    if (!sc_security_token_monitor_worker_emit_security_token_inserted (worker, token, &processing_error)) {
aa06693
+				    g_propagate_error (error, processing_error);
aa06693
+				    return FALSE;
aa06693
+			    }
aa06693
+		    }
aa06693
+
aa06693
+		    if (!sc_security_token_monitor_worker_emit_security_token_removed (worker, token, &processing_error)) {
aa06693
+			    g_propagate_error (error, processing_error);
aa06693
+			    return FALSE;
aa06693
+		    }
aa06693
+
aa06693
+		    g_hash_table_remove (worker->security_tokens, key);
aa06693
+		    token = NULL;
aa06693
+	    } else {
aa06693
+		    sc_debug ("got spurious remove event");
aa06693
+	    }
aa06693
+    }
aa06693
+
aa06693
+    g_free (key);
aa06693
+    PK11_FreeSlot (slot);
aa06693
+
aa06693
+    return TRUE;
aa06693
+}
aa06693
+
aa06693
+static gboolean
aa06693
+sc_security_token_monitor_create_worker (ScSecurityTokenMonitor *monitor,
aa06693
+					 gint *worker_fd, GPid *worker_pid)
aa06693
+{
aa06693
+    GPid child_pid;
aa06693
+    gint write_fd, read_fd;
aa06693
+
aa06693
+    write_fd = -1;
aa06693
+    read_fd = -1;
aa06693
+    if (!sc_open_pipe (&write_fd, &read_fd))
aa06693
+	    return FALSE;
aa06693
+
aa06693
+    child_pid = sc_fork_and_disown ();
aa06693
+
aa06693
+    if (child_pid < 0)
aa06693
+	    return FALSE;
aa06693
+
aa06693
+    if (child_pid == 0) {
aa06693
+	    GError *error;
aa06693
+	    ScSecurityTokenMonitorWorker *worker;
aa06693
+
aa06693
+/* FIXME: Gotta figure out why this isn't working
aa06693
+*/
aa06693
+#ifdef SC_SECURITY_TOKEN_MONITOR_DRIVER_CAN_BE_RELOADED_AFTER_BEING_DESTROYED
aa06693
+	    gint fds_to_keep_open[] = { -1, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO, -1 };
aa06693
+
aa06693
+	    SECMOD_DestroyModule (monitor->priv->module);
aa06693
+	    monitor->priv->module = NULL;
aa06693
+
aa06693
+	    NSS_Shutdown ();
aa06693
+
aa06693
+	    fds_to_keep_open[0] = write_fd;
aa06693
+	    sc_close_open_fds (fds_to_keep_open);
aa06693
+	    read_fd = -1;
aa06693
+
aa06693
+	    if (!sc_load_nss (&error)) {
aa06693
+		    sc_debug ("could not load nss - %s", error->message);
aa06693
+		    g_error_free (error);
aa06693
+		    _exit (1);
aa06693
+	    }
aa06693
+#else
aa06693
+	    g_array_append_val (monitor->priv->fds_to_close_on_fork, read_fd);
aa06693
+	    /* Junky workaround to keep from leaking fds
aa06693
+	     */
aa06693
+	    sc_close_fds ((gint *) monitor->priv->fds_to_close_on_fork->data,
aa06693
+			  monitor->priv->fds_to_close_on_fork->len);
aa06693
+#endif
aa06693
+	    error = NULL;
aa06693
+
aa06693
+	    worker = sc_security_token_monitor_worker_new (write_fd);
aa06693
+
aa06693
+	    sc_security_token_monitor_worker_die_with_parent (worker);
aa06693
+
aa06693
+	    worker->module = sc_load_driver (monitor->priv->module_path, &error);
aa06693
+
aa06693
+	    if (worker->module == NULL) {
aa06693
+		    sc_debug ("could not load nss driver - %s", error->message);
aa06693
+		    g_error_free (error);
aa06693
+		    _exit (2);
aa06693
+	    }
aa06693
+
aa06693
+	    while (sc_security_token_monitor_worker_watch_for_and_process_event (worker, &error));
aa06693
+
aa06693
+	    sc_debug ("could not process token event - %s", error->message);
aa06693
+	    sc_security_token_monitor_worker_free (worker);
aa06693
+
aa06693
+	    _exit (0);
aa06693
+    }
aa06693
+
aa06693
+    close (write_fd);
aa06693
+
aa06693
+#ifndef SC_SECURITY_TOKEN_MONITOR_DRIVER_CAN_BE_RELOADED_AFTER_BEING_DESTROYED
aa06693
+    g_array_append_val (monitor->priv->fds_to_close_on_fork, read_fd);
aa06693
+#endif
aa06693
+
aa06693
+    if (worker_pid)
aa06693
+	    *worker_pid = child_pid;
aa06693
+
aa06693
+    if (worker_fd)
aa06693
+	    *worker_fd = read_fd;
aa06693
+
aa06693
+    return TRUE;
aa06693
+}
aa06693
+
aa06693
+#ifdef SC_SECURITY_TOKEN_MONITOR_ENABLE_TEST
aa06693
+#include <glib.h>
aa06693
+
aa06693
+static GMainLoop *event_loop;
aa06693
+static gboolean should_exit_on_next_remove = FALSE;
aa06693
+
aa06693
+static gboolean 
aa06693
+on_timeout (ScSecurityTokenMonitor *monitor)
aa06693
+{
aa06693
+    GError *error;
aa06693
+    g_print ("Re-enabling monitor.\n");
aa06693
+
aa06693
+    if (!sc_security_token_monitor_start (monitor, &error)) {
aa06693
+	    g_warning ("could not start security token monitor - %s",
aa06693
+		       error->message);
aa06693
+	    g_error_free (error);
aa06693
+	    return 1;
aa06693
+    }
aa06693
+    g_print ("Please re-insert security token\n");
aa06693
+
aa06693
+    should_exit_on_next_remove = TRUE;
aa06693
+
aa06693
+    return FALSE;
aa06693
+}
aa06693
+
aa06693
+static void
aa06693
+on_device_inserted (ScSecurityTokenMonitor * monitor,
aa06693
+		    ScSecurityToken *token)
aa06693
+{
aa06693
+    g_print ("security token inserted!\n");
aa06693
+    g_print ("Please remove it.\n");
aa06693
+}
aa06693
+
aa06693
+static void
aa06693
+on_device_removed (ScSecurityTokenMonitor * monitor,
aa06693
+		   ScSecurityToken *token)
aa06693
+{
aa06693
+    g_print ("security token removed!\n");
aa06693
+
aa06693
+    if (should_exit_on_next_remove)
aa06693
+	    g_main_loop_quit (event_loop);
aa06693
+    else {
aa06693
+	    g_print ("disabling monitor for 2 seconds\n");
aa06693
+	    sc_security_token_monitor_stop (monitor);
aa06693
+	    g_timeout_add (2000, (GSourceFunc) on_timeout, monitor);
aa06693
+    }
aa06693
+}
aa06693
+
aa06693
+int 
aa06693
+main (int   argc, 
aa06693
+      char *argv[])
aa06693
+{
aa06693
+    ScSecurityTokenMonitor *monitor;
aa06693
+    GError *error;
aa06693
+
aa06693
+    g_log_set_always_fatal (G_LOG_LEVEL_ERROR
aa06693
+			    | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING);
aa06693
+
aa06693
+    g_type_init ();
aa06693
+
aa06693
+    g_message ("creating instance of 'security token monitor' object...");
aa06693
+    monitor = sc_security_token_monitor_new (NULL);
aa06693
+    g_message ("'security token monitor' object created successfully");
aa06693
+
aa06693
+    g_signal_connect (monitor, "security-token-inserted",
aa06693
+		      G_CALLBACK (on_device_inserted), NULL);
aa06693
+
aa06693
+    g_signal_connect (monitor, "security-token-removed",
aa06693
+		      G_CALLBACK (on_device_removed), NULL);
aa06693
+
aa06693
+    g_message ("starting listener...");
aa06693
+
aa06693
+    error = NULL;
aa06693
+    if (!sc_security_token_monitor_start (monitor, &error)) {
aa06693
+	    g_warning ("could not start security token monitor - %s",
aa06693
+		       error->message);
aa06693
+	    g_error_free (error);
aa06693
+	    return 1;
aa06693
+    }
aa06693
+
aa06693
+    event_loop = g_main_loop_new (NULL, FALSE);
aa06693
+    g_main_loop_run (event_loop);
aa06693
+    g_main_loop_unref (event_loop);
aa06693
+    event_loop = NULL;
aa06693
+
aa06693
+    g_message ("destroying previously created 'security token monitor' object...");
aa06693
+    g_object_unref (monitor);
aa06693
+    monitor = NULL;
aa06693
+    g_message ("'security token monitor' object destroyed successfully");
aa06693
+
aa06693
+    return 0;
aa06693
+}
aa06693
+#endif
aa06693
diff -up /dev/null gnome-screensaver-2.26.0/src/securitytokenmonitor.h
aa06693
--- /dev/null	2009-03-18 22:51:48.055015100 -0400
6d5f864
+++ gnome-screensaver-2.26.0/src/securitytokenmonitor.h	2009-03-19 00:20:36.643204483 -0400
aa06693
@@ -0,0 +1,84 @@
aa06693
+/* securitytokenmonitor.h - monitor for security token insertion and
aa06693
+ *                          removal events
aa06693
+ *
aa06693
+ * Copyright (C) 2006 Ray Strode
aa06693
+ *
aa06693
+ * This program is free software; you can redistribute it and/or modify
aa06693
+ * it under the terms of the GNU General Public License as published by
aa06693
+ * the Free Software Foundation; either version 2, or (at your option)
aa06693
+ * any later version.
aa06693
+ *
aa06693
+ * This program is distributed in the hope that it will be useful,
aa06693
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
aa06693
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
aa06693
+ * GNU General Public License for more details.
aa06693
+ *
aa06693
+ * You should have received a copy of the GNU General Public License
aa06693
+ * along with this program; if not, write to the Free Software
aa06693
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
aa06693
+ * 02111-1307, USA.  
aa06693
+ */
aa06693
+#ifndef SC_SECURITY_TOKEN_MONITOR_H
aa06693
+#define SC_SECURITY_TOKEN_MONITOR_H
aa06693
+
aa06693
+#define SC_SECURITY_TOKEN_ENABLE_INTERNAL_API
aa06693
+#include "securitytoken.h"
aa06693
+
aa06693
+#include <glib.h>
aa06693
+#include <glib-object.h>
aa06693
+
aa06693
+G_BEGIN_DECLS
aa06693
+#define SC_TYPE_SECURITY_TOKEN_MONITOR            (sc_security_token_monitor_get_type ())
aa06693
+#define SC_SECURITY_TOKEN_MONITOR(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), SC_TYPE_SECURITY_TOKEN_MONITOR, ScSecurityTokenMonitor))
aa06693
+#define SC_SECURITY_TOKEN_MONITOR_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), SC_TYPE_SECURITY_TOKEN_MONITOR, ScSecurityTokenMonitorClass))
aa06693
+#define SC_IS_SECURITY_TOKEN_MONITOR(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SC_TYPE_SECURITY_TOKEN_MONITOR))
aa06693
+#define SC_IS_SECURITY_TOKEN_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SC_TYPE_SECURITY_TOKEN_MONITOR))
aa06693
+#define SC_SECURITY_TOKEN_MONITOR_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), SC_TYPE_SECURITY_TOKEN_MONITOR, ScSecurityTokenMonitorClass))
aa06693
+#define SC_SECURITY_TOKEN_MONITOR_ERROR           (sc_security_token_monitor_error_quark ())
aa06693
+typedef struct _ScSecurityTokenMonitor ScSecurityTokenMonitor;
aa06693
+typedef struct _ScSecurityTokenMonitorClass ScSecurityTokenMonitorClass;
aa06693
+typedef struct _ScSecurityTokenMonitorPrivate ScSecurityTokenMonitorPrivate;
aa06693
+typedef enum _ScSecurityTokenMonitorError ScSecurityTokenMonitorError;
aa06693
+
aa06693
+struct _ScSecurityTokenMonitor {
aa06693
+    GObject parent;
aa06693
+
aa06693
+    /*< private > */
aa06693
+    ScSecurityTokenMonitorPrivate *priv;
aa06693
+};
aa06693
+
aa06693
+struct _ScSecurityTokenMonitorClass {
aa06693
+    GObjectClass parent_class;
aa06693
+
aa06693
+    /* Signals */
aa06693
+    void (*security_token_inserted) (ScSecurityTokenMonitor *monitor,
aa06693
+				     ScSecurityToken *token);
aa06693
+    void (*security_token_removed) (ScSecurityTokenMonitor *monitor,
aa06693
+				    ScSecurityToken *token);
aa06693
+    void (*error) (ScSecurityTokenMonitor *monitor, 
aa06693
+		   GError                 *error);
aa06693
+};
aa06693
+
aa06693
+enum _ScSecurityTokenMonitorError {
aa06693
+    SC_SECURITY_TOKEN_MONITOR_ERROR_GENERIC = 0,
aa06693
+    SC_SECURITY_TOKEN_MONITOR_ERROR_WITH_NSS,
aa06693
+    SC_SECURITY_TOKEN_MONITOR_ERROR_LOADING_DRIVER,
aa06693
+    SC_SECURITY_TOKEN_MONITOR_ERROR_WATCHING_FOR_EVENTS,
aa06693
+    SC_SECURITY_TOKEN_MONITOR_ERROR_REPORTING_EVENTS
aa06693
+};
aa06693
+
aa06693
+GType sc_security_token_monitor_get_type (void) G_GNUC_CONST;
aa06693
+GQuark sc_security_token_monitor_error_quark (void) G_GNUC_CONST;
aa06693
+
aa06693
+ScSecurityTokenMonitor *sc_security_token_monitor_new (const gchar *module);
aa06693
+
aa06693
+gboolean sc_security_token_monitor_start (ScSecurityTokenMonitor  *monitor, 
aa06693
+				 	  GError                 **error);
aa06693
+
aa06693
+void sc_security_token_monitor_stop (ScSecurityTokenMonitor *monitor);
aa06693
+
aa06693
+gchar *sc_security_token_monitor_get_module_path (ScSecurityTokenMonitor *monitor);
aa06693
+gboolean sc_security_token_monitor_login_token_is_inserted (ScSecurityTokenMonitor *monitor);
aa06693
+
aa06693
+G_END_DECLS
aa06693
+#endif				/* SC_SECURITY_TOKEN_MONITOR_H */