initsite.in 20.2 KB
Newer Older
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1 2
#!/usr/bin/perl -w
#
3
# GENIPUBLIC-COPYRIGHT
4
# Copyright (c) 2008-2010 University of Utah and the Flux Group.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
# All rights reserved.
#
use strict;
use English;
use Getopt::Std;

#
# Initialize an emulab to act as a protogeni emulab. Add optional -c
# option if this is a clearinghouse.
# 
sub usage()
{
    print "Usage: initpgenisite [-c]\n";
    exit(1);
}
my $optlist = "c";
my $asch    = 0;
my $cflag   = "";

#
# Configure variables
#
my $TB		  = "@prefix@";
my $TBOPS         = "@TBOPSEMAIL@";
my $TBLOGS        = "@TBLOGSEMAIL@";
30
my $OURDOMAIN     = "@OURDOMAIN@";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
31 32 33
my $PGENIDOMAIN   = "@PROTOGENI_DOMAIN@";
my $PGENISUPPORT  = @PROTOGENI_SUPPORT@;
my $TBBASE        = "@TBBASE@";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
34 35 36 37 38 39 40 41 42
my $geniuserid    = "geniuser";
my $geniprojid    = "GeniSlices";
my $PROTOUSER	  = "elabman";
my $NEWUSER	  = "$TB/sbin/newuser";
my $NEWPROJ	  = "$TB/sbin/newproj";
my $MKPROJ	  = "$TB/sbin/mkproj";
my $TBACCT	  = "$TB/sbin/tbacct";
my $ADDAUTHORITY  = "$TB/sbin/protogeni/addauthority";
my $GETCACERTS    = "$TB/sbin/protogeni/getcacerts";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
43
my $POSTCRL       = "$TB/sbin/protogeni/postcrl";
44
my $GENCRL        = "$TB/sbin/protogeni/gencrl";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
45
my $GENCRLBUNDLE  = "$TB/sbin/protogeni/gencrlbundle";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
46
my $MKSYSCERT	  = "$TB/sbin/mksyscert";
47
my $MKUSERCERT	  = "$TB/sbin/mkusercert";
48
my $BATCHEXP      = "$TB/bin/batchexp";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
49
my $WAP           = "$TB/sbin/withadminprivs";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
50 51 52
my $SACERT	  = "$TB/etc/genisa.pem";
my $CMCERT	  = "$TB/etc/genicm.pem";
my $CHCERT	  = "$TB/etc/genich.pem";
53
my $SESCERT	  = "$TB/etc/genises.pem";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
54 55 56 57 58
my $SUDO	  = "/usr/local/bin/sudo";
my $MYSQL         = "/usr/local/bin/mysql";
my $MYSQLADMIN    = "/usr/local/bin/mysqladmin";
my $MYSQLSHOW     = "/usr/local/bin/mysqlshow";
my $MYSQLDUMP     = "/usr/local/bin/mysqldump";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
59 60
my $PKG_INFO      = "/usr/sbin/pkg_info";
my $FETCH	  = "/usr/bin/fetch";
61
my $OPENSSL       = "/usr/bin/openssl";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
62 63 64 65 66 67 68

# un-taint path
$ENV{'PATH'} = '/bin:/usr/bin:/usr/local/bin:/usr/site/bin';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};

# Protos
sub fatal($);
69
sub UpdateCert($$$$);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
70 71 72 73 74 75 76 77

#
# Turn off line buffering on output
#
$| = 1; 

# Load the Testbed support stuff.
use lib "@prefix@/lib";
78
use libtestbed;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
79
use libdb qw(TBSetSiteVar TBOPSPID DBQueryFatal);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
80 81
use User;
use Project;
82
use Experiment;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
83
use OSinfo;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100

if ($UID != 0) {
    fatal("Must be root to run this script\n");
}

