Commit 2e3f0abc authored by Leigh Stoller's avatar Leigh Stoller

Commit my changes that use the UUID in the certificate, rather then the

uid of the user. Not sure this change will survive in its present form
since this was done for protogeni and the spec will probably call for
something different. But this is what it is for now. Note that the server
side is backwards compatable with old certs, at least for now.
parent 54749a00
#!/usr/bin/perl -wT
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2004, 2006, 2007 University of Utah and the Flux Group.
# Copyright (c) 2000-2008 University of Utah and the Flux Group.
# All rights reserved.
#
use strict;
use English;
use Getopt::Std;
use Fcntl ':flock';
#
# Load the Testbed support stuff.
......@@ -23,13 +22,14 @@ use User;
#
sub usage()
{
print("Usage: mkusercert [-d] [-o] [-p password] <user>\n");
print("Usage: mkusercert [-d] [-o] [-g] [-p password] <user>\n");
exit(-1);
}
my $optlist = "dp:o";
my $debug = 0;
my $output = 0;
my $password;
my $optlist = "dp:og";
my $debug = 0;
my $output = 0;
my $password = "";
my $geniflag = 0;
#
# Configure variables
......@@ -40,6 +40,7 @@ my $TBLOGS = "@TBLOGSEMAIL@";
my $OURDOMAIN = "@OURDOMAIN@";
my $CONTROL = "@USERNODE@";
my $BOSSNODE = "@BOSSNODE@";
my $OU = "sslxmlrpc"; # orgunit
# Locals
my $USERDIR = USERROOT();
......@@ -52,6 +53,11 @@ my $OPENSSL = "/usr/bin/openssl";
my $WORKDIR = "$TB/ssl";
my $SAVEUID = $UID;
# Locals
my $encrypted = 0;
my $db_password = "''";
my $sh_password = "";
#
# We don't want to run this script unless its the real version.
#
......@@ -89,7 +95,7 @@ sub fatal($);
# Rewrite audit version of ARGV to prevent password in mail logs.
#
my @NEWARGV = @ARGV;
for ($i = 0; $i < scalar(@NEWARGV); $i++) {
for (my $i = 0; $i < scalar(@NEWARGV); $i++) {
if ($NEWARGV[$i] eq "-p") {
$NEWARGV[$i + 1] = "**********";
}
......@@ -100,13 +106,17 @@ AuditSetARGV(@NEWARGV);
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
%options = ();
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"d"})) {
$debug = 1;
}
if (defined($options{"g"})) {
$OU = "geni";
$geniflag = 1;
}
if (defined($options{"p"})) {
$password = $options{"p"};
......@@ -119,12 +129,18 @@ if (defined($options{"p"})) {
else {
die("Tainted argument: $password\n");
}
$password =~ s/\'/\'\\\'\'/g;
$password = "'$password'";
$db_password = DBQuoteSpecial($password);
$sh_password = $password;
$sh_password =~ s/\'/\'\\\'\'/g;
$sh_password = "$sh_password";
$encrypted = 1;
}
if (@ARGV != 1) {
usage();
}
if ($geniflag && !$encrypted) {
fatal("GENI certs must be encrypted (use -p password).");
}
my $user = $ARGV[0];
#
......@@ -172,9 +188,7 @@ TBScriptLock("mkusercert") == 0 or
#
# Get the user info (the user being operated on).
#
my $fullname = $target_user->name();
my $user_email = $target_user->email();
my $usr_admin = $target_user->admin();
my $user_uuid = $target_user->uuid();
my $user_number = $target_user->unix_uid();
my $user_uid = $target_user->uid();
my $user_dbid = $target_user->dbid();
......@@ -200,6 +214,27 @@ else {
(undef,undef,$default_groupgid,undef) = getgrnam("guest");
}
#
# Need an index file, which is the openssl version of the DB.
#
if (! -e "index.txt") {
open(IND, ">index.txt")
or fatal("Could not create index.txt");
close(IND);
}
#
# We have to figure out what the next serial number will be and write
# that into the file. We could let "ca' keep track, but with devel
# trees, we might end up with duplicate serial numbers.
#
my $serial = TBGetUniqueIndex("user_sslcerts");
open(SER, ">serial")
or fatal("Could not create new serial file");
printf SER "%08x\n", $serial;
close(SER);
#
# Create a template conf file. We tack on the DN record based on the
# user particulars.
......@@ -210,9 +245,8 @@ system("cp -f $TEMPLATE usercert.cnf") == 0
open(TEMP, ">>usercert.cnf")
or fatal("Could not open $TEMPLATE for append: $!");
print TEMP "OU\t\t= sslxmlrpc\n";
print TEMP "CN\t\t= $user_uid\n";
print TEMP "emailAddress\t= $user_uid" . "\@" . "$OURDOMAIN\n";
print TEMP "OU\t\t= $OU\n";
print TEMP "CN\t\t= $user_uuid\n";
close(TEMP)
or fatal("Could not close usercert.cnf: $!");
......@@ -220,53 +254,35 @@ close(TEMP)
# Create a client side private key and certificate request.
#
system("$OPENSSL req -new -config usercert.cnf ".
(defined($password) ? " -passout pass:${password} " : " -nodes ") .
($encrypted ? " -passout 'pass:${sh_password}' " : " -nodes ") .
" -keyout usercert_key.pem -out usercert_req.pem") == 0
or fatal("Could not create certificate request");
#
# Remove the index file. We keep track of things ourselves. We also have to
# figure out what the next serial number will be and write that into the
# file. We could let "ca' keep track, but with devel trees, we might end
# up with duplicate serial numbers.
#
open(IND, ">index.txt")
or fatal("Could not clear index.txt");
close(IND);
my $curidx = TBGetUniqueIndex("user_sslcerts");
open(SER, ">serial")
or fatal("Could not create new serial file");
printf SER "%08x\n", $curidx;
close(SER);
#
# Sign the client cert request, creating a client certificate.
#
$UID = 0;
system("$OPENSSL ca -batch -policy policy_sslxmlrpc -config $CACONFIG ".
" -name CA_usercerts ".
system("$OPENSSL ca -batch -policy policy_sslxmlrpc ".
" -name CA_usercerts -config $CACONFIG ".
" -out usercert_cert.pem -cert $EMULAB_CERT -keyfile $EMULAB_KEY ".
" -infiles usercert_req.pem") == 0
or fatal("Could not sign certificate request");
$UID = $SAVEUID;
#
# For now, there can be just one cert of each kind (encrypted, and
# unencrypted). Might change that at some point.
# We save all of the certs in the DB, but we are not worrying about
# revocation yet. By saving them, we can eventually do that. But we do
# have to set the status bit to revoked though or else we will not know
# later (okay, we can probably figure it out if we had to).
#
DBQueryFatal("delete from user_sslcerts ".
"where uid_idx='$user_dbid' and ".
" encrypted=" . (defined($password) ? 1 : 0));
DBQueryFatal("update user_sslcerts set ".
" status='revoked',revoked=now() ".
"where uid_idx='$user_dbid' and encrypted=$encrypted");
#
# Create a new entry in the table.
#
DBQueryFatal("insert into user_sslcerts ".
"(uid, uid_idx, idx, created, encrypted) values ".
"('$user_uid', '$user_dbid', $curidx, now(), ".
(defined($password) ? 1 : 0) . ")");
"(uid,uid_idx,idx,created,encrypted,orgunit,status,password) ".
"values ('$user_uid', '$user_dbid', $serial, now(), ".
" $encrypted, '$OU', 'valid', $db_password)");
#
# Grab the cert path and strip off the header goo, then insert into
......@@ -301,12 +317,11 @@ close(PKEY);
$pkeystring = DBQuoteSpecial($pkeystring);
$certstring = DBQuoteSpecial($certstring);
DBQueryFatal("update user_sslcerts set cert=$certstring,privkey=$pkeystring ".
"where uid_idx='$user_dbid' and idx=$curidx");
"where uid_idx='$user_dbid' and idx=$serial");
#
# Combine the key and the certificate into one file which is installed
# on each remote node and used by tmcc. Installed on boss too so
# we can test tmcc there.
# Combine the key and the certificate into one file which is
# installed in the users home directory.
#
system("cat usercert_key.pem usercert_cert.pem > usercert.pem") == 0
or fatal("Could not combine cert and key into one file");
......@@ -325,7 +340,7 @@ if (! -d $ssldir) {
my $target;
if (defined($password)) {
if ($encrypted) {
$target = "$ssldir/encrypted.pem";
}
else {
......@@ -338,6 +353,25 @@ system("cp -f usercert.pem $target") == 0
chown($user_number, $default_groupgid, "$target")
or fatal("Could not chown $target: $!");
if ($encrypted) {
#
# Convert to pkcs12 format, strictly for the geni xmlrpc code, whichs
# does not provide a way to give the passphrase for encrypted x509 keys.
#
system("$OPENSSL pkcs12 -export -in usercert.pem -des ".
"-passin 'pass:${sh_password}' -passout 'pass:${sh_password}' ".
"-out usercert.p12 -rand ./.rnd")
== 0 or fatal("Could not create usercert.p12");
$target = "$ssldir/encrypted.p12";
system("cp -f usercert.p12 $target") == 0
or fatal("Could not copy usercert.p12 to $target");
chown($user_number, $default_groupgid, "$target")
or fatal("Could not chown $target: $!");
}
TBScriptUnlock();
exit(0);
......
#!/usr/local/bin/python
#
# EMULAB-COPYRIGHT
# Copyright (c) 2005-2008 University of Utah and the Flux Group.
# All rights reserved.
#
......@@ -221,24 +220,26 @@ class MyServer(SSL.ForkingSSLServer, SimpleXMLRPCDispatcher):
#
# Get the unix_uid for the user. User must be active.
#
def getuserid(self, uid):
userQuery = DBQueryFatal("select unix_uid,status from users "
"where uid=%s",
(uid,))
def getuserid(self, uuid):
userQuery = DBQueryFatal("select uid,uid_idx,unix_uid,status "
" from users "
"where uid_uuid=%s or uid=%s",
(uuid, uuid))
if len(userQuery) == 0:
return 0
return (None, None, 0);
if (userQuery[0][1] != "active"):
return -1
if (userQuery[0][3] != "active"):
return (None, None, -1);
return int(userQuery[0][0])
return (userQuery[0][0], int(userQuery[0][1]), int(userQuery[0][2]))
#
# Check if the user is an stud.
#
def isstuduser(self, uid):
res = DBQueryFatal("select stud from users where uid=%s", (uid,))
def isstuduser(self, uid_idx):
res = DBQueryFatal("select stud from users where uid_idx=%s",
(str(uid_idx),))
if len(res) == 0:
return 0
......@@ -248,26 +249,26 @@ class MyServer(SSL.ForkingSSLServer, SimpleXMLRPCDispatcher):
#
# Check the certificate serial number.
#
def checkcert(self, uid, serial):
def checkcert(self, uid_idx, serial):
res = DBQueryFatal("select idx from user_sslcerts "
"where uid=%s and idx=%s",
(uid, serial))
"where uid_idx=%s and idx=%s and status='valid'",
(str(uid_idx), serial))
return len(res)
#
# Get the group list for the user.
#
def getusergroups(self, user):
def getusergroups(self, uid_idx):
result = []
res = DBQueryFatal("select distinct g.gid,g.unix_gid "
" from group_membership as m "
"left join groups as g on "
" g.pid=m.pid and g.gid=m.gid "
"where m.uid=%s "
" g.pid_idx=m.pid_idx and g.gid_idx=m.gid_idx "
"where m.uid_idx=%s "
"order by date_approved asc ",
(user,))
(str(uid_idx),))
for group in res:
result.append(int(group[1]));
......@@ -283,22 +284,28 @@ class MyServer(SSL.ForkingSSLServer, SimpleXMLRPCDispatcher):
if self.debug:
self.logit(str(subject))
pass
#
# The CN might look like UUID,serial so split it up.
#
cnwords = getattr(subject, "CN").split(",")
self.uuid = cnwords[0]
self.user = getattr(subject, "CN");
#
# Must be a valid and non-zero unix_uid from the DB.
#
self.uid = self.getuserid(self.user)
(self.uid,self.uid_idx,self.unix_uid) = self.getuserid(self.uuid)
if self.uid == 0:
self.logit('No such user: "%s"' % self.user)
raise Exception('No such user: "%s"' % self.user)
if self.unix_uid == 0:
self.logit('No such user: "%s"' % self.uuid)
raise Exception('No such user: "%s"' % self.uuid)
if self.uid == -1:
self.logit('User "%s" is not active' % self.user)
raise Exception('User "%s" is not active' % self.user)
if self.unix_uid == -1:
self.logit('User "%s,%d" is not active' % (self.uid,self.uid_idx))
raise Exception('User "%s,%d" is not active' %
(self.uid,self.uid_idx))
self.stud = self.isstuduser(self.user)
self.stud = self.isstuduser(self.uid_idx)
if self.stud:
try:
ALLOWED_PATHS.extend(map(lambda x:
......@@ -309,13 +316,14 @@ class MyServer(SSL.ForkingSSLServer, SimpleXMLRPCDispatcher):
pass
pass
self.glist = self.getusergroups(self.user);
self.glist = self.getusergroups(self.uid_idx);
if len(self.glist) == 0:
self.logit('No groups for user: "%s"' % self.user)
raise Exception('No groups for user: "%s"' % self.user)
self.logit('No groups for user: "%s,%d"' % (self.uid,self.uid_idx))
raise Exception('No groups for user: "%s,%d"' %
(self.uid,self.uid_idx))
self.logit("Connect from %s: %s %s" %
(client[0], self.user, str(self.glist)))
self.logit("Connect from %s: %s,%d %s" %
(client[0], self.uid, self.uid_idx, str(self.glist)))
#
# Check the certificate serial number. At the moment, the serial
......@@ -324,19 +332,19 @@ class MyServer(SSL.ForkingSSLServer, SimpleXMLRPCDispatcher):
#
serial = request.get_peer_cert().get_serial_number()
if self.checkcert(self.user, serial) == 0:
if self.checkcert(self.uid_idx, serial) == 0:
self.logit('No such cert with serial "%s"' % serial)
raise Exception('No such cert with serial "%s"' % serial)
try:
os.setgid(self.glist[0])
os.setgroups(self.glist)
os.setuid(self.uid)
pwddb = pwd.getpwuid(self.uid);
os.setuid(self.unix_uid)
pwddb = pwd.getpwuid(self.unix_uid);
os.environ["HOME"] = pwddb[5];
os.environ["USER"] = self.user;
os.environ["LOGNAME"] = self.user;
os.environ["USER"] = self.uid;
os.environ["LOGNAME"] = self.uid;
pass
except:
traceback.print_exc()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment