示例#1
0
    def make_hello_base(self):
        capabilities = flatten_dict(get_network_caps())
        import struct

        bits = struct.calcsize("P") * 8
        capabilities.update(
            {
                "version": local_version,
                "encoding.generic": True,
                "namespace": True,
                "hostname": socket.gethostname(),
                "uuid": self.uuid,
                "username": self.username,
                "name": get_name(),
                "client_type": self.client_type(),
                "python.version": sys.version_info[:3],
                "python.bits": bits,
                "compression_level": self.compression_level,
                "argv": sys.argv,
            }
        )
        capabilities.update(self.get_file_transfer_features())
        if self.display:
            capabilities["display"] = self.display

        def up(prefix, d):
            updict(capabilities, prefix, d)

        up("build", self.get_version_info())
        mid = get_machine_id()
        if mid:
            capabilities["machine_id"] = mid

        if self.encryption:
            assert self.encryption in ENCRYPTION_CIPHERS
            iv = get_iv()
            key_salt = get_salt()
            iterations = get_iterations()
            padding = choose_padding(self.server_padding_options)
            up(
                "cipher",
                {
                    "": self.encryption,
                    "iv": iv,
                    "key_salt": key_salt,
                    "key_stretch_iterations": iterations,
                    "padding": padding,
                    "padding.options": PADDING_OPTIONS,
                },
            )
            key = self.get_encryption_key()
            if key is None:
                self.warn_and_quit(EXIT_ENCRYPTION, "encryption key is missing")
                return
            self._protocol.set_cipher_in(self.encryption, iv, key, key_salt, iterations, padding)
            netlog(
                "encryption capabilities: %s", dict((k, v) for k, v in capabilities.items() if k.startswith("cipher"))
            )
        capabilities.update(self.hello_extra)
        return capabilities
示例#2
0
 def make_uuid(self):
     try:
         import hashlib
         u = hashlib.sha1()
     except:
         #try python2.4 variant:
         import sha
         u = sha.new()
     def uupdate(ustr):
         u.update(ustr.encode("utf-8"))
     uupdate(get_machine_id())
     if os.name=="posix":
         uupdate(u"/")
         uupdate(str(os.getuid()))
         uupdate(u"/")
         uupdate(str(os.getgid()))
     self.uuid = u.hexdigest()
示例#3
0
    def make_hello_base(self):
        capabilities = get_network_caps()
        capabilities.update({
                "version"               : local_version,
                "encoding.generic"      : True,
                "namespace"             : True,
                "file-transfer"         : self.file_transfer,
                "file-size-limit"       : self.file_size_limit,
                "printing"              : self.printing,
                "hostname"              : socket.gethostname(),
                "uuid"                  : self.uuid,
                "username"              : self.username,
                "name"                  : get_name(),
                "client_type"           : self.client_type(),
                "python.version"        : sys.version_info[:3],
                "compression_level"     : self.compression_level,
                })
        if self.display:
            capabilities["display"] = self.display
        def up(prefix, d):
            updict(capabilities, prefix, d)
        up("platform",  get_platform_info())
        up("build",     get_version_info())
        mid = get_machine_id()
        if mid:
            capabilities["machine_id"] = mid

        if self.encryption:
            assert self.encryption in ENCRYPTION_CIPHERS
            iv = get_hex_uuid()[:16]
            key_salt = get_hex_uuid()+get_hex_uuid()
            iterations = 1000
            capabilities.update({
                        "cipher"                       : self.encryption,
                        "cipher.iv"                    : iv,
                        "cipher.key_salt"              : key_salt,
                        "cipher.key_stretch_iterations": iterations,
                        })
            key = self.get_encryption_key()
            if key is None:
                self.warn_and_quit(EXIT_ENCRYPTION, "encryption key is missing")
                return
            self._protocol.set_cipher_in(self.encryption, iv, key, key_salt, iterations)
            log("encryption capabilities: %s", [(k,v) for k,v in capabilities.items() if k.startswith("cipher")])
        return capabilities
