OSDN Git Service

implement getgrouplist()
authorDenis Vlasenko <vda.linux@googlemail.com>
Sat, 27 Sep 2008 23:36:50 +0000 (23:36 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Sat, 27 Sep 2008 23:36:50 +0000 (23:36 -0000)
include/grp.h
libc/pwd_grp/pwd_grp.c

index 6ad8be1..fa381d2 100644 (file)
@@ -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.
index 217ed39..5af1f0c 100644 (file)
@@ -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;
 }