Пример #1
0
    def parse_server_capabilities(self, capabilities):
        def get(key, default=None):
            return self.capsget(capabilities, key, default)

        self._remote_version = get("version")
        self._remote_revision = get("revision")
        self._remote_revision = get("build.revision", self._remote_revision)
        self._remote_platform = get("platform")
        self._remote_platform_release = get("platform.release")
        self._remote_platform_platform = get("platform.platform")
        self._remote_platform_linux_distribution = get(
            "platform.linux_distribution")
        verr = version_compat_check(self._remote_version)
        if verr is not None:
            self.warn_and_quit(
                EXIT_INCOMPATIBLE_VERSION,
                "incompatible remote version %s: %s" %
                (self._remote_version, verr))
            return False
        if capabilities.get("rencode") and use_rencode:
            self._protocol.enable_rencode()
        if self.encryption:
            #server uses a new cipher after second hello:
            self.set_server_encryption(capabilities)
        self._protocol.chunked_compression = get("chunked_compression", False)
        self._protocol.aliases = get("aliases", {})
        if self.pings:
            self.timeout_add(1000, self.send_ping)
        else:
            self.timeout_add(10 * 1000, self.send_ping)
        return True
Пример #2
0
 def parse_hello(self, c: typedict):
     self.ui_client = c.boolget("ui_client", True)
     self.wants_encodings = c.boolget("wants_encodings", self.ui_client)
     self.wants_display = c.boolget("wants_display", self.ui_client)
     self.wants_events = c.boolget("wants_events", False)
     self.wants_aliases = c.boolget("wants_aliases", True)
     self.wants_versions = c.boolget("wants_versions", True)
     self.wants_features = c.boolget("wants_features", True)
     self.wants_default_cursor = c.boolget("wants_default_cursor",
                                           False)
     for bc in CC_BASES:
         log("%s.parse_client_caps(..)", bc)
         bc.parse_client_caps(self, c)
     #log client info:
     cinfo = self.get_connect_info()
     for i, ci in enumerate(cinfo):
         log.info("%s%s", ["", " "][int(i > 0)], ci)
     if self.client_proxy:
         from xpra.version_util import version_compat_check
         msg = version_compat_check(self.proxy_version)
         if msg:
             proxylog = Logger("proxy")
             proxylog.warn(
                 "Warning: proxy version may not be compatible: %s",
                 msg)
Пример #3
0
    def parse_server_capabilities(self, c):
        self._remote_machine_id = c.strget("machine_id")
        self._remote_uuid = c.strget("uuid")
        self._remote_version = c.strget("version")
        self._remote_revision = c.strget("revision")
        self._remote_revision = c.strget("build.revision", self._remote_revision)
        self._remote_platform = c.strget("platform")
        self._remote_platform_release = c.strget("platform.release")
        self._remote_platform_platform = c.strget("platform.platform")
        self._remote_platform_linux_distribution = c.get("platform.linux_distribution")
        verr = version_compat_check(self._remote_version)
        if verr is not None:
            self.warn_and_quit(EXIT_INCOMPATIBLE_VERSION, "incompatible remote version '%s': %s" % (self._remote_version, verr))
            return False

        self._protocol.chunked_compression = c.boolget("chunked_compression")
        if use_rencode and c.boolget("rencode"):
            self._protocol.enable_rencode()
        if use_lz4 and c.boolget("lz4") and self._protocol.chunked_compression and self.compression_level==1:
            self._protocol.enable_lz4()
        if self.encryption:
            #server uses a new cipher after second hello:
            key = self.get_encryption_key()
            assert key, "encryption key is missing"
            if not self.set_server_encryption(c, key):
                return False
        self._protocol.aliases = c.dictget("aliases", {})
        if self.pings:
            self.timeout_add(1000, self.send_ping)
        else:
            self.timeout_add(10*1000, self.send_ping)
        return True
Пример #4
0
 def parse_server_capabilities(self, capabilities):
     def get(key, default=None):
         return self.capsget(capabilities, key, default)
     self._remote_version = get("version")
     self._remote_revision = get("revision")
     self._remote_revision = get("build.revision", self._remote_revision)
     self._remote_platform = get("platform")
     self._remote_platform_release = get("platform.release")
     self._remote_platform_platform = get("platform.platform")
     self._remote_platform_linux_distribution = get("platform.linux_distribution")
     verr = version_compat_check(self._remote_version)
     if verr is not None:
         self.warn_and_quit(EXIT_INCOMPATIBLE_VERSION, "incompatible remote version %s: %s" % (self._remote_version, verr))
         return False
     if capabilities.get("rencode") and use_rencode:
         self._protocol.enable_rencode()
     if self.encryption:
         #server uses a new cipher after second hello:
         self.set_server_encryption(capabilities)
     self._protocol.chunked_compression = get("chunked_compression", False)
     self._protocol.aliases = get("aliases", {})
     if self.pings:
         self.timeout_add(1000, self.send_ping)
     else:
         self.timeout_add(10*1000, self.send_ping)
     return True
