diff --git a/account/newuser.in b/account/newuser.in
index 6940b44061a832790e05d26525b0c7234c543b86..34021832b70cd27824d8adcc79b8075f1ff6f3b0 100644
--- a/account/newuser.in
+++ b/account/newuser.in
@@ -1,7 +1,7 @@
-#!/usr/bin/perl -wT
+#!/usr/bin/perl -w
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2000-2008, 2010 University of Utah and the Flux Group.
+# Copyright (c) 2000-2011 University of Utah and the Flux Group.
 # All rights reserved.
 #
 use English;
@@ -15,12 +15,15 @@ use Data::Dumper;
 #
 sub usage()
 {
-    print("Usage: newuser -t <type> <xmlfile>\n");
+    print("Usage: newuser [-s] -t <type> <xmlfile>\n");
     exit(-1);
 }
-my $optlist = "dt:";
+my $optlist = "dt:ns";
 my $debug   = 0;
+my $impotent= 0;
 my $type    = "";
+my $silent  = 0;
+my @keyfiles = ();
 
 #
 # Configure variables
@@ -71,7 +74,6 @@ sub escapeshellarg($);
 
 # Locals
 my $SAVEUID	= $UID;
-my $keyfile;
 
 #
 # Parse command arguments. Once we return from getopts, all that should be
