From 6941265f47260d1e576bea4964dd4fe05b01c06a Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: May 21 2007 18:00:19 +0000 Subject: Update tons of patches --- diff --git a/.cvsignore b/.cvsignore index d8206a1..c22e04b 100644 --- a/.cvsignore +++ b/.cvsignore @@ -1,2 +1 @@ -gdm-2.18.0.tar.bz2 -fedora-faces-20070319.tar.bz2 +gdm-2.19.1.tar.bz2 diff --git a/gdm-2.16.0-wtmp.patch b/gdm-2.16.0-wtmp.patch deleted file mode 100644 index e8967aa..0000000 --- a/gdm-2.16.0-wtmp.patch +++ /dev/null @@ -1,257 +0,0 @@ ---- gdm-2.16.0/config/PreSession.in.wtmp 2006-04-26 21:06:05.000000000 -0400 -+++ gdm-2.16.0/config/PreSession.in 2006-10-15 20:05:45.000000000 -0400 -@@ -68,17 +68,4 @@ if [ "x$XSETROOT" != "x" ] ; then - "$XSETROOT" -cursor_name left_ptr -solid "$BACKCOLOR" - fi - -- --SESSREG=`gdmwhich sessreg` --if [ "x$SESSREG" != "x" ] ; then -- # some output for easy debugging -- echo "$0: Registering your session with wtmp and utmp" -- echo "$0: running: $SESSREG -a -w /var/log/wtmp -u /var/run/utmp -x \"$X_SERVERS\" -h \"$REMOTE_HOST\" -l \"$DISPLAY\" \"$USER\"" -- -- exec "$SESSREG" -a -w /var/log/wtmp -u /var/run/utmp -x "$X_SERVERS" -h "$REMOTE_HOST" -l "$DISPLAY" "$USER" -- # this is not reached --fi -- --# some output for easy debugging --echo "$0: could not find the sessreg utility, cannot update wtmp and utmp" - exit 0 ---- gdm-2.16.0/daemon/slave.c.wtmp 2006-10-15 20:05:45.000000000 -0400 -+++ gdm-2.16.0/daemon/slave.c 2006-10-15 20:05:45.000000000 -0400 -@@ -4315,6 +4315,14 @@ gdm_slave_session_start (void) - g_free (language); - g_free (gnome_session); - -+ gdm_verify_write_record (d, -+ GDM_VERIFY_RECORD_TYPE_LOGIN, -+ pwent->pw_name, -+ d->name, -+ !d->attached? d->hostname : NULL, -+ pid); -+ -+ - gdm_slave_send_num (GDM_SOP_SESSPID, pid); - - gdm_sigchld_block_push (); -@@ -4363,6 +4371,17 @@ gdm_slave_session_start (void) - uid, gid); - } - -+ if ((pid != 0) && (d->last_sess_status != -1)) { -+ gdm_debug ("session '%d' exited with status '%d', recording logout", -+ pid, d->last_sess_status); -+ gdm_verify_write_record (d, -+ GDM_VERIFY_RECORD_TYPE_LOGOUT, -+ pwent->pw_name, -+ d->name, -+ !d->attached? d->hostname : NULL, -+ pid); -+ } -+ - gdm_slave_session_stop (pid != 0 /* run_post_session */, - FALSE /* no_shutdown_check */); - -@@ -4721,7 +4740,7 @@ gdm_slave_child_handler (int sig) - } - } else if (pid != 0 && pid == d->sesspid) { - d->sesspid = 0; -- if (WIFEXITED (status)) -+ if (WIFEXITED (status)) - d->last_sess_status = WEXITSTATUS (status); - else - d->last_sess_status = -1; ---- gdm-2.16.0/daemon/verify.h.wtmp 2005-11-03 19:51:21.000000000 -0500 -+++ gdm-2.16.0/daemon/verify.h 2006-10-15 20:05:45.000000000 -0400 -@@ -21,6 +21,12 @@ - - #include "gdm.h" - -+typedef enum { -+ GDM_VERIFY_RECORD_TYPE_LOGIN, -+ GDM_VERIFY_RECORD_TYPE_LOGOUT, -+ GDM_VERIFY_RECORD_TYPE_FAILED_ATTEMPT -+} GdmVerifyRecordType; -+ - /* If username is NULL, we ask, if local is FALSE, don't start - * the timed login timer */ - gchar *gdm_verify_user (GdmDisplay *d, -@@ -30,6 +36,13 @@ gchar *gdm_verify_user (GdmDisplay *d - void gdm_verify_cleanup (GdmDisplay *d); - void gdm_verify_check (void); - void gdm_verify_select_user (const char *user); -+void gdm_verify_write_record (GdmDisplay *d, -+ GdmVerifyRecordType record_type, -+ const gchar *username, -+ const gchar *console_name, -+ const gchar *host_name, -+ GPid pid); -+ - /* used in pam */ - gboolean gdm_verify_setup_env (GdmDisplay *d); - gboolean gdm_verify_setup_user (GdmDisplay *d, ---- gdm-2.16.0/daemon/verify-pam.c.wtmp 2006-10-15 20:05:45.000000000 -0400 -+++ gdm-2.16.0/daemon/verify-pam.c 2006-10-15 20:08:48.000000000 -0400 -@@ -29,6 +29,7 @@ - #ifdef sun - #include - #endif -+#include - - #include - -@@ -55,6 +56,14 @@ - #define log_to_audit_system(l,h,d,s) do { ; } while (0) - #endif - -+#ifndef GDM_BAD_RECORDS_FILE -+#define GDM_BAD_RECORDS_FILE "/var/log/btmp" -+#endif -+ -+#ifndef GDM_NEW_RECORDS_FILE -+#define GDM_NEW_RECORDS_FILE "/var/log/wtmp" -+#endif -+ - /* Evil, but this way these things are passed to the child session */ - static pam_handle_t *pamh = NULL; - -@@ -417,6 +426,125 @@ gdm_verify_select_user (const char *user - selected_user = g_strdup (user); - } - -+void -+gdm_verify_write_record (GdmDisplay *d, -+ GdmVerifyRecordType record_type, -+ const gchar *username, -+ const gchar *console_name, -+ const gchar *host_name, -+ GPid pid) -+{ -+ struct utmp record = { 0 }; -+ GTimeVal now = { 0 }; -+ gchar *host; -+ -+ gdm_debug ("writing %s record", -+ record_type == GDM_VERIFY_RECORD_TYPE_LOGIN? "session" : -+ record_type == GDM_VERIFY_RECORD_TYPE_LOGOUT? "logout" : -+ "failed session attempt"); -+ -+ if (record_type != GDM_VERIFY_RECORD_TYPE_LOGOUT) -+ { -+ /* it's possible that PAM failed before -+ * it mapped the user input into a valid username -+ * so we fallback to try using "(unknown)" -+ */ -+ if (username != NULL) -+ strncpy (record.ut_user, -+ username, -+ sizeof (record.ut_user)); -+ else -+ strncpy (record.ut_user, -+ "(unknown)", -+ sizeof (record.ut_user)); -+ } -+ -+ gdm_debug ("using username %.*s", -+ sizeof (record.ut_user), -+ record.ut_user); -+ -+ strncpy (record.ut_id, -+ console_name + -+ strlen (console_name) - -+ sizeof (record.ut_id), -+ sizeof (record.ut_id)); -+ -+ gdm_debug ("using id %.*s", -+ sizeof (record.ut_id), -+ record.ut_id); -+ -+ if (g_str_has_prefix (console_name, "/dev/")) { -+ strncpy (record.ut_line, -+ console_name + strlen ("/dev/"), -+ sizeof (record.ut_line)); -+ } else if (g_str_has_prefix (console_name, ":")) { -+ strncpy (record.ut_line, -+ console_name, -+ sizeof (record.ut_line)); -+ } -+ -+ gdm_debug ("using line %.*s", -+ sizeof (record.ut_line), -+ record.ut_line); -+ -+ host = NULL; -+ if ((host_name != NULL) && -+ g_str_has_prefix (console_name, ":")) -+ host = g_strdup_printf ("%s%s", -+ host_name, -+ console_name); -+ else if ((host_name != NULL) && -+ !strstr (console_name, ":")) -+ host = g_strdup (host_name); -+ else if (!g_str_has_prefix (console_name, ":") && -+ strstr (console_name, ":")) -+ host = g_strdup (console_name); -+ -+ if (host) -+ { -+ strncpy (record.ut_host, host, sizeof (record.ut_host)); -+ g_free (host); -+ gdm_debug ("using hostname %.*s", -+ sizeof (record.ut_host), -+ record.ut_host); -+ } -+ -+ g_get_current_time (&now); -+ record.ut_tv.tv_sec = now.tv_sec; -+ record.ut_tv.tv_usec = now.tv_usec; -+ -+ gdm_debug ("using time %ld", (glong) record.ut_tv.tv_sec); -+ -+ record.ut_type = USER_PROCESS; -+ gdm_debug ("using type USER_PROCESS"); -+ -+ record.ut_pid = pid; -+ -+ gdm_debug ("using pid %d", (gint) record.ut_pid); -+ -+ switch (record_type) -+ { -+ case GDM_VERIFY_RECORD_TYPE_LOGIN: -+ gdm_debug ("writing session record to " -+ GDM_NEW_RECORDS_FILE); -+ updwtmp (GDM_NEW_RECORDS_FILE, &record); -+ break; -+ -+ case GDM_VERIFY_RECORD_TYPE_LOGOUT: -+ gdm_debug ("writing logout record to " -+ GDM_NEW_RECORDS_FILE); -+ updwtmp (GDM_NEW_RECORDS_FILE, &record); -+ break; -+ -+ case GDM_VERIFY_RECORD_TYPE_FAILED_ATTEMPT: -+ gdm_debug ("writing failed session attempt record to " -+ GDM_BAD_RECORDS_FILE); -+ updwtmp (GDM_BAD_RECORDS_FILE, &record); -+ break; -+ } -+ -+} -+ - static const char * - perhaps_translate_message (const char *msg) - { -@@ -1173,6 +1301,12 @@ authenticate_again: - * message from the PAM subsystem */ - if ( ! error_msg_given && - gdm_slave_action_pending ()) { -+ -+ gdm_verify_write_record (d, GDM_VERIFY_RECORD_TYPE_FAILED_ATTEMPT, -+ login, display, -+ d->attached? NULL : d->hostname, -+ getpid ()); -+ - /* I'm not sure yet if I should display this message for any other issues - heeten */ - if (pamerr == PAM_AUTH_ERR || - pamerr == PAM_USER_UNKNOWN) { diff --git a/gdm-2.17.6-audit-login.patch b/gdm-2.17.6-audit-login.patch deleted file mode 100644 index 8a3cb3f..0000000 --- a/gdm-2.17.6-audit-login.patch +++ /dev/null @@ -1,171 +0,0 @@ ---- gdm-2.17.6/configure.ac.audit-login 2007-01-30 16:21:18.000000000 -0500 -+++ gdm-2.17.6/configure.ac 2007-02-07 22:27:55.000000000 -0500 -@@ -825,6 +825,10 @@ - AC_SUBST(logdir, ${localstatedir}/log/gdm) - AC_SUBST(pixmapdir, ${datadir}/pixmaps) - -+AC_ARG_WITH(libaudit, -+ [ --with-libaudit=[auto/yes/no] Add Linux audit support [default=auto]],, -+ with_libaudit=auto) -+ - withval="" - AC_ARG_WITH(at-bindir, - [ --with-at-bindir= PATH to Accessible Technology programs [default=BINDIR]],) -@@ -936,6 +940,24 @@ - AC_MSG_RESULT(no) - fi - -+# Check for Linux auditing API -+# -+# libaudit detection -+if test x$with_libaudit = xno ; then -+ have_libaudit=no; -+else -+ # See if we have audit daemon library -+ AC_CHECK_LIB(audit, audit_log_user_message, -+ have_libaudit=yes, have_libaudit=no) -+fi -+ -+AM_CONDITIONAL(HAVE_LIBAUDIT, test x$have_libaudit = xyes) -+ -+if test x$have_libaudit = xyes ; then -+ EXTRA_DAEMON_LIBS="$EXTRA_DAEMON_LIBS -laudit" -+ AC_DEFINE(HAVE_LIBAUDIT,1,[linux audit support]) -+fi -+ - # Check for Solaris auditing API - # Note, Solaris auditing not supported for Solaris 9 or earlier and - # should not be used on these versions of Solaris if auditing is ---- gdm-2.17.6/daemon/verify-pam.c.audit-login 2007-02-07 22:05:17.000000000 -0500 -+++ gdm-2.17.6/daemon/verify-pam.c 2007-02-07 22:30:55.000000000 -0500 -@@ -47,6 +47,14 @@ - #include - #endif /* HAVE_ADT */ - -+#define AU_FAILED 0 -+#define AU_SUCCESS 1 -+#ifdef HAVE_LIBAUDIT -+#include -+#else -+#define log_to_audit_system(l,h,d,s) do { ; } while (0) -+#endif -+ - /* Evil, but this way these things are passed to the child session */ - static pam_handle_t *pamh = NULL; - -@@ -784,6 +792,53 @@ - return TRUE; - } - -+/** -+ * log_to_audit_system: -+ * @login: Name of user -+ * @hostname: Name of host machine -+ * @tty: Name of display -+ * @success: 1 for success, 0 for failure -+ * -+ * Logs the success or failure of the login attempt with the linux kernel -+ * audit system. The intent is to capture failed events where the user -+ * fails authentication or otherwise is not permitted to login. There are -+ * many other places where pam could potentially fail and cause login to -+ * fail, but these are system failures rather than the signs of an account -+ * being hacked. -+ * -+ * Returns nothing. -+ */ -+ -+#ifdef HAVE_LIBAUDIT -+static void -+log_to_audit_system(const char *login, -+ const char *hostname, -+ const char *tty, -+ gboolean success) -+{ -+ struct passwd *pw; -+ char buf[64]; -+ int audit_fd; -+ -+ audit_fd = audit_open(); -+ if (login) -+ pw = getpwnam(login); -+ else { -+ login = "unknown"; -+ pw = NULL; -+ } -+ if (pw) { -+ snprintf(buf, sizeof(buf), "uid=%d", pw->pw_uid); -+ audit_log_user_message(audit_fd, AUDIT_USER_LOGIN, -+ buf, hostname, NULL, tty, (int)success); -+ } else { -+ snprintf(buf, sizeof(buf), "acct=%s", login); -+ audit_log_user_message(audit_fd, AUDIT_USER_LOGIN, -+ buf, hostname, NULL, tty, (int)success); -+ } -+ close(audit_fd); -+} -+#endif - - /** - * gdm_verify_user: -@@ -903,6 +958,9 @@ - /* Start authentication session */ - did_we_ask_for_password = FALSE; - if ((pamerr = pam_authenticate (pamh, null_tok)) != PAM_SUCCESS) { -+ /* Log the failed login attempt */ -+ log_to_audit_system(login, d->hostname, display, AU_FAILED); -+ - if ( ! ve_string_empty (selected_user)) { - pam_handle_t *tmp_pamh; - -@@ -1024,6 +1082,8 @@ - ( ! gdm_get_value_bool (GDM_KEY_ALLOW_REMOTE_ROOT) && ! local) ) && - pwent != NULL && - pwent->pw_uid == 0) { -+ /* Log the failed login attempt */ -+ log_to_audit_system(login, d->hostname, display, AU_FAILED); - gdm_error (_("Root login disallowed on display '%s'"), - display); - gdm_slave_greeter_ctl_no_ret (GDM_ERRBOX, -@@ -1057,6 +1117,8 @@ - break; - case PAM_NEW_AUTHTOK_REQD : - if ((pamerr = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK)) != PAM_SUCCESS) { -+ /* Log the failed login attempt */ -+ log_to_audit_system(login, d->hostname, display, AU_FAILED); - gdm_error (_("Authentication token change failed for user %s"), login); - gdm_slave_greeter_ctl_no_ret (GDM_ERRBOX, - _("\nThe change of the authentication token failed. " -@@ -1074,18 +1136,24 @@ - #endif /* HAVE_ADT */ - break; - case PAM_ACCT_EXPIRED : -+ /* Log the failed login attempt */ -+ log_to_audit_system(login, d->hostname, display, AU_FAILED); - gdm_error (_("User %s no longer permitted to access the system"), login); - gdm_slave_greeter_ctl_no_ret (GDM_ERRBOX, - _("\nThe system administrator has disabled your account.")); - error_msg_given = TRUE; - goto pamerr; - case PAM_PERM_DENIED : -+ /* Log the failed login attempt */ -+ log_to_audit_system(login, d->hostname, display, AU_FAILED); - gdm_error (_("User %s not permitted to gain access at this time"), login); - gdm_slave_greeter_ctl_no_ret (GDM_ERRBOX, - _("\nThe system administrator has disabled access to the system temporarily.")); - error_msg_given = TRUE; - goto pamerr; - default : -+ /* Log the failed login attempt */ -+ log_to_audit_system(login, d->hostname, display, AU_FAILED); - if (gdm_slave_action_pending ()) - gdm_error (_("Couldn't set acct. mgmt for %s"), login); - goto pamerr; -@@ -1137,6 +1205,8 @@ - gdm_error (_("Couldn't open session for %s"), login); - goto pamerr; - } -+ /* Login succeeded */ -+ log_to_audit_system(login, d->hostname, display, AU_SUCCESS); - - /* Workaround to avoid gdm messages being logged as PAM_pwdb */ - closelog (); diff --git a/gdm-2.17.7-move-default-message.patch b/gdm-2.17.7-move-default-message.patch deleted file mode 100644 index 0ce4e7b..0000000 --- a/gdm-2.17.7-move-default-message.patch +++ /dev/null @@ -1,147 +0,0 @@ ---- gdm-2.17.7/gui/gdmlogin.c.move-default-message 2007-02-12 00:40:13.000000000 -0500 -+++ gdm-2.17.7/gui/gdmlogin.c 2007-02-23 22:53:47.000000000 -0500 -@@ -160,6 +160,7 @@ - extern const gchar *current_session; - extern gboolean session_dir_whacked_out; - extern gint gdm_timed_delay; -+static gboolean using_fallback_message = FALSE; - - static gboolean first_prompt = TRUE; - -@@ -1558,9 +1559,20 @@ - gdm_config_get_string (GDM_KEY_SOUND_ON_LOGIN_FILE), - gdm_config_get_bool (GDM_KEY_SOUND_ON_LOGIN)); - gtk_label_set_text_with_mnemonic (GTK_LABEL (label), _("_Username:")); -+ if (ve_string_empty (gtk_label_get_text (GTK_LABEL (msg)))) { -+ gtk_label_set_text (GTK_LABEL (msg), -+ _("Please enter your username")); -+ using_fallback_message = TRUE; -+ } -+ - } else { - if (tmp != NULL) - gtk_label_set_text (GTK_LABEL (label), tmp); -+ if (using_fallback_message) { -+ gtk_label_set_text (GTK_LABEL (msg), ""); -+ using_fallback_message = FALSE; -+ } -+ - } - g_free (tmp); - -@@ -1648,6 +1660,7 @@ - g_free (tmp); - } - replace_msg = FALSE; -+ using_fallback_message = FALSE; - - gtk_widget_show (GTK_WIDGET (msg)); - printf ("%c\n", STX); -@@ -1828,9 +1841,7 @@ - if (browser_ok && gdm_config_get_bool (GDM_KEY_BROWSER)) - gtk_widget_set_sensitive (GTK_WIDGET (browser), TRUE); - -- tmp = ve_locale_to_utf8 (args); -- gtk_label_set_text (GTK_LABEL (msg), tmp); -- g_free (tmp); -+ gtk_label_set_text (GTK_LABEL (msg), ""); - gtk_widget_show (GTK_WIDGET (msg)); - - printf ("%c\n", STX); ---- gdm-2.17.7/gui/greeter/greeter_item_pam.c.move-default-message 2007-02-12 00:40:12.000000000 -0500 -+++ gdm-2.17.7/gui/greeter/greeter_item_pam.c 2007-02-23 22:50:22.000000000 -0500 -@@ -46,6 +46,7 @@ - gboolean require_quarter = FALSE; - - extern gboolean greeter_probably_login_prompt; -+static gboolean using_fallback_message = FALSE; - extern GtkButton *gtk_ok_button; - extern GtkButton *gtk_start_again_button; - -@@ -250,13 +251,35 @@ - int entry_len, - gboolean entry_visible) - { -+ GreeterItemInfo *message_info; - GreeterItemInfo *conversation_info; - GreeterItemInfo *entry_info; - GtkWidget *entry; - -+ message_info = greeter_lookup_id ("pam-message"); - conversation_info = greeter_lookup_id ("pam-prompt"); - entry_info = greeter_lookup_id ("user-pw-entry"); - -+ if (strcmp (message, _("Username:")) == 0 && message_info) -+ { -+ gchar *text; -+ text = NULL; -+ g_object_get (G_OBJECT (message_info->item), -+ "text", &text, -+ NULL); -+ if (ve_string_empty (text)) -+ { -+ set_text (message_info, _("Please enter your username")); -+ using_fallback_message = TRUE; -+ } -+ g_free (text); -+ } -+ else if (using_fallback_message) -+ { -+ set_text (message_info, ""); -+ using_fallback_message = FALSE; -+ } -+ - if (conversation_info) - { - set_text (conversation_info, message); -@@ -296,6 +319,7 @@ - * we try to collect them until the next prompt or reset or - * whatnot */ - if ( ! replace_msg && -+ ! using_fallback_message && - /* empty message is for clearing */ - ! ve_string_empty (message)) - { -@@ -315,6 +339,7 @@ - set_text (message_info, message); - } - replace_msg = FALSE; -+ using_fallback_message = FALSE; - } - - ---- gdm-2.17.7/daemon/verify-pam.c.move-default-message 2007-02-23 22:50:22.000000000 -0500 -+++ gdm-2.17.7/daemon/verify-pam.c 2007-02-23 22:50:22.000000000 -0500 -@@ -534,12 +534,6 @@ - case PAM_PROMPT_ECHO_ON: - if (strcmp (m, _("Username:")) == 0) { - if ( ve_string_empty (selected_user)) { -- /* this is an evil hack, but really there is no way we'll -- know this is a username prompt. However we SHOULD NOT -- rely on this working. The pam modules can set their -- prompt to whatever they wish to */ -- gdm_slave_greeter_ctl_no_ret -- (GDM_MSG, _("Please enter your username")); - s = gdm_slave_greeter_ctl (GDM_PROMPT, m); - /* this will clear the message */ - gdm_slave_greeter_ctl_no_ret (GDM_MSG, ""); ---- gdm-2.17.7/daemon/verify-crypt.c.move-default-message 2007-02-12 00:40:19.000000000 -0500 -+++ gdm-2.17.7/daemon/verify-crypt.c 2007-02-23 22:50:22.000000000 -0500 -@@ -115,7 +115,6 @@ - authenticate_again: - /* Ask for the user's login */ - gdm_verify_select_user (NULL); -- gdm_slave_greeter_ctl_no_ret (GDM_MSG, _("Please enter your username")); - login = gdm_slave_greeter_ctl (GDM_PROMPT, _("Username:")); - if (login == NULL || - gdm_slave_greeter_check_interruption ()) { ---- gdm-2.17.7/daemon/verify-shadow.c.move-default-message 2007-02-12 00:40:19.000000000 -0500 -+++ gdm-2.17.7/daemon/verify-shadow.c 2007-02-23 22:50:22.000000000 -0500 -@@ -114,7 +114,6 @@ - authenticate_again: - /* Ask for the user's login */ - gdm_verify_select_user (NULL); -- gdm_slave_greeter_ctl_no_ret (GDM_MSG, _("Please enter your username")); - login = gdm_slave_greeter_ctl (GDM_PROMPT, _("Username:")); - if (login == NULL || - gdm_slave_greeter_check_interruption ()) { diff --git a/gdm-2.17.7-pass-at-to-session-4.patch b/gdm-2.17.7-pass-at-to-session-4.patch deleted file mode 100644 index c2589eb..0000000 --- a/gdm-2.17.7-pass-at-to-session-4.patch +++ /dev/null @@ -1,279 +0,0 @@ -Index: gui/modules/dwellmouselistener.c -=================================================================== ---- gui/modules/dwellmouselistener.c (revision 4608) -+++ gui/modules/dwellmouselistener.c (working copy) -@@ -665,6 +665,8 @@ - G_CALLBACK (gtk_widget_destroy), NULL); - gtk_widget_show (dialog); - } else { -+ const char *at_name; -+ const char *ats_launched; - GdkCursor *cursor = gdk_cursor_new (GDK_WATCH); - gdk_window_set_cursor (gdk_get_default_root_window (), - cursor); -@@ -673,6 +675,26 @@ - latch_core_pointer = FALSE; - /* once we've recognized a gesture, we need to * - * leave the pointer alone */ -+ -+ at_name = strstr (action, "#AT_TYPE="); -+ if (at_name != NULL) { -+ int i; -+ char **v; -+ at_name += 9; -+ v = g_strsplit (at_name, " ", 0); -+ for (i = 0; v[i] != NULL; i++) { -+ ats_launched = g_getenv ("GDM_ATS"); -+ if (ats_launched == NULL) { -+ g_setenv ("GDM_ATS", v[i], TRUE); -+ } else if (strstr (ats_launched, v[i]) == NULL) { -+ char *s; -+ s = g_strdup_printf ("%s %s", ats_launched, v[i]); -+ g_setenv ("GDM_ATS", s, TRUE); -+ g_free (s); -+ } -+ } -+ g_strfreev (v); -+ } - } - } - } -Index: gui/modules/keymouselistener.c -=================================================================== ---- gui/modules/keymouselistener.c (revision 4608) -+++ gui/modules/keymouselistener.c (working copy) -@@ -937,6 +937,8 @@ - NULL); - gtk_widget_show (dialog); - } else { -+ char *at_name; -+ const char *ats_launched; - GdkCursor *cursor = gdk_cursor_new (GDK_WATCH); - gdk_window_set_cursor (gdk_get_default_root_window (), - cursor); -@@ -944,6 +946,26 @@ - g_timeout_add (2000, - change_cursor_back, - NULL); -+ -+ at_name = strstr (action, "#AT_TYPE="); -+ if (at_name != NULL) { -+ int i; -+ char **v; -+ at_name += 9; -+ v = g_strsplit (at_name, " ", 0); -+ for (i = 0; v[i] != NULL; i++) { -+ ats_launched = g_getenv ("GDM_ATS"); -+ if (ats_launched == NULL) { -+ g_setenv ("GDM_ATS", v[i], TRUE); -+ } else if (strstr (ats_launched, v[i]) == NULL) { -+ char *s; -+ s = g_strdup_printf ("%s %s", ats_launched, v[i]); -+ g_setenv ("GDM_ATS", s, TRUE); -+ g_free (s); -+ } -+ } -+ g_strfreev (v); -+ } - } - } - return GDK_FILTER_CONTINUE; -Index: gui/modules/AccessDwellMouseEvents.in -=================================================================== ---- gui/modules/AccessDwellMouseEvents.in (revision 4608) -+++ gui/modules/AccessDwellMouseEvents.in (working copy) -@@ -37,23 +37,23 @@ - # user needs. Note these gestures all start by moving the mouse into the top - # window border. - # --TBLR I 10000 @AT_BINDIR@/gok --login --access-method=dwellselection --TLBR I 10000 @AT_BINDIR@/gok --login --access-method=automaticscanning --scan-action=switch1 --select-action=switch1 --TRBL I 10000 @AT_BINDIR@/gok --login --access-method=inversescanning --scan-action=switch1 --select-action=switch2 --TBRL I 10000 @AT_BINDIR@/gok --login --access-method=automaticscanning --scan-action=switch3 --select-action=switch3 -+TBLR I 10000 @AT_BINDIR@/gok --login --access-method=dwellselection #AT_TYPE=onscreenkeyboard -+TLBR I 10000 @AT_BINDIR@/gok --login --access-method=automaticscanning --scan-action=switch1 --select-action=switch1 #AT_TYPE=onscreenkeyboard -+TRBL I 10000 @AT_BINDIR@/gok --login --access-method=inversescanning --scan-action=switch1 --select-action=switch2 #AT_TYPE=onscreenkeyboard -+TBRL I 10000 @AT_BINDIR@/gok --login --access-method=automaticscanning --scan-action=switch3 --select-action=switch3 #AT_TYPE=onscreenkeyboard - - # Orca. Note these gestures all start by moving the mouse into the - # bottom window border. - # - # Speech - # --BTRL I 10000 @AT_BINDIR@/orca -n -d main-window -+BTRL I 10000 @AT_BINDIR@/orca -n -d main-window #AT_TYPE=screenreader - - # Magnifier - # --BTLR I 10000 @AT_BINDIR@/orca -n -d main-window -d speech -e magnifier -+BTLR I 10000 @AT_BINDIR@/orca -n -d main-window -d speech -e magnifier #AT_TYPE=magnifier - - # Speech and Magnifier - # --BRTL I 10000 @AT_BINDIR@/orca -n -d main-window -e magnifier -+BRTL I 10000 @AT_BINDIR@/orca -n -d main-window -e magnifier #AT_TYPE=screenreader magnifier - -Index: gui/modules/AccessKeyMouseEvents.in -=================================================================== ---- gui/modules/AccessKeyMouseEvents.in (revision 4608) -+++ gui/modules/AccessKeyMouseEvents.in (working copy) -@@ -69,18 +69,18 @@ - - # press ctrl-s for 1 second to launch orca in speech mode - # --s 1 1000 10000 @AT_BINDIR@/orca -n -d main-window -+s 1 1000 10000 @AT_BINDIR@/orca -n -d main-window #AT_TYPE=screenreader - - # press ctrl-m for 1 second to launch orca in mag mode - # --m 1 1000 10000 @AT_BINDIR@/orca -n -d main-window -d speech -e magnifier -+m 1 1000 10000 @AT_BINDIR@/orca -n -d main-window -d speech -e magnifier #AT_TYPE=magnifier - - # press ctrl-o or ctrl-g for 1 second to launch orca in speech and mag mode - # --o 1 1000 10000 @AT_BINDIR@/orca -n -d main-window -e magnifier --g 1 1000 10000 @AT_BINDIR@/orca -n -d main-window -e magnifier -+o 1 1000 10000 @AT_BINDIR@/orca -n -d main-window -e magnifier #AT_TYPE=screenreader magnifier -+g 1 1000 10000 @AT_BINDIR@/orca -n -d main-window -e magnifier #AT_TYPE=screenreader magnifier - - # Start GOK with direct selection mode. - # --k 5 1000 10000 @AT_BINDIR@/gok --login --access-method=directselection -+k 5 1000 10000 @AT_BINDIR@/gok --login --access-method=directselection #AT_TYPE=onscreenkeyboard - -Index: gui/greeter/greeter.c -=================================================================== ---- gui/greeter/greeter.c (revision 4608) -+++ gui/greeter/greeter.c (working copy) -@@ -340,6 +340,19 @@ - g_free (session); - break; - -+ case GDM_A11Y: -+ { -+ const char *ats_launched; -+ /* print out the assistive technologies that we've started for the user */ -+ ats_launched = g_getenv ("GDM_ATS"); -+ if (ats_launched != NULL) -+ printf ("%c%s\n", STX, ats_launched); -+ else -+ printf ("%c\n", STX); -+ fflush (stdout); -+ break; -+ } -+ - case GDM_LANG: - language = greeter_language_get_language (args); - if (greeter_language_get_save_language () == GTK_RESPONSE_CANCEL) -Index: daemon/gdm.h -=================================================================== ---- daemon/gdm.h (revision 4608) -+++ daemon/gdm.h (working copy) -@@ -98,6 +98,7 @@ - #define GDM_PROMPT 'N' - #define GDM_SESS 'G' - #define GDM_LANG '&' -+#define GDM_A11Y 'Z' - #define GDM_SSESS 'C' - #define GDM_SLANG 'R' - #define GDM_RESET 'A' -Index: daemon/slave.c -=================================================================== ---- daemon/slave.c (revision 4608) -+++ daemon/slave.c (working copy) -@@ -3430,6 +3430,7 @@ - const char *session, - const char *save_session, - const char *language, -+ const char *a11y_ats, - const char *gnome_session, - gboolean usrcfgok, - gboolean savesess, -@@ -3522,6 +3523,9 @@ - g_setenv ("XDG_SESSION_COOKIE", ck_session_cookie, TRUE); - } - #endif -+ if (a11y_ats != NULL) { -+ g_setenv ("GDM_ATS", a11y_ats, TRUE); -+ } - g_setenv ("GDMSESSION", session, TRUE); - g_setenv ("DESKTOP_SESSION", session, TRUE); - g_setenv ("SHELL", pwent->pw_shell, TRUE); -@@ -4016,7 +4020,7 @@ - { - struct passwd *pwent; - const char *home_dir = NULL; -- char *save_session = NULL, *session = NULL, *language = NULL, *usrsess, *usrlang; -+ char *save_session = NULL, *session = NULL, *language = NULL, *a11y_ats = NULL, *usrsess, *usrlang; - char *gnome_session = NULL; - #ifdef WITH_CONSOLE_KIT - char *ck_session_cookie; -@@ -4187,9 +4191,19 @@ - g_free (usrlang); - return; - } -+ -+ a11y_ats = gdm_slave_greeter_ctl (GDM_A11Y, NULL); -+ if (a11y_ats != NULL && -+ strcmp (a11y_ats, GDM_RESPONSE_CANCEL) == 0) { -+ gdm_debug ("User canceled login"); -+ gdm_verify_cleanup (d); -+ session_started = FALSE; -+ return; -+ } - } else { - session = g_strdup (usrsess); - language = g_strdup (usrlang); -+ a11y_ats = NULL; - } - - tmp = gdm_strip_extension (session, ".desktop"); -@@ -4210,11 +4224,16 @@ - language = NULL; - } - -+ if G_LIKELY (ve_string_empty (a11y_ats)) { -+ g_free (a11y_ats); -+ a11y_ats = NULL; -+ } -+ - g_free (usrsess); - g_free (usrlang); - -- gdm_debug ("Initial setting: session: '%s' language: '%s'\n", -- session, ve_sure_string (language)); -+ gdm_debug ("Initial setting: session: '%s' language: '%s' ATs enabled in gdm: '%s'\n", -+ session, ve_sure_string (language), ve_sure_string (a11y_ats)); - - /* save this session as the users session */ - save_session = g_strdup (session); -@@ -4378,6 +4397,7 @@ - session, - save_session, - language, -+ a11y_ats, - gnome_session, - usrcfgok, - savesess, ---- gui/gdmlogin.c.orig 2007-03-19 23:32:04.000000000 -0400 -+++ gui/gdmlogin.c 2007-03-19 23:32:33.000000000 -0400 -@@ -1784,6 +1784,19 @@ - fflush (stdout); - break; - -+ case GDM_A11Y: -+ { -+ const char *ats_launched; -+ /* print out the assistive technologies that we've started for the user */ -+ ats_launched = g_getenv ("GDM_ATS"); -+ if (ats_launched != NULL) -+ printf ("%c%s\n", STX, ats_launched); -+ else -+ printf ("%c\n", STX); -+ fflush (stdout); -+ break; -+ } -+ - case GDM_LANG: - gdm_login_language_lookup (args); - if (savelang == GTK_RESPONSE_CANCEL) diff --git a/gdm-2.17.7-reset-pam.patch b/gdm-2.17.7-reset-pam.patch deleted file mode 100644 index 7db89e7..0000000 --- a/gdm-2.17.7-reset-pam.patch +++ /dev/null @@ -1,176 +0,0 @@ ---- gdm-2.17.7/gui/greeter/greeter.c.reset-pam 2007-02-12 00:40:12.000000000 -0500 -+++ gdm-2.17.7/gui/greeter/greeter.c 2007-02-23 22:54:28.000000000 -0500 -@@ -171,7 +171,6 @@ - GtkWidget *dlg; - char *tmp; - char *session; -- GreeterItemInfo *conversation_info; - static GnomeCanvasItem *disabled_cover = NULL; - gchar *language; - gchar *selected_user = NULL; -@@ -380,17 +379,10 @@ - - first_prompt = TRUE; - -- conversation_info = greeter_lookup_id ("pam-conversation"); -- -- if (conversation_info) -- { -- tmp = ve_locale_to_utf8 (args); -- g_object_set (G_OBJECT (conversation_info->item), -- "text", tmp, -- NULL); -- g_free (tmp); -- } -- -+ greeter_item_ulist_unset_selected_user (); -+ greeter_item_pam_prompt ("", PW_ENTRY_SIZE, TRUE); -+ greeter_item_pam_message (""); -+ - printf ("%c\n", STX); - fflush (stdout); - greeter_ignore_buttons (FALSE); ---- gdm-2.17.7/daemon/slave.c.reset-pam 2007-02-23 22:54:28.000000000 -0500 -+++ gdm-2.17.7/daemon/slave.c 2007-02-23 22:54:28.000000000 -0500 -@@ -133,6 +133,12 @@ - static int greeter_fd_out = -1; - static int greeter_fd_in = -1; - -+/* a dup of the other side of greeter_fd_in so that -+ * the slave can talk to itself from its sig handler -+ * using the greeter ipc mechanism -+ */ -+static int slave_fd_out = -1; -+ - #ifdef HAVE_TSOL - static gboolean have_suntsol_extension = FALSE; - #endif -@@ -626,7 +632,7 @@ - } - - static void --whack_greeter_fds (void) -+whack_greeter_and_slave_fds (void) - { - if (greeter_fd_out > 0) - VE_IGNORE_EINTR (close (greeter_fd_out)); -@@ -634,6 +640,9 @@ - if (greeter_fd_in > 0) - VE_IGNORE_EINTR (close (greeter_fd_in)); - greeter_fd_in = -1; -+ if (slave_fd_out > 0) -+ VE_IGNORE_EINTR (close (slave_fd_out)); -+ slave_fd_out = -1; - } - - static void -@@ -1084,7 +1093,7 @@ - - d->greetpid = 0; - -- whack_greeter_fds (); -+ whack_greeter_and_slave_fds (); - - gdm_slave_send_num (GDM_SOP_GREETPID, 0); - -@@ -1887,7 +1896,7 @@ - - d->greetpid = 0; - -- whack_greeter_fds (); -+ whack_greeter_and_slave_fds (); - - gdm_slave_send_num (GDM_SOP_GREETPID, 0); - } -@@ -2124,6 +2133,12 @@ - break; - } - -+ if (do_cancel) { -+ gdm_debug ("canceling..."); -+ gdm_slave_greeter_ctl_no_ret (GDM_RESETOK, ""); -+ continue; -+ } -+ - if (login == NULL) { - char *failuresound = gdm_get_value_string (GDM_KEY_SOUND_ON_LOGIN_FAILURE_FILE); - -@@ -2723,9 +2738,9 @@ - - default: - VE_IGNORE_EINTR (close (pipe1[0])); -- VE_IGNORE_EINTR (close (pipe2[1])); -+ whack_greeter_and_slave_fds (); - -- whack_greeter_fds (); -+ slave_fd_out = pipe2[1]; - - greeter_fd_out = pipe1[1]; - greeter_fd_in = pipe2[0]; -@@ -4784,7 +4799,7 @@ - - greet = FALSE; - d->greetpid = 0; -- whack_greeter_fds (); -+ whack_greeter_and_slave_fds (); - gdm_slave_send_num (GDM_SOP_GREETPID, 0); - - do_restart_greeter = TRUE; -@@ -4796,7 +4811,7 @@ - continue; - } - -- whack_greeter_fds (); -+ whack_greeter_and_slave_fds (); - - /* if greet is TRUE, then the greeter died outside of our - * control really, so clean up and die, something is wrong -@@ -4939,6 +4954,11 @@ - gdm_wait_for_go = FALSE; - } else if (strcmp (&s[1], GDM_NOTIFY_TWIDDLE_POINTER) == 0) { - gdm_twiddle_pointer (d); -+ } else if (strcmp (&s[1], GDM_NOTIFY_RESET) == 0) { -+ if (!d->logged_in) { -+ gdm_fdprintf (slave_fd_out, "%c%c%c\n", -+ STX, BEL, GDM_INTERRUPT_CANCEL); -+ } - } - } else if (s[0] == GDM_SLAVE_NOTIFY_RESPONSE) { - gdm_got_ack = TRUE; ---- gdm-2.17.7/daemon/gdm.h.reset-pam 2007-02-12 00:40:19.000000000 -0500 -+++ gdm-2.17.7/daemon/gdm.h 2007-02-23 22:54:28.000000000 -0500 -@@ -749,6 +749,9 @@ - #define GDM_SOP_SHOW_QUESTION_DIALOG "SHOW_QUESTION_DIALOG" /* show the question dialog from daemon */ - #define GDM_SOP_SHOW_ASKBUTTONS_DIALOG "SHOW_ASKBUTTON_DIALOG" /* show the askbutton dialog from daemon */ - -+/* Reset any in progress authentication conversations */ -+#define GDM_SOP_CANCEL_LOGIN_REQUESTS "CANCEL_LOGIN_REQUESTS" /* no arguments */ -+ - /* Notification protocol */ - /* keys */ - #define GDM_NOTIFY_ALLOW_REMOTE_ROOT "AllowRemoteRoot" /* */ -@@ -776,6 +779,7 @@ - #define GDM_NOTIFY_SOFT_RESTART_SERVERS "SOFT_RESTART_SERVERS" - #define GDM_NOTIFY_GO "GO" - #define GDM_NOTIFY_TWIDDLE_POINTER "TWIDDLE_POINTER" -+#define GDM_NOTIFY_RESET "RESET" - - /* Ack for a slave message */ - /* Note that an extra response can follow an 'ack' */ ---- gdm-2.17.7/daemon/gdm.c.reset-pam 2007-02-12 00:40:19.000000000 -0500 -+++ gdm-2.17.7/daemon/gdm.c 2007-02-23 22:55:35.000000000 -0500 -@@ -2557,6 +2557,14 @@ - TRUE /* handled */, - FALSE /* chooser */, - NULL, 0, NULL, NULL, NULL); -+ } else if (strcmp (msg, GDM_SOP_CANCEL_LOGIN_REQUESTS) == 0) { -+ GSList *li; -+ for (li = displays; li != NULL; li = li->next) { -+ GdmDisplay *d = li->data; -+ if (!d->logged_in) { -+ send_slave_command (d, GDM_NOTIFY_RESET); -+ } -+ } - } else if (strncmp (msg, "opcode="GDM_SOP_SHOW_ERROR_DIALOG, - strlen ("opcode="GDM_SOP_SHOW_ERROR_DIALOG)) == 0) { - GdmDisplay *d; diff --git a/gdm-2.17.8-a11y-fixes-for-themed-greeter.patch b/gdm-2.17.8-a11y-fixes-for-themed-greeter.patch deleted file mode 100644 index 9496fd2..0000000 --- a/gdm-2.17.8-a11y-fixes-for-themed-greeter.patch +++ /dev/null @@ -1,205 +0,0 @@ -Index: gui/greeter/greeter_item_ulist.c -=================================================================== ---- gui/greeter/greeter_item_ulist.c (revision 4626) -+++ gui/greeter/greeter_item_ulist.c (working copy) -@@ -217,18 +217,41 @@ - void - greeter_item_ulist_select_user (gchar *login) - { -- printf ("%c%c%c%s\n", STX, BEL, -- GDM_INTERRUPT_SELECT_USER, login); -+ /*printf ("%c%c%c%s\n", STX, BEL, -+ GDM_INTERRUPT_SELECT_USER, login);*/ -+ printf ("%c%s\n", STX, login); - - fflush (stdout); - } - -+ -+static GTimeVal last_key_press = {0, 0}; -+static GTimeVal last_button_press = {0, 0}; -+ - static void - user_selected (GtkTreeSelection *selection, gpointer data) - { - GtkTreeModel *tm = NULL; - GtkTreeIter iter = {0}; -+ gboolean is_button_press; -+ guint64 button_msec; -+ guint64 key_msec; - -+ /* HACK: determine whether selection changed because of key or -+ * button press -+ * -+ * The rationale is this: if a face is pressed with the mouse -+ * we should start authenticating that user right away. But if -+ * the user uses keynav in the user list (think accessibility -+ * and blind users) we shouldn't. -+ */ -+ button_msec = last_button_press.tv_sec * 1000 + last_button_press.tv_usec / 1000; -+ key_msec = last_key_press.tv_sec * 1000 + last_key_press.tv_usec / 1000; -+ is_button_press = FALSE; -+ if (button_msec > key_msec) { -+ is_button_press = TRUE; -+ } -+ - if (gtk_tree_selection_get_selected (selection, &tm, &iter)) { - char *login; - -@@ -236,14 +259,19 @@ - &login, -1); - if (login != NULL) { - if (selecting_user && greeter_probably_login_prompt) { -- gtk_entry_set_text (GTK_ENTRY (pam_entry), login); -+ if (is_button_press) { -+ gtk_entry_set_text (GTK_ENTRY (pam_entry), login); -+ } else { -+ gtk_entry_set_text (GTK_ENTRY (pam_entry), ""); -+ } - } - if (selecting_user) { - GreeterItemInfo *pamlabel = greeter_lookup_id ("pam-message"); - if (pamlabel == NULL) { - gdm_common_warning ("Theme broken: must have pam-message label!"); - } -- greeter_item_ulist_select_user (login); -+ if (is_button_press) -+ greeter_item_ulist_select_user (login); - if (selected_user != NULL) - g_free (selected_user); - selected_user = g_strdup (login); -@@ -253,11 +281,28 @@ - } - - static void --browser_change_focus (GtkWidget *widget, GdkEventButton *event, gpointer data) -+row_activated (GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column, gpointer data) - { -- gtk_widget_grab_focus (pam_entry); -+ if (selecting_user && greeter_probably_login_prompt) { -+ greeter_item_ulist_select_user (selected_user); -+ } - } - -+static gboolean -+tv_key_press (GtkWidget *entry, GdkEventKey *event, gpointer data) -+{ -+ g_get_current_time (&last_key_press); -+ return FALSE; -+} -+ -+ -+static gboolean -+tv_button_press (GtkWidget *entry, GdkEventKey *event, gpointer data) -+{ -+ g_get_current_time (&last_button_press); -+ return FALSE; -+} -+ - static void - greeter_generate_userlist (GtkWidget *tv) - { -@@ -267,6 +312,12 @@ - GreeterItemInfo *info; - GList *list, *li; - -+ AtkObject *atk_widget; -+ atk_widget = gtk_widget_get_accessible (tv); -+ if (atk_widget != NULL) { -+ atk_object_set_name (atk_widget, _("Select user to log in")); -+ } -+ - gdm_greeter_users_init (); - - check_for_displays (); -@@ -279,11 +330,14 @@ - g_signal_connect (selection, "changed", - G_CALLBACK (user_selected), - NULL); -- -- g_signal_connect (GTK_TREE_VIEW (tv), "button_release_event", -- G_CALLBACK (browser_change_focus), -+ g_signal_connect (G_OBJECT (tv), "row-activated", -+ G_CALLBACK (row_activated), - NULL); -+ g_signal_connect (G_OBJECT (tv), "key-press-event", -+ G_CALLBACK (tv_key_press), user_list); -+ g_signal_connect (G_OBJECT (tv), "button-press-event", -+ G_CALLBACK (tv_button_press), user_list); - - tm = (GtkTreeModel *)gtk_list_store_new (4, - GDK_TYPE_PIXBUF, - -Index: gui/greeter/greeter_item_pam.c -=================================================================== ---- gui/greeter/greeter_item_pam.c (revision 4626) -+++ gui/greeter/greeter_item_pam.c (working copy) -@@ -184,14 +184,6 @@ - const char *login_string; - GtkWidget *entry = GNOME_CANVAS_WIDGET (entry_info->item)->widget; - -- if ((event->keyval == GDK_Tab || -- event->keyval == GDK_KP_Tab) && -- (event->state & (GDK_CONTROL_MASK|GDK_MOD1_MASK|GDK_SHIFT_MASK)) == 0) -- { -- greeter_item_pam_login (GTK_ENTRY (entry), entry_info); -- return TRUE; -- } -- - if (gtk_ok_button != NULL) - { - /* -@@ -208,6 +200,19 @@ - return FALSE; - } - -+/* We *never* want to lose focus when we are in the process of -+ * authenticating the user */ -+static gboolean -+pam_focus_out_event (GtkWidget *widget, -+ GdkEventFocus *event, -+ gpointer user_data) -+{ -+ if (!greeter_probably_login_prompt) { -+ gtk_widget_grab_focus (widget); -+ } -+ return FALSE; -+} -+ - gboolean - greeter_item_pam_setup (void) - { -@@ -238,7 +243,9 @@ - g_signal_connect (entry, "activate", - G_CALLBACK (greeter_item_pam_login), entry_info); - g_signal_connect (G_OBJECT (entry), "key_release_event", -- G_CALLBACK (pam_key_release_event), NULL); -+ G_CALLBACK (pam_key_release_event), NULL); -+ g_signal_connect (G_OBJECT (entry), "focus-out-event", -+ G_CALLBACK (pam_focus_out_event), NULL); - } - - return TRUE; -@@ -260,6 +267,21 @@ - if (conversation_info) - { - set_text (conversation_info, message); -+ -+ if (entry_info != NULL) { -+ GnomeCanvasWidget *item = GNOME_CANVAS_WIDGET (entry_info->item); -+ if (item != NULL) { -+ GtkWidget *widget = item->widget; -+ if (widget != NULL) { -+ AtkObject *atk_widget; -+ atk_widget = gtk_widget_get_accessible (widget); -+ if (atk_widget != NULL) { -+ atk_object_set_name (atk_widget, message); -+ } -+ } -+ } -+ } -+ - } - - if (entry_info && entry_info->item && - diff --git a/gdm-2.17.8-hide-uninstalled-languages.patch b/gdm-2.17.8-hide-uninstalled-languages.patch deleted file mode 100644 index 71a9fa7..0000000 --- a/gdm-2.17.8-hide-uninstalled-languages.patch +++ /dev/null @@ -1,153 +0,0 @@ ---- gdm-2.17.8/gui/gdmcommon.h.hide-uninstalled-languages 2007-03-09 12:30:58.000000000 -0500 -+++ gdm-2.17.8/gui/gdmcommon.h 2007-03-09 12:31:59.000000000 -0500 -@@ -67,5 +67,5 @@ - void gdm_common_atspi_launch (void); - gchar* gdm_common_expand_text (const gchar *text); - gchar* gdm_common_get_clock (struct tm **the_tm); -- -+gboolean gdm_common_locale_is_displayable (const gchar *locale); - #endif /* GDM_COMMON_H */ ---- gdm-2.17.8/gui/gdmlogin.c.hide-uninstalled-languages 2007-03-09 12:22:36.000000000 -0500 -+++ gdm-2.17.8/gui/gdmlogin.c 2007-03-09 12:22:39.000000000 -0500 -@@ -1192,6 +1192,11 @@ - - li->data = NULL; - -+ if (!gdm_common_locale_is_displayable (lang)) { -+ g_free (lang); -+ continue; -+ } -+ - group = name = gdm_lang_name (lang, - FALSE /* never_encoding */, - FALSE /* no_group */, -@@ -1202,6 +1207,8 @@ - continue; - } - -+ -+ - untranslated = gdm_lang_untranslated_name (lang, - TRUE /* markup */); - ---- gdm-2.17.8/gui/gdmcommon.c.hide-uninstalled-languages 2007-02-26 03:59:31.000000000 -0500 -+++ gdm-2.17.8/gui/gdmcommon.c 2007-03-09 12:21:29.000000000 -0500 -@@ -33,6 +33,8 @@ - #include - #include - -+#include -+ - #include - #include - #include -@@ -843,3 +845,95 @@ - return g_string_free (str, FALSE); - } - -+typedef enum -+{ -+ LOCALE_UP_TO_LANGUAGE = 0, -+ LOCALE_UP_TO_COUNTRY, -+ LOCALE_UP_TO_ENCODING, -+ LOCALE_UP_TO_MODIFIER, -+} LocaleScope; -+ -+static char * -+get_less_specific_locale (const char *locale, -+ LocaleScope scope) -+{ -+ char *generalized_locale; -+ char *end; -+ -+ generalized_locale = strdup (locale); -+ -+ end = strchr (generalized_locale, '_'); -+ -+ if (end != NULL && scope <= LOCALE_UP_TO_LANGUAGE) -+ { -+ *end = '\0'; -+ return generalized_locale; -+ } -+ -+ end = strchr (generalized_locale, '.'); -+ -+ if (end != NULL && scope <= LOCALE_UP_TO_COUNTRY) -+ { -+ *end = '\0'; -+ return generalized_locale; -+ } -+ -+ end = strchr (generalized_locale, '@'); -+ -+ if (end != NULL && scope <= LOCALE_UP_TO_ENCODING) -+ { -+ *end = '\0'; -+ return generalized_locale; -+ } -+ -+ return generalized_locale; -+} -+ -+gboolean -+gdm_common_locale_is_displayable (const gchar *locale) -+{ -+ char *language_code; -+ gboolean is_displayable; -+ -+ FcPattern *pattern; -+ FcObjectSet *object_set; -+ FcFontSet *font_set; -+ -+ is_displayable = FALSE; -+ pattern = NULL; -+ object_set = NULL; -+ font_set = NULL; -+ -+ language_code = get_less_specific_locale (locale, LOCALE_UP_TO_LANGUAGE); -+ -+ pattern = FcPatternBuild (NULL, FC_LANG, FcTypeString, language_code, NULL); -+ -+ if (pattern == NULL) -+ goto done; -+ -+ object_set = FcObjectSetBuild (NULL, NULL); -+ -+ if (object_set == NULL) -+ goto done; -+ -+ font_set = FcFontList (NULL, pattern, object_set); -+ -+ if (font_set == NULL) -+ goto done; -+ -+ is_displayable = (font_set->nfont > 0); -+ -+done: -+ -+ if (font_set != NULL) -+ FcFontSetDestroy (font_set); -+ -+ if (object_set != NULL) -+ FcObjectSetDestroy (object_set); -+ -+ if (pattern != NULL) -+ FcPatternDestroy (pattern); -+ -+ g_free (language_code); -+ return is_displayable; -+} ---- gdm-2.17.8/gui/greeter/greeter_action_language.c.hide-uninstalled-languages 2007-02-26 03:59:30.000000000 -0500 -+++ gdm-2.17.8/gui/greeter/greeter_action_language.c 2007-03-09 12:37:17.000000000 -0500 -@@ -86,6 +86,11 @@ - - li->data = NULL; - -+ if (!gdm_common_locale_is_displayable (lang)) { -+ g_free (lang); -+ continue; -+ } -+ - name = gdm_lang_name (lang, - FALSE /* never_encoding */, - TRUE /* no_group */, diff --git a/gdm-2.18.0-add-lowres-fix.patch b/gdm-2.18.0-add-lowres-fix.patch deleted file mode 100644 index f49623f..0000000 --- a/gdm-2.18.0-add-lowres-fix.patch +++ /dev/null @@ -1,92 +0,0 @@ ---- gdm-2.18.0/gui/greeter/greeter_item.c.add-lowres-fix 2007-03-11 17:46:10.000000000 -0400 -+++ gdm-2.18.0/gui/greeter/greeter_item.c 2007-03-20 12:13:24.000000000 -0400 -@@ -26,6 +26,7 @@ - #include - - #include "gdm.h" -+#include "gdmwm.h" - #include "gdmconfig.h" - #include "gdmcommon.h" - #include "misc.h" -@@ -181,6 +182,10 @@ - ! (info->show_modes & GREETER_ITEM_SHOW_REMOTE)) - return FALSE; - -+ if ((gdm_wm_screen.width < info->minimum_required_screen_width) || -+ (gdm_wm_screen.height < info->minimum_required_screen_height)) -+ return FALSE; -+ - sysmenu = gdm_config_get_bool (GDM_KEY_SYSTEM_MENU); - - if (( ! gdm_config_get_bool (GDM_KEY_CONFIG_AVAILABLE) || ---- gdm-2.18.0/gui/greeter/greeter_parser.c.add-lowres-fix 2007-03-20 12:13:24.000000000 -0400 -+++ gdm-2.18.0/gui/greeter/greeter_parser.c 2007-03-20 12:45:26.000000000 -0400 -@@ -27,6 +27,7 @@ - #include - #include - #include -+#include - - #include "gdmwm.h" - #include "gdmcommon.h" -@@ -597,7 +598,23 @@ - } - xmlFree (prop); - } -- -+ -+ prop = xmlGetProp (node,(const xmlChar *) "min-screen-width"); -+ if (prop != NULL) -+ { -+ syslog (LOG_ERR, "minimum width is %d", info->minimum_required_screen_height); -+ info->minimum_required_screen_width = atoi ((char *) prop); -+ xmlFree (prop); -+ } -+ -+ prop = xmlGetProp (node,(const xmlChar *) "min-screen-height"); -+ if (prop != NULL) -+ { -+ info->minimum_required_screen_height = atoi ((char *) prop); -+ syslog (LOG_ERR, "minimum height is %d", info->minimum_required_screen_height); -+ xmlFree (prop); -+ } -+ - prop = xmlGetProp (node,(const xmlChar *) "modes"); - if (prop != NULL) - { ---- gdm-2.18.0/gui/greeter/greeter_item.h.add-lowres-fix 2007-03-20 12:13:24.000000000 -0400 -+++ gdm-2.18.0/gui/greeter/greeter_item.h 2007-03-20 12:13:24.000000000 -0400 -@@ -89,6 +89,10 @@ - float y; - float width; - float height; -+ -+ int minimum_required_screen_width; -+ int minimum_required_screen_height; -+ - GreeterItemPosType x_type:2; - GreeterItemPosType y_type:2; - GreeterItemSizeType width_type:4; ---- gdm-2.18.0/docs/C/gdm.xml.add-lowres-fix 2007-03-20 12:53:33.000000000 -0400 -+++ gdm-2.18.0/docs/C/gdm.xml 2007-03-20 12:56:20.000000000 -0400 -@@ -6544,6 +6544,20 @@ - - - -+ Alternatively, you can specify a "min-screen-width" or -+ "min-screen-height" value to indicate that certain -+ items should only be displayed if the screen resolution is the -+ at least the given required size. -+ -+ -+ -+ For example: -+ -+<show min-screen-height="768"/> -+ -+ -+ -+ - Note that if SystemMenu is off then the halt, restart, suspend, - chooser and config choices will not be shown, so this is a global - toggle for them all. See some of the standard themes for how the diff --git a/gdm-2.18.0-change-defaults.patch b/gdm-2.18.0-change-defaults.patch deleted file mode 100644 index b5171fb..0000000 --- a/gdm-2.18.0-change-defaults.patch +++ /dev/null @@ -1,181 +0,0 @@ ---- gdm-2.18.0/config/gdm.conf.in.orig 2007-03-11 17:46:16.000000000 -0400 -+++ gdm-2.18.0/config/gdm.conf.in 2007-03-13 18:25:12.000000000 -0400 -@@ -66,9 +66,9 @@ - # should leave this alone. - #Chooser=@libexecdir@/gdmchooser - --# The greeter for local (non-xdmcp) logins. Change gdmlogin to gdmgreeter to --# get the new graphical greeter. --#Greeter=@libexecdir@/gdmlogin -+# The greeter for local (non-xdmcp) logins. Change gdmgreeter to gdmlogin to -+# get the boring greeter. -+Greeter=@libexecdir@/gdmgreeter - - # The greeter for xdmcp logins, usually you want a less graphically intensive - # greeter here so it's better to leave this with gdmlogin -@@ -78,23 +78,21 @@ - # This is useful for enabling additional feature support e.g. GNOME - # accessibility framework. Only "trusted" modules should be allowed to minimize - # security holes --#AddGtkModules=false -+AddGtkModules=true - # By default, these are the accessibility modules. --#GtkModulesList=gail:atk-bridge:@libdir@/gtk-2.0/modules/libdwellmouselistener:@libdir@/gtk-2.0/modules/libkeymouselistener -+GtkModulesList=gail:atk-bridge:@libdir@/gtk-2.0/modules/libdwellmouselistener:@libdir@/gtk-2.0/modules/libkeymouselistener - - # Default path to set. The profile scripts will likely override this value. - # This value will be overridden with the value from /etc/default/login if it - # contains "ROOT=". --#DefaultPath=@GDM_USER_PATH@ -+DefaultPath=/usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin - # Default path for root. The profile scripts will likely override this value. - # This value will be overridden with the value from /etc/default/login if it - # contains "SUROOT=". --#RootPath=/sbin:/usr/sbin:@GDM_USER_PATH@ -+RootPath=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin - --# If you are having trouble with using a single server for a long time and want --# GDM to kill/restart the server, turn this on. On Solaris, this value is --# always true and this configuration setting is ignored. --#AlwaysRestartServer=false -+# Whether to restart X server after the user logs out or not. -+AlwaysRestartServer=true - - # User and group used for running GDM GUI applicaitons. By default this is set - # to user "gdm" and group "gdm". This user/group should have very limited -@@ -125,22 +123,21 @@ - XKeepsCrashing=@gdmconfdir@/XKeepsCrashing - # Reboot, Halt and suspend commands, you can add different commands separated - # by a semicolon. GDM will use the first one it can find. --#RebootCommand=@REBOOT_COMMAND@ --#HaltCommand=@HALT_COMMAND@ --#SuspendCommand=@SUSPEND_COMMAND@ -+RebootCommand=/sbin/reboot;/sbin/shutdown -r now;/usr/sbin/shutdown -r now;/usr/bin/reboot -+HaltCommand=/sbin/poweroff;/sbin/shutdown -h now;/usr/sbin/shutdown -h now;/usr/bin/poweroff - # Probably should not touch the below this is the standard setup. - ServAuthDir=@authdir@ - # This is our standard startup script. A bit different from a normal X - # session, but it shares a lot of stuff with that. See the provided default - # for more information. --BaseXsession=@gdmconfdir@/Xsession -+BaseXsession=/etc/X11/xinit/Xsession - # This is a directory where .desktop files describing the sessions live. It is - # really a PATH style variable since 2.4.4.2 to allow actual interoperability - # with KDM. Note that /Sessions is there for backwards - # compatibility reasons with 2.4.4.x. - #SessionDesktopDir=/etc/X11/sessions/:@dmconfdir@/Sessions/:@datadir@/gdm/BuiltInSessions/:@datadir@/xsessions/ - # This is the default .desktop session. One of the ones in SessionDesktopDir --#DefaultSession=gnome.desktop -+DefaultSession=default.desktop - # Better leave this blank and HOME will be used. You can use syntax ~/ below - # to indicate home directory of the user. You can also set this to something - # like /tmp if you don't want the authorizations to be in home directories. -@@ -148,11 +145,11 @@ - # is the home directory the UserAuthFBDir will still be used in case the home - # directory is NFS, see security/NeverPlaceCookiesOnNFS to override this - # behavior. --UserAuthDir= -+UserAuthDir=/tmp - # Fallback directory for writing authorization file if user's home directory - # is not writable. - UserAuthFBDir=/tmp --UserAuthFile=.Xauthority -+#UserAuthFile=.Xauthority - # The X server to use if we can't figure out what else to run. - StandardXServer=@X_SERVER@ - # The maximum number of flexible X servers to run. -@@ -173,7 +170,7 @@ - #DoubleLoginWarning=true - # Should a second login always resume the current session and switch VT's on - # Linux and FreeBSD systems for console logins --#AlwaysLoginCurrentSession=true -+AlwaysLoginCurrentSession=true - - # If true then the last login information is printed to the user before being - # prompted for password. While this gives away some info on what users are on -@@ -297,7 +294,7 @@ - #GtkRC=@datadir@/themes/Default/gtk-2.0/gtkrc - - # The GTK+ theme to use for the GUI. --#GtkTheme=Default -+GtkTheme=Clearlooks - # If to allow changing the GTK+ (widget) theme from the greeter. Currently - # this only affects the standard greeter as the graphical greeter does not yet - # have this ability. -@@ -318,7 +315,7 @@ - # themed login (gdmgreeter). - # - # The standard login has a title bar that the user can move. --#TitleBar=true -+TitleBar=false - # Don't allow user to move the standard login window. Only makes sense if - # TitleBar is on. - #LockPosition=false -@@ -342,7 +339,7 @@ - # User ID's less than the MinimalUID value will not be included in the face - # browser or in the gdmselection list for Automatic/Timed login. They will not - # be displayed regardless of the settings for Include and Exclude. --#MinimalUID=100 -+MinimalUID=500 - # Users listed in Include will be included in the face browser and in the - # gdmsetup selection list for Automatic/Timed login. Users should be separated - # by commas. -@@ -359,7 +356,7 @@ - # large numbers of users and this feature should not be used in such - # environments. The setting of IncludeAll does nothing if Include is set to a - # non-empty value. --#IncludeAll=false -+IncludeAll=true - # If user or user.png exists in this dir it will be used as his picture. - #GlobalFaceDir=@datadir@/pixmaps/faces/ - -@@ -368,7 +365,7 @@ - # file, although GDM will be able to read a standard locale.alias file as well. - #LocaleFile=@gdmlocaledir@/locale.alias - # Logo shown in the standard greeter. --#Logo=@pixmapdir@/gdm-foot-logo.png -+Logo= - # Logo shown on file chooser button in gdmsetup (do not modify this value). - #ChooserButtonLogo=@pixmapdir@/gdm-foot-logo.png - # The standard greeter should shake if a user entered the wrong username or -@@ -415,8 +412,9 @@ - # The Standard greeter (gdmlogin) uses BackgroundColor as the background - # color, while the themed greeter (gdmgreeter) uses GraphicalThemedColor - # as the background color. --BackgroundColor=#76848F --GraphicalThemedColor=#76848F -+BackgroundColor=#20305a -+GraphicalThemedColor=#000000 -+ - # XDMCP session should only get a color, this is the sanest setting since you - # don't want to take up too much bandwidth - #BackgroundRemoteOnlyColor=true -@@ -437,8 +435,8 @@ - # Show the Failsafe sessions. These are much MUCH nicer (focus for xterm for - # example) and more failsafe then those supplied by scripts so distros should - # use this rather then just running an xterm from a script. --#ShowGnomeFailsafeSession=true --#ShowXtermFailsafeSession=true -+ShowGnomeFailsafeSession=false -+ShowXtermFailsafeSession=false - # Normally there is a session type called 'Last' that is shown which refers to - # the last session the user used. If off, we will be in 'switchdesk' mode - # where the session saving stuff is disabled in GDM -@@ -457,7 +455,7 @@ - # list then provide a list that is delimited by /: to the GraphicalThemes - # key and set GraphicalThemeRand to true. Otherwise use GraphicalTheme - # and specify just one theme. --#GraphicalTheme=circles -+GraphicalTheme=FedoraFlyingHigh - #GraphicalThemes=circles/:happygnome - GraphicalThemeDir=@datadir@/gdm/themes/ - GraphicalThemeRand=false -@@ -561,7 +559,7 @@ - # Definition of the standard X server. - [server-Standard] - name=Standard server --command=@X_SERVER@ @X_CONFIG_OPTIONS@ @XEVIE_OPTION@ -+command=@X_SERVER@ -br @X_CONFIG_OPTIONS@ @XEVIE_OPTION@ - flexible=true - # Indicates that the X server should be started at a different process - # priority. Values can be any integer value accepted by the setpriority C diff --git a/gdm-2.18.0-dont-expect-utf8.patch b/gdm-2.18.0-dont-expect-utf8.patch deleted file mode 100644 index 7578e07..0000000 --- a/gdm-2.18.0-dont-expect-utf8.patch +++ /dev/null @@ -1,69 +0,0 @@ ---- gdm-2.18.0/gui/gdmlogin.c.dont-expect-utf8 2007-04-05 12:02:47.000000000 -0400 -+++ gdm-2.18.0/gui/gdmlogin.c 2007-04-05 12:03:24.000000000 -0400 -@@ -2042,8 +2042,8 @@ - char *label; - char *login, *gecos; - -- login = g_markup_escape_text (usr->login, -1); -- gecos = g_markup_escape_text (usr->gecos, -1); -+ login = gdm_common_text_to_escaped_utf8 (usr->login); -+ gecos = gdm_common_text_to_escaped_utf8 (usr->gecos); - - label = g_strdup_printf ("%s\n%s", - login, ---- gdm-2.18.0/gui/gdmcommon.c.dont-expect-utf8 2007-04-05 11:59:23.000000000 -0400 -+++ gdm-2.18.0/gui/gdmcommon.c 2007-04-05 12:02:29.000000000 -0400 -@@ -379,6 +379,29 @@ - return pixbuf; - } - -+gchar * -+gdm_common_text_to_escaped_utf8 (const char *text) -+{ -+ gchar *utf8_string, *escaped_string, *p; -+ const gchar *q; -+ -+ utf8_string = g_strdup (text); -+ p = utf8_string; -+ while ((*p != '\0') && -+ !g_utf8_validate (p, -1, &q)) { -+ p = (gchar *) q; -+ *p = '?'; -+ p++; -+ } -+ -+ g_assert (g_utf8_validate (utf8_string, -1, NULL)); -+ -+ escaped_string = g_markup_escape_text (utf8_string, -1); -+ g_free (utf8_string); -+ -+ return escaped_string; -+} -+ - gchar * - gdm_common_get_config_file (void) - { ---- gdm-2.18.0/gui/gdmcommon.h.dont-expect-utf8 2007-04-05 11:59:37.000000000 -0400 -+++ gdm-2.18.0/gui/gdmcommon.h 2007-04-05 12:00:40.000000000 -0400 -@@ -58,6 +58,7 @@ - guint max_width, - guint max_height); - -+gchar* gdm_common_text_to_escaped_utf8 (const char *text); - gchar* gdm_common_get_config_file (void); - gchar* gdm_common_get_custom_config_file (void); - gboolean gdm_common_select_time_format (void); ---- gdm-2.18.0/gui/greeter/greeter_item_ulist.c.dont-expect-utf8 2007-04-05 11:59:05.000000000 -0400 -+++ gdm-2.18.0/gui/greeter/greeter_item_ulist.c 2007-04-05 12:02:09.000000000 -0400 -@@ -181,9 +181,9 @@ - gboolean active; - - if (usr->gecos && strcmp (usr->gecos, "") != 0) { -- name = g_markup_escape_text (usr->gecos, -1); -+ name = gdm_common_text_to_escaped_utf8 (usr->gecos); - } else { -- name = g_markup_escape_text (usr->login, -1); -+ name = gdm_common_text_to_escaped_utf8 (usr->login); - } - - if (g_hash_table_lookup (displays_hash, usr->login)) diff --git a/gdm-2.18.0-dont-strcpy-overlapping-strings.patch b/gdm-2.18.0-dont-strcpy-overlapping-strings.patch deleted file mode 100644 index a810bf1..0000000 --- a/gdm-2.18.0-dont-strcpy-overlapping-strings.patch +++ /dev/null @@ -1,13 +0,0 @@ ---- gdm-2.18.0/gui/gdmlanguages.c.dont-strcpy-overlapping-strings 2007-03-29 15:03:42.000000000 -0400 -+++ gdm-2.18.0/gui/gdmlanguages.c 2007-03-29 15:05:07.000000000 -0400 -@@ -445,7 +445,9 @@ - if (no_group) { - char *p = strchr (name, '|'); - if (p != NULL) { -- strcpy (name, p+1); -+ p = g_strdup (p + 1); -+ g_free (name); -+ name = p; - } - } - diff --git a/gdm-2.18.0-security-tokens.patch b/gdm-2.18.0-security-tokens.patch deleted file mode 100644 index 276bb88..0000000 --- a/gdm-2.18.0-security-tokens.patch +++ /dev/null @@ -1,2880 +0,0 @@ ---- gdm-2.18.0/config/gdm.conf.in.security-tokens 2007-03-20 01:21:20.000000000 -0400 -+++ gdm-2.18.0/config/gdm.conf.in 2007-03-20 01:21:24.000000000 -0400 -@@ -200,6 +200,10 @@ - # kills it. 10 seconds should be long enough for X, but Xgl may need 20 or 25. - GdmXserverTimeout=10 - -+# Whether or not to listen for smart card insertion/removal events -+SecurityTokensEnable=true -+SecurityTokensDriver= -+ - [security] - # Allow root to login. It makes sense to turn this off for kiosk use, when - # you want to minimize the possibility of break in. ---- /dev/null 2007-03-19 18:45:10.978423391 -0400 -+++ gdm-2.18.0/config/securitytokens.conf.in 2007-03-20 01:21:24.000000000 -0400 -@@ -0,0 +1,3 @@ -+[SecurityTokens] -+Enable=true -+#Driver=@libdir@/pkcs11/libcoolkeypk11.so ---- gdm-2.18.0/config/Makefile.am.security-tokens 2007-03-11 17:46:16.000000000 -0400 -+++ gdm-2.18.0/config/Makefile.am 2007-03-20 01:22:40.000000000 -0400 -@@ -34,9 +34,11 @@ - XKeepsCrashing \ - gettextfoo.h \ - gdmprefetchlist.in \ -+ securitytokens.conf.in \ - extract-shell.sh - --CLEANFILES = Xsession gdm.conf gdm.conf-custom default.desktop gnome.desktop CDE.desktop ssh.desktop Init PreSession PostSession gdmprefetchlist -+CLEANFILES = Xsession gdm.conf gdm.conf-custom default.desktop gnome.desktop CDE.desktop ssh.desktop Init PreSession PostSession gdmprefetchlist securitytokens.conf -+ - - Xsession: $(srcdir)/Xsession.in - sed -e 's,[@]XSESSION_SHELL[@],$(XSESSION_SHELL),g' \ -@@ -72,6 +74,31 @@ - sed -e 's,[@]GDM_DEFAULTS_CONF[@],$(GDM_DEFAULTS_CONF),g' \ - <$(srcdir)/gdm.conf-custom.in >gdm.conf-custom - -+securitytokens.conf: $(srcdir)/securitytokens.conf.in -+ sed -e 's,[@]GDMPREFETCHCMD[@],$(GDMPREFETCHCMD),g' \ -+ -e 's,[@]GDM_USER_PATH[@],$(GDM_USER_PATH),g' \ -+ -e 's,[@]HALT_COMMAND[@],$(HALT_COMMAND),g' \ -+ -e 's,[@]REBOOT_COMMAND[@],$(REBOOT_COMMAND),g' \ -+ -e 's,[@]SOUND_PROGRAM[@],$(SOUND_PROGRAM),g' \ -+ -e 's,[@]SUSPEND_COMMAND[@],$(SUSPEND_COMMAND),g' \ -+ -e 's,[@]XEVIE_OPTION[@],$(XEVIE_OPTION),g' \ -+ -e 's,[@]X_CONFIG_OPTIONS[@],$(X_CONFIG_OPTIONS),g' \ -+ -e 's,[@]X_SERVER[@],$(X_SERVER),g' \ -+ -e 's,[@]X_XNEST_CONFIG_OPTIONS[@],$(X_XNEST_CONFIG_OPTIONS),g' \ -+ -e 's,[@]X_XNEST_PATH[@],$(X_XNEST_PATH),g' \ -+ -e 's,[@]authdir[@],$(authdir),g' \ -+ -e 's,[@]datadir[@],$(datadir),g' \ -+ -e 's,[@]dmconfdir[@],$(dmconfdir),g' \ -+ -e 's,[@]gdmconfdir[@],$(gdmconfdir),g' \ -+ -e 's,[@]libdir[@],$(libdir),g' \ -+ -e 's,[@]libexecdir[@],$(libexecdir),g' \ -+ -e 's,[@]localedir[@],$(libexecdir),g' \ -+ -e 's,[@]logdir[@],$(logdir),g' \ -+ -e 's,[@]pixmapdir[@],$(pixmapdir),g' \ -+ -e 's,[@]sbindir[@],$(sbindir),g' \ -+ <$(srcdir)/securitytokens.conf.in >securitytokens.conf -+ -+ - gettextfoo.h: XKeepsCrashing Xsession.in - cat $^ | $(srcdir)/extract-shell.sh > gettextfoo.h - -@@ -100,7 +127,7 @@ - $(DESTDIR)$(predir)/Default \ - $(DESTDIR)$(postdir)/Default - --install-data-hook: gdm.conf gdm.conf-custom Xsession Init PostSession PreSession $(DESKTOP_FILES) $(GDMPREFETCHLIST) -+install-data-hook: gdm.conf gdm.conf-custom Xsession Init PostSession PreSession $(DESKTOP_FILES) $(GDMPREFETCHLIST) securitytokens.conf - if test '!' -d $(DESTDIR)$(confdir); then \ - $(mkinstalldirs) $(DESTDIR)$(confdir); \ - chmod 755 $(DESTDIR)$(confdir); \ -@@ -133,6 +160,7 @@ - chmod 644 $(DESTDIR)$(GDM_CUSTOM_CONF); \ - fi - $(INSTALL_DATA) gdm.conf `dirname $(DESTDIR)$(GDM_DEFAULTS_CONF)`/factory-`basename $(DESTDIR)$(GDM_DEFAULTS_CONF)` -+ $(INSTALL_DATA) securitytokens.conf $(DESTDIR)$(confdir)/securitytokens.conf - - $(INSTALL_SCRIPT) $(srcdir)/XKeepsCrashing $(DESTDIR)$(confdir)/XKeepsCrashing - $(INSTALL_SCRIPT) Xsession $(DESTDIR)$(confdir)/Xsession ---- gdm-2.18.0/configure.ac.security-tokens 2007-03-20 01:21:24.000000000 -0400 -+++ gdm-2.18.0/configure.ac 2007-03-20 01:21:24.000000000 -0400 -@@ -20,6 +20,7 @@ - LIBXML_REQUIRED=2.4.12 - LIBART_REQUIRED=2.3.11 - SCROLLKEEPER_REQUIRED=0.1.4 -+NSS_REQUIRED=3.11.1 - - dnl - dnl Let the user configure where to look for the configuration files. -@@ -176,7 +177,7 @@ - AC_SUBST(VICIOUS_CFLAGS) - AC_SUBST(VICIOUS_LIBS) - --PKG_CHECK_MODULES(DAEMON, gtk+-2.0 >= $GTK_REQUIRED dbus-glib-1 >= $DBUS_REQUIRED) -+PKG_CHECK_MODULES(DAEMON, gtk+-2.0 >= $GTK_REQUIRED dbus-glib-1 >= $DBUS_REQUIRED nss >= $NSS_REQUIRED) - AC_SUBST(DAEMON_CFLAGS) - AC_SUBST(DAEMON_LIBS) - ---- /dev/null 2007-03-19 18:45:10.978423391 -0400 -+++ gdm-2.18.0/daemon/securitytokenmonitor.h 2007-03-20 01:21:24.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 */ ---- gdm-2.18.0/daemon/gdm.c.security-tokens 2007-03-20 01:21:24.000000000 -0400 -+++ gdm-2.18.0/daemon/gdm.c 2007-03-20 01:21:24.000000000 -0400 -@@ -68,6 +68,8 @@ - #include "filecheck.h" - #include "gdmconfig.h" - #include "errorgui.h" -+#include "securitytokenmonitor.h" -+#include "securitytoken.h" - - #define DYNAMIC_ADD 0 - #define DYNAMIC_RELEASE 1 -@@ -77,6 +79,7 @@ - #include - #endif /* HAVE_LOGINDEVPERM */ - -+ - extern GSList *displays; - - /* Local functions */ -@@ -86,6 +89,10 @@ - static void gdm_handle_user_message (GdmConnection *conn, - const gchar *msg, - gpointer data); -+ -+static void gdm_reset_local_displays (void); -+static void gdm_watch_for_security_tokens (void); -+ - static void gdm_daemonify (void); - static void gdm_safe_restart (void); - static void gdm_try_logout_action (GdmDisplay *disp); -@@ -159,7 +166,6 @@ - - static gboolean monte_carlo_sqrt2 = FALSE; - -- - /* - * lookup display number if the display number is - * exists then clear the remove flag and return TRUE -@@ -1546,6 +1552,8 @@ - - g_type_init (); - -+ g_type_init (); -+ - ctx = g_option_context_new (_("- The GNOME login manager")); - g_option_context_add_main_entries (ctx, options, _("main options")); - -@@ -1788,6 +1796,8 @@ - gdm_xdmcp_run (); - } - -+ gdm_watch_for_security_tokens (); -+ - /* We always exit via exit (), and sadly we need to g_main_quit () - * at times not knowing if it's this main or a recursive one we're - * quitting. -@@ -3996,4 +4006,85 @@ - } - } - -+static void -+gdm_reset_local_displays (void) -+{ -+ GSList *li; -+ -+ for (li = displays; li != NULL; li = li->next) { -+ GdmDisplay *d = li->data; -+ -+ if (d->attached) -+ send_slave_command (d, GDM_NOTIFY_RESET); -+ } -+} -+ -+ -+ -+ -+ -+ -+ -+#ifndef GDM_SECURITY_TOKENS_CONF -+#define GDM_SECURITY_TOKENS_CONF GDMCONFDIR "/securitytokens.conf" -+#endif -+ -+#ifndef GDM_SECURITY_TOKENS_KEY_ENABLED -+#define GDM_SECURITY_TOKENS_KEY_ENABLED "SecurityTokens/Enabled=true" -+#endif -+ -+#ifndef GDM_SECURITY_TOKENS_KEY_DRIVER -+#define GDM_SECURITY_TOKENS_KEY_DRIVER "SecurityTokens/Driver" -+#endif -+ -+static void -+gdm_watch_for_security_tokens (void) -+{ -+ GError *error; -+ ScSecurityTokenMonitor *monitor; -+ gchar *driver; -+ VeConfig *cfg; -+ -+ cfg = ve_config_new (GDM_SECURITY_TOKENS_CONF); -+ -+ if (!ve_config_get_bool (cfg, GDM_SECURITY_TOKENS_KEY_ENABLED)) { -+ gdm_debug ("security token support is not enabled"); -+ goto out; -+ } -+ -+ gdm_debug ("watching for security token insertion and removal events"); -+ -+ driver = ve_config_get_string (cfg, GDM_SECURITY_TOKENS_KEY_DRIVER); -+ gdm_debug ("security tokens driver is set to '%s'", -+ ve_string_empty (driver)? "" : driver); -+ monitor = sc_security_token_monitor_new (driver); -+ g_free (driver); -+ -+ g_signal_connect (monitor, -+ "security-token-inserted", -+ G_CALLBACK (gdm_reset_local_displays), -+ NULL); -+ -+ g_signal_connect (monitor, -+ "security-token-removed", -+ G_CALLBACK (gdm_reset_local_displays), -+ NULL); -+ -+ error = NULL; -+ if (!sc_security_token_monitor_start (monitor, &error)) { -+ g_object_unref (monitor); -+ monitor = NULL; -+ -+ if (error != NULL) { -+ syslog (LOG_ERR, "%s", error->message); -+ g_error_free (error); -+ } else { -+ syslog (LOG_ERR, "could not start security token monitor"); -+ -+ } -+ goto out; -+ } -+out: -+ ve_config_destroy (cfg); -+} - /* EOF */ ---- /dev/null 2007-03-19 18:45:10.978423391 -0400 -+++ gdm-2.18.0/daemon/securitytoken.h 2007-03-20 01:21:24.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 */ ---- /dev/null 2007-03-19 18:45:10.978423391 -0400 -+++ gdm-2.18.0/daemon/securitytoken.c 2007-03-20 01:21:24.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 ---- gdm-2.18.0/daemon/Makefile.am.security-tokens 2007-03-11 17:46:16.000000000 -0400 -+++ gdm-2.18.0/daemon/Makefile.am 2007-03-20 01:21:24.000000000 -0400 -@@ -9,6 +9,7 @@ - -DAUTHDIR=\"$(authdir)\" \ - -DBINDIR=\"$(bindir)\" \ - -DDATADIR=\"$(datadir)\" \ -+ -DSYSCONFDIR=\"$(sysconfdir)\" \ - -DDMCONFDIR=\"$(dmconfdir)\" \ - -DGDMCONFDIR=\"$(gdmconfdir)\" \ - -DGDMLOCALEDIR=\"$(gdmlocaledir)\" \ -@@ -72,7 +73,11 @@ - gdm-net.c \ - gdm-net.h \ - getvt.c \ -- getvt.h -+ getvt.h \ -+ securitytoken.c \ -+ securitytoken.h \ -+ securitytokenmonitor.c \ -+ securitytokenmonitor.h - - EXTRA_gdm_binary_SOURCES = verify-pam.c verify-crypt.c verify-shadow.c - ---- /dev/null 2007-03-19 18:45:10.978423391 -0400 -+++ gdm-2.18.0/daemon/securitytokenmonitor.c 2007-03-20 01:21:24.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 --git a/gdm-2.19.1-a11y-fixes-for-themed-greeter.patch b/gdm-2.19.1-a11y-fixes-for-themed-greeter.patch new file mode 100644 index 0000000..dfb4600 --- /dev/null +++ b/gdm-2.19.1-a11y-fixes-for-themed-greeter.patch @@ -0,0 +1,126 @@ +--- gdm-2.19.1/gui/greeter/greeter_item_ulist.c.a11y-fixes 2007-05-21 13:32:04.000000000 -0400 ++++ gdm-2.19.1/gui/greeter/greeter_item_ulist.c 2007-05-21 13:32:04.000000000 -0400 +@@ -236,17 +236,40 @@ greeter_populate_user_list (GtkTreeModel + void + greeter_item_ulist_select_user (gchar *login) + { +- printf ("%c%c%c%s\n", STX, BEL, +- GDM_INTERRUPT_SELECT_USER, login); ++ /*printf ("%c%c%c%s\n", STX, BEL, ++ GDM_INTERRUPT_SELECT_USER, login);*/ ++ printf ("%c%s\n", STX, login); + + fflush (stdout); + } + ++ ++static GTimeVal last_key_press = {0, 0}; ++static GTimeVal last_button_press = {0, 0}; ++ + static void + user_selected (GtkTreeSelection *selection, gpointer data) + { + GtkTreeModel *tm = NULL; + GtkTreeIter iter = {0}; ++ gboolean is_button_press; ++ guint64 button_msec; ++ guint64 key_msec; ++ ++ /* HACK: determine whether selection changed because of key or ++ * button press ++ * ++ * The rationale is this: if a face is pressed with the mouse ++ * we should start authenticating that user right away. But if ++ * the user uses keynav in the user list (think accessibility ++ * and blind users) we shouldn't. ++ */ ++ button_msec = last_button_press.tv_sec * 1000 + last_button_press.tv_usec / 1000; ++ key_msec = last_key_press.tv_sec * 1000 + last_key_press.tv_usec / 1000; ++ is_button_press = FALSE; ++ if (button_msec > key_msec) { ++ is_button_press = TRUE; ++ } + + if (gtk_tree_selection_get_selected (selection, &tm, &iter)) { + char *login; +@@ -255,14 +278,19 @@ user_selected (GtkTreeSelection *selecti + &login, -1); + if (login != NULL) { + if (selecting_user && greeter_probably_login_prompt) { +- gtk_entry_set_text (GTK_ENTRY (pam_entry), login); ++ if (is_button_press) { ++ gtk_entry_set_text (GTK_ENTRY (pam_entry), login); ++ } else { ++ gtk_entry_set_text (GTK_ENTRY (pam_entry), ""); ++ } + } + if (selecting_user) { + GreeterItemInfo *pamlabel = greeter_lookup_id ("pam-message"); + if (pamlabel == NULL) { + gdm_common_warning ("Theme broken: must have pam-message label!"); + } +- greeter_item_ulist_select_user (login); ++ if (is_button_press) ++ greeter_item_ulist_select_user (login); + if (selected_user != NULL) + g_free (selected_user); + selected_user = g_strdup (login); +@@ -272,9 +300,26 @@ user_selected (GtkTreeSelection *selecti + } + + static void +-browser_change_focus (GtkWidget *widget, GdkEventButton *event, gpointer data) ++row_activated (GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column, gpointer data) ++{ ++ if (selecting_user && greeter_probably_login_prompt) { ++ greeter_item_ulist_select_user (selected_user); ++ } ++} ++ ++static gboolean ++tv_key_press (GtkWidget *entry, GdkEventKey *event, gpointer data) + { +- gtk_widget_grab_focus (pam_entry); ++ g_get_current_time (&last_key_press); ++ return FALSE; ++} ++ ++ ++static gboolean ++tv_button_press (GtkWidget *entry, GdkEventKey *event, gpointer data) ++{ ++ g_get_current_time (&last_button_press); ++ return FALSE; + } + + static void +@@ -285,6 +330,12 @@ greeter_generate_userlist (GtkWidget *tv + GtkTreeSelection *selection; + GList *list, *li; + ++ AtkObject *atk_widget; ++ atk_widget = gtk_widget_get_accessible (tv); ++ if (atk_widget != NULL) { ++ atk_object_set_name (atk_widget, _("Select user to log in")); ++ } ++ + gdm_greeter_users_init (); + + check_for_displays (); +@@ -297,10 +348,13 @@ greeter_generate_userlist (GtkWidget *tv + g_signal_connect (selection, "changed", + G_CALLBACK (user_selected), + NULL); +- +- g_signal_connect (GTK_TREE_VIEW (tv), "button_release_event", +- G_CALLBACK (browser_change_focus), ++ g_signal_connect (G_OBJECT (tv), "row-activated", ++ G_CALLBACK (row_activated), + NULL); ++ g_signal_connect (G_OBJECT (tv), "key-press-event", ++ G_CALLBACK (tv_key_press), user_list); ++ g_signal_connect (G_OBJECT (tv), "button-press-event", ++ G_CALLBACK (tv_button_press), user_list); + + tm = (GtkTreeModel *)gtk_list_store_new (4, + GDK_TYPE_PIXBUF, diff --git a/gdm-2.19.1-audit-login.patch b/gdm-2.19.1-audit-login.patch new file mode 100644 index 0000000..2342e77 --- /dev/null +++ b/gdm-2.19.1-audit-login.patch @@ -0,0 +1,171 @@ +--- gdm-2.19.1/daemon/verify-pam.c.audit-login 2007-05-13 22:08:24.000000000 -0400 ++++ gdm-2.19.1/daemon/verify-pam.c 2007-05-21 11:59:00.000000000 -0400 +@@ -55,6 +55,14 @@ + #include + #endif /* HAVE_ADT */ + ++#define AU_FAILED 0 ++#define AU_SUCCESS 1 ++#ifdef HAVE_LIBAUDIT ++#include ++#else ++#define log_to_audit_system(l,h,d,s) do { ; } while (0) ++#endif ++ + /* Evil, but this way these things are passed to the child session */ + static pam_handle_t *pamh = NULL; + +@@ -789,6 +797,54 @@ create_pamh (GdmDisplay *d, + } + + /** ++ * log_to_audit_system: ++ * @login: Name of user ++ * @hostname: Name of host machine ++ * @tty: Name of display ++ * @success: 1 for success, 0 for failure ++ * ++ * Logs the success or failure of the login attempt with the linux kernel ++ * audit system. The intent is to capture failed events where the user ++ * fails authentication or otherwise is not permitted to login. There are ++ * many other places where pam could potentially fail and cause login to ++ * fail, but these are system failures rather than the signs of an account ++ * being hacked. ++ * ++ * Returns nothing. ++ */ ++ ++#ifdef HAVE_LIBAUDIT ++static void ++log_to_audit_system(const char *login, ++ const char *hostname, ++ const char *tty, ++ gboolean success) ++{ ++ struct passwd *pw; ++ char buf[64]; ++ int audit_fd; ++ ++ audit_fd = audit_open(); ++ if (login) ++ pw = getpwnam(login); ++ else { ++ login = "unknown"; ++ pw = NULL; ++ } ++ if (pw) { ++ snprintf(buf, sizeof(buf), "uid=%d", pw->pw_uid); ++ audit_log_user_message(audit_fd, AUDIT_USER_LOGIN, ++ buf, hostname, NULL, tty, (int)success); ++ } else { ++ snprintf(buf, sizeof(buf), "acct=%s", login); ++ audit_log_user_message(audit_fd, AUDIT_USER_LOGIN, ++ buf, hostname, NULL, tty, (int)success); ++ } ++ close(audit_fd); ++} ++#endif ++ ++/** + * gdm_verify_user: + * @username: Name of user or NULL if we should ask + * @display: Name of display to register with the authentication system +@@ -910,6 +966,8 @@ gdm_verify_user (GdmDisplay *d, + /* Start authentication session */ + did_we_ask_for_password = FALSE; + if ((pamerr = pam_authenticate (pamh, null_tok)) != PAM_SUCCESS) { ++ /* Log the failed login attempt */ ++ log_to_audit_system(login, d->hostname, display, AU_FAILED); + if ( ! ve_string_empty (selected_user)) { + pam_handle_t *tmp_pamh; + +@@ -1030,6 +1088,8 @@ gdm_verify_user (GdmDisplay *d, + ( ! gdm_daemon_config_get_value_bool (GDM_KEY_ALLOW_REMOTE_ROOT) && ! local) ) && + pwent != NULL && + pwent->pw_uid == 0) { ++ /* Log the failed login attempt */ ++ log_to_audit_system(login, d->hostname, display, AU_FAILED); + gdm_error (_("Root login disallowed on display '%s'"), + display); + gdm_slave_greeter_ctl_no_ret (GDM_ERRBOX, +@@ -1063,6 +1123,8 @@ gdm_verify_user (GdmDisplay *d, + break; + case PAM_NEW_AUTHTOK_REQD : + if ((pamerr = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK)) != PAM_SUCCESS) { ++ /* Log the failed login attempt */ ++ log_to_audit_system(login, d->hostname, display, AU_FAILED); + gdm_error (_("Authentication token change failed for user %s"), login); + gdm_slave_greeter_ctl_no_ret (GDM_ERRBOX, + _("\nThe change of the authentication token failed. " +@@ -1080,18 +1142,24 @@ gdm_verify_user (GdmDisplay *d, + #endif /* HAVE_ADT */ + break; + case PAM_ACCT_EXPIRED : ++ /* Log the failed login attempt */ ++ log_to_audit_system(login, d->hostname, display, AU_FAILED); + gdm_error (_("User %s no longer permitted to access the system"), login); + gdm_slave_greeter_ctl_no_ret (GDM_ERRBOX, + _("\nThe system administrator has disabled your account.")); + error_msg_given = TRUE; + goto pamerr; + case PAM_PERM_DENIED : ++ /* Log the failed login attempt */ ++ log_to_audit_system(login, d->hostname, display, AU_FAILED); + gdm_error (_("User %s not permitted to gain access at this time"), login); + gdm_slave_greeter_ctl_no_ret (GDM_ERRBOX, + _("\nThe system administrator has disabled access to the system temporarily.")); + error_msg_given = TRUE; + goto pamerr; + default : ++ /* Log the failed login attempt */ ++ log_to_audit_system(login, d->hostname, display, AU_FAILED); + if (gdm_slave_action_pending ()) + gdm_error (_("Couldn't set acct. mgmt for %s"), login); + goto pamerr; +@@ -1143,6 +1211,8 @@ gdm_verify_user (GdmDisplay *d, + gdm_error (_("Couldn't open session for %s"), login); + goto pamerr; + } ++ /* Login succeeded */ ++ log_to_audit_system(login, d->hostname, display, AU_SUCCESS); + + /* Workaround to avoid gdm messages being logged as PAM_pwdb */ + gdm_log_shutdown (); +--- gdm-2.19.1/configure.ac.audit-login 2007-05-13 22:08:48.000000000 -0400 ++++ gdm-2.19.1/configure.ac 2007-05-21 11:37:59.000000000 -0400 +@@ -837,6 +837,10 @@ else + fi + AC_SUBST(logdir, $GDM_LOG_DIR) + ++AC_ARG_WITH(libaudit, ++ [ --with-libaudit=[auto/yes/no] Add Linux audit support [default=auto]],, ++ with_libaudit=auto) ++ + withval="" + AC_ARG_WITH(at-bindir, + [ --with-at-bindir= PATH to Accessible Technology programs [default=BINDIR]],) +@@ -948,6 +952,24 @@ else + AC_MSG_RESULT(no) + fi + ++# Check for Linux auditing API ++# ++# libaudit detection ++if test x$with_libaudit = xno ; then ++ have_libaudit=no; ++else ++ # See if we have audit daemon library ++ AC_CHECK_LIB(audit, audit_log_user_message, ++ have_libaudit=yes, have_libaudit=no) ++fi ++ ++AM_CONDITIONAL(HAVE_LIBAUDIT, test x$have_libaudit = xyes) ++ ++if test x$have_libaudit = xyes ; then ++ EXTRA_DAEMON_LIBS="$EXTRA_DAEMON_LIBS -laudit" ++ AC_DEFINE(HAVE_LIBAUDIT,1,[linux audit support]) ++fi ++ + # Check for Solaris auditing API + # Note, Solaris auditing not supported for Solaris 9 or earlier and + # should not be used on these versions of Solaris if auditing is diff --git a/gdm-2.19.1-change-defaults.patch b/gdm-2.19.1-change-defaults.patch new file mode 100644 index 0000000..88ac1ea --- /dev/null +++ b/gdm-2.19.1-change-defaults.patch @@ -0,0 +1,183 @@ +--- gdm-2.19.1/config/gdm.conf.in.change-defaults 2007-05-13 22:08:25.000000000 -0400 ++++ gdm-2.19.1/config/gdm.conf.in 2007-05-21 11:16:43.000000000 -0400 +@@ -66,9 +66,9 @@ TimedLoginDelay=30 + # should leave this alone. + #Chooser=@libexecdir@/gdmchooser + +-# The greeter for local (non-xdmcp) logins. Change gdmlogin to gdmgreeter to +-# get the new graphical greeter. +-#Greeter=@libexecdir@/gdmlogin ++# The greeter for local (non-xdmcp) logins. Change gdmgreeter to gdmlogin to ++# get the boring greeter. ++Greeter=@libexecdir@/gdmgreeter + + # The greeter for xdmcp logins, usually you want a less graphically intensive + # greeter here so it's better to leave this with gdmlogin +@@ -78,23 +78,23 @@ TimedLoginDelay=30 + # This is useful for enabling additional feature support e.g. GNOME + # accessibility framework. Only "trusted" modules should be allowed to minimize + # security holes +-#AddGtkModules=false ++AddGtkModules=true + # By default, these are the accessibility modules. +-#GtkModulesList=gail:atk-bridge:@libdir@/gtk-2.0/modules/libdwellmouselistener:@libdir@/gtk-2.0/modules/libkeymouselistener ++GtkModulesList=gail:atk-bridge:@libdir@/gtk-2.0/modules/libdwellmouselistener:@libdir@/gtk-2.0/modules/libkeymouselistener + + # Default path to set. The profile scripts will likely override this value. + # This value will be overridden with the value from /etc/default/login if it + # contains "ROOT=". +-#DefaultPath=@GDM_USER_PATH@ ++DefaultPath=/usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin + # Default path for root. The profile scripts will likely override this value. + # This value will be overridden with the value from /etc/default/login if it + # contains "SUROOT=". +-#RootPath=/sbin:/usr/sbin:@GDM_USER_PATH@ ++RootPath=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin + + # If you are having trouble with using a single server for a long time and want + # GDM to kill/restart the server, turn this on. On Solaris, this value is + # always true and this configuration setting is ignored. +-#AlwaysRestartServer=@ALWAYS_RESTART_SERVER@ ++AlwaysRestartServer=true + + # User and group used for running GDM GUI applications. By default this is set + # to user "gdm" and group "gdm". This user/group should have very limited +@@ -126,9 +126,9 @@ XKeepsCrashing=@gdmconfdir@/XKeepsCrashi + # + # Reboot, Halt and suspend commands, you can add different commands separated + # by a semicolon. GDM will use the first one it can find. +-RebootCommand=@REBOOT_COMMAND@ +-HaltCommand=@HALT_COMMAND@ +-SuspendCommand=@SUSPEND_COMMAND@ ++# ++RebootCommand=/sbin/reboot;/sbin/shutdown -r now;/usr/sbin/shutdown -r now;/usr/bin/reboot ++HaltCommand=/sbin/poweroff;/sbin/shutdown -h now;/usr/sbin/shutdown -h now;/usr/bin/poweroff + + # The following options specify how GDM system commands are supported. + # +@@ -158,14 +158,14 @@ ServAuthDir=@authdir@ + # This is our standard startup script. A bit different from a normal X + # session, but it shares a lot of stuff with that. See the provided default + # for more information. +-BaseXsession=@gdmconfdir@/Xsession ++BaseXsession=/etc/X11/xinit/Xsession + # This is a directory where .desktop files describing the sessions live. It is + # really a PATH style variable since 2.4.4.2 to allow actual interoperability + # with KDM. Note that /Sessions is there for backwards + # compatibility reasons with 2.4.4.x. + #SessionDesktopDir=/etc/X11/sessions/:@dmconfdir@/Sessions/:@datadir@/gdm/BuiltInSessions/:@datadir@/xsessions/ + # This is the default .desktop session. One of the ones in SessionDesktopDir +-#DefaultSession=gnome.desktop ++DefaultSession=default.desktop + # Better leave this blank and HOME will be used. You can use syntax ~/ below + # to indicate home directory of the user. You can also set this to something + # like /tmp if you don't want the authorizations to be in home directories. +@@ -173,11 +173,11 @@ BaseXsession=@gdmconfdir@/Xsession + # is the home directory the UserAuthFBDir will still be used in case the home + # directory is NFS, see security/NeverPlaceCookiesOnNFS to override this + # behavior. +-UserAuthDir= ++UserAuthDir=/tmp + # Fallback directory for writing authorization file if user's home directory + # is not writable. + UserAuthFBDir=/tmp +-UserAuthFile=.Xauthority ++#UserAuthFile=.Xauthority + # The X server to use if we can't figure out what else to run. + StandardXServer=@X_SERVER@ + # The maximum number of flexible X servers to run. +@@ -209,7 +209,7 @@ XnestUnscaledFontPath=@X_XNEST_UNSCALED_ + #DoubleLoginWarning=true + # Should a second login always resume the current session and switch VT's on + # Linux and FreeBSD systems for console logins +-#AlwaysLoginCurrentSession=true ++AlwaysLoginCurrentSession=true + + # If true then the last login information is printed to the user before being + # prompted for password. While this gives away some info on what users are on +@@ -333,7 +333,7 @@ Enable=false + #GtkRC=@datadir@/themes/Default/gtk-2.0/gtkrc + + # The GTK+ theme to use for the GUI. +-#GtkTheme=Default ++GtkTheme=Clearlooks + # If to allow changing the GTK+ (widget) theme from the greeter. Currently + # this only affects the standard greeter as the graphical greeter does not yet + # have this ability. +@@ -354,7 +354,7 @@ Enable=false + # themed login (gdmgreeter). + # + # The standard login has a title bar that the user can move. +-#TitleBar=true ++TitleBar=false + # Don't allow user to move the standard login window. Only makes sense if + # TitleBar is on. + #LockPosition=false +@@ -378,7 +378,7 @@ Browser=false + # User ID's less than the MinimalUID value will not be included in the face + # browser or in the gdmselection list for Automatic/Timed login. They will not + # be displayed regardless of the settings for Include and Exclude. +-#MinimalUID=100 ++MinimalUID=500 + # Users listed in Include will be included in the face browser and in the + # gdmsetup selection list for Automatic/Timed login. Users should be separated + # by commas. +@@ -395,7 +395,7 @@ Browser=false + # large numbers of users and this feature should not be used in such + # environments. The setting of IncludeAll does nothing if Include is set to a + # non-empty value. +-#IncludeAll=false ++IncludeAll=true + # If user or user.png exists in this dir it will be used as his picture. + #GlobalFaceDir=@datadir@/pixmaps/faces/ + +@@ -404,7 +404,7 @@ Browser=false + # file, although GDM will be able to read a standard locale.alias file as well. + #LocaleFile=@gdmlocaledir@/locale.alias + # Logo shown in the standard greeter. +-#Logo=@pixmapdir@/gdm-foot-logo.png ++Logo= + # Logo shown on file chooser button in gdmsetup (do not modify this value). + #ChooserButtonLogo=@pixmapdir@/gdm-foot-logo.png + # The standard greeter should shake if a user entered the wrong username or +@@ -451,8 +451,9 @@ DefaultRemoteWelcome=true + # The Standard greeter (gdmlogin) uses BackgroundColor as the background + # color, while the themed greeter (gdmgreeter) uses GraphicalThemedColor + # as the background color. +-BackgroundColor=#76848F +-GraphicalThemedColor=#76848F ++BackgroundColor=#20305a ++GraphicalThemedColor=#000000 ++ + # XDMCP session should only get a color, this is the sanest setting since you + # don't want to take up too much bandwidth + #BackgroundRemoteOnlyColor=true +@@ -473,8 +474,8 @@ GraphicalThemedColor=#76848F + # Show the Failsafe sessions. These are much MUCH nicer (focus for xterm for + # example) and more failsafe then those supplied by scripts so distros should + # use this rather then just running an xterm from a script. +-#ShowGnomeFailsafeSession=true +-#ShowXtermFailsafeSession=true ++ShowGnomeFailsafeSession=false ++ShowXtermFailsafeSession=false + # Normally there is a session type called 'Last' that is shown which refers to + # the last session the user used. If off, we will be in 'switchdesk' mode + # where the session saving stuff is disabled in GDM +@@ -493,7 +494,7 @@ GraphicalThemedColor=#76848F + # list then provide a list that is delimited by /: to the GraphicalThemes + # key and set GraphicalThemeRand to true. Otherwise use GraphicalTheme + # and specify just one theme. +-#GraphicalTheme=circles ++GraphicalTheme=FedoraFlyingHigh + #GraphicalThemes=circles/:happygnome + GraphicalThemeDir=@datadir@/gdm/themes/ + GraphicalThemeRand=false +@@ -597,7 +598,7 @@ Gestures=false + # Definition of the standard X server. + [server-Standard] + name=Standard server +-command=@X_SERVER@ @X_CONFIG_OPTIONS@ @XEVIE_OPTION@ ++command=@X_SERVER@ -br @X_CONFIG_OPTIONS@ @XEVIE_OPTION@ + flexible=true + # Indicates that the X server should be started at a different process + # priority. Values can be any integer value accepted by the setpriority C diff --git a/gdm-2.19.1-clean-up-xsession-errors.patch b/gdm-2.19.1-clean-up-xsession-errors.patch new file mode 100644 index 0000000..78c077f --- /dev/null +++ b/gdm-2.19.1-clean-up-xsession-errors.patch @@ -0,0 +1,14 @@ +--- gdm-2.19.1/daemon/slave.c.clean-up-xsession-errors 2007-05-13 22:08:25.000000000 -0400 ++++ gdm-2.19.1/daemon/slave.c 2007-05-21 11:27:27.000000000 -0400 +@@ -4523,6 +4523,11 @@ gdm_slave_session_stop (gboolean run_pos + + finish_session_output (run_post_session /* do_read */); + ++ /* If successfully exited then clear the log file ++ */ ++ if (d->xsession_errors_filename != NULL) ++ VE_IGNORE_EINTR (unlink (d->xsession_errors_filename) ++ + if (local_login == NULL) + pwent = NULL; + else diff --git a/gdm-2.19.1-hide-uninstalled-languages.patch b/gdm-2.19.1-hide-uninstalled-languages.patch new file mode 100644 index 0000000..cec433c --- /dev/null +++ b/gdm-2.19.1-hide-uninstalled-languages.patch @@ -0,0 +1,130 @@ +--- gdm-2.19.1/gui/gdmcommon.c.hide-uninstalled-languages 2007-05-13 22:08:15.000000000 -0400 ++++ gdm-2.19.1/gui/gdmcommon.c 2007-05-21 13:24:20.000000000 -0400 +@@ -32,6 +32,8 @@ + #include + #include + ++#include ++ + #include + #include + #include +@@ -928,3 +930,95 @@ gdm_common_expand_text (const gchar *tex + return g_string_free (str, FALSE); + } + ++typedef enum ++{ ++ LOCALE_UP_TO_LANGUAGE = 0, ++ LOCALE_UP_TO_COUNTRY, ++ LOCALE_UP_TO_ENCODING, ++ LOCALE_UP_TO_MODIFIER, ++} LocaleScope; ++ ++static char * ++get_less_specific_locale (const char *locale, ++ LocaleScope scope) ++{ ++ char *generalized_locale; ++ char *end; ++ ++ generalized_locale = strdup (locale); ++ ++ end = strchr (generalized_locale, '_'); ++ ++ if (end != NULL && scope <= LOCALE_UP_TO_LANGUAGE) ++ { ++ *end = '\0'; ++ return generalized_locale; ++ } ++ ++ end = strchr (generalized_locale, '.'); ++ ++ if (end != NULL && scope <= LOCALE_UP_TO_COUNTRY) ++ { ++ *end = '\0'; ++ return generalized_locale; ++ } ++ ++ end = strchr (generalized_locale, '@'); ++ ++ if (end != NULL && scope <= LOCALE_UP_TO_ENCODING) ++ { ++ *end = '\0'; ++ return generalized_locale; ++ } ++ ++ return generalized_locale; ++} ++ ++gboolean ++gdm_common_locale_is_displayable (const gchar *locale) ++{ ++ char *language_code; ++ gboolean is_displayable; ++ ++ FcPattern *pattern; ++ FcObjectSet *object_set; ++ FcFontSet *font_set; ++ ++ is_displayable = FALSE; ++ pattern = NULL; ++ object_set = NULL; ++ font_set = NULL; ++ ++ language_code = get_less_specific_locale (locale, LOCALE_UP_TO_LANGUAGE); ++ ++ pattern = FcPatternBuild (NULL, FC_LANG, FcTypeString, language_code, NULL); ++ ++ if (pattern == NULL) ++ goto done; ++ ++ object_set = FcObjectSetBuild (NULL, NULL); ++ ++ if (object_set == NULL) ++ goto done; ++ ++ font_set = FcFontList (NULL, pattern, object_set); ++ ++ if (font_set == NULL) ++ goto done; ++ ++ is_displayable = (font_set->nfont > 0); ++ ++done: ++ ++ if (font_set != NULL) ++ FcFontSetDestroy (font_set); ++ ++ if (object_set != NULL) ++ FcObjectSetDestroy (object_set); ++ ++ if (pattern != NULL) ++ FcPatternDestroy (pattern); ++ ++ g_free (language_code); ++ return is_displayable; ++} +--- gdm-2.19.1/gui/gdmlanguages.c.hide-uninstalled-languages 2007-05-21 13:29:38.000000000 -0400 ++++ gdm-2.19.1/gui/gdmlanguages.c 2007-05-21 13:30:28.000000000 -0400 +@@ -705,6 +705,11 @@ gdm_lang_initialize_model (gchar * local + + li->data = NULL; + ++ if (!gdm_common_locale_is_displayable (lang)) { ++ g_free (lang); ++ continue; ++ } ++ + name = gdm_lang_name (lang, + FALSE /* never_encoding */, + TRUE /* no_group */, +--- gdm-2.19.1/gui/gdmcommon.h.hide-uninstalled-languages 2007-05-13 22:08:15.000000000 -0400 ++++ gdm-2.19.1/gui/gdmcommon.h 2007-05-21 13:24:20.000000000 -0400 +@@ -70,5 +70,5 @@ void gdm_common_pre_fetch_launch + void gdm_common_atspi_launch (void); + gchar* gdm_common_expand_text (const gchar *text); + gchar* gdm_common_get_clock (struct tm **the_tm); +- ++gboolean gdm_common_locale_is_displayable (const gchar *locale); + #endif /* GDM_COMMON_H */ diff --git a/gdm-2.19.1-move-default-message.patch b/gdm-2.19.1-move-default-message.patch new file mode 100644 index 0000000..9574947 --- /dev/null +++ b/gdm-2.19.1-move-default-message.patch @@ -0,0 +1,147 @@ +--- gdm-2.19.1/gui/greeter/greeter_item_pam.c.move-default-message 2007-05-13 22:08:14.000000000 -0400 ++++ gdm-2.19.1/gui/greeter/greeter_item_pam.c 2007-05-21 12:05:21.000000000 -0400 +@@ -47,6 +47,7 @@ gchar *greeter_current_user = NULL; + gboolean require_quarter = FALSE; + + extern gboolean greeter_probably_login_prompt; ++static gboolean using_fallback_message = FALSE; + extern GtkButton *gtk_ok_button; + extern GtkButton *gtk_start_again_button; + +@@ -249,13 +250,35 @@ greeter_item_pam_prompt (const char *mes + int entry_len, + gboolean entry_visible) + { ++ GreeterItemInfo *message_info; + GreeterItemInfo *conversation_info; + GreeterItemInfo *entry_info; + GtkWidget *entry; + ++ message_info = greeter_lookup_id ("pam-message"); + conversation_info = greeter_lookup_id ("pam-prompt"); + entry_info = greeter_lookup_id ("user-pw-entry"); + ++ if (strcmp (message, _("Username:")) == 0 && message_info) ++ { ++ gchar *text; ++ text = NULL; ++ g_object_get (G_OBJECT (message_info->item), ++ "text", &text, ++ NULL); ++ if (ve_string_empty (text)) ++ { ++ set_text (message_info, _("Please enter your username")); ++ using_fallback_message = TRUE; ++ } ++ g_free (text); ++ } ++ else if (using_fallback_message) ++ { ++ set_text (message_info, ""); ++ using_fallback_message = FALSE; ++ } ++ + if (conversation_info) + { + set_text (conversation_info, message); +@@ -320,6 +343,7 @@ greeter_item_pam_message (const char *me + * we try to collect them until the next prompt or reset or + * whatnot */ + if ( ! replace_msg && ++ ! using_fallback_message && + /* empty message is for clearing */ + ! ve_string_empty (message)) + { +@@ -339,6 +363,7 @@ greeter_item_pam_message (const char *me + set_text (message_info, message); + } + replace_msg = FALSE; ++ using_fallback_message = FALSE; + } + + +--- gdm-2.19.1/gui/gdmlogin.c.move-default-message 2007-05-13 22:08:15.000000000 -0400 ++++ gdm-2.19.1/gui/gdmlogin.c 2007-05-21 12:05:21.000000000 -0400 +@@ -169,6 +169,7 @@ extern gchar *default_session; + extern const gchar *current_session; + extern gboolean session_dir_whacked_out; + extern gint gdm_timed_delay; ++static gboolean using_fallback_message = FALSE; + + static gboolean first_prompt = TRUE; + +@@ -1357,9 +1358,20 @@ process_operation (guchar op_code, + gdm_config_get_string (GDM_KEY_SOUND_ON_LOGIN_FILE), + gdm_config_get_bool (GDM_KEY_SOUND_ON_LOGIN)); + gtk_label_set_text_with_mnemonic (GTK_LABEL (label), _("_Username:")); ++ if (ve_string_empty (gtk_label_get_text (GTK_LABEL (msg)))) { ++ gtk_label_set_text (GTK_LABEL (msg), ++ _("Please enter your username")); ++ using_fallback_message = TRUE; ++ } ++ + } else { + if (tmp != NULL) + gtk_label_set_text (GTK_LABEL (label), tmp); ++ if (using_fallback_message) { ++ gtk_label_set_text (GTK_LABEL (msg), ""); ++ using_fallback_message = FALSE; ++ } ++ + } + g_free (tmp); + +@@ -1447,6 +1459,7 @@ process_operation (guchar op_code, + g_free (tmp); + } + replace_msg = FALSE; ++ using_fallback_message = FALSE; + + gtk_widget_show (GTK_WIDGET (msg)); + printf ("%c\n", STX); +@@ -1625,9 +1638,7 @@ process_operation (guchar op_code, + if (browser_ok && gdm_config_get_bool (GDM_KEY_BROWSER)) + gtk_widget_set_sensitive (GTK_WIDGET (browser), TRUE); + +- tmp = ve_locale_to_utf8 (args); +- gtk_label_set_text (GTK_LABEL (msg), tmp); +- g_free (tmp); ++ gtk_label_set_text (GTK_LABEL (msg), ""); + gtk_widget_show (GTK_WIDGET (msg)); + + printf ("%c\n", STX); +--- gdm-2.19.1/daemon/verify-pam.c.move-default-message 2007-05-21 12:05:21.000000000 -0400 ++++ gdm-2.19.1/daemon/verify-pam.c 2007-05-21 12:07:50.000000000 -0400 +@@ -539,12 +539,6 @@ gdm_verify_pam_conv (int num_msg, struct + case PAM_PROMPT_ECHO_ON: + if (strcmp (m, _("Username:")) == 0) { + if ( ve_string_empty (selected_user)) { +- /* this is an evil hack, but really there is no way we'll +- know this is a username prompt. However we SHOULD NOT +- rely on this working. The pam modules can set their +- prompt to whatever they wish to */ +- gdm_slave_greeter_ctl_no_ret +- (GDM_MSG, _("Please enter your username")); + s = gdm_slave_greeter_ctl (GDM_PROMPT, m); + /* this will clear the message */ + gdm_slave_greeter_ctl_no_ret (GDM_MSG, ""); +--- gdm-2.19.1/daemon/verify-shadow.c.move-default-message 2007-05-13 22:08:24.000000000 -0400 ++++ gdm-2.19.1/daemon/verify-shadow.c 2007-05-21 12:11:06.000000000 -0400 +@@ -127,7 +127,6 @@ gdm_verify_user (GdmDisplay *d, + authenticate_again: + /* Ask for the user's login */ + gdm_verify_select_user (NULL); +- gdm_slave_greeter_ctl_no_ret (GDM_MSG, _("Please enter your username")); + login = gdm_slave_greeter_ctl (GDM_PROMPT, _("Username:")); + if (login == NULL || + gdm_slave_greeter_check_interruption ()) { +--- gdm-2.19.1/daemon/verify-crypt.c.move-default-message 2007-05-13 22:08:24.000000000 -0400 ++++ gdm-2.19.1/daemon/verify-crypt.c 2007-05-21 12:10:33.000000000 -0400 +@@ -125,7 +125,6 @@ gdm_verify_user (GdmDisplay *d, + authenticate_again: + /* Ask for the user's login */ + gdm_verify_select_user (NULL); +- gdm_slave_greeter_ctl_no_ret (GDM_MSG, _("Please enter your username")); + login = gdm_slave_greeter_ctl (GDM_PROMPT, _("Username:")); + if (login == NULL || + gdm_slave_greeter_check_interruption ()) { diff --git a/gdm-2.19.1-pass-ats-to-session.patch b/gdm-2.19.1-pass-ats-to-session.patch new file mode 100644 index 0000000..f62c411 --- /dev/null +++ b/gdm-2.19.1-pass-ats-to-session.patch @@ -0,0 +1,265 @@ +--- gdm-2.19.1/gui/gdmlogin.c.pass-ats-to-session 2007-05-21 13:38:32.000000000 -0400 ++++ gdm-2.19.1/gui/gdmlogin.c 2007-05-21 13:38:32.000000000 -0400 +@@ -1576,6 +1576,19 @@ process_operation (guchar op_code, + fflush (stdout); + break; + ++ case GDM_A11Y: ++ { ++ const char *ats_launched; ++ /* print out the assistive technologies that we've started for the user */ ++ ats_launched = g_getenv ("GDM_ATS"); ++ if (ats_launched != NULL) ++ printf ("%c%s\n", STX, ats_launched); ++ else ++ printf ("%c\n", STX); ++ fflush (stdout); ++ break; ++ } ++ + case GDM_LANG: + gdm_lang_op_lang (args); + break; +--- gdm-2.19.1/gui/modules/dwellmouselistener.c.pass-ats-to-session 2007-05-13 22:08:12.000000000 -0400 ++++ gdm-2.19.1/gui/modules/dwellmouselistener.c 2007-05-21 13:38:32.000000000 -0400 +@@ -678,6 +678,8 @@ leave_enter_emission_hook (GSignalInvoca + G_CALLBACK (gtk_widget_destroy), NULL); + gtk_widget_show (dialog); + } else { ++ const char *at_name; ++ const char *ats_launched; + GdkCursor *cursor = gdk_cursor_new (GDK_WATCH); + gdk_window_set_cursor (gdk_get_default_root_window (), + cursor); +@@ -686,6 +688,26 @@ leave_enter_emission_hook (GSignalInvoca + latch_core_pointer = FALSE; + /* once we've recognized a gesture, we need to * + * leave the pointer alone */ ++ ++ at_name = strstr (action, "#AT_TYPE="); ++ if (at_name != NULL) { ++ int i; ++ char **v; ++ at_name += 9; ++ v = g_strsplit (at_name, " ", 0); ++ for (i = 0; v[i] != NULL; i++) { ++ ats_launched = g_getenv ("GDM_ATS"); ++ if (ats_launched == NULL) { ++ g_setenv ("GDM_ATS", v[i], TRUE); ++ } else if (strstr (ats_launched, v[i]) == NULL) { ++ char *s; ++ s = g_strdup_printf ("%s %s", ats_launched, v[i]); ++ g_setenv ("GDM_ATS", s, TRUE); ++ g_free (s); ++ } ++ } ++ g_strfreev (v); ++ } + } + } + } +--- gdm-2.19.1/gui/modules/AccessKeyMouseEvents.in.pass-ats-to-session 2007-05-13 22:08:12.000000000 -0400 ++++ gdm-2.19.1/gui/modules/AccessKeyMouseEvents.in 2007-05-21 13:43:54.000000000 -0400 +@@ -78,14 +78,14 @@ + # + # press ctrl-s for 1 second to launch orca in speech mode + # +-s 1 1000 10000 @AT_BINDIR@/orca -n -d main-window ++s 1 1000 10000 @AT_BINDIR@/orca -n -d main-window #AT_TYPE=screenreader + + # press ctrl-m for 1 second to launch orca in mag mode + # +-m 1 1000 10000 @AT_BINDIR@/orca -n -d main-window -d speech -e magnifier ++m 1 1000 10000 @AT_BINDIR@/orca -n -d main-window -d speech -e magnifier #AT_TYPE=magnifier + + # press ctrl-o or ctrl-g for 1 second to launch orca in speech and mag mode + # +-o 1 1000 10000 @AT_BINDIR@/orca -n -d main-window -e magnifier +-g 1 1000 10000 @AT_BINDIR@/orca -n -d main-window -e magnifier ++o 1 1000 10000 @AT_BINDIR@/orca -n -d main-window -e magnifier #AT_TYPE=screenreader magnifier ++g 1 1000 10000 @AT_BINDIR@/orca -n -d main-window -e magnifier #AT_TYPE=screenreader magnifier + +--- gdm-2.19.1/gui/modules/AccessDwellMouseEvents.in.pass-ats-to-session 2007-05-13 22:08:12.000000000 -0400 ++++ gdm-2.19.1/gui/modules/AccessDwellMouseEvents.in 2007-05-21 13:40:39.000000000 -0400 +@@ -38,10 +38,10 @@ + # Support several different options for different user needs. Note these + # gestures all start by moving the mouse into the top window border. + # +-TBLR I 10000 @AT_BINDIR@/gok --login --access-method=dwellselection +-TLBR I 10000 @AT_BINDIR@/gok --login --access-method=automaticscanning --scan-action=switch1 --select-action=switch1 +-TRBL I 10000 @AT_BINDIR@/gok --login --access-method=inversescanning --scan-action=switch1 --select-action=switch2 +-TBRL I 10000 @AT_BINDIR@/gok --login --access-method=automaticscanning --scan-action=switch3 --select-action=switch3 ++TBLR I 10000 @AT_BINDIR@/gok --login --access-method=dwellselection #AT_TYPE=onscreenkeyboard ++TLBR I 10000 @AT_BINDIR@/gok --login --access-method=automaticscanning --scan-action=switch1 --select-action=switch1 #AT_TYPE=onscreenkeyboard ++TRBL I 10000 @AT_BINDIR@/gok --login --access-method=inversescanning --scan-action=switch1 --select-action=switch2 #AT_TYPE=onscreenkeyboard ++TBRL I 10000 @AT_BINDIR@/gok --login --access-method=automaticscanning --scan-action=switch3 --select-action=switch3 #AT_TYPE=onscreenkeyboard + + # AT Program - ORCA + # +@@ -50,13 +50,13 @@ TBRL I 10000 @AT_BINDIR@/gok --login + # + # Speech + # +-BTRL I 10000 @AT_BINDIR@/orca -n -d main-window ++BTRL I 10000 @AT_BINDIR@/orca -n -d main-window #AT_TYPE=screenreader + + # Magnifier + # +-BTLR I 10000 @AT_BINDIR@/orca -n -d main-window -d speech -e magnifier ++BTLR I 10000 @AT_BINDIR@/orca -n -d main-window -d speech -e magnifier #AT_TYPE=magnifier + + # Speech and Magnifier + # +-BRTL I 10000 @AT_BINDIR@/orca -n -d main-window -e magnifier ++BRTL I 10000 @AT_BINDIR@/orca -n -d main-window -e magnifier #AT_TYPE=screenreader magnifier + +--- gdm-2.19.1/gui/modules/keymouselistener.c.pass-ats-to-session 2007-05-13 22:08:12.000000000 -0400 ++++ gdm-2.19.1/gui/modules/keymouselistener.c 2007-05-21 13:38:32.000000000 -0400 +@@ -951,6 +951,8 @@ gestures_filter (GdkXEvent *gdk_xevent, + NULL); + gtk_widget_show (dialog); + } else { ++ char *at_name; ++ const char *ats_launched; + GdkCursor *cursor = gdk_cursor_new (GDK_WATCH); + gdk_window_set_cursor (gdk_get_default_root_window (), + cursor); +@@ -958,6 +960,26 @@ gestures_filter (GdkXEvent *gdk_xevent, + g_timeout_add (2000, + change_cursor_back, + NULL); ++ ++ at_name = strstr (action, "#AT_TYPE="); ++ if (at_name != NULL) { ++ int i; ++ char **v; ++ at_name += 9; ++ v = g_strsplit (at_name, " ", 0); ++ for (i = 0; v[i] != NULL; i++) { ++ ats_launched = g_getenv ("GDM_ATS"); ++ if (ats_launched == NULL) { ++ g_setenv ("GDM_ATS", v[i], TRUE); ++ } else if (strstr (ats_launched, v[i]) == NULL) { ++ char *s; ++ s = g_strdup_printf ("%s %s", ats_launched, v[i]); ++ g_setenv ("GDM_ATS", s, TRUE); ++ g_free (s); ++ } ++ } ++ g_strfreev (v); ++ } + } + } + return GDK_FILTER_CONTINUE; +--- gdm-2.19.1/gui/greeter/greeter.c.pass-ats-to-session 2007-05-21 13:38:32.000000000 -0400 ++++ gdm-2.19.1/gui/greeter/greeter.c 2007-05-21 13:38:32.000000000 -0400 +@@ -390,6 +390,19 @@ process_operation (guchar op_code, + g_free (session); + break; + ++ case GDM_A11Y: ++ { ++ const char *ats_launched; ++ /* print out the assistive technologies that we've started for the user */ ++ ats_launched = g_getenv ("GDM_ATS"); ++ if (ats_launched != NULL) ++ printf ("%c%s\n", STX, ats_launched); ++ else ++ printf ("%c\n", STX); ++ fflush (stdout); ++ break; ++ } ++ + case GDM_LANG: + gdm_lang_op_lang (args); + break; +--- gdm-2.19.1/daemon/gdm-socket-protocol.h.pass-ats-to-session 2007-05-21 13:44:35.000000000 -0400 ++++ gdm-2.19.1/daemon/gdm-socket-protocol.h 2007-05-21 13:45:04.000000000 -0400 +@@ -41,6 +41,7 @@ + #define GDM_PROMPT 'N' + #define GDM_SESS 'G' + #define GDM_LANG '&' ++#define GDM_A11Y 'Z' + #define GDM_SSESS 'C' + #define GDM_SLANG 'R' + #define GDM_SETLANG 'L' +--- gdm-2.19.1/daemon/slave.c.pass-ats-to-session 2007-05-21 13:38:32.000000000 -0400 ++++ gdm-2.19.1/daemon/slave.c 2007-05-21 13:50:08.000000000 -0400 +@@ -3489,6 +3489,7 @@ session_child_run (struct passwd *pwent, + const char *session, + const char *save_session, + const char *language, ++ const char *a11y_ats, + const char *gnome_session, + gboolean usrcfgok, + gboolean savesess, +@@ -3579,6 +3580,9 @@ session_child_run (struct passwd *pwent, + } + #endif + g_setenv ("PWD", home_dir, TRUE); ++ if (a11y_ats != NULL) { ++ g_setenv ("GDM_ATS", a11y_ats, TRUE); ++ } + g_setenv ("GDMSESSION", session, TRUE); + g_setenv ("DESKTOP_SESSION", session, TRUE); + g_setenv ("SHELL", pwent->pw_shell, TRUE); +@@ -3989,6 +3993,7 @@ gdm_slave_session_start (void) + struct passwd *pwent; + const char *home_dir = NULL; + char *save_session = NULL, *session = NULL, *language = NULL, *usrsess, *usrlang; ++ char *a11y_ats = NULL; + char *gnome_session = NULL; + #ifdef WITH_CONSOLE_KIT + char *ck_session_cookie; +@@ -4157,9 +4162,19 @@ gdm_slave_session_start (void) + g_free (usrlang); + return; + } ++ ++ a11y_ats = gdm_slave_greeter_ctl (GDM_A11Y, NULL); ++ if (a11y_ats != NULL && ++ strcmp (a11y_ats, GDM_RESPONSE_CANCEL) == 0) { ++ gdm_debug ("User canceled login"); ++ gdm_verify_cleanup (d); ++ session_started = FALSE; ++ return; ++ } + } else { + session = g_strdup (usrsess); + language = g_strdup (usrlang); ++ a11y_ats = NULL; + } + + tmp = gdm_strip_extension (session, ".desktop"); +@@ -4180,10 +4195,15 @@ gdm_slave_session_start (void) + language = NULL; + } + ++ if G_LIKELY (ve_string_empty (a11y_ats)) { ++ g_free (a11y_ats); ++ a11y_ats = NULL; ++ } ++ + g_free (usrsess); + +- gdm_debug ("Initial setting: session: '%s' language: '%s'\n", +- session, ve_sure_string (language)); ++ gdm_debug ("Initial setting: session: '%s' language: '%s'i ATs enabled in gdm: '%s'\n", ++ session, ve_sure_string (language), ve_sure_string (a11y_ats)); + + /* save this session as the users session */ + save_session = g_strdup (session); +@@ -4377,6 +4397,7 @@ gdm_slave_session_start (void) + session, + save_session, + lang, ++ a11y_ats, + gnome_session, + usrcfgok, + savesess, +@@ -5893,4 +5914,4 @@ gboolean + gdm_is_user_valid (const char *username) + { + return (NULL != getpwnam (username)); +-} ++ diff --git a/gdm-2.19.1-reset-pam.patch b/gdm-2.19.1-reset-pam.patch new file mode 100644 index 0000000..04f4a7d --- /dev/null +++ b/gdm-2.19.1-reset-pam.patch @@ -0,0 +1,170 @@ +--- gdm-2.19.1/gui/greeter/greeter.c.reset-pam 2007-05-13 22:08:14.000000000 -0400 ++++ gdm-2.19.1/gui/greeter/greeter.c 2007-05-21 12:37:13.000000000 -0400 +@@ -224,7 +224,6 @@ process_operation (guchar op_code, + GtkWidget *dlg; + char *tmp; + char *session; +- GreeterItemInfo *conversation_info; + static GnomeCanvasItem *disabled_cover = NULL; + gint lookup_status = SESSION_LOOKUP_SUCCESS; + gchar *firstmsg = NULL; +@@ -428,17 +427,10 @@ process_operation (guchar op_code, + + first_prompt = TRUE; + +- conversation_info = greeter_lookup_id ("pam-conversation"); +- +- if (conversation_info) +- { +- tmp = ve_locale_to_utf8 (args); +- g_object_set (G_OBJECT (conversation_info->item), +- "text", tmp, +- NULL); +- g_free (tmp); +- } +- ++ greeter_item_ulist_unset_selected_user (); ++ greeter_item_pam_prompt ("", PW_ENTRY_SIZE, TRUE); ++ greeter_item_pam_message (""); ++ + printf ("%c\n", STX); + fflush (stdout); + greeter_ignore_buttons (FALSE); +--- gdm-2.19.1/daemon/slave.c.reset-pam 2007-05-13 22:08:25.000000000 -0400 ++++ gdm-2.19.1/daemon/slave.c 2007-05-21 12:39:57.000000000 -0400 +@@ -146,6 +146,12 @@ static int gdm_normal_runlevel = + static pid_t extra_process = 0; + static int extra_status = 0; + ++/* a dup of the other side of greeter_fd_in so that ++ * the slave can talk to itself from its sig handler ++ * using the greeter ipc mechanism ++ */ ++static int slave_fd_out = -1; ++ + #ifdef HAVE_TSOL + static gboolean have_suntsol_extension = FALSE; + #endif +@@ -632,7 +638,7 @@ ignore_xerror_handler (Display *disp, XE + } + + static void +-whack_greeter_fds (void) ++whack_greeter_and_slave_fds (void) + { + if (greeter_fd_out > 0) + VE_IGNORE_EINTR (close (greeter_fd_out)); +@@ -640,6 +646,9 @@ whack_greeter_fds (void) + if (greeter_fd_in > 0) + VE_IGNORE_EINTR (close (greeter_fd_in)); + greeter_fd_in = -1; ++ if (slave_fd_out > 0) ++ VE_IGNORE_EINTR (close (slave_fd_out)); ++ slave_fd_out = -1; + } + + static void +@@ -1102,7 +1111,7 @@ gdm_slave_whack_greeter (void) + + d->greetpid = 0; + +- whack_greeter_fds (); ++ whack_greeter_and_slave_fds (); + + gdm_slave_send_num (GDM_SOP_GREETPID, 0); + +@@ -1936,7 +1945,7 @@ restart_the_greeter (void) + + d->greetpid = 0; + +- whack_greeter_fds (); ++ whack_greeter_and_slave_fds (); + + gdm_slave_send_num (GDM_SOP_GREETPID, 0); + } +@@ -2177,6 +2186,12 @@ gdm_slave_wait_for_login (void) + break; + } + ++ if (do_cancel) { ++ gdm_debug ("canceling..."); ++ gdm_slave_greeter_ctl_no_ret (GDM_RESETOK, ""); ++ continue; ++ } ++ + if (login == NULL) { + const char *failuresound = gdm_daemon_config_get_value_string (GDM_KEY_SOUND_ON_LOGIN_FAILURE_FILE); + +@@ -2780,10 +2795,10 @@ gdm_slave_greeter (void) + + default: + VE_IGNORE_EINTR (close (pipe1[0])); +- VE_IGNORE_EINTR (close (pipe2[1])); + +- whack_greeter_fds (); ++ whack_greeter_and_slave_fds (); + ++ slave_fd_out = pipe2[1]; + greeter_fd_out = pipe1[1]; + greeter_fd_in = pipe2[0]; + +@@ -4740,7 +4755,7 @@ gdm_slave_child_handler (int sig) + + greet = FALSE; + d->greetpid = 0; +- whack_greeter_fds (); ++ whack_greeter_and_slave_fds (); + gdm_slave_send_num (GDM_SOP_GREETPID, 0); + + do_restart_greeter = TRUE; +@@ -4895,6 +4910,11 @@ gdm_slave_handle_usr2_message (void) + gdm_wait_for_go = FALSE; + } else if (strcmp (&s[1], GDM_NOTIFY_TWIDDLE_POINTER) == 0) { + gdm_twiddle_pointer (d); ++ } else if (strcmp (&s[1], GDM_NOTIFY_RESET) == 0) { ++ if (!d->logged_in) { ++ gdm_fdprintf (slave_fd_out, "%c%c%c\n", ++ STX, BEL, GDM_INTERRUPT_CANCEL); ++ } + } + } else if (s[0] == GDM_SLAVE_NOTIFY_RESPONSE) { + gdm_got_ack = TRUE; +--- gdm-2.19.1/daemon/gdm-daemon-config-keys.h.reset-pam 2007-05-21 12:43:21.000000000 -0400 ++++ gdm-2.19.1/daemon/gdm-daemon-config-keys.h 2007-05-21 12:43:42.000000000 -0400 +@@ -226,6 +226,7 @@ G_BEGIN_DECLS + #define GDM_NOTIFY_SOFT_RESTART_SERVERS "SOFT_RESTART_SERVERS" + #define GDM_NOTIFY_GO "GO" + #define GDM_NOTIFY_TWIDDLE_POINTER "TWIDDLE_POINTER" ++#define GDM_NOTIFY_RESET "RESET" + + G_END_DECLS + +--- gdm-2.19.1/daemon/gdm.c.reset-pam 2007-05-13 22:08:24.000000000 -0400 ++++ gdm-2.19.1/daemon/gdm.c 2007-05-21 12:45:14.000000000 -0400 +@@ -2585,6 +2585,14 @@ gdm_handle_message (GdmConnection *conn, + TRUE /* handled */, + FALSE /* chooser */, + NULL, 0, NULL, NULL, NULL); ++} else if (strcmp (msg, GDM_SOP_CANCEL_LOGIN_REQUESTS) == 0) { ++ GSList *li; ++ for (li = displays; li != NULL; li = li->next) { ++ GdmDisplay *d = li->data; ++ if (!d->logged_in) { ++ send_slave_command (d, GDM_NOTIFY_RESET); ++ } ++ } + } else if (strncmp (msg, "opcode="GDM_SOP_SHOW_ERROR_DIALOG, + strlen ("opcode="GDM_SOP_SHOW_ERROR_DIALOG)) == 0) { + GdmDisplay *d; +--- gdm-2.19.1/daemon/gdm-socket-protocol.h.reset-pam 2007-05-21 12:42:32.000000000 -0400 ++++ gdm-2.19.1/daemon/gdm-socket-protocol.h 2007-05-21 12:42:58.000000000 -0400 +@@ -155,6 +155,9 @@ + #define GDM_SOP_SHOW_QUESTION_DIALOG "SHOW_QUESTION_DIALOG" /* show the question dialog from daemon */ + #define GDM_SOP_SHOW_ASKBUTTONS_DIALOG "SHOW_ASKBUTTON_DIALOG" /* show the askbutton dialog from daemon */ + ++/* Reset any in progress authentication conversations */ ++#define GDM_SOP_CANCEL_LOGIN_REQUESTS "CANCEL_LOGIN_REQUESTS" /* no arguments */ ++ + + /* Ack for a slave message */ + /* Note that an extra response can follow an 'ack' */ diff --git a/gdm-2.19.1-security-tokens.patch b/gdm-2.19.1-security-tokens.patch new file mode 100644 index 0000000..105eb5d --- /dev/null +++ b/gdm-2.19.1-security-tokens.patch @@ -0,0 +1,2848 @@ +--- gdm-2.19.1/configure.ac.security-tokens 2007-05-21 12:57:13.000000000 -0400 ++++ gdm-2.19.1/configure.ac 2007-05-21 13:03:45.000000000 -0400 +@@ -20,6 +20,7 @@ LIBRSVG_REQUIRED=1.1.1 + LIBXML_REQUIRED=2.4.12 + LIBART_REQUIRED=2.3.11 + SCROLLKEEPER_REQUIRED=0.1.4 ++NSS_REQUIRED=3.11.1 + + dnl + dnl Let the user configure where to look for the configuration files. +@@ -176,7 +177,7 @@ PKG_CHECK_MODULES(COMMON, gtk+-2.0 >= $G + AC_SUBST(COMMON_CFLAGS) + AC_SUBST(COMMON_LIBS) + +-PKG_CHECK_MODULES(DAEMON, gtk+-2.0 >= $GTK_REQUIRED) ++PKG_CHECK_MODULES(DAEMON, gtk+-2.0 >= $GTK_REQUIRED ns >= $NSS_REQUIRED) + AC_SUBST(DAEMON_CFLAGS) + AC_SUBST(DAEMON_LIBS) + +--- /dev/null 2007-05-21 09:34:56.803421964 -0400 ++++ gdm-2.19.1/config/securitytokens.conf.in 2007-05-21 12:57:13.000000000 -0400 +@@ -0,0 +1,3 @@ ++[SecurityTokens] ++Enable=true ++#Driver=@libdir@/pkcs11/libcoolkeypk11.so +--- gdm-2.19.1/config/Makefile.am.security-tokens 2007-05-13 22:08:25.000000000 -0400 ++++ gdm-2.19.1/config/Makefile.am 2007-05-21 12:57:13.000000000 -0400 +@@ -34,9 +34,11 @@ EXTRA_DIST = \ + XKeepsCrashing \ + gettextfoo.h \ + gdmprefetchlist.in \ ++ securitytokens.conf.in \ + extract-shell.sh + +-CLEANFILES = Xsession gdm.conf gdm.conf-custom default.desktop gnome.desktop CDE.desktop ssh.desktop Init PreSession PostSession gdmprefetchlist ++CLEANFILES = Xsession gdm.conf gdm.conf-custom default.desktop gnome.desktop CDE.desktop ssh.desktop Init PreSession PostSession gdmprefetchlist securitytokens.conf ++ + + Xsession: $(srcdir)/Xsession.in + sed -e 's,[@]XSESSION_SHELL[@],$(XSESSION_SHELL),g' \ +@@ -75,6 +77,31 @@ gdm.conf-custom: $(srcdir)/gdm.conf-cust + sed -e 's,[@]GDM_DEFAULTS_CONF[@],$(GDM_DEFAULTS_CONF),g' \ + <$(srcdir)/gdm.conf-custom.in >gdm.conf-custom + ++securitytokens.conf: $(srcdir)/securitytokens.conf.in ++ sed -e 's,[@]GDMPREFETCHCMD[@],$(GDMPREFETCHCMD),g' \ ++ -e 's,[@]GDM_USER_PATH[@],$(GDM_USER_PATH),g' \ ++ -e 's,[@]HALT_COMMAND[@],$(HALT_COMMAND),g' \ ++ -e 's,[@]REBOOT_COMMAND[@],$(REBOOT_COMMAND),g' \ ++ -e 's,[@]SOUND_PROGRAM[@],$(SOUND_PROGRAM),g' \ ++ -e 's,[@]SUSPEND_COMMAND[@],$(SUSPEND_COMMAND),g' \ ++ -e 's,[@]XEVIE_OPTION[@],$(XEVIE_OPTION),g' \ ++ -e 's,[@]X_CONFIG_OPTIONS[@],$(X_CONFIG_OPTIONS),g' \ ++ -e 's,[@]X_SERVER[@],$(X_SERVER),g' \ ++ -e 's,[@]X_XNEST_CONFIG_OPTIONS[@],$(X_XNEST_CONFIG_OPTIONS),g' \ ++ -e 's,[@]X_XNEST_PATH[@],$(X_XNEST_PATH),g' \ ++ -e 's,[@]authdir[@],$(authdir),g' \ ++ -e 's,[@]datadir[@],$(datadir),g' \ ++ -e 's,[@]dmconfdir[@],$(dmconfdir),g' \ ++ -e 's,[@]gdmconfdir[@],$(gdmconfdir),g' \ ++ -e 's,[@]libdir[@],$(libdir),g' \ ++ -e 's,[@]libexecdir[@],$(libexecdir),g' \ ++ -e 's,[@]localedir[@],$(libexecdir),g' \ ++ -e 's,[@]logdir[@],$(logdir),g' \ ++ -e 's,[@]pixmapdir[@],$(pixmapdir),g' \ ++ -e 's,[@]sbindir[@],$(sbindir),g' \ ++ <$(srcdir)/securitytokens.conf.in >securitytokens.conf ++ ++ + gettextfoo.h: XKeepsCrashing Xsession.in + cat $^ | $(srcdir)/extract-shell.sh > gettextfoo.h + +@@ -103,7 +130,7 @@ uninstall-hook: + $(DESTDIR)$(predir)/Default \ + $(DESTDIR)$(postdir)/Default + +-install-data-hook: gdm.conf gdm.conf-custom Xsession Init PostSession PreSession $(DESKTOP_FILES) $(GDMPREFETCHLIST) ++install-data-hook: gdm.conf gdm.conf-custom Xsession Init PostSession PreSession $(DESKTOP_FILES) $(GDMPREFETCHLIST) securitytokens.conf + if test '!' -d $(DESTDIR)$(confdir); then \ + $(mkinstalldirs) $(DESTDIR)$(confdir); \ + chmod 755 $(DESTDIR)$(confdir); \ +@@ -136,6 +163,7 @@ install-data-hook: gdm.conf gdm.conf-cus + chmod 644 $(DESTDIR)$(GDM_CUSTOM_CONF); \ + fi + $(INSTALL_DATA) gdm.conf `dirname $(DESTDIR)$(GDM_DEFAULTS_CONF)`/factory-`basename $(DESTDIR)$(GDM_DEFAULTS_CONF)` ++ $(INSTALL_DATA) securitytokens.conf $(DESTDIR)$(confdir)/securitytokens.conf + + $(INSTALL_SCRIPT) $(srcdir)/XKeepsCrashing $(DESTDIR)$(confdir)/XKeepsCrashing + $(INSTALL_SCRIPT) Xsession $(DESTDIR)$(confdir)/Xsession +--- gdm-2.19.1/config/gdm.conf.in.security-tokens 2007-05-21 12:57:13.000000000 -0400 ++++ gdm-2.19.1/config/gdm.conf.in 2007-05-21 12:57:13.000000000 -0400 +@@ -239,6 +239,10 @@ AlwaysLoginCurrentSession=true + # kills it. 10 seconds should be long enough for X, but Xgl may need 20 or 25. + GdmXserverTimeout=10 + ++# Whether or not to listen for smart card insertion/removal events ++SecurityTokensEnable=true ++SecurityTokensDriver= ++ + [security] + # Allow root to login. It makes sense to turn this off for kiosk use, when + # you want to minimize the possibility of break in. +--- gdm-2.19.1/daemon/gdm.c.security-tokens 2007-05-21 12:57:13.000000000 -0400 ++++ gdm-2.19.1/daemon/gdm.c 2007-05-21 13:14:26.000000000 -0400 +@@ -71,6 +71,8 @@ + #include "cookie.h" + #include "filecheck.h" + #include "errorgui.h" ++#include "securitytokenmonitor.h" ++#include "securitytoken.h" + + #include "gdm-socket-protocol.h" + #include "gdm-daemon-config.h" +@@ -93,6 +95,10 @@ static void gdm_handle_message (GdmConne + static void gdm_handle_user_message (GdmConnection *conn, + const gchar *msg, + gpointer data); ++ ++static void gdm_reset_local_displays (void); ++static void gdm_watch_for_security_tokens (void); ++ + static void gdm_daemonify (void); + static void gdm_safe_restart (void); + static void gdm_try_logout_action (GdmDisplay *disp); +@@ -1787,6 +1793,8 @@ main (int argc, char *argv[]) + gdm_xdmcp_run (); + } + ++ gdm_watch_for_security_tokens (); ++ + /* We always exit via exit (), and sadly we need to g_main_quit () + * at times not knowing if it's this main or a recursive one we're + * quitting. +@@ -4342,3 +4350,80 @@ gdm_handle_user_message (GdmConnection * + gdm_connection_close (conn); + } + } ++ ++static void ++gdm_reset_local_displays (void) ++{ ++ GSList *li; ++ ++ for (li = displays; li != NULL; li = li->next) { ++ GdmDisplay *d = li->data; ++ ++ if (d->attached) ++ send_slave_command (d, GDM_NOTIFY_RESET); ++ } ++} ++ ++#ifndef GDM_SECURITY_TOKENS_CONF ++#define GDM_SECURITY_TOKENS_CONF GDMCONFDIR "/securitytokens.conf" ++#endif ++ ++#ifndef GDM_SECURITY_TOKENS_KEY_ENABLED ++#define GDM_SECURITY_TOKENS_KEY_ENABLED "SecurityTokens/Enabled=true" ++#endif ++ ++#ifndef GDM_SECURITY_TOKENS_KEY_DRIVER ++#define GDM_SECURITY_TOKENS_KEY_DRIVER "SecurityTokens/Driver" ++#endif ++ ++static void ++gdm_watch_for_security_tokens (void) ++{ ++ GError *error; ++ ScSecurityTokenMonitor *monitor; ++ gchar *driver; ++ VeConfig *cfg; ++ ++ cfg = ve_config_new (GDM_SECURITY_TOKENS_CONF); ++ ++ if (!ve_config_get_bool (cfg, GDM_SECURITY_TOKENS_KEY_ENABLED)) { ++ gdm_debug ("security token support is not enabled"); ++ goto out; ++ } ++ ++ gdm_debug ("watching for security token insertion and removal events"); ++ ++ driver = ve_config_get_string (cfg, GDM_SECURITY_TOKENS_KEY_DRIVER); ++ gdm_debug ("security tokens driver is set to '%s'", ++ ve_string_empty (driver)? "" : driver); ++ monitor = sc_security_token_monitor_new (driver); ++ g_free (driver); ++ ++ g_signal_connect (monitor, ++ "security-token-inserted", ++ G_CALLBACK (gdm_reset_local_displays), ++ NULL); ++ ++ g_signal_connect (monitor, ++ "security-token-removed", ++ G_CALLBACK (gdm_reset_local_displays), ++ NULL); ++ ++ error = NULL; ++ if (!sc_security_token_monitor_start (monitor, &error)) { ++ g_object_unref (monitor); ++ monitor = NULL; ++ ++ if (error != NULL) { ++ syslog (LOG_ERR, "%s", error->message); ++ g_error_free (error); ++ } else { ++ syslog (LOG_ERR, "could not start security token monitor"); ++ ++ } ++ goto out; ++ } ++out: ++ ve_config_destroy (cfg); ++} ++ +--- /dev/null 2007-05-21 09:34:56.803421964 -0400 ++++ gdm-2.19.1/daemon/securitytokenmonitor.h 2007-05-21 12:57: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 */ +--- gdm-2.19.1/daemon/Makefile.am.security-tokens 2007-05-13 22:08:25.000000000 -0400 ++++ gdm-2.19.1/daemon/Makefile.am 2007-05-21 13:16:08.000000000 -0400 +@@ -9,6 +9,7 @@ INCLUDES = \ + -DAUTHDIR=\"$(authdir)\" \ + -DBINDIR=\"$(bindir)\" \ + -DDATADIR=\"$(datadir)\" \ ++ -DSYSCONFDIR=\"$(sysconfdir)\" \ + -DDMCONFDIR=\"$(dmconfdir)\" \ + -DGDMCONFDIR=\"$(gdmconfdir)\" \ + -DGDMLOCALEDIR=\"$(gdmlocaledir)\" \ +@@ -68,6 +69,10 @@ gdm_binary_SOURCES = \ + gdm-net.h \ + getvt.c \ + getvt.h \ ++ securitytoken.c \ ++ securitytoken.h \ ++ securitytokenmonitor.c \ ++ securitytokenmonitor.h \ + $(NULL) + + XDMCP_SOURCES = \ +--- /dev/null 2007-05-21 09:34:56.803421964 -0400 ++++ gdm-2.19.1/daemon/securitytoken.h 2007-05-21 12:57: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 */ +--- /dev/null 2007-05-21 09:34:56.803421964 -0400 ++++ gdm-2.19.1/daemon/securitytokenmonitor.c 2007-05-21 12:57: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-05-21 09:34:56.803421964 -0400 ++++ gdm-2.19.1/daemon/securitytoken.c 2007-05-21 12:57: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 diff --git a/gdm-2.19.1-wtmp.patch b/gdm-2.19.1-wtmp.patch new file mode 100644 index 0000000..29eb6e2 --- /dev/null +++ b/gdm-2.19.1-wtmp.patch @@ -0,0 +1,246 @@ +--- gdm-2.19.1/config/PreSession.in.wtmp 2007-05-13 22:08:25.000000000 -0400 ++++ gdm-2.19.1/config/PreSession.in 2007-05-21 13:17:09.000000000 -0400 +@@ -68,17 +68,4 @@ if [ "x$XSETROOT" != "x" ] ; then + "$XSETROOT" -cursor_name left_ptr -solid "$BACKCOLOR" + fi + +- +-SESSREG=`gdmwhich sessreg` +-if [ "x$SESSREG" != "x" ] ; then +- # some output for easy debugging +- echo "$0: Registering your session with wtmp and utmp" +- echo "$0: running: $SESSREG -a -w /var/log/wtmp -u /var/run/utmp -x \"$X_SERVERS\" -h \"$REMOTE_HOST\" -l \"$DISPLAY\" \"$USER\"" +- +- exec "$SESSREG" -a -w /var/log/wtmp -u /var/run/utmp -x "$X_SERVERS" -h "$REMOTE_HOST" -l "$DISPLAY" "$USER" +- # this is not reached +-fi +- +-# some output for easy debugging +-echo "$0: could not find the sessreg utility, cannot update wtmp and utmp" + exit 0 +--- gdm-2.19.1/daemon/slave.c.wtmp 2007-05-21 13:17:09.000000000 -0400 ++++ gdm-2.19.1/daemon/slave.c 2007-05-21 13:20:51.000000000 -0400 +@@ -4426,6 +4426,13 @@ gdm_slave_session_start (void) + g_free (language); + g_free (gnome_session); + ++ gdm_verify_write_record (d, ++ GDM_VERIFY_RECORD_TYPE_LOGIN, ++ pwent->pw_name, ++ d->name, ++ !d->attached? d->hostname : NULL, ++ pid); ++ + gdm_slave_send_num (GDM_SOP_SESSPID, pid); + + gdm_sigchld_block_push (); +@@ -4488,6 +4495,17 @@ gdm_slave_session_start (void) + } + #endif + ++ if ((pid != 0) && (d->last_sess_status != -1)) { ++ gdm_debug ("session '%d' exited with status '%d', recording logout", ++ pid, d->last_sess_status); ++ gdm_verify_write_record (d, ++ GDM_VERIFY_RECORD_TYPE_LOGOUT, ++ pwent->pw_name, ++ d->name, ++ !d->attached? d->hostname : NULL, ++ pid); ++ } ++ + gdm_slave_session_stop (pid != 0 /* run_post_session */, + FALSE /* no_shutdown_check */); + +--- gdm-2.19.1/daemon/verify-pam.c.wtmp 2007-05-21 13:17:09.000000000 -0400 ++++ gdm-2.19.1/daemon/verify-pam.c 2007-05-21 13:23:28.000000000 -0400 +@@ -32,6 +32,7 @@ + #ifdef __sun + #include + #endif ++#include + + #include + +@@ -63,6 +64,14 @@ + #define log_to_audit_system(l,h,d,s) do { ; } while (0) + #endif + ++#ifndef GDM_BAD_RECORDS_FILE ++#define GDM_BAD_RECORDS_FILE "/var/log/btmp" ++#endif ++ ++#ifndef GDM_NEW_RECORDS_FILE ++#define GDM_NEW_RECORDS_FILE "/var/log/wtmp" ++#endif ++ + /* Evil, but this way these things are passed to the child session */ + static pam_handle_t *pamh = NULL; + +@@ -427,6 +436,125 @@ gdm_verify_select_user (const char *user + selected_user = g_strdup (user); + } + ++void ++gdm_verify_write_record (GdmDisplay *d, ++ GdmVerifyRecordType record_type, ++ const gchar *username, ++ const gchar *console_name, ++ const gchar *host_name, ++ GPid pid) ++{ ++ struct utmp record = { 0 }; ++ GTimeVal now = { 0 }; ++ gchar *host; ++ ++ gdm_debug ("writing %s record", ++ record_type == GDM_VERIFY_RECORD_TYPE_LOGIN? "session" : ++ record_type == GDM_VERIFY_RECORD_TYPE_LOGOUT? "logout" : ++ "failed session attempt"); ++ ++ if (record_type != GDM_VERIFY_RECORD_TYPE_LOGOUT) ++ { ++ /* it's possible that PAM failed before ++ * it mapped the user input into a valid username ++ * so we fallback to try using "(unknown)" ++ */ ++ if (username != NULL) ++ strncpy (record.ut_user, ++ username, ++ sizeof (record.ut_user)); ++ else ++ strncpy (record.ut_user, ++ "(unknown)", ++ sizeof (record.ut_user)); ++ } ++ ++ gdm_debug ("using username %.*s", ++ sizeof (record.ut_user), ++ record.ut_user); ++ ++ strncpy (record.ut_id, ++ console_name + ++ strlen (console_name) - ++ sizeof (record.ut_id), ++ sizeof (record.ut_id)); ++ ++ gdm_debug ("using id %.*s", ++ sizeof (record.ut_id), ++ record.ut_id); ++ ++ if (g_str_has_prefix (console_name, "/dev/")) { ++ strncpy (record.ut_line, ++ console_name + strlen ("/dev/"), ++ sizeof (record.ut_line)); ++ } else if (g_str_has_prefix (console_name, ":")) { ++ strncpy (record.ut_line, ++ console_name, ++ sizeof (record.ut_line)); ++ } ++ ++ gdm_debug ("using line %.*s", ++ sizeof (record.ut_line), ++ record.ut_line); ++ ++ host = NULL; ++ if ((host_name != NULL) && ++ g_str_has_prefix (console_name, ":")) ++ host = g_strdup_printf ("%s%s", ++ host_name, ++ console_name); ++ else if ((host_name != NULL) && ++ !strstr (console_name, ":")) ++ host = g_strdup (host_name); ++ else if (!g_str_has_prefix (console_name, ":") && ++ strstr (console_name, ":")) ++ host = g_strdup (console_name); ++ ++ if (host) ++ { ++ strncpy (record.ut_host, host, sizeof (record.ut_host)); ++ g_free (host); ++ gdm_debug ("using hostname %.*s", ++ sizeof (record.ut_host), ++ record.ut_host); ++ } ++ ++ g_get_current_time (&now); ++ record.ut_tv.tv_sec = now.tv_sec; ++ record.ut_tv.tv_usec = now.tv_usec; ++ ++ gdm_debug ("using time %ld", (glong) record.ut_tv.tv_sec); ++ ++ record.ut_type = USER_PROCESS; ++ gdm_debug ("using type USER_PROCESS"); ++ ++ record.ut_pid = pid; ++ ++ gdm_debug ("using pid %d", (gint) record.ut_pid); ++ ++ switch (record_type) ++ { ++ case GDM_VERIFY_RECORD_TYPE_LOGIN: ++ gdm_debug ("writing session record to " ++ GDM_NEW_RECORDS_FILE); ++ updwtmp (GDM_NEW_RECORDS_FILE, &record); ++ break; ++ ++ case GDM_VERIFY_RECORD_TYPE_LOGOUT: ++ gdm_debug ("writing logout record to " ++ GDM_NEW_RECORDS_FILE); ++ updwtmp (GDM_NEW_RECORDS_FILE, &record); ++ break; ++ ++ case GDM_VERIFY_RECORD_TYPE_FAILED_ATTEMPT: ++ gdm_debug ("writing failed session attempt record to " ++ GDM_BAD_RECORDS_FILE); ++ updwtmp (GDM_BAD_RECORDS_FILE, &record); ++ break; ++ } ++ ++} ++ + static const char * + perhaps_translate_message (const char *msg) + { +@@ -1234,6 +1362,11 @@ gdm_verify_user (GdmDisplay *d, + * message from the PAM subsystem */ + if ( ! error_msg_given && + gdm_slave_action_pending ()) { ++ gdm_verify_write_record (d, GDM_VERIFY_RECORD_TYPE_FAILED_ATTEMPT, ++ login, display, ++ d->attached? NULL : d->hostname, ++ getpid ()); ++ + /* + * I'm not sure yet if I should display this message for any + * other issues - heeten +--- gdm-2.19.1/daemon/verify.h.wtmp 2007-05-13 22:08:25.000000000 -0400 ++++ gdm-2.19.1/daemon/verify.h 2007-05-21 13:17:09.000000000 -0400 +@@ -22,6 +22,12 @@ + #include "gdm.h" + #include "display.h" + ++typedef enum { ++ GDM_VERIFY_RECORD_TYPE_LOGIN, ++ GDM_VERIFY_RECORD_TYPE_LOGOUT, ++ GDM_VERIFY_RECORD_TYPE_FAILED_ATTEMPT ++} GdmVerifyRecordType; ++ + /* If username is NULL, we ask, if local is FALSE, don't start + * the timed login timer */ + gchar *gdm_verify_user (GdmDisplay *d, +@@ -32,6 +38,13 @@ gchar *gdm_verify_user (GdmDisplay *d + void gdm_verify_cleanup (GdmDisplay *d); + void gdm_verify_check (void); + void gdm_verify_select_user (const char *user); ++void gdm_verify_write_record (GdmDisplay *d, ++ GdmVerifyRecordType record_type, ++ const gchar *username, ++ const gchar *console_name, ++ const gchar *host_name, ++ GPid pid); ++ + /* used in pam */ + gboolean gdm_verify_setup_env (GdmDisplay *d); + gboolean gdm_verify_setup_user (GdmDisplay *d, diff --git a/gdm-2.8.0.2-clean-up-xsession-errors.patch b/gdm-2.8.0.2-clean-up-xsession-errors.patch deleted file mode 100644 index 44d181a..0000000 --- a/gdm-2.8.0.2-clean-up-xsession-errors.patch +++ /dev/null @@ -1,16 +0,0 @@ ---- gdm-2.6.0.5/daemon/slave.c.old 2004-10-20 05:58:05.449740960 -0400 -+++ gdm-2.6.0.5/daemon/slave.c 2004-10-20 05:58:37.230909488 -0400 -@@ -4293,7 +4293,12 @@ - #endif - - finish_session_output (run_post_session /* do_read */); -- -+ -+ /* If successfully exited then clear the log file -+ */ -+ if (d->xsession_errors_filename != NULL) -+ VE_IGNORE_EINTR (unlink (d->xsession_errors_filename)); -+ - if (local_login == NULL) - pwent = NULL; - else diff --git a/gdm.spec b/gdm.spec index 5a89193..6ba22e6 100644 --- a/gdm.spec +++ b/gdm.spec @@ -16,13 +16,13 @@ Summary: The GNOME Display Manager Name: gdm -Version: 2.18.0 -Release: 14%{?dist} +Version: 2.19.1 +Release: 1%{?dist} Epoch: 1 License: LGPL/GPL Group: User Interface/X -URL: ftp://ftp.gnome.org/pub/GNOME/sources/gdm -Source: http://ftp.gnome.org/pub/gnome/sources/gdm/2.18/gdm-%{version}.tar.bz2 +URL: ftp://download.gnome.org/sources/gdm +Source: http://download.gnome.org/sources/gdm/2.19/gdm-%{version}.tar.bz2 Source1: gdm-pam Source2: gdm-autologin-pam Source3: gdmsetup-pam @@ -30,25 +30,19 @@ Source4: 90-grant-audio-devices-to-gdm.fdi Source5: fedora-faces-20070319.tar.bz2 Source6: default.desktop -Patch1: gdm-2.18.0-change-defaults.patch +Patch1: gdm-2.19.1-change-defaults.patch Patch4: gdm-2.13.0.4-update-switchdesk-location.patch -# http://bugzilla.gnome.org/show_bug.cgi?id=301817 -Patch6: gdm-2.8.0.2-clean-up-xsession-errors.patch - -# http://bugzilla.gnome.org/show_bug.cgi?id=301826 -Patch7: gdm-2.8.0.2-merge-resources.patch - # http://bugzilla.gnome.org/show_bug.cgi?id=349835 -Patch12: gdm-2.17.6-audit-login.patch +Patch12: gdm-2.19.1-audit-login.patch # http://bugzilla.gnome.org/show_bug.cgi?id=347798 -Patch19: gdm-2.17.7-move-default-message.patch -Patch20: gdm-2.17.7-reset-pam.patch -Patch21: gdm-2.18.0-security-tokens.patch +Patch19: gdm-2.19.1-move-default-message.patch +Patch20: gdm-2.19.1-reset-pam.patch +Patch21: gdm-2.19.1-security-tokens.patch # http://bugzilla.gnome.org/show_bug.cgi?id=347871 -Patch24: gdm-2.16.0-wtmp.patch +Patch24: gdm-2.19.1-wtmp.patch # https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=203917 Patch25: gdm-2.16.0-indic-langs.patch @@ -59,27 +53,18 @@ Patch28: gdm-2.17.1-desensitize-entry.patch Patch29: gdm-2.17.7-greeter.patch # http://bugzilla.gnome.org/show_bug.cgi?id=426653 -Patch31: gdm-2.17.8-hide-uninstalled-languages.patch +Patch31: gdm-2.19.1-hide-uninstalled-languages.patch # http://bugzilla.gnome.org/show_bug.cgi?id=412576 -Patch32: gdm-2.17.8-a11y-fixes-for-themed-greeter.patch +Patch32: gdm-2.19.1-a11y-fixes-for-themed-greeter.patch # http://bugzilla.gnome.org/show_bug.cgi?id=411501 -Patch33: gdm-2.17.7-pass-at-to-session-4.patch - -# http://bugzilla.gnome.org/show_bug.cgi?id=420610 -Patch34: gdm-2.18.0-add-lowres-fix.patch - -# http://bugzilla.gnome.org/show_bug.cgi?id=424229 -Patch35: gdm-2.18.0-dont-strcpy-overlapping-strings.patch - -# http://bugzilla.gnome.org/show_bug.cgi?id=426647 -Patch36: gdm-2.18.0-dont-expect-utf8.patch +Patch33: gdm-2.19.1-pass-ats-to-session.patch Patch37: gdm-2.18.0-hide-disabled-users.patch # https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=234567 -Patch99: gdm-2.18.0-be-more-verbose.patch +#Patch99: gdm-2.18.0-be-more-verbose.patch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) @@ -154,8 +139,6 @@ Extra icons / faces for the GNOME Display Manager. %patch1 -p1 -b .change-defaults %patch4 -p1 -b .update-switchdesk-location -%patch6 -p1 -b .clean-up-xsession-errors -%patch7 -p1 -b .merge-resources %patch12 -p1 -b .audit-login %patch19 -p1 -b .move-default-message %patch20 -p1 -b .reset-pam @@ -165,13 +148,10 @@ Extra icons / faces for the GNOME Display Manager. %patch28 -p1 -b .desensitize-entry %patch29 -p0 -b .greeter %patch31 -p1 -b .hide-uninstalled-languages -%patch32 -p0 -b .a11y-fixes -%patch33 -p0 -b .pass-ats-to-session -%patch34 -p1 -b .add-lowres-fix -%patch35 -p1 -b .dont-strcpy-overlapping-strings -%patch36 -p1 -b .dont-expect-utf8 +%patch32 -p1 -b .a11y-fixes +%patch33 -p1 -b .pass-ats-to-session %patch37 -p1 -b hide-disabled-users -%patch99 -p1 -b .be-more-verbose +#%patch99 -p1 -b .be-more-verbose %build cp -f %{SOURCE1} config/gdm @@ -394,6 +374,9 @@ fi %{_datadir}/pixmaps/faces/extras/*.jpg %changelog +* Mon May 21 2007 Matthias Clasen - 1:2.19.1-1 +- Update to 2.19.1 + * Tue May 15 2007 Ray Strode - 1:2.18.0-14 - hide users from userlist that have disabled shells (bug 240148) diff --git a/sources b/sources index 72d955e..c91cf92 100644 --- a/sources +++ b/sources @@ -1,2 +1 @@ -a569a8275f0e0396e6ef5f63c5f56ad5 gdm-2.18.0.tar.bz2 -7387935ad09f746889b58bd69bf815e1 fedora-faces-20070319.tar.bz2 +b18053fc83f66649e4c53939503c325c gdm-2.19.1.tar.bz2