#!/usr/bin/env python import os import sys import pwd import grp from stat import S_ISREG, ST_MODE from os.path import join, isdir from optparse import OptionParser from pprint import pformat from rainbow.inject import inject from rainbow.permissions import PermissionSet from rainbow.util import make_reporter, trace, unshare, CLONE_NEWNS, read_envdir sys.excepthook = trace def main(): parser = OptionParser(version='0.1') parser.add_option('-v', '--verbose', default=0, action='count', help='Verbosity. Repeat for more verbose output.') parser.add_option('-q', '--quiet', default=False, action='store_true', help='Quiet. Disable all output.') parser.add_option('-s', '--spool', default=None, help='Location of the rainbow spool.') parser.add_option('-e', '--envdir', default=None, help="Location of an envdir describing the desired environment.") parser.add_option('-E', '--env', default=[], action='append', help="Environment bindings to override.") parser.add_option('-c', '--cwd', default=None, help="Working directory.") parser.add_option('-f', '--fd', default=[], action='append', help="File descriptor number to leave open.") 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.") parser.add_option('-p', '--permissions', default=None, help="Location of a permissions.info file.") parser.add_option('-u', '--user', default=None, help="Owning user.") parser.add_option('-r', '--resume-user', default=None, help="Resume .") parser.add_option('-a', '--assistant', default=None, help="Task-specific assistant.") parser.add_option('-G', '--group', default=[], action='append', help="Extra groups.") opts, args = parser.parse_args() if len(args) == 0: parser.print_help() exit(1) report = make_reporter(opts.verbose, opts.quiet, sys.stdout) def check_spool(opts): return opts.spool def check_env(opts): return read_envdir(opts.envdir, opts.env) def check_argv(args): return args def check_cwd(opts): return opts.cwd def check_fds(opts): return [int(s) for s in opts.fd] def check_owner(opts): p = pwd.getpwnam(opts.user) return p.pw_uid, p.pw_gid 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_constant_uid(opts): return 'constant-uid' in opts.option def check_audio(opts): return 'audio' in opts.option def check_video(opts): return 'video' in opts.option def check_serial(opts): return 'serial' in opts.option def check_network(opts): return 'network' in opts.option def check_resume_user(opts): uid = None if opts.resume_user: uid = pwd.getpwnam(opts.resume_user).pw_uid assert 10000 <= uid and uid < 60000 return uid def check_data_ids(opts): return opts.id def check_assistant(opts): return opts.assistant uid, gid = check_owner(opts) spool = check_spool(opts) # Use empty env? Use partial env? Fail unless perfect? env = check_env(opts) argv = check_argv(args) cwd = check_cwd(opts) safe_fds = check_fds(opts) groups = check_groups(opts) pset = PermissionSet(opts.permissions or []) # Dirty hack -- pass 'constant-uid' and 'strace' in as permissions. for perm in ('constant-uid', 'audio', 'video', 'serial', 'network'): pset._permissions.setdefault(perm, locals()['check_'+perm.replace('-','_')](opts)) data_ids = check_data_ids(opts) assistant = check_assistant(opts) xephyr = check_xephyr(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) report(1, 'rainbow:\n%s', pformat(args)) unshare(CLONE_NEWNS) return inject(*args) if __name__ == '__main__': main() # vim : et sw=4 ts=4 sts=4 :