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