From 5b8ad4f19fe16b65df3607be57882bc187899cd6 Mon Sep 17 00:00:00 2001 From: Michael Stone Date: Tue, 29 Jun 2010 04:30:45 +0000 Subject: Start work on a port to VNC. --- diff --git a/bin/rainbow-gc b/bin/rainbow-gc index 60a4ebe..6f1d99a 100755 --- a/bin/rainbow-gc +++ b/bin/rainbow-gc @@ -42,7 +42,7 @@ def gc_uid(log, spool, uid): log(1, "skipped uid %s", uid) return - for table in ('uid_to_instance_dir', 'uid_to_home_dir', 'uid_to_gid', 'uid_to_xephyr_auth', 'uid_to_xephyr_cookie', 'uid_to_xephyr_display'): + for table in ('uid_to_instance_dir', 'uid_to_home_dir', 'uid_to_gid', 'uid_to_x11_auth', 'uid_to_x11_cookie', 'uid_to_x11_display'): row = join(spool, table, uid) # NB: it is important that rm -rf doesn't follow links. cmd = ['/bin/rm', '-r', '-f', row] diff --git a/bin/rainbow-run b/bin/rainbow-run index 7f5241c..70ba823 100755 --- a/bin/rainbow-run +++ b/bin/rainbow-run @@ -35,7 +35,7 @@ def main(): parser.add_option('-i', '--id', default=[], action='append', help="ID of shared-data group.") parser.add_option('-o', '--option', default=[], action='append', - help="Options: video, audio, serial, constant-uid, xephyr, network.") + help="Options: video, audio, serial, constant-uid, x11, network.") parser.add_option('-p', '--permissions', default=None, help="Location of a permissions.info file.") parser.add_option('-u', '--user', default=None, @@ -75,8 +75,8 @@ def main(): def check_groups(opts): return [grp.getgrnam(g)[2] for g in opts.group] - def check_xephyr(opts): - return 'xephyr' in opts.option + def check_x11(opts): + return 'x11' in opts.option def check_constant_uid(opts): return 'constant-uid' in opts.option @@ -125,12 +125,12 @@ def main(): data_ids = check_data_ids(opts) assistant = check_assistant(opts) - xephyr = check_xephyr(opts) + x11 = check_x11(opts) resume_uid = check_resume_user(opts) if resume_uid: report(1, "resuming uid (%d)", resume_uid) - args = (report, spool, env, argv, cwd, pset, safe_fds, uid, gid, resume_uid, groups, data_ids, assistant, xephyr) + args = (report, spool, env, argv, cwd, pset, safe_fds, uid, gid, resume_uid, groups, data_ids, assistant, x11) report(1, 'rainbow:\n%s', pformat(args)) unshare(CLONE_NEWNS) diff --git a/rainbow/inject.py b/rainbow/inject.py index 1dfd4d6..f628f6d 100644 --- a/rainbow/inject.py +++ b/rainbow/inject.py @@ -10,6 +10,7 @@ from tempfile import mkdtemp, mkstemp from grp import getgrnam, getgrgid from pwd import getpwuid from glob import glob +from time import sleep import resource from rainbow.util import Checker, mount, make_dirs, get_fds, read_envdir @@ -93,40 +94,39 @@ def mount_fsen(log, _): #mount('tmpfs', '/tmp', 'tmpfs', 0, '') mount('tmpfs', '/var/tmp', 'tmpfs', 0, '') +def run_cmd_as_owner(log, cmd, env, owner_uid, owner_gid, groups, safe_fds): + pid = fork() + if not pid: + log(1, 'Dropping privilege to run cmd as owner.') + setgroups(groups) + setgid(owner_gid) + setuid(owner_uid) + log(1, 'Closing fds.') + for fd in get_fds(): + if fd not in safe_fds: + try: os.close(fd) # propagate failure from EIO or EBADF. + except: pass + log(1, 'Running cmd.') + log(1, '%r %r', cmd, env) + execvpe(cmd[0], cmd, env) + _exit(59) + else: + return pid + def run_assistant(log, assistant, env, owner_uid, owner_gid, uid, groups, safe_fds): envdir = None try: envdir = mkdtemp() chown(envdir, owner_uid, owner_gid) - pid = fork() - except: + assistant_argv = [assistant, '-v', '-v', '-v', '-u', str(uid), '-e', envdir] + pid = run_cmd_as_owner(log, assistant_argv, env, owner_uid, owner_gid, groups, safe_fds) + pid, status = waitpid(pid, 0) + log(1, 'Assistant returned %d.', status) + log(1, 'pid %d uid %d', getpid(), getuid()) + assert not WEXITSTATUS(status) + return read_envdir(envdir) + finally: if envdir: check_call(['/bin/rm', '-rf', envdir]) - raise - else: - if not pid: - log(1, 'Dropping privilege to run assistant.') - setgroups(groups) - setgid(owner_gid) - setuid(owner_uid) - log(1, 'Closing fds.') - for fd in get_fds(): - if fd not in safe_fds: - try: os.close(fd) # propagate failure from EIO or EBADF. - except: pass - log(1, 'Running assistant.') - assistant_argv = [assistant, '-v', '-v', '-v', '-u', str(uid), '-e', envdir] - log(1, '%r %r', assistant_argv, env) - execvpe(assistant_argv[0], assistant_argv, env) - _exit(55) - else: - try: - pid, status = waitpid(pid, 0) - log(1, 'Assistant returned %d.', status) - assert not WEXITSTATUS(status) - return read_envdir(envdir) - finally: - log(1, 'pid %d uid %d', getpid(), getuid()) - if envdir: check_call(['/bin/rm', '-rf', envdir]) def launch(log, _, uid, gid, groups, argv, env, cwd, pset, safe_fds): # Set appropriate group membership(s), depending on requested permissions @@ -187,9 +187,9 @@ def check_cwd(uid, gid, cwd): def check_spool(spool, owner_uid, owner_gid): make_dirs(spool, 0, 0, 0755) spool_dirs = ('uid_pool', 'gid_pool', 'uid_to_gid', 'bundle_id_to_gid', - 'gid_to_data_dir', 'uid_to_home_dir', 'xephyr_display_pool', - 'uid_to_xephyr_cookie', 'uid_to_xephyr_display', - 'uid_to_xephyr_auth', 'gid_to_members', 'gid_to_owner') + 'gid_to_data_dir', 'uid_to_home_dir', 'x11_display_pool', + 'uid_to_x11_cookie', 'uid_to_x11_display', + 'uid_to_x11_auth', 'gid_to_members', 'gid_to_owner') for frag in spool_dirs: make_dirs(join(spool, frag), 0, 0, 0755) ck = Checker(join(spool, frag), owner_uid, owner_gid) @@ -231,37 +231,48 @@ def configure_groups(log, owner_uid, groups, gid, data_group_to_gid, recorded_gr except Exception, e: log(1, "Skipping permission (%s) because of (%s).", cap, e) return list(set(groups)) -def configure_xephyr(_, spool, owner_gid, uid, env, safe_fds): +def configure_x11(log, spool, owner_uid, owner_gid, uid, env, safe_fds): # XXX: MUST CHECK RETURN VALUES on subprocesses!!!!! # XXX: I shouldn't be running these subprocesses as uid 0. # XXX: Must get env, fds right!!!! - cookie_path = join(spool, 'uid_to_xephyr_cookie', str(uid)) + cookie_path = join(spool, 'uid_to_x11_cookie', str(uid)) if lexists(cookie_path): cookie = readlink(cookie_path) else: cookie = Popen(["mcookie"], stdout=PIPE).communicate()[0] - symlink(cookie, join(spool, 'uid_to_xephyr_cookie', str(uid))) + symlink(cookie, join(spool, 'uid_to_x11_cookie', str(uid))) - display_path = join(spool, 'uid_to_xephyr_display', str(uid)) + display_path = join(spool, 'uid_to_x11_display', str(uid)) if lexists(display_path): display = int(readlink(display_path)) else: - display = reserve_elt(join(spool, 'xephyr_display_pool'), 100, 10000, 2, 'displays') + display = reserve_elt(join(spool, 'x11_display_pool'), 100, 10000, 2, 'displays') symlink(str(display), display_path) - auth_path = join(spool, 'uid_to_xephyr_auth', str(uid)) + auth_path = join(spool, 'uid_to_x11_auth', str(uid)) if not exists(auth_path): - fd, name = mkstemp(prefix='tmp', dir=join(spool, 'uid_to_xephyr_auth')) + fd, name = mkstemp(prefix='tmp', dir=join(spool, 'uid_to_x11_auth')) os.close(fd) Popen(["xauth", "-f", name], stdin=PIPE).communicate("add :%d . %s\n" % (display, cookie)) rename(name, auth_path) chmod(auth_path, 0640) chown(auth_path, 0, owner_gid) - # NB: Current versions of Xephyr will exit if the display we specified is - # already in use. This permits us to run Xephyr unconditionally even when - # we're resuming an old uid. - Popen(["Xephyr", "-screen", "800x600x24", "-auth", auth_path, "-reset", "-terminate", ":%d" % display]) + x11_server_argv = (['Xvnc', '-DisconnectClients', '-NeverShared', + '-localhost', '-SecurityTypes', 'None', '-auth', + auth_path, '-geometry', '1024x768', '-depth', '24', + ':%d' % display]) + # -extension XFIXES, on ubuntu? + + run_cmd_as_owner(log, x11_server_argv, {}, owner_uid, owner_gid, [owner_gid], safe_fds) + sleep(1.0) # XXX: Argh; race condition. + + owner_pw = getpwuid(owner_uid) + client_env = { 'HOME' : owner_pw.pw_dir, 'DISPLAY' : env['DISPLAY'] } + + x11_client_argv = (['vncviewer', 'localhost:%d' % (5900 + display)]) + run_cmd_as_owner(log, x11_client_argv, client_env, owner_uid, owner_gid, [owner_gid], safe_fds) + # XXX: need to check that the client successfully connected to the server. newenv = {'DISPLAY' : ':%d' % display, 'XAUTHORITY' : auth_path} return newenv @@ -283,7 +294,7 @@ def check_uid(_, spool, owner_uid, uid): assert getpwuid(owner_uid).pw_name in getgrgid(uid).gr_mem def inject(log, spool, env, argv, cwd, pset, safe_fds, owner_uid, owner_gid, - uid, groups, data_groups, assistant, xephyr): + uid, groups, data_groups, assistant, x11): # Note: exceptions are intended to bubble up to the caller and should # terminate execution. check_data_groups(data_groups) @@ -314,8 +325,8 @@ def inject(log, spool, env, argv, cwd, pset, safe_fds, owner_uid, owner_gid, check_home(uid, gid, home) groups = configure_groups(log, owner_uid, groups, gid, data_group_to_gid, recorded_groups, pset) - if xephyr: - env.update(configure_xephyr(log, spool, owner_gid, uid, env, safe_fds)) + if x11: + env.update(configure_x11(log, spool, owner_uid, owner_gid, uid, env, safe_fds)) if assistant: env.update(run_assistant(log, assistant, env, owner_uid, owner_gid, uid, groups, safe_fds)) -- cgit v0.9.1