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()
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()
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.")
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()
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()
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
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
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)
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
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
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
def __init__(self, username): self.salt = None self.pw = None self.username = get_username()
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
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
def __init__(self, username, **kwargs): SysAuthenticator.__init__(self, username, **kwargs) self.salt = None self.pw = None self.username = get_username()
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
"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")
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
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
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
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
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
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
def __init__(self, username, **kwargs): super().__init__(username or get_username(), **kwargs) self.salt = None
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
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
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
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()
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