xref: /netbsd-src/lib/libc/gen/getpwent.c (revision fdecd6a253f999ae92b139670d9e15cc9df4497c)
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