Patch for changing expired passwords

Dave Dykstra dwd at bell-labs.com
Tue Jun 19 23:23:10 EST 2001


On Tue, Jun 19, 2001 at 02:30:46PM +0200, Markus Friedl wrote:
> On Mon, Jun 18, 2001 at 03:55:45PM -0500, Dave Dykstra wrote:
> > The primary purpose of the attached patches is for portable OpenSSH to
> > support changing expired passwords as specified in shadow password files.
> 
> hi, can you provide a
> 	diff -u
> version for me, too :)
> 
> thanks.

Sure, sorry about that.  I saw somewhere that I should provide unified
diffs but I didn't really know what that meant; now I do.  The diffs
against the two CVS versions are attached.

- Dave Dykstra
-------------- next part --------------
--- auth.c.O	Mon Jun 18 09:31:58 2001
+++ auth.c	Mon Jun 18 09:35:08 2001
@@ -68,16 +68,25 @@
 	shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
 
 	/* deny if shell does not exists or is not executable */
-	if (stat(shell, &st) != 0)
+	if (stat(shell, &st) != 0) {
+		log("User %.100s not allowed because shell %.100s does not exist",
+			pw->pw_name, shell);
 		return 0;
-	if (!((st.st_mode & S_IFREG) && (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP))))
+	}
+	if (!((st.st_mode & S_IFREG) && (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)))) {
+		log("User %.100s not allowed because shell %.100s is not executable",
+			pw->pw_name, shell);
 		return 0;
+	}
 
 	/* Return false if user is listed in DenyUsers */
 	if (options.num_deny_users > 0) {
 		for (i = 0; i < options.num_deny_users; i++)
-			if (match_pattern(pw->pw_name, options.deny_users[i]))
+			if (match_pattern(pw->pw_name, options.deny_users[i])) {
+				log("User %.100s not allowed because listed in DenyUsers",
+					pw->pw_name);
 				return 0;
+			}
 	}
 	/* Return false if AllowUsers isn't empty and user isn't listed there */
 	if (options.num_allow_users > 0) {
@@ -85,19 +94,27 @@
 			if (match_pattern(pw->pw_name, options.allow_users[i]))
 				break;
 		/* i < options.num_allow_users iff we break for loop */
-		if (i >= options.num_allow_users)
+		if (i >= options.num_allow_users) {
+			log("User %.100s not allowed because not listed in AllowUsers",
+				pw->pw_name);
 			return 0;
+		}
 	}
 	if (options.num_deny_groups > 0 || options.num_allow_groups > 0) {
 		/* Get the user's group access list (primary and supplementary) */
-		if (ga_init(pw->pw_name, pw->pw_gid) == 0)
+		if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
+			log("User %.100s not allowed because not in any group",
+				pw->pw_name);
 			return 0;
+		}
 
 		/* Return false if one of user's groups is listed in DenyGroups */
 		if (options.num_deny_groups > 0)
 			if (ga_match(options.deny_groups,
 			    options.num_deny_groups)) {
 				ga_free();
+				log("User %.100s not allowed because a group is listed in DenyGroups",
+					pw->pw_name);
 				return 0;
 			}
 		/*
@@ -108,6 +125,8 @@
 			if (!ga_match(options.allow_groups,
 			    options.num_allow_groups)) {
 				ga_free();
+				log("User %.100s not allowed because none of user's group are listed in AllowGroups",
+					pw->pw_name);
 				return 0;
 			}
 		ga_free();
--- session.c.O	Mon Jun 18 13:59:57 2001
+++ session.c	Mon Jun 18 14:15:29 2001
@@ -93,6 +93,7 @@
 void	session_close(Session *s);
 void	do_exec_pty(Session *s, const char *command);
 void	do_exec_no_pty(Session *s, const char *command);
+void	do_exec(Session *s, const char *command);
 void	do_login(Session *s, const char *command);
 void	do_child(Session *s, const char *command);
 void	do_motd(void);
@@ -270,17 +271,7 @@
 				command = NULL;
 				packet_integrity_check(plen, 0, type);
 			}
-			if (forced_command != NULL) {
-				original_command = command;
-				command = forced_command;
-				debug("Forced command '%.500s'", forced_command);
-			}
-			if (s->ttyfd != -1)
-				do_exec_pty(s, command);
-			else
-				do_exec_no_pty(s, command);
-			if (command != NULL)
-				xfree(command);
+			do_exec(s, command);
 			session_close(s);
 			return;
 
@@ -504,6 +495,35 @@
 	}
 }
 
+/*
+ * This is called to fork and execute a command.  If another command is
+ *   to be forced, execute that instead.
+ */
+void
+do_exec(Session *s, const char *command)
+{
+	if (forced_command) {
+		original_command = command;
+		command = forced_command;
+		forced_command = NULL;
+		debug("Forced command '%.900s'", command);
+	}
+
+	if (s->ttyfd != -1)
+		do_exec_pty(s, command);
+	else
+		do_exec_no_pty(s, command);
+
+	if (command != NULL)
+		xfree(command);
+
+	if (original_command != NULL) {
+		xfree(original_command);
+		original_command = NULL;
+	}
+}
+
+
 /* administrative, login(1)-like work */
 void
 do_login(Session *s, const char *command)
