Example #1
0
    def do_connect_builtin(self):
        self.set_sensitive(False)
        self.set_info_text("Connecting.")
        #cooked vars used by connect_or_fail
        params = {"type": xpra_opts.mode}
        if xpra_opts.mode == "ssh":
            remote_xpra = xpra_opts.remote_xpra.split()
            if xpra_opts.sockdir:
                remote_xpra.append("--socket-dir=%s" % xpra_opts.sockdir)
            params["remote_xpra"] = remote_xpra
            if xpra_opts.port:
                params["display"] = ":%s" % xpra_opts.port
                params["display_as_args"] = [params["display"]]
            else:
                params["display"] = "auto"
                params["display_as_args"] = []
            full_ssh = shlex.split(xpra_opts.ssh)
            password = xpra_opts.password
            username = xpra_opts.username
            host = xpra_opts.host
            upos = host.find("@")
            if upos >= 0:
                #found at sign: username@host
                username = host[:upos]
                host = host[upos + 1:]
                ppos = username.find(":")
                if ppos >= 0:
                    #found separator: username:password@host
                    password = username[ppos + 1:]
                    username = username[:ppos]
            if username:
                params["username"] = username
                full_ssh += ["-l", username]
            full_ssh += ["-T", host]
            params["full_ssh"] = full_ssh
            params["password"] = password
            params["display_name"] = "ssh:%s:%s" % (xpra_opts.host,
                                                    xpra_opts.port)
        elif xpra_opts.mode == "unix-domain":
            params["display"] = ":%s" % xpra_opts.port
            params["display_name"] = "unix-domain:%s" % xpra_opts.port
        else:
            #tcp:
            params["host"] = xpra_opts.host
            params["port"] = int(xpra_opts.port)
            params["display_name"] = "tcp:%s:%s" % (xpra_opts.host,
                                                    xpra_opts.port)

        #print("connect_or_fail(%s)" % params)
        self.set_info_text("Connecting...")
        try:
            conn = connect_to(params, self.set_info_text)
        except Exception, e:
            self.set_sensitive(True)
            self.set_info_color(True)
            self.set_info_text(str(e))
            return
Example #2
0
 def do_connect_builtin(self, params):
     self.exit_code = None
     self.set_info_text("Connecting.")
     self.set_sensitive(False)
     try:
         conn = connect_to(params, self.set_info_text, ssh_fail_cb=self.ssh_failed)
     except Exception, e:
         log.error("failed to connect", exc_info=True)
         self.handle_exception(e)
         return
Example #3
0
 def do_connect_builtin(self, params):
     self.exit_code = None
     self.set_info_text("Connecting.")
     self.set_sensitive(False)
     try:
         conn = connect_to(params, self.set_info_text, ssh_fail_cb=self.ssh_failed)
     except Exception, e:
         log.error("failed to connect", exc_info=True)
         self.handle_exception(e)
         return
Example #4
0
    def start_proxy(self, client_proto, c, auth_caps):
        assert client_proto.authenticator is not None

        #find the target server session:
        def disconnect(msg):
            self.send_disconnect(client_proto, msg)

        sessions = client_proto.authenticator.get_sessions()
        if sessions is None:
            disconnect("no sessions found")
            return
        debug("start_proxy(%s, {..}, %s) found sessions: %s", client_proto,
              auth_caps, sessions)
        uid, gid, displays, env_options, session_options = sessions
        #debug("unused options: %s, %s", env_options, session_options)
        if len(displays) == 0:
            disconnect("no displays found")
            return
        display = c.strget("display")
        proxy_virtual_display = os.environ["DISPLAY"]
        #ensure we don't loop back to the proxy:
        if proxy_virtual_display in displays:
            displays.remove(proxy_virtual_display)
        if display == proxy_virtual_display:
            disconnect("invalid display")
            return
        if display:
            if display not in displays:
                disconnect("display not found")
                return
        else:
            if len(displays) != 1:
                disconnect(
                    "please specify a display (more than one available)")
                return
            display = displays[0]

        debug("start_proxy(%s, {..}, %s) using server display at: %s",
              client_proto, auth_caps, display)

        def parse_error(*args):
            disconnect("invalid display string")
            log.warn("parse error on %s: %s", display, args)
            raise Exception("parse error on %s: %s" % (display, args))

        opts = make_defaults_struct()
        opts.username = c.strget("username")
        disp_desc = parse_display_name(parse_error, opts, display)
        debug("display description(%s) = %s", display, disp_desc)
        try:
            server_conn = connect_to(disp_desc)
        except Exception, e:
            log.error("cannot start proxy connection to %s: %s", disp_desc, e)
            disconnect("failed to connect to display")
            return
Example #5
0
	def do_connect_builtin(self):
		self.set_sensitive(False)
		self.set_info_text("Connecting.")
		#cooked vars used by connect_or_fail
		params = {"type"	: xpra_opts.mode}
		if xpra_opts.mode=="ssh":
			remote_xpra = xpra_opts.remote_xpra.split()
			if xpra_opts.sockdir:
				remote_xpra.append("--socket-dir=%s" % xpra_opts.sockdir)
			params["remote_xpra"] = remote_xpra
			if xpra_opts.port:
				params["display"] = ":%s" % xpra_opts.port
				params["display_as_args"] = [params["display"]]
			else:
				params["display"] = "auto"
				params["display_as_args"] = []
			full_ssh = shlex.split(xpra_opts.ssh)
			password = xpra_opts.password
			username = xpra_opts.username
			host = xpra_opts.host
			upos = host.find("@")
			if upos>=0:
				#found at sign: username@host
				username = host[:upos]
				host = host[upos+1:]
				ppos = username.find(":")
				if ppos>=0:
					#found separator: username:password@host
					password = username[ppos+1:]
					username = username[:ppos]
			if username:
				params["username"] = username
				full_ssh += ["-l", username]
			full_ssh += ["-T", host]
			params["full_ssh"] = full_ssh
			params["password"] = password
			params["display_name"] = "ssh:%s:%s" % (xpra_opts.host, xpra_opts.port)
		elif xpra_opts.mode=="unix-domain":
			params["display"] = ":%s" % xpra_opts.port
			params["display_name"] = "unix-domain:%s" % xpra_opts.port
		else:
			#tcp:
			params["host"] = xpra_opts.host
			params["port"] = int(xpra_opts.port)
			params["display_name"] = "tcp:%s:%s" % (xpra_opts.host, xpra_opts.port)

		#print("connect_or_fail(%s)" % params)
		self.set_info_text("Connecting...")
		try:
			conn = connect_to(params, self.set_info_text)
		except Exception, e:
			self.set_sensitive(True)
			self.set_info_color(True)
			self.set_info_text(str(e))
			return
