From ae77bdb6022576985644bae7ed70ecda79718fe1 Mon Sep 17 00:00:00 2001 From: "Leigh B. Stoller" <stoller@flux.utah.edu> Date: Mon, 26 Aug 2002 23:06:38 +0000 Subject: [PATCH] Rework all of the ssh key handling. Moved the parsing and verification to an external perl script, and use ssh-keygen to attempt conversion off SSH2/SECSH key formats. This is actually a simplification of the php code, which is not generally very good at this kind of thing (or maybe I mean perl is just better at it). The parsing and error handling it also much improved. --- account/addpubkey.in | 285 +++++++++++++++++++++++++++++++++++ account/webaddpubkey.in | 25 +++ utils/GNUmakefile.in | 2 +- utils/addpubkey.in | 285 +++++++++++++++++++++++++++++++++++ utils/webaddpubkey.in | 25 +++ www/cdromcheckin.php3 | 21 +-- www/defs.php3.in | 13 ++ www/joinproject.php3 | 114 +++++++------- www/newproject.php3 | 125 +++++++-------- www/showpubkeys.php3 | 157 ++++++++----------- www/stoller-emulab-defs.php3 | 10 +- www/stoller-home-defs.php3 | 10 +- 12 files changed, 821 insertions(+), 251 deletions(-) create mode 100644 account/addpubkey.in create mode 100644 account/webaddpubkey.in create mode 100644 utils/addpubkey.in create mode 100644 utils/webaddpubkey.in diff --git a/account/addpubkey.in b/account/addpubkey.in new file mode 100644 index 0000000000..53fc4db1db --- /dev/null +++ b/account/addpubkey.in @@ -0,0 +1,285 @@ +#!/usr/bin/perl -wT +# +# EMULAB-COPYRIGHT +# Copyright (c) 2000-2002 University of Utah and the Flux Group. +# All rights reserved. +# +use English; +use Getopt::Std; + +# +# Parse ssh public keys and enter into the DB. The default format is +# openssh, but if the key is not in that format, then use ssh-keygen +# to see if it can be converted from either SSH2 or SECSH format into +# openssh format. This gets called from the webpage to parse keys +# uploaded by users. +# +sub usage() +{ + print "Usage: addpubkeys [-n] [-a] [-k] <user> [<keyfile> | <key>]\n"; + print "Options:\n"; + print " -k Indicates that key was passed in on the command line\n"; + print " -n Verify key format only; do not enter into into DB\n"; + print " -a Audit mode; send audit message to log file\n"; + exit(-1); +} +my $optlist = "kna"; +my $iskey = 0; +my $verify = 0; +my $auditmode = 0; + +# +# Configure variables +# +my $TB = "@prefix@"; +my $TBOPS = "@TBOPSEMAIL@"; +my $TBAUDIT = "@TBAUDITEMAIL@"; + +# +# Testbed Support libraries +# +use lib "@prefix@/lib"; +use libdb; +use libtestbed; + +# +# Turn off line buffering on output +# +$| = 1; + +# +# Untaint the path +# +$ENV{'PATH'} = "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin"; +delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'}; + +# +# Please do not run it as root. Hard to track what has happened. +# +if ($UID == 0) { + die("*** $0:\n". + " Please do not run this as root!\n"); +} + +# +# Parse command arguments. Once we return from getopts, all that should be +# left are the required arguments. +# +%options = (); +if (! getopts($optlist, \%options)) { + usage(); +} +if (defined($options{"k"})) { + $iskey = 1; +} +if (defined($options{"n"})) { + $verify = 1; +} +if (defined($options{"a"})) { + $auditmode = 1; +} +if (@ARGV != 2) { + usage(); +} +my $user = $ARGV[0]; +my $keyfile = $ARGV[1]; +my $keyline; +my $key; +my $comment; +my $db_uid; +my $db_name = "Testbed Operations"; +my $db_email = $TBOPS; +my $user_name; +my $user_email; + +# +# Untaint the arguments. +# +if ($iskey) { + if ($keyfile =~ /^([-\w\s\.\@\+\/\=]*)$/) { + $keyfile = $1; + } + else { + fatal("Tainted key: $keyfile"); + } + $keyline = $keyfile; + print "$keyline\n"; +} +else { + if ($keyfile =~ /^([-\w\.\/]+)$/) { + $keyfile = $1; + } + else { + fatal("Tainted filename: $keyfile"); + } + if (! -e $keyfile) { + fatal("*** $0\n". + " No such file: $keyfile\n"); + } + $keyline = `head -1 $keyfile`; +} +if ($user =~ /^([a-z0-9]+)$/i) { + $user = $1; +} +else { + fatal("Tainted username: $user"); +} + +# +# Check user and get his DB uid and email stuff, unless only verfying +# the format of the key, or if its a new user and the caller is "nobody". +# In that case, the user better not exist. +# +if (getpwuid($UID) eq "nobody") { + if (getpwnam($user) || + UserDBInfo($user, \$user_name, \$user_email)) { + fatal("*** $0:\n". + " Attempt to insert first key for existing user!\n"); + } +} +elsif (! $verify) { + if (! UNIX2DBUID($UID, \$db_uid)) { + fatal("*** $0:\n". + " You do not exist in the Emulab Database.\n"); + } + if (! UserDBInfo($db_uid, \$db_name, \$db_email)) { + fatal("*** $0:\n". + " Cannot determine your name and email address.\n"); + } + if ($user ne $db_uid) { + # + # Only admins can set pubkeys for another user. + # + if (!TBAdmin($UID)) { + fatal("*** $0:\n". + " You are not allowed to set pubkeys for $user.\n"); + } + + if (! UserDBInfo($user, \$user_name, \$user_email)) { + fatal("*** $0:\n". + " Cannot determine name and email address for $user.\n"); + } + # Always audit when setting other people's keys. + $auditmode = 1; + } + else { + $user_name = $db_name; + $user_email = $db_email; + } +} + +# +# Grab the first line of the file. Parse it to see if its in the +# format we like (openssh), either protocol 1 or 2. +# +if (ParseKey($keyline)) { + if ($auditmode) { + audit(); + } + exit 0; +} +# If the key was entered on the command line, then nothing more to do. +if ($iskey) { + exit 1; +} + +# +# Run ssh-keygen over it and see if it can convert it. +# +if (! open(KEYGEN, "ssh-keygen -i -f $keyfile 2>/dev/null |")) { + fatal("*** $0:\n". + " Could not start ssh-keygen\n"); +} +$keyline = <KEYGEN>; +if (close(KEYGEN) && ParseKey($keyline)) { + if ($auditmode) { + audit(); + } + exit 0; +} +exit 1; + +sub ParseKey($) { + my ($keyline) = @_; + + if ($keyline =~ /^(\d*\s\d*\s[0-9a-zA-Z]*) ([-\w\@\.]*)$/) { + # Protocol 1 + $type = "ssh-rsa1"; + $key = $1; + $comment = $2; + } + elsif ($keyline =~ /^(\d*\s\d*\s[0-9a-zA-Z]*)\s*$/) { + # Protocol 1 but no comment field. + $type = "ssh-rsa1"; + $key = $1; + } + elsif ($keyline =~ + /^(ssh-rsa|ssh-dss) ([-\w\.\@\+\/\=]*) ([-\w\@\.]*)$/) { + # Protocol 2 + $type = $1; + $key = "$1 $2"; + $comment = $3; + } + elsif ($keyline =~ /^(ssh-rsa|ssh-dss) ([-\w\.\@\+\/\=]*)$/) { + # Protocol 2 but no comment field + $type = $1; + $key = "$1 $2"; + } + + if (!defined($key)) { + return 0; + } + # Do not enter into DB if in verify mode. + if ($verify) { + return 1; + } + + # + # Make up a comment field for the DB index. Need something. + # + if (!defined($comment)) { + $comment = "$type-${user_email}"; + } + $key = "$key $comment"; + + DBQueryFatal("replace into user_pubkeys ". + "values ('$user', '$comment', '$key', now())"); + + return 1; +} + +sub audit() +{ + my $chunked = ""; + + while (length($key)) { + $chunked .= substr($key, 0, 65, ""); + if (length($key)) { + $chunked .= "\n"; + } + } + + SENDMAIL("$user_name <$user_email>", + "SSH Public Key for '$user' Added", + "SSH Public Key for '$user' added by '$db_uid'.\n". + "\n". + "$chunked\n", + "$db_name <$db_email>", "Bcc: $TBAUDIT"); +} + +sub fatal($) +{ + my($mesg) = $_[0]; + + print STDERR "$mesg\n"; + + # + # Send a message to the testbed list. + # + SENDMAIL($TBOPS, + "SSH Public key insertion failed!", + $mesg, + "$db_name <$db_email>"); + exit(-1); +} + diff --git a/account/webaddpubkey.in b/account/webaddpubkey.in new file mode 100644 index 0000000000..bcbd52680b --- /dev/null +++ b/account/webaddpubkey.in @@ -0,0 +1,25 @@ +#!/usr/bin/perl -w + +# +# EMULAB-COPYRIGHT +# Copyright (c) 2000-2002 University of Utah and the Flux Group. +# All rights reserved. +# + +use English; + +# +# This gets invoked from the Web interface. Simply a wrapper ... +# + +# +# Configure variables +# +my $TB = "@prefix@"; + +# +# Run the real thing, and never return. +# +exec "$TB/bin/addpubkey", @ARGV; + +die("webaddpubkey: Could not exec addpubkey: $!"); diff --git a/utils/GNUmakefile.in b/utils/GNUmakefile.in index 85c504e9e8..a511c86986 100644 --- a/utils/GNUmakefile.in +++ b/utils/GNUmakefile.in @@ -12,7 +12,7 @@ UNIFIED = @UNIFIED_BOSS_AND_OPS@ include $(OBJDIR)/Makeconf -BIN_SCRIPTS = delay_config sshtb create_image node_admin +BIN_SCRIPTS = delay_config sshtb create_image node_admin addpubkey SBIN_SCRIPTS = vlandiff vlansync withadminprivs export_tables cvsupd.pl LIBEXEC_SCRIPTS = webcreateimage webaddpubkey diff --git a/utils/addpubkey.in b/utils/addpubkey.in new file mode 100644 index 0000000000..53fc4db1db --- /dev/null +++ b/utils/addpubkey.in @@ -0,0 +1,285 @@ +#!/usr/bin/perl -wT +# +# EMULAB-COPYRIGHT +# Copyright (c) 2000-2002 University of Utah and the Flux Group. +# All rights reserved. +# +use English; +use Getopt::Std; + +# +# Parse ssh public keys and enter into the DB. The default format is +# openssh, but if the key is not in that format, then use ssh-keygen +# to see if it can be converted from either SSH2 or SECSH format into +# openssh format. This gets called from the webpage to parse keys +# uploaded by users. +# +sub usage() +{ + print "Usage: addpubkeys [-n] [-a] [-k] <user> [<keyfile> | <key>]\n"; + print "Options:\n"; + print " -k Indicates that key was passed in on the command line\n"; + print " -n Verify key format only; do not enter into into DB\n"; + print " -a Audit mode; send audit message to log file\n"; + exit(-1); +} +my $optlist = "kna"; +my $iskey = 0; +my $verify = 0; +my $auditmode = 0; + +# +# Configure variables +# +my $TB = "@prefix@"; +my $TBOPS = "@TBOPSEMAIL@"; +my $TBAUDIT = "@TBAUDITEMAIL@"; + +# +# Testbed Support libraries +# +use lib "@prefix@/lib"; +use libdb; +use libtestbed; + +# +# Turn off line buffering on output +# +$| = 1; + +# +# Untaint the path +# +$ENV{'PATH'} = "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin"; +delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'}; + +# +# Please do not run it as root. Hard to track what has happened. +# +if ($UID == 0) { + die("*** $0:\n". + " Please do not run this as root!\n"); +} + +# +# Parse command arguments. Once we return from getopts, all that should be +# left are the required arguments. +# +%options = (); +if (! getopts($optlist, \%options)) { + usage(); +} +if (defined($options{"k"})) { + $iskey = 1; +} +if (defined($options{"n"})) { + $verify = 1; +} +if (defined($options{"a"})) { + $auditmode = 1; +} +if (@ARGV != 2) { + usage(); +} +my $user = $ARGV[0]; +my $keyfile = $ARGV[1]; +my $keyline; +my $key; +my $comment; +my $db_uid; +my $db_name = "Testbed Operations"; +my $db_email = $TBOPS; +my $user_name; +my $user_email; + +# +# Untaint the arguments. +# +if ($iskey) { + if ($keyfile =~ /^([-\w\s\.\@\+\/\=]*)$/) { + $keyfile = $1; + } + else { + fatal("Tainted key: $keyfile"); + } + $keyline = $keyfile; + print "$keyline\n"; +} +else { + if ($keyfile =~ /^([-\w\.\/]+)$/) { + $keyfile = $1; + } + else { + fatal("Tainted filename: $keyfile"); + } + if (! -e $keyfile) { + fatal("*** $0\n". + " No such file: $keyfile\n"); + } + $keyline = `head -1 $keyfile`; +} +if ($user =~ /^([a-z0-9]+)$/i) { + $user = $1; +} +else { + fatal("Tainted username: $user"); +} + +# +# Check user and get his DB uid and email stuff, unless only verfying +# the format of the key, or if its a new user and the caller is "nobody". +# In that case, the user better not exist. +# +if (getpwuid($UID) eq "nobody") { + if (getpwnam($user) || + UserDBInfo($user, \$user_name, \$user_email)) { + fatal("*** $0:\n". + " Attempt to insert first key for existing user!\n"); + } +} +elsif (! $verify) { + if (! UNIX2DBUID($UID, \$db_uid)) { + fatal("*** $0:\n". + " You do not exist in the Emulab Database.\n"); + } + if (! UserDBInfo($db_uid, \$db_name, \$db_email)) { + fatal("*** $0:\n". + " Cannot determine your name and email address.\n"); + } + if ($user ne $db_uid) { + # + # Only admins can set pubkeys for another user. + # + if (!TBAdmin($UID)) { + fatal("*** $0:\n". + " You are not allowed to set pubkeys for $user.\n"); + } + + if (! UserDBInfo($user, \$user_name, \$user_email)) { + fatal("*** $0:\n". + " Cannot determine name and email address for $user.\n"); + } + # Always audit when setting other people's keys. + $auditmode = 1; + } + else { + $user_name = $db_name; + $user_email = $db_email; + } +} + +# +# Grab the first line of the file. Parse it to see if its in the +# format we like (openssh), either protocol 1 or 2. +# +if (ParseKey($keyline)) { + if ($auditmode) { + audit(); + } + exit 0; +} +# If the key was entered on the command line, then nothing more to do. +if ($iskey) { + exit 1; +} + +# +# Run ssh-keygen over it and see if it can convert it. +# +if (! open(KEYGEN, "ssh-keygen -i -f $keyfile 2>/dev/null |")) { + fatal("*** $0:\n". + " Could not start ssh-keygen\n"); +} +$keyline = <KEYGEN>; +if (close(KEYGEN) && ParseKey($keyline)) { + if ($auditmode) { + audit(); + } + exit 0; +} +exit 1; + +sub ParseKey($) { + my ($keyline) = @_; + + if ($keyline =~ /^(\d*\s\d*\s[0-9a-zA-Z]*) ([-\w\@\.]*)$/) { + # Protocol 1 + $type = "ssh-rsa1"; + $key = $1; + $comment = $2; + } + elsif ($keyline =~ /^(\d*\s\d*\s[0-9a-zA-Z]*)\s*$/) { + # Protocol 1 but no comment field. + $type = "ssh-rsa1"; + $key = $1; + } + elsif ($keyline =~ + /^(ssh-rsa|ssh-dss) ([-\w\.\@\+\/\=]*) ([-\w\@\.]*)$/) { + # Protocol 2 + $type = $1; + $key = "$1 $2"; + $comment = $3; + } + elsif ($keyline =~ /^(ssh-rsa|ssh-dss) ([-\w\.\@\+\/\=]*)$/) { + # Protocol 2 but no comment field + $type = $1; + $key = "$1 $2"; + } + + if (!defined($key)) { + return 0; + } + # Do not enter into DB if in verify mode. + if ($verify) { + return 1; + } + + # + # Make up a comment field for the DB index. Need something. + # + if (!defined($comment)) { + $comment = "$type-${user_email}"; + } + $key = "$key $comment"; + + DBQueryFatal("replace into user_pubkeys ". + "values ('$user', '$comment', '$key', now())"); + + return 1; +} + +sub audit() +{ + my $chunked = ""; + + while (length($key)) { + $chunked .= substr($key, 0, 65, ""); + if (length($key)) { + $chunked .= "\n"; + } + } + + SENDMAIL("$user_name <$user_email>", + "SSH Public Key for '$user' Added", + "SSH Public Key for '$user' added by '$db_uid'.\n". + "\n". + "$chunked\n", + "$db_name <$db_email>", "Bcc: $TBAUDIT"); +} + +sub fatal($) +{ + my($mesg) = $_[0]; + + print STDERR "$mesg\n"; + + # + # Send a message to the testbed list. + # + SENDMAIL($TBOPS, + "SSH Public key insertion failed!", + $mesg, + "$db_name <$db_email>"); + exit(-1); +} + diff --git a/utils/webaddpubkey.in b/utils/webaddpubkey.in new file mode 100644 index 0000000000..bcbd52680b --- /dev/null +++ b/utils/webaddpubkey.in @@ -0,0 +1,25 @@ +#!/usr/bin/perl -w + +# +# EMULAB-COPYRIGHT +# Copyright (c) 2000-2002 University of Utah and the Flux Group. +# All rights reserved. +# + +use English; + +# +# This gets invoked from the Web interface. Simply a wrapper ... +# + +# +# Configure variables +# +my $TB = "@prefix@"; + +# +# Run the real thing, and never return. +# +exec "$TB/bin/addpubkey", @ARGV; + +die("webaddpubkey: Could not exec addpubkey: $!"); diff --git a/www/cdromcheckin.php3 b/www/cdromcheckin.php3 index 99d54be00a..376a1cd702 100644 --- a/www/cdromcheckin.php3 +++ b/www/cdromcheckin.php3 @@ -54,7 +54,8 @@ if (! mysql_num_rows($query_result)) { SPITSTATUS(CDROMSTATUS_BADCDKEY); return; } -$row = mysql_fetch_array($query_result); +$row = mysql_fetch_array($query_result); +$cdvers = $row[version]; # # Grab the privkey record. First squeeze out any spaces. @@ -148,15 +149,7 @@ DBQueryFatal("update widearea_privkeys ". header("Content-Type: text/plain"); echo "privkey=$newkey\n"; -if (0) { - echo "fdisk=http://${WWWHOST}/images/image.fdisk\n"; - echo "slice1_image=http://${WWWHOST}/images/slice1.ndz\n"; - echo "slice1_md5=2970e2cf045f5872c6728eeea3b51dae\n"; - echo "slicex_mount=/users\n"; - echo "slicex_tarball=http://${WWWHOST}/images/slicex.tar.gz\n"; - echo "slicex_md5=1f84fbc3434d174151ac3a2b8389799a\n"; -} -else { +if ($cdvers == 1) { echo "fdisk=image.fdisk\n"; echo "slice1_image=slice1.ndz\n"; echo "slice1_md5=cb810b43f49d15b3ac4122ff42f8925d\n"; @@ -164,5 +157,13 @@ else { echo "slicex_tarball=slicex.tar.gz\n"; echo "slicex_md5=1f84fbc3434d174151ac3a2b8389799a\n"; } +else { + echo "fdisk=http://${WWWHOST}/images/image.fdisk\n"; + echo "slice1_image=http://${WWWHOST}/images/slice1-v2.ndz\n"; + echo "slice1_md5=5389a2687cee16ff212bbd842585a5d5\n"; + echo "slicex_mount=/users\n"; + echo "slicex_tarball=http://${WWWHOST}/images/slicex.tar.gz\n"; + echo "slicex_md5=1f84fbc3434d174151ac3a2b8389799a\n"; +} echo "emulab_status=0\n"; diff --git a/www/defs.php3.in b/www/defs.php3.in index 5ce574dc35..2686563544 100644 --- a/www/defs.php3.in +++ b/www/defs.php3.in @@ -169,6 +169,19 @@ function SUEXEC($uid, $gid, $cmdandargs, $die) { return $retval; } +function ADDPUBKEY($uid, $cmdandargs) { + global $TBSUEXEC_PATH; + + ignore_user_abort(1); + + $output = array(); + $retval = 0; + $result = exec("$TBSUEXEC_PATH $uid nobody $cmdandargs", + $output, $retval); + + return $retval; +} + # # Verify a URL. # diff --git a/www/joinproject.php3 b/www/joinproject.php3 index f5a13983c1..0392343955 100644 --- a/www/joinproject.php3 +++ b/www/joinproject.php3 @@ -44,9 +44,10 @@ function SPITFORM($formfields, $returning, $errors) PAGEHEADER("Apply for Project Membership"); if ($errors) { - echo "<table align=center border=0 cellpadding=0 cellspacing=2> + echo "<table class=stealth + align=center border=0 cellpadding=0 cellspacing=2> <tr> - <td nowrap align=center colspan=3> + <td class=stealth nowrap align=center colspan=3> <font size=+1 color=red> Oops, please fix the following errors! </font> @@ -55,9 +56,11 @@ function SPITFORM($formfields, $returning, $errors) while (list ($name, $message) = each ($errors)) { echo "<tr> - <td align=right><font color=red>$name:</font></td> - <td>   </td> - <td align=left><font color=red>$message</font></td> + <td class=stealth align=right> + <font color=red>$name:</font></td> + <td class=stealth>   </td> + <td class=stealth align=left> + <font color=red>$message</font></td> </tr>\n"; } echo "</table><br>\n"; @@ -204,6 +207,7 @@ function SPITFORM($formfields, $returning, $errors) <br> <input type=text name=\"formfields[usr_key]\" + value=\"$formfields[usr_key]\" size=50 maxlength=1024> </td> @@ -275,7 +279,15 @@ function SPITFORM($formfields, $returning, $errors) if (! $returning) { echo "<li> If you want us to use your existing ssh public key, then either paste it in or specify the path to your - your identity.pub file. + your identity.pub file. <font color=red>NOTE:</font> + We use the <a href=www.openssh.org>OpenSSH</a> key format, + which has a slightly different protocol 2 public key format + than some of the commercial vendors such as + <a href=www.ssh.com>SSH Communications</a>. If you + use one of these commercial vendors, then please + upload the public key file and we will convert it + for you. <i>Please do not paste it in.</i>\n + <li> Note to <a href=http://www.opera.com><b>Opera 5</b></a> users: The file upload mechanism is broken in Opera, so you cannot specify a local file for upload. Instead, @@ -451,55 +463,41 @@ if (!$returning) { } # - # Pasted in key. - # + # Pub Key. + # if (isset($formfields[usr_key]) && strcmp($formfields[usr_key], "")) { # - # Replace any embedded newlines first. - # - $formfields[usr_key] = ereg_replace("[\n]", "", $formfields[usr_key]); - + # This is passed off to the shell, so taint check it. + # if (! preg_match("/^[-\w\s\.\@\+\/\=]*$/", $formfields[usr_key])) { $errors["PubKey"] = "Invalid characters"; - - SPITFORM($formfields, $errors); - PAGEFOOTER(); - return; } else { - $usr_key[] = $formfields[usr_key]; + # + # Replace any embedded newlines first. + # + $formfields[usr_key] = + ereg_replace("[\n]", "", $formfields[usr_key]); + $usr_key = $formfields[usr_key]; + $addpubkeyargs = "-k $joining_uid '$usr_key' "; } } - + # # If usr provided a file for the key, it overrides the paste in text. - # Must read and check it. # if (isset($usr_keyfile) && strcmp($usr_keyfile, "") && strcmp($usr_keyfile, "none")) { - if (! ($fp = fopen($usr_keyfile, "r"))) { - TBERROR("Could not open $usr_keyfile", 1); + if (! stat($usr_keyfile)) { + $errors["PubKey File"] = "No such file"; } - while (!feof($fp)) { - $buffer = fgets($fp, 4096); - - if (ereg("^[\n\#]", $buffer)) - continue; - - if (! preg_match("/^[-\w\s\.\@\+\/\=\r\n]*$/", $buffer)) { - $errors["PubKey File Contents"] = "Invalid characters"; - - fclose($fp); - SPITFORM($formfields, $returning, $errors); - PAGEFOOTER(); - return; - } - $usr_key[] = Chop($buffer); + else { + $addpubkeyargs = "$joining_uid $usr_keyfile"; + chmod($usr_keyfile, 0640); } - fclose($fp); } } else { @@ -542,6 +540,14 @@ elseif (TBGroupMember($joining_uid, $pid, $gid, $approved)) { $errors["Membership"] = "You are already a member"; } +# +# Verify key format. +# +if (isset($addpubkeyargs) && + ADDPUBKEY("nobody", "webaddpubkey -n $addpubkeyargs")) { + $errors["Pubkey Format"] = "Could not be parsed. Is it a public key?"; +} + if (count($errors)) { SPITFORM($formfields, $returning, $errors); PAGEFOOTER(); @@ -557,6 +563,14 @@ if (count($errors)) { if (! $returning) { $encoding = crypt("$password1"); + # + # Must be done before user record is inserted! + # XXX Since user does not exist, must run as nobody. Script checks. + # + if (isset($addpubkeyargs)) { + ADDPUBKEY("nobody", "webaddpubkey $addpubkeyargs"); + } + DBQueryFatal("INSERT INTO users ". "(uid,usr_created,usr_expires,usr_name,usr_email,usr_addr,". " usr_URL,usr_phone,usr_title,usr_affil,usr_pswd,unix_uid,". @@ -567,32 +581,6 @@ if (! $returning) { "'$encoding', NULL, 'newuser', ". "date_add(now(), interval 1 year), now())"); - if (isset($usr_key)) { - while (list ($idx, $stuff) = each ($usr_key)) { - # - # Need to separate out the comment field. - # - $pieces = explode(" ", $stuff); - - if (count($pieces) == 4) { - $key = "$pieces[0] $pieces[1] $pieces[2] $pieces[3]"; - $comment = $pieces[3]; - } - elseif (count($pieces) == 3) { - $key = "$pieces[0] $pieces[1] $pieces[2]"; - $comment = $pieces[0] . "-" . $pieces[2]; - } - elseif (count($pieces) == 1) { - continue; - } - else { - TBERROR("Improper key: $stuff", 0); - } - DBQueryFatal("replace into user_pubkeys ". - "values ('$joining_uid', '$comment', '$key', now())"); - } - } - $key = GENKEY($joining_uid); TBMAIL("$usr_name '$joining_uid' <$usr_email>", diff --git a/www/newproject.php3 b/www/newproject.php3 index 781c32158f..ab11eef96f 100755 --- a/www/newproject.php3 +++ b/www/newproject.php3 @@ -51,9 +51,10 @@ function SPITFORM($formfields, $returning, $errors) </font></center><br>\n"; if ($errors) { - echo "<table align=center border=0 cellpadding=0 cellspacing=2> + echo "<table class=stealth + align=center border=0 cellpadding=0 cellspacing=2> <tr> - <td nowrap align=center colspan=3> + <td class=stealth nowrap align=center colspan=3> <font size=+1 color=red> Oops, please fix the following errors! </font> @@ -62,9 +63,11 @@ function SPITFORM($formfields, $returning, $errors) while (list ($name, $message) = each ($errors)) { echo "<tr> - <td align=right><font color=red>$name:</font></td> - <td>   </td> - <td align=left><font color=red>$message</font></td> + <td class=stealth align=right> + <font color=red>$name:</font></td> + <td class=stealth>   </td> + <td class=stealth align=left> + <font color=red>$message</font></td> </tr>\n"; } echo "</table><br>\n"; @@ -220,6 +223,7 @@ function SPITFORM($formfields, $returning, $errors) <br> <input type=text name=\"formfields[usr_key]\" + value=\"$formfields[usr_key]\" size=50 maxlength=1024> </td> @@ -431,7 +435,15 @@ function SPITFORM($formfields, $returning, $errors) if (! $returning) { echo "<li> If you want us to use your existing ssh public key, then either paste it in or specify the path to your - your identity.pub file. + your identity.pub file. <font color=red>NOTE:</font> + We use the <a href=www.openssh.org>OpenSSH</a> key format, + which has a slightly different protocol 2 public key format + than some of the commercial vendors such as + <a href=www.ssh.com>SSH Communications</a>. If you + use one of these commercial vendors, then please + upload the public key file and we will convert it + for you. <i>Please do not paste it in.</i>\n + <li> Note to <a href=http://www.opera.com><b>Opera 5</b></a> users: The file upload mechanism is broken in Opera, so you cannot specify a local file for upload. Instead, @@ -574,11 +586,6 @@ if (! $returning) { $formfields[usr_email], $checkerror)) { $errors["Password"] = "$checkerror"; } - if (isset($formfields[usr_key]) && - strcmp($formfields[usr_key], "") && - ! ereg("^[0-9a-zA-Z\@\. ]*$", $formfields[usr_key])) { - $errors["PubKey"] = "Invalid characters"; - } } if (!isset($formfields[pid]) || @@ -694,55 +701,54 @@ if (!$returning) { } # - # Pasted in key. - # + # Pub Key. + # if (isset($formfields[usr_key]) && strcmp($formfields[usr_key], "")) { # - # Replace any embedded newlines first. - # - $formfields[usr_key] = ereg_replace("[\n]", "", $formfields[usr_key]); - + # This is passed off to the shell, so taint check it. + # if (! preg_match("/^[-\w\s\.\@\+\/\=]*$/", $formfields[usr_key])) { $errors["PubKey"] = "Invalid characters"; - - SPITFORM($formfields, $errors); - PAGEFOOTER(); - return; } else { - $usr_key[] = $formfields[usr_key]; + # + # Replace any embedded newlines first. + # + $formfields[usr_key] = + ereg_replace("[\n]", "", $formfields[usr_key]); + $usr_key = $formfields[usr_key]; + $addpubkeyargs = "-k $proj_head_uid '$usr_key' "; } } - + # # If usr provided a file for the key, it overrides the paste in text. - # Must read and check it. # if (isset($usr_keyfile) && strcmp($usr_keyfile, "") && strcmp($usr_keyfile, "none")) { - if (! ($fp = fopen($usr_keyfile, "r"))) { - TBERROR("Could not open $usr_keyfile", 1); + if (! stat($usr_keyfile)) { + $errors["PubKey File"] = "No such file"; } - while (!feof($fp)) { - $buffer = fgets($fp, 4096); - - if (ereg("^[\n\#]", $buffer)) - continue; - - if (! preg_match("/^[-\w\s\.\@\+\/\=\r\n]*$/", $buffer)) { - $errors["PubKey File Contents"] = "Invalid characters"; - - fclose($fp); - SPITFORM($formfields, $returning, $errors); - PAGEFOOTER(); - return; - } - $usr_key[] = Chop($buffer); + else { + $addpubkeyargs = "$proj_head_uid $usr_keyfile"; + chmod($usr_keyfile, 0640); } - fclose($fp); + } + # + # Verify key format. + # + if (isset($addpubkeyargs) && + ADDPUBKEY("nobody", "webaddpubkey -n $addpubkeyargs")) { + $errors["Pubkey Format"] = "Could not be parsed. Is it a public key?"; + } + + if (count($errors)) { + SPITFORM($formfields, $returning, $errors); + PAGEFOOTER(); + return; } } else { @@ -811,6 +817,14 @@ if (mysql_num_rows($query_result)) { if (! $returning) { $encoding = crypt("$password1"); + # + # Must be done before user record is inserted! + # XXX Since, user does not exist, must run as nobody. Script checks. + # + if (isset($addpubkeyargs)) { + ADDPUBKEY("nobody", "webaddpubkey $addpubkeyargs"); + } + DBQueryFatal("INSERT INTO users ". "(uid,usr_created,usr_expires,usr_name,usr_email,usr_addr,". " usr_URL,usr_title,usr_affil,usr_phone,usr_pswd,unix_uid,". @@ -820,33 +834,6 @@ if (! $returning) { "'$usr_phone', '$encoding', NULL, 'newuser', ". "date_add(now(), interval 1 year), now())"); - if (isset($usr_key)) { - while (list ($idx, $stuff) = each ($usr_key)) { - # - # Need to separate out the comment field. - # - $pieces = explode(" ", $stuff); - - if (count($pieces) == 4) { - $key = "$pieces[0] $pieces[1] $pieces[2] $pieces[3]"; - $comment = $pieces[3]; - } - elseif (count($pieces) == 3) { - $key = "$pieces[0] $pieces[1] $pieces[2]"; - $comment = $pieces[0] . "-" . $pieces[2]; - } - elseif (count($pieces) == 1) { - continue; - } - else { - TBERROR("Improper key: $stuff", 0); - } - DBQueryFatal("replace into user_pubkeys ". - "values ('$proj_head_uid', ". - " '$comment', '$key', now())"); - } - } - $key = GENKEY($proj_head_uid); TBMAIL("$usr_name '$proj_head_uid' <$usr_email>", diff --git a/www/showpubkeys.php3 b/www/showpubkeys.php3 index cf1d583b53..2737e13c53 100644 --- a/www/showpubkeys.php3 +++ b/www/showpubkeys.php3 @@ -112,9 +112,10 @@ function SPITFORM($formfields, $errors) </center><br>\n"; if ($errors) { - echo "<table align=center border=0 cellpadding=0 cellspacing=2> + echo "<table class=stealth + align=center border=0 cellpadding=0 cellspacing=2> <tr> - <td align=center colspan=3> + <td class=stealth align=center colspan=3> <font size=+1 color=red> Oops, please fix the following errors! </font> @@ -123,9 +124,11 @@ function SPITFORM($formfields, $errors) while (list ($name, $message) = each ($errors)) { echo "<tr> - <td align=right><font color=red>$name:</font></td> - <td> </td> - <td align=left><font color=red>$message</font></td> + <td class=stealth align=right> + <font color=red>$name:</font></td> + <td class=stealth> </td> + <td class=stealth align=left> + <font color=red>$message</font></td> </tr>\n"; } echo "</table><br>\n"; @@ -153,6 +156,7 @@ function SPITFORM($formfields, $errors) <br> <input type=text name=\"formfields[usr_key]\" + value=\"$formfields[usr_key]\" size=50 maxlength=1024> </td> @@ -199,6 +203,14 @@ function SPITFORM($formfields, $errors) when adding new ssh public keys. </ol> </blockquote></blockquote></blockquote>\n"; + + echo "<font color=red>NOTE:</font> We use the + <a href=www.openssh.org>OpenSSH</a> key format, which has a slightly + different protocol 2 public key format than some of the commercial + vendors such as <a href=www.ssh.com>SSH Communications</a>. If you + use one of these commercial vendors, then please upload the public + key file and we will convert it for you. <i>Please do not paste + it in.</i>\n"; } # @@ -219,58 +231,43 @@ $errors = array(); if (isset($formfields[usr_key]) && strcmp($formfields[usr_key], "")) { - # - # Replace any embedded newlines first. - # - $formfields[usr_key] = ereg_replace("[\n]", "", $formfields[usr_key]); + # + # This is passed off to the shell, so taint check it. + # if (! preg_match("/^[-\w\s\.\@\+\/\=]*$/", $formfields[usr_key])) { $errors["PubKey"] = "Invalid characters"; - - SPITFORM($formfields, $errors); - PAGEFOOTER(); - return; } else { - $usr_key[] = $formfields[usr_key]; + # + # Replace any embedded newlines first. + # + $formfields[usr_key] = ereg_replace("[\n]", "", $formfields[usr_key]); + $usr_key = $formfields[usr_key]; + $addpubkeyargs = "-k $uid '$usr_key' "; } } # # If usr provided a file for the key, it overrides the paste in text. -# Must read and check it. # if (isset($usr_keyfile) && strcmp($usr_keyfile, "") && strcmp($usr_keyfile, "none")) { - if (! ($fp = fopen($usr_keyfile, "r"))) { - TBERROR("Could not open $usr_keyfile", 1); + if (! stat($usr_keyfile)) { + $errors["PubKey File"] = "No such file"; } - while (!feof($fp)) { - $buffer = fgets($fp, 4096); - - if (ereg("^[\n\#]", $buffer)) - continue; - - if (! preg_match("/^[-\w\s\.\@\+\/\=\r\n]*$/", $buffer)) { - $errors["PubKey File Contents"] = "Invalid characters"; - - fclose($fp); - SPITFORM($formfields, $errors); - PAGEFOOTER(); - return; - } - $usr_key[] = Chop($buffer); + else { + $addpubkeyargs = "$uid $usr_keyfile"; + chmod($usr_keyfile, 0640); } - fclose($fp); } # -# Insert each key. The comment field serves as the secondary key -# to avoid duplication. -# -if (isset($usr_key)) { +# Must verify passwd to add keys. +# +if (isset($addpubkeyargs)) { if (! $isadmin) { if (!isset($formfields[password]) || strcmp($formfields[password], "") == 0) { @@ -279,71 +276,35 @@ if (isset($usr_key)) { elseif (VERIFYPASSWD($target_uid, $formfields[password]) != 0) { $errors["Password"] = "Incorrect password"; } - - if (count($errors)) { - SPITFORM($formfields, $errors); - PAGEFOOTER(); - return; - } - } - - $chunky = ""; - - while (list ($idx, $stuff) = each ($usr_key)) { - # - # Need to separate out the comment field. - # - $pieces = explode(" ", $stuff); - - if (count($pieces) == 4) { - $key = "$pieces[0] $pieces[1] $pieces[2] $pieces[3]"; - $comment = $pieces[3]; - } - elseif (count($pieces) == 3) { - $key = "$pieces[0] $pieces[1] $pieces[2]"; - $comment = $pieces[0] . "-" . $pieces[2]; - } - elseif (count($pieces) == 1) { - continue; - } - else { - TBERROR("Improper key: $stuff", 0); - } - DBQueryFatal("replace into user_pubkeys ". - "values ('$target_uid', '$comment', '$key', now())"); - - $chunky .= chunk_split($key, 70, "\n"); - $chunky .= "\n"; } +} +else { + $errors["Missing Args"] = "Please supply a key or a keyfile"; +} - DBQueryFatal("update users set usr_modified=now() ". - "where uid='$target_uid'"); - - # - # Audit - # - TBUserInfo($uid, $uid_name, $uid_email); - TBUserInfo($target_uid, $targuid_name, $targuid_email); - - TBMAIL("$targuid_name <$targuid_email>", - "SSH Public Key for '$target_uid' Added", - "\n". - "SSH Public Key for '$target_uid' added by '$uid'.\n". - "\n". - "$chunky\n". - "\n". - "Thanks,\n". - "Testbed Ops\n". - "Utah Network Testbed\n", - "From: $uid_name <$uid_email>\n". - "Cc: $TBMAIL_AUDIT\n". - "Errors-To: $TBMAIL_WWW"); +# Spit the errors +if (count($errors)) { + SPITFORM($formfields, $errors); + PAGEFOOTER(); + return; +} - # - # mkacct updates the user pubkeys. - # - SUEXEC($uid, $TBADMINGROUP, "webmkacct -a $target_uid", 0); +# +# Okay, first run the script in verify mode to see if the key is +# parsable. If it is, then do it for real. +# +if (ADDPUBKEY($uid, "webaddpubkey -n $addpubkeyargs")) { + $errors["Pubkey Format"] = "Could not be parsed. Is it a public key?"; + SPITFORM($formfields, $errors); + PAGEFOOTER(); + return; } +ADDPUBKEY($uid, "webaddpubkey -a $addpubkeyargs"); + +# +# mkacct updates the user pubkeys in ~ssh/authorized_keys. +# +SUEXEC($uid, $TBADMINGROUP, "webmkacct -a $target_uid", 0); header("Location: showpubkeys.php3?target_uid=$target_uid&finished=1"); ?> diff --git a/www/stoller-emulab-defs.php3 b/www/stoller-emulab-defs.php3 index 55abbf60ad..ba5f05d2fe 100644 --- a/www/stoller-emulab-defs.php3 +++ b/www/stoller-emulab-defs.php3 @@ -24,14 +24,14 @@ $BANNERCOLOR = "#ABABE0"; $THISHOMEBASE = "Stoller.Emulab.Net"; $THISPROJECT = "Stoller's Utah Network Testbed"; -$TBMAILADDR_OPS = "stoller@fast.cs.utah.edu"; +$TBMAILADDR_OPS = "stoller@flux.utah.edu"; $TBMAIL_OPS = "Testbed Ops <$TBMAILADDR_OPS>"; -$TBMAILADDR_WWW = "stoller@fast.cs.utah.edu"; +$TBMAILADDR_WWW = "stoller@flux.utah.edu"; $TBMAIL_WWW = "Testbed WWW <$TBMAILADDR_WWW>"; -$TBMAILADDR_APPROVAL = "stoller@fast.cs.utah.edu"; +$TBMAILADDR_APPROVAL = "stoller@flux.utah.edu"; $TBMAIL_APPROVAL = "Testbed Approval <$TBMAILADDR_APPROVAL>"; -$TBMAILADDR_LOGS = "stoller@fast.cs.utah.edu"; +$TBMAILADDR_LOGS = "stoller@flux.utah.edu"; $TBMAIL_LOGS = "Testbed Logs <$TBMAILADDR_LOGS>"; -$TBMAILADDR_AUDIT = "stoller@fast.cs.utah.edu"; +$TBMAILADDR_AUDIT = "stoller@flux.utah.edu"; $TBMAIL_AUDIT = "Testbed Audit <$TBMAILADDR_AUDIT>"; ?> diff --git a/www/stoller-home-defs.php3 b/www/stoller-home-defs.php3 index d46a381afa..8d9e5ddccf 100644 --- a/www/stoller-home-defs.php3 +++ b/www/stoller-home-defs.php3 @@ -25,14 +25,14 @@ $BANNERCOLOR = "#ABABE0"; $THISHOMEBASE = "Stoller.Emulab.Net"; $THISPROJECT = "My Home Network Testbed"; -$TBMAILADDR_OPS = "stoller@fast.cs.utah.edu"; +$TBMAILADDR_OPS = "stoller@stoller.casco.net"; $TBMAIL_OPS = "Testbed Ops <$TBMAILADDR_OPS>"; -$TBMAILADDR_WWW = "stoller@fast.cs.utah.edu"; +$TBMAILADDR_WWW = "stoller@stoller.casco.net"; $TBMAIL_WWW = "Testbed WWW <$TBMAILADDR_WWW>"; -$TBMAILADDR_APPROVAL = "stoller@fast.cs.utah.edu"; +$TBMAILADDR_APPROVAL = "stoller@stoller.casco.net"; $TBMAIL_APPROVAL = "Testbed Approval <$TBMAILADDR_APPROVAL>"; -$TBMAILADDR_LOGS = "stoller@fast.cs.utah.edu"; +$TBMAILADDR_LOGS = "stoller@stoller.casco.net"; $TBMAIL_LOGS = "Testbed Logs <$TBMAILADDR_LOGS>"; -$TBMAILADDR_AUDIT = "stoller@fast.cs.utah.edu"; +$TBMAILADDR_AUDIT = "stoller@stoller.casco.net"; $TBMAIL_AUDIT = "Testbed Audit <$TBMAILADDR_AUDIT>"; ?> -- GitLab