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