id: fix "id <user>" case. Requires getgrouplist().
authorDenis Vlasenko <vda.linux@googlemail.com>
Thu, 18 Sep 2008 00:56:24 +0000 (00:56 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Thu, 18 Sep 2008 00:56:24 +0000 (00:56 -0000)
function                                             old     new   delta
getgrouplist_internal                                  -     200    +200
id_main                                              462     539     +77
bb_internal_getgrouplist                               -      67     +67
bb__parsespent                                       119     117      -2
bb_internal_initgroups                               213      58    -155
------------------------------------------------------------------------------
(add/remove: 2/0 grow/shrink: 1/2 up/down: 344/-157)          Total: 187 bytes

coreutils/id.c
libpwdgrp/pwd_grp.c

index 5225f35..aa27ed3 100644 (file)
@@ -38,14 +38,25 @@ static int printf_full(unsigned id, const char *arg, const char *prefix)
        return status;
 }
 
+#if (defined(__GLIBC__) && !defined(__UCLIBC__))
+#define HAVE_getgrouplist 1
+#elif ENABLE_USE_BB_PWD_GRP
+#define HAVE_getgrouplist 1
+#else
+#define HAVE_getgrouplist 0
+#endif
+
 int id_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int id_main(int argc UNUSED_PARAM, char **argv)
 {
+       const char *username;
        struct passwd *p;
        uid_t uid;
        gid_t gid;
+#if HAVE_getgrouplist
        gid_t *groups;
        int n;
+#endif
        unsigned flags;
        short status;
 #if ENABLE_SELINUX
@@ -55,6 +66,7 @@ int id_main(int argc UNUSED_PARAM, char **argv)
        /* Don't allow more than one username */
        opt_complementary = "?1:u--g:g--u:G--u:u--G:g--G:G--g:r?ugG:n?ugG" USE_SELINUX(":u--Z:Z--u:g--Z:Z--g");
        flags = getopt32(argv, "rnugG" USE_SELINUX("Z"));
+       username = argv[optind];
 
        /* This values could be overwritten later */
        uid = geteuid();
@@ -64,19 +76,34 @@ int id_main(int argc UNUSED_PARAM, char **argv)
                gid = getgid();
        }
 
