diff options
Diffstat (limited to 'Src')
-rw-r--r-- | Src/Modules/parameter.c | 139 | ||||
-rw-r--r-- | Src/zsh.h | 17 |
2 files changed, 155 insertions, 1 deletions
diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c index 793249f32..092efa0c3 100644 --- a/Src/Modules/parameter.c +++ b/Src/Modules/parameter.c @@ -1820,6 +1820,141 @@ scanpmdissaliases(HashTable ht, ScanFunc func, int flags) scanaliases(sufaliastab, ht, func, flags, ALIAS_SUFFIX|DISABLED); } + +/* Functions for the usergroups special parameter */ + +/* + * Get GID and names for groups of which the current user is a member. + */ + +/**/ +static Groupset get_all_groups(void) +{ + Groupset gs = zhalloc(sizeof(*gs)); + Groupmap gaptr; + gid_t *list, *lptr, egid; + int add_egid; + struct group *grptr; + + egid = getegid(); + add_egid = 1; + gs->num = getgroups(0, NULL); + if (gs->num > 0) { + list = zhalloc(gs->num * sizeof(*list)); + if (getgroups(gs->num, list) < 0) { + return NULL; + } + + /* + * It's unspecified whether $EGID is included in the + * group set, so check. + */ + for (lptr = list; lptr < list + gs->num; lptr++) { + if (*lptr == egid) { + add_egid = 0; + break; + } + } + gs->array = zhalloc((gs->num + add_egid) * sizeof(*gs->array)); + /* Put EGID if needed first */ + gaptr = gs->array + add_egid; + for (lptr = list; lptr < list + gs->num; lptr++) { + gaptr->gid = *lptr; + gaptr++; + } + gs->num += add_egid; + } else { + /* Just use effective GID */ + gs->num = 1; + gs->array = zhalloc(sizeof(*gs->array)); + } + if (add_egid) { + gs->array->gid = egid; + } + + /* Get group names */ + for (gaptr = gs->array; gaptr < gs->array + gs->num; gaptr++) { + grptr = getgrgid(gaptr->gid); + if (!grptr) { + return NULL; + } + gaptr->name = dupstring(grptr->gr_name); + } + + return gs; +} + +/* Standard hash element lookup. */ + +/**/ +static HashNode +getpmusergroups(UNUSED(HashTable ht), const char *name) +{ + Param pm = NULL; + Groupset gs = get_all_groups(); + Groupmap gaptr; + + pm = (Param)hcalloc(sizeof(struct param)); + pm->node.nam = dupstring(name); + pm->node.flags = PM_SCALAR | PM_READONLY; + pm->gsu.s = &nullsetscalar_gsu; + + if (!gs) { + zerr("failed to retrieve groups for user: %e", errno); + pm->u.str = dupstring(""); + pm->node.flags |= PM_UNSET; + return &pm->node; + } + + for (gaptr = gs->array; gaptr < gs->array + gs->num; gaptr++) { + if (!strcmp(name, gaptr->name)) { + char buf[DIGBUFSIZE]; + + sprintf(buf, "%d", (int)gaptr->gid); + pm->u.str = dupstring(buf); + return &pm->node; + } + } + + pm->u.str = dupstring(""); + pm->node.flags |= PM_UNSET; + return &pm->node; +} + +/* Standard hash scan. */ + +/**/ +static void +scanpmusergroups(UNUSED(HashTable ht), ScanFunc func, int flags) +{ + struct param pm; + Groupset gs = get_all_groups(); + Groupmap gaptr; + + if (!gs) { + zerr("failed to retrieve groups for user: %e", errno); + return; + } + + memset((void *)&pm, 0, sizeof(pm)); + pm.node.flags = PM_SCALAR | PM_READONLY; + pm.gsu.s = &nullsetscalar_gsu; + + for (gaptr = gs->array; gaptr < gs->array + gs->num; gaptr++) { + pm.node.nam = gaptr->name; + if (func != scancountparams && + ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) || + !(flags & SCANPM_WANTKEYS))) { + char buf[DIGBUFSIZE]; + + sprintf(buf, "%d", (int)gaptr->gid); + pm.u.str = dupstring(buf); + } + func(&pm.node, flags); + } +} + + /* Table for defined parameters. */ struct pardef { @@ -1926,7 +2061,9 @@ static struct paramdef partab[] = { SPECIALPMDEF("saliases", 0, &pmsaliases_gsu, getpmsalias, scanpmsaliases), SPECIALPMDEF("userdirs", PM_READONLY, - NULL, getpmuserdir, scanpmuserdirs) + NULL, getpmuserdir, scanpmuserdirs), + SPECIALPMDEF("usergroups", PM_READONLY, + NULL, getpmusergroups, scanpmusergroups) }; static struct features module_features = { diff --git a/Src/zsh.h b/Src/zsh.h index 6d8ac0353..51ec937fe 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -1731,6 +1731,23 @@ struct nameddir { #define ND_USERNAME (1<<1) /* nam is actually a username */ #define ND_NOABBREV (1<<2) /* never print as abbrev (PWD or OLDPWD) */ +/* Storage for single group/name mapping */ +typedef struct { + /* Name of group */ + char *name; + /* Group identifier */ + gid_t gid; +} groupmap; +typedef groupmap *Groupmap; + +/* Storage for a set of group/name mappings */ +typedef struct { + /* The set of name to gid mappings */ + Groupmap array; + /* A count of the valid entries in groupmap. */ + int num; +} groupset; +typedef groupset *Groupset; /* flags for controlling printing of hash table nodes */ #define PRINT_NAMEONLY (1<<0) |