@@ -84,6 +86,12 @@ if (! getopts($optlist, \%options)) {
 if (defined($options{"d"})) {
     $debug = 1;
 }
+if (defined($options{"n"})) {
+    $impotent = 1;
+}
+if (defined($options{"s"})) {
+    $silent = 1;
+}
 if (defined($options{"t"})) {
     $type = $options{"t"};
 }
@@ -135,14 +143,15 @@ else {
 # This first set is required by all types of users
 #
 my %required = ("name"		=> "usr_name",
-		"email"		=> "usr_email",
-		"password"	=> undef);
+		"email"		=> "usr_email");
 
-my %optional = ("login"		=> "uid",
+my %optional = ("uid"		=> "uid",
 		"address2"	=> "usr_addr2",
 		"URL"		=> "usr_URL",
 		"shell"		=> "usr_shell",
-		"pubkey"        => undef);
+		"password"	=> undef,
+		"pubkey"        => undef,
+		"pubkeys"       => undef);
 
 #
 # These are required for most users, but are optional for wiki-only users
@@ -168,12 +177,15 @@ if ($type eq "wikionly") {
 # Must wrap the parser in eval since it exits on error.
 #
 my $xmlparse = eval { XMLin($xmlfile,
+			    ForceArray => ["pubkeys"],
 			    VarAttr => 'name',
 			    ContentKey => '-content',
 			    SuppressEmpty => undef); };
 fatal($@)
     if ($@);
 
+print STDERR Dumper($xmlparse)
+    if ($debug);
 
 #
 # Make sure all the required arguments were provided.
@@ -275,11 +287,17 @@ UserError("Email address already in use; please pick another!")
 #
 # Check the password.
 #
-my $pswd = $xmlparse->{'attribute'}->{'password'}->{'value'};
+my $pswd = (exists($xmlparse->{'attribute'}->{'password'}) ?
+	    $xmlparse->{'attribute'}->{'password'}->{'value'} : "*");
 
 # Admins can "star" the password entry.
-if (defined($this_user) && $this_user->IsAdmin() && $pswd eq "*") {
-    $newuser_args{'usr_pswd'} = "*";
+if ($pswd eq "*") {
+    if (defined($this_user) && $this_user->IsAdmin()) {
+	$newuser_args{'usr_pswd'} = "*";
+    }
+    else {
+	UserError("Only admins can star the password entry");
+    }
 }
 else {
     my $checkpass_args = escapeshellarg($pswd);
@@ -304,26 +322,41 @@ else {
 # Do a check on the pubkey if supplied. The safest thing to do is generate
 # a temporary file and pass that to addpubkey to check.
 #
-if (exists($xmlparse->{'attribute'}->{'pubkey'})) {
-    $keyfile = TBMakeTempFile("addpubkey");
-    fatal("Could not create tempfile")
-	if ($?);
+if (exists($xmlparse->{'attribute'}->{'pubkey'}) ||
+    exists($xmlparse->{'pubkeys'})) {
 
-    open(KEY, ">> $keyfile") or
-	fatal("Could not open $keyfile");
-    print KEY $xmlparse->{'attribute'}->{'pubkey'}->{'value'};
-    close($keyfile);
+    my @keys = (exists($xmlparse->{'pubkeys'}) ? 
+		@{ $xmlparse->{'pubkeys'} } :
+		($xmlparse->{'attribute'}->{'pubkey'}->{'value'}));
 
-    my $result = `$addpubkey -n -f $keyfile`;
-    chomp($result);
-    UserError("Could not parse public key")
-	if ($?);
+    foreach my $key (@keys) {
+	my $keyfile = TBMakeTempFile("addpubkey");
+	fatal("Could not create tempfile")
+	    if ($?);
+
+	open(KEY, ">> $keyfile") or
+	    fatal("Could not open $keyfile");
+	print KEY $key; 
+	close($keyfile);
+
+	if ($debug) {
+	    print STDERR "Checking key in $keyfile ...\n";
+	}
+	my $result = `$addpubkey -n -f $keyfile`;
+	chomp($result);
+	UserError("Could not parse public key")
+	    if ($?);
+	push(@keyfiles, $keyfile);
+    }
 }
 
 #
 # Now safe to create the user. Move the uid out of the argument array
 # since its actually an argument to the Create() routine.
 #
+exit(0)
+    if ($impotent);
+
 my $new_uid;
 
 if (exists($newuser_args{'uid'})) {
@@ -417,22 +450,27 @@ SENDMAIL("$usr_name '$usr_uid' <$usr_email>",
 	 "Thanks,\n".
 	 "Testbed Operations\n",
 	 "$TBAPPROVAL",
-	 "Bcc: $TBAUDIT");
+	 "Bcc: $TBAUDIT")
+    if (!$silent);
 
 #
 # Do we have a keyfile? If so, rerun addpubkey for real now that the
 # user is created and email is sent.
 #
-if (defined($keyfile)) {
+if (@keyfiles) {
     # Set the implied user for addpubkey.
     $ENV{'HTTP_INVOKING_USER'} = $usr_idx;
-    my $result   = `$addpubkey -u $usr_uid -f $keyfile`;
-    chomp($result);
-    fatal("Could not parse public key: $result")
-	if ($?);
-    unlink($keyfile)
-	if (! $debug);
-    
+    my $opt = ($silent ? "-s" : "");
+
+    foreach my $keyfile (@keyfiles) {
+	my $result = `$addpubkey $opt -u $usr_uid -f $keyfile`;
+	chomp($result);
+	fatal("Could not parse public key: $result")
+	    if ($?);
+	
+	unlink($keyfile)
+	    if (! $debug);
+    }
 }
 
 # The web interface requires this line to be printed!
@@ -442,8 +480,11 @@ exit(0);
 sub fatal($) {
     my($mesg) = $_[0];
 
-    unlink($keyfile)
-	if (defined($keyfile) && !$debug);
+    if (@keyfiles && !$debug) {
+	foreach my $keyfile (@keyfiles) {
+	    unlink($keyfile)
+	}
+    }
 
     print STDERR "*** $0:\n".
 	         "    $mesg\n";
@@ -452,8 +493,11 @@ sub fatal($) {
 sub UserError($) {
     my($mesg) = $_[0];
 
-    unlink($keyfile)
-	if (defined($keyfile) && !$debug);
+    if (@keyfiles && !$debug) {
+	foreach my $keyfile (@keyfiles) {
+	    unlink($keyfile)
+	}
+    }
 
     print $mesg;
     exit(1);