Index: Linux-PAM/configure.in
===================================================================
--- Linux-PAM/configure.in	(revision 337)
+++ Linux-PAM/configure.in	(working copy)
@@ -231,6 +231,13 @@
 if test $HAVE_LIBNSL = yes ; then
 	pwdblibs="$pwdblibs -lnsl"
 fi
+AC_CHECK_LIB(selinux, getfilecon, HAVE_LIBSELINUX=yes ; AC_DEFINE(HAVE_LIBSELINUX),
+	HAVE_LIBSELINUX=no)
+AC_SUBST(HAVE_LIBSELINUX)
+
+if test $HAVE_LIBSELINUX = yes ; then
+	pwdblibs="$pwdblibs -lselinux" 
+fi
 AC_CHECK_LIB(pwdb, pwdb_db_name, HAVE_LIBPWDB=yes ; AC_DEFINE(HAVE_LIBPWDB),
 	HAVE_LIBPWDB=no,$pwdblibs)
 AC_SUBST(HAVE_LIBPWDB)
Index: Linux-PAM/modules/pam_unix/pam_unix_passwd.c
===================================================================
--- Linux-PAM/modules/pam_unix/pam_unix_passwd.c	(revision 337)
+++ Linux-PAM/modules/pam_unix/pam_unix_passwd.c	(working copy)
@@ -57,6 +57,19 @@
 #include <rpcsvc/yp_prot.h>
 #include <rpcsvc/ypclnt.h>
 
+#include <signal.h>
+#include <linux/limits.h>
+#include <errno.h>
+#include <sys/wait.h>
+#ifdef WITH_SELINUX
+static int selinux_enabled = -1;
+#include <selinux/selinux.h>
+static security_context_t prev_context = NULL;
+#define SELINUX_ENABLED (selinux_enabled != -1 ? selinux_enabled : (selinux_enabled = is_selinux_enabled() > 0))
+#else
+#define SELINUX_ENABLED 0
+#endif
+
 #ifdef USE_CRACKLIB
 #include <crack.h>
 #endif
@@ -273,37 +286,58 @@
     }
 
     oldmask = umask(077);
+
+#ifdef WITH_SELINUX
+    if (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);
+    }
+#endif
     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;
     }
 
-    if (fstat (fileno (opwfile), &st) == -1)
-      {
-	fclose (opwfile);
-	fclose (pwfile);
-	return PAM_AUTHTOK_ERR;
-      }
+    if (fstat(fileno(opwfile), &st) == -1) {
+	fclose(opwfile);
+	fclose(pwfile);
+	err = 1;
+	goto done;
+    }
 
-    if (fchown (fileno (pwfile), st.st_uid, st.st_gid) == -1)
-      {
-	fclose (opwfile);
-	fclose (pwfile);
-	return PAM_AUTHTOK_ERR;
-      }
-    if (fchmod (fileno (pwfile), st.st_mode) == -1)
-      {
-	fclose (opwfile);
-	fclose (pwfile);
-	return PAM_AUTHTOK_ERR;
-      }
+    if (fchown(fileno(pwfile), st.st_uid, st.st_gid) == -1) {
+	fclose(opwfile);
+	fclose(pwfile);
+	err = 1;
+	goto done;
+    }
+    if (fchmod(fileno(pwfile), st.st_mode) == -1) {
+	fclose(opwfile);
+	fclose(pwfile);
+	err = 1;
+	goto done;
+    }
 
     while (fgets(buf, 16380, opwfile)) {
 	if (!strncmp(buf, forwho, strlen(forwho))) {
@@ -360,14 +394,27 @@
 	err = 1;
     }
 
+done:
     if (!err) {
-	if (!rename(OPW_TMPFILE, OLD_PASSWORDS_FILE)) {
-	    return PAM_SUCCESS;
-	}
+	if (rename(OPW_TMPFILE, OLD_PASSWORDS_FILE))
+	    err = 1;
     }
-
-    unlink(OPW_TMPFILE);
-    return PAM_AUTHTOK_ERR;
+#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);
+	return PAM_AUTHTOK_ERR;
+    }
 }
 
 static int _update_passwd(pam_handle_t *pamh,
@@ -380,38 +427,59 @@
     int oldmask;
 
     oldmask = umask(077);
+#ifdef WITH_SELINUX
+    if (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);
+    }
+#endif
     pwfile = fopen(PW_TMPFILE, "w");
     umask(oldmask);
     if (pwfile == NULL) {
-	return PAM_AUTHTOK_ERR;
+      err = 1;
+      goto done;
     }
 
     opwfile = fopen("/etc/passwd", "r");
     if (opwfile == NULL) {
 	fclose(pwfile);
-	return PAM_AUTHTOK_ERR;
+	err = 1;
+	goto done;
     }
 
-    if (fstat (fileno (opwfile), &st) == -1)
-      {
-	fclose (opwfile);
-	fclose (pwfile);
-	return PAM_AUTHTOK_ERR;
-      }
+    if (fstat(fileno(opwfile), &st) == -1) {
+	fclose(opwfile);
+	fclose(pwfile);
+	err = 1;
+	goto done;
+    }
 
-    if (fchown (fileno (pwfile), st.st_uid, st.st_gid) == -1)
-      {
-	fclose (opwfile);
-	fclose (pwfile);
-	return PAM_AUTHTOK_ERR;
-      }
-    if (fchmod (fileno (pwfile), st.st_mode) == -1)
-      {
-	fclose (opwfile);
-	fclose (pwfile);
-      }
+    if (fchown(fileno(pwfile), st.st_uid, st.st_gid) == -1) {
+	fclose(opwfile);
+	fclose(pwfile);
+	err = 1;
+	goto done;
+    }
+    if (fchmod(fileno(pwfile), st.st_mode) == -1) {
+	fclose(opwfile);
+	fclose(pwfile);
+	err = 1;
+	goto done;
+    }
 
-    tmpent = fgetpwent (opwfile);
+    tmpent = fgetpwent(opwfile);
     while (tmpent) {
 	if (!strcmp(tmpent->pw_name, forwho)) {
 	    /* To shut gcc up */
@@ -439,15 +507,29 @@
 	err = 1;
     }
 
+done:
     if (!err) {
-	if (!rename(PW_TMPFILE, "/etc/passwd")) {
+	if (!rename(PW_TMPFILE, "/etc/passwd"))
 	    _log_err(LOG_NOTICE, pamh, "password changed for %s", forwho);
-	    return PAM_SUCCESS;
+	else
+	    err = 1;
+    }
+#ifdef WITH_SELINUX
+    if (SELINUX_ENABLED) {
+	if (setfscreatecon(prev_context)) {
+	    err = 1;
 	}
+	if (prev_context)
+	    freecon(prev_context);
+	prev_context = NULL;
     }
-
-    unlink(PW_TMPFILE);
-    return found ? PAM_AUTHTOK_ERR : PAM_USER_UNKNOWN;
+#endif
+    if (!err) {
+	return PAM_SUCCESS;
+    } else {
+	unlink(PW_TMPFILE);
+	return found ? PAM_AUTHTOK_ERR : PAM_USER_UNKNOWN;
+    }
 }
 
 static int _update_shadow(pam_handle_t *pamh, const char *forwho, char *towhat)
@@ -463,37 +545,58 @@
 	return PAM_USER_UNKNOWN;
     }
     oldmask = umask(077);
+
+#ifdef WITH_SELINUX
+    if (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)
-      {
-	fclose (opwfile);
-	fclose (pwfile);
-	return PAM_AUTHTOK_ERR;
-      }
+    if (fstat(fileno(opwfile), &st) == -1) {
+	fclose(opwfile);
+	fclose(pwfile);
+	err = 1;
+	goto done;
+    }
 
-    if (fchown (fileno (pwfile), st.st_uid, st.st_gid) == -1)
-      {
-	fclose (opwfile);
-	fclose (pwfile);
-	return PAM_AUTHTOK_ERR;
-      }
-    if (fchmod (fileno (pwfile), st.st_mode) == -1)
-      {
-	fclose (opwfile);
-	fclose (pwfile);
-	return PAM_AUTHTOK_ERR;
-      }
+    if (fchown(fileno(pwfile), st.st_uid, st.st_gid) == -1) {
+	fclose(opwfile);
+	fclose(pwfile);
+	err = 1;
+	goto done;
+    }
+    if (fchmod(fileno(pwfile), st.st_mode) == -1) {
+	fclose(opwfile);
+	fclose(pwfile);
+	err = 1;
+	goto done;
+    }
 
     stmpent = fgetspent(opwfile);
     while (stmpent) {
@@ -521,15 +624,31 @@
 	err = 1;
     }
 
+done:
     if (!err) {
-	if (!rename(SH_TMPFILE, "/etc/shadow")) {
+	if (!rename(SH_TMPFILE, "/etc/shadow"))
 	    _log_err(LOG_NOTICE, pamh, "password changed for %s", forwho);
-	    return PAM_SUCCESS;
+	else
+	    err = 1;
+    }
+
+#ifdef WITH_SELINUX
+    if (SELINUX_ENABLED) {
+	if (setfscreatecon(prev_context)) {
+	    err = 1;
 	}
+	if (prev_context)
+	    freecon(prev_context);
+	prev_context = NULL;
     }
+#endif
 
-    unlink(SH_TMPFILE);
-    return found ? PAM_AUTHTOK_ERR : PAM_USER_UNKNOWN;
+    if (!err) {
+	return PAM_SUCCESS;
+    } else {
+	unlink(SH_TMPFILE);
+	return found ? PAM_AUTHTOK_ERR : PAM_USER_UNKNOWN;
+    }
 }
 
 static int _do_setpass(pam_handle_t* pamh, const char *forwho, char *fromwhat,
@@ -665,6 +784,8 @@
 		spwdent = getspnam(user);
 		endspent();
 
+		if (spwdent == NULL && SELINUX_ENABLED ) 
+		    spwdent = _unix_run_verify_binary(pamh, ctrl, user);
 		if (spwdent == NULL)
 			return PAM_AUTHINFO_UNAVAIL;
 	} else {
@@ -1088,6 +1209,16 @@
 			}
 		}
 
+		/* A null pointer here indicates a memory failure
+		   somewhere along the way; don't set the password to
+		   NULL! */
+		if (tpass == NULL) {
+			_log_err(LOG_CRIT, pamh,
+			         "out of memory for password");
+			pass_new = pass_old = NULL;	/* tidy up */
+			return PAM_BUF_ERR;
+		}
+
 		D(("password processed"));
 
 		/* update the password database(s) -- race conditions..? */
Index: Linux-PAM/modules/pam_unix/lckpwdf.-c
===================================================================
--- Linux-PAM/modules/pam_unix/lckpwdf.-c	(revision 337)
+++ Linux-PAM/modules/pam_unix/lckpwdf.-c	(working copy)
@@ -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,6 +67,28 @@
 	if (lockfd != -1)
 		return -1;
 
