summaryrefslogtreecommitdiff
path: root/libc/pwd_grp/pwd_grp.c
diff options
context:
space:
mode:
Diffstat (limited to 'libc/pwd_grp/pwd_grp.c')
-rw-r--r--libc/pwd_grp/pwd_grp.c129
1 files changed, 87 insertions, 42 deletions
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;
}