def start_Xvfb(self, display=None, screens=[(1024, 768)]): assert POSIX if display is None: display = self.find_free_display() for x in list(os.environ.keys()): if x in ("LOGNAME", "USER", "PATH", "LANG", "TERM", "HOME", "USERNAME", "PYTHONPATH", "HOSTNAME"): #DBUS_SESSION_BUS_ADDRESS #keep it continue try: del os.environ[x] except: pass if len(screens) > 1: cmd = [ "Xvfb", "+extension", "Composite", "-nolisten", "tcp", "-noreset", "-auth", self.default_env["XAUTHORITY"] ] for i, screen in enumerate(screens): (w, h) = screen cmd += ["-screen", "%i" % i, "%ix%ix24+32" % (w, h)] else: xvfb_cmd = self.default_config.get("xvfb") assert xvfb_cmd, "no 'xvfb' command in default config" import shlex cmd = shlex.split(osexpand(xvfb_cmd)) try: i = cmd.index("/etc/xpra/xorg.conf") except ValueError: i = -1 if i > 0 and os.path.exists("./etc/xpra/xorg.conf"): cmd[i] = "./etc/xpra/xorg.conf" cmd.append(display) os.environ["DISPLAY"] = display os.environ["XPRA_LOG_DIR"] = "/tmp" cmd_expanded = [osexpand(v) for v in cmd] cmdstr = " ".join("'%s'" % x for x in cmd_expanded) if SHOW_XORG_OUTPUT: stdout = sys.stdout stderr = sys.stderr else: stdout = self._temp_file(prefix="Xorg-stdout-") log("stdout=%s for %s", stdout.name, cmd) stderr = self._temp_file(prefix="Xorg-stderr-") log("stderr=%s for %s", stderr.name, cmd) xvfb = self.run_command(cmd_expanded, stdout=stdout, stderr=stderr) time.sleep(1) log("xvfb(%s)=%s" % (cmdstr, xvfb)) if pollwait(xvfb, XVFB_TIMEOUT) is not None: self.show_proc_error( xvfb, "xvfb command \"%s\" failed and returned %s" % (cmdstr, xvfb.poll())) return xvfb
def start_Xvfb(cls, display=None, screens=[(1024, 768)]): assert POSIX if display is None: display = cls.find_free_display() with OSEnvContext(): XAUTHORITY = os.environ.get("XAUTHORITY", os.path.expanduser("~/.Xauthority")) for x in list(os.environ.keys()): if x in ("LOGNAME", "USER", "PATH", "LANG", "TERM", "HOME", "USERNAME", "PYTHONPATH", "HOSTNAME"): #DBUS_SESSION_BUS_ADDRESS #keep it continue try: del os.environ[x] except: pass if len(screens) > 1: cmd = [ "Xvfb", "+extension", "Composite", "-nolisten", "tcp", "-noreset", "-auth", XAUTHORITY ] for i, screen in enumerate(screens): (w, h) = screen cmd += ["-screen", "%i" % i, "%ix%ix24+32" % (w, h)] else: xvfb_cmd = cls.default_config.get("xvfb") assert xvfb_cmd, "no 'xvfb' command in default config" import shlex cmd = shlex.split(osexpand(xvfb_cmd)) try: i = cmd.index("/etc/xpra/xorg.conf") except ValueError: i = -1 if i > 0 and os.path.exists("./etc/xpra/xorg.conf"): cmd[i] = "./etc/xpra/xorg.conf" cmd.append(display) os.environ["DISPLAY"] = display os.environ["XPRA_LOG_DIR"] = "/tmp" cmd_expanded = [osexpand(v) for v in cmd] cmdstr = " ".join("'%s'" % x for x in cmd_expanded) xvfb = cls.run_command(cmd_expanded, stdout=sys.stdout, stderr=sys.stderr) time.sleep(1) print("xvfb(%s)=%s" % (cmdstr, xvfb)) assert pollwait( xvfb, XVFB_TIMEOUT ) is None, "xvfb command \"%s\" failed and returned %s" % ( cmdstr, xvfb.poll()) return xvfb
def _process_request_file(self, proto, packet): ss = self.get_server_source(proto) if not ss: printlog.warn("Warning: invalid client source for send-data-response packet") return argf = u(packet[1]) openit = packet[2] filename = os.path.abspath(osexpand(argf)) if not os.path.exists(filename): filelog.warn("Warning: the file requested does not exist:") filelog.warn(" %s", filename) ss.may_notify(XPRA_FILETRANSFER_NOTIFICATION_ID, "File not found", "The file requested does not exist:\n%s" % filename, icon_name="file") return try: stat = os.stat(filename) filelog("os.stat(%s)=%s", filename, stat) except os.error: filelog("os.stat(%s)", filename, exc_info=True) else: file_size = stat.st_size if file_size>self.file_transfer.file_size_limit or file_size>ss.file_size_limit: ss.may_notify(XPRA_FILETRANSFER_NOTIFICATION_ID, "File too large", "The file requested is too large to send:\n%s\nis %s" % (argf, std_unit(file_size)), icon_name="file") return data = load_binary_file(filename) ss.send_file(filename, "", data, len(data), openit=openit, options={"request-file" : (argf, openit)})
def set_icon_from_data(self, pixels, has_alpha, w, h, rowstride, _options=None): self.clean_last_tmp_icon() #use a temporary file (yuk) from xpra.gtk_common.gtk_util import pixbuf_save_to_memory, get_pixbuf_from_data tray_icon = get_pixbuf_from_data(pixels, has_alpha, w, h, rowstride) png_data = pixbuf_save_to_memory(tray_icon) tmp_dir = osexpand(get_xpra_tmp_dir()) if not os.path.exists(tmp_dir): os.mkdir(tmp_dir, 0o755) fd = None try: fd, self.tmp_filename = tempfile.mkstemp(prefix="tray", suffix=".png", dir=tmp_dir) log("set_icon_from_data%s using temporary file %s", ("%s pixels" % len(pixels), has_alpha, w, h, rowstride), self.tmp_filename) os.write(fd, png_data) except OSError as e: log("error saving temporary file", exc_info=True) log.error("Error saving icon data to temporary file") log.error(" %s", e) return finally: if fd: os.fchmod(fd, 0o644) os.close(fd) self.do_set_icon_from_file(self.tmp_filename)
def auth_publickey(): log("trying public key authentication") for keyfile in ("id_rsa", "id_dsa"): keyfile_path = osexpand(os.path.join("~/", ".ssh", keyfile)) if not os.path.exists(keyfile_path): log("no keyfile at '%s'", keyfile_path) continue key = None try: key = RSAKey.from_private_key_file(keyfile_path) except PasswordRequiredException: log("%s keyfile requires a passphrase", keyfile_path) passphrase = input_pass("please enter the passphrase for %s:" % (keyfile_path, )) if passphrase: try: key = RSAKey.from_private_key_file( keyfile_path, passphrase) except SSHException as e: log("from_private_key_file", exc_info=True) log.info("cannot load key from file '%s':", keyfile_path) log.info(" %s", e) if key: log("auth_publickey using %s: %s", keyfile_path, keymd5(key)) try: transport.auth_publickey(username, key) except SSHException as e: log("key '%s' rejected", keyfile_path, exc_info=True) log.info("SSH authentication using key '%s' failed:", keyfile_path) log.info(" %s", e) else: if transport.is_authenticated(): break
def get_icon_string(self, nid: int, app_icon, icon): if app_icon and not os.path.isabs(app_icon): #safe to use return app_icon if icon and icon[0] == b"png": icon_data = icon[3] from xpra.platform.paths import get_xpra_tmp_dir tmp = osexpand(get_xpra_tmp_dir()) d = tmp missing = [] while d and not os.path.exists(d): missing.append(d) d = os.path.dirname(d) for d in reversed(missing): os.mkdir(d, 0o700) temp = tempfile.NamedTemporaryFile( mode='w+b', suffix='.png', prefix='xpra-notification-icon-', dir=tmp, delete=False) temp.write(icon_data) temp.close() self.temp_files[nid] = temp.name return temp.name return ""
def find_ssl_cert(filename="ssl-cert.pem"): from xpra.log import Logger ssllog = Logger("ssl") #try to locate the cert file from known locations from xpra.platform.paths import get_ssl_cert_dirs #pylint: disable=import-outside-toplevel dirs = get_ssl_cert_dirs() ssllog("find_ssl_cert(%s) get_ssl_cert_dirs()=%s", filename, dirs) for d in dirs: p = osexpand(d) if not os.path.exists(p): ssllog("ssl cert dir '%s' does not exist", p) continue f = os.path.join(p, "ssl-cert.pem") if not os.path.exists(f): ssllog("ssl cert '%s' does not exist", f) continue if not os.path.isfile(f): ssllog.warn("Warning: '%s' is not a file", f) continue if not os.access(p, os.R_OK): ssllog.info("SSL certificate file '%s' is not accessible", f) continue ssllog("found ssl cert '%s'", f) return f return None
def check_auth_publickey(self, username, key): log("check_auth_publickey(%s, %r) pubkey_auth=%s", username, key, self.pubkey_auth) if not self.pubkey_auth: return paramiko.AUTH_FAILED if not POSIX or getuid() != 0: import getpass sysusername = getpass.getuser() if sysusername != username: log.warn("Warning: ssh password authentication failed,") log.warn(" username does not match:") log.warn(" expected '%s', got '%s'", sysusername, username) return paramiko.AUTH_FAILED authorized_keys_filename = osexpand(AUTHORIZED_KEYS) if not os.path.exists(authorized_keys_filename) or not os.path.isfile( authorized_keys_filename): log("file '%s' does not exist", authorized_keys_filename) return paramiko.AUTH_FAILED import base64 import binascii fingerprint = key.get_fingerprint() hex_fingerprint = binascii.hexlify(fingerprint) log("looking for key fingerprint '%s' in '%s'", hex_fingerprint, authorized_keys_filename) count = 0 with open(authorized_keys_filename, "rb") as f: for line in f: if line.startswith("#"): continue line = line.strip("\n\r") try: key = base64.b64decode( line.strip().split()[1].encode('ascii')) except Exception as e: log("ignoring line '%s': %s", line, e) continue import hashlib for hash_algo in AUTHORIZED_KEYS_HASHES: hash_instance = None try: hash_class = getattr(hashlib, hash_algo) #ie: hashlib.md5 hash_instance = hash_class( key ) #can raise ValueError (ie: on FIPS compliant systems) except ValueError: hash_instance = None if not hash_instance: if first_time("hash-%s-missing" % hash_algo): log.warn("Warning: unsupported hash '%s'", hash_algo) continue fp_plain = hash_instance.hexdigest() log("%s(%s)=%s", hash_algo, line, fp_plain) if fp_plain == hex_fingerprint: return paramiko.OPEN_SUCCEEDED count += 1 log("no match in %i keys from '%s'", count, authorized_keys_filename) return paramiko.AUTH_FAILED
def get_default_keyfiles(): dkf = os.environ.get("XPRA_SSH_DEFAULT_KEYFILES", None) if dkf is not None: return [x for x in dkf.split(":") if x] return [ osexpand(os.path.join("~/", ".ssh", keyfile)) for keyfile in ("id_ed25519", "id_ecdsa", "id_rsa", "id_dsa") ]
def __init__(self, **kwargs): self.app_id = kwargs.pop("app_id", APP_ID) key_hexstring = kwargs.pop("public_key", "") super().__init__(**kwargs) self.public_keys = {} key_strs = {} if key_hexstring: log("u2f_auth: public key from configuration=%s", key_hexstring) key_strs["command-option"] = key_hexstring #try to load public keys from the user conf dir(s): if getuid() == 0 and POSIX: #root: use the uid of the username specified: uid = self.get_uid() else: uid = getuid() conf_dirs = get_user_conf_dirs(uid) log("u2f: will try to load public keys from %s", csv(conf_dirs)) #load public keys: for d in conf_dirs: ed = osexpand(d) if os.path.exists(ed) and os.path.isdir(ed): pub_keyfiles = glob.glob(os.path.join(ed, "u2f*-pub.hex")) log("u2f: keyfiles(%s)=%s", ed, pub_keyfiles) for f in sorted(pub_keyfiles): key_hexstring = load_binary_file(f) if key_hexstring: key_hexstring = key_hexstring.rstrip(b" \n\r") key_strs[f] = key_hexstring log("u2f_auth: loaded public key from file '%s': %s", f, key_hexstring) #parse public key data: #pylint: disable=import-outside-toplevel from cryptography.hazmat.primitives.serialization import load_der_public_key from cryptography.hazmat.backends import default_backend for origin, key_hexstring in key_strs.items(): try: key = binascii.unhexlify(key_hexstring) except Exception as e: log("unhexlify(%s)", key_hexstring, exc_info=True) log.warn("Warning: failed to parse key '%s'", origin) log.warn(" %s", e) continue log("u2f: trying to load DER public key %s", repr(key)) if not key.startswith(PUB_KEY_DER_PREFIX): key = PUB_KEY_DER_PREFIX + key try: k = load_der_public_key(key, default_backend()) except Exception as e: log("load_der_public_key(%r)", key, exc_info=True) log.warn("Warning: failed to parse key '%s'", origin) log.warn(" %s", e) continue self.public_keys[origin] = k if not self.public_keys: raise Exception( "u2f authenticator requires at least one public key")
def start_Xvfb(cls, display=None, screens=((1024,768),), depth=24, extensions=("Composite", )): assert POSIX if display is None: display = cls.find_free_display() env = {} for x in list(os.environ.keys()): if x in ( "LOGNAME", "USER", "PATH", "LANG", "TERM", "HOME", "USERNAME", "PYTHONPATH", "HOSTNAME", #"XAUTHORITY", ): #DBUS_SESSION_BUS_ADDRESS #keep it env[x] = os.environ.get(x) real_display = os.environ.get("DISPLAY") cmd = [cls.which(TEST_XVFB_COMMAND)] is_xephyr = TEST_XVFB_COMMAND.find("Xephyr")>=0 if is_xephyr: if len(screens)>1 or not real_display: #we can't use Xephyr for multi-screen cmd = [cls.which("Xvfb")] elif real_display: env["DISPLAY"] = real_display for ext in extensions: if ext.startswith("-"): cmd += ["-extension", ext[1:]] else: cmd += ["+extension", ext] cmd += ["-nolisten", "tcp", "-noreset"] #"-auth", self.default_env["XAUTHORITY"]] depth_str = "%i+%i" % (depth, 32) for i, screen in enumerate(screens): (w, h) = screen cmd += ["-screen"] if not is_xephyr: cmd += ["%i" % i] cmd += ["%ix%ix%s" % (w, h, depth_str)] cmd.append(display) env["XPRA_LOG_DIR"] = tempfile.gettempdir() cmd_expanded = [osexpand(v) for v in cmd] cmdstr = " ".join("'%s'" % x for x in cmd_expanded) if SHOW_XORG_OUTPUT: stdout = sys.stdout stderr = sys.stderr else: stdout = cls._temp_file(prefix="Xorg-stdout-") log("stdout=%s for %s", stdout.name, cmd) stderr = cls._temp_file(prefix="Xorg-stderr-") log("stderr=%s for %s", stderr.name, cmd) xvfb = cls.class_run_command(cmd_expanded, env=env, stdout=stdout, stderr=stderr) xvfb.display = display time.sleep(1) log("xvfb(%s)=%s" % (cmdstr, xvfb)) if pollwait(xvfb, XVFB_TIMEOUT) is not None: show_proc_error(xvfb, "xvfb command \"%s\" failed and returned %s" % (cmdstr, xvfb.poll())) return xvfb
def start_Xvfb(self, display=None, screens=((1024, 768), )): assert POSIX if display is None: display = self.find_free_display() env = {} for x in list(os.environ.keys()): if x in ( "LOGNAME", "USER", "PATH", "LANG", "TERM", "HOME", "USERNAME", "PYTHONPATH", "HOSTNAME", #"XAUTHORITY", ): #DBUS_SESSION_BUS_ADDRESS #keep it env[x] = os.environ.get(x) cmd = [ "Xvfb", "+extension", "Composite", "-nolisten", "tcp", "-noreset" ] #"-auth", self.default_env["XAUTHORITY"]] for i, screen in enumerate(screens): (w, h) = screen cmd += ["-screen", "%i" % i, "%ix%ix24+32" % (w, h)] cmd.append(display) env["DISPLAY"] = display env["XPRA_LOG_DIR"] = "/tmp" cmd_expanded = [osexpand(v) for v in cmd] cmdstr = " ".join("'%s'" % x for x in cmd_expanded) if SHOW_XORG_OUTPUT: stdout = sys.stdout stderr = sys.stderr else: stdout = self._temp_file(prefix="Xorg-stdout-") log("stdout=%s for %s", stdout.name, cmd) stderr = self._temp_file(prefix="Xorg-stderr-") log("stderr=%s for %s", stderr.name, cmd) xvfb = self.run_command(cmd_expanded, env=env, stdout=stdout, stderr=stderr) xvfb.display = display time.sleep(1) log("xvfb(%s)=%s" % (cmdstr, xvfb)) if pollwait(xvfb, XVFB_TIMEOUT) is not None: self.show_proc_error( xvfb, "xvfb command \"%s\" failed and returned %s" % (cmdstr, xvfb.poll())) return xvfb
def run(self): register_SIGUSR_signals(self.idle_add) client_protocol_class = get_client_protocol_class(self.client_conn.socktype) server_protocol_class = get_server_protocol_class(self.server_conn.socktype) self.client_protocol = client_protocol_class(self, self.client_conn, self.process_client_packet, self.get_client_packet) self.client_protocol.restore_state(self.client_state) self.server_protocol = server_protocol_class(self, self.server_conn, self.process_server_packet, self.get_server_packet) self.log_start() log("ProxyProcessProcess.run() pid=%s, uid=%s, gid=%s", os.getpid(), getuid(), getgid()) set_proc_title("Xpra Proxy Instance for %s" % self.server_conn) if POSIX and (getuid()!=self.uid or getgid()!=self.gid): #do we need a valid XDG_RUNTIME_DIR for the socket-dir? username = get_username_for_uid(self.uid) socket_dir = osexpand(self.socket_dir, username, self.uid, self.gid) if not os.path.exists(socket_dir): log("the socket directory '%s' does not exist, checking for $XDG_RUNTIME_DIR path", socket_dir) for prefix in ("/run/user/", "/var/run/user/"): if socket_dir.startswith(prefix): from xpra.scripts.server import create_runtime_dir xrd = os.path.join(prefix, str(self.uid)) #ie: /run/user/99 log("creating XDG_RUNTIME_DIR=%s for uid=%i, gid=%i", xrd, self.uid, self.gid) create_runtime_dir(xrd, self.uid, self.gid) break #change uid or gid: setuidgid(self.uid, self.gid) if self.env_options: #TODO: whitelist env update? os.environ.update(self.env_options) signal.signal(signal.SIGTERM, self.signal_quit) signal.signal(signal.SIGINT, self.signal_quit) log("registered signal handler %s", self.signal_quit) start_thread(self.server_message_queue, "server message queue") if not self.create_control_socket(): return self.control_socket_thread = start_thread(self.control_socket_loop, "control", daemon=True) self.main_queue = Queue() ProxyInstance.run(self) try: QueueScheduler.run(self) except KeyboardInterrupt as e: self.stop(None, str(e)) finally: log("ProxyProcess.run() ending %s", os.getpid())
def do_run_client(self, client_display, *args): from xpra.x11.vfb_util import xauth_add xauth_data = get_hex_uuid() xauthority = self.default_env.get("XAUTHORITY", osexpand("~/.Xauthority")) xauth_add(xauthority, client_display, xauth_data, os.getuid(), os.getgid()) env = self.get_run_env() env["DISPLAY"] = client_display env["XPRA_LOG_PREFIX"] = "client %i: " % X11ClientTestUtil.uq X11ClientTestUtil.uq += 1 log("starting test client on Xvfb %s", client_display) return self.run_xpra(["attach"] + list(args), env=env)
def process_challenge_u2f(self, packet): digest = packet[3] if not digest.startswith(b"u2f:"): authlog("%s is not a u2f challenge", digest) return False import binascii import logging if not is_debug_enabled("auth"): logging.getLogger("pyu2f.hardware").setLevel(logging.INFO) logging.getLogger("pyu2f.hidtransport").setLevel(logging.INFO) from pyu2f import model from pyu2f.u2f import GetLocalU2FInterface dev = GetLocalU2FInterface() APP_ID = os.environ.get("XPRA_U2F_APP_ID", "Xpra") key_handle_str = os.environ.get("XPRA_U2F_KEY_HANDLE") authlog("process_challenge_u2f XPRA_U2F_KEY_HANDLE=%s", key_handle_str) if not key_handle_str: #try to load the key handle from the user conf dir(s): from xpra.platform.paths import get_user_conf_dirs info = self._protocol.get_info(False) key_handle_filenames = [] for hostinfo in ("-%s" % info.get("host", ""), ""): key_handle_filenames += [ os.path.join(d, "u2f-keyhandle%s.hex" % hostinfo) for d in get_user_conf_dirs() ] for filename in key_handle_filenames: p = osexpand(filename) key_handle_str = load_binary_file(p) authlog("key_handle_str(%s)=%s", p, key_handle_str) if key_handle_str: key_handle_str = key_handle_str.rstrip(b" \n\r") break if not key_handle_str: authlog.warn("Warning: no U2F key handle found") return False authlog("process_challenge_u2f key_handle=%s", key_handle_str) key_handle = binascii.unhexlify(key_handle_str) key = model.RegisteredKey(key_handle) #use server salt as challenge directly challenge = packet[1] authlog.info("activate your U2F device for authentication") response = dev.Authenticate(APP_ID, challenge, [key]) sig = response.signature_data client_data = response.client_data authlog("process_challenge_u2f client data=%s, signature=%s", client_data, binascii.hexlify(sig)) self.do_send_challenge_reply(bytes(sig), client_data.origin) return True
def check_peercred(self, connection, uids="", gids="", allow_owner=False): allow_uids = allow_gids = None if uids or allow_owner: allow_uids = [] if allow_owner: allow_uids.append(getuid()) for x in uids.split(":"): if not x.strip(): continue x = osexpand(x.strip()) try: allow_uids.append(int(x)) except ValueError: import pwd #pylint: disable=import-outside-toplevel try: pw = pwd.getpwnam(x) allow_uids.append(pw.pw_uid) except KeyError: log.warn("Warning: unknown username '%s'", x) log("peercred: allow_uids(%s)=%s", uids, allow_uids) if gids: allow_gids = [] for x in gids.split(":"): if not x.strip(): continue x = osexpand(x.strip()) try: allow_gids.append(int(x)) except ValueError: gid = get_group_id(x) if gid >= 0: allow_gids.append(gid) else: log.warn("Warning: unknown group '%s'", x) log("peercred: allow_gids(%s)=%s", gids, allow_gids) self.do_check_peercred(connection, allow_uids, allow_gids)
def set_icon_from_data(self, pixels, has_alpha, w, h, rowstride, _options=None): self.clean_last_tmp_icon() #use a temporary file (yuk) from xpra.gtk_common.gtk_util import COLORSPACE_RGB, pixbuf_new_from_data, pixbuf_save_to_memory import tempfile tmp_dir = osexpand(get_xpra_tmp_dir()) if not os.path.exists(tmp_dir): os.mkdir(tmp_dir, 0o755) self.tmp_filename = tempfile.mkstemp(prefix="tray", suffix=".png", dir=tmp_dir)[1] log("set_icon_from_data%s using temporary file %s", ("%s pixels" % len(pixels), has_alpha, w, h, rowstride), self.tmp_filename) tray_icon = pixbuf_new_from_data(pixels, COLORSPACE_RGB, has_alpha, 8, w, h, rowstride) png_data = pixbuf_save_to_memory(tray_icon) with open(self.tmp_filename, "wb") as f: f.write(png_data) self.do_set_icon_from_file(self.tmp_filename)
def do_setup_menu_watcher(self): if self.watch_manager: #already setup return try: import pyinotify except ImportError as e: log("setup_menu_watcher() cannot import pyinotify", exc_info=True) log.warn( "Warning: cannot watch for application menu changes without pyinotify:" ) log.warn(" %s", e) return self.watch_manager = pyinotify.WatchManager() def menu_data_updated(create, pathname): log("menu_data_updated(%s, %s)", create, pathname) self.schedule_xdg_menu_reload() class EventHandler(pyinotify.ProcessEvent): def process_IN_CREATE(self, event): menu_data_updated(True, event.pathname) def process_IN_DELETE(self, event): menu_data_updated(False, event.pathname) mask = pyinotify.IN_DELETE | pyinotify.IN_CREATE #@UndefinedVariable pylint: disable=no-member handler = EventHandler() self.watch_notifier = pyinotify.ThreadedNotifier( self.watch_manager, handler) self.watch_notifier.setDaemon(True) data_dirs = os.environ.get("XDG_DATA_DIRS", DEFAULT_XDG_DATA_DIRS).split(":") watched = [] for data_dir in data_dirs: menu_dir = os.path.join(osexpand(data_dir), "applications") if not os.path.exists(menu_dir) or menu_dir in watched: continue wdd = self.watch_manager.add_watch(menu_dir, mask) watched.append(menu_dir) log("watch_notifier=%s, watch=%s", self.watch_notifier, wdd) self.watch_notifier.start() if watched: log.info("watching for applications menu changes in:") for wd in watched: log.info(" '%s'", wd)
def find_log_dir(username="", uid=0, gid=0): from xpra.platform.paths import get_default_log_dirs errs = [] for x in get_default_log_dirs(): v = osexpand(x, username, uid, gid) if not os.path.exists(v): if getuid()==0 and uid!=0: continue try: os.mkdir(v, 0o700) except Exception as e: errs.append((v, e)) continue return v for d, e in errs: sys.stderr.write("Error: cannot create log directory '%s':" % d) sys.stderr.write(" %s\n" % e) return None
def write_runner_shell_scripts(contents, overwrite=True): assert POSIX # This used to be given a display-specific name, but now we give it a # single fixed name and if multiple servers are started then the last one # will clobber the rest. This isn't great, but the tradeoff is that it # makes it possible to use bare 'ssh:hostname' display names and # autodiscover the proper numeric display name when only one xpra server # is running on the remote host. Might need to revisit this later if # people run into problems or autodiscovery turns out to be less useful # than expected. log = get_util_logger() MODE = 0o700 from xpra.platform.paths import get_script_bin_dirs for d in get_script_bin_dirs(): scriptdir = osexpand(d) if not os.path.exists(scriptdir): try: os.mkdir(scriptdir, MODE) except Exception as e: log("os.mkdir(%s, %s)", scriptdir, oct(MODE), exc_info=True) log.warn("Warning: failed to create script directory '%s':", scriptdir) log.warn(" %s", e) if scriptdir.startswith( "/var/run/user") or scriptdir.startswith("/run/user"): log.warn(" ($XDG_RUNTIME_DIR has not been created?)") continue scriptpath = os.path.join(scriptdir, "run-xpra") if os.path.exists(scriptpath) and not overwrite: continue # Write out a shell-script so that we can start our proxy in a clean # environment: try: with umask_context(0o022): h = os.open(scriptpath, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, MODE) try: os.write(h, contents) finally: os.close(h) except Exception as e: log("writing to %s", scriptpath, exc_info=True) log.error("Error: failed to write script file '%s':", scriptpath) log.error(" %s\n", e)
def check_auth_publickey(self, username, key): log("check_auth_publickey(%s, %r) pubkey_auth=%s", username, key, self.pubkey_auth) if not self.pubkey_auth: return paramiko.AUTH_FAILED if not POSIX or getuid() != 0: import getpass sysusername = getpass.getuser() if sysusername != username: log.warn("Warning: ssh password authentication failed,") log.warn(" username does not match:") log.warn(" expected '%s', got '%s'", sysusername, username) return paramiko.AUTH_FAILED authorized_keys_filename = osexpand(AUTHORIZED_KEYS) if not os.path.exists(authorized_keys_filename) or not os.path.isfile( authorized_keys_filename): log("file '%s' does not exist", authorized_keys_filename) return paramiko.AUTH_FAILED import base64 import binascii fingerprint = key.get_fingerprint() hex_fingerprint = binascii.hexlify(fingerprint) log("looking for key fingerprint '%s' in '%s'", hex_fingerprint, authorized_keys_filename) count = 0 with open(authorized_keys_filename, "rb") as f: for line in f: if line.startswith("#"): continue line = line.strip("\n\r") try: key = base64.b64decode( line.strip().split()[1].encode('ascii')) except Exception as e: log("ignoring line '%s': %s", line, e) continue import hashlib fp_plain = hashlib.md5(key).hexdigest() log("key(%s)=%s", line, fp_plain) if fp_plain == hex_fingerprint: return paramiko.OPEN_SUCCEEDED count += 1 log("no match in %i keys from '%s'", count, authorized_keys_filename) return paramiko.AUTH_FAILED
def _unique_sock_dirs(self): dirs = [] if self._sockdir!="undefined": dirs.append(self._sockdir) dirs += [x for x in self._sockdirs if x not in dirs] seen = set() for d in dirs: if d in seen or not d: continue seen.add(d) real_dir = os.path.realpath(osexpand(d)) if real_dir!=d: if real_dir in seen: continue seen.add(real_dir) if not os.path.exists(real_dir): debug("socket_details: directory '%s' does not exist", real_dir) continue yield real_dir
def get_icon_string(self, nid, app_icon, icon): if app_icon and not os.path.isabs(app_icon): #safe to use return app_icon elif icon and icon[0] == b"png": icon_data = icon[3] from xpra.platform.paths import get_xpra_tmp_dir tmp = osexpand(get_xpra_tmp_dir()) if not os.path.exists(tmp): os.mkdir(tmp, 0o700) temp = tempfile.NamedTemporaryFile(mode='w+b', suffix='png', prefix='xpra-notification', dir=tmp, delete=False) temp.write(icon_data) temp.close() self.temp_files[nid] = temp.name return temp.name return ""
def write_runner_shell_scripts(contents, overwrite=True): # This used to be given a display-specific name, but now we give it a # single fixed name and if multiple servers are started then the last one # will clobber the rest. This isn't great, but the tradeoff is that it # makes it possible to use bare 'ssh:hostname' display names and # autodiscover the proper numeric display name when only one xpra server # is running on the remote host. Might need to revisit this later if # people run into problems or autodiscovery turns out to be less useful # than expected. log = get_util_logger() from xpra.platform.paths import get_script_bin_dirs for d in get_script_bin_dirs(): scriptdir = osexpand(d) if not os.path.exists(scriptdir): try: os.mkdir(scriptdir, 0o700) except Exception as e: log("os.mkdir(%s, 0o700)", scriptdir, exc_info=True) log.warn("Warning: failed to create script directory '%s':", scriptdir) log.warn(" %s", e) if scriptdir.startswith( "/var/run/user") or scriptdir.startswith("/run/user"): log.warn(" ($XDG_RUNTIME_DIR has not been created?)") continue scriptpath = os.path.join(scriptdir, "run-xpra") if os.path.exists(scriptpath) and not overwrite: continue # Write out a shell-script so that we can start our proxy in a clean # environment: try: with open(scriptpath, "w") as scriptfile: # Unix is a little silly sometimes: umask = os.umask(0) os.umask(umask) os.fchmod(scriptfile.fileno(), 0o700 & ~umask) scriptfile.write(contents.encode()) except Exception as e: log("writing to %s", scriptpath, exc_info=True) log.error("Error: failed to write script file '%s':", scriptpath) log.error(" %s\n", e)
def get_key_handle(self) -> bytes: key_handle_str = os.environ.get("XPRA_U2F_KEY_HANDLE") log("process_challenge_u2f XPRA_U2F_KEY_HANDLE=%s", key_handle_str) if not key_handle_str: #try to load the key handle from the user conf dir(s): from xpra.platform.paths import get_user_conf_dirs info = self.client._protocol.get_info(False) key_handle_filenames = [] for hostinfo in ("-%s" % info.get("host", ""), ""): for d in get_user_conf_dirs(): key_handle_filenames.append(os.path.join(d, "u2f-keyhandle%s.hex" % hostinfo)) for filename in key_handle_filenames: p = osexpand(filename) key_handle_str = load_binary_file(p) log("key_handle_str(%s)=%s", p, key_handle_str) if key_handle_str: key_handle_str = key_handle_str.rstrip(b" \n\r") break if not key_handle_str: log.warn("Warning: no U2F key handle found") return None log("process_challenge_u2f key_handle=%s", key_handle_str) return binascii.unhexlify(key_handle_str)
def pathexpand(s): return osexpand(s, actual_username=username, uid=uid, gid=gid, subs=subs)
def __init__(self, username, **kwargs): log("peercred.Authenticator(%s, %s)", username, kwargs) if not POSIX: log.warn("Warning: peercred authentication is not supported on %s", os.name) return self.uid = -1 self.gid = -1 self.peercred_check = False connection = kwargs.get("connection", None) uids = kwargs.pop("uid", None) gids = kwargs.pop("gid", None) allow_uids = None allow_gids = None if uids: allow_uids = [] for x in uids.split(","): x = osexpand(x.strip()) try: allow_uids.append(int(x)) except ValueError: import pwd try: pw = pwd.getpwnam(x) uids.append(pw.pw_uid) except KeyError: log.warn("Warning: unknown username '%s'", x) log("peercred: allow_uids(%s)=%s", uids, allow_uids) if gids: allow_gids = [] for x in gids.split(","): x = osexpand(x.strip()) try: allow_gids.append(int(x)) except ValueError: gid = get_group_id(x) if gid >= 0: allow_gids.append(gid) else: log.warn("Warning: unknown group '%s'", x) log("peercred: allow_gids(%s)=%s", gids, allow_gids) try: from xpra.net.bytestreams import SocketConnection if connection and isinstance(connection, SocketConnection): sock = connection._socket peercred = get_peercred(sock) log("get_peercred(%s)=%s", sock, peercred) if not peercred: log.warn("Warning: failed to get peer credentials on %s", sock) return _, uid, gid = peercred if allow_uids is not None and uid not in allow_uids: log.warn("Warning: peercred access denied,") log.warn(" uid %i is not in the whitelist: %s", uid, csv(allow_uids)) elif allow_gids is not None and gid not in allow_gids: log.warn("Warning: peercred access denied,") log.warn(" gid %i is not in the whitelist: %s", gid, csv(allow_gids)) else: self.peercred_check = True self.uid = uid self.gid = gid else: log( "peercred: invalid connection '%s' (not a socket connection)", connection) except Exception as e: log.error("Error: cannot get peer uid") log.error(" %s", e) SysAuthenticator.__init__(self, username, **kwargs)
def osexpand(self, v): return osexpand(v, self.username, self.uid, self.gid)
def socket_expand(self, path): return osexpand(path, self.username, uid=self.uid, gid=self.gid)
def main(): from xpra.platform import program_context with program_context("U2F-Register", "Xpra U2F Registration Tool"): gui = not sys.stdin.isatty() or os.environ.get("MSYSCON") if gui: from xpra.gtk_common.gobject_compat import import_gtk, import_glib gtk = import_gtk() glib = import_glib() from xpra.gtk_common.gtk_util import MESSAGE_INFO, MESSAGE_ERROR, BUTTONS_CLOSE def show_dialog(mode, *msgs): dialog = gtk.MessageDialog(None, 0, mode, BUTTONS_CLOSE, "\n".join(msgs)) dialog.set_title("Xpra U2F Registration Tool") v = dialog.run() dialog.destroy() #run the main loop long enough to destroy the dialog: glib.idle_add(gtk.main_quit) gtk.main() return v def error(*msgs): return show_dialog(MESSAGE_ERROR, *msgs) def info(*msgs): return show_dialog(MESSAGE_INFO, *msgs) else: print("U2F Registration Tool") def printmsgs(*msgs): for x in msgs: print(x) error = info = printmsgs key_handle_filenames = [ os.path.join(d, "u2f-keyhandle.hex") for d in get_user_conf_dirs() ] assert len(key_handle_filenames) > 0 for filename in key_handle_filenames: p = osexpand(filename) key_handle_str = load_binary_file(p) if key_handle_str: error( " found an existing key handle in file '%s':" % p, #" %s" % key_handle_str, " skipping U2F registration", " delete this file if you want to register again") return 1 public_key_filenames = [] for d in get_user_conf_dirs(): public_key_filenames += glob.glob(os.path.join(d, "u2f*.pub")) if public_key_filenames: info( " found %i existing public key%s" % (len(public_key_filenames, engs(public_key_filenames))), *((" - %s" % x) for x in public_key_filenames)) #pick the first directory: conf_dir = osexpand(get_user_conf_dirs()[0]) if not os.path.exists(conf_dir): os.mkdir(conf_dir) from pyu2f.u2f import GetLocalU2FInterface #@UnresolvedImport try: dev = GetLocalU2FInterface() except Exception as e: error("Failed to open local U2F device:", "%s" % (str(e) or type(e))) return 1 info("Please activate your U2F device now to generate a new key") registered_keys = [] challenge = b'01234567890123456789012345678901' #unused rr = dev.Register(APP_ID, challenge, registered_keys) b = rr.registration_data assert b[0] == 5 pubkey = bytes(b[1:66]) khl = b[66] key_handle = bytes(b[67:67 + khl]) #save to files: key_handle_filename = osexpand(key_handle_filenames[0]) f = open(key_handle_filename, "wb") f.write(hexstr(key_handle).encode()) f.close #find a filename we can use for this public key: i = 1 while True: c = "" if i > 1: c = "-%i" public_key_filename = os.path.join(conf_dir, "u2f%s-pub.hex" % c) if not os.path.exists(public_key_filename): break f = open(public_key_filename, "wb") f.write(hexstr(pubkey).encode()) f.close #info("key handle: %s" % csv(hex40(key_handle)), # "saved to file '%s'" % key_handle_filename, # "public key: %s" % csv(hex40(pubkey)), # "saved to file '%s'" % public_key_filename, # ) info( "key handle saved to file:", "'%s'" % key_handle_filename, "public key saved to file:", "'%s'" % public_key_filename, ) return 0