Commit 3bc9d3a2 authored by Jonathon Duerig's avatar Jonathon Duerig
Browse files

Merge branch 'master' of git-public.flux.utah.edu:/flux/git/emulab-devel

parents dd2289cb c50139c6
......@@ -55,13 +55,14 @@ sub checknodeid($$)
my ($nid,$msg) = @_;
if ($nid =~ /^(.*)\x0/) {
my $onid = $nid;
$nid = $1;
if (!exists($carped{$nid}) && open(MAIL, "| /usr/sbin/sendmail -t")) {
$carped{$nid} = 1;
require Carp;
my $TBOPS = "@TBOPSEMAIL@";
print MAIL "To: $TBOPS\n";
print MAIL "Subject: NUL in node_id '$nid'\n";
print MAIL "Subject: NUL in node_id '$nid' ('$onid')\n";
print MAIL "$msg\n";
print MAIL "\n";
print MAIL Carp::longmess();
......
......@@ -144,7 +144,14 @@ sub GetCredential($)
"Malformed URN in the certificate")
if (!GeniHRN::IsValid($urn));
my ($auth, $type, $id) = GeniHRN::Parse($urn);
return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"Not an authority certificate")
if ($type ne "authority");
return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"Not an am/cm/sa/ses certificate")
if (! ($id =~ /^(am|cm|ses|sa)$/i));
#
# Check for an existing authority.
#
......@@ -179,15 +186,22 @@ sub GetCredential($)
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Who are you?");
}
my $credential =
GeniCredential->CreateSigned($authority,
$caller_authority,
$GeniCredential::LOCALMA_FLAG);
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
my $credential = GeniCredential->Create($authority, $caller_authority);
if (!defined($credential)) {
print STDERR "Could not create credential for $caller_authority\n";
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
#
# We want this credential to be valid for a long time;
#
$credential->SetExpiration(time() + 24 * 60 * 60 * 120);
if ($credential->Sign($GeniCredential::LOCALMA_FLAG) != 0) {
$credential->Delete();
print STDERR "Could not sign credential for $caller_authority\n";
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Could not create signed credential")
if (!defined($credential));
}
return GeniResponse->Create(GENIRESPONSE_SUCCESS,
$credential->asString());
}
......
......@@ -512,7 +512,7 @@ sub PipeTo($$$)
{
my ($self, $withkey, $string) = @_;
print STDERR "PipeTo: $self, '$string'\n";
# print STDERR "PipeTo: $self, '$string'\n";
require Socket;
import Socket qw(:DEFAULT);
......
#!/usr/bin/perl -wT
#
# GENIPUBLIC-COPYRIGHT
# Copyright (c) 2008-2010 University of Utah and the Flux Group.
# Copyright (c) 2008-2011 University of Utah and the Flux Group.
# All rights reserved.
#
package GeniCredential;
......@@ -135,6 +135,7 @@ sub Create($$$)
$self->{'string'} = undef;
$self->{'capabilities'} = undef;
$self->{'extensions'} = undef;
$self->{'parent_cred'} = undef;
$self->{'idx'} = undef; # Only set when stored to DB.
bless($self, $class);
......@@ -157,6 +158,7 @@ sub hrn($) { return $_[0]->{"target_cert"}->hrn(); }
sub target_urn($) { return $_[0]->{"target_cert"}->urn(); }
sub owner_urn($) { return $_[0]->{"owner_cert"}->urn(); }
sub signer_certs($) { return $_[0]->{"signer_certs"}; }
sub parent_cred($) { return $_[0]->{"parent_cred"}; }
#
# Stringify for output.
......@@ -190,6 +192,20 @@ sub IsExpired($)
return (time() >= $expires);
}
#
# Set the expiration time for a credential. Only changes the
# in memory copy, not the DB.
#
sub SetExpiration($$)
{
my ($self, $expires) = @_;
$self->{'valid_until'} =
POSIX::strftime("20%y-%m-%dT%H:%M:%S", localtime($expires));
return 0;
}
#
# Compare the certs inside a credential to make sure that the
# certs for the target/owner have not changed. Say, if the user
......@@ -323,6 +339,18 @@ sub GetSelfCredential($$)
return GeniCredential->CreateSigned($me, $me, $signer);
}
# Find an element (which must exist exactly once) within a node.
my $find = sub
{
my( $node, $name ) = @_;
my @cnodes = grep( $_->nodeName eq $name, $node->childNodes );
return undef unless scalar( @cnodes ) == 1;
return $cnodes[ 0 ];
};
#
# Create a credential object from a signed credential string.
#
......@@ -364,6 +392,14 @@ sub CreateFromSigned($$;$)
return undef;
}
my $root = $doc->documentElement();
my $credential_el = &$find( $root, "credential" );
return undef unless defined( $credential_el );
# Dig out the entire credential structure to save it.
my ($credential) = $doc->getElementsByTagName("credential");
# Ditto the signatures.
my @signatures = $doc->getElementsByTagName("signatures");
# Dig out the extensions
# now extensions is an xml element.
......@@ -371,7 +407,7 @@ sub CreateFromSigned($$;$)
$root)->get_nodelist;
# UUID of the credential.
my ($uuid_node) = $doc->getElementsByTagName("uuid");
my $uuid_node = &$find( $credential_el, "uuid" );
return undef
if (!defined($uuid_node));
my $this_uuid = $uuid_node->to_literal();
......@@ -382,7 +418,7 @@ sub CreateFromSigned($$;$)
}
# Expiration
my ($expires_node) = $doc->getElementsByTagName("expires");
my $expires_node = &$find( $credential_el, "expires" );
if (!defined($expires_node)) {
print STDERR "Credential is missing expires node\n";
return undef;
......@@ -402,7 +438,7 @@ sub CreateFromSigned($$;$)
$expires = POSIX::strftime("20%y-%m-%dT%H:%M:%S", localtime($when));
# Dig out the target certificate.
my ($cert_node) = $doc->getElementsByTagName("target_gid");
my $cert_node = &$find( $credential_el, "target_gid" );
return undef
if (!defined($cert_node));
my $target_certificate =
......@@ -426,7 +462,7 @@ sub CreateFromSigned($$;$)
}
# Dig out the owner certificate.
($cert_node) = $doc->getElementsByTagName("owner_gid");
$cert_node = &$find( $credential_el, "owner_gid" );
return undef
if (!defined($cert_node));
......@@ -468,6 +504,9 @@ sub CreateFromSigned($$;$)
$self->{'owner_uuid'} = $owner_certificate->uuid();
$self->{'owner_cert'} = $owner_certificate;
$self->{'string'} = $string;
$self->{'parent_cred'} = undef;
$self->{'credentialdoc'} = $credential;
$self->{'signatures'} = \@signatures;
$self->{'signer_certs'} = $signer_certs;
$self->{'idx'} = undef; # Only set when stored to DB.
bless($self, $class);
......@@ -569,7 +608,7 @@ sub Sign($$)
$cap_xml .= "<can_delegate>$can_delegate</can_delegate>";
$cap_xml .= "</privilege>\n";
}
$cap_xml .= "</privileges>\n";
$cap_xml .= "</privileges>";
my $extensions = $self->extensions();
$cap_xml .= GeniXML::Serialize($extensions)
......@@ -620,8 +659,16 @@ sub Sign($$)
my $id = sprintf( "%04X%04X%04X%04X", int( rand( 0x10000 ) ),
int( rand( 0x10000 ) ), int( rand( 0x10000 ) ),
int( rand( 0x10000 ) ) );
# If this is a delegation, need to construct a different XML file.
my $parent_xml = "";
if (defined($self->{'parent_cred'})) {
$parent_xml = "<parent>" .
$self->{'parent_cred'}->{'credentialdoc'}->toString() .
"</parent>";
}
my $template =
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n".
"<credential xml:id=\"ref$id\">\n".
" <type>privilege</type>\n".
" <serial>$idx</serial>\n".
......@@ -631,13 +678,20 @@ sub Sign($$)
" <target_urn>$target_urn</target_urn>\n".
" <uuid>$cred_uuid</uuid>\n".
" <expires>$expires</expires>\n".
" $cap_xml\n".
" $cap_xml". $parent_xml .
"</credential>\n";
if (defined($self->{'parent_cred'})) {
$template = "<signed-credential>\n$template\n";
foreach my $sig (@{ $self->{'parent_cred'}->{'signatures'}}) {
$template .= $sig->toString();
}
$template .= "</signed-credential>\n";
}
my ($fh, $filename) = tempfile(UNLINK => 0);
return -1
if (!defined($fh));
print $fh "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n";
print $fh $template;
close($fh);
......@@ -697,6 +751,27 @@ sub Sign($$)
return 0;
}
#
# Delegate to another owner. This creates a new credential.
#
sub Delegate($$)
{
my ($self, $owner) = @_;
my $credential = GeniCredential->Create($self->target_cert(), $owner);
if (!defined($credential)) {
print STDERR "Could not delegate $self to $owner\n";
return undef;
}
#
# The new credential has no privs; the caller has to fill
# them for this credential to be useful.
#
$credential->{'parent_cred'} = $self;
$credential->{'valid_until'} = $self->{'valid_until'};
return $credential;
}
#
# Store the given signed credential in the DB.
#
......@@ -709,6 +784,11 @@ sub Store($)
return 0
if (defined($self->idx()));
if (defined($self->{'parent_cred'})) {
print STDERR "Not allowed to store delegted credential: $self\n";
return -1;
}
# Every credential store gets a new unique index.
my $idx = TBGetUniqueIndex('next_ticket', 1);
......
......@@ -18,8 +18,8 @@ PSBIN_STUFF = register_resources expire_daemon gencrl postcrl \
gencrlbundle shutdownslice remauthority listusage \
update reregister cleanupticket listhistory \
register_sliver sa_daemon genadmincredential \
genclrcredentials genallow_extcred advt-merge.py \
reservevlans delgeniuser
getchcredential genallow_extcred advt-merge.py \
reservevlans delgeniuser delegatecredential
ifeq ($(ISMAINSITE),1)
PSBIN_STUFF += ch_daemon
......
#!/usr/bin/perl -w
#
# GENIPUBLIC-COPYRIGHT
# Copyright (c) 2008-2011 University of Utah and the Flux Group.
# All rights reserved.
#
use strict;
use English;
use Getopt::Std;
#
# This script can be used to delegate a credential to a local user.
# Acts as the SA, but use -c to act as the CM. The credential is
# specified as a text file on the command line, or on stdin. The output
# is written to the file or stdout. The permissions to delegate are
# specified as pairs in the form 'perm:delegate" where 'perm' is
# something like "resolve" and 'delegate' is a boolean that says if
# that permission can be further delegated. You must supply at least
# one permission (can be special tag 'all' to grant all perms).
#
# For example:
#
# boss> getchcredential | delegatecredential urn:stoller resolve:0 list:1
#
# Note that I shortened the URN for brevity.
#
sub usage()
{
print STDERR "Usage: $0 [-c] [-i input_file] [-o output_file] <user-urn> ";
print STDERR "[permission,delegate ...]\n";
exit(-1);
}
my $optlist = "ci:o:";
my $ascm = 0;
my $infile;
my $outfile;
# Configure ...
my $TB = "@prefix@";
my $SACERT = "$TB/etc/genisa.pem";
my $CMCERT = "$TB/etc/genicm.pem";
# Do this early so that we talk to the right DB.
use vars qw($GENI_DBNAME);
BEGIN { $GENI_DBNAME = "geni"; }
use lib '@prefix@/lib';
use GeniCredential;
use GeniCertificate;
use GeniAuthority;
use GeniHRN;
use GeniResponse;
use GeniUser;
use GeniRegistry;
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{"i"})) {
$infile = 1;
}
if (defined($options{"o"})) {
$outfile = 1;
}
if (defined($options{"c"})) {
$ascm = 1;
}
usage()
if (@ARGV < 2);
my $user_urn = shift();
#
# Must be an emulab user.
#
if (! (GeniHRN::IsValid($user_urn))) {
fatal("Malformed user urn");
}
my $geniuser = GeniUser->Lookup($user_urn, 1);
if (!defined($geniuser)) {
fatal("No such user in the DB");
}
#
# Load the cert to act as caller context.
#
my $certificate = GeniCertificate->LoadFromFile(($ascm ? $CMCERT : $SACERT));
if (!defined($certificate)) {
fatal("Could not load certificate\n");
}
Genixmlrpc->SetContext(Genixmlrpc->Context($certificate));
#
# Load the input credential.
#
my $credstring = "";
if ($infile) {
open(IN, $infile)
or fatal("Could not open $infile");
while (<IN>) {
$credstring .= $_;
}
}
else {
while (<STDIN>) {
$credstring .= $_;
}
}
my $credential = GeniCredential->CreateFromSigned($credstring);
if (!defined($credential)) {
fatal("Could not load credential\n");
}
my $delegate = $credential->Delegate($geniuser);
#
# Add the perms
#
foreach my $arg (@ARGV) {
if ($arg =~ /^(\w*):(\d)$/) {
$delegate->AddCapability($1, $2);
}
else {
fatal("Bad permission: $arg");
}
}
if ($delegate->Sign(($ascm ? $GeniCredential::LOCALCM_FLAG :
$GeniCredential::LOCALSA_FLAG)) != 0) {
fatal("Could not sign delegated credential");
}
if ($outfile) {
open(OUT, ">$outfile")
or fatal("Could not open $outfile");
print OUT $delegate->asString();
close(OUT);
}
else {
print $delegate->asString();
}
exit(0);
#!/usr/bin/perl -w
#
# GENIPUBLIC-COPYRIGHT
# Copyright (c) 2008-2010 University of Utah and the Flux Group.
# All rights reserved.
#
use strict;
use lib '@prefix@/lib';
# Do this early so that we talk to the right DB.
use vars qw($GENI_DBNAME $GENI_ISCLRHOUSE);
BEGIN { $GENI_DBNAME = "geni-ch"; $GENI_ISCLRHOUSE = 1; }
use GeniCredential;
use GeniCertificate;
use GeniAuthority;
use GeniHRN;
use GeniResponse;
use GeniUser;
# This script can be used to issue a credential to a user with specified
# clearinghouse as target with only Resolve privilege. It means he can only
# List and Resolve on the clearinghouse.
# ./genclrcredentials.pl <user-urn> <clearinghouse-urn>
sub CreateSpecialCredential
{
my $owner_urn = shift;
my $target_ch_urn = shift;
#
# Must be an emulab user who is talking to us.
# If any of the URN specified is invalid do no accept.
if (! (GeniHRN::IsValid($owner_urn) &&
GeniHRN::IsValid($target_ch_urn))) {
return GeniResponse->MalformedArgsResponse();
}
my $geniuser = GeniUser->Lookup($owner_urn, 1);
if (!defined($geniuser)) {
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN,
undef, "Who are you?");
}
my $authority = GeniAuthority->Lookup($target_ch_urn);
if (!defined($authority)) {
print STDERR "Could not find local authority object for".
"$target_ch_urn\n";
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
my $signer = $GeniCredential::LOCALMA_FLAG;
my $credential = GeniCredential->Create($authority, $geniuser);
if (!defined($credential)) {
print "Could not create credential for $authority, $geniuser\n";
return undef;
}
$credential->AddCapability("resolve",1);
if ($credential->Sign($signer) != 0) {
$credential->Delete();
print "Could not sign credential for $authority, $geniuser\n";
return undef;
}
return GeniResponse->Create(GENIRESPONSE_SUCCESS,
$credential->asString());
}
my $numArgs = $#ARGV + 1;
if($numArgs !=2) {
print "Please specify <user-urn> <ch-urn> as command line arguments\n\n";
}else{
my $val = CreateSpecialCredential @ARGV;
#print $val->{"output"};
#print $val->{"code"};
print $val->{"value"};
}
#!/usr/bin/perl -w
#
# GENIPUBLIC-COPYRIGHT
# Copyright (c) 2008-2011 University of Utah and the Flux Group.
# All rights reserved.
#
use strict;
use lib '@prefix@/lib';
# Do this early so that we talk to the right DB.
use vars qw($GENI_DBNAME);
BEGIN { $GENI_DBNAME = "geni"; }
use GeniCredential;
use GeniCertificate;
use GeniAuthority;
use GeniHRN;
use GeniResponse;
use GeniUser;
use GeniRegistry;
# Configure ...
my $TB = "@prefix@";
my $SACERT = "$TB/etc/genisa.pem";
#
# This script can be used grab a CH credential and dump it to stdout.
# The context is the SA (the CH is granting a credential to the SA).
#
sub usage()
{
print STDERR "Usage: $0\n";
exit(-1);
}
sub fatal($)
{
my ($msg) = @_;
die("*** $0:\n".
" $msg\n");
}
usage()
if (@ARGV);
#
# Load the cert to act as caller context.
#
my $certificate = GeniCertificate->LoadFromFile($SACERT);
if (!defined($certificate)) {
fatal("Could not load certificate from $SACERT\n");
}
Genixmlrpc->SetContext(Genixmlrpc->Context($certificate));
my $clrcredential = GeniRegistry::ClearingHouse->GetCredential();
if (!defined($clrcredential)) {
fatal("Could not get clearinghouse credential\n");
}
print $clrcredential->asString();
#!/usr/bin/perl -w
#
# GENIPUBLIC-COPYRIGHT
# Copyright (c) 2008-2009 University of Utah and the Flux Group.
# Copyright (c) 2008-2011 University of Utah and the Flux Group.
# All rights reserved.
#
use strict;
......@@ -237,6 +237,17 @@ if ($root->nodeName eq "credential") {
#print $root->toString(1) . "\n";
}
else {
#
# Must be consistent about namespaces or else the signature does
# not verify later.
#
$root->setNamespace($GeniUtil::XSI_NS, "xsi", 0);
$root->setAttributeNS($GeniUtil::XSI_NS, "noNamespaceSchemaLocation"
, $GeniUtil::CREDENTIAL_SCHEMA_LOCATION);
$root->setAttributeNS($GeniUtil::XSI_NS, "schemaLocation"
, $GeniUtil::EXTENSIONS_NS . " "
. $GeniUtil::EXTENSIONS_SCHEMA_LOCATION);