Example #6
0
 def do_connect_builtin(self, params):
     self.exit_code = None
     self.set_info_text("Connecting.")
     self.set_sensitive(False)
     try:
         conn = connect_to(params, self.set_info_text, ssh_fail_cb=self.ssh_failed)
     except Exception as e:
         log.error("failed to connect", exc_info=True)
         self.handle_exception(e)
         return
     glib.idle_add(self.window.hide)
     glib.idle_add(self.start_XpraClient, conn)
Example #7
0
 def do_connect_builtin(self, params):
     self.exit_code = None
     self.set_info_text("Connecting.")
     self.set_sensitive(False)
     try:
         conn = connect_to(params, self.set_info_text, ssh_fail_cb=self.ssh_failed)
     except Exception as e:
         log.error("failed to connect", exc_info=True)
         self.handle_exception(e)
         return
     glib.idle_add(self.window.hide)
     glib.idle_add(self.start_XpraClient, conn)
Example #8
0
	def do_connect_builtin(self, params):
		self.exit_code = None
		self.set_info_text("Connecting.")
		self.set_sensitive(False)
		try:
			conn = connect_to(params, self.set_info_text, ssh_fail_cb=self.ssh_failed)
		except Exception, e:
			log.error("failed to connect", exc_info=True)
			self.set_sensitive(True)
			self.set_info_color(True)
			self.set_info_text(str(e))
			gobject.idle_add(self.window.show)
			return
Example #9
0
 def do_connect_builtin(self, display_desc):
     log("do_connect_builtin(%s)", display_desc)
     self.exit_code = None
     self.current_error = None
     self.set_info_text("Connecting.")
     self.set_sensitive(False)
     try:
         conn = connect_to(display_desc, opts=self.config, debug_cb=self.set_info_text, ssh_fail_cb=self.ssh_failed)
     except Exception as e:
         log.error("failed to connect", exc_info=True)
         self.handle_exception(e)
         return
     glib.idle_add(self.window.hide)
     glib.idle_add(self.start_XpraClient, conn, display_desc)
Example #10
0
 def do_connect_builtin(self, display_desc):
     log("do_connect_builtin(%s)", display_desc)
     self.exit_code = None
     self.current_error = None
     self.set_info_text("Connecting.")
     self.set_sensitive(False)
     try:
         conn = connect_to(display_desc, opts=self.config, debug_cb=self.set_info_text, ssh_fail_cb=self.ssh_failed)
     except Exception as e:
         log.error("failed to connect", exc_info=True)
         self.handle_exception(e)
         return
     glib.idle_add(self.window.hide)
     glib.idle_add(self.start_XpraClient, conn, display_desc)
Example #11
0
 def do_connect_builtin(self, display_desc):
     log("do_connect_builtin(%s)", display_desc)
     self.exit_code = None
     self.current_error = None
     self.set_info_text("Connecting.")
     self.set_sensitive(False)
     try:
         log("calling %s%s", connect_to, (display_desc, repr_ellipsized(str(self.config)), self.set_info_text, self.ssh_failed))
         conn = connect_to(display_desc, opts=self.config, debug_cb=self.set_info_text, ssh_fail_cb=self.ssh_failed)
     except Exception as e:
         log("do_connect_builtin(%s) failed to connect", display_desc, exc_info=True)
         self.handle_exception(e)
         return
     log("connect_to(..)=%s, hiding launcher window, starting client", conn)
     GLib.idle_add(self.start_XpraClient, conn, display_desc)
Example #12
0
 def do_connect_builtin(self, params):
     self.exit_code = None
     self.set_info_text("Connecting.")
     self.set_sensitive(False)
     try:
         conn = connect_to(params,
                           self.set_info_text,
                           ssh_fail_cb=self.ssh_failed)
     except Exception, e:
         log.error("failed to connect", exc_info=True)
         self.set_sensitive(True)
         self.set_info_color(True)
         self.set_info_text(str(e))
         gobject.idle_add(self.window.show)
         return
Example #13
0
    def start_proxy(self, client_proto, c, auth_caps):
        assert client_proto.authenticator is not None
        #find the target server session:
        def disconnect(msg):
            self.send_disconnect(client_proto, msg)
        sessions = client_proto.authenticator.get_sessions()
        if sessions is None:
            disconnect("no sessions found")
            return
        debug("start_proxy(%s, {..}, %s) found sessions: %s", client_proto, auth_caps, sessions)
        uid, gid, displays, env_options, session_options = sessions
        #debug("unused options: %s, %s", env_options, session_options)
        if len(displays)==0:
            disconnect("no displays found")
            return
        display = c.strget("display")
        proxy_virtual_display = os.environ["DISPLAY"]
        #ensure we don't loop back to the proxy:
        if proxy_virtual_display in displays:
            displays.remove(proxy_virtual_display)
        if display==proxy_virtual_display:
            disconnect("invalid display")
            return
        if display:
            if display not in displays:
                disconnect("display not found")
                return
        else:
            if len(displays)!=1:
                disconnect("please specify a display (more than one available)")
                return
            display = displays[0]

        debug("start_proxy(%s, {..}, %s) using server display at: %s", client_proto, auth_caps, display)
        def parse_error(*args):
            disconnect("invalid display string")
            log.warn("parse error on %s: %s", display, args)
            raise Exception("parse error on %s: %s" % (display, args))
        opts = make_defaults_struct()
        opts.username = c.strget("username")
        disp_desc = parse_display_name(parse_error, opts, display)
        debug("display description(%s) = %s", display, disp_desc)
        try:
            server_conn = connect_to(disp_desc)
        except Exception, e:
            log.error("cannot start proxy connection to %s: %s", disp_desc, e)
            disconnect("failed to connect to display")
            return
Example #14
0
 def fd(d):
     opts = AdHocStruct()
     try:
         #silence errors since we're expecting them:
         from xpra.scripts import main as xpra_main
         try:
             saved_timeout = xpra_main.CONNECT_TIMEOUT
             xpra_main.CONNECT_TIMEOUT = 5
             saved_werr = xpra_main.werr
             xpra_main.werr = noop
             conn = connect_to(d, opts)
         finally:
             xpra_main.werr = saved_werr
             xpra_main.CONNECT_TIMEOUT = saved_timeout
     except Exception:
         #from xpra.util import get_util_logger
         #get_util_logger().error("connect_to(%s, %s)", d, opts, exc_info=True)
         pass
     else:
         try:
             conn.close()
         except Exception:
             pass
         raise Exception("connect_to(%s) should have failed" % (d, ))