-       if (argv[optind]) {
-               p = getpwnam(argv[optind]);
+       if (username) {
+#if HAVE_getgrouplist
+               int m;
+#endif
+               p = getpwnam(username);
                /* xuname2uid is needed because it exits on failure */
-               uid = xuname2uid(argv[optind]);
-               gid = p->pw_gid;
-               /* in this case PRINT_REAL is the same */
+               uid = xuname2uid(username);
+               gid = p->pw_gid; /* in this case PRINT_REAL is the same */
+
+#if HAVE_getgrouplist
+               n = 16;
+               groups = NULL;
+               do {
+                       m = n;
+                       groups = xrealloc(groups, sizeof(groups[0]) * m);
+                       getgrouplist(username, gid, groups, &n); /* GNUism? */
+               } while (n > m);
+#endif
+       } else {
+#if HAVE_getgrouplist
+               n = getgroups(0, NULL);
+               groups = xmalloc(sizeof(groups[0]) * n);
+               getgroups(n, groups);
+#endif
        }
 
-       n = getgroups(0, NULL);
-       groups = xmalloc(sizeof(groups[0]) * n);
-       getgroups(n, groups);
-
        if (flags & JUST_ALL_GROUPS) {
+#if HAVE_getgrouplist
                while (n--) {
                        if (flags & NAME_NOT_NUMBER)
                                printf("%s", bb_getgrgid(NULL, 0, *groups++));
@@ -84,6 +111,7 @@ int id_main(int argc UNUSED_PARAM, char **argv)
                                printf("%u", (unsigned) *groups++);
                        bb_putchar((n > 0) ? ' ' : '\n');
                }
+#endif
                /* exit */
                fflush_stdout_and_exit(EXIT_SUCCESS);
        }
@@ -105,7 +133,7 @@ int id_main(int argc UNUSED_PARAM, char **argv)
 #if ENABLE_SELINUX
                if (flags & JUST_CONTEXT) {
                        selinux_or_die();
-                       if (argv[optind]) {
+                       if (username) {
                                bb_error_msg_and_die("user name can't be passed with -Z");
                        }
 
@@ -123,6 +151,7 @@ int id_main(int argc UNUSED_PARAM, char **argv)
        /* bb_getpwuid(0) doesn't exit on failure (returns NULL) */
        status = printf_full(uid, bb_getpwuid(NULL, 0, uid), "uid=");
        status |= printf_full(gid, bb_getgrgid(NULL, 0, gid), " gid=");
+#if HAVE_getgrouplist
        {
                const char *msg = " groups=";
                while (n--) {
@@ -132,6 +161,7 @@ int id_main(int argc UNUSED_PARAM, char **argv)
                }
        }
        /* we leak groups vector... */
+#endif
 
 #if ENABLE_SELINUX
        if (is_selinux_enabled()) {
index 2065190..98b8367 100644 (file)
@@ -620,43 +620,67 @@ struct spwd *sgetspent(const char *string)
 }
 #endif
 
-int initgroups(const char *user, gid_t gid)
+static gid_t *getgrouplist_internal(int *ngroups_ptr, const char *user, gid_t gid)
 {
        FILE *grfile;
        gid_t *group_list;
-       int num_groups, rv;
-       char **m;
+       int ngroups;
        struct group group;
        char buff[PWD_BUFFER_SIZE];
 
-       rv = -1;
-       grfile = fopen_for_read(_PATH_GROUP);
-       if (grfile != NULL) {
-
-               /* We alloc space for 8 gids at a time. */
-               group_list = xmalloc(8 * sizeof(gid_t *));
-               *group_list = gid;
-               num_groups = 1;
+       /* We alloc space for 8 gids at a time. */
+       group_list = xmalloc(8 * sizeof(group_list[0]));
+       group_list[0] = gid;
+       ngroups = 1;
 
+       grfile = fopen_for_read(_PATH_GROUP);
+       if (grfile) {
                while (!bb__pgsreader(bb__parsegrent, &group, buff, sizeof(buff), grfile)) {
+                       char **m;
                        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)) {
-                                               group_list = xrealloc_vector(group_list, 3, num_groups);
-                                               group_list[num_groups++] = group.gr_gid;
-                                               break;
-                                       }
-                               }
+                       if (group.gr_gid == gid)
+                               continue;
+                       for (m = group.gr_mem; *m; m++) {
+                               if (strcmp(*m, user) != 0)
+                                       continue;
+                               group_list = xrealloc_vector(group_list, 3, ngroups);
+                               group_list[ngroups++] = group.gr_gid;
+                               break;
                        }
                }
-
-               rv = setgroups(num_groups, group_list);
-               free(group_list);
                fclose(grfile);
        }
+       *ngroups_ptr = ngroups;
+       return group_list;
+}
 
-       return rv;
+int initgroups(const char *user, gid_t gid)
+{
+       int ngroups;
+       gid_t *group_list = getgrouplist_internal(&ngroups, user, gid);
+
+       if (!group_list)
+               return -1;
+
+       ngroups = setgroups(ngroups, group_list);
+       free(group_list);
+       return ngroups;
+}
+
+/* TODO: uclibc needs this ported to it! */
+int getgrouplist(const char *user, gid_t gid, gid_t *groups, int *ngroups)
+{
+       int ngroups_old = *ngroups;
+       gid_t *group_list = getgrouplist_internal(ngroups, user, gid);
+
+       if (*ngroups <= ngroups_old) {
+               ngroups_old = *ngroups;
+               memcpy(groups, group_list, ngroups_old * sizeof(groups[0]));
+       } else {
+               ngroups_old = -1;
+       }
+       free(group_list);
+       return ngroups_old;
 }
 
 int putpwent(const struct passwd *__restrict p, FILE *__restrict f)