diff -ur Linux-PAM-0.77.orig/modules/pam_unix/support.c Linux-PAM-0.77/modules/pam_unix/support.c
--- Linux-PAM-0.77.orig/modules/pam_unix/support.c	2004-07-22 01:24:33.000000000 +0200
+++ Linux-PAM-0.77/modules/pam_unix/support.c	2004-07-22 01:38:41.919360120 +0200
@@ -403,7 +403,7 @@
 #include <sys/wait.h>
 
 static int _unix_run_helper_binary(pam_handle_t *pamh, const char *passwd,
-				   unsigned int ctrl, const char *user)
+				   unsigned int ctrl, const char *user, uid_t uid)
 {
     int retval, child, fds[2];
     void (*sighandler)(int) = NULL;
@@ -443,6 +443,9 @@
 	args[0] = x_strdup(CHKPWD_HELPER);
 	args[1] = x_strdup(user);
 
+	if(uid != -1)
+		setreuid(uid, uid);
+
 	execve(CHKPWD_HELPER, args, envp);
 
 	/* should not get here: exit with error */
@@ -468,6 +471,87 @@
 	retval = (retval == 0) ? PAM_SUCCESS:PAM_AUTH_ERR;
     } else {
 	D(("fork failed"));
+	close(fds[0]);
+	close(fds[1]);
+	retval = PAM_AUTH_ERR;
+    }
+
+    if (sighandler != NULL) {
+        (void) signal(SIGCHLD, sighandler);   /* restore old signal handler */
+    }
+
+    D(("returning %d", retval));
+    return retval;
+}
+
+int _unix_run_verify_binary(pam_handle_t *pamh, unsigned int ctrl, const char *user, uid_t uid)
+{
+    int retval, child, fds[2];
+    void (*sighandler)(int) = NULL;
+
+    D(("called."));
+    /* create a pipe for the password */
+    if (pipe(fds) != 0) {
+	D(("could not make pipe"));
+	return PAM_AUTH_ERR;
+    }
+
+    if (off(UNIX_NOREAP, ctrl)) {
+	/*
+	 * This code arranges that the demise of the child does not cause
+	 * the application to receive a signal it is not expecting - which
+	 * may kill the application or worse.
+	 *
+	 * The "noreap" module argument is provided so that the admin can
+	 * override this behavior.
+	 */
+	sighandler = signal(SIGCHLD, SIG_DFL);
+    }
+
+    /* fork */
+    child = fork();
+    if (child == 0) {
+	static char *envp[] = { NULL };
+	char *args[] = { NULL, NULL, NULL };
+
+	/* XXX - should really tidy up PAM here too */
+
+	close(fds[0]);
+	close(0);
+	dup2(fds[1], STDOUT_FILENO);
+
+	/* exec binary helper */
+	args[0] = x_strdup(VERIFY_HELPER);
+	args[1] = x_strdup(user);
+
+	if(uid != -1)
+		setreuid(uid, uid);
+
+	execve(VERIFY_HELPER, args, envp);
+
+	/* should not get here: exit with error */
+	D(("helper binary is not available"));
+	exit(PAM_AUTHINFO_UNAVAIL);
+    } else if (child > 0) {
+	char buf[1024];
+	int rc;
+	/* wait for child */
+	close(fds[1]);
+	(void) waitpid(child, &retval, 0);  /* wait for helper to complete */
+	rc = read(fds[0], buf, sizeof(buf) - 1);
+	if(rc > 0)
+	{
+		buf[rc] = '\0';
+		if(!strncmp(buf, "I:", 2))
+			_make_remark(pamh, ctrl, PAM_TEXT_INFO, buf + 2);
+		else
+			_make_remark(pamh, ctrl, PAM_ERROR_MSG, buf);
+	}
+	retval = (retval == 0) ? PAM_SUCCESS:PAM_AUTH_ERR;
+    } else {
+	D(("fork failed"));
+	close(fds[0]);
+	close(fds[1]);
 	retval = PAM_AUTH_ERR;
     }
 
@@ -570,30 +654,13 @@
 
 	retval = PAM_SUCCESS;
 	if (pwd == NULL || salt == NULL || strlen(salt) == 1) {
-		if (geteuid()) {
-			/* we are not root perhaps this is the reason? Run helper */
 			D(("running helper binary"));
-			retval = _unix_run_helper_binary(pamh, p, ctrl, name);
+			retval = _unix_run_helper_binary(pamh, p, ctrl, name, pwd ? pwd->pw_uid : -1);
 			if (pwd == NULL && !on(UNIX_AUDIT,ctrl)
 			    && retval != PAM_SUCCESS)
 			{
 				name = NULL;
 			}
-		} else {
-			D(("user's record unavailable"));
-			if (on(UNIX_AUDIT, ctrl)) {
-				/* this might be a typo and the user has given a password
-				   instead of a username. Careful with this. */
-				_log_err(LOG_ALERT, pamh,
-				         "check pass; user (%s) unknown", name);
-			} else {
-				name = NULL;
-				_log_err(LOG_ALERT, pamh,
-				         "check pass; user unknown");
-			}
-			p = NULL;
-			retval = PAM_AUTHINFO_UNAVAIL;
-		}
 	} else {
 	    int salt_len;
 	    strip_hpux_aging(salt);
diff -urN Linux-PAM-0.77.orig/modules/pam_unix/lckpwdf.-c ./lckpwdf.-c
--- Linux-PAM-0.77.orig/modules/pam_unix/lckpwdf.-c	2000-06-21 00:12:02.000000000 +0200
+++ Linux-PAM-0.77/modules/pam_unix/lckpwdf.-c	2004-07-22 01:28:39.997099088 +0200
@@ -26,6 +26,9 @@
 
 #include <fcntl.h>
 #include <signal.h>
+#ifdef WITH_SELINUX
+#include <selinux/selinux.h>
+#endif
 
 #define LOCKFILE "/etc/.pwd.lock"
 #define TIMEOUT 15
@@ -64,7 +67,29 @@
 	if (lockfd != -1)
 		return -1;
 
-	lockfd = open(LOCKFILE, O_CREAT | O_WRONLY, 0600);
+#ifdef WITH_SELINUX
+	if(is_selinux_enabled())
+	{
+		lockfd = open(LOCKFILE, O_WRONLY);
+		if(lockfd == -1 && errno == ENOENT)
+		{
+			security_context_t create_context;
+			int rc;
+
+			if(getfilecon("/etc/passwd", &create_context))
+				return -1;
+			rc = setfscreatecon(create_context);
+			freecon(create_context);
+			if(rc)
+				return -1;
+			lockfd = open(LOCKFILE, O_CREAT | O_WRONLY, 0600);
+			if(setfscreatecon(NULL))
+				return -1;
+		}
+	}
+	else
+#endif
+		lockfd = open(LOCKFILE, O_CREAT | O_WRONLY, 0600);
 	if (lockfd == -1)
 		return -1;
 	if (set_close_on_exec(lockfd) == -1)
diff -urN Linux-PAM-0.77.orig/modules/pam_unix/pam_unix_acct.c ./pam_unix_acct.c
--- Linux-PAM-0.77.orig/modules/pam_unix/pam_unix_acct.c	2004-07-22 01:43:36.027648864 +0200
+++ Linux-PAM-0.77/modules/pam_unix/pam_unix_acct.c	2004-07-22 01:28:39.997099088 +0200
@@ -97,6 +97,8 @@
 		return PAM_USER_UNKNOWN;
 	}
 
+	return _unix_run_verify_binary(pamh, ctrl, uname, pwent->pw_uid);
+#if 0
 	if (!strcmp( pwent->pw_passwd, "*NP*" )) { /* NIS+ */
 		uid_t save_euid, save_uid;
 
@@ -191,6 +189,7 @@
 	D(("all done"));
 
 	return PAM_SUCCESS;
+#endif
 }
 
 
diff -urN Linux-PAM-0.77.orig/modules/pam_unix/support.c ./support.c
--- Linux-PAM-0.77.orig/modules/pam_unix/support.c	2004-07-22 01:43:36.036647496 +0200
+++ Linux-PAM-0.77/modules/pam_unix/support.c	2004-07-22 01:28:40.000098632 +0200
@@ -1,5 +1,5 @@
 /* 
- * $Id: support.c,v 1.17 2003/11/26 08:50:59 kukuk Exp $
+ * $Id: support.c,v 1.15 2002/09/23 17:33:22 agmorgan Exp $
  *
  * Copyright information at end of file.
  */
@@ -108,6 +107,36 @@
 	return retval;
 }
 