#
# Check args.
#
my %options = ();
if (! getopts($optlist, \%options)) {
    usage();
}
if (defined($options{"c"})) {
    $asch  = 1;
    $cflag = "-c";
}

101 102 103
#
# People seem to miss this.
#
104
if ($PGENIDOMAIN =~ /^unknown/i) {
105 106 107 108 109
    print STDERR "Please define PROTOGENI_DOMAIN in your defs file!\n";
    print STDERR "Then reconfig,rebuild,reinstall, then try this again.\n";
    exit(1);
}

110 111 112
#
# Check for (and update) an old (pre-URN) root certificate.
#
113 114 115 116 117 118
system( "$OPENSSL x509 -text -noout < $TB/etc/emulab.pem | " .
	"grep -q -i URI:urn:publicid:IDN" );
if( $? == -1 ) {
    die( "could not inspect root certificate $TB/etc/emulab.pem" );
} elsif( $? & 0x7F ) {
    die( "unexpected signal while inspecting root certificate" );
Gary Wong's avatar
Gary Wong committed
119
} elsif( $? ) {
120 121
    # grep returned non-zero exit code (indicating no matches): this is
    # an old certificate, so regenerate it.
122 123 124 125 126 127 128 129
    my $extfile = "/tmp/$$"; # not worth trying to be secure
    open( EXTFILE, "> $extfile" ) or die "can't open $extfile";
    print EXTFILE "subjectAltName=URI:urn:publicid:IDN+${OURDOMAIN}+authority+root\n";
    print EXTFILE "issuerAltName=URI:urn:publicid:IDN+${OURDOMAIN}+authority+root\n";
    close EXTFILE;

    print "Adding URN to root certificate...\n";

130 131 132 133
    my $originalfile = "$TB/etc/emulab.pem.orig";
    -f $originalfile and
	die( "refusing to overwrite $originalfile" );
    rename( "$TB/etc/emulab.pem", "$originalfile" ) or
134
	die( "could not rename root certificate" );
135 136 137 138
    # Save the new certificate to a temporary file: OpenSSL will reuse the
    # plain text from the old certificate instead of the current version,
    # so we regenerate the whole thing once we've finished to avoid
    # horrible confusion.
139
    system( "$OPENSSL x509 -days 2000 -text -extfile $extfile " .
140
	    "-signkey $TB/etc/emulab.key < $originalfile " .
141
	    "> $TB/etc/emulab.tmp" );
142 143
    # For some reason, OpenSSL can return non-zero even when the certificate
    # generation succeeded.  Check the output file instead.
144 145
    if( !( -s "$TB/etc/emulab.tmp" ) ) {
	rename( "$originalfile", "$TB/etc/emulab.pem" );
146
	die( "could not generate new root certificate" );	    
147 148 149 150 151
    }

    # Regenerate the certificate, so that the comments are up to date.
    system( "$OPENSSL x509 -text < $TB/etc/emulab.tmp > $TB/etc/emulab.pem" );
    unlink( "$TB/etc/emulab.tmp" );
152 153 154 155 156 157 158

    print "Root certificate updated.  You will need to send the new\n";
    print "certificate to the clearing house.\n";

    unlink( "$TB/etc/.federated" );
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
159 160 161
#
# Have you sent in your certificate to Utah?
#
162
if (!$asch && ! -e "$TB/etc/.federated") {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
    my $done = 0;
    my $federated = 0;

    while (!$done) {
	print "Have you sent in your root certificate to Utah? [y/n]: ";

	$_ = <STDIN>;
	if ($_ =~ /^(y|yes)$/i) {
	    $federated = 1;
	    $done = 1;
	}
	elsif ($_ =~ /^(n|no)$/i) {
	    $federated = 0;
	    $done = 1;
	}
    }
    if ($federated) {
	system("/usr/bin/touch $TB/etc/.federated");
    }
    else {
	print "Please email $TB/etc/emulab.pem to testbed-ops\@flux.utah.edu";
	print "\n";
	print "This is a public key, so no harm in sending it in email.\n";
	print "Once you hear back from Utah, please rerun this script.\n";
	exit(1);
    }
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
191 192 193
#
# Packages.
#
194 195 196 197 198 199 200 201 202
my %packlist =
    ("libxml2>=2.6.26"       => "/usr/ports/textproc/libxml2",
     "p5-Frontier-RPC"       => "/usr/ports/net/p5-Frontier-RPC",
     "p5-XML-LibXML>=1.70"   => "/usr/ports/textproc/p5-XML-LibXML",
     "xmlsec1"               => "/usr/ports/security/xmlsec1",
     "p5-Crypt-SSLeay>=0.57" => "/usr/ports/security/p5-Crypt-SSLeay",
     "p5-Crypt-OpenSSL-X509" => "/usr/ports/security/p5-Crypt-OpenSSL-X509",
     "p5-Crypt-X509"         => "/usr/ports/security/p5-Crypt-X509"
     );
Leigh B. Stoller's avatar
Leigh B. Stoller committed
203 204
my $needpkgs = 0;

205
foreach my $pkgname (sort(keys(%packlist))) {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
206 207
    my $pkgdir = $packlist{$pkgname};
    
208 209
    print STDERR "Checking for package $pkgname\n";

Leigh B. Stoller's avatar
Leigh B. Stoller committed
210 211 212 213 214 215 216 217 218 219 220
    next
	if (system("$PKG_INFO -E '${pkgname}*' >/dev/null") == 0);

    print STDERR "Please install $pkgdir\n";
    $needpkgs++;
}
if ($needpkgs) {
    print STDERR "Then return to this script and start again.\n";
    exit(1);
}

221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
#
# crossdomain.xml is needed to allow the flash client to talk to
# this host.
#

my $crosstext = <<'CROSSEND';
<?xml version="1.0"?>
<cross-domain-policy>
    <site-control permitted-cross-domain-policies="all"/>
</cross-domain-policy>
CROSSEND

open CROSS_OUT, ">$TB/www/crossdomain.xml"
    or fatal("Could not create $TB/www/crossdomain.xml");
print CROSS_OUT $crosstext;
close CROSS_OUT;

chmod(0644, "$TB/www/crossdomain.xml");

if (! -e "$TB/www/protogeni") {
    mkdir("$TB/www/protogeni", 0775)
	or fatal("Could not mkdir $TB/www/protogeni");
}

$crosstext = <<'CROSSEND';
<?xml version="1.0"?>
<cross-domain-policy>
248
    <allow-access-from domain="*.emulab.net" />
249 250 251 252 253 254 255 256 257 258 259
    <allow-access-from domain="*.protogeni.net" />
</cross-domain-policy>
CROSSEND

open CROSS_OUT, ">$TB/www/protogeni/crossdomain.xml"
    or fatal("Could not create $TB/www/protogeni/crossdomain.xml");
print CROSS_OUT $crosstext;
close CROSS_OUT;

chmod(0644, "$TB/www/protogeni/crossdomain.xml");

Leigh B. Stoller's avatar
Leigh B. Stoller committed
260 261 262 263 264
#
# The web server needs to do client authentication, for the geni xmlrpc
# interface. A bundle of CA certs from the trusted roots (emulabs) will
# be used. This bundle will periodically update as sites come online.
#
265 266 267 268 269 270 271 272 273
if (! -e "$TB/etc/genica.bundle") {
    system("/bin/cp $TB/etc/emulab.pem $TB/etc/genica.bundle") == 0
	or fatal("Could not initialize $TB/etc/genica.bundle");
}
if (! -e "$TB/etc/genicrl.bundle") {
    system("/usr/bin/touch $TB/etc/genicrl.bundle") == 0
	or fatal("Could not initialize $TB/etc/genicrl.bundle");
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
274 275 276 277 278
if ($asch) {
    if (! -e "$TB/www/genica.bundle") {
	system("/bin/cp $TB/etc/emulab.pem $TB/www/genica.bundle") == 0
	    or fatal("Could not initialize $TB/www/genica.bundle");
    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
279 280
    chmod(0644, "$TB/www/genica.bundle");

Leigh B. Stoller's avatar
Leigh B. Stoller committed
281 282 283 284 285 286 287
    # CRL 
    if (! -e "$TB/www/genicrl.bundle") {
	system("/usr/bin/touch $TB/www/genicrl.bundle") == 0
	    or fatal("Could not initialize $TB/www/genicrl.bundle");
    }
    chmod(0644, "$TB/www/genicrl.bundle");

Leigh B. Stoller's avatar
Leigh B. Stoller committed
288 289 290 291 292 293 294 295 296 297 298 299
    #
    # This is a pain. xmlsec1 cannot deal with a bundle of certs and so we
    # need to split up the bundle into a directory of certs. I hope to deal
    # with this at some point.
    #
    if (! -e "$TB/etc/genicacerts") {
	mkdir("$TB/etc/genicacerts", 0755)
	    or fatal("Could not mkdir $TB/etc/genicacerts");
    }
    system("/bin/cp $TB/etc/emulab.pem $TB/etc/genicacerts") == 0
	or fatal("Could not initialize $TB/etc/genicacerts");
}
300 301
if (! -e "$TB/lib/ssl/syscert.cnf" ||
    system( "grep -q protogeni_oids \"$TB/lib/ssl/syscert.cnf\"" ) != 0 ) {
302 303 304 305 306
    print "Please go to the ssl subdir of your build tree and do:\n";
    print "    sudo gmake install-conf\n";
    print "Then rerun this script\n";
    exit(1);
}
307 308 309 310 311 312 313 314
#
# I do not understand where this file comes from.
#
if (! -e "$TB/ssl/index.txt.attr" ||
    system("egrep -q -s 'no' $TB/ssl/index.txt.attr")) {
    system("echo 'unique_subject = no' > $TB/ssl/index.txt.attr") == 0
	or fatal("Could not update $TB/ssl/index.txt.attr");
}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
315

Leigh B. Stoller's avatar
Leigh B. Stoller committed
316 317 318
my $restartapache = 0;

if (system("egrep -q -s 'PGENI' /usr/local/etc/apache/httpd.conf")) {
319
    print "Please go to the apache subdir of your build tree and do:\n";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
320 321 322
    print "    gmake\n";
    print "    sudo gmake install\n";
    $restartapache++;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
323 324 325
}
if (system("egrep -q -s 'DPGENI' /etc/rc.conf")) {
    print "Please add 'apache_flags=\"-DSSL -DPGENI\"' to /etc/rc.conf\n";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
326 327
    $restartapache++;
}
328 329 330 331 332 333 334
if (!system("egrep -q -s 'apache_flags=\"-DSSL' " .
	    "/usr/local/etc/rc.d/apache.sh")) {
    system("sed -i .backup 's/apache_flags=\"-DSSL/" .
	   "apache_flags=\"\${apache_flags--DSSL}/' " .
	   "/usr/local/etc/rc.d/apache.sh");
    $restartapache++;
}
335
if ($restartapache) {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
336
    print "Then restart apache:\n";
337
    print "    sudo /usr/local/etc/rc.d/apache.sh restart\n";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
338
    print "Then rerun this script\n";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
339 340 341
    exit(1);
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
342 343 344 345 346 347 348
#
# On the clients, we have to get the bundle from Utah website and
# then break it up for xmlsec (see above). We use a script for this
# since the clients need to do this everytime a new client is added.
# This script restarts apache.
#
if (!$asch) {
349
    system("$GETCACERTS -l -p") == 0
Leigh B. Stoller's avatar
Leigh B. Stoller committed
350 351
	or fatal("Could not get CA bundle from Utah");

Leigh B. Stoller's avatar
Leigh B. Stoller committed
352
    #
Leigh B. Stoller's avatar
Leigh B. Stoller committed
353 354
    # This cron entry will autoupdate the CA/CRL certs by getting them from
    # Utah.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
355 356 357
    #
    if (system("egrep -q -s '$GETCACERTS' /etc/crontab")) {
	print "Please add this line to /etc/crontab:\n\n";
358
	print "13  4  *  *	*  root  $GETCACERTS\n\n";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
359 360 361 362 363 364
	print "Then rerun this script\n";
	exit(1);
    }
}
else {
    #
Leigh B. Stoller's avatar
Leigh B. Stoller committed
365 366
    # But on the clearinghouse, we have to generate the CRL bundle for 
    # downloading by remote sites.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
367 368 369
    #
    if (system("egrep -q -s '$GENCRLBUNDLE' /etc/crontab")) {
	print "Please add this line to /etc/crontab:\n\n";
370
	print "10  4  *  *  *  root  $GENCRLBUNDLE\n\n";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
371 372
	print "Then rerun this script\n";
	exit(1);
Gary Wong's avatar
Gary Wong committed
373
    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
374 375
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
376 377 378
#
# user/project that slices (experiments) belong to.
#
Leigh B. Stoller's avatar
Leigh B. Stoller committed
379 380
my $geniuser = User->Lookup($geniuserid);
if (!defined($geniuser)) {
381
    fatal("Need to do an install in the protogeni/etc directory.")
Leigh B. Stoller's avatar
Leigh B. Stoller committed
382 383
	if (! -e "$TB/etc/protogeni/geniuser.xml");

384
    print "Creating Geni pseudo user ...\n";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
    system("$SUDO -u $PROTOUSER $WAP $NEWUSER $TB/etc/protogeni/geniuser.xml");
    fatal("Could not create geni user")
	if ($?);

    system("$SUDO -u $PROTOUSER $WAP $TBACCT verify $geniuserid");
    fatal("Could not verify geni user")
	if ($?);

    $geniuser = User->Lookup($geniuserid);    
    fatal("Could not lookup $geniuserid")
	if (!defined($geniuser));
}
my $geniproj = Project->Lookup($geniprojid);
if (!defined($geniproj)) {
    fatal("Need to do an install")
	if (! -e "$TB/etc/protogeni/geniproj.xml");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
401

402
    print "Creating Geni slices project ...\n";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
403 404 405 406 407 408 409 410 411 412 413
    system("$SUDO -u $PROTOUSER $WAP $NEWPROJ $TB/etc/protogeni/geniproj.xml");
    fatal("Could not create geni project")
	if ($?);

    system("$SUDO -u $PROTOUSER $WAP $MKPROJ -s $geniprojid");
    fatal("Could not approve geni project")
	if ($?);

    $geniproj = Project->Lookup($geniprojid);
    fatal("Could not lookup $geniprojid")
	if (!defined($geniproj));
Leigh B. Stoller's avatar
Leigh B. Stoller committed
414 415 416
}
$geniuser->Refresh();
$geniproj->Refresh();
417

Leigh B. Stoller's avatar
Leigh B. Stoller committed
418 419 420 421
# Create an encrypted certificate for the test scripts.
my $sslcert;
$geniuser->SSLCert(1, \$sslcert);
if (!defined($sslcert)) {
422 423 424 425
    my $passwd = substr(TBGenSecretKey(), 0, 10);
    system("$SUDO -u $PROTOUSER $WAP $MKUSERCERT -p '$passwd' $geniuserid");
    fatal("Could not create encrypted certificate for geni user")
	if ($?);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
426
}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
427 428

#
Leigh B. Stoller's avatar
Leigh B. Stoller committed
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
# Need this fake type for now.
#
my $osinfo = OSinfo->Lookup(TBOPSPID(), "RHL-STD");
if (!defined($osinfo)) {
    fatal("No RHL-STD OSID in the ops project!");
}
my $osid = $osinfo->osid();

DBQueryFatal("replace into node_types (type,class,isvirtnode,isdynamic) ".
	     "values ('pcfake','pcvm',1,1)");
DBQueryFatal("replace into node_type_attributes ".
	     "(type,attrkey,attrvalue,attrtype) values ".
	     "('pcfake','rebootable','1','boolean')");
DBQueryFatal("replace into node_type_attributes ".
	     "(type,attrkey,attrvalue,attrtype) values ".
	     "('pcfake','default_osid','$osid','integer')");

#
Leigh B. Stoller's avatar
Leigh B. Stoller committed
447 448
# Databases.
#
449
print "Creating Databases ...\n";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
450 451 452 453 454 455 456 457 458 459 460
foreach my $dbname ("geni", "geni-ch", "geni-cm") {
    if (system("$MYSQLSHOW $dbname >/dev/null 2>/dev/null")) {
	system("$MYSQLADMIN create $dbname") == 0
	    or fatal("Could not create DB: $dbname");
    }
    if (system("$MYSQLDUMP -d $dbname geni_users >/dev/null 2>/dev/null")) {
	system("$MYSQL $dbname < $TB/etc/protogeni/protogeni.sql") == 0
	    or fatal("Could not initialize DB: $dbname");
    }
}

461 462 463 464 465 466
foreach my $dbname( "geni", "geni-ch", "geni-cm" ) {
    system( "$MYSQL -e \"UPDATE geni_authorities SET type='ses' WHERE " .
	    "hrn LIKE '%.ses' AND type='';\" $dbname" ) == 0
	    or fatal( "Could not update SES type: $dbname" );
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
467 468 469 470 471
#
# Now we can load the libraries.
#
require Genixmlrpc;
require GeniRegistry;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
472 473 474 475

#
# Generate the certs we need.
#
Leigh B. Stoller's avatar
Leigh B. Stoller committed
476
if (! -e $CMCERT) {
477
    print "Creating CM certificate ...\n";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
478
    system("$SUDO -u $PROTOUSER $MKSYSCERT -o $CMCERT ".
479 480 481
	   "  -u $TBBASE/protogeni/xmlrpc/cm " .
	   "  -i urn:publicid:IDN+${OURDOMAIN}+authority+cm " .
	   "$PGENIDOMAIN.cm") == 0
Leigh B. Stoller's avatar
Leigh B. Stoller committed
482 483 484
	   or fatal("Could not generate $CMCERT");
}
if (! -e $SACERT) {
485
    print "Creating SA certificate ...\n";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
486
    system("$SUDO -u $PROTOUSER $MKSYSCERT -o $SACERT ".
487 488 489
	   "  -u $TBBASE/protogeni/xmlrpc/sa " .
	   "  -i urn:publicid:IDN+${OURDOMAIN}+authority+sa " .
	   "$PGENIDOMAIN.sa") == 0
Leigh B. Stoller's avatar
Leigh B. Stoller committed
490 491
	   or fatal("Could not generate $SACERT");
}
492 493 494
if (! -e $SESCERT) {
    print "Creating SES certificate ...\n";
    system("$SUDO -u $PROTOUSER $MKSYSCERT -o $SESCERT ".
495 496 497
	   "  -u $TBBASE/protogeni/xmlrpc/ses " .
	   "  -i urn:publicid:IDN+${OURDOMAIN}+authority+ses " .
	   "$PGENIDOMAIN.ses") == 0
498 499
	   or fatal("Could not generate $SESCERT");
}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
500 501
if ($asch) {
    if (! -e $CHCERT) {
502
	print "Creating CH certificate ...\n";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
503
	system("$SUDO -u $PROTOUSER $MKSYSCERT -o $CHCERT ".
504 505 506
	       "  -u $TBBASE/protogeni/xmlrpc/ch " .
	       "  -i urn:publicid:IDN+${OURDOMAIN}+authority+ch " .
	       "$PGENIDOMAIN.ch") == 0
Leigh B. Stoller's avatar
Leigh B. Stoller committed
507 508
	       or fatal("Could not generate $CHCERT");
    }
509 510 511
    UpdateCert( $CHCERT, "$TBBASE/protogeni/xmlrpc/ch",
		"urn:publicid:IDN+${OURDOMAIN}+authority+ch",
		"$PGENIDOMAIN.ch" );
Leigh B. Stoller's avatar
Leigh B. Stoller committed
512 513 514 515 516 517 518 519 520 521 522 523 524 525
    #
    # Copy the CH certificate out to the web interface, but only the public
    # key of course. 
    #
    my $chcertificate = GeniCertificate->LoadFromFile($CHCERT);
    fatal("Could not load certificate from $CHCERT")
	if (!defined($chcertificate));
    
    my $certfile = $chcertificate->WriteToFile();
    if (system("$SUDO /bin/mv $certfile $TB/www/genich.pem")) {
	$chcertificate->Delete();
	unlink($certfile);
	fatal("Could not mv $certfile to $TB/www/genich.pem");
    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
526 527
    chmod(0644, "$TB/www/genich.pem");

Leigh B. Stoller's avatar
Leigh B. Stoller committed
528 529 530 531 532 533 534 535 536 537
    #
    # Add the cert to the DB directly.
    #
    system("$ADDAUTHORITY -c $CHCERT ma") == 0
	or fatal("Could not add MA certificate");
}
else {
    #
    # Grab the CH certificate from Utah. Only one for now.
    #
538
    print "Fetching clearinghouse certificate from Utah ...\n";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
539 540 541
    system("$FETCH -q -o $CHCERT http://boss.emulab.net/genich.pem") == 0
	or fatal("Could not fetch clearinghouse certificate from Utah");
}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
542

543 544 545 546 547 548 549 550 551 552 553 554 555
#
# Update obsolete (pre-URN) certificates.
#
UpdateCert( $CMCERT, "$TBBASE/protogeni/xmlrpc/cm",
	    "urn:publicid:IDN+${OURDOMAIN}+authority+cm",
	    "$PGENIDOMAIN.cm" );
UpdateCert( $SACERT, "$TBBASE/protogeni/xmlrpc/sa",
	    "urn:publicid:IDN+${OURDOMAIN}+authority+sa",
	    "$PGENIDOMAIN.sa" );
UpdateCert( $SESCERT, "$TBBASE/protogeni/xmlrpc/ses",
	    "urn:publicid:IDN+${OURDOMAIN}+authority+ses",
	    "$PGENIDOMAIN.ses" );

Leigh B. Stoller's avatar
Leigh B. Stoller committed
556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571
#
# Load the SA cert to act as caller context.
#
my $certificate = GeniCertificate->LoadFromFile($SACERT);
if (!defined($certificate)) {
    fatal("Could not load certificate from $SACERT\n");
}
my $context = Genixmlrpc->Context($certificate);
if (!defined($context)) {
    fatal("Could not create context to talk to clearinghouse");
}

#
# Note that we had to send the clearinghouse $TB/etc/emulab.pem so they
# know about this new site. That is sent out of band (email).
#
572
print "Getting credential to talk to clearinghouse ...\n";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
573 574 575 576 577 578 579 580 581 582 583
my $credential = GeniRegistry::ClearingHouse->GetCredential($context);
if (!defined($credential)) {
    fatal("Could not get credential to talk to clearinghouse");
}
my $clearinghouse = GeniRegistry::ClearingHouse->Create($context,
							$credential);
if (!defined($clearinghouse)) {
    fatal("Could not create a clearinghouse client");
}

#
584 585 586 587 588 589
# Add certs to the local SA database.
#
system("$ADDAUTHORITY $SACERT sa") == 0
    or fatal("Could not add SA certificate");
system("$ADDAUTHORITY $CMCERT cm") == 0
    or fatal("Could not add CM certificate");
590 591
system("$ADDAUTHORITY $SESCERT ses") == 0
    or fatal("Could not add SES certificate");
592 593 594

#
# Register our certs at the clearinghouse.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
595 596
#
print "Registering SA cert at the clearinghouse.\n";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
597
if ($clearinghouse->Register("SA", $certificate->cert())) {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
598 599 600
    fatal("Could not register SA cert at the clearinghouse");
}
my $cmcert = GeniCertificate->LoadFromFile($CMCERT);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
601
if (!defined($cmcert)) {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
602 603 604
    fatal("Could not load certificate from $CMCERT\n");
}
print "Registering CM cert at the clearinghouse.\n";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
605
if ($clearinghouse->Register("CM", $cmcert->cert())) {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
606 607
    fatal("Could not register CM cert at the clearinghouse");
}
608 609 610 611
my $sescert = GeniCertificate->LoadFromFile($SESCERT);
if (!defined($sescert)) {
    fatal("Could not load certificate from $SESCERT\n");
}
612 613 614 615 616 617
# Don't treat SES registration failure as a fatal error quite yet, until
# we're certain that server-side support exists everywhere.
print "Registering SES cert at the clearinghouse.\n";
if ($clearinghouse->Register("SES", $sescert->cert())) {
    print("Warning: could not register SES cert at the clearinghouse\n");
}
618 619 620 621 622 623

#
# Local SiteVars to hold the UUIDs.
#
TBSetSiteVar('protogeni/sa_uuid', $certificate->uuid());
TBSetSiteVar('protogeni/cm_uuid', $cmcert->uuid());
624
TBSetSiteVar('protogeni/ses_uuid', $sescert->uuid());
625

Leigh B. Stoller's avatar
Leigh B. Stoller committed
626 627 628 629 630 631 632 633 634
exit(0);

sub fatal($)
{
    my ($msg) = @_;

    die("*** $0:\n".
	"    $msg\n");
}
635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664

# Add a URN to old certificates.  (This is horrible, mainly because
# we want to reuse the same private keys.)
sub UpdateCert($$$$)
{
    my ($cert, $url, $urn, $hrn) = @_;

    if( system( "$OPENSSL x509 -text -noout < $cert | " .
		"grep -q -i URI:urn:publicid:IDN" ) ) {
	my $extfile = "/tmp/$$.ext"; # not worth trying to be secure
	my $keyfile = "/tmp/$$.key";
	my $uuid = qx{$OPENSSL x509 -subject -noout < $cert};

	die "could not read subject from $cert"
	    unless defined( $uuid );
	die "no UUID found in subject"
	    unless $uuid =~ /CN=([-a-f0-9]+)/;
	$uuid = $1;

	open( OLDFILE, "< $cert" ) or die "can't open $cert";
	open( NEWFILE, "> $keyfile" ) or die "can't open $keyfile";
	while( <OLDFILE> ) {
	    print NEWFILE;
	    last if /-----END RSA PRIVATE KEY-----/;
	}
	close OLDFILE;
	close NEWFILE;

	print "Adding URN to $cert...\n";

665 666 667 668
	my $originalfile = "${cert}.orig";
	-f $originalfile and
	    die( "refusing to overwrite $originalfile" );
	rename( "$cert", "$originalfile" ) or
669 670 671 672 673 674 675
	    die( "could not rename $cert" );

	system("$SUDO -u $PROTOUSER $MKSYSCERT -o $cert ".
	       "  -u $url -i $urn -k $keyfile $hrn $uuid" ) == 0
	       or fatal("Could not generate $cert");
    }
}