Sisyphus repository
Last update: 1 october 2023 | SRPMs: 18631 | Visits: 37888037
en ru br
ALT Linux repos
S:5.69-alt1
5.0: 5.27-alt10.M50.1
4.1: 5.27-alt5.M41.1
4.0: 5.27-alt8.M40.1.1

Group :: Graphical desktop/Other
RPM: xlockmore

 Main   Changelog   Spec   Patches   Sources   Download   Gear   Bugs and FR  Repocop 

Patch: xlockmore-5.46-pam.patch
Download


 xlock/passwd.c |  149 +++++++++++++++++++++++++++++++++++++++++++++++---------
 xlock/passwd.h |   23 ++++++++-
 xlock/xlock.c  |  108 ++++++++++++++++++++++++++++++++++++-----
 3 files changed, 244 insertions(+), 36 deletions(-)
diff --git a/xlock/passwd.c b/xlock/passwd.c
index be8ca00..3f130ea 100644
--- a/xlock/passwd.c
+++ b/xlock/passwd.c
@@ -10,6 +10,21 @@ static const char sccsid[] = "@(#)passwd.c	5.00 2000/11/01 xlockmore";
  *
  * Revision History:
  *
+ * Changes made by Paul Wolneykien <manowar@altlinux.ru> (ALT Linux Team)
+ * 14-Oct-08: Fix of the multistage conversation and button logout
+ *            conflict: 
+ *            - adds new 'PAM_conv_count' counter to distinguish first
+ *              conversation call from the subsequent calls.
+ * 09-Oct-08: Further PAM integration:
+ *            - PAM_conv() function uses interactive conversation to
+ *              obtain secret (password) values in general case;
+ *            - in the case of a repeated authentication made for the
+ *              root user by guess (if allowed) first password entered
+ *              during conversation is used;
+ *            - return codes of the input/output function
+ *              PAM_putText() is analyzed to detect an interruption
+ *              signal.
+ *
  * Changes maintained by David Bagley <bagleyd@tux.org>
  * 23-Feb-2003: Timothy Reed <treed1@twcny.rr.com>
  *              Updated PAM_conv to call over to xlock to display messages
@@ -278,8 +293,25 @@ char        global_user[PASSLENGTH];
 
 #ifdef USE_PAM
 
-/* used to pass the password to the conversation function */
-static char *PAM_password;
+/* Used to store the first entered password. */
+static char *PAM_password = NULL;
+
+#define FREE_PAM_PASSWORD if (PAM_password != NULL) { \
+  /* Clear plaintext password. */ \
+  bzero(PAM_password, strlen(PAM_password)); \
+  /* Free memory. */ \
+  free(PAM_password); \
+  PAM_password = NULL; \
+}
+
+/* Used to indicate to use the stored password. */
+static int PAM_conv_use_stored = 0;
+
+/* Used to store the result code of the conversation. */
+static int PAM_conv_retcode;
+
+/* Used as counter for the number of conversations. */
+static int PAM_conv_count;
 
 /*-
  * PAM conversation function
@@ -298,9 +330,10 @@ PAM_conv(int num_msg,
 {
 	int         replies = 0;
 	struct pam_response *reply = NULL;
+	int isnew = 0;
 
 
-#define COPY_STRING(s) (s) ? strdup(s) : NULL
+#define COPY_STRING(s) (s) ? strndup(s, PASSLENGTH) : NULL
 
 	reply = (struct pam_response *) malloc(sizeof (struct pam_response) *
 					       num_msg);
@@ -319,6 +352,8 @@ PAM_conv(int num_msg,
 	reply[replies].resp = NULL;
 
 	for (replies = 0; replies < num_msg; replies++) {
+	  isnew = PAM_conv_count == 0;
+	  PAM_conv_count++;
 #ifdef DEBUG
 		(void) printf( "PAM_conv: message of style (%d) received\n", msg[replies]->msg_style );
 		(void) printf( " + Message is: (%s)\n", msg[replies]->msg );
@@ -328,17 +363,24 @@ PAM_conv(int num_msg,
 #ifdef DEBUG
 				(void) printf( " + Message style: PAM_PROMPT_ECHO_ON\n" );
 #endif
-				PAM_putText( msg[replies], &reply[replies], True );
+				PAM_putText(isnew, msg[replies], &reply[replies], True );
 				/* PAM frees resp */
 				break;
 			case PAM_PROMPT_ECHO_OFF:
 #ifdef DEBUG
 				(void) printf( " + Message style: PAM_PROMPT_ECHO_OFF\n" );
 #endif
