summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-09-27 23:36:50 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-09-27 23:36:50 +0000
commit9385a9419d98aeb56fe54b7452d1310ef20cea95 (patch)
treedef3722fbdf6faaf869666fb881dc5afb8fd0e10
parent615aed08180943965201c658435e94134eea6f93 (diff)
implement getgrouplist()
-rw-r--r--include/grp.h13
-rw-r--r--libc/pwd_grp/pwd_grp.c129
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;
}