From 2228426512eabc05767b5abac69770e3ae9cd9bb Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Thu, 18 Sep 2008 00:56:24 +0000 Subject: [PATCH] id: fix "id " case. Requires getgrouplist(). 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 | 50 +++++++++++++++++++++++++------- libpwdgrp/pwd_grp.c | 70 ++++++++++++++++++++++++++++++--------------- 2 files changed, 87 insertions(+), 33 deletions(-) diff --git a/coreutils/id.c b/coreutils/id.c index 5225f357c..aa27ed394 100644 --- a/coreutils/id.c +++ b/coreutils/id.c @@ -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()) { diff --git a/libpwdgrp/pwd_grp.c b/libpwdgrp/pwd_grp.c index 206519084..98b8367ca 100644 --- a/libpwdgrp/pwd_grp.c +++ b/libpwdgrp/pwd_grp.c @@ -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; + /* 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 != NULL) { - - /* We alloc space for 8 gids at a time. */ - group_list = xmalloc(8 * sizeof(gid_t *)); - *group_list = gid; - num_groups = 1; - + 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)