Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/rainbow
diff options
context:
space:
mode:
authorMichael Stone <michael@laptop.org>2009-04-12 09:56:09 (GMT)
committer Michael Stone <michael@laptop.org>2009-04-12 09:56:09 (GMT)
commit485a84cba4284edd98c93385d9510605c2541fb7 (patch)
tree28dcd673f4f1afffd2d9d793d6ee5773f10190e6 /rainbow
parente81c6ce196116d6b6afe0efbfb559012820c88f2 (diff)
Resume and multi-group now appear to function.
Diffstat (limited to 'rainbow')
-rwxr-xr-xrainbow/bin/rainbow-run22
-rw-r--r--rainbow/nss/nss-rainbow.c125
-rw-r--r--rainbow/rainbow/inject.py35
3 files changed, 75 insertions, 107 deletions
diff --git a/rainbow/bin/rainbow-run b/rainbow/bin/rainbow-run
index 2fa8d95..ca3b5cd 100755
--- a/rainbow/bin/rainbow-run
+++ b/rainbow/bin/rainbow-run
@@ -12,7 +12,7 @@ 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
+from rainbow.util import make_reporter, trace, unshare, CLONE_NEWNS, read_envdir
sys.excepthook = trace
@@ -32,7 +32,7 @@ def main():
help="Working directory.")
parser.add_option('-f', '--fd', default=[], action='append',
help="File descriptor number to leave open.")
- parser.add_option('-i', '--id', default=None,
+ 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.")
@@ -40,6 +40,8 @@ def main():
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',
@@ -88,7 +90,14 @@ def main():
def check_serial(opts):
return 'serial' in opts.option
- def check_data_id(opts):
+ 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):
@@ -111,13 +120,14 @@ def main():
for perm in ('constant-uid', 'audio', 'video', 'serial'):
pset._permissions.setdefault(perm, locals()['check_'+perm.replace('-','_')](opts))
- data_id = check_data_id(opts)
+ data_ids = check_data_ids(opts)
assistant = check_assistant(opts)
xephyr = check_xephyr(opts)
- resume_uid = None
+ resume_uid = check_resume_user(opts)
+ if uid: report(1, "resuming uid (%d)", uid)
- args = (report, spool, env, argv, cwd, pset, safe_fds, uid, gid, resume_uid, groups, [data_id], assistant, xephyr)
+ 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)
diff --git a/rainbow/nss/nss-rainbow.c b/rainbow/nss/nss-rainbow.c
index d043b67..21d746a 100644
--- a/rainbow/nss/nss-rainbow.c
+++ b/rainbow/nss/nss-rainbow.c
@@ -62,25 +62,42 @@ out_error_spool:
return NSS_STATUS_UNAVAIL;
}
-enum nss_status
-_nss_rainbow_getpwent_r(struct passwd *result, char* buf, size_t buflen, int *errnop) {
- /* I'm going to interpret the reentrancy requirement on this function to mean
- * that the sequence of all results returned by all calls to this function
- * between calls to setpwent() should contain contain every entry exactly
- * once. It is undefined whether writes to the underlying storage that
- * interleave with calls to getpwent() will be visible to callers. */
-
+int
+read_gid_for_uid(unsigned long uid, unsigned long* gid) {
char gid_path[NAME_MAX+1];
char gid_name[NAME_MAX+1];
size_t gid_path_len;
ssize_t gid_name_len;
char* gid_path_str;
- unsigned long gid;
+ unsigned long val;
-begin:
gid_path_len = gid_name_len = NAME_MAX+1;
gid_path_str = gid_path;
+ CHK(format_buf(&gid_path_str, &gid_path_len, SPOOL "/uid_to_gid/%d", uid) == 1,
+ "Unable to calculate gid-path.", out_err);
+ LET(gid_name_len = readlink(gid_path, gid_name, gid_name_len), gid_name_len == -1,
+ "Unable to read gid-path.", out_err);
+ CHK(parse_nat(&val, gid_name, gid_name_len) == 1,
+ "Unable to parse gid_buf into a gid.", out_err);
+ CHK(val < 10000 || val > 60000,
+ "gid not in valid range.", out_err);
+
+ *gid = val;
+ return 0;
+out_err:
+ return 1;
+}
+
+enum nss_status
+_nss_rainbow_getpwent_r(struct passwd *result, char* buf, size_t buflen, int *errnop) {
+ /* I'm going to interpret the reentrancy requirement on this function to mean
+ * that the sequence of all results returned by all calls to this function
+ * between calls to setpwent() should contain contain every entry exactly
+ * once. It is undefined whether writes to the underlying storage that
+ * interleave with calls to getpwent() will be visible to callers. */
+
+begin:
/* Locate the next reserved uid. */
while (true){
g_uid++;
@@ -90,14 +107,9 @@ begin:
result->pw_uid = g_uid;
- CHK(format_buf(&gid_path_str, &gid_path_len, SPOOL "/uid_to_gid/%d", g_uid) == 1,
- "Unable to calculate gid-path.", begin);
- LET(gid_name_len = readlink(gid_path, gid_name, gid_name_len), gid_name_len == -1,
- "Unable to read gid-path.", begin);
- CHK(parse_nat(&gid, gid_name, gid_name_len) == 1,
- "Unable to parse gid_buf into a gid.", begin);
- CHK(gid < 10000 || gid > 60000,
- "gid not in valid range.", begin);
+ unsigned long gid;
+ CHK(read_gid_for_uid(g_uid, &gid) == 1,
+ "Unable to calculate gid for uid.", begin);
result->pw_gid = gid;
result->pw_dir = buf;
@@ -132,7 +144,11 @@ enum nss_status _nss_rainbow_getpwuid_r(uid_t uid, struct passwd *result, char*
CHK(stat(result->pw_dir, &st) == -1,
"Stat failed for homebuf.", out_error_errno);
result->pw_uid = uid;
- result->pw_gid = st.st_gid;
+
+ unsigned long gid;
+ CHK(read_gid_for_uid(uid, &gid) == 1,
+ "Unable to read gid for uid.", out_error_errno);
+ result->pw_gid = gid;
result->pw_gecos = result->pw_name = result->pw_passwd = buf;
CHK(format_buf(&buf, &buflen, "%d", uid) == 1,
@@ -213,67 +229,6 @@ struct gid_list {
struct gid_list g_gids;
struct gid_list* g_gid;
-/* I'm going to assume that every appropriately named dirent represents a user.
- * We may need to revise this, e.g. by checking for the existence of home dir.
- * We're also going to be evil and use the scandir() traversal to directly
- * record allocated uids. <MS> */
-int
-uid_to_gid_scanner(const struct dirent* d) {
- unsigned long gid;
- char gid_path[NAME_MAX+1];
- char gid_name[NAME_MAX+1];
- size_t gid_path_len = NAME_MAX + 1;
- ssize_t gid_name_len = NAME_MAX + 1;
- char* gid_path_str = gid_path;
- char* uid_str = d->d_name;
- size_t uid_len = strlen(d->d_name);
-
- CHK(uid_len == 0
- || (uid_len == 1 && d->d_name[0] == '.')
- || (uid_len == 2 && d->d_name[0] == '.' && d->d_name[1] == '.'),
- "Invalid path.", exit);
-
- CHK(format_buf(&gid_path_str, &gid_path_len, SPOOL "/uid_to_gid/%s", uid_str) == 1,
- "Unable to calculate uid-to-gid-path.", exit);
- LET(gid_name_len = readlink(gid_path, gid_name, gid_name_len), gid_name_len == -1,
- "Unable to read gid-path.", exit);
- CHK(parse_nat(&gid, gid_name, gid_name_len) == 1,
- "Unable to parse gid_buf into a gid.", exit);
- CHK(gid < 10000 || gid > 60000,
- "gid not in valid range.", exit);
-
- /* We might have already allocated a gid_list for our gid.
- * Therefore, search for it. */
- struct gid_list* gid_iter = NULL;
- list_for_each_entry(gid_iter, &g_gids.list, list) {
- if (gid_iter->gid == gid)
- break;
- }
-
- /* If we find no gid_list, make one and insert it. */
- if (&gid_iter->list == &g_gids.list) {
- LET(gid_iter = malloc(sizeof(struct gid_list)), !gid_iter,
- "Unable to allocate new gid_list node.", exit);
- gid_iter->gid = gid;
- INIT_LIST_HEAD(&(gid_iter->members.list));
- list_add_tail(&(gid_iter->list), &g_gids.list);
- g_gid = gid_iter;
- }
-
- /* gid_iter now points to the appropriate gid_list node.
- * There's no way that we could already have our current (uid, gid) row.
- * Therefore, we'll immediately insert it. */
- struct member_list* member_iter;
- LET(member_iter = calloc(1, sizeof(struct member_list)), !member_iter,
- "Unable to allocate new member_list node.", exit);
- LET(member_iter->name = malloc(uid_len+1), !member_iter->name,
- "Unable to allocate new member_list->name.", exit);
- strncpy(member_iter->name, uid_str, uid_len+1);
- list_add_tail(&(member_iter->list), &(gid_iter->members.list));
-exit:
- return 0;
-}
-
int members_scanner(const struct dirent* d) {
size_t member_len = strlen(d->d_name);
char* member_str = d->d_name;
@@ -299,7 +254,7 @@ exit:
}
int
-data_gid_to_members_scanner(const struct dirent* d) {
+gid_to_members_scanner(const struct dirent* d) {
unsigned long gid;
struct dirent** ents;
char path[NAME_MAX+1];
@@ -316,7 +271,7 @@ data_gid_to_members_scanner(const struct dirent* d) {
CHK(gid < 10000 || gid > 60000,
"gid not in valid range.", exit);
- CHK(format_buf(&path_str, &path_len, SPOOL "/data_gid_to_members/%d", gid) == 1,
+ CHK(format_buf(&path_str, &path_len, SPOOL "/gid_to_members/%d", gid) == 1,
"Unable to calculate data-gid-to-members path.", exit);
/* We might have already allocated a gid_list for our gid.
@@ -341,7 +296,7 @@ data_gid_to_members_scanner(const struct dirent* d) {
/* g_gid now points to an appropriate gid_list for us to fill in. */
CHK(scandir(path, &ents, members_scanner, versionsort) == -1,
- "Unable to scan members dir from $RAINBOW_SPOOL/data_gid_to_members/$GID.", exit);
+ "Unable to scan members dir from $RAINBOW_SPOOL/gid_to_members/$GID.", exit);
exit:
return 0;
}
@@ -351,9 +306,7 @@ enum nss_status _nss_rainbow_setgrent(void) {
INIT_LIST_HEAD(&g_gids.list);
INIT_LIST_HEAD(&g_gids.members.list);
g_gid = &g_gids;
- CHK(scandir(SPOOL "/uid_to_gid", &ents, uid_to_gid_scanner, versionsort) == -1,
- "Unable to extract uid->gids links from $RAINBOW_SPOOL.", out_error_spool);
- CHK(scandir(SPOOL "/data_gid_to_members", &ents, data_gid_to_members_scanner, versionsort) == -1,
+ CHK(scandir(SPOOL "/gid_to_members", &ents, gid_to_members_scanner, versionsort) == -1,
"Unable to extract gid->members dirs from $RAINBOW_SPOOL.", out_error_spool);
g_gid = list_entry(g_gids.list.next, struct gid_list, list);
return NSS_STATUS_SUCCESS;
diff --git a/rainbow/rainbow/inject.py b/rainbow/rainbow/inject.py
index 7dec051..4480114 100644
--- a/rainbow/rainbow/inject.py
+++ b/rainbow/rainbow/inject.py
@@ -43,24 +43,28 @@ def reserve_tag(log, spool, tag, tag_map, tag_type, tag_type_plural, min, max, s
elt = int(basename(realpath(tag_path)))
return elt
-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 reserve_group(log, spool, owner_uid, uid, group):
- gid = reserve_tag(log, spool, group, 'bundle_id_to_gid', 'gid', 'gids', 10000, 65534, 1)
- map_dir = join(spool, 'data_gid_to_members', str(gid))
+def add_uid_to_group(log, spool, owner_uid, uid, gid):
+ map_dir = join(spool, 'gid_to_members', str(gid))
make_dirs(map_dir, 0, 0, 0755)
- owner_path = join(spool, 'data_gid_to_owner', str(gid))
+ owner_path = join(spool, 'gid_to_owner', str(gid))
if not lexists(owner_path):
- symlink(str(owner_uid), join(spool, 'data_gid_to_owner', str(gid)))
+ symlink(str(owner_uid), join(spool, 'gid_to_owner', str(gid)))
# Only join groups that we own.
assert readlink(owner_path) == str(owner_uid)
open(join(map_dir, str(uid)), 'w').close()
open(join(map_dir, str(getpwuid(owner_uid).pw_name)), 'w').close()
+ log(1, "added owner (%d) and uid (%d) to gid (%d)", owner_uid, uid, gid)
+
+def reserve_uid(log, spool, owner_uid):
+ gid = reserve_elt(join(spool, 'gid_pool'), 10000, 65534, 1, 'gids')
+ uid = reserve_elt(join(spool, 'uid_pool'), 10000, 65534, 1, 'uids')
+ symlink(str(gid), join(spool, 'uid_to_gid', str(uid)))
+ add_uid_to_group(log, spool, owner_uid, uid, gid)
+ return (uid, gid)
+
+def reserve_group(log, spool, owner_uid, uid, group):
+ gid = reserve_tag(log, spool, group, 'bundle_id_to_gid', 'gid', 'gids', 10000, 65534, 1)
+ add_uid_to_group(log, spool, owner_uid, uid, gid)
return gid
def grab_home(_, spool, uid, __, owner_gid):
@@ -182,7 +186,7 @@ def check_spool(spool, owner_uid, owner_gid):
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', 'data_gid_to_members', 'data_gid_to_owner')
+ 'uid_to_xephyr_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)
@@ -247,7 +251,7 @@ def configure_xephyr(_, spool, owner_gid, uid, env, safe_fds):
def check_uid(_, spool, owner_uid, uid):
assert 10000 <= uid and uid <= 65534
- assert readlink(join(spool, 'uid_to_owner_uid', str(uid))) == str(owner_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):
@@ -260,12 +264,13 @@ def inject(log, spool, env, argv, cwd, pset, safe_fds, owner_uid, owner_gid,
check_spool(spool, owner_uid, owner_gid)
if not uid:
- uid, gid = reserve_uid(log, spool)
+ uid, gid = reserve_uid(log, spool, owner_uid)
home = grab_home(log, spool, uid, gid, owner_gid)
else:
check_uid(log, spool, owner_uid, uid)
pw = getpwuid(uid)
gid, home = pw.pw_gid, pw.pw_dir
+ log(1, "resuming uid (%d) for owner (%d) with gid (%d) and home (%s)", uid, owner_uid, gid, home)
# XXX: Need to verify ownership and membership before joining data groups.
data_group_to_gid = [(group, reserve_group(log, spool, owner_uid, uid, group)) for group in data_groups]