diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-09-27 23:36:50 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-09-27 23:36:50 +0000 |
commit | 9385a9419d98aeb56fe54b7452d1310ef20cea95 (patch) | |
tree | def3722fbdf6faaf869666fb881dc5afb8fd0e10 | |
parent | 615aed08180943965201c658435e94134eea6f93 (diff) |
implement getgrouplist()
-rw-r--r-- | include/grp.h | 13 | ||||
-rw-r--r-- | libc/pwd_grp/pwd_grp.c | 129 |
2 files changed, 95 insertions, 47 deletions
diff --git a/include/grp.h b/include/grp.h index 6ad8be1dd..fa381d2d0 100644 --- a/include/grp.h +++ b/include/grp.h @@ -169,18 +169,15 @@ extern int fgetgrent_r (FILE *__restrict __stream, #endif /* POSIX or reentrant */ -#ifdef __USE_BSD +#if defined __USE_BSD || defined __USE_GNU # define __need_size_t # include <stddef.h> -/* Set the group set for the current user to GROUPS (N of them). */ -extern int setgroups (size_t __n, __const __gid_t *__groups) __THROW; - -#if 0 /* Store at most *NGROUPS members of the group set for USER into *GROUPS. Also include GROUP. The actual number of groups found is returned in *NGROUPS. Return -1 if the if *NGROUPS is too small. + In all cases the actual number of groups is stored in *NGROUPS. This function is not part of POSIX and therefore no official cancellation point. But due to similarity with an POSIX interface @@ -188,8 +185,14 @@ extern int setgroups (size_t __n, __const __gid_t *__groups) __THROW; therefore not marked with __THROW. */ extern int getgrouplist (__const char *__user, __gid_t __group, __gid_t *__groups, int *__ngroups); + #endif +#if defined __USE_BSD + +/* Set the group set for the current user to GROUPS (N of them). */ +extern int setgroups (size_t __n, __const __gid_t *__groups) __THROW; + /* Initialize the group set for the current user by reading the group database and using all groups of which USER is a member. Also include GROUP. diff --git a/libc/pwd_grp/pwd_grp.c b/libc/pwd_grp/pwd_grp.c index 217ed39a7..5af1f0c15 100644 --- a/libc/pwd_grp/pwd_grp.c +++ b/libc/pwd_grp/pwd_grp.c @@ -64,6 +64,8 @@ extern int __parsespent(void *sp, char *line) attribute_hidden; extern int __pgsreader(int (*__parserfunc)(void *d, char *line), void *data, char *__restrict line_buff, size_t buflen, FILE *f) attribute_hidden; +extern gid_t* __getgrouplist_internal(const char *user, gid_t gid, int *ngroups) attribute_hidden; + /**********************************************************************/ /* For the various fget??ent_r funcs, return * @@ -684,62 +686,105 @@ struct spwd *sgetspent(const char *string) #endif /**********************************************************************/ -#ifdef L_initgroups +#ifdef L___getgrouplist_internal -#ifdef __USE_BSD - -libc_hidden_proto(setgroups) - -int initgroups(const char *user, gid_t gid) +gid_t attribute_hidden *__getgrouplist_internal(const char *user, gid_t gid, int *ngroups) { FILE *grfile; gid_t *group_list; - int num_groups, rv; - char **m; + int num_groups; struct group group; char buff[__UCLIBC_PWD_BUFFER_SIZE__]; - rv = -1; + *ngroups = num_groups = 1; /* We alloc space for 8 gids at a time. */ - if (((group_list = (gid_t *) malloc(8*sizeof(gid_t *))) != NULL) - && ((grfile = fopen(_PATH_GROUP, "r")) != NULL) - ) { - - __STDIO_SET_USER_LOCKING(grfile); - - *group_list = gid; - num_groups = 1; - - while (!__pgsreader(__parsegrent, &group, buff, sizeof(buff), grfile)) { - assert(group.gr_mem); /* Must have at least a NULL terminator. */ - if (group.gr_gid != gid) { - for (m=group.gr_mem ; *m ; m++) { - if (!strcmp(*m, user)) { - if (!(num_groups & 7)) { - gid_t *tmp = (gid_t *) - realloc(group_list, - (num_groups+8) * sizeof(gid_t *)); - if (!tmp) { - rv = -1; - goto DO_CLOSE; - } - group_list = tmp; - } - group_list[num_groups++] = group.gr_gid; - break; - } - } + group_list = malloc(8 * sizeof(group_list[0])); + if (!group_list) + return NULL; + + group_list[0] = gid; + grfile = fopen(_PATH_GROUP, "r"); + /* If /etc/group doesn't exist, we still return 1-element vector */ + if (!grfile) + return group_list; + + __STDIO_SET_USER_LOCKING(grfile); + + while (!__pgsreader(__parsegrent, &group, buff, sizeof(buff), grfile)) { + char **m; + + assert(group.gr_mem); /* Must have at least a NULL terminator. */ + if (group.gr_gid == gid) + continue; + for (m = group.gr_mem; *m; m++) { + if (strcmp(*m, user) != 0) + continue; + if (!(num_groups & 7)) { + gid_t *tmp = realloc(group_list, (num_groups+8) * sizeof(group_list[0])); + if (!tmp) + goto DO_CLOSE; + group_list = tmp; } + group_list[num_groups++] = group.gr_gid; + break; } + } + + DO_CLOSE: + fclose(grfile); + *ngroups = num_groups; + return group_list; +} + +#endif +/**********************************************************************/ +#ifdef L_getgrouplist - rv = setgroups(num_groups, group_list); - DO_CLOSE: - fclose(grfile); +#if defined __USE_BSD || defined __USE_GNU +int getgrouplist(const char *user, gid_t gid, gid_t *groups, int *ngroups) +{ + int sz = *ngroups; + gid_t *group_list = __getgrouplist_internal(user, gid, ngroups); + + if (!group_list) { + /* malloc failure - what shall we do? + * fail with ENOMEM? I bet users never check for that */ + /* *ngroups = 1; - already done by __getgrouplist_internal */ + if (sz) { + groups[0] = gid; + return 1; + } + return -1; } + /* *ngroups is non-zero here */ + + if (sz > *ngroups) + sz = *ngroups; + if (sz) + memcpy(groups, group_list, sz * sizeof(group_list[0])); + free(group_list); + if (sz < *ngroups) + return -1; + return sz; +} +#endif + +#endif +/**********************************************************************/ +#ifdef L_initgroups - /* group_list will be NULL if initial malloc failed, which may trigger - * warnings from various malloc debuggers. */ +#ifdef __USE_BSD +libc_hidden_proto(setgroups) + +int initgroups(const char *user, gid_t gid) +{ + int rv; + int num_groups = ((unsigned)~0) >> 1; /* INT_MAX */ + gid_t *group_list = __getgrouplist_internal(user, gid, &num_groups); + if (!group_list) + return -1; + rv = setgroups(num_groups, group_list); free(group_list); return rv; } |