-				if( strstr( msg[replies]->msg, "Password" ) == NULL ) {
-					PAM_putText( msg[replies], &reply[replies], False );
+				/* If stored password is set use it
+				 * for the first reply. */
+				if (replies == 0 && PAM_conv_use_stored && \
+				    PAM_password != NULL) {
+				  reply[0].resp = COPY_STRING(PAM_password);
+				  reply[0].resp_retcode = PAM_SUCCESS;
+#ifdef DEBUG
+				  (void) printf( " + Use stored password.\n");
+#endif
 				} else {
-					reply[replies].resp = COPY_STRING(PAM_password);
+				  PAM_putText(isnew, msg[replies], &reply[replies], False );
 				}
 				/* PAM frees resp */
 				break;
@@ -346,18 +388,14 @@ PAM_conv(int num_msg,
 #ifdef DEBUG
 				(void) printf( " + Message style: PAM_TEXT_INFO\n" );
 #endif
-				if( strstr( msg[replies]->msg, "Password" ) == NULL ) {
-					PAM_putText( msg[replies], &reply[replies], False );
-				}
+				PAM_putText(isnew, msg[replies], &reply[replies], False );
 				/* PAM frees resp */
 				break;
 			case PAM_ERROR_MSG:
 #ifdef DEBUG
 				(void) printf( " + Message style: PAM_ERROR_MSG\n" );
 #endif
-				if( strstr( msg[replies]->msg, "Password" ) == NULL ) {
-					PAM_putText( msg[replies], &reply[replies], False );
-				}
+				PAM_putText(isnew, msg[replies], &reply[replies], False );
 				/* PAM frees resp */
 				break;
 			default:
@@ -372,8 +410,45 @@ PAM_conv(int num_msg,
 		(void) printf( " + Response is: (%s). Return Code is: (%d)\n",
 			reply[replies].resp, reply[replies].resp_retcode );
 #endif
+		/* Non-success return code from the input/output
+		 * function is the interruption signal. In that case
+		 * authentication should be aborted. */
+		if (reply[replies].resp_retcode != PAM_SUCCESS) {
+		  PAM_conv_retcode |= AUTH_INT;
+		  /* Don't be optimistic this time: distribute status
+		   * of the last reply to the remaining replies, thus
+		   * initialize them. */
+		  if ((replies + 1) < num_msg) {
+		    for (replies += replies; replies < num_msg; replies++) {
+		      reply[replies].resp_retcode = reply[replies-1].resp_retcode;
+		      reply[replies].resp = NULL;
+		    }
+		  }
+		  return reply[replies].resp_retcode;
+		}
+		/* Empty value is posible sign of the user's attempt
+		 * to refuse the authentication. In that case special
+		 * return code is also used, but the conversation is not
+		 * interrupted. */
+		if (reply[replies].resp == NULL || strlen(reply[replies].resp) == 0) {
+		  PAM_conv_retcode |= AUTH_NO_TRY;
+		}
+		/* Saving first password if it wasn't saved yet and
+		 * second authentication attempt (for root user) is
+		 * possible. */
+		if (allowroot && replies == 0 && PAM_password == NULL) {
+#ifdef DEBUG
+		  (void) printf( "PAM_conv: store password.\n");
+#endif
+		  PAM_password = COPY_STRING(reply[replies].resp);
+		}
 	}
 	*resp = reply;
+#ifdef DEBUG
+	/* Useful for debugging as the conversation can be
+	 * interrupted. */
+	(void) printf( "PAM_conv: conversation finished successfully.\n");
+#endif
 	return PAM_SUCCESS;
 }
 
@@ -1171,7 +1246,8 @@ checkPasswd(char *buffer)
 #endif
 
 #define PAM_BAIL if (pam_error != PAM_SUCCESS) { \
-    pam_end(pamh, pam_error); BAD_PAM_SETUID return False; \
+    FREE_PAM_PASSWORD \
+    pam_end(pamh, pam_error); BAD_PAM_SETUID return AUTH_NO; \
 }
 #ifdef BAD_PAM
 	ruid = getuid();  /* the real user we are running as */