Пример #5
0
    def parse_version_capabilities(self):
        c = self.server_capabilities
        self._remote_machine_id = c.strget("machine_id")
        self._remote_uuid = c.strget("uuid")
        self._remote_version = c.strget("build.version", c.strget("version"))
        self._remote_revision = c.strget("build.revision", c.strget("revision"))
        self._remote_platform = c.strget("platform")
        self._remote_platform_release = c.strget("platform.release")
        self._remote_platform_platform = c.strget("platform.platform")
        # linux distribution is a tuple of different types, ie: ('Linux Fedora' , 20, 'Heisenbug')
        pld = c.listget("platform.linux_distribution")
        if pld and len(pld) == 3:

            def san(v):
                if type(v) == int:
                    return v
                return bytestostr(v)

            self._remote_platform_linux_distribution = [san(x) for x in pld]
        verr = version_compat_check(self._remote_version)
        if verr is not None:
            self.warn_and_quit(
                EXIT_INCOMPATIBLE_VERSION, "incompatible remote version '%s': %s" % (self._remote_version, verr)
            )
            return False
        return True
Пример #6
0
    def parse_version_capabilities(self):
        c = self.server_capabilities
        self._remote_machine_id = c.strget("machine_id")
        self._remote_uuid = c.strget("uuid")
        self._remote_version = c.strget("build.version", c.strget("version"))
        self._remote_revision = c.strget("build.revision",
                                         c.strget("revision"))
        self._remote_platform = c.strget("platform")
        self._remote_platform_release = c.strget("platform.release")
        self._remote_platform_platform = c.strget("platform.platform")
        #linux distribution is a tuple of different types, ie: ('Linux Fedora' , 20, 'Heisenbug')
        pld = c.listget("platform.linux_distribution")
        if pld and len(pld) == 3:

            def san(v):
                if type(v) == int:
                    return v
                return bytestostr(v)

            self._remote_platform_linux_distribution = [san(x) for x in pld]
        verr = version_compat_check(self._remote_version)
        if verr is not None:
            self.warn_and_quit(
                EXIT_INCOMPATIBLE_VERSION,
                "incompatible remote version '%s': %s" %
                (self._remote_version, verr))
            return False
        return True
Пример #7
0
    def parse_hello(self, c):
        self.ui_client = c.boolget("ui_client", True)
        self.wants_encodings = c.boolget("wants_encodings", self.ui_client)
        self.wants_display = c.boolget("wants_display", self.ui_client)
        self.wants_events = c.boolget("wants_events", False)
        self.wants_aliases = c.boolget("wants_aliases", True)
        self.wants_versions = c.boolget("wants_versions", True)
        self.wants_features = c.boolget("wants_features", True)
        self.wants_default_cursor = c.boolget("wants_default_cursor", False)

        for mixin in CC_BASES:
            mixin.parse_client_caps(self, c)

        #general features:
        self.info_namespace = c.boolget("info-namespace")
        self.send_notifications = c.boolget("notifications")
        self.send_notifications_actions = c.boolget("notifications.actions")
        log("notifications=%s, actions=%s", self.send_notifications,
            self.send_notifications_actions)
        self.share = c.boolget("share")
        self.lock = c.boolget("lock")
        self.control_commands = c.strlistget("control_commands")
        bandwidth_limit = c.intget("bandwidth-limit", 0)
        server_bandwidth_limit = self.server_bandwidth_limit
        if self.server_bandwidth_limit is None:
            server_bandwidth_limit = self.get_socket_bandwidth_limit(
            ) or bandwidth_limit
        self.bandwidth_limit = min(server_bandwidth_limit, bandwidth_limit)
        if self.bandwidth_detection:
            self.bandwidth_detection = c.boolget("bandwidth-detection", True)
        cd = typedict(c.dictget("connection-data"))
        self.jitter = cd.intget("jitter", 0)
        bandwidthlog(
            "server bandwidth-limit=%s, client bandwidth-limit=%s, value=%s, detection=%s",
            server_bandwidth_limit, bandwidth_limit, self.bandwidth_limit,
            self.bandwidth_detection)

        cinfo = self.get_connect_info()
        for i, ci in enumerate(cinfo):
            log.info("%s%s", ["", " "][int(i > 0)], ci)
        if self.client_proxy:
            from xpra.version_util import version_compat_check
            msg = version_compat_check(self.proxy_version)
            if msg:
                proxylog.warn(
                    "Warning: proxy version may not be compatible: %s", msg)
        self.update_connection_data(c.dictget("connection-data"))
        if getattr(self, "mmap_size", 0) > 0:
            log("mmap enabled, ignoring bandwidth-limit")
            self.bandwidth_limit = 0
        #adjust max packet size if file transfers are enabled:
        #TODO: belongs in mixin:
        file_transfer = getattr(self, "file_transfer", None)
        if file_transfer:
            self.protocol.max_packet_size = max(
                self.protocol.max_packet_size,
                self.file_size_limit * 1024 * 1024)
