diff -ru openssh-3.5p1.orig/auth-passwd.c openssh-3.5p1/auth-passwd.c
--- openssh-3.5p1.orig/auth-passwd.c	Thu Sep 26 09:14:16 2002
+++ openssh-3.5p1/auth-passwd.c	Sat Oct 19 14:59:26 2002
@@ -82,6 +82,7 @@
 
 extern ServerOptions options;
 #ifdef WITH_AIXAUTHENTICATE
+void aix_remove_embedded_newlines(char *);
 extern char *aixloginmsg;
 #endif
 
@@ -149,13 +150,20 @@
 #endif
 #ifdef WITH_AIXAUTHENTICATE
 	authsuccess = (authenticate(pw->pw_name,password,&reenter,&authmsg) == 0);
+	aix_remove_embedded_newlines(authmsg);
 
-	if (authsuccess)
+	if (authsuccess) {
+		debug("authenticate() succeeded for user %s: %.100s", pw->pw_name, authmsg);
 	        /* We don't have a pty yet, so just label the line as "ssh" */
 	        if (loginsuccess(authctxt->user,
 			get_canonical_hostname(options.verify_reverse_mapping),
 			"ssh", &aixloginmsg) < 0)
 				aixloginmsg = NULL;
+	} else {
+		debug("authenticate() failed for user %s: %.100s", pw->pw_name, authmsg);
+	}
+	if (authmsg)
+		xfree(authmsg);
 
 	return(authsuccess);
 #endif
diff -ru openssh-3.5p1.orig/auth.c openssh-3.5p1/auth.c
--- openssh-3.5p1.orig/auth.c	Sun Sep 22 01:26:53 2002
+++ openssh-3.5p1/auth.c	Thu Oct 24 00:23:02 2002
@@ -59,6 +59,12 @@
 Buffer auth_debug;
 int auth_debug_init;
 
+#ifdef WITH_AIXAUTHENTICATE
+void aix_remove_embedded_newlines(char *);
+extern char *aixexpiremsg;
+extern int aix_password_change_required;
+#endif
+
 /*
  * Check if the user is allowed to log in via ssh. If user is listed
  * in DenyUsers or one of user's groups is listed in DenyGroups, false
@@ -75,9 +81,6 @@
 	const char *hostname = NULL, *ipaddr = NULL;
 	char *shell;
 	int i;
-#ifdef WITH_AIXAUTHENTICATE
-	char *loginmsg;
-#endif /* WITH_AIXAUTHENTICATE */
 #if !defined(USE_PAM) && defined(HAVE_SHADOW_H) && \
 	!defined(DISABLE_SHADOW) && defined(HAS_SHADOW_EXPIRE)
 	struct spwd *spw;
@@ -202,19 +205,48 @@
 	}
 
 #ifdef WITH_AIXAUTHENTICATE
