1"""RPC Server module.""" 2 3import sys 4import socket 5import pickle 6from fnmatch import fnmatch 7from repr import repr 8 9 10# Default verbosity (0 = silent, 1 = print connections, 2 = print requests too) 11VERBOSE = 1 12 13 14class Server: 15 16 """RPC Server class. Derive a class to implement a particular service.""" 17 18 def __init__(self, address, verbose = VERBOSE): 19 if type(address) == type(0): 20 address = ('', address) 21 self._address = address 22 self._verbose = verbose 23 self._socket = None 24 self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 25 self._socket.bind(address) 26 self._socket.listen(1) 27 self._listening = 1 28 29 def _setverbose(self, verbose): 30 self._verbose = verbose 31 32 def __del__(self): 33 self._close() 34 35 def _close(self): 36 self._listening = 0 37 if self._socket: 38 self._socket.close() 39 self._socket = None 40 41 def _serverloop(self): 42 while self._listening: 43 self._serve() 44 45 def _serve(self): 46 if self._verbose: print "Wait for connection ..." 47 conn, address = self._socket.accept() 48 if self._verbose: print "Accepted connection from %s" % repr(address) 49 if not self._verify(conn, address): 50 print "*** Connection from %s refused" % repr(address) 51 conn.close() 52 return 53 rf = conn.makefile('r') 54 wf = conn.makefile('w') 55 ok = 1 56 while ok: 57 wf.flush() 58 if self._verbose > 1: print "Wait for next request ..." 59 ok = self._dorequest(rf, wf) 60 61 _valid = ['192.16.201.*', '192.16.197.*', '132.151.1.*', '129.6.64.*'] 62 63 def _verify(self, conn, address): 64 host, port = address 65 for pat in self._valid: 66 if fnmatch(host, pat): return 1 67 return 0 68 69 def _dorequest(self, rf, wf): 70 rp = pickle.Unpickler(rf) 71 try: 72 request = rp.load() 73 except EOFError: 74 return 0 75 if self._verbose > 1: print "Got request: %s" % repr(request) 76 try: 77 methodname, args, id = request 78 if '.' in methodname: 79 reply = (None, self._special(methodname, args), id) 80 elif methodname[0] == '_': 81 raise NameError, "illegal method name %s" % repr(methodname) 82 else: 83 method = getattr(self, methodname) 84 reply = (None, apply(method, args), id) 85 except: 86 reply = (sys.exc_type, sys.exc_value, id) 87 if id < 0 and reply[:2] == (None, None): 88 if self._verbose > 1: print "Suppress reply" 89 return 1 90 if self._verbose > 1: print "Send reply: %s" % repr(reply) 91 wp = pickle.Pickler(wf) 92 wp.dump(reply) 93 return 1 94 95 def _special(self, methodname, args): 96 if methodname == '.methods': 97 if not hasattr(self, '_methods'): 98 self._methods = tuple(self._listmethods()) 99 return self._methods 100 raise NameError, "unrecognized special method name %s" % repr(methodname) 101 102 def _listmethods(self, cl=None): 103 if not cl: cl = self.__class__ 104 names = cl.__dict__.keys() 105 names = filter(lambda x: x[0] != '_', names) 106 names.sort() 107 for base in cl.__bases__: 108 basenames = self._listmethods(base) 109 basenames = filter(lambda x, names=names: x not in names, basenames) 110 names[len(names):] = basenames 111 return names 112 113 114from security import Security 115 116 117class SecureServer(Server, Security): 118 119 def __init__(self, *args): 120 apply(Server.__init__, (self,) + args) 121 Security.__init__(self) 122 123 def _verify(self, conn, address): 124 import string 125 challenge = self._generate_challenge() 126 conn.send("%d\n" % challenge) 127 response = "" 128 while "\n" not in response and len(response) < 100: 129 data = conn.recv(100) 130 if not data: 131 break 132 response = response + data 133 try: 134 response = string.atol(string.strip(response)) 135 except string.atol_error: 136 if self._verbose > 0: 137 print "Invalid response syntax", repr(response) 138 return 0 139 if not self._compare_challenge_response(challenge, response): 140 if self._verbose > 0: 141 print "Invalid response value", repr(response) 142 return 0 143 if self._verbose > 1: 144 print "Response matches challenge. Go ahead!" 145 return 1 146