xref: /netbsd-src/lib/libc/gen/getpwent.c (revision 81b108b45f75f89f1e3ffad9fb6f074e771c0935)
1 /*	$NetBSD: getpwent.c,v 1.14 1995/07/28 05:43:01 phil 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.14 1995/07/28 05:43:01 phil 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 	register char *ptr;
143 	register 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;
222 
223 	/* since this is currently using strsep(), parse it first */
224 	bp = s;
225 	pw->pw_name = strsep(&bp, ":\n");
226 	pw->pw_passwd = strsep(&bp, ":\n");
227 	if (!(cp = strsep(&bp, ":\n")))
228 		return 1;
229 	pw->pw_uid = atoi(cp);
230 	if (!(cp = strsep(&bp, ":\n")))
231 		return 1;
232 	pw->pw_gid = atoi(cp);
233 	pw->pw_change = 0;
234 	pw->pw_class = "";
235 	pw->pw_gecos = strsep(&bp, ":\n");
236 	pw->pw_dir = strsep(&bp, ":\n");
237 	pw->pw_shell = strsep(&bp, ":\n");
238 	pw->pw_expire = 0;
239 
240 	/* now let the prototype override, if set. */
241 	if(__ypproto != (struct passwd *)NULL) {
242 #ifdef YP_OVERRIDE_PASSWD
243 		if(__ypproto->pw_passwd != (char *)NULL)
244 			pw->pw_passwd = __ypproto->pw_passwd;
245 #endif
246 		if(!(__ypflags & _PASSWORD_NOUID))
247 			pw->pw_uid = __ypproto->pw_uid;
248 		if(!(__ypflags & _PASSWORD_NOGID))
249 			pw->pw_gid = __ypproto->pw_gid;
250 		if(__ypproto->pw_gecos != (char *)NULL)
251 			pw->pw_gecos = __ypproto->pw_gecos;
252 		if(__ypproto->pw_dir != (char *)NULL)
253 			pw->pw_dir = __ypproto->pw_dir;
254 		if(__ypproto->pw_shell != (char *)NULL)
255 			pw->pw_shell = __ypproto->pw_shell;
256 	}
257 	return 0;
258 }
259 #endif
260 
261 struct passwd *
262 getpwent()
263 {
264 	DBT key;
265 	char bf[sizeof(_pw_keynum) + 1];
266 #ifdef YP
267 	char *cp;
268 	static char *name = (char *)NULL;
269 	const char *user, *host, *dom;
270 	int has_yppw;
271 #endif
272 
273 	if (!_pw_db && !__initdb())
274 		return((struct passwd *)NULL);
275 
276 #ifdef YP
277 	has_yppw = __has_yppw();
278 
279 again:
280 	if(has_yppw && (__ypmode != YPMODE_NONE)) {
281 		char *key, *data;
282 		int keylen, datalen;
283 		int r, s;
284 
285 		if(!__ypdomain) {
286 			if( _yp_check(&__ypdomain) == 0) {
287 				__ypmode = YPMODE_NONE;
288 				goto again;
289 			}
290 		}
291 		switch(__ypmode) {
292 		case YPMODE_FULL:
293 			if(__ypcurrent) {
294 				r = yp_next(__ypdomain, "passwd.byname",
295 					__ypcurrent, __ypcurrentlen,
296 					&key, &keylen, &data, &datalen);
297 				free(__ypcurrent);
298 				if(r != 0) {
299 					__ypcurrent = NULL;
300 					__ypmode = YPMODE_NONE;
301 					if(data)
302 						free(data);
303 					data = NULL;
304 					goto again;
305 				}
306 				__ypcurrent = key;
307 				__ypcurrentlen = keylen;
308 				bcopy(data, line, datalen);
309 				free(data);
310 				data = NULL;
311 			} else {
312 				r = yp_first(__ypdomain, "passwd.byname",
313 					&__ypcurrent, &__ypcurrentlen,
314 					&data, &datalen);
315 				if(r != 0) {
316 					__ypmode = YPMODE_NONE;
317 					if(data)
318 						free(data);
319 					goto again;
320 				}
321 				bcopy(data, line, datalen);
322 				free(data);
323 				data = NULL;
324 			}
325 			break;
326 		case YPMODE_NETGRP:
327 			s = getnetgrent(&host, &user, &dom);
328 			if(s == 0) {	/* end of group */
329 				endnetgrent();
330 				__ypmode = YPMODE_NONE;
331 				goto again;
332 			}
333 			if(user && *user) {
334 				r = yp_match(__ypdomain, "passwd.byname",
335 					user, strlen(user),
336 					&data, &datalen);
337 			} else
338 				goto again;
339 			if(r != 0) {
340 				/*
341 				 * if the netgroup is invalid, keep looking
342 				 * as there may be valid users later on.
343 				 */
344 				if(data)
345 					free(data);
346 				goto again;
347 			}
348 			bcopy(data, line, datalen);
349 			free(data);
350 			data = (char *)NULL;
351 			break;
352 		case YPMODE_USER:
353 			if(name != (char *)NULL) {
354 				r = yp_match(__ypdomain, "passwd.byname",
355 					name, strlen(name),
356 					&data, &datalen);
357 				__ypmode = YPMODE_NONE;
358 				free(name);
359 				name = (char *)NULL;
360 				if(r != 0) {
361 					if(data)
362 						free(data);
363 					goto again;
364 				}
365 				bcopy(data, line, datalen);
366 				free(data);
367 				data = (char *)NULL;
368 			} else {		/* XXX */
369 				__ypmode = YPMODE_NONE;
370 				goto again;
371 			}
372 			break;
373 		}
374 
375 		line[datalen] = '\0';
376 		if (__ypparse(&_pw_passwd, line))
377 			goto again;
378 		return &_pw_passwd;
379 	}
380 #endif
381 
382 	++_pw_keynum;
383 	bf[0] = _PW_KEYBYNUM;
384 	bcopy((char *)&_pw_keynum, bf + 1, sizeof(_pw_keynum));
385 	key.data = (u_char *)bf;
386 	key.size = sizeof(_pw_keynum) + 1;
387 	if(__hashpw(&key)) {
388 #ifdef YP
389 		/* if we don't have YP at all, don't bother. */
390 		if(has_yppw) {
391 			if(_pw_passwd.pw_name[0] == '+') {
392 				/* set the mode */
393 				switch(_pw_passwd.pw_name[1]) {
394 				case '\0':
395 					__ypmode = YPMODE_FULL;
396 					break;
397 				case '@':
398 					__ypmode = YPMODE_NETGRP;
399 					setnetgrent(_pw_passwd.pw_name + 2);
400 					break;
401 				default:
402 					__ypmode = YPMODE_USER;
403 					name = strdup(_pw_passwd.pw_name + 1);
404 					break;
405 				}
406 
407 				/* save the prototype */
408 				__ypproto_set();
409 				goto again;
410 			} else if(_pw_passwd.pw_name[0] == '-') {
411 				/* an attempted exclusion */
412 				switch(_pw_passwd.pw_name[1]) {
413 				case '\0':
414 					break;
415 				case '@':
416 					setnetgrent(_pw_passwd.pw_name + 2);
417 					while(getnetgrent(&host, &user, &dom)) {
418 						if(user && *user)
419 							__ypexclude_add(user);
420 					}
421 					endnetgrent();
422 					break;
423 				default:
424 					__ypexclude_add(_pw_passwd.pw_name + 1);
425 					break;
426 				}
427 				goto again;
428 			}
429 		}
430 #endif
431 		return &_pw_passwd;
432 	}
433 	return (struct passwd *)NULL;
434 }
435 
436 #ifdef YP
437 
438 /*
439  * See if the YP token is in the database.  Only works if pwd_mkdb knows
440  * about the token.
441  */
442 static int
443 __has_yppw()
444 {
445 	DBT key, data;
446 	DBT pkey, pdata;
447 	int len;
448 	char bf[UT_NAMESIZE];
449 
450 	key.data = (u_char *)__yp_token;
451 	key.size = strlen(__yp_token);
452 
453 	/* Pre-token database support. */
454 	bf[0] = _PW_KEYBYNAME;
455 	len = strlen("+");
456 	bcopy("+", bf + 1, MIN(len, UT_NAMESIZE));
457 	pkey.data = (u_char *)bf;
458 	pkey.size = len + 1;
459 
460 	if ((_pw_db->get)(_pw_db, &key, &data, 0)
461 	    && (_pw_db->get)(_pw_db, &pkey, &pdata, 0))
462 		return(0);	/* No YP. */
463 	return(1);
464 }
465 #endif
466 
467 struct passwd *
468 getpwnam(name)
469 	const char *name;
470 {
471 	DBT key;
472 	int len, rval;
473 	char bf[UT_NAMESIZE + 1];
474 
475 	if (!_pw_db && !__initdb())
476 		return((struct passwd *)NULL);
477 
478 #ifdef YP
479 	/*
480 	 * If YP is active, we must sequence through the passwd file
481 	 * in sequence.
482 	 */
483 	if (__has_yppw()) {
484 		int r;
485 		int s = -1;
486 		const char *host, *user, *dom;
487 
488 		for(_pw_keynum=1; _pw_keynum; _pw_keynum++) {
489 			bf[0] = _PW_KEYBYNUM;
490 			bcopy((char *)&_pw_keynum, bf + 1, sizeof(_pw_keynum));
491 			key.data = (u_char *)bf;
492 			key.size = sizeof(_pw_keynum) + 1;
493 			if(__hashpw(&key) == 0)
494 				break;
495 			switch(_pw_passwd.pw_name[0]) {
496 			case '+':
497 				if(!__ypdomain) {
498 					if(_yp_check(&__ypdomain) == 0) {
499 						continue;
500 					}
501 				}
502 				/* save the prototype */
503 				__ypproto_set();
504 
505 				switch(_pw_passwd.pw_name[1]) {
506 				case '\0':
507 					if(__ypcurrent) {
508 						free(__ypcurrent);
509 						__ypcurrent = NULL;
510 					}
511 					r = yp_match(__ypdomain,
512 						"passwd.byname",
513 						name, strlen(name),
514 						&__ypcurrent, &__ypcurrentlen);
515 					if(r != 0) {
516 						if(__ypcurrent)
517 							free(__ypcurrent);
518 						__ypcurrent = NULL;
519 						continue;
520 					}
521 					break;
522 				case '@':
523 pwnam_netgrp:
524 					if(__ypcurrent) {
525 						free(__ypcurrent);
526 						__ypcurrent = NULL;
527 					}
528 					if(s == -1)	/* first time */
529 						setnetgrent(_pw_passwd.pw_name + 2);
530 					s = getnetgrent(&host, &user, &dom);
531 					if(s == 0) {	/* end of group */
532 						endnetgrent();
533 						s = -1;
534 						continue;
535 					} else {
536 						if(user && *user) {
537 							r = yp_match(__ypdomain,
538 							    "passwd.byname",
539 							    user, strlen(user),
540 							    &__ypcurrent,
541 							    &__ypcurrentlen);
542 						} else
543 							goto pwnam_netgrp;
544 						if(r != 0) {
545 							if(__ypcurrent)
546 							    free(__ypcurrent);
547 							__ypcurrent = NULL;
548 							/*
549 							 * just because this
550 							 * user is bad, doesn't
551 							 * mean they all are.
552 							 */
553 							goto pwnam_netgrp;
554 						}
555 					}
556 					break;
557 				default:
558 					if(__ypcurrent) {
559 						free(__ypcurrent);
560 						__ypcurrent = NULL;
561 					}
562 					user = _pw_passwd.pw_name + 1;
563 					r = yp_match(__ypdomain,
564 						"passwd.byname",
565 						user, strlen(user),
566 						&__ypcurrent,
567 						&__ypcurrentlen);
568 					if(r != 0) {
569 						if(__ypcurrent)
570 							free(__ypcurrent);
571 						__ypcurrent = NULL;
572 						continue;
573 					}
574 					break;
575 				}
576 				bcopy(__ypcurrent, line, __ypcurrentlen);
577 				line[__ypcurrentlen] = '\0';
578 				if(__ypparse(&_pw_passwd, line)
579 				   || __ypexclude_is(_pw_passwd.pw_name)) {
580 					if(s == 1)	/* inside netgrp */
581 						goto pwnam_netgrp;
582 					continue;
583 				}
584 				break;
585 			case '-':
586 				/* attempted exclusion */
587 				switch(_pw_passwd.pw_name[1]) {
588 				case '\0':
589 					break;
590 				case '@':
591 					setnetgrent(_pw_passwd.pw_name + 2);
592 					while(getnetgrent(&host, &user, &dom)) {
593 						if(user && *user)
594 							__ypexclude_add(user);
595 					}
596 					endnetgrent();
597 					break;
598 				default:
599 					__ypexclude_add(_pw_passwd.pw_name + 1);
600 					break;
601 				}
602 				break;
603 
604 				continue;
605 			}
606 			if(strcmp(_pw_passwd.pw_name, name) == 0) {
607 				if (!_pw_stayopen) {
608 					(void)(_pw_db->close)(_pw_db);
609 					_pw_db = (DB *)NULL;
610 				}
611 				if(__ypexclude != (DB *)NULL) {
612 					(void)(__ypexclude->close)(__ypexclude);
613 					__ypexclude = (DB *)NULL;
614 				}
615 				__ypproto = (struct passwd *)NULL;
616 				return &_pw_passwd;
617 			}
618 			if(s == 1)	/* inside netgrp */
619 				goto pwnam_netgrp;
620 			continue;
621 		}
622 		if (!_pw_stayopen) {
623 			(void)(_pw_db->close)(_pw_db);
624 			_pw_db = (DB *)NULL;
625 		}
626 		if(__ypexclude != (DB *)NULL) {
627 			(void)(__ypexclude->close)(__ypexclude);
628 			__ypexclude = (DB *)NULL;
629 		}
630 		__ypproto = (struct passwd *)NULL;
631 		return (struct passwd *)NULL;
632 	}
633 #endif /* YP */
634 
635 	bf[0] = _PW_KEYBYNAME;
636 	len = strlen(name);
637 	bcopy(name, bf + 1, MIN(len, UT_NAMESIZE));
638 	key.data = (u_char *)bf;
639 	key.size = len + 1;
640 	rval = __hashpw(&key);
641 
642 	if (!_pw_stayopen) {
643 		(void)(_pw_db->close)(_pw_db);
644 		_pw_db = (DB *)NULL;
645 	}
646 	return(rval ? &_pw_passwd : (struct passwd *)NULL);
647 }
648 
649 struct passwd *
650 #ifdef __STDC__
651 getpwuid(uid_t uid)
652 #else
653 getpwuid(uid)
654 	int uid;
655 #endif
656 {
657 	DBT key;
658 	char bf[sizeof(_pw_keynum) + 1];
659 	int keyuid, rval;
660 
661 	if (!_pw_db && !__initdb())
662 		return((struct passwd *)NULL);
663 
664 #ifdef YP
665 	/*
666 	 * If YP is active, we must sequence through the passwd file
667 	 * in sequence.
668 	 */
669 	if (__has_yppw()) {
670 		char uidbuf[20];
671 		int r;
672 		int s = -1;
673 		const char *host, *user, *dom;
674 
675 		sprintf(uidbuf, "%d", uid);
676 		for(_pw_keynum=1; _pw_keynum; _pw_keynum++) {
677 			bf[0] = _PW_KEYBYNUM;
678 			bcopy((char *)&_pw_keynum, bf + 1, sizeof(_pw_keynum));
679 			key.data = (u_char *)bf;
680 			key.size = sizeof(_pw_keynum) + 1;
681 			if(__hashpw(&key) == 0)
682 				break;
683 			switch(_pw_passwd.pw_name[0]) {
684 			case '+':
685 				if(!__ypdomain) {
686 					if(_yp_check(&__ypdomain) == 0) {
687 						continue;
688 					}
689 				}
690 				/* save the prototype */
691 				__ypproto_set();
692 
693 				switch(_pw_passwd.pw_name[1]) {
694 				case '\0':
695 					if(__ypcurrent) {
696 						free(__ypcurrent);
697 						__ypcurrent = NULL;
698 					}
699 					r = yp_match(__ypdomain, "passwd.byuid",
700 						uidbuf, strlen(uidbuf),
701 						&__ypcurrent, &__ypcurrentlen);
702 					if(r != 0) {
703 						if(__ypcurrent)
704 							free(__ypcurrent);
705 						__ypcurrent = NULL;
706 						continue;
707 					}
708 					break;
709 				case '@':
710 pwuid_netgrp:
711 					if(__ypcurrent) {
712 						free(__ypcurrent);
713 						__ypcurrent = NULL;
714 					}
715 					if(s == -1)	/* first time */
716 						setnetgrent(_pw_passwd.pw_name + 2);
717 					s = getnetgrent(&host, &user, &dom);
718 					if(s == 0) {	/* end of group */
719 						endnetgrent();
720 						s = -1;
721 						continue;
722 					} else {
723 						if(user && *user) {
724 							r = yp_match(__ypdomain,
725 							    "passwd.byname",
726 							    user, strlen(user),
727 							    &__ypcurrent,
728 							    &__ypcurrentlen);
729 						} else
730 							goto pwuid_netgrp;
731 						if(r != 0) {
732 							if(__ypcurrent)
733 							    free(__ypcurrent);
734 							__ypcurrent = NULL;
735 							/*
736                                                          * just because this
737 							 * user is bad, doesn't
738 							 * mean they all are.
739 							 */
740 							goto pwuid_netgrp;
741 						}
742 					}
743 					break;
744 				default:
745 					if(__ypcurrent) {
746 						free(__ypcurrent);
747 						__ypcurrent = NULL;
748 					}
749 					user = _pw_passwd.pw_name + 1;
750 					r = yp_match(__ypdomain,
751 						"passwd.byname",
752 						user, strlen(user),
753 						&__ypcurrent,
754 						&__ypcurrentlen);
755 					if(r != 0) {
756 						if(__ypcurrent)
757 							free(__ypcurrent);
758 						__ypcurrent = NULL;
759 						continue;
760 					}
761 					break;
762 				}
763 				bcopy(__ypcurrent, line, __ypcurrentlen);
764 				line[__ypcurrentlen] = '\0';
765 				if(__ypparse(&_pw_passwd, line)
766 				   || __ypexclude_is(_pw_passwd.pw_name)) {
767 					if(s == 1)	/* inside netgroup */
768 						goto pwuid_netgrp;
769 					continue;
770 				}
771 				break;
772 			case '-':
773 				/* attempted exclusion */
774 				switch(_pw_passwd.pw_name[1]) {
775 				case '\0':
776 					break;
777 				case '@':
778 					setnetgrent(_pw_passwd.pw_name + 2);
779 					while(getnetgrent(&host, &user, &dom)) {
780 						if(user && *user)
781 							__ypexclude_add(user);
782 					}
783 					endnetgrent();
784 					break;
785 				default:
786 					__ypexclude_add(_pw_passwd.pw_name + 1);
787 					break;
788 				}
789 				break;
790 
791 				continue;
792 			}
793 			if( _pw_passwd.pw_uid == uid) {
794 				if (!_pw_stayopen) {
795 					(void)(_pw_db->close)(_pw_db);
796 					_pw_db = (DB *)NULL;
797 				}
798 				if (__ypexclude != (DB *)NULL) {
799 					(void)(__ypexclude->close)(__ypexclude);
800 					__ypexclude = (DB *)NULL;
801 				}
802 				__ypproto = NULL;
803 				return &_pw_passwd;
804 			}
805 			if(s == 1)	/* inside netgroup */
806 				goto pwuid_netgrp;
807 			continue;
808 		}
809 		if (!_pw_stayopen) {
810 			(void)(_pw_db->close)(_pw_db);
811 			_pw_db = (DB *)NULL;
812 		}
813 		if(__ypexclude != (DB *)NULL) {
814 			(void)(__ypexclude->close)(__ypexclude);
815 			__ypexclude = (DB *)NULL;
816 		}
817 		__ypproto = (struct passwd *)NULL;
818 		return (struct passwd *)NULL;
819 	}
820 #endif /* YP */
821 
822 	bf[0] = _PW_KEYBYUID;
823 	keyuid = uid;
824 	bcopy(&keyuid, bf + 1, sizeof(keyuid));
825 	key.data = (u_char *)bf;
826 	key.size = sizeof(keyuid) + 1;
827 	rval = __hashpw(&key);
828 
829 	if (!_pw_stayopen) {
830 		(void)(_pw_db->close)(_pw_db);
831 		_pw_db = (DB *)NULL;
832 	}
833 	return(rval ? &_pw_passwd : (struct passwd *)NULL);
834 }
835 
836 int
837 setpassent(stayopen)
838 	int stayopen;
839 {
840 	_pw_keynum = 0;
841 	_pw_stayopen = stayopen;
842 #ifdef YP
843 	__ypmode = YPMODE_NONE;
844 	if(__ypcurrent)
845 		free(__ypcurrent);
846 	__ypcurrent = NULL;
847 	if(__ypexclude != (DB *)NULL) {
848 		(void)(__ypexclude->close)(__ypexclude);
849 		__ypexclude = (DB *)NULL;
850 	}
851 	__ypproto = (struct passwd *)NULL;
852 #endif
853 	return(1);
854 }
855 
856 void
857 setpwent()
858 {
859 	(void) setpassent(0);
860 }
861 
862 void
863 endpwent()
864 {
865 	_pw_keynum = 0;
866 	if (_pw_db) {
867 		(void)(_pw_db->close)(_pw_db);
868 		_pw_db = (DB *)NULL;
869 	}
870 #ifdef YP
871 	__ypmode = YPMODE_NONE;
872 	if(__ypcurrent)
873 		free(__ypcurrent);
874 	__ypcurrent = NULL;
875 	if(__ypexclude != (DB *)NULL) {
876 		(void)(__ypexclude->close)(__ypexclude);
877 		__ypexclude = (DB *)NULL;
878 	}
879 	__ypproto = (struct passwd *)NULL;
880 #endif
881 }
882 
883 static int
884 __initdb()
885 {
886 	static int warned;
887 	char *p;
888 
889 #ifdef YP
890 	__ypmode = YPMODE_NONE;
891 #endif
892 	p = (geteuid()) ? _PATH_MP_DB : _PATH_SMP_DB;
893 	_pw_db = dbopen(p, O_RDONLY, 0, DB_HASH, NULL);
894 	if (_pw_db)
895 		return(1);
896 	if (!warned)
897 		syslog(LOG_ERR, "%s: %m", p);
898 	warned = 1;
899 	return(0);
900 }
901 
902 static int
903 __hashpw(key)
904 	DBT *key;
905 {
906 	register char *p, *t;
907 	static u_int max;
908 	static char *line;
909 	DBT data;
910 
911 	if ((_pw_db->get)(_pw_db, key, &data, 0))
912 		return(0);
913 	p = (char *)data.data;
914 	if (data.size > max && !(line = realloc(line, (max += 1024))))
915 		return(0);
916 
917 	t = line;
918 #define	EXPAND(e)	e = t; while ((*t++ = *p++));
919 	EXPAND(_pw_passwd.pw_name);
920 	EXPAND(_pw_passwd.pw_passwd);
921 	bcopy(p, (char *)&_pw_passwd.pw_uid, sizeof(int));
922 	p += sizeof(int);
923 	bcopy(p, (char *)&_pw_passwd.pw_gid, sizeof(int));
924 	p += sizeof(int);
925 	bcopy(p, (char *)&_pw_passwd.pw_change, sizeof(time_t));
926 	p += sizeof(time_t);
927 	EXPAND(_pw_passwd.pw_class);
928 	EXPAND(_pw_passwd.pw_gecos);
929 	EXPAND(_pw_passwd.pw_dir);
930 	EXPAND(_pw_passwd.pw_shell);
931 	bcopy(p, (char *)&_pw_passwd.pw_expire, sizeof(time_t));
932 	p += sizeof(time_t);
933 
934 	/* See if there's any data left.  If so, read in flags. */
935 	if (data.size > (p - (char *)data.data)) {
936 		bcopy(p, (char *)&_pw_flags, sizeof(int));
937 		p += sizeof(int);
938 	} else
939 		_pw_flags = _PASSWORD_NOUID|_PASSWORD_NOGID;	/* default */
940 
941 	return(1);
942 }
943