@@ -1180,7 +1256,11 @@ checkPasswd(char *buffer)
 #ifdef DEBUG
 	(void) printf("PAM: Before: UID (%d), EUID (%d)\n", getuid(), geteuid());
 #endif
-	PAM_password = buffer;
+	/* Reset conversation status and data. */
+	FREE_PAM_PASSWORD
+	PAM_conv_retcode = 0;
+	PAM_conv_use_stored = 0;
+	PAM_conv_count = 0;
 	pam_error = pam_start(DEFAULT_NAME, user, &PAM_conversation, &pamh);
 	PAM_BAIL;
 
@@ -1195,16 +1275,39 @@ checkPasswd(char *buffer)
 	(void) printf("PAM: pam_authenticate returns code (%d)\n", pam_error);
 #endif
 	if (pam_error != PAM_SUCCESS) {
-                if (!allowroot) {
-					PAM_BAIL;
-                }
+	  /* Check if conversation was interrupted and return the
+	   * corresponding signal if so. */
+	  if (PAM_conv_retcode) {
+#ifdef DEBUG
+	    (void) printf("PAM: conversation interrupted.\n");
+#endif
+	    FREE_PAM_PASSWORD
+	    return PAM_conv_retcode;
+	  }
+	  /* Try to authenticate second time, as root, using the
+	   * stored password if allowed. */
+	  if (allowroot) {
+#ifdef DEBUG
+	    (void) printf("PAM: try to authenticate as root.\n");
+#endif
+	    pam_error = pam_set_item(pamh, PAM_USER, ROOT);
+#ifdef DEBUG
+	    (void) printf("PAM: pam_set_item (PAM_USER) returns code (%d)\n", pam_error);
+#endif
+	    PAM_BAIL;
 
-		/* Try as root; bail if no success there either */
-		pam_error = pam_set_item(pamh, PAM_USER, ROOT);
-		PAM_BAIL;
-		pam_error = pam_authenticate(pamh, 0);
-		PAM_BAIL;
+	    /* Set flag to use stored password in place of
+	     * conversation with the user. */
+	    PAM_conv_use_stored = 1;
+
+	    pam_error = pam_authenticate(pamh, 0);
+#ifdef DEBUG
+	    (void) printf("PAM: pam_authenticate returns code (%d)\n", pam_error);
+#endif
+	  }
+	  PAM_BAIL;
 	}
+	FREE_PAM_PASSWORD
 #ifdef BAD_PAM
 	(void) seteuid(ruid); /* back to user's privileges */
 #endif
diff --git a/xlock/passwd.h b/xlock/passwd.h
index 9b27873..5a28eba 100644
--- a/xlock/passwd.h
+++ b/xlock/passwd.h
@@ -9,6 +9,17 @@
  * See xlock.c for copying information.
  *
  * Revision History:
+ *
+ * Changes made by Paul Wolneykien <manowar@altlinux.ru> (ALT Linux Team)
+ * 14-Oct-08: Fix of the multistage conversation and button logout
+ *            conflict: 
+ *            - add 'isnew' parameter to the PAM_putText() function to
+ *              manage this value from PAM conversation procedure.
+ * 09-Oct-08: Further PAM integration:
+ *            - set of the possible return values of the checkPasswd()
+ *              function expanded to represent interruption (icon
+ *              pressed) and no-data (just 'enter' pressed) cases.
+ *
  * 17-06-99: Started log. :)
  */
 
@@ -16,8 +27,18 @@ extern void initPasswd(void);
 extern int checkPasswd(char *buffer);
 
 #ifdef USE_PAM
+
+/* Not authenticated code .*/
+#define AUTH_NO 0
+/* Successfully authenticated code. */
+#define AUTH_YES 1
+/* Authentication interrupted code. */
+#define AUTH_INT 2
+/* No real authentication attempt. */
+#define AUTH_NO_TRY 4
+
 #include <security/pam_appl.h>
 /*#include <security/pam_misc.h>*/
 
-void PAM_putText( const struct pam_message *msg, struct pam_response *resp, Bool PAM_echokeys );
+void PAM_putText(int isnew, const struct pam_message *msg, struct pam_response *resp, Bool PAM_echokeys );
 #endif
