1995-04-10 08:40:52 -03:00
|
|
|
"""RPC Server module."""
|
|
|
|
|
|
|
|
import sys
|
|
|
|
import socket
|
|
|
|
import pickle
|
|
|
|
from fnmatch import fnmatch
|
2008-05-23 02:03:59 -03:00
|
|
|
from repr import repr
|
1995-04-10 08:40:52 -03:00
|
|
|
|
|
|
|
|
|
|
|
# Default verbosity (0 = silent, 1 = print connections, 2 = print requests too)
|
|
|
|
VERBOSE = 1
|
|
|
|
|
|
|
|
|
|
|
|
class Server:
|
2004-07-18 02:56:09 -03:00
|
|
|
|
|
|
|
"""RPC Server class. Derive a class to implement a particular service."""
|
|
|
|
|
|
|
|
def __init__(self, address, verbose = VERBOSE):
|
|
|
|
if type(address) == type(0):
|
|
|
|
address = ('', address)
|
|
|
|
self._address = address
|
|
|
|
self._verbose = verbose
|
|
|
|
self._socket = None
|
|
|
|
self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
|
|
self._socket.bind(address)
|
|
|
|
self._socket.listen(1)
|
|
|
|
self._listening = 1
|
|
|
|
|
|
|
|
def _setverbose(self, verbose):
|
|
|
|
self._verbose = verbose
|
|
|
|
|
|
|
|
def __del__(self):
|
|
|
|
self._close()
|
|
|
|
|
|
|
|
def _close(self):
|
|
|
|
self._listening = 0
|
|
|
|
if self._socket:
|
|
|
|
self._socket.close()
|
|
|
|
self._socket = None
|
|
|
|
|
|
|
|
def _serverloop(self):
|
|
|
|
while self._listening:
|
|
|
|
self._serve()
|
|
|
|
|
|
|
|
def _serve(self):
|
|
|
|
if self._verbose: print "Wait for connection ..."
|
|
|
|
conn, address = self._socket.accept()
|
|
|
|
if self._verbose: print "Accepted connection from %s" % repr(address)
|
|
|
|
if not self._verify(conn, address):
|
|
|
|
print "*** Connection from %s refused" % repr(address)
|
|
|
|
conn.close()
|
|
|
|
return
|
|
|
|
rf = conn.makefile('r')
|
|
|
|
wf = conn.makefile('w')
|
|
|
|
ok = 1
|
|
|
|
while ok:
|
|
|
|
wf.flush()
|
|
|
|
if self._verbose > 1: print "Wait for next request ..."
|
|
|
|
ok = self._dorequest(rf, wf)
|
|
|
|
|
|
|
|
_valid = ['192.16.201.*', '192.16.197.*', '132.151.1.*', '129.6.64.*']
|
|
|
|
|
|
|
|
def _verify(self, conn, address):
|
|
|
|
host, port = address
|
|
|
|
for pat in self._valid:
|
|
|
|
if fnmatch(host, pat): return 1
|
|
|
|
return 0
|
|
|
|
|
|
|
|
def _dorequest(self, rf, wf):
|
|
|
|
rp = pickle.Unpickler(rf)
|
|
|
|
try:
|
|
|
|
request = rp.load()
|
|
|
|
except EOFError:
|
|
|
|
return 0
|
|
|
|
if self._verbose > 1: print "Got request: %s" % repr(request)
|
|
|
|
try:
|
|
|
|
methodname, args, id = request
|
|
|
|
if '.' in methodname:
|
|
|
|
reply = (None, self._special(methodname, args), id)
|
|
|
|
elif methodname[0] == '_':
|
|
|
|
raise NameError, "illegal method name %s" % repr(methodname)
|
|
|
|
else:
|
|
|
|
method = getattr(self, methodname)
|
|
|
|
reply = (None, apply(method, args), id)
|
|
|
|
except:
|
|
|
|
reply = (sys.exc_type, sys.exc_value, id)
|
|
|
|
if id < 0 and reply[:2] == (None, None):
|
|
|
|
if self._verbose > 1: print "Suppress reply"
|
|
|
|
return 1
|
|
|
|
if self._verbose > 1: print "Send reply: %s" % repr(reply)
|
|
|
|
wp = pickle.Pickler(wf)
|
|
|
|
wp.dump(reply)
|
|
|
|
return 1
|
|
|
|
|
|
|
|
def _special(self, methodname, args):
|
|
|
|
if methodname == '.methods':
|
|
|
|
if not hasattr(self, '_methods'):
|
|
|
|
self._methods = tuple(self._listmethods())
|
|
|
|
return self._methods
|
|
|
|
raise NameError, "unrecognized special method name %s" % repr(methodname)
|
|
|
|
|
|
|
|
def _listmethods(self, cl=None):
|
|
|
|
if not cl: cl = self.__class__
|
|
|
|
names = cl.__dict__.keys()
|
|
|
|
names = filter(lambda x: x[0] != '_', names)
|
|
|
|
names.sort()
|
|
|
|
for base in cl.__bases__:
|
|
|
|
basenames = self._listmethods(base)
|
|
|
|
basenames = filter(lambda x, names=names: x not in names, basenames)
|
|
|
|
names[len(names):] = basenames
|
|
|
|
return names
|
1995-06-20 22:00:17 -03:00
|
|
|
|
|
|
|
|
|
|
|
from security import Security
|
|
|
|
|
|
|
|
|
|
|
|
class SecureServer(Server, Security):
|
|
|
|
|
2004-07-18 02:56:09 -03:00
|
|
|
def __init__(self, *args):
|
|
|
|
apply(Server.__init__, (self,) + args)
|
|
|
|
Security.__init__(self)
|
|
|
|
|
|
|
|
def _verify(self, conn, address):
|
|
|
|
import string
|
|
|
|
challenge = self._generate_challenge()
|
|
|
|
conn.send("%d\n" % challenge)
|
|
|
|
response = ""
|
|
|
|
while "\n" not in response and len(response) < 100:
|
|
|
|
data = conn.recv(100)
|
|
|
|
if not data:
|
|
|
|
break
|
|
|
|
response = response + data
|
|
|
|
try:
|
|
|
|
response = string.atol(string.strip(response))
|
|
|
|
except string.atol_error:
|
|
|
|
if self._verbose > 0:
|
|
|
|
print "Invalid response syntax", repr(response)
|
|
|
|
return 0
|
|
|
|
if not self._compare_challenge_response(challenge, response):
|
|
|
|
if self._verbose > 0:
|
|
|
|
print "Invalid response value", repr(response)
|
|
|
|
return 0
|
|
|
|
if self._verbose > 1:
|
|
|
|
print "Response matches challenge. Go ahead!"
|
|
|
|
return 1
|