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