diff options
-rw-r--r-- | lib/libc/gen/getpwent.c | 108 |
1 files changed, 72 insertions, 36 deletions
diff --git a/lib/libc/gen/getpwent.c b/lib/libc/gen/getpwent.c index 452aa21..af93478 100644 --- a/lib/libc/gen/getpwent.c +++ b/lib/libc/gen/getpwent.c @@ -288,18 +288,23 @@ __hashpw(key) #ifdef YP /* - * Build special +@netgroup and -@netgroup caches. We handle ordinary - * +user/-user translations too, since there's no other way to have it - * work right in all situations. The +user/-user stuff is somewhat - * non-standard -- I don't think any other OSes use it -- but handling - * it here is simple, so why not. This also lets us have just one + * Build special +@netgroup and -@netgroup caches. We also handle ordinary + * +user/-user entries, *and* +@group/-@group entries, which are special + * cases of the +@netgroup/-@netgroup substitutions: if we can't find + * netgroup 'foo', we look for a regular user group called 'foo' and + * match against that instead. The netgroup takes precedence since the + * +group/-group support is basically just a hack to make Justin T. Gibbs + * happy. :) Sorting out all the funny business here lets us have a * yp_enabled flag with a simple on or off value instead of the somewhat * bogus setup we had before. + * * We cache everything here in one shot so that we only have to scan - * each netgroup once. The alternative is to use innetgr() inside the + * each netgroup/group once. The alternative is to use innetgr() inside the * NIS lookup functions, which would make retrieving the whole password - * database though getpwent() very slow. + * database though getpwent() very slow. +user/-user entries are treated + * like @groups/@netgroups with only one member. */ +#include <grp.h> static void _createcaches() { @@ -310,6 +315,7 @@ _createcaches() struct _pw_cache *p, *m; struct _namelist *n, *namehead; char *user, *host, *domain; + struct group *grp; /* * Assume that the database has already been initialized @@ -319,7 +325,7 @@ _createcaches() if (!_yp_enabled) return; /* - * For the plus lists, we have to store both the linked list of + * For the plus list, we have to store both the linked list of * names and the +entries from the password database so we can * do the substitution later if we find a match. */ @@ -334,15 +340,36 @@ _createcaches() key.size = (sizeof(i)) + 1; if (__hashpw(&key)) { p = (struct _pw_cache *)malloc(sizeof (struct _pw_cache)); - if (_pw_passwd.pw_name[1]) + if (strlen(_pw_passwd.pw_name) > 2 && _pw_passwd.pw_name[1] == '@') { setnetgrent(_pw_passwd.pw_name+2); - namehead = NULL; - while(getnetgrent(&host, &user, &domain)) { - n = (struct _namelist *)malloc(sizeof (struct _namelist)); - n->name = strdup(user); - n->next = namehead; - namehead = n; + namehead = NULL; + while(getnetgrent(&host, &user, &domain)) { + n = (struct _namelist *)malloc(sizeof (struct _namelist)); + n->name = strdup(user); + n->next = namehead; + namehead = n; + } + /* + * If netgroup 'foo' doesn't exist, + * try group 'foo' instead. + */ + if (namehead == NULL && (grp = getgrnam(_pw_passwd.pw_name+2)) != NULL) { + while(*grp->gr_mem) { + n = (struct _namelist *)malloc(sizeof (struct _namelist)); + n->name = strdup(*grp->gr_mem); + n->next = namehead; + namehead = n; + grp->gr_mem++; + } + } + } else { + if (_pw_passwd.pw_name[1] != '@') { + namehead = (struct _namelist *)malloc(sizeof (struct _namelist)); + namehead->name = strdup(_pw_passwd.pw_name+1); + namehead->next = NULL; + } } + p->namelist = namehead; p->pw_entry.pw_name = strdup(_pw_passwd.pw_name); p->pw_entry.pw_passwd = strdup(_pw_passwd.pw_passwd); p->pw_entry.pw_uid = _pw_passwd.pw_uid; @@ -354,12 +381,6 @@ _createcaches() p->pw_entry.pw_dir = strdup(_pw_passwd.pw_dir); p->pw_entry.pw_shell = strdup(_pw_passwd.pw_shell); p->pw_entry.pw_fields = _pw_passwd.pw_fields; - if (_pw_passwd.pw_name[1] != '@') { - p->namelist = (struct _namelist *)malloc(sizeof (struct _namelist)); - p->namelist->name = strdup(_pw_passwd.pw_name+1); - p->namelist->next = NULL; - } else - p->namelist = namehead; p->next = _plushead; _plushead = p; } @@ -367,8 +388,8 @@ _createcaches() } /* - * All we need for the minuslist are the usernames. - * The actual -entries can be ignored since no substitution + * All we need for the minuslist is the usernames. + * The actual -entries data can be ignored since no substitution * will be done: anybody on the minus list is treated like a * non-person. */ @@ -383,21 +404,36 @@ _createcaches() key.size = (sizeof(i)) + 1; if (__hashpw(&key)) { m = (struct _pw_cache *)malloc(sizeof (struct _pw_cache)); - if (_pw_passwd.pw_name[1]) + if (strlen (_pw_passwd.pw_name) > 2 && _pw_passwd.pw_name[1] == '@') { + namehead = NULL; setnetgrent(_pw_passwd.pw_name+2); - namehead = NULL; - while(getnetgrent(&host, &user, &domain)) { - n = (struct _namelist *)malloc(sizeof (struct _namelist)); - n->name = strdup(user); - n->next = namehead; - namehead = n; + while(getnetgrent(&host, &user, &domain)) { + n = (struct _namelist *)malloc(sizeof (struct _namelist)); + n->name = strdup(user); + n->next = namehead; + namehead = n; + } + /* + * If netgroup 'foo' doesn't exist, + * try group 'foo' instead. + */ + if (namehead == NULL && (grp = getgrnam(_pw_passwd.pw_name+2)) != NULL) { + while(*grp->gr_mem) { + n = (struct _namelist *)malloc(sizeof (struct _namelist)); + n->name = strdup(*grp->gr_mem); + n->next = namehead; + namehead = n; + grp->gr_mem++; + } + } + } else { + if (_pw_passwd.pw_name[1] != '@') { + namehead = (struct _namelist *)malloc(sizeof (struct _namelist)); + namehead->name = strdup(_pw_passwd.pw_name+1); + namehead->next = NULL; + } } - if (_pw_passwd.pw_name[1] != '@') { - m->namelist = (struct _namelist *)malloc(sizeof (struct _namelist)); - m->namelist->name = strdup(_pw_passwd.pw_name+1); - m->namelist->next = NULL; - } else - m->namelist = namehead; + m->namelist = namehead; m->next = _minushead; _minushead = m; } |