diff --git a/NEWS b/NEWS
index 6c140036c642b23b0ab0cda7519147772624433c..603041731e85b100136c44db6b6eb753eed1f5a3 100644
--- a/NEWS
+++ b/NEWS
@@ -5,16 +5,21 @@ documents those changes that are of interest to users and admins.
 ========================
  -- Set SLURM_TASKS_PER_NODE env var for batch jobs (and LAM/MPI).
  -- Fix for slurmd spinning when stdin buffers full (gnats:434)
- -- Change some slurmctld malloc sizes to reduce demand for realloc
-    calls, improves performance and eliminates realloc failure on 
-    RH EL3 under extremely heavy workload apparently due to memory 
-    fragmentation.
+ -- Change some slurmctld malloc sizes to reduce demand for realloc calls, 
+    improves performance and eliminates realloc failure on RH EL3 under 
+    extremely heavy workload apparently due to memory fragmentation.
  -- Fix scheduling logic for heterogeneous processor count.
  -- Modify security_2_2 test to function with release 0.3
  -- Fix broken rpm build when libslurm not already installed.
  -- New slurmd option -M to mlock() slurmd process into memory.
- -- Fix node processing if state change requested via scontrol 
-    prior to initial node registration.
+ -- New srun option --no-shell causes srun to exit instead of spawning 
+    shell when using --allocate, -A.
+ -- Modify  srun --uid=user and --gid=group options to maintain invoking 
+    user's credentials until after nodes have been allocated to requested 
+    user/group (allows root to run jobs and allocate nodes for other users 
+    in a RootOnly partition).
+ -- Fix node processing if state change requested via scontrol prior to 
+    initial node registration.
  
 * Changes in SLURM 0.3.0
 ========================
diff --git a/doc/man/man1/srun.1 b/doc/man/man1/srun.1
index 579dfdf5ba0189feba5e6d3c5edb47bdf6a4b577..98833feb9aae0a52701a2418a38b4c48f4dd53d9 100644
--- a/doc/man/man1/srun.1
+++ b/doc/man/man1/srun.1
@@ -238,10 +238,13 @@ Quiet operation. Suppress informational messages. Errors will still
 be displayed.
 .TP
 \fB\-\-uid\fR=\fIuser\fR
-If
-.B srun
-is run as root, submit the job with \fIuser\fR's access permissions.
-\fIuser\fR may be the user name or the numerical user ID.
+Attempt to submit and/or run a job as \fIuser\fR instead of the
+invoking user id. The invoking user's credentials will be used
+to check access permissions for the target partition. User root
+may use this option to run jobs as a normal user in a RootOnly
+partition for example. If run as root, \fBsrun\fR will drop
+its permissions to the uid specified after node allocation is
+successful. \fIuser\fR may be the user name or numerical user ID.
 .TP
 \fB\-\-gid\fR=\fIgroup\fR
 If \fBsrun\fR is run as root, and the \fB\-\-gid\fR option is used, 
@@ -261,6 +264,10 @@ allocate resources and spawn a shell. When \fB\-\-allocate\fR is specified to
 \fBsrun\fR, no remote tasks are started. Instead a subshell is started that 
 has access to the allocated resources. Multiple jobs can then be run on the 
 same cpus from within this subshell. See \fBAllocate Mode\fR below.
+.TP
+\fB\-\-no\-shell\fR
+immediately exit after allocating resources instead of spawning a
+shell when used with the \fB\-A\fR, \fB\-\-allocate\fR option.
 .PP
 Attach to running job:
 .TP
diff --git a/src/common/uid.c b/src/common/uid.c
index e5e5d433866b7a21c72f0a3aac0b5a6dc5d92f6e..749671e445979eb65485850e2a45b618237c2bbe 100644
--- a/src/common/uid.c
+++ b/src/common/uid.c
@@ -1,3 +1,30 @@
+/*****************************************************************************\
+ * src/common/uid.c - uid/gid lookup utility functions
+ * $Id$
+ *****************************************************************************
+ *  Copyright (C) 2002 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Mark Grondona <mgrondona@llnl.gov>.
+ *  UCRL-CODE-2002-040.
+ *  
+ *  This file is part of SLURM, a resource management program.
+ *  For details, see <http://www.llnl.gov/linux/slurm/>.
+ *  
+ *  SLURM is free software; you can redistribute it and/or modify it under
+ *  the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; either version 2 of the License, or (at your option)
+ *  any later version.
+ *  
+ *  SLURM is distributed in the hope that it will be useful, but WITHOUT ANY
+ *  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ *  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ *  details.
+ *  
+ *  You should have received a copy of the GNU General Public License along
+ *  with SLURM; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
+\*****************************************************************************/
+
 #include <stdlib.h>
 #include <pwd.h>
 #include <grp.h>