Пример #8
0
    def parse_hello(self, c):
        self.ui_client = c.boolget("ui_client", True)
        self.wants_encodings = c.boolget("wants_encodings", self.ui_client)
        self.wants_display = c.boolget("wants_display", self.ui_client)
        self.wants_events = c.boolget("wants_events", False)
        self.wants_aliases = c.boolget("wants_aliases", True)
        self.wants_versions = c.boolget("wants_versions", True)
        self.wants_features = c.boolget("wants_features", True)
        self.wants_default_cursor = c.boolget("wants_default_cursor", False)

        for mixin in ClientConnection.__bases__:
            mixin.parse_client_caps(self, c)

        #general features:
        self.info_namespace = c.boolget("info-namespace")
        self.send_notifications = c.boolget("notifications")
        self.send_notifications_actions = c.boolget("notifications.actions")
        self.share = c.boolget("share")
        self.lock = c.boolget("lock")
        self.control_commands = c.strlistget("control_commands")
        bandwidth_limit = c.intget("bandwidth-limit", 0)
        if self.server_bandwidth_limit <= 0:
            self.bandwidth_limit = bandwidth_limit
        else:
            self.bandwidth_limit = min(self.server_bandwidth_limit,
                                       bandwidth_limit)
        bandwidthlog(
            "server bandwidth-limit=%s, client bandwidth-limit=%s, value=%s",
            self.server_bandwidth_limit, bandwidth_limit, self.bandwidth_limit)
        log("cursors=%s (encodings=%s), bell=%s, notifications=%s",
            self.send_cursors, self.cursor_encodings, self.send_bell,
            self.send_notifications)

        cinfo = self.get_connect_info()
        for i, ci in enumerate(cinfo):
            log.info("%s%s", ["", " "][int(i > 0)], ci)
        if self.client_proxy:
            from xpra.version_util import version_compat_check
            msg = version_compat_check(self.proxy_version)
            if msg:
                proxylog.warn(
                    "Warning: proxy version may not be compatible: %s", msg)
        self.update_connection_data(c.dictget("connection-data"))
        if self.mmap_size > 0:
            log("mmap enabled, ignoring bandwidth-limit")
            self.bandwidth_limit = 0
        #adjust max packet size if file transfers are enabled:
        if self.file_transfer:
            self.protocol.max_packet_size = max(
                self.protocol.max_packet_size,
                self.file_size_limit * 1024 * 1024)
Пример #9
0
    def parse_server_capabilities(self, c: typedict) -> bool:
        p = self._protocol
        if p.TYPE == "rfb":
            #only the xpra protocol provides the server info
            return True
        self._remote_machine_id = c.strget("machine_id")
        self._remote_uuid = c.strget("uuid")
        self._remote_version = c.strget("build.version", c.strget("version"))
        self._remote_revision = c.strget("build.revision",
                                         c.strget("revision"))
        mods = c.get("build.local_modifications")
        if mods and str(mods).find("dfsg") >= 0:  # pragma: no cover
            get_util_logger().warn(
                "Warning: the xpra server is running a buggy Debian version")
            get_util_logger().warn(
                " those are usually out of date and unstable")
        else:
            self._remote_modifications = c.intget("build.local_modifications",
                                                  0)
        self._remote_commit = c.strget("build.commit")
        self._remote_branch = c.strget("build.branch")
        self._remote_build_date = c.strget("build.date")
        self._remote_build_time = c.strget("build.time")
        self._remote_hostname = c.strget("hostname")
        self._remote_display = c.strget("display")
        self._remote_platform = c.strget("platform")
        self._remote_platform_release = c.strget("platform.release")
        self._remote_platform_platform = c.strget("platform.platform")
        self._remote_python_version = c.strget("python.version")
        self._remote_subcommands = c.strtupleget("subcommands")
        self._remote_server_log = c.strget("server-log")
        self._remote_lib_versions = get_remote_lib_versions(c)
        #linux distribution is a tuple of different types, ie: ('Linux Fedora' , 20, 'Heisenbug')
        pld = c.tupleget("platform.linux_distribution")
        if pld and len(pld) == 3:

            def san(v):
                if isinstance(v, int):
                    return v
                return bytestostr(v)

            self._remote_platform_linux_distribution = [san(x) for x in pld]
        verr = version_compat_check(self._remote_version)
        if verr is not None:
            self.warn_and_quit(
                EXIT_INCOMPATIBLE_VERSION,
                "incompatible remote version '%s': %s" %
                (self._remote_version, verr))
            return False
        return True