Example #15
0
    def proxy_session(self, client_proto, c, auth_caps, sessions):
        def disconnect(reason, *extras):
            log("disconnect(%s, %s)", reason, extras)
            self.send_disconnect(client_proto, reason, *extras)
        uid, gid, displays, env_options, session_options = sessions
        if POSIX:
            if getuid()==0:
                if uid==0 or gid==0:
                    log.error("Error: proxy instances cannot run as root")
                    log.error(" use a different uid and gid (ie: nobody)")
                    disconnect(AUTHENTICATION_ERROR, "cannot run proxy instances as root")
                    return
            else:
                uid = getuid()
                gid = getgid()
            username = get_username_for_uid(uid)
            groups = get_groups(username)
            log("username(%i)=%s, groups=%s", uid, username, groups)
        else:
            #the auth module recorded the username we authenticate against
            assert client_proto.authenticators
            for authenticator in client_proto.authenticators:
                username = getattr(authenticator, "username", "")
                if username:
                    break
        #ensure we don't loop back to the proxy:
        proxy_virtual_display = os.environ.get("DISPLAY")
        if proxy_virtual_display in displays:
            displays.remove(proxy_virtual_display)
        #remove proxy instance virtual displays:
        displays = [x for x in displays if not x.startswith(":proxy-")]
        #log("unused options: %s, %s", env_options, session_options)
        proc = None
        socket_path = None
        display = None
        sns = c.dictget("start-new-session")
        authlog("proxy_session: displays=%s, start_sessions=%s, start-new-session=%s", displays, self._start_sessions, sns)
        if len(displays)==0 or sns:
            if not self._start_sessions:
                disconnect(SESSION_NOT_FOUND, "no displays found")
                return
            try:
                proc, socket_path, display = self.start_new_session(username, uid, gid, sns, displays)
                log("start_new_session%s=%s", (username, uid, gid, sns, displays), (proc, socket_path, display))
            except Exception as e:
                log("start_server_subprocess failed", exc_info=True)
                log.error("Error: failed to start server subprocess:")
                log.error(" %s", e)
                disconnect(SERVER_ERROR, "failed to start a new session")
                return
        if display is None:
            display = c.strget("display")
            authlog("proxy_session: proxy-virtual-display=%s (ignored), user specified display=%s, found displays=%s", proxy_virtual_display, display, displays)
            if display==proxy_virtual_display:
                disconnect(SESSION_NOT_FOUND, "invalid display")
                return
            if display:
                if display not in displays:
                    disconnect(SESSION_NOT_FOUND, "display '%s' not found" % display)
                    return
            else:
                if len(displays)!=1:
                    disconnect(SESSION_NOT_FOUND, "please specify a display, more than one is available: %s" % csv(displays))
                    return
                display = displays[0]

        connect = c.boolget("connect", True)
        #ConnectTestXpraClient doesn't want to connect to the real session either:
        ctr = c.strget("connect_test_request")
        log("connect=%s, connect_test_request=%s", connect, ctr)
        if not connect or ctr:
            log("proxy_session: not connecting to the session")
            hello = {"display" : display}
            if socket_path:
                hello["socket-path"] = socket_path
            #echo mode if present:
            mode = sns.get("mode")
            if mode:
                hello["mode"] = mode
            client_proto.send_now(("hello", hello))
            return

        def stop_server_subprocess():
            log("stop_server_subprocess() proc=%s", proc)
            if proc and proc.poll() is None:
                proc.terminate()

        log("start_proxy(%s, {..}, %s) using server display at: %s", client_proto, auth_caps, display)
        def parse_error(*args):
            stop_server_subprocess()
            disconnect(SESSION_NOT_FOUND, "invalid display string")
            log.warn("Error: parsing failed for display string '%s':", display)
            for arg in args:
                log.warn(" %s", arg)
            raise Exception("parse error on %s: %s" % (display, args))
        opts = make_defaults_struct(username=username, uid=uid, gid=gid)
        opts.username = username
        disp_desc = parse_display_name(parse_error, opts, display)
        if uid or gid:
            disp_desc["uid"] = uid
            disp_desc["gid"] = gid
        log("display description(%s) = %s", display, disp_desc)
        try:
            server_conn = connect_to(disp_desc, opts)
        except Exception as e:
            log("cannot connect", exc_info=True)
            log.error("Error: cannot start proxy connection:")
            for x in str(e).splitlines():
                log.error(" %s", x)
            log.error(" connection definition:")
            print_nested_dict(disp_desc, prefix=" ", lchar="*", pad=20, print_fn=log.error)
            disconnect(SESSION_NOT_FOUND, "failed to connect to display")
            stop_server_subprocess()
            return
        log("server connection=%s", server_conn)

        #no other packets should be arriving until the proxy instance responds to the initial hello packet
        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))
        client_conn = client_proto.steal_connection(unexpected_packet)
        client_state = client_proto.save_state()
        cipher = None
        encryption_key = None
        if auth_caps:
            cipher = auth_caps.get("cipher")
            if cipher:
                encryption_key = self.get_encryption_key(client_proto.authenticators, client_proto.keyfile)
        log("start_proxy(..) client connection=%s", client_conn)
        log("start_proxy(..) client state=%s", client_state)

        #this may block, so run it in a thread:
        def do_start_proxy():
            log("do_start_proxy()")
            message_queue = MQueue()
            try:
                ioe = client_proto.wait_for_io_threads_exit(5+self._socket_timeout)
                if not ioe:
                    log.error("Error: some network IO threads have failed to terminate")
                    return
                client_conn.set_active(True)
                process = ProxyInstanceProcess(uid, gid, env_options, session_options, self._socket_dir,
                                               self.video_encoders, self.csc_modules,
                                               client_conn, disp_desc, client_state, cipher, encryption_key, server_conn, c, message_queue)
                log("starting %s from pid=%s", process, os.getpid())
                self.processes[process] = (display, message_queue)
                process.start()
                log("process started")
                popen = process._popen
                assert popen
                #when this process dies, run reap to update our list of proxy processes:
                self.child_reaper.add_process(popen, "xpra-proxy-%s" % display, "xpra-proxy-instance", True, True, self.reap)
            finally:
                #now we can close our handle on the connection:
                client_conn.close()
                server_conn.close()
                message_queue.put("socket-handover-complete")
        start_thread(do_start_proxy, "start_proxy(%s)" % client_conn)
