def init(self, opts): if not parse_bool("rfb-upgrade", opts.rfb_upgrade): self._rfb_upgrade = 0 else: self._rfb_upgrade = parse_number(int, "rfb-upgrade", opts.rfb_upgrade, 0) log("init(..) rfb-upgrade=%i", self._rfb_upgrade)
def init(self, opts): X11ServerBase.init(self, opts) if not parse_bool("rfb-upgrade", opts.rfb_upgrade): self._rfb_upgrade = 0 else: self._rfb_upgrade = parse_number(int, "rfb-upgrade", opts.rfb_upgrade, 0)
def main(): import sys if len(sys.argv)!=4: print("usage: %s DISPLAY WID True|False" % sys.argv[0]) return DISPLAY = int(sys.argv[1]) wid = int(sys.argv[2]) from xpra.scripts.config import parse_bool flag = parse_bool("flag", sys.argv[3]) test_dbus(DISPLAY, wid, flag)
def makeRootWindowModels(self): screenlog("makeRootWindowModels() root=%s, display_options=%s", self.root, self.display_options) self.capture = self.setup_capture() model_class = self.get_root_window_model_class() models = [] display_name = prettify_plug_name(self.root.get_screen().get_display().get_name()) monitors = self.get_shadow_monitors() match_str = None multi_window = MULTI_WINDOW geometries = None if "=" in self.display_options: #parse the display options as a dictionary: opt_dict = parse_simple_dict(self.display_options) windows = opt_dict.get("windows") if windows: self.window_matches = windows.split("/") return self.makeDynamicWindowModels() match_str = opt_dict.get("plug") multi_window = parse_bool("multi-window", opt_dict.get("multi-window", multi_window)) geometries_str = opt_dict.get("geometry") if geometries_str: geometries = parse_geometries(geometries_str) else: try: geometries = parse_geometries(self.display_options) except Exception: match_str = self.display_options if not multi_window or geometries: for geometry in (geometries or (self.root.get_geometry()[:4],)): model = model_class(self.root, self.capture, display_name, geometry) models.append(model) return models found = [] screenlog("capture inputs matching %r", match_str or "all") for i, monitor in enumerate(monitors): plug_name, x, y, width, height, scale_factor = monitor title = display_name if plug_name or i>1: title = plug_name or str(i) found.append(plug_name or title) if match_str and not(title in match_str or plug_name in match_str): screenlog.info(" skipped monitor %s", plug_name or title) continue geometry = (x, y, width, height) model = model_class(self.root, self.capture, title, geometry) models.append(model) screenlog("monitor %i: %10s geometry=%s, scale factor=%s", i, title, geometry, scale_factor) screenlog("makeRootWindowModels()=%s", models) if not models and match_str: screenlog.warn("Warning: no monitors found matching %r", match_str) screenlog.warn(" only found: %s", csv(found)) return models
def do_init(self, opts): super().do_init(opts) #the server class sets the default value for 'xsettings_enabled' #it is overriden in the seamless server (enabled by default), #and we let the options have the final say here: self._xsettings_enabled = parse_bool("xsettings", opts.xsettings, self._xsettings_enabled) log("xsettings_enabled(%s)=%s", opts.xsettings, self._xsettings_enabled) if self._xsettings_enabled: from xpra.x11.xsettings import XSettingsHelper self._default_xsettings = XSettingsHelper().get_settings() log("_default_xsettings=%s", self._default_xsettings) self.init_all_server_settings()
def init(self, opts): """ initialize variables from configuration """ self.init_aliases() for c in CLIENT_BASES: log("init: %s", c) c.init(self, opts) self.title = opts.title self.session_name = bytestostr(opts.session_name) self.xsettings_enabled = not (OSX or WIN32) and parse_bool("xsettings", opts.xsettings, True) self.readonly = opts.readonly self.client_supports_sharing = opts.sharing is True self.client_lock = opts.lock is True self.headerbar = opts.headerbar
def configbool(key, default_value=True): return parse_bool(key, configvalue(key), default_value)
def init(self, opts, _extra_args=None): self.log_both = (opts.remote_logging or "").lower() == "both" self.client_supports_remote_logging = self.log_both or parse_bool( "remote-logging", opts.remote_logging)
def get_run_command(self, attach=False): localhost = self.localhost_btn.get_active() if xdg and localhost: if self.desktop_entry.getTryExec(): try: command = self.desktop_entry.findTryExec() except Exception: command = self.desktop_entry.getTryExec() else: command = self.desktop_entry.getExec() else: command = self.entry.get_text() cmd = get_xpra_command() + [self.get_run_mode()] ewc = self.exit_with_client_cb.get_active() cmd.append("--exit-with-client=%s" % ewc) shadow = self.shadow_btn.get_active() if not shadow: ewc = self.exit_with_children_cb.get_active() cmd.append("--exit-with-children=%s" % ewc) if ewc: cmd.append("--start-child=%s" % command) else: cmd.append("--start=%s" % command) cmd.append("--attach=%s" % attach) #process session_config if we have one: for k in ( "splash", "border", "headerbar", "notifications", "system-tray", "cursors", "bell", "modal-windows", "pixel-depth", "mousewheel", ): fn = k.replace("-", "_") if not hasattr(self.session_options, fn): continue value = getattr(self.session_options, fn) default_value = self.default_config.get(k) ot = OPTION_TYPES.get(k) if ot is bool: value = parse_bool(k, value) if value!=default_value: log.info("%s=%s (%s) - not %s (%s)", k, value, type(value), default_value, type(default_value)) cmd.append("--%s=%s" % (k, value)) localhost = self.localhost_btn.get_active() if self.display_entry.is_visible(): display = self.display_entry.get_text().lstrip(":") else: display = self.display_combo.get_active_text() if localhost: uri = ":"+display if display else "" else: mode = self.mode_combo.get_active_text() uri = "%s://" % mode.lower() username = self.username_entry.get_text() if username: uri += "%s@" % username host = self.host_entry.get_text() if host: uri += host port = self.port_entry.get_text() if port!=self.get_default_port(mode): uri += ":%s" % port uri += "/" if display: uri += display if uri: cmd.append(uri) return cmd
def __init__(self, **kwargs): self.service = kwargs.pop("service", PAM_AUTH_SERVICE) self.check_account = parse_bool( "check-account", kwargs.pop("check-account", PAM_CHECK_ACCOUNT), False) super().__init__(**kwargs)
def do_run_server(error_cb, opts, mode, xpra_file, extra_args, desktop_display=None, progress_cb=None): assert mode in ( "start", "start-desktop", "upgrade", "upgrade-desktop", "shadow", "proxy", ) def _progress(i, msg): if progress_cb: progress_cb(i, msg) progress = _progress progress(10, "initializing environment") 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) #remove anything pointing to dbus from the current env #(so we only detect a dbus instance started by pam, # and override everything else) for k in tuple(os.environ.keys()): if k.startswith("DBUS_"): del os.environ[k] use_display = parse_bool("use-display", opts.use_display) starting = mode == "start" starting_desktop = mode == "start-desktop" upgrading = mode == "upgrade" upgrading_desktop = mode == "upgrade-desktop" shadowing = mode == "shadow" proxying = mode == "proxy" if not proxying and POSIX and not OSX: #we don't support wayland servers, #so make sure GDK will use the X11 backend: from xpra.os_util import saved_env saved_env["GDK_BACKEND"] = "x11" os.environ["GDK_BACKEND"] = "x11" has_child_arg = (opts.start_child or opts.start_child_on_connect or opts.start_child_after_connect or opts.start_child_on_last_client_exit) if proxying or upgrading or upgrading_desktop: #when proxying or upgrading, don't exec any plain start commands: opts.start = opts.start_child = [] elif opts.exit_with_children: assert has_child_arg, "exit-with-children was specified but start-child* is missing!" elif opts.start_child: warn("Warning: the 'start-child' option is used,") warn(" but 'exit-with-children' is not enabled,") warn(" use 'start' instead") 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 upgrading_desktop or shadowing: #there should already be one running #so change None ('auto') to False if opts.pulseaudio is None: 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 = "Main" 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 or upgrading_desktop) 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 upgrading and not 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 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 or proxying or upgrading or upgrading_desktop) and \ opts.exit_with_children and not has_child_arg: 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, find_log_dir, create_input_devices, source_env, ) script = None if POSIX and getuid() != 0: 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) 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 clobber = int(upgrading or upgrading_desktop) * CLOBBER_UPGRADE | int( use_display or 0) * CLOBBER_USE_DISPLAY start_vfb = not (shadowing or proxying or clobber) xauth_data = None if start_vfb: xauth_data = get_hex_uuid() # 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 script: # Write out a shell-script so that we can start our proxy in a clean # environment: write_runner_shell_scripts(script) import datetime extra_expand = { "TIMESTAMP": datetime.datetime.now().strftime("%Y%m%d-%H%M%S") } log_to_file = opts.daemon or os.environ.get("XPRA_LOG_TO_FILE", "") == "1" if start_vfb or log_to_file: #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 log_to_file: 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, extra_expand) if os.path.exists(log_filename0) and not display_name.startswith("S"): #don't overwrite the log file just yet, #as we may still fail to start log_filename0 += ".new" logfd = open_log_file(log_filename0) if POSIX and ROOT and (uid > 0 or gid > 0): try: os.fchown(logfd, uid, gid) except OSError as e: noerr(stderr.write, "failed to chown the log file '%s'\n" % log_filename0) noerr(stderr.flush) stdout, stderr = redirect_std_to_log(logfd, *protected_fds) noerr( stderr.write, "Entering daemon mode; " + "any further errors will be reported to:\n" + (" %s\n" % log_filename0)) noerr(stderr.flush) os.environ["XPRA_SERVER_LOG"] = log_filename0 else: #server log does not exist: os.environ.pop("XPRA_SERVER_LOG", None) #warn early about this: if (starting or starting_desktop ) and desktop_display and opts.notifications and not opts.dbus_launch: print_DE_warnings() if start_vfb and opts.xvfb.find("Xephyr") >= 0 and opts.sync_xvfb <= 0: warn("Warning: using Xephyr as vfb") warn(" you should also enable the sync-xvfb option") warn(" to keep the Xephyr window updated") progress(10, "creating sockets") from xpra.net.socket_util import get_network_logger, setup_local_sockets, create_sockets sockets = create_sockets(opts, error_cb) sanitize_env() os.environ.update(source_env(opts.source)) if POSIX: if xrd: os.environ["XDG_RUNTIME_DIR"] = xrd if not OSX: 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 if POSIX: os.environ["CKCON_X11_DISPLAY"] = display_name elif not start_vfb or opts.xvfb.find("Xephyr") < 0: os.environ.pop("DISPLAY", None) os.environ.update(protected_env) from xpra.log import Logger log = Logger("server") 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 and use_display is None: #use-display='auto' so we have to figure out #if we have to start the vfb or not: if not display_name: use_display = False else: progress(20, "connecting to the display") start_vfb = verify_display( None, display_name, log_errors=False, timeout=1) != 0 if start_vfb: progress(20, "starting a virtual display") 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, parse_resolution 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) vfb_geom = "" try: vfb_geom = parse_resolution(opts.resize_display) except Exception: pass xvfb, display_name, cleanups = start_Xvfb(opts.xvfb, vfb_geom, 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(timeout=0): return check_xvfb_process(xvfb, timeout=timeout, command=opts.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): log("found XAUTHORITY=%s", xauthority) os.environ["XAUTHORITY"] = xauthority def check_xvfb(timeout=0): #pylint: disable=unused-argument return True if POSIX and not OSX and displayfd > 0: from xpra.platform.displayfd import write_displayfd try: display_no = display_name[1:] #ensure it is a string containing the number: display_no = str(int(display_no)) log("writing display_no='%s' to displayfd=%i", display_no, displayfd) assert write_displayfd(displayfd, display_no), "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 if not check_xvfb(1): noerr(stderr.write, "vfb failed to start, exiting\n") return EXIT_VFB_ERROR if WIN32 and os.environ.get("XPRA_LOG_FILENAME"): os.environ["XPRA_SERVER_LOG"] = os.environ["XPRA_LOG_FILENAME"] if opts.daemon: log_filename1 = osexpand( select_log_file(log_dir, opts.log_file, display_name), username, uid, gid, extra_expand) if log_filename0 != log_filename1: # we now have the correct log filename, so use it: try: os.rename(log_filename0, log_filename1) except (OSError, IOError): pass else: os.environ["XPRA_SERVER_LOG"] = 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(): noerr(stderr.write, "vfb failed to start, exiting\n") return EXIT_VFB_ERROR #create devices for vfb if needed: devices = {} if not start_vfb and not proxying and not shadowing and envbool( "XPRA_UINPUT", True): #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: log("chdir(%s)", opts.chdir) os.chdir(opts.chdir) dbus_pid, dbus_env = 0, {} if not shadowing and POSIX and not OSX and not clobber: no_gtk() assert starting or starting_desktop or proxying try: from xpra.server.dbus.dbus_start import start_dbus except ImportError as e: log("dbus components are not installed: %s", e) else: dbus_pid, dbus_env = start_dbus(opts.dbus_launch) if dbus_env: os.environ.update(dbus_env) if not proxying: if POSIX and not OSX: no_gtk() if starting or starting_desktop or shadowing: r = verify_display(xvfb, display_name, shadowing) if r: return r #on win32, this ensures that we get the correct screen size to shadow: from xpra.platform.gui import init as gui_init log("gui_init()") gui_init() progress(50, "creating local sockets") #setup unix domain socket: netlog = get_network_logger() 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) sockets.update(local_sockets) if POSIX and (starting or upgrading or starting_desktop or upgrading_desktop): #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_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(" non-embedded ssh connections will not be available") set_server_features(opts) if not proxying and POSIX and not OSX: if not check_xvfb(): return 1 from xpra.x11.gtk_x11.gdk_display_source import init_gdk_display_source if os.environ.get("NO_AT_BRIDGE") is None: os.environ["NO_AT_BRIDGE"] = "1" init_gdk_display_source() #(now we can access the X11 server) if uinput_uuid: save_uinput_id(uinput_uuid) progress(60, "initializing server") if shadowing: app = make_shadow_server() elif proxying: app = make_proxy_server() else: if starting or upgrading: app = make_server(clobber) else: assert starting_desktop or upgrading_desktop app = make_desktop_server(clobber) app.init_virtual_devices(devices) try: app.exec_cwd = opts.chdir or cwd app.display_name = display_name app.init(opts) progress(70, "initializing sockets") app.init_sockets(sockets) app.init_dbus(dbus_pid, dbus_env) if not shadowing and not proxying: app.init_display_pid(xvfb_pid) app.original_desktop_display = desktop_display del opts if not app.server_ready(): return 1 progress(80, "finalizing") app.server_init() app.setup() app.init_when_ready(_when_ready) except InitException as e: log.error("xpra server initialization error:") log.error(" %s", e) app.cleanup() 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("") if upgrading or upgrading_desktop: #something abnormal occurred, #don't kill the vfb on exit: from xpra.server import EXITING_CODE app._upgrading = EXITING_CODE app.cleanup() return 1 try: progress(100, "running") log("running %s", app.run) r = app.run() log("%s()=%s", app.run, r) except KeyboardInterrupt: log.info("stopping on KeyboardInterrupt") app.cleanup() return EXIT_OK except Exception: log.error("server error", exc_info=True) app.cleanup() return -128 else: if r > 0: r = 0 return r
def __init__(self, username, **kwargs): self.service = kwargs.pop("service", PAM_AUTH_SERVICE) self.check_account = parse_bool("check-account", kwargs.pop("check-account", PAM_CHECK_ACCOUNT), False) SysAuthenticator.__init__(self, username, **kwargs)
def control_command_set_lock(self, lock): self.lock = parse_bool("lock", lock) self.setting_changed("lock", lock is not False) self.setting_changed("lock-toggle", lock is None) return "lock set to %s" % self.lock
def check_channel_exec_request(self, channel, command): def fail(): self.event.set() channel.close() return False log("check_channel_exec_request(%s, %s)", channel, command) cmd = shlex.split(decode_str(command)) log("check_channel_exec_request: cmd=%s", cmd) # not sure if this is the best way to handle this, 'command -v xpra' has len=3 if cmd[0] in ("type", "which", "command") and len(cmd) in (2, 3): xpra_cmd = cmd[-1] #ie: $XDG_RUNTIME_DIR/xpra/run-xpra or "xpra" if not POSIX: assert WIN32 #we can't execute "type" or "which" on win32, #so we just answer as best we can #and only accept "xpra" as argument: if xpra_cmd.strip('"').strip("'") == "xpra": chan_send(channel.send, "xpra is xpra") channel.send_exit_status(0) else: chan_send(channel.send_stderr, "type: %s: not found" % xpra_cmd) channel.send_exit_status(1) return True #we don't want to use a shell, #but we need to expand the file argument: cmd[-1] = osexpand(xpra_cmd) try: proc = Popen(cmd, stdout=PIPE, stderr=PIPE, close_fds=not WIN32) out, err = proc.communicate() except Exception as e: log("check_channel_exec_request(%s, %s)", channel, command, exc_info=True) chan_send(channel.send_stderr, "failed to execute command: %s" % e) channel.send_exit_status(1) else: log("check_channel_exec_request: out(%s)=%s", cmd, out) log("check_channel_exec_request: err(%s)=%s", cmd, err) chan_send(channel.send, out) chan_send(channel.send_stderr, err) channel.send_exit_status(proc.returncode) elif cmd[0].endswith("xpra") and len(cmd) >= 2: subcommand = cmd[1].strip("\"'").rstrip(";") log("ssh xpra subcommand: %s", subcommand) if subcommand in ("_proxy_start", "_proxy_start_desktop", "_proxy_shadow_start"): proxy_start = parse_bool("proxy-start", self.options.get("proxy-start"), False) if not proxy_start: log.warn("Warning: received a %r session request", subcommand) log.warn( " this feature is not yet implemented with the builtin ssh server" ) return fail() self.proxy_start(channel, subcommand, cmd[2:]) elif subcommand == "_proxy": if len(cmd) == 3: #only the display can be specified here display = cmd[2] display_name = getattr(self, "display_name", None) if display_name != display: log.warn("Warning: the display requested (%r)", display) log.warn(" is not the current display (%r)", display_name) return fail() else: log.warn("Warning: unsupported xpra subcommand '%s'", cmd[1]) return fail() #we're ready to use this socket as an xpra channel self._run_proxy(channel) else: #plain 'ssh' clients execute a long command with if+else statements, #try to detect it and extract the actual command the client is trying to run. #ie: #['sh', '-c', # ': run-xpra _proxy;xpra initenv;\ # if [ -x $XDG_RUNTIME_DIR/xpra/run-xpra ]; then $XDG_RUNTIME_DIR/xpra/run-xpra _proxy;\ # elif [ -x ~/.xpra/run-xpra ]; then ~/.xpra/run-xpra _proxy;\ # elif type "xpra" > /dev/null 2>&1; then xpra _proxy;\ # elif [ -x /usr/local/bin/xpra ]; then /usr/local/bin/xpra _proxy;\ # else echo "no run-xpra command found"; exit 1; fi'] #if .* ; then .*/run-xpra _proxy; log("parse cmd=%s (len=%i)", cmd, len(cmd)) if len(cmd) == 1: #ie: 'thelongcommand' parse_cmd = cmd[0] elif len(cmd) == 3 and cmd[:2] == [ "sh", "-c" ]: #ie: 'sh' '-c' 'thelongcommand' parse_cmd = cmd[2] else: parse_cmd = "" #for older clients, try to parse the long command #and identify the subcommands from there subcommands = [] for s in parse_cmd.split("if "): if (s.startswith("type \"xpra\"") or s.startswith("which \"xpra\"") or s.startswith("[ -x")) and s.find("then ") > 0: then_str = s.split("then ", 1)[1] #ie: then_str="$XDG_RUNTIME_DIR/xpra/run-xpra _proxy; el" if then_str.find(";") > 0: then_str = then_str.split(";")[0] parts = shlex.split(then_str) if len(parts) >= 2: subcommand = parts[1] #ie: "_proxy" subcommands.append(subcommand) log("subcommands=%s", subcommands) if subcommands and tuple(set(subcommands))[0] == "_proxy": self._run_proxy(channel) else: log.warn("Warning: unsupported ssh command:") log.warn(" %s", cmd) return fail() return True
parser.error("invalid dpi: %s" % e) if options.encoding and options.encoding not in ENCODINGS: parser.error("encoding %s is not supported, try: %s" % (options.encoding, ", ".join(ENCODINGS))) if options.encryption: assert len(ENCRYPTION_CIPHERS ) > 0, "cannot use encryption: no ciphers available" if options.encryption not in ENCRYPTION_CIPHERS: parser.error("encryption %s is not supported, try: %s" % (options.encryption, ", ".join(ENCRYPTION_CIPHERS))) if not options.password_file: parser.error( "encryption %s cannot be used without a password (see --password-file option)" % options.encryption) #ensure opengl is either True, False or None options.opengl = parse_bool("opengl", options.opengl) def toggle_logging(level): if not options.debug: logging.root.setLevel(level) return categories = options.debug.split(",") for cat in categories: if cat.startswith("-"): logging.getLogger(cat[1:]).setLevel(logging.INFO) if cat == "all": logger = logging.root else: logger = logging.getLogger(cat) logger.setLevel(level)
def makeRootWindowModels(self): screenlog("makeRootWindowModels() root=%s, display_options=%s", self.root, self.display_options) self.capture = self.setup_capture() model_class = self.get_root_window_model_class() models = [] display_name = prettify_plug_name( self.root.get_screen().get_display().get_name()) monitors = self.get_shadow_monitors() match_str = None multi_window = MULTI_WINDOW geometries = None def parse_geometry(s): try: parts = s.split("@") if len(parts) == 1: x = y = 0 else: x, y = [int(v.strip(" ")) for v in parts[1].split("x")] w, h = [int(v.strip(" ")) for v in parts[0].split("x")] geometry = [x, y, w, h] screenlog("capture geometry: %s", geometry) return geometry except ValueError: screenlog("failed to parse geometry %r", s, exc_info=True) screenlog.error( "Error: invalid display geometry specified: %r", s) screenlog.error(" use the format: WIDTHxHEIGHT@x,y") raise def parse_geometries(s): g = [] for geometry_str in s.split("/"): if geometry_str: g.append(parse_geometry(geometry_str)) return g if "=" in self.display_options: #parse the display options as a dictionary: opt_dict = parse_simple_dict(self.display_options) match_str = opt_dict.get("plug") multi_window = parse_bool( "multi-window", opt_dict.get("multi-window", multi_window)) geometries_str = opt_dict.get("geometry") if geometries_str: geometries = parse_geometries(geometries_str) else: try: geometries = parse_geometries(self.display_options) except: match_str = self.display_options if not multi_window or geometries: for geometry in (geometries or (None, )): model = model_class(self.root, self.capture) model.title = display_name if geometry: model.geometry = geometry models.append(model) return models found = [] screenlog("capture inputs matching %r", match_str or "all") for i, monitor in enumerate(monitors): plug_name, x, y, width, height, scale_factor = monitor title = display_name if plug_name or i > 1: title = plug_name or str(i) found.append(plug_name or title) if match_str and not (title in match_str or plug_name in match_str): screenlog.info(" skipped monitor %s", plug_name or title) continue model = model_class(self.root, self.capture) model.title = title model.geometry = (x, y, width, height) models.append(model) screenlog("monitor %i: %10s geometry=%s, scale factor=%s", i, title, model.geometry, scale_factor) screenlog("makeRootWindowModels()=%s", models) if not models and match_str: screenlog.warn("Warning: no monitors found matching %r", match_str) screenlog.warn(" only found: %s", csv(found)) return models
def init(self, opts): if opts.mmap and os.path.isabs(opts.mmap): self.supports_mmap = True self.mmap_filename = opts.mmap else: self.supports_mmap = bool(parse_bool("mmap", opts.mmap.lower()))
def pbool(name, v): return parse_bool(name, v, True)
def make_ssh_server_connection(conn, socket_options, none_auth=False, password_auth=None): log("make_ssh_server_connection%s", (conn, socket_options, none_auth, password_auth)) ssh_server = SSHServer(none_auth=none_auth, password_auth=password_auth, options=socket_options) DoGSSAPIKeyExchange = parse_bool( "ssh-gss-key-exchange", socket_options.get("ssh-gss-key-exchange", False), False) sock = conn._socket t = None def close(): if t: log("close() closing %s", t) try: t.close() except Exception: log("%s.close()", t, exc_info=True) log("close() closing %s", conn) try: conn.close() except Exception: log("%s.close()", conn) try: t = paramiko.Transport(sock, gss_kex=DoGSSAPIKeyExchange) gss_host = socket_options.get("ssh-gss-host", socket.getfqdn("")) t.set_gss_host(gss_host) #load host keys: PREFIX = "ssh_host_" SUFFIX = "_key" host_keys = {} def add_host_key(fd, f): ff = os.path.join(fd, f) keytype = f[len(PREFIX):-len(SUFFIX)] if not keytype: log.warn("Warning: unknown host key format '%s'", f) return False keyclass = getattr(paramiko, "%sKey" % keytype.upper(), None) if keyclass is None: #Ed25519Key keyclass = getattr( paramiko, "%s%sKey" % (keytype[:1].upper(), keytype[1:]), None) if keyclass is None: log("key type %s is not supported, cannot load '%s'", keytype, ff) return False log("loading %s key from '%s' using %s", keytype, ff, keyclass) try: host_key = keyclass(filename=ff) if host_key not in host_keys: host_keys[host_key] = ff t.add_server_key(host_key) return True except IOError as e: log("cannot add host key '%s'", ff, exc_info=True) except paramiko.SSHException as e: log("error adding host key '%s'", ff, exc_info=True) log.error("Error: cannot add %s host key '%s':", keytype, ff) log.error(" %s", e) return False host_key = socket_options.get("ssh-host-key") if host_key: d, f = os.path.split(host_key) if f.startswith(PREFIX) and f.endswith(SUFFIX): add_host_key(d, f) if not host_keys: log.error("Error: failed to load host key '%s'", host_key) close() return None else: ssh_key_dirs = get_ssh_conf_dirs() log("trying to load ssh host keys from: %s", csv(ssh_key_dirs)) for d in ssh_key_dirs: fd = osexpand(d) log("osexpand(%s)=%s", d, fd) if not os.path.exists(fd) or not os.path.isdir(fd): log("ssh host key directory '%s' is invalid", fd) continue for f in os.listdir(fd): if f.startswith(PREFIX) and f.endswith(SUFFIX): add_host_key(fd, f) if not host_keys: log.error("Error: cannot start SSH server,") log.error(" no readable SSH host keys found in:") log.error(" %s", csv(ssh_key_dirs)) close() return None log("loaded host keys: %s", tuple(host_keys.values())) t.start_server(server=ssh_server) except (paramiko.SSHException, EOFError) as e: log("failed to start ssh server", exc_info=True) log.error("Error handling SSH connection:") log.error(" %s", e) close() return None try: chan = t.accept(SERVER_WAIT) if chan is None: log.warn("Warning: SSH channel setup failed") #prevent errors trying to access this connection, now likely dead: conn.set_active(False) close() return None except paramiko.SSHException as e: log("failed to open ssh channel", exc_info=True) log.error("Error opening channel:") log.error(" %s", e) close() return None log("client authenticated, channel=%s", chan) timedout = not ssh_server.event.wait(SERVER_WAIT) proxy_channel = ssh_server.proxy_channel log("proxy channel=%s, timedout=%s", proxy_channel, timedout) if not ssh_server.event.is_set() or not proxy_channel: if timedout: log.warn("Warning: timeout waiting for xpra SSH subcommand,") log.warn(" closing connection from %s", pretty_socket(conn.target)) close() return None if getattr(proxy_channel, "proxy_process", None): log("proxy channel is handled using a subprocess") return None log("client authenticated, channel=%s", chan) return SSHSocketConnection(proxy_channel, sock, conn.local, conn.endpoint, conn.target, socket_options=socket_options)
#assume tcp if not specified address = "tcp:%s" % address args[1] = address try: int(options.dpi) except Exception, e: parser.error("invalid dpi: %s" % e) if options.encryption: assert len(ENCRYPTION_CIPHERS)>0, "cannot use encryption: no ciphers available" if options.encryption not in ENCRYPTION_CIPHERS: parser.error("encryption %s is not supported, try: %s" % (options.encryption, ", ".join(ENCRYPTION_CIPHERS))) if not options.password_file and not options.encryption_keyfile: parser.error("encryption %s cannot be used without a keyfile (see --encryption-keyfile option)" % options.encryption) #ensure opengl is either True, False or None options.opengl = parse_bool("opengl", options.opengl) return parser, options, args def dump_frames(*arsg): import traceback frames = sys._current_frames() print("") print("found %s frames:" % len(frames)) for fid,frame in frames.items(): print("%s - %s:" % (fid, frame)) traceback.print_stack(frame) print("") def configure_logging(options, mode): if mode in ("start", "upgrade", "attach", "shadow", "proxy"):
def control_command_set_sharing(self, sharing): self.sharing = parse_bool("sharing", sharing) self.setting_changed("sharing", sharing is not False) self.setting_changed("sharing-toggle", sharing is None) return "sharing set to %s" % self.sharing
def init_ui(self, opts): """ initialize user interface """ if not self.readonly: def noauto(v): if not v: return None if str(v).lower() == "auto": return None return v overrides = [ noauto(getattr(opts, "keyboard_%s" % x)) for x in ( "layout", "layouts", "variant", "variants", "options", ) ] def send_keyboard(*parts): self.after_handshake(self.send, *parts) try: self.keyboard_helper = self.keyboard_helper_class( send_keyboard, opts.keyboard_sync, opts.shortcut_modifiers, opts.key_shortcut, opts.keyboard_raw, *overrides) except ImportError as e: keylog("error instantiating %s", self.keyboard_helper_class, exc_info=True) keylog.warn("Warning: no keyboard support, %s", e) if mixin_features.windows: self.init_opengl(opts.opengl) if ClientExtras is not None: self.client_extras = ClientExtras(self, opts) #pylint: disable=not-callable self.start_new_commands = parse_bool("start-new-commands", opts.start_new_commands, True) if self.start_new_commands and (opts.start or opts.start_child): from xpra.scripts.main import strip_defaults_start_child from xpra.scripts.config import make_defaults_struct defaults = make_defaults_struct() self.request_start = strip_defaults_start_child( opts.start, defaults.start) #pylint: disable=no-member self.request_start_child = strip_defaults_start_child( opts.start_child, defaults.start_child) #pylint: disable=no-member if MOUSE_DELAY_AUTO: try: #some platforms don't detect the vrefresh correctly #(ie: macos in virtualbox?), so use a sane default minimum #discount by 5ms to ensure we have time to hit the target v = max(60, self.get_vrefresh()) self._mouse_position_delay = max(5, 1000 // v // 2 - 5) log("mouse delay: %s", self._mouse_position_delay) except Exception: log("failed to calculate automatic delay", exc_info=True)