def recv(cls, connection, requiredMsgTypes=None, hmac_key=None): """ Receives a pyro message from a given connection. Accepts the given message types (None=any, or pass a sequence). Also reads annotation chunks and the actual payload data. Validates a HMAC chunk if present. """ msg = cls.from_header(connection.recv(cls.header_size)) msg.hmac_key = hmac_key if 0 < Pyro4.config.MAX_MESSAGE_SIZE < (msg.data_size + msg.annotations_size): errorMsg = "max message size exceeded (%d where max=%d)" % ( msg.data_size + msg.annotations_size, Pyro4.config.MAX_MESSAGE_SIZE) log.error("connection " + str(connection) + ": " + errorMsg) connection.close( ) # close the socket because at this point we can't return the correct sequence number for returning an error message exc = errors.MessageTooLargeError(errorMsg) exc.pyroMsg = msg raise exc if requiredMsgTypes and msg.type not in requiredMsgTypes: err = "invalid msg type %d received" % msg.type log.error(err) exc = errors.ProtocolError(err) exc.pyroMsg = msg raise exc if msg.annotations_size: # read annotation chunks annotations_data = connection.recv(msg.annotations_size) msg.annotations = {} i = 0 while i < msg.annotations_size: anno, length = struct.unpack("!4sH", annotations_data[i:i + 6]) if sys.version_info >= (3, 0): anno = anno.decode("ASCII") msg.annotations[anno] = annotations_data[i + 6:i + 6 + length] if sys.platform == "cli": msg.annotations[anno] = bytes(msg.annotations[anno]) i += 6 + length # read data msg.data = connection.recv(msg.data_size) if "HMAC" in msg.annotations and hmac_key: if not secure_compare(msg.annotations["HMAC"], msg.hmac()): exc = errors.SecurityError("message hmac mismatch") exc.pyroMsg = msg raise exc elif ("HMAC" in msg.annotations) != bool(hmac_key): # Not allowed: message contains hmac but hmac_key is not set, or vice versa. err = "hmac key config not symmetric" log.warning(err) exc = errors.SecurityError(err) exc.pyroMsg = msg raise exc return msg
def start(daemon): """ Create and register a Flame server in the given daemon. Be *very* cautious before starting this: it allows the clients full access to everything on your system. """ if config.FLAME_ENABLED: if set(config.SERIALIZERS_ACCEPTED) != {"pickle"}: raise errors.SerializeError( "Flame requires the pickle serializer exclusively") return daemon.register(Flame(), constants.FLAME_NAME) else: raise errors.SecurityError( "Flame is disabled in the server configuration")
def getMessage(cls, connection, requiredMsgType): headerdata = connection.recv(cls.HEADERSIZE) msgType, flags, seq, datalen, datahmac = cls.parseMessageHeader(headerdata) if 0 < Pyro4.config.MAX_MESSAGE_SIZE < datalen: errorMsg = "max message size exceeded (%d where max=%d)" % (datalen, Pyro4.config.MAX_MESSAGE_SIZE) log.error("connection "+str(connection)+": "+errorMsg) connection.close() # close the socket because at this point we can't return the correct sequence number for returning an error message raise errors.ProtocolError(errorMsg) if requiredMsgType is not None and msgType != requiredMsgType: err="invalid msg type %d received" % msgType log.error(err) raise errors.ProtocolError(err) databytes=connection.recv(datalen) local_hmac_set=Pyro4.config.HMAC_KEY is not None and len(Pyro4.config.HMAC_KEY) > 0 if flags&MessageFactory.FLAGS_HMAC and local_hmac_set: if datahmac != hmac.new(Pyro4.config.HMAC_KEY, databytes, digestmod=hashlib.sha1).digest(): raise errors.SecurityError("message hmac mismatch") elif flags&MessageFactory.FLAGS_HMAC != local_hmac_set: # Message contains hmac and local HMAC_KEY not set, or vice versa. This is not allowed. err="hmac key config not symmetric" log.warn(err) raise errors.SecurityError(err) return msgType, flags, seq, databytes
def dict_to_class(cls, data): """ Recreate an object out of a dict containing the class name and the attributes. Only a fixed set of classes are recognized. Not used for the pickle serializer. """ from Pyro4 import core, futures # XXX circular classname = data.get("__class__", "<unknown>") if isinstance(classname, bytes): classname = classname.decode("utf-8") if classname in cls.__custom_dict_to_class_registry: converter = cls.__custom_dict_to_class_registry[classname] return converter(classname, data) if "__" in classname: raise errors.SecurityError("refused to deserialize types with double underscores in their name: " + classname) # for performance, the constructors below are hardcoded here instead of added on a per-class basis to the dict-to-class registry if classname.startswith("Pyro4.core."): if classname == "Pyro4.core.URI": uri = core.URI.__new__(core.URI) uri.__setstate_from_dict__(data["state"]) return uri elif classname == "Pyro4.core.Proxy": proxy = core.Proxy.__new__(core.Proxy) proxy.__setstate_from_dict__(data["state"]) return proxy elif classname == "Pyro4.core.Daemon": daemon = core.Daemon.__new__(core.Daemon) daemon.__setstate_from_dict__(data["state"]) return daemon elif classname.startswith("Pyro4.util."): if classname == "Pyro4.util.SerpentSerializer": return SerpentSerializer() elif classname == "Pyro4.util.PickleSerializer": return PickleSerializer() elif classname == "Pyro4.util.MarshalSerializer": return MarshalSerializer() elif classname == "Pyro4.util.JsonSerializer": return JsonSerializer() elif classname == "Pyro4.util.MsgpackSerializer": return MsgpackSerializer() elif classname == "Pyro4.util.CloudpickleSerializer": return CloudpickleSerializer() elif classname == "Pyro4.util.DillSerializer": return DillSerializer() elif classname.startswith("Pyro4.errors."): errortype = getattr(errors, classname.split('.', 2)[2]) if issubclass(errortype, errors.PyroError): return SerializerBase.make_exception(errortype, data) elif classname == "Pyro4.futures._ExceptionWrapper": ex = data["exception"] if isinstance(ex, dict) and "__class__" in ex: ex = SerializerBase.dict_to_class(ex) return futures._ExceptionWrapper(ex) elif data.get("__exception__", False): if classname in all_exceptions: return SerializerBase.make_exception(all_exceptions[classname], data) # python 2.x: exceptions.ValueError # python 3.x: builtins.ValueError # translate to the appropriate namespace... namespace, short_classname = classname.split('.', 1) if namespace in ("builtins", "exceptions"): if sys.version_info < (3, 0): exceptiontype = getattr(exceptions, short_classname) if issubclass(exceptiontype, BaseException): return SerializerBase.make_exception(exceptiontype, data) else: exceptiontype = getattr(builtins, short_classname) if issubclass(exceptiontype, BaseException): return SerializerBase.make_exception(exceptiontype, data) elif namespace == "sqlite3" and short_classname.endswith("Error"): import sqlite3 exceptiontype = getattr(sqlite3, short_classname) if issubclass(exceptiontype, BaseException): return SerializerBase.make_exception(exceptiontype, data) log.warning("unsupported serialized class: " + classname) raise errors.SerializeError("unsupported serialized class: " + classname)