Esempio n. 1
0
 def _process_gibberish(self, packet):
     (_, message, data) = packet
     p = self._protocol
     show_as_text = p and p.input_packetcount==0 and all(c in string.printable for c in bytestostr(data))
     if show_as_text:
         #looks like the first packet back is just text, print it:
         data = bytestostr(data)
         if data.find("Traceback "):
             for x in data.split("\n"):
                 log.warn(x.strip("\r"))
         else:
             log.warn("Failed to connect, received: %s", repr_ellipsized(data.strip("\n").strip("\r")))
     else:
         log.warn("Received uninterpretable nonsense: %s", message)
         log.warn(" packet no %i data: %s", p.input_packetcount, repr_ellipsized(data))
     if str(data).find("assword")>0:
         self.warn_and_quit(EXIT_SSH_FAILURE,
                           "Your ssh program appears to be asking for a password."
                          + GOT_PASSWORD_PROMPT_SUGGESTION)
     elif str(data).find("login")>=0:
         self.warn_and_quit(EXIT_SSH_FAILURE,
                          "Your ssh program appears to be asking for a username.\n"
                          "Perhaps try using something like 'ssh:USER@host:display'?")
     else:
         self.quit(EXIT_PACKET_FAILURE)
Esempio n. 2
0
 def _copy_loop(self, log_name, from_conn, to_conn):
     #log("XpraProxy._copy_loop(%s, %s, %s)", log_name, from_conn, to_conn)
     try:
         while not self._closed:
             log("%s: waiting for data", log_name)
             buf = untilConcludes(self.is_active, noretry, from_conn.read,
                                  PROXY_BUFFER_SIZE)
             if not buf:
                 log("%s: connection lost", log_name)
                 return
             if SHOW_DATA:
                 log("%s: %s bytes: %s", log_name, len(buf),
                     repr_ellipsized(buf))
                 log("%s:           %s", log_name,
                     repr_ellipsized(hexstr(buf)))
             while buf and not self._closed:
                 log("%s: writing %s bytes", log_name, len(buf))
                 written = untilConcludes(self.is_active, noretry,
                                          to_conn.write, buf)
                 buf = buf[written:]
                 log("%s: written %s bytes", log_name, written)
         log("%s copy loop ended", log_name)
     except Exception as e:
         log("%s: %s", log_name, e)
     finally:
         self.quit()
Esempio n. 3
0
 def query_xkbmap(self):
     (
         self.xkbmap_layout,
         self.xkbmap_layouts,
         self.xkbmap_variant,
         self.xkbmap_variants,
         self.xkbmap_options,
     ) = self.get_layout_spec()
     self.xkbmap_print, self.xkbmap_query, self.xkbmap_query_struct = self.get_keymap_spec(
     )
     self.xkbmap_keycodes = self.get_full_keymap()
     self.xkbmap_x11_keycodes = self.keyboard.get_x11_keymap()
     (
         self.xkbmap_mod_meanings,
         self.xkbmap_mod_managed,
         self.xkbmap_mod_pointermissing,
     ) = self.keyboard.get_keymap_modifiers()
     self.update_hash()
     log("layout=%s, layouts=%s, variant=%s, variants=%s",
         self.xkbmap_layout, self.xkbmap_layouts, self.xkbmap_variant,
         self.xkbmap_variants)
     log("print=%s, query=%s, struct=%s", nonl(self.xkbmap_print),
         nonl(self.xkbmap_query), self.xkbmap_query_struct)
     log("keycodes=%s", repr_ellipsized(str(self.xkbmap_keycodes)))
     log("x11 keycodes=%s", repr_ellipsized(str(self.xkbmap_x11_keycodes)))
     log("mod managed: %s", self.xkbmap_mod_managed)
     log("mod meanings: %s", self.xkbmap_mod_meanings)
     log("mod pointermissing: %s", self.xkbmap_mod_pointermissing)
     log("hash=%s", self.hash)
Esempio n. 4
0
 def do_cmp_unmask(buf, hlen, plen):
     c = memoryview_to_bytes(hybi_unmask(buf, hlen, plen))
     w = numpy_unmask(buf, hlen, plen)
     assert w == c, "expected %s got %s" % (
         repr_ellipsized(binascii.hexlify(w)),
         repr_ellipsized(binascii.hexlify(c)),
     )
Esempio n. 5
0
 def __init__(self, uid, gid, env_options, session_options, socket_dir,
              video_encoder_modules, pings, client_conn, disp_desc,
              client_state, cipher, encryption_key, server_conn, caps,
              message_queue):
     ProxyInstance.__init__(self, session_options, video_encoder_modules,
                            pings, disp_desc, cipher, encryption_key, caps)
     QueueScheduler.__init__(self)
     Process.__init__(self, name=str(client_conn))
     self.client_conn = client_conn
     self.server_conn = server_conn
     self.uid = uid
     self.gid = gid
     self.env_options = env_options
     self.socket_dir = socket_dir
     self.client_state = client_state
     log("ProxyProcess%s",
         (uid, gid, env_options, session_options, socket_dir,
          video_encoder_modules, client_conn, disp_desc,
          repr_ellipsized(str(client_state)), cipher, encryption_key,
          server_conn, "%s: %s.." %
          (type(caps), repr_ellipsized(str(caps))), message_queue))
     self.message_queue = message_queue
     #for handling the local unix domain socket:
     self.control_socket_cleanup = None
     self.control_socket = None
     self.control_socket_thread = None
     self.control_socket_path = None
     self.potential_protocols = []
     self.max_connections = MAX_CONCURRENT_CONNECTIONS
Esempio n. 6
0
def peek_connection(conn, timeout=PEEK_TIMEOUT_MS):
    log = get_network_logger()
    log("peek_connection(%s, %i)", conn, timeout)
    PEEK_SIZE = 8192
    start = monotonic_time()
    peek_data = b""
    while not peek_data and int(1000*(monotonic_time()-start))<timeout:
        try:
            peek_data = conn.peek(PEEK_SIZE)
        except (OSError, IOError):
            pass
        except ValueError:
            log("peek_connection(%s, %i) failed", conn, timeout, exc_info=True)
            break
        if not peek_data:
            sleep(timeout/4000.0)
    line1 = b""
    log("socket %s peek: got %i bytes", conn, len(peek_data))
    set_socket_timeout(conn, PEEK_TIMEOUT_MS*1000)
    if peek_data:
        line1 = peek_data.splitlines()[0]
        log("socket peek=%s", repr_ellipsized(peek_data, limit=512))
        log("socket peek hex=%s", hexstr(peek_data[:128]))
        log("socket peek line1=%s", repr_ellipsized(bytestostr(line1)))
    return peek_data, line1
Esempio n. 7
0
 def _process_gibberish(self, packet):
     (_, message, data) = packet
     p = self._protocol
     show_as_text = p and p.input_packetcount == 0 and all(
         c in string.printable for c in bytestostr(data))
     if show_as_text:
         #looks like the first packet back is just text, print it:
         data = bytestostr(data)
         if data.find("Traceback "):
             for x in data.split("\n"):
                 log.warn(x.strip("\r"))
         else:
             log.warn("Failed to connect, received: %s",
                      repr_ellipsized(data.strip("\n").strip("\r")))
     else:
         log.warn("Received uninterpretable nonsense: %s", message)
         log.warn(" packet no %i data: %s", p.input_packetcount,
                  repr_ellipsized(data))
     if str(data).find("assword") > 0:
         self.warn_and_quit(
             EXIT_SSH_FAILURE,
             "Your ssh program appears to be asking for a password." +
             GOT_PASSWORD_PROMPT_SUGGESTION)
     elif str(data).find("login") >= 0:
         self.warn_and_quit(
             EXIT_SSH_FAILURE,
             "Your ssh program appears to be asking for a username.\n"
             "Perhaps try using something like 'ssh:USER@host:display'?")
     else:
         self.quit(EXIT_PACKET_FAILURE)
Esempio n. 8
0
 def _process_setting_change(self, packet):
     setting, value = packet[1:3]
     setting = bytestostr(setting)
     #convert "hello" / "setting" variable names to client variables:
     if setting in (
         "clipboard-limits",
         ):
         pass
     elif setting in (
         "bell", "randr", "cursors", "notifications", "dbus-proxy", "clipboard",
         "clipboard-direction", "session_name",
         "sharing", "sharing-toggle", "lock", "lock-toggle",
         "start-new-commands", "client-shutdown", "webcam",
         "bandwidth-limit", "clipboard-limits",
         "xdg-menu",
         ):
         setattr(self, "server_%s" % setting.replace("-", "_"), value)
     else:
         log.info("unknown server setting changed: %s=%s", setting, repr_ellipsized(bytestostr(value)))
         return
     log("_process_setting_change: %s=%s", setting, value)
     #xdg-menu is too big to log, and we have to update our attribute:
     if setting=="xdg-menu":
         self.server_xdg_menu = value
     else:
         log.info("server setting changed: %s=%s", setting, repr_ellipsized(value))
     self.server_setting_changed(setting, value)
Esempio n. 9
0
 def _process_gibberish(self, packet):
     log("process_gibberish(%s)", ellipsizer(packet))
     message, data = packet[1:3]
     p = self._protocol
     show_as_text = p and p.input_packetcount == 0 and len(
         data) < 128 and all(c in string.printable
                             for c in bytestostr(data))
     if show_as_text:
         #looks like the first packet back is just text, print it:
         data = bytestostr(data)
         if data.find("\n") >= 0:
             for x in data.splitlines():
                 netlog.warn(x)
         else:
             netlog.error("Error: failed to connect, received")
             netlog.error(" %s", repr_ellipsized(data))
     else:
         from xpra.net.socket_util import guess_packet_type
         packet_type = guess_packet_type(data)
         log("guess_packet_type(%r)=%s", data, packet_type)
         if packet_type and packet_type != "xpra":
             netlog.error("Error: received a %s packet", packet_type)
             netlog.error(" this is not an xpra server?")
         else:
             netlog.error("Error: received uninterpretable nonsense: %s",
                          message)
         if p:
             netlog.error(" packet no %i data: %s", p.input_packetcount,
                          repr_ellipsized(data))
         else:
             netlog.error(" data: %s", repr_ellipsized(data))
     self.quit(EXIT_PACKET_FAILURE)
Esempio n. 10
0
    def start_tcp_proxy(self, proto, data):
        log("start_tcp_proxy(%s, %s)", proto, data[:10])
        #any buffers read after we steal the connection will be placed in this temporary queue:
        temp_read_buffer = Queue()
        client_connection = proto.steal_connection(temp_read_buffer.put)
        try:
            self._potential_protocols.remove(proto)
        except:
            pass  #might already have been removed by now
        #connect to web server:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(10)
        host, port = self._tcp_proxy.split(":", 1)
        try:
            web_server_connection = _socket_connect(sock, (host, int(port)),
                                                    "web-proxy-for-%s" % proto,
                                                    "tcp")
        except:
            log.warn("failed to connect to proxy: %s:%s", host, port)
            proto.gibberish("invalid packet header", data)
            return
        log("proxy connected to tcp server at %s:%s : %s", host, port,
            web_server_connection)
        sock.settimeout(self._socket_timeout)

        ioe = proto.wait_for_io_threads_exit(0.5 + self._socket_timeout)
        if not ioe:
            log.warn("proxy failed to stop all existing network threads!")
            self.disconnect_protocol(proto, "internal threading error")
            return
        #now that we own it, we can start it again:
        client_connection.set_active(True)
        #and we can use blocking sockets:
        self.set_socket_timeout(client_connection, None)
        #prevent deadlocks on exit:
        sock.settimeout(1)

        log("pushing initial buffer to its new destination: %s",
            repr_ellipsized(data))
        web_server_connection.write(data)
        while not temp_read_buffer.empty():
            buf = temp_read_buffer.get()
            if buf:
                log("pushing read buffer to its new destination: %s",
                    repr_ellipsized(buf))
                web_server_connection.write(buf)
        p = XpraProxy(client_connection, web_server_connection)
        self._tcp_proxy_clients.append(p)

        def run_proxy():
            p.run()
            log("run_proxy() %s ended", p)
            if p in self._tcp_proxy_clients:
                self._tcp_proxy_clients.remove(p)

        t = make_daemon_thread(run_proxy, "web-proxy-for-%s" % proto)
        t.start()
        log.info("client %s forwarded to proxy server %s:%s",
                 client_connection, host, port)
Esempio n. 11
0
    def start_tcp_proxy(self, proto, data):
        proxylog("start_tcp_proxy(%s, '%s')", proto, repr_ellipsized(data))
        try:
            self._potential_protocols.remove(proto)
        except:
            pass  # might already have been removed by now
        proxylog("start_tcp_proxy: protocol state before stealing: %s", proto.get_info(alias_info=False))
        # any buffers read after we steal the connection will be placed in this temporary queue:
        temp_read_buffer = Queue()
        client_connection = proto.steal_connection(temp_read_buffer.put)
        # connect to web server:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(10)
        host, port = self._tcp_proxy.split(":", 1)
        try:
            web_server_connection = _socket_connect(sock, (host, int(port)), "web-proxy-for-%s" % proto, "tcp")
        except:
            proxylog.warn("failed to connect to proxy: %s:%s", host, port)
            proto.gibberish("invalid packet header", data)
            return
        proxylog("proxy connected to tcp server at %s:%s : %s", host, port, web_server_connection)
        sock.settimeout(self._socket_timeout)

        ioe = proto.wait_for_io_threads_exit(0.5 + self._socket_timeout)
        if not ioe:
            proxylog.warn("proxy failed to stop all existing network threads!")
            self.disconnect_protocol(proto, "internal threading error")
            return
        # now that we own it, we can start it again:
        client_connection.set_active(True)
        # and we can use blocking sockets:
        self.set_socket_timeout(client_connection, None)
        # prevent deadlocks on exit:
        sock.settimeout(1)

        proxylog("pushing initial buffer to its new destination: %s", repr_ellipsized(data))
        web_server_connection.write(data)
        while not temp_read_buffer.empty():
            buf = temp_read_buffer.get()
            if buf:
                proxylog("pushing read buffer to its new destination: %s", repr_ellipsized(buf))
                web_server_connection.write(buf)
        p = XpraProxy(client_connection.target, client_connection, web_server_connection)
        self._tcp_proxy_clients.append(p)
        proxylog.info(
            "client connection from %s forwarded to proxy server on %s:%s", client_connection.target, host, port
        )
        p.run()
        proxylog("run_proxy() %s ended", p)
        if p in self._tcp_proxy_clients:
            self._tcp_proxy_clients.remove(p)
Esempio n. 12
0
 def __init__(self, uid, gid, env_options, session_options, socket_dir,
              video_encoder_modules, csc_modules, client_conn, disp_desc,
              client_state, cipher, encryption_key, server_conn, caps,
              message_queue):
     Process.__init__(self, name=str(client_conn))
     self.uid = uid
     self.gid = gid
     self.env_options = env_options
     self.session_options = session_options
     self.socket_dir = socket_dir
     self.video_encoder_modules = video_encoder_modules
     self.csc_modules = csc_modules
     self.client_conn = client_conn
     self.disp_desc = disp_desc
     self.client_state = client_state
     self.cipher = cipher
     self.encryption_key = encryption_key
     self.server_conn = server_conn
     self.caps = caps
     log("ProxyProcess%s",
         (uid, gid, env_options, session_options, socket_dir,
          video_encoder_modules, csc_modules, client_conn, disp_desc,
          repr_ellipsized(str(client_state)), cipher, encryption_key,
          server_conn, "%s: %s.." %
          (type(caps), repr_ellipsized(str(caps))), message_queue))
     self.client_protocol = None
     self.server_protocol = None
     self.exit = False
     self.main_queue = None
     self.message_queue = message_queue
     self.encode_queue = None  #holds draw packets to encode
     self.encode_thread = None
     self.video_encoding_defs = None
     self.video_encoders = None
     self.video_encoders_last_used_time = None
     self.video_encoder_types = None
     self.video_helper = None
     self.lost_windows = None
     #for handling the local unix domain socket:
     self.control_socket_cleanup = None
     self.control_socket = None
     self.control_socket_thread = None
     self.control_socket_path = None
     self.potential_protocols = []
     self.max_connections = MAX_CONCURRENT_CONNECTIONS
     self.timer_id = AtomicInteger()
     self.timers = {}
     self.timer_lock = RLock()
Esempio n. 13
0
    def show_notify(self, dbus_id, tray, nid, app_name, replaces_nid, app_icon,
                    summary, body, actions, hints, expire_timeout, icon):
        if not self.dbus_check(dbus_id):
            return
        self.may_retry = True
        try:
            icon_string = self.get_icon_string(nid, app_icon, icon)
            log("get_icon_string%s=%s",
                (nid, app_icon, repr_ellipsized(str(icon))), icon_string)
            try:
                app_str = self.app_name_format % app_name
            except:
                app_str = app_name or "Xpra"
            self.last_notification = (dbus_id, tray, nid, app_name,
                                      replaces_nid, app_icon, summary, body,
                                      expire_timeout, icon)

            def NotifyReply(notification_id):
                log("NotifyReply(%s) for nid=%i", notification_id, nid)
                self.actual_notification_id[nid] = int(notification_id)

            dbus_hints = self.parse_hints(hints)
            self.dbusnotify.Notify(app_str,
                                   0,
                                   icon_string,
                                   summary,
                                   body,
                                   actions,
                                   dbus_hints,
                                   expire_timeout,
                                   reply_handler=NotifyReply,
                                   error_handler=self.NotifyError)
        except:
            log.error("Error: dbus notify failed", exc_info=True)
Esempio n. 14
0
def do_test_encoder(encoder, src_format, w, h, images, name="encoder", log=None, pause=0, after_encode_cb=None):
    start = time.time()
    tsize = 0
    client_options = {}
    for i, image in enumerate(images):
        log("image %i of %i, calling %s compress_image(%s)", i+1, len(images), encoder.get_type(), image)
        c = encoder.compress_image(image)
        assert c is not None, "no image!"
        data, client_options = c
        if not data:
            assert client_options.get("delayed", 0)>0
            continue
        tsize += len(data)
        log("data %6i bytes: %s" % (len(data), repr_ellipsized(str(data))))
        if pause>0:
            time.sleep(pause)
        if after_encode_cb:
            after_encode_cb(encoder)
    delayed = client_options.get("delayed", 0)
    if delayed>0:
        encoder.flush(delayed)
    end = time.time()
    #log.info("%s finished encoding %s frames at %sx%s, total encoding time: %.1fms" % (name, len(images), w, h, 1000.0*(end-start)))
    perf = int(len(images)*w*h/(end-start)/1024/1024)
    tpf = int(1000*(end-start)/len(images))
    sized = "%sx%s" % (w, h)
    fsize = tsize/len(images)
    log.info("%60s finished encoding %3s %7s frames at %10s: %4s MPixels/s, %4sms/frame, %8sKB/frame (%s)",
             encoder, len(images), src_format, sized, perf, tpf, fsize//1024, encoder.get_info().get("pixel_format"))
Esempio n. 15
0
 def invalid_header(self, proto, data):
     log("invalid_header(%s, %s)", proto, repr_ellipsized(data))
     if proto.input_packetcount==0 and self._tcp_proxy:
         self.start_tcp_proxy(proto, data)
         return
     err = "invalid packet format, not an xpra client?"
     proto.gibberish(err, data)
Esempio n. 16
0
 def _process_gibberish(self, packet):
     (_, message, data) = packet
     p = self._protocol
     show_as_text = p and p.input_packetcount==0 and all(c in string.printable for c in bytestostr(data))
     if show_as_text:
         #looks like the first packet back is just text, print it:
         data = bytestostr(data)
         if data.find("Traceback ")>=0:
             for x in data.split("\n"):
                 netlog.warn(x.strip("\r"))
         else:
             netlog.warn("Failed to connect, received: %s", repr_ellipsized(data.strip("\n").strip("\r")))
     else:
         netlog.warn("Received uninterpretable nonsense: %s", message)
         netlog.warn(" packet no %i data: %s", p.input_packetcount, repr_ellipsized(data))
     self.quit(EXIT_PACKET_FAILURE)
Esempio n. 17
0
def load_command_to_type():
    global command_to_type
    if command_to_type is None:
        command_to_type = {}
        from xpra.platform.xposix.xdg_helper import load_xdg_menu_data
        xdg_menu = load_xdg_menu_data()
        categories_to_type = load_categories_to_type()
        log("load_command_to_type() xdg_menu=%s, categories_to_type=%s", xdg_menu, categories_to_type)
        if xdg_menu and categories_to_type:
            for category, category_props in xdg_menu.items():
                log("category %s: %s", category, repr_ellipsized(str(category_props)))
                entries = category_props.get("Entries", {})
                for name, props in entries.items():
                    command = props.get("TryExec") or props.get("Exec")
                    categories = props.get("Categories")
                    log("Entry '%s': command=%s, categories=%s", name, command, categories)
                    if command and categories:
                        for c in categories:
                            ctype = categories_to_type.get(c.lower())
                            if not ctype:
                                #try a more fuzzy match:
                                for category_name,ct in categories_to_type.items():
                                    if c.lower().find(category_name)>=0:
                                        ctype = ct
                                        break
                            if ctype:
                                cmd = os.path.basename(command.split(" ")[0]).encode()
                                if cmd:
                                    command_to_type[cmd] = ctype
                                    break
        log("load_command_to_type()=%s", command_to_type)
    return command_to_type
Esempio n. 18
0
    def _process_logging(self, packet):
        assert not self.local_logging, "cannot receive logging packets when forwarding logging!"
        level, msg = packet[1:3]
        prefix = "server: "
        if len(packet) >= 4:
            dtime = packet[3]
            prefix += "@%02i.%03i " % ((dtime // 1000) % 60, dtime % 1000)

        def dec(x):
            try:
                return x.decode("utf8")
            except Exception:
                return bytestostr(x)

        try:
            if isinstance(msg, (tuple, list)):
                dmsg = " ".join(dec(x) for x in msg)
            else:
                dmsg = dec(msg)
            for l in dmsg.splitlines():
                self.do_log(level, prefix + l)
        except Exception as e:
            log("log message decoding error", exc_info=True)
            log.error("Error: failed to parse logging message:")
            log.error(" %s", repr_ellipsized(msg))
            log.error(" %s", e)
Esempio n. 19
0
 def _process_gibberish(self, packet):
     (_, message, data) = packet
     p = self._protocol
     show_as_text = p and p.input_packetcount==0 and all(c in string.printable for c in bytestostr(data))
     if show_as_text:
         #looks like the first packet back is just text, print it:
         data = bytestostr(data)
         if data.find("Traceback "):
             for x in data.split("\n"):
                 netlog.warn(x.strip("\r"))
         else:
             netlog.warn("Failed to connect, received: %s", repr_ellipsized(data.strip("\n").strip("\r")))
     else:
         netlog.warn("Received uninterpretable nonsense: %s", message)
         netlog.warn(" packet no %i data: %s", p.input_packetcount, repr_ellipsized(data))
     self.quit(EXIT_PACKET_FAILURE)
Esempio n. 20
0
 def _send_clipboard_token_handler(self, proxy, packet_data=()):
     if log.is_debug_enabled():
         log("_send_clipboard_token_handler(%s, %s)", proxy,
             repr_ellipsized(packet_data))
     remote = self.local_to_remote(proxy._selection)
     packet = ["clipboard-token", remote]
     if packet_data:
         #append 'TARGETS' unchanged:
         packet.append(packet_data[0])
         #if present, the next element is the target data,
         #which we have to convert to wire format:
         if len(packet_data) >= 2:
             target, dtype, dformat, data = packet_data[1]
             wire_encoding, wire_data = self._munge_raw_selection_to_wire(
                 target, dtype, dformat, data)
             if wire_encoding:
                 wire_data = self._may_compress(dtype, dformat, wire_data)
                 if wire_data:
                     packet += [
                         target, dtype, dformat, wire_encoding, wire_data
                     ]
                     claim = proxy._can_send
                     packet += [claim, CLIPBOARD_GREEDY]
     log("send_clipboard_token_handler %s to %s", proxy._selection, remote)
     self.send(*packet)
Esempio n. 21
0
 def __init__(self, session_options, video_encoder_modules, pings,
              disp_desc, cipher, encryption_key, caps):
     self.session_options = session_options
     self.video_encoder_modules = video_encoder_modules
     self.pings = pings
     self.disp_desc = disp_desc
     self.cipher = cipher
     self.encryption_key = encryption_key
     self.caps = caps
     log("ProxyInstance%s", (session_options, video_encoder_modules,
                             disp_desc, cipher, encryption_key, "%s: %s.." %
                             (type(caps), repr_ellipsized(str(caps)))))
     self.uuid = get_hex_uuid()
     self.client_protocol = None
     self.server_protocol = None
     #ping handling:
     self.client_last_ping = 0
     self.server_last_ping = 0
     self.client_last_ping_echo = 0
     self.server_last_ping_echo = 0
     self.client_last_ping_latency = 0
     self.server_last_ping_latency = 0
     self.client_ping_timer = None
     self.server_ping_timer = None
     self.client_challenge_packet = None
     self.exit = False
     self.lost_windows = None
     self.encode_queue = None  #holds draw packets to encode
     self.encode_thread = None
     self.video_encoding_defs = None
     self.video_encoders = None
     self.video_encoders_last_used_time = None
     self.video_encoder_types = None
     self.video_helper = None
Esempio n. 22
0
 def log_message(self, fmt, *args):
     if args and len(
             args) == 3 and fmt == '"%s" %s %s' and args[1] == "400":
         fmt = '"%r" %s %s'
         args = list(args)
         args[0] = repr_ellipsized(args[0])
     log(fmt, *args)
Esempio n. 23
0
 def get_text():
     data_handle = GetClipboardData(win32con.CF_UNICODETEXT)
     if not data_handle:
         errback("no data handle")
         return
     data = GlobalLock(data_handle)
     if not data:
         errback("failed to lock handle")
         return
     try:
         wstr = cast(data, LPCWSTR)
         ulen = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, None, 0, None, None)
         if ulen>MAX_CLIPBOARD_PACKET_SIZE:
             errback("too much data")
             return
         buf = create_string_buffer(ulen)
         l = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, byref(buf), ulen, None, None)
         if l>0:
             if buf.raw[l-1:l]==b"\0":
                 s = buf.raw[:l-1]
             else:
                 s = buf.raw[:l]
             log("got %i bytes of data: %s", len(s), repr_ellipsized(str(s)))
             callback(strtobytes(s))
         else:
             errback("failed to convert to UTF8: %s" % FormatError(get_last_error()))
     finally:
         GlobalUnlock(data)
Esempio n. 24
0
 def set_selection_response(self,
                            requestor,
                            target,
                            prop,
                            dtype,
                            dformat,
                            data,
                            time=0):
     log("set_selection_response(%s, %s, %s, %s, %s, %r, %i)",
         requestor, target, prop, dtype, dformat,
         repr_ellipsized(bytestostr(data)), time)
     #answer the selection request:
     try:
         with xsync:
             xid = get_xwindow(requestor)
             if data is not None:
                 X11Window.XChangeProperty(xid, prop, dtype, dformat, data)
             else:
                 #maybe even delete the property?
                 #X11Window.XDeleteProperty(xid, prop)
                 prop = None
             X11Window.sendSelectionNotify(xid, self._selection, target,
                                           prop, time)
     except XError as e:
         log("failed to set selection", exc_info=True)
         log.warn("Warning: failed to set selection for target '%s'",
                  target)
         log.warn(" on requestor %s", self.get_wininfo(xid))
         log.warn(" property '%s'", prop)
         log.warn(" %s", e)
Esempio n. 25
0
 def invalid_header(self, proto, data):
     log("invalid_header(%s, %s)", proto, repr_ellipsized(data))
     if proto.input_packetcount == 0 and self._tcp_proxy:
         self.start_tcp_proxy(proto, data)
         return
     err = "invalid packet format, not an xpra client?"
     proto.gibberish(err, data)
Esempio n. 26
0
 def _process_logging(self, proto, packet):
     assert self.remote_logging_receive
     ss = self.get_server_source(proto)
     if ss is None:
         return
     level, msg = packet[1:3]
     prefix = "client "
     counter = getattr(ss, "counter", 0)
     if counter>0:
         prefix += "%3i " % counter
     if len(packet)>=4:
         dtime = packet[3]
         prefix += "@%02i.%03i " % ((dtime//1000)%60, dtime%1000)
     def dec(x):
         try:
             return x.decode("utf8")
         except Exception:
             return bytestostr(x)
     try:
         if isinstance(msg, (tuple, list)):
             dmsg = " ".join(dec(x) for x in msg)
         else:
             dmsg = dec(msg)
         for l in dmsg.splitlines():
             self.do_log(level, prefix+l)
     except Exception as e:
         log("log message decoding error", exc_info=True)
         log.error("Error: failed to parse logging message:")
         log.error(" %s", repr_ellipsized(msg))
         log.error(" %s", e)
Esempio n. 27
0
def get_workarea():
    if not is_Wayland():
        try:
            d = get_current_desktop()
            if d < 0:
                return None
            workarea = _get_X11_root_property("_NET_WORKAREA", "CARDINAL")
            if not workarea:
                return None
            screenlog("get_workarea() _NET_WORKAREA=%s (%s), len=%s",
                      repr_ellipsized(workarea), type(workarea), len(workarea))
            #workarea comes as a list of 4 CARDINAL dimensions (x,y,w,h), one for each desktop
            sizeof_long = struct.calcsize(b"@L")
            if len(workarea) < (d + 1) * 4 * sizeof_long:
                screenlog.warn("get_workarea() invalid _NET_WORKAREA value")
            else:
                cur_workarea = workarea[d * 4 * sizeof_long:(d + 1) * 4 *
                                        sizeof_long]
                v = struct.unpack(b"@LLLL", cur_workarea)
                screenlog("get_workarea() %s=%s", hexstr(cur_workarea), v)
                return v
        except Exception as e:
            screenlog("get_workarea()", exc_info=True)
            screenlog.warn("Warning: failed to query workarea: %s", e)
    return None
Esempio n. 28
0
 def class_run_command(cls, command, **kwargs):
     if "env" not in kwargs:
         kwargs["env"] = cls.get_default_run_env()
     stdout_file = stderr_file = None
     if isinstance(command, (list, tuple)):
         strcommand = " ".join("'%s'" % x for x in command)
     else:
         strcommand = command
     if XPRA_TEST_DEBUG:
         log("************************")
         log("class_run_command(%s, %s)", command,
             repr_ellipsized(str(kwargs), 80))
         log("************************")
     else:
         if "stdout" not in kwargs:
             stdout_file = cls._temp_file(prefix="xpra-stdout-")
             kwargs["stdout"] = stdout_file
             log("stdout: %s for %s", stdout_file.name, strcommand)
         if "stderr" not in kwargs:
             stderr_file = cls._temp_file(prefix="xpra-stderr-")
             kwargs["stderr"] = stderr_file
             log("stderr: %s for %s", stderr_file.name, strcommand)
     try:
         log("class_run_command%s", (command, kwargs))
         proc = subprocess.Popen(args=command, **kwargs)
         proc.command = command
         proc.stdout_file = stdout_file
         proc.stderr_file = stderr_file
     except OSError as e:
         log.warn("class_run_command(%s, %s) %s", command, kwargs, e)
         raise
     cls.processes.append(proc)
     return proc
Esempio n. 29
0
 def server_connection_established(self, caps):
     self.log("server_connection_established(%s)" % repr_ellipsized(caps))
     self.log("traceback: %s" % (traceback.extract_stack(), ))
     r = super().server_connection_established(caps)
     self.stdscr = curses_init()
     self.update_screen()
     return r
Esempio n. 30
0
 def unexpected_packet(packet):
     if packet:
         log.warn("Warning: received an unexpected packet")
         log.warn(" from the proxy connection %s:",
                  client_proto)
         log.warn(" %s", repr_ellipsized(packet))
         client_proto.close()
Esempio n. 31
0
 def _process_gibberish(self, packet):
     log("process_gibberish(%s)", ellipsizer(packet))
     message, data = packet[1:3]
     from xpra.net.socket_util import guess_packet_type #pylint: disable=import-outside-toplevel
     packet_type = guess_packet_type(data)
     p = self._protocol
     exit_code = EXIT_PACKET_FAILURE
     pcount = p.input_packetcount if p else 0
     if pcount<=1:
         exit_code = EXIT_CONNECTION_FAILED
         netlog.error("Error: failed to connect")
     else:
         netlog.error("Error: received an invalid packet")
     if packet_type=="xpra":
         netlog.error(" xpra server bug or mangled packet")
     if packet_type and packet_type!="xpra":
         netlog.error(" this is a '%s' packet,", packet_type)
         netlog.error(" not from an xpra server?")
     else:
         netlog.error(" received uninterpretable nonsense: %r", message)
     data = bytestostr(data).strip("\n\r")
     show_as_text = pcount<=1 and len(data)<128 and all((c in string.printable) or c in ("\n\r") for c in data)
     if show_as_text:
         if data.find("\n")>=0:
             netlog.error(" data:")
             for x in data.split("\n"):
                 netlog.error("  %r", x.split("\0")[0])
         else:
             netlog.error(" data: %r", data)
     else:
         netlog.error(" packet no %i data: %s", pcount, nonl(repr_ellipsized(data)))
     self.quit(exit_code)
Esempio n. 32
0
 def invalid_header(self, _proto, data, msg="invalid packet header"):
     self._packet_parser = self._parse_invalid
     err = "%s: '%s'" % (msg, hexstr(data[:8]))
     if len(data) > 1:
         err += " read buffer=%s (%i bytes)" % (repr_ellipsized(data),
                                                len(data))
     self.invalid(err, data)
Esempio n. 33
0
 def run_command(self, command, env=None, **kwargs):
     if env is None:
         env = kwargs.get("env") or self.get_run_env()
     kwargs["env"] = env
     stdout_file = stderr_file = None
     if isinstance(command, (list, tuple)):
         strcommand = " ".join("'%s'" % x for x in command)
     else:
         strcommand = command
     if XPRA_TEST_DEBUG:
         log("************************")
         log("run_command(%s, %s)", command, repr_ellipsized(str(env), 40))
         log("************************")
     else:
         if "stdout" not in kwargs:
             stdout_file = self._temp_file(prefix="xpra-stdout-")
             kwargs["stdout"] = stdout_file
             log("stdout: %s for %s", stdout_file.name, strcommand)
         if "stderr" not in kwargs:
             stderr_file = self._temp_file(prefix="xpra-stderr-")
             kwargs["stderr"] = stderr_file
             log("stderr: %s for %s", stderr_file.name, strcommand)
     try:
         proc = subprocess.Popen(args=command, **kwargs)
         proc.command = command
         proc.stdout_file = stdout_file
         proc.stderr_file = stderr_file
     except OSError as e:
         log.warn("run_command(%s, %s, %s) %s", command, env, kwargs, e)
         raise
     self.processes.append(proc)
     return proc
Esempio n. 34
0
 def _process_notify_show(self, packet):
     if not self.notifications_enabled:
         log("process_notify_show: ignoring packet, notifications are disabled")
         return
     self._ui_event()
     dbus_id, nid, app_name, replaces_nid, app_icon, summary, body, expire_timeout = packet[1:9]
     icon, actions, hints = None, [], {}
     if len(packet)>=10:
         icon = packet[9]
     if len(packet)>=12:
         actions, hints = packet[10], packet[11]
     #note: if the server doesn't support notification forwarding,
     #it can still send us the messages (via xpra control or the dbus interface)
     log("_process_notify_show(%s) notifier=%s, server_notifications=%s", repr_ellipsized(str(packet)), self.notifier, self.server_notifications)
     log("notification actions=%s, hints=%s", actions, hints)
     assert self.notifier
     #this one of the few places where we actually do care about character encoding:
     try:
         summary = summary.decode("utf8")
     except:
         summary = bytestostr(summary)
     try:
         body = body.decode("utf8")
     except:
         body = bytestostr(body)
     app_name = bytestostr(app_name)
     tray = self.get_tray_window(app_name, hints)
     log("get_tray_window(%s)=%s", app_name, tray)
     self.notifier.show_notify(dbus_id, tray, nid, app_name, replaces_nid, app_icon, summary, body, actions, hints, expire_timeout, icon)
Esempio n. 35
0
	def test_ssl_socket(self):
		server = None
		display_no = self.find_free_display_no()
		display = ":%s" % display_no
		tcp_port = get_free_tcp_port()
		ssl_port = get_free_tcp_port()
		try:
			tmpdir = tempfile.mkdtemp(suffix='ssl-xpra')
			certfile = os.path.join(tmpdir, "self.pem")
			openssl_command = [
								"openssl", "req", "-new", "-newkey", "rsa:4096", "-days", "2", "-nodes", "-x509",
								"-subj", "/C=US/ST=Denial/L=Springfield/O=Dis/CN=localhost",
    							"-keyout", certfile, "-out", certfile,
    							]
			openssl = self.run_command(openssl_command)
			assert pollwait(openssl, 10)==0, "openssl certificate generation failed"
			cert_data = load_binary_file(certfile)
			log("generated cert data: %s", repr_ellipsized(cert_data))
			if not cert_data:
				#cannot run openssl? (happens from rpmbuild)
				log.warn("SSL test skipped, cannot run '%s'", b" ".join(openssl_command))
				return
			server_args = [
							"--bind-tcp=0.0.0.0:%i" % tcp_port,
							"--bind-ssl=0.0.0.0:%i" % ssl_port,
							"--ssl=on",
							"--ssl-cert=%s" % certfile]

			log("starting test ssl server on %s", display)
			server = self.start_server(display, *server_args)

			#test it with openssl client:
			for port in (tcp_port, ssl_port):
				openssl_verify_command = "openssl s_client -connect 127.0.0.1:%i -CAfile %s < /dev/null" % (port, certfile)
				openssl = self.run_command(openssl_verify_command, shell=True)
				assert pollwait(openssl, 10)==0, "openssl certificate verification failed"

			def test_connect(uri, exit_code, *client_args):
				cmd = ["info", uri] + list(client_args)
				client = self.run_xpra(cmd)
				r = pollwait(client, 5)
				if client.poll() is None:
					client.terminate()
				assert r==exit_code, "expected info client to return %s but got %s" % (exit_code, client.poll())
			noverify = "--ssl-server-verify-mode=none"
			#connect to ssl socket:
			test_connect("ssl/127.0.0.1:%i/" % ssl_port, EXIT_OK, noverify)
			#tcp socket should upgrade:
			test_connect("ssl/127.0.0.1:%i/" % tcp_port, EXIT_OK, noverify)
			#self signed cert should fail without noverify:
			test_connect("ssl/127.0.0.1:%i/" % ssl_port, EXIT_CONNECTION_LOST)
			test_connect("ssl/127.0.0.1:%i/" % tcp_port, EXIT_CONNECTION_LOST)

		finally:
			shutil.rmtree(tmpdir)
			if server:
				server.terminate()
Esempio n. 36
0
 def _copy_loop(self, log_name, from_conn, to_conn):
     #log("XpraProxy._copy_loop(%s, %s, %s)", log_name, from_conn, to_conn)
     try:
         while not self._closed:
             log("%s: waiting for data", log_name)
             buf = untilConcludes(self.is_active, from_conn.read, PROXY_BUFFER_SIZE)
             if not buf:
                 log("%s: connection lost", log_name)
                 return
             if SHOW_DATA:
                 log("%s: %s bytes: %s", log_name, len(buf), repr_ellipsized(buf))
                 log("%s:           %s", log_name, repr_ellipsized(binascii.hexlify(buf)))
             while buf and not self._closed:
                 log("%s: writing %s bytes", log_name, len(buf))
                 written = untilConcludes(self.is_active, to_conn.write, buf)
                 buf = buf[written:]
                 log("%s: written %s bytes", log_name, written)
     except Exception as e:
         log("%s: %s", log_name, e)
         self.quit()
Esempio n. 37
0
 def __init__(self, uid, gid, env_options, session_options, socket_dir,
              video_encoder_modules, csc_modules,
              client_conn, client_state, cipher, encryption_key, server_conn, caps, message_queue):
     Process.__init__(self, name=str(client_conn))
     self.uid = uid
     self.gid = gid
     self.env_options = env_options
     self.session_options = session_options
     self.socket_dir = socket_dir
     self.video_encoder_modules = video_encoder_modules
     self.csc_modules = csc_modules
     self.client_conn = client_conn
     self.client_state = client_state
     self.cipher = cipher
     self.encryption_key = encryption_key
     self.server_conn = server_conn
     self.caps = caps
     log("ProxyProcess%s", (uid, gid, env_options, session_options, socket_dir,
                            video_encoder_modules, csc_modules,
                            client_conn, repr_ellipsized(str(client_state)), cipher, encryption_key, server_conn,
                            "%s: %s.." % (type(caps), repr_ellipsized(str(caps))), message_queue))
     self.client_protocol = None
     self.server_protocol = None
     self.exit = False
     self.main_queue = None
     self.message_queue = message_queue
     self.encode_queue = None            #holds draw packets to encode
     self.encode_thread = None
     self.video_encoding_defs = None
     self.video_encoders = None
     self.video_encoders_last_used_time = None
     self.video_encoder_types = None
     self.video_helper = None
     self.lost_windows = None
     #for handling the local unix domain socket:
     self.control_socket_cleanup = None
     self.control_socket = None
     self.control_socket_thread = None
     self.control_socket_path = None
     self.potential_protocols = []
     self.max_connections = MAX_CONCURRENT_CONNECTIONS
Esempio n. 38
0
 def process_packet(self, proto, packet):
     command = bytestostr(packet[0])
     if command==Protocol.CONNECTION_LOST:
         log("connection-lost: %s, calling stop", packet[1:])
         self.net_stop()
         return
     elif command==Protocol.GIBBERISH:
         log.warn("gibberish received:")
         log.warn(" %s", repr_ellipsized(packet[1], limit=80))
         log.warn(" stopping")
         self.net_stop()
         return
     elif command=="stop":
         log("received stop message")
         self.net_stop()
         return
     elif command=="exit":
         log("received exit message")
         sys.exit(0)
         return
     #make it easier to hookup signals to methods:
     attr = command.replace("-", "_")
     if self.method_whitelist is not None and attr not in self.method_whitelist:
         log.warn("invalid command: %s (not in whitelist: %s)", attr, self.method_whitelist)
         return
     wo = self.wrapped_object
     if not wo:
         log("wrapped object is no more, ignoring method call '%s'", attr)
         return
     method = getattr(wo, attr, None)
     if not method:
         log.warn("unknown command: '%s'", attr)
         log.warn(" packet: '%s'", repr_ellipsized(str(packet)))
         return
     if DEBUG_WRAPPER:
         log("calling %s.%s%s", wo, attr, str(tuple(packet[1:]))[:128])
     self.idle_add(method, *packet[1:])
     INJECT_FAULT(proto)
Esempio n. 39
0
 def t(s, ev, remainder=""):
     try:
         rv, rr = self.decode(s)
         #print("decode(%s)=%s (%s)" % (s, rv, type(rv)))
         _cmp(rv, ev)
     except Exception as e:
         print("error on decoding of '%s'" % repr_ellipsized(s))
         raise e
     rrstr = s[rr:]
     assert rrstr == remainder, "expected remainder value '%s' but got %s" % (remainder, rrstr)
     # With gibberish added:
     g_str = s + "asdf"
     rv, rr = self.decode(g_str)
     _cmp(rv, ev)
     rrstr = g_str[rr:]
     assert rrstr.endswith("asdf")
Esempio n. 40
0
 def check_packet_size(size_to_check, packet_header):
     if self._closed:
         return False
     log(
         "check_packet_size(%s, 0x%s) limit is %s",
         size_to_check,
         repr_ellipsized(packet_header),
         self.max_packet_size,
     )
     if size_to_check > self.max_packet_size:
         msg = "packet size requested is %s but maximum allowed is %s" % (
             size_to_check,
             self.max_packet_size,
         )
         self.invalid(msg, packet_header)
     return False
Esempio n. 41
0
    def invalid_header(self, proto, data):
        netlog(
            "invalid_header(%s, %s bytes: '%s') input_packetcount=%s, tcp_proxy=%s",
            proto,
            len(data or ""),
            repr_ellipsized(data),
            proto.input_packetcount,
            self._tcp_proxy,
        )
        if proto.input_packetcount == 0 and self._tcp_proxy and not proto._closed:
            # start a new proxy in a thread
            def run_proxy():
                self.start_tcp_proxy(proto, data)

            t = make_daemon_thread(run_proxy, "web-proxy-for-%s" % proto)
            t.start()
            return
        err = "invalid packet format, not an xpra client?"
        proto.gibberish(err, data)
Esempio n. 42
0
 def encode(self, packet_in):
     """
     Given a packet (tuple or list of items), converts it for the wire.
     This method returns all the binary packets to send, as an array of:
     (index, compression_level and compression flags, binary_data)
     The index, if positive indicates the item to populate in the packet
     whose index is zero.
     ie: ["blah", [large binary data], "hello", 200]
     may get converted to:
     [
         (1, compression_level, [large binary data now zlib compressed]),
         (0,                 0, bencoded/rencoded(["blah", '', "hello", 200]))
     ]
     """
     packets = []
     packet = list(packet_in)
     level = self.compression_level
     size_check = LARGE_PACKET_SIZE
     min_comp_size = 378
     for i in range(1, len(packet)):
         item = packet[i]
         ti = type(item)
         if ti in (int, long, bool, dict, list, tuple):
             continue
         l = len(item)
         if ti == Uncompressed:
             # this is a marker used to tell us we should compress it now
             # (used by the client for clipboard data)
             item = item.compress()
             packet[i] = item
             ti = type(item)
             # (it may now be a "Compressed" item and be processed further)
         if ti in (Compressed, LevelCompressed):
             # already compressed data (usually pixels, cursors, etc)
             if not item.can_inline or l > INLINE_SIZE:
                 il = 0
                 if ti == LevelCompressed:
                     # unlike Compressed (usually pixels, decompressed in the paint thread),
                     # LevelCompressed is decompressed by the network layer
                     # so we must tell it how to do that and pass the level flag
                     il = item.level
                 packets.append((i, il, item.data))
                 packet[i] = ""
             else:
                 # data is small enough, inline it:
                 packet[i] = item.data
                 min_comp_size += l
                 size_check += l
         elif ti in (str, bytes) and level > 0 and l > LARGE_PACKET_SIZE:
             log.warn(
                 "found a large uncompressed item in packet '%s' at position %s: %s bytes", packet[0], i, len(item)
             )
             # add new binary packet with large item:
             cl, cdata = self._compress(item, level)
             packets.append((i, cl, cdata))
             # replace this item with an empty string placeholder:
             packet[i] = ""
         elif ti not in (str, bytes):
             log.warn("unexpected data type %s in %s packet: %s", ti, packet[0], repr_ellipsized(item))
     # now the main packet (or what is left of it):
     packet_type = packet[0]
     self.output_stats[packet_type] = self.output_stats.get(packet_type, 0) + 1
     if USE_ALIASES and self.send_aliases and packet_type in self.send_aliases:
         # replace the packet type with the alias:
         packet[0] = self.send_aliases[packet_type]
     try:
         main_packet, proto_version = self._encoder(packet)
     except Exception as e:
         if self._closed:
             return [], 0
         log.error("failed to encode packet: %s", packet, exc_info=True)
         # make the error a bit nicer to parse: undo aliases:
         packet[0] = packet_type
         self.verify_packet(packet)
         raise e
     if len(main_packet) > size_check and packet_in[0] not in self.large_packets:
         log.warn(
             "found large packet (%s bytes): %s, argument types:%s, sizes: %s, packet head=%s",
             len(main_packet),
             packet_in[0],
             [type(x) for x in packet[1:]],
             [len(str(x)) for x in packet[1:]],
             repr_ellipsized(packet),
         )
     # compress, but don't bother for small packets:
     if level > 0 and len(main_packet) > min_comp_size:
         cl, cdata = self._compress(main_packet, level)
         packets.append((0, cl, cdata))
     else:
         packets.append((0, 0, main_packet))
     return packets, proto_version
Esempio n. 43
0
 def _process_invalid(self, packet):
     (_, message, data) = packet
     log.info("Received invalid packet: %s", message)
     log(" data: %s", repr_ellipsized(data))
     self.quit(EXIT_PACKET_FAILURE)
Esempio n. 44
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:
                    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
            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
Esempio n. 45
0
 def gibberish(self, *args):
     log.warn("%s stopping on gibberish:", self.description)
     log.warn(" %s", repr_ellipsized(args[1], limit=80))
     self.stop()
Esempio n. 46
0
 def _process_invalid(self, protocol, packet):
     (_, message, data) = packet
     netlog("Received invalid packet: %s", message)
     netlog(" data: %s", repr_ellipsized(data))
     self.disconnect_client(protocol, message)
Esempio n. 47
0
 def _process_gibberish(self, proto, packet):
     (_, message, data) = packet
     netlog("Received uninterpretable nonsense from %s: %s", proto, message)
     netlog(" data: %s", repr_ellipsized(data))
     self.disconnect_client(proto, message)
Esempio n. 48
0
    def do_read_parse_thread_loop(self):
        """
            Process the individual network packets placed in _read_queue.
            Concatenate the raw packet data, then try to parse it.
            Extract the individual packets from the potentially large buffer,
            saving the rest of the buffer for later, and optionally decompress this data
            and re-construct the one python-object-packet from potentially multiple packets (see packet_index).
            The 8 bytes packet header gives us information on the packet index, packet size and compression.
            The actual processing of the packet is done via the callback process_packet_cb,
            this will be called from this parsing thread so any calls that need to be made
            from the UI thread will need to use a callback (usually via 'idle_add')
        """
        read_buffer = None
        payload_size = -1
        padding_size = 0
        packet_index = 0
        compression_level = False
        packet = None
        raw_packets = {}
        while not self._closed:
            buf = self._read_queue.get()
            if not buf:
                log("read thread: empty marker, exiting")
                self.idle_add(self.close)
                return
            if read_buffer:
                read_buffer = read_buffer + buf
            else:
                read_buffer = buf
            bl = len(read_buffer)
            while not self._closed:
                packet = None
                bl = len(read_buffer)
                if bl<=0:
                    break
                if payload_size<0:
                    if read_buffer[0] not in ("P", ord("P")):
                        self._invalid_header(read_buffer)
                        return
                    if bl<8:
                        break   #packet still too small
                    #packet format: struct.pack('cBBBL', ...) - 8 bytes
                    _, protocol_flags, compression_level, packet_index, data_size = unpack_header(read_buffer[:8])

                    #sanity check size (will often fail if not an xpra client):
                    if data_size>self.abs_max_packet_size:
                        self._invalid_header(read_buffer)
                        return

                    bl = len(read_buffer)-8
                    if protocol_flags & FLAGS_CIPHER:
                        if self.cipher_in_block_size==0 or not self.cipher_in_name:
                            cryptolog.warn("received cipher block but we don't have a cipher to decrypt it with, not an xpra client?")
                            self._invalid_header(read_buffer)
                            return
                        padding_size = self.cipher_in_block_size - (data_size % self.cipher_in_block_size)
                        payload_size = data_size + padding_size
                    else:
                        #no cipher, no padding:
                        padding_size = 0
                        payload_size = data_size
                    assert payload_size>0, "invalid payload size: %i" % payload_size
                    read_buffer = read_buffer[8:]

                    if payload_size>self.max_packet_size:
                        #this packet is seemingly too big, but check again from the main UI thread
                        #this gives 'set_max_packet_size' a chance to run from "hello"
                        def check_packet_size(size_to_check, packet_header):
                            if self._closed:
                                return False
                            log("check_packet_size(%s, 0x%s) limit is %s", size_to_check, repr_ellipsized(packet_header), self.max_packet_size)
                            if size_to_check>self.max_packet_size:
                                msg = "packet size requested is %s but maximum allowed is %s" % \
                                              (size_to_check, self.max_packet_size)
                                self.invalid(msg, packet_header)
                            return False
                        self.timeout_add(1000, check_packet_size, payload_size, read_buffer[:32])

                if bl<payload_size:
                    # incomplete packet, wait for the rest to arrive
                    break

                #chop this packet from the buffer:
                if len(read_buffer)==payload_size:
                    raw_string = read_buffer
                    read_buffer = ''
                else:
                    raw_string = read_buffer[:payload_size]
                    read_buffer = read_buffer[payload_size:]
                #decrypt if needed:
                data = raw_string
                if self.cipher_in and protocol_flags & FLAGS_CIPHER:
                    cryptolog("received %i %s encrypted bytes with %s padding", payload_size, self.cipher_in_name, padding_size)
                    data = self.cipher_in.decrypt(raw_string)
                    if padding_size > 0:
                        def debug_str(s):
                            try:
                                return binascii.hexlify(bytearray(s))
                            except:
                                return csv(list(str(s)))
                        # pad byte value is number of padding bytes added
                        padtext = pad(self.cipher_in_padding, padding_size)
                        if data.endswith(padtext):
                            cryptolog("found %s %s padding", self.cipher_in_padding, self.cipher_in_name)
                        else:
                            actual_padding = data[-padding_size:]
                            cryptolog.warn("Warning: %s decryption failed: invalid padding", self.cipher_in_name)
                            cryptolog(" data does not end with %s padding bytes %s", self.cipher_in_padding, debug_str(padtext))
                            cryptolog(" but with %s (%s)", debug_str(actual_padding), type(data))
                            cryptolog(" decrypted data: %s", debug_str(data[:128]))
                            return self._internal_error("%s encryption padding error - wrong key?" % self.cipher_in_name)
                        data = data[:-padding_size]
                #uncompress if needed:
                if compression_level>0:
                    try:
                        data = decompress(data, compression_level)
                    except InvalidCompressionException as e:
                        self.invalid("invalid compression: %s" % e, data)
                        return
                    except Exception as e:
                        ctype = compression.get_compression_type(compression_level)
                        log("%s packet decompression failed", ctype, exc_info=True)
                        msg = "%s packet decompression failed" % ctype
                        if self.cipher_in:
                            msg += " (invalid encryption key?)"
                        else:
                            #only include the exception text when not using encryption
                            #as this may leak crypto information:
                            msg += " %s" % e
                        return self.gibberish(msg, data)

                if self.cipher_in and not (protocol_flags & FLAGS_CIPHER):
                    self.invalid("unencrypted packet dropped", data)
                    return

                if self._closed:
                    return
                if packet_index>0:
                    #raw packet, store it and continue:
                    raw_packets[packet_index] = data
                    payload_size = -1
                    packet_index = 0
                    if len(raw_packets)>=4:
                        self.invalid("too many raw packets: %s" % len(raw_packets), data)
                        return
                    continue
                #final packet (packet_index==0), decode it:
                try:
                    packet = decode(data, protocol_flags)
                except InvalidPacketEncodingException as e:
                    self.invalid("invalid packet encoding: %s" % e, data)
                    return
                except ValueError as e:
                    etype = packet_encoding.get_packet_encoding_type(protocol_flags)
                    log.error("Error parsing %s packet:", etype)
                    log.error(" %s", e)
                    if self._closed:
                        return
                    log("failed to parse %s packet: %s", etype, binascii.hexlify(data[:128]))
                    log(" %s", e)
                    log(" data: %s", repr_ellipsized(data))
                    log(" packet index=%i, packet size=%i, buffer size=%s", packet_index, payload_size, bl)
                    self.gibberish("failed to parse %s packet" % etype, data)
                    return

                if self._closed:
                    return
                payload_size = -1
                padding_size = 0
                #add any raw packets back into it:
                if raw_packets:
                    for index,raw_data in raw_packets.items():
                        #replace placeholder with the raw_data packet data:
                        packet[index] = raw_data
                    raw_packets = {}

                packet_type = packet[0]
                if self.receive_aliases and type(packet_type)==int and packet_type in self.receive_aliases:
                    packet_type = self.receive_aliases.get(packet_type)
                    packet[0] = packet_type
                self.input_stats[packet_type] = self.output_stats.get(packet_type, 0)+1

                self.input_packetcount += 1
                log("processing packet %s", packet_type)
                self._process_packet_cb(self, packet)
                packet = None
                INJECT_FAULT(self)
Esempio n. 49
0
 def unexpected_packet(packet):
     if packet:
         log.warn("received an unexpected packet on the proxy connection: %s", repr_ellipsized(packet))
Esempio n. 50
0
 def invalid_header(self, proto, data):
     err = "invalid packet header: '%s'" % binascii.hexlify(data[:8])
     if len(data) > 1:
         err += " read buffer=%s" % repr_ellipsized(data)
     self.gibberish(err, data)
Esempio n. 51
0
 def unexpected_packet(packet):
     if packet:
         log.warn("Warning: received an unexpected packet on the proxy connection %s:", client_proto)
         log.warn(" %s", repr_ellipsized(packet))