diff --git a/db/libdb.py.in b/db/libdb.py.in index 829876ffc3da23da34232cc10fc6c5ef2a8f5a4d..f5e80f6a37975f5cf82454fbe529a55c6b20d00a 100644 --- a/db/libdb.py.in +++ b/db/libdb.py.in @@ -10,10 +10,14 @@ # import sys -sys.path.append("@prefix@/lib") -import os +import os, os.path import pwd +TBPATH = os.path.join("@prefix@", "lib") +if TBPATH not in sys.path: + sys.path.append(TBPATH) + pass + import MySQLdb from libtestbed import * diff --git a/event/sched/GNUmakefile.in b/event/sched/GNUmakefile.in index f6cf02dc7aa1bb7652b7c8804ea6ccc4708e943d..9c21e4c0c605bae9950ffdb013ff76a333435d04 100644 --- a/event/sched/GNUmakefile.in +++ b/event/sched/GNUmakefile.in @@ -11,7 +11,7 @@ SUBDIR = event/sched include $(OBJDIR)/Makeconf -all: event-sched event-sched_rpc +all: event-sched event-sched_rrpc include $(TESTBED_SRCDIR)/GNUmakerules @@ -50,7 +50,7 @@ event-sched_rpc: event-sched_rpc.o rpc.o queue.o event-sched.h \ event-sched_rrpc: event-sched_rpc.o rrpc.o queue.o event-sched.h \ ../lib/libevent.a - $(CXX) $(CFLAGS) $(LDFLAGS) -o $@ event-sched_rpc.o \ + $(CXX) $(CFLAGS) -static $(LDFLAGS) -o $@ event-sched_rpc.o \ rrpc.o queue.o $(ULXRLIBS) $(LIBS) queue.o: event-sched.h @@ -62,12 +62,12 @@ rpc.o: rpc.cc rpc.h rrpc.o: rpc.cc rpc.h $(CXX) $(CXXFLAGS) -DSSLRPC $(ULXRINC) -c -o rrpc.o $< -install: event-sched_rpc +install: event-sched_rrpc -mkdir -p $(INSTALL_DIR)/opsdir/sbin - $(INSTALL_PROGRAM) event-sched_rpc $(INSTALL_DIR)/opsdir/sbin/event-sched + $(INSTALL_PROGRAM) event-sched_rrpc $(INSTALL_DIR)/opsdir/sbin/event-sched -control-install: event-sched_rpc - $(INSTALL_PROGRAM) event-sched_rpc $(INSTALL_SBINDIR)/event-sched +control-install: event-sched_rrpc + $(INSTALL_PROGRAM) event-sched_rrpc $(INSTALL_SBINDIR)/event-sched # not a client thing client: diff --git a/event/sched/event-sched.c b/event/sched/event-sched.c index 6c099de894eebb53da44698ad456628824703829..cd2f3d36390f6c04362af42b931d2f6936a42170 100644 --- a/event/sched/event-sched.c +++ b/event/sched/event-sched.c @@ -154,7 +154,7 @@ main(int argc, char **argv) if (!server) server = "localhost"; #ifdef RPC - if (RPC_init(NULL, BOSSNODE, 0)) { + if (RPC_init(NULL, BOSSNODE, 3069)) { fatal("could not connect to rpc server"); } #endif diff --git a/event/sched/rpc.cc b/event/sched/rpc.cc index 1d2344803027592e201851c8dbc9ef85372e2012..54b19d844e85caffde7f0b7388a8dbb9492057ba 100644 --- a/event/sched/rpc.cc +++ b/event/sched/rpc.cc @@ -50,15 +50,15 @@ main(int argc, char **argv) int RPC_init(char *certpath, char *host, int port) { + struct passwd *pwd; int retval = -1; + pwd = getpwuid(getuid()); #ifdef SSHRPC { char identity_path[PATH_MAX]; - struct passwd *pwd; /* Construct the path to the identity and */ - pwd = getpwuid(getuid()); snprintf(identity_path, sizeof(identity_path), "%s/.ssh/identity", @@ -115,13 +115,19 @@ int RPC_init(char *certpath, char *host, int port) } } #else - /* XXX THIS IS OUT OF DATE */ { - ulxr::SSLConnection conn(false, host, port); - ulxr::HttpProtocol proto(&conn, conn.getHostName()); - if (certpath == NULL) - certpath = "/usr/testbed/etc/client.pem"; - conn.setCryptographyData("", certpath, certpath); + ulxr::SSLConnection *sslconn; + char buf[BUFSIZ]; + + rpc_data.conn = sslconn = new ulxr::SSLConnection(false, host, port); + rpc_data.proto = new ulxr::HttpProtocol(rpc_data.conn, + sslconn->getHostName()); + rpc_data.proto->setPersistent(true); + if (certpath == NULL) { + snprintf(buf, sizeof(buf), "%s/.ssl/emulab.pem", pwd->pw_dir); + certpath = buf; + } + sslconn->setCryptographyData("", certpath, certpath); } #endif return 0; @@ -150,12 +156,7 @@ RPC_invoke(char *pid, char *eid, char *method, emulab::EmulabResponse *er) { try { -#ifdef SSHRPC - emulab::ServerProxy proxy(rpc_data.proto); -#else - /* XXX THIS IS OUT OF DATE */ - emulab::ServerProxy proxy(rpc_data.proto, false, "/RPC2"); -#endif + emulab::ServerProxy proxy(rpc_data.proto, false, TBROOT); *er = proxy.invoke(method, emulab::SPA_String, "proj", pid, diff --git a/xmlrpc/emulabserver.py.in b/xmlrpc/emulabserver.py.in index ccd3b18066bc3261aeeaf6ba017de6771b7ca75f..4005ad1fd88026bcb4c8b9930d4dc546fddbd356 100755 --- a/xmlrpc/emulabserver.py.in +++ b/xmlrpc/emulabserver.py.in @@ -22,15 +22,22 @@ import xmlrpclib import signal import types import datetime -sys.path.append("@prefix@/lib") -from libdb import * -from libtestbed import SENDMAIL, TBOPS -from emulabclient import * # Configure variables TBDIR = "@prefix@" BOSSNODE = "@BOSSNODE@" BOSSEVENTPORT = "@BOSSEVENTPORT@" +OURDOMAIN = "@OURDOMAIN@" +USERNODE = "@USERNODE@" + +TBPATH = os.path.join(TBDIR, "lib") +if TBPATH not in sys.path: + sys.path.append(TBPATH) + pass + +from libdb import * +from libtestbed import SENDMAIL, TBOPS +from emulabclient import * # Version VERSION = 0.1 diff --git a/xmlrpc/sslxmlrpc_server.py.in b/xmlrpc/sslxmlrpc_server.py.in index 9197a91e46824d0e6cf96470ec6d4ef5828ea271..dd644f0dbe9bd65618bd8602446974fd048913d9 100755 --- a/xmlrpc/sslxmlrpc_server.py.in +++ b/xmlrpc/sslxmlrpc_server.py.in @@ -6,21 +6,30 @@ # import sys import getopt -import os +import os, os.path import traceback import syslog import string +import BaseHTTPServer + +from SimpleXMLRPCServer import SimpleXMLRPCDispatcher + # Testbed specific stuff -sys.path.append("@prefix@/lib") +TBPATH = "@prefix@/lib" +if TBPATH not in sys.path: + sys.path.append(TBPATH) + pass + from libdb import * -from libtestbed import SENDMAIL, TBOPS -from emulabserver import * -from SimpleXMLRPCServer import SimpleXMLRPCDispatcher -from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler -from M2Crypto import SSL -from M2Crypto.SSL import SSLError +try: + from M2Crypto import SSL + from M2Crypto.SSL import SSLError +except ImportError, e: + sys.stderr.write("error: The py-m2crypto port is not installed\n") + sys.exit(1) + pass # When debugging, runs in foreground printing to stdout instead of syslog debug = 0 @@ -43,9 +52,89 @@ ca_cert = "@prefix@/etc/emulab.pem" DEFAULT_MODULE = "EmulabServer" module = DEFAULT_MODULE +# +# "Standard" paths for the real and development versions of the software. +# +STD_PATH = "/usr/testbed" +STD_DEVEL_PATH = "/usr/testbed/devel" + +# +# The set of paths that the user is allowed to specify in their request. The +# path specifies where the 'emulabserver' module will be loaded from. In +# reality, the path only has an effect on the first request in a persistent +# connection, any subsequent requests will reuse the same module. +# +ALLOWED_PATHS = [ STD_PATH, "@prefix@" ] +ALLOWED_PATHS.extend(map(lambda x: os.path.join(STD_DEVEL_PATH, x), + os.listdir(STD_DEVEL_PATH))) + # syslog facility LOGFACIL = "@TBLOGFACIL@" +## +# Taken from the SimpleXMLRPCServer module in the python installation and +# modified to support persistent connections. +# +class MyXMLRPCRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): + """Simple XML-RPC request handler class. + + Handles all HTTP POST requests and attempts to decode them as + XML-RPC requests. + """ + + ## + # Change the default protocol so that persistent connections are the norm. + # + protocol_version = "HTTP/1.1" + + ## + # Handle a POST request from the user. This method was changed from the + # standard version to not close the + # + def do_POST(self): + """Handles the HTTP POST request. + + Attempts to interpret all HTTP POST requests as XML-RPC calls, + which are forwarded to the server's _dispatch method for handling. + """ + + # Update PYTHONPATH with the user's requested path. + self.server.set_path(self.path) + + try: + # get arguments + data = self.rfile.read(int(self.headers["content-length"])) + # In previous versions of SimpleXMLRPCServer, _dispatch + # could be overridden in this class, instead of in + # SimpleXMLRPCDispatcher. To maintain backwards compatibility, + # check to see if a subclass implements _dispatch and dispatch + # using that method if present. + response = self.server._marshaled_dispatch( + data, getattr(self, '_dispatch', None) + ) + except: # This should only happen if the module is buggy + # internal error, report as HTTP server error + self.send_response(500) + self.end_headers() + self.wfile.flush() + else: + # got a valid XML RPC response + self.send_response(200) + self.send_header("Content-type", "text/xml") + self.send_header("Content-length", str(len(response))) + self.end_headers() + self.wfile.write(response) + self.wfile.flush() + pass + return + + def log_request(self, code='-', size='-'): + """Selectively log an accepted request.""" + + if self.server.logRequests: + BaseHTTPServer.BaseHTTPRequestHandler.log_request(self, code, size) + + # # A simple server based on the forking version SSLServer. We fork cause # we want to change our uid/gid to that of the person on the other end. @@ -62,12 +151,17 @@ class MyServer(SSL.ForkingSSLServer, SimpleXMLRPCDispatcher): ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 16) ctx.set_allow_unknown_ca(0) #ctx.set_info_callback() - + SimpleXMLRPCDispatcher.__init__(self) SSL.SSLServer.__init__(self, (ADDR, PORT), - SimpleXMLRPCRequestHandler, ctx) + MyXMLRPCRequestHandler, ctx) pass + ## + # Log a message to stdout, if in debug mode, otherwise write to syslog. + # + # @param msg The message to log. + # def logit(self, msg): if debug: print msg @@ -76,6 +170,36 @@ class MyServer(SSL.ForkingSSLServer, SimpleXMLRPCDispatcher): syslog.syslog(syslog.LOG_INFO, msg); pass return + + ## + # Updates PYTHONPATH and imports the 'emulabserver' module on its first + # invocation. The specified path must be in the ALLOWED_PATHS list and + # readable by the user, otherwise the request will fail. + # + # @param path The path from the POST request, should not include "lib" on + # the end (e.g. "/usr/testbed") + # + def set_path(self, path): + if not self.emulabserver: + if path not in ALLOWED_PATHS: + self.logit("Disallowed path: %s" % path) + raise Exception("Path not allowed: %s" % path) + path = os.path.join(path, "lib") + if not os.access(path, os.X_OK): + self.logit("Path not accessible by user: %s" % path) + raise Exception("Permission denied: %s" % path) + + print `path` + print `sys.path` + + if path not in sys.path: + sys.path.append(path) + pass + from emulabserver import EmulabServer + + self.emulabserver = EmulabServer(readonly=0) + pass + return # # There might be a better arrangement, but the problem is that we @@ -221,7 +345,10 @@ class MyServer(SSL.ForkingSSLServer, SimpleXMLRPCDispatcher): # This must never return, hence os._exit()! try: self.fliptouser(request, client_address); - self.emulabserver = EmulabServer(readonly=0) + + # Remove the old path since the user can request a different + # one. + sys.path.remove(TBPATH) self.finish_request(request, client_address) self.close_request(request) self.logit("request finished"); @@ -249,10 +376,10 @@ if len(sys.argv) > 1 and sys.argv[1] == "-d": # if not debug: # - # Connect to syslog. + # Connect to syslog. # syslog.openlog("sslxmlrpc", syslog.LOG_PID, - eval("syslog.LOG_" + string.upper(LOGFACIL))) + getattr(syslog, "LOG_" + string.upper(LOGFACIL))) syslog.syslog(syslog.LOG_INFO, "SSL XMLRPC server starting up"); #