Exemple #1
0
    def __init__(self, options, title="Xpra Session Browser"):
        gtk.Window.__init__(self)
        self.exit_code = 0
        self.set_title(title)
        self.set_border_width(20)
        self.set_resizable(True)
        self.set_decorated(True)
        icon = self.get_pixbuf("xpra")
        if icon:
            self.set_icon(icon)
        add_close_accel(self, self.quit)
        self.connect("delete_event", self.quit)

        self.child_reaper = getChildReaper()

        self.vbox = gtk.VBox(False, 20)
        self.add(self.vbox)

        title_label = gtk.Label(title)
        title_label.modify_font(pango.FontDescription("sans 14"))
        self.vbox.add(title_label)

        self.warning = gtk.Label(" ")
        red = color_parse("red")
        self.warning.modify_fg(STATE_NORMAL, red)
        self.vbox.add(self.warning)

        hbox = gtk.HBox(False, 10)
        al = gtk.Alignment(xalign=1, yalign=0.5)
        al.add(gtk.Label("Password:"******""
        #log.info("options=%s (%s)", options, type(options))
        self.local_info_cache = {}
        self.dotxpra = DotXpra(options.socket_dir, options.socket_dirs,
                               username)
        self.poll_local_sessions()
        glib.timeout_add(5 * 1000, self.poll_local_sessions)
        self.populate_table()

        import signal
        signal.signal(signal.SIGINT, self.app_signal)
        signal.signal(signal.SIGTERM, self.app_signal)
        self.show_all()
Exemple #2
0
 def check_returncode(_proc_cb):
     returncode = proc.poll()
     log("returncode(%s)=%s", command, returncode)
     if returncode!=0:
         log.warn("lpadmin failed and returned error code: %s", returncode)
         from xpra.platform.info import get_username
         log.warn(" verify that user '%s' has all the required permissions", get_username())
         log.warn(" for running: '%s'", LPADMIN)
         log.warn(" full command: %s", " ".join("'%s'" % x for x in command))
     elif success_cb:
         success_cb()
Exemple #3
0
 def pulseaudio_warning():
     soundlog.warn(
         "Warning: pulseaudio has terminated shortly after startup.")
     soundlog.warn(
         " pulseaudio is limited to a single instance per user account,"
     )
     soundlog.warn(" and one may be running already for user '%s'.",
                   get_username())
     soundlog.warn(
         " To avoid this warning, either fix the pulseaudio command line"
     )
     soundlog.warn(" or use the 'pulseaudio=no' option.")
Exemple #4
0
	def test_multifile(self):
		from xpra.platform.info import get_username
		username = get_username()
		from xpra.os_util import get_hex_uuid
		password = get_hex_uuid()
		displays = ""
		data = "%s|%s|%i|%i|%s||" % (username, password, os.getuid(), os.getgid(), displays)
		f = self._temp_file(data)
		self._test_auth("multifile", "", EXIT_PASSWORD_REQUIRED)
		self._test_auth("multifile:filename=%s" % f.name, "", EXIT_PASSWORD_REQUIRED)
		self._test_auth("multifile:filename=%s" % f.name, "", EXIT_OK, password)
		self._test_auth("multifile:filename=%s" % f.name, "", EXIT_FAILURE, password+"A")
		f.close()
Exemple #5
0
 def test_multifile(self):
     from xpra.platform.info import get_username
     username = get_username()
     from xpra.os_util import get_hex_uuid
     password = get_hex_uuid()
     displays = ""
     data = "%s|%s|%i|%i|%s||" % (username, password, os.getuid(), os.getgid(), displays)
     f = self._temp_file(strtobytes(data))
     self._test_auth("multifile", "", EXIT_PASSWORD_REQUIRED)
     self._test_auth("multifile:filename=%s" % f.name, "", EXIT_PASSWORD_REQUIRED)
     self._test_auth("multifile:filename=%s" % f.name, "", EXIT_OK, password)
     self._test_auth("multifile:filename=%s" % f.name, "", EXIT_FAILURE, password+"A")
     f.close()
Exemple #6
0
 def make_hello(self, challenge_response=None):
     capabilities = {}
     add_version_info(capabilities)
     capabilities["python.version"] = sys.version_info[:3]
     if challenge_response:
         assert self.password
         capabilities["challenge_response"] = challenge_response
     if self.encryption:
         assert self.encryption in ENCRYPTION_CIPHERS
         capabilities["cipher"] = self.encryption
         iv = get_hex_uuid()[:16]
         capabilities["cipher.iv"] = iv
         key_salt = get_hex_uuid()
         capabilities["cipher.key_salt"] = key_salt
         iterations = 1000
         capabilities["cipher.key_stretch_iterations"] = iterations
         self._protocol.set_cipher_in(self.encryption, iv,
                                      self.get_password(), key_salt,
                                      iterations)
         log("encryption capabilities: %s",
             [(k, v)
              for k, v in capabilities.items() if k.startswith("cipher")])
     capabilities["platform"] = sys.platform
     capabilities["platform.release"] = python_platform.release()
     capabilities["platform.machine"] = python_platform.machine()
     capabilities["platform.processor"] = python_platform.processor()
     capabilities["client_type"] = self.client_type()
     capabilities["namespace"] = True
     capabilities["raw_packets"] = True
     capabilities["chunked_compression"] = True
     capabilities["bencode"] = True
     capabilities["rencode"] = has_rencode
     if has_rencode:
         capabilities["rencode.version"] = rencode_version
     capabilities["hostname"] = socket.gethostname()
     capabilities["uuid"] = self.uuid
     try:
         from xpra.platform.info import get_username, get_name
         capabilities["username"] = get_username()
         capabilities["name"] = get_name()
     except:
         log.error("failed to get username/name", exc_info=True)
     capabilities["randr_notify"] = False  #only client.py cares about this
     capabilities["windows"] = False  #only client.py cares about this
     if self._reverse_aliases:
         capabilities["aliases"] = self._reverse_aliases
     return capabilities
Exemple #7
0
 def make_hello(self, challenge_response=None):
     capabilities = {}
     add_version_info(capabilities)
     capabilities["python.version"] = sys.version_info[:3]
     if challenge_response:
         assert self.password
         capabilities["challenge_response"] = challenge_response
     if self.encryption:
         assert self.encryption in ENCRYPTION_CIPHERS
         capabilities["cipher"] = self.encryption
         iv = get_hex_uuid()[:16]
         capabilities["cipher.iv"] = iv
         key_salt = get_hex_uuid()
         capabilities["cipher.key_salt"] = key_salt
         iterations = 1000
         capabilities["cipher.key_stretch_iterations"] = iterations
         self._protocol.set_cipher_in(self.encryption, iv, self.get_password(), key_salt, iterations)
         log("encryption capabilities: %s", [(k,v) for k,v in capabilities.items() if k.startswith("cipher")])
     capabilities["platform"] = sys.platform
     capabilities["platform.release"] = python_platform.release()
     capabilities["platform.machine"] = python_platform.machine()
     capabilities["platform.processor"] = python_platform.processor()
     capabilities["client_type"] = self.client_type()
     capabilities["namespace"] = True
     capabilities["raw_packets"] = True
     capabilities["chunked_compression"] = True
     capabilities["bencode"] = True
     capabilities["rencode"] = has_rencode
     if has_rencode:
         capabilities["rencode.version"] = rencode_version
     capabilities["hostname"] = socket.gethostname()
     capabilities["uuid"] = self.uuid
     try:
         from xpra.platform.info import get_username, get_name
         capabilities["username"] = get_username()
         capabilities["name"] = get_name()
     except:
         log.error("failed to get username/name", exc_info=True)
     capabilities["randr_notify"] = False    #only client.py cares about this
     capabilities["windows"] = False         #only client.py cares about this
     if self._reverse_aliases:
         capabilities["aliases"] = self._reverse_aliases
     return capabilities
Exemple #8
0
 def __init__(self, **kwargs):
     self.username = kwargs.get("username", get_username())
     if str(kwargs.get("client-username",
                       self.CLIENT_USERNAME)).lower() in TRUE_OPTIONS:
         #allow the client to specify the username to authenticate with:
         self.username = kwargs.get("remote",
                                    {}).get("username", self.username)
     self.salt = None
     self.digest = None
     self.salt_digest = None
     prompt_attr = {"username": std(self.username)}
     self.prompt = kwargs.pop("prompt",
                              self.DEFAULT_PROMPT).format(**prompt_attr)
     self.socket_dirs = kwargs.pop("socket-dirs", get_socket_dirs())
     self.challenge_sent = False
     self.passed = False
     self.password_used = None
     #we can't warn about unused options
     #because the options are shared with other socket options (nodelay, cork, etc)
     #unused = dict((k,v) for k,v in kwargs.items() if k not in ("connection", "exec_cwd", "username"))
     #if unused:
     #    log.warn("Warning: unused keyword arguments for %s authentication:", self)
     #    log.warn(" %s", unused)
     log("auth prompt=%s, socket_dirs=%s", self.prompt, self.socket_dirs)
Exemple #9
0
def run_server(error_cb,
               opts,
               mode,
               xpra_file,
               extra_args,
               desktop_display=None):
    try:
        cwd = os.getcwd()
    except:
        cwd = os.path.expanduser("~")
        warn("current working directory does not exist, using '%s'\n" % cwd)
    validate_encryption(opts)
    if opts.encoding == "help" or "help" in opts.encodings:
        return show_encoding_help(opts)

    from xpra.server.socket_util import parse_bind_tcp, parse_bind_vsock
    bind_tcp = parse_bind_tcp(opts.bind_tcp)
    bind_ssl = parse_bind_tcp(opts.bind_ssl)
    bind_vsock = parse_bind_vsock(opts.bind_vsock)

    assert mode in ("start", "start-desktop", "upgrade", "shadow", "proxy")
    starting = mode == "start"
    starting_desktop = mode == "start-desktop"
    upgrading = mode == "upgrade"
    shadowing = mode == "shadow"
    proxying = mode == "proxy"
    clobber = upgrading or opts.use_display
    start_vfb = not shadowing and not proxying and not clobber

    if upgrading or shadowing:
        #there should already be one running
        opts.pulseaudio = False

    #get the display name:
    if shadowing and len(extra_args) == 0:
        if WIN32 or OSX:
            #just a virtual name for the only display available:
            display_name = ":0"
        else:
            from xpra.scripts.main import guess_X11_display
            dotxpra = DotXpra(opts.socket_dir, opts.socket_dirs)
            display_name = guess_X11_display(dotxpra)
    elif upgrading and len(extra_args) == 0:
        display_name = guess_xpra_display(opts.socket_dir, opts.socket_dirs)
    else:
        if len(extra_args) > 1:
            error_cb(
                "too many extra arguments (%i): only expected a display number"
                % len(extra_args))
        if len(extra_args) == 1:
            display_name = extra_args[0]
            if not shadowing and not proxying and not opts.use_display:
                display_name_check(display_name)
        else:
            if proxying:
                #find a free display number:
                dotxpra = DotXpra(opts.socket_dir, opts.socket_dirs)
                all_displays = dotxpra.sockets()
                #ie: [("LIVE", ":100"), ("LIVE", ":200"), ...]
                displays = [v[1] for v in all_displays]
                display_name = None
                for x in range(1000, 20000):
                    v = ":%s" % x
                    if v not in displays:
                        display_name = v
                        break
                if not display_name:
                    error_cb(
                        "you must specify a free virtual display name to use with the proxy server"
                    )
            elif opts.use_display:
                #only use automatic guess for xpra displays and not X11 displays:
                display_name = guess_xpra_display(opts.socket_dir,
                                                  opts.socket_dirs)
            else:
                # We will try to find one automaticaly
                # Use the temporary magic value 'S' as marker:
                display_name = 'S' + str(os.getpid())

    if not shadowing and not proxying and not upgrading and opts.exit_with_children and not opts.start_child:
        error_cb(
            "--exit-with-children specified without any children to spawn; exiting immediately"
        )

    atexit.register(run_cleanups)

    # Generate the script text now, because os.getcwd() will
    # change if/when we daemonize:
    from xpra.server.server_util import xpra_runner_shell_script, write_runner_shell_scripts, write_pidfile, find_log_dir
    script = xpra_runner_shell_script(xpra_file, cwd, opts.socket_dir)

    uid = int(opts.uid)
    gid = int(opts.gid)
    username = get_username_for_uid(uid)
    home = get_home_for_uid(uid)
    xauth_data = None
    if start_vfb:
        xauth_data = get_hex_uuid()
    ROOT = POSIX and getuid() == 0

    stdout = sys.stdout
    stderr = sys.stderr
    # Daemonize:
    if POSIX and opts.daemon:
        #daemonize will chdir to "/", so try to use an absolute path:
        if opts.password_file:
            opts.password_file = os.path.abspath(opts.password_file)
        from xpra.server.server_util import daemonize
        daemonize()

    # if pam is present, try to create a new session:
    pam = None
    protected_fds = []
    protected_env = {}
    PAM_OPEN = POSIX and envbool("XPRA_PAM_OPEN", ROOT and uid != 0)
    if PAM_OPEN:
        try:
            from xpra.server.pam import pam_session  #@UnresolvedImport
        except ImportError as e:
            stderr.write("Error: failed to import pam module\n")
            stderr.write(" %s" % e)
            PAM_OPEN = False
    if PAM_OPEN:
        fdc = FDChangeCaptureContext()
        with fdc:
            pam = pam_session(username)
            env = {
                #"XDG_SEAT"               : "seat1",
                #"XDG_VTNR"               : "0",
                "XDG_SESSION_TYPE": "x11",
                #"XDG_SESSION_CLASS"      : "user",
                "XDG_SESSION_DESKTOP": "xpra",
            }
            #maybe we should just bail out instead?
            if pam.start():
                pam.set_env(env)
                items = {}
                if display_name.startswith(":"):
                    items["XDISPLAY"] = display_name
                if xauth_data:
                    items["XAUTHDATA"] = xauth_data
                pam.set_items(items)
                if pam.open():
                    #we can't close it, because we're not going to be root any more,
                    #but since we're the process leader for the session,
                    #terminating will also close the session
                    #add_cleanup(pam.close)
                    protected_env = pam.get_envlist()
                    os.environ.update(protected_env)
        #closing the pam fd causes the session to be closed,
        #and we don't want that!
        protected_fds = fdc.get_new_fds()

    xrd = create_runtime_dir(uid, gid)

    if opts.pidfile:
        write_pidfile(opts.pidfile, uid, gid)

    if POSIX and not ROOT:
        # Write out a shell-script so that we can start our proxy in a clean
        # environment:
        write_runner_shell_scripts(script)

    if start_vfb or opts.daemon:
        #we will probably need a log dir
        #either for the vfb, or for our own log file
        log_dir = opts.log_dir or ""
        if not log_dir or log_dir.lower() == "auto":
            log_dir = find_log_dir(username, uid=uid, gid=gid)
            if not log_dir:
                raise InitException(
                    "cannot find or create a logging directory")
        #expose the log-dir as "XPRA_LOG_DIR",
        #this is used by Xdummy for the Xorg log file
        if "XPRA_LOG_DIR" not in os.environ:
            os.environ["XPRA_LOG_DIR"] = log_dir

        if opts.daemon:
            from xpra.server.server_util import select_log_file, open_log_file, redirect_std_to_log
            log_filename0 = select_log_file(log_dir, opts.log_file,
                                            display_name)
            logfd = open_log_file(log_filename0)
            if ROOT and (uid > 0 or gid > 0):
                try:
                    os.fchown(logfd, uid, gid)
                except:
                    pass
            stdout, stderr = redirect_std_to_log(logfd, *protected_fds)
            stderr.write("Entering daemon mode; " +
                         "any further errors will be reported to:\n" +
                         ("  %s\n" % log_filename0))

    #warn early about this:
    if (starting or starting_desktop) and desktop_display:
        print_DE_warnings(desktop_display, opts.pulseaudio, opts.notifications,
                          opts.dbus_launch)

    from xpra.log import Logger
    log = Logger("server")
    netlog = Logger("network")

    mdns_recs = []
    sockets = []

    #SSL sockets:
    wrap_socket_fn = None
    need_ssl = False
    ssl_opt = opts.ssl.lower()
    if ssl_opt in TRUE_OPTIONS or bind_ssl:
        need_ssl = True
    if opts.bind_tcp:
        if ssl_opt == "auto" and opts.ssl_cert:
            need_ssl = True
        elif ssl_opt == "tcp":
            need_ssl = True
        elif ssl_opt == "www":
            need_ssl = True
    if need_ssl:
        from xpra.scripts.main import ssl_wrap_socket_fn
        try:
            wrap_socket_fn = ssl_wrap_socket_fn(opts, server_side=True)
            netlog("wrap_socket_fn=%s", wrap_socket_fn)
        except Exception as e:
            netlog("SSL error", exc_info=True)
            cpaths = csv("'%s'" % x for x in (opts.ssl_cert, opts.ssl_key)
                         if x)
            raise InitException(
                "cannot create SSL socket, check your certificate paths (%s): %s"
                % (cpaths, e))

    from xpra.server.socket_util import setup_tcp_socket, setup_vsock_socket, setup_local_sockets
    min_port = int(opts.min_port)
    netlog("setting up SSL sockets: %s", bind_ssl)
    for host, iport in bind_ssl:
        if iport < min_port:
            error_cb("invalid %s port number %i (minimum value is %i)" %
                     (socktype, iport, min_port))
        _, tcp_socket, host_port = setup_tcp_socket(host, iport, "SSL")
        socket = ("SSL", wrap_socket_fn(tcp_socket), host_port)
        sockets.append(socket)
        rec = "ssl", [(host, iport)]
        netlog("%s : %s", rec, socket)
        mdns_recs.append(rec)

    # Initialize the TCP sockets before the display,
    # That way, errors won't make us kill the Xvfb
    # (which may not be ours to kill at that point)
    tcp_ssl = ssl_opt in TRUE_OPTIONS or (ssl_opt == "auto" and opts.ssl_cert)

    def add_tcp_mdns_rec(host, iport):
        rec = "tcp", [(host, iport)]
        netlog("%s : %s", rec, socket)
        mdns_recs.append(rec)
        if tcp_ssl:
            #SSL is also available on this TCP socket:
            rec = "ssl", [(host, iport)]
            netlog("%s : %s", rec, socket)
            mdns_recs.append(rec)

    netlog("setting up TCP sockets: %s", bind_tcp)
    for host, iport in bind_tcp:
        if iport < min_port:
            error_cb("invalid %s port number %i (minimum value is %i)" %
                     (socktype, iport, min_port))
        socket = setup_tcp_socket(host, iport)
        sockets.append(socket)
        add_tcp_mdns_rec(host, iport)

    # VSOCK:
    netlog("setting up vsock sockets: %s", bind_vsock)
    for cid, iport in bind_vsock:
        socket = setup_vsock_socket(cid, iport)
        sockets.append(socket)
        rec = "vsock", [("", iport)]
        netlog("%s : %s", rec, socket)
        mdns_recs.append(rec)

    # systemd socket activation:
    try:
        from xpra.server.sd_listen import get_sd_listen_sockets
    except ImportError:
        pass
    else:
        sd_sockets = get_sd_listen_sockets()
        netlog("systemd sockets: %s", sd_sockets)
        for stype, socket, addr in sd_sockets:
            sockets.append((stype, socket, addr))
            netlog("%s : %s", (stype, [addr]), socket)
            if stype == "tcp":
                host, iport = addr
                add_tcp_mdns_rec(host, iport)

    sanitize_env()
    if POSIX:
        if xrd:
            os.environ["XDG_RUNTIME_DIR"] = xrd
        os.environ["XDG_SESSION_TYPE"] = "x11"
        if not starting_desktop:
            os.environ["XDG_CURRENT_DESKTOP"] = opts.wm_name
        configure_imsettings_env(opts.input_method)
    if display_name[0] != 'S':
        os.environ["DISPLAY"] = display_name
        os.environ["CKCON_X11_DISPLAY"] = display_name
    else:
        try:
            del os.environ["DISPLAY"]
        except:
            pass
    os.environ.update(protected_env)
    log("env=%s", os.environ)

    # Start the Xvfb server first to get the display_name if needed
    from xpra.server.vfb_util import start_Xvfb, check_xvfb_process, verify_display_ready, verify_gdk_display, set_initial_resolution
    odisplay_name = display_name
    xvfb = None
    xvfb_pid = None
    if start_vfb:
        assert not proxying and xauth_data
        pixel_depth = validate_pixel_depth(opts.pixel_depth)
        xvfb, display_name = start_Xvfb(opts.xvfb, pixel_depth, display_name,
                                        cwd, uid, gid, xauth_data)
        xvfb_pid = xvfb.pid
        #always update as we may now have the "real" display name:
        os.environ["DISPLAY"] = display_name
        os.environ["CKCON_X11_DISPLAY"] = display_name
        os.environ.update(protected_env)
        if display_name != odisplay_name and pam:
            pam.set_items({"XDISPLAY": display_name})

    close_display = None
    if not proxying:

        def close_display():
            # Close our display(s) first, so the server dying won't kill us.
            # (if gtk has been loaded)
            gtk_mod = sys.modules.get("gtk")
            if gtk_mod:
                for d in gtk_mod.gdk.display_manager_get().list_displays():
                    d.close()
            if xvfb_pid:
                log.info("killing xvfb with pid %s", xvfb_pid)
                try:
                    os.kill(xvfb_pid, signal.SIGTERM)
                except OSError as e:
                    log.info("failed to kill xvfb process with pid %s:",
                             xvfb_pid)
                    log.info(" %s", e)

        add_cleanup(close_display)

    if opts.daemon:

        def noerr(fn, *args):
            try:
                fn(*args)
            except:
                pass

        log_filename1 = select_log_file(log_dir, opts.log_file, display_name)
        if log_filename0 != log_filename1:
            # we now have the correct log filename, so use it:
            os.rename(log_filename0, log_filename1)
            if odisplay_name != display_name:
                #this may be used by scripts, let's try not to change it:
                noerr(stderr.write, "Actual display used: %s\n" % display_name)
            noerr(stderr.write,
                  "Actual log file name is now: %s\n" % log_filename1)
            noerr(stderr.flush)
        noerr(stdout.close)
        noerr(stderr.close)
    #we should not be using stdout or stderr from this point:
    del stdout
    del stderr

    if not check_xvfb_process(xvfb):
        #xvfb problem: exit now
        return 1

    if ROOT and (uid != 0 or gid != 0):
        log("root: switching to uid=%i, gid=%i", uid, gid)
        setuidgid(uid, gid)
        os.environ.update({
            "HOME": home,
            "USER": username,
            "LOGNAME": username,
        })
        shell = get_shell_for_uid(uid)
        if shell:
            os.environ["SHELL"] = shell
        os.environ.update(protected_env)

    if opts.chdir:
        os.chdir(opts.chdir)

    display = None
    if not proxying:
        no_gtk()
        if POSIX and (starting or starting_desktop or shadowing):
            #check that we can access the X11 display:
            if not verify_display_ready(xvfb, display_name, shadowing):
                return 1
            display = verify_gdk_display(display_name)
            if not display:
                return 1
            import gtk  #@Reimport
            assert gtk
        #on win32, this ensures that we get the correct screen size to shadow:
        from xpra.platform.gui import init as gui_init
        gui_init()

    #setup unix domain socket:
    if not opts.socket_dir and not opts.socket_dirs:
        #we always need at least one valid socket dir
        from xpra.platform.paths import get_socket_dirs
        opts.socket_dirs = get_socket_dirs()
    local_sockets = setup_local_sockets(opts.bind, opts.socket_dir,
                                        opts.socket_dirs, display_name,
                                        clobber, opts.mmap_group,
                                        opts.socket_permissions, username, uid,
                                        gid)
    netlog("setting up local sockets: %s", local_sockets)
    for rec, cleanup_socket in local_sockets:
        socktype, socket, sockpath = rec
        #ie: ("unix-domain", sock, sockpath), cleanup_socket
        sockets.append(rec)
        netlog("%s : %s", (socktype, [sockpath]), socket)
        add_cleanup(cleanup_socket)
        if opts.mdns:
            ssh_port = get_ssh_port()
            rec = "ssh", [("", ssh_port)]
            netlog("%s : %s", rec, socket)
            if ssh_port and rec not in mdns_recs:
                mdns_recs.append(rec)

    kill_dbus = None
    if shadowing:
        from xpra.platform.shadow_server import ShadowServer
        app = ShadowServer()
        server_type_info = "shadow"
    elif proxying:
        from xpra.server.proxy.proxy_server import ProxyServer
        app = ProxyServer()
        server_type_info = "proxy"
    else:
        assert starting or starting_desktop or upgrading
        from xpra.x11.gtk2.gdk_display_source import init_gdk_display_source
        init_gdk_display_source()
        #(now we can access the X11 server)

        if xvfb_pid is not None:
            #save the new pid (we should have one):
            save_xvfb_pid(xvfb_pid)

        if POSIX:
            dbus_pid = -1
            dbus_env = {}
            if clobber:
                #get the saved pids and env
                dbus_pid = get_dbus_pid()
                dbus_env = get_dbus_env()
                log("retrieved existing dbus attributes")
            else:
                assert starting or starting_desktop
                if xvfb_pid is not None:
                    #save the new pid (we should have one):
                    save_xvfb_pid(xvfb_pid)
                bus_address = protected_env.get("DBUS_SESSION_BUS_ADDRESS")
                log("dbus_launch=%s, current DBUS_SESSION_BUS_ADDRESS=%s",
                    opts.dbus_launch, bus_address)
                if opts.dbus_launch and not bus_address:
                    #start a dbus server:
                    def kill_dbus():
                        log("kill_dbus: dbus_pid=%s" % dbus_pid)
                        if dbus_pid <= 0:
                            return
                        try:
                            os.kill(dbus_pid, signal.SIGINT)
                        except Exception as e:
                            log.warn(
                                "Warning: error trying to stop dbus with pid %i:",
                                dbus_pid)
                            log.warn(" %s", e)

                    add_cleanup(kill_dbus)
                    #this also updates os.environ with the dbus attributes:
                    dbus_pid, dbus_env = start_dbus(opts.dbus_launch)
                    if dbus_pid > 0:
                        save_dbus_pid(dbus_pid)
                    if dbus_env:
                        save_dbus_env(dbus_env)
            log("dbus attributes: pid=%s, env=%s", dbus_pid, dbus_env)
            if dbus_env:
                os.environ.update(dbus_env)
                os.environ.update(protected_env)

        log("env=%s", os.environ)
        try:
            # This import is delayed because the module depends on gtk:
            from xpra.x11.bindings.window_bindings import X11WindowBindings
            X11Window = X11WindowBindings()
            if (starting or
                    starting_desktop) and not clobber and opts.resize_display:
                set_initial_resolution(starting_desktop)
        except ImportError as e:
            log.error(
                "Failed to load Xpra server components, check your installation: %s"
                % e)
            return 1
        if starting or upgrading:
            if not X11Window.displayHasXComposite():
                log.error(
                    "Xpra 'start' subcommand runs as a compositing manager")
                log.error(
                    " it cannot use a display which lacks the XComposite extension!"
                )
                return 1
            if starting:
                #check for an existing window manager:
                from xpra.x11.gtk2.wm import wm_check
                if not wm_check(display, opts.wm_name, upgrading):
                    return 1
            log("XShape=%s", X11Window.displayHasXShape())
            from xpra.x11.server import XpraServer
            app = XpraServer(clobber)
            server_type_info = "xpra"
        else:
            assert starting_desktop
            from xpra.x11.desktop_server import XpraDesktopServer
            app = XpraDesktopServer()
            server_type_info = "xpra desktop"

    #publish mdns records:
    if opts.mdns:
        from xpra.os_util import strtobytes
        from xpra.platform.info import get_username
        from xpra.server.socket_util import mdns_publish
        mdns_info = {
            "display": display_name,
            "username": get_username(),
            "uuid": strtobytes(app.uuid),
            "platform": sys.platform,
            "type": {
                "xpra": "seamless",
                "xpra desktop": "desktop"
            }.get(server_type_info, server_type_info),
        }
        if opts.session_name:
            mdns_info["session"] = opts.session_name
        for mode, listen_on in mdns_recs:
            mdns_publish(display_name, mode, listen_on, mdns_info)

    try:
        app._ssl_wrap_socket = wrap_socket_fn
        app.original_desktop_display = desktop_display
        app.exec_cwd = opts.chdir or cwd
        app.init(opts)
        app.init_components(opts)
    except InitException as e:
        log.error("xpra server initialization error:")
        log.error(" %s", e)
        return 1
    except Exception as e:
        log.error("Error: cannot start the %s server",
                  server_type_info,
                  exc_info=True)
        log.error(str(e))
        log.info("")
        return 1

    #honour start child, html webserver, and setup child reaper
    if not proxying and not upgrading:
        if opts.exit_with_children:
            assert opts.start_child, "exit-with-children was specified but start-child is missing!"
        app.start_commands = opts.start
        app.start_child_commands = opts.start_child
        app.start_after_connect = opts.start_after_connect
        app.start_child_after_connect = opts.start_child_after_connect
        app.start_on_connect = opts.start_on_connect
        app.start_child_on_connect = opts.start_child_on_connect
        app.exec_start_commands()
    del opts

    log("%s(%s)", app.init_sockets, sockets)
    app.init_sockets(sockets)
    log("%s(%s)", app.init_when_ready, _when_ready)
    app.init_when_ready(_when_ready)

    try:
        #from here on, we own the vfb, even if we inherited one:
        if (starting or starting_desktop or upgrading) and clobber:
            #and it will be killed if exit cleanly:
            xvfb_pid = get_xvfb_pid()

        log("running %s", app.run)
        e = app.run()
        log("%s()=%s", app.run, e)
    except KeyboardInterrupt:
        log.info("stopping on KeyboardInterrupt")
        e = 0
    except Exception as e:
        log.error("server error", exc_info=True)
        e = -128
    if e > 0:
        # Upgrading/exiting, so leave X and dbus servers running
        if close_display:
            _cleanups.remove(close_display)
        if kill_dbus:
            _cleanups.remove(kill_dbus)
        from xpra.server.server_core import ServerCore
        if e == ServerCore.EXITING_CODE:
            log.info("exiting: not cleaning up Xvfb")
        else:
            log.info("upgrading: not cleaning up Xvfb")
        log("cleanups=%s", _cleanups)
        e = 0
    return e
Exemple #10
0
def get_defaults():
    global GLOBAL_DEFAULTS
    if GLOBAL_DEFAULTS is not None:
        return GLOBAL_DEFAULTS
    from xpra.platform.features import DEFAULT_SSH_COMMAND, OPEN_COMMAND, DEFAULT_PULSEAUDIO_COMMAND, XDUMMY, XDUMMY_WRAPPER, DISPLAYFD, DEFAULT_ENV, CAN_DAEMONIZE
    from xpra.platform.paths import get_download_dir, get_default_log_dir
    try:
        from xpra.platform.info import get_username
        username = get_username()
    except:
        username = ""
    if WIN32 or OSX or PYTHON3:
        xvfb = ""
    elif XDUMMY:
        xvfb = get_Xdummy_command(use_wrapper=XDUMMY_WRAPPER)
    else:
        xvfb = get_Xvfb_command()

    GLOBAL_DEFAULTS = {
                    "encoding"          : "",
                    "title"             : "@title@ on @client-machine@",
                    "username"          : username,
                    "auth"              : "",
                    "tcp-auth"          : "",
                    "wm-name"           : DEFAULT_NET_WM_NAME,
                    "remote-xpra"       : "~/.xpra/run-xpra",
                    "session-name"      : "",
                    "dock-icon"         : "",
                    "tray-icon"         : "",
                    "window-icon"       : "",
                    "password-file"     : "",
                    "clipboard"         : "yes",
                    "clipboard-filter-file" : "",
                    "remote-clipboard"  : "CLIPBOARD",
                    "local-clipboard"   : "CLIPBOARD",
                    "pulseaudio-command": DEFAULT_PULSEAUDIO_COMMAND,
                    "encryption"        : "",
                    "tcp-encryption"    : "",
                    "encryption-keyfile": "",
                    "tcp-encryption-keyfile": "",
                    "ssh"               : DEFAULT_SSH_COMMAND,
                    "xvfb"              : " ".join(xvfb),
                    "socket-dir"        : "",
                    "log-dir"           : get_default_log_dir(),
                    "log-file"          : "$DISPLAY.log",
                    "border"            : "auto,0",
                    "max-size"          : "",
                    "desktop-scaling"   : "auto",
                    "display"           : "",
                    "tcp-proxy"         : "",
                    "download-path"     : get_download_dir(),
                    "open-command"      : OPEN_COMMAND,
                    "lpadmin"           : "/usr/sbin/lpadmin",
                    "lpinfo"            : "/usr/sbin/lpinfo",
                    "pdf-printer"       : "",
                    "postscript-printer": "",
                    "debug"             : "",
                    "input-method"      : "none",
                    "sound-source"      : "",
                    "html"              : "",
                    "socket-permissions": "600",
                    "quality"           : 0,
                    "min-quality"       : 30,
                    "speed"             : 0,
                    "min-speed"         : 0,
                    "compression_level" : 1,
                    "dpi"               : 0,
                    "video-scaling"     : 1,
                    "file-size-limit"   : 10,
                    "idle-timeout"      : 0,
                    "server-idle-timeout" : 0,
                    "sync-xvfb"         : 0,
                    "auto-refresh-delay": 0.15,
                    "daemon"            : CAN_DAEMONIZE,
                    "use-display"       : False,
                    "displayfd"         : DISPLAYFD,
                    "fake-xinerama"     : not OSX and not WIN32,
                    "tray"              : True,
                    "pulseaudio"        : not OSX and not WIN32,
                    "dbus-proxy"        : not OSX and not WIN32,
                    "mmap"              : not OSX and not WIN32,
                    "mmap-group"        : False,
                    "speaker"           : ["disabled", "on"][has_sound_support],
                    "microphone"        : ["disabled", "off"][has_sound_support],
                    "readonly"          : False,
                    "keyboard-sync"     : True,
                    "pings"             : False,
                    "cursors"           : True,
                    "bell"              : True,
                    "notifications"     : True,
                    "xsettings"         : not OSX and not WIN32,
                    "system-tray"       : True,
                    "sharing"           : False,
                    "delay-tray"        : False,
                    "windows"           : True,
                    "exit-with-children": False,
                    "exit-with-client"  : False,
                    "start-new-commands": False,
                    "remote-logging"    : WIN32 or OSX,
                    "av-sync"           : True,
                    "exit-ssh"          : True,
                    "dbus-control"      : not WIN32 and not OSX,
                    "opengl"            : OPENGL_DEFAULT,
                    "mdns"              : not WIN32,
                    "file-transfer"     : True,
                    "printing"          : True,
                    "open-files"        : False,
                    "swap-keys"         : OSX,  #only used on osx
                    "shadow-fullscreen" : False,
                    "global-menus"      : True,
                    "socket-dirs"       : [],
                    "encodings"         : ["all"],
                    "video-encoders"    : ["all"],
                    "csc-modules"       : ["all"],
                    "video-decoders"    : ["all"],
                    "speaker-codec"     : [],
                    "microphone-codec"  : [],
                    "compressors"       : ["all"],
                    "packet-encoders"   : ["all"],
                    "key-shortcut"      : [
                                           "Meta+Shift+F1:show_menu",
                                           "Meta+Shift+F2:show_start_new_command",
                                           "Meta+Shift+F4:quit",
                                           "Meta+Shift+F5:increase_quality",
                                           "Meta+Shift+F6:decrease_quality",
                                           "Meta+Shift+F7:increase_speed",
                                           "Meta+Shift+F8:decrease_speed",
                                           "Meta+Shift+F10:magic_key",
                                           "Meta+Shift+F11:show_session_info",
                                           "Meta+Shift+plus:scaleup",
                                           "Meta+Shift+plusminus:scaleup",          #the keyname on OSX...
                                           "Meta+Shift+minus:scaledown",
                                           "Meta+Shift+underscore:scaledown",
                                           "Meta+Shift+emdash:scaledown",           #OSX
                                           "Meta+Shift+KP_Add:scaleup",
                                           "Meta+Shift+KP_Subtract:scaledown",
                                           "Meta+Shift+KP_Multiply:scalereset",
                                           "Meta+Shift+degree:scalereset",          #OSX
                                           ],
                    "bind-tcp"          : [],
                    "start"             : [],
                    "start-child"       : [],
                    "env"               : DEFAULT_ENV,
                    }
    return GLOBAL_DEFAULTS
Exemple #11
0
def do_run_server(error_cb,
                  opts,
                  mode,
                  xpra_file,
                  extra_args,
                  desktop_display=None):
    try:
        cwd = os.getcwd()
    except OSError:
        cwd = os.path.expanduser("~")
        warn("current working directory does not exist, using '%s'\n" % cwd)
    validate_encryption(opts)
    if opts.encoding == "help" or "help" in opts.encodings:
        return show_encoding_help(opts)

    assert mode in ("start", "start-desktop", "upgrade", "shadow", "proxy")
    starting = mode == "start"
    starting_desktop = mode == "start-desktop"
    upgrading = mode == "upgrade"
    shadowing = mode == "shadow"
    proxying = mode == "proxy"
    clobber = upgrading or opts.use_display
    start_vfb = not shadowing and not proxying and not clobber

    if shadowing and is_Wayland():
        warn("shadow servers do not support Wayland, switch to X11")

    if opts.bind_rfb and (proxying or starting):
        get_util_logger().warn(
            "Warning: bind-rfb sockets cannot be used with '%s' mode" % mode)
        opts.bind_rfb = ""

    if not shadowing and not starting_desktop:
        opts.rfb_upgrade = 0

    if upgrading or shadowing:
        #there should already be one running
        opts.pulseaudio = False

    #get the display name:
    if shadowing and not extra_args:
        if WIN32 or OSX:
            #just a virtual name for the only display available:
            display_name = ":0"
        else:
            from xpra.scripts.main import guess_X11_display
            dotxpra = DotXpra(opts.socket_dir, opts.socket_dirs)
            display_name = guess_X11_display(dotxpra, desktop_display)
    elif upgrading and not extra_args:
        display_name = guess_xpra_display(opts.socket_dir, opts.socket_dirs)
    else:
        if len(extra_args) > 1:
            error_cb(
                "too many extra arguments (%i): only expected a display number"
                % len(extra_args))
        if len(extra_args) == 1:
            display_name = extra_args[0]
            if not shadowing and not proxying and not opts.use_display:
                display_name_check(display_name)
        else:
            if proxying:
                #find a free display number:
                dotxpra = DotXpra(opts.socket_dir, opts.socket_dirs)
                all_displays = dotxpra.sockets()
                #ie: [("LIVE", ":100"), ("LIVE", ":200"), ...]
                displays = [v[1] for v in all_displays]
                display_name = None
                for x in range(1000, 20000):
                    v = ":%s" % x
                    if v not in displays:
                        display_name = v
                        break
                if not display_name:
                    error_cb(
                        "you must specify a free virtual display name to use with the proxy server"
                    )
            elif opts.use_display:
                #only use automatic guess for xpra displays and not X11 displays:
                display_name = guess_xpra_display(opts.socket_dir,
                                                  opts.socket_dirs)
            else:
                # We will try to find one automaticaly
                # Use the temporary magic value 'S' as marker:
                display_name = 'S' + str(os.getpid())

    if not shadowing and not proxying and not upgrading and opts.exit_with_children and not opts.start_child:
        error_cb(
            "--exit-with-children specified without any children to spawn; exiting immediately"
        )

    atexit.register(run_cleanups)

    # Generate the script text now, because os.getcwd() will
    # change if/when we daemonize:
    from xpra.server.server_util import (
        xpra_runner_shell_script,
        write_runner_shell_scripts,
        write_pidfile,
        find_log_dir,
        create_input_devices,
    )
    script = xpra_runner_shell_script(xpra_file, cwd, opts.socket_dir)

    uid = int(opts.uid)
    gid = int(opts.gid)
    username = get_username_for_uid(uid)
    home = get_home_for_uid(uid)
    xauth_data = None
    if start_vfb:
        xauth_data = get_hex_uuid()
    ROOT = POSIX and getuid() == 0

    protected_fds = []
    protected_env = {}
    stdout = sys.stdout
    stderr = sys.stderr
    # Daemonize:
    if POSIX and opts.daemon:
        #daemonize will chdir to "/", so try to use an absolute path:
        if opts.password_file:
            opts.password_file = tuple(
                os.path.abspath(x) for x in opts.password_file)
        from xpra.server.server_util import daemonize
        daemonize()

    displayfd = 0
    if POSIX and opts.displayfd:
        try:
            displayfd = int(opts.displayfd)
            if displayfd > 0:
                protected_fds.append(displayfd)
        except ValueError as e:
            stderr.write("Error: invalid displayfd '%s':\n" % opts.displayfd)
            stderr.write(" %s\n" % e)
            del e

    # if pam is present, try to create a new session:
    pam = None
    PAM_OPEN = POSIX and envbool("XPRA_PAM_OPEN", ROOT and uid != 0)
    if PAM_OPEN:
        try:
            from xpra.server.pam import pam_session  #@UnresolvedImport
        except ImportError as e:
            stderr.write("Error: failed to import pam module\n")
            stderr.write(" %s" % e)
            del e
            PAM_OPEN = False
    if PAM_OPEN:
        fdc = FDChangeCaptureContext()
        with fdc:
            pam = pam_session(username)
            env = {
                #"XDG_SEAT"               : "seat1",
                #"XDG_VTNR"               : "0",
                "XDG_SESSION_TYPE": "x11",
                #"XDG_SESSION_CLASS"      : "user",
                "XDG_SESSION_DESKTOP": "xpra",
            }
            #maybe we should just bail out instead?
            if pam.start():
                pam.set_env(env)
                items = {}
                if display_name.startswith(":"):
                    items["XDISPLAY"] = display_name
                if xauth_data:
                    items["XAUTHDATA"] = xauth_data
                pam.set_items(items)
                if pam.open():
                    #we can't close it, because we're not going to be root any more,
                    #but since we're the process leader for the session,
                    #terminating will also close the session
                    #add_cleanup(pam.close)
                    protected_env = pam.get_envlist()
                    os.environ.update(protected_env)
        #closing the pam fd causes the session to be closed,
        #and we don't want that!
        protected_fds += fdc.get_new_fds()

    #get XDG_RUNTIME_DIR from env options,
    #which may not be have updated os.environ yet when running as root with "--uid="
    xrd = os.path.abspath(parse_env(opts.env).get("XDG_RUNTIME_DIR", ""))
    if ROOT and (uid > 0 or gid > 0):
        #we're going to chown the directory if we create it,
        #ensure this cannot be abused, only use "safe" paths:
        if not any(x for x in ("/run/user/%i" % uid, "/tmp", "/var/tmp")
                   if xrd.startswith(x)):
            xrd = ""
        #these paths could cause problems if we were to create and chown them:
        if xrd.startswith("/tmp/.X11-unix") or xrd.startswith(
                "/tmp/.XIM-unix"):
            xrd = ""
    if not xrd:
        xrd = os.environ.get("XDG_RUNTIME_DIR")
    xrd = create_runtime_dir(xrd, uid, gid)
    if xrd:
        #this may override the value we get from pam
        #with the value supplied by the user:
        protected_env["XDG_RUNTIME_DIR"] = xrd

    if opts.pidfile:
        write_pidfile(opts.pidfile, uid, gid)

    if POSIX and not ROOT:
        # Write out a shell-script so that we can start our proxy in a clean
        # environment:
        write_runner_shell_scripts(script)

    if start_vfb or opts.daemon:
        #we will probably need a log dir
        #either for the vfb, or for our own log file
        log_dir = opts.log_dir or ""
        if not log_dir or log_dir.lower() == "auto":
            log_dir = find_log_dir(username, uid=uid, gid=gid)
            if not log_dir:
                raise InitException(
                    "cannot find or create a logging directory")
        #expose the log-dir as "XPRA_LOG_DIR",
        #this is used by Xdummy for the Xorg log file
        if "XPRA_LOG_DIR" not in os.environ:
            os.environ["XPRA_LOG_DIR"] = log_dir

        if opts.daemon:
            from xpra.server.server_util import select_log_file, open_log_file, redirect_std_to_log
            log_filename0 = osexpand(
                select_log_file(log_dir, opts.log_file, display_name),
                username, uid, gid)
            logfd = open_log_file(log_filename0)
            if ROOT and (uid > 0 or gid > 0):
                try:
                    os.fchown(logfd, uid, gid)
                except:
                    pass
            stdout, stderr = redirect_std_to_log(logfd, *protected_fds)
            try:
                stderr.write("Entering daemon mode; " +
                             "any further errors will be reported to:\n" +
                             ("  %s\n" % log_filename0))
            except IOError:
                #we tried our best, logging another error won't help
                pass

    #warn early about this:
    if (starting or starting_desktop
        ) and desktop_display and opts.notifications and not opts.dbus_launch:
        print_DE_warnings()

    log = get_util_logger()
    sockets, mdns_recs, wrap_socket_fn = create_sockets(opts, error_cb)

    sanitize_env()
    if POSIX:
        if xrd:
            os.environ["XDG_RUNTIME_DIR"] = xrd
        os.environ["XDG_SESSION_TYPE"] = "x11"
        if not starting_desktop:
            os.environ["XDG_CURRENT_DESKTOP"] = opts.wm_name
        configure_imsettings_env(opts.input_method)
    if display_name[0] != 'S':
        os.environ["DISPLAY"] = display_name
        os.environ["CKCON_X11_DISPLAY"] = display_name
    else:
        try:
            del os.environ["DISPLAY"]
        except KeyError:
            pass
    os.environ.update(protected_env)
    log("env=%s", os.environ)

    UINPUT_UUID_LEN = 12
    UINPUT_UUID_MIN_LEN = 12
    UINPUT_UUID_MAX_LEN = 32
    # Start the Xvfb server first to get the display_name if needed
    odisplay_name = display_name
    xvfb = None
    xvfb_pid = None
    uinput_uuid = None
    if start_vfb:
        assert not proxying and xauth_data
        pixel_depth = validate_pixel_depth(opts.pixel_depth, starting_desktop)
        from xpra.x11.vfb_util import start_Xvfb, check_xvfb_process
        from xpra.server.server_util import has_uinput
        uinput_uuid = None
        if has_uinput() and opts.input_devices.lower() in (
                "uinput", "auto") and not shadowing:
            from xpra.os_util import get_rand_chars
            uinput_uuid = get_rand_chars(UINPUT_UUID_LEN)
        xvfb, display_name, cleanups = start_Xvfb(opts.xvfb, pixel_depth,
                                                  display_name, cwd, uid, gid,
                                                  username, xauth_data,
                                                  uinput_uuid)
        for f in cleanups:
            add_cleanup(f)
        xvfb_pid = xvfb.pid
        #always update as we may now have the "real" display name:
        os.environ["DISPLAY"] = display_name
        os.environ["CKCON_X11_DISPLAY"] = display_name
        os.environ.update(protected_env)
        if display_name != odisplay_name and pam:
            pam.set_items({"XDISPLAY": display_name})

        def check_xvfb():
            return check_xvfb_process(xvfb)
    else:
        if POSIX and clobber:
            #if we're meant to be using a private XAUTHORITY file,
            #make sure to point to it:
            from xpra.x11.vfb_util import get_xauthority_path
            xauthority = get_xauthority_path(display_name, username, uid, gid)
            if os.path.exists(xauthority):
                os.environ["XAUTHORITY"] = xauthority

        def check_xvfb():
            return True

    if POSIX and not OSX and displayfd > 0:
        from xpra.platform.displayfd import write_displayfd
        try:
            display = display_name[1:]
            log("writing display='%s' to displayfd=%i", display, displayfd)
            assert write_displayfd(displayfd, display), "timeout"
        except Exception as e:
            log.error("write_displayfd failed", exc_info=True)
            log.error("Error: failed to write '%s' to fd=%s", display_name,
                      displayfd)
            log.error(" %s", str(e) or type(e))
            del e
        try:
            os.close(displayfd)
        except IOError:
            pass

    kill_display = None
    if not proxying:
        add_cleanup(close_gtk_display)
    if not proxying and not shadowing:

        def kill_display():
            if xvfb_pid:
                kill_xvfb(xvfb_pid)

        add_cleanup(kill_display)

    if opts.daemon:

        def noerr(fn, *args):
            try:
                fn(*args)
            except:
                pass

        log_filename1 = osexpand(
            select_log_file(log_dir, opts.log_file, display_name), username,
            uid, gid)
        if log_filename0 != log_filename1:
            # we now have the correct log filename, so use it:
            os.rename(log_filename0, log_filename1)
            if odisplay_name != display_name:
                #this may be used by scripts, let's try not to change it:
                noerr(stderr.write, "Actual display used: %s\n" % display_name)
            noerr(stderr.write,
                  "Actual log file name is now: %s\n" % log_filename1)
            noerr(stderr.flush)
        noerr(stdout.close)
        noerr(stderr.close)
    #we should not be using stdout or stderr from this point:
    del stdout
    del stderr

    if not check_xvfb():
        #xvfb problem: exit now
        return 1

    #create devices for vfb if needed:
    devices = {}
    if not start_vfb and not proxying and not shadowing:
        #try to find the existing uinput uuid:
        #use a subprocess to avoid polluting our current process
        #with X11 connections before we get a chance to change uid
        prop = "_XPRA_UINPUT_ID"
        cmd = ["xprop", "-display", display_name, "-root", prop]
        log("looking for '%s' on display '%s' with XAUTHORITY='%s'", prop,
            display_name, os.environ.get("XAUTHORITY"))
        try:
            code, out, err = get_status_output(cmd)
        except Exception as e:
            log("failed to get existing uinput id: %s", e)
            del e
        else:
            log("Popen(%s)=%s", cmd, (code, out, err))
            if code == 0 and out.find("=") > 0:
                uinput_uuid = out.split("=", 1)[1]
                log("raw uinput uuid=%s", uinput_uuid)
                uinput_uuid = strtobytes(uinput_uuid.strip('\n\r"\\ '))
                if uinput_uuid:
                    if len(uinput_uuid) > UINPUT_UUID_MAX_LEN or len(
                            uinput_uuid) < UINPUT_UUID_MIN_LEN:
                        log.warn("Warning: ignoring invalid uinput id:")
                        log.warn(" '%s'", uinput_uuid)
                        uinput_uuid = None
                    else:
                        log.info("retrieved existing uinput id: %s",
                                 bytestostr(uinput_uuid))
    if uinput_uuid:
        devices = create_input_devices(uinput_uuid, uid)

    if ROOT and (uid != 0 or gid != 0):
        log("root: switching to uid=%i, gid=%i", uid, gid)
        setuidgid(uid, gid)
        os.environ.update({
            "HOME": home,
            "USER": username,
            "LOGNAME": username,
        })
        shell = get_shell_for_uid(uid)
        if shell:
            os.environ["SHELL"] = shell
        #now we've changed uid, it is safe to honour all the env updates:
        configure_env(opts.env)
        os.environ.update(protected_env)

    if opts.chdir:
        os.chdir(opts.chdir)

    display = None
    if not proxying:
        no_gtk()
        if POSIX and not OSX and (starting or starting_desktop or shadowing):
            #check that we can access the X11 display:
            from xpra.x11.vfb_util import verify_display_ready
            if not verify_display_ready(xvfb, display_name, shadowing):
                return 1
            if not PYTHON3:
                from xpra.x11.gtk2.gdk_display_util import verify_gdk_display  #@UnusedImport
            else:
                from xpra.x11.gtk3.gdk_display_util import verify_gdk_display  #@Reimport
            display = verify_gdk_display(display_name)
            if not display:
                return 1
        #on win32, this ensures that we get the correct screen size to shadow:
        from xpra.platform.gui import init as gui_init
        gui_init()

    #setup unix domain socket:
    from xpra.server.socket_util import get_network_logger, setup_local_sockets
    netlog = get_network_logger()
    if not opts.socket_dir and not opts.socket_dirs:
        #we always need at least one valid socket dir
        from xpra.platform.paths import get_socket_dirs
        opts.socket_dirs = get_socket_dirs()
    local_sockets = setup_local_sockets(opts.bind, opts.socket_dir,
                                        opts.socket_dirs, display_name,
                                        clobber, opts.mmap_group,
                                        opts.socket_permissions, username, uid,
                                        gid)
    netlog("setting up local sockets: %s", local_sockets)
    ssh_port = get_ssh_port()
    ssh_access = ssh_port > 0 and opts.ssh.lower().strip() not in FALSE_OPTIONS
    for rec, cleanup_socket in local_sockets:
        socktype, socket, sockpath = rec
        #ie: ("unix-domain", sock, sockpath), cleanup_socket
        sockets.append(rec)
        netlog("%s %s : %s", socktype, sockpath, socket)
        add_cleanup(cleanup_socket)
        if opts.mdns and ssh_access:
            netlog("ssh %s:%s : %s", "", ssh_port, socket)
            add_mdns(mdns_recs, "ssh", "", ssh_port)

    def b(v):
        return str(v).lower() not in FALSE_OPTIONS

    #turn off some server mixins:
    from xpra.server import server_features
    impwarned = []

    def impcheck(*modules):
        for mod in modules:
            try:
                __import__("xpra.%s" % mod, {}, {}, [])
            except ImportError:
                if mod not in impwarned:
                    impwarned.append(mod)
                    log = get_util_logger()
                    log.warn("Warning: missing %s module", mod)
                return False
        return True

    server_features.notifications = opts.notifications and impcheck(
        "notifications")
    server_features.webcam = b(opts.webcam) and impcheck("codecs")
    server_features.clipboard = b(opts.clipboard) and impcheck("clipboard")
    server_features.audio = (b(opts.speaker)
                             or b(opts.microphone)) and impcheck("sound")
    server_features.av_sync = server_features.audio and b(opts.av_sync)
    server_features.fileprint = b(opts.printing) or b(opts.file_transfer)
    server_features.mmap = b(opts.mmap)
    server_features.input_devices = not opts.readonly and impcheck("keyboard")
    server_features.commands = impcheck("server.control_command")
    server_features.dbus = opts.dbus_proxy and impcheck("dbus")
    server_features.encoding = impcheck("codecs")
    server_features.logging = b(opts.remote_logging)
    #server_features.network_state   = ??
    server_features.display = opts.windows
    server_features.windows = opts.windows and impcheck("codecs")
    server_features.rfb = b(opts.rfb_upgrade) and impcheck("server.rfb")

    kill_dbus = None
    if shadowing:
        app = make_shadow_server()
    elif proxying:
        app = make_proxy_server()
    else:
        if not check_xvfb():
            return 1
        assert starting or starting_desktop or upgrading
        from xpra.x11.gtk_x11.gdk_display_source import init_gdk_display_source, close_gdk_display_source
        init_gdk_display_source()
        insert_cleanup(close_gdk_display_source)
        #(now we can access the X11 server)

        #make sure the pid we save is the real one:
        if not check_xvfb():
            return 1
        if xvfb_pid is not None:
            #save the new pid (we should have one):
            save_xvfb_pid(xvfb_pid)

        if POSIX:
            save_uinput_id(uinput_uuid)
            dbus_pid = -1
            dbus_env = {}
            if clobber:
                #get the saved pids and env
                dbus_pid = get_dbus_pid()
                dbus_env = get_dbus_env()
                log("retrieved existing dbus attributes")
            else:
                assert starting or starting_desktop
                if xvfb_pid is not None:
                    #save the new pid (we should have one):
                    save_xvfb_pid(xvfb_pid)
                bus_address = protected_env.get("DBUS_SESSION_BUS_ADDRESS")
                log("dbus_launch=%s, current DBUS_SESSION_BUS_ADDRESS=%s",
                    opts.dbus_launch, bus_address)
                if opts.dbus_launch and not bus_address:
                    #start a dbus server:
                    def kill_dbus():
                        log("kill_dbus: dbus_pid=%s" % dbus_pid)
                        if dbus_pid <= 0:
                            return
                        try:
                            os.kill(dbus_pid, signal.SIGINT)
                        except Exception as e:
                            log.warn(
                                "Warning: error trying to stop dbus with pid %i:",
                                dbus_pid)
                            log.warn(" %s", e)

                    add_cleanup(kill_dbus)
                    #this also updates os.environ with the dbus attributes:
                    dbus_pid, dbus_env = start_dbus(opts.dbus_launch)
                    if dbus_pid > 0:
                        save_dbus_pid(dbus_pid)
                    if dbus_env:
                        save_dbus_env(dbus_env)
            log("dbus attributes: pid=%s, env=%s", dbus_pid, dbus_env)
            if dbus_env:
                os.environ.update(dbus_env)
                os.environ.update(protected_env)

        if POSIX:
            #all unix domain sockets:
            ud_paths = [
                sockpath for (stype, _, sockpath), _ in local_sockets
                if stype == "unix-domain"
            ]
            if ud_paths:
                #choose one so our xdg-open override script can use to talk back to us:
                if opts.forward_xdg_open:
                    for x in ("/usr/libexec/xpra", "/usr/lib/xpra"):
                        xdg_override = os.path.join(x, "xdg-open")
                        if os.path.exists(xdg_override):
                            os.environ[
                                "PATH"] = x + os.pathsep + os.environ.get(
                                    "PATH", "")
                            os.environ[
                                "XPRA_XDG_OPEN_SERVER_SOCKET"] = ud_paths[0]
                            break
            else:
                log.warn("Warning: no local server sockets,")
                if opts.forward_xdg_open:
                    log.warn(" forward-xdg-open cannot be enabled")
                log.warn(" ssh connections will not be available")

        log("env=%s", os.environ)
        try:
            # This import is delayed because the module depends on gtk:
            from xpra.x11.bindings.window_bindings import X11WindowBindings
            X11Window = X11WindowBindings()
            if (starting or
                    starting_desktop) and not clobber and opts.resize_display:
                from xpra.x11.vfb_util import set_initial_resolution
                set_initial_resolution(starting_desktop)
        except ImportError as e:
            log.error(
                "Failed to load Xpra server components, check your installation: %s"
                % e)
            return 1
        if starting or upgrading:
            if not X11Window.displayHasXComposite():
                log.error(
                    "Xpra 'start' subcommand runs as a compositing manager")
                log.error(
                    " it cannot use a display which lacks the XComposite extension!"
                )
                return 1
            if starting:
                #check for an existing window manager:
                from xpra.x11.gtk_x11.wm_check import wm_check
                if not wm_check(display, opts.wm_name, upgrading):
                    return 1
            log("XShape=%s", X11Window.displayHasXShape())
            app = make_server(clobber)
        else:
            assert starting_desktop
            app = make_desktop_server()
        app.init_virtual_devices(devices)

    if proxying or upgrading:
        #when proxying or upgrading, don't exec any plain start commands:
        opts.start = opts.start_child = []
    elif opts.exit_with_children:
        assert opts.start_child, "exit-with-children was specified but start-child is missing!"
    elif opts.start_child:
        log.warn("Warning: the 'start-child' option is used,")
        log.warn(" but 'exit-with-children' is not enabled,")
        log.warn(" use 'start' instead")

    try:
        app._ssl_wrap_socket = wrap_socket_fn
        app.original_desktop_display = desktop_display
        app.exec_cwd = opts.chdir or cwd
        app.init(opts)
        app.setup()
    except InitException as e:
        log.error("xpra server initialization error:")
        log.error(" %s", e)
        return 1
    except Exception as e:
        log.error("Error: cannot start the %s server",
                  app.session_type,
                  exc_info=True)
        log.error(str(e))
        log.info("")
        return 1

    #publish mdns records:
    if opts.mdns:
        from xpra.platform.info import get_username
        from xpra.server.socket_util import mdns_publish
        mdns_info = {
            "display": display_name,
            "username": get_username(),
            "uuid": app.uuid,
            "platform": sys.platform,
            "type": app.session_type,
        }
        MDNS_EXPOSE_NAME = envbool("XPRA_MDNS_EXPOSE_NAME", True)
        if MDNS_EXPOSE_NAME and app.session_name:
            mdns_info["name"] = app.session_name
        for mode, listen_on in mdns_recs.items():
            mdns_publish(display_name, mode, listen_on, mdns_info)

    del opts

    log("%s(%s)", app.init_sockets, sockets)
    app.init_sockets(sockets)
    log("%s(%s)", app.init_when_ready, _when_ready)
    app.init_when_ready(_when_ready)

    try:
        #from here on, we own the vfb, even if we inherited one:
        if (starting or starting_desktop or upgrading) and clobber:
            #and it will be killed if exit cleanly:
            xvfb_pid = get_xvfb_pid()

        log("running %s", app.run)
        r = app.run()
        log("%s()=%s", app.run, r)
    except KeyboardInterrupt:
        log.info("stopping on KeyboardInterrupt")
        return 0
    except Exception:
        log.error("server error", exc_info=True)
        return -128
    else:
        if r > 0:
            # Upgrading/exiting, so leave X and dbus servers running
            if kill_display:
                _cleanups.remove(kill_display)
            if kill_dbus:
                _cleanups.remove(kill_dbus)
            from xpra.server import EXITING_CODE
            if r == EXITING_CODE:
                log.info("exiting: not cleaning up Xvfb")
            else:
                log.info("upgrading: not cleaning up Xvfb")
            r = 0
    return r
Exemple #12
0
 def __init__(self, username):
     self.salt = None
     self.pw = None
     self.username = get_username()
Exemple #13
0
def get_defaults():
    global GLOBAL_DEFAULTS
    if GLOBAL_DEFAULTS is not None:
        return GLOBAL_DEFAULTS
    from xpra.platform.features import DEFAULT_SSH_COMMAND, OPEN_COMMAND, DEFAULT_PULSEAUDIO_CONFIGURE_COMMANDS, DEFAULT_PULSEAUDIO_COMMAND, XDUMMY, XDUMMY_WRAPPER, DISPLAYFD, DEFAULT_ENV, CAN_DAEMONIZE
    from xpra.platform.paths import get_download_dir, get_default_log_dir, get_socket_dirs, get_remote_run_xpra_scripts
    try:
        from xpra.platform.info import get_username
        username = get_username()
    except:
        username = ""
    if WIN32 or OSX or PYTHON3:
        xvfb = ""
    elif XDUMMY:
        xvfb = get_Xdummy_command(use_wrapper=XDUMMY_WRAPPER, log_dir=get_default_log_dir())
    else:
        xvfb = get_Xvfb_command()
    def addtrailingslash(v):
        if v.endswith("/"):
            return v
        return v+"/"
    if WIN32:
        bind_dirs = []
    else:
        bind_dirs = [addtrailingslash(get_socket_dirs()[0])]

    GLOBAL_DEFAULTS = {
                    "encoding"          : "",
                    "title"             : "@title@ on @client-machine@",
                    "username"          : username,
                    "auth"              : "",
                    "vsock-auth"        : "",
                    "tcp-auth"          : "",
                    "wm-name"           : DEFAULT_NET_WM_NAME,
                    "session-name"      : "",
                    "dock-icon"         : "",
                    "tray-icon"         : "",
                    "window-icon"       : "",
                    "password-file"     : "",
                    "clipboard"         : "yes",
                    "clipboard-filter-file" : "",
                    "remote-clipboard"  : "CLIPBOARD",
                    "local-clipboard"   : "CLIPBOARD",
                    "pulseaudio-command": " ".join(DEFAULT_PULSEAUDIO_COMMAND),
                    "encryption"        : "",
                    "tcp-encryption"    : "",
                    "encryption-keyfile": "",
                    "tcp-encryption-keyfile": "",
                    "ssh"               : DEFAULT_SSH_COMMAND,
                    "xvfb"              : " ".join(xvfb),
                    "socket-dir"        : "",
                    "log-dir"           : get_default_log_dir(),
                    "log-file"          : "$DISPLAY.log",
                    "border"            : "auto,5:off",
                    "window-close"      : "auto",
                    "max-size"          : "",
                    "desktop-scaling"   : "auto",
                    "display"           : "",
                    "tcp-proxy"         : "",
                    "download-path"     : get_download_dir(),
                    "open-command"      : OPEN_COMMAND,
                    "remote-logging"    : "both",
                    "lpadmin"           : "/usr/sbin/lpadmin",
                    "lpinfo"            : "/usr/sbin/lpinfo",
                    "pdf-printer"       : "",
                    "postscript-printer": "",
                    "debug"             : "",
                    "input-method"      : "none",
                    "sound-source"      : "",
                    "html"              : "",
                    "socket-permissions": "600",
                    "exec-wrapper"      : "",
                    "dbus-launch"       : "dbus-launch --close-stderr",
                    "webcam"            : "auto",
                    "quality"           : 0,
                    "min-quality"       : 30,
                    "speed"             : 0,
                    "min-speed"         : 30,
                    "compression_level" : 1,
                    "dpi"               : 0,
                    "video-scaling"     : 1,
                    "file-size-limit"   : 10,
                    "idle-timeout"      : 0,
                    "server-idle-timeout" : 0,
                    "sync-xvfb"         : 0,
                    "auto-refresh-delay": 0.15,
                    "daemon"            : CAN_DAEMONIZE,
                    "use-display"       : False,
                    "displayfd"         : DISPLAYFD,
                    "fake-xinerama"     : not OSX and not WIN32,
                    "resize-display"    : not OSX and not WIN32,
                    "tray"              : True,
                    "pulseaudio"        : not OSX and not WIN32,
                    "dbus-proxy"        : not OSX and not WIN32,
                    "mmap"              : ["off", "on"][not OSX and not WIN32],
                    "mmap-group"        : False,
                    "speaker"           : ["disabled", "on"][has_sound_support],
                    "microphone"        : ["disabled", "off"][has_sound_support],
                    "readonly"          : False,
                    "keyboard-sync"     : True,
                    "pings"             : False,
                    "cursors"           : True,
                    "bell"              : True,
                    "notifications"     : True,
                    "xsettings"         : not OSX and not WIN32,
                    "system-tray"       : True,
                    "sharing"           : False,
                    "delay-tray"        : False,
                    "windows"           : True,
                    "exit-with-children": False,
                    "exit-with-client"  : False,
                    "start-after-connect": False,
                    "start-new-commands": False,
                    "av-sync"           : True,
                    "exit-ssh"          : True,
                    "dbus-control"      : not WIN32 and not OSX,
                    "opengl"            : OPENGL_DEFAULT,
                    "mdns"              : not WIN32,
                    "file-transfer"     : True,
                    "printing"          : True,
                    "open-files"        : False,
                    "swap-keys"         : OSX,  #only used on osx
                    "shadow-fullscreen" : False,
                    "global-menus"      : True,
                    "pulseaudio-configure-commands"  : [" ".join(x) for x in DEFAULT_PULSEAUDIO_CONFIGURE_COMMANDS],
                    "socket-dirs"       : [],
                    "remote-xpra"       : get_remote_run_xpra_scripts(),
                    "encodings"         : ["all"],
                    "video-encoders"    : ["all"],
                    "csc-modules"       : ["all"],
                    "video-decoders"    : ["all"],
                    "speaker-codec"     : [],
                    "microphone-codec"  : [],
                    "compressors"       : ["all"],
                    "packet-encoders"   : ["all"],
                    "key-shortcut"      : get_default_key_shortcuts(),
                    "bind"              : bind_dirs,
                    "bind-vsock"        : [],
                    "bind-tcp"          : [],
                    "start"             : [],
                    "start-child"       : [],
                    "start-after-connect"       : [],
                    "start-child-after-connect" : [],
                    "start-on-connect"          : [],
                    "start-child-on-connect"    : [],
                    "env"               : DEFAULT_ENV,
                    }
    return GLOBAL_DEFAULTS
Exemple #14
0
def run_server(error_cb, opts, mode, xpra_file, extra_args):
    try:
        cwd = os.getcwd()
    except:
        cwd = os.path.expanduser("~")
        sys.stderr.write("current working directory does not exist, using '%s'\n" % cwd)
    if opts.encoding and opts.encoding=="help":
        #avoid errors and warnings:
        opts.encoding = ""
        opts.clipboard = False
        opts.notifications = False
        print("xpra server supports the following encodings:")
        print("(please wait, encoder initialization may take a few seconds)")
        #disable info logging which would be confusing here
        from xpra.log import get_all_loggers, set_default_level
        import logging
        set_default_level(logging.WARN)
        logging.root.setLevel(logging.WARN)
        for x in get_all_loggers():
            x.logger.setLevel(logging.WARN)
        from xpra.server.server_base import ServerBase
        sb = ServerBase()
        sb.init(opts)
        #ensures that the threaded video helper init has completed
        #(by running it again, which will block on the init lock)
        from xpra.codecs.video_helper import getVideoHelper
        getVideoHelper().init()
        sb.init_encodings()
        from xpra.codecs.loader import encoding_help
        for e in sb.encodings:
            print(" * %s" % encoding_help(e))
        return 0

    assert mode in ("start", "upgrade", "shadow", "proxy")
    starting  = mode == "start"
    upgrading = mode == "upgrade"
    shadowing = mode == "shadow"
    proxying  = mode == "proxy"
    clobber   = upgrading or opts.use_display

    if upgrading or shadowing:
        #there should already be one running
        opts.pulseaudio = False

    #get the display name:
    if shadowing and len(extra_args)==0:
        if sys.platform.startswith("win") or sys.platform.startswith("darwin"):
            #just a virtual name for the only display available:
            display_name = ":0"
        else:
            from xpra.scripts.main import guess_X11_display
            display_name = guess_X11_display(opts.socket_dir)
    elif upgrading and len(extra_args)==0:
        from xpra.scripts.main import guess_xpra_display
        display_name = guess_xpra_display(opts.socket_dir)
    else:
        if len(extra_args) > 1:
            error_cb("too many extra arguments: only expected a display number")
        if len(extra_args) == 1:
            display_name = extra_args[0]
            if not shadowing and not proxying:
                display_name_check(display_name)
        else:
            if proxying:
                error_cb("you must specify a free virtual display name to use with the proxy server")
            if not opts.displayfd:
                error_cb("displayfd support is not enabled on this system, you must specify the display to use")
            if opts.use_display:
                #only use automatic guess for xpra displays and not X11 displays:
                from xpra.scripts.main import guess_xpra_display     #@Reimport
                display_name = guess_xpra_display(opts.socket_dir)
            else:
                # We will try to find one automaticaly
                # Use the temporary magic value 'S' as marker:
                display_name = 'S' + str(os.getpid())

    if not shadowing and not proxying and not upgrading and opts.exit_with_children and not opts.start_child:
        error_cb("--exit-with-children specified without any children to spawn; exiting immediately")

    atexit.register(run_cleanups)
    #the server class will usually override those:
    signal.signal(signal.SIGINT, deadly_signal)
    signal.signal(signal.SIGTERM, deadly_signal)

    dotxpra = DotXpra(opts.socket_dir)

    # Generate the script text now, because os.getcwd() will
    # change if/when we daemonize:
    script = xpra_runner_shell_script(xpra_file, os.getcwd(), opts.socket_dir)

    stdout = sys.stdout
    stderr = sys.stderr
    # Daemonize:
    if opts.daemon:
        #daemonize will chdir to "/", so try to use an absolute path:
        if opts.password_file:
            opts.password_file = os.path.abspath(opts.password_file)
        # At this point we may not know the display name,
        # so log_filename0 may point to a temporary file which we will rename later
        log_filename0 = select_log_file(dotxpra, opts.log_file, display_name)
        logfd = open_log_file(log_filename0)
        assert logfd > 2
        stdout, stderr = daemonize(logfd)
        try:
            stderr.write("Entering daemon mode; "
                 + "any further errors will be reported to:\n"
                 + ("  %s\n" % log_filename0))
        except:
            #this can happen if stderr is closed by the caller already
            pass

    if os.name=="posix":
        # Write out a shell-script so that we can start our proxy in a clean
        # environment:
        write_runner_shell_script(dotxpra, script)

    from xpra.log import Logger
    log = Logger("server")

    mdns_recs = []
    sockets = []
    try:
        # Initialize the TCP sockets before the display,
        # That way, errors won't make us kill the Xvfb
        # (which may not be ours to kill at that point)
        bind_tcp = parse_bind_tcp(opts.bind_tcp)
        for host, iport in bind_tcp:
            socket = setup_tcp_socket(host, iport)
            sockets.append(socket)
        if opts.mdns:
            mdns_recs.append(("tcp", bind_tcp))
    except Exception as e:
        log.error("cannot start server: failed to setup sockets: %s", e)
        return 1

    # Do this after writing out the shell script:
    if display_name[0] != 'S':
        os.environ["DISPLAY"] = display_name
    sanitize_env()
    configure_imsettings_env(opts.input_method)

    # Start the Xvfb server first to get the display_name if needed
    xvfb = None
    xvfb_pid = None
    if not shadowing and not proxying and not clobber:
        try:
            xvfb, display_name = start_Xvfb(opts.xvfb, display_name)
        except OSError as e:
            log.error("Error starting Xvfb: %s\n", e)
            return  1
        xvfb_pid = xvfb.pid
        #always update as we may now have the "real" display name:
        os.environ["DISPLAY"] = display_name

    if opts.daemon:
        log_filename1 = select_log_file(dotxpra, opts.log_file, display_name)
        if log_filename0 != log_filename1:
            # we now have the correct log filename, so use it:
            os.rename(log_filename0, log_filename1)
            stderr.write("Actual log file name is now: %s\n" % log_filename1)
        stdout.close()
        stderr.close()

    if not check_xvfb_process(xvfb):
        #xvfb problem: exit now
        return  1

    #setup unix domain socket:
    socket, cleanup_socket = setup_local_socket(dotxpra, display_name, clobber, opts.mmap_group, opts.socket_permissions)
    if socket:      #win32 returns None!
        sockets.append(socket)
        if opts.mdns:
            ssh_port = get_ssh_port()
            if ssh_port:
                mdns_recs.append(("ssh", [("", ssh_port)]))

    #publish mdns records:
    if opts.mdns:
        from xpra.platform.info import get_username
        mdns_info = {"display" : display_name,
                     "username": get_username()}
        if opts.session_name:
            mdns_info["session"] = opts.session_name
        for mode, listen_on in mdns_recs:
            mdns_publish(display_name, mode, listen_on, mdns_info)

    if not check_xvfb_process(xvfb):
        #xvfb problem: exit now
        return  1

    display = None
    if not sys.platform.startswith("win") and not sys.platform.startswith("darwin") and not proxying:
        display = verify_display_ready(xvfb, display_name, shadowing)
        if not display:
            return 1
    elif not proxying:
        assert "gtk" not in sys.modules
        import gtk          #@Reimport
        assert gtk

    if shadowing:
        from xpra.platform.shadow_server import ShadowServer
        app = ShadowServer()
        info = "shadow"
    elif proxying:
        from xpra.server.proxy_server import ProxyServer
        app = ProxyServer()
        info = "proxy"
    else:
        assert starting or upgrading
        from xpra.x11.gtk_x11 import gdk_display_source
        assert gdk_display_source
        #(now we can access the X11 server)

        if clobber:
            #get the saved pid (there should be one):
            xvfb_pid = get_xvfb_pid()
        elif xvfb_pid is not None:
            #save the new pid (we should have one):
            save_xvfb_pid(xvfb_pid)

        #check for an existing window manager:
        from xpra.x11.gtk_x11.wm import wm_check
        if not wm_check(display, opts.wm_name, upgrading):
            return 1
        try:
            # This import is delayed because the module depends on gtk:
            from xpra.x11.server import XpraServer
            from xpra.x11.bindings.window_bindings import X11WindowBindings     #@UnresolvedImport
            X11Window = X11WindowBindings()
        except ImportError as e:
            log.error("Failed to load Xpra server components, check your installation: %s" % e)
            return 1
        if not X11Window.displayHasXComposite():
            log.error("Xpra is a compositing manager, it cannot use a display which lacks the XComposite extension!")
            return 1
        app = XpraServer(clobber)
        info = "xpra"

    try:
        app.exec_cwd = cwd
        app.init(opts)
    except Exception as e:
        log.error("Error: cannot start the %s server", info, exc_info=True)
        log.error(str(e))
        log.info("")
        return 1

    #honour start child, html webserver, and setup child reaper
    if os.name=="posix" and not proxying and not upgrading and not shadowing:
        # start websockify?
        try:
            start_websockify(app.child_reaper, opts, bind_tcp)
            #websockify overrides the tcp proxy, so we must re-set it:
            app._tcp_proxy = opts.tcp_proxy
        except Exception as e:
            error_cb("failed to setup websockify html server: %s" % e)
        if opts.exit_with_children:
            assert opts.start_child, "exit-with-children was specified but start-child is missing!"
        if opts.start:
            for x in opts.start:
                if x:
                    app.start_child(x, x, True)
        if opts.start_child:
            for x in opts.start_child:
                if x:
                    app.start_child(x, x, False)

    log("%s(%s)", app.init_sockets, sockets)
    app.init_sockets(sockets)
    log("%s(%s)", app.init_when_ready, _when_ready)
    app.init_when_ready(_when_ready)

    #we got this far so the sockets have initialized and
    #the server should be able to manage the display
    #from now on, if we exit without upgrading we will also kill the Xvfb
    def kill_xvfb():
        # Close our display(s) first, so the server dying won't kill us.
        log.info("killing xvfb with pid %s" % xvfb_pid)
        import gtk  #@Reimport
        for display in gtk.gdk.display_manager_get().list_displays():
            display.close()
        os.kill(xvfb_pid, signal.SIGTERM)
    if xvfb_pid is not None and not opts.use_display and not shadowing:
        _cleanups.append(kill_xvfb)

    try:
        log("running %s", app.run)
        e = app.run()
        log("%s()=%s", app.run, e)
    except KeyboardInterrupt:
        log.info("stopping on KeyboardInterrupt")
        e = 0
    except Exception as e:
        log.error("server error", exc_info=True)
        e = -128
    if e>0:
        # Upgrading/exiting, so leave X server running
        if kill_xvfb in _cleanups:
            _cleanups.remove(kill_xvfb)
        from xpra.server.server_core import ServerCore
        if e==ServerCore.EXITING_CODE:
            log.info("exiting: not cleaning up Xvfb")
        elif cleanup_socket in _cleanups:
            log.info("upgrading: not cleaning up Xvfb or socket")
            # don't delete the new socket (not ours)
            _cleanups.remove(cleanup_socket)
        log("cleanups=%s", _cleanups)
        e = 0
    return e
Exemple #15
0
 def __init__(self, username, **kwargs):
     SysAuthenticator.__init__(self, username, **kwargs)
     self.salt = None
     self.pw = None
     self.username = get_username()
Exemple #16
0
def run_server(error_cb, opts, mode, xpra_file, extra_args):
    try:
        cwd = os.getcwd()
    except:
        cwd = os.path.expanduser("~")
        sys.stderr.write(
            "current working directory does not exist, using '%s'\n" % cwd)
    if opts.encoding and opts.encoding == "help":
        #avoid errors and warnings:
        opts.encoding = ""
        opts.clipboard = False
        opts.notifications = False
        print("xpra server supports the following encodings:")
        print("(please wait, encoder initialization may take a few seconds)")
        #disable info logging which would be confusing here
        from xpra.log import get_all_loggers, set_default_level
        import logging
        set_default_level(logging.WARN)
        logging.root.setLevel(logging.WARN)
        for x in get_all_loggers():
            x.logger.setLevel(logging.WARN)
        from xpra.server.server_base import ServerBase
        sb = ServerBase()
        sb.init(opts)
        #ensures that the threaded video helper init has completed
        #(by running it again, which will block on the init lock)
        from xpra.codecs.video_helper import getVideoHelper
        getVideoHelper().init()
        sb.init_encodings()
        from xpra.codecs.loader import encoding_help
        for e in sb.encodings:
            print(" * %s" % encoding_help(e))
        return 0

    assert mode in ("start", "upgrade", "shadow", "proxy")
    starting = mode == "start"
    upgrading = mode == "upgrade"
    shadowing = mode == "shadow"
    proxying = mode == "proxy"
    clobber = upgrading or opts.use_display
    start_vfb = not shadowing and not proxying and not clobber

    if upgrading or shadowing:
        #there should already be one running
        opts.pulseaudio = False

    #get the display name:
    if shadowing and len(extra_args) == 0:
        if sys.platform.startswith("win") or sys.platform.startswith("darwin"):
            #just a virtual name for the only display available:
            display_name = ":0"
        else:
            from xpra.scripts.main import guess_X11_display
            display_name = guess_X11_display(opts.socket_dir, opts.socket_dirs)
    elif upgrading and len(extra_args) == 0:
        display_name = guess_xpra_display(opts.socket_dir, opts.socket_dirs)
    else:
        if len(extra_args) > 1:
            error_cb(
                "too many extra arguments: only expected a display number")
        if len(extra_args) == 1:
            display_name = extra_args[0]
            if not shadowing and not proxying:
                display_name_check(display_name)
        else:
            if proxying:
                error_cb(
                    "you must specify a free virtual display name to use with the proxy server"
                )
            if not opts.displayfd:
                error_cb(
                    "displayfd support is not enabled on this system, you must specify the display to use"
                )
            if opts.use_display:
                #only use automatic guess for xpra displays and not X11 displays:
                display_name = guess_xpra_display(opts.socket_dir,
                                                  opts.socket_dirs)
            else:
                # We will try to find one automaticaly
                # Use the temporary magic value 'S' as marker:
                display_name = 'S' + str(os.getpid())

    if not shadowing and not proxying and not upgrading and opts.exit_with_children and not opts.start_child:
        error_cb(
            "--exit-with-children specified without any children to spawn; exiting immediately"
        )

    atexit.register(run_cleanups)
    #the server class will usually override those:
    #SIGINT breaks GTK3.. (but there are no py3k servers!)
    signal.signal(signal.SIGINT, deadly_signal)
    signal.signal(signal.SIGTERM, deadly_signal)

    # Generate the script text now, because os.getcwd() will
    # change if/when we daemonize:
    script = xpra_runner_shell_script(xpra_file, os.getcwd(), opts.socket_dir)

    if start_vfb or opts.daemon:
        #we will probably need a log dir
        #either for the vfb, or for our own log file
        log_dir = os.path.expanduser(opts.log_dir)
        if not os.path.exists(log_dir):
            try:
                os.mkdir(log_dir, 0o700)
            except OSError as e:
                raise InitException(
                    "failed to create the Xorg log directory '%s': %s" %
                    (xorg_log_dir, e))

    stdout = sys.stdout
    stderr = sys.stderr
    # Daemonize:
    if opts.daemon:
        #daemonize will chdir to "/", so try to use an absolute path:
        if opts.password_file:
            opts.password_file = os.path.abspath(opts.password_file)
        # At this point we may not know the display name,
        # so log_filename0 may point to a temporary file which we will rename later
        log_filename0 = select_log_file(log_dir, opts.log_file, display_name)
        logfd = open_log_file(log_filename0)
        assert logfd > 2
        stdout, stderr = daemonize(logfd)
        try:
            stderr.write("Entering daemon mode; " +
                         "any further errors will be reported to:\n" +
                         ("  %s\n" % log_filename0))
        except:
            #this can happen if stderr is closed by the caller already
            pass

    if os.name == "posix":
        # Write out a shell-script so that we can start our proxy in a clean
        # environment:
        write_runner_shell_script(script)

    from xpra.log import Logger
    log = Logger("server")

    #warn early about this:
    if starting:
        de = os.environ.get("XDG_SESSION_DESKTOP") or os.environ.get(
            "SESSION_DESKTOP")
        if de and (opts.pulseaudio or opts.notifications):
            log.warn(
                "Warning: xpra start from an existing '%s' desktop session",
                de)
            log.warn(" pulseaudio and notifications forwarding may not work")
            log.warn(
                " try using a clean environment, a dedicated user, or turn off those options"
            )

    mdns_recs = []
    sockets = []
    # Initialize the TCP sockets before the display,
    # That way, errors won't make us kill the Xvfb
    # (which may not be ours to kill at that point)
    bind_tcp = parse_bind_tcp(opts.bind_tcp)
    for host, iport in bind_tcp:
        socket = setup_tcp_socket(host, iport)
        sockets.append(socket)
        if opts.mdns:
            rec = "tcp", [(host, iport)]
            mdns_recs.append(rec)

    # Do this after writing out the shell script:
    if display_name[0] != 'S':
        os.environ["DISPLAY"] = display_name
    sanitize_env()
    configure_imsettings_env(opts.input_method)

    # Start the Xvfb server first to get the display_name if needed
    xvfb = None
    xvfb_pid = None
    if start_vfb:
        try:
            xvfb, display_name = start_Xvfb(opts.xvfb, display_name)
        except OSError as e:
            log.error("Error starting Xvfb: %s\n", e)
            return 1
        xvfb_pid = xvfb.pid
        #always update as we may now have the "real" display name:
        os.environ["DISPLAY"] = display_name

    if opts.daemon:
        log_filename1 = select_log_file(log_dir, opts.log_file, display_name)
        if log_filename0 != log_filename1:
            # we now have the correct log filename, so use it:
            os.rename(log_filename0, log_filename1)
            stderr.write("Actual log file name is now: %s\n" % log_filename1)
        stdout.close()
        stderr.close()

    if not check_xvfb_process(xvfb):
        #xvfb problem: exit now
        return 1

    #setup unix domain socket:
    socket, cleanup_socket = setup_local_socket(opts.socket_dir,
                                                opts.socket_dirs, display_name,
                                                clobber, opts.mmap_group,
                                                opts.socket_permissions)
    if socket:  #win32 returns None!
        sockets.append(socket)
        if opts.mdns:
            ssh_port = get_ssh_port()
            if ssh_port:
                mdns_recs.append(("ssh", [("", ssh_port)]))

    #publish mdns records:
    if opts.mdns:
        from xpra.platform.info import get_username
        mdns_info = {"display": display_name, "username": get_username()}
        if opts.session_name:
            mdns_info["session"] = opts.session_name
        for mode, listen_on in mdns_recs:
            mdns_publish(display_name, mode, listen_on, mdns_info)

    if not check_xvfb_process(xvfb):
        #xvfb problem: exit now
        return 1

    display = None
    if not sys.platform.startswith("win") and not sys.platform.startswith(
            "darwin") and not proxying:
        display = verify_display_ready(xvfb, display_name, shadowing)
        if not display:
            return 1
    elif not proxying:
        no_gtk()
        import gtk  #@Reimport
        assert gtk

    if shadowing:
        from xpra.platform.shadow_server import ShadowServer
        app = ShadowServer()
        info = "shadow"
    elif proxying:
        from xpra.server.proxy.proxy_server import ProxyServer
        app = ProxyServer()
        info = "proxy"
    else:
        assert starting or upgrading
        from xpra.x11.gtk2 import gdk_display_source
        assert gdk_display_source
        #(now we can access the X11 server)

        if clobber:
            #get the saved pid (there should be one):
            xvfb_pid = get_xvfb_pid()
        elif xvfb_pid is not None:
            #save the new pid (we should have one):
            save_xvfb_pid(xvfb_pid)

        #check for an existing window manager:
        from xpra.x11.gtk2.wm import wm_check
        if not wm_check(display, opts.wm_name, upgrading):
            return 1
        try:
            # This import is delayed because the module depends on gtk:
            from xpra.x11.server import XpraServer
            from xpra.x11.bindings.window_bindings import X11WindowBindings  #@UnresolvedImport
            X11Window = X11WindowBindings()
        except ImportError as e:
            log.error(
                "Failed to load Xpra server components, check your installation: %s"
                % e)
            return 1
        if not X11Window.displayHasXComposite():
            log.error(
                "Xpra is a compositing manager, it cannot use a display which lacks the XComposite extension!"
            )
            return 1
        log("XShape=%s", X11Window.displayHasXShape())
        app = XpraServer(clobber)
        info = "xpra"

    #we got this far so the sockets have initialized and
    #the server should be able to manage the display
    #from now on, if we exit without upgrading we will also kill the Xvfb
    def kill_xvfb():
        # Close our display(s) first, so the server dying won't kill us.
        log.info("killing xvfb with pid %s" % xvfb_pid)
        import gtk  #@Reimport
        for display in gtk.gdk.display_manager_get().list_displays():
            display.close()
        os.kill(xvfb_pid, signal.SIGTERM)

    if xvfb_pid is not None and not opts.use_display and not shadowing:
        _cleanups.append(kill_xvfb)

    try:
        app.exec_cwd = cwd
        app.init(opts)
    except InitException as e:
        log.error("xpra server initialization error:")
        log.error(" %s", e)
        return 1
    except Exception as e:
        log.error("Error: cannot start the %s server", info, exc_info=True)
        log.error(str(e))
        log.info("")
        return 1

    #honour start child, html webserver, and setup child reaper
    if os.name == "posix" and not proxying and not upgrading and not shadowing:
        # start websockify?
        try:
            start_websockify(app.child_reaper, opts, bind_tcp)
            #websockify overrides the tcp proxy, so we must re-set it:
            app._tcp_proxy = opts.tcp_proxy
        except Exception as e:
            error_cb("failed to setup websockify html server: %s" % e)
        if opts.exit_with_children:
            assert opts.start_child, "exit-with-children was specified but start-child is missing!"
        if opts.start:
            for x in opts.start:
                if x:
                    app.start_child(x, x, True)
        if opts.start_child:
            for x in opts.start_child:
                if x:
                    app.start_child(x, x, False)

    log("%s(%s)", app.init_sockets, sockets)
    app.init_sockets(sockets)
    log("%s(%s)", app.init_when_ready, _when_ready)
    app.init_when_ready(_when_ready)

    try:
        log("running %s", app.run)
        e = app.run()
        log("%s()=%s", app.run, e)
    except KeyboardInterrupt:
        log.info("stopping on KeyboardInterrupt")
        e = 0
    except Exception as e:
        log.error("server error", exc_info=True)
        e = -128
    if e > 0:
        # Upgrading/exiting, so leave X server running
        if kill_xvfb in _cleanups:
            _cleanups.remove(kill_xvfb)
        from xpra.server.server_core import ServerCore
        if e == ServerCore.EXITING_CODE:
            log.info("exiting: not cleaning up Xvfb")
        elif cleanup_socket in _cleanups:
            log.info("upgrading: not cleaning up Xvfb or socket")
            # don't delete the new socket (not ours)
            _cleanups.remove(cleanup_socket)
        log("cleanups=%s", _cleanups)
        e = 0
    return e
Exemple #17
0
    "port": int,
    "username": str,
    "password": str,
    "mode": str,
    "autoconnect": bool,
    "ssh_port": int,
    "proxy_host": str,
    "proxy_port": int,
    "proxy_username": str,
    "proxy_password": str,
    "proxy_key": str,
}
LAUNCHER_DEFAULTS = {
    "host": "",
    "port": -1,
    "username": get_username(),
    "password": "",
    "mode": MODE_TCP,  #tcp,ssh,..
    "autoconnect": False,
    "ssh_port": 22,
    "proxy_host": "",
    "proxy_port": 22,
    "proxy_username": get_username(),
    "proxy_password": "",
    "proxy_key": "",
}

black = color_parse("black")
red = color_parse("red")
white = color_parse("white")
Exemple #18
0
def get_defaults():
    global GLOBAL_DEFAULTS
    if GLOBAL_DEFAULTS is not None:
        return GLOBAL_DEFAULTS
    from xpra.platform.features import DEFAULT_SSH_CMD, DEFAULT_PULSEAUDIO_COMMAND, DEFAULT_XVFB_COMMAND
    try:
        from xpra.platform.info import get_username
        username = get_username()
    except:
        username = ""
    GLOBAL_DEFAULTS = {
        "encoding":
        "",
        "title":
        "@title@ on @client-machine@",
        "username":
        username,
        "auth":
        "",
        "wm-name":
        DEFAULT_NET_WM_NAME,
        "remote-xpra":
        "~/.xpra/run-xpra",
        "session-name":
        "",
        "client-toolkit":
        "",
        "dock-icon":
        "",
        "tray-icon":
        "",
        "window-icon":
        "",
        "password-file":
        "",
        "clipboard-filter-file":
        "",
        "pulseaudio-command":
        DEFAULT_PULSEAUDIO_COMMAND,
        "encryption":
        "",
        "encryption_keyfile":
        "",
        "ssh":
        DEFAULT_SSH_CMD,
        "xvfb":
        DEFAULT_XVFB_COMMAND,
        "socket-dir":
        "",
        "log-file":
        "$DISPLAY.log",
        "border":
        "auto,0",
        "window-layout":
        "",
        "display":
        "",
        "tcp-proxy":
        "",
        "debug":
        "",
        "input-method":
        "none",
        "quality":
        0,
        "min-quality":
        30,
        "speed":
        0,
        "min-speed":
        0,
        "compression_level":
        1,
        "dpi":
        96,
        "max-bandwidth":
        0.0,
        "auto-refresh-delay":
        0.25,
        "daemon":
        True,
        "use-display":
        False,
        "displayfd":
        False,
        "fake-xinerama":
        True,
        "tray":
        True,
        "clipboard":
        True,
        "pulseaudio":
        True,
        "dbus-proxy":
        os.name == "posix" and not sys.platform.startswith("darwin"),
        "mmap":
        True,
        "mmap-group":
        False,
        "speaker":
        has_sound_support,
        "microphone":
        has_sound_support,
        "readonly":
        False,
        "keyboard-sync":
        True,
        "pings":
        False,
        "cursors":
        True,
        "bell":
        True,
        "notifications":
        True,
        "xsettings":
        os.name == "posix",
        "system-tray":
        True,
        "sharing":
        False,
        "delay-tray":
        False,
        "windows":
        True,
        "exit-with-children":
        False,
        "exit-with-client":
        False,
        "exit-ssh":
        True,
        "opengl":
        OPENGL_DEFAULT,
        "mdns":
        False,
        "swap-keys":
        sys.platform.startswith("darwin"),  #only used on osx
        "encodings": ["all"],
        "video-encoders": ["all"],
        "csc-modules": ["all"],
        "video-decoders": ["all"],
        "speaker-codec": [],
        "microphone-codec": [],
        "compressors": ["all"],
        "packet-encoders": ["all"],
        "key-shortcut": [
            "Meta+Shift+F1:show_menu", "Meta+Shift+F4:quit",
            "Meta+Shift+F8:magic_key", "Meta+Shift+F11:show_session_info"
        ],
        "bind-tcp":
        None,
        "start-child":
        None,
    }
    return GLOBAL_DEFAULTS
Exemple #19
0
def get_defaults():
    global GLOBAL_DEFAULTS
    if GLOBAL_DEFAULTS is not None:
        return GLOBAL_DEFAULTS
    from xpra.platform.features import DEFAULT_SSH_COMMAND, OPEN_COMMAND, DEFAULT_PULSEAUDIO_COMMAND, XDUMMY, XDUMMY_WRAPPER, DISPLAYFD, DEFAULT_ENV, CAN_DAEMONIZE
    from xpra.platform.paths import get_download_dir, get_default_log_dir
    try:
        from xpra.platform.info import get_username
        username = get_username()
    except:
        username = ""
    if WIN32 or OSX or PYTHON3:
        xvfb = ""
    elif XDUMMY:
        xvfb = get_Xdummy_command(use_wrapper=XDUMMY_WRAPPER)
    else:
        xvfb = get_Xvfb_command()

    GLOBAL_DEFAULTS = {
        "encoding":
        "",
        "title":
        "@title@ on @client-machine@",
        "username":
        username,
        "auth":
        "",
        "tcp-auth":
        "",
        "wm-name":
        DEFAULT_NET_WM_NAME,
        "remote-xpra":
        "~/.xpra/run-xpra",
        "session-name":
        "",
        "dock-icon":
        "",
        "tray-icon":
        "",
        "window-icon":
        "",
        "password-file":
        "",
        "clipboard":
        "yes",
        "clipboard-filter-file":
        "",
        "remote-clipboard":
        "CLIPBOARD",
        "local-clipboard":
        "CLIPBOARD",
        "pulseaudio-command":
        DEFAULT_PULSEAUDIO_COMMAND,
        "encryption":
        "",
        "tcp-encryption":
        "",
        "encryption-keyfile":
        "",
        "tcp-encryption-keyfile":
        "",
        "ssh":
        DEFAULT_SSH_COMMAND,
        "xvfb":
        " ".join(xvfb),
        "socket-dir":
        "",
        "log-dir":
        get_default_log_dir(),
        "log-file":
        "$DISPLAY.log",
        "border":
        "auto,0",
        "max-size":
        "",
        "desktop-scaling":
        "auto",
        "display":
        "",
        "tcp-proxy":
        "",
        "download-path":
        get_download_dir(),
        "open-command":
        OPEN_COMMAND,
        "lpadmin":
        "/usr/sbin/lpadmin",
        "lpinfo":
        "/usr/sbin/lpinfo",
        "pdf-printer":
        "",
        "postscript-printer":
        "",
        "debug":
        "",
        "input-method":
        "none",
        "sound-source":
        "",
        "html":
        "",
        "socket-permissions":
        "600",
        "quality":
        0,
        "min-quality":
        30,
        "speed":
        0,
        "min-speed":
        0,
        "compression_level":
        1,
        "dpi":
        0,
        "video-scaling":
        1,
        "file-size-limit":
        10,
        "idle-timeout":
        0,
        "server-idle-timeout":
        0,
        "sync-xvfb":
        0,
        "auto-refresh-delay":
        0.15,
        "daemon":
        CAN_DAEMONIZE,
        "use-display":
        False,
        "displayfd":
        DISPLAYFD,
        "fake-xinerama":
        not OSX and not WIN32,
        "tray":
        True,
        "pulseaudio":
        not OSX and not WIN32,
        "dbus-proxy":
        not OSX and not WIN32,
        "mmap":
        not OSX and not WIN32,
        "mmap-group":
        False,
        "speaker": ["disabled", "on"][has_sound_support],
        "microphone": ["disabled", "off"][has_sound_support],
        "readonly":
        False,
        "keyboard-sync":
        True,
        "pings":
        False,
        "cursors":
        True,
        "bell":
        True,
        "notifications":
        True,
        "xsettings":
        not OSX and not WIN32,
        "system-tray":
        True,
        "sharing":
        False,
        "delay-tray":
        False,
        "windows":
        True,
        "exit-with-children":
        False,
        "exit-with-client":
        False,
        "start-new-commands":
        False,
        "remote-logging":
        WIN32 or OSX,
        "av-sync":
        True,
        "exit-ssh":
        True,
        "dbus-control":
        not WIN32 and not OSX,
        "opengl":
        OPENGL_DEFAULT,
        "mdns":
        not WIN32,
        "file-transfer":
        True,
        "printing":
        True,
        "open-files":
        False,
        "swap-keys":
        OSX,  #only used on osx
        "shadow-fullscreen":
        False,
        "global-menus":
        True,
        "socket-dirs": [],
        "encodings": ["all"],
        "video-encoders": ["all"],
        "csc-modules": ["all"],
        "video-decoders": ["all"],
        "speaker-codec": [],
        "microphone-codec": [],
        "compressors": ["all"],
        "packet-encoders": ["all"],
        "key-shortcut": [
            "Meta+Shift+F1:show_menu",
            "Meta+Shift+F2:show_start_new_command",
            "Meta+Shift+F4:quit",
            "Meta+Shift+F5:increase_quality",
            "Meta+Shift+F6:decrease_quality",
            "Meta+Shift+F7:increase_speed",
            "Meta+Shift+F8:decrease_speed",
            "Meta+Shift+F10:magic_key",
            "Meta+Shift+F11:show_session_info",
            "Meta+Shift+plus:scaleup",
            "Meta+Shift+plusminus:scaleup",  #the keyname on OSX...
            "Meta+Shift+minus:scaledown",
            "Meta+Shift+underscore:scaledown",
            "Meta+Shift+emdash:scaledown",  #OSX
            "Meta+Shift+KP_Add:scaleup",
            "Meta+Shift+KP_Subtract:scaledown",
            "Meta+Shift+KP_Multiply:scalereset",
            "Meta+Shift+degree:scalereset",  #OSX
        ],
        "bind-tcp": [],
        "start": [],
        "start-child": [],
        "env":
        DEFAULT_ENV,
    }
    return GLOBAL_DEFAULTS
Exemple #20
0
 def make_hello_base(self):
     capabilities = flatten_dict(get_network_caps())
     #add "kerberos", "gss" and "u2f" digests if enabled:
     for handler in self.challenge_handlers:
         digest = handler.get_digest()
         if digest:
             capabilities["digest"].append(digest)
     capabilities.update(FilePrintMixin.get_caps(self))
     capabilities.update({
             "version"               : XPRA_VERSION,
             "websocket.multi-packet": True,
             "hostname"              : socket.gethostname(),
             "uuid"                  : self.uuid,
             "session-id"            : self.session_id,
             "username"              : self.username,    #for authentication
             "user"                  : get_username(),
             "name"                  : get_name(),
             "client_type"           : self.client_type(),
             "python.version"        : sys.version_info[:3],
             "python.bits"           : BITS,
             "compression_level"     : self.compression_level,
             "argv"                  : sys.argv,
             })
     capabilities.update(self.get_file_transfer_features())
     if self.display:
         capabilities["display"] = self.display
     def up(prefix, d):
         updict(capabilities, prefix, d)
     up("build",     self.get_version_info())
     mid = get_machine_id()
     if mid:
         capabilities["machine_id"] = mid
     encryption = self.get_encryption()
     cryptolog("encryption=%s", encryption)
     if encryption:
         crypto_backend_init()
         enc, mode = (encryption+"-").split("-")[:2]
         if not mode:
             mode = DEFAULT_MODE
         assert enc in ENCRYPTION_CIPHERS, "invalid encryption '%s', options: %s" % (enc, csv(ENCRYPTION_CIPHERS))
         assert mode in MODES, "invalid encryption mode '%s', options: %s" % (mode, csv(MODES))
         iv = get_iv()
         key_salt = get_salt()
         iterations = get_iterations()
         padding = choose_padding(self.server_padding_options)
         cipher_caps = {
             ""                      : enc,
             "mode"                  : mode,
             "iv"                    : iv,
             "key_salt"              : key_salt,
             "key_size"              : DEFAULT_KEYSIZE,
             "key_hash"              : DEFAULT_KEY_HASH,
             "key_stretch"           : "PBKDF2",
             "key_stretch_iterations": iterations,
             "padding"               : padding,
             "padding.options"       : PADDING_OPTIONS,
             }
         cryptolog("cipher_caps=%s", cipher_caps)
         up("cipher", cipher_caps)
         key = self.get_encryption_key()
         self._protocol.set_cipher_in(encryption, iv, key,
                                      key_salt, DEFAULT_KEY_HASH, DEFAULT_KEYSIZE, iterations, padding)
     capabilities.update(self.hello_extra)
     return capabilities
Exemple #21
0
def get_defaults():
    global GLOBAL_DEFAULTS
    if GLOBAL_DEFAULTS is not None:
        return GLOBAL_DEFAULTS
    from xpra.platform.features import DEFAULT_SSH_COMMAND, OPEN_COMMAND, DEFAULT_PULSEAUDIO_CONFIGURE_COMMANDS, DEFAULT_PULSEAUDIO_COMMAND, \
                                        DEFAULT_ENV, CAN_DAEMONIZE
    from xpra.platform.paths import get_download_dir, get_remote_run_xpra_scripts
    try:
        from xpra.platform.info import get_username
        username = get_username()
    except:
        username = ""
    conf_dirs = [os.environ.get("XPRA_CONF_DIR")]
    build_root = os.environ.get("RPM_BUILD_ROOT")
    if build_root:
        conf_dirs.append(os.path.join(build_root, "etc", "xpra"))
    xpra_cmd = sys.argv[0]
    bin_dir = None
    if len(sys.argv)>0:
        for strip in ("/usr/bin", "/bin"):
            pos = xpra_cmd.find(strip)
            if pos>=0:
                bin_dir = xpra_cmd[:pos+len(strip)]
                root = xpra_cmd[:pos] or "/"
                conf_dirs.append(os.path.join(root, "etc", "xpra"))
                break
    if sys.prefix=="/usr":
        conf_dirs.append("/etc/xpra")
    else:
        conf_dirs.append(os.path.join(sys.prefix, "etc", "xpra"))
    for conf_dir in [x for x in conf_dirs if x]:
        if os.path.exists(conf_dir):
            break
    xvfb = detect_xvfb_command(conf_dir, bin_dir)
    def addtrailingslash(v):
        if v.endswith("/"):
            return v
        return v+"/"
    if WIN32:
        bind_dirs = ["Main"]
    else:
        bind_dirs = ["auto"]

    ssl_protocol = "TLSv1_2"
    if sys.version_info<(2, 7, 9):
        ssl_protocol = "SSLv23"

    GLOBAL_DEFAULTS = {
                    "encoding"          : "",
                    "title"             : "@title@ on @client-machine@",
                    "username"          : username,
                    "password"          : "",
                    "auth"              : "",
                    "vsock-auth"        : "",
                    "tcp-auth"          : "",
                    "ssl-auth"          : "",
                    "wm-name"           : DEFAULT_NET_WM_NAME,
                    "session-name"      : "",
                    "dock-icon"         : "",
                    "tray-icon"         : "",
                    "window-icon"       : "",
                    "password-file"     : "",
                    "keyboard-raw"      : False,
                    "keyboard-layout"   : "",
                    "keyboard-layouts"  : [],
                    "keyboard-variant"  : "",
                    "keyboard-variants" : [],
                    "keyboard-options"  : "",
                    "clipboard"         : "yes",
                    "clipboard-direction" : "both",
                    "clipboard-filter-file" : "",
                    "remote-clipboard"  : "CLIPBOARD",
                    "local-clipboard"   : "CLIPBOARD",
                    "pulseaudio-command": " ".join(DEFAULT_PULSEAUDIO_COMMAND),
                    "encryption"        : "",
                    "tcp-encryption"    : "",
                    "encryption-keyfile": "",
                    "tcp-encryption-keyfile": "",
                    "pidfile"           : "",
                    "ssh"               : DEFAULT_SSH_COMMAND,
                    "systemd-run"       : get_default_systemd_run(),
                    "systemd-run-args"  : "",
                    "xvfb"              : " ".join(xvfb),
                    "socket-dir"        : "",
                    "log-dir"           : "auto",
                    "log-file"          : "$DISPLAY.log",
                    "border"            : "auto,5:off",
                    "window-close"      : "auto",
                    "max-size"          : "",
                    "desktop-scaling"   : "auto",
                    "display"           : "",
                    "tcp-proxy"         : "",
                    "download-path"     : get_download_dir(),
                    "open-command"      : OPEN_COMMAND,
                    "remote-logging"    : "both",
                    "lpadmin"           : "/usr/sbin/lpadmin",
                    "lpinfo"            : "/usr/sbin/lpinfo",
                    "add-printer-options" : ["-E", "-o printer-is-shared=false", "-u allow:$USER"],
                    "pdf-printer"       : "",
                    "postscript-printer": DEFAULT_POSTSCRIPT_PRINTER,
                    "debug"             : "",
                    "input-method"      : "none",
                    "sound-source"      : "",
                    "html"              : "auto",
                    "socket-permissions": "600",
                    "exec-wrapper"      : "",
                    "dbus-launch"       : "dbus-launch --close-stderr",
                    "webcam"            : ["auto", "no"][OSX],
                    #ssl options:
                    "ssl"               : "auto",
                    "ssl-key"           : "",
                    "ssl-cert"          : "",
                    "ssl-protocol"      : ssl_protocol,
                    "ssl-ca-certs"      : "default",
                    "ssl-ca-data"       : "",
                    "ssl-ciphers"       : "DEFAULT",
                    "ssl-client-verify-mode"   : "optional",
                    "ssl-server-verify-mode"   : "required",
                    "ssl-verify-flags"  : "X509_STRICT",
                    "ssl-check-hostname": False,
                    "ssl-server-hostname": "localhost",
                    "ssl-options"       : "ALL,NO_COMPRESSION",
                    "quality"           : 0,
                    "min-quality"       : 30,
                    "speed"             : 0,
                    "min-speed"         : 30,
                    "compression_level" : 1,
                    "dpi"               : 0,
                    "video-scaling"     : 1,
                    "file-size-limit"   : 100,
                    "idle-timeout"      : 0,
                    "server-idle-timeout" : 0,
                    "sync-xvfb"         : 0,
                    "auto-refresh-delay": 0.15,
                    "daemon"            : CAN_DAEMONIZE,
                    "use-display"       : False,
                    "fake-xinerama"     : not OSX and not WIN32,
                    "resize-display"    : not OSX and not WIN32,
                    "tray"              : True,
                    "pulseaudio"        : not OSX and not WIN32,
                    "dbus-proxy"        : not OSX and not WIN32,
                    "mmap"              : ["no", "yes"][not OSX and not WIN32],
                    "mmap-group"        : False,
                    "speaker"           : ["disabled", "on"][has_sound_support()],
                    "microphone"        : ["disabled", "off"][has_sound_support()],
                    "readonly"          : False,
                    "keyboard-sync"     : True,
                    "pings"             : False,
                    "cursors"           : True,
                    "bell"              : True,
                    "notifications"     : True,
                    "xsettings"         : not OSX and not WIN32,
                    "system-tray"       : True,
                    "sharing"           : False,
                    "delay-tray"        : False,
                    "windows"           : True,
                    "exit-with-children": False,
                    "exit-with-client"  : False,
                    "start-after-connect": False,
                    "start-new-commands": False,
                    "proxy-start-sessions": True,
                    "av-sync"           : True,
                    "exit-ssh"          : True,
                    "dbus-control"      : not WIN32 and not OSX,
                    "opengl"            : get_opengl_default(),
                    "mdns"              : not WIN32,
                    "file-transfer"     : True,
                    "printing"          : True,
                    "open-files"        : False,
                    "swap-keys"         : OSX,  #only used on osx
                    "desktop-fullscreen": False,
                    "global-menus"      : True,
                    "pulseaudio-configure-commands"  : [" ".join(x) for x in DEFAULT_PULSEAUDIO_CONFIGURE_COMMANDS],
                    "socket-dirs"       : [],
                    "remote-xpra"       : get_remote_run_xpra_scripts(),
                    "encodings"         : ["all"],
                    "proxy-video-encoders" : [],
                    "video-encoders"    : ["all"],
                    "csc-modules"       : ["all"],
                    "video-decoders"    : ["all"],
                    "speaker-codec"     : [],
                    "microphone-codec"  : [],
                    "compressors"       : ["all"],
                    "packet-encoders"   : ["all"],
                    "key-shortcut"      : get_default_key_shortcuts(),
                    "bind"              : bind_dirs,
                    "bind-vsock"        : [],
                    "bind-tcp"          : [],
                    "bind-ssl"          : [],
                    "start"             : [],
                    "start-child"       : [],
                    "start-after-connect"       : [],
                    "start-child-after-connect" : [],
                    "start-on-connect"          : [],
                    "start-child-on-connect"    : [],
                    "start-env"         : DEFAULT_ENV,
                    "env"               : [],
                    }
    return GLOBAL_DEFAULTS
Exemple #22
0
def get_defaults():
    global GLOBAL_DEFAULTS
    if GLOBAL_DEFAULTS is not None:
        return GLOBAL_DEFAULTS
    from xpra.platform.features import DEFAULT_SSH_CMD, DOWNLOAD_PATH, OPEN_COMMAND, DEFAULT_PULSEAUDIO_COMMAND, DEFAULT_XVFB_COMMAND
    try:
        from xpra.platform.info import get_username
        username = get_username()
    except:
        username = ""
    GLOBAL_DEFAULTS = {
                    "encoding"          : "",
                    "title"             : "@title@ on @client-machine@",
                    "username"          : username,
                    "auth"              : "",
                    "tcp-auth"          : "",
                    "wm-name"           : DEFAULT_NET_WM_NAME,
                    "remote-xpra"       : "~/.xpra/run-xpra",
                    "session-name"      : "",
                    "dock-icon"         : "",
                    "tray-icon"         : "",
                    "window-icon"       : "",
                    "password-file"     : "",
                    "clipboard-filter-file" : "",
                    "pulseaudio-command": DEFAULT_PULSEAUDIO_COMMAND,
                    "encryption"        : "",
                    "encryption_keyfile": "",
                    "ssh"               : DEFAULT_SSH_CMD,
                    "xvfb"              : DEFAULT_XVFB_COMMAND,
                    "socket-dir"        : "",
                    "log-file"          : "$DISPLAY.log",
                    "border"            : "auto,0",
                    "max-size"          : "",
                    "window-layout"     : "",
                    "display"           : "",
                    "tcp-proxy"         : "",
                    "download-path"     : DOWNLOAD_PATH,
                    "open-command"      : OPEN_COMMAND,
                    "lpadmin"           : "lpadmin",
                    "debug"             : "",
                    "input-method"      : "none",
                    "sound-source"      : "",
                    "html"              : "",
                    "socket-permissions": "600",
                    "quality"           : 0,
                    "min-quality"       : 30,
                    "speed"             : 0,
                    "min-speed"         : 0,
                    "compression_level" : 1,
                    "dpi"               : 0,
                    "scaling"           : 1,
                    "file-size-limit"   : 10,
                    "idle-timeout"      : 0,
                    "auto-refresh-delay": 0.25,
                    "daemon"            : True,
                    "use-display"       : False,
                    "displayfd"         : False,
                    "fake-xinerama"     : True,
                    "tray"              : True,
                    "clipboard"         : True,
                    "pulseaudio"        : True,
                    "dbus-proxy"        : os.name=="posix" and not sys.platform.startswith("darwin"),
                    "mmap"              : True,
                    "mmap-group"        : False,
                    "speaker"           : ["disabled", "on"][has_sound_support],
                    "microphone"        : ["disabled", "off"][has_sound_support],
                    "readonly"          : False,
                    "keyboard-sync"     : True,
                    "pings"             : False,
                    "cursors"           : True,
                    "bell"              : True,
                    "notifications"     : True,
                    "xsettings"         : os.name=="posix",
                    "system-tray"       : True,
                    "sharing"           : False,
                    "delay-tray"        : False,
                    "windows"           : True,
                    "exit-with-children": False,
                    "exit-with-client"  : False,
                    "start-new-commands": False,
                    "remote-logging"    : sys.platform.startswith("win") or sys.platform.startswith("darwin"),
                    "exit-ssh"          : True,
                    "opengl"            : OPENGL_DEFAULT,
                    "mdns"              : False,
                    "file-transfer"     : True,
                    "printing"          : True,
                    "open-files"        : False,
                    "swap-keys"         : sys.platform.startswith("darwin"),    #only used on osx
                    "encodings"         : ["all"],
                    "video-encoders"    : ["all"],
                    "csc-modules"       : ["all"],
                    "video-decoders"    : ["all"],
                    "speaker-codec"     : [],
                    "microphone-codec"  : [],
                    "compressors"       : ["all"],
                    "packet-encoders"   : ["all"],
                    "key-shortcut"      : [
                                           "Meta+Shift+F1:show_menu",
                                           "Meta+Shift+F2:show_start_new_command",
                                           "Meta+Shift+F4:quit",
                                           "Meta+Shift+F8:magic_key",
                                           "Meta+Shift+F11:show_session_info"
                                           ],
                    "bind-tcp"          : None,
                    "start"             : None,
                    "start-child"       : None,
                    "env"               : None,
                    }
    return GLOBAL_DEFAULTS
Exemple #23
0
def ssh_paramiko_connect_to(display_desc):
    #plain socket attributes:
    host = display_desc["host"]
    port = display_desc.get("ssh-port", 22)
    #ssh and command attributes:
    username = display_desc.get("username") or get_username()
    if "proxy_host" in display_desc:
        display_desc.setdefault("proxy_username", get_username())
    password = display_desc.get("password")
    remote_xpra = display_desc["remote_xpra"]
    proxy_command = display_desc["proxy_command"]       #ie: "_proxy_start"
    socket_dir = display_desc.get("socket_dir")
    display = display_desc.get("display")
    display_as_args = display_desc["display_as_args"]   #ie: "--start=xterm :10"
    paramiko_config = display_desc.copy()
    paramiko_config.update(display_desc.get("paramiko-config", {}))
    socket_info = {
            "host"  : host,
            "port"  : port,
            }
    def get_keyfiles(host_config, config_name="key"):
        keyfiles = (host_config or {}).get("identityfile") or get_default_keyfiles()
        keyfile = paramiko_config.get(config_name)
        if keyfile:
            keyfiles.insert(0, keyfile)
        return keyfiles

    def fail(msg):
        log("ssh_paramiko_connect_to(%s)", display_desc, exc_info=True)
        raise InitExit(EXIT_SSH_FAILURE, msg) from None

    with nogssapi_context():
        from paramiko import SSHConfig, ProxyCommand
        ssh_config = SSHConfig()
        user_config_file = os.path.expanduser("~/.ssh/config")
        sock = None
        host_config = None
        if os.path.exists(user_config_file):
            with open(user_config_file) as f:
                ssh_config.parse(f)
            log("parsed user config '%s'", user_config_file)
            try:
                log("%i hosts found", len(ssh_config.get_hostnames()))
            except KeyError:
                pass
            host_config = ssh_config.lookup(host)
            if host_config:
                log("got host config for '%s': %s", host, host_config)
                host = host_config.get("hostname", host)
                if "username" not in display_desc:
                    username = host_config.get("user", username)
                if "ssh-port" not in display_desc:
                    port = host_config.get("port", port)
                    try:
                        port = int(port)    
                    except (TypeError, ValueError):
                        raise InitExit(EXIT_SSH_FAILURE, "invalid ssh port specified: '%s'" % port) from None
                proxycommand = host_config.get("proxycommand")
                if proxycommand:
                    log("found proxycommand='%s' for host '%s'", proxycommand, host)
                    sock = ProxyCommand(proxycommand)
                    log("ProxyCommand(%s)=%s", proxycommand, sock)
                    from xpra.child_reaper import getChildReaper
                    cmd = getattr(sock, "cmd", [])
                    def proxycommand_ended(proc):
                        log("proxycommand_ended(%s) exit code=%s", proc, proc.poll())
                    getChildReaper().add_process(sock.process, "paramiko-ssh-client", cmd, True, True,
                                                 callback=proxycommand_ended)
                    proxy_keys = get_keyfiles(host_config, "proxy_key")
                    log("proxy keys=%s", proxy_keys)
                    from paramiko.client import SSHClient
                    ssh_client = SSHClient()
                    ssh_client.load_system_host_keys()
                    log("ssh proxy command connect to %s", (host, port, sock))
                    ssh_client.connect(host, port, sock=sock)
                    transport = ssh_client.get_transport()
                    do_ssh_paramiko_connect_to(transport, host,
                                               username, password,
                                               host_config or ssh_config.lookup("*"),
                                               proxy_keys,
                                               paramiko_config)
                    chan = paramiko_run_remote_xpra(transport, proxy_command, remote_xpra, socket_dir, display_as_args)
                    peername = (host, port)
                    conn = SSHProxyCommandConnection(chan, peername, peername, socket_info)
                    conn.target = host_target_string("ssh", username, host, port, display)
                    conn.timeout = SOCKET_TIMEOUT
                    conn.start_stderr_reader()
                    conn.process = (sock.process, "ssh", cmd)
                    from xpra.net import bytestreams
                    from paramiko.ssh_exception import ProxyCommandFailure
                    bytestreams.CLOSED_EXCEPTIONS = tuple(list(bytestreams.CLOSED_EXCEPTIONS)+[ProxyCommandFailure])
                    return conn

        keys = get_keyfiles(host_config)
        from xpra.net.socket_util import socket_connect
        from paramiko.transport import Transport
        from paramiko import SSHException
        if "proxy_host" in display_desc:
            proxy_host = display_desc["proxy_host"]
            proxy_port = display_desc.get("proxy_port", 22)
            proxy_username = display_desc.get("proxy_username", username)
            proxy_password = display_desc.get("proxy_password", password)
            proxy_keys = get_keyfiles(host_config, "proxy_key")
            sock = socket_connect(proxy_host, proxy_port)
            middle_transport = Transport(sock)
            middle_transport.use_compression(False)
            try:
                middle_transport.start_client()
            except SSHException as e:
                fail("SSH proxy transport negotiation failed: %s" % e)
            proxy_host_config = ssh_config.lookup(host)
            do_ssh_paramiko_connect_to(middle_transport, proxy_host,
                                       proxy_username, proxy_password,
                                       proxy_host_config or ssh_config.lookup("*"),
                                       proxy_keys,
                                       paramiko_config)
            log("Opening proxy channel")
            chan_to_middle = middle_transport.open_channel("direct-tcpip", (host, port), ('localhost', 0))

            transport = Transport(chan_to_middle)
            transport.use_compression(False)
            try:
                transport.start_client()
            except SSHException as e:
                fail("SSH transport negotiation failed: %s" % e)
            do_ssh_paramiko_connect_to(transport, host,
                                       username, password,
                                       host_config or ssh_config.lookup("*"),
                                       keys,
                                       paramiko_config)
            chan = paramiko_run_remote_xpra(transport, proxy_command, remote_xpra, socket_dir, display_as_args)
            peername = (host, port)
            conn = SSHProxyCommandConnection(chan, peername, peername, socket_info)
            conn.target = "%s via %s" % (
                host_target_string("ssh", username, host, port, display),
                host_target_string("ssh", proxy_username, proxy_host, proxy_port, None),
                )
            conn.timeout = SOCKET_TIMEOUT
            conn.start_stderr_reader()
            return conn

        #plain TCP connection to the server,
        #we open it then give the socket to paramiko:
        sock = socket_connect(host, port)
        sockname = sock.getsockname()
        peername = sock.getpeername()
        log("paramiko socket_connect: sockname=%s, peername=%s", sockname, peername)
        transport = Transport(sock)
        transport.use_compression(False)
        try:
            transport.start_client()
        except SSHException as e:
            fail("SSH negotiation failed: %s" % e)
        do_ssh_paramiko_connect_to(transport, host, username, password,
                                   host_config or ssh_config.lookup("*"),
                                   keys,
                                   paramiko_config)
        remote_port = display_desc.get("remote_port", 0)
        if remote_port:
            #we want to connect directly to a remote port,
            #we don't need to run a command
            chan = transport.open_channel("direct-tcpip", ("localhost", remote_port), ('localhost', 0))
            log("direct channel to remote port %i : %s", remote_port, chan)
        else:
            chan = paramiko_run_remote_xpra(transport, proxy_command, remote_xpra, socket_dir, display_as_args)
        conn = SSHSocketConnection(chan, sock, sockname, peername, (host, port), socket_info)
        conn.target = host_target_string("ssh", username, host, port, display)
        conn.timeout = SOCKET_TIMEOUT
        conn.start_stderr_reader()
        return conn
Exemple #24
0
 def __init__(self, username, **kwargs):
     super().__init__(username or get_username(), **kwargs)
     self.salt = None
Exemple #25
0
def get_defaults():
    global GLOBAL_DEFAULTS
    if GLOBAL_DEFAULTS is not None:
        return GLOBAL_DEFAULTS
    from xpra.platform.features import DEFAULT_SSH_COMMAND, OPEN_COMMAND, DEFAULT_PULSEAUDIO_CONFIGURE_COMMANDS, DEFAULT_PULSEAUDIO_COMMAND, \
                                        DEFAULT_ENV, CAN_DAEMONIZE
    from xpra.platform.paths import get_download_dir, get_remote_run_xpra_scripts
    try:
        from xpra.platform.info import get_username
        username = get_username()
    except:
        username = ""
    conf_dirs = [os.environ.get("XPRA_CONF_DIR")]
    build_root = os.environ.get("RPM_BUILD_ROOT")
    if build_root:
        conf_dirs.append(os.path.join(build_root, "etc", "xpra"))
    xpra_cmd = sys.argv[0]
    bin_dir = None
    if len(sys.argv) > 0:
        for strip in ("/usr/bin", "/bin"):
            pos = xpra_cmd.find(strip)
            if pos >= 0:
                bin_dir = xpra_cmd[:pos + len(strip)]
                root = xpra_cmd[:pos] or "/"
                conf_dirs.append(os.path.join(root, "etc", "xpra"))
                break
    if sys.prefix == "/usr":
        conf_dirs.append("/etc/xpra")
    else:
        conf_dirs.append(os.path.join(sys.prefix, "etc", "xpra"))
    for conf_dir in [x for x in conf_dirs if x]:
        if os.path.exists(conf_dir):
            break
    xvfb = detect_xvfb_command(conf_dir, bin_dir)

    def addtrailingslash(v):
        if v.endswith("/"):
            return v
        return v + "/"

    if WIN32:
        bind_dirs = ["Main"]
    else:
        bind_dirs = ["auto"]

    ssl_protocol = "TLSv1_2"
    if sys.version_info < (2, 7, 9):
        ssl_protocol = "SSLv23"

    GLOBAL_DEFAULTS = {
        "encoding":
        "",
        "title":
        "@title@ on @client-machine@",
        "username":
        username,
        "password":
        "",
        "auth":
        "",
        "vsock-auth":
        "",
        "tcp-auth":
        "",
        "ssl-auth":
        "",
        "wm-name":
        DEFAULT_NET_WM_NAME,
        "session-name":
        "",
        "dock-icon":
        "",
        "tray-icon":
        "",
        "window-icon":
        "",
        "password-file":
        "",
        "keyboard-raw":
        False,
        "keyboard-layout":
        "",
        "keyboard-layouts": [],
        "keyboard-variant":
        "",
        "keyboard-variants": [],
        "keyboard-options":
        "",
        "clipboard":
        "yes",
        "clipboard-direction":
        "both",
        "clipboard-filter-file":
        "",
        "remote-clipboard":
        "CLIPBOARD",
        "local-clipboard":
        "CLIPBOARD",
        "pulseaudio-command":
        " ".join(DEFAULT_PULSEAUDIO_COMMAND),
        "encryption":
        "",
        "tcp-encryption":
        "",
        "encryption-keyfile":
        "",
        "tcp-encryption-keyfile":
        "",
        "pidfile":
        "",
        "ssh":
        DEFAULT_SSH_COMMAND,
        "systemd-run":
        get_default_systemd_run(),
        "systemd-run-args":
        "",
        "xvfb":
        " ".join(xvfb),
        "socket-dir":
        "",
        "log-dir":
        "auto",
        "log-file":
        "$DISPLAY.log",
        "border":
        "auto,5:off",
        "window-close":
        "auto",
        "max-size":
        "",
        "desktop-scaling":
        "auto",
        "display":
        "",
        "tcp-proxy":
        "",
        "download-path":
        get_download_dir(),
        "open-command":
        OPEN_COMMAND,
        "remote-logging":
        "both",
        "lpadmin":
        "/usr/sbin/lpadmin",
        "lpinfo":
        "/usr/sbin/lpinfo",
        "add-printer-options":
        ["-E", "-o printer-is-shared=false", "-u allow:$USER"],
        "pdf-printer":
        "",
        "postscript-printer":
        DEFAULT_POSTSCRIPT_PRINTER,
        "debug":
        "",
        "input-method":
        "none",
        "sound-source":
        "",
        "html":
        "auto",
        "socket-permissions":
        "600",
        "exec-wrapper":
        "",
        "dbus-launch":
        "dbus-launch --close-stderr",
        "webcam": ["auto", "no"][OSX],
        #ssl options:
        "ssl":
        "auto",
        "ssl-key":
        "",
        "ssl-cert":
        "",
        "ssl-protocol":
        ssl_protocol,
        "ssl-ca-certs":
        "default",
        "ssl-ca-data":
        "",
        "ssl-ciphers":
        "DEFAULT",
        "ssl-client-verify-mode":
        "optional",
        "ssl-server-verify-mode":
        "required",
        "ssl-verify-flags":
        "X509_STRICT",
        "ssl-check-hostname":
        False,
        "ssl-server-hostname":
        "localhost",
        "ssl-options":
        "ALL,NO_COMPRESSION",
        "quality":
        0,
        "min-quality":
        30,
        "speed":
        0,
        "min-speed":
        30,
        "compression_level":
        1,
        "dpi":
        0,
        "video-scaling":
        1,
        "file-size-limit":
        100,
        "idle-timeout":
        0,
        "server-idle-timeout":
        0,
        "sync-xvfb":
        0,
        "auto-refresh-delay":
        0.15,
        "daemon":
        CAN_DAEMONIZE,
        "use-display":
        False,
        "fake-xinerama":
        not OSX and not WIN32,
        "resize-display":
        not OSX and not WIN32,
        "tray":
        True,
        "pulseaudio":
        not OSX and not WIN32,
        "dbus-proxy":
        not OSX and not WIN32,
        "mmap": ["no", "yes"][not OSX and not WIN32],
        "mmap-group":
        False,
        "speaker": ["disabled", "on"][has_sound_support()],
        "microphone": ["disabled", "off"][has_sound_support()],
        "readonly":
        False,
        "keyboard-sync":
        True,
        "pings":
        False,
        "cursors":
        True,
        "bell":
        True,
        "notifications":
        True,
        "xsettings":
        not OSX and not WIN32,
        "system-tray":
        True,
        "sharing":
        False,
        "delay-tray":
        False,
        "windows":
        True,
        "exit-with-children":
        False,
        "exit-with-client":
        False,
        "start-after-connect":
        False,
        "start-new-commands":
        False,
        "proxy-start-sessions":
        True,
        "av-sync":
        True,
        "exit-ssh":
        True,
        "dbus-control":
        not WIN32 and not OSX,
        "opengl":
        get_opengl_default(),
        "mdns":
        not WIN32,
        "file-transfer":
        True,
        "printing":
        True,
        "open-files":
        False,
        "swap-keys":
        OSX,  #only used on osx
        "desktop-fullscreen":
        False,
        "global-menus":
        True,
        "pulseaudio-configure-commands":
        [" ".join(x) for x in DEFAULT_PULSEAUDIO_CONFIGURE_COMMANDS],
        "socket-dirs": [],
        "remote-xpra":
        get_remote_run_xpra_scripts(),
        "encodings": ["all"],
        "proxy-video-encoders": [],
        "video-encoders": ["all"],
        "csc-modules": ["all"],
        "video-decoders": ["all"],
        "speaker-codec": [],
        "microphone-codec": [],
        "compressors": ["all"],
        "packet-encoders": ["all"],
        "key-shortcut":
        get_default_key_shortcuts(),
        "bind":
        bind_dirs,
        "bind-vsock": [],
        "bind-tcp": [],
        "bind-ssl": [],
        "start": [],
        "start-child": [],
        "start-after-connect": [],
        "start-child-after-connect": [],
        "start-on-connect": [],
        "start-child-on-connect": [],
        "start-env":
        DEFAULT_ENV,
        "env": [],
    }
    return GLOBAL_DEFAULTS
Exemple #26
0
def get_defaults():
    global GLOBAL_DEFAULTS
    if GLOBAL_DEFAULTS is not None:
        return GLOBAL_DEFAULTS
    from xpra.platform.features import DEFAULT_SSH_COMMAND, OPEN_COMMAND, DEFAULT_PULSEAUDIO_CONFIGURE_COMMANDS, DEFAULT_PULSEAUDIO_COMMAND, XDUMMY, XDUMMY_WRAPPER, DISPLAYFD, DEFAULT_ENV, CAN_DAEMONIZE
    from xpra.platform.paths import get_download_dir, get_default_log_dir, get_socket_dirs, get_remote_run_xpra_scripts
    try:
        from xpra.platform.info import get_username
        username = get_username()
    except:
        username = ""
    if WIN32 or OSX or PYTHON3:
        xvfb = ""
    elif XDUMMY:
        xvfb = get_Xdummy_command(use_wrapper=XDUMMY_WRAPPER, log_dir=get_default_log_dir())
    else:
        xvfb = get_Xvfb_command()
    def addtrailingslash(v):
        if v.endswith("/"):
            return v
        return v+"/"
    if WIN32:
        bind_dirs = []
    else:
        bind_dirs = [addtrailingslash(get_socket_dirs()[0])]

    GLOBAL_DEFAULTS = {
                    "encoding"          : "",
                    "title"             : "@title@ on @client-machine@",
                    "username"          : username,
                    "auth"              : "",
                    "vsock-auth"        : "",
                    "tcp-auth"          : "",
                    "wm-name"           : DEFAULT_NET_WM_NAME,
                    "session-name"      : "",
                    "dock-icon"         : "",
                    "tray-icon"         : "",
                    "window-icon"       : "",
                    "password-file"     : "",
                    "clipboard"         : "yes",
                    "clipboard-filter-file" : "",
                    "remote-clipboard"  : "CLIPBOARD",
                    "local-clipboard"   : "CLIPBOARD",
                    "pulseaudio-command": " ".join(DEFAULT_PULSEAUDIO_COMMAND),
                    "encryption"        : "",
                    "tcp-encryption"    : "",
                    "encryption-keyfile": "",
                    "tcp-encryption-keyfile": "",
                    "ssh"               : DEFAULT_SSH_COMMAND,
                    "xvfb"              : " ".join(xvfb),
                    "socket-dir"        : "",
                    "log-dir"           : get_default_log_dir(),
                    "log-file"          : "$DISPLAY.log",
                    "border"            : "auto,5:off",
                    "window-close"      : "auto",
                    "max-size"          : "",
                    "desktop-scaling"   : "auto",
                    "display"           : "",
                    "tcp-proxy"         : "",
                    "download-path"     : get_download_dir(),
                    "open-command"      : OPEN_COMMAND,
                    "remote-logging"    : "both",
                    "lpadmin"           : "/usr/sbin/lpadmin",
                    "lpinfo"            : "/usr/sbin/lpinfo",
                    "pdf-printer"       : "",
                    "postscript-printer": "",
                    "debug"             : "",
                    "input-method"      : "none",
                    "sound-source"      : "",
                    "html"              : "",
                    "socket-permissions": "600",
                    "exec-wrapper"      : "",
                    "dbus-launch"       : "dbus-launch --close-stderr",
                    "webcam"            : "auto",
                    "quality"           : 0,
                    "min-quality"       : 30,
                    "speed"             : 0,
                    "min-speed"         : 30,
                    "compression_level" : 1,
                    "dpi"               : 0,
                    "video-scaling"     : 1,
                    "file-size-limit"   : 10,
                    "idle-timeout"      : 0,
                    "server-idle-timeout" : 0,
                    "sync-xvfb"         : 0,
                    "auto-refresh-delay": 0.15,
                    "daemon"            : CAN_DAEMONIZE,
                    "use-display"       : False,
                    "displayfd"         : DISPLAYFD,
                    "fake-xinerama"     : not OSX and not WIN32,
                    "resize-display"    : not OSX and not WIN32,
                    "tray"              : True,
                    "pulseaudio"        : not OSX and not WIN32,
                    "dbus-proxy"        : not OSX and not WIN32,
                    "mmap"              : not OSX and not WIN32,
                    "mmap-group"        : False,
                    "speaker"           : ["disabled", "on"][has_sound_support],
                    "microphone"        : ["disabled", "off"][has_sound_support],
                    "readonly"          : False,
                    "keyboard-sync"     : True,
                    "pings"             : False,
                    "cursors"           : True,
                    "bell"              : True,
                    "notifications"     : True,
                    "xsettings"         : not OSX and not WIN32,
                    "system-tray"       : True,
                    "sharing"           : False,
                    "delay-tray"        : False,
                    "windows"           : True,
                    "exit-with-children": False,
                    "exit-with-client"  : False,
                    "start-after-connect": False,
                    "start-new-commands": False,
                    "av-sync"           : True,
                    "exit-ssh"          : True,
                    "dbus-control"      : not WIN32 and not OSX,
                    "opengl"            : OPENGL_DEFAULT,
                    "mdns"              : not WIN32,
                    "file-transfer"     : True,
                    "printing"          : True,
                    "open-files"        : False,
                    "swap-keys"         : OSX,  #only used on osx
                    "shadow-fullscreen" : False,
                    "global-menus"      : True,
                    "pulseaudio-configure-commands"  : [" ".join(x) for x in DEFAULT_PULSEAUDIO_CONFIGURE_COMMANDS],
                    "socket-dirs"       : [],
                    "remote-xpra"       : get_remote_run_xpra_scripts(),
                    "encodings"         : ["all"],
                    "video-encoders"    : ["all"],
                    "csc-modules"       : ["all"],
                    "video-decoders"    : ["all"],
                    "speaker-codec"     : [],
                    "microphone-codec"  : [],
                    "compressors"       : ["all"],
                    "packet-encoders"   : ["all"],
                    "key-shortcut"      : get_default_key_shortcuts(),
                    "bind"              : bind_dirs,
                    "bind-vsock"        : [],
                    "bind-tcp"          : [],
                    "start"             : [],
                    "start-child"       : [],
                    "start-after-connect"       : [],
                    "start-child-after-connect" : [],
                    "start-on-connect"          : [],
                    "start-child-on-connect"    : [],
                    "env"               : DEFAULT_ENV,
                    }
    return GLOBAL_DEFAULTS
Exemple #27
0
def get_defaults():
    global GLOBAL_DEFAULTS
    if GLOBAL_DEFAULTS is not None:
        return GLOBAL_DEFAULTS
    from xpra.platform.features import DEFAULT_SSH_CMD
    try:
        from xpra.platform.info import get_username
        username = get_username()
    except:
        username = ""
    GLOBAL_DEFAULTS = {
                    "encoding"          : "",
                    "title"             : "@title@ on @client-machine@",
                    "host"              : "",
                    "username"          : username,
                    "auth"              : "",
                    "remote-xpra"       : ".xpra/run-xpra",
                    "session-name"      : "",
                    "client-toolkit"    : "",
                    "dock-icon"         : "",
                    "tray-icon"         : "",
                    "window-icon"       : "",
                    "password"          : "",
                    "password-file"     : "",
                    "clipboard-filter-file" : "",
                    "pulseaudio-command": "pulseaudio --start --daemonize=false --system=false "
                                            +" --exit-idle-time=-1 -n --load=module-suspend-on-idle "
                                            +" --load=module-null-sink --load=module-native-protocol-unix "
                                            +" --log-level=2 --log-target=stderr",
                    "encryption"        : "",
                    "encryption_keyfile": "",
                    "mode"              : "tcp",
                    "ssh"               : DEFAULT_SSH_CMD,
                    "xvfb"              : "Xvfb +extension Composite -screen 0 3840x2560x24+32 -nolisten tcp -noreset -auth $XAUTHORITY",
                    "socket-dir"        : "",
                    "log-file"          : "$DISPLAY.log",
                    "window-layout"     : "",
                    "display"           : "",
                    "tcp-proxy"         : "",
                    "quality"           : -1,
                    "min-quality"       : 50,
                    "speed"             : -1,
                    "min-speed"         : -1,
                    "port"              : -1,
                    "compression_level" : 1,
                    "dpi"               : 96,
                    "max-bandwidth"     : 0.0,
                    "auto-refresh-delay": 0.25,
                    "debug"             : False,
                    "daemon"            : True,
                    "use-display"       : False,
                    "fake-xinerama"     : True,
                    "tray"              : True,
                    "clipboard"         : True,
                    "pulseaudio"        : True,
                    "dbus-proxy"        : os.name=="posix" and not sys.platform.startswith("darwin"),
                    "mmap"              : True,
                    "mmap-group"        : False,
                    "speaker"           : True,
                    "microphone"        : True,
                    "readonly"          : False,
                    "keyboard-sync"     : True,
                    "pings"             : False,
                    "cursors"           : True,
                    "bell"              : True,
                    "notifications"     : True,
                    "xsettings"         : os.name=="posix",
                    "system-tray"       : True,
                    "sharing"           : False,
                    "delay-tray"        : False,
                    "windows"           : True,
                    "autoconnect"       : False,
                    "exit-with-children": False,
                    "exit-with-client"  : False,
                    "opengl"            : OPENGL_DEFAULT,
                    "mdns"              : True,
                    "speaker-codec"     : [],
                    "microphone-codec"  : [],
                    "key-shortcut"      : ["Meta+Shift+F4:quit", "Meta+Shift+F8:magic_key", "Meta+Shift+F11:show_session_info"],
                    "bind-tcp"          : None,
                    "start-child"       : None,
                    }
    return GLOBAL_DEFAULTS
Exemple #28
0
    def __init__(self, options, title="Xpra Session Browser"):
        super().__init__()
        self.exit_code = 0
        self.set_title(title)
        self.set_border_width(20)
        self.set_resizable(True)
        self.set_default_size(800, 220)
        self.set_decorated(True)
        self.set_size_request(800, 220)
        self.set_position(Gtk.WindowPosition.CENTER)
        self.set_wmclass("xpra-sessions-gui", "Xpra-Sessions-GUI")
        add_close_accel(self, self.quit)
        self.connect("delete_event", self.quit)
        icon = get_icon_pixbuf("browse.png")
        if icon:
            self.set_icon(icon)

        hb = Gtk.HeaderBar()
        hb.set_show_close_button(True)
        hb.props.title = "Xpra"
        button = Gtk.Button()
        icon = Gio.ThemedIcon(name="help-about")
        image = Gtk.Image.new_from_gicon(icon, Gtk.IconSize.BUTTON)
        button.add(image)
        button.set_tooltip_text("About")
        button.connect("clicked", self.show_about)
        hb.add(button)
        hb.show_all()
        self.set_titlebar(hb)

        self.clients = {}
        self.clients_disconnecting = set()
        self.child_reaper = getChildReaper()

        self.vbox = Gtk.VBox(False, 20)
        self.add(self.vbox)

        title_label = Gtk.Label(title)
        title_label.modify_font(Pango.FontDescription("sans 14"))
        title_label.show()
        self.vbox.add(title_label)

        self.warning = Gtk.Label(" ")
        red = color_parse("red")
        self.warning.modify_fg(Gtk.StateType.NORMAL, red)
        self.warning.show()
        self.vbox.add(self.warning)

        self.password_box = Gtk.HBox(False, 10)
        self.password_label = Gtk.Label("Password:"******""
        #log.info("options=%s (%s)", options, type(options))
        self.local_info_cache = {}
        self.dotxpra = DotXpra(options.socket_dir, options.socket_dirs, username)
        self.poll_local_sessions()
        self.populate()
        GLib.timeout_add(5*1000, self.update)
        self.vbox.show()
        self.show()
Exemple #29
0
def run_server(error_cb,
               opts,
               mode,
               xpra_file,
               extra_args,
               desktop_display=None):
    try:
        cwd = os.getcwd()
    except:
        cwd = os.path.expanduser("~")
        warn("current working directory does not exist, using '%s'\n" % cwd)
    validate_encryption(opts)
    if opts.encoding == "help" or "help" in opts.encodings:
        return show_encoding_help(opts)

    from xpra.server.socket_util import parse_bind_ip, parse_bind_vsock, get_network_logger
    bind_tcp = parse_bind_ip(opts.bind_tcp)
    bind_udp = parse_bind_ip(opts.bind_udp)
    bind_ssl = parse_bind_ip(opts.bind_ssl)
    bind_ws = parse_bind_ip(opts.bind_ws)
    bind_wss = parse_bind_ip(opts.bind_wss)
    bind_rfb = parse_bind_ip(opts.bind_rfb, 5900)
    bind_vsock = parse_bind_vsock(opts.bind_vsock)

    assert mode in ("start", "start-desktop", "upgrade", "shadow", "proxy")
    starting = mode == "start"
    starting_desktop = mode == "start-desktop"
    upgrading = mode == "upgrade"
    shadowing = mode == "shadow"
    proxying = mode == "proxy"
    clobber = upgrading or opts.use_display
    start_vfb = not shadowing and not proxying and not clobber

    if upgrading or shadowing:
        #there should already be one running
        opts.pulseaudio = False

    #get the display name:
    if shadowing and len(extra_args) == 0:
        if WIN32 or OSX:
            #just a virtual name for the only display available:
            display_name = ":0"
        else:
            from xpra.scripts.main import guess_X11_display
            dotxpra = DotXpra(opts.socket_dir, opts.socket_dirs)
            display_name = guess_X11_display(dotxpra)
    elif upgrading and len(extra_args) == 0:
        display_name = guess_xpra_display(opts.socket_dir, opts.socket_dirs)
    else:
        if len(extra_args) > 1:
            error_cb(
                "too many extra arguments (%i): only expected a display number"
                % len(extra_args))
        if len(extra_args) == 1:
            display_name = extra_args[0]
            if not shadowing and not proxying and not opts.use_display:
                display_name_check(display_name)
        else:
            if proxying:
                #find a free display number:
                dotxpra = DotXpra(opts.socket_dir, opts.socket_dirs)
                all_displays = dotxpra.sockets()
                #ie: [("LIVE", ":100"), ("LIVE", ":200"), ...]
                displays = [v[1] for v in all_displays]
                display_name = None
                for x in range(1000, 20000):
                    v = ":%s" % x
                    if v not in displays:
                        display_name = v
                        break
                if not display_name:
                    error_cb(
                        "you must specify a free virtual display name to use with the proxy server"
                    )
            elif opts.use_display:
                #only use automatic guess for xpra displays and not X11 displays:
                display_name = guess_xpra_display(opts.socket_dir,
                                                  opts.socket_dirs)
            else:
                # We will try to find one automaticaly
                # Use the temporary magic value 'S' as marker:
                display_name = 'S' + str(os.getpid())

    if not shadowing and not proxying and not upgrading and opts.exit_with_children and not opts.start_child:
        error_cb(
            "--exit-with-children specified without any children to spawn; exiting immediately"
        )

    atexit.register(run_cleanups)

    # Generate the script text now, because os.getcwd() will
    # change if/when we daemonize:
    from xpra.server.server_util import xpra_runner_shell_script, write_runner_shell_scripts, write_pidfile, find_log_dir, create_input_devices
    script = xpra_runner_shell_script(xpra_file, cwd, opts.socket_dir)

    uid = int(opts.uid)
    gid = int(opts.gid)
    username = get_username_for_uid(uid)
    home = get_home_for_uid(uid)
    xauth_data = None
    if start_vfb:
        xauth_data = get_hex_uuid()
    ROOT = POSIX and getuid() == 0

    protected_fds = []
    protected_env = {}
    stdout = sys.stdout
    stderr = sys.stderr
    # Daemonize:
    if POSIX and opts.daemon:
        #daemonize will chdir to "/", so try to use an absolute path:
        if opts.password_file:
            opts.password_file = os.path.abspath(opts.password_file)
        from xpra.server.server_util import daemonize
        daemonize()

    displayfd = 0
    if POSIX and opts.displayfd:
        try:
            displayfd = int(opts.displayfd)
            if displayfd > 0:
                protected_fds.append(displayfd)
        except ValueError as e:
            stderr.write("Error: invalid displayfd '%s':\n" % opts.displayfd)
            stderr.write(" %s\n" % e)
            del e

    # if pam is present, try to create a new session:
    pam = None
    PAM_OPEN = POSIX and envbool("XPRA_PAM_OPEN", ROOT and uid != 0)
    if PAM_OPEN:
        try:
            from xpra.server.pam import pam_session  #@UnresolvedImport
        except ImportError as e:
            stderr.write("Error: failed to import pam module\n")
            stderr.write(" %s" % e)
            del e
            PAM_OPEN = False
    if PAM_OPEN:
        fdc = FDChangeCaptureContext()
        with fdc:
            pam = pam_session(username)
            env = {
                #"XDG_SEAT"               : "seat1",
                #"XDG_VTNR"               : "0",
                "XDG_SESSION_TYPE": "x11",
                #"XDG_SESSION_CLASS"      : "user",
                "XDG_SESSION_DESKTOP": "xpra",
            }
            #maybe we should just bail out instead?
            if pam.start():
                pam.set_env(env)
                items = {}
                if display_name.startswith(":"):
                    items["XDISPLAY"] = display_name
                if xauth_data:
                    items["XAUTHDATA"] = xauth_data
                pam.set_items(items)
                if pam.open():
                    #we can't close it, because we're not going to be root any more,
                    #but since we're the process leader for the session,
                    #terminating will also close the session
                    #add_cleanup(pam.close)
                    protected_env = pam.get_envlist()
                    os.environ.update(protected_env)
        #closing the pam fd causes the session to be closed,
        #and we don't want that!
        protected_fds += fdc.get_new_fds()

    #get XDG_RUNTIME_DIR from env options,
    #which may not be have updated os.environ yet when running as root with "--uid="
    xrd = os.path.abspath(parse_env(opts.env).get("XDG_RUNTIME_DIR", ""))
    if ROOT and (uid > 0 or gid > 0):
        #we're going to chown the directory if we create it,
        #ensure this cannot be abused, only use "safe" paths:
        if not any(x for x in ("/run/user/%i" % uid, "/tmp", "/var/tmp")
                   if xrd.startswith(x)):
            xrd = ""
        #these paths could cause problems if we were to create and chown them:
        if xrd.startswith("/tmp/.X11-unix") or xrd.startswith(
                "/tmp/.XIM-unix"):
            xrd = ""
    if not xrd:
        xrd = os.environ.get("XDG_RUNTIME_DIR")
    xrd = create_runtime_dir(xrd, uid, gid)
    if xrd:
        #this may override the value we get from pam
        #with the value supplied by the user:
        protected_env["XDG_RUNTIME_DIR"] = xrd

    if opts.pidfile:
        write_pidfile(opts.pidfile, uid, gid)

    if POSIX and not ROOT:
        # Write out a shell-script so that we can start our proxy in a clean
        # environment:
        write_runner_shell_scripts(script)

    if start_vfb or opts.daemon:
        #we will probably need a log dir
        #either for the vfb, or for our own log file
        log_dir = opts.log_dir or ""
        if not log_dir or log_dir.lower() == "auto":
            log_dir = find_log_dir(username, uid=uid, gid=gid)
            if not log_dir:
                raise InitException(
                    "cannot find or create a logging directory")
        #expose the log-dir as "XPRA_LOG_DIR",
        #this is used by Xdummy for the Xorg log file
        if "XPRA_LOG_DIR" not in os.environ:
            os.environ["XPRA_LOG_DIR"] = log_dir

        if opts.daemon:
            from xpra.server.server_util import select_log_file, open_log_file, redirect_std_to_log
            log_filename0 = select_log_file(log_dir, opts.log_file,
                                            display_name)
            logfd = open_log_file(log_filename0)
            if ROOT and (uid > 0 or gid > 0):
                try:
                    os.fchown(logfd, uid, gid)
                except:
                    pass
            stdout, stderr = redirect_std_to_log(logfd, *protected_fds)
            try:
                stderr.write("Entering daemon mode; " +
                             "any further errors will be reported to:\n" +
                             ("  %s\n" % log_filename0))
            except:
                #we tried our best, logging another error won't help
                pass

    #warn early about this:
    if (starting or starting_desktop) and desktop_display:
        print_DE_warnings(desktop_display, opts.pulseaudio, opts.notifications,
                          opts.dbus_launch)

    log = get_util_logger()
    netlog = get_network_logger()

    mdns_recs = {}
    sockets = []

    #SSL sockets:
    wrap_socket_fn = None
    need_ssl = False
    ssl_opt = opts.ssl.lower()
    if ssl_opt in TRUE_OPTIONS or bind_ssl or bind_wss:
        need_ssl = True
    if opts.bind_tcp or opts.bind_ws:
        if ssl_opt == "auto" and opts.ssl_cert:
            need_ssl = True
        elif ssl_opt == "tcp" and opts.bind_tcp:
            need_ssl = True
        elif ssl_opt == "www":
            need_ssl = True
    if need_ssl:
        from xpra.scripts.main import ssl_wrap_socket_fn
        try:
            wrap_socket_fn = ssl_wrap_socket_fn(opts, server_side=True)
            netlog("wrap_socket_fn=%s", wrap_socket_fn)
        except Exception as e:
            netlog("SSL error", exc_info=True)
            cpaths = csv("'%s'" % x for x in (opts.ssl_cert, opts.ssl_key)
                         if x)
            raise InitException(
                "cannot create SSL socket, check your certificate paths (%s): %s"
                % (cpaths, e))

    from xpra.server.socket_util import setup_tcp_socket, setup_udp_socket, setup_vsock_socket, setup_local_sockets, has_dual_stack
    min_port = int(opts.min_port)

    def hosts(host_str):
        if host_str == "*":
            if has_dual_stack():
                #IPv6 will also listen for IPv4:
                return ["::"]
            #no dual stack, so we have to listen on both IPv4 and IPv6 explicitly:
            return ["0.0.0.0", "::"]
        return [host_str]

    def add_mdns(socktype, host_str, port):
        recs = mdns_recs.setdefault(socktype.lower(), [])
        for host in hosts(host_str):
            rec = (host, port)
            if rec not in recs:
                recs.append(rec)

    def add_tcp_socket(socktype, host_str, iport):
        if iport < min_port:
            error_cb("invalid %s port number %i (minimum value is %i)" %
                     (socktype, iport, min_port))
        for host in hosts(host_str):
            socket = setup_tcp_socket(host, iport, socktype)
            sockets.append(socket)
            add_mdns(socktype, host, iport)

    def add_udp_socket(socktype, host_str, iport):
        if iport < min_port:
            error_cb("invalid %s port number %i (minimum value is %i)" %
                     (socktype, iport, min_port))
        for host in hosts(host_str):
            socket = setup_udp_socket(host, iport, socktype)
            sockets.append(socket)
            add_mdns(socktype, host, iport)

    # Initialize the TCP sockets before the display,
    # That way, errors won't make us kill the Xvfb
    # (which may not be ours to kill at that point)
    netlog("setting up SSL sockets: %s", csv(bind_ssl))
    for host, iport in bind_ssl:
        add_tcp_socket("ssl", host, iport)
    netlog("setting up https / wss (secure websockets): %s", csv(bind_wss))
    for host, iport in bind_wss:
        add_tcp_socket("wss", host, iport)
    tcp_ssl = ssl_opt in TRUE_OPTIONS or (ssl_opt == "auto" and opts.ssl_cert)
    netlog("setting up TCP sockets: %s", csv(bind_tcp))
    for host, iport in bind_tcp:
        add_tcp_socket("tcp", host, iport)
        if tcp_ssl:
            add_mdns("ssl", host, iport)
    netlog("setting up UDP sockets: %s", csv(bind_udp))
    for host, iport in bind_udp:
        add_udp_socket("udp", host, iport)
    netlog("setting up http / ws (websockets): %s", csv(bind_ws))
    for host, iport in bind_ws:
        add_tcp_socket("ws", host, iport)
        if tcp_ssl:
            add_mdns("wss", host, iport)
    if bind_rfb and (proxying or starting):
        log.warn("Warning: bind-rfb sockets cannot be used with '%s' mode" %
                 mode)
    else:
        netlog("setting up rfb sockets: %s", csv(bind_rfb))
        for host, iport in bind_rfb:
            add_tcp_socket("rfb", host, iport)
    netlog("setting up vsock sockets: %s", csv(bind_vsock))
    for cid, iport in bind_vsock:
        socket = setup_vsock_socket(cid, iport)
        sockets.append(socket)
        #add_mdns("vsock", str(cid), iport)

    # systemd socket activation:
    try:
        from xpra.platform.xposix.sd_listen import get_sd_listen_sockets
    except ImportError:
        pass
    else:
        sd_sockets = get_sd_listen_sockets()
        netlog("systemd sockets: %s", sd_sockets)
        for stype, socket, addr in sd_sockets:
            sockets.append((stype, socket, addr))
            netlog("%s : %s", (stype, [addr]), socket)
            if stype == "tcp":
                host, iport = addr
                add_mdns("tcp", host, iport)

    sanitize_env()
    if POSIX:
        if xrd:
            os.environ["XDG_RUNTIME_DIR"] = xrd
        os.environ["XDG_SESSION_TYPE"] = "x11"
        if not starting_desktop:
            os.environ["XDG_CURRENT_DESKTOP"] = opts.wm_name
        configure_imsettings_env(opts.input_method)
    if display_name[0] != 'S':
        os.environ["DISPLAY"] = display_name
        os.environ["CKCON_X11_DISPLAY"] = display_name
    else:
        try:
            del os.environ["DISPLAY"]
        except:
            pass
    os.environ.update(protected_env)
    log("env=%s", os.environ)

    UINPUT_UUID_LEN = 12
    UINPUT_UUID_MIN_LEN = 12
    UINPUT_UUID_MAX_LEN = 32
    # Start the Xvfb server first to get the display_name if needed
    odisplay_name = display_name
    xvfb = None
    xvfb_pid = None
    uinput_uuid = None
    if start_vfb:
        assert not proxying and xauth_data
        pixel_depth = validate_pixel_depth(opts.pixel_depth)
        from xpra.x11.vfb_util import start_Xvfb, check_xvfb_process
        from xpra.server.server_util import has_uinput
        uinput_uuid = None
        if has_uinput() and opts.input_devices.lower() in (
                "uinput", "auto") and not shadowing:
            from xpra.os_util import get_rand_chars
            uinput_uuid = get_rand_chars(UINPUT_UUID_LEN)
        xvfb, display_name, cleanups = start_Xvfb(opts.xvfb, pixel_depth,
                                                  display_name, cwd, uid, gid,
                                                  username, xauth_data,
                                                  uinput_uuid)
        for f in cleanups:
            add_cleanup(f)
        xvfb_pid = xvfb.pid
        #always update as we may now have the "real" display name:
        os.environ["DISPLAY"] = display_name
        os.environ["CKCON_X11_DISPLAY"] = display_name
        os.environ.update(protected_env)
        if display_name != odisplay_name and pam:
            pam.set_items({"XDISPLAY": display_name})

        def check_xvfb():
            return check_xvfb_process(xvfb)
    else:

        def check_xvfb():
            return True

    if POSIX and not OSX and displayfd > 0:
        from xpra.platform.displayfd import write_displayfd
        try:
            display = display_name[1:]
            log("writing display='%s' to displayfd=%i", display, displayfd)
            assert write_displayfd(displayfd, display), "timeout"
        except Exception as e:
            log.error("write_displayfd failed", exc_info=True)
            log.error("Error: failed to write '%s' to fd=%s", display_name,
                      displayfd)
            log.error(" %s", str(e) or type(e))
            del e
        try:
            os.close(displayfd)
        except:
            pass

    if not proxying:

        def close_display():
            close_gtk_display()
            kill_xvfb(xvfb_pid)

        add_cleanup(close_display)
    else:
        close_display = None

    if opts.daemon:

        def noerr(fn, *args):
            try:
                fn(*args)
            except:
                pass

        log_filename1 = select_log_file(log_dir, opts.log_file, display_name)
        if log_filename0 != log_filename1:
            # we now have the correct log filename, so use it:
            os.rename(log_filename0, log_filename1)
            if odisplay_name != display_name:
                #this may be used by scripts, let's try not to change it:
                noerr(stderr.write, "Actual display used: %s\n" % display_name)
            noerr(stderr.write,
                  "Actual log file name is now: %s\n" % log_filename1)
            noerr(stderr.flush)
        noerr(stdout.close)
        noerr(stderr.close)
    #we should not be using stdout or stderr from this point:
    del stdout
    del stderr

    if not check_xvfb():
        #xvfb problem: exit now
        return 1

    #create devices for vfb if needed:
    devices = {}
    if not start_vfb and not proxying and not shadowing:
        #try to find the existing uinput uuid:
        #use a subprocess to avoid polluting our current process
        #with X11 connections before we get a chance to change uid
        cmd = ["xprop", "-display", display_name, "-root", "_XPRA_UINPUT_ID"]
        try:
            code, out, err = get_status_output(cmd)
        except Exception as e:
            log("failed to get existing uinput id: %s", e)
            del e
        else:
            log("Popen(%s)=%s", cmd, (code, out, err))
            if code == 0 and out.find("=") > 0:
                uinput_uuid = out.split("=", 1)[1]
                log("raw uinput uuid=%s", uinput_uuid)
                uinput_uuid = strtobytes(uinput_uuid.strip('\n\r"\\ '))
                if uinput_uuid:
                    if len(uinput_uuid) > UINPUT_UUID_MAX_LEN or len(
                            uinput_uuid) < UINPUT_UUID_MIN_LEN:
                        log.warn("Warning: ignoring invalid uinput id:")
                        log.warn(" '%s'", uinput_uuid)
                        uinput_uuid = None
                    else:
                        log.info("retrieved existing uinput id: %s",
                                 bytestostr(uinput_uuid))
    if uinput_uuid:
        devices = create_input_devices(uinput_uuid, uid)

    if ROOT and (uid != 0 or gid != 0):
        log("root: switching to uid=%i, gid=%i", uid, gid)
        setuidgid(uid, gid)
        os.environ.update({
            "HOME": home,
            "USER": username,
            "LOGNAME": username,
        })
        shell = get_shell_for_uid(uid)
        if shell:
            os.environ["SHELL"] = shell
        #now we've changed uid, it is safe to honour all the env updates:
        configure_env(opts.env)
        os.environ.update(protected_env)

    if opts.chdir:
        os.chdir(opts.chdir)

    display = None
    if not proxying:
        no_gtk()
        if POSIX and not OSX and (starting or starting_desktop or shadowing):
            #check that we can access the X11 display:
            from xpra.x11.vfb_util import verify_display_ready
            if not verify_display_ready(xvfb, display_name, shadowing):
                return 1
            if not PYTHON3:
                from xpra.x11.gtk2.gdk_display_util import verify_gdk_display  #@UnusedImport
            else:
                from xpra.x11.gtk3.gdk_display_util import verify_gdk_display  #@Reimport
            display = verify_gdk_display(display_name)
            if not display:
                return 1
        #on win32, this ensures that we get the correct screen size to shadow:
        from xpra.platform.gui import init as gui_init
        gui_init()

    #setup unix domain socket:
    if not opts.socket_dir and not opts.socket_dirs:
        #we always need at least one valid socket dir
        from xpra.platform.paths import get_socket_dirs
        opts.socket_dirs = get_socket_dirs()
    local_sockets = setup_local_sockets(opts.bind, opts.socket_dir,
                                        opts.socket_dirs, display_name,
                                        clobber, opts.mmap_group,
                                        opts.socket_permissions, username, uid,
                                        gid)
    netlog("setting up local sockets: %s", local_sockets)
    for rec, cleanup_socket in local_sockets:
        socktype, socket, sockpath = rec
        #ie: ("unix-domain", sock, sockpath), cleanup_socket
        sockets.append(rec)
        netlog("%s %s : %s", socktype, sockpath, socket)
        add_cleanup(cleanup_socket)
        if opts.mdns:
            ssh_port = get_ssh_port()
            netlog("ssh %s:%s : %s", "", ssh_port, socket)
            if ssh_port:
                add_mdns("ssh", "", ssh_port)

    kill_dbus = None
    if shadowing:
        from xpra.platform.shadow_server import ShadowServer
        app = ShadowServer()
    elif proxying:
        from xpra.server.proxy.proxy_server import ProxyServer
        app = ProxyServer()
    else:
        if not check_xvfb():
            return 1
        assert starting or starting_desktop or upgrading
        from xpra.x11.gtk2.gdk_display_source import init_gdk_display_source
        init_gdk_display_source()
        #(now we can access the X11 server)

        #make sure the pid we save is the real one:
        if not check_xvfb():
            return 1
        if xvfb_pid is not None:
            #save the new pid (we should have one):
            save_xvfb_pid(xvfb_pid)

        if POSIX:
            save_uinput_id(uinput_uuid or "")
            dbus_pid = -1
            dbus_env = {}
            if clobber:
                #get the saved pids and env
                dbus_pid = get_dbus_pid()
                dbus_env = get_dbus_env()
                log("retrieved existing dbus attributes")
            else:
                assert starting or starting_desktop
                if xvfb_pid is not None:
                    #save the new pid (we should have one):
                    save_xvfb_pid(xvfb_pid)
                bus_address = protected_env.get("DBUS_SESSION_BUS_ADDRESS")
                log("dbus_launch=%s, current DBUS_SESSION_BUS_ADDRESS=%s",
                    opts.dbus_launch, bus_address)
                if opts.dbus_launch and not bus_address:
                    #start a dbus server:
                    def kill_dbus():
                        log("kill_dbus: dbus_pid=%s" % dbus_pid)
                        if dbus_pid <= 0:
                            return
                        try:
                            os.kill(dbus_pid, signal.SIGINT)
                        except Exception as e:
                            log.warn(
                                "Warning: error trying to stop dbus with pid %i:",
                                dbus_pid)
                            log.warn(" %s", e)

                    add_cleanup(kill_dbus)
                    #this also updates os.environ with the dbus attributes:
                    dbus_pid, dbus_env = start_dbus(opts.dbus_launch)
                    if dbus_pid > 0:
                        save_dbus_pid(dbus_pid)
                    if dbus_env:
                        save_dbus_env(dbus_env)
            log("dbus attributes: pid=%s, env=%s", dbus_pid, dbus_env)
            if dbus_env:
                os.environ.update(dbus_env)
                os.environ.update(protected_env)

        log("env=%s", os.environ)
        try:
            # This import is delayed because the module depends on gtk:
            from xpra.x11.bindings.window_bindings import X11WindowBindings
            X11Window = X11WindowBindings()
            if (starting or
                    starting_desktop) and not clobber and opts.resize_display:
                from xpra.x11.vfb_util import set_initial_resolution
                set_initial_resolution(starting_desktop)
        except ImportError as e:
            log.error(
                "Failed to load Xpra server components, check your installation: %s"
                % e)
            return 1
        if starting or upgrading:
            if not X11Window.displayHasXComposite():
                log.error(
                    "Xpra 'start' subcommand runs as a compositing manager")
                log.error(
                    " it cannot use a display which lacks the XComposite extension!"
                )
                return 1
            if starting:
                #check for an existing window manager:
                from xpra.x11.gtk2.wm import wm_check
                if not wm_check(display, opts.wm_name, upgrading):
                    return 1
            log("XShape=%s", X11Window.displayHasXShape())
            from xpra.x11.server import XpraServer
            app = XpraServer(clobber)
        else:
            assert starting_desktop
            from xpra.x11.desktop_server import XpraDesktopServer
            app = XpraDesktopServer()
        app.init_virtual_devices(devices)

    #publish mdns records:
    if opts.mdns:
        from xpra.platform.info import get_username
        from xpra.server.socket_util import mdns_publish
        mdns_info = {
            "display": display_name,
            "username": get_username(),
            "uuid": strtobytes(app.uuid),
            "platform": sys.platform,
            "type": app.session_type,
        }
        if opts.session_name:
            mdns_info["session"] = opts.session_name
        for mode, listen_on in mdns_recs.items():
            mdns_publish(display_name, mode, listen_on, mdns_info)

    try:
        app._ssl_wrap_socket = wrap_socket_fn
        app.original_desktop_display = desktop_display
        app.exec_cwd = opts.chdir or cwd
        app.init(opts)
        app.init_components(opts)
    except InitException as e:
        log.error("xpra server initialization error:")
        log.error(" %s", e)
        return 1
    except Exception as e:
        log.error("Error: cannot start the %s server",
                  app.session_type,
                  exc_info=True)
        log.error(str(e))
        log.info("")
        return 1

    #honour start child, html webserver, and setup child reaper
    if not proxying and not upgrading:
        if opts.exit_with_children:
            assert opts.start_child, "exit-with-children was specified but start-child is missing!"
        app.start_commands = opts.start
        app.start_child_commands = opts.start_child
        app.start_after_connect = opts.start_after_connect
        app.start_child_after_connect = opts.start_child_after_connect
        app.start_on_connect = opts.start_on_connect
        app.start_child_on_connect = opts.start_child_on_connect
        app.exec_start_commands()
    del opts

    log("%s(%s)", app.init_sockets, sockets)
    app.init_sockets(sockets)
    log("%s(%s)", app.init_when_ready, _when_ready)
    app.init_when_ready(_when_ready)

    try:
        #from here on, we own the vfb, even if we inherited one:
        if (starting or starting_desktop or upgrading) and clobber:
            #and it will be killed if exit cleanly:
            xvfb_pid = get_xvfb_pid()

        log("running %s", app.run)
        r = app.run()
        log("%s()=%s", app.run, r)
    except KeyboardInterrupt:
        log.info("stopping on KeyboardInterrupt")
        r = 0
    except Exception:
        log.error("server error", exc_info=True)
        r = -128
    if r > 0:
        # Upgrading/exiting, so leave X and dbus servers running
        if close_display:
            _cleanups.remove(close_display)
        if kill_dbus:
            _cleanups.remove(kill_dbus)
        from xpra.server.server_core import ServerCore
        if r == ServerCore.EXITING_CODE:
            log.info("exiting: not cleaning up Xvfb")
        else:
            log.info("upgrading: not cleaning up Xvfb")
        log("cleanups=%s", _cleanups)
        r = 0
    return r
Exemple #30
0
 def __init__(self, username):
     self.salt = None
     self.pw = None
     self.username = get_username()