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