Пример #10
0
    def parse_server_capabilities(self, c):
        self._remote_machine_id = c.strget("machine_id")
        self._remote_uuid = c.strget("uuid")
        self._remote_version = c.strget("version")
        self._remote_version = c.strget("build.version", self._remote_version)
        self._remote_revision = c.strget("revision")
        self._remote_revision = c.strget("build.revision",
                                         self._remote_revision)
        self._remote_platform = c.strget("platform")
        self._remote_platform_release = c.strget("platform.release")
        self._remote_platform_platform = c.strget("platform.platform")
        #linux distribution is a tuple of different types, ie: ('Linux Fedora' , 20, 'Heisenbug')
        pld = c.listget("platform.linux_distribution")
        if pld and len(pld) == 3:

            def san(v):
                if type(v) == int:
                    return v
                return bytestostr(v)

            self._remote_platform_linux_distribution = [san(x) for x in pld]
        verr = version_compat_check(self._remote_version)
        if verr is not None:
            self.warn_and_quit(
                EXIT_INCOMPATIBLE_VERSION,
                "incompatible remote version '%s': %s" %
                (self._remote_version, verr))
            return False

        if use_rencode and c.boolget("rencode"):
            self._protocol.enable_rencode()
        if use_lz4 and c.boolget("lz4") and self.compression_level == 1:
            self._protocol.enable_lz4()
        if self.encryption:
            #server uses a new cipher after second hello:
            key = self.get_encryption_key()
            assert key, "encryption key is missing"
            if not self.set_server_encryption(c, key):
                return False
        self._protocol.send_aliases = c.dictget("aliases", {})
        if self.pings:
            self.timeout_add(1000, self.send_ping)
        else:
            self.timeout_add(10 * 1000, self.send_ping)
        return True
Пример #11
0
    def verify_hello(self, proto, c):
        remote_version = c.strget("version")
        verr = version_compat_check(remote_version)
        if verr is not None:
            self.disconnect_client(proto, "incompatible version: %s" % verr)
            proto.close()
            return False

        def auth_failed(msg):
            log.info("authentication failed: %s", msg)
            self.timeout_add(1000, self.disconnect_client, proto, msg)

        #authenticator:
        username = c.strget("username")
        if proto.authenticator is None and self.auth_class:
            try:
                proto.authenticator = self.auth_class(username)
            except Exception, e:
                log.warn("error instantiating %s: %s", self.auth_class, e)
                auth_failed("authentication failed")
                return False
Пример #12
0
    def verify_hello(self, proto, c):
        remote_version = c.strget("version")
        verr = version_compat_check(remote_version)
        if verr is not None:
            self.disconnect_client(proto, "incompatible version: %s" % verr)
            proto.close()
            return  False

        def auth_failed(msg):
            log.info("authentication failed: %s", msg)
            self.timeout_add(1000, self.disconnect_client, proto, msg)

        #authenticator:
        username = c.strget("username")
        if proto.authenticator is None and self.auth_class:
            try:
                proto.authenticator = self.auth_class(username)
            except Exception, e:
                log.warn("error instantiating %s: %s", self.auth_class, e)
                auth_failed("authentication failed")
                return False
Пример #13
0
    def parse_server_capabilities(self, c):
        self._remote_machine_id = c.strget("machine_id")
        self._remote_uuid = c.strget("uuid")
        self._remote_version = c.strget("version")
        self._remote_version = c.strget("build.version", self._remote_version)
        self._remote_revision = c.strget("revision")
        self._remote_revision = c.strget("build.revision", self._remote_revision)
        self._remote_platform = c.strget("platform")
        self._remote_platform_release = c.strget("platform.release")
        self._remote_platform_platform = c.strget("platform.platform")
        #linux distribution is a tuple of different types, ie: ('Linux Fedora' , 20, 'Heisenbug')
        pld = c.listget("platform.linux_distribution")
        if pld and len(pld)==3:
            def san(v):
                if type(v)==int:
                    return v
                return bytestostr(v)
            self._remote_platform_linux_distribution = [san(x) for x in pld]
        verr = version_compat_check(self._remote_version)
        if verr is not None:
            self.warn_and_quit(EXIT_INCOMPATIBLE_VERSION, "incompatible remote version '%s': %s" % (self._remote_version, verr))
            return False

        if use_rencode and c.boolget("rencode"):
            self._protocol.enable_rencode()
        if use_lz4 and c.boolget("lz4") and self.compression_level==1:
            self._protocol.enable_lz4()
        if self.encryption:
            #server uses a new cipher after second hello:
            key = self.get_encryption_key()
            assert key, "encryption key is missing"
            if not self.set_server_encryption(c, key):
                return False
        self._protocol.send_aliases = c.dictget("aliases", {})
        if self.pings:
            self.timeout_add(1000, self.send_ping)
        else:
            self.timeout_add(10*1000, self.send_ping)
        return True
