14710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"""RPC Server module.""" 24710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 34710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmimport sys 44710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmimport socket 54710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmimport pickle 64710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmfrom fnmatch import fnmatch 74710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmfrom repr import repr 84710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 94710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# Default verbosity (0 = silent, 1 = print connections, 2 = print requests too) 114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmVERBOSE = 1 124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass Server: 154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm """RPC Server class. Derive a class to implement a particular service.""" 174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def __init__(self, address, verbose = VERBOSE): 194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if type(address) == type(0): 204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm address = ('', address) 214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._address = address 224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._verbose = verbose 234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._socket = None 244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._socket.bind(address) 264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._socket.listen(1) 274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._listening = 1 284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def _setverbose(self, verbose): 304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._verbose = verbose 314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def __del__(self): 334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._close() 344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def _close(self): 364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._listening = 0 374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if self._socket: 384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._socket.close() 394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._socket = None 404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def _serverloop(self): 424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm while self._listening: 434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._serve() 444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def _serve(self): 464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if self._verbose: print "Wait for connection ..." 474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm conn, address = self._socket.accept() 484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if self._verbose: print "Accepted connection from %s" % repr(address) 494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if not self._verify(conn, address): 504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print "*** Connection from %s refused" % repr(address) 514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm conn.close() 524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return 534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm rf = conn.makefile('r') 544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm wf = conn.makefile('w') 554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm ok = 1 564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm while ok: 574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm wf.flush() 584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if self._verbose > 1: print "Wait for next request ..." 594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm ok = self._dorequest(rf, wf) 604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm _valid = ['192.16.201.*', '192.16.197.*', '132.151.1.*', '129.6.64.*'] 624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def _verify(self, conn, address): 644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm host, port = address 654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for pat in self._valid: 664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if fnmatch(host, pat): return 1 674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return 0 684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def _dorequest(self, rf, wf): 704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm rp = pickle.Unpickler(rf) 714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm try: 724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm request = rp.load() 734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm except EOFError: 744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return 0 754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if self._verbose > 1: print "Got request: %s" % repr(request) 764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm try: 774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm methodname, args, id = request 784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if '.' in methodname: 794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm reply = (None, self._special(methodname, args), id) 804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm elif methodname[0] == '_': 814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm raise NameError, "illegal method name %s" % repr(methodname) 824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm else: 834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm method = getattr(self, methodname) 844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm reply = (None, apply(method, args), id) 854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm except: 864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm reply = (sys.exc_type, sys.exc_value, id) 874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if id < 0 and reply[:2] == (None, None): 884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if self._verbose > 1: print "Suppress reply" 894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return 1 904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if self._verbose > 1: print "Send reply: %s" % repr(reply) 914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm wp = pickle.Pickler(wf) 924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm wp.dump(reply) 934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return 1 944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def _special(self, methodname, args): 964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if methodname == '.methods': 974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if not hasattr(self, '_methods'): 984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self._methods = tuple(self._listmethods()) 994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return self._methods 1004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm raise NameError, "unrecognized special method name %s" % repr(methodname) 1014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def _listmethods(self, cl=None): 1034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if not cl: cl = self.__class__ 1044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm names = cl.__dict__.keys() 1054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm names = filter(lambda x: x[0] != '_', names) 1064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm names.sort() 1074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for base in cl.__bases__: 1084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm basenames = self._listmethods(base) 1094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm basenames = filter(lambda x, names=names: x not in names, basenames) 1104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm names[len(names):] = basenames 1114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return names 1124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmfrom security import Security 1154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass SecureServer(Server, Security): 1184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def __init__(self, *args): 1204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm apply(Server.__init__, (self,) + args) 1214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm Security.__init__(self) 1224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def _verify(self, conn, address): 1244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm import string 1254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm challenge = self._generate_challenge() 1264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm conn.send("%d\n" % challenge) 1274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm response = "" 1284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm while "\n" not in response and len(response) < 100: 1294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm data = conn.recv(100) 1304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if not data: 1314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm break 1324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm response = response + data 1334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm try: 1344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm response = string.atol(string.strip(response)) 1354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm except string.atol_error: 1364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if self._verbose > 0: 1374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print "Invalid response syntax", repr(response) 1384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return 0 1394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if not self._compare_challenge_response(challenge, response): 1404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if self._verbose > 0: 1414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print "Invalid response value", repr(response) 1424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return 0 1434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if self._verbose > 1: 1444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print "Response matches challenge. Go ahead!" 1454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return 1 146