--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/components/desktop/xscreensaver/patches/0020-bug-15769303.patch Tue Mar 08 09:00:31 2016 -0800
@@ -0,0 +1,374 @@
+From a946e560758d0041aea4fc55ee7f5f657cbe27df Mon Sep 17 00:00:00 2001
+From: Alan Coopersmith <[email protected]>
+Date: Sat, 2 Jan 2016 23:16:21 -0800
+Subject: [PATCH] bug 15769303
+
+15769303 SUNBT7136531 xscreensaver incorrectly processes PAM_ERROR_MSG
+ and possibly PAM_TEXT_INFO
+
+Displayed PAM_ERROR_MSG and PAM_TEXT_INFO at Locked screen with Dismiss
+button. After reading message, user can click Dismiss button or press
+Enter to close the Locked Screen.
+
+Upstream applicability & status unknown.
+---
+ driver/lock-Gtk.c | 45 +++++++++++++++++++++--------
+ driver/lock.c | 49 ++++++++++++++++++++++++++------
+ driver/passwd-pam.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++----
+ 3 files changed, 150 insertions(+), 25 deletions(-)
+
+diff --git a/driver/lock-Gtk.c b/driver/lock-Gtk.c
+index 13e0213..cbb70a2 100644
+--- a/driver/lock-Gtk.c
++++ b/driver/lock-Gtk.c
+@@ -394,11 +394,13 @@ make_dialog (gboolean center_pos)
+ NULL);
+
+ /* Ok button */
+- button = gtk_button_new_from_stock (GTK_STOCK_OK);
++ button = g_object_new (GTK_TYPE_BUTTON, "visible", FALSE, "label",
++ "Dismiss", "can_focus", TRUE, NULL) ;
+ pwd->button = button;
+
+ gtk_box_pack_end (GTK_BOX (bbox), button,
+ FALSE, TRUE, 0);
++ gtk_box_pack_start (GTK_BOX (vbox2), bbox, FALSE, FALSE, 0);
+
+ free (user);
+ free (version);
+@@ -417,18 +419,26 @@ ok_clicked_cb (GtkWidget *button, PasswdDialog *pwd)
+ {
+ const char *s;
+
+- g_object_set (pwd->msg_label, "label", _("<b>Checking...</b>"), NULL);
++ if (GTK_IS_BUTTON (button) && gtk_widget_get_visible (button)) /* Is it Dismiss Dialog Box */
++ {
++ write_to_parent ("dismiss", "true", TRUE);
++ gtk_widget_hide (button);
++ }
++ else
++ {
++ g_object_set (pwd->msg_label, "label", _("<b>Checking...</b>"), NULL);
+
+- s = gtk_entry_get_text (GTK_ENTRY (pwd->user_input_entry));
+- write_to_parent ("input", s, TRUE);
++ s = gtk_entry_get_text (GTK_ENTRY (pwd->user_input_entry));
++ write_to_parent ("input", s, TRUE);
+
+- /* Reset password field to blank, else passwd field shows old passwd *'s,
+- visible when passwd is expired, and pam is walking the user to change
+- old passwd.
+- */
+- gtk_editable_delete_text (GTK_EDITABLE (pwd->user_input_entry), 0, -1);
+- gtk_widget_hide (pwd->user_input_entry);
+- gtk_widget_hide (pwd->user_prompt_label);
++ /* Reset password field to blank, else passwd field shows old passwd *'s,
++ visible when passwd is expired, and pam is walking the user to change
++ old passwd.
++ */
++ gtk_editable_delete_text (GTK_EDITABLE (pwd->user_input_entry), 0, -1);
++ gtk_widget_hide (pwd->user_input_entry);
++ gtk_widget_hide (pwd->user_prompt_label);
++ }
+ }
+
+ static void
+@@ -445,6 +455,10 @@ connect_signals (PasswdDialog *pwd)
+ g_signal_connect (pwd->dialog, "delete-event",
+ G_CALLBACK (gtk_main_quit),
+ NULL);
++
++ g_signal_connect (pwd->button, "button-press-event",
++ G_CALLBACK (ok_clicked_cb),
++ pwd);
+ }
+
+ static GdkFilterReturn
+@@ -561,6 +575,7 @@ handle_input (GIOChannel *source, GIOCondition cond, gpointer data)
+ {
+ gtk_label_set_text (GTK_LABEL (pwd->user_prompt_label), msgstr);
+ gtk_widget_show (pwd->user_prompt_label);
++ gtk_widget_hide (pwd->button);
+ msgstr = NULL; /* clear message so we don't show it twice */
+ }
+ else if ((strcmp (str, "ul_prompt_echo") == 0))
+@@ -595,6 +610,14 @@ handle_input (GIOChannel *source, GIOCondition cond, gpointer data)
+ {
+ hmsg = NULL; /* only show msg */
+ }
++ else if ((strcmp (str, "ul_pam_msg") == 0))
++ {
++ GTK_WIDGET_SET_FLAGS (pwd->button,GTK_CAN_DEFAULT);
++ gtk_widget_show (pwd->button);
++ gtk_widget_grab_default (pwd->button);
++ gtk_widget_grab_focus (pwd->button);
++ hmsg = NULL; /* only show msg */
++ }
+ else
+ {
+ /* Should not be others, but if so just show it */
+diff --git a/driver/lock.c b/driver/lock.c
+index dc40ca4..b494eae 100644
+--- a/driver/lock.c
++++ b/driver/lock.c
+@@ -437,6 +437,10 @@ handle_passwd_input (XtPointer xtdata, int *fd, XtInputId *id)
+ pw->passwd_string = strdup (data);
+ memset (data, 0, strlen(data));
+ }
++ else if ((strcmp(msg, "dismiss") == 0)) /* Dismiss Dialog */
++ {
++ si->unlock_state = ul_finished;
++ }
+ else if ((strcmp(msg, "ungrab_keyboard") == 0))
+ {
+ /* An accessibility helper needs to access the keyboard, so we have
+@@ -514,7 +518,7 @@ handle_passwd_input (XtPointer xtdata, int *fd, XtInputId *id)
+ si->num_typeahead_events = 0;
+ }
+ XGrabKeyboard (si->dpy, window, True, GrabModeAsync, GrabModeAsync, CurrentTime);
+- XGrabPointer (si->dpy, window, True, 0, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
++ XGrabPointer (si->dpy, window, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
+ XFlush (si->dpy);
+ XSetInputFocus (si->dpy, window, RevertToPointerRoot, CurrentTime);
+ XSync (si->dpy, False);
+@@ -957,7 +961,7 @@ static int
+ make_passwd_window (saver_info *si,
+ const char *info_msg,
+ const char *prompt,
+- Bool echo)
++ Bool echo, Bool dismissDialog)
+ {
+ #ifndef HAVE_XSCREENSAVER_LOCK
+ XSetWindowAttributes attrs;
+@@ -1006,7 +1010,7 @@ make_passwd_window (saver_info *si,
+ }
+
+ if (info_msg)
+- write_to_child (si, "ul_message", info_msg);
++ write_to_child (si, dismissDialog ? "ul_pam_msg" : "ul_message", info_msg);
+ if (prompt)
+ {
+ write_to_child (si, "ul_pamprompt", prompt);
+@@ -2719,8 +2723,22 @@ passwd_event_loop (saver_info *si)
+ handle_passwd_key (si, &event.x_event.xkey);
+ si->pw_data->caps_p = (event.x_event.xkey.state & LockMask);
+ }
+-#ifndef HAVE_XSCREENSAVER_LOCK
+- else if (event.x_event.xany.type == ButtonPress ||
++#ifdef HAVE_XSCREENSAVER_LOCK
++ else if ( event.x_event.xany.type == ButtonPress)
++ {
++ Bool status;
++ status= safe_XSendEvent (si->dpy, si->passwd_dialog,
++ False, ButtonPressMask, &event.x_event);
++ if (si->prefs.verbose_p)
++ {
++ if (status)
++ fprintf (stderr, "sent Button Press...\n");
++ else
++ fprintf (stderr, "error %d Button Press...\n", status);
++ }
++ }
++#else
++ else if (event.x_event.xany.type == ButtonPress ||
+ event.x_event.xany.type == ButtonRelease)
+ {
+ si->pw_data->button_state_changed_p = True;
+@@ -2937,6 +2955,8 @@ gui_auth_conv(int num_msg,
+ const char *info_msg, *prompt;
+ struct auth_response *responses;
+
++ Bool dismissDialog = False;
++
+ if (si->unlock_state == ul_cancel ||
+ si->unlock_state == ul_time)
+ /* If we've already cancelled or timed out in this PAM conversation,
+@@ -2977,9 +2997,14 @@ gui_auth_conv(int num_msg,
+ info_msg_trimmed = remove_trailing_whitespace(info_msg);
+ prompt_trimmed = remove_trailing_whitespace(prompt);
+
++ if( info_msg_trimmed != NULL && prompt_trimmed == NULL )
++ dismissDialog = True;
++ else
++ dismissDialog = False;
++
+ if (make_passwd_window(si, info_msg_trimmed, prompt_trimmed,
+ auth_msgs[i].type == AUTH_MSGTYPE_PROMPT_ECHO
+- ? True : False)
++ ? True : False, dismissDialog)
+ < 0)
+ goto fail;
+
+@@ -3001,6 +3026,9 @@ gui_auth_conv(int num_msg,
+ handle_typeahead (si);
+ passwd_event_loop (si);
+
++ if( dismissDialog )
++ goto fail; /* If it is DismissDialog, no response message */
++
+ if (si->unlock_state == ul_cancel)
+ goto fail;
+
+@@ -3040,10 +3068,13 @@ fail:
+ {
+ for (i = 0; i < num_msg; ++i)
+ if (responses[i].response)
+- free (responses[i].response);
++ {
++ bzero(responses[i].response, strlen(responses[i].response));
++ free (responses[i].response);
++ }
+ free (responses);
+ }
+-
++ *resp = NULL;
+ return -1;
+ }
+
+@@ -3084,7 +3115,7 @@ auth_finished_cb (saver_info *si)
+ else /* good, with no failures, */
+ goto END; /* or timeout, or cancel. */
+
+- make_passwd_window (si, s, NULL, True);
++ make_passwd_window (si, s, NULL, True, False);
+ XSync (si->dpy, False);
+
+ {
+diff --git a/driver/passwd-pam.c b/driver/passwd-pam.c
+index 4d24ac3..f5cd07c 100644
+--- a/driver/passwd-pam.c
++++ b/driver/passwd-pam.c
+@@ -541,7 +541,7 @@ pam_try_unlock(saver_info *si, Bool verbose_p,
+ else if (acct_rc != PAM_SUCCESS)
+ {
+ pam_auth_status = acct_rc;
+- write_to_child (si, "pw_acct_fail", PAM_STRERROR(pamh, acct_rc));
++ write_to_child (si, "ul_acct_fail", PAM_STRERROR(pamh, acct_rc));
+ sleep (3);
+ goto DONE;
+ }
+@@ -726,6 +726,7 @@ pam_conversation (int nmsgs,
+ struct pam_response *pam_responses;
+ saver_info *si = (saver_info *) vsaver_info;
+ Bool verbose_p;
++ size_t msg_len = 0;
+
+ /* On SunOS 5.6, the `closure' argument always comes in as random garbage. */
+ si = (saver_info *) suns_pam_implementation_blows;
+@@ -741,6 +742,20 @@ pam_conversation (int nmsgs,
+ * pass along whatever was passed in here.
+ */
+
++ if (nmsgs >= PAM_MAX_NUM_MSG)
++ {
++ if (verbose_p)
++ {
++ fprintf (stderr, "Too many PAM messages "
++ "%d >= %d\n", nmsgs, PAM_MAX_NUM_MSG);
++ }
++
++ syslog (LOG_AUTH | LOG_ERR, "Too many PAM messages "
++ "%d >= %d", nmsgs, PAM_MAX_NUM_MSG);
++ *resp = NULL;
++ return (PAM_CONV_ERR);
++ }
++
+ messages = calloc(nmsgs, sizeof(struct auth_message));
+ pam_responses = calloc(nmsgs, sizeof(*pam_responses));
+
+@@ -752,6 +767,34 @@ pam_conversation (int nmsgs,
+
+ for (i = 0; i < nmsgs; ++i)
+ {
++
++ if (msg[i]->msg == NULL)
++ {
++ if (verbose_p)
++ {
++ fprintf (stderr, "PAM message[%d] "
++ "style %d NULL\n", i, msg[i]->msg_style);
++ }
++ syslog (LOG_AUTH | LOG_WARNING, "PAM message[%d] "
++ "style %d NULL", i, msg[i]->msg_style);
++ goto end;
++ }
++
++ msg_len = strlen (msg[i]->msg);
++
++ if (msg_len > PAM_MAX_MSG_SIZE)
++ {
++ if (verbose_p)
++ {
++ fprintf (stderr, "PAM message[%d] "
++ " style %d length %d too long\n",
++ i, msg[i]->msg_style, msg_len);
++ }
++ syslog (LOG_AUTH | LOG_WARNING, "PAM message[%d] "
++ "style %d length %d too long",i, msg[i]->msg_style, msg_len);
++ goto end;
++ }
++
+ if (verbose_p && i > 0) fprintf (stderr, ", ");
+
+ messages[i].msg = msg[i]->msg;
+@@ -769,9 +812,16 @@ pam_conversation (int nmsgs,
+ case PAM_TEXT_INFO: messages[i].type = AUTH_MSGTYPE_INFO;
+ if (verbose_p) fprintf (stderr, "TEXT_INFO");
+ break;
+- default: messages[i].type = AUTH_MSGTYPE_PROMPT_ECHO;
+- if (verbose_p) fprintf (stderr, "PROMPT_ECHO");
+- break;
++ default:
++ if (verbose_p)
++ {
++ fprintf (stderr, "Invalid PAM "
++ "message style %d\n", msg[i]->msg_style);
++ }
++ syslog (LOG_AUTH | LOG_WARNING, "Invalid PAM "
++ "message style %d", msg[i]->msg_style);
++
++ goto end;
+ }
+
+ if (verbose_p)
+@@ -793,8 +843,28 @@ pam_conversation (int nmsgs,
+
+ if (ret == 0)
+ {
++ msg_len = 0;
+ for (i = 0; i < nmsgs; ++i)
+- pam_responses[i].resp = authresp[i].response;
++ {
++ if (authresp[i].response)
++ msg_len = strlen (authresp[i].response);
++
++ if (msg_len > PAM_MAX_RESP_SIZE)
++ {
++ if (verbose_p)
++ {
++ fprintf (stderr, "PAM "
++ "message[%d] style %d response %d too long\n",
++ i, msg[i]->msg_style, msg_len);
++ }
++ syslog (LOG_AUTH | LOG_WARNING, "PAM "
++ "message[%d] style %d response %d too long",
++ i, msg[i]->msg_style, msg_len);
++ ret = -1;
++ goto end;
++ }
++ pam_responses[i].resp = authresp[i].response;
++ }
+ }
+
+ end:
+@@ -818,6 +888,7 @@ end:
+ if (pam_responses)
+ free(pam_responses);
+
++ *resp == NULL;
+ return PAM_CONV_ERR;
+ }
+
+--
+2.6.1
+