1 /*	$OpenBSD: getpwent.c,v 1.64 2021/12/07 18:13:45 deraadt Exp $ */
2 /*
3  * Copyright (c) 2008 Theo de Raadt
4  * Copyright (c) 1988, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  * Portions Copyright (c) 1994, 1995, 1996, 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. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #include <sys/types.h>
34 #include <sys/mman.h>
35 #include <fcntl.h>
36 #include <db.h>
37 #include <syslog.h>
38 #include <pwd.h>
39 #include <errno.h>
40 #include <unistd.h>
41 #include <stdbool.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <limits.h>
45 #include <netgroup.h>
46 #ifdef YP
47 #include <stdio.h>
48 #include <rpc/rpc.h>
49 #include <rpcsvc/yp.h>
50 #include <rpcsvc/ypclnt.h>
51 #include "ypinternal.h"
52 #include "ypexclude.h"
53 #endif
54 #include "thread_private.h"
55 
56 #define MINIMUM(a, b)	(((a) < (b)) ? (a) : (b))
57 
58 struct pw_storage {
59 	struct passwd pw;
60 	uid_t uid;
61 	char name[_PW_NAME_LEN + 1];
62 	char pwbuf[_PW_BUF_LEN];
63 };
64 
65 _THREAD_PRIVATE_KEY(pw);
66 
67 static DB *_pw_db;			/* password database */
68 
69 /* mmap'd password storage */
70 static struct pw_storage *_pw_storage = MAP_FAILED;
71 
72 /* Following are used only by setpwent(), getpwent(), and endpwent() */
73 static int _pw_keynum;			/* key counter */
74 static int _pw_stayopen;		/* keep fd's open */
75 static int _pw_flags;			/* password flags */
76 
77 static int __hashpw(DBT *, char *buf, size_t buflen, struct passwd *, int *);
78 static int __initdb(int);
79 static struct passwd *_pwhashbyname(const char *name, char *buf,
80 	size_t buflen, struct passwd *pw, int *);
81 static struct passwd *_pwhashbyuid(uid_t uid, char *buf,
82 	size_t buflen, struct passwd *pw, int *);
83 
84 #ifdef YP
85 static char	*__ypdomain;
86 
87 /* Following are used only by setpwent(), getpwent(), and endpwent() */
88 enum _ypmode { YPMODE_NONE, YPMODE_FULL, YPMODE_USER, YPMODE_NETGRP };
89 static enum	_ypmode __ypmode;
90 static char	*__ypcurrent;
91 static int	__ypcurrentlen;
92 static int	__yp_pw_flags;
93 static int	__getpwent_has_yppw = -1;
94 static struct _ypexclude *__ypexhead;
95 
96 static int __has_yppw(void);
97 static int __has_ypmaster(void);
98 static int __ypparse(struct passwd *pw, char *s, int);
99 
100 #define LOOKUP_BYNAME 0
101 #define LOOKUP_BYUID 1
102 static struct passwd *__yppwlookup(int, char *, uid_t, struct passwd *,
103     char *, size_t, int *);
104 
105 /* macro for deciding which YP maps to use. */
106 #define PASSWD_BYNAME \
107 	(__has_ypmaster() ? "master.passwd.byname" : "passwd.byname")
108 #define PASSWD_BYUID \
109 	(__has_ypmaster() ? "master.passwd.byuid" : "passwd.byuid")
110 
111 static struct passwd *__ypproto;
112 
113 static void __ypproto_set(struct passwd *, struct pw_storage *, int, int *);
114 
115 static void
__ypproto_set(struct passwd * pw,struct pw_storage * buf,int flags,int * yp_pw_flagsp)116 __ypproto_set(struct passwd *pw, struct pw_storage *buf, int flags,
117     int *yp_pw_flagsp)
118 {
119 	char *ptr = buf->pwbuf;
120 	__ypproto = &buf->pw;
121 
122 	/* name */
123 	if (pw->pw_name && (pw->pw_name)[0]) {
124 		bcopy(pw->pw_name, ptr, strlen(pw->pw_name) + 1);
125 		__ypproto->pw_name = ptr;
126 		ptr += (strlen(pw->pw_name) + 1);
127 	} else
128 		__ypproto->pw_name = NULL;
129 
130 	/* password */
131 	if (pw->pw_passwd && (pw->pw_passwd)[0]) {
132 		bcopy(pw->pw_passwd, ptr, strlen(pw->pw_passwd) + 1);
133 		__ypproto->pw_passwd = ptr;
134 		ptr += (strlen(pw->pw_passwd) + 1);
135 	} else
136 		__ypproto->pw_passwd = NULL;
137 
138 	/* uid */
139 	__ypproto->pw_uid = pw->pw_uid;
140 
141 	/* gid */
142 	__ypproto->pw_gid = pw->pw_gid;
143 
144 	/* change (ignored anyway) */
145 	__ypproto->pw_change = pw->pw_change;
146 
147 	/* class (ignored anyway) */
148 	__ypproto->pw_class = "";
149 
150 	/* gecos */
151 	if (pw->pw_gecos && (pw->pw_gecos)[0]) {
152 		bcopy(pw->pw_gecos, ptr, strlen(pw->pw_gecos) + 1);
153 		__ypproto->pw_gecos = ptr;
154 		ptr += (strlen(pw->pw_gecos) + 1);
155 	} else
156 		__ypproto->pw_gecos = NULL;
157 
158 	/* dir */
159 	if (pw->pw_dir && (pw->pw_dir)[0]) {
160 		bcopy(pw->pw_dir, ptr, strlen(pw->pw_dir) + 1);
161 		__ypproto->pw_dir = ptr;
162 		ptr += (strlen(pw->pw_dir) + 1);
163 	} else
164 		__ypproto->pw_dir = NULL;
165 
166 	/* shell */
167 	if (pw->pw_shell && (pw->pw_shell)[0]) {
168 		bcopy(pw->pw_shell, ptr, strlen(pw->pw_shell) + 1);
169 		__ypproto->pw_shell = ptr;
170 		ptr += (strlen(pw->pw_shell) + 1);
171 	} else
172 		__ypproto->pw_shell = NULL;
173 
174 	/* expire (ignored anyway) */
175 	__ypproto->pw_expire = pw->pw_expire;
176 
177 	/* flags */
178 	*yp_pw_flagsp = flags;
179 }
180 
181 static int
__ypparse(struct passwd * pw,char * s,int yp_pw_flags)182 __ypparse(struct passwd *pw, char *s, int yp_pw_flags)
183 {
184 	char *bp, *cp, *endp;
185 	u_long ul;
186 	int count = 0;
187 
188 	/* count the colons. */
189 	bp = s;
190 	while (*bp != '\0') {
191 		if (*bp++ == ':')
192 			count++;
193 	}
194 
195 	/* since this is currently using strsep(), parse it first */
196 	bp = s;
197 	pw->pw_name = strsep(&bp, ":\n");
198 	pw->pw_passwd = strsep(&bp, ":\n");
199 	if (!(cp = strsep(&bp, ":\n")))
200 		return (1);
201 	ul = strtoul(cp, &endp, 10);
202 	if (endp == cp || *endp != '\0' || ul >= UID_MAX)
203 		return (1);
204 	pw->pw_uid = (uid_t)ul;
205 	if (!(cp = strsep(&bp, ":\n")))
206 		return (1);
207 	ul = strtoul(cp, &endp, 10);
208 	if (endp == cp || *endp != '\0' || ul >= GID_MAX)
209 		return (1);
210 	pw->pw_gid = (gid_t)ul;
211 	if (count == 9) {
212 		long l;
213 
214 		/* If the ypserv gave us all the fields, use them. */
215 		pw->pw_class = strsep(&bp, ":\n");
216 		if (!(cp = strsep(&bp, ":\n")))
217 			return (1);
218 		l = strtol(cp, &endp, 10);
219 		if (endp == cp || *endp != '\0' || l >= INT_MAX || l <= INT_MIN)
220 			return (1);
221 		pw->pw_change = (time_t)l;
222 		if (!(cp = strsep(&bp, ":\n")))
223 			return (1);
224 		l = strtol(cp, &endp, 10);
225 		if (endp == cp || *endp != '\0' || l >= INT_MAX || l <= INT_MIN)
226 			return (1);
227 		pw->pw_expire = (time_t)l;
228 	} else {
229 		/* ..else it is a normal ypserv. */
230 		pw->pw_class = "";
231 		pw->pw_change = 0;
232 		pw->pw_expire = 0;
233 	}
234 	pw->pw_gecos = strsep(&bp, ":\n");
235 	pw->pw_dir = strsep(&bp, ":\n");
236 	pw->pw_shell = strsep(&bp, ":\n");
237 
238 	/* now let the prototype override, if set. */
239 	if (__ypproto) {
240 		if (!(yp_pw_flags & _PASSWORD_NOUID))
241 			pw->pw_uid = __ypproto->pw_uid;
242 		if (!(yp_pw_flags & _PASSWORD_NOGID))
243 			pw->pw_gid = __ypproto->pw_gid;
244 		if (__ypproto->pw_gecos)
245 			pw->pw_gecos = __ypproto->pw_gecos;
246 		if (__ypproto->pw_dir)
247 			pw->pw_dir = __ypproto->pw_dir;
248 		if (__ypproto->pw_shell)
249 			pw->pw_shell = __ypproto->pw_shell;
250 	}
251 	return (0);
252 }
253 #endif
254 
255 static struct passwd *
__get_pw_buf(char ** bufp,size_t * buflenp,uid_t uid,const char * name)256 __get_pw_buf(char **bufp, size_t *buflenp, uid_t uid, const char *name)
257 {
258 	bool remap = true;
259 
260 	/* Unmap the old buffer unless we are looking up the same uid/name */
261 	if (_pw_storage != MAP_FAILED) {
262 		if (name != NULL) {
263 			if (strcmp(_pw_storage->name, name) == 0) {
264 #ifdef PWDEBUG
265 				struct syslog_data sdata = SYSLOG_DATA_INIT;
266 				syslog_r(LOG_CRIT | LOG_CONS, &sdata,
267 				    "repeated passwd lookup of user \"%s\"",
268 				    name);
269 #endif
270 				remap = false;
271 			}
272 		} else if (uid != (uid_t)-1) {
273 			if (_pw_storage->uid == uid) {
274 #ifdef PWDEBUG
275 				struct syslog_data sdata = SYSLOG_DATA_INIT;
276 				syslog_r(LOG_CRIT | LOG_CONS, &sdata,
277 				    "repeated passwd lookup of uid %u",
278 				    uid);
279 #endif
280 				remap = false;
281 			}
282 		}
283 		if (remap)
284 			munmap(_pw_storage, sizeof(*_pw_storage));
285 	}
286 
287 	if (remap) {
288 		_pw_storage = mmap(NULL, sizeof(*_pw_storage),
289 		    PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
290 		if (_pw_storage == MAP_FAILED)
291 			return NULL;
292 		if (name != NULL)
293 			strlcpy(_pw_storage->name, name, sizeof(_pw_storage->name));
294 		_pw_storage->uid = uid;
295 	}
296 
297 	*bufp = _pw_storage->pwbuf;
298 	*buflenp = sizeof(_pw_storage->pwbuf);
299 	return &_pw_storage->pw;
300 }
301 
302 struct passwd *
getpwent(void)303 getpwent(void)
304 {
305 #ifdef YP
306 	static char *name = NULL;
307 	char *map;
308 #endif
309 	char bf[1 + sizeof(_pw_keynum)];
310 	struct passwd *pw, *ret = NULL;
311 	char *pwbuf;
312 	size_t buflen;
313 	DBT key;
314 
315 	_THREAD_PRIVATE_MUTEX_LOCK(pw);
316 	if (!_pw_db && !__initdb(0))
317 		goto done;
318 
319 	/* Allocate space for struct and strings, unmapping the old. */
320 	if ((pw = __get_pw_buf(&pwbuf, &buflen, -1, NULL)) == NULL)
321 		goto done;
322 
323 #ifdef YP
324 	map = PASSWD_BYNAME;
325 
326 	if (__getpwent_has_yppw == -1)
327 		__getpwent_has_yppw = __has_yppw();
328 
329 again:
330 	if (__getpwent_has_yppw && (__ypmode != YPMODE_NONE)) {
331 		const char *user, *host, *dom;
332 		int keylen, datalen, r, s;
333 		char *key, *data = NULL;
334 
335 		if (!__ypdomain) {
336 			if (_yp_check(&__ypdomain) == 0) {
337 				__ypmode = YPMODE_NONE;
338 				goto again;
339 			}
340 		}
341 		switch (__ypmode) {
342 		case YPMODE_FULL:
343 			if (__ypcurrent) {
344 				r = yp_next(__ypdomain, map,
345 				    __ypcurrent, __ypcurrentlen,
346 				    &key, &keylen, &data, &datalen);
347 				free(__ypcurrent);
348 				__ypcurrent = NULL;
349 				if (r != 0) {
350 					__ypmode = YPMODE_NONE;
351 					free(data);
352 					goto again;
353 				}
354 				__ypcurrent = key;
355 				__ypcurrentlen = keylen;
356 			} else {
357 				r = yp_first(__ypdomain, map,
358 				    &__ypcurrent, &__ypcurrentlen,
359 				    &data, &datalen);
360 				if (r != 0 ||
361 				    __ypcurrentlen > buflen) {
362 					__ypmode = YPMODE_NONE;
363 					free(data);
364 					goto again;
365 				}
366 			}
367 			bcopy(data, pwbuf, datalen);
368 			free(data);
369 			break;
370 		case YPMODE_NETGRP:
371 			s = getnetgrent(&host, &user, &dom);
372 			if (s == 0) {	/* end of group */
373 				endnetgrent();
374 				__ypmode = YPMODE_NONE;
375 				goto again;
376 			}
377 			if (user && *user) {
378 				r = yp_match(__ypdomain, map,
379 				    user, strlen(user), &data, &datalen);
380 			} else
381 				goto again;
382 			if (r != 0 ||
383 			    __ypcurrentlen > buflen) {
384 				/*
385 				 * if the netgroup is invalid, keep looking
386 				 * as there may be valid users later on.
387 				 */
388 				free(data);
389 				goto again;
390 			}
391 			bcopy(data, pwbuf, datalen);
392 			free(data);
393 			break;
394 		case YPMODE_USER:
395 			if (name) {
396 				r = yp_match(__ypdomain, map,
397 				    name, strlen(name), &data, &datalen);
398 				__ypmode = YPMODE_NONE;
399 				free(name);
400 				name = NULL;
401 				if (r != 0 ||
402 				    __ypcurrentlen > buflen) {
403 					free(data);
404 					goto again;
405 				}
406 				bcopy(data, pwbuf, datalen);
407 				free(data);
408 			} else {		/* XXX */
409 				__ypmode = YPMODE_NONE;
410 				goto again;
411 			}
412 			break;
413 		case YPMODE_NONE:
414 			/* NOTREACHED */
415 			break;
416 		}
417 
418 		pwbuf[datalen] = '\0';
419 		if (__ypparse(pw, pwbuf, __yp_pw_flags))
420 			goto again;
421 		ret = pw;
422 		goto done;
423 	}
424 #endif
425 
426 	++_pw_keynum;
427 	bf[0] = _PW_KEYBYNUM;
428 	bcopy((char *)&_pw_keynum, &bf[1], sizeof(_pw_keynum));
429 	key.data = (u_char *)bf;
430 	key.size = 1 + sizeof(_pw_keynum);
431 	if (__hashpw(&key, pwbuf, buflen, pw, &_pw_flags)) {
432 #ifdef YP
433 		static struct pw_storage __yppbuf;
434 		const char *user, *host, *dom;
435 
436 		/* if we don't have YP at all, don't bother. */
437 		if (__getpwent_has_yppw) {
438 			if (pw->pw_name[0] == '+') {
439 				/* set the mode */
440 				switch (pw->pw_name[1]) {
441 				case '\0':
442 					__ypmode = YPMODE_FULL;
443 					break;
444 				case '@':
445 					__ypmode = YPMODE_NETGRP;
446 					setnetgrent(pw->pw_name + 2);
447 					break;
448 				default:
449 					__ypmode = YPMODE_USER;
450 					name = strdup(pw->pw_name + 1);
451 					break;
452 				}
453 
454 				__ypproto_set(pw, &__yppbuf, _pw_flags,
455 				    &__yp_pw_flags);
456 				goto again;
457 			} else if (pw->pw_name[0] == '-') {
458 				/* an attempted exclusion */
459 				switch (pw->pw_name[1]) {
460 				case '\0':
461 					break;
462 				case '@':
463 					setnetgrent(pw->pw_name + 2);
464 					while (getnetgrent(&host, &user, &dom)) {
465 						if (user && *user)
466 							__ypexclude_add(&__ypexhead,
467 							    user);
468 					}
469 					endnetgrent();
470 					break;
471 				default:
472 					__ypexclude_add(&__ypexhead,
473 					    pw->pw_name + 1);
474 					break;
475 				}
476 				goto again;
477 			}
478 		}
479 #endif
480 		ret = pw;
481 		goto done;
482 	}
483 
484 done:
485 	_THREAD_PRIVATE_MUTEX_UNLOCK(pw);
486 	return (ret);
487 }
488 
489 #ifdef YP
490 /*
491  * See if the YP token is in the database.  Only works if pwd_mkdb knows
492  * about the token.
493  */
494 static int
__has_yppw(void)495 __has_yppw(void)
496 {
497 	DBT key, data, pkey, pdata;
498 	char bf[2];
499 
500 	key.data = (u_char *)_PW_YPTOKEN;
501 	key.size = strlen(_PW_YPTOKEN);
502 
503 	/* Pre-token database support. */
504 	bf[0] = _PW_KEYBYNAME;
505 	bf[1] = '+';
506 	pkey.data = (u_char *)bf;
507 	pkey.size = sizeof(bf);
508 
509 	if ((_pw_db->get)(_pw_db, &key, &data, 0) &&
510 	    (_pw_db->get)(_pw_db, &pkey, &pdata, 0))
511 		return (0);	/* No YP. */
512 	return (1);
513 }
514 
515 /*
516  * See if there's a master.passwd map.
517  */
518 static int
__has_ypmaster(void)519 __has_ypmaster(void)
520 {
521 	int keylen, resultlen;
522 	char *key, *result;
523 	static int checked = -1;
524 	static uid_t saved_uid, saved_euid;
525 	uid_t uid = getuid(), euid = geteuid();
526 
527 	/*
528 	 * Do not recheck IFF the saved UID and the saved
529 	 * EUID are the same. In all other cases, recheck.
530 	 */
531 	if (checked != -1 && saved_uid == uid && saved_euid == euid)
532 		return (checked);
533 
534 	if (euid != 0) {
535 		saved_uid = uid;
536 		saved_euid = euid;
537 		checked = 0;
538 		return (checked);
539 	}
540 
541 	if (!__ypdomain) {
542 		if (_yp_check(&__ypdomain) == 0) {
543 			saved_uid = uid;
544 			saved_euid = euid;
545 			checked = 0;
546 			return (checked);	/* No domain. */
547 		}
548 	}
549 
550 	if (yp_first(__ypdomain, "master.passwd.byname",
551 	    &key, &keylen, &result, &resultlen)) {
552 		saved_uid = uid;
553 		saved_euid = euid;
554 		checked = 0;
555 		return (checked);
556 	}
557 	free(result);
558 	free(key);
559 
560 	saved_uid = uid;
561 	saved_euid = euid;
562 	checked = 1;
563 	return (checked);
564 }
565 
566 static struct passwd *
__yppwlookup(int lookup,char * name,uid_t uid,struct passwd * pw,char * buf,size_t buflen,int * flagsp)567 __yppwlookup(int lookup, char *name, uid_t uid, struct passwd *pw,
568     char *buf, size_t buflen, int *flagsp)
569 {
570 	char bf[1 + _PW_NAME_LEN], *ypcurrent = NULL, *map = NULL;
571 	int yp_pw_flags = 0, ypcurrentlen, r, s = -1, pw_keynum;
572 	static struct pw_storage __yppbuf;
573 	struct _ypexclude *ypexhead = NULL;
574 	const char *host, *user, *dom;
575 	DBT key;
576 
577 	for (pw_keynum = 1; pw_keynum; pw_keynum++) {
578 		bf[0] = _PW_KEYBYNUM;
579 		bcopy((char *)&pw_keynum, &bf[1], sizeof(pw_keynum));
580 		key.data = (u_char *)bf;
581 		key.size = 1 + sizeof(pw_keynum);
582 		if (__hashpw(&key, buf, buflen, pw, flagsp) == 0)
583 			break;
584 		switch (pw->pw_name[0]) {
585 		case '+':
586 			if (!__ypdomain) {
587 				if (_yp_check(&__ypdomain) == 0)
588 					continue;
589 			}
590 			__ypproto_set(pw, &__yppbuf, *flagsp, &yp_pw_flags);
591 			if (!map) {
592 				if (lookup == LOOKUP_BYNAME) {
593 					if ((name = strdup(name)) == NULL) {
594 						pw = NULL;
595 						goto done;
596 					}
597 					map = PASSWD_BYNAME;
598 				} else {
599 					if (asprintf(&name, "%u", uid) == -1) {
600 						pw = NULL;
601 						goto done;
602 					}
603 					map = PASSWD_BYUID;
604 				}
605 			}
606 
607 			switch (pw->pw_name[1]) {
608 			case '\0':
609 				free(ypcurrent);
610 				ypcurrent = NULL;
611 				r = yp_match(__ypdomain, map,
612 				    name, strlen(name),
613 				    &ypcurrent, &ypcurrentlen);
614 				if (r != 0 || ypcurrentlen > buflen) {
615 					free(ypcurrent);
616 					ypcurrent = NULL;
617 					continue;
618 				}
619 				break;
620 			case '@':
621 pwnam_netgrp:
622 				free(ypcurrent);
623 				ypcurrent = NULL;
624 				if (s == -1)	/* first time */
625 					setnetgrent(pw->pw_name + 2);
626 				s = getnetgrent(&host, &user, &dom);
627 				if (s == 0) {	/* end of group */
628 					endnetgrent();
629 					s = -1;
630 					continue;
631 				} else {
632 					if (user && *user) {
633 						r = yp_match(__ypdomain, map,
634 						    user, strlen(user),
635 						    &ypcurrent, &ypcurrentlen);
636 					} else
637 						goto pwnam_netgrp;
638 					if (r != 0 || ypcurrentlen > buflen) {
639 						free(ypcurrent);
640 						ypcurrent = NULL;
641 						/*
642 						 * just because this
643 						 * user is bad, doesn't
644 						 * mean they all are.
645 						 */
646 						goto pwnam_netgrp;
647 					}
648 				}
649 				break;
650 			default:
651 				free(ypcurrent);
652 				ypcurrent = NULL;
653 				user = pw->pw_name + 1;
654 				r = yp_match(__ypdomain, map,
655 				    user, strlen(user),
656 				    &ypcurrent, &ypcurrentlen);
657 				if (r != 0 || ypcurrentlen > buflen) {
658 					free(ypcurrent);
659 					ypcurrent = NULL;
660 					continue;
661 				}
662 				break;
663 			}
664 			bcopy(ypcurrent, buf, ypcurrentlen);
665 			buf[ypcurrentlen] = '\0';
666 			if (__ypparse(pw, buf, yp_pw_flags) ||
667 			    __ypexclude_is(&ypexhead, pw->pw_name)) {
668 				if (s == 1)	/* inside netgrp */
669 					goto pwnam_netgrp;
670 				continue;
671 			}
672 			break;
673 		case '-':
674 			/* attempted exclusion */
675 			switch (pw->pw_name[1]) {
676 			case '\0':
677 				break;
678 			case '@':
679 				setnetgrent(pw->pw_name + 2);
680 				while (getnetgrent(&host, &user, &dom)) {
681 					if (user && *user)
682 						__ypexclude_add(&ypexhead, user);
683 				}
684 				endnetgrent();
685 				break;
686 			default:
687 				__ypexclude_add(&ypexhead, pw->pw_name + 1);
688 				break;
689 			}
690 			break;
691 		}
692 		if ((lookup == LOOKUP_BYUID && pw->pw_uid == uid) ||
693 		    (lookup == LOOKUP_BYNAME && strcmp(pw->pw_name, name) == 0))
694 			goto done;
695 		if (s == 1)	/* inside netgrp */
696 			goto pwnam_netgrp;
697 		continue;
698 	}
699 	pw = NULL;
700 done:
701 	__ypexclude_free(&ypexhead);
702 	__ypproto = NULL;
703 	free(ypcurrent);
704 	ypcurrent = NULL;
705 	if (map)
706 		free(name);
707 	return (pw);
708 }
709 #endif /* YP */
710 
711 static struct passwd *
_pwhashbyname(const char * name,char * buf,size_t buflen,struct passwd * pw,int * flagsp)712 _pwhashbyname(const char *name, char *buf, size_t buflen, struct passwd *pw,
713     int *flagsp)
714 {
715 	char bf[1 + _PW_NAME_LEN];
716 	size_t len;
717 	DBT key;
718 	int r;
719 
720 	len = strlen(name);
721 	if (len > _PW_NAME_LEN)
722 		return (NULL);
723 	bf[0] = _PW_KEYBYNAME;
724 	bcopy(name, &bf[1], MINIMUM(len, _PW_NAME_LEN));
725 	key.data = (u_char *)bf;
726 	key.size = 1 + MINIMUM(len, _PW_NAME_LEN);
727 	r = __hashpw(&key, buf, buflen, pw, flagsp);
728 	if (r)
729 		return (pw);
730 	return (NULL);
731 }
732 
733 static struct passwd *
_pwhashbyuid(uid_t uid,char * buf,size_t buflen,struct passwd * pw,int * flagsp)734 _pwhashbyuid(uid_t uid, char *buf, size_t buflen, struct passwd *pw,
735     int *flagsp)
736 {
737 	char bf[1 + sizeof(int)];
738 	DBT key;
739 	int r;
740 
741 	bf[0] = _PW_KEYBYUID;
742 	bcopy(&uid, &bf[1], sizeof(uid));
743 	key.data = (u_char *)bf;
744 	key.size = 1 + sizeof(uid);
745 	r = __hashpw(&key, buf, buflen, pw, flagsp);
746 	if (r)
747 		return (pw);
748 	return (NULL);
749 }
750 
751 static int
getpwnam_internal(const char * name,struct passwd * pw,char * buf,size_t buflen,struct passwd ** pwretp,bool shadow,bool reentrant)752 getpwnam_internal(const char *name, struct passwd *pw, char *buf, size_t buflen,
753     struct passwd **pwretp, bool shadow, bool reentrant)
754 {
755 	struct passwd *pwret = NULL;
756 	int flags = 0, *flagsp = &flags;
757 	int my_errno = 0;
758 	int saved_errno, tmp_errno;
759 
760 	_THREAD_PRIVATE_MUTEX_LOCK(pw);
761 	saved_errno = errno;
762 	errno = 0;
763 	if (!_pw_db && !__initdb(shadow))
764 		goto fail;
765 
766 	if (!reentrant) {
767 		/* Allocate space for struct and strings, unmapping the old. */
768 		if ((pw = __get_pw_buf(&buf, &buflen, -1, name)) == NULL)
769 			goto fail;
770 		flagsp = &_pw_flags;
771 	}
772 
773 #ifdef YP
774 	if (__has_yppw())
775 		pwret = __yppwlookup(LOOKUP_BYNAME, (char *)name, 0, pw,
776 		    buf, buflen, flagsp);
777 #endif /* YP */
778 	if (!pwret)
779 		pwret = _pwhashbyname(name, buf, buflen, pw, flagsp);
780 
781 	if (!_pw_stayopen) {
782 		tmp_errno = errno;
783 		(void)(_pw_db->close)(_pw_db);
784 		_pw_db = NULL;
785 		errno = tmp_errno;
786 	}
787 fail:
788 	if (pwretp)
789 		*pwretp = pwret;
790 	if (pwret == NULL)
791 		my_errno = errno;
792 	errno = saved_errno;
793 	_THREAD_PRIVATE_MUTEX_UNLOCK(pw);
794 	return (my_errno);
795 }
796 
797 int
getpwnam_r(const char * name,struct passwd * pw,char * buf,size_t buflen,struct passwd ** pwretp)798 getpwnam_r(const char *name, struct passwd *pw, char *buf, size_t buflen,
799     struct passwd **pwretp)
800 {
801 	return getpwnam_internal(name, pw, buf, buflen, pwretp, false, true);
802 }
803 DEF_WEAK(getpwnam_r);
804 
805 struct passwd *
getpwnam(const char * name)806 getpwnam(const char *name)
807 {
808 	struct passwd *pw = NULL;
809 	int my_errno;
810 
811 	my_errno = getpwnam_internal(name, NULL, NULL, 0, &pw, false, false);
812 	if (my_errno) {
813 		pw = NULL;
814 		errno = my_errno;
815 	}
816 	return (pw);
817 }
818 
819 struct passwd *
getpwnam_shadow(const char * name)820 getpwnam_shadow(const char *name)
821 {
822 	struct passwd *pw = NULL;
823 	int my_errno;
824 
825 	my_errno = getpwnam_internal(name, NULL, NULL, 0, &pw, true, false);
826 	if (my_errno) {
827 		pw = NULL;
828 		errno = my_errno;
829 	}
830 	return (pw);
831 }
832 DEF_WEAK(getpwnam_shadow);
833 
834 static int
getpwuid_internal(uid_t uid,struct passwd * pw,char * buf,size_t buflen,struct passwd ** pwretp,bool shadow,bool reentrant)835 getpwuid_internal(uid_t uid, struct passwd *pw, char *buf, size_t buflen,
836     struct passwd **pwretp, bool shadow, bool reentrant)
837 {
838 	struct passwd *pwret = NULL;
839 	int flags = 0, *flagsp = &flags;
840 	int my_errno = 0;
841 	int saved_errno, tmp_errno;
842 
843 	_THREAD_PRIVATE_MUTEX_LOCK(pw);
844 	saved_errno = errno;
845 	errno = 0;
846 	if (!_pw_db && !__initdb(shadow))
847 		goto fail;
848 
849 	if (!reentrant) {
850 		/* Allocate space for struct and strings, unmapping the old. */
851 		if ((pw = __get_pw_buf(&buf, &buflen, uid, NULL)) == NULL)
852 			goto fail;
853 		flagsp = &_pw_flags;
854 	}
855 
856 #ifdef YP
857 	if (__has_yppw())
858 		pwret = __yppwlookup(LOOKUP_BYUID, NULL, uid, pw,
859 		    buf, buflen, flagsp);
860 #endif /* YP */
861 	if (!pwret)
862 		pwret = _pwhashbyuid(uid, buf, buflen, pw, flagsp);
863 
864 	if (!_pw_stayopen) {
865 		tmp_errno = errno;
866 		(void)(_pw_db->close)(_pw_db);
867 		_pw_db = NULL;
868 		errno = tmp_errno;
869 	}
870 fail:
871 	if (pwretp)
872 		*pwretp = pwret;
873 	if (pwret == NULL)
874 		my_errno = errno;
875 	errno = saved_errno;
876 	_THREAD_PRIVATE_MUTEX_UNLOCK(pw);
877 	return (my_errno);
878 }
879 
880 
881 int
getpwuid_r(uid_t uid,struct passwd * pw,char * buf,size_t buflen,struct passwd ** pwretp)882 getpwuid_r(uid_t uid, struct passwd *pw, char *buf, size_t buflen,
883     struct passwd **pwretp)
884 {
885 	return getpwuid_internal(uid, pw, buf, buflen, pwretp, false, true);
886 }
887 DEF_WEAK(getpwuid_r);
888 
889 struct passwd *
getpwuid(uid_t uid)890 getpwuid(uid_t uid)
891 {
892 	struct passwd *pw = NULL;
893 	int my_errno;
894 
895 	my_errno = getpwuid_internal(uid, NULL, NULL, 0, &pw, false, false);
896 	if (my_errno) {
897 		pw = NULL;
898 		errno = my_errno;
899 	}
900 	return (pw);
901 }
902 
903 struct passwd *
getpwuid_shadow(uid_t uid)904 getpwuid_shadow(uid_t uid)
905 {
906 	struct passwd *pw = NULL;
907 	int my_errno;
908 
909 	my_errno = getpwuid_internal(uid, NULL, NULL, 0, &pw, true, false);
910 	if (my_errno) {
911 		pw = NULL;
912 		errno = my_errno;
913 	}
914 	return (pw);
915 }
916 DEF_WEAK(getpwuid_shadow);
917 
918 int
setpassent(int stayopen)919 setpassent(int stayopen)
920 {
921 	_THREAD_PRIVATE_MUTEX_LOCK(pw);
922 	_pw_keynum = 0;
923 	_pw_stayopen = stayopen;
924 #ifdef YP
925 	__ypmode = YPMODE_NONE;
926 	free(__ypcurrent);
927 	__ypcurrent = NULL;
928 	__ypexclude_free(&__ypexhead);
929 	__ypproto = NULL;
930 #endif
931 	_THREAD_PRIVATE_MUTEX_UNLOCK(pw);
932 	return (1);
933 }
934 DEF_WEAK(setpassent);
935 
936 void
setpwent(void)937 setpwent(void)
938 {
939 	(void) setpassent(0);
940 }
941 
942 void
endpwent(void)943 endpwent(void)
944 {
945 	int saved_errno;
946 
947 	_THREAD_PRIVATE_MUTEX_LOCK(pw);
948 	saved_errno = errno;
949 	_pw_keynum = 0;
950 	if (_pw_db) {
951 		(void)(_pw_db->close)(_pw_db);
952 		_pw_db = NULL;
953 	}
954 #ifdef YP
955 	__ypmode = YPMODE_NONE;
956 	free(__ypcurrent);
957 	__ypcurrent = NULL;
958 	__ypexclude_free(&__ypexhead);
959 	__ypproto = NULL;
960 #endif
961 	errno = saved_errno;
962 	_THREAD_PRIVATE_MUTEX_UNLOCK(pw);
963 }
964 
965 static int
__initdb(int shadow)966 __initdb(int shadow)
967 {
968 	static int warned;
969 	int saved_errno = errno;
970 
971 #ifdef YP
972 	/*
973 	 * Hint to the kernel that a passwd database operation is happening.
974 	 */
975 	(void)access("/var/run/ypbind.lock", R_OK);
976 	errno = saved_errno;
977 
978 	__ypmode = YPMODE_NONE;
979 	__getpwent_has_yppw = -1;
980 #endif
981 	if (shadow)
982 		_pw_db = dbopen(_PATH_SMP_DB, O_RDONLY, 0, DB_HASH, NULL);
983 	if (!_pw_db)
984 	    _pw_db = dbopen(_PATH_MP_DB, O_RDONLY, 0, DB_HASH, NULL);
985 	if (_pw_db) {
986 		errno = saved_errno;
987 		return (1);
988 	}
989 	if (!warned) {
990 		saved_errno = errno;
991 		errno = saved_errno;
992 		warned = 1;
993 	}
994 	return (0);
995 }
996 
997 static int
__hashpw(DBT * key,char * buf,size_t buflen,struct passwd * pw,int * flagsp)998 __hashpw(DBT *key, char *buf, size_t buflen, struct passwd *pw,
999     int *flagsp)
1000 {
1001 	char *p, *t;
1002 	DBT data;
1003 
1004 	if ((_pw_db->get)(_pw_db, key, &data, 0))
1005 		return (0);
1006 	p = (char *)data.data;
1007 	if (data.size > buflen) {
1008 		errno = ERANGE;
1009 		return (0);
1010 	}
1011 
1012 	t = buf;
1013 #define	EXPAND(e)	e = t; while ((*t++ = *p++));
1014 	EXPAND(pw->pw_name);
1015 	EXPAND(pw->pw_passwd);
1016 	bcopy(p, (char *)&pw->pw_uid, sizeof(int));
1017 	p += sizeof(int);
1018 	bcopy(p, (char *)&pw->pw_gid, sizeof(int));
1019 	p += sizeof(int);
1020 	bcopy(p, (char *)&pw->pw_change, sizeof(time_t));
1021 	p += sizeof(time_t);
1022 	EXPAND(pw->pw_class);
1023 	EXPAND(pw->pw_gecos);
1024 	EXPAND(pw->pw_dir);
1025 	EXPAND(pw->pw_shell);
1026 	bcopy(p, (char *)&pw->pw_expire, sizeof(time_t));
1027 	p += sizeof(time_t);
1028 
1029 	/* See if there's any data left.  If so, read in flags. */
1030 	if (data.size > (p - (char *)data.data)) {
1031 		bcopy(p, (char *)flagsp, sizeof(int));
1032 		p += sizeof(int);
1033 	} else
1034 		*flagsp = _PASSWORD_NOUID|_PASSWORD_NOGID;	/* default */
1035 	return (1);
1036 }
1037