示例#4
0
 def audio_loop_check(self, mode="speaker"):
     log("audio_loop_check(%s)", mode)
     from xpra.sound.gstreamer_util import ALLOW_SOUND_LOOP, loop_warning_messages
     if ALLOW_SOUND_LOOP:
         return True
     machine_id = get_machine_id()
     uuid = get_user_uuid()
     log(
         "audio_loop_check(%s) machine_id=%s client machine_id=%s, uuid=%s, client uuid=%s",
         mode, machine_id, self.machine_id, uuid, self.uuid)
     if self.machine_id:
         if self.machine_id != machine_id:
             #not the same machine, so OK
             return True
         if self.uuid != uuid:
             #different user, assume different pulseaudio server
             return True
     #check pulseaudio id if we have it
     pulseaudio_id = self.sound_properties.get("pulseaudio", {}).get("id")
     pulseaudio_cookie_hash = self.sound_properties.get(
         "pulseaudio", {}).get("cookie-hash")
     log(
         "audio_loop_check(%s) pulseaudio id=%s, client pulseaudio id=%s, pulseaudio cookie hash=%s, client pulseaudio cookie hash=%s",
         mode, pulseaudio_id, self.pulseaudio_id, pulseaudio_cookie_hash,
         self.pulseaudio_cookie_hash)
     if pulseaudio_id and self.pulseaudio_id:
         if self.pulseaudio_id != pulseaudio_id:
             return True
     elif pulseaudio_cookie_hash and self.pulseaudio_cookie_hash:
         if self.pulseaudio_cookie_hash != pulseaudio_cookie_hash:
             return True
     else:
         #no cookie or id, so probably not a pulseaudio setup,
         #hope for the best:
         return True
     msgs = loop_warning_messages(mode)
     summary = msgs[0]
     body = "\n".join(msgs[1:])
     nid = XPRA_AUDIO_NOTIFICATION_ID
     self.may_notify(nid, summary, body, icon_name=mode)
     log.warn("Warning: %s", summary)
     for x in msgs[1:]:
         log.warn(" %s", x)
     return False
示例#5
0
    def make_hello_base(self):
        capabilities = get_network_caps()
        capabilities.update({
            "version": local_version,
            "encoding.generic": True,
            "namespace": True,
            "hostname": socket.gethostname(),
            "uuid": self.uuid,
            "username": self.username,
            "name": get_name(),
            "client_type": self.client_type(),
            "python.version": sys.version_info[:3],
            "compression_level": self.compression_level,
        })
        if self.display:
            capabilities["display"] = self.display
        capabilities.update(get_platform_info("platform"))
        capabilities.update(get_version_info("build"))
        mid = get_machine_id()
        if mid:
            capabilities["machine_id"] = mid

        if self.encryption:
            assert self.encryption in ENCRYPTION_CIPHERS
            iv = get_hex_uuid()[:16]
            key_salt = get_hex_uuid() + get_hex_uuid()
            iterations = 1000
            capabilities.update({
                "cipher": self.encryption,
                "cipher.iv": iv,
                "cipher.key_salt": key_salt,
                "cipher.key_stretch_iterations": iterations,
            })
            key = self.get_encryption_key()
            if key is None:
                self.warn_and_quit(EXIT_ENCRYPTION,
                                   "encryption key is missing")
                return
            self._protocol.set_cipher_in(self.encryption, iv, key, key_salt,
                                         iterations)
            log("encryption capabilities: %s",
                [(k, v)
                 for k, v in capabilities.items() if k.startswith("cipher")])
        return capabilities
示例#6
0
    def make_uuid(self):
        try:
            import hashlib
            u = hashlib.sha1()
        except:
            #try python2.4 variant:
            import sha
            u = sha.new()

        def uupdate(ustr):
            u.update(ustr.encode("utf-8"))

        uupdate(get_machine_id())
        if os.name == "posix":
            uupdate(u"/")
            uupdate(str(os.getuid()))
            uupdate(u"/")
            uupdate(str(os.getgid()))
        self.uuid = u.hexdigest()
示例#7
0
 def make_hello(self):
     now = time.time()
     capabilities = get_network_caps()
     capabilities.update(get_server_info())
     capabilities.update({
         "start_time": int(self.start_time),
         "current_time": int(now),
         "elapsed_time": int(now - self.start_time),
         "server_type": "core",
         "info-request": True,
         "uuid": get_user_uuid(),
     })
     mid = get_machine_id()
     if mid:
         capabilities["machine_id"] = mid
     if self.session_name:
         capabilities["session_name"] = self.session_name
     if self._reverse_aliases:
         capabilities["aliases"] = self._reverse_aliases
     add_version_info(capabilities)
     return capabilities
示例#8
0
 def make_hello(self):
     now = time.time()
     capabilities = get_network_caps()
     capabilities.update(get_server_info())
     capabilities.update({
                     "start_time"            : int(self.start_time),
                     "current_time"          : int(now),
                     "elapsed_time"          : int(now - self.start_time),
                     "server_type"           : "core",
                     "info-request"          : True,
                     "uuid"                  : get_user_uuid(),
                     })
     mid = get_machine_id()
     if mid:
         capabilities["machine_id"] = mid
     if self.session_name:
         capabilities["session_name"] = self.session_name
     if self._reverse_aliases:
         capabilities["aliases"] = self._reverse_aliases
     add_version_info(capabilities)
     return capabilities
示例#9
0
 def make_hello(self, source):
     now = time.time()
     capabilities = get_network_caps()
     if source.wants_versions:
         capabilities.update(get_server_info())
     capabilities.update({
         "version": xpra.__version__,
         "start_time": int(self.start_time),
         "current_time": int(now),
         "elapsed_time": int(now - self.start_time),
         "server_type": "core",
     })
     if source.wants_features:
         capabilities["info-request"] = True
     if source.wants_versions:
         capabilities["uuid"] = get_user_uuid()
         mid = get_machine_id()
         if mid:
             capabilities["machine_id"] = mid
     if self.session_name:
         capabilities["session_name"] = self.session_name
     return capabilities
示例#10
0
 def make_hello(self, source):
     now = time.time()
     capabilities = get_network_caps()
     if source.wants_versions:
         capabilities.update(get_server_info())
     capabilities.update({
                     "version"               : xpra.__version__,
                     "start_time"            : int(self.start_time),
                     "current_time"          : int(now),
                     "elapsed_time"          : int(now - self.start_time),
                     "server_type"           : "core",
                     })
     if source.wants_features:
         capabilities["info-request"] = True
     if source.wants_versions:
         capabilities["uuid"] = get_user_uuid()
         mid = get_machine_id()
         if mid:
             capabilities["machine_id"] = mid
     if self.session_name:
         capabilities["session_name"] = self.session_name
     return capabilities
示例#11
0
    def make_hello_base(self):
        capabilities = flatten_dict(get_network_caps())
        #add "kerberos", "gss" and "u2f" digests if enabled:
        for handler in self.challenge_handlers:
            digest = handler.get_digest()
            if digest:
                capabilities["digest"].append(digest)
        capabilities.update(FilePrintMixin.get_caps(self))
        capabilities.update({
            "version": XPRA_VERSION,
            "websocket.multi-packet": True,
            "hostname": socket.gethostname(),
            "uuid": self.uuid,
            "session-id": self.session_id,
            "username": self.username,
            "name": get_name(),
            "client_type": self.client_type(),
            "python.version": sys.version_info[:3],
            "python.bits": BITS,
            "compression_level": self.compression_level,
            "argv": sys.argv,
        })
        capabilities.update(self.get_file_transfer_features())
        if self.display:
            capabilities["display"] = self.display

        def up(prefix, d):
            updict(capabilities, prefix, d)

        up("build", self.get_version_info())
        mid = get_machine_id()
        if mid:
            capabilities["machine_id"] = mid
        if self.encryption:
            assert self.encryption in ENCRYPTION_CIPHERS
            iv = get_iv()
            key_salt = get_salt()
            iterations = get_iterations()
            padding = choose_padding(self.server_padding_options)
            up(
                "cipher", {
                    "": self.encryption,
                    "iv": iv,
                    "key_salt": key_salt,
                    "key_stretch_iterations": iterations,
                    "padding": padding,
                    "padding.options": PADDING_OPTIONS,
                })
            key = self.get_encryption_key()
            if key is None:
                self.warn_and_quit(EXIT_ENCRYPTION,
                                   "encryption key is missing")
                return None
            self._protocol.set_cipher_in(self.encryption, iv, key, key_salt,
                                         iterations, padding)
            netlog(
                "encryption capabilities: %s",
                dict((k, v) for k, v in capabilities.items()
                     if k.startswith("cipher")))
        capabilities.update(self.hello_extra)
        return capabilities
示例#12
0
    def do_update_screen(self):
        self.log("do_update_screen()")
        #c = self.stdscr.getch()
        #if c==curses.KEY_RESIZE:
        height, width = self.stdscr.getmaxyx()
        #log.info("update_screen() %ix%i", height, width)
        title = get_title()
        sli = self.server_last_info

        def _addstr(pad, y, x, s, *args):
            if len(s) + x >= width - pad:
                s = s[:max(0, width - x - 2 - pad)] + ".."
            self.stdscr.addstr(y, x, s, *args)

        def addstr_main(y, x, s, *args):
            _addstr(0, y, x, s, *args)

        def addstr_box(y, x, s, *args):
            _addstr(2, y, x, s, *args)

        try:
            x = max(0, width // 2 - len(title) // 2)
            addstr_main(0, x, title, curses.A_BOLD)
            if height <= 1:
                return
            server_info = self.slidictget("server")
            build = self.slidictget("server", "build")
            vstr = caps_to_version(build)
            mode = server_info.strget("mode", "server")
            python_info = typedict(server_info.dictget("python", {}))
            bits = python_info.intget("bits", 32)
            server_str = "Xpra %s server version %s %i-bit" % (mode, vstr,
                                                               bits)
            proxy_info = self.slidictget("proxy")
            if proxy_info:
                proxy_platform_info = typedict(
                    proxy_info.dictget("platform", {}))
                proxy_platform = proxy_platform_info.strget("")
                proxy_release = proxy_platform_info.strget("release")
                proxy_build_info = typedict(proxy_info.dictget("build", {}))
                proxy_version = proxy_build_info.strget("version")
                proxy_distro = proxy_info.strget("linux_distribution")
                server_str += " via: %s proxy version %s" % (platform_name(
                    proxy_platform, proxy_distro
                    or proxy_release), std(proxy_version or "unknown"))
            addstr_main(1, 0, server_str)
            if height <= 2:
                return
            #load and uptime:
            now = datetime.now()
            uptime = ""
            elapsed_time = server_info.intget("elapsed_time")
            if elapsed_time:
                td = timedelta(seconds=elapsed_time)
                uptime = " up %s" % str(td).lstrip("0:")
            clients_info = self.slidictget("clients")
            nclients = clients_info.intget("")
            load_average = ""
            load = sli.inttupleget("load")
            if load and len(load) == 3:
                float_load = tuple(v / 1000.0 for v in load)
                load_average = ", load average: %1.2f, %1.2f, %1.2f" % float_load
            addstr_main(
                2, 0, "xpra top - %s%s, %2i users%s" %
                (now.strftime("%H:%M:%S"), uptime, nclients, load_average))
            if height <= 3:
                return
            thread_info = self.slidictget("threads")
            rinfo = "%i threads" % thread_info.intget("count")
            server_pid = server_info.intget("pid", 0)
            if server_pid:
                rinfo += ", pid %i" % server_pid
                machine_id = server_info.get("machine-id")
                if machine_id is None or machine_id == get_machine_id():
                    try:
                        process = self.psprocess.get(server_pid)
                        if not process:
                            import psutil
                            process = psutil.Process(server_pid)
                            self.psprocess[server_pid] = process
                        else:
                            cpu = process.cpu_percent()
                            rinfo += ", %i%% CPU" % (cpu)
                    except Exception:
                        pass
            cpuinfo = self.slidictget("cpuinfo")
            if cpuinfo:
                rinfo += ", %s" % cpuinfo.strget("hz_actual")
            elapsed = monotonic_time() - self.server_last_info_time
            color = WHITE
            if self.server_last_info_time == 0:
                rinfo += " - no server data"
            elif elapsed > 2:
                rinfo += " - last updated %i seconds ago" % elapsed
                color = RED
            addstr_main(3, 0, rinfo, curses.color_pair(color))
            if height <= 4:
                return
            #display:
            dinfo = []
            server = self.slidictget("server")
            rws = server.intpair("root_window_size", None)
            if rws:
                sinfo = "%ix%i display" % (rws[0], rws[1])
                mds = server.intpair("max_desktop_size")
                if mds:
                    sinfo += " (max %ix%i)" % (mds[0], mds[1])
                dinfo.append(sinfo)
            cursor_info = self.slidictget("cursor")
            if cursor_info:
                cx, cy = cursor_info.inttupleget("position", (0, 0))
                dinfo.append("cursor at %ix%i" % (cx, cy))
            display_info = self.slidictget("display")
            pid = display_info.intget("pid")
            if pid:
                dinfo.append("pid %i" % pid)
            addstr_main(4, 0, csv(dinfo))
            if height <= 5:
                return
            hpos = 5
            gl_info = self.get_gl_info(display_info.dictget("opengl"))
            if gl_info:
                addstr_main(5, 0, gl_info)
                hpos += 1

            if hpos < height - 3:
                hpos += 1
                if nclients == 0:
                    addstr_main(hpos, 0, "no clients connected")
                else:
                    addstr_main(
                        hpos, 0,
                        "%i client%s connected:" % (nclients, engs(nclients)))
                hpos += 1
            client_info = self.slidictget("client")
            client_no = 0
            while True:
                ci = client_info.dictget(client_no)
                if not ci:
                    break
                client_no += 1
                ci = typedict(ci)
                session_id = ci.strget("session-id")
                if session_id:
                    #don't show ourselves:
                    if session_id == self.session_id:
                        continue
                elif not ci.boolget("windows", True):
                    #for older servers, hide any client that doesn't display windows:
                    continue
                ci = self.get_client_info(ci)
                l = len(ci)
                if hpos + 2 + l > height:
                    if hpos < height:
                        more = nclients - client_no
                        addstr_box(
                            hpos, 0,
                            "%i client%s not shown" % (more, engs(more)),
                            curses.A_BOLD)
                    break
                self.box(1, hpos, width - 2, 2 + l)
                for i, info in enumerate(ci):
                    info_text, color = info
                    cpair = curses.color_pair(color)
                    addstr_box(hpos + i + 1, 2, info_text, cpair)
                hpos += 2 + l

            windows = self.slidictget("windows")
            if hpos < height - 3:
                hpos += 1
                addstr_main(hpos, 0,
                            "%i window%s:" % (len(windows), engs(windows)))
                hpos += 1
            wins = tuple(windows.values())
            nwindows = len(wins)
            for win_no, win in enumerate(wins):
                wi = self.get_window_info(typedict(win))
                l = len(wi)
                if hpos + 2 + l > height:
                    if hpos < height:
                        more = nwindows - win_no
                        addstr_main(hpos, 0, "terminal window is too small: %i window%s not shown" % \
                                           (more, engs(more)), curses.A_BOLD)
                    break
                self.box(1, hpos, width - 2, 2 + l)
                for i, info in enumerate(wi):
                    info_text, color = info
                    cpair = curses.color_pair(color)
                    addstr_box(hpos + i + 1, 2, info_text, cpair)
                hpos += 2 + l
        except Exception as e:
            self.err(e)
示例#13
0
    def set_printers(self, printers, password_file, auth, encryption,
                     encryption_keyfile):
        log("set_printers(%s, %s, %s, %s, %s) for %s", printers, password_file,
            auth, encryption, encryption_keyfile, self)
        if self.machine_id == get_machine_id() and not ADD_LOCAL_PRINTERS:
            self.printers = printers
            log("local client with identical machine id,")
            log(" not configuring local printers")
            return
        if not self.uuid:
            log.warn("Warning: client did not supply a UUID,")
            log.warn(" printer forwarding cannot be enabled")
            return
        #remove the printers no longer defined
        #or those whose definition has changed (and we will re-add them):
        for k in tuple(self.printers.keys()):
            cpd = self.printers.get(k)
            npd = printers.get(k)
            if cpd == npd:
                #unchanged: make sure we don't try adding it again:
                try:
                    del printers[k]
                except KeyError:
                    pass
                continue
            if npd is None:
                log("printer %s no longer exists", k)
            else:
                log("printer %s has been modified:", k)
                log(" was %s", cpd)
                log(" now %s", npd)
            #remove it:
            try:
                del self.printers[k]
            except KeyError:
                pass
            self.remove_printer(k)
        #expand it here so the xpraforwarder doesn't need to import anything xpra:
        attributes = {
            "display": os.environ.get("DISPLAY"),
            "source": self.uuid
        }

        def makeabs(filename):
            #convert to an absolute path since the backend may run as a different user:
            return os.path.abspath(os.path.expanduser(filename))

        if auth:
            auth_password_file = None
            try:
                name, authclass, authoptions = auth
                auth_password_file = authoptions.get("file")
                log("file for %s / %s: '%s'", name, authclass, password_file)
            except Exception as e:
                log.error(
                    "Error: cannot forward authentication attributes to printer backend:"
                )
                log.error(" %s", e)
            if auth_password_file or password_file:
                attributes["password-file"] = makeabs(auth_password_file
                                                      or password_file)
        if encryption:
            if not encryption_keyfile:
                log.error("Error: no encryption keyfile found for printing")
            else:
                attributes["encryption"] = encryption
                attributes["encryption-keyfile"] = makeabs(encryption_keyfile)
        #if we can, tell it exactly where to connect:
        if self.unix_socket_paths:
            #prefer sockets in public paths:
            spath = self.unix_socket_paths[0]
            for x in self.unix_socket_paths:
                if x.startswith("/tmp") or x.startswith(
                        "/var") or x.startswith("/run"):
                    spath = x
            attributes["socket-path"] = spath
        log("printer attributes: %s", attributes)
        for k, props in printers.items():
            if k not in self.printers:
                self.setup_printer(k, props, attributes)
示例#14
0
 def remove_printers(self):
     if self.machine_id == get_machine_id() and not ADD_LOCAL_PRINTERS:
         return
     self.printers = {}
     for k in tuple(self.printers_added):
         self.remove_printer(k)
示例#15
0
 def make_hello_base(self):
     capabilities = flatten_dict(get_network_caps())
     #add "kerberos", "gss" and "u2f" digests if enabled:
     for handler in self.challenge_handlers:
         digest = handler.get_digest()
         if digest:
             capabilities["digest"].append(digest)
     capabilities.update(FilePrintMixin.get_caps(self))
     capabilities.update({
             "version"               : XPRA_VERSION,
             "websocket.multi-packet": True,
             "hostname"              : socket.gethostname(),
             "uuid"                  : self.uuid,
             "session-id"            : self.session_id,
             "username"              : self.username,
             "name"                  : get_name(),
             "client_type"           : self.client_type(),
             "python.version"        : sys.version_info[:3],
             "python.bits"           : BITS,
             "compression_level"     : self.compression_level,
             "argv"                  : sys.argv,
             })
     capabilities.update(self.get_file_transfer_features())
     if self.display:
         capabilities["display"] = self.display
     def up(prefix, d):
         updict(capabilities, prefix, d)
     up("build",     self.get_version_info())
     mid = get_machine_id()
     if mid:
         capabilities["machine_id"] = mid
     encryption = self.get_encryption()
     cryptolog("encryption=%s", encryption)
     if encryption:
         crypto_backend_init()
         enc, mode = (encryption+"-").split("-")[:2]
         if not mode:
             mode = DEFAULT_MODE
         assert enc in ENCRYPTION_CIPHERS, "invalid encryption '%s', options: %s" % (enc, csv(ENCRYPTION_CIPHERS))
         assert mode in MODES, "invalid encryption mode '%s', options: %s" % (mode, csv(MODES))
         iv = get_iv()
         key_salt = get_salt()
         iterations = get_iterations()
         padding = choose_padding(self.server_padding_options)
         cipher_caps = {
             ""                      : enc,
             "mode"                  : mode,
             "iv"                    : iv,
             "key_salt"              : key_salt,
             "key_size"              : DEFAULT_KEYSIZE,
             "key_hash"              : DEFAULT_KEY_HASH,
             "key_stretch"           : "PBKDF2",
             "key_stretch_iterations": iterations,
             "padding"               : padding,
             "padding.options"       : PADDING_OPTIONS,
             }
         cryptolog("cipher_caps=%s", cipher_caps)
         up("cipher", cipher_caps)
         key = self.get_encryption_key()
         self._protocol.set_cipher_in(encryption, iv, key,
                                      key_salt, DEFAULT_KEY_HASH, DEFAULT_KEYSIZE, iterations, padding)
     capabilities.update(self.hello_extra)
     return capabilities
示例#16
0
    def make_hello_base(self):
        capabilities = flatten_dict(get_network_caps())
        import struct
        bits = struct.calcsize("P") * 8
        capabilities.update({
                "version"               : XPRA_VERSION,
                "encoding.generic"      : True,
                "namespace"             : True,
                "hostname"              : socket.gethostname(),
                "uuid"                  : self.uuid,
                "username"              : self.username,
                "name"                  : get_name(),
                "client_type"           : self.client_type(),
                "python.version"        : sys.version_info[:3],
                "python.bits"           : bits,
                "compression_level"     : self.compression_level,
                "argv"                  : sys.argv,
                })
        capabilities.update(self.get_file_transfer_features())
        if self.display:
            capabilities["display"] = self.display
        def up(prefix, d):
            updict(capabilities, prefix, d)
        up("build",     self.get_version_info())
        mid = get_machine_id()
        if mid:
            capabilities["machine_id"] = mid
        #get socket speed if we have it:
        pinfo = self._protocol.get_info()
        netlog("protocol info=%s", pinfo)
        socket_speed = pinfo.get("socket", {}).get("speed")
        if socket_speed:
            capabilities["connection-data"] = {"speed" : socket_speed}
        bandwidth_limit = self.bandwidth_limit
        log("bandwidth-limit=%s, socket-speed=%s", self.bandwidth_limit, socket_speed)
        if bandwidth_limit is None:
            if socket_speed:
                #auto: use 80% of socket speed if we have it:
                bandwidth_limit = socket_speed*AUTO_BANDWIDTH_PCT//100 or 0
            else:
                bandwidth_limit = 0
        if bandwidth_limit>0:
            capabilities["bandwidth-limit"] = bandwidth_limit

        if self.encryption:
            assert self.encryption in ENCRYPTION_CIPHERS
            iv = get_iv()
            key_salt = get_salt()
            iterations = get_iterations()
            padding = choose_padding(self.server_padding_options)
            up("cipher", {
                    ""                      : self.encryption,
                    "iv"                    : iv,
                    "key_salt"              : key_salt,
                    "key_stretch_iterations": iterations,
                    "padding"               : padding,
                    "padding.options"       : PADDING_OPTIONS,
                    })
            key = self.get_encryption_key()
            if key is None:
                self.warn_and_quit(EXIT_ENCRYPTION, "encryption key is missing")
                return
            self._protocol.set_cipher_in(self.encryption, iv, key, key_salt, iterations, padding)
            netlog("encryption capabilities: %s", dict((k,v) for k,v in capabilities.items() if k.startswith("cipher")))
        capabilities.update(self.hello_extra)
        return capabilities