Пример #14
0
    def parse_server_capabilities(self, c):
        self._remote_machine_id = c.strget("machine_id")
        self._remote_uuid = c.strget("uuid")
        self._remote_version = c.strget("version")
        self._remote_revision = c.strget("revision")
        self._remote_revision = c.strget("build.revision",
                                         self._remote_revision)
        self._remote_platform = c.strget("platform")
        self._remote_platform_release = c.strget("platform.release")
        self._remote_platform_platform = c.strget("platform.platform")
        self._remote_platform_linux_distribution = c.get(
            "platform.linux_distribution")
        verr = version_compat_check(self._remote_version)
        if verr is not None:
            self.warn_and_quit(
                EXIT_INCOMPATIBLE_VERSION,
                "incompatible remote version '%s': %s" %
                (self._remote_version, verr))
            return False

        self._protocol.chunked_compression = c.boolget("chunked_compression")
        if use_rencode and c.boolget("rencode"):
            self._protocol.enable_rencode()
        if use_lz4 and c.boolget(
                "lz4"
        ) and self._protocol.chunked_compression and self.compression_level == 1:
            self._protocol.enable_lz4()
        if self.encryption:
            #server uses a new cipher after second hello:
            key = self.get_encryption_key()
            assert key, "encryption key is missing"
            if not self.set_server_encryption(c, key):
                return False
        self._protocol.send_aliases = c.dictget("aliases", {})
        if self.pings:
            self.timeout_add(1000, self.send_ping)
        else:
            self.timeout_add(10 * 1000, self.send_ping)
        return True
Пример #15
0
 def parse_server_capabilities(self, c : typedict) -> bool:
     self._remote_machine_id = c.strget("machine_id")
     self._remote_uuid = c.strget("uuid")
     self._remote_version = c.strget("build.version", c.strget("version"))
     self._remote_revision = c.strget("build.revision", c.strget("revision"))
     mods = c.rawget("build.local_modifications")
     if mods and str(mods).find("dfsg")>=0:
         get_util_logger().warn("Warning: the xpra server is running a buggy Debian version")
         get_util_logger().warn(" those are usually out of date and unstable")
     else:
         self._remote_modifications = c.intget("build.local_modifications", 0)
     self._remote_build_date = c.strget("build.date")
     self._remote_build_time = c.strget("build.time")
     self._remote_hostname = c.strget("hostname")
     self._remote_display = c.strget("display")
     self._remote_platform = c.strget("platform")
     self._remote_platform_release = c.strget("platform.release")
     self._remote_platform_platform = c.strget("platform.platform")
     self._remote_python_version = c.strget("python.version")
     self._remote_subcommands = c.strtupleget("subcommands")
     for x in ("glib", "gobject", "gtk", "gdk", "cairo", "pango", "sound.gst", "sound.pygst"):
         v = c.rawget("%s.version" % x, None)
         if v is not None:
             self._remote_lib_versions[x] = v
     #linux distribution is a tuple of different types, ie: ('Linux Fedora' , 20, 'Heisenbug')
     pld = c.tupleget("platform.linux_distribution")
     if pld and len(pld)==3:
         def san(v):
             if isinstance(v, int):
                 return v
             return bytestostr(v)
         self._remote_platform_linux_distribution = [san(x) for x in pld]
     verr = version_compat_check(self._remote_version)
     if verr is not None:
         self.warn_and_quit(EXIT_INCOMPATIBLE_VERSION,
                            "incompatible remote version '%s': %s" % (self._remote_version, verr))
         return False
     return True
