diff --git a/NEWS b/NEWS
index 5fc78bbdbd14b8378eb305ccd0884f8098b5dddf..85336dab451c7a9a170441cd9e95f259be461ea7 100644
--- a/NEWS
+++ b/NEWS
@@ -130,6 +130,7 @@ documents those changes that are of interest to users and admins.
  -- Avoid printing negative job run time in squeue due to clock skew.
  -- In sched/wiki and sched/wiki2, add support for wiki.conf option
     HidePartitionJobs (see man pages for details).
+ -- Update to srun/sbatch --get-user-env option logic (needed by Moab).
 
 * Changes in SLURM 1.2.21
 =========================
diff --git a/contribs/env_cache_builder.c b/contribs/env_cache_builder.c
index 5bcd9149cadc79a6fbac431c26f2e98dfccc5e0d..f13d7f8e799a3e1e9c121125f8a42b7c26b782ed 100644
--- a/contribs/env_cache_builder.c
+++ b/contribs/env_cache_builder.c
@@ -14,7 +14,7 @@
  *
  *  This program must execute as user root. 
  *****************************************************************************
- *  Copyright (C) 2007 The Regents of the University of California.
+ *  Copyright (C) 2007-2008 The Regents of the University of California.
  *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
  *  Written by Morris Jette <jette1@llnl.gov>.
  *  UCRL-CODE-226842.
@@ -53,16 +53,18 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <strings.h>
 #include <unistd.h>
+#include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 
-#define DEBUG 0
+#define _DEBUG 0
 #define SU_WAIT_MSEC 8000
 
 static long int	_build_cache(char *user_name, char *cache_dir);
 static int	_get_cache_dir(char *buffer, int buf_size);
-static void	_parse_line(char *in_line, char **user_name, int *user_id);
+static int	_parse_line(char *in_line, char **user_name, int *user_id);
 
 main (int argc, char **argv)
 {
@@ -80,19 +82,17 @@ main (int argc, char **argv)
 		exit(1);
 	strncat(cache_dir, "/env_cache", sizeof(cache_dir));
 	if (mkdir(cache_dir, 0500) && (errno != EEXIST)) {
-		printf("Could not create cache directory %s: %s", cache_dir,
+		printf("Could not create cache directory %s: %s\n", cache_dir,
 			strerror(errno));
 		exit(1);
 	}
-#if DEBUG
 	printf("cache_dir=%s\n", cache_dir);
-#endif
 
 	for (i=1; i<argc; i++) {
 		delta_t = _build_cache(argv[i], cache_dir);
-#if DEBUG
-		printf("user %-8s time %ld usec\n", argv[i], delta_t);
-#endif
+		if (delta_t < ((SU_WAIT_MSEC * 0.8) * 1000))
+			continue;
+		printf("WARNING: user %-8s time %ld usec\n", argv[i], delta_t);
 	}
 	if (i > 1)
 		exit(0);
@@ -104,52 +104,76 @@ main (int argc, char **argv)
 	}
 
 	while (fgets(in_line, sizeof(in_line), passwd_fd)) {
-		_parse_line(in_line, &user_name, &user_id);
+		if (_parse_line(in_line, &user_name, &user_id) < 0)
+			continue;
 		if (user_id <= 100)
 			continue;
 		delta_t = _build_cache(user_name, cache_dir);
-#if DEBUG
 		if (delta_t < ((SU_WAIT_MSEC * 0.8) * 1000))
 			continue;
-		printf("user %-8s time %ld usec\n", user_name, delta_t);
-#endif
+		printf("WARNING: user %-8s time %ld usec\n", user_name, delta_t);
 	}
 	fclose(passwd_fd);
 }
 
-/* Given a line from /etc/passwd, return the user_name and user_id */
-static void _parse_line(char *in_line, char **user_name, int *user_id)
+/* Given a line from /etc/passwd, sets the user_name and user_id
+ * RET -1 if user can't login, 0 otherwise */
+static int _parse_line(char *in_line, char **user_name, int *user_id)
 {
-	char *tok;
-
+	char *tok, *shell;
+	
+	/* user name */
 	*user_name = strtok(in_line, ":");
+
 	(void) strtok(NULL, ":");
+
+	/* uid */
 	tok = strtok(NULL, ":");
 	if (tok)
 		*user_id = atoi(tok);
 	else {
-		printf("error parsing /etc/passwd: %s\n", in_line);
+		printf("ERROR: parsing /etc/passwd: %s\n", in_line);
 		*user_id = 0;
 	}
+
+	(void) strtok(NULL, ":");	/* gid */
+	(void) strtok(NULL, ":");	/* name */
+	(void) strtok(NULL, ":");	/* home */
+
+	shell = strtok(NULL, ":");
+	if (shell) {
+		tok = strchr(shell, '\n');
+		if (tok)
+			tok[0] = '\0';
+		if ((strcmp(shell, "/sbin/nologin") == 0) ||
+		    (strcmp(shell, "/bin/false") == 0))
+			return -1;
+	}
+
+	return 0;
+
 }
 
 /* For a given user_name, get his environment variable by executing
  * "su - <user_name> -c env" and store the result in 
  * cache_dir/env_<user_name>
- * Returns time to perform the operation in usec
+ * Returns time to perform the operation in usec or -1 on error
  */
 static long int _build_cache(char *user_name, char *cache_dir)
 {
-	FILE *su, *cache;
-	char line[BUFSIZ], name[BUFSIZ], value[BUFSIZ], out_file[BUFSIZ];
+	FILE *cache;
+	char *line, *last, out_file[BUFSIZ], buffer[64 * 1024];
 	char *starttoken = "XXXXSLURMSTARTPARSINGHEREXXXX";
 	char *stoptoken  = "XXXXSLURMSTOPPARSINGHEREXXXXX";
 	int fildes[2], found, fval, len, rc, timeleft;
+	int buf_read, buf_rem;
 	pid_t child;
 	struct timeval begin, now;
 	struct pollfd ufds;
 	long int delta_t;
 
+	gettimeofday(&begin, NULL);
+
 	if (pipe(fildes) < 0) {
 		perror("pipe");
 		return -1;
@@ -166,13 +190,14 @@ static long int _build_cache(char *user_name, char *cache_dir)
 		dup2(fildes[1], 1);
 		close(2);
 		open("/dev/null", O_WRONLY);
-		snprintf(line, sizeof(line),
-			 "echo; echo; echo; echo %s; env; echo %s",
+		snprintf(buffer, sizeof(buffer),
+			 "/bin/echo; /bin/echo; /bin/echo; "
+			 "/bin/echo %s; /bin/env; /bin/echo %s",
 			 starttoken, stoptoken);
 #ifdef LOAD_ENV_NO_LOGIN
-		execl("/bin/su", "su", user_name, "-c", line, NULL);
+		execl("/bin/su", "su", user_name, "-c", buffer, NULL);
 #else
-		execl("/bin/su", "su", "-", user_name, "-c", line, NULL);
+		execl("/bin/su", "su", "-", user_name, "-c", buffer, NULL);
 #endif
 		exit(1);
 	}
@@ -180,30 +205,30 @@ static long int _build_cache(char *user_name, char *cache_dir)
 	close(fildes[1]);
 	if ((fval = fcntl(fildes[0], F_GETFL, 0)) >= 0)
 		fcntl(fildes[0], F_SETFL, fval | O_NONBLOCK);
-	su = fdopen(fildes[0], "r");
 
-	gettimeofday(&begin, NULL);
 	ufds.fd = fildes[0];
 	ufds.events = POLLIN;
+	ufds.revents = 0;
 
-	/* First look for the start token in the output */
-	len = strlen(starttoken);
+	/* Read all of the output from /bin/su into buffer */
 	found = 0;
-	while (!found) {
+	buf_read = 0;
+	bzero(buffer, sizeof(buffer));
+	while (1) {
 		gettimeofday(&now, NULL);
 		timeleft = SU_WAIT_MSEC * 10;
 		timeleft -= (now.tv_sec -  begin.tv_sec)  * 1000;
 		timeleft -= (now.tv_usec - begin.tv_usec) / 1000;
 		if (timeleft <= 0) {
-#if DEBUG
-			printf("timeout1\n");
+#if _DEBUG
+			printf("timeout1 for %s\n", user_name);
 #endif
 			break;
 		}
 		if ((rc = poll(&ufds, 1, timeleft)) <= 0) {
 			if (rc == 0) {
-#if DEBUG
-				printf("timeout2\n");
+#if _DEBUG
+				printf("timeout2 for %s\n, user_name");
 #endif
 				break;
 			}
@@ -213,88 +238,97 @@ static long int _build_cache(char *user_name, char *cache_dir)
 			break;
 		}
 		if (!(ufds.revents & POLLIN)) {
-			perror("POLLERR|POLLHUP");
+			if (ufds.revents & POLLHUP) {	/* EOF */
+#if _DEBUG
+				printf("POLLHUP for %s\n", user_name);
+#endif
+				found = 1;		/* success */
+			} else if (ufds.revents & POLLERR) {
+				printf("ERROR: POLLERR for %s\n", user_name);
+			} else {
+				printf("ERROR: poll() revents=%d for %s\n", 
+					ufds.revents, user_name);
+			}
 			break;
 		}
-		while (fgets(line, BUFSIZ, su)) {
-			if (!strncmp(line, starttoken, len)) {
-				found = 1;
-				break;
-			}
+		buf_rem = sizeof(buffer) - buf_read;
+		if (buf_rem == 0) {
+			printf("ERROR: buffer overflow for %s\n", user_name);
+			break;
+		}
+		rc = read(fildes[0], &buffer[buf_read], buf_rem);
+		if (rc > 0)
+			buf_read += rc;
+		else if (rc == 0) {	/* EOF */
+#if _DEBUG
+			printf("EOF for %s\n", user_name);
+#endif
+			found = 1;	/* success */
+			break;
+		} else {		/* error */
+			perror("read");
+			break;
 		}
 	}
+	close(fildes[0]);
 	if (!found) {
-		printf("Failed to get current user environment variables "
-			"for %s\n", user_name);
-		close(fildes[0]);
-		gettimeofday(&now, NULL);
-		delta_t  = now.tv_sec -  begin.tv_sec * 1000000;
-		delta_t += now.tv_usec - begin.tv_usec;
-		if (delta_t < (SU_WAIT_MSEC * 1000))
-			return (SU_WAIT_MSEC * 1000);
-		return delta_t;
+		printf("ERROR: Failed to load current user environment "
+			"variables for %s\n", user_name);
+		return -1;
+	}
+
+	/* First look for the start token in the output */
+	len = strlen(starttoken);
+	found = 0;
+	line = strtok_r(buffer, "\n", &last);
+	while (!found && line) {
+		if (!strncmp(line, starttoken, len)) {
+			found = 1;
+			break;
+		}
+		line = strtok_r(NULL, "\n", &last);
+	}
+	if (!found) {
+		printf("ERROR: Failed to get current user environment "
+			"variables for %s\n", user_name);
+		return -1;
 	}
 
 	snprintf(out_file, sizeof(out_file), "%s/%s", cache_dir, user_name);
 	cache = fopen(out_file, "w");
 	if (!cache) {
-		printf("Could not create cache file %s: %s\n", out_file, 
-			strerror(errno));
+		printf("ERROR: Could not create cache file %s for %s: %s\n", 
+			out_file, user_name, strerror(errno));
+		return -1;
 	}
+	chmod(out_file, 0600);
 
+	/* Process environment variables until we find the stop token */
 	len = strlen(stoptoken);
 	found = 0;
-	while (!found && cache) {
-		gettimeofday(&now, NULL);
-		timeleft = SU_WAIT_MSEC * 10;
-		timeleft -= (now.tv_sec -  begin.tv_sec)  * 1000;
-		timeleft -= (now.tv_usec - begin.tv_usec) / 1000;
-		if (timeleft <= 0) {
-#if DEBUG
-			printf("timeout3\n");
-#endif
-			break;
-		}
-		if ((rc = poll(&ufds, 1, timeleft)) <= 0) {
-			if (rc == 0) {
-#if DEBUG
-				printf("timeout4\n");
-#endif
-				break;
-			}
-			if ((errno == EINTR) || (errno == EAGAIN))
-				continue;
-			perror("poll");
-			break;
-		}
-		if (!(ufds.revents & POLLIN)) {
-			perror("POLLERR|POLLHUP");
-			break;
-		}
-		/* stop at the line containing the stoptoken string */
-		if ((fgets(line, BUFSIZ, su) == 0) ||
-		    (!strncmp(line, stoptoken, len))) {
+	line = strtok_r(NULL, "\n", &last);
+	while (!found && line) {
+		if (!strncmp(line, stoptoken, len)) {
 			found = 1;
 			break;
 		}
-
-		if (fputs(line, cache) == EOF) {
-			printf("Could not write cache file %s: %s\n", 
-				out_file, strerror(errno));
+		if (fprintf(cache, "%s\n",line) < 0) {
+			printf("ERROR: Could not write cache file %s "
+				"for %s: %s\n", 
+				out_file, user_name, strerror(errno));
 			found = 1;	/* quit now */
 		}
+		line = strtok_r(NULL, "\n", &last);
 	}
-	close(fildes[0]);
-	if (cache)
-		fclose(cache);
+	fclose(cache);
 	waitpid(-1, NULL, WNOHANG);
 
 	gettimeofday(&now, NULL);
 	delta_t  = (now.tv_sec  - begin.tv_sec)  * 1000000;
 	delta_t +=  now.tv_usec - begin.tv_usec;
 	if (!found) {
-		printf("Failed to get current user environment variables "
-			"for %s\n", user_name);
+		printf("ERROR: Failed to write all user environment "
+			"variables for %s\n", user_name);
 		if (delta_t < (SU_WAIT_MSEC * 1000))
 			return (SU_WAIT_MSEC * 1000);
 	}
@@ -349,7 +383,7 @@ static int _get_cache_dir(char *buffer, int buf_size)
 	}
 	close(fildes[0]);
 	if (!buffer[0]) {
-		printf("Failed to get StateSaveLocation\n");
+		printf("ERROR: Failed to get StateSaveLocation\n");
 		close(fildes[0]);
 		return -1;
 	}
diff --git a/src/common/env.c b/src/common/env.c
index 8f71b4c9e0f37498f9a68f4eebe570a29959f42d..0b7ad731dfeebc850038e4a5ebd05d1da7363989 100644
--- a/src/common/env.c
+++ b/src/common/env.c
@@ -1300,15 +1300,14 @@ char **_load_env_cache(const char *username)
  */
 char **env_array_user_default(const char *username, int timeout, int mode)
 {
-	FILE *su;
-	char line[ENV_BUFSIZE];
-	char name[128];
-	char value[ENV_BUFSIZE];
+	char *line, *last, name[128], value[ENV_BUFSIZE];
+	char buffer[ENV_BUFSIZE];
 	char **env = NULL;
 	char *starttoken = "XXXXSLURMSTARTPARSINGHEREXXXX";
 	char *stoptoken  = "XXXXSLURMSTOPPARSINGHEREXXXXX";
 	char cmdstr[256];
 	int fildes[2], found, fval, len, rc, timeleft;
+	int buf_read, buf_rem;
 	pid_t child;
 	struct timeval begin, now;
 	struct pollfd ufds;
@@ -1335,7 +1334,8 @@ char **env_array_user_default(const char *username, int timeout, int mode)
 		close(2);
 		open("/dev/null", O_WRONLY);
 		snprintf(cmdstr, sizeof(cmdstr),
-			 "/bin/echo; /bin/echo; /bin/echo; /bin/echo %s; /bin/env; /bin/echo %s",
+			 "/bin/echo; /bin/echo; /bin/echo; "
+			 "/bin/echo %s; /bin/env; /bin/echo %s",
 			 starttoken, stoptoken);
 		if      (mode == 1)
 			execl("/bin/su", "su", username, "-c", cmdstr, NULL);
@@ -1354,25 +1354,24 @@ char **env_array_user_default(const char *username, int timeout, int mode)
 	close(fildes[1]);
 	if ((fval = fcntl(fildes[0], F_GETFL, 0)) >= 0)
 		fcntl(fildes[0], F_SETFL, fval | O_NONBLOCK);
-	su= fdopen(fildes[0], "r");
 
 	gettimeofday(&begin, NULL);
 	ufds.fd = fildes[0];
 	ufds.events = POLLIN;
 
-	/* First look for the start token in the output */
-	len = strlen(starttoken);
+	/* Read all of the output from /bin/su into buffer */
 	found = 0;
-	while (!found) {
+	buf_read = 0;
+	bzero(buffer, sizeof(buffer));
+	while (1) {
 		gettimeofday(&now, NULL);
-		if (timeout > 0)
-			timeleft = timeout * 1000;
-		else
-			timeleft = SU_WAIT_MSEC;
+		timeleft = SU_WAIT_MSEC;
 		timeleft -= (now.tv_sec -  begin.tv_sec)  * 1000;
 		timeleft -= (now.tv_usec - begin.tv_usec) / 1000;
-		if (timeleft <= 0)
+		if (timeleft <= 0) {
+			verbose("timeout waiting for /bin/su to complete");
 			break;
+		}
 		if ((rc = poll(&ufds, 1, timeleft)) <= 0) {
 			if (rc == 0) {
 				verbose("timeout waiting for /bin/su to complete");
@@ -1380,64 +1379,76 @@ char **env_array_user_default(const char *username, int timeout, int mode)
 			}
 			if ((errno == EINTR) || (errno == EAGAIN))
 				continue;
-			error("poll: %m");
+			error("poll(): %m");
 			break;
 		}
-		if (!(ufds.revents & POLLIN))
-			break;
-		while (fgets(line, sizeof(line), su)) {
-			if (!strncmp(line, starttoken, len)) {
-				found = 1;
-				break;
+		if (!(ufds.revents & POLLIN)) {
+			if (ufds.revents & POLLHUP) {	/* EOF */
+				found = 1;		/* success */
+			} else if (ufds.revents & POLLERR) {
+				error("POLLERR");
+			} else {
+				error("poll() revents=%d", ufds.revents);
 			}
+			break;
+		}
+		buf_rem = sizeof(buffer) - buf_read;
+		if (buf_rem == 0) {
+			error("buffer overflow loading env vars");
+			break;
+		}
+		rc = read(fildes[0], &buffer[buf_read], buf_rem);
+		if (rc > 0)
+			buf_read += rc;
+		else if (rc == 0) {	/* EOF */
+			found = 1;	/* success */
+			break;
+		} else {		/* error */
+			error("read(env pipe): %m");
+			break;
+		}
+	}
+	close(fildes[0]);
+	if (!found) {
+		error("Failed to load current user environment variables");
+		_load_env_cache(username);
+	}
+
+	/* First look for the start token in the output */
+	len = strlen(starttoken);
+	found = 0;
+	line = strtok_r(buffer, "\n", &last);
+	while (!found && line) {
+		if (!strncmp(line, starttoken, len)) {
+			found = 1;
+			break;
 		}
+		line = strtok_r(NULL, "\n", &last);
 	}
 	if (!found) {
 		error("Failed to get current user environment variables");
-		close(fildes[0]);
 		return _load_env_cache(username);
 	}
 
-	/* Now read in the environment variable strings. */
-	env = env_array_create();
+	/* Process environment variables until we find the stop token */
 	len = strlen(stoptoken);
 	found = 0;
-	while (!found) {
-		gettimeofday(&now, NULL);
-		if (timeout > 0)
-			timeleft = timeout * 1000;
-		else
-			timeleft = SU_WAIT_MSEC;
-		timeleft -= (now.tv_sec -  begin.tv_sec)  * 1000;
-		timeleft -= (now.tv_usec - begin.tv_usec) / 1000;
-		if (timeleft <= 0)
-			break;
-		if ((rc = poll(&ufds, 1, timeleft)) <= 0) {
-			if (rc == 0) {
-				verbose("timeout waiting for /bin/su to complete");
-				break;
-			}
-			if ((errno == EINTR) || (errno == EAGAIN))
-				continue;
-			error("poll: %m");
-			break;
-		}
-		/* stop at the line containing the stoptoken string */
-		if (!(ufds.revents & POLLIN))
-			break;
-		if ((fgets(line, sizeof(line), su) == 0) ||
-		    (!strncmp(line, stoptoken, len))) {
+	env = env_array_create();
+	line = strtok_r(NULL, "\n", &last);
+	while (!found && line) {
+		if (!strncmp(line, stoptoken, len)) {
 			found = 1;
 			break;
 		}
-
-		_strip_cr_nl(line);
-		if (_env_array_entry_splitter(line, name, sizeof(name),
+		if (_env_array_entry_splitter(line, name, sizeof(name), 
 					      value, sizeof(value)))
 			env_array_overwrite(&env, name, value);
+		line = strtok_r(NULL, "\n", &last);
+	}
+	if (!found) {
+		error("Failed to get all user environment variables");
+		return _load_env_cache(username);
 	}
-	close(fildes[0]);
 
 	return env;
 }
-