-	if (loginrestrictions(pw->pw_name, S_RLOGIN, NULL, &loginmsg) != 0) {
-		if (loginmsg && *loginmsg) {
-			/* Remove embedded newlines (if any) */
-			char *p;
-			for (p = loginmsg; *p; p++) {
-				if (*p == '\n')
-					*p = ' ';
+	/*
+	 * Don't check loginrestrictions or expiry for root account (use
+	 * PermitRootLogin to control logins via ssh), or if running as
+	 * non-root user (since loginrestrictions will always fail).
+	 */
+	if ( (pw->pw_uid != 0) && (geteuid() == 0) ) {
+		char *restrictmsg, *expiremsg;
+		int passexpcode;
+
+		/* check for AIX account restrictions */
+		if (loginrestrictions(pw->pw_name, S_RLOGIN, NULL, &restrictmsg) != 0) {
+			if (restrictmsg && *restrictmsg) {
+				aix_remove_embedded_newlines(restrictmsg);
+				log("Login restricted for %s: %.100s", pw->pw_name, restrictmsg);
+				xfree(restrictmsg);
 			}
-			/* Remove trailing newline */
-			*--p = '\0';
-			log("Login restricted for %s: %.100s", pw->pw_name, loginmsg);
+			return 0;
+		}
+
+		/* check for AIX expired account */
+		passexpcode = passwdexpired(pw->pw_name, &aixexpiremsg);
+		debug("passwdexpired() returned %d", passexpcode);
+
+		switch (passexpcode) {
+			case 0:		/* success, password not expired */
+				break;
+			case 1:		/* expired, password change required */
+				aix_password_change_required = 1;
+				break;
+			default:	/* expired too long (2) or other error (-1) */
+				/* make local copy of message and remove newlines for logging */
+				if (aixexpiremsg && *aixexpiremsg) {
+					expiremsg = xstrdup(aixexpiremsg);
+					aix_remove_embedded_newlines(expiremsg);
+				}
+				debug("passwdexpired() returned %d", passexpcode);
+				log("Password expired too long or system failure for user %s: %.100s",
+				    pw->pw_name, expiremsg);
+				if (expiremsg)
+					xfree(expiremsg);
+				return 0;
 		}
-		return 0;
 	}
 #endif /* WITH_AIXAUTHENTICATE */
 
diff -ru openssh-3.5p1.orig/openbsd-compat/port-aix.c openssh-3.5p1/openbsd-compat/port-aix.c
--- openssh-3.5p1.orig/openbsd-compat/port-aix.c	Sun Jul  7 12:17:36 2002
+++ openssh-3.5p1/openbsd-compat/port-aix.c	Sat Oct 19 15:02:26 2002
@@ -24,6 +24,7 @@
  *
  */
 #include "includes.h"
+#include "misc.h"
 
 #ifdef _AIX
 
@@ -52,5 +53,60 @@
 	xfree(cp);
 }
 
-#endif /* _AIX */
+#ifdef WITH_AIXAUTHENTICATE
+
+/*
+ * Remove embedded newlines in string (if any).
+ * Used before logging messages returned by AIX authentication functions
+ * so the message is logged on one line.
+ */
+void
+aix_remove_embedded_newlines(char *p)
+{
+	if (p == NULL)
+		return;
+
+	for (; *p; p++) {
+		if (*p == '\n')
+			*p = ' ';
+	}
+	/* Remove trailing newline */
+	*--p = '\0';
+}
+
+/*
+ * Perform password change on AIX
+ * Like do_pam_chauthtok(), it throws a fatal error if the password can't be changed.
+ */
+void
+do_aix_change_password(struct passwd *pw)
+{
+	pid_t pid;
+	int status;
+	mysig_t old_signal;
+
+	old_signal = mysignal(SIGCHLD, SIG_DFL);
+
+	if ((pid = fork()) == -1)
+		fatal("Couldn't fork: %s", strerror(errno));
+
+	if (pid == 0) {
+		setuid(pw->pw_uid);
+		execl("/usr/bin/passwd","passwd",pw->pw_name,
+			(char *)NULL);
+		/* execl shouldn't return */
+		fatal("Couldn't exec /usr/bin/passwd");
+		exit(1);
+	}
+
+	if (waitpid(pid, &status, 0) == -1)
+		fatal("Couldn't wait for child: %s", strerror(errno));
 
+	if (WEXITSTATUS(status))	/* Passwd exited abnormally */
+		fatal("Failed to change password for %s, passwd returned %d", pw->pw_name, status);
+
+	mysignal(SIGCHLD, old_signal);
+}
+#endif /* WITH_AIXAUTHENTICATE */
+
+#endif /* _AIX */
diff -ru openssh-3.5p1.orig/session.c openssh-3.5p1/session.c
--- openssh-3.5p1.orig/session.c	Thu Sep 26 10:38:50 2002
+++ openssh-3.5p1/session.c	Sat Oct 19 16:46:10 2002
@@ -104,7 +104,10 @@
 Session	sessions[MAX_SESSIONS];
 
 #ifdef WITH_AIXAUTHENTICATE
-char *aixloginmsg;
+void do_aix_change_password(struct passwd *);
+char *aixloginmsg;	/* message returned by loginsuccess() */
+char *aixexpiremsg;	/* message returned by passwdexpire() */
+int aix_password_change_required = 0;
 #endif /* WITH_AIXAUTHENTICATE */
 
 #ifdef HAVE_LOGIN_CAP
@@ -461,6 +464,12 @@
 		    "TTY available");
 #endif /* USE_PAM */
 
+#ifdef WITH_AIXAUTHENTICATE
+	if (aix_password_change_required)
+		packet_disconnect("Password change required but no "
+		    "TTY available");
+#endif /* WITH_AIXAUTHENTICATE */
+
 	/* Fork the child. */
 	if ((pid = fork()) == 0) {
 		fatal_remove_all_cleanups();
@@ -757,6 +766,13 @@
 	}
 #endif
 
+#ifdef WITH_AIXAUTHENTICATE
+	if (aix_password_change_required) {
+		printf("%s\n", aixexpiremsg);
+		do_aix_change_password(pw);
+	}
+#endif
+
 	if (check_quietlogin(s, command))
 		return;
 
@@ -764,9 +780,17 @@
 	if (!is_pam_password_change_required())
 		print_pam_messages();
 #endif /* USE_PAM */
+
 #ifdef WITH_AIXAUTHENTICATE
-	if (aixloginmsg && *aixloginmsg)
+	if (aixexpiremsg && *aixexpiremsg) {
+		if (!aix_password_change_required)
+			printf("%s\n", aixexpiremsg);
+		xfree(aixexpiremsg);
+	}
+	if (aixloginmsg && *aixloginmsg) {
 		printf("%s\n", aixloginmsg);
+		xfree(aixloginmsg);
+	}
 #endif /* WITH_AIXAUTHENTICATE */
 
 #ifndef NO_SSH_LASTLOG