+#ifdef WITH_SELINUX
+	if (is_selinux_enabled() > 0)
+	{
+		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;
Index: Linux-PAM/modules/pam_unix/pam_unix_acct.c
===================================================================
--- Linux-PAM/modules/pam_unix/pam_unix_acct.c	(revision 337)
+++ Linux-PAM/modules/pam_unix/pam_unix_acct.c	(working copy)
@@ -45,6 +45,15 @@
 #include <pwd.h>
 #include <shadow.h>
 #include <time.h>		/* for time() */
+#include <linux/limits.h>
+#include <errno.h>
+#include <sys/wait.h>
+#ifdef WITH_SELINUX
+#include <selinux/selinux.h>
+#define SELINUX_ENABLED is_selinux_enabled() > 0
+#else
+#define SELINUX_ENABLED 0
+#endif
 
 #include <security/_pam_macros.h>
 
@@ -60,7 +69,112 @@
 #endif				/* LINUX_PAM */
 
 #include "support.h"
+struct spwd spwd;
  
+struct spwd *_unix_run_verify_binary(pam_handle_t *pamh, unsigned int ctrl, const char *user)
+{
+  int retval=0, child, fds[2];
+  void (*sighandler)(int) = NULL;
+  D(("running verify_binary"));
+
+  /* create a pipe for the messages */
+  if (pipe(fds) != 0) {
+    D(("could not make pipe"));
+    _log_err(LOG_ERR, pamh, "Could not make pipe %s",strerror(errno));
+    return NULL;
+  }
+  D(("called."));
+  
+  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) {
+    int i=0;
+    struct rlimit rlim;
+    static char *envp[] = { NULL };
+    char *args[] = { NULL, NULL, NULL, NULL };
+
+    close(0); close(1);
+    /* reopen stdin as pipe */
+    close(fds[0]);
+    dup2(fds[1], STDOUT_FILENO);
+    
+    /* XXX - should really tidy up PAM here too */
+    
+    if (getrlimit(RLIMIT_NOFILE,&rlim)==0) {
+      for (i=2; i < rlim.rlim_max; i++) {
+	if (fds[1] != i) {
+	  close(i);
+	}
+      }	
+    }
+    /* exec binary helper */
+    args[0] = x_strdup(CHKPWD_HELPER);
+    args[1] = x_strdup(user);
+    args[2] = x_strdup("verify");
+    
+    execve(CHKPWD_HELPER, args, envp);
+    
+    _log_err(LOG_ERR, pamh, "helper binary execve failed: %s",strerror(errno));
+    /* should not get here: exit with error */
+    close (fds[1]);
+    D(("helper binary is not available"));
+    exit(PAM_AUTHINFO_UNAVAIL);
+  } else { 
+    close(fds[1]);
+    if (child > 0) {
+      char buf[1024];
+      int rc=0;
+      rc=waitpid(child, &retval, 0);  /* wait for helper to complete */
+      if (rc<0) {
+	_log_err(LOG_ERR, pamh, "unix_chkpwd waitpid returned %d: %s", rc, strerror(errno));
+	retval = PAM_AUTH_ERR;
+      } else {
+	retval = WEXITSTATUS(retval);
+	if (retval != PAM_AUTHINFO_UNAVAIL) {
+          rc = _pammodutil_read(fds[0], buf, sizeof(buf) - 1);
+	  if(rc > 0) {
+	      buf[rc] = '\0';
+	      if (sscanf(buf,"%ld:%ld:%ld:%ld:%ld:%ld",
+		     &spwd.sp_lstchg, /* last password change */
+		     &spwd.sp_min, /* days until change allowed. */
+		     &spwd.sp_max, /* days before change required */
+		     &spwd.sp_warn, /* days warning for expiration */
+		     &spwd.sp_inact, /* days before account inactive */
+		     &spwd.sp_expire) /* date when account expires */ != 6 ) retval = PAM_AUTH_ERR;
+	    }		
+	  else {
+	    _log_err(LOG_ERR, pamh, " ERROR %d:%s \n",rc, strerror(errno)); retval = PAM_AUTH_ERR;
+	  }
+	}
+      }
+    } else {
+      _log_err(LOG_ERR, pamh, "Fork failed %s \n",strerror(errno));
+      D(("fork failed"));
+      retval = PAM_AUTH_ERR;
+    }
+    close(fds[0]);
+  }
+  if (sighandler != NULL) {
+    (void) signal(SIGCHLD, sighandler);   /* restore old signal handler */
+  }
+  D(("Returning %d",retval));
+  if (retval != PAM_SUCCESS) {
+    return NULL;
+  } 
+  return &spwd;
+}	
 /*
  * PAM framework looks for this entry-point to pass control to the
  * account management module.
@@ -128,6 +242,9 @@
 	else
 		return PAM_SUCCESS;
 
+	if (!spent && SELINUX_ENABLED ) 
+	    spent = _unix_run_verify_binary(pamh, ctrl, uname);
+
 	if (!spent)
 		if (on(UNIX_BROKEN_SHADOW,ctrl))
 			return PAM_SUCCESS;
Index: Linux-PAM/modules/pam_unix/support.c
===================================================================
--- Linux-PAM/modules/pam_unix/support.c	(revision 337)
+++ Linux-PAM/modules/pam_unix/support.c	(working copy)
@@ -15,6 +15,7 @@
 #include <pwd.h>
 #include <shadow.h>
 #include <limits.h>
+#include <linux/limits.h>
 #include <utmp.h>
 #include <errno.h>
 #include <signal.h>
@@ -27,7 +28,12 @@
 
 #include "md5.h"
 #include "support.h"
-
+#ifdef WITH_SELINUX
+#include <selinux/selinux.h>
+#define SELINUX_ENABLED is_selinux_enabled()>0
+#else
+#define SELINUX_ENABLED 0
+#endif
 extern char *crypt(const char *key, const char *salt);
 extern char *bigcrypt(const char *key, const char *salt);
 
@@ -591,18 +597,32 @@
     /* fork */
     child = fork();
     if (child == 0) {
+        int i=0;
+        struct rlimit rlim;
 	static char *envp[] = { NULL };
-	char *args[] = { NULL, NULL, NULL };
+	char *args[] = { NULL, NULL, NULL, NULL };
 
 	/* XXX - should really tidy up PAM here too */
 
+	close(0); close(1);
 	/* reopen stdin as pipe */
 	close(fds[1]);
 	dup2(fds[0], STDIN_FILENO);
 
+	if (getrlimit(RLIMIT_NOFILE,&rlim)==0) {
+	  for (i=2; i < rlim.rlim_max; i++) {
+		if (fds[0] != i)
+	  	   close(i);
+	  }	
+	}
 	/* exec binary helper */
 	args[0] = x_strdup(CHKPWD_HELPER);
 	args[1] = x_strdup(user);
+	if (off(UNIX__NONULL, ctrl)) {
+	    args[2] = x_strdup("nullok");
+	} else {
+	    args[2] = x_strdup("nonull");
+	}
 
 	execve(CHKPWD_HELPER, args, envp);
 
@@ -612,23 +632,25 @@
     } else if (child > 0) {
 	/* wait for child */
 	/* if the stored password is NULL */
-	if (off(UNIX__NONULL, ctrl)) {	/* this means we've succeeded */
-	    write(fds[1], "nullok\0\0", 8);
+        int rc=0;
+	if (passwd)
+	    _pammodutil_write(fds[1], passwd, strlen(passwd)+1);
+	else
+	    _pammodutil_write(fds[1], "", 1);	/* blank password */
+
+	close(fds[0]);       /* close here to avoid possible SIGPIPE above */
+	close(fds[1]);
+	rc=waitpid(child, &retval, 0);  /* wait for helper to complete */
+	if (rc<0) {
+	  _log_err(LOG_ERR, pamh, "unix_chkpwd waitpid returned %d: %s", rc, strerror(errno));
+	  retval = PAM_AUTH_ERR;
 	} else {
-	    write(fds[1], "nonull\0\0", 8);
+	  retval = WEXITSTATUS(retval);
 	}
-	if (passwd != NULL) {            /* send the password to the child */
-	    write(fds[1], passwd, strlen(passwd)+1);
-	    passwd = NULL;
-	} else {
-	    write(fds[1], "", 1);                        /* blank password */
-	}
-	close(fds[0]);       /* close here to avoid possible SIGPIPE above */
-	close(fds[1]);
-	(void) waitpid(child, &retval, 0);  /* wait for helper to complete */
-	retval = (retval == 0) ? PAM_SUCCESS:PAM_AUTH_ERR;
     } else {
 	D(("fork failed"));
+	close(fds[0]);
+ 	close(fds[1]);
 	retval = PAM_AUTH_ERR;
     }
 
@@ -650,6 +672,7 @@
 	char *data_name;
 	int retval;
 
+
 	D(("called"));
 
 #ifdef HAVE_PAM_FAIL_DELAY
@@ -716,7 +739,8 @@
 
 	retval = PAM_SUCCESS;
 	if (pwd == NULL || salt == NULL || !strcmp(salt, "x") || ((salt[0] == '#') && (salt[1] == '#') && !strcmp(salt + 2, name))) {
-		if (geteuid()) {
+	  
+		if (geteuid() || SELINUX_ENABLED) {
 			/* we are not root perhaps this is the reason? Run helper */
 			D(("running helper binary"));
 			retval = _unix_run_helper_binary(pamh, p, ctrl, name);
Index: Linux-PAM/modules/pam_unix/support.h
===================================================================
--- Linux-PAM/modules/pam_unix/support.h	(revision 337)
+++ Linux-PAM/modules/pam_unix/support.h	(working copy)
@@ -165,4 +165,5 @@
 extern unsigned int pass_min_len;
 extern unsigned int pass_max_len;
 
+extern struct spwd *_unix_run_verify_binary(pam_handle_t *pamh, unsigned int ctrl, const char *user);
 #endif /* _PAM_UNIX_SUPPORT_H */
Index: Linux-PAM/modules/pam_unix/unix_chkpwd.c
===================================================================
--- Linux-PAM/modules/pam_unix/unix_chkpwd.c	(revision 337)
+++ Linux-PAM/modules/pam_unix/unix_chkpwd.c	(working copy)
@@ -28,12 +28,25 @@
 #include <syslog.h>
 #include <unistd.h>
 #include <sys/types.h>
+#include <sys/stat.h>
 #include <pwd.h>
 #include <shadow.h>
 #include <signal.h>
+#include <time.h>
 
+static int selinux_enabled = -1;
+
+#ifdef WITH_SELINUX
+#include <selinux/selinux.h>
+#define SELINUX_ENABLED (selinux_enabled != -1 ? selinux_enabled : (selinux_enabled = is_selinux_enabled() > 0))
+static security_context_t prev_context=NULL;
+#else
+#define SELINUX_ENABLED 0
+#endif
+
 #define MAXPASS		200	/* the maximum length of a password */
 
+#include <security/_pam_types.h>
 #include <security/_pam_macros.h>
 
 #include "md5.h"
@@ -41,9 +54,6 @@
 extern char *crypt(const char *key, const char *salt);
 extern char *bigcrypt(const char *key, const char *salt);
 
-#define UNIX_PASSED	0
-#define UNIX_FAILED	1
-
 /* syslogging function for errors and other information */
 
 static void _log_err(int err, const char *format,...)
@@ -112,13 +122,40 @@
 	(void) sigaction(SIGQUIT, &action, NULL);
 }
 
+static int _verify_account(const char * const uname)
+{
+	struct spwd *spent;
+	struct passwd *pwent;
+
+	pwent = getpwnam(uname);
+	if (!pwent) {
+		_log_err(LOG_ALERT, "could not identify user (from getpwnam(%s))", uname);
+		return PAM_USER_UNKNOWN;
+	}
+
+	spent = getspnam( uname );
+	if (!spent) {
+		_log_err(LOG_ALERT, "could not get username from shadow (%s))", uname);
+		return PAM_AUTHINFO_UNAVAIL;	/* Couldn't get username from shadow */
+	}
+	printf("%ld:%ld:%ld:%ld:%ld:%ld",
+		 spent->sp_lstchg, /* last password change */
+                 spent->sp_min, /* days until change allowed. */
+                 spent->sp_max, /* days before change required */
+                 spent->sp_warn, /* days warning for expiration */
+                 spent->sp_inact, /* days before account inactive */
+                 spent->sp_expire); /* date when account expires */
+              
+	return PAM_SUCCESS;
+}
+
 static int _unix_verify_password(const char *name, const char *p, int nullok)
 {
 	struct passwd *pwd = NULL;
 	struct spwd *spwdent = NULL;
 	char *salt = NULL;
 	char *pp = NULL;
-	int retval = UNIX_FAILED;
+	int retval = PAM_AUTH_ERR;
 	int salt_len;
 
 	/* UNIX passwords area */
@@ -156,14 +193,14 @@
 	if (pwd == NULL || salt == NULL) {
 		_log_err(LOG_WARNING, "check pass; user unknown");
 		p = NULL;
-		return retval;
+		return PAM_USER_UNKNOWN;
 	}
 
 	salt_len = strlen(salt);
 	if (salt_len == 0)
-		return (nullok == 0) ? UNIX_FAILED : UNIX_PASSED;
+		return (nullok == 0) ? PAM_AUTH_ERR : PAM_SUCCESS;
 	else if (p == NULL || strlen(p) == 0)
-		return UNIX_FAILED;
+		return PAM_AUTHTOK_ERR;
 
 	/* Hack off SysVR4 password aging */
 	{
@@ -173,18 +210,18 @@
 	}
 
 	/* the moment of truth -- do we agree with the password? */
-	retval = UNIX_FAILED;
+	retval = PAM_AUTH_ERR;
 	if (!strncmp(salt, "$1$", 3)) {
 		pp = Goodcrypt_md5(p, salt);
 		if (strcmp(pp, salt) == 0) {
-			retval = UNIX_PASSED;
+			retval = PAM_SUCCESS;
 		} else {
 			pp = Brokencrypt_md5(p, salt);
 			if (strcmp(pp, salt) == 0)
-				retval = UNIX_PASSED;
+				retval = PAM_SUCCESS;
 		}
 	} else if ((*salt == '*') || (salt_len < 13)) {
-	    retval = UNIX_FAILED;
+	    retval = PAM_AUTH_ERR;
 	} else {
 		pp = bigcrypt(p, salt);
 		/*
@@ -197,7 +234,7 @@
 		 * Bug 521314: the strncmp comparison is for legacy support.
 		 */
 		if (strncmp(pp, salt, salt_len) == 0) {
-			retval = UNIX_PASSED;
+			retval = PAM_SUCCESS;
 		}
 	}
 	p = NULL;		/* no longer needed here */
@@ -234,10 +271,10 @@
 int main(int argc, char *argv[])
 {
 	char pass[MAXPASS + 1];
-	char option[8];
+	char *option;
 	int npass, nullok;
 	int force_failure = 0;
-	int retval = UNIX_FAILED;
+	int retval = PAM_AUTH_ERR;
 	char *user;
 
 	/*
@@ -254,8 +291,7 @@
 	 * account).
 	 */
 
-	if (isatty(STDIN_FILENO)) {
-
+	if (isatty(STDIN_FILENO) || argc != 3 ) {
 		_log_err(LOG_NOTICE
 		      ,"inappropriate use of Unix helper binary [UID=%d]"
 			 ,getuid());
@@ -263,36 +299,37 @@
 		 ,"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;
+		return PAM_SYSTEM_ERR;
 	}
 
 	/*
-	 * determine the current user's name is
+	 * Determine the current user's name.
+	 * On a SELinux enabled system, policy will prevent third
+	 * parties from using unix_chkpwd as a password guesser.
+	 * Leaving the existing check prevents su from working, since
+	 * the current uid is the user's and the password is for root.
 	 */
-	user = getuidname(getuid());
-	if (argc == 2) {
-	    /* if the caller specifies the username, verify that user
-	       matches it */
+	if (SELINUX_ENABLED) {
+	    user = argv[1];
+	} else {
+	    user = getuidname(getuid());
 	    if (strcmp(user, argv[1])) {
-		force_failure = 1;
+		return PAM_AUTH_ERR;
 	    }
 	}
 
-	/* read the nullok/nonull option */
+	option = argv[2];
 
-	npass = read(STDIN_FILENO, option, 8);
-
-	if (npass < 0 || option == NULL || option[0] == '\0') {
-		_log_err(LOG_DEBUG, "no option supplied");
-		return UNIX_FAILED;
-	} else {
-		option[7] = '\0';
-		if (strncmp(option, "nullok", 8) == 0)
-			nullok = 1;
-		else
-			nullok = 0;
+	if (strncmp(argv[2], "verify", 8) == 0) {
+	    /* Get the account information from the shadow file */
+	    return _verify_account(argv[1]);
 	}
 
+	if (strncmp(option, "nullok", 8) == 0)
+	    nullok = 1;
+	else
+	    nullok = 0;
+
 	/* read the password from stdin (a pipe from the pam_unix module) */
 
 	npass = read(STDIN_FILENO, pass, MAXPASS);
@@ -324,10 +361,10 @@
 
 	/* return pass or fail */
 
-	if ((retval != UNIX_PASSED) || force_failure) {
-	    return UNIX_FAILED;
+	if ((retval != PAM_SUCCESS) || force_failure) {
+	    return PAM_AUTH_ERR;
 	} else {
-	    return UNIX_PASSED;
+	    return PAM_SUCCESS;
 	}
 }
 
Index: Linux-PAM/modules/pam_unix/Makefile
===================================================================
--- Linux-PAM/modules/pam_unix/Makefile	(revision 337)
+++ Linux-PAM/modules/pam_unix/Makefile	(working copy)
@@ -60,9 +60,9 @@
 ########################################################################
 
 CFLAGS += $(USE_CRACKLIB) $(USE_LCKPWDF) $(NEED_LCKPWDF) $(EXTRAS) \
-	 $(INCLUDE_PAMMODUTILS)
+	 $(INCLUDE_PAMMODUTILS) -DWITH_SELINUX
 
-LDLIBS = $(EXTRALS) $(LINK_PAMMODUTILS)
+LDLIBS = $(EXTRALS) $(LINK_PAMMODUTILS) -lselinux
 
 ifdef USE_CRACKLIB
 CRACKLIB = -lcrack
Index: Linux-PAM/modules/pam_rootok/pam_rootok.c
===================================================================
--- Linux-PAM/modules/pam_rootok/pam_rootok.c	(revision 337)
+++ Linux-PAM/modules/pam_rootok/pam_rootok.c	(working copy)
@@ -39,6 +39,11 @@
 }
 
 
+#ifdef WITH_SELINUX
+#include <selinux/selinux.h>
+#include <selinux/av_permissions.h>
+#endif
+
 /* argument parsing */
 
 #define PAM_DEBUG_ARG       01
@@ -72,7 +77,10 @@
     int retval = PAM_AUTH_ERR;
 
     ctrl = _pam_parse(argc, argv);
-    if (getuid() == 0)
+    if (getuid() == 0) 
+#ifdef WITH_SELINUX
+      if (is_selinux_enabled()<1 || selinux_check_passwd_access(PASSWD__ROOTOK)==0)
+#endif
 	retval = PAM_SUCCESS;
 
     if (ctrl & PAM_DEBUG_ARG) {
Index: Linux-PAM/modules/pam_rootok/Makefile
===================================================================
--- Linux-PAM/modules/pam_rootok/Makefile	(revision 337)
+++ Linux-PAM/modules/pam_rootok/Makefile	(working copy)
@@ -13,3 +13,6 @@
 TITLE=pam_rootok
 
 include ../Simple.Rules
+
+CFLAGS += -DWITH_SELINUX
+LINK_PAMMODUTILS += -lselinux 
Index: Linux-PAM/modules/pam_selinux/pam_selinux_check.c
===================================================================
--- Linux-PAM/modules/pam_selinux/pam_selinux_check.c	(revision 0)
+++ Linux-PAM/modules/pam_selinux/pam_selinux_check.c	(revision 0)
@@ -0,0 +1,43 @@
+/******************************************************************************
+ * A module for Linux-PAM that will set the default security context after login 
+ * via PAM.
+ *
+ * Copyright (c) 2003 Red Hat, Inc.
+ * Written by Dan Walsh <dwalsh@redhat.com>
+ *
+ * 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.
+ *
+ */
+
+#define PAM_SELINUX_MAIN 1
+#include "pam_selinux.c"
+
Index: Linux-PAM/modules/pam_selinux/pam_selinux.c
===================================================================
--- Linux-PAM/modules/pam_selinux/pam_selinux.c	(revision 0)
+++ Linux-PAM/modules/pam_selinux/pam_selinux.c	(revision 0)
@@ -0,0 +1,644 @@
+/******************************************************************************
+ * A module for Linux-PAM that will set the default security context after login 
+ * via PAM.
+ *
+ * Copyright (c) 2003 Red Hat, Inc.
+ * Written by Dan Walsh <dwalsh@redhat.com>
+ *
+ * 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.
+ *
+ */
+
+#define PAM_SM_AUTH
+#define PAM_SM_SESSION
+
+#include "../../_pam_aconf.h"
+
+#include <errno.h>
+#include <limits.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <linux/limits.h>
+
+#include "../../_pam_aconf.h"
+#include <security/pam_modules.h>
+#include <security/_pam_macros.h>
+#include <security/_pam_modutil.h>
+
+#include <libintl.h>
+#define _(x) gettext(x)
+
+#ifndef PAM_SELINUX_MAIN
+#define MODULE "pam_selinux"
+
+#include <selinux/selinux.h>
+#include <selinux/get_context_list.h>
+#include <selinux/flask.h>
+#include <selinux/selinux.h>
+#include <selinux/context.h>
+
+static int send_text(  struct pam_conv *conv, const char *text, int debug) {
+  struct pam_message message;
+  const struct pam_message *messages[] = {&message};
+  struct pam_response *responses;
+  int retval;
+
+  memset(&message, 0, sizeof(message));
+  message.msg_style = PAM_TEXT_INFO;
+  message.msg = text;
+  if (debug)
+    syslog(LOG_NOTICE, MODULE ": %s", message.msg);
+  retval = conv->conv(1, messages, &responses, conv->appdata_ptr);
+  if (responses)
+    _pam_drop_reply(responses, 1);
+  return retval;
+}
+
+/*
+ * This function sends a message to the user and gets the response. The caller 
+ * is responsible for freeing the responses.
+ */
+static int query_response(  struct pam_conv *conv, const char *text,
+                            struct pam_response **responses, int debug) {
+  struct pam_message message;
+  const struct pam_message *messages[] = {&message};
+
+  memset(&message, 0, sizeof(message));
+  message.msg_style = PAM_PROMPT_ECHO_ON;
+  message.msg = text;
+
+  if (debug)
+    syslog(LOG_NOTICE, MODULE ": %s", message.msg);
+
+  return conv->conv(1, messages, responses, conv->appdata_ptr);
+}
+
+static const security_context_t 
+select_context( pam_handle_t *pamh, security_context_t* contextlist,int debug)
+{
+  struct pam_conv *conv;
+
+  if (pam_get_item(pamh, PAM_CONV, (const void**) &conv) == PAM_SUCCESS && 
+	conv) {
+    if (conv->conv != NULL) {
+      struct pam_response *responses;
+      char *text=calloc(PATH_MAX,1);
+
+      if (text == NULL)
+	return (security_context_t) strdup(contextlist[0]);
+
+      snprintf(text, PATH_MAX,
+	       _("Your default context is %s. \n"), contextlist[0]);
+      send_text(conv,text,debug);
+      free(text);
+      query_response(conv,_("Do you want to choose a different one? [n]"), 
+		&responses,debug);
+      if (responses && (responses[0].resp[0] == 'y') || 
+                       (responses[0].resp[0] == 'Y'))
+      {
+	  int choice=0;
+	  int i;
+	  char *prompt=_("Enter number of choice: ");
+	  int len=strlen(prompt);
+	  char buf[PATH_MAX];
+
+	  _pam_drop_reply(responses, 1);
+	  for (i = 0; contextlist[i]; i++) {
+	    len+=strlen(contextlist[i]) + 10; 
+	  }
+	  text=calloc(len,1);
+	  for (i = 0; contextlist[i]; i++) {
+	    snprintf(buf, PATH_MAX,
+		     "[%d] %s\n", i+1, contextlist[i]);
+	    strncat(text,buf,len);
+	  }
+	  strcat(text,prompt);
+	  while ((choice < 1) || (choice > i)) {
+	    query_response(conv,text,&responses,debug);
+	    choice = strtol (responses[0].resp, NULL, 10);
+            _pam_drop_reply(responses, 1);
+	  }
+	  free(text);
+	  return (security_context_t) strdup(contextlist[choice-1]);  
+      }
+      else if (responses)
+        _pam_drop_reply(responses, 1);
+    } else {
+      if (debug)
+	syslog(LOG_NOTICE, _("%s: bogus conversation function"),MODULE);
+    }
+  } else {
+    if (debug)
+      syslog(LOG_NOTICE, _("%s: no conversation function"),MODULE);
+  }
+  return (security_context_t) strdup(contextlist[0]);  
+}
+
+static const security_context_t 
+manual_context( pam_handle_t *pamh, char *user, int debug)
+{
+  struct pam_conv *conv;
+  security_context_t newcon;
+  context_t new_context;
+  int mls_enabled = is_selinux_mls_enabled();
+
+  if (pam_get_item(pamh, PAM_CONV, (const void**) &conv) == PAM_SUCCESS) {
+    if (conv && conv->conv != NULL) {
+      struct pam_response *responses;
+
+      while (1) {
+	query_response(conv,
+                       _("Would you like to enter a security context? [y] "),
+                       &responses,debug);
+	if ((responses[0].resp[0] == 'y') || (responses[0].resp[0] == 'Y') || 
+            (responses[0].resp[0] == '\0') )
+	{
+ 	  if (mls_enabled)
+ 	    new_context = context_new ("user:role:type:level");
+ 	  else
+ 	    new_context = context_new ("user:role:type");
+          _pam_drop_reply(responses, 1);
+
+	  /* Allow the user to enter each field of the context individually */
+	  if (context_user_set (new_context, user))
+	  {
+	      context_free (new_context);
+	      return NULL;
+	  }
+	  query_response(conv,_("role: "),&responses,debug);
+	  if (context_role_set (new_context, responses[0].resp))
+	  {
+              _pam_drop_reply(responses, 1);
+	      context_free (new_context);
+	      return NULL;
+	  }
+          _pam_drop_reply(responses, 1);
+	  query_response(conv,_("type: "),&responses,debug);
+	  if (context_type_set (new_context, responses[0].resp))
+	  {
+              _pam_drop_reply(responses, 1);
+	      context_free (new_context);
+	      return NULL;
+	  }
+          _pam_drop_reply(responses, 1);
+ 	  if (mls_enabled)
+ 	    {
+ 	      query_response(conv,_("level: "),&responses,debug);
+ 	      if (context_range_set (new_context, responses[0].resp))
+ 	        {
+ 	          context_free (new_context);
+ 	          return NULL;
+ 	        }
+ 	    }
+	  /* Get the string value of the context and see if it is valid. */
+	  if (!security_check_context(context_str(new_context))) {
+	    newcon = strdup(context_str(new_context));
+	    context_free (new_context);
+	    return newcon;
+	  }
+	  else 
+	    send_text(conv,_("Not a valid security context"),debug);
+	}
+	else {
+          _pam_drop_reply(responses, 1);
+	  return NULL;
+	}
+      } /* end while */
+    } else {
+      if (debug)
+	syslog(LOG_NOTICE, _("%s: bogus conversation function"),MODULE);
+    }
+  } else {
+    if (debug)
+      syslog(LOG_NOTICE, _("%s: no conversation function"),MODULE);
+  }
+  return NULL;
+}
+
+static void security_restorelabel_tty(const char *tty, 
+                                      security_context_t context) {
+  char ttybuf[PATH_MAX];
+  const char *ptr;
+
+  if (context==NULL)
+    return;
+  
+  if(strncmp("/dev/", tty, 5)) {
+    snprintf(ttybuf,sizeof(ttybuf),"/dev/%s",tty);
+    ptr = ttybuf;
+  }
+  else
+    ptr = tty;
+
+  if (setfilecon(ptr, context) && errno != ENOENT) 
+  {
+      syslog(LOG_NOTICE, 
+             _("Warning!  Could not relabel %s with %s, not relabeling.\n"), 
+             ptr, context);
+  }
+}
+
+static security_context_t security_label_tty(char *tty, 
+                                             security_context_t usercon) {
+  char ttybuf[PATH_MAX];
+  int status=0;
+  security_context_t newdev_context=NULL; /* The new context of a device */
+  security_context_t prev_context=NULL; /* The new context of a device */
+  const char *ptr;
+
+  if(strncmp("/dev/", tty, 5))
+  {
+    snprintf(ttybuf,sizeof(ttybuf),"/dev/%s",tty);
+    ptr = ttybuf;
+  }
+  else
+    ptr = tty;
+
+  if (getfilecon(ptr, &prev_context) < 0) 
+  {
+      syslog(LOG_NOTICE, 
+           _("Warning!  Could not get current context for %s, not relabeling."),           ptr);
+      return NULL;
+  }	
+  if( security_compute_relabel(usercon,prev_context,SECCLASS_CHR_FILE,
+                               &newdev_context)!=0) 
+  {
+    syslog(LOG_NOTICE, 
+           _("Warning!  Could not get new context for %s, not relabeling."), 
+           ptr);
+    syslog(LOG_NOTICE, "usercon=%s, prev_context=%s\n", usercon, prev_context);
+    freecon(prev_context);
+    return NULL;
+  }
+  status=setfilecon(ptr,newdev_context);
+  if (status)
+  {
+      syslog(LOG_NOTICE, 
+             _("Warning!  Could not relabel %s with %s, not relabeling.%s"), 
+             ptr,newdev_context,strerror(errno));
+      freecon(prev_context);
+      prev_context=NULL;
+  } 
+  freecon(newdev_context);
+  return prev_context;
+}
+
+static security_context_t user_context=NULL;
+static security_context_t prev_user_context=NULL;
+static security_context_t ttyn_context=NULL;  /* The current context of ttyn device */
+static int selinux_enabled=0;
+static char *ttyn=NULL;
+
+/* Tell the user that access has been granted. */
+static void
+verbose_message(pam_handle_t *pamh, char *msg, int debug)
+{
+  struct pam_conv *conv;
+  struct pam_message message;
+  const struct pam_message *messages[] = {&message};
+  struct pam_response *responses;
+  if (pam_get_item(pamh, PAM_CONV, (const void**) &conv) == PAM_SUCCESS) {
+    if (conv && conv->conv != NULL) {
+      char text[PATH_MAX];
+
+      memset(&message, 0, sizeof(message));
+      message.msg_style = PAM_TEXT_INFO;
+      snprintf(text, sizeof(text), msg);
+
+      message.msg = text;
+      if (debug)
+	syslog(LOG_NOTICE, MODULE ": %s", message.msg);
+      conv->conv(1, messages, &responses, conv->appdata_ptr);
+      if (responses)
+        _pam_drop_reply(responses, 1);
+    } else {
+      if (debug)
+	syslog(LOG_NOTICE, _("%s: bogus conversation function"),MODULE);
+    }
+  } else {
+    if (debug)
+      syslog(LOG_NOTICE,_("%s: no conversation function"),MODULE);
+  }
+}
+
+PAM_EXTERN int
+pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
+{
+	/* Fail by default. */
+	return PAM_AUTH_ERR;
+}
+
+PAM_EXTERN int
+pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)
+{
+	return PAM_SUCCESS;
+}
+
+PAM_EXTERN int
+pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
+{
+  int i, debug = 0, ttys=1, has_tty=isatty(0), verbose=0, multiple=0, close_session=0;
+  int ret=0;
+  security_context_t* contextlist=NULL;
+  int num_contexts = 0;
+  char *username=NULL;
+  const char *tty=NULL;
+
+  /* Parse arguments. */
+  for (i = 0; i < argc; i++) {
+    if (strcmp(argv[i], "debug") == 0) {
+      debug = 1;
+    }
+    if (strcmp(argv[i], "nottys") == 0) {
+      ttys = 0;
+    }
+    if (strcmp(argv[i], "verbose") == 0) {
+      verbose = 1;
+    }
+    if (strcmp(argv[i], "multiple") == 0) {
+      multiple = 1;
+    }
+    if (strcmp(argv[i], "close") == 0) {
+      close_session = 1;
+    }
+  }
+
+  if (debug) 
+    syslog(LOG_NOTICE, MODULE ": %s", "Open Session");
+
+  /* this module is only supposed to execute close_session */
+  if (close_session)
+      return PAM_SUCCESS;
+
+  if (!(selinux_enabled = is_selinux_enabled()>0) )
+      return PAM_SUCCESS;
+
+  if (pam_get_item(pamh, PAM_USER, (const void**)&username) != PAM_SUCCESS ||
+                   username == NULL) {
+    return PAM_AUTH_ERR;
+  }
+  num_contexts = get_ordered_context_list(username, 0, &contextlist);
+  if (num_contexts > 0) {
+    if (multiple && (num_contexts > 1) && has_tty) {
+      user_context = select_context(pamh,contextlist, debug);
+      freeconary(contextlist);
+    } else {
+      user_context = (security_context_t) strdup(contextlist[0]);
+      freeconary(contextlist);
+    }
+  } else {
+    if (has_tty) {
+      user_context = manual_context(pamh,username,debug);
+      if (user_context == NULL) {
+	syslog (LOG_ERR, _("Unable to get valid context for %s"), username);
+	return PAM_AUTH_ERR;
+      }
+    } else {
+	syslog (LOG_ERR, _("Unable to get valid context for %s, No valid tty"), username);
+	return PAM_AUTH_ERR;
+    }
+  }
+  if (getexeccon(&prev_user_context)<0) {
+    prev_user_context=NULL;
+  }
+  if (ttys) {
+    /* Get the name of the terminal. */
+    if (pam_get_item(pamh, PAM_TTY, (const void**)&tty) != PAM_SUCCESS) {
+      tty = NULL;
+    }
+    
+    if ((tty == NULL) || (strlen(tty) == 0) || 
+	strcmp(tty, "ssh") == 0 || strncmp(tty, "NODEV", 5) == 0) {
+      tty = ttyname(STDIN_FILENO);
+      if ((tty == NULL) || (strlen(tty) == 0)) {
+	tty = ttyname(STDOUT_FILENO);
+      }
+      if ((tty == NULL) || (strlen(tty) == 0)) {
+	tty = ttyname(STDERR_FILENO);
+      }
+    }
+  }
+  if(ttys && tty ) {
+    ttyn=strdup(tty);
+    ttyn_context=security_label_tty(ttyn,user_context);
+  }
+  ret = setexeccon(user_context);
+  if (ret==0 && verbose) {
+    char msg[PATH_MAX];
+    snprintf(msg, sizeof(msg), 
+	     _("Security Context %s Assigned"), user_context);
+    verbose_message(pamh, msg, debug);
+  }
+  if (ret) {
+    syslog(LOG_ERR, _("Error!  Unable to set %s executable context %s."),
+           username, user_context);
+    freecon(user_context);
+    return PAM_AUTH_ERR;
+  } else {
+    if (debug)
+      syslog(LOG_NOTICE, _("%s: set %s security context to %s"),MODULE, 
+             username, user_context);
+  }
+  freecon(user_context);
+
+  return PAM_SUCCESS;
+}
+
+PAM_EXTERN int
+pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
+{
+  int i, debug = 0,status=0, open_session=0;
+  if (! (selinux_enabled ))
+      return PAM_SUCCESS;
+    
+  /* Parse arguments. */
+  for (i = 0; i < argc; i++) {
+    if (strcmp(argv[i], "debug") == 0) {
+      debug = 1;
+    }
+    if (strcmp(argv[i], "open") == 0) {
+      open_session = 1;
+    }
+  }
+
+  if (debug)
+    syslog(LOG_NOTICE, MODULE ": %s", "Close Session");
+
+  if (open_session)
+    return PAM_SUCCESS;
+
+  if (ttyn) {
+    if (debug)
+      syslog(LOG_NOTICE, MODULE ":Restore tty  %s -> %s", ttyn,ttyn_context);
+
+    security_restorelabel_tty(ttyn,ttyn_context);
+    freecon(ttyn_context);
+    free(ttyn);
+    ttyn=NULL;
+  }
+  status=setexeccon(prev_user_context);
+  freecon(prev_user_context);
+  if (status) {
+    syslog(LOG_ERR, _("Error!  Unable to set executable context %s."), 
+           prev_user_context);
+    return PAM_AUTH_ERR;
+  }
+
+  if (debug)
+    syslog(LOG_NOTICE, _("%s: setcontext back to orginal"),MODULE);
+
+  return PAM_SUCCESS;
+}
+
+#else /* PAM_SELINUX_MAIN */
+
+/************************************************************************
+ *
+ * All PAM code goes in this section.
+ *
+ ************************************************************************/
+
+#include <unistd.h>               /* for getuid(), exit(), getopt() */
+#include <signal.h>
+#include <sys/wait.h>		  /* for wait() */
+
+#include <security/pam_appl.h>    /* for PAM functions */
+#include <security/pam_misc.h>    /* for misc_conv PAM utility function */
+
+#define SERVICE_NAME "pam_selinux_check"   /* the name of this program for PAM */
+				  /* The file containing the context to run 
+				   * the scripts under.                     */
+int authenticate_via_pam( const char *user ,   pam_handle_t **pamh);
+
+/* authenticate_via_pam()
+ *
+ * in:     user
+ * out:    nothing
+ * return: value   condition
+ *         -----   ---------
+ *           1     pam thinks that the user authenticated themselves properly
+ *           0     otherwise
+ *
+ * this function uses pam to authenticate the user running this
+ * program.  this is the only function in this program that makes pam
+ * calls.
+ *
+ */
+
+int authenticate_via_pam( const char *user ,   pam_handle_t **pamh) {
+
+  struct pam_conv *conv;
+  int result = 0;    /* our result, set to 0 (not authenticated) by default */
+
+  /* this is a jump table of functions for pam to use when it wants to *
+   * communicate with the user.  we'll be using misc_conv(), which is  *
+   * provided for us via pam_misc.h.                                   */
+  struct pam_conv pam_conversation = {
+    misc_conv,
+    NULL
+  };
+  conv = &pam_conversation;
+
+
+  /* make `p_pam_handle' a valid pam handle so we can use it when *
+   * calling pam functions.                                       */
+  if( PAM_SUCCESS != pam_start( SERVICE_NAME,
+				user,
+				conv,
+				pamh ) ) {
+    fprintf( stderr, _("failed to initialize PAM\n") );
+    exit( -1 );
+  }
+
+  if( PAM_SUCCESS != pam_set_item(*pamh, PAM_RUSER, user))
+  {
+      fprintf( stderr, _("failed to pam_set_item()\n") );
+      exit( -1 );
+  }
+
+  /* Ask PAM to authenticate the user running this program */
+  if( PAM_SUCCESS == pam_authenticate(*pamh,0) ) {
+    if ( PAM_SUCCESS == pam_open_session(*pamh, 0) )
+      result = 1;  /* user authenticated OK! */
+  }
+  return( result );
+
+} /* authenticate_via_pam() */
+
+int main(int argc, char **argv) {
+  pam_handle_t *pamh;
+  int childPid;
+
+  if (!authenticate_via_pam(argv[1],&pamh))
+    exit(-1);
+
+  childPid = fork();
+  if (childPid < 0) {
+    int errsv = errno;
+
+    /* error in fork() */
+    fprintf(stderr, _("login: failure forking: %s"), strerror(errsv));
+    pam_close_session(pamh, 0);
+    /* We're done with PAM.  Free `pam_handle'. */
+    pam_end( pamh, PAM_SUCCESS );
+    exit(0);
+  }
+  if (childPid) {
+    close(0); close(1); close(2); 
+    struct sigaction sa;
+    memset(&sa,0,sizeof(sa));
+    sa.sa_handler = SIG_IGN;
+    sigaction(SIGQUIT, &sa, NULL);
+    sigaction(SIGINT, &sa, NULL);
+    while(wait(NULL) == -1 && errno == EINTR) /**/ ;
+    openlog("login", LOG_ODELAY, LOG_AUTHPRIV);
+    pam_close_session(pamh, 0);
+    /* We're done with PAM.  Free `pam_handle'. */
+    pam_end( pamh, PAM_SUCCESS );
+    exit(0);
+  }
+  argv[0]="/bin/sh";
+  argv[1]=NULL;
+
+  /* NOTE: The environment has not been sanitized. LD_PRELOAD and other fun 
+   * things could be set. */
+  execv("/bin/sh",argv);
+  fprintf(stderr,"Failure\n");
+  return 0;
+}
+#endif
Index: Linux-PAM/modules/pam_selinux/pam_selinux_check.8
===================================================================
--- Linux-PAM/modules/pam_selinux/pam_selinux_check.8	(revision 0)
+++ Linux-PAM/modules/pam_selinux/pam_selinux_check.8	(revision 0)
@@ -0,0 +1,35 @@
+.TH pam_selinux_check 8 2002/05/23 "Red Hat Linux" "System Administrator's Manual"
+.SH NAME
+pam_selinux_check \- login program to test pam_selinux_check
+.SH SYNOPSIS
+.B pam_selinux_check [user]
+.br
+
+.SH DESCRIPTION
+With no arguments,
+.B pam_selinux_check
+will prompt for user
+
+.SH OPTIONS
+.IP target_user
+The user to login as.
+
+.SH DIAGNOSTICS
+You must setup a /etc/pam.d/pam_selinux_check file, in order for the check to work.
+
+When checking if a selinux is valid,
+.B pam_selinux_check
+returns an exit code of 0 for success and > 0 on error:
+
+.nf
+1: Authentication failure
+.fi
+
+.SH SEE ALSO
+pam_selinux(8)
+
+.SH BUGS
+Let's hope not, but if you find any, please email the author.  
+
+.SH AUTHOR
+Dan Walsh <dwalsh@redhat.com>
Index: Linux-PAM/modules/pam_selinux/pam_selinux.8
===================================================================
--- Linux-PAM/modules/pam_selinux/pam_selinux.8	(revision 0)
+++ Linux-PAM/modules/pam_selinux/pam_selinux.8	(revision 0)
@@ -0,0 +1,63 @@
+.TH pam_selinux 8 2003/08/26 "Red Hat Linux" "System Administrator's Manual"
+.SH NAME
+pam_selinux \- set the default security context after login via PAM.
+.SH SYNOPSIS
+.B session optional /lib/security/pam_selinux.so
+.br
+
+.SH DESCRIPTION
+In a nutshell, pam_selinux sets up the default security context for the next execed 
+shell.  
+
+When an application opens a session using pam_selinux, the shell that gets
+executed will be run in the default security context, or if the user chooses
+and the pam file allows the selected security context. Also the controlling
+tty will have it's security context modified to match the users.
+
+Adding pam_selinux into a pam file could cause other pam modules to change 
+their behavior if the exec another application.  The close and open option help 
+mitigate this problem.  close option will only cause the close portion of the
+pam_selinux to execute, and open will only cause the open portion to run.  You 
+can add pam_selinux to the config file twice.  Add the pam_selinux close as the
+'first' session entry and open as the 'last' session entry.  This way when pam 
+executes the open pass through the modules,  pam_selinux open_session will 
+happen last.  When pam executes the close pass through the modules pam_selinux 
+close_session will happen first.
+
+.SH ARGUMENTS
+.IP close
+Only execute the close_session portion of the module.
+.IP debug
+turns on debugging via \fBsyslog(3)\fR.
+.IP multiple
+tells pam_selinux.so to allow the user to select the security context they will
+login with, if the user has more than one role.
+.IP open
+Only execute the open_session portion of the module.
+.IP nottys
+Do not try to setup the ttys security context.
+.IP verbose
+attempt to inform the user when security context is set.
+
+.SH EXAMPLE
+\fB/etc/pam.d/some-login-program\fP:
+.br
+auth required   /lib/security/pam_unix.so
+.br
+session required /lib/security/pam_permit.so
+session optional /lib/security/pam_selinux.so
+.br
+
+.SH CAVEATS
+Setting the following line will cause the login to fail
+auth sufficient /lib/security/pam_selinux.so verbose
+
+
+.SH SEE ALSO
+pam_selinux_check(8)
+
+.SH BUGS
+Let's hope not, but if you find any, please email the author.  
+
+.SH AUTHOR
+Dan Walsh <dwalsh@redhat.com>
Index: Linux-PAM/modules/pam_selinux/Makefile
===================================================================
--- Linux-PAM/modules/pam_selinux/Makefile	(revision 0)
+++ Linux-PAM/modules/pam_selinux/Makefile	(revision 0)
@@ -0,0 +1,19 @@
+#
+# $Id: Makefile,v 1.5 2003/07/08 03:16:28 nalin Exp $
+#
+
+include ../../Make.Rules
+
+TITLE=pam_selinux
+APPLICATION=$(TITLE)_check
+APPMODE=04511
+MAN8=$(TITLE).8 $(TITLE)_check.8
+MODULE_SIMPLE_EXTRALIBS=-lselinux 
+
+#MODULE_SIMPLE_INSTALL=$(MAKE) $(APPLICATION); $(INSTALL) -m $(APPMODE) $(APPLICATION) $(FAKEROOT)$(SUPLEMENTED)
+
+include ../Simple.Rules
+
+$(APPLICATION): $(APPLICATION).c 
+	$(CC) $(CFLAGS) $(INCLUDE_PAMMODUTILS) -o $@ $^ $(LINK_PAMMODUTILS) -lpam -lpam_misc
+
Index: Linux-PAM/modules/pam_selinux/README
===================================================================
--- Linux-PAM/modules/pam_selinux/README	(revision 0)
+++ Linux-PAM/modules/pam_selinux/README	(revision 0)
@@ -0,0 +1,17 @@
+This is pam_selinux, a module for setting the default security context after 
+login via PAM.
+
+Background:  SELinux provides a mechanism for allowing people to login with 
+different security contexts.
+
+The module takes these arguments:
+The module takes these arguments:
+    close           Only execute the close_session portion of the module.
+    debug           Log debug messages (with priority DEBUG) to syslog.	
+    nottys          Do not set security context on controlling tty
+    verbose         Attempt to tell the user when security context is set.
+    open            Only execute the open_session portion of the module.
+
+Dan Walsh <dwalsh@redhat.com>
+
+
