--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/open-src/app/xscreensaver/pam_audit.patch Fri Jun 09 18:09:17 2006 -0700
@@ -0,0 +1,670 @@
+
+Fixes for bugs:
+5015296, P1, gnome/screensaver - xscreensaver doesn't audit
+6417168, P3, gnome/screensaver - xcreensaver loops while trying to unlock a session for a user whose password was expired
+
+diff -ur driver/Makefile.in driver/Makefile.in
+--- driver/Makefile.in Wed Jun 7 18:28:35 2006
++++ driver/Makefile.in Wed Jun 7 19:19:46 2006
+@@ -202,7 +202,7 @@
+ SAVER_LIBS = $(LIBS) $(X_LIBS) $(XMU_LIBS) @SAVER_LIBS@ \
+ $(XDPMS_LIBS) $(GL_LIBS) $(X_PRE_LIBS) \
+ -lXt -lX11 -lXext -lXi $(X_EXTRA_LIBS) \
+- $(PASSWD_LIBS)
++ -lbsm $(PASSWD_LIBS)
+
+ CMD_LIBS = $(LIBS) $(X_LIBS) \
+ $(X_PRE_LIBS) -lX11 -lXext $(X_EXTRA_LIBS)
+diff -ur driver/demo-Gtk.c driver/demo-Gtk.c
+--- driver/demo-Gtk.c Wed Jun 7 18:28:35 2006
++++ driver/demo-Gtk.c Wed Jun 7 19:19:46 2006
+@@ -541,7 +541,7 @@
+ if (getuid() == 0)
+ {
+ char buf [255];
+- strcpy (buf, _("Cant run hacks if logged in as root!"));
++ strcpy (buf, _("Can not run hacks if logged in as root!"));
+ warning_dialog (s->toplevel_widget, buf, False, 100);
+ return;
+ }
+@@ -569,7 +569,7 @@
+ if (getuid() == 0)
+ {
+ char buf [255];
+- strcpy (buf, _("Cant run hacks if logged in as root!"));
++ strcpy (buf, _("Can not run hacks if logged in as root!"));
+ warning_dialog (s->toplevel_widget, buf, False, 100);
+ return;
+ }
+diff -ur driver/passwd-pam.c driver/passwd-pam.c
+--- driver/passwd-pam.c Wed Jun 7 18:28:35 2006
++++ driver/passwd-pam.c Wed Jun 7 19:19:46 2006
+@@ -44,12 +44,14 @@
+ #ifdef HAVE_UNISTD_H
+ # include <unistd.h>
+ #endif
++
++#ifdef sun
++#include <deflt.h>
++#include <bsm/adt.h>
++#include <bsm/adt_event.h>
++#endif
+
+-# ifdef sun
+-# include <deflt.h>
+-# endif
+
+-
+ /*extern char *blurb(void);*/
+
+
+@@ -97,12 +99,14 @@
+ #define True 1
+ #define False 0
+
+-
+ Bool we_have_pam;
+
+ #undef countof
+ #define countof(x) (sizeof((x))/sizeof(*(x)))
+
++static struct pam_response *reply = 0; /*making it global so we can free it */
++static int replies = 0;
++
+ /* Some time between Red Hat 4.2 and 7.0, the words were transposed
+ in the various PAM_x_CRED macro names. Yay!
+ */
+@@ -112,8 +116,8 @@
+
+ int pam_conversation (int nmsgs,
+ struct pam_message **msg,
+- struct pam_response **resp,
+- void *closure);
++ struct pam_response **resp,
++ void *closure);
+
+ struct pam_closure {
+ const char *user;
+@@ -199,13 +203,154 @@
+ */
+ static void *suns_pam_implementation_blows = 0;
+
++#ifdef sun
++#include <syslog.h>
++#include <bsm/adt.h>
++#include <bsm/adt_event.h>
+
++static Bool audit_flag_global = True;
++
++/*
++ * audit_lock - audit entry to screenlock
++ *
++ * Entry Process running with appropriate privilege to generate
++ * audit records and real uid of the user.
++ *
++ * Exit ADT_screenlock audit record written.
++ */
++void
++audit_lock(void)
++{
++ adt_session_data_t *ah; /* audit session handle */
++ adt_event_data_t *event; /* audit event handle */
++
++ /* Audit start of screen lock -- equivalent to logout ;-) */
++ if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) {
++
++ syslog(LOG_AUTH | LOG_ALERT, "adt_start_session: %m");
++ return;
++ }
++ if ((event = adt_alloc_event(ah, ADT_screenlock)) == NULL) {
++
++ syslog(LOG_AUTH | LOG_ALERT,
++ "adt_alloc_event(ADT_screenlock): %m");
++ } else {
++ if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
++
++ syslog(LOG_AUTH | LOG_ALERT,
++ "adt_put_event(ADT_screenlock): %m");
++ }
++ adt_free_event(event);
++ }
++ (void) adt_end_session(ah);
++}
++
++/*
++ * audit_unlock - audit screen unlock
++ *
++ * Entry Process running with appropriate privilege to generate
++ * audit records and real uid of the user.
++ * pam_status = PAM error code; reason for failure.
++ *
++ * Exit ADT_screenunlock audit record written.
++ */
++static void
++audit_unlock(int pam_status)
++{
++ adt_session_data_t *ah; /* audit session handle */
++ adt_event_data_t *event;/* audit event handle */
++
++ if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) {
++
++ syslog(LOG_AUTH | LOG_ALERT,
++ "adt_start_session(ADT_screenunlock): %m");
++ return;
++ }
++ if ((event = adt_alloc_event(ah, ADT_screenunlock)) == NULL) {
++
++ syslog(LOG_AUTH | LOG_ALERT,
++ "adt_alloc_event(ADT_screenunlock): %m");
++ } else {
++ if (adt_put_event(event,
++ pam_status == PAM_SUCCESS ? ADT_SUCCESS : ADT_FAILURE,
++ pam_status == PAM_SUCCESS ? ADT_SUCCESS : ADT_FAIL_PAM +
++ pam_status) != 0) {
++
++ syslog(LOG_AUTH | LOG_ALERT,
++ "adt_put_event(ADT_screenunlock(%s): %m",
++ pam_strerror(NULL, pam_status));
++ }
++ adt_free_event(event);
++ }
++ (void) adt_end_session(ah);
++}
++
++/*
++ * audit_passwd - audit password change
++ * Entry Process running with appropriate privilege to generate
++ * audit records and real uid of the user.
++ * pam_status = PAM error code; reason for failure.
++ *
++ * Exit ADT_passwd audit record written.
++ */
++static void
++audit_passwd(int pam_status)
++{
++ adt_session_data_t *ah; /* audit session handle */
++ adt_event_data_t *event; /* audit event handle */
++
++ if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) {
++
++ syslog(LOG_AUTH | LOG_ALERT,
++ "adt_start_session(ADT_passwd): %m");
++ return;
++ }
++ if ((event = adt_alloc_event(ah, ADT_passwd)) == NULL) {
++
++ syslog(LOG_AUTH | LOG_ALERT,
++ "adt_alloc_event(ADT_passwd): %m");
++ } else {
++ if (adt_put_event(event,
++ pam_status == PAM_SUCCESS ? ADT_SUCCESS : ADT_FAILURE,
++ pam_status == PAM_SUCCESS ? ADT_SUCCESS : ADT_FAIL_PAM +
++ pam_status) != 0) {
++
++ syslog(LOG_AUTH | LOG_ALERT,
++ "adt_put_event(ADT_passwd(%s): %m",
++ pam_strerror(NULL, pam_status));
++ }
++ adt_free_event(event);
++ }
++ (void) adt_end_session(ah);
++}
++#endif /* sun */
++
++void free_pam_response_struct ()
++{
++ int i;
++ struct pam_response *pam_resp = reply;
++
++ if (!replies)
++ return;
++
++ for (i = 0; i < replies; i++,pam_resp++)
++ if (pam_resp->resp)
++ {
++ free (pam_resp->resp);
++ pam_resp->resp = NULL;
++ }
++ if (pam_resp)
++ free (pam_resp);
++ pam_resp = NULL;
++ replies = 0;
++}
++
+ /* This can be called at any time, and says whether the typed password
+ belongs to either the logged in user (real uid, not effective); or
+ to root.
+ */
+ Bool
+-pam_passwd_valid_p ()
++pam_passwd_valid_p (void)
+ {
+ const char *service;
+ uid_t euid;
+@@ -266,6 +411,15 @@
+ fprintf (stderr, "%s: pam_start (\"%s\", \"%s\", ...) ==> %d (%s)\n",
+ blurb(), service, c.user,
+ status, PAM_STRERROR (pamh, status));
++
++/* We call pam_passwd_valid_p() everytime we lock screen,
++ * so calling audit here is fine.
++ */
++#ifdef sun
++ if (audit_flag_global) /* We want one audit lock log per lock */
++ audit_lock();
++#endif /**sun*/
++
+ if (status != PAM_SUCCESS)
+ {
+ we_have_pam = False;
+@@ -296,32 +450,6 @@
+ }
+ #endif
+
+- /* #### We should set PAM_TTY to the display we're using, but we
+- don't have that handy from here. So set it to :0.0, which is a
+- good guess (and has the bonus of counting as a "secure tty" as
+- far as PAM is concerned...)
+- */
+-
+-/* From the pam trace and log file, it is found out that the
+- Sun pam modules can drive itself.
+-*/
+-
+-#if 0
+-
+- {
+- char *tty,*displayname;
+- if ((displayname = getenv ("DISPLAY")) != NULL)
+- tty = strdup(displayname);
+- else
+- tty = strdup (":0.0");
+- status = pam_set_item (pamh, PAM_TTY, tty);
+- if (verbose_p)
+- fprintf (stderr, "%s: pam_set_item (p, PAM_TTY, \"%s\") ==> %d (%s)\n",
+- blurb(), tty, status, PAM_STRERROR(pamh, status));
+- free (tty);
+- }
+-#endif
+-
+ /* Try to authenticate as the current user.
+ We must turn off our SIGCHLD handler for the duration of the call to
+ pam_authenticate(), because in some cases, the underlying PAM code
+@@ -344,15 +472,18 @@
+
+ PAM_NO_DELAY(pamh);
+
+-/************* no need
+- fprintf(stderr,"before calling pam_authenticate passwd_string: %s\n",si->pw_data->passwd_string);
+- if (si->pw_data->passwd_string)
+-****************************/
+ {
+
+- block_sigchld();
++ block_sigchld();
+ pam_auth_status = pam_authenticate (pamh, pam_flags);
+- unblock_sigchld();
++ unblock_sigchld();
++
++#ifdef sun
++ audit_unlock(pam_auth_status);
++ if (pam_auth_status == PAM_SUCCESS) audit_flag_global = True;
++ else audit_flag_global = False;
++#endif /*sun*/
++
+ /* Send status message to unlock dialog ***/
+ if (pam_auth_status == PAM_SUCCESS)
+ {
+@@ -375,7 +506,7 @@
+
+ /* PAM_SUCCESS defined to be 0 in /usr/include/security/pam_appl.h */
+ si->pw_data->state = (pam_auth_status == PAM_SUCCESS ? pw_ok : pw_fail);
+- if (verbose_p)
++ if (verbose_p)
+ fprintf(stderr,"after calling pam_authenticate status is:%d state is:%d\n",
+ pam_auth_status,si->pw_data->state);
+
+@@ -390,23 +521,8 @@
+ {
+ /* perform PAM account validation procedures for login user only */
+ acct_rc = pam_acct_mgmt(pamh, pam_flags);
++ /*free_pam_response_struct ();**/
+
+- /******************************************************************
+- ignore other cases for the time being
+- PAM_USER_UNKNOWN, PAM_AUTH_ERR, PAM_ACCT_EXPIRED
+- (password mgn service module)
+- same as pam_setcred(), focus on auth. service module only
+- *****************************************************************/
+-
+- if (acct_rc == PAM_NEW_AUTHTOK_REQD) {
+- do {
+- chauth_rc = pam_chauthtok(pamh, 0);
+- } while (chauth_rc == PAM_AUTHTOK_ERR ||
+- chauth_rc == PAM_TRY_AGAIN);
+- if (verbose_p)
+- fprintf (stderr, "%s: pam_chauthtok (...) ==> %d (%s)\n",
+- blurb(), chauth_rc, PAM_STRERROR(pamh, chauth_rc));
+- }
+ if (verbose_p)
+ fprintf (stderr, "%s: pam_acct_mgmt (...) ==> %d (%s)\n",
+ blurb(), acct_rc, PAM_STRERROR(pamh, acct_rc));
+@@ -427,13 +543,49 @@
+ write_to_child (si, tmp_buf);
+ if (verbose_p)
+ sleep (1);
+- }
+
++ /* Only in failure of pam_acct_mgmt case we call audit */
++#ifdef sun
++ audit_unlock(acct_rc);
++#endif /*sun*/
++
++ }/* end of else */
++
++ if (acct_rc == PAM_NEW_AUTHTOK_REQD)
++ {
++ for (int i=0; i<3; i++)
++ {
++ chauth_rc = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
++ if (chauth_rc == PAM_AUTHTOK_ERR ||
++ chauth_rc == PAM_TRY_AGAIN )
++ {
++ i = 0; /* Reset num tries we need to do to change expired passwd */
++ si->pw_data->state = pw_read;
++ }
++ else break; /* get out of the loop */
++ }/*for*/
++
++ if (verbose_p)
++ fprintf (stderr, "%s: pam_chauthtok (...) ==> %d (%s)\n",
++ blurb(), chauth_rc, PAM_STRERROR(pamh, chauth_rc));
++
++#ifdef sun
++ audit_passwd(chauth_rc);
++#endif /* sun */
++
++ if (chauth_rc != PAM_SUCCESS)
++ {
++ pam_auth_status = chauth_rc;
++ goto DONE;
++ }
++ }
++
+ /* Each time we successfully authenticate, refresh credentials,
+ for Kerberos/AFS/DCE/etc. If this fails, just ignore that
+ failure and blunder along; it shouldn't matter.
+ */
+ setcred_rc = pam_setcred (pamh, PAM_REFRESH_CRED);
++
+ if (verbose_p)
+ fprintf (stderr, "%s: pam_setcred (...) ==> %d (%s)\n",
+ blurb(), setcred_rc , PAM_STRERROR(pamh, setcred_rc));
+@@ -454,6 +606,11 @@
+ write_to_child (si, tmp_buf);
+ if (verbose_p)
+ sleep (1);
++
++/* Only in failure of pam_setcred() case we call audit. */
++#ifdef sun
++ audit_unlock(setcred_rc);
++#endif /*sun*/
+ }
+
+ goto DONE;
+@@ -490,7 +647,7 @@
+ tmp_buf = strdup (_("Letting you in as ROOT!!"));
+ write_to_child (si, tmp_buf);
+ free (tmp_buf);
+- if (verbose_p)
++ if (verbose_p)
+ sleep (1);
+ }
+
+@@ -506,10 +663,11 @@
+ DONE:
+ if (service) free((void *)service);
+ if (user) free (user);
++ if (reply) free (reply);
+ if (pamh)
+ {
+ int status2 = pam_end (pamh, pam_auth_status);
+- pamh = 0;
++ pamh = NULL;
+ if (verbose_p)
+ fprintf (stderr, "%s: pam_end (...) ==> %d (%s)\n",
+ blurb(), status2,
+@@ -520,7 +678,7 @@
+ {
+ if (verbose_p)
+ perror("Error pam could not revert euid to user running as euid root, locking may not work now\n");
+-}
++ }
+
+ if (verbose_p)
+ fprintf (stderr, "<--end of pam_authenticate() returning ok_to_unblank = %d\n",
+@@ -536,8 +694,8 @@
+
+ if (si->pw_data->passwd_string)
+ {
++ memset(si->pw_data->passwd_string, 0, strlen(si->pw_data->passwd_string));
+ free (si->pw_data->passwd_string);
+- si->pw_data->passwd_string = 0;
+ }
+
+ if(pam_auth_status == PAM_SUCCESS)
+@@ -572,7 +730,7 @@
+ #ifndef S_ISDIR
+ # define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
+ #endif
+-
++
+ if (stat (dir, &st) == 0 && S_ISDIR(st.st_mode))
+ {
+ if (stat (file, &st) != 0)
+@@ -645,10 +803,10 @@
+ struct pam_response **resp,
+ void *closure)
+ {
+- int replies = 0;
+- struct pam_response *reply = 0;
++/*mali fix struct pam_response *reply = 0; */
+ struct pam_closure *c = (struct pam_closure *) closure;
+ saver_info *si = global_si_kludge;
++ int conv_status = PAM_SUCCESS;
+
+ /* On SunOS 5.6, the `closure' argument always comes in as random garbage. */
+ c = (struct pam_closure *) suns_pam_implementation_blows;
+@@ -657,6 +815,7 @@
+ fprintf(stderr, "-->pam_conv() \n");
+
+ reply = (struct pam_response *) calloc (nmsgs, sizeof (*reply));
++
+ if (!reply) return PAM_CONV_ERR;
+
+ for (replies = 0; replies < nmsgs; replies++)
+@@ -671,7 +830,6 @@
+ make_passwd_window (si);
+ }
+
+-/**fprintf(stderr, "top of switch %d\n", replies);**/
+ switch (msg[replies]->msg_style)
+ {
+ case PAM_PROMPT_ECHO_ON:
+@@ -681,8 +839,6 @@
+ fprintf (stderr, "%s: PAM ECHO_OFF(\"%s\") ==> password\n",
+ blurb(), msg[replies]->msg);
+
+- /**fprintf(stderr, "PAM_ECHO_OFF/ECHO_ON nmsgs=%d\n",nmsgs);**/
+-
+ write_to_child (si, msg[replies]->msg);
+ if (c->verbose_p)
+ sleep (1); /* let user see these */
+@@ -691,9 +847,37 @@
+ fprintf(stderr, "PAM_ECHO_OFF/ECHO_ON msg[replies]-> %s\n",
+ msg[replies]->msg);
+
++ /* For our hack to see if the user typed in root passwd to unlock. */
++ if (strcmp (c->user, "root") == 0)
++ {
++ if (c->verbose_p)
++ {
++ write_to_child (si, "Checking if you typed root password");
++ sleep (1);
++ }
++
++ if (si->pw_data->passwd_string) /* if passwd is still stored */
++ reply[replies].resp = strdup (si->pw_data->passwd_string); /*freed by PAM*/
++ else
++ reply[replies].resp = NULL; /* freed by PAM */
++
++ break; /* To check if user has entered a root passwd, we dont want to prompt
++ * user to enter the root passwd, we already have it so try that. */
++ }
++
+ si->pw_data->state = pw_read;
+- while (!si->pw_data->got_windowid && si->pw_data->state == pw_read)
++
++ /* Wipe the old password, so we get prompted to enter new password. */
++ if (si->pw_data->passwd_string)
+ {
++ memset(si->pw_data->passwd_string, 0, strlen(si->pw_data->passwd_string));
++ free (si->pw_data->passwd_string);
++ si->pw_data->passwd_string = NULL;
++ }
++
++ /***while (!si->pw_data->got_windowid && si->pw_data->state == pw_read)**/
++ while (si->pw_data->state == pw_read)
++ {
+ if (c->verbose_p)
+ fprintf(stderr,"WAiting for window id from lock dialog\n");
+ handle_typeahead (si);
+@@ -702,13 +886,13 @@
+ fprintf(stderr,"<---passwd_event_loop() state =%d\n",si->pw_data->state);
+ }
+
+- reply[replies].resp_retcode = PAM_SUCCESS;
++ reply[replies].resp = NULL; /* freed by PAM */
+
+- /*Make sure user inputs a response..and dialog is not timiing out **/
++ /*Make sure user inputs a response..and dialog is not timing out **/
+ if (si->pw_data->state != pw_time && si->pw_data->passwd_string != NULL)
+ {
+ reply[replies].resp = strdup (si->pw_data->passwd_string);/*freed by PAM*/
+- if (c->verbose_p)
++ if (c->verbose_p)
+ fprintf(stderr, "in ECHO OFF and got a passwd..:%s\n",
+ si->pw_data->passwd_string);
+ }
+@@ -716,37 +900,37 @@
+ {
+ /* this shouldnt happen...perhaps sending null passwd to pam is
+ * best for now**/
+- /* reply[replies].resp = 0;Dont send any resp*/ /* freed by PAM */
++ reply[replies].resp = NULL; /*Dont send any resp*/ /* freed by PAM */
+ /* Reset state to fail */
+ si->pw_data->state = pw_fail;
+
+ if (c->verbose_p)
+ {
+- fprintf(stderr, "Dude sending null password to pam..\n");
+ fprintf(stderr,"We didnt receive any input from user!!!\n");
+ }
+ }
+ break;
+ }
++
+ case PAM_TEXT_INFO:
+ case PAM_ERROR_MSG:
+ {
+- char* tmp_msg;
+
+ /* display messages coming from pam... */
+ /* we should have dialog up still to show this */
+ if (c->verbose_p)
+ fprintf(stderr, "PAM_ERROR/PAM_TEXT_INFO nmsgs=%d\n",nmsgs);
++
+ if (!g_passwd_dialog_created)
+ {
+ make_passwd_window (si);
+- /*sleep (1);*/ /*make sure window is created by now **/
++ usleep (500000); /*make sure window is created by now **/
+ }
+- tmp_msg = strdup (msg[replies]->msg);
+- write_to_child (si, tmp_msg);
+- sleep(1);
++ write_to_child (si, msg[replies]->msg);
++ sleep(2);
+
+- fprintf (stderr,"scf_scdata_state = %d\n",
++ if (c->verbose_p)
++ fprintf (stderr,"scf_scdata_state = %d\n",
+ si->scf_si->scdata->state);
+ /* The following need to change to some other variable which gets set
+ * when the user hits OK button in the dialog displaying the TEXT_INFO or
+@@ -758,13 +942,6 @@
+ XEvent event;
+ XtAppNextEvent (si->app, &event);
+ XtDispatchEvent (&event);
+-#if 0
+- /* handle_typeahead (si);**/
+- passwd_event_loop (si);
+- if (c->verbose_p)
+- fprintf (stderr,"scf_scdata_state = %d\n",
+- si->scf_si->scdata->state);
+-#endif /*0*/
+ }
+
+ if (c->verbose_p)
+@@ -771,12 +948,10 @@
+ fprintf(stderr, "PAM_ERROR/PAM_TEXT_INFO msg[%d]-> %s\n",
+ replies,msg[replies]->msg);
+
+- reply[replies].resp_retcode = PAM_CONV_ERR;
+- /*reply[replies].resp = 0;*/
++ reply[replies].resp = NULL;
+ /* Reset state to read */
+ si->pw_data->state = pw_read;
+
+- free(tmp_msg);
+ break;
+ }
+
+@@ -784,17 +959,14 @@
+
+ {
+ int i;
+- if (c->verbose_p)
+- fprintf (stderr, "%s: PAM unknown %d(\"%s\") ==> ERROR..default case:\n",
+- blurb(), msg[replies]->msg_style, msg[replies]->msg);
+- /* Must be an error of some sort... */
+- for (i = 0; i < replies; i++)
+- if (reply[replies].resp != NULL)
+- free (reply[replies].resp);
+- free (reply);
+- reply = NULL;
+- return PAM_CONV_ERR;
++ if (c->verbose_p)
++ fprintf (stderr, "%s: PAM unknown ==> ..default case:\n", blurb());
++#ifdef sun
++ audit_unlock("PAM_CONV_ERR");
++#endif /* sun */
+
++ return PAM_CONV_ERR;
++
+ } /* end default */
+ } /* end switch */
+ } /* end for loop */
+diff -ur driver/xscreensaver.c driver/xscreensaver.c
+--- driver/xscreensaver.c Wed Jun 7 18:28:36 2006
++++ driver/xscreensaver.c Wed Jun 7 19:19:46 2006
+@@ -1221,6 +1221,9 @@
+ if (ok_to_unblank == True)
+ {
+ set_locked_p (si, False);
++ XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
++ /* If hack is not resumed it doesnt get killed and leaves zombie processes. */
++ suspend_screenhack (si, False); /* resume */
+ goto DONE;
+ }
+ }