+  /*
+   * Beacause getlogin() is braindead and sometimes it just
+   * doesn't work, we reimplement it here.
+   */
+char *PAM_getlogin(void)
+{
+	struct utmp *ut, line;
+	char *curr_tty, *retval;
+	static char curr_user[sizeof(ut->ut_user) + 4];
+
+	retval = NULL;
+
+	curr_tty = ttyname(0);
+	if (curr_tty != NULL) {
+		D(("PAM_getlogin ttyname: %s", curr_tty));
+		curr_tty += 5;
+		setutent();
+		strncpy(line.ut_line, curr_tty, sizeof(line.ut_line));
+		if ((ut = getutline(&line)) != NULL) {
+			strncpy(curr_user, ut->ut_user, sizeof(ut->ut_user));
+			curr_user[sizeof(curr_user) - 1] = '\0';
+			retval = curr_user;
+		}
+		endutent();
+	}
+	D(("PAM_getlogin retval: %s", retval));
+
+	return retval;
+}
+
 /*
  * set the control flags for the UNIX module.
  */
@@ -167,7 +196,7 @@
 			if (remember != NULL) {
 				if (j == UNIX_REMEMBER_PASSWD) {
 					*remember = strtol(*argv + 9, NULL, 10);
-					if ((*remember == INT_MIN) || (*remember == INT_MAX))
+					if ((*remember == LONG_MIN) || (*remember == LONG_MAX))
 						*remember = -1;
 					if (*remember > 400)
 						*remember = 400;
@@ -563,21 +592,6 @@
     return retval;
 }
 
-static void strip_hpux_aging(char *p)
-{
-	const char *valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-			    "abcdefghijklmnopqrstuvwxyz"
-			    "0123456789./";
-	if ((*p != '$') && (strlen(p) > 13)) {
-		for (p += 13; *p != '\0'; p++) {
-			if (strchr(valid, *p) == NULL) {
-				*p = '\0';
-				break;
-			}
-		}
-	}
-}
-
 int _unix_verify_password(pam_handle_t * pamh, const char *name
 			  ,const char *p, unsigned int ctrl)
 {
@@ -653,7 +667,7 @@
 	}
 
 	retval = PAM_SUCCESS;
-	if (pwd == NULL || salt == NULL || strlen(salt) == 1) {
+	if (pwd == NULL || salt == NULL || !strcmp(salt, "x")) {
 			D(("running helper binary"));
 			retval = _unix_run_helper_binary(pamh, p, ctrl, name, pwd ? pwd->pw_uid : -1);
 			if (pwd == NULL && !on(UNIX_AUDIT,ctrl)
@@ -662,9 +676,7 @@
 				name = NULL;
 			}
 	} else {
-	    int salt_len;
-	    strip_hpux_aging(salt);
-	    salt_len = strlen(salt);
+	    int salt_len = strlen(salt);
 	    if (!salt_len) {
 		/* the stored password is NULL */
 		if (off(UNIX__NONULL, ctrl)) {/* this means we've succeeded */
@@ -723,17 +735,10 @@
 
 			if (new != NULL) {
 
-			    const char *login_name;
-
-			    login_name = _pammodutil_getlogin(pamh);
-			    if (login_name == NULL) {
-				login_name = "";
-			    }
-
-			        new->user = x_strdup(name ? name : "");
+				new->user = x_strdup(name ? name : "");
 				new->uid = getuid();
 				new->euid = geteuid();
-				new->name = x_strdup(login_name);
+				new->name = x_strdup(PAM_getlogin()? PAM_getlogin() : "");
 
 				/* any previous failures for this user ? */
 				pam_get_data(pamh, data_name, (const void **) &old);
diff -urN Linux-PAM-0.77.orig/modules/pam_unix/support.h ./support.h
--- Linux-PAM-0.77.orig/modules/pam_unix/support.h	2004-07-22 01:43:36.026649016 +0200
+++ Linux-PAM-0.77/modules/pam_unix/support.h	2002-07-11 07:43:51.000000000 +0200
@@ -1,5 +1,5 @@
 /*
- * $Id: support.h,v 1.5 2003/01/14 05:43:07 agmorgan Exp $
+ * $Id: support.h,v 1.4 2002/07/11 05:43:51 agmorgan Exp $
  */
 
 #ifndef _PAM_UNIX_SUPPORT_H
@@ -128,6 +125,7 @@
 	_pam_drop(xx);		\
 }
 
+extern char *PAM_getlogin(void);
 extern void _log_err(int err, pam_handle_t *pamh, const char *format,...);
 extern int _make_remark(pam_handle_t * pamh, unsigned int ctrl
 		       ,int type, const char *text);
diff -urN Linux-PAM-0.77.orig/modules/pam_unix/unix_chkpwd.c ./unix_chkpwd.c
--- Linux-PAM-0.77.orig/modules/pam_unix/unix_chkpwd.c	2004-07-22 01:43:36.031648256 +0200
+++ Linux-PAM-0.77/modules/pam_unix/unix_chkpwd.c	2004-07-22 01:28:40.001098480 +0200
@@ -87,19 +87,15 @@
 	(void) sigaction(SIGQUIT, &action, NULL);
 }
 
-static void strip_hpux_aging(char *p)
+static uid_t getuidname(const char * const username)
 {
-	const char *valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-			    "abcdefghijklmnopqrstuvwxyz"
-			    "0123456789./";
-	if ((*p != '$') && (strlen(p) > 13)) {
-		for (p += 13; *p != '\0'; p++) {
-			if (strchr(valid, *p) == NULL) {
-				*p = '\0';
-				break;
-			}
-		}
-	}
+	struct passwd *pw;
+
+	pw = getpwnam(username);
+	if (pw == NULL)
+		return -1;
+
+	return pw->pw_uid;
 }
 
 static int _unix_verify_password(const char *name, const char *p, int opt)
@@ -149,7 +145,6 @@
 		return retval;
 	}
 
-	strip_hpux_aging(salt);
 	salt_len = strlen(salt);
 	if (salt_len == 0) {
 		return (opt == 0) ? UNIX_FAILED : UNIX_PASSED;
@@ -199,21 +194,6 @@
 	return retval;
 }
 
-static char *getuidname(uid_t uid)
-{
-	struct passwd *pw;
-	static char username[32];
-
-	pw = getpwuid(uid);
-	if (pw == NULL)
-		return NULL;
-
-	strncpy(username, pw->pw_name, sizeof(username));
-	username[sizeof(username) - 1] = '\0';
-	
-	return username;
-}
-
 int main(int argc, char *argv[])
 {
 	char pass[MAXPASS + 1];
@@ -221,7 +201,7 @@
 	int npass, opt;
 	int force_failure = 0;
 	int retval = UNIX_FAILED;
-	char *user;
+	uid_t my_uid;
 
 	/*
 	 * Catch or ignore as many signal as possible.
@@ -237,7 +217,7 @@
 	 * account).
 	 */
 
-	if (isatty(STDIN_FILENO)) {
+	if (isatty(STDIN_FILENO) || argc != 2) {
 
 		_log_err(LOG_NOTICE
 		      ,"inappropriate use of Unix helper binary [UID=%d]"
@@ -252,13 +232,9 @@
 	/*
 	 * determine the current user's name is
 	 */
-	user = getuidname(getuid());
-	if (argc == 2) {
-	    /* if the caller specifies the username, verify that user
-	       matches it */
-	    if (strcmp(user, argv[1])) {
-		force_failure = 1;
-	    }
+	my_uid = getuidname(argv[1]);
+	if (my_uid == -1 || my_uid != getuid()) {
+	    return UNIX_FAILED;
 	}
 
 	/* read the nullok/nonull option */
@@ -292,13 +268,13 @@
 		if (npass == 0) {
 			/* the password is NULL */
 
-			retval = _unix_verify_password(user, NULL, opt);
+			retval = _unix_verify_password(argv[1], NULL, opt);
 
 		} else {
 			/* does pass agree with the official one? */
 
 			pass[npass] = '\0';	/* NUL terminate */
-			retval = _unix_verify_password(user, pass, opt);
+			retval = _unix_verify_password(argv[1], pass, opt);
 
 		}
 	}
diff -urN Linux-PAM-0.77.orig/modules/pam_unix/unix_verify.c ./unix_verify.c
--- Linux-PAM-0.77.orig/modules/pam_unix/unix_verify.c	1970-01-01 01:00:00.000000000 +0100
+++ Linux-PAM-0.77/modules/pam_unix/unix_verify.c	2004-07-22 01:28:40.002098328 +0200
@@ -0,0 +1,250 @@
+/*
+ * $Id: unix_chkpwd.c,v 1.9 2002/09/23 17:33:22 agmorgan Exp $
+ *
+ * This program is designed to run setuid(root) or with sufficient
+ * privilege to read all of the unix password databases. It is designed
+ * to provide a mechanism for the current user (defined by this
+ * process' uid) to verify their own password.
+ *
+ * The password is read from the standard input. The exit status of
+ * this program indicates whether the user is authenticated or not.
+ *
+ * Copyright information is located at the end of the file.
+ *
+ */
+
+#include <security/_pam_aconf.h>
+
+#ifdef MEMORY_DEBUG
+# undef exit
+# undef strdup
+# undef free
+#endif /* MEMORY_DEBUG */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <shadow.h>
+#include <signal.h>
+#include <security/_pam_types.h>
+#include <time.h>
+
+#include <security/_pam_macros.h>
+
+#define UNIX_PASSED	0
+#define UNIX_FAILED	1
+
+/* syslogging function for errors and other information */
+
+static void _log_err(int err, const char *format,...)
+{
+	va_list args;
+
+	va_start(args, format);
+	openlog("unix_chkpwd", LOG_CONS | LOG_PID, LOG_AUTH);
+	vsyslog(err, format, args);
+	va_end(args);
+	closelog();
+}
+
+static void su_sighandler(int sig)
+{
+	if (sig > 0) {
+		_log_err(LOG_NOTICE, "caught signal %d.", sig);
+		exit(sig);
+	}
+}
+
+static void setup_signals(void)
+{
+	struct sigaction action;	/* posix signal structure */
+
+	/*
+	 * Setup signal handlers
+	 */
+	(void) memset((void *) &action, 0, sizeof(action));
+	action.sa_handler = su_sighandler;
+	action.sa_flags = SA_RESETHAND;
+	(void) sigaction(SIGILL, &action, NULL);
+	(void) sigaction(SIGTRAP, &action, NULL);
+	(void) sigaction(SIGBUS, &action, NULL);
+	(void) sigaction(SIGSEGV, &action, NULL);
+	action.sa_handler = SIG_IGN;
+	action.sa_flags = 0;
+	(void) sigaction(SIGTERM, &action, NULL);
+	(void) sigaction(SIGHUP, &action, NULL);
+	(void) sigaction(SIGINT, &action, NULL);
+	(void) sigaction(SIGQUIT, &action, NULL);
+}
+
+static uid_t getuidname(const char * const username)
+{
+	struct passwd *pw;
+
+	pw = getpwnam(username);
+	if (pw == NULL)
+		return -1;
+
+	return pw->pw_uid;
+}
+
+
+static int verify_account(const char * const uname)
+{
+	int daysleft;
+	time_t curdays;
+	struct spwd *spent;
+	struct passwd *pwent;
+	char buf[80];
+
+	pwent = getpwnam(uname);
+	if (!pwent) {
+		_log_err(LOG_ALERT, "could not identify user (from getpwnam(%s))", uname);
+		return PAM_USER_UNKNOWN;
+	}
+
+	if (!strcmp( pwent->pw_passwd, "*NP*" )) { /* NIS+ */
+		uid_t save_euid, save_uid;
+
+		save_euid = geteuid();
+		save_uid = getuid();
+		if (save_uid == pwent->pw_uid)
+			setreuid( save_euid, save_uid );
+		else  {
+			setreuid( 0, -1 );
+			if (setreuid( -1, pwent->pw_uid ) == -1) {
+				setreuid( -1, 0 );
+				setreuid( 0, -1 );
+				if(setreuid( -1, pwent->pw_uid ) == -1)
+					return PAM_CRED_INSUFFICIENT;
+			}
+		}
+		spent = getspnam( uname );
+		if (save_uid == pwent->pw_uid)
+			setreuid( save_uid, save_euid );
+		else {
+			if (setreuid( -1, 0 ) == -1)
+			setreuid( save_uid, -1 );
+			setreuid( -1, save_euid );
+		}
+
+	} else if (!strcmp( pwent->pw_passwd, "x" )) {
+		spent = getspnam(uname);
+	} else {
+		return PAM_SUCCESS;
+	}
+
+	if (!spent)
+		return PAM_AUTHINFO_UNAVAIL;	/* Couldn't get username from shadow */
+
+	curdays = time(NULL) / (60 * 60 * 24);
+	if ((curdays > spent->sp_expire) && (spent->sp_expire != -1)
+	    && (spent->sp_lstchg != 0)) {
+		_log_err(LOG_NOTICE, "account %s has expired (account expired)", uname);
+		printf("Your account has expired; please contact your system administrator");
+		return PAM_ACCT_EXPIRED;
+	}
+	if ((curdays > (spent->sp_lstchg + spent->sp_max + spent->sp_inact))
+	    && (spent->sp_max != -1) && (spent->sp_inact != -1)
+	    && (spent->sp_lstchg != 0)) {
+		_log_err(LOG_NOTICE, "account %s has expired (failed to change password)", uname);
+		printf("Your account has expired; please contact your system administrator");
+		return PAM_ACCT_EXPIRED;
+	}
+	if (spent->sp_lstchg == 0) {
+		_log_err(LOG_NOTICE, "expired password for user %s (root enforced)", uname);
+		printf("You are required to change your password immediately (root enforced)");
+		return PAM_NEW_AUTHTOK_REQD;
+	}
+	if (((spent->sp_lstchg + spent->sp_max) < curdays) && (spent->sp_max != -1)) {
+		_log_err(LOG_DEBUG, "expired password for user %s (password aged)", uname);
+		printf("You are required to change your password immediately (password aged)");
+		return PAM_NEW_AUTHTOK_REQD;
+	}
+	if ((curdays > (spent->sp_lstchg + spent->sp_max - spent->sp_warn))
+	    && (spent->sp_max != -1) && (spent->sp_warn != -1)) {
+		daysleft = (spent->sp_lstchg + spent->sp_max) - curdays;
+		_log_err(LOG_DEBUG, "password for user %s will expire in %d days", uname, daysleft);
+		snprintf(buf, 80, "I:Warning: your password will expire in %d day%.2s",
+			 daysleft, daysleft == 1 ? "" : "s");
+		printf(buf);
+	}
+
+	return UNIX_PASSED;
+}
+
+int main(int argc, char *argv[])
+{
+	uid_t my_uid;
+
+	/*
+	 * Catch or ignore as many signal as possible.
+	 */
+	setup_signals();
+
+	/*
+	 * we establish that this program is running with non-tty stdin.
+	 * this is to discourage casual use.
+	 */
+
+	if (isatty(STDIN_FILENO) || argc != 2) {
+
+		_log_err(LOG_NOTICE
+		      ,"inappropriate use of Unix helper binary [UID=%d]"
+			 ,getuid());
+		fprintf(stderr
+		 ,"This binary is not designed for running in this way\n"
+		      "-- the system administrator has been informed\n");
+		sleep(10);	/* this should discourage/annoy the user */
+		return UNIX_FAILED;
+	}
+
+	/*
+	 * determine the current user's name is
+	 */
+	my_uid = getuidname(argv[1]);
+	if (my_uid == -1 || my_uid != getuid())
+	    return UNIX_FAILED;
+
+	return verify_account(argv[1]);
+}
+
+/*
+ * Copyright (c) Andrew G. Morgan, 1996. All rights reserved
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ * 
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions.  (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
--- Linux-PAM-0.77.orig/modules/pam_unix/Makefile	2004-07-22 02:03:57.192542264 +0200
+++ Linux-PAM-0.77/modules/pam_unix/Makefile	2004-07-22 02:06:13.270855216 +0200
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.5 2003/07/13 18:41:04 vorlon Exp $
+# $Id: Makefile,v 1.3 2001/02/11 06:33:53 agmorgan Exp $
 #
 # This Makefile controls a build process of the pam_unix modules
 # for Linux-PAM. You should not modify this Makefile.
@@ -36,15 +36,14 @@
 endif
 
 CHKPWD=unix_chkpwd
+VERIFY=unix_verify
 
-EXTRAS += -DCHKPWD_HELPER=\"$(SUPLEMENTED)/$(CHKPWD)\"
+EXTRAS += -DCHKPWD_HELPER=\"$(SUPLEMENTED)/$(CHKPWD)\" -DVERIFY_HELPER=\"$(SUPLEMENTED)/$(VERIFY)\"
 
 ########################################################################
 
-CFLAGS += $(USE_CRACKLIB) $(USE_LCKPWDF) $(NEED_LCKPWDF) $(EXTRAS) \
-	 -I../pammodutil/include
-
-LDLIBS = $(EXTRALS) -L../pammodutil -lpammodutil
+CFLAGS += $(USE_CRACKLIB) $(USE_LCKPWDF) $(NEED_LCKPWDF) $(EXTRAS) -I../pammodutil/include -DWITH_SELINUX
+LDLIBS = $(EXTRALS) -L../pammodutil -lpammodutil -lselinux
 
 ifdef USE_CRACKLIB
 CRACKLIB = -lcrack
@@ -71,7 +70,7 @@
 
 ########################### don't edit below #######################
 
-all: dirs info $(PLUS) $(LIBSHARED) $(LIBSTATIC) $(CHKPWD) register
+all: dirs info $(PLUS) $(LIBSHARED) $(LIBSTATIC) $(CHKPWD) $(VERIFY) register
 
 dynamic/%.o : %.c
 	$(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
@@ -127,6 +126,12 @@
 unix_chkpwd.o: unix_chkpwd.c
 	$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
 
+$(VERIFY): unix_verify.o
+	$(CC) -o $(VERIFY) $^ $(LDLIBS)
+
+unix_verify.o: unix_verify.c
+	$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
 md5_good.o: md5.c
 	$(CC) $(CFLAGS) $(CPPFLAGS) -DHIGHFIRST -D'MD5Name(x)=Good##x' \
 		$(TARGET_ARCH) -c $< -o $@
@@ -153,15 +158,17 @@
 endif
 	$(MKDIR) $(FAKEROOT)$(SUPLEMENTED)
 	install -m 4555 $(CHKPWD) $(FAKEROOT)$(SUPLEMENTED)
+	install -m 4555 $(VERIFY) $(FAKEROOT)$(SUPLEMENTED)
 
 remove:
 	rm -f $(FAKEROOT)$(SECUREDIR)/$(LIBSHARED)
 	for x in pam_unix_auth pam_unix_acct pam_unix_passwd pam_unix_session;\
 		do rm -f $(FAKEROOT)$(SECUREDIR)/$$x.so ; done
 	rm -f $(FAKEROOT)$(SUPLEMENTED)/$(CHKPWD)
+	rm -f $(FAKEROOT)$(SUPLEMENTED)/$(VERIFY)
 
 clean:
-	rm -f $(LIBOBJD) $(LIBOBJS) $(CHKPWD) *.o *.so core
+	rm -f $(LIBOBJD) $(LIBOBJS) $(CHKPWD) $(VERIFY) *.o *.so core
 	rm -f *~ *.a *.out *.bak
 	rm -rf dynamic static
 
--- Linux-PAM-0.77.orig/modules/pam_unix/pam_unix_passwd.c	2004-07-22 02:03:57.179544240 +0200
+++ Linux-PAM-0.77/modules/pam_unix/pam_unix_passwd.c	2004-07-22 02:08:42.667143528 +0200
@@ -57,6 +57,12 @@
 #include <rpcsvc/yp_prot.h>
 #include <rpcsvc/ypclnt.h>
 
+#ifdef WITH_SELINUX
+#include <selinux/selinux.h>
+static int selinux_enabled=0;
+static security_context_t prev_context=NULL;
+#endif
+
 #ifdef USE_CRACKLIB
 #include <crack.h>
 #endif
@@ -88,7 +94,7 @@
  */
 
 #ifdef NEED_LCKPWDF
-# include "./lckpwdf.-c"
+#include "./lckpwdf.-c"
 #endif
 
 extern char *bigcrypt(const char *key, const char *salt);
@@ -264,16 +270,34 @@
     }
 
     oldmask = umask(077);
+    if ((selinux_enabled=is_selinux_enabled())) {
+      security_context_t passwd_context=NULL;
+      if (getfilecon("/etc/passwd",&passwd_context)<0) {
+        return PAM_AUTHTOK_ERR;
+      };
+      if (getfscreatecon(&prev_context)<0) {
+        freecon(passwd_context);
+        return PAM_AUTHTOK_ERR;
+      }
+      if (setfscreatecon(passwd_context)) {
+        freecon(passwd_context);
+        freecon(prev_context);
+        return PAM_AUTHTOK_ERR;
+      }
+      freecon(passwd_context);
+    }
     pwfile = fopen(OPW_TMPFILE, "w");
     umask(oldmask);
     if (pwfile == NULL) {
-	return PAM_AUTHTOK_ERR;
+      err = 1;
+      goto done;
     }
 
     opwfile = fopen(OLD_PASSWORDS_FILE, "r");
     if (opwfile == NULL) {
 	fclose(pwfile);
-	return PAM_AUTHTOK_ERR;
+	err = 1;
+	goto done;
     }
 
     chown(OPW_TMPFILE, 0, 0);
@@ -334,8 +358,20 @@
 	err = 1;
     }
 
-    if (!err) {
+done:
+    if (!err)
 	rename(OPW_TMPFILE, OLD_PASSWORDS_FILE);
+#ifdef WITH_SELINUX
+    if (selinux_enabled) {
+      if (setfscreatecon(prev_context)) {
+        err = 1;
+      }
+      if (prev_context)
+        freecon(prev_context);
+      prev_context=NULL;
+    }
+#endif
+    if (!err) {
 	return PAM_SUCCESS;
     } else {
 	unlink(OPW_TMPFILE);
@@ -422,16 +451,38 @@
 	return PAM_USER_UNKNOWN;
     }
     oldmask = umask(077);
+
+#ifdef WITH_SELINUX
+    if ((selinux_enabled=is_selinux_enabled())) {
+      security_context_t shadow_context=NULL;
+      if (getfilecon("/etc/shadow",&shadow_context)<0) {
+        return PAM_AUTHTOK_ERR;
+      };
+      if (getfscreatecon(&prev_context)<0) {
+        freecon(shadow_context);
+        return PAM_AUTHTOK_ERR;
+      }
+      if (setfscreatecon(shadow_context)) {
+        freecon(shadow_context);
+        freecon(prev_context);
+        return PAM_AUTHTOK_ERR;
+      }
+      freecon(shadow_context);
+    }
+#endif
+
     pwfile = fopen(SH_TMPFILE, "w");
     umask(oldmask);
     if (pwfile == NULL) {
-	return PAM_AUTHTOK_ERR;
+       err = 1;
+       goto done;
     }
 
     opwfile = fopen("/etc/shadow", "r");
     if (opwfile == NULL) {
 	fclose(pwfile);
-	return PAM_AUTHTOK_ERR;
+        err = 1;
+        goto done;
     }
 
     if (fstat(fileno(opwfile), &st) == -1) {
@@ -466,8 +517,23 @@
 	err = 1;
     }
 
+ done:
     if (!err) {
 	rename(SH_TMPFILE, "/etc/shadow");
+    }
+
+#ifdef WITH_SELINUX
+    if (selinux_enabled) {
+      if (setfscreatecon(prev_context)) {
+	err = 1;
+      }
+      if (prev_context) 
+	freecon(prev_context);
+      prev_context=NULL;
+    }
+#endif
+
+    if (!err) {
 	return PAM_SUCCESS;
     } else {
 	unlink(SH_TMPFILE);
@@ -483,7 +549,10 @@
 
 	D(("called"));
 
+	setpwent();
 	pwd = getpwnam(forwho);
+	endpwent();
+
 	if (pwd == NULL)
 		return PAM_AUTHTOK_ERR;
 
@@ -594,7 +663,9 @@
 	int retval = PAM_SUCCESS;
 
 	/* UNIX passwords area */
+	setpwent();
 	pwd = getpwnam(user);	/* Get password file entry... */
+	endpwent();
 	if (pwd == NULL)
 		return PAM_AUTHINFO_UNAVAIL;	/* We don't need to do the rest... */
 
@@ -708,7 +779,7 @@
 				int argc, const char **argv)
 {
 	unsigned int ctrl, lctrl;
-	int retval;
+	int retval, i;
 	int remember = -1;
 
 	/* <DO NOT free() THESE> */
