diff options
Diffstat (limited to 'rainbow/inject.py')
-rw-r--r-- | rainbow/inject.py | 101 |
1 files changed, 56 insertions, 45 deletions
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. <MS> - 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)) |