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: $!");