@@ -5,28 +32,33 @@
 
 #include "uid.h"
 
-int
-is_digit_string( char *str )
+uid_t
+uid_from_string (char *name)
 {
-	char *p;
+	struct passwd *pwd = NULL;
+	char *p = NULL;
+	uid_t uid = (uid_t) strtoul (name, &p, 10);
 
-	for ( p = str; *p; ++p ) {
-		if ( ! isdigit( *p ) ) return 0;
-	}
-	return 1;
-}
+	if (*p != '\0')
+		pwd = getpwnam (name);
+	else
+		pwd = getpwuid (uid);
 
-uid_t
-uid_from_name( char *name )
-{
-	struct passwd *p = getpwnam( name );
-	return p ? p->pw_uid : NFS_NOBODY;
+	return pwd ? pwd->pw_uid : (uid_t) -1; 
 }
 
 gid_t
-gid_from_name( char *name )
+gid_from_string (char *name)
 {
-	struct group *g = getgrnam( name );
-	return g ? g->gr_gid : NFS_NOBODY;
+	struct group *g = NULL;
+	char *p = NULL;
+	gid_t gid = (gid_t) strtoul (name, &p, 10);
+
+	if (*p != '\0')
+		g = getgrnam (name);
+	else
+		g = getgrgid (gid);
+
+	return g ? g->gr_gid : (gid_t) -1;
 }
 
diff --git a/src/common/uid.h b/src/common/uid.h
index c672917056701532290989cabeba3bae302face7..4c1be538b015f2aeeba38bae636c70b8e9781836 100644
--- a/src/common/uid.h
+++ b/src/common/uid.h
@@ -1,10 +1,45 @@
+/*****************************************************************************\
+ * src/common/uid.h - uid/gid lookup utility functions
+ * $Id$
+ *****************************************************************************
+ *  Copyright (C) 2002 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Mark Grondona <mgrondona@llnl.gov>.
+ *  UCRL-CODE-2002-040.
+ *  
+ *  This file is part of SLURM, a resource management program.
+ *  For details, see <http://www.llnl.gov/linux/slurm/>.
+ *  
+ *  SLURM is free software; you can redistribute it and/or modify it under
+ *  the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; either version 2 of the License, or (at your option)
+ *  any later version.
+ *  
+ *  SLURM is distributed in the hope that it will be useful, but WITHOUT ANY
+ *  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ *  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ *  details.
+ *  
+ *  You should have received a copy of the GNU General Public License along
+ *  with SLURM; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
+\*****************************************************************************/
+
 #ifndef __SLURM_UID_UTILITY_H__
 #define __SLURM_UID_UTILITY_H__
 
-#define NFS_NOBODY 65534
+/*
+ * Return validated uid_t for string in ``name'' which contains
+ *  either the UID number or user name
+ * 
+ * Returns uid after verifying presence in /etc/passwd, or
+ *  (uid_t) -1 on failure.
+ */
+uid_t uid_from_string (char *name);
 
-int	is_digit_string( char *str );
-uid_t	uid_from_name( char *name );
-gid_t	gid_from_name( char *name );
+/*
+ * Same as uid_from_name(), but for group name/id.
+ */
+gid_t gid_from_string (char *name);
 
 #endif /*__SLURM_UID_UTILITY_H__*/
diff --git a/src/srun/allocate.c b/src/srun/allocate.c
index c1b7126f8d2999ba4a563e24d48339ccac3ae4a5..57f67a66eccae096b7dc90bbb6da91878c1b2340 100644
--- a/src/srun/allocate.c
+++ b/src/srun/allocate.c
@@ -230,7 +230,11 @@ job_desc_msg_create(void)
 	j->min_nodes      = opt.min_nodes;
 	j->num_tasks      = opt.nprocs;
 	j->user_id        = opt.uid;