Example #16
0
    def start_proxy(self, client_proto, c, auth_caps):
        assert client_proto.authenticator is not None
        #find the target server session:
        def disconnect(reason, *extras):
            self.send_disconnect(client_proto, reason, *extras)
        try:
            sessions = client_proto.authenticator.get_sessions()
        except Exception as e:
            log.error("failed to get the list of sessions: %s", e)
            disconnect(AUTHENTICATION_ERROR)
            return
        if sessions is None:
            disconnect(SESSION_NOT_FOUND, "no sessions found")
            return
        log("start_proxy(%s, {..}, %s) found sessions: %s", client_proto, auth_caps, sessions)
        uid, gid, displays, env_options, session_options = sessions
        #log("unused options: %s, %s", env_options, session_options)
        if len(displays)==0:
            disconnect(SESSION_NOT_FOUND, "no displays found")
            return
        display = c.strget("display")
        proxy_virtual_display = os.environ.get("DISPLAY")
        #ensure we don't loop back to the proxy:
        if proxy_virtual_display in displays:
            displays.remove(proxy_virtual_display)
        if display==proxy_virtual_display:
            disconnect(SESSION_NOT_FOUND, "invalid display")
            return
        if display:
            if display not in displays:
                disconnect(SESSION_NOT_FOUND, "display not found")
                return
        else:
            if len(displays)!=1:
                disconnect(SESSION_NOT_FOUND, "please specify a display (more than one available)")
                return
            display = displays[0]

        log("start_proxy(%s, {..}, %s) using server display at: %s", client_proto, auth_caps, display)
        def parse_error(*args):
            disconnect(SESSION_NOT_FOUND, "invalid display string")
            log.warn("parse error on %s: %s", display, args)
            raise Exception("parse error on %s: %s" % (display, args))
        opts = make_defaults_struct()
        opts.username = client_proto.authenticator.username
        disp_desc = parse_display_name(parse_error, opts, display)
        log("display description(%s) = %s", display, disp_desc)
        try:
            server_conn = connect_to(disp_desc)
        except Exception as e:
            log.error("cannot start proxy connection to %s: %s", disp_desc, e, exc_info=True)
            disconnect(SESSION_NOT_FOUND, "failed to connect to display")
            return
        log("server connection=%s", server_conn)

        #no other packets should be arriving until the proxy instance responds to the initial hello packet
        def unexpected_packet(packet):
            if packet:
                log.warn("received an unexpected packet on the proxy connection: %s", repr_ellipsized(packet))
        client_conn = client_proto.steal_connection(unexpected_packet)
        client_state = client_proto.save_state()
        cipher = None
        encryption_key = None
        if auth_caps:
            cipher = auth_caps.get("cipher")
            if cipher:
                encryption_key = self.get_encryption_key(client_proto.authenticator, client_proto.keyfile)
        log("start_proxy(..) client connection=%s", client_conn)
        log("start_proxy(..) client state=%s", client_state)

        #this may block, so run it in a thread:
        def do_start_proxy():
            log("do_start_proxy()")
            message_queue = MQueue()
            try:
                ioe = client_proto.wait_for_io_threads_exit(5+self._socket_timeout)
                if not ioe:
                    log.error("some network IO threads have failed to terminate!")
                    return
                client_conn.set_active(True)
                assert uid!=0 and gid!=0
                process = ProxyInstanceProcess(uid, gid, env_options, session_options, self._socket_dir,
                                               self.video_encoders, self.csc_modules,
                                               client_conn, client_state, cipher, encryption_key, server_conn, c, message_queue)
                log("starting %s from pid=%s", process, os.getpid())
                self.processes[process] = (display, message_queue)
                process.start()
                log("process started")
            finally:
                #now we can close our handle on the connection:
                client_conn.close()
                server_conn.close()
                message_queue.put("socket-handover-complete")
            #FIXME: remove processes that have terminated
        make_thread(do_start_proxy, "start_proxy(%s)" % client_conn).start()
Example #17
0
    def start_proxy(self, client_proto, c, auth_caps):
        def disconnect(reason, *extras):
            log("disconnect(%s, %s)", reason, extras)
            self.send_disconnect(client_proto, reason, *extras)

        #find the target server session:
        if not client_proto.authenticator:
            log.error(
                "Error: the proxy server requires an authentication mode,")
            try:
                log.error(" client connection '%s' does not specify one",
                          client_proto._conn.socktype)
            except:
                pass
            log.error(" use 'none' to disable authentication")
            disconnect(SESSION_NOT_FOUND, "no sessions found")
            return
        try:
            sessions = client_proto.authenticator.get_sessions()
        except Exception as e:
            authlog("failed to get the list of sessions", exc_info=True)
            authlog.error(
                "Error: failed to get the list of sessions using '%s' authenticator",
                client_proto.authenticator)
            authlog.error(" %s", e)
            disconnect(AUTHENTICATION_ERROR)
            return
        if sessions is None:
            disconnect(SESSION_NOT_FOUND, "no sessions found")
            return
        authlog("start_proxy(%s, {..}, %s) found sessions: %s", client_proto,
                auth_caps, sessions)
        uid, gid, displays, env_options, session_options = sessions
        #log("unused options: %s, %s", env_options, session_options)
        if len(displays) == 0:
            disconnect(SESSION_NOT_FOUND, "no displays found")
            return
        display = c.strget("display")
        proxy_virtual_display = os.environ.get("DISPLAY")
        #ensure we don't loop back to the proxy:
        if proxy_virtual_display in displays:
            displays.remove(proxy_virtual_display)
        authlog(
            "start_proxy: proxy-virtual-display=%s (ignored), user specified display=%s, found displays=%s",
            proxy_virtual_display, display, displays)
        if display == proxy_virtual_display:
            disconnect(SESSION_NOT_FOUND, "invalid display")
            return
        if display:
            if display not in displays:
                disconnect(SESSION_NOT_FOUND,
                           "display '%s' not found" % display)
                return
        else:
            if len(displays) != 1:
                disconnect(
                    SESSION_NOT_FOUND,
                    "please specify a display, more than one is available: %s"
                    % csv(displays))
                return
            display = displays[0]

        log("start_proxy(%s, {..}, %s) using server display at: %s",
            client_proto, auth_caps, display)

        def parse_error(*args):
            disconnect(SESSION_NOT_FOUND, "invalid display string")
            log.warn("Error: parsing failed for display string '%s':", display)
            for arg in args:
                log.warn(" %s", arg)
            raise Exception("parse error on %s: %s" % (display, args))

        opts = make_defaults_struct()
        opts.username = client_proto.authenticator.username
        disp_desc = parse_display_name(parse_error, opts, display)
        log("display description(%s) = %s", display, disp_desc)
        try:
            server_conn = connect_to(disp_desc, opts)
        except Exception as e:
            log("cannot connect", exc_info=True)
            log.error("Error: cannot start proxy connection:")
            log.error(" %s", e)
            log.error(" connection definition:")
            print_nested_dict(disp_desc,
                              prefix=" ",
                              lchar="*",
                              pad=20,
                              print_fn=log.error)
            disconnect(SESSION_NOT_FOUND, "failed to connect to display")
            return
        log("server connection=%s", server_conn)

        #no other packets should be arriving until the proxy instance responds to the initial hello packet
        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))

        client_conn = client_proto.steal_connection(unexpected_packet)
        client_state = client_proto.save_state()
        cipher = None
        encryption_key = None
        if auth_caps:
            cipher = auth_caps.get("cipher")
            if cipher:
                encryption_key = self.get_encryption_key(
                    client_proto.authenticator, client_proto.keyfile)
        log("start_proxy(..) client connection=%s", client_conn)
        log("start_proxy(..) client state=%s", client_state)

        #this may block, so run it in a thread:
        def do_start_proxy():
            log("do_start_proxy()")
            message_queue = MQueue()
            try:
                ioe = client_proto.wait_for_io_threads_exit(
                    5 + self._socket_timeout)
                if not ioe:
                    log.error(
                        "Error: some network IO threads have failed to terminate"
                    )
                    return
                client_conn.set_active(True)
                assert uid != 0 and gid != 0
                process = ProxyInstanceProcess(
                    uid, gid, env_options, session_options, self._socket_dir,
                    self.video_encoders, self.csc_modules, client_conn,
                    client_state, cipher, encryption_key, server_conn, c,
                    message_queue)
                log("starting %s from pid=%s", process, os.getpid())
                self.processes[process] = (display, message_queue)
                process.start()
                log("process started")
                popen = process._popen
                assert popen
                #when this process dies, run reap to update our list of proxy processes:
                self.child_reaper.add_process(popen, "xpra-proxy-%s" % display,
                                              "xpra-proxy-instance", True,
                                              True, self.reap)
            finally:
                #now we can close our handle on the connection:
                client_conn.close()
                server_conn.close()
                message_queue.put("socket-handover-complete")
            #FIXME: remove processes that have terminated

        start_thread(do_start_proxy, "start_proxy(%s)" % client_conn)
