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