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