Commit 3afc584e authored by Russ Fish's avatar Russ Fish

Change the showpubkeys page to call addpubkey via XML.

      www/showpubkeys.php3 - Add a NewPubKey function to spit out XML to addpubkey.
      account/addpubkey.in - Add -X <xmlfile> in place of other command-line args.
      sql/database-fill.sql - Add 'user_pubkeys' entries for addpubkey's use.
parent 9a586d0b
......@@ -6,6 +6,7 @@
#
use English;
use Getopt::Std;
use XML::Simple;
#
# Parse ssh public keys and enter into the DB. The default format is
......@@ -17,17 +18,19 @@ use Getopt::Std;
sub usage()
{
print "Usage: addpubkeys [-k | -f] [-n | -u <user>] [<keyfile> | <key>]\n";
print " addpubkeys -x <xmlfile>\n";
print " addpubkeys [-i [-r] | -w] <user>\n";
print "Options:\n";
print " -k Indicates that key was passed in on the command line\n";
print " -f Indicates that key was passed in as a filename\n";
print " -n Verify key format only; do not enter into into DB\n";
print " -X Get args from an XML file: verify, user, keyfile.\n";
print " -w Generate new authkeys (protocol 1 and 2) file for user\n";
print " -i Initialize mode; generate initial key for user\n";
print " -r Force a regenerate of initial key for user\n";
exit(-1);
}
my $optlist = "kniwfu:r";
my $optlist = "kniwfu:rX:";
my $iskey = 0;
my $verify = 0;
my $initmode = 0;
......@@ -35,6 +38,7 @@ my $force = 0;
my $genmode = 0;
my $nobody = 0;
my $noemail = 0;
my $xmlfile;
#
# Configure variables
......@@ -73,10 +77,23 @@ use libtestbed;
sub ParseKey($);
sub InitUser();
sub GenerateKeyFile();
sub ParseXmlArgs($$$$$);
sub fatal($);
my $HOMEDIR = USERROOT();
#
# These are the fields that we allow to come in from the XMLfile.
#
my $SLOT_OPTIONAL = 0x1; # The field is not required.
my $SLOT_REQUIRED = 0x2; # The field is required and must be non-null.
my $SLOT_ADMINONLY = 0x4; # Only admins can set this field.
my %xmlfields =
# XML Field Name DB slot name Flags Default
("verify" => ["verify", $SLOT_OPTIONAL, 0],
"user" => ["user", $SLOT_OPTIONAL],
"keyfile" => ["keyfile", $SLOT_REQUIRED]);
#
# Turn off line buffering on output
#
......@@ -133,6 +150,26 @@ if (defined($options{"w"})) {
if (defined($options{"u"})) {
$user = $options{"u"};
}
if (defined($options{"X"})) {
$xmlfile = $options{"X"};
my %xmlargs = ();
my %errors = ();
ParseXmlArgs($xmlfile, "user_pubkeys", \%xmlfields, \%xmlargs, \%errors);
if (keys(%errors)) {
foreach my $key (keys(%errors)) {
my $val = $errors{$key};
print "${key}: $val\n";
}
fatal("XML arg error");
}
$verify = $xmlargs{"verify"};
$user = $xmlargs{"user"}
if (exists($xmlargs{"user"}));
$ARGV[0] = $xmlargs{"keyfile"};
}
if ($verify && $genmode) {
usage();
}
......@@ -544,6 +581,91 @@ sub GenerateKeyFile()
return 0;
}
sub ParseXmlArgs($$$$$) {
my ($xmlfile, $table_name, $fields_ref, $args_ref, $errs_ref) = @_;
#
# Input args:
# $xmlfile - XML file path.
# $table_name - table_regex table_name for low-level checking patterns.
# $fields_ref - xmlfields specification (hash reference.)
#
# Output args:
# $args_ref - Parsed argument values (hash reference.)
# $errs_ref - Error messages on failure (hash reference.)
my $debug = 0;
#
# Must wrap the parser in eval since it exits on error.
#
my $xmlparse = eval { XMLin($xmlfile,
VarAttr => 'name',
ContentKey => '-content',
SuppressEmpty => undef); };
if ($@) {
$errs_ref->{"XML Parse Error"} = "Return code $@";
return;
}
#
# Make sure all the required arguments were provided.
#
my $key;
foreach $key (keys(%{ $fields_ref })) {
my (undef, $required, undef) = @{$fields_ref->{$key}};
$errs_ref->{$key} = "Required value not provided"
if ($required & $SLOT_REQUIRED &&
! exists($xmlparse->{'attribute'}->{"$key"}));
}
return
if (keys(%{ $errs_ref }));
foreach $key (keys(%{ $xmlparse->{'attribute'} })) {
my $value = $xmlparse->{'attribute'}->{"$key"}->{'value'};
if ($debug) {
print STDERR "User attribute: '$key' -> '$value'\n";
}
$errs_ref->{$key} = "Unknown attribute"
if (!exists($fields_ref->{$key}));
my ($dbslot, $required, $default) = @{$fields_ref->{$key}};
if ($required & $SLOT_REQUIRED) {
# A slot that must be provided, so do not allow a null value.
if (!defined($value)) {
$errs_ref->{$key} = "Must provide a non-null value";
next;
}
}
if ($required & $SLOT_OPTIONAL) {
# Optional slot. If value is null skip it. Might not be the correct
# thing to do all the time?
if (!defined($value)) {
next
if (!defined($default));
$value = $default;
}
}
if ($required & $SLOT_ADMINONLY) {
# Admin implies optional, but thats probably not correct approach.
$errs_ref->{$key} = "Administrators only"
if (! $this_user->IsAdmin());
}
# Now check that the value is legal.
if (! TBcheck_dbslot($value, $table_name, $dbslot,
TBDB_CHECKDBSLOT_ERROR)) {
$errs_ref->{$key} = TBFieldErrorString();
next;
}
$args_ref->{$dbslot} = $value;
}
}
sub fatal($) {
my($mesg) = $_[0];
......
......@@ -924,6 +924,11 @@ REPLACE INTO table_regex VALUES ('sitevariables','reset','text','redirect','defa
REPLACE INTO table_regex VALUES ('sitevariables','defaultvalue','text','redirect','default:text',0,0,NULL);
REPLACE INTO table_regex VALUES ('sitevariables','description','text','redirect','default:text',0,0,NULL);
REPLACE INTO table_regex VALUES ('experiment_template_searches','name','text','regex','^[-\\w]*$',2,64,NULL);
REPLACE INTO table_regex VALUES ('user_pubkeys','verify','text','redirect','default:boolean',0,0,NULL);
REPLACE INTO table_regex VALUES ('user_pubkeys','user','text','redirect','users:uid',0,0,NULL);
REPLACE INTO table_regex VALUES ('user_pubkeys','keyfile','text','regex','^[-_\\w\\.\\/:+]*$',1,256,NULL);
--
-- Dumping data for table `testsuite_preentables`
--
......
......@@ -35,6 +35,9 @@ if (!$isadmin &&
USERERROR("You do not have permission to view ${target_uid}'s keys!", 1);
}
#
# Spit the form out using the array of data.
#
function SPITFORM($formfields, $errors)
{
global $isadmin, $target_user, $BOSSNODE;
......@@ -211,7 +214,7 @@ function SPITFORM($formfields, $errors)
#
# On first load, display a form of current values.
#
if (! isset($submit)) {
if (!isset($submit)) {
$defaults = array();
$defaults["password"] = "";
SPITFORM($defaults, 0);
......@@ -246,7 +249,7 @@ if (isset($_FILES['usr_keyfile']) &&
$errors["PubKey File"] = "Invalid characters";
}
else {
$addpubkeyargs = escapeshellarg($localfile);
$keyfile = $localfile;
chmod($localfile, 0644);
}
}
......@@ -254,7 +257,7 @@ if (isset($_FILES['usr_keyfile']) &&
#
# Must verify passwd to add keys.
#
if (isset($addpubkeyargs)) {
if (isset($keyfile)) {
if (! $isadmin) {
if (!isset($formfields["password"]) ||
strcmp($formfields["password"], "") == 0) {
......@@ -276,23 +279,114 @@ if (count($errors)) {
return;
}
#
# Build up argument array to pass along.
#
$args = array();
$args["user"] = $target_uid;
if (isset($keyfile) && $keyfile != "") {
$args["keyfile"] = $keyfile;
}
#
# 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("-n -u $target_uid $addpubkeyargs")) {
$args["verify"] = 1;
if (! ($result = NewPubKey($args, $errors))) {
$errors["Pubkey Format"] = "Could not be parsed. Is it a public key?";
# Always respit the form so that the form fields are not lost.
# I just hate it when that happens so lets not be guilty of it ourselves.
SPITFORM($formfields, $errors);
PAGEFOOTER();
return;
}
#
# Insert key, update authkeys files and nodes if appropriate.
#
ADDPUBKEY("-u $target_uid $addpubkeyargs");
$args["verify"] = 0;
if (! ($result = NewPubKey($args, $errors))) {
# Always respit the form so that the form fields are not lost.
# I just hate it when that happens so lets not be guilty of it ourselves.
SPITFORM($formfields, $errors);
PAGEFOOTER();
return;
}
#
# Redirect back, avoiding a POST in the history.
#
header("Location: ". CreateURL("showpubkeys", $target_user));
#
# When there's a PubKeys class, this will be a Class function to edit them...
#
function NewPubKey($args, &$errors) {
global $suexec_output, $suexec_output_array, $TBADMINGROUP;
#
# Generate a temporary file and write in the XML goo.
#
$xmlname = tempnam("/tmp", "addpubkey");
if (! $xmlname) {
TBERROR("Could not create temporary filename", 0);
$errors[] = "Transient error; please try again later.";
return null;
}
if (! ($fp = fopen($xmlname, "w"))) {
TBERROR("Could not open temp file $xmlname", 0);
$errors[] = "Transient error; please try again later.";
return null;
}
fwrite($fp, "<PubKey>\n");
foreach ($args as $name => $value) {
fwrite($fp, "<attribute name=\"$name\">");
fwrite($fp, " <value>" . htmlspecialchars($value) . "</value>");
fwrite($fp, "</attribute>\n");
}
fwrite($fp, "</PubKey>\n");
fclose($fp);
chmod($xmlname, 0666);
$retval = SUEXEC("nobody", "nobody", "webaddpubkey -X $xmlname",
SUEXEC_ACTION_IGNORE);
if ($retval) {
if ($retval < 0) {
$errors[] = "Transient error; please try again later.";
SUEXECERROR(SUEXEC_ACTION_CONTINUE);
}
else {
# unlink($xmlname);
if (count($suexec_output_array)) {
for ($i = 0; $i < count($suexec_output_array); $i++) {
$line = $suexec_output_array[$i];
if (preg_match("/^([-\w]+):\s*(.*)$/",
$line, $matches)) {
$errors[$matches[1]] = $matches[2];
}
else
$errors[] = $line;
}
}
else
$errors[] = "Transient error; please try again later.";
}
return null;
}
# There are no return value(s) to parse at the end of the output.
# Unlink this here, so that the file is left behind in case of error.
# We can then edit the pubkeys by hand from the xmlfile, if desired.
unlink($xmlname);
return true;
}
?>
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