=== StorageServer.py ================================================================== Index: lib/python/ZEO/StorageServer.py =================================================================== --- lib/python/ZEO/StorageServer.py +++ lib/python/ZEO/StorageServer.py @@ -98,7 +98,7 @@ class ZEOStorage: for func in self.extensions: self._extensions[func.func_name] = None - def finish_auth(self, authenticated): + def _finish_auth(self, authenticated): if not self.auth_realm: return 1 self.authenticated = authenticated @@ -350,6 +350,7 @@ class ZEOStorage: def new_oids(self, n=100): """Return a sequence of n new oids, where n defaults to 100""" + n = min(n, 100) if self.read_only: raise ReadOnlyError() if n <= 0: Index: lib/python/ZEO/auth/auth_digest.py =================================================================== --- lib/python/ZEO/auth/auth_digest.py +++ lib/python/ZEO/auth/auth_digest.py @@ -121,7 +121,7 @@ class StorageClass(ZEOStorage): check = hexdigest("%s:%s" % (h_up, challenge)) if check == response: self.connection.setSessionKey(session_key(h_up, self._key_nonce)) - return self.finish_auth(check == response) + return self._finish_auth(check == response) extensions = [auth_get_challenge, auth_response] Index: lib/python/ZEO/tests/auth_plaintext.py =================================================================== --- lib/python/ZEO/tests/auth_plaintext.py +++ lib/python/ZEO/tests/auth_plaintext.py @@ -41,7 +41,7 @@ class StorageClass(ZEOStorage): self.connection.setSessionKey(session_key(username, self.database.realm, password)) - return self.finish_auth(dbpw == password_dig) + return self._finish_auth(dbpw == password_dig) class PlaintextClient(Client): extensions = ["auth"] Index: lib/python/ZEO/zrpc/connection.py =================================================================== --- lib/python/ZEO/zrpc/connection.py +++ lib/python/ZEO/zrpc/connection.py @@ -22,7 +22,7 @@ import logging import ThreadedAsync from ZEO.zrpc import smac from ZEO.zrpc.error import ZRPCError, DisconnectedError -from ZEO.zrpc.marshal import Marshaller +from ZEO.zrpc.marshal import Marshaller, ServerMarshaller from ZEO.zrpc.trigger import trigger from ZEO.zrpc.log import short_repr, log from ZODB.loglevels import BLATHER, TRACE @@ -716,6 +716,7 @@ class ManagedServerConnection(Connection def __init__(self, sock, addr, obj, mgr): self.mgr = mgr self.__super_init(sock, addr, obj, 'S') + self.marshal = ServerMarshaller() self.obj.notifyConnected(self) def handshake(self): Index: lib/python/ZEO/zrpc/marshal.py =================================================================== --- lib/python/ZEO/zrpc/marshal.py +++ lib/python/ZEO/zrpc/marshal.py @@ -53,6 +53,20 @@ class Marshaller: level=logging.ERROR) raise +class ServerMarshaller(Marshaller): + + def decode(self, msg): + """Decodes msg and returns its parts""" + unpickler = cPickle.Unpickler(StringIO(msg)) + unpickler.find_global = server_find_global + + try: + return unpickler.load() # msgid, flags, name, args + except: + log("can't decode message: %s" % short_repr(msg), + level=logging.ERROR) + raise + _globals = globals() _silly = ('__doc__',) @@ -77,3 +91,21 @@ def find_global(module, name): return r raise ZRPCError("Unsafe global: %s.%s" % (module, name)) + +def server_find_global(module, name): + """Helper for message unpickler""" + try: + m = __import__(module, _globals, _globals, _silly) + except ImportError, msg: + raise ZRPCError("import error %s: %s" % (module, msg)) + + try: + r = getattr(m, name) + except AttributeError: + raise ZRPCError("module %s has no global %s" % (module, name)) + + safe = getattr(r, '__no_side_effects__', 0) + if safe: + return r + + raise ZRPCError("Unsafe global: %s.%s" % (module, name))