Example #18
0
class ProxyServer(ServerCore):
    """
        This is the proxy server you can launch with "xpra proxy",
        once authenticated, it will dispatch the connection
        to the session found using the authenticator's
        get_sessions() function.
    """
    def __init__(self):
        log("ProxyServer.__init__()")
        ServerCore.__init__(self)
        self._max_connections = MAX_CONCURRENT_CONNECTIONS
        self.main_loop = None
        #keep track of the proxy process instances
        #the display they're on and the message queue we can
        # use to communicate with them
        self.processes = {}
        self.idle_add = gobject.idle_add
        self.timeout_add = gobject.timeout_add
        self.source_remove = gobject.source_remove
        self._socket_timeout = PROXY_SOCKET_TIMEOUT
        self._socket_dir = None
        self.control_commands = ["hello", "stop"]
        #ensure we cache the platform info before intercepting SIGCHLD
        #as this will cause a fork and SIGCHLD to be emitted:
        from xpra.version_util import get_platform_info
        get_platform_info()
        signal.signal(signal.SIGCHLD, self.sigchld)

    def init(self, opts):
        log("ProxyServer.init(%s)", opts)
        if not opts.auth:
            raise Exception(
                "The proxy server requires an authentication mode (use 'none' to disable authentication)"
            )
        self._socket_dir = opts.socket_dir
        self.video_encoders = opts.video_encoders
        self.csc_modules = opts.csc_modules
        ServerCore.init(self, opts)

    def get_server_mode(self):
        return "proxy"

    def init_aliases(self):
        pass

    def do_run(self):
        self.main_loop = gobject.MainLoop()
        self.main_loop.run()

    def do_handle_command_request(self, proto, command, args):
        if command in ("help", "hello"):
            return ServerCore.do_handle_command_request(
                self, proto, command, args)
        assert command == "stop"
        if len(args) != 1:
            return ServerCore.control_command_response(
                self, proto, command, 4,
                "invalid number of arguments, usage: 'xpra control stop DISPLAY'"
            )
        display = args[0]
        log("stop command: will try to find proxy process for display %s",
            display)
        for process, v in list(self.processes.items()):
            disp, mq = v
            if disp == display:
                pid = process.pid
                log.info(
                    "stop command: found process %s with pid %s for display %s, sending it 'stop' request",
                    process, pid, display)
                mq.put("stop")
                return self.control_command_response(
                    proto, command, 0,
                    "stopped proxy process with pid %s" % pid)
        return self.control_command_response(
            proto, command, 14, "no proxy found for display %s" % display)

    def stop_all_proxies(self):
        processes = self.processes
        self.processes = {}
        log("stop_all_proxies() will stop proxy processes: %s", processes)
        for process, v in processes.items():
            if not process.is_alive():
                continue
            disp, mq = v
            log("stop_all_proxies() stopping process %s for display %s",
                process, disp)
            mq.put("stop")
        log("stop_all_proxies() done")

    def cleanup(self):
        self.stop_all_proxies()
        ServerCore.cleanup(self)

    def do_quit(self):
        self.main_loop.quit()
        log.info("Proxy Server process ended")

    def add_listen_socket(self, socktype, sock):
        sock.listen(5)
        gobject.io_add_watch(sock, gobject.IO_IN, self._new_connection, sock)
        self.socket_types[sock] = socktype

    def verify_connection_accepted(self, protocol):
        #if we start a proxy, the protocol will be closed
        #(a new one is created in the proxy process)
        if not protocol._closed:
            self.send_disconnect(protocol, "connection timeout")

    def hello_oked(self, proto, packet, c, auth_caps):
        if c.boolget("stop_request"):
            self.clean_quit()
            return
        self.accept_client(proto, c)
        self.start_proxy(proto, c, auth_caps)

    def start_proxy(self, client_proto, c, auth_caps):
        assert client_proto.authenticator is not None

        #find the target server session:
        def disconnect(msg):
            self.send_disconnect(client_proto, msg)

        try:
            sessions = client_proto.authenticator.get_sessions()
        except Exception, e:
            log.error("failed to get the list of sessions: %s", e)
            disconnect("authentication error")
            return
        if sessions is None:
            disconnect("no sessions found")
            return
        log("start_proxy(%s, {..}, %s) found sessions: %s", client_proto,
            auth_caps, sessions)
        uid, gid, displays, env_options, session_options = sessions
        #log("unused options: %s, %s", env_options, session_options)
        if len(displays) == 0:
            disconnect("no displays found")
            return
        display = c.strget("display")
        proxy_virtual_display = os.environ.get("DISPLAY")
        #ensure we don't loop back to the proxy:
        if proxy_virtual_display in displays:
            displays.remove(proxy_virtual_display)
        if display == proxy_virtual_display:
            disconnect("invalid display")
            return
        if display:
            if display not in displays:
                disconnect("display not found")
                return
        else:
            if len(displays) != 1:
                disconnect(
                    "please specify a display (more than one available)")
                return
            display = displays[0]

        log("start_proxy(%s, {..}, %s) using server display at: %s",
            client_proto, auth_caps, display)

        def parse_error(*args):
            disconnect("invalid display string")
            log.warn("parse error on %s: %s", display, args)
            raise Exception("parse error on %s: %s" % (display, args))

        opts = make_defaults_struct()
        opts.username = client_proto.authenticator.username
        disp_desc = parse_display_name(parse_error, opts, display)
        log("display description(%s) = %s", display, disp_desc)
        try:
            server_conn = connect_to(disp_desc)
        except Exception, e:
            log.error("cannot start proxy connection to %s: %s",
                      disp_desc,
                      e,
                      exc_info=True)
            disconnect("failed to connect to display")
            return
