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