Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Stone <michael@laptop.org>2009-04-11 08:40:36 (GMT)
committer Michael Stone <michael@laptop.org>2009-04-11 08:40:36 (GMT)
commit4c16e2af14a8c13d718f3505a18dfe51e187925e (patch)
tree85eeb68d8bbf1763dc87dcaeb99e3ee5dd7d6ad3
parent21bc400eb8723e489916201f40243cdb3edbb587 (diff)
Permit zero to many data groups.
-rw-r--r--rainbow/rainbow/inject.py154
1 files changed, 73 insertions, 81 deletions
diff --git a/rainbow/rainbow/inject.py b/rainbow/rainbow/inject.py
index 2d15ada..9fd3ab8 100644
--- a/rainbow/rainbow/inject.py
+++ b/rainbow/rainbow/inject.py
@@ -1,26 +1,17 @@
import os
-from os import R_OK, W_OK, X_OK, fork, symlink, unlink, O_CREAT, O_EXCL, readlink, chown, chmod
+from os import R_OK, W_OK, X_OK, fork, symlink, unlink, O_CREAT, O_EXCL, chown, chmod
from os import setgroups, setgid, setuid, chdir, umask, execvpe, waitpid, WEXITSTATUS
from os import getpid, getuid, _exit, rename
-from os.path import join, basename, realpath, lexists, islink
+from os.path import join, basename, realpath, lexists
from subprocess import check_call, Popen, PIPE
from stat import S_IFDIR
from tempfile import mkdtemp, mkstemp
-from grp import getgrnam
+from grp import getgrnam, getgrgid
+from pwd import getpwuid
import resource
from rainbow.util import Checker, mount, make_dirs, get_fds, read_envdir
-def strace(log, argv, env):
- log(1, 'applying strace')
- args = ['/usr/bin/strace', '-f']
- for k, v in env.iteritems():
- args.append('-E')
- args.append('%s=%s' % (k, v))
- args.extend(argv)
-
- return args, {}
-
def reserve_elt(pool_dir, elt, max_elt, incr, elt_name):
fd = None
while elt < max_elt:
@@ -34,66 +25,54 @@ def reserve_elt(pool_dir, elt, max_elt, incr, elt_name):
raise RuntimeError("No " + elt_name + " available.")
return elt
-def reserve_credentials(log, spool, data_id, pset):
- # Pick a gid for yourself.
- gid = reserve_elt(join(spool, 'gid_pool'), 10001, 65534, 2, 'gids')
-
- # Then try to atomically symlink the gid you picked to 'name' in gid_dir.
- # If you succeed, then you have the right gid.
- # If you fail, someone else has the right gid so release yours and use theirs.
- name_path = join(spool, 'bundle_id_to_gid', data_id)
- gid_path = join(spool, 'gid_pool', str(gid))
+def reserve_tag(log, spool, tag, tag_map, tag_type, tag_type_plural, min, max, step):
+ # Pick an element for yourself.
+ pool_dir = join(spool, tag_type+'_pool')
+ elt = reserve_elt(pool_dir, min, max, step, tag_type_plural)
+ log(1, 'reserved %s (%d) for tag %s', tag_type, elt, tag)
+
+ # Then try to atomically symlink the elt you picked to 'tag' in 'tag_map' dir.
+ # If you succeed, then you have the right elt.
+ # If you fail, someone else has the right elt so release yours and use theirs.
+ tag_path = join(spool, tag_map, tag)
+ elt_path = join(pool_dir, str(elt))
try:
- symlink(gid_path, name_path)
+ symlink(elt_path, tag_path)
except OSError:
- unlink(gid_path)
- gid = int(basename(realpath(name_path)))
-
- # Decide whether to reserve a new (even) uid or to set uid <- gid and reserve that.
- uid = pset.has_permission('constant-uid') and gid or reserve_elt(join(spool, 'uid_pool'), 10000, 65534, 2, 'uids')
- open(join(spool, 'uid_pool', str(gid)), 'w').close()
- log(1, 'reserved credentials (%d, %d)', uid, gid)
+ unlink(elt_path)
+ elt = int(basename(realpath(tag_path)))
+ return elt
- path = join(spool, 'uid_to_gid', str(uid))
- if not lexists(path):
- symlink(str(gid), path)
- else:
- assert islink(path) and readlink(path) == str(gid)
+def reserve_uid(log, spool):
+ gid = reserve_elt(join(spool, 'gid_pool'), 10000, 65534, 1, 'gids')
+ log(1, 'reserved gid (%d) for new uid', gid)
+ uid = reserve_tag(log, spool, str(gid), 'uid_to_gid', 'uid', 'uids', 10000, 65534, 1)
return (uid, gid)
-def grab_home(log, spool, data_id, uid, gid, owner_gid):
+def reserve_group(log, spool, group):
+ return reserve_tag(log, spool, group, 'bundle_id_to_gid', 'gid', 'gids', 10000, 65534, 1)
+
+def grab_home(_, spool, uid, _, owner_gid):
home = join(spool, 'uid_to_home_dir', str(uid))
make_dirs(home, uid, owner_gid, 0770)
chown(home, uid, owner_gid)
- # Per discussion with Bert Freudenberg, set the setgid bit on $SAR/instance
+ # Per discussion with Bert Freudenberg, set the setgid bit on $HOME
# (i.e. $HOME) so that Sugar can better write inside it. <MS>
chmod(home, 02770)
return home
-def configure_home(spool, owner_uid, owner_gid, uid, gid, home):
- # Beware of CONSTANT_UID + instance==home: the instance dir may already exist.
- path = join(spool, 'uid_to_instance_dir', str(uid))
- if not lexists(path):
- symlink(home, path)
-
- if not lexists(join(home, 'instance')):
- symlink('.', join(home, 'instance'))
-
- path = join(spool, 'gid_to_data_dir', str(gid))
- make_dirs(path, owner_uid, gid, 0770)
- chown(path, owner_uid, gid)
- chmod(path, 0770)
- if not lexists(join(home, 'data')):
- symlink(path, join(home, 'data'))
-
- #XXX: ARGH pippy. <MS>
- make_dirs(join(home, 'tmp'), uid, gid, 0700)
- mount('tmpfs', join(home, 'tmp'), 'tmpfs', 0, '')
-
-def mount_fsen(log, home):
- log(1, 'Mounting tmpfsen on /tmp and /var/tmp.')
- #XXX: Kills X socket. :( <MS>
+def configure_home(_, spool, home, owner_uid, _, _, gid, data_group_to_gid):
+ for group, gid in data_group_to_gid:
+ path = join(spool, 'gid_to_data_dir', str(gid))
+ make_dirs(path, owner_uid, gid, 0770)
+ chown(path, owner_uid, gid)
+ chmod(path, 02770)
+ if not lexists(join(home, group)):
+ symlink(path, join(home, group))
+
+def mount_fsen(log, _):
+ log(1, 'Mounting tmpfsen on /var/tmp and... drat; /tmp kills the X socket. :( <MS>')
#mount('tmpfs', '/tmp', 'tmpfs', 0, '')
mount('tmpfs', '/var/tmp', 'tmpfs', 0, '')
@@ -133,7 +112,7 @@ def run_assistant(log, assistant, env, owner_uid, owner_gid, uid, groups, safe_f
log(1, 'pid %d uid %d', getpid(), getuid())
if envdir: check_call(['/bin/rm', '-rf', envdir])
-def launch(log, home, uid, gid, groups, argv, env, cwd, pset, safe_fds):
+def launch(log, _, uid, gid, groups, argv, env, cwd, pset, safe_fds):
# Set appropriate group membership(s), depending on requested permissions
log(1, 'dropping privilege to (%d, %d, %r)', uid, gid, groups)
setgroups(groups)
@@ -167,9 +146,6 @@ def launch(log, home, uid, gid, groups, argv, env, cwd, pset, safe_fds):
log(1, 'umask(0)')
umask(0)
- if pset.has_permission('strace'):
- argv, env = strace(log, argv, env)
-
log(1, 'about to execve\nargv: %s\nenv: %s', argv, env)
log(1, 'closing all fds but %s', safe_fds)
for fd in get_fds():
@@ -179,10 +155,11 @@ def launch(log, home, uid, gid, groups, argv, env, cwd, pset, safe_fds):
execvpe(argv[0], argv, env)
-def check_data_id(data_id):
+def check_data_groups(data_groups):
# XXX: How do I figure out what MAX_PATH_LEN is in python? <MS>
# XXX: How long are GECOS fields permitted to be? <MS>
- assert data_id and '\0' not in data_id and len(data_id) < 128
+ for data_id in data_groups:
+ assert data_id and '\0' not in data_id and len(data_id) < 128
def check_argv(argv):
assert argv
@@ -194,15 +171,15 @@ 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',
- 'uid_to_instance_dir', '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_data_dir', 'uid_to_home_dir', 'xephyr_display_pool',
+ 'uid_to_xephyr_cookie', 'uid_to_xephyr_display',
+ 'uid_to_xephyr_auth')
for frag in spool_dirs:
make_dirs(join(spool, frag), 0, 0, 0755)
ck = Checker(join(spool, frag), owner_uid, owner_gid)
assert ck.positive(R_OK | X_OK, S_IFDIR)
-def check_owner(owner_uid, owner_gid):
+def check_owner(_, _):
return True
def check_home_dirs(uid, gid, home):
@@ -214,14 +191,27 @@ def check_home(uid, gid, home):
ck = Checker(home, uid, gid)
assert ck.positive(R_OK | W_OK | X_OK, S_IFDIR)
-def configure_groups(groups, gid, pset):
+def maybe_add_gid(owner_uid, gid):
+ # rainbow should only let you drop privilege.
+ return getpwuid(owner_uid).pw_name in getgrgid(gid).mem
+
+def configure_groups(log, owner_uid, groups, gid, data_group_to_gid, pset):
groups.insert(0, gid)
- if pset.has_permission("audio"): groups.append(getgrnam("audio").gr_gid)
- if pset.has_permission("video"): groups.append(getgrnam("video").gr_gid)
- if pset.has_permission("serial"): groups.append(getgrnam("uucp").gr_gid)
+
+ for _, data_gid in data_group_to_gid:
+ if maybe_add_gid(owner_uid, data_gid):
+ groups.insert(data_gid)
+
+ for cap in ("audio", "video", "serial"):
+ try:
+ if pset.has_permission(cap):
+ cap_gid = getgrnam(cap).gr_gid
+ if maybe_add_gid(owner_uid, cap_gid):
+ groups.insert(cap_gid)
+ except Exception, e: log(1, "Skipping permission (%s) because of (%s).", cap, e)
return list(set(groups))
-def configure_xephyr(log, spool, owner_gid, uid, env, safe_fds):
+def configure_xephyr(_, spool, 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!!!!
@@ -244,18 +234,20 @@ def configure_xephyr(log, spool, owner_gid, uid, env, safe_fds):
return newenv
def inject(log, spool, env, argv, cwd, pset, safe_fds, owner_uid, owner_gid,
- groups, data_id, assistant):
+ groups, data_groups, assistant):
# Note: exceptions are intended to bubble up to the caller and should
# terminate execution.
- check_data_id(data_id)
+ check_data_groups(data_groups)
check_argv(argv)
check_owner(owner_uid, owner_gid)
check_spool(spool, owner_uid, owner_gid)
- uid, gid = reserve_credentials(log, spool, data_id, pset)
- home = grab_home(log, spool, data_id, uid, gid, owner_gid)
- configure_home(spool, owner_uid, owner_gid, uid, gid, home)
+ uid, gid = reserve_uid(log, spool)
+ data_group_to_gid = [(group, reserve_group(log, spool, group)) for group in data_groups]
+
+ home = grab_home(log, spool, uid, gid, owner_gid, )
+ configure_home(log, spool, home, owner_uid, owner_gid, uid, gid, data_group_to_gid)
if cwd is None:
cwd = home
@@ -264,7 +256,7 @@ def inject(log, spool, env, argv, cwd, pset, safe_fds, owner_uid, owner_gid,
check_home_dirs(owner_uid, owner_gid, home)
check_home(uid, gid, home)
- groups = configure_groups(groups, gid, pset)
+ groups = configure_groups(log, owner_uid, groups, gid, data_group_to_gid, pset)
env_updates = configure_xephyr(log, spool, owner_gid, uid, env, safe_fds)
if env_updates: env.update(env_updates)
env_updates = run_assistant(log, assistant, env, owner_uid, owner_gid, uid, groups, safe_fds)