diff --git a/www/GNUmakefile.in b/www/GNUmakefile.in index d14c1f8405d5a0b5697a6544129b148c036cac4f..c9de76282e485473ded624cb9e7220fe4aaea724 100644 --- a/www/GNUmakefile.in +++ b/www/GNUmakefile.in @@ -20,7 +20,7 @@ include $(OBJDIR)/Makeconf # Force dependencies to make sure configure regenerates if the .in file # is changed. # -all: defs.php3 dbdefs.php3 swish.conf websearch +all: defs.php3 dbdefs.php3 swish.conf websearch xmlrpc.php3 include $(TESTBED_SRCDIR)/GNUmakerules diff --git a/www/defs.php3.in b/www/defs.php3.in index 2056754d95e874d693602c5740a437b411d467c7..758831a382d35d4a57cb852e2244f9393e60e729 100644 --- a/www/defs.php3.in +++ b/www/defs.php3.in @@ -286,95 +286,6 @@ function SUEXEC($uid, $gid, $cmdandargs, $action) { return $suexec_retval; } -# -# Invoke the XMLRPC backend. We invoke the xmlrpc server, writing the request -# to its stdin. We then wait for the reply to came back on its stdout. We -# decode that reply, and return an error status and output to the caller. -# Note that we run the backend as the uid/gid, much like we do for plain -# scripts. This might change in the future. -# -function XMLRPC($uid, $gid, $method, $arghash) -{ - global $TBSUEXEC_PATH; - - $xmlcode = xmlrpc_encode_request($method, array(0.1, $arghash)); - - $descriptorspec = array(0 => array("pipe", "r"), - 1 => array("pipe", "w")); - - $process = proc_open("$TBSUEXEC_PATH $uid $gid webxmlrpc", - $descriptorspec, $pipes); - - if (! is_resource($process)) { - TBERROR("Could not invoke XMLRPC backend!\n". - "$uid $gid $method\n". - print_r($arghash, true), 1); - } - # $pipes now looks like this: - # 0 => writeable handle connected to child stdin - # 1 => readable handle connected to child stdout - - # - # Write the request to the process, and then close the pipe so that - # the other side sees the EOF. The sshxmlrpc protocol looks sorta - # like a POST request, so we have to do that. - # - fwrite($pipes[0], "content-length: " . strlen($xmlcode) . "\r\n"); - fwrite($pipes[0], "\r\n"); - fwrite($pipes[0], "$xmlcode"); - fflush($pipes[0]); - fclose($pipes[0]); - - # - # Now read back the results into a string. We then convert the string - # back into a PHP datatype. This datatype is defined outside this code - # though. - # - # Skip the headers, but we need the content-length. - # - $content_length = 0; - while (!feof($pipes[1]) && ($foo = trim(fgets($pipes[1], 4096)))) { - if (preg_match("/^content-length: (\d*)/", $foo, $matches)) { - $content_length = $matches[1]; - } - } - - $output = ""; - while(!feof($pipes[1])) { - $output .= fgets($pipes[1], 1024); - } - fclose($pipes[1]); - - # It is important that you close any pipes before calling - # proc_close in order to avoid a deadlock. - $return_value = proc_close($process); - - if (!$return_value && $content_length) { - $decoded = xmlrpc_decode_request(substr($output, 0, $content_length), - $meth); - } - - # On command error or on a "Fault" reply, send email and terminate the - # script; something went really wrong. - if ($return_value || !$content_length || - (count($decoded) == 2 && - array_key_exists("faultCode", $decoded) && - array_key_exists("faultString", $decoded)) || - !(array_key_exists("code", $decoded) && - array_key_exists("value", $decoded) && - array_key_exists("output", $decoded))) { - TBERROR("XMLRPC backend failure!\n". - "$uid $gid $method returned $return_value\n". - "Arg Hash:\n" . - print_r($arghash, true) . "\n\n" . - "XML:\n" . - "$xmlcode\n\n" . - "Output:\n" . - "$output\n", 1); - } - return $decoded; -} - function ADDPUBKEY($uid, $cmdandargs) { global $TBSUEXEC_PATH; diff --git a/www/nodetipacl.php3 b/www/nodetipacl.php3 index 0db649b2eb1bc9fb56ca70a64452acb00b5a6b6c..08d48ed1bfd73d459196aa2a35bf92f153c5c507 100644 --- a/www/nodetipacl.php3 +++ b/www/nodetipacl.php3 @@ -1,10 +1,11 @@ <?php # # EMULAB-COPYRIGHT -# Copyright (c) 2000-2002 University of Utah and the Flux Group. +# Copyright (c) 2000-2002, 2004 University of Utah and the Flux Group. # All rights reserved. # include("defs.php3"); +include("xmlrpc.php3"); # # This script generates an "acl" file. @@ -36,28 +37,57 @@ if (! $isadmin) { } } -$query_result = DBQueryFatal("SELECT server, portnum, keylen, keydata " . - "FROM tiplines WHERE node_id='$node_id'" ); - -if (mysql_num_rows($query_result) == 0) { - USERERROR("The node $node_id does not exist, or seem to have a tipline!", 1); -} - # -# Read in the fingerprint of capture's certificate +# Ask outer emulab for the stuff we need. It does it own perm checks # -$capfile = "$TBETC_DIR/capture.fingerprint"; -$lines = file($capfile,"r"); -if (!$lines) { - TBERROR("Unable to open $capfile!",1); -} +if ($ELABINELAB) { + $arghash = array(); + $arghash["node"] = $node_id; -$fingerline = rtrim($lines[0]); -if (!preg_match("/Fingerprint=([\w:]+)$/",$fingerline,$matches)) { - TBERROR("Unable to find fingerprint in string $fingerline!",1); + $results = XMLRPC($uid, "nobody", "elabinelab.console", $arghash); + + if (!$results || + ! (isset($results{'server'}) && isset($results{'portnum'}) && + isset($results{'keydata'}) && isset($results{'certsha'}))) { + TBERROR("Did not get everything we needed from RPC call", 1); + } + + $server = $results['server']; + $portnum = $results['portnum']; + $keydata = $results['keydata']; + $keylen = strlen($keydata); + $certhash= strtolower($results{'certsha'}); } +else { -$certhash = str_replace(":","",strtolower($matches[1])); + $query_result = DBQueryFatal("SELECT server, portnum, keylen, keydata " . + "FROM tiplines WHERE node_id='$node_id'" ); + + if (mysql_num_rows($query_result) == 0) { + USERERROR("The node $node_id does not exist, ". + "or does not have a tipline!", 1); + } + $row = mysql_fetch_array($query_result); + $server = $row[server]; + $portnum = $row[portnum]; + $keylen = $row[keylen]; + $keydata = $row[keydata]; + + # + # Read in the fingerprint of the capture certificate + # + $capfile = "$TBETC_DIR/capture.fingerprint"; + $lines = file($capfile,"r"); + if (!$lines) { + TBERROR("Unable to open $capfile!",1); + } + + $fingerline = rtrim($lines[0]); + if (!preg_match("/Fingerprint=([\w:]+)$/",$fingerline,$matches)) { + TBERROR("Unable to find fingerprint in string $fingerline!",1); + } + $certhash = str_replace(":","",strtolower($matches[1])); +} $filename = $node_id . ".tbacl"; @@ -68,12 +98,6 @@ header("Content-Description: ACL key file for a testbed node serial port"); # XXX, should handle multiple tip lines gracefully somehow, # but not important for now. -$row = mysql_fetch_array($query_result); -$server = $row[server]; -$portnum = $row[portnum]; -$keylen = $row[keylen]; -$keydata = $row[keydata]; - echo "host: $server\n"; echo "port: $portnum\n"; echo "keylen: $keylen\n"; diff --git a/www/xmlrpc.php3.in b/www/xmlrpc.php3.in new file mode 100644 index 0000000000000000000000000000000000000000..d3874fa3dcabc81fdfaa649dbf6f0656f5df3718 --- /dev/null +++ b/www/xmlrpc.php3.in @@ -0,0 +1,147 @@ +<?php +# +# EMULAB-COPYRIGHT +# Copyright (c) 2004 University of Utah and the Flux Group. +# All rights reserved. +# +# This is an included file. No headers or footers. +# +# Stuff to use the xmlrpc client/server. This is functionally equivalent +# to the perl stuff I wrote in xmlrpc/libxmlrpc.pm.in. +# +$RPCSERVER = "@OUTERBOSS_NODENAME@"; +$RPCPORT = "@OUTERBOSS_XMLRPCPORT@"; +$RPCCERT = "@OUTERBOSS_SSLCERTNAME@"; + +# +# Emulab XMLRPC defs. +# +# WARNING: If you change this stuff, also change defs in xmlrpc directory. +# +define("XMLRPC_RESPONSE_SUCCESS", 0); +define("XMLRPC_RESPONSE_BADARGS", 1); +define("XMLRPC_RESPONSE_ERROR", 2); +define("XMLRPC_RESPONSE_FORBIDDEN", 3); +define("XMLRPC_RESPONSE_BADVERSION", 4); +define("XMLRPC_RESPONSE_SERVERERROR", 5); +define("XMLRPC_RESPONSE_TOOBIG", 6); +define("XMLRPC_RESPONSE_REFUSED", 7); +define("XMLRPC_RESPONSE_TIMEDOUT", 8); + +## +# The package version number +# +define("XMLRPC_PACKAGE_VERSION", 0.1); + +# +# This is the "structure" returned by the RPC server. It gets converted into +# a php hash by the unmarshaller, and we return that directly to the caller +# (as a reference). +# +# class EmulabResponse: +# def __init__(self, code, value=0, output=""): +# self.code = code # A RESPONSE code +# self.value = value # A return value; any valid XML type. +# self.output = output # Pithy output to print +# return +# +function ParseResponse($xmlgoo) +{ + # The method is ignored. + $decoded = xmlrpc_decode_request($xmlgoo, $meth); + $rval = array(); + + if (array_key_exists("faultCode", $decoded) && + array_key_exists("faultString", $decoded)) { + $code = $decoded{"faultCode"}; + $value = $code; + $output = $decoded{"faultString"}; + } + elseif (!(array_key_exists("code", $decoded) && + array_key_exists("value", $decoded) && + array_key_exists("output", $decoded))) { + # + # Malformed response; let caller do something reasonable. + # + return NULL; + } + else { + $code = $decoded{"code"}; + $value = $decoded{"value"}; + $output = $decoded{"output"}; + } + $rval{'code'} = $code; + $rval{'value'} = $value; + $rval{'output'} = $output; + + return $rval; +} + +# +# Invoke the ssl xmlrpc client in raw mode, passing it an encoded XMLRPC +# string, reading back an XMLRPC encoded response, which is converted to +# a PHP datatype with the ParseResponse() function above. In other words, +# we invoke a method on a remote xmlrpc server, and get back a response. +# Invoked as the current user, but the actual uid of the caller is contained +# in the ssl certificate we use, which for now is the elabinelab certificate +# of the creator (since that is the only place this code is being used). +# +function XMLRPC($uid, $gid, $method, $arghash) +{ + global $TBSUEXEC_PATH, $TBADMINGROUP; + global $RPCSERVER, $RPCPORT, $RPCCERT; + + $xmlcode = xmlrpc_encode_request($method, + array(XMLRPC_PACKAGE_VERSION, $arghash)); + + $descriptorspec = array(0 => array("pipe", "r"), + 1 => array("pipe", "w")); + + $process = proc_open("$TBSUEXEC_PATH $uid $TBADMINGROUP webxmlrpc -r ". + "-s $RPCSERVER -p $RPCPORT --cert=$RPCCERT ", + $descriptorspec, $pipes); + + if (! is_resource($process)) { + TBERROR("Could not invoke XMLRPC backend!\n". + "$uid $gid $method\n". + print_r($arghash, true), 1); + } + # $pipes now looks like this: + # 0 => writeable handle connected to child stdin + # 1 => readable handle connected to child stdout + + # + # Write the request to the process, and then close the pipe so that + # the other side sees the EOF. + # + fwrite($pipes[0], "$xmlcode"); + fflush($pipes[0]); + fclose($pipes[0]); + + # + # Now read back the results into a string. + $output = ""; + while(!feof($pipes[1])) { + $output .= fgets($pipes[1], 1024); + } + fclose($pipes[1]); + + # It is important that you close any pipes before calling + # proc_close in order to avoid a deadlock. + $return_value = proc_close($process); + + if ($return_value || $output == "" || + (($decoded = ParseResponse($output)) == NULL) || $decoded->{"code"}) { + TBERROR("XMLRPC backend failure!\n". + "$uid $gid $method returned $return_value\n". + "Arg Hash:\n" . + print_r($arghash, true) . "\n\n" . + "XML:\n" . + "$xmlcode\n\n" . + "Output:\n" . + "$output\n", 1); + } +# TBERROR(print_r($decoded, true), 0); + return $decoded{'value'}; +} + diff --git a/xmlrpc/webxmlrpc.in b/xmlrpc/webxmlrpc.in index f7506e59acb5edf5218548557b537b43f1a68e1f..0b18310d6337de1083f6902b9dffab9706a409c8 100644 --- a/xmlrpc/webxmlrpc.in +++ b/xmlrpc/webxmlrpc.in @@ -17,12 +17,9 @@ use English; # my $TB = "@prefix@"; -# We have to do this to fake out the server. Harmless. -$ENV{'SSH_CONNECTION'} = "localhost 0 localhost 0"; - # # Run the real thing, and never return. # -exec "$TB/sbin/sshxmlrpc_server.py", @ARGV; +exec "$TB/bin/sslxmlrpc_client.py", @ARGV; -die("webxmlrpc: Could not exec sshxmlrpc_server.py: $!"); +die("webxmlrpc: Could not exec sslxmlrpc_client.py: $!");