Пример #16
0
    def verify_hello(self, proto, c):
        remote_version = c.strget("version")
        verr = version_compat_check(remote_version)
        if verr is not None:
            self.disconnect_client(proto, VERSION_ERROR,
                                   "incompatible version: %s" % verr)
            proto.close()
            return False

        def auth_failed(msg):
            log.warn("Warning: authentication failed: %s", msg)
            self.timeout_add(1000, self.disconnect_client, proto, msg)

        #authenticator:
        username = c.strget("username")
        if proto.authenticator is None and proto.auth_class:
            try:
                proto.authenticator = proto.auth_class(username)
            except Exception as e:
                log.warn("error instantiating %s: %s", proto.auth_class, e)
                auth_failed("authentication failed")
                return False
        self.digest_modes = c.get("digest", ("hmac", ))

        #client may have requested encryption:
        cipher = c.strget("cipher")
        cipher_iv = c.strget("cipher.iv")
        key_salt = c.strget("cipher.key_salt")
        iterations = c.intget("cipher.key_stretch_iterations")
        auth_caps = {}
        if cipher and cipher_iv:
            if cipher not in ENCRYPTION_CIPHERS:
                log.warn("unsupported cipher: %s", cipher)
                auth_failed("unsupported cipher")
                return False
            encryption_key = self.get_encryption_key(proto.authenticator)
            if encryption_key is None:
                auth_failed("encryption key is missing")
                return False
            proto.set_cipher_out(cipher, cipher_iv, encryption_key, key_salt,
                                 iterations)
            #use the same cipher as used by the client:
            auth_caps = new_cipher_caps(proto, cipher, encryption_key)
            log("server cipher=%s", auth_caps)
        else:
            auth_caps = None

        #verify authentication if required:
        if (proto.authenticator and proto.authenticator.requires_challenge()
            ) or c.get("challenge") is not None:
            challenge_response = c.strget("challenge_response")
            client_salt = c.strget("challenge_client_salt")
            log(
                "processing authentication with %s, response=%s, client_salt=%s, challenge_sent=%s",
                proto.authenticator, challenge_response,
                binascii.hexlify(client_salt or ""), proto.challenge_sent)
            #send challenge if this is not a response:
            if not challenge_response:
                if proto.challenge_sent:
                    auth_failed(
                        "invalid state, challenge already sent - no response!")
                    return False
                if proto.authenticator:
                    challenge = proto.authenticator.get_challenge()
                    if challenge is None:
                        auth_failed(
                            "invalid state: unexpected challenge response")
                        return False
                    salt, digest = challenge
                    log.info(
                        "Authentication required, %s sending challenge for '%s' using digest %s",
                        proto.authenticator, username, digest)
                    if digest not in self.digest_modes:
                        auth_failed(
                            "cannot proceed without %s digest support" %
                            digest)
                        return False
                else:
                    log.warn(
                        "Warning: client expects a challenge but this connection is unauthenticated"
                    )
                    #fake challenge so the client will send the real hello:
                    from xpra.os_util import get_hex_uuid
                    salt = get_hex_uuid() + get_hex_uuid()
                    digest = "hmac"
                proto.challenge_sent = True
                proto.send_now(("challenge", salt, auth_caps or "", digest))
                return False

            if not proto.authenticator.authenticate(challenge_response,
                                                    client_salt):
                auth_failed("invalid challenge response")
                return False
            log("authentication challenge passed")
        else:
            #did the client expect a challenge?
            if c.boolget("challenge"):
                log.warn(
                    "this server does not require authentication (client supplied a challenge)"
                )
        return auth_caps
Пример #17
0
    def test_version_compat_check_invalid(self):
        from xpra import __version__

        self.assertIsNone(version_compat_check(__version__))
        self.assertIsNotNone(version_compat_check("0.1"))
Пример #18
0
    def verify_hello(self, proto, c):
        remote_version = c.strget("version")
        verr = version_compat_check(remote_version)
        if verr is not None:
            self.disconnect_client(proto, VERSION_ERROR,
                                   "incompatible version: %s" % verr)
            proto.close()
            return False

        def auth_failed(msg):
            authlog.error("Error: authentication failed")
            authlog.error(" %s", msg)
            self.timeout_add(1000, self.disconnect_client, proto, msg)

        #authenticator:
        username = c.strget("username")
        if proto.authenticator is None and proto.auth_class:
            authlog("creating authenticator %s", proto.auth_class)
            try:
                auth, aclass, options = proto.auth_class
                ainstance = aclass(username, **options)
                proto.authenticator = ainstance
                authlog("%s=%s", auth, ainstance)
            except Exception as e:
                authlog.error("Error instantiating %s:", proto.auth_class)
                authlog.error(" %s", e)
                auth_failed("authentication failed")
                return False
        self.digest_modes = c.get("digest", ("hmac", ))

        #client may have requested encryption:
        cipher = c.strget("cipher")
        cipher_iv = c.strget("cipher.iv")
        key_salt = c.strget("cipher.key_salt")
        iterations = c.intget("cipher.key_stretch_iterations")
        padding = c.strget("cipher.padding", DEFAULT_PADDING)
        padding_options = c.strlistget("cipher.padding.options",
                                       [DEFAULT_PADDING])
        auth_caps = {}
        if cipher and cipher_iv:
            if cipher not in ENCRYPTION_CIPHERS:
                authlog.warn("unsupported cipher: %s", cipher)
                auth_failed("unsupported cipher")
                return False
            encryption_key = self.get_encryption_key(proto.authenticator,
                                                     proto.keyfile)
            if encryption_key is None:
                auth_failed("encryption key is missing")
                return False
            if padding not in ALL_PADDING_OPTIONS:
                auth_failed("unsupported padding: %s" % padding)
                return False
            authlog("set output cipher using encryption key '%s'",
                    repr_ellipsized(encryption_key))
            proto.set_cipher_out(cipher, cipher_iv, encryption_key, key_salt,
                                 iterations, padding)
            #use the same cipher as used by the client:
            auth_caps = new_cipher_caps(proto, cipher, encryption_key,
                                        padding_options)
            authlog("server cipher=%s", auth_caps)
        else:
            if proto.encryption:
                authlog("client does not provide encryption tokens")
                auth_failed("missing encryption tokens")
                return False
            auth_caps = None

        #verify authentication if required:
        if (proto.authenticator and proto.authenticator.requires_challenge()
            ) or c.get("challenge") is not None:
            challenge_response = c.strget("challenge_response")
            client_salt = c.strget("challenge_client_salt")
            authlog(
                "processing authentication with %s, response=%s, client_salt=%s, challenge_sent=%s",
                proto.authenticator, challenge_response,
                binascii.hexlify(client_salt or ""), proto.challenge_sent)
            #send challenge if this is not a response:
            if not challenge_response:
                if proto.challenge_sent:
                    auth_failed(
                        "invalid state, challenge already sent - no response!")
                    return False
                if proto.authenticator:
                    challenge = proto.authenticator.get_challenge()
                    if challenge is None:
                        auth_failed(
                            "invalid state, unexpected challenge response")
                        return False
                    authlog("challenge: %s", challenge)
                    salt, digest = challenge
                    authlog.info(
                        "Authentication required by %s authenticator module",
                        proto.authenticator)
                    authlog.info(" sending challenge for '%s' using %s digest",
                                 username, digest)
                    if digest not in self.digest_modes:
                        auth_failed(
                            "cannot proceed without %s digest support" %
                            digest)
                        return False
                else:
                    authlog.warn(
                        "Warning: client expects a challenge but this connection is unauthenticated"
                    )
                    #fake challenge so the client will send the real hello:
                    salt = get_salt()
                    digest = "hmac"
                proto.challenge_sent = True
                proto.send_now(("challenge", salt, auth_caps or "", digest))
                return False

            if not proto.authenticator.authenticate(challenge_response,
                                                    client_salt):
                auth_failed("invalid challenge response")
                return False
            authlog("authentication challenge passed")
        else:
            #did the client expect a challenge?
            if c.boolget("challenge"):
                authlog.warn(
                    "this server does not require authentication (client supplied a challenge)"
                )
        return auth_caps