-	j->group_id	  = getgid();
+
+	if (opt.egid == (gid_t) -1)
+		j->group_id = getgid ();
+	else
+		j->group_id = opt.egid;
 
 	if (opt.hold)
 		j->priority     = 0;
@@ -255,10 +259,11 @@ job_desc_msg_create(void)
 	if (opt.share)
 		j->shared              = 1;
 
-	if (slurmctld_comm_addr.port) {
+	j->port = slurmctld_comm_addr.port;
+	if (slurmctld_comm_addr.hostname) 
 		j->host = xstrdup(slurmctld_comm_addr.hostname);
-		j->port = slurmctld_comm_addr.port;
-	}
+	else
+		j->host = NULL;
 
 	return (j);
 }
diff --git a/src/srun/msg.c b/src/srun/msg.c
index 6d99ac8692f50c944523105f2618721ed4a370a3..016d2f4fc7b728f96f83b8108a3ec2eef5ca6fbe 100644
--- a/src/srun/msg.c
+++ b/src/srun/msg.c
@@ -775,6 +775,13 @@ extern void slurmctld_msg_init(void)
 	slurm_addr slurm_address;
 	char hostname[64];
 	uint16_t port;
+	
+	slurmctld_fd = -1;
+	slurmctld_comm_addr.hostname = NULL;
+	slurmctld_comm_addr.port = 0;
+
+	if (opt.allocate && opt.noshell)
+		return;
 
 	if ((slurmctld_fd = slurm_init_msg_engine_port(0)) < 0)
 		fatal("slurm_init_msg_engine_port error %m");
diff --git a/src/srun/opt.c b/src/srun/opt.c
index 83d6b72c9419b6b2820662b1ab26d72ee21bf9bb..d3fb2a83d553218417e487a901906c4ebc114ce3 100644
--- a/src/srun/opt.c
+++ b/src/srun/opt.c
@@ -102,6 +102,7 @@
 #define LONG_OPT_GID      0x10b
 #define LONG_OPT_MPI      0x10c
 #define LONG_OPT_CORE	  0x10e
+#define LONG_OPT_NOSHELL  0x10f
 
 /*---- forward declarations of static functions  ----*/
 
@@ -132,9 +133,6 @@ static void  _opt_list(void);
 /* verify options sanity  */
 static bool _opt_verify(void);
 
-/* demote to regular user */
-static uid_t _become_user( char *uid_string, char *gid_string );
-
 static void  _print_version(void);
 
 static void _process_env_var(env_vars_t *e, const char *val);
@@ -409,6 +407,7 @@ static void _opt_default()
 	opt.immediate	= false;
 
 	opt.allocate	= false;
+	opt.noshell	= false;
 	opt.attach	= NULL;
 	opt.join	= false;
 	opt.max_wait	= slurm_get_wait_time();
@@ -433,8 +432,8 @@ static void _opt_default()
 	opt.max_exit_timeout= 60; /* Warn user 60 seconds after task exit */
 	opt.msg_timeout     = 5;  /* Default launch msg timeout           */
 
-	opt.euid	    = NULL;
-	opt.egid	    = NULL;
+	opt.euid	    = (uid_t) -1;
+	opt.egid	    = (gid_t) -1;
 	
 	mode	= MODE_NORMAL;
 
@@ -644,6 +643,7 @@ static void _opt_args(int argc, char **argv)
 		{"mincpus",          required_argument, 0, LONG_OPT_MINCPU},
 		{"mem",              required_argument, 0, LONG_OPT_MEM},
 		{"mpi",              required_argument, 0, LONG_OPT_MPI},
+		{"no-shell",         no_argument,       0, LONG_OPT_NOSHELL},
 		{"tmp",              required_argument, 0, LONG_OPT_TMP},
 		{"jobid",            required_argument, 0, LONG_OPT_JOBID},
 		{"msg-timeout",      required_argument, 0, LONG_OPT_TIMEO},
