Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/bin
diff options
context:
space:
mode:
authorSascha Silbe <sascha-pgp@silbe.org>2010-07-21 17:30:43 (GMT)
committer Sascha Silbe <sascha-pgp@silbe.org>2010-07-21 17:30:43 (GMT)
commit5ab8ddb8ddb8dc6925cb3bb5f52e0a06b7a1c439 (patch)
tree01e6ca6d9d6eaa54052480200f039c8e50f0166f /bin
parentd4fe57f377d8f78f02a9e5f6d9c201b4e9eb86f4 (diff)
rearrange source tree to match that of the tarball
Diffstat (limited to 'bin')
-rw-r--r--bin/Makefile11
-rwxr-xr-xbin/mkenvdir25
-rwxr-xr-xbin/rainbow-easy26
-rwxr-xr-xbin/rainbow-gc101
-rwxr-xr-xbin/rainbow-resume26
-rwxr-xr-xbin/rainbow-run142
-rwxr-xr-xbin/rainbow-sugarize90
-rwxr-xr-xbin/rainbow-xify76
8 files changed, 497 insertions, 0 deletions
diff --git a/bin/Makefile b/bin/Makefile
new file mode 100644
index 0000000..143e1d1
--- /dev/null
+++ b/bin/Makefile
@@ -0,0 +1,11 @@
+
+install:
+ install -D -m 0755 rainbow-run $(BINDIR)/rainbow-run
+ install -D -m 0755 rainbow-easy $(BINDIR)/rainbow-easy
+ install -D -m 0755 rainbow-resume $(BINDIR)/rainbow-resume
+ install -D -m 0755 rainbow-gc $(BINDIR)/rainbow-gc
+ install -D -m 0755 rainbow-sugarize $(BINDIR)/rainbow-sugarize
+ install -D -m 0755 rainbow-xify $(BINDIR)/rainbow-xify
+ install -D -m 0755 mkenvdir $(BINDIR)/mkenvdir
+
+.PHONY: install
diff --git a/bin/mkenvdir b/bin/mkenvdir
new file mode 100755
index 0000000..542400f
--- /dev/null
+++ b/bin/mkenvdir
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+import os, sys
+from os.path import join, exists, isdir
+from rainbow.util import make_dirs
+
+if len(sys.argv) < 2:
+ print sys.argv[0] + " DIR"
+ sys.exit(1)
+
+dir = sys.argv[1]
+
+if not exists(dir):
+ uid = os.geteuid()
+ gid = os.getegid()
+ make_dirs(dir, os.geteuid(), os.getegid(), 0755)
+
+def writable(path):
+ return os.access(path, os.W_OK)
+
+if exists(dir) and not (isdir(dir) and writable(dir)):
+ print 'DIR is not a writable directory.'
+ exit(1)
+
+for k,v in os.environ.iteritems():
+ open(join(dir, k), 'w').write(v)
diff --git a/bin/rainbow-easy b/bin/rainbow-easy
new file mode 100755
index 0000000..b5a5c34
--- /dev/null
+++ b/bin/rainbow-easy
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+function usage() {
+ echo "sudo $0 ID /path/to/program"
+ echo "ex: sudo $0 banking /bin/bash"
+ exit 1
+}
+
+if [ -z "$1" ] || [ -z "$SUDO_USER" ]; then usage || exit 1; fi
+
+ID="$1"; shift
+
+if [ -z "$DISPLAY" ]; then
+ DISPLAY=`python <<EOF
+import os
+from os.path import join
+
+ppid = os.getppid()
+env = open(join('/proc', str(ppid),'environ')).read().split('\0')
+for kv in env:
+ if kv.startswith("DISPLAY="):
+ print kv[len("DISPLAY="):]
+EOF`
+fi
+
+exec rainbow-run -s /var/spool/rainbow/2 -u "$SUDO_USER" -c "`pwd`" -f 0 -f 1 -f 2 -i "${SUDO_USER}_${ID}" -E "DISPLAY=$DISPLAY" -E "XAUTHORITY=${XAUTHORITY:-${HOME}/.Xauthority}" -a /usr/bin/rainbow-xify -o audio -o network -- "$@"
diff --git a/bin/rainbow-gc b/bin/rainbow-gc
new file mode 100755
index 0000000..82a5cd7
--- /dev/null
+++ b/bin/rainbow-gc
@@ -0,0 +1,101 @@
+#!/usr/bin/env python
+
+import sys
+
+from subprocess import call, check_call, CalledProcessError
+from os import listdir, unlink
+from os.path import join, isdir, islink, exists
+from optparse import OptionParser
+from glob import glob
+
+from rainbow.util import trace, make_reporter
+
+def active_uid(uid):
+ cmd = ['/usr/bin/pgrep', '-U', uid]
+ ret = call(cmd, stdout=open('/dev/null'))
+ if ret in (0, 1):
+ return ret == 0
+ raise CalledProcessError(ret, cmd)
+
+def sticky_uid(spool, uid):
+ return exists(join(spool, "sticky_uids", uid))
+
+def gc_uid(log, spool, uid):
+ """This function conservatively attempts to garbage-collect stale uid
+ reservations.
+ """
+
+ # XXX: D-Bus caches passwd-db data!
+ # XXX: D-Bus uses a fixed 1k passwd buffer - be careful with long paths &
+ # comments
+
+ reservation = join(spool, 'uid_pool', uid)
+ assert not isdir(reservation) and not islink(reservation)
+
+ # XXX: We perform several execv()'s as root based on strings derived from
+ # this 'uid' parameter, which originates as a file-name in a user-writable
+ # directory. Better ideas for input validation would be welcome.
+ uid_num = int(uid)
+ assert uid_num >= 1000 and uid_num <= 65534 # XXX: magic numbers from util/spool.py
+
+ if active_uid(uid) or sticky_uid(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'):
+ row = join(spool, table, uid)
+ # NB: it is important that rm -rf doesn't follow links. <MS>
+ cmd = ['/bin/rm', '-r', '-f', row]
+ log(2, "%s", ' '.join(cmd))
+ check_call(cmd)
+
+ for row in glob(join(spool, 'gid_to_members', '*', uid)):
+ # NB: it is important that rm -rf doesn't follow links. <MS>
+ cmd = ['/bin/rm', '-r', '-f', row]
+ log(2, "%s", ' '.join(cmd))
+ check_call(cmd)
+
+ # So long as we unlink the reservation last, we run no risk of seeing inconsistency
+ unlink(reservation)
+ log(1, "cleaned uid %s", uid)
+
+def gc_spool(log, spool):
+ ret = 0
+ uspool = join(spool, 'uid_pool')
+ if exists(uspool) and isdir(uspool):
+ for maybe_uid in listdir(uspool):
+ try: gc_uid(log, spool, maybe_uid)
+ except KeyboardInterrupt:
+ raise
+ except:
+ trace()
+ ret = 1
+ else:
+ log(1, "Skipping spool %s", spool)
+ ret = 1
+ return ret
+
+def main():
+ sys.excepthook = trace
+
+ 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="/var/spool/rainbow/2",
+ help='Location of the rainbow spool.')
+
+ opts, _ = parser.parse_args()
+
+ report = make_reporter(opts.verbose, opts.quiet, sys.stdout)
+
+ def check_spool(opts):
+ assert exists(opts.spool) and isdir(opts.spool)
+ return opts.spool
+
+ spool = check_spool(opts)
+ return gc_spool(report, spool)
+
+if __name__ == "__main__":
+ exit(main())
diff --git a/bin/rainbow-resume b/bin/rainbow-resume
new file mode 100755
index 0000000..2af756f
--- /dev/null
+++ b/bin/rainbow-resume
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+function usage() {
+ echo "sudo $0 RESUME_UID /path/to/program"
+ echo "ex: sudo $0 banking /bin/bash"
+ exit 1
+}
+
+if [ -z "$1" ] || [ -z "$SUDO_USER" ]; then usage || exit 1; fi
+
+RESUME_UID="$1"; shift
+
+if [ -z "$DISPLAY" ]; then
+ DISPLAY=`python <<EOF
+import os
+from os.path import join
+
+ppid = os.getppid()
+env = open(join('/proc', str(ppid),'environ')).read().split('\0')
+for kv in env:
+ if kv.startswith("DISPLAY="):
+ print kv[len("DISPLAY="):]
+EOF`
+fi
+
+exec rainbow-run -s /var/spool/rainbow/2 -u "$SUDO_USER" -c "`pwd`" -f 0 -f 1 -f 2 -E "DISPLAY=$DISPLAY" -E "XAUTHORITY=$XAUTHORITY" -a /usr/bin/rainbow-xify -o audio -o network -r "$RESUME_UID" -- "$@"
diff --git a/bin/rainbow-run b/bin/rainbow-run
new file mode 100755
index 0000000..3ce2590
--- /dev/null
+++ b/bin/rainbow-run
@@ -0,0 +1,142 @@
+#!/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 <user>.")
+ 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. <MS>
+ 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 :
diff --git a/bin/rainbow-sugarize b/bin/rainbow-sugarize
new file mode 100755
index 0000000..ea0e312
--- /dev/null
+++ b/bin/rainbow-sugarize
@@ -0,0 +1,90 @@
+#!/usr/bin/env python
+
+import sys
+import pwd
+
+from os import getuid, getgid, environ, chmod, chown, symlink
+from os.path import join, isdir, dirname
+from optparse import OptionParser
+from shutil import copyfile
+
+from rainbow.util import make_reporter, trace, make_dirs
+
+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('-u', '--user', default=None,
+ help="Isolated user.")
+ parser.add_option('-e', '--envdir', default=None,
+ help="Envdir to be used for launching.")
+ opts, args = parser.parse_args()
+ if not opts.user or not opts.envdir:
+ parser.print_help()
+ exit(1)
+
+ report = make_reporter(opts.verbose, opts.quiet, sys.stdout)
+
+ def check_user(report, opts):
+ report(1, 'Sugarizing isolated uid %s.', opts.user)
+ return opts.user
+
+ def check_envdir(report, envdir):
+ report(1, 'Sugarizing envdir %s.', envdir)
+ assert isdir(envdir)
+ def write_envvar(k, v):
+ report(1, '-E %s=%s', k, v)
+ open(join(envdir, k), 'w').write(v)
+ return write_envvar
+
+ user = check_user(report, opts)
+ write_envvar = check_envdir(report, opts.envdir)
+
+ o = pwd.getpwuid(getuid())
+ i = pwd.getpwnam(user)
+ h_o = o.pw_dir
+ h_i = i.pw_dir
+
+ # We want to use xauth generate $DISPLAY . untrusted, but we don't have
+ # XSECURITY enabled. <MS>
+ #environ.setdefault('XAUTHORITY', join(h_o, '.Xauthority'))
+ environ.setdefault('ICEAUTHORITY', join(h_o, '.ICEauthority'))
+
+ x_cookie_path = join(h_i, '.Xauthority')
+ make_dirs(dirname(x_cookie_path), getuid(), getgid(), 0777)
+ #copyfile(environ['XAUTHORITY'], x_cookie_path)
+ #chmod(x_cookie_path, 0666)
+ #chown(x_cookie_path, o.pw_uid, i.pw_gid)
+
+ ice_cookie_path = join(h_i, '.ICEauthority')
+ make_dirs(dirname(ice_cookie_path), getuid(), getgid(), 0777)
+ copyfile(environ['ICEAUTHORITY'], ice_cookie_path)
+ chmod(ice_cookie_path, 0666)
+ chown(ice_cookie_path, o.pw_uid, i.pw_gid)
+
+ for frag in ['owner.key.pub']:
+ path = join('.sugar/default/', frag)
+ make_dirs(dirname(join(h_i, path)), getuid(), getgid(), 0777)
+ copyfile(join(h_o, path), join(h_i, path))
+ chmod(join(h_i, path), 0666)
+
+ write_envvar('USER', i.pw_name)
+ write_envvar('HOME', h_i)
+ #write_envvar('XAUTHORITY', x_cookie_path)
+ write_envvar('ICEAUTHORITY', ice_cookie_path)
+ write_envvar('SUGAR_ACTIVITY_ROOT', h_i)
+ write_envvar('TMPDIR', join(h_i, 'tmp'))
+ write_envvar('DISPLAY', environ['DISPLAY'])
+
+ symlink(".", join(h_i, "instance"))
+ symlink(environ["SUGAR_BUNDLE_ID"], join(h_i, "data"))
+ symlink(environ.get("TMPDIR", "/tmp"), join(h_i, "tmp"))
+
+if __name__ == '__main__':
+ main()
+
+# vim : et sw=4 ts=4 sts=4 :
diff --git a/bin/rainbow-xify b/bin/rainbow-xify
new file mode 100755
index 0000000..c51c00c
--- /dev/null
+++ b/bin/rainbow-xify
@@ -0,0 +1,76 @@
+#!/usr/bin/env python
+
+import sys
+import pwd
+
+from os import getuid, getgid, environ, chmod, chown
+from os.path import join, isdir, dirname, exists
+from optparse import OptionParser
+from shutil import copyfile
+
+from rainbow.util import make_reporter, trace, make_dirs
+
+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('-u', '--user', default=None,
+ help="Isolated user.")
+ parser.add_option('-e', '--envdir', default=None,
+ help="Envdir to be used for launching.")
+ opts, args = parser.parse_args()
+ if not opts.user or not opts.envdir:
+ parser.print_help()
+ exit(1)
+
+ report = make_reporter(opts.verbose, opts.quiet, sys.stdout)
+
+ def check_user(report, opts):
+ report(1, 'X-ifying isolated uid %s.', opts.user)
+ return opts.user
+
+ def check_envdir(report, envdir):
+ report(1, 'X-ifying envdir %s.', envdir)
+ assert isdir(envdir)
+ def write_envvar(k, v):
+ report(1, '-E %s=%s', k, v)
+ open(join(envdir, k), 'w').write(v)
+ return write_envvar
+
+ user = check_user(report, opts)
+ write_envvar = check_envdir(report, opts.envdir)
+
+ o = pwd.getpwuid(getuid())
+ i = pwd.getpwnam(user)
+ h_o = o.pw_dir
+ h_i = i.pw_dir
+
+ # XXX: Is it _always_ right to set these defaults? <MS>
+ environ.setdefault('XAUTHORITY', join(h_o, '.Xauthority'))
+ environ.setdefault('ICEAUTHORITY', join(h_o, '.ICEauthority'))
+
+ for cookie in ['XAUTHORITY', 'ICEAUTHORITY']:
+ if exists(environ[cookie]):
+ cookie_path = join(h_i, cookie)
+ make_dirs(dirname(cookie_path), getuid(), getgid(), 0777)
+ copyfile(environ[cookie], cookie_path)
+ chmod(cookie_path, 0666)
+ chown(cookie_path, o.pw_uid, i.pw_gid)
+ write_envvar(cookie, cookie_path)
+ else:
+ report(1, "Cookie %s -> %s which doesn't exist.", cookie, environ[cookie])
+
+ write_envvar('USER', i.pw_name)
+ write_envvar('HOME', h_i)
+ #write_envvar('TMPDIR', join(h_i, 'tmp'))
+ if 'DISPLAY' in environ:
+ write_envvar('DISPLAY', environ['DISPLAY'])
+
+if __name__ == '__main__':
+ main()
+
+# vim : et sw=4 ts=4 sts=4 :