Пример #19
0
    def verify_hello(self, proto, c):
        remote_version = c.strget("version")
        verr = version_compat_check(remote_version)
        if verr is not None:
            self.disconnect_client(proto, VERSION_ERROR, "incompatible version: %s" % verr)
            proto.close()
            return False

        def auth_failed(msg):
            log.warn("Warning: authentication failed: %s", msg)
            self.timeout_add(1000, self.disconnect_client, proto, msg)

        # authenticator:
        username = c.strget("username")
        if proto.authenticator is None and proto.auth_class:
            try:
                proto.authenticator = proto.auth_class(username)
            except Exception as e:
                log.warn("error instantiating %s: %s", proto.auth_class, e)
                auth_failed("authentication failed")
                return False
        self.digest_modes = c.get("digest", ("hmac",))

        # client may have requested encryption:
        cipher = c.strget("cipher")
        cipher_iv = c.strget("cipher.iv")
        key_salt = c.strget("cipher.key_salt")
        iterations = c.intget("cipher.key_stretch_iterations")
        auth_caps = {}
        if cipher and cipher_iv:
            if cipher not in ENCRYPTION_CIPHERS:
                log.warn("unsupported cipher: %s", cipher)
                auth_failed("unsupported cipher")
                return False
            encryption_key = self.get_encryption_key(proto.authenticator)
            if encryption_key is None:
                auth_failed("encryption key is missing")
                return False
            proto.set_cipher_out(cipher, cipher_iv, encryption_key, key_salt, iterations)
            # use the same cipher as used by the client:
            auth_caps = new_cipher_caps(proto, cipher, encryption_key)
            log("server cipher=%s", auth_caps)
        else:
            auth_caps = None

        # verify authentication if required:
        if (proto.authenticator and proto.authenticator.requires_challenge()) or c.get("challenge") is not None:
            challenge_response = c.strget("challenge_response")
            client_salt = c.strget("challenge_client_salt")
            log(
                "processing authentication with %s, response=%s, client_salt=%s, challenge_sent=%s",
                proto.authenticator,
                challenge_response,
                binascii.hexlify(client_salt or ""),
                proto.challenge_sent,
            )
            # send challenge if this is not a response:
            if not challenge_response:
                if proto.challenge_sent:
                    auth_failed("invalid state, challenge already sent - no response!")
                    return False
                if proto.authenticator:
                    challenge = proto.authenticator.get_challenge()
                    if challenge is None:
                        auth_failed("invalid state: unexpected challenge response")
                        return False
                    salt, digest = challenge
                    log.info(
                        "Authentication required, %s sending challenge for '%s' using digest %s",
                        proto.authenticator,
                        username,
                        digest,
                    )
                    if digest not in self.digest_modes:
                        auth_failed("cannot proceed without %s digest support" % digest)
                        return False
                else:
                    log.warn("Warning: client expects a challenge but this connection is unauthenticated")
                    # fake challenge so the client will send the real hello:
                    from xpra.os_util import get_hex_uuid

                    salt = get_hex_uuid() + get_hex_uuid()
                    digest = "hmac"
                proto.challenge_sent = True
                proto.send_now(("challenge", salt, auth_caps or "", digest))
                return False

            if not proto.authenticator.authenticate(challenge_response, client_salt):
                auth_failed("invalid challenge response")
                return False
            log("authentication challenge passed")
        else:
            # did the client expect a challenge?
            if c.boolget("challenge"):
                log.warn("this server does not require authentication (client supplied a challenge)")
        return auth_caps
