Commit 98d2ab5f authored by Leigh Stoller's avatar Leigh Stoller

Rework old XMLRPC code that I stuck into defs.php3 a long time ago,

but never made use of. Moved to its own file (www/xmlrpc.php3.in)
and made to be more like the perl library I did a couple of months ago,
that presents an interface to an sslxmlrpc server, via the sslxmlrpc
client program operating in "raw" mode (takes raw xml on stdin, and
returns raw xml on stdout).

Added ELABINELAB code to nodetipacl.php3 so that you can click on
console icon on an inner emulab web page, and it will ask the outer
emulab sslxmlrpc server for the stuff it needs, and return that to the
user.
parent e5f3617b
......@@ -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
......
......@@ -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;
......
<?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";
......
<?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'};
}
......@@ -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: $!");
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