Patch for changing expired passwords

Dave Dykstra dwd at bell-labs.com
Sat Oct 13 06:34:52 EST 2001


On Fri, Oct 12, 2001 at 11:47:38AM +1000, Damien Miller wrote:
> Subject: Re: Please test snapshots for 3.0 release
> Could everyone please test the latest snapshots as we will be making a
> new release soon.
> 
> If you have any patches you would like us to consider, please resend 
> them to the list ASAP.

I have posted this one several times and I ask that you *please* put it
in.  Many people have asked for this one, and Markus has done all the
preparatory work in the base code so changes only need to be made to the
portable code.  It works for all systems that use /etc/shadow, most notably
Solaris and Linux.

Below is the patch updated to the latest CVS.  Don't forget to run
autoheader and autoconf before re-running configure.

- Dave Dykstra


--- auth.c.O	Fri Oct 12 14:42:38 2001
+++ auth.c	Fri Oct 12 14:57:29 2001
@@ -49,6 +49,9 @@
 #include "uidswap.h"
 #include "tildexpand.h"
 
+/* set when password has expired */
+int forced_passwd_change = 0;
+
 /* import */
 extern ServerOptions options;
 
@@ -89,8 +92,12 @@
 
 		/* Check password expiry */
 		if ((spw->sp_lstchg >= 0) && (spw->sp_max >= 0) &&
-		    (days > (spw->sp_lstchg + spw->sp_max)))
-			return 0;
+		    (days > (spw->sp_lstchg + spw->sp_max))) {
+			if ((pw->pw_uid == 0))
+				return 0;
+
+			forced_passwd_change = 1;
+		}
 	}
 #else
 	/* Shouldn't be called if pw is NULL, but better safe than sorry... */
--- auth.h.O	Thu Aug 23 13:18:52 2001
+++ auth.h	Fri Oct 12 15:00:10 2001
@@ -40,6 +40,9 @@
 #include <krb5.h>
 #endif
 
+/* set when password has expired */
+extern int forced_passwd_change;
+
 typedef struct Authctxt Authctxt;
 typedef struct KbdintDevice KbdintDevice;
 
--- session.c.O	Fri Oct 12 14:42:41 2001
+++ session.c	Fri Oct 12 15:04:29 2001
@@ -656,7 +656,31 @@
 void
 do_exec(Session *s, const char *command)
 {
-	if (forced_command) {
+	if (forced_passwd_change) {
+		char *user = s->pw->pw_name;
+		char *msg;
+
+		if (s->ttyfd != -1) {
+			msg = "Password for %.100s has expired, running 'passwd' to reset it";
+			/*
+			 * Can't pass "user" to 'passwd' because Linux doesn't
+			 * allow it.
+			 * Also, the prompt is friendlier without "user".
+			 */
+			command = PASSWD_PATH;
+		} else {
+			msg = "Password for %.100s has expired and cannot be changed without a pty";
+			/*
+			 * Without a pty, Solaris 'passwd' prints "Permission
+			 * denied", but Linux attempts to change the password
+			 * and fails miserably, so echo an error message instead
+			 */
+			command = "/bin/sh -c 'echo Permission denied >&2; exit 1'";
+		}
+		log(msg, user);
+		packet_send_debug(msg, user);
+
+	} else if (forced_command) {
 		original_command = command;
 		command = forced_command;
 		debug("Forced command '%.900s'", command);
--- configure.in.O	Fri Oct 12 14:42:39 2001
+++ configure.in	Fri Oct 12 15:00:57 2001
@@ -1449,6 +1449,10 @@
 	AC_DEFINE_UNQUOTED(RSH_PATH, "$rsh_path")
 fi
 
+AC_PATH_PROG(PASSWD_PATH, passwd)
+AC_DEFINE_UNQUOTED(PASSWD_PATH, "$PASSWD_PATH")
+
+
 # Check for mail directory (last resort if we cannot get it from headers)
 if test ! -z "$MAIL" ; then
 	maildir=`dirname $MAIL`
--- acconfig.h.O	Fri Oct 12 14:42:37 2001
+++ acconfig.h	Fri Oct 12 14:58:43 2001
@@ -214,6 +214,9 @@
 /* Define if rsh is found in your path */
 #undef RSH_PATH
 
+/* Define if passwd is found in your path */
+#undef PASSWD_PATH
+
 /* Define if you want to allow MD5 passwords */
 #undef HAVE_MD5_PASSWORDS
 



More information about the openssh-unix-dev mailing list