Example #19
0
    def start_proxy(self, client_proto, c, auth_caps):
        def disconnect(reason, *extras):
            log("disconnect(%s, %s)", reason, extras)
            self.send_disconnect(client_proto, reason, *extras)

        #find the target server session:
        if not client_proto.authenticator:
            log.error(
                "Error: the proxy server requires an authentication mode,")
            try:
                log.error(" client connection '%s' does not specify one",
                          client_proto._conn.socktype)
            except:
                pass
            log.error(" use 'none' to disable authentication")
            disconnect(SESSION_NOT_FOUND, "no sessions found")
            return
        try:
            sessions = client_proto.authenticator.get_sessions()
        except Exception as e:
            authlog("failed to get the list of sessions", exc_info=True)
            authlog.error(
                "Error: failed to get the list of sessions using '%s' authenticator",
                client_proto.authenticator)
            authlog.error(" %s", e)
            disconnect(AUTHENTICATION_ERROR, "cannot access sessions")
            return
        authlog("start_proxy(%s, {..}, %s) found sessions: %s", client_proto,
                auth_caps, sessions)
        if sessions is None:
            disconnect(SESSION_NOT_FOUND, "no sessions found")
            return
        uid, gid, displays, env_options, session_options = sessions
        if os.name == "posix":
            if uid == 0 or gid == 0:
                log.error("Error: proxy instances should not run as root")
                log.error(" use a different uid and gid (ie: nobody)")
                disconnect(AUTHENTICATION_ERROR,
                           "cannot run proxy instances as root")
                return
            username = get_username_for_uid(uid)
            groups = get_groups(username)
            if "xpra" not in groups:
                log("user '%s' (uid=%i) is not in the xpra group", username,
                    uid)
                log(" it belongs to: %s", csv(groups) or None)
        #ensure we don't loop back to the proxy:
        proxy_virtual_display = os.environ.get("DISPLAY")
        if proxy_virtual_display in displays:
            displays.remove(proxy_virtual_display)
        #remove proxy instance virtual displays:
        displays = [x for x in displays if not x.startswith(":proxy-")]
        #log("unused options: %s, %s", env_options, session_options)
        opts = make_defaults_struct()
        display = None
        proc = None
        sns = c.dictget("start-new-session")
        authlog("start_proxy: displays=%s, start-new-session=%s", displays,
                bool(sns))
        if len(displays) == 0 or sns:
            if self._start_sessions:
                #start a new session
                mode = sns.get("mode", "start")
                assert mode in (
                    "start", "start-desktop",
                    "shadow"), "invalid start-new-session mode '%s'" % mode
                sns = typedict(sns)
                display = sns.get("display")
                args = []
                if display:
                    args = [display]
                start = sns.strlistget("start")
                start_child = sns.strlistget("start-child")
                exit_with_children = sns.boolget("exit-with-children")
                exit_with_client = sns.boolget("exit-with-client")
                log(
                    "starting new server subprocess: mode=%s, socket-dir=%s, socket-dirs=%s, start=%s, start-child=%s, exit-with-children=%s, exit-with-client=%s, uid=%s, gid=%s",
                    mode, opts.socket_dir, opts.socket_dirs, start,
                    start_child, exit_with_children, exit_with_client, uid,
                    gid)
                try:
                    proc, socket_path = start_server_subprocess(
                        sys.argv[0],
                        args,
                        mode,
                        opts,
                        opts.socket_dir,
                        opts.socket_dirs,
                        start,
                        start_child,
                        exit_with_children,
                        exit_with_client,
                        uid=uid,
                        gid=gid)
                    display = "socket:%s" % socket_path
                except Exception as e:
                    log("start_server_subprocess failed", exc_info=True)
                    log.error("Error: failed to start server subprocess:")
                    log.error(" %s", e)
                    disconnect(SERVER_ERROR, "failed to start a new session")
                    return
                if proc:
                    self.child_reaper.add_process(proc, "server-%s" % display,
                                                  "xpra start", True, True)
            else:
                disconnect(SESSION_NOT_FOUND, "no displays found")
                return
        if display is None:
            display = c.strget("display")
            authlog(
                "start_proxy: proxy-virtual-display=%s (ignored), user specified display=%s, found displays=%s",
                proxy_virtual_display, display, displays)
            if display == proxy_virtual_display:
                disconnect(SESSION_NOT_FOUND, "invalid display")
                return
            if display:
                if display not in displays:
                    disconnect(SESSION_NOT_FOUND,
                               "display '%s' not found" % display)
                    return
            else:
                if len(displays) != 1:
                    disconnect(
                        SESSION_NOT_FOUND,
                        "please specify a display, more than one is available: %s"
                        % csv(displays))
                    return
                display = displays[0]

        def stop_server_subprocess():
            if proc:
                proc.terminate()

        log("start_proxy(%s, {..}, %s) using server display at: %s",
            client_proto, auth_caps, display)

        def parse_error(*args):
            stop_server_subprocess()
            disconnect(SESSION_NOT_FOUND, "invalid display string")
            log.warn("Error: parsing failed for display string '%s':", display)
            for arg in args:
                log.warn(" %s", arg)
            raise Exception("parse error on %s: %s" % (display, args))

        opts.username = client_proto.authenticator.username
        disp_desc = parse_display_name(parse_error, opts, display)
        if uid or gid:
            disp_desc["uid"] = uid
            disp_desc["gid"] = gid
        log("display description(%s) = %s", display, disp_desc)
        try:
            server_conn = connect_to(disp_desc, opts)
        except Exception as e:
            log("cannot connect", exc_info=True)
            log.error("Error: cannot start proxy connection:")
            log.error(" %s", e)
            log.error(" connection definition:")
            print_nested_dict(disp_desc,
                              prefix=" ",
                              lchar="*",
                              pad=20,
                              print_fn=log.error)
            disconnect(SESSION_NOT_FOUND, "failed to connect to display")
            stop_server_subprocess()
            return
        log("server connection=%s", server_conn)

        #no other packets should be arriving until the proxy instance responds to the initial hello packet
        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))

        client_conn = client_proto.steal_connection(unexpected_packet)
        client_state = client_proto.save_state()
        cipher = None
        encryption_key = None
        if auth_caps:
            cipher = auth_caps.get("cipher")
            if cipher:
                encryption_key = self.get_encryption_key(
                    client_proto.authenticator, client_proto.keyfile)
        log("start_proxy(..) client connection=%s", client_conn)
        log("start_proxy(..) client state=%s", client_state)

        #this may block, so run it in a thread:
        def do_start_proxy():
            log("do_start_proxy()")
            message_queue = MQueue()
            try:
                ioe = client_proto.wait_for_io_threads_exit(
                    5 + self._socket_timeout)
                if not ioe:
                    log.error(
                        "Error: some network IO threads have failed to terminate"
                    )
                    return
                client_conn.set_active(True)
                process = ProxyInstanceProcess(
                    uid, gid, env_options, session_options, self._socket_dir,
                    self.video_encoders, self.csc_modules, client_conn,
                    client_state, cipher, encryption_key, server_conn, c,
                    message_queue)
                log("starting %s from pid=%s", process, os.getpid())
                self.processes[process] = (display, message_queue)
                process.start()
                log("process started")
                popen = process._popen
                assert popen
                #when this process dies, run reap to update our list of proxy processes:
                self.child_reaper.add_process(popen, "xpra-proxy-%s" % display,
                                              "xpra-proxy-instance", True,
                                              True, self.reap)
            finally:
                #now we can close our handle on the connection:
                client_conn.close()
                server_conn.close()
                message_queue.put("socket-handover-complete")

        start_thread(do_start_proxy, "start_proxy(%s)" % client_conn)