@@ -1288,13 +1308,8 @@
 int
 session_shell_req(Session *s)
 {
-	/* if forced_command == NULL, the shell is execed */
-	char *shell = forced_command;
 	packet_done();
-	if (s->ttyfd == -1)
-		do_exec_no_pty(s, shell);
-	else
-		do_exec_pty(s, shell);
+	do_exec(s, NULL);
 	return 1;
 }
 
@@ -1304,17 +1319,7 @@
 	u_int len;
 	char *command = packet_get_string(&len);
 	packet_done();
-	if (forced_command) {
-		original_command = command;
-		command = forced_command;
-		debug("Forced command '%.500s'", forced_command);
-	}
-	if (s->ttyfd == -1)
-		do_exec_no_pty(s, command);
-	else
-		do_exec_pty(s, command);
-	if (forced_command == NULL)
-		xfree(command);
+	do_exec(s, command);
 	return 1;
 }
 
-------------- next part --------------
--- auth.c.O2	Mon Jun 18 14:21:06 2001
+++ auth.c	Mon Jun 18 14:24:33 2001
@@ -47,6 +47,9 @@
 #include "buffer.h"
 #include "bufaux.h"
 
+/* set when password has expired */
+int forced_passwd_change = 0;
+
 /* import */
 extern ServerOptions options;
 
@@ -81,13 +84,23 @@
 		int days = time(NULL) / 86400;
 
 		/* Check account expiry */
-		if ((spw->sp_expire >= 0) && (days > spw->sp_expire))
+		if ((spw->sp_expire >= 0) && (days > spw->sp_expire)) {
+			log("User %.100s not allowed because account expired",
+				pw->pw_name);
 			return 0;
+		}
 
 		/* 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)) {
+				log("User %.100s not allowed because password expired",
+					pw->pw_name);
+				return 0;
+			}
+
+			forced_passwd_change = 1;
+		}
 	}
 #else
 	/* Shouldn't be called if pw is NULL, but better safe than sorry... */
@@ -177,7 +190,7 @@
 			}
 			/* Remove trailing newline */
 			*--p = '\0';
-			log("Login restricted for %s: %.100s", pw->pw_name, loginmsg);
+			log("Login restricted for %.100s: %.100s", pw->pw_name, loginmsg);
 		}
 		return 0;
 	}
--- auth.h.O	Tue Jun  5 15:25:06 2001
+++ auth.h	Mon Jun 18 14:28:04 2001
@@ -35,6 +35,9 @@
 #include <bsd_auth.h>
 #endif
 
+/* set when password has expired */
+extern int forced_passwd_change;
+
 typedef struct Authctxt Authctxt;
 typedef struct KbdintDevice KbdintDevice;
 
--- session.c.O2	Mon Jun 18 14:21:15 2001
+++ session.c	Mon Jun 18 14:39:36 2001
@@ -603,6 +603,34 @@
 		debug("Forced command '%.900s'", command);
 	}
 
+	if (forced_passwd_change) {
+		char *user = s->pw->pw_name;
+		char *msg;
+
+		if (command != NULL)
+			xfree(command);
+
+		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 = xstrdup(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 = xstrdup("/bin/sh -c 'echo Permission denied >&2; exit 1'");
+		}
+		log(msg, user);
+		packet_send_debug(msg, user);
+	}
+
 	if (s->ttyfd != -1)
 		do_exec_pty(s, command);
 	else
--- configure.in.O	Sun Jun 10 12:24:52 2001
+++ configure.in	Mon Jun 18 14:27:23 2001
@@ -1304,6 +1304,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	Tue May  8 15:33:06 2001
+++ acconfig.h	Mon Jun 18 14:30:16 2001
@@ -211,6 +211,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