Пример #20
0
 def test_version_compat_check_invalid(self):
     from xpra import __version__
     self.assertIsNone(version_compat_check(__version__))
     self.assertIsNotNone(version_compat_check("0.1"))
Пример #21
0
    def verify_hello(self, proto, c):
        remote_version = c.strget("version")
        verr = version_compat_check(remote_version)
        if verr is not None:
            self.disconnect_client(proto, VERSION_ERROR, "incompatible version: %s" % verr)
            proto.close()
            return  False

        def auth_failed(msg):
            authlog.error("Error: authentication failed")
            authlog.error(" %s", msg)
            self.timeout_add(1000, self.disconnect_client, proto, msg)

        #authenticator:
        username = c.strget("username")
        if proto.authenticator is None and proto.auth_class:
            authlog("creating authenticator %s", proto.auth_class)
            try:
                auth, aclass, options = proto.auth_class
                ainstance = aclass(username, **options)
                proto.authenticator = ainstance
                authlog("%s=%s", auth, ainstance)
            except Exception as e:
                authlog.error("Error instantiating %s:", proto.auth_class)
                authlog.error(" %s", e)
                auth_failed("authentication failed")
                return False

        digest_modes = c.get("digest", ("hmac", ))
        #client may have requested encryption:
        cipher = c.strget("cipher")
        cipher_iv = c.strget("cipher.iv")
        key_salt = c.strget("cipher.key_salt")
        iterations = c.intget("cipher.key_stretch_iterations")
        padding = c.strget("cipher.padding", DEFAULT_PADDING)
        padding_options = c.strlistget("cipher.padding.options", [DEFAULT_PADDING])
        auth_caps = {}
        if cipher and cipher_iv:
            if cipher not in ENCRYPTION_CIPHERS:
                authlog.warn("unsupported cipher: %s", cipher)
                auth_failed("unsupported cipher")
                return False
            encryption_key = self.get_encryption_key(proto.authenticator, proto.keyfile)
            if encryption_key is None:
                auth_failed("encryption key is missing")
                return False
            if padding not in ALL_PADDING_OPTIONS:
                auth_failed("unsupported padding: %s" % padding)
                return False
            authlog("set output cipher using encryption key '%s'", repr_ellipsized(encryption_key))
            proto.set_cipher_out(cipher, cipher_iv, encryption_key, key_salt, iterations, padding)
            #use the same cipher as used by the client:
            auth_caps = new_cipher_caps(proto, cipher, encryption_key, padding_options)
            authlog("server cipher=%s", auth_caps)
        else:
            if proto.encryption:
                authlog("client does not provide encryption tokens")
                auth_failed("missing encryption tokens")
                return False
            auth_caps = None

        #verify authentication if required:
        if (proto.authenticator and proto.authenticator.requires_challenge()) or c.get("challenge") is not None:
            challenge_response = c.strget("challenge_response")
            client_salt = c.strget("challenge_client_salt")
            authlog("processing authentication with %s, response=%s, client_salt=%s, challenge_sent=%s", proto.authenticator, challenge_response, binascii.hexlify(client_salt or ""), proto.challenge_sent)
            #send challenge if this is not a response:
            if not challenge_response:
                if proto.challenge_sent:
                    auth_failed("invalid state, challenge already sent - no response!")
                    return False
                if proto.authenticator:
                    challenge = proto.authenticator.get_challenge()
                    if challenge is None:
                        auth_failed("invalid state, unexpected challenge response")
                        return False
                    authlog("challenge: %s", challenge)
                    salt, digest = challenge
                    authlog.info("Authentication required by %s authenticator module", proto.authenticator)
                    authlog.info(" sending challenge for '%s' using %s digest", username, digest)
                    if digest not in digest_modes:
                        auth_failed("cannot proceed without %s digest support" % digest)
                        return False
                else:
                    authlog.warn("Warning: client expects a challenge but this connection is unauthenticated")
                    #fake challenge so the client will send the real hello:
                    salt = get_salt()
                    digest = "hmac"
                proto.challenge_sent = True
                proto.send_now(("challenge", salt, auth_caps or "", digest))
                return False

            if not proto.authenticator.authenticate(challenge_response, client_salt):
                auth_failed("invalid challenge response")
                return False
            authlog("authentication challenge passed")
        else:
            #did the client expect a challenge?
            if c.boolget("challenge"):
                authlog.warn("this server does not require authentication (client supplied a challenge)")
        return auth_caps