Example #20
0
    def start_proxy(self, client_proto, c, auth_caps):
        def disconnect(reason, *extras):
            log("disconnect(%s, %s)", reason, extras)
            self.send_disconnect(client_proto, reason, *extras)

        #find the target server session:
        if not client_proto.authenticator:
            log.error("Error: the proxy server requires an authentication mode,")
            try:
                log.error(" client connection '%s' does not specify one", client_proto._conn.socktype)
            except:
                pass
            log.error(" use 'none' to disable authentication")
            disconnect(SESSION_NOT_FOUND, "no sessions found")
            return
        try:
            sessions = client_proto.authenticator.get_sessions()
        except Exception as e:
            authlog("failed to get the list of sessions", exc_info=True)
            authlog.error("Error: failed to get the list of sessions using '%s' authenticator", client_proto.authenticator)
            authlog.error(" %s", e)
            disconnect(AUTHENTICATION_ERROR, "cannot access sessions")
            return
        authlog("start_proxy(%s, {..}, %s) found sessions: %s", client_proto, auth_caps, sessions)
        if sessions is None:
            disconnect(SESSION_NOT_FOUND, "no sessions found")
            return
        uid, gid, displays, env_options, session_options = sessions
        if os.name=="posix":
            if uid==0 or gid==0:
                log.error("Error: proxy instances should not run as root")
                log.error(" use a different uid and gid (ie: nobody)")
                disconnect(AUTHENTICATION_ERROR, "cannot run proxy instances as root")
                return
            username = get_username_for_uid(uid)
            groups = get_groups(username)
            if "xpra" not in groups:
                log.error("Error: user '%s' (uid=%i) is not in the xpra group", username, uid)
                log.error(" it belongs to: %s", csv(groups) or None)
                disconnect(PERMISSION_ERROR, "user missing 'xpra' group membership")
                return
        #ensure we don't loop back to the proxy:
        proxy_virtual_display = os.environ.get("DISPLAY")
        if proxy_virtual_display in displays:
            displays.remove(proxy_virtual_display)
        #remove proxy instance virtual displays:
        displays = [x for x in displays if not x.startswith(":proxy-")]
        #log("unused options: %s, %s", env_options, session_options)
        opts = make_defaults_struct()
        display = None
        proc = None
        sns = c.dictget("start-new-session")
        authlog("start_proxy: displays=%s, start-new-session=%s", displays, bool(sns))
        if len(displays)==0 or sns:
            if self._start_sessions:
                #start a new session
                mode = sns.get("mode", "start")
                assert mode in ("start", "start-desktop", "shadow"), "invalid start-new-session mode '%s'" % mode
                sns = typedict(sns)
                display = sns.get("display")
                args = []
                if display:
                    args = [display]
                start = sns.strlistget("start")
                start_child = sns.strlistget("start-child")
                exit_with_children = sns.boolget("exit-with-children")
                exit_with_client = sns.boolget("exit-with-client")
                log("starting new server subprocess: mode=%s, socket-dir=%s, socket-dirs=%s, start=%s, start-child=%s, exit-with-children=%s, exit-with-client=%s, uid=%s, gid=%s",
                    mode, opts.socket_dir, opts.socket_dirs, start, start_child, exit_with_children, exit_with_client, uid, gid)
                try:
                    proc, socket_path = start_server_subprocess(sys.argv[0], args, mode, opts,
                                                                opts.socket_dir, opts.socket_dirs,
                                                                start, start_child,
                                                                exit_with_children, exit_with_client,
                                                                uid=uid, gid=gid)
                    display = "socket:%s" % socket_path
                except Exception as e:
                    log("start_server_subprocess failed", exc_info=True)
                    log.error("Error: failed to start server subprocess:")
                    log.error(" %s", e)
                    disconnect(SERVER_ERROR, "failed to start a new session")
                    return
                if proc:
                    self.child_reaper.add_process(proc, "server-%s" % display, "xpra start", True, True)
            else:
                disconnect(SESSION_NOT_FOUND, "no displays found")
                return
        if display is None:
            display = c.strget("display")
            authlog("start_proxy: proxy-virtual-display=%s (ignored), user specified display=%s, found displays=%s", proxy_virtual_display, display, displays)
            if display==proxy_virtual_display:
                disconnect(SESSION_NOT_FOUND, "invalid display")
                return
            if display:
                if display not in displays:
                    disconnect(SESSION_NOT_FOUND, "display '%s' not found" % display)
                    return
            else:
                if len(displays)!=1:
                    disconnect(SESSION_NOT_FOUND, "please specify a display, more than one is available: %s" % csv(displays))
                    return
                display = displays[0]

        def stop_server_subprocess():
            if proc:
                proc.terminate()

        log("start_proxy(%s, {..}, %s) using server display at: %s", client_proto, auth_caps, display)
        def parse_error(*args):
            stop_server_subprocess()
            disconnect(SESSION_NOT_FOUND, "invalid display string")
            log.warn("Error: parsing failed for display string '%s':", display)
            for arg in args:
                log.warn(" %s", arg)
            raise Exception("parse error on %s: %s" % (display, args))
        opts.username = client_proto.authenticator.username
        disp_desc = parse_display_name(parse_error, opts, display)
        if uid or gid:
            disp_desc["uid"] = uid
            disp_desc["gid"] = gid
        log("display description(%s) = %s", display, disp_desc)
        try:
            server_conn = connect_to(disp_desc, opts)
        except Exception as e:
            log("cannot connect", exc_info=True)
            log.error("Error: cannot start proxy connection:")
            log.error(" %s", e)
            log.error(" connection definition:")
            print_nested_dict(disp_desc, prefix=" ", lchar="*", pad=20, print_fn=log.error)
            disconnect(SESSION_NOT_FOUND, "failed to connect to display")
            stop_server_subprocess()
            return
        log("server connection=%s", server_conn)

        #no other packets should be arriving until the proxy instance responds to the initial hello packet
        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))
        client_conn = client_proto.steal_connection(unexpected_packet)
        client_state = client_proto.save_state()
        cipher = None
        encryption_key = None
        if auth_caps:
            cipher = auth_caps.get("cipher")
            if cipher:
                encryption_key = self.get_encryption_key(client_proto.authenticator, client_proto.keyfile)
        log("start_proxy(..) client connection=%s", client_conn)
        log("start_proxy(..) client state=%s", client_state)

        #this may block, so run it in a thread:
        def do_start_proxy():
            log("do_start_proxy()")
            message_queue = MQueue()
            try:
                ioe = client_proto.wait_for_io_threads_exit(5+self._socket_timeout)
                if not ioe:
                    log.error("Error: some network IO threads have failed to terminate")
                    return
                client_conn.set_active(True)
                process = ProxyInstanceProcess(uid, gid, env_options, session_options, self._socket_dir,
                                               self.video_encoders, self.csc_modules,
                                               client_conn, client_state, cipher, encryption_key, server_conn, c, message_queue)
                log("starting %s from pid=%s", process, os.getpid())
                self.processes[process] = (display, message_queue)
                process.start()
                log("process started")
                popen = process._popen
                assert popen
                #when this process dies, run reap to update our list of proxy processes:
                self.child_reaper.add_process(popen, "xpra-proxy-%s" % display, "xpra-proxy-instance", True, True, self.reap)
            finally:
                #now we can close our handle on the connection:
                client_conn.close()
                server_conn.close()
                message_queue.put("socket-handover-complete")
        start_thread(do_start_proxy, "start_proxy(%s)" % client_conn)
