diff options
Diffstat (limited to 'rainbow/nss/nss-rainbow.c')
-rw-r--r-- | rainbow/nss/nss-rainbow.c | 176 |
1 files changed, 102 insertions, 74 deletions
diff --git a/rainbow/nss/nss-rainbow.c b/rainbow/nss/nss-rainbow.c index de6be89..1f69ac3 100644 --- a/rainbow/nss/nss-rainbow.c +++ b/rainbow/nss/nss-rainbow.c @@ -20,7 +20,7 @@ #include "buf.h" #include "nat.h" -#include "list.h" +#include "slist.h" /* constants */ #include "config/shell.h" @@ -62,6 +62,16 @@ out_error_spool: return NSS_STATUS_UNAVAIL; } +int check_gid_in_range(gid_t gid) +{ + TST(gid < 10000 || gid > 60000, errno = ENOENT, + "Gid outside [10000, 60000].", out_error); + return 0; +out_error: + return 1; +} + + int read_gid_for_uid(unsigned long uid, unsigned long* gid) { char gid_path[NAME_MAX+1]; @@ -191,19 +201,33 @@ out_error_name: return NSS_STATUS_NOTFOUND; } -struct member_list { - struct list_head list; +struct member_row { + struct slist list; char* name; }; - -struct gid_list { - struct list_head list; - struct member_list members; +struct gid_row { + struct slist list; + struct member_row *members; gid_t gid; }; -struct gid_list g_gids; -struct gid_list* g_gid; +struct gid_row* g_gids; +struct gid_row* g_cur_gid; + +void member_row_init(struct member_row* self) { + self->name = NULL; + slist_init(&self->list); +} + +void gid_row_init(struct gid_row* self) { + slist_init(&self->list); + self->members = NULL; + self->gid = -1; +} + +void gid_row_add_member(struct gid_row* self, struct member_row* mr) { + slist_extend(&self->members->list, &mr->list); +} int members_scanner(const struct dirent* d) { size_t member_len = strlen(d->d_name); @@ -214,17 +238,22 @@ int members_scanner(const struct dirent* d) { || (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. + /* g_cur_gid now points to the appropriate gid_row 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)); + struct member_row* mr; + + LET(mr = calloc(1, sizeof(struct member_row)), !mr, + "Unable to allocate new member_row node.", exit); + member_row_init(mr); + + LET(mr->name = malloc(member_len+1), !mr->name, + "Unable to allocate new member_row->name.", exit); + strncpy(mr->name, member_str, member_len+1); + + gid_row_add_member(g_cur_gid, mr); + exit: return 0; } @@ -236,6 +265,8 @@ gid_to_members_scanner(const struct dirent* d) { char path[NAME_MAX+1]; size_t path_len = NAME_MAX + 1; char* path_str = path; + struct gid_row* gr; + CHK(path_len == 0 || (path_len == 1 && d->d_name[0] == '.') @@ -250,27 +281,28 @@ gid_to_members_scanner(const struct dirent* d) { 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. + /* We might have already allocated a gid_row 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; - } + bool find_gid(struct gid_row* iter) { + if (iter->gid == gid) { g_cur_gid = iter; return 0; } else return 1; } + slist_search(struct gid_row, list, g_gids, found, not_found, &find_gid); - /* 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; - } +not_found: + LET(gr = calloc(1, sizeof(struct gid_row)), !gr, + "Unable to allocate new gid_row node.", exit); + gid_row_init(gr); + gr->gid = gid; + + LET(gr->members = calloc(1, sizeof(struct member_row)), !gr->members, + "Unable to allocate new gid_row->members node.", exit); + member_row_init(gr->members); + + slist_extend(&g_gids->list, &gr->list); + g_cur_gid = gr; - /* g_gid now points to an appropriate gid_list for us to fill in. */ +found: + /* g_cur_gid now points to an appropriate gid_row for us to fill in. */ CHK(scandir(path, &ents, members_scanner, versionsort) == -1, "Unable to scan members dir from $RAINBOW_SPOOL/gid_to_members/$GID.", exit); exit: @@ -279,31 +311,29 @@ exit: enum nss_status _nss_rainbow_setgrent(void) { struct dirent** ents; - INIT_LIST_HEAD(&g_gids.list); - INIT_LIST_HEAD(&g_gids.members.list); - g_gid = &g_gids; + LET(g_gids = calloc(1, sizeof(struct gid_row)), !g_gids, + "Unable to allocate new g_gids node.", out_error); + gid_row_init(g_gids); CHK(scandir(SPOOL "/gid_to_members", &ents, gid_to_members_scanner, versionsort) == -1, "Unable to extract gid->members dirs from $RAINBOW_SPOOL.", out_error); - g_gid = list_entry(g_gids.list.next, struct gid_list, list); + + g_cur_gid = container_of(g_gids->list.next, struct gid_row, list); return NSS_STATUS_SUCCESS; out_error: return NSS_STATUS_UNAVAIL; } enum nss_status _nss_rainbow_endgrent(void) { - struct gid_list* gid_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->members.list))) { - member_iter = list_entry(gid_iter->members.list.next, struct member_list, list); - list_del(&(member_iter->list)); + void free_gid(struct gid_row* gid_iter) { + void free_member(struct member_row* member_iter) { free(member_iter->name); free(member_iter); } - list_del(&(gid_iter->list)); + slist_for(struct member_row, list, gid_iter->members, &free_member); free(gid_iter); } + slist_for(struct gid_row, list, g_gids, &free_gid); + return NSS_STATUS_SUCCESS; } /* @@ -315,9 +345,19 @@ struct group char **gr_mem; }; */ +int fill_member(struct member_row* member_iter, struct group* result, char** buf, size_t* buflen, size_t* member_count) { + result->gr_mem[*member_count] = *buf; + CHK(format_buf(buf, buflen, "%s", member_iter->name) == 1, + "Unable to write a group member.", out_error); + *member_count += 1; + + return 0; +out_error: + return 1; +} int -fill_group(struct group* result, char* buf, size_t buflen, struct gid_list* gid_iter) { +fill_group(struct group* result, char* buf, size_t buflen, struct gid_row* gid_iter) { result->gr_gid = gid_iter->gid; result->gr_name = result->gr_passwd = buf; @@ -325,12 +365,9 @@ fill_group(struct group* result, char* buf, size_t buflen, struct gid_list* gid_ "Unable to calculate group name.", out_error); /* count the number of members */ - struct member_list* member_iter; - struct list_head* member_node_iter; size_t member_count = 0; - list_for_each(member_node_iter, &(gid_iter->members.list)) { - member_count++; - } + void count_member(struct member_row* iter) { member_count++; } + slist_for(struct member_row, list, gid_iter->members, &count_member); /* reserve space for the member-pointers */ size_t member_size = (member_count+1)* sizeof(char*); @@ -343,12 +380,8 @@ fill_group(struct group* result, char* buf, size_t buflen, struct gid_list* gid_ /* fill in the members and swing the pointers */ member_count = 0; - list_for_each_entry(member_iter, &(gid_iter->members.list), list) { - result->gr_mem[member_count] = buf; - CHK(format_buf(&buf, &buflen, "%s", member_iter->name) == 1, - "Unable to write a group member.", out_error); - member_count++; - } + slist_while(struct member_row, list, gid_iter->members, out_error, + &fill_member, result, &buf, &buflen, &member_count); return 0; @@ -358,12 +391,12 @@ out_error: enum nss_status _nss_rainbow_getgrent_r(struct group *result, char *buf, size_t buflen, int *errnop) { - if (&g_gid->list == &g_gids.list) + if (&g_cur_gid->list == &g_gids->list) return NSS_STATUS_NOTFOUND; - CHK(fill_group(result, buf, buflen, g_gid) == 1, + CHK(fill_group(result, buf, buflen, g_cur_gid) == 1, "Unable to fill in group struct.", out_error_errno); - g_gid = list_entry(g_gid->list.next, struct gid_list, list); + g_cur_gid = container_of(g_cur_gid->list.next, struct gid_row, list); return NSS_STATUS_SUCCESS; @@ -372,15 +405,6 @@ out_error_errno: return NSS_STATUS_TRYAGAIN; } -int check_gid_in_range(gid_t gid) -{ - TST(gid < 10000 || gid > 60000, errno = ENOENT, - "Gid outside [10000, 60000].", out_error); - return 0; -out_error: - return 1; -} - enum nss_status _nss_rainbow_getgrgid_r(gid_t gid, struct group *result, char *buf, size_t buflen, int *errnop) { /* Getting errno and the return code exactly right is a pain. @@ -402,12 +426,16 @@ _nss_rainbow_getgrgid_r(gid_t gid, struct group *result, char *buf, size_t bufle "Gid outside [10000, 60000].", out_error); /* look up group data */ - struct gid_list* gid_iter = NULL; - list_for_each_entry(gid_iter, &g_gids.list, list) { - if (gid_iter->gid == gid) break; + struct gid_row* gid_iter = NULL; + bool find_gid(struct gid_row* iter, struct gid_row** result) { + if (iter->gid == gid) { *result = iter; return 0; } else return 1; } - TST(&gid_iter->list == &g_gids.list, ret = NSS_STATUS_NOTFOUND, + slist_search(struct gid_row, list, g_gids, resume, resume, + &find_gid, &gid_iter); +resume: + + TST(&gid_iter->list == NULL, ret = NSS_STATUS_NOTFOUND, "Gid not found.", out_dealloc); CHK(fill_group(result, buf, buflen, gid_iter) == 1, |