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
|
---|