Home | History | Annotate | Line # | Download | only in gen
getpwent.c revision 1.14.8.1
      1 /*	$NetBSD: getpwent.c,v 1.14.8.1 1996/11/06 00:48:37 lukem Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1988, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  * Portions Copyright (c) 1994, 1995, Jason Downs.  All rights reserved.
      7  * Portions Copyright (c) 1995, 1996
      8  *	Luke Mewburn <lm (at) werj.com.au>. All rights reserved.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *	This product includes software developed by the University of
     21  *	California, Berkeley and its contributors.
     22  * 4. Neither the name of the University nor the names of its contributors
     23  *    may be used to endorse or promote products derived from this software
     24  *    without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     36  * SUCH DAMAGE.
     37  */
     38 
     39 #if defined(LIBC_SCCS) && !defined(lint)
     40 #if 0
     41 static char sccsid[] = "@(#)getpwent.c	8.1 (Berkeley) 6/4/93";
     42 #else
     43 static char rcsid[] = "$NetBSD: getpwent.c,v 1.14.8.1 1996/11/06 00:48:37 lukem Exp $";
     44 #endif
     45 #endif /* LIBC_SCCS and not lint */
     46 
     47 #include <sys/param.h>
     48 #include <fcntl.h>
     49 #include <db.h>
     50 #include <syslog.h>
     51 #include <pwd.h>
     52 #include <utmp.h>
     53 #include <errno.h>
     54 #include <unistd.h>
     55 #include <stdlib.h>
     56 #include <string.h>
     57 #include <limits.h>
     58 #include <netgroup.h>
     59 #include <nsswitch.h>
     60 #ifdef HESIOD
     61 #include <hesiod.h>
     62 #endif
     63 #ifdef YP
     64 #include <machine/param.h>
     65 #include <stdio.h>
     66 #include <rpc/rpc.h>
     67 #include <rpcsvc/yp_prot.h>
     68 #include <rpcsvc/ypclnt.h>
     69 #endif
     70 
     71 static struct passwd _pw_passwd;	/* password structure */
     72 static DB *_pw_db;			/* password database */
     73 static int _pw_keynum;			/* key counter */
     74 static int _pw_stayopen;		/* keep fd's open */
     75 static int _pw_flags;			/* password flags */
     76 
     77 static int __hashpw __P((DBT *));
     78 static int __initdb __P((void));
     79 
     80 const char __yp_token[] = "__YP!";	/* Let pwd_mkdb pull this in. */
     81 
     82 #ifdef YP
     83 static char     *__ypcurrent, *__ypdomain;
     84 static int      __ypcurrentlen;
     85 #endif
     86 
     87 #ifdef HESIOD
     88 static int	 _pw_hesnum;
     89 #endif
     90 
     91 #if defined(YP) || defined(HESIOD)
     92 enum _pwmode { PWMODE_NONE, PWMODE_FULL, PWMODE_USER, PWMODE_NETGRP };
     93 static enum _pwmode	 __pwmode;
     94 
     95 static struct passwd	*__pwproto = (struct passwd *)NULL;
     96 static int		 __pwproto_flags;
     97 static char		 line[1024];
     98 static long		 prbuf[1024 / sizeof(long)];
     99 static DB		*__pwexclude = (DB *)NULL;
    100 
    101 /*
    102  * add a name to the compat mode exclude list
    103  */
    104 static int
    105 __pwexclude_add(name)
    106 	const char *name;
    107 {
    108 	DBT key, data;
    109 
    110 	/* initialize the exclusion table if needed. */
    111 	if(__pwexclude == (DB *)NULL) {
    112 		__pwexclude = dbopen(NULL, O_RDWR, 600, DB_HASH, NULL);
    113 		if(__pwexclude == (DB *)NULL)
    114 			return(1);
    115 	}
    116 
    117 	/* set up the key */
    118 	key.data = (char *)name;
    119 	key.size = strlen(name);
    120 
    121 	/* data is nothing. */
    122 	data.data = NULL;
    123 	data.size = 0;
    124 
    125 	/* store it */
    126 	if((__pwexclude->put)(__pwexclude, &key, &data, 0) == -1)
    127 		return(1);
    128 
    129 	return(0);
    130 }
    131 
    132 /*
    133  * test if a name is in the compat mode exclude list
    134  */
    135 static int
    136 __pwexclude_is(name)
    137 	const char *name;
    138 {
    139 	DBT key, data;
    140 
    141 	if(__pwexclude == (DB *)NULL)
    142 		return(0);	/* nothing excluded */
    143 
    144 	/* set up the key */
    145 	key.data = (char *)name;
    146 	key.size = strlen(name);
    147 
    148 	if((__pwexclude->get)(__pwexclude, &key, &data, 0) == 0)
    149 		return(1);	/* excluded */
    150 
    151 	return(0);
    152 }
    153 
    154 /*
    155  * setup the compat mode prototype template
    156  */
    157 static void
    158 __pwproto_set()
    159 {
    160 	register char *ptr;
    161 	register struct passwd *pw = &_pw_passwd;
    162 
    163 	/* make this the new prototype */
    164 	ptr = (char *)prbuf;
    165 
    166 	/* first allocate the struct. */
    167 	__pwproto = (struct passwd *)ptr;
    168 	ptr += sizeof(struct passwd);
    169 
    170 	/* name */
    171 	if(pw->pw_name && (pw->pw_name)[0]) {
    172 		ptr = (char *)ALIGN(ptr);
    173 		memmove(ptr, pw->pw_name, strlen(pw->pw_name) + 1);
    174 		__pwproto->pw_name = ptr;
    175 		ptr += (strlen(pw->pw_name) + 1);
    176 	} else
    177 		__pwproto->pw_name = (char *)NULL;
    178 
    179 	/* password */
    180 	if(pw->pw_passwd && (pw->pw_passwd)[0]) {
    181 		ptr = (char *)ALIGN(ptr);
    182 		memmove(ptr, pw->pw_passwd, strlen(pw->pw_passwd) + 1);
    183 		__pwproto->pw_passwd = ptr;
    184 		ptr += (strlen(pw->pw_passwd) + 1);
    185 	} else
    186 		__pwproto->pw_passwd = (char *)NULL;
    187 
    188 	/* uid */
    189 	__pwproto->pw_uid = pw->pw_uid;
    190 
    191 	/* gid */
    192 	__pwproto->pw_gid = pw->pw_gid;
    193 
    194 	/* change (ignored anyway) */
    195 	__pwproto->pw_change = pw->pw_change;
    196 
    197 	/* class (ignored anyway) */
    198 	__pwproto->pw_class = "";
    199 
    200 	/* gecos */
    201 	if(pw->pw_gecos && (pw->pw_gecos)[0]) {
    202 		ptr = (char *)ALIGN(ptr);
    203 		memmove(ptr, pw->pw_gecos, strlen(pw->pw_gecos) + 1);
    204 		__pwproto->pw_gecos = ptr;
    205 		ptr += (strlen(pw->pw_gecos) + 1);
    206 	} else
    207 		__pwproto->pw_gecos = (char *)NULL;
    208 
    209 	/* dir */
    210 	if(pw->pw_dir && (pw->pw_dir)[0]) {
    211 		ptr = (char *)ALIGN(ptr);
    212 		memmove(ptr, pw->pw_dir, strlen(pw->pw_dir) + 1);
    213 		__pwproto->pw_dir = ptr;
    214 		ptr += (strlen(pw->pw_dir) + 1);
    215 	} else
    216 		__pwproto->pw_dir = (char *)NULL;
    217 
    218 	/* shell */
    219 	if(pw->pw_shell && (pw->pw_shell)[0]) {
    220 		ptr = (char *)ALIGN(ptr);
    221 		memmove(ptr, pw->pw_shell, strlen(pw->pw_shell) + 1);
    222 		__pwproto->pw_shell = ptr;
    223 		ptr += (strlen(pw->pw_shell) + 1);
    224 	} else
    225 		__pwproto->pw_shell = (char *)NULL;
    226 
    227 	/* expire (ignored anyway) */
    228 	__pwproto->pw_expire = pw->pw_expire;
    229 
    230 	/* flags */
    231 	__pwproto_flags = _pw_flags;
    232 }
    233 
    234 /*
    235  * parse an old-style passwd file line (from NIS or HESIOD)
    236  */
    237 static int
    238 __pwparse(pw, s)
    239 	struct passwd *pw;
    240 	char *s;
    241 {
    242 	char *bp, *cp;
    243 
    244 	/* since this is currently using strsep(), parse it first */
    245 	bp = s;
    246 	pw->pw_name = strsep(&bp, ":\n");
    247 	pw->pw_passwd = strsep(&bp, ":\n");
    248 	if (!(cp = strsep(&bp, ":\n")))
    249 		return 1;
    250 	pw->pw_uid = atoi(cp);
    251 	if (!(cp = strsep(&bp, ":\n")))
    252 		return 1;
    253 	pw->pw_gid = atoi(cp);
    254 	pw->pw_change = 0;
    255 	pw->pw_class = "";
    256 	pw->pw_gecos = strsep(&bp, ":\n");
    257 	pw->pw_dir = strsep(&bp, ":\n");
    258 	pw->pw_shell = strsep(&bp, ":\n");
    259 	pw->pw_expire = 0;
    260 
    261 	/* now let the prototype override, if set. */
    262 	if(__pwproto != (struct passwd *)NULL) {
    263 #ifdef PW_OVERRIDE_PASSWD
    264 		if(__pwproto->pw_passwd != (char *)NULL)
    265 			pw->pw_passwd = __pwproto->pw_passwd;
    266 #endif
    267 		if(!(__pwproto_flags & _PASSWORD_NOUID))
    268 			pw->pw_uid = __pwproto->pw_uid;
    269 		if(!(__pwproto_flags & _PASSWORD_NOGID))
    270 			pw->pw_gid = __pwproto->pw_gid;
    271 		if(__pwproto->pw_gecos != (char *)NULL)
    272 			pw->pw_gecos = __pwproto->pw_gecos;
    273 		if(__pwproto->pw_dir != (char *)NULL)
    274 			pw->pw_dir = __pwproto->pw_dir;
    275 		if(__pwproto->pw_shell != (char *)NULL)
    276 			pw->pw_shell = __pwproto->pw_shell;
    277 	}
    278 	return 0;
    279 }
    280 #endif /* YP || HESIOD */
    281 
    282 /*
    283  * local files implementation of getpw*()
    284  * varargs: type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ]
    285  */
    286 static int
    287 _local_getpw(rv, cb_data, ap)
    288 	void	*rv;
    289 	void	*cb_data;
    290 	va_list	 ap;
    291 {
    292 	DBT key;
    293 	char		 bf[MAX(UT_NAMESIZE, sizeof(_pw_keynum)) + 1];
    294 	int		 search, len, uid, rval;
    295 	const char	*name;
    296 
    297 
    298 	if (!_pw_db && !__initdb())
    299 		return NS_UNAVAIL;
    300 
    301 	search = va_arg(ap, int);
    302 	bf[0] = search;
    303 	switch (search) {
    304 	case _PW_KEYBYNUM:
    305 		++_pw_keynum;
    306 		memmove(bf + 1, (char *)&_pw_keynum, sizeof(_pw_keynum));
    307 		key.size = sizeof(_pw_keynum) + 1;
    308 		break;
    309 	case _PW_KEYBYNAME:
    310 		name = va_arg(ap, const char *);
    311 		len = strlen(name);
    312 		memmove(bf + 1, name, MIN(len, UT_NAMESIZE));
    313 		key.size = len + 1;
    314 		break;
    315 	case _PW_KEYBYUID:
    316 		uid = va_arg(ap, int);
    317 		memmove(bf + 1, (char *)&uid, sizeof(len));
    318 		key.size = sizeof(uid) + 1;
    319 		break;
    320 	default:
    321 		abort();
    322 	}
    323 
    324 	key.data = (u_char *)bf;
    325 	rval = __hashpw(&key);
    326 
    327 	if (!_pw_stayopen && (search != _PW_KEYBYNUM)) {
    328 		(void)(_pw_db->close)(_pw_db);
    329 		_pw_db = (DB *)NULL;
    330 	}
    331 	return (rval);
    332 } /* _local_getpw */
    333 
    334 #ifdef HESIOD
    335 /*
    336  * hesiod implementation of getpw*()
    337  * varargs: type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ]
    338  */
    339 static int
    340 _dns_getpw(rv, cb_data, ap)
    341 	void	*rv;
    342 	void	*cb_data;
    343 	va_list	 ap;
    344 {
    345 	const char	 *name;
    346 	int		  uid, search;
    347 	char		**hp;
    348 
    349 
    350 	search = va_arg(ap, int);
    351 	switch (search) {
    352 	case _PW_KEYBYNUM:
    353 		snprintf(line, sizeof(line) - 1, "passwd-%d", _pw_hesnum);
    354 		_pw_hesnum++;
    355 		break;
    356 	case _PW_KEYBYNAME:
    357 		name = va_arg(ap, const char *);
    358 		strncpy(line, name, sizeof(line));
    359 		break;
    360 	case _PW_KEYBYUID:
    361 		uid = va_arg(ap, int);
    362 		sprintf(line, "%d", uid);
    363 		break;
    364 	default:
    365 		abort();
    366 	}
    367 	line[sizeof(line) - 1] = '\0';
    368 
    369 	hp = hes_resolve(line, "passwd");
    370 	if (hp == NULL) {
    371 		switch (hes_error()) {
    372 		case HES_ER_NOTFOUND:
    373 			if (search == _PW_KEYBYNUM)
    374 				_pw_hesnum = 0;
    375 			return NS_NOTFOUND;
    376 		case HES_ER_OK:
    377 			abort();
    378 		default:
    379 			return NS_UNAVAIL;
    380 		}
    381 	}
    382 
    383 	strncpy(line, hp[0], sizeof(line));	/* only check first elem */
    384 	line[sizeof(line) - 1] = '\0';
    385 	hes_free(hp);
    386 	if (__pwparse(&_pw_passwd, line))
    387 		return NS_UNAVAIL;
    388 	return NS_SUCCESS;
    389 } /* _dns_getpw */
    390 #endif
    391 
    392 #ifdef YP
    393 /*
    394  * nis implementation of getpw*()
    395  * varargs: type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ]
    396  */
    397 static int
    398 _nis_getpw(rv, cb_data, ap)
    399 	void	*rv;
    400 	void	*cb_data;
    401 	va_list	 ap;
    402 {
    403 	const char	*name;
    404 	int		 uid, search;
    405 	char		*key, *data;
    406 	char		*map = "passwd.byname";
    407 	int		 keylen, datalen, r;
    408 
    409 	if(__ypdomain == NULL) {
    410 		if(_yp_check(&__ypdomain) == 0)
    411 			return NS_UNAVAIL;
    412 	}
    413 
    414 	search = va_arg(ap, int);
    415 	switch (search) {
    416 	case _PW_KEYBYNUM:
    417 		break;
    418 	case _PW_KEYBYNAME:
    419 		name = va_arg(ap, const char *);
    420 		strncpy(line, name, sizeof(line));
    421 		break;
    422 	case _PW_KEYBYUID:
    423 		uid = va_arg(ap, int);
    424 		sprintf(line, "%d", uid);
    425 		map = "passwd.byuid";
    426 		break;
    427 	default:
    428 		abort();
    429 			}
    430 	line[sizeof(line) - 1] = '\0';
    431 	if (search != _PW_KEYBYNUM) {
    432 		r = yp_match(__ypdomain, map, line, strlen(line),
    433 				&data, &datalen);
    434 		switch (r) {
    435 		case 0:
    436 			break;
    437 		case YPERR_KEY:
    438 			free(data);
    439 			return NS_NOTFOUND;
    440 		default:
    441 			free(data);
    442 			return NS_UNAVAIL;
    443 		}
    444 		data[datalen] = '\0';		/* clear trailing \n */
    445 		strncpy(line, data, sizeof(line));
    446 		line[sizeof(line) - 1] = '\0';
    447 		free(data);
    448 		if (__pwparse(&_pw_passwd, line))
    449 			return NS_UNAVAIL;
    450 		return NS_SUCCESS;
    451 		}
    452 
    453 	for (;;) {
    454 		if (__ypcurrent) {
    455 			r = yp_next(__ypdomain, map,
    456 					__ypcurrent, __ypcurrentlen,
    457 					&key, &keylen, &data, &datalen);
    458 				free(__ypcurrent);
    459 			switch (r) {
    460 			case 0:
    461 				break;
    462 			case YPERR_NOMORE:
    463 				__ypcurrent = NULL;
    464 				free(data);
    465 				return NS_NOTFOUND;
    466 			default:
    467 				free(data);
    468 				return NS_UNAVAIL;
    469 				}
    470 				__ypcurrent = key;
    471 				__ypcurrentlen = keylen;
    472 			} else {
    473 			if (yp_first(__ypdomain, map, &__ypcurrent,
    474 					&__ypcurrentlen, &data, &datalen)) {
    475 						free(data);
    476 				return NS_UNAVAIL;
    477 			}
    478 				}
    479 		data[datalen] = '\0';		/* clear trailing \n */
    480 		strncpy(line, data, sizeof(line));
    481 		line[sizeof(line) - 1] = '\0';
    482 				free(data);
    483 		if (! __pwparse(&_pw_passwd, line))
    484 			return NS_SUCCESS;
    485 			}
    486 	/* NOTREACHED */
    487 } /* _nis_getpw */
    488 #endif
    489 
    490 #if defined(YP) || defined(HESIOD)
    491 /*
    492  * See if the compat token is in the database.  Only works if pwd_mkdb knows
    493  * about the token.
    494  */
    495 static int
    496 __has_compatpw()
    497 {
    498 	DBT key, data;
    499 	DBT pkey, pdata;
    500 	int len;
    501 	char bf[UT_NAMESIZE];
    502 
    503 	key.data = (u_char *)__yp_token;
    504 	key.size = strlen(__yp_token);
    505 
    506 	/* Pre-token database support. */
    507 	bf[0] = _PW_KEYBYNAME;
    508 	len = strlen("+");
    509 	bcopy("+", bf + 1, MIN(len, UT_NAMESIZE));
    510 	pkey.data = (u_char *)bf;
    511 	pkey.size = len + 1;
    512 
    513 	if ((_pw_db->get)(_pw_db, &key, &data, 0)
    514 	    && (_pw_db->get)(_pw_db, &pkey, &pdata, 0))
    515 		return(0);		/* No compat token */
    516 	return(1);
    517 }
    518 
    519 /*
    520  * log an error if "files" or "compat" is specified in passwd_compat database
    521  */
    522 static int
    523 _bad_getpw(rv, cb_data, ap)
    524 	void	*rv;
    525 	void	*cb_data;
    526 	va_list	 ap;
    527 {
    528 	static int warned;
    529 	if (!warned) {
    530 		syslog(LOG_ERR,
    531 			"nsswitch.conf passwd_compat database can't use '%s'",
    532 			(char *)cb_data);
    533 	}
    534 	warned = 1;
    535 	return NS_UNAVAIL;
    536 }
    537 
    538 /*
    539  * when a name lookup in compat mode is required (e.g., '+name', or a name in
    540  * '+@netgroup'), look it up in the 'passwd_compat' nsswitch database.
    541  * only Hesiod and NIS is supported - it doesn't make sense to lookup
    542  * compat names from 'files' or 'compat'.
    543  */
    544 static int
    545 __getpwcompat(type, uid, name)
    546 	int		 type;
    547 	int		 uid;
    548 	const char	*name;
    549 {
    550 	static ns_dtab	dtab;
    551 
    552 	NS_FILES_CB(dtab, _bad_getpw, "files");
    553 	NS_DNS_CB(dtab, _dns_getpw, NULL);
    554 	NS_NIS_CB(dtab, _nis_getpw, NULL);
    555 	NS_COMPAT_CB(dtab, _bad_getpw, "compat");
    556 
    557 	switch (type) {
    558 	case _PW_KEYBYNUM:
    559 		return nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, type);
    560 	case _PW_KEYBYNAME:
    561 		return nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, type, name);
    562 	case _PW_KEYBYUID:
    563 		return nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, type, uid);
    564 	default:
    565 		abort();
    566 	}
    567 }
    568 
    569 /*
    570  * compat implementation of getpwent()
    571  * varargs: type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ]
    572  */
    573 static int
    574 _compat_getpwent(rv, cb_data, ap)
    575 	void	*rv;
    576 	void	*cb_data;
    577 	va_list	 ap;
    578 {
    579 	DBT		 key;
    580 	char		 bf[sizeof(_pw_keynum) + 1];
    581 	static char	*name = (char *)NULL;
    582 	const char	*user, *host, *dom;
    583 	int		 has_compatpw;
    584 
    585 	if (!_pw_db && !__initdb())
    586 		return(NS_UNAVAIL);
    587 
    588 	has_compatpw = __has_compatpw();
    589 
    590 again:
    591 	if (has_compatpw && (__pwmode != PWMODE_NONE)) {
    592 		int r;
    593 
    594 		switch (__pwmode) {
    595 		case PWMODE_FULL:
    596 			r = __getpwcompat(_PW_KEYBYNUM, 0, NULL);
    597 			if (r == NS_SUCCESS)
    598 				return(r);
    599 			__pwmode = PWMODE_NONE;
    600 			break;
    601 		case PWMODE_NETGRP:
    602 			r = getnetgrent(&host, &user, &dom);
    603 			if (r == 0) {	/* end of group */
    604 				endnetgrent();
    605 				__pwmode = PWMODE_NONE;
    606 				break;
    607 			}
    608 			if (!user || !*user)
    609 				break;
    610 			r = __getpwcompat(_PW_KEYBYNAME, 0, user);
    611 			if (r == NS_SUCCESS)
    612 				return(r);
    613 			break;
    614 		case PWMODE_USER:
    615 			if(name == (char *)NULL) {
    616 				__pwmode = PWMODE_NONE;
    617 				break;
    618 			}
    619 			r = __getpwcompat(_PW_KEYBYNAME, 0, name);
    620 			free(name);
    621 			name = (char *)NULL;
    622 			if (r == NS_SUCCESS)
    623 				return(r);
    624 			break;
    625 		case PWMODE_NONE:
    626 			abort();
    627 		}
    628 		goto again;
    629 	}
    630 
    631 	++_pw_keynum;
    632 	bf[0] = _PW_KEYBYNUM;
    633 	bcopy((char *)&_pw_keynum, bf + 1, sizeof(_pw_keynum));
    634 	key.data = (u_char *)bf;
    635 	key.size = sizeof(_pw_keynum) + 1;
    636 	if(__hashpw(&key) == NS_SUCCESS) {
    637 		/* if we don't have YP at all, don't bother. */
    638 		if(has_compatpw) {
    639 			if(_pw_passwd.pw_name[0] == '+') {
    640 				/* set the mode */
    641 				switch(_pw_passwd.pw_name[1]) {
    642 				case '\0':
    643 					__pwmode = PWMODE_FULL;
    644 					break;
    645 				case '@':
    646 					__pwmode = PWMODE_NETGRP;
    647 					setnetgrent(_pw_passwd.pw_name + 2);
    648 					break;
    649 				default:
    650 					__pwmode = PWMODE_USER;
    651 					name = strdup(_pw_passwd.pw_name + 1);
    652 					break;
    653 				}
    654 
    655 				/* save the prototype */
    656 				__pwproto_set();
    657 				goto again;
    658 			} else if(_pw_passwd.pw_name[0] == '-') {
    659 				/* an attempted exclusion */
    660 				switch(_pw_passwd.pw_name[1]) {
    661 				case '\0':
    662 					break;
    663 				case '@':
    664 					setnetgrent(_pw_passwd.pw_name + 2);
    665 					while(getnetgrent(&host, &user, &dom)) {
    666 						if(user && *user)
    667 							__pwexclude_add(user);
    668 					}
    669 					endnetgrent();
    670 					break;
    671 				default:
    672 					__pwexclude_add(_pw_passwd.pw_name + 1);
    673 					break;
    674 				}
    675 				goto again;
    676 			}
    677 		}
    678 		return(NS_SUCCESS);
    679 	}
    680 	return(NS_NOTFOUND);
    681 }
    682 
    683 /*
    684  * compat implementation of getpwnam() & getpwuid()
    685  * varargs: type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ]
    686  */
    687 static int
    688 _compat_getpw(rv, cb_data, ap)
    689 	void	*rv;
    690 	void	*cb_data;
    691 	va_list	 ap;
    692 {
    693 	DBT key;
    694 	int		 len;
    695 	char bf[UT_NAMESIZE + 1];
    696 
    697 	int		 search = va_arg(ap, int);
    698 	int		 uid = 0;
    699 	const char	*name = (char *)NULL;
    700 	int		 rval = NS_NOTFOUND;
    701 
    702 	if (!_pw_db && !__initdb())
    703 		return(NS_UNAVAIL);
    704 
    705 	switch (search) {
    706 	case _PW_KEYBYNAME:
    707 		name = va_arg(ap, const char *);
    708 		break;
    709 	case _PW_KEYBYUID:
    710 		uid = va_arg(ap, int);
    711 		break;
    712 	default:
    713 		abort();
    714 	}
    715 
    716 	/*
    717 	 * If YP is active, we must sequence through the passwd file
    718 	 * in sequence.
    719 	 */
    720 	if (__has_compatpw()) {
    721 		int r;
    722 		int s = -1;
    723 		const char *host, *user, *dom;
    724 
    725 		for(_pw_keynum=1; _pw_keynum; _pw_keynum++) {
    726 			bf[0] = _PW_KEYBYNUM;
    727 			bcopy((char *)&_pw_keynum, bf + 1, sizeof(_pw_keynum));
    728 			key.data = (u_char *)bf;
    729 			key.size = sizeof(_pw_keynum) + 1;
    730 			if(__hashpw(&key) != NS_SUCCESS)
    731 				break;
    732 			switch(_pw_passwd.pw_name[0]) {
    733 			case '+':
    734 				/* save the prototype */
    735 				__pwproto_set();
    736 
    737 				switch(_pw_passwd.pw_name[1]) {
    738 				case '\0':
    739 					r = __getpwcompat(search, uid, name);
    740 					if (r != NS_SUCCESS)
    741 						continue;
    742 					break;
    743 				case '@':
    744 pwnam_netgrp:
    745 					if(s == -1)	/* first time */
    746 						setnetgrent(_pw_passwd.pw_name + 2);
    747 					s = getnetgrent(&host, &user, &dom);
    748 					if(s == 0) {	/* end of group */
    749 						endnetgrent();
    750 						s = -1;
    751 						continue;
    752 					}
    753 					if(!user || !*user)
    754 							goto pwnam_netgrp;
    755 
    756 					r = __getpwcompat(_PW_KEYBYNAME,
    757 								0, user);
    758 					if (r == NS_UNAVAIL)
    759 						return(r);
    760 					if (r == NS_NOTFOUND)
    761 							/*
    762 						 * just because this user is bad
    763 						 * doesn't mean they all are
    764 							 */
    765 							goto pwnam_netgrp;
    766 					break;
    767 				default:
    768 					user = _pw_passwd.pw_name + 1;
    769 					r = __getpwcompat(_PW_KEYBYNAME,
    770 								0, user);
    771 					if (r == NS_UNAVAIL)
    772 						return(r);
    773 					if (r == NS_NOTFOUND)
    774 						continue;
    775 					break;
    776 				}
    777 				if(__pwexclude_is(_pw_passwd.pw_name)) {
    778 					if (s == 1)	/* inside netgrp */
    779 						goto pwnam_netgrp;
    780 					continue;
    781 				}
    782 				break;
    783 			case '-':
    784 				/* attempted exclusion */
    785 				switch(_pw_passwd.pw_name[1]) {
    786 				case '\0':
    787 					break;
    788 				case '@':
    789 					setnetgrent(_pw_passwd.pw_name + 2);
    790 					while(getnetgrent(&host, &user, &dom)) {
    791 						if(user && *user)
    792 							__pwexclude_add(user);
    793 					}
    794 					endnetgrent();
    795 					break;
    796 				default:
    797 					__pwexclude_add(_pw_passwd.pw_name + 1);
    798 					break;
    799 				}
    800 				break;
    801 
    802 				continue;
    803 			}
    804 			if ((search == _PW_KEYBYNAME &&
    805 					strcmp(_pw_passwd.pw_name, name) == 0)
    806 				|| (search == _PW_KEYBYUID &&
    807 					_pw_passwd.pw_uid == uid)) {
    808 				rval = NS_SUCCESS;
    809 				break;
    810 			}
    811 			if(s == 1)	/* inside netgrp */
    812 				goto pwnam_netgrp;
    813 			continue;
    814 		}
    815 		__pwproto = (struct passwd *)NULL;
    816 	} else {
    817 		bf[0] = _PW_KEYBYNAME;
    818 		len = strlen(name);
    819 		bcopy(name, bf + 1, MIN(len, UT_NAMESIZE));
    820 		key.data = (u_char *)bf;
    821 		key.size = len + 1;
    822 		rval = __hashpw(&key);
    823 	}
    824 
    825 	if (!_pw_stayopen) {
    826 		(void)(_pw_db->close)(_pw_db);
    827 		_pw_db = (DB *)NULL;
    828 	}
    829 	if(__pwexclude != (DB *)NULL) {
    830 		(void)(__pwexclude->close)(__pwexclude);
    831 		__pwexclude = (DB *)NULL;
    832 	}
    833 	return rval;
    834 }
    835 #endif /* YP || HESIOD */
    836 
    837 struct passwd *
    838 getpwent()
    839 {
    840 	int		r;
    841 	static ns_dtab	dtab;
    842 
    843 	NS_FILES_CB(dtab, _local_getpw, NULL);
    844 	NS_DNS_CB(dtab, _dns_getpw, NULL);
    845 	NS_NIS_CB(dtab, _nis_getpw, NULL);
    846 	NS_COMPAT_CB(dtab, _compat_getpwent, NULL);
    847 
    848 	r = nsdispatch(NULL, dtab, NSDB_PASSWD, _PW_KEYBYNUM);
    849 	return (r == NS_SUCCESS ? &_pw_passwd : (struct passwd *)NULL);
    850 }
    851 
    852 struct passwd *
    853 getpwnam(name)
    854 	const char *name;
    855 {
    856 		int r;
    857 	static ns_dtab	dtab;
    858 
    859 	NS_FILES_CB(dtab, _local_getpw, NULL);
    860 	NS_DNS_CB(dtab, _dns_getpw, NULL);
    861 	NS_NIS_CB(dtab, _nis_getpw, NULL);
    862 	NS_COMPAT_CB(dtab, _compat_getpw, NULL);
    863 
    864 	if (name == NULL || name[0] == '\0')
    865 		return (struct passwd *)NULL;
    866 
    867 	r = nsdispatch(NULL, dtab, NSDB_PASSWD, _PW_KEYBYNAME, name);
    868 	return (r == NS_SUCCESS ? &_pw_passwd : (struct passwd *)NULL);
    869 }
    870 
    871 struct passwd *
    872 getpwuid(uid)
    873 	uid_t uid;
    874 {
    875 	int		r;
    876 	static ns_dtab	dtab;
    877 
    878 	NS_FILES_CB(dtab, _local_getpw, NULL);
    879 	NS_DNS_CB(dtab, _dns_getpw, NULL);
    880 	NS_NIS_CB(dtab, _nis_getpw, NULL);
    881 	NS_COMPAT_CB(dtab, _compat_getpw, NULL);
    882 
    883 	r = nsdispatch(NULL, dtab, NSDB_PASSWD, _PW_KEYBYUID, (int)uid);
    884 	return (r == NS_SUCCESS ? &_pw_passwd : (struct passwd *)NULL);
    885 }
    886 
    887 int
    888 setpassent(stayopen)
    889 	int stayopen;
    890 {
    891 	_pw_keynum = 0;
    892 	_pw_stayopen = stayopen;
    893 #ifdef YP
    894 	__pwmode = PWMODE_NONE;
    895 	if(__ypcurrent)
    896 		free(__ypcurrent);
    897 	__ypcurrent = NULL;
    898 #endif
    899 #ifdef HESIOD
    900 	_pw_hesnum = 0;
    901 #endif
    902 #if defined(YP) || defined(HESIOD)
    903 	if(__pwexclude != (DB *)NULL) {
    904 		(void)(__pwexclude->close)(__pwexclude);
    905 		__pwexclude = (DB *)NULL;
    906 	}
    907 	__pwproto = (struct passwd *)NULL;
    908 #endif
    909 	return(1);
    910 }
    911 
    912 void
    913 setpwent()
    914 {
    915 	(void) setpassent(0);
    916 }
    917 
    918 void
    919 endpwent()
    920 {
    921 	_pw_keynum = 0;
    922 	if (_pw_db) {
    923 		(void)(_pw_db->close)(_pw_db);
    924 		_pw_db = (DB *)NULL;
    925 	}
    926 #ifdef YP
    927 	__pwmode = PWMODE_NONE;
    928 	if(__ypcurrent)
    929 		free(__ypcurrent);
    930 	__ypcurrent = NULL;
    931 #endif
    932 #ifdef HESIOD
    933 	_pw_hesnum = 0;
    934 #endif
    935 #if defined(YP) || defined(HESIOD)
    936 	if(__pwexclude != (DB *)NULL) {
    937 		(void)(__pwexclude->close)(__pwexclude);
    938 		__pwexclude = (DB *)NULL;
    939 	}
    940 	__pwproto = (struct passwd *)NULL;
    941 #endif
    942 }
    943 
    944 static int
    945 __initdb()
    946 {
    947 	static int warned;
    948 	char *p;
    949 
    950 #if defined(YP) || defined(HESIOD)
    951 	__pwmode = PWMODE_NONE;
    952 #endif
    953 	p = (geteuid()) ? _PATH_MP_DB : _PATH_SMP_DB;
    954 	_pw_db = dbopen(p, O_RDONLY, 0, DB_HASH, NULL);
    955 	if (_pw_db)
    956 		return(1);
    957 	if (!warned)
    958 		syslog(LOG_ERR, "%s: %m", p);
    959 	warned = 1;
    960 	return(0);
    961 }
    962 
    963 static int
    964 __hashpw(key)
    965 	DBT *key;
    966 {
    967 	register char *p, *t;
    968 	static u_int max;
    969 	static char *line;
    970 	DBT data;
    971 
    972 	switch ((_pw_db->get)(_pw_db, key, &data, 0)) {
    973 	case 0:
    974 		break;			/* found */
    975 	case 1:
    976 		return NS_NOTFOUND;	/* not found */
    977 	case -1:
    978 		return NS_UNAVAIL;	/* error in db routines */
    979 	default:
    980 		abort();
    981 	}
    982 
    983 	p = (char *)data.data;
    984 	if (data.size > max && !(line = realloc(line, (max += 1024))))
    985 		return NS_UNAVAIL;
    986 
    987 	t = line;
    988 #define	EXPAND(e)	e = t; while ((*t++ = *p++));
    989 	EXPAND(_pw_passwd.pw_name);
    990 	EXPAND(_pw_passwd.pw_passwd);
    991 	memmove((char *)&_pw_passwd.pw_uid, p, sizeof(int));
    992 	p += sizeof(int);
    993 	memmove((char *)&_pw_passwd.pw_gid, p, sizeof(int));
    994 	p += sizeof(int);
    995 	memmove((char *)&_pw_passwd.pw_change, p, sizeof(time_t));
    996 	p += sizeof(time_t);
    997 	EXPAND(_pw_passwd.pw_class);
    998 	EXPAND(_pw_passwd.pw_gecos);
    999 	EXPAND(_pw_passwd.pw_dir);
   1000 	EXPAND(_pw_passwd.pw_shell);
   1001 	memmove((char *)&_pw_passwd.pw_expire, p, sizeof(time_t));
   1002 	p += sizeof(time_t);
   1003 
   1004 	/* See if there's any data left.  If so, read in flags. */
   1005 	if (data.size > (p - (char *)data.data)) {
   1006 		memmove((char *)&_pw_flags, p, sizeof(int));
   1007 		p += sizeof(int);
   1008 	} else
   1009 		_pw_flags = _PASSWORD_NOUID|_PASSWORD_NOGID;	/* default */
   1010 
   1011 	return NS_SUCCESS;
   1012 }
   1013