From 759e670e304f829134168265898b6f290fc0246d Mon Sep 17 00:00:00 2001 From: Michael Stone Date: Sun, 19 Dec 2010 00:43:39 +0000 Subject: Merge branches 'ms/vnc', 'ms/slo2199', 'bp/build' and 'ss/orbit' into next * ms/vnc: Start work on a port to VNC. * ms/slo2199: slo#2199: Pass rainbow-easy's parent's PATH through to its child. Abstract out the procedure for reading parent environment variables. * bp/build: build: prettify make output build: remove -W warning, is the same thing as -Wextra * ss/orbit: rainbow-sugarize: tweak permissions for Orbit unix socket (SL#2458) --- diff --git a/bin/rainbow-easy b/bin/rainbow-easy index dafb9c0..cdcef8d 100755 --- a/bin/rainbow-easy +++ b/bin/rainbow-easy @@ -10,17 +10,23 @@ if [ -z "$1" ] || [ -z "$SUDO_USER" ]; then usage || exit 1; fi ID="$1"; shift -if [ -z "$DISPLAY" ]; then - DISPLAY=`python < 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/bin/rainbow-sugarize b/bin/rainbow-sugarize index 275d164..ec0f119 100755 --- a/bin/rainbow-sugarize +++ b/bin/rainbow-sugarize @@ -3,8 +3,8 @@ import sys import pwd -from os import getuid, getgid, environ, chmod, chown, symlink -from os.path import join, isdir, dirname +from os import getuid, getgid, environ, chmod, chown, symlink, listdir +from os.path import join, isdir, dirname, exists from optparse import OptionParser from shutil import copyfile @@ -66,6 +66,12 @@ def main(): chmod(ice_cookie_path, 0666) chown(ice_cookie_path, o.pw_uid, i.pw_gid) + corba_socket_path = join('/tmp', 'orbit-' + o.pw_name) + if exists(corba_socket_path): + chmod(corba_socket_path, 0750) + for socket_name in listdir(corba_socket_path): + chmod(join(corba_socket_path, socket_name), 0660) + for frag in ['owner.key.pub']: path = join('.sugar/default/', frag) make_dirs(dirname(join(h_i, path)), getuid(), getgid(), 0777) diff --git a/nss/Makefile b/nss/Makefile index c4ff2ea..17600a1 100644 --- a/nss/Makefile +++ b/nss/Makefile @@ -1,6 +1,6 @@ WARNFLAGS = \ - -W -Wformat -Wall -Wundef -Wpointer-arith -Wcast-qual \ + -Wformat -Wall -Wundef -Wpointer-arith -Wcast-qual \ -Wcast-align -Wwrite-strings -Wsign-compare \ -Wmissing-noreturn \ -Wextra -Wstrict-aliasing=2 \ @@ -26,6 +26,14 @@ TEST_FORMAT_BUF_OBJS = test_format_buf.o buf.o ALL_OBJS = $(RAINBOW_OBJS) $(UIDS_OBJS) $(GIDS_OBJS) $(TEST_SLIST_OBJS) $(TEST_NAT_OBJS) BINARIES = libnss_rainbow.so.2 uids gids test_slist test_nat test_endgrent test_format_buf +# if you invoke make as 'make V=1' it will verbosely report on what it +# is doing, otherwise it defaults to quiet/pretty mode, which makes +# errors _much_ easier to see +ifneq ($V, 1) +MAKEFLAGS = -s +endif + + # targets all: $(BINARIES) @@ -39,30 +47,38 @@ install: # objects %.o: %.c + @echo " CC $@" $(CC) $(ALLCFLAGS) -c -o $@ $< # linked binaries test_endgrent: $(TEST_ENDGRENT_OBJS) + @echo " LD $@" $(CC) $(ALLCFLAGS) -o $@ $^ test_slist: $(TEST_SLIST_OBJS) + @echo " LD $@" $(CC) $(ALLCFLAGS) -o $@ $^ test_nat: $(TEST_NAT_OBJS) + @echo " LD $@" $(CC) $(ALLCFLAGS) -o $@ $^ test_format_buf: $(TEST_FORMAT_BUF_OBJS) + @echo " LD $@" $(CC) $(ALLCFLAGS) -o $@ $^ uids: $(UIDS_OBJS) + @echo " LD $@" $(CC) $(ALLCFLAGS) -o $@ $^ gids: $(GIDS_OBJS) + @echo " LD $@" $(CC) $(ALLCFLAGS) -o $@ $^ libnss_rainbow.so.2: $(RAINBOW_OBJS) + @echo " LD $@" $(CC) -shared $(LDFLAGS) -o $@ -Wl,-soname,$@ $^ 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