Commit 980f6cbd authored by Leigh B Stoller's avatar Leigh B Stoller

Large set of changes for using the Geni trusted signer tool, to

authenticate Geni users to CloudLab (who do not have Emulab accounts).
CloudLab users must have an account to do anything (unlike APT which allows
guest users). But instead of requiring them to go through the Emulab
account creation (high bar), let then use their Geni credentials to prove
who they are. We then build a local account for that new user, and save off
the speaksfor credential so that we can act on their behalf when talking to
the backend clusters (and their MA to get their ssh keys).

These users do not have a local account password, so they cannot log into
the web interface using the Emulab login page, nor do they have a shell on
ops.

Once authenticated, we put the appropriate cookies into the browser via
javascript, so they can use the Cloud (okay, APT) web interface (they
appear logged in).

I make use of the nonlocal_id field of the users table, which was not being
used for anything else. Officially, these are "nonlocal" users in the code
(IsNonLocal()).

When a nonlocal user instantiates a profile, we use their speaksfor
credential to ask their home MA for their ssh keys, which we then store in
the DB, and then provide to the aggregate via the CreateSliver call.
Note that no provision has been made for users who edit their profile and
add keys; I am not currently expecting these users to stumble into the web
interface (yet).
parent b8fb1917
#!/usr/bin/perl -wT #!/usr/bin/perl -wT
# #
# Copyright (c) 2000-2012 University of Utah and the Flux Group. # Copyright (c) 2000-2014 University of Utah and the Flux Group.
# #
# {{{EMULAB-LICENSE # {{{EMULAB-LICENSE
# #
...@@ -619,6 +619,9 @@ if ($encrypted) { ...@@ -619,6 +619,9 @@ if ($encrypted) {
chmod(0600, $target) chmod(0600, $target)
or fatal("Could not chmod $target: $!"); or fatal("Could not chmod $target: $!");
goto skipssh
if ($target_user->IsNonLocal());
# #
# Create an SSH key from the private key. Mostly for geni users, # Create an SSH key from the private key. Mostly for geni users,
# who tend not to know how to do such things. # who tend not to know how to do such things.
...@@ -662,6 +665,7 @@ if ($encrypted) { ...@@ -662,6 +665,7 @@ if ($encrypted) {
" -f $sshdir/encrypted.pub") " -f $sshdir/encrypted.pub")
== 0 or fatal("Could not add pubkey $sshdir/encrypted.pub"); == 0 or fatal("Could not add pubkey $sshdir/encrypted.pub");
} }
skipssh:
} }
TBScriptUnlock(); TBScriptUnlock();
......
...@@ -38,7 +38,7 @@ use File::Basename; ...@@ -38,7 +38,7 @@ use File::Basename;
use overload ('""' => 'Stringify'); use overload ('""' => 'Stringify');
use vars qw($NEWUSER_FLAGS_PROJLEADER $NEWUSER_FLAGS_WIKIONLY use vars qw($NEWUSER_FLAGS_PROJLEADER $NEWUSER_FLAGS_WIKIONLY
$NEWUSER_FLAGS_WEBONLY $NEWUSER_FLAGS_ARCHIVED $NEWUSER_FLAGS_WEBONLY $NEWUSER_FLAGS_ARCHIVED
$NEWUSER_FLAGS_NOUUID $NEWUSER_FLAGS_NONLOCAL $NEWUSER_FLAGS_VIAAPT $NEWUSER_FLAGS_NOUUID $NEWUSER_FLAGS_NONLOCAL
$USERSTATUS_ACTIVE $USERSTATUS_FROZEN $USERSTATUS_ACTIVE $USERSTATUS_FROZEN
$USERSTATUS_UNAPPROVED $USERSTATUS_UNVERIFIED $USERSTATUS_UNAPPROVED $USERSTATUS_UNVERIFIED
$USERSTATUS_NEWUSER $USERSTATUS_ARCHIVED $USERSTATUS_NONLOCAL $USERSTATUS_NEWUSER $USERSTATUS_ARCHIVED $USERSTATUS_NONLOCAL
...@@ -66,7 +66,6 @@ $NEWUSER_FLAGS_WEBONLY = 0x04; ...@@ -66,7 +66,6 @@ $NEWUSER_FLAGS_WEBONLY = 0x04;
$NEWUSER_FLAGS_ARCHIVED = 0x08; $NEWUSER_FLAGS_ARCHIVED = 0x08;
$NEWUSER_FLAGS_NOUUID = 0x80; $NEWUSER_FLAGS_NOUUID = 0x80;
$NEWUSER_FLAGS_NONLOCAL = 0x40; $NEWUSER_FLAGS_NONLOCAL = 0x40;
$NEWUSER_FLAGS_VIAAPT = 0x20;
# Status values. # Status values.
$USERSTATUS_ACTIVE = "active"; $USERSTATUS_ACTIVE = "active";
...@@ -80,7 +79,7 @@ $USERSTATUS_NONLOCAL = "nonlocal"; ...@@ -80,7 +79,7 @@ $USERSTATUS_NONLOCAL = "nonlocal";
# Why, why, why? # Why, why, why?
@EXPORT_OK = qw($NEWUSER_FLAGS_PROJLEADER $NEWUSER_FLAGS_WIKIONLY @EXPORT_OK = qw($NEWUSER_FLAGS_PROJLEADER $NEWUSER_FLAGS_WIKIONLY
$NEWUSER_FLAGS_WEBONLY $NEWUSER_FLAGS_ARCHIVED $NEWUSER_FLAGS_WEBONLY $NEWUSER_FLAGS_ARCHIVED
$NEWUSER_FLAGS_NOUUID $NEWUSER_FLAGS_VIAAPT $NEWUSER_FLAGS_NOUUID
$USERSTATUS_ACTIVE $USERSTATUS_FROZEN $USERSTATUS_ACTIVE $USERSTATUS_FROZEN
$USERSTATUS_UNAPPROVED $USERSTATUS_UNVERIFIED $USERSTATUS_UNAPPROVED $USERSTATUS_UNVERIFIED
$USERSTATUS_NEWUSER $USERSTATUS_ARCHIVED $USERSTATUS_NONLOCAL); $USERSTATUS_NEWUSER $USERSTATUS_ARCHIVED $USERSTATUS_NONLOCAL);
...@@ -110,7 +109,6 @@ sub Lookup($$) ...@@ -110,7 +109,6 @@ sub Lookup($$)
{ {
my ($class, $token) = @_; my ($class, $token) = @_;
my $status_archived = $USERSTATUS_ARCHIVED; my $status_archived = $USERSTATUS_ARCHIVED;
my $status_nonlocal = $USERSTATUS_NONLOCAL;
my $query_result; my $query_result;
# Look in cache first # Look in cache first
...@@ -133,8 +131,7 @@ sub Lookup($$) ...@@ -133,8 +131,7 @@ sub Lookup($$)
$query_result = $query_result =
DBQueryWarn("select * from users ". DBQueryWarn("select * from users ".
"where uid='$token' and ". "where uid='$token' and ".
" status!='$status_archived' and ". " status!='$status_archived'");
" status!='$status_nonlocal'");
} }
else { else {
return undef; return undef;
...@@ -294,13 +291,11 @@ sub LookupByWikiName($$) ...@@ -294,13 +291,11 @@ sub LookupByWikiName($$)
{ {
my ($class, $wikiname) = @_; my ($class, $wikiname) = @_;
my $status_archived = $USERSTATUS_ARCHIVED; my $status_archived = $USERSTATUS_ARCHIVED;
my $status_nonlocal = $USERSTATUS_NONLOCAL;
my $query_result = my $query_result =
DBQueryFatal("select uid_idx from users ". DBQueryFatal("select uid_idx from users ".
"where wikiname='$wikiname' and ". "where wikiname='$wikiname' and ".
" status!='$status_archived' and ". " status!='$status_archived'");
" status!='$status_nonlocal'");
return undef return undef
if (! $query_result || !$query_result->numrows); if (! $query_result || !$query_result->numrows);
...@@ -318,13 +313,11 @@ sub LookupByEmail($$) ...@@ -318,13 +313,11 @@ sub LookupByEmail($$)
{ {
my ($class, $email) = @_; my ($class, $email) = @_;
my $status_archived = $USERSTATUS_ARCHIVED; my $status_archived = $USERSTATUS_ARCHIVED;
my $status_nonlocal = $USERSTATUS_NONLOCAL;
my $query_result = my $query_result =
DBQueryFatal("select uid_idx from users ". DBQueryFatal("select uid_idx from users ".
"where LCASE(usr_email)=LCASE('$email') and ". "where LCASE(usr_email)=LCASE('$email') and ".
" status!='$status_archived' and ". " status!='$status_archived'");
" status!='$status_nonlocal'");
return undef return undef
...@@ -342,14 +335,12 @@ sub LookupByUUID($$) ...@@ -342,14 +335,12 @@ sub LookupByUUID($$)
{ {
my ($class, $uuid) = @_; my ($class, $uuid) = @_;
my $status_archived = $USERSTATUS_ARCHIVED; my $status_archived = $USERSTATUS_ARCHIVED;
my $status_nonlocal = $USERSTATUS_NONLOCAL;
my $safe_uuid = DBQuoteSpecial($uuid); my $safe_uuid = DBQuoteSpecial($uuid);
my $query_result = my $query_result =
DBQueryFatal("select uid_idx from users ". DBQueryFatal("select uid_idx from users ".
"where uid_uuid=$safe_uuid and ". "where uid_uuid=$safe_uuid and ".
" status!='$status_archived' and ". " status!='$status_archived'");
" status!='$status_nonlocal'");
return undef return undef
if (! $query_result || !$query_result->numrows); if (! $query_result || !$query_result->numrows);
...@@ -365,13 +356,13 @@ sub LookupByUUID($$) ...@@ -365,13 +356,13 @@ sub LookupByUUID($$)
sub LookupNonLocal($$) sub LookupNonLocal($$)
{ {
my ($class, $urn) = @_; my ($class, $urn) = @_;
my $status_nonlocal = $USERSTATUS_NONLOCAL; my $status_archived = $USERSTATUS_ARCHIVED;
my $safe_urn = DBQuoteSpecial($urn); my $safe_urn = DBQuoteSpecial($urn);
my $query_result = my $query_result =
DBQueryFatal("select uid_idx from users ". DBQueryFatal("select uid_idx from users ".
"where nonlocal_id=$safe_urn and ". "where nonlocal_id=$safe_urn and ".
" status='$status_nonlocal'"); " status!='$status_archived'");
return undef return undef
if (! $query_result || !$query_result->numrows); if (! $query_result || !$query_result->numrows);
...@@ -395,7 +386,6 @@ sub Create($$$$) ...@@ -395,7 +386,6 @@ sub Create($$$$)
my $archived = ($flags & $NEWUSER_FLAGS_ARCHIVED ? 1 : 0); my $archived = ($flags & $NEWUSER_FLAGS_ARCHIVED ? 1 : 0);
my $nonlocal = ($flags & $NEWUSER_FLAGS_NONLOCAL ? 1 : 0); my $nonlocal = ($flags & $NEWUSER_FLAGS_NONLOCAL ? 1 : 0);
my $nouuid = ($flags & $NEWUSER_FLAGS_NOUUID ? 1 : 0); my $nouuid = ($flags & $NEWUSER_FLAGS_NOUUID ? 1 : 0);
my $viaapt = ($flags & $NEWUSER_FLAGS_VIAAPT ? 1 : 0);
# #
# If no uid, we need to generate a unique one for the user. # If no uid, we need to generate a unique one for the user.
...@@ -576,15 +566,10 @@ sub Create($$$$) ...@@ -576,15 +566,10 @@ sub Create($$$$)
"Must provide nonlocal_id and nonlocal_type!\n"; "Must provide nonlocal_id and nonlocal_type!\n";
return undef; return undef;
} }
push(@insert_data, "status='$USERSTATUS_NONLOCAL'"); push(@insert_data, "status='$USERSTATUS_ACTIVE'");
push(@insert_data, "pswd_expires=now()"); push(@insert_data, "pswd_expires=now()");
push(@insert_data, "usr_pswd='*'"); push(@insert_data, "usr_pswd='*'");
} }
elsif ($viaapt) {
push(@insert_data, "status='$USERSTATUS_UNAPPROVED'");
push(@insert_data, "pswd_expires=date_add(now(), interval 5 year)");
push(@insert_data, "viaAPT='1'");
}
else { else {
push(@insert_data, "status='$USERSTATUS_NEWUSER'"); push(@insert_data, "status='$USERSTATUS_NEWUSER'");
push(@insert_data, "pswd_expires=date_add(now(), interval 1 year)"); push(@insert_data, "pswd_expires=date_add(now(), interval 1 year)");
...@@ -620,6 +605,8 @@ sub Delete($) ...@@ -620,6 +605,8 @@ sub Delete($)
my $uid_idx = $self->uid_idx(); my $uid_idx = $self->uid_idx();
DBQueryWarn("delete from user_credentials where uid_idx='$uid_idx'")
or return -1;
DBQueryWarn("delete from user_pubkeys where uid_idx='$uid_idx'") DBQueryWarn("delete from user_pubkeys where uid_idx='$uid_idx'")
or return -1; or return -1;
DBQueryWarn("delete from user_sslcerts where uid_idx='$uid_idx'") DBQueryWarn("delete from user_sslcerts where uid_idx='$uid_idx'")
...@@ -1861,6 +1848,15 @@ sub ValidUID($$) ...@@ -1861,6 +1848,15 @@ sub ValidUID($$)
TBDB_CHECKDBSLOT_ERROR()); TBDB_CHECKDBSLOT_ERROR());
} }
sub ValidEmail($$)
{
my ($class, $email) = @_;
return TBcheck_dbslot($email, "users", "usr_email",
TBDB_CHECKDBSLOT_WARN()|
TBDB_CHECKDBSLOT_ERROR());
}
# #
# Default project. If not set in the users table, then look at the # Default project. If not set in the users table, then look at the
# project membership, and if only one project then use that. # project membership, and if only one project then use that.
...@@ -1977,6 +1973,48 @@ sub HomeDirOkay($;$) ...@@ -1977,6 +1973,48 @@ sub HomeDirOkay($;$)
return 0; return 0;
} }
#
# Set/Get credential for a user. These are used by APT to store a speaksfor
# credential for a nonlocal user, but might also use it later to
#
sub StoreCredential($$$$)
{
my ($self, $cred, $expires, $cert) = @_;
my $uid = $self->uid();
my $uid_idx = $self->uid_idx();
my $safe_credential = DBQuoteSpecial($cred);
my $safe_certificate = DBQuoteSpecial($cert);
return -1
if (!DBQueryWarn("replace into user_credentials set ".
" uid='$uid', uid_idx='$uid_idx',created=now(), ".
" expires='$expires', ".
" credential_string=$safe_credential, ".
" certificate_string=$safe_certificate"));
return 0;
}
sub GetStoredCredential($)
{
my ($self) = @_;
my $uid = $self->uid();
my $uid_idx = $self->uid_idx();
my $query_result =
DBQueryWarn("select credential_string,certificate_string ".
" from user_credentials ".
"where uid_idx='$uid_idx'");
return undef
if (!$query_result || !$query_result->numrows);
my ($cred, $cert) = $query_result->fetchrow_array();
return ($cred, $cert);
}
# _Always_ make sure that this 1 is at the end of the file... # _Always_ make sure that this 1 is at the end of the file...
1; 1;
...@@ -49,7 +49,8 @@ PSBIN_STUFF = register_resources expire_daemon gencrl postcrl \ ...@@ -49,7 +49,8 @@ PSBIN_STUFF = register_resources expire_daemon gencrl postcrl \
updatecert fixcerts initcerts cacontrol webcacontrol \ updatecert fixcerts initcerts cacontrol webcacontrol \
genextendcred rspeclint chstats listactive \ genextendcred rspeclint chstats listactive \
maptoslice webmaptoslice setexpiration quickvm webquickvm \ maptoslice webmaptoslice setexpiration quickvm webquickvm \
mondbd mondbd parsecert creategeniuser webcreategeniuser \
updategeniuser webupdategeniuser
ifeq ($(ISCLEARINGHOUSE),1) ifeq ($(ISCLEARINGHOUSE),1)
PSBIN_STUFF += ch_daemon PSBIN_STUFF += ch_daemon
...@@ -76,6 +77,8 @@ install: apt-install \ ...@@ -76,6 +77,8 @@ install: apt-install \
$(addprefix $(INSTALL_SBINDIR)/protogeni/, $(PSBIN_STUFF)) \ $(addprefix $(INSTALL_SBINDIR)/protogeni/, $(PSBIN_STUFF)) \
$(INSTALL_LIBEXECDIR)/webquickvm \ $(INSTALL_LIBEXECDIR)/webquickvm \
$(INSTALL_LIBEXECDIR)/webcacontrol \ $(INSTALL_LIBEXECDIR)/webcacontrol \
$(INSTALL_LIBEXECDIR)/webcreategeniuser \
$(INSTALL_LIBEXECDIR)/webupdategeniuser \
$(INSTALL_LIBEXECDIR)/webmaptoslice $(INSTALL_LIBEXECDIR)/webmaptoslice
-rm -f $(INSTALL_SBINDIR)/protogeni/cleanupticket -rm -f $(INSTALL_SBINDIR)/protogeni/cleanupticket
......
#!/usr/bin/perl -w
#
# Copyright (c) 2008-2014 University of Utah and the Flux Group.
#
# {{{GENIPUBLIC-LICENSE
#
# GENI Public License
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and/or hardware specification (the "Work") to
# deal in the Work without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Work, and to permit persons to whom the Work
# is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Work.
#
# THE WORK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE WORK OR THE USE OR OTHER DEALINGS
# IN THE WORK.
#
# }}}
#
use strict;
use English;
use Getopt::Std;
use Data::Dumper;
#
# Create a geni user. This is a nonlocal user, derived from the
# only info we have which is the urn/email. We use this from CloudLab
# web interface (geni-login) to create a stub local account for a
# geni user.
#
sub usage()
{
print STDERR "Usage: $0 [-n] <urn> <email>\n";
exit(1);
}
my $optlist = "nr";
my $impotent = 0;
my $delete = 0;
# Configure ...
my $TB = "@prefix@";
my $TBACCT = "$TB/sbin/tbacct";
my $MKUSERCERT = "$TB/sbin/mkusercert";
my $MODGROUPS = "$TB/sbin/modgroups";
use lib '@prefix@/lib';
use emutil;
use User;
use Project;
use GeniCertificate;
use GeniHRN;
use EmulabConstants;
# Protos.
sub DeleteGeniUser($);
sub fatal($)
{
my ($msg) = @_;
die("*** $0:\n".
" $msg\n");
}
#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"n"})) {
$impotent = 1;
}
if (defined($options{"r"})) {
usage()
if (@ARGV != 1);
$delete = 1;
}
else {
usage()
if (@ARGV != 2);
}
my $urn = $ARGV[0];
fatal("Invalid urn")
if (! GeniHRN::IsValid($urn));
# Make sure we can get this project.
my $project = Project->Lookup("CloudLab");
if (!defined($project)) {
fatal("Cannot find the project.");
}
if ($delete) {
exit(DeleteGeniUser($urn));
}
my $email = $ARGV[1];
my $usr_uid;
fatal("Invalid email")
if (! User->ValidEmail($email));
# Must not be a user with same nonlocal ID.
if (User->LookupNonLocal($urn)) {
fatal("We already have a user with that nonlocal ID (urn)");
}
#
# Parse urn and email, maybe we can get a unique uid out of one.
#
my (undef,undef,$uid) = GeniHRN::Parse($urn);
fatal("Could not parse urn")
if (!defined($uid));
if (User->ValidUID($uid) && !User->Lookup($uid)) {
$usr_uid = $uid;
}
else {
#
# Split email and try that.
#
my ($token) = split("@", $email);
if (defined($token) &&
User->ValidUID($token) && !User->Lookup($token)) {
$usr_uid = $token;
}
}
#
# Neither worked, so need to generate something. Ick.
#
if (!defined($usr_uid)) {
if (!User->ValidUID($uid)) {
# Random
$usr_uid = "g" . substr(lc(emutil::GenHash()), 0, 6);
}
else {
my $i;
$uid = substr($uid, 0, 7);
for ($i = 0 ; $i <= 9; $i++) {
if (!User->Lookup("${uid}${i}")) {
$usr_uid = "${uid}${i}";
last;
}
}
if ($i > 9) {
$usr_uid = "g" . substr(lc(emutil::GenHash()), 0, 6);
}
}
}
if ($impotent) {
print "Would create nolocal user '$usr_uid' ...\n";
exit(0);
}
#
# Okay, create new account in the DB.
#
my $user = User->Create($usr_uid,
$User::NEWUSER_FLAGS_NONLOCAL,
{"usr_name" => "Geni User $usr_uid",
"usr_email" => $email,
"nonlocal_id" => $urn,
"nonlocal_type" => "geni",
});
fatal("Could not create user!")
if (!defined($user));
#
# Add them to the holding project. This will need more thought.
#
if ($project->AddMemberShip($user, $Group::MemberShip::TRUSTSTRING_LOCALROOT)) {
$user->Delete();
fatal("Could not add new user to project");
}
# And then instantiate the user.
system("$TBACCT add $usr_uid");
if ($?) {
$project->DeleteMemberShip($user);
$user->Delete();
fatal("Could not instantiate user account!")
}
# We need to generate the encrypted ssl certificate to keep
# things happy.
my $certpass = substr(lc(emutil::GenHash()), 0, 10);
system("$MKUSERCERT -p $certpass $usr_uid");
if ($?) {
$project->DeleteMemberShip($user);
$user->Delete();
fatal("Could not create local SSL certificate");
}
exit(0);
#
# Delete (purge!) geni user. Not to be used generally, please use
# the normal archive path. This is for debugging.
#
sub DeleteGeniUser($)
{
my ($urn) = @_;
my $user = User->LookupNonLocal($urn);
if (!defined($user)) {
fatal("No such local user!");
}
my $uid = $user->uid();
my $pid = $project->pid();
system("$MODGROUPS -r $pid:$pid $uid");
system("$TBACCT -f del $uid") == 0 or
fatal("$TBACCT $uid failed!");
$user->Delete();
return 0;
}
#!/usr/bin/perl -w
#
# Copyright (c) 2008-2014 University of Utah and the Flux Group.
#
# {{{GENIPUBLIC-LICENSE
#
# GENI Public License
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and/or hardware specification (the "Work") to
# deal in the Work without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Work, and to permit persons to whom the Work
# is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Work.
#
# THE WORK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE WORK OR THE USE OR OTHER DEALINGS
# IN THE WORK.
#
# }}}
#
use strict;
use English;
use Getopt::Std;
use Data::Dumper;
#
# Parse a certificate and print out useful info. Used by the web interface
# so that it does not need to duplicate code in GeniCertificate.
#
sub usage()
{
print STDERR "Usage: $0 [-a] <cert file> <outfile>\n";
exit(1);
}
my $optlist = "a";
my $showall = 0;
# Configure ...
my $TB = "@prefix@";
use lib '@prefix@/lib';
use GeniCertificate;
use GeniHRN;
sub fatal($)
{
my ($msg) = @_;
die("*** $0:\n".
" $msg\n");
}
#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"a"})) {
$showall = 1;
}
usage()
if (@ARGV != 2);
my $certfile = $ARGV[0];
my $outfile = $ARGV[1];
my $certificate = GeniCertificate->LoadFromFile($certfile);
if (!defined($certificate)) {
fatal("Could not parse certificate");
}
if (!open(OUT, ">$outfile")) {
fatal("Could not open file for output");
}
print OUT "<attributes>\n";
print OUT "<attribute name='urn'>" . $certificate->urn();
print OUT "</attribute>\n";
print OUT "<attribute name='email'>" . $certificate->email();
print OUT "</attribute>\n";
print OUT "<attribute name='uuid'>" . $certificate->uuid();
print OUT "</attribute>\n";
print OUT "</attributes>\n";
close(OUT);
exit(0);
...@@ -40,27 +40,28 @@ use Cwd qw(realpath); ...@@ -40,27 +40,28 @@ use Cwd qw(realpath);
# #
sub usage() sub usage()
{ {
print "Usage: quickvm [-l] [-u uuid] [-a aggregate] <xmlfile>\n"; print "Usage: quickvm [-u uuid] [-a aggregate] <xmlfile>\n";
print "Usage: quickvm -k <uuid>\n"; print "Usage: quickvm -k <uuid>\n";
print "Usage: quickvm -e <seconds> <uuid>\n"; print "Usage: quickvm -e <seconds> <uuid>\n";
print "Usage: quickvm -s <uuid> <sliver_urn> <imagename>\n"; print "Usage: quickvm -s <uuid> <sliver_urn> <imagename>\n";
exit(1); exit(1);
} }
my $optlist = "dkve:lu:a:st:f"; my $optlist = "dkve:u:a:st:f";
my $debug = 0; my $debug = 0;
my $verbose = 1; my $verbose = 1;
my $killit = 0;