diff --git a/xlock/xlock.c b/xlock/xlock.c
index 9fa2970..0847699 100644
--- a/xlock/xlock.c
+++ b/xlock/xlock.c
@@ -23,6 +23,26 @@ static const char sccsid[] = "@(#)xlock.c	5.25 2007/06/26 xlockmore";
  *
  * Revision History:
  *
+ * Changes made by Paul Wolneykien <manowar@altlinux.ru> (ALT Linux Team)
+ * 14-Oct-08: Fix of the multistage conversation and button logout
+ *            conflict: 
+ *            - adds wrapper for ReadXString() to keep 'isnew' flag value
+ *              for the statusUpdate() function bettween calls;
+ *            - add 'isnew' parameter to the PAM_putText() function to
+ *              manage this value from PAM conversation procedure.
+ * 09-Oct-08: Further PAM integration:
+ *            - in the case of enabled PAM, all authentification data
+ *              is acquired through the conversation with a user; no
+ *              special conversation for password is made before start
+ *              of the PAM conversation;
+ *            - PAM conversation input/output appear at the original
+ *              password prompt position;
+ *            - set of the possible return values of the checkPasswd()
+ *              function expanded to represent interruption (icon
+ *              pressed) and no-data (just 'enter' pressed) cases;
+ *            - PAM_putText() function uses res_retcode field to
+ *              signal interruption.
+ *
  * Changes maintained by David Bagley <bagleyd@tux.org>
  * 23-Feb-03: Timothy Reed <treed1@twcny.rr.com>
  *            Added PAM_putText to converse with passwd.c PAM_conv function
@@ -1991,7 +2011,7 @@ runMainLoop(int maxtime, int iconscreen)
 #endif /* !USE_OLD_EVENT_LOOP */
 
 static int
-ReadXString(char *s, int slen, Bool *capsLock
+ReadXStringX(int isnew, char *s, int slen, Bool *capsLock
 #ifdef GLOBAL_UNLOCK
   , Bool pass
 #elif defined( USE_PAM )
@@ -2020,7 +2040,7 @@ ReadXString(char *s, int slen, Bool *capsLock
 			call_init_hook((LockStruct *) NULL,
 				mode_info(dsp, screen, Scr[screen].window, False));
 		}
-	statusUpdate(True, thisscreen);
+	statusUpdate(isnew, thisscreen);
 	bp = 0;
 	*s = 0;
 
@@ -2241,6 +2261,25 @@ ReadXString(char *s, int slen, Bool *capsLock
 	}
 }
 
+static int
+ReadXString(char *s, int slen, Bool *capsLock
+#ifdef GLOBAL_UNLOCK
+  , Bool pass
+#elif defined( USE_PAM )
+  , Bool PAM_echokeys
+#endif
+
+)
+{
+  return ReadXStringX(True, s, slen, capsLock,
+#ifdef GLOBAL_UNLOCK
+  pass
+#elif defined( USE_PAM )
+  PAM_echokeys
+#endif
+		      );
+}
+
 void
 modeDescription(ModeInfo * mi)
 {
@@ -2432,9 +2471,15 @@ getPassword(void)
 	} else
 #endif
 	{
+#ifdef USE_PAM
+	  /* No special password prompt is used in the case of the
+	   * PAM-enabled conversation. Current prompt positon is
+	   * stored to be used in the conversation input/output
+	   * function (PAM_putText()). */
+#else
 		putText(dsp, Scr[screen].window, Scr[screen].textgc, text_pass, True, left, &x, &y);
 		putText(dsp, Scr[screen].window, Scr[screen].textgc, " ", False, left, &x, &y);
-
+#endif
 		passx = x;
 		passy = y;
 	}
@@ -2606,14 +2651,26 @@ getPassword(void)
 			global_user, strlen(global_user));
 		checkUser(global_user);
 #endif
+
+#ifdef USE_PAM
+		/* By this call the whole, possibly multistep,
+		 * conversation with the user is done, driven by PAM
+		 * subsystem. It finishes either terminated by PAM or
+		 * interrupted by the user. */
+		done = checkPasswd(buffer);
+		/* In the case of interruption the control returns to
+		 * the screensaver. */
+		if ((done & AUTH_INT) > 0) {
+		  break;
+		}
+#else
 		if (ReadXString(buffer, PASSLENGTH, &capsLock
 #ifdef GLOBAL_UNLOCK
 			, True
-#elif defined( USE_PAM )
-			, False
 #endif
 			))
 			break;
+#endif
 		y = remy + 6;
 #ifdef DIRECTCOLOR_FIX
 		XSetForeground(dsp, Scr[screen].gc, MI_BLACK_PIXEL(mi));
@@ -2621,6 +2678,11 @@ getPassword(void)
 		XSetForeground(dsp, Scr[screen].gc, Scr[screen].bg_pixel);
 #endif
 #ifdef SAFEWORD
+#ifdef USE_PAM
+		/* In the case of PAM all data is acquired and
+		 * processed inside the PAM subsystem, so the buffer
+		 * may not be set to any value. */
+#else
 		(void) strcpy(pb->dynpwd, buffer);
 		pb->mode = EVALUATE_ALL;
 		pbmain(pb);
@@ -2628,6 +2690,7 @@ getPassword(void)
 		done = (pb->status == PASS || pb->status == PASS_MASTER);
 		pb->mode = UPDATE_LOGS;
 		pbmain(pb);
+#endif
 #else
 		{
 			XFillRectangle(dsp, Scr[screen].window, Scr[screen].gc,
@@ -2640,11 +2703,22 @@ getPassword(void)
 			Scr[screen].iconpos.x, y, text_valid, strlen(text_valid));
 		XFlush(dsp);
 
+#ifdef USE_PAM
+		/* In the case of using PAM the whole conversation is
+		 * made on the previous call to the checkPasswd()
+		 * function. */
+
+		/* The conversation can be interrupted by the user by
+		 * not entering any data (just hit the 'return' key)
+		 * assumed that the user wouldn't be authenticated. */
+		if ((done & AUTH_NO_TRY) > 0) {
+#else
 		done = checkPasswd(buffer);
 
 		if (!done && !*buffer) {
 			/* just hit return, and it was not his password */
 			/* count_failed++; */  /* not really an attempt, is it? */
+#endif
 			break;
 		} else if (!done) {
 			/* bad password... log it... */
@@ -3989,15 +4063,18 @@ main(int argc, char **argv)
 
 #ifdef USE_PAM
 /* PAM_putText - method to have pam_converse functionality with in XLOCK */
-void PAM_putText( const struct pam_message *msg, struct pam_response *resp, Bool PAM_echokeys )
+void PAM_putText(int isnew, const struct pam_message *msg, 
+		 struct pam_response *resp, Bool PAM_echokeys )
 {
   int x = 50, y = 50;
   int oldX, oldY;
   int left;
   char buffer[PASSLENGTH];
+  int rc;
 
-  x = left = Scr[screen].iconpos.x;
-  y = Scr[screen].iconpos.y + fontAscent + 200;
+  /* Use current conversation (password) position. */
+  x = left = passx;
+  y = passy;
 
 #ifdef DEBUG
     (void) printf( "PAM_putText: message of style %d received: (%s)\n", msg->msg_style, msg->msg );
@@ -4014,7 +4091,7 @@ void PAM_putText( const struct pam_message *msg, struct pam_response *resp, Bool
     unamex = x;
     unamey = y;
 
-    (void) ReadXString(buffer, PASSLENGTH, (Bool *) NULL
+    rc = ReadXStringX(isnew, buffer, PASSLENGTH, (Bool *) NULL
 #ifdef GLOBAL_UNLOCK
 		, True
 #elif defined( USE_PAM )
@@ -4023,11 +4100,18 @@ void PAM_putText( const struct pam_message *msg, struct pam_response *resp, Bool
 		);
 
     XSetForeground(dsp, Scr[screen].gc, Scr[screen].bg_pixel);
-    resp->resp = strdup(buffer);
-    resp->resp_retcode = PAM_SUCCESS;
+    if (rc) {
+      /* Signal of interruption. */
+      resp->resp_retcode = PAM_ABORT;
+      resp->resp = NULL;
+    } else {
+      /* Signal of a successfull read. */
+      resp->resp_retcode = PAM_SUCCESS;
+      resp->resp = strdup(buffer);
+    }
 
 #ifdef DEBUG
-    (void) printf( "Received Username: (%s)\n", resp->resp );
+    (void) printf( "Received value: (%s)\n", resp->resp );
 #endif
   }
   else
 
design & coding: Vladimir Lettiev aka crux © 2004-2005, Andrew Avramenko aka liks © 2007-2008
current maintainer: Michael Shigorin