diff options
author | wpaul <wpaul@FreeBSD.org> | 1995-03-23 00:59:15 +0000 |
---|---|---|
committer | wpaul <wpaul@FreeBSD.org> | 1995-03-23 00:59:15 +0000 |
commit | 24d962fe5d54b4fd7dbc3c6a16411c0f406193bf (patch) | |
tree | 17fce2bd2e9dbbacf1cc2ce576e71bf216ed2bc8 /lib/libc | |
parent | a8b9de30612526d2cb68b319f1461fd85e98074f (diff) | |
download | FreeBSD-src-24d962fe5d54b4fd7dbc3c6a16411c0f406193bf.zip FreeBSD-src-24d962fe5d54b4fd7dbc3c6a16411c0f406193bf.tar.gz |
Phew! Done at last: getpwent now understands +@netgroup/-@netgroup directives
in addition to the existing NIS substitutions. I may tweak this a bit in
the future, but the important stuff is all here.
Diffstat (limited to 'lib/libc')
-rw-r--r-- | lib/libc/gen/getpwent.c | 221 |
1 files changed, 212 insertions, 9 deletions
diff --git a/lib/libc/gen/getpwent.c b/lib/libc/gen/getpwent.c index c9bbd37..d65b627 100644 --- a/lib/libc/gen/getpwent.c +++ b/lib/libc/gen/getpwent.c @@ -52,7 +52,19 @@ static DB *_pw_db; /* password database */ static int _pw_keynum; /* key counter */ static int _pw_stayopen; /* keep fd's open */ #ifdef YP +struct _namelist { + char *name; + struct _namelist *next; +}; static struct passwd _pw_copy; +struct _pw_cache { + struct passwd pw_entry; + struct _namelist *namelist; + struct _pw_cache *next; +}; +static int pluscnt, minuscnt; +static struct _pw_cache *plushead =NULL, *minushead = NULL; +static void _createcaches(), _freecaches(); static int _yp_enabled; /* set true when yp enabled */ static int _pw_stepping_yp; /* set true when stepping thru map */ #endif @@ -143,10 +155,7 @@ getpwnam(name) */ if (rval && _pw_passwd.pw_name[0] == '+') rval = 0; - if (!_pw_stayopen) { - (void)(_pw_db->close)(_pw_db); - _pw_db = (DB *)NULL; - } + endpwent(); return(rval ? &_pw_passwd : (struct passwd *)NULL); } @@ -179,10 +188,8 @@ getpwuid(uid) rval = _getyppass(&_pw_passwd, ypbuf, "passwd.byuid"); } #endif - if (!_pw_stayopen) { - (void)(_pw_db->close)(_pw_db); - _pw_db = (DB *)NULL; - } + + endpwent(); return(rval ? &_pw_passwd : (struct passwd *)NULL); } @@ -219,6 +226,9 @@ endpwent() if (_pw_db) { (void)(_pw_db->close)(_pw_db); _pw_db = (DB *)NULL; +#ifdef YP + _freecaches(); +#endif } } @@ -246,6 +256,7 @@ __initdb() } else { _yp_enabled = (int)*((char *)data.data) - 2; } + _createcaches(); } #endif return(1); @@ -306,6 +317,137 @@ __hashpw(key) } #ifdef YP +/* + * Build special +@netgroup and -@netgroup caches. We do the + * actual netgroup lookups here so that we don't have to do a + * bunch of innetgr() calls when doing a getpwent(). This lets us + * query the netgroup database only once for each special entry. + * The alternative is to do use innetgr() inside _getyppass() and + * _netyppass(), which would make getpwent() unbearably slow. + */ +static void +_createcaches() +{ + DBT key, data; + int i, len, rval; + char bf[UT_NAMESIZE + 2]; + char entry[UT_NAMESIZE]; + struct _pw_cache *p, *m; + struct _namelist *n, *namehead; + char *user, *host, *domain; + + /* Assume that the database has already been initialized. */ + + /* + * For the plus lists, 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. + */ + bf[0] = _PW_KEYPLUSCNT; + key.data = (u_char*)bf; + key.size = 1; + if (!(_pw_db->get)(_pw_db, &key, &data, 0)) { + pluscnt = (int)*((char *)data.data); + for (i = 0; i < pluscnt; i++) { + bf[0] = _PW_KEYPLUSBYNUM; + bcopy(&i, bf + 1, sizeof(i) + 1); + key.size = (sizeof(i)) + 1; + if ((rval = __hashpw(&key))) { + p = (struct _pw_cache *)malloc(sizeof (struct _pw_cache)); + 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; + } + 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; + p->pw_entry.pw_gid = _pw_passwd.pw_gid; + p->pw_entry.pw_expire = _pw_passwd.pw_expire; + p->pw_entry.pw_change = _pw_passwd.pw_change; + p->pw_entry.pw_class = strdup(_pw_passwd.pw_class); + p->pw_entry.pw_gecos = strdup(_pw_passwd.pw_gecos); + 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; + p->namelist = namehead; + p->next = plushead; + plushead = p; + } + } + } + + /* + * All we need for the minuslist are the usernames. + * The actual -@entries can be ignored since no substitution + * will be done: anybody on the minus list is treated like a + * non-person. + */ + bf[0] = _PW_KEYMINUSCNT; + key.data = (u_char*)bf; + key.size = 1; + if (!(_pw_db->get)(_pw_db, &key, &data, 0)) { + minuscnt = (int)*((char *)data.data); + for (i = 0; i < minuscnt; i++) { + bf[0] = _PW_KEYMINUSBYNUM; + bcopy(&i, bf + 1, sizeof(i) + 1); + key.size = (sizeof(i)) + 1; + if ((rval = __hashpw(&key))) { + m = (struct _pw_cache *)malloc(sizeof (struct _pw_cache)); + 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; + } + m->namelist = namehead; + m->next = minushead; + minushead = m; + } + } + } +} + +/* + * Free the +@netgroup/-@netgroup caches. Should be called + * from endpwent(). We have to blow away both the list of + * netgroups and the attached linked lists of usernames. + */ +static void +_freecaches() +{ +struct _pw_cache *p, *m; +struct _namelist *n; + + while (plushead) { + while(plushead->namelist) { + n = plushead->namelist->next; + free(plushead->namelist); + plushead->namelist = n; + } + p = plushead->next; + free(plushead); + plushead = p; + } + + while(minushead) { + while(minushead->namelist) { + n = minushead->namelist->next; + free(minushead->namelist); + minushead->namelist = n; + } + m = minushead->next; + free(minushead); + minushead = m; + } + pluscnt = minuscnt = 0; +} + static void _pw_breakout_yp(struct passwd *pw, char *result, int master) { @@ -399,6 +541,8 @@ _getyppass(struct passwd *pw, const char *name, const char *map) int resultlen; char mastermap[1024]; int gotmaster = 0; + struct _pw_cache *m, *p; + struct _namelist *n; if(!_pw_yp_domain) { if(yp_get_default_domain(&_pw_yp_domain)) @@ -423,6 +567,35 @@ _getyppass(struct passwd *pw, const char *name, const char *map) if(resultlen >= sizeof resultbuf) return 0; strcpy(resultbuf, result); + s = strsep(&result,":"); + if (minuscnt && minushead) { + m = minushead; + while (m) { + n = m->namelist; + while (n) { + if (!strcmp(n->name, s)) { + free(result); + return (0); + } + n = n->next; + } + m = m->next; + } + } + if (pluscnt && plushead) { + p = plushead; + while (p) { + n = p->namelist; + while (n) { + if (!strcmp(n->name, s)) + bcopy((char *)&p->pw_entry, + (char *)&_pw_passwd, sizeof(p->pw_entry)); + n = n->next; + } + p = p->next; + } + } + free(result); result = resultbuf; _pw_breakout_yp(pw, resultbuf, gotmaster); @@ -432,7 +605,7 @@ _getyppass(struct passwd *pw, const char *name, const char *map) static int _nextyppass(struct passwd *pw) { - static char *key; + static char *key, *s; static int keylen; char *lastkey, *result; static char resultbuf[1024]; @@ -440,6 +613,8 @@ _nextyppass(struct passwd *pw) int rv; char *map = "passwd.byname"; int gotmaster = 0; + struct _pw_cache *m, *p; + struct _namelist *n; if(!_pw_yp_domain) { if(yp_get_default_domain(&_pw_yp_domain)) @@ -480,6 +655,34 @@ unpack: } strcpy(resultbuf, result); + s = strsep(&result,":"); + if (minuscnt && minushead) { + m = minushead; + while (m) { + n = m->namelist; + while (n) { + if (!strcmp(n->name, s)) { + free(result); + goto tryagain; + } + n = n->next; + } + m = m->next; + } + } + if (pluscnt && plushead) { + p = plushead; + while (p) { + n = p->namelist; + while (n) { + if (!strcmp(n->name, s)) + bcopy((char *)&p->pw_entry, + (char*)&_pw_passwd, sizeof(p->pw_entry)); + n = n->next; + } + p = p->next; + } + } free(result); if(result = strchr(resultbuf, '\n')) *result = '\0'; _pw_breakout_yp(pw, resultbuf, gotmaster); |