@@ -847,6 +847,9 @@ static void _opt_args(int argc, char **argv)
 			if (strncasecmp(optarg, "lam",  3) == 0)
 			       opt.mpi_type = MPI_LAM;	
 			break;
+		case LONG_OPT_NOSHELL:
+			opt.noshell = true;
+			break;
 		case LONG_OPT_TMP:
 			opt.tmpdisk = _to_bytes(optarg);
 			if (opt.tmpdisk < 0) {
@@ -870,16 +873,14 @@ static void _opt_args(int argc, char **argv)
 				_get_int(optarg, "max-exit-timeout");
 			break;
 		case LONG_OPT_UID:
-			xfree( opt.euid );
-			opt.euid = xstrdup( optarg );
-			if ( getuid() )
-				info( "UID ignored for non-root user" );
+			opt.euid = uid_from_string (optarg);
+			if (opt.euid == (uid_t) -1)
+				fatal ("--uid=\"%s\" invalid", optarg);
 			break;
 		case LONG_OPT_GID:
-			xfree( opt.egid );
-			opt.egid = xstrdup( optarg );
-			if ( getuid() )
-				info( "GID ignored for non-root user" );
+			opt.egid = gid_from_string (optarg);
+			if (opt.egid == (gid_t) -1)
+				fatal ("--gid=\"%s\" invalid", optarg);
 			break;
 		case LONG_OPT_HELP:
 			_help();
@@ -924,7 +925,6 @@ static void _opt_args(int argc, char **argv)
 static bool _opt_verify(void)
 {
 	bool verified = true;
-	uid_t euid;
 
 	/*
 	 *  Do not set slurmd debug level higher than DEBUG2,
@@ -941,22 +941,6 @@ static bool _opt_verify(void)
 		verified = false;
 	}
 
-	/*
-	 * If we are root and have been asked to submit as another
-	 * user, become that user now.
-	 */
-	if ( getuid() == 0 ) {
-		if ( opt.euid ) {
-			euid = _become_user( opt.euid, opt.egid );
-			if ( euid != NFS_NOBODY ) {
-				opt.uid = euid;
-				strncpy( opt.user, opt.euid, MAX_USERNAME );
-			} else {
-				verified = false;
-			}
-		}
-	}
-
 	if (opt.no_alloc && !opt.nodelist) {
 		error("must specify a node list with -Z, --no-allocate.");
 		verified = false;
@@ -1078,6 +1062,14 @@ static bool _opt_verify(void)
 	if (opt.time_limit == 0)
 		opt.time_limit = INFINITE;
 
+	if ((opt.euid != (uid_t) -1) && (opt.euid != opt.uid)) 
+		opt.uid = opt.euid;
+
+	if (opt.noshell && !opt.allocate) {
+		error ("--no-shell only valid with -A (--allocate)");
+		verified = false;
+	}
+
 	return verified;
 }
 
@@ -1155,54 +1147,6 @@ _search_path(char *cmd, bool check_current_dir, int access_mode)
 }
 
 
-static uid_t
-_become_user( char *uid_string, char *gid_string )
-{
-	uid_t euid = 0;
-	gid_t egid = 0;
-
-	/*
-	 * The group is not strictly necessary but we have to change
-	 * the group before we change the user, else we lose the
-	 * ability to change the group after having become a normal
-	 * user.
-	 */
-	if ( gid_string ) {
-
-		/* Resolve group name/ID to numerical form. */
-		if ( is_digit_string( gid_string ) ) {
-			egid = atoi( gid_string );
-		} else {
-			egid = gid_from_name( gid_string );
-		}
-
-		/* Assume this group. */
-		if ( egid ) {
-			if ( setregid( egid, egid ) < 0 ) {
-				error( "can't assume group %s", gid_string );
-			}
-		}
-	}
-	
-	/* Resolve user name/ID to numerical form. */
-	if ( is_digit_string( uid_string ) ) {
-		euid = atoi( uid_string );
-	} else {
-		euid = uid_from_name( uid_string );
-	}
-
-	/* Become this user. */
-	if ( euid ) {
-		if ( setreuid( euid, euid ) < 0 ) {
-			error( "can't become user %s", uid_string );
-			return 0;
-		}
-	}
-
-	return euid;
-}
-
-
 /* helper function for printing options
  * 
  * warning: returns pointer to memory allocated on the stack.
@@ -1351,6 +1295,7 @@ Parallel run options:\n\
 \n\
 Allocate only:\n\
   -A, --allocate              allocate resources and spawn a shell\n\
+      --no-shell              don't spawn shell in allocate mode\n\
 \n\
 Attach to running job:\n\
   -a, --attach=jobid          attach to running job with specified id\n\
diff --git a/src/srun/opt.h b/src/srun/opt.h
index 338a8cbd261b592b63fb14a260c250ecf49c25a9..54b0f3b8d1953beed6a8e10ce7df7ef5485b6ece 100644
--- a/src/srun/opt.h
+++ b/src/srun/opt.h
@@ -87,8 +87,8 @@ typedef struct srun_options {
 	char *progname;		/* argv[0] of this program 	*/
 	char user[MAX_USERNAME];/* local username		*/
 	uid_t uid;		/* local uid			*/
-	char *euid;		/* effective user --uid=user	*/
-	char *egid;		/* effective group --gid=group	*/
+	uid_t euid;		/* effective user --uid=user	*/
+	gid_t egid;		/* effective group --gid=group	*/
 	char *cwd;		/* current working directory	*/
 
 	int  nprocs;		/* --nprocs=n,      -n n	*/
@@ -126,6 +126,7 @@ typedef struct srun_options {
 	bool labelio;		/* --label-output, -l		*/
 	bool unbuffered;        /* --unbuffered,   -u           */
 	bool allocate;		/* --allocate, 	   -A		*/
+	bool noshell;		/* --noshell                    */
 	bool overcommit;	/* --overcommit,   -O		*/
 	bool batch;		/* --batch,   -b		*/
 	bool no_kill;		/* --no-kill, -k		*/
diff --git a/src/srun/srun.c b/src/srun/srun.c
index 4e52b9582590c35386c2001ee5bea304299b03ca..52128f7817935835b080edd3697c2e44d1ac35b3 100644
--- a/src/srun/srun.c
+++ b/src/srun/srun.c
@@ -51,6 +51,7 @@
 #include <signal.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <grp.h>
 
 #include "src/common/fd.h"
 #include "src/common/log.h"
@@ -96,6 +97,7 @@ static int   _set_batch_script_env(job_t *job);
 static int   _set_rlimit_env(void);
 static char *_sprint_task_cnt(job_t *job);
 static void  _switch_standalone(job_t *job);
+static int   _become_user (void);
 
 int srun(int ac, char **av)
 {
@@ -159,6 +161,12 @@ int srun(int ac, char **av)
 		sig_setup_sigmask();
 		if ( !(resp = allocate_nodes()) ) 
 			exit(1);
+		if (opt.noshell) {
+			fprintf (stdout, "SLURM_JOBID=%u\n", resp->job_id);
+			exit (0);
+		}
+		if (_become_user () < 0)
+			info ("Warning: unable to assume uid=%lu\n", opt.uid);
 		if (_verbose)
 			_print_job_information(resp);
 		job = job_create_allocation(resp); 
@@ -186,6 +194,12 @@ int srun(int ac, char **av)
 		slurm_free_resource_allocation_response_msg(resp);
 	}
 
+	/*
+	 *  Become --uid user
+	 */
+	if (_become_user () < 0)
+		info ("Warning: Unable to assume uid=%lu\n", opt.uid);
+
 	/* job structure should now be filled in */
 
 	/*
@@ -840,3 +854,21 @@ static void _run_job_script (job_t *job)
 	}
 
 }
+
+static int _become_user (void)
+{
+	struct passwd *pwd = getpwuid (opt.uid);
+
+	if (opt.uid == getuid ())
+		return (0);
+
+	if ((opt.egid != (gid_t) -1) && (setgid (opt.egid) < 0))
+		return (error ("setgid: %m"));
+
+	initgroups (pwd->pw_name, pwd->pw_gid); /* Ignore errors */
+
+	if (setuid (opt.uid) < 0)
+		return (error ("setuid: %m"));
+
+	return (0);
+}