Example #21
0
    def start_proxy(self, client_proto, c, auth_caps):
        assert client_proto.authenticator is not None
        #find the target server session:
        def disconnect(reason, *extras):
            self.send_disconnect(client_proto, reason, *extras)
        try:
            sessions = client_proto.authenticator.get_sessions()
        except Exception as e:
            log.error("failed to get the list of sessions: %s", e)
            disconnect(AUTHENTICATION_ERROR)
            return
        if sessions is None:
            disconnect(SESSION_NOT_FOUND, "no sessions found")
            return
        log("start_proxy(%s, {..}, %s) found sessions: %s", client_proto, auth_caps, sessions)
        uid, gid, displays, env_options, session_options = sessions
        #log("unused options: %s, %s", env_options, session_options)
        if len(displays)==0:
            disconnect(SESSION_NOT_FOUND, "no displays found")
            return
        display = c.strget("display")
        proxy_virtual_display = os.environ.get("DISPLAY")
        #ensure we don't loop back to the proxy:
        if proxy_virtual_display in displays:
            displays.remove(proxy_virtual_display)
        if display==proxy_virtual_display:
            disconnect(SESSION_NOT_FOUND, "invalid display")
            return
        if display:
            if display not in displays:
                disconnect(SESSION_NOT_FOUND, "display not found")
                return
        else:
            if len(displays)!=1:
                disconnect(SESSION_NOT_FOUND, "please specify a display (more than one available)")
                return
            display = displays[0]

        log("start_proxy(%s, {..}, %s) using server display at: %s", client_proto, auth_caps, display)
        def parse_error(*args):
            disconnect(SESSION_NOT_FOUND, "invalid display string")
            log.warn("parse error on %s: %s", display, args)
            raise Exception("parse error on %s: %s" % (display, args))
        opts = make_defaults_struct()
        opts.username = client_proto.authenticator.username
        disp_desc = parse_display_name(parse_error, opts, display)
        log("display description(%s) = %s", display, disp_desc)
        try:
            server_conn = connect_to(disp_desc)
        except Exception as e:
            log.error("cannot start proxy connection to %s: %s", disp_desc, e, exc_info=True)
            disconnect(SESSION_NOT_FOUND, "failed to connect to display")
            return
        log("server connection=%s", server_conn)

        #no other packets should be arriving until the proxy instance responds to the initial hello packet
        def unexpected_packet(packet):
            if packet:
                log.warn("received an unexpected packet on the proxy connection: %s", repr_ellipsized(packet))
        client_conn = client_proto.steal_connection(unexpected_packet)
        client_state = client_proto.save_state()
        cipher = None
        encryption_key = None
        if auth_caps:
            cipher = auth_caps.get("cipher")
            if cipher:
                encryption_key = self.get_encryption_key(client_proto.authenticator, client_proto.keyfile)
        log("start_proxy(..) client connection=%s", client_conn)
        log("start_proxy(..) client state=%s", client_state)

        #this may block, so run it in a thread:
        def do_start_proxy():
            log("do_start_proxy()")
            message_queue = MQueue()
            try:
                ioe = client_proto.wait_for_io_threads_exit(0.5+self._socket_timeout)
                if not ioe:
                    log.error("some network IO threads have failed to terminate!")
                    return
                client_conn.set_active(True)
                assert uid!=0 and gid!=0
                process = ProxyInstanceProcess(uid, gid, env_options, session_options, self._socket_dir,
                                               self.video_encoders, self.csc_modules,
                                               client_conn, client_state, cipher, encryption_key, server_conn, c, message_queue)
                log("starting %s from pid=%s", process, os.getpid())
                self.processes[process] = (display, message_queue)
                process.start()
                log("process started")
            finally:
                #now we can close our handle on the connection:
                client_conn.close()
                server_conn.close()
                message_queue.put("socket-handover-complete")
            #FIXME: remove processes that have terminated
        make_thread(do_start_proxy, "start_proxy(%s)" % client_conn).start()
Example #22
0
    def test_connect_to(self):
        def f(**kwargs):
            fd(kwargs)

        def fd(d):
            opts = AdHocStruct()
            try:
                #silence errors since we're expecting them:
                from xpra.scripts import main as xpra_main
                try:
                    saved_timeout = xpra_main.CONNECT_TIMEOUT
                    xpra_main.CONNECT_TIMEOUT = 5
                    saved_werr = xpra_main.werr
                    xpra_main.werr = main.noop
                    conn = connect_to(d, opts)
                finally:
                    xpra_main.werr = saved_werr
                    xpra_main.CONNECT_TIMEOUT = saved_timeout
            except Exception:
                #from xpra.util import get_util_logger
                #get_util_logger().error("connect_to(%s, %s)", d, opts, exc_info=True)
                pass
            else:
                try:
                    conn.close()
                except Exception:
                    pass
                raise Exception("connect_to(%s) should have failed" % (d, ))

        #without extra arguments to specify the endpoint,
        #all connections should fail, even if they have a valid type:
        f(type="invalid", display_name="test")
        f(type="vsock", display_name="test", vsock=(10, 1000))
        fd({
            "type": "named-pipe",
            "display_name": "test",
            "named-pipe": "TEST-INVALID"
        })
        f(type="unix-domain", display_name=":100000", display="100000")
        for socktype in (
                "tcp",
                "ssl",
                "ws",
                "wss",
        ):
            f(type=socktype,
              display_name="test",
              host="localhost",
              port=100000)
        for paramiko in (True, False):
            f(type="ssh",
              display_name="test",
              host="localhost",
              port=100000,
              is_paramiko=paramiko)
        fd({
            "type": "ssl",
            "display_name": "test",
            "host": "localhost",
            "port": 100000,
            "strict-host-check": False,
        })
        #udp never fails when opening the connection:
        conn = connect_to(
            {
                "type": "udp",
                "host": "localhost",
                "port": 20000,
                "display_name": ":200"
            }, AdHocStruct())
        conn.close()