|
1 """RPC Server module.""" |
|
2 |
|
3 import sys |
|
4 import socket |
|
5 import pickle |
|
6 from fnmatch import fnmatch |
|
7 from repr import repr |
|
8 |
|
9 |
|
10 # Default verbosity (0 = silent, 1 = print connections, 2 = print requests too) |
|
11 VERBOSE = 1 |
|
12 |
|
13 |
|
14 class 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 |
|
114 from security import Security |
|
115 |
|
116 |
|
117 class 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 |