1 /* $OpenBSD: getpwent.c,v 1.68 2024/01/22 21:07:09 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 yp_get_default_domain(&__ypdomain);
337 switch (__ypmode) {
338 case YPMODE_FULL:
339 if (__ypcurrent) {
340 r = yp_next(__ypdomain, map,
341 __ypcurrent, __ypcurrentlen,
342 &key, &keylen, &data, &datalen);
343 free(__ypcurrent);
344 __ypcurrent = NULL;
345 if (r != 0) {
346 __ypmode = YPMODE_NONE;
347 free(data);
348 goto again;
349 }
350 __ypcurrent = key;
351 __ypcurrentlen = keylen;
352 } else {
353 r = yp_first(__ypdomain, map,
354 &__ypcurrent, &__ypcurrentlen,
355 &data, &datalen);
356 if (r != 0 ||
357 __ypcurrentlen > buflen) {
358 __ypmode = YPMODE_NONE;
359 free(data);
360 goto again;
361 }
362 }
363 bcopy(data, pwbuf, datalen);
364 free(data);
365 break;
366 case YPMODE_NETGRP:
367 s = getnetgrent(&host, &user, &dom);
368 if (s == 0) { /* end of group */
369 endnetgrent();
370 __ypmode = YPMODE_NONE;
371 goto again;
372 }
373 if (user && *user) {
374 r = yp_match(__ypdomain, map,
375 user, strlen(user), &data, &datalen);
376 } else
377 goto again;
378 if (r != 0 ||
379 __ypcurrentlen > buflen) {
380 /*
381 * if the netgroup is invalid, keep looking
382 * as there may be valid users later on.
383 */
384 free(data);
385 goto again;
386 }
387 bcopy(data, pwbuf, datalen);
388 free(data);
389 break;
390 case YPMODE_USER:
391 if (name) {
392 r = yp_match(__ypdomain, map,
393 name, strlen(name), &data, &datalen);
394 __ypmode = YPMODE_NONE;
395 free(name);
396 name = NULL;
397 if (r != 0 ||
398 __ypcurrentlen > buflen) {
399 free(data);
400 goto again;
401 }
402 bcopy(data, pwbuf, datalen);
403 free(data);
404 } else { /* XXX */
405 __ypmode = YPMODE_NONE;
406 goto again;
407 }
408 break;
409 case YPMODE_NONE:
410 /* NOTREACHED */
411 break;
412 }
413
414 pwbuf[datalen] = '\0';
415 if (__ypparse(pw, pwbuf, __yp_pw_flags))
416 goto again;
417 ret = pw;
418 goto done;
419 }
420 #endif
421
422 ++_pw_keynum;
423 bf[0] = _PW_KEYBYNUM;
424 bcopy((char *)&_pw_keynum, &bf[1], sizeof(_pw_keynum));
425 key.data = (u_char *)bf;
426 key.size = 1 + sizeof(_pw_keynum);
427 if (__hashpw(&key, pwbuf, buflen, pw, &_pw_flags)) {
428 #ifdef YP
429 static struct pw_storage __yppbuf;
430 const char *user, *host, *dom;
431
432 /* if we don't have YP at all, don't bother. */
433 if (__getpwent_has_yppw) {
434 if (pw->pw_name[0] == '+') {
435 /* set the mode */
436 switch (pw->pw_name[1]) {
437 case '\0':
438 __ypmode = YPMODE_FULL;
439 break;
440 case '@':
441 __ypmode = YPMODE_NETGRP;
442 setnetgrent(pw->pw_name + 2);
443 break;
444 default:
445 __ypmode = YPMODE_USER;
446 name = strdup(pw->pw_name + 1);
447 break;
448 }
449
450 __ypproto_set(pw, &__yppbuf, _pw_flags,
451 &__yp_pw_flags);
452 goto again;
453 } else if (pw->pw_name[0] == '-') {
454 /* an attempted exclusion */
455 switch (pw->pw_name[1]) {
456 case '\0':
457 break;
458 case '@':
459 setnetgrent(pw->pw_name + 2);
460 while (getnetgrent(&host, &user, &dom)) {
461 if (user && *user)
462 __ypexclude_add(&__ypexhead,
463 user);
464 }
465 endnetgrent();
466 break;
467 default:
468 __ypexclude_add(&__ypexhead,
469 pw->pw_name + 1);
470 break;
471 }
472 goto again;
473 }
474 }
475 #endif
476 ret = pw;
477 goto done;
478 }
479
480 done:
481 _THREAD_PRIVATE_MUTEX_UNLOCK(pw);
482 return (ret);
483 }
484
485 #ifdef YP
486 /*
487 * See if the YP token is in the database. Only works if pwd_mkdb knows
488 * about the token.
489 */
490 static int
__has_yppw(void)491 __has_yppw(void)
492 {
493 DBT key, data, pkey, pdata;
494 char bf[2];
495
496 key.data = (u_char *)_PW_YPTOKEN;
497 key.size = strlen(_PW_YPTOKEN);
498
499 /* Pre-token database support. */
500 bf[0] = _PW_KEYBYNAME;
501 bf[1] = '+';
502 pkey.data = (u_char *)bf;
503 pkey.size = sizeof(bf);
504
505 if ((_pw_db->get)(_pw_db, &key, &data, 0) &&
506 (_pw_db->get)(_pw_db, &pkey, &pdata, 0))
507 return (0); /* No YP. */
508 return (1);
509 }
510
511 /*
512 * See if there's a master.passwd map.
513 */
514 static int
__has_ypmaster(void)515 __has_ypmaster(void)
516 {
517 int keylen, resultlen;
518 char *key, *result;
519 static int checked = -1;
520 static uid_t saved_uid, saved_euid;
521 uid_t uid = getuid(), euid = geteuid();
522
523 /*
524 * Do not recheck IFF the saved UID and the saved
525 * EUID are the same. In all other cases, recheck.
526 */
527 if (checked != -1 && saved_uid == uid && saved_euid == euid)
528 return (checked);
529
530 if (euid != 0) {
531 saved_uid = uid;
532 saved_euid = euid;
533 checked = 0;
534 return (checked);
535 }
536
537 if (!__ypdomain)
538 yp_get_default_domain(&__ypdomain);
539
540 if (yp_first(__ypdomain, "master.passwd.byname",
541 &key, &keylen, &result, &resultlen)) {
542 saved_uid = uid;
543 saved_euid = euid;
544 checked = 0;
545 return (checked);
546 }
547 free(result);
548 free(key);
549
550 saved_uid = uid;
551 saved_euid = euid;
552 checked = 1;
553 return (checked);
554 }
555
556 static struct passwd *
__yppwlookup(int lookup,char * name,uid_t uid,struct passwd * pw,char * buf,size_t buflen,int * flagsp)557 __yppwlookup(int lookup, char *name, uid_t uid, struct passwd *pw,
558 char *buf, size_t buflen, int *flagsp)
559 {
560 char bf[1 + _PW_NAME_LEN], *ypcurrent = NULL, *map = NULL;
561 int yp_pw_flags = 0, ypcurrentlen, r, s = -1, pw_keynum;
562 static struct pw_storage __yppbuf;
563 struct _ypexclude *ypexhead = NULL;
564 const char *host, *user, *dom;
565 DBT key;
566
567 for (pw_keynum = 1; pw_keynum; pw_keynum++) {
568 bf[0] = _PW_KEYBYNUM;
569 bcopy((char *)&pw_keynum, &bf[1], sizeof(pw_keynum));
570 key.data = (u_char *)bf;
571 key.size = 1 + sizeof(pw_keynum);
572 if (__hashpw(&key, buf, buflen, pw, flagsp) == 0)
573 break;
574 switch (pw->pw_name[0]) {
575 case '+':
576 if (!__ypdomain)
577 yp_get_default_domain(&__ypdomain);
578 __ypproto_set(pw, &__yppbuf, *flagsp, &yp_pw_flags);
579 if (!map) {
580 if (lookup == LOOKUP_BYNAME) {
581 if ((name = strdup(name)) == NULL) {
582 pw = NULL;
583 goto done;
584 }
585 map = PASSWD_BYNAME;
586 } else {
587 if (asprintf(&name, "%u", uid) == -1) {
588 pw = NULL;
589 goto done;
590 }
591 map = PASSWD_BYUID;
592 }
593 }
594
595 switch (pw->pw_name[1]) {
596 case '\0':
597 free(ypcurrent);
598 ypcurrent = NULL;
599 r = yp_match(__ypdomain, map,
600 name, strlen(name),
601 &ypcurrent, &ypcurrentlen);
602 if (r != 0 || ypcurrentlen > buflen) {
603 free(ypcurrent);
604 ypcurrent = NULL;
605 continue;
606 }
607 break;
608 case '@':
609 pwnam_netgrp:
610 free(ypcurrent);
611 ypcurrent = NULL;
612 if (s == -1) /* first time */
613 setnetgrent(pw->pw_name + 2);
614 s = getnetgrent(&host, &user, &dom);
615 if (s == 0) { /* end of group */
616 endnetgrent();
617 s = -1;
618 continue;
619 } else {
620 if (user && *user) {
621 r = yp_match(__ypdomain, map,
622 user, strlen(user),
623 &ypcurrent, &ypcurrentlen);
624 } else
625 goto pwnam_netgrp;
626 if (r != 0 || ypcurrentlen > buflen) {
627 free(ypcurrent);
628 ypcurrent = NULL;
629 /*
630 * just because this
631 * user is bad, doesn't
632 * mean they all are.
633 */
634 goto pwnam_netgrp;
635 }
636 }
637 break;
638 default:
639 free(ypcurrent);
640 ypcurrent = NULL;
641 user = pw->pw_name + 1;
642 r = yp_match(__ypdomain, map,
643 user, strlen(user),
644 &ypcurrent, &ypcurrentlen);
645 if (r != 0 || ypcurrentlen > buflen) {
646 free(ypcurrent);
647 ypcurrent = NULL;
648 continue;
649 }
650 break;
651 }
652 bcopy(ypcurrent, buf, ypcurrentlen);
653 buf[ypcurrentlen] = '\0';
654 if (__ypparse(pw, buf, yp_pw_flags) ||
655 __ypexclude_is(&ypexhead, pw->pw_name)) {
656 if (s == 1) /* inside netgrp */
657 goto pwnam_netgrp;
658 continue;
659 }
660 break;
661 case '-':
662 /* attempted exclusion */
663 switch (pw->pw_name[1]) {
664 case '\0':
665 break;
666 case '@':
667 setnetgrent(pw->pw_name + 2);
668 while (getnetgrent(&host, &user, &dom)) {
669 if (user && *user)
670 __ypexclude_add(&ypexhead, user);
671 }
672 endnetgrent();
673 break;
674 default:
675 __ypexclude_add(&ypexhead, pw->pw_name + 1);
676 break;
677 }
678 break;
679 }
680 if ((lookup == LOOKUP_BYUID && pw->pw_uid == uid) ||
681 (lookup == LOOKUP_BYNAME && strcmp(pw->pw_name, name) == 0))
682 goto done;
683 if (s == 1) /* inside netgrp */
684 goto pwnam_netgrp;
685 continue;
686 }
687 pw = NULL;
688 done:
689 __ypexclude_free(&ypexhead);
690 __ypproto = NULL;
691 free(ypcurrent);
692 ypcurrent = NULL;
693 if (map)
694 free(name);
695 return (pw);
696 }
697 #endif /* YP */
698
699 static struct passwd *
_pwhashbyname(const char * name,char * buf,size_t buflen,struct passwd * pw,int * flagsp)700 _pwhashbyname(const char *name, char *buf, size_t buflen, struct passwd *pw,
701 int *flagsp)
702 {
703 char bf[1 + _PW_NAME_LEN];
704 size_t len;
705 DBT key;
706 int r;
707
708 len = strlen(name);
709 if (len > _PW_NAME_LEN)
710 return (NULL);
711 bf[0] = _PW_KEYBYNAME;
712 bcopy(name, &bf[1], MINIMUM(len, _PW_NAME_LEN));
713 key.data = (u_char *)bf;
714 key.size = 1 + MINIMUM(len, _PW_NAME_LEN);
715 r = __hashpw(&key, buf, buflen, pw, flagsp);
716 if (r)
717 return (pw);
718 return (NULL);
719 }
720
721 static struct passwd *
_pwhashbyuid(uid_t uid,char * buf,size_t buflen,struct passwd * pw,int * flagsp)722 _pwhashbyuid(uid_t uid, char *buf, size_t buflen, struct passwd *pw,
723 int *flagsp)
724 {
725 char bf[1 + sizeof(int)];
726 DBT key;
727 int r;
728
729 bf[0] = _PW_KEYBYUID;
730 bcopy(&uid, &bf[1], sizeof(uid));
731 key.data = (u_char *)bf;
732 key.size = 1 + sizeof(uid);
733 r = __hashpw(&key, buf, buflen, pw, flagsp);
734 if (r)
735 return (pw);
736 return (NULL);
737 }
738
739 static int
getpwnam_internal(const char * name,struct passwd * pw,char * buf,size_t buflen,struct passwd ** pwretp,bool shadow,bool reentrant)740 getpwnam_internal(const char *name, struct passwd *pw, char *buf, size_t buflen,
741 struct passwd **pwretp, bool shadow, bool reentrant)
742 {
743 struct passwd *pwret = NULL;
744 int flags = 0, *flagsp = &flags;
745 int my_errno = 0;
746 int saved_errno, tmp_errno;
747
748 _THREAD_PRIVATE_MUTEX_LOCK(pw);
749 saved_errno = errno;
750 errno = 0;
751 if (!_pw_db && !__initdb(shadow))
752 goto fail;
753
754 if (!reentrant) {
755 /* Allocate space for struct and strings, unmapping the old. */
756 if ((pw = __get_pw_buf(&buf, &buflen, -1, name)) == NULL)
757 goto fail;
758 flagsp = &_pw_flags;
759 }
760
761 #ifdef YP
762 if (__has_yppw())
763 pwret = __yppwlookup(LOOKUP_BYNAME, (char *)name, 0, pw,
764 buf, buflen, flagsp);
765 #endif /* YP */
766 if (!pwret)
767 pwret = _pwhashbyname(name, buf, buflen, pw, flagsp);
768
769 if (!_pw_stayopen) {
770 tmp_errno = errno;
771 (void)(_pw_db->close)(_pw_db);
772 _pw_db = NULL;
773 errno = tmp_errno;
774 }
775 fail:
776 if (pwretp)
777 *pwretp = pwret;
778 if (pwret == NULL)
779 my_errno = errno;
780 errno = saved_errno;
781 _THREAD_PRIVATE_MUTEX_UNLOCK(pw);
782 return (my_errno);
783 }
784
785 int
getpwnam_r(const char * name,struct passwd * pw,char * buf,size_t buflen,struct passwd ** pwretp)786 getpwnam_r(const char *name, struct passwd *pw, char *buf, size_t buflen,
787 struct passwd **pwretp)
788 {
789 return getpwnam_internal(name, pw, buf, buflen, pwretp, false, true);
790 }
791 DEF_WEAK(getpwnam_r);
792
793 struct passwd *
getpwnam(const char * name)794 getpwnam(const char *name)
795 {
796 struct passwd *pw = NULL;
797 int my_errno;
798
799 my_errno = getpwnam_internal(name, NULL, NULL, 0, &pw, false, false);
800 if (my_errno) {
801 pw = NULL;
802 errno = my_errno;
803 }
804 return (pw);
805 }
806
807 struct passwd *
getpwnam_shadow(const char * name)808 getpwnam_shadow(const char *name)
809 {
810 struct passwd *pw = NULL;
811 int my_errno;
812
813 my_errno = getpwnam_internal(name, NULL, NULL, 0, &pw, true, false);
814 if (my_errno) {
815 pw = NULL;
816 errno = my_errno;
817 }
818 return (pw);
819 }
820 DEF_WEAK(getpwnam_shadow);
821
822 static int
getpwuid_internal(uid_t uid,struct passwd * pw,char * buf,size_t buflen,struct passwd ** pwretp,bool shadow,bool reentrant)823 getpwuid_internal(uid_t uid, struct passwd *pw, char *buf, size_t buflen,
824 struct passwd **pwretp, bool shadow, bool reentrant)
825 {
826 struct passwd *pwret = NULL;
827 int flags = 0, *flagsp = &flags;
828 int my_errno = 0;
829 int saved_errno, tmp_errno;
830
831 _THREAD_PRIVATE_MUTEX_LOCK(pw);
832 saved_errno = errno;
833 errno = 0;
834 if (!_pw_db && !__initdb(shadow))
835 goto fail;
836
837 if (!reentrant) {
838 /* Allocate space for struct and strings, unmapping the old. */
839 if ((pw = __get_pw_buf(&buf, &buflen, uid, NULL)) == NULL)
840 goto fail;
841 flagsp = &_pw_flags;
842 }
843
844 #ifdef YP
845 if (__has_yppw())
846 pwret = __yppwlookup(LOOKUP_BYUID, NULL, uid, pw,
847 buf, buflen, flagsp);
848 #endif /* YP */
849 if (!pwret)
850 pwret = _pwhashbyuid(uid, buf, buflen, pw, flagsp);
851
852 if (!_pw_stayopen) {
853 tmp_errno = errno;
854 (void)(_pw_db->close)(_pw_db);
855 _pw_db = NULL;
856 errno = tmp_errno;
857 }
858 fail:
859 if (pwretp)
860 *pwretp = pwret;
861 if (pwret == NULL)
862 my_errno = errno;
863 errno = saved_errno;
864 _THREAD_PRIVATE_MUTEX_UNLOCK(pw);
865 return (my_errno);
866 }
867
868
869 int
getpwuid_r(uid_t uid,struct passwd * pw,char * buf,size_t buflen,struct passwd ** pwretp)870 getpwuid_r(uid_t uid, struct passwd *pw, char *buf, size_t buflen,
871 struct passwd **pwretp)
872 {
873 return getpwuid_internal(uid, pw, buf, buflen, pwretp, false, true);
874 }
875 DEF_WEAK(getpwuid_r);
876
877 struct passwd *
getpwuid(uid_t uid)878 getpwuid(uid_t uid)
879 {
880 struct passwd *pw = NULL;
881 int my_errno;
882
883 my_errno = getpwuid_internal(uid, NULL, NULL, 0, &pw, false, false);
884 if (my_errno) {
885 pw = NULL;
886 errno = my_errno;
887 }
888 return (pw);
889 }
890
891 struct passwd *
getpwuid_shadow(uid_t uid)892 getpwuid_shadow(uid_t uid)
893 {
894 struct passwd *pw = NULL;
895 int my_errno;
896
897 my_errno = getpwuid_internal(uid, NULL, NULL, 0, &pw, true, false);
898 if (my_errno) {
899 pw = NULL;
900 errno = my_errno;
901 }
902 return (pw);
903 }
904 DEF_WEAK(getpwuid_shadow);
905
906 int
setpassent(int stayopen)907 setpassent(int stayopen)
908 {
909 _THREAD_PRIVATE_MUTEX_LOCK(pw);
910 _pw_keynum = 0;
911 _pw_stayopen = stayopen;
912 #ifdef YP
913 __ypmode = YPMODE_NONE;
914 free(__ypcurrent);
915 __ypcurrent = NULL;
916 __ypexclude_free(&__ypexhead);
917 __ypproto = NULL;
918 #endif
919 _THREAD_PRIVATE_MUTEX_UNLOCK(pw);
920 return (1);
921 }
922 DEF_WEAK(setpassent);
923
924 void
setpwent(void)925 setpwent(void)
926 {
927 (void) setpassent(0);
928 }
929
930 void
endpwent(void)931 endpwent(void)
932 {
933 int saved_errno;
934
935 _THREAD_PRIVATE_MUTEX_LOCK(pw);
936 saved_errno = errno;
937 _pw_keynum = 0;
938 if (_pw_db) {
939 (void)(_pw_db->close)(_pw_db);
940 _pw_db = NULL;
941 }
942 #ifdef YP
943 __ypmode = YPMODE_NONE;
944 free(__ypcurrent);
945 __ypcurrent = NULL;
946 __ypexclude_free(&__ypexhead);
947 __ypproto = NULL;
948 #endif
949 errno = saved_errno;
950 _THREAD_PRIVATE_MUTEX_UNLOCK(pw);
951 }
952
953 static int
__initdb(int shadow)954 __initdb(int shadow)
955 {
956 static int warned;
957 int saved_errno = errno;
958
959 #ifdef YP
960 __ypmode = YPMODE_NONE;
961 __getpwent_has_yppw = -1;
962 #endif
963 if (shadow) {
964 #ifdef FORCE_DBOPEN
965 _pw_db = dbopen(_PATH_SMP_DB, O_RDONLY, 0, DB_HASH, NULL);
966 #else
967 _pw_db = __hash_open(_PATH_SMP_DB, O_RDONLY, 0, NULL, 0);
968 #endif
969 }
970 if (!_pw_db) {
971 #ifdef FORCE_DBOPEN
972 _pw_db = dbopen(_PATH_MP_DB, O_RDONLY, 0, DB_HASH, NULL);
973 #else
974 _pw_db = __hash_open(_PATH_MP_DB, O_RDONLY, 0, NULL, 0);
975 #endif
976 }
977 if (_pw_db) {
978 errno = saved_errno;
979 return (1);
980 }
981 if (!warned) {
982 saved_errno = errno;
983 errno = saved_errno;
984 warned = 1;
985 }
986 return (0);
987 }
988
989 static int
__hashpw(DBT * key,char * buf,size_t buflen,struct passwd * pw,int * flagsp)990 __hashpw(DBT *key, char *buf, size_t buflen, struct passwd *pw,
991 int *flagsp)
992 {
993 char *p, *t;
994 DBT data;
995
996 if ((_pw_db->get)(_pw_db, key, &data, 0))
997 return (0);
998 p = (char *)data.data;
999 if (data.size > buflen) {
1000 errno = ERANGE;
1001 return (0);
1002 }
1003
1004 t = buf;
1005 #define EXPAND(e) e = t; while ((*t++ = *p++));
1006 EXPAND(pw->pw_name);
1007 EXPAND(pw->pw_passwd);
1008 bcopy(p, (char *)&pw->pw_uid, sizeof(int));
1009 p += sizeof(int);
1010 bcopy(p, (char *)&pw->pw_gid, sizeof(int));
1011 p += sizeof(int);
1012 bcopy(p, (char *)&pw->pw_change, sizeof(time_t));
1013 p += sizeof(time_t);
1014 EXPAND(pw->pw_class);
1015 EXPAND(pw->pw_gecos);
1016 EXPAND(pw->pw_dir);
1017 EXPAND(pw->pw_shell);
1018 bcopy(p, (char *)&pw->pw_expire, sizeof(time_t));
1019 p += sizeof(time_t);
1020
1021 /* See if there's any data left. If so, read in flags. */
1022 if (data.size > (p - (char *)data.data)) {
1023 bcopy(p, (char *)flagsp, sizeof(int));
1024 p += sizeof(int);
1025 } else
1026 *flagsp = _PASSWORD_NOUID|_PASSWORD_NOGID; /* default */
1027 return (1);
1028 }
1029