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-12 07:49:31 (GMT)
committer Michael Stone <michael@laptop.org>2009-04-12 07:49:31 (GMT)
commitbf8af14d62c53e0307bd08e7023ddc9a7bb67ce7 (patch)
treec8dbe642948f39ddcc4083bd46195cad9bc449b7
parent210be7b72d9a036586667f9a904073bac0b7b34a (diff)
Improve nss-rainbow to produce adequate group membership data.
-rw-r--r--rainbow/nss/buf.c3
-rw-r--r--rainbow/nss/cgen.h3
-rw-r--r--rainbow/nss/gids.c2
-rw-r--r--rainbow/nss/nat.c3
-rw-r--r--rainbow/nss/nss-rainbow.c146
-rw-r--r--rainbow/nss/test_nat.c3
-rw-r--r--rainbow/rainbow/inject.py23
-rw-r--r--rainbow/rainbow/util.py15
8 files changed, 152 insertions, 46 deletions
diff --git a/rainbow/nss/buf.c b/rainbow/nss/buf.c
index 9ba8f64..5cf0fa4 100644
--- a/rainbow/nss/buf.c
+++ b/rainbow/nss/buf.c
@@ -4,10 +4,13 @@
#include <syslog.h>
#include <string.h>
#include <stdarg.h>
+#include <stdlib.h>
#include "cgen.h"
#include "buf.h"
+#include "config/debug.h"
+
int write_buf(char** buf, size_t * buflen, const char* val)
{
diff --git a/rainbow/nss/cgen.h b/rainbow/nss/cgen.h
index 2172ad0..6d9f48e 100644
--- a/rainbow/nss/cgen.h
+++ b/rainbow/nss/cgen.h
@@ -2,7 +2,8 @@
#define SAVE_ERR(EXPR) {int __errno_save = errno; EXPR; errno = __errno_save;}
#define __XSTRING(X) __STRING(X)
/* #define PERROR(msg) {int __errno_cache = errno; dprintf(2, "%s|%d| %s: %s\nError %d: %s\n", __FILE__, __LINE__, __func__, msg, __errno_cache, strerror(__errno_cache));} */
-#define PERROR(msg)
+#define PERROR(msg) {int __errno_cache = errno; if (getenv(DEBUG) != NULL) {dprintf(2, "%s|%d| %s: %s\n", __FILE__, __LINE__, __func__, msg); if (__errno_cache) {dprintf(2, "Error %d: %s\n", __errno_cache, strerror(__errno_cache));}};}
+/* #define PERROR(msg) */
#define CHK(EXPR, MSG, ERR_LABEL) {if(EXPR) { PERROR(MSG); goto ERR_LABEL;}}
#define LET(LETEXPR, CONDEXPR, MSG, ERR_LABEL) LETEXPR; if (CONDEXPR) { PERROR(MSG); goto ERR_LABEL;}
#define TST(EXPR, ERRNO, MSG, ERR_LABEL) {if (EXPR) {errno = ERRNO; PERROR(MSG); goto ERR_LABEL;}}
diff --git a/rainbow/nss/gids.c b/rainbow/nss/gids.c
index 3fb93b2..a374dbe 100644
--- a/rainbow/nss/gids.c
+++ b/rainbow/nss/gids.c
@@ -13,7 +13,6 @@ int main() {
setgrent();
while (1) {
- printf("\n\n");
i = getgrent_r(&gr, buf, BUFLEN, &grp);
if (i) {
printf("status: %d\n", i);
@@ -23,6 +22,7 @@ int main() {
int num_members = strlen((char*)grp->gr_mem) / sizeof(char*);
for (i = 0; i < num_members; i++)
printf("%s ", grp->gr_mem[i]);
+ if (num_members) printf("\n");
cnt++;
}
endgrent();
diff --git a/rainbow/nss/nat.c b/rainbow/nss/nat.c
index a5e70a1..dc6b648 100644
--- a/rainbow/nss/nat.c
+++ b/rainbow/nss/nat.c
@@ -3,10 +3,13 @@
#include <stdio.h>
#include <syslog.h>
#include <string.h>
+#include <stdlib.h>
#include "cgen.h"
#include "nat.h"
+#include "config/debug.h"
+
int nat_add(unsigned long* result, unsigned long arg)
{
unsigned long tmp = *result + arg;
diff --git a/rainbow/nss/nss-rainbow.c b/rainbow/nss/nss-rainbow.c
index bc51102..d043b67 100644
--- a/rainbow/nss/nss-rainbow.c
+++ b/rainbow/nss/nss-rainbow.c
@@ -35,7 +35,7 @@ static unsigned short g_uid = 0;
* We're also going to be evil and use the scandir() traversal to directly
* record allocated uids. <MS> */
int
-uid_filter(const struct dirent* d) {
+uid_scanner(const struct dirent* d) {
unsigned long val;
if(parse_nat(&val, d->d_name, strlen(d->d_name)) == 1) return 0;
if(val < 10000 || val > 60000) return 0;
@@ -54,8 +54,8 @@ _nss_rainbow_setpwent(void) {
for (unsigned short i = 10000; i < 60000; i++)
g_uids[i] = 0;
g_uid = 0;
- struct dirent** uids;
- CHK(scandir(SPOOL "/uid_pool", &uids, uid_filter, versionsort) == -1,
+ struct dirent** ents;
+ CHK(scandir(SPOOL "/uid_pool", &ents, uid_scanner, versionsort) == -1,
"Unable to extract uids from $RAINBOW_SPOOL.", out_error_spool);
return NSS_STATUS_SUCCESS;
out_error_spool:
@@ -199,14 +199,14 @@ out_error_errno:
#endif
-struct uid_list {
+struct member_list {
struct list_head list;
- uid_t uid;
+ char* name;
};
struct gid_list {
struct list_head list;
- struct uid_list uids;
+ struct member_list members;
gid_t gid;
};
@@ -218,20 +218,22 @@ struct gid_list* g_gid;
* We're also going to be evil and use the scandir() traversal to directly
* record allocated uids. <MS> */
int
-uid_to_gid_filter(const struct dirent* d) {
- unsigned long uid, gid;
+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(parse_nat(&uid, d->d_name, strlen(d->d_name)) == 1,
- "Unable to parse uid.", exit);
- CHK(uid < 10000 || uid > 60000,
- "uid not in valid range.", exit);
+ 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/%d", uid) == 1,
+ 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);
@@ -240,7 +242,7 @@ uid_to_gid_filter(const struct dirent* d) {
CHK(gid < 10000 || gid > 60000,
"gid not in valid range.", exit);
- /* We might have already allocated a uid_list for our gid.
+ /* 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) {
@@ -248,12 +250,12 @@ uid_to_gid_filter(const struct dirent* d) {
break;
}
- /* If we find no uid_list, make one and insert it. */
+ /* 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->uids.list));
+ INIT_LIST_HEAD(&(gid_iter->members.list));
list_add_tail(&(gid_iter->list), &g_gids.list);
g_gid = gid_iter;
}
@@ -261,23 +263,98 @@ uid_to_gid_filter(const struct dirent* d) {
/* 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 uid_list* uid_iter;
- LET(uid_iter = malloc(sizeof(struct uid_list)), !uid_iter,
- "Unable to allocate new uid_list node.", exit);
- uid_iter->uid = uid;
- list_add_tail(&(uid_iter->list), &(gid_iter->uids.list));
+ 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;
+
+ CHK(member_len == 0
+ || (member_len == 1 && d->d_name[0] == '.')
+ || (member_len == 2 && d->d_name[0] == '.' && d->d_name[1] == '.'),
+ "Invalid data-gid-to-member member path.", exit);
+
+ /* g_gid now points to the appropriate gid_list node.
+ * There's no way that we could already have our current (uid, gid) row.
+ * I think. :)
+ * 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(member_len+1), !member_iter->name,
+ "Unable to allocate new member_list->name.", exit);
+ strncpy(member_iter->name, member_str, member_len+1);
+ list_add_tail(&(member_iter->list), &(g_gid->members.list));
exit:
return 0;
}
+int
+data_gid_to_members_scanner(const struct dirent* d) {
+ unsigned long gid;
+ struct dirent** ents;
+ char path[NAME_MAX+1];
+ size_t path_len = NAME_MAX + 1;
+ char* path_str = path;
+
+ CHK(path_len == 0
+ || (path_len == 1 && d->d_name[0] == '.')
+ || (path_len == 2 && d->d_name[0] == '.' && d->d_name[1] == '.'),
+ "Invalid data-gid-to-member gid dir.", exit);
+
+ CHK(parse_nat(&gid, d->d_name, strlen(d->d_name)) == 1,
+ "Unable to parse d->d_name into a gid.", exit);
+ 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,
+ "Unable to calculate data-gid-to-members path.", 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) {
+ g_gid = gid_iter;
+ 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;
+ }
+
+ /* 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);
+exit:
+ return 0;
+}
enum nss_status _nss_rainbow_setgrent(void) {
- struct dirent** uids;
+ struct dirent** ents;
INIT_LIST_HEAD(&g_gids.list);
- INIT_LIST_HEAD(&g_gids.uids.list);
+ INIT_LIST_HEAD(&g_gids.members.list);
g_gid = &g_gids;
- CHK(scandir(SPOOL "/uid_to_gid", &uids, uid_to_gid_filter, versionsort) == -1,
+ 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,
+ "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;
out_error_spool:
@@ -286,13 +363,14 @@ out_error_spool:
enum nss_status _nss_rainbow_endgrent(void) {
struct gid_list* gid_iter;
- struct uid_list* uid_iter;
+ struct member_list* member_iter;
while(!list_empty(&g_gids.list)) {
gid_iter = list_entry(g_gids.list.next, struct gid_list, list);
- while(!list_empty(&(gid_iter->uids.list))) {
- uid_iter = list_entry(gid_iter->uids.list.next, struct uid_list, list);
- list_del(&(uid_iter->list));
- free(uid_iter);
+ while(!list_empty(&(gid_iter->members.list))) {
+ member_iter = list_entry(gid_iter->members.list.next, struct member_list, list);
+ list_del(&(member_iter->list));
+ free(member_iter->name);
+ free(member_iter);
}
list_del(&(gid_iter->list));
free(gid_iter);
@@ -318,10 +396,10 @@ fill_group(struct group* result, char* buf, size_t buflen, int *errnop, struct g
"Unable to calculate group name.", out_error_errno);
/* count the number of members */
- struct uid_list* uid_iter;
- struct list_head* uid_node_iter;
+ struct member_list* member_iter;
+ struct list_head* member_node_iter;
size_t member_count = 0;
- list_for_each(uid_node_iter, &(gid_iter->uids.list)) {
+ list_for_each(member_node_iter, &(gid_iter->members.list)) {
member_count++;
}
@@ -336,9 +414,9 @@ fill_group(struct group* result, char* buf, size_t buflen, int *errnop, struct g
/* fill in the members and swing the pointers */
member_count = 0;
- list_for_each_entry(uid_iter, &(gid_iter->uids.list), list) {
+ list_for_each_entry(member_iter, &(gid_iter->members.list), list) {
result->gr_mem[member_count] = buf;
- CHK(format_buf(&buf, &buflen, "%d", uid_iter->uid) == 1,
+ CHK(format_buf(&buf, &buflen, "%s", member_iter->name) == 1,
"Unable to write a group member.", out_error_errno);
member_count++;
}
diff --git a/rainbow/nss/test_nat.c b/rainbow/nss/test_nat.c
index 99c7f84..b7a01cb 100644
--- a/rainbow/nss/test_nat.c
+++ b/rainbow/nss/test_nat.c
@@ -3,10 +3,13 @@
#include <stdio.h>
#include <syslog.h>
#include <string.h>
+#include <stdlib.h>
#include "cgen.h"
#include "nat.h"
+#include "config/debug.h"
+
int main()
{
openlog("nat", LOG_PERROR, LOG_LOCAL0);
diff --git a/rainbow/rainbow/inject.py b/rainbow/rainbow/inject.py
index 8ff9a8c..a8812f3 100644
--- a/rainbow/rainbow/inject.py
+++ b/rainbow/rainbow/inject.py
@@ -37,7 +37,7 @@ def reserve_tag(log, spool, tag, tag_map, tag_type, tag_type_plural, min, max, s
tag_path = join(spool, tag_map, tag)
elt_path = join(pool_dir, str(elt))
try:
- symlink(elt_path, tag_path)
+ symlink(str(elt), tag_path)
except OSError:
unlink(elt_path)
elt = int(basename(realpath(tag_path)))
@@ -50,8 +50,17 @@ def reserve_uid(log, spool):
uid = reserve_tag(log, spool, str(gid), 'uid_to_gid', 'uid', 'uids', 10000, 65534, 1)
return (uid, gid)
-def reserve_group(log, spool, group):
- return reserve_tag(log, spool, group, 'bundle_id_to_gid', 'gid', 'gids', 10000, 65534, 1)
+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))
+ make_dirs(map_dir, 0, 0, 0755)
+ owner_path = join(spool, 'data_gid_to_owner', str(gid))
+ if not lexists(owner_path):
+ symlink(str(owner_uid), join(spool, 'data_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()
+ return gid
def grab_home(_, spool, uid, __, owner_gid):
home = join(spool, 'uid_to_home_dir', str(uid))
@@ -173,7 +182,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')
+ 'uid_to_xephyr_auth', 'data_gid_to_members', 'data_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)
@@ -184,7 +193,7 @@ def check_owner(_, __):
def check_home_dirs(uid, gid, home, data_group_to_gid):
for frag, _ in data_group_to_gid:
- ck = Checker(join(home, frag), uid, gid)
+ ck = Checker(join(home, frag), uid, gid, [x for _, x in data_group_to_gid])
assert ck.positive(R_OK | W_OK | X_OK, S_IFDIR)
def check_home(uid, gid, home):
@@ -193,7 +202,7 @@ def check_home(uid, gid, home):
def maybe_add_gid(owner_uid, gid):
# rainbow should only let you drop privilege.
- return getpwuid(owner_uid).pw_name in getgrgid(gid).mem
+ return getpwuid(owner_uid).pw_name in getgrgid(gid).gr_mem
def configure_groups(log, owner_uid, groups, gid, data_group_to_gid, pset):
groups.insert(0, gid)
@@ -256,7 +265,7 @@ def inject(log, spool, env, argv, cwd, pset, safe_fds, owner_uid, owner_gid,
gid, home = pw.pw_gid, pw.pw_dir
# XXX: Need to verify ownership and membership before joining data groups.
- data_group_to_gid = [(group, reserve_group(log, spool, group)) for group in data_groups]
+ data_group_to_gid = [(group, reserve_group(log, spool, owner_uid, uid, group)) for group in data_groups]
configure_home(log, spool, home, owner_uid, owner_gid, uid, gid, data_group_to_gid)
if cwd is None:
diff --git a/rainbow/rainbow/util.py b/rainbow/rainbow/util.py
index 5cd4029..3679c20 100644
--- a/rainbow/rainbow/util.py
+++ b/rainbow/rainbow/util.py
@@ -95,12 +95,21 @@ class Checker(object):
In particular, this class does not know the special rules that adhere to
uid 0.
"""
- def __init__(self, path, uid, gid):
+ def __init__(self, path, uid, gid, groups=None):
self.path = path
self.uid = uid
self.gid = gid
+ self.groups = set(groups or []).union(set([gid]))
self.observation = stat(self.path)
+ def __repr__(self):
+ return "Checker(%r, %r, %r, groups=%r)" % (self.path, self.uid, self.gid, self.groups)
+
+ def __str__(self):
+ return ("Checker(%s, %s, %s, %s) -> mode: %o uid: %s, gid: %s" %
+ (self.path, self.uid, self.gid, self.groups, self.observation[ST_MODE],
+ self.observation[ST_UID], self.observation[ST_GID]))
+
def positive(self, needed, mask):
# I'm going to try to turn off bits in mode as I verify that they can
# be satisfied.
@@ -108,7 +117,7 @@ class Checker(object):
real_mode = o[ST_MODE]
if self.uid == o[ST_UID]:
needed &= ~((real_mode & 0700) >> 6)
- if self.gid == o[ST_GID]:
+ if o[ST_GID] in self.groups:
needed &= ~((real_mode & 0070) >> 3)
needed &= ~(real_mode & 0007)
# Make sure needed is empty and real_mode satisfies stat.
@@ -122,7 +131,7 @@ class Checker(object):
allowed = 0
if self.uid == o[ST_UID]:
allowed |= (real_mode & 0700) >> 6
- if self.gid == o[ST_GID]:
+ if o[ST_GID] in self.groups:
allowed |= (real_mode & 0070) >> 3
allowed |= (real_mode & 0007)
# Did we avoid everything?