Bug Summary

File:src/lib/libc/gen/getpwent.c
Warning:line 418, column 3
Array subscript is undefined

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name getpwent.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/lib/libc/obj -resource-dir /usr/local/lib/clang/13.0.0 -include namespace.h -I /usr/src/lib/libc/include -I /usr/src/lib/libc/hidden -D __LIBC__ -D APIWARN -D YP -I /usr/src/lib/libc/yp -I /usr/src/lib/libc -I /usr/src/lib/libc/gdtoa -I /usr/src/lib/libc/arch/amd64/gdtoa -D INFNAN_CHECK -D MULTIPLE_THREADS -D NO_FENV_H -D USE_LOCALE -I /usr/src/lib/libc -I /usr/src/lib/libc/citrus -D RESOLVSORT -D FLOATING_POINT -D PRINTF_WIDE_CHAR -D SCANF_WIDE_CHAR -D FUTEX -D PIC -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/lib/libc/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/lib/libc/gen/getpwent.c
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(*__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 YP1
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)) (((a) < (b)) ? (a) : (b))
57
58struct pw_storage {
59 struct passwd pw;
60 uid_t uid;
61 char name[_PW_NAME_LEN31 + 1];
62 char pwbuf[_PW_BUF_LEN1024];
63};
64
65_THREAD_PRIVATE_KEY(pw)static void *_thread_tagname_pw;
66
67static DB *_pw_db; /* password database */
68
69/* mmap'd password storage */
70static struct pw_storage *_pw_storage = MAP_FAILED((void *)-1);
71
72/* Following are used only by setpwent(), getpwent(), and endpwent() */
73static int _pw_keynum; /* key counter */
74static int _pw_stayopen; /* keep fd's open */
75static int _pw_flags; /* password flags */
76
77static int __hashpw(DBT *, char *buf, size_t buflen, struct passwd *, int *);
78static int __initdb(int);
79static struct passwd *_pwhashbyname(const char *name, char *buf,
80 size_t buflen, struct passwd *pw, int *);
81static struct passwd *_pwhashbyuid(uid_t uid, char *buf,
82 size_t buflen, struct passwd *pw, int *);
83
84#ifdef YP1
85static char *__ypdomain;
86
87/* Following are used only by setpwent(), getpwent(), and endpwent() */
88enum _ypmode { YPMODE_NONE, YPMODE_FULL, YPMODE_USER, YPMODE_NETGRP };
89static enum _ypmode __ypmode;
90static char *__ypcurrent;
91static int __ypcurrentlen;
92static int __yp_pw_flags;
93static int __getpwent_has_yppw = -1;
94static struct _ypexclude *__ypexhead;
95
96static int __has_yppw(void);
97static int __has_ypmaster(void);
98static int __ypparse(struct passwd *pw, char *s, int);
99
100#define LOOKUP_BYNAME0 0
101#define LOOKUP_BYUID1 1
102static 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(__has_ypmaster() ? "master.passwd.byname" : "passwd.byname") \
107 (__has_ypmaster() ? "master.passwd.byname" : "passwd.byname")
108#define PASSWD_BYUID(__has_ypmaster() ? "master.passwd.byuid" : "passwd.byuid") \
109 (__has_ypmaster() ? "master.passwd.byuid" : "passwd.byuid")
110
111static struct passwd *__ypproto;
112
113static void __ypproto_set(struct passwd *, struct pw_storage *, int, int *);
114
115static void
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((void *)0);
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((void *)0);
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((void *)0);
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((void *)0);
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((void *)0);
173
174 /* expire (ignored anyway) */
175 __ypproto->pw_expire = pw->pw_expire;
176
177 /* flags */
178 *yp_pw_flagsp = flags;
179}
180
181static int
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(2147483647 *2U +1U))
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(2147483647 *2U +1U))
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_MAX2147483647 || l <= INT_MIN(-2147483647 -1))
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_MAX2147483647 || l <= INT_MIN(-2147483647 -1))
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_NOUID0x01))
241 pw->pw_uid = __ypproto->pw_uid;
242 if (!(yp_pw_flags & _PASSWORD_NOGID0x02))
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
255static struct passwd *
256__get_pw_buf(char **bufp, size_t *buflenp, uid_t uid, const char *name)
257{
258 bool_Bool remap = true1;
259
260 /* Unmap the old buffer unless we are looking up the same uid/name */
261 if (_pw_storage != MAP_FAILED((void *)-1)) {
262 if (name != NULL((void *)0)) {
263 if (strcmp(_pw_storage->name, name) == 0) {
264#ifdef PWDEBUG
265 struct syslog_data sdata = SYSLOG_DATA_INIT{0, (const char *)0, (1<<3), 0xff};
266 syslog_r(LOG_CRIT2 | LOG_CONS0x02, &sdata,
267 "repeated passwd lookup of user \"%s\"",
268 name);
269#endif
270 remap = false0;
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{0, (const char *)0, (1<<3), 0xff};
276 syslog_r(LOG_CRIT2 | LOG_CONS0x02, &sdata,
277 "repeated passwd lookup of uid %u",
278 uid);
279#endif
280 remap = false0;
281 }
282 }
283 if (remap)
284 munmap(_pw_storage, sizeof(*_pw_storage));
285 }
286
287 if (remap) {
288 _pw_storage = mmap(NULL((void *)0), sizeof(*_pw_storage),
289 PROT_READ0x01|PROT_WRITE0x02, MAP_PRIVATE0x0002|MAP_ANON0x1000, -1, 0);
290 if (_pw_storage == MAP_FAILED((void *)-1))
291 return NULL((void *)0);
292 if (name != NULL((void *)0))
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
302struct passwd *
303getpwent(void)
304{
305#ifdef YP1
306 static char *name = NULL((void *)0);
307 char *map;
308#endif
309 char bf[1 + sizeof(_pw_keynum)];
310 struct passwd *pw, *ret = NULL((void *)0);
311 char *pwbuf;
312 size_t buflen;
313 DBT key;
314
315 _THREAD_PRIVATE_MUTEX_LOCK(pw)do { if (_thread_cb.tc_tag_lock != ((void *)0)) _thread_cb.tc_tag_lock
(&(_thread_tagname_pw)); } while (0)
;
1
Assuming field 'tc_tag_lock' is equal to null
2
Taking false branch
3
Loop condition is false. Exiting loop
316 if (!_pw_db && !__initdb(0))
4
Assuming '_pw_db' is non-null
317 goto done;
318
319 /* Allocate space for struct and strings, unmapping the old. */
320 if ((pw = __get_pw_buf(&pwbuf, &buflen, -1, NULL((void *)0))) == NULL((void *)0))
5
Taking false branch
321 goto done;
322
323#ifdef YP1
324 map = PASSWD_BYNAME(__has_ypmaster() ? "master.passwd.byname" : "passwd.byname");
6
Assuming the condition is false
7
'?' condition is false
325
326 if (__getpwent_has_yppw == -1)
8
Assuming the condition is false
9
Taking false branch
327 __getpwent_has_yppw = __has_yppw();
328
329again:
330 if (__getpwent_has_yppw && (__ypmode != YPMODE_NONE)) {
10
Assuming '__getpwent_has_yppw' is not equal to 0
11
Assuming '__ypmode' is not equal to YPMODE_NONE
12
Taking true branch
331 const char *user, *host, *dom;
332 int keylen, datalen, r, s;
13
'datalen' declared without an initial value
333 char *key, *data = NULL((void *)0);
334
335 if (!__ypdomain) {
14
Assuming '__ypdomain' is null
15
Taking true branch
336 if (_yp_check(&__ypdomain) == 0) {
16
Assuming the condition is false
17
Taking false branch
337 __ypmode = YPMODE_NONE;
338 goto again;
339 }
340 }
341 switch (__ypmode) {
18
Control jumps to 'case YPMODE_NONE:' at line 413
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((void *)0);
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((void *)0);
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;
19
Execution continues on line 418
416 }
417
418 pwbuf[datalen] = '\0';
20
Array subscript is undefined
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'2';
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 YP1
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
484done:
485 _THREAD_PRIVATE_MUTEX_UNLOCK(pw)do { if (_thread_cb.tc_tag_unlock != ((void *)0)) _thread_cb.
tc_tag_unlock(&(_thread_tagname_pw)); } while (0)
;
486 return (ret);
487}
488
489#ifdef YP1
490/*
491 * See if the YP token is in the database. Only works if pwd_mkdb knows
492 * about the token.
493 */
494static int
495__has_yppw(void)
496{
497 DBT key, data, pkey, pdata;
498 char bf[2];
499
500 key.data = (u_char *)_PW_YPTOKEN"__YP!";
501 key.size = strlen(_PW_YPTOKEN"__YP!");
502
503 /* Pre-token database support. */
504 bf[0] = _PW_KEYBYNAME'1';
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 */
518static int
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
566static struct passwd *
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_LEN31], *ypcurrent = NULL((void *)0), *map = NULL((void *)0);
571 int yp_pw_flags = 0, ypcurrentlen, r, s = -1, pw_keynum;
572 static struct pw_storage __yppbuf;
573 struct _ypexclude *ypexhead = NULL((void *)0);
574 const char *host, *user, *dom;
575 DBT key;
576
577 for (pw_keynum = 1; pw_keynum; pw_keynum++) {
578 bf[0] = _PW_KEYBYNUM'2';
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_BYNAME0) {
593 if ((name = strdup(name)) == NULL((void *)0)) {
594 pw = NULL((void *)0);
595 goto done;
596 }
597 map = PASSWD_BYNAME(__has_ypmaster() ? "master.passwd.byname" : "passwd.byname");
598 } else {
599 if (asprintf(&name, "%u", uid) == -1) {
600 pw = NULL((void *)0);
601 goto done;
602 }
603 map = PASSWD_BYUID(__has_ypmaster() ? "master.passwd.byuid" : "passwd.byuid");
604 }
605 }
606
607 switch (pw->pw_name[1]) {
608 case '\0':
609 free(ypcurrent);
610 ypcurrent = NULL((void *)0);
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((void *)0);
617 continue;
618 }
619 break;
620 case '@':
621pwnam_netgrp:
622 free(ypcurrent);
623 ypcurrent = NULL((void *)0);
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((void *)0);
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((void *)0);
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((void *)0);
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_BYUID1 && pw->pw_uid == uid) ||
693 (lookup == LOOKUP_BYNAME0 && 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((void *)0);
700done:
701 __ypexclude_free(&ypexhead);
702 __ypproto = NULL((void *)0);
703 free(ypcurrent);
704 ypcurrent = NULL((void *)0);
705 if (map)
706 free(name);
707 return (pw);
708}
709#endif /* YP */
710
711static struct passwd *
712_pwhashbyname(const char *name, char *buf, size_t buflen, struct passwd *pw,
713 int *flagsp)
714{
715 char bf[1 + _PW_NAME_LEN31];
716 size_t len;
717 DBT key;
718 int r;
719
720 len = strlen(name);
721 if (len > _PW_NAME_LEN31)
722 return (NULL((void *)0));
723 bf[0] = _PW_KEYBYNAME'1';
724 bcopy(name, &bf[1], MINIMUM(len, _PW_NAME_LEN)(((len) < (31)) ? (len) : (31)));
725 key.data = (u_char *)bf;
726 key.size = 1 + MINIMUM(len, _PW_NAME_LEN)(((len) < (31)) ? (len) : (31));
727 r = __hashpw(&key, buf, buflen, pw, flagsp);
728 if (r)
729 return (pw);
730 return (NULL((void *)0));
731}
732
733static struct passwd *
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'3';
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((void *)0));
749}
750
751static int
752getpwnam_internal(const char *name, struct passwd *pw, char *buf, size_t buflen,
753 struct passwd **pwretp, bool_Bool shadow, bool_Bool reentrant)
754{
755 struct passwd *pwret = NULL((void *)0);
756 int flags = 0, *flagsp = &flags;
757 int my_errno = 0;
758 int saved_errno, tmp_errno;
759
760 _THREAD_PRIVATE_MUTEX_LOCK(pw)do { if (_thread_cb.tc_tag_lock != ((void *)0)) _thread_cb.tc_tag_lock
(&(_thread_tagname_pw)); } while (0)
;
761 saved_errno = errno(*__errno());
762 errno(*__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((void *)0))
769 goto fail;
770 flagsp = &_pw_flags;
771 }
772
773#ifdef YP1
774 if (__has_yppw())
775 pwret = __yppwlookup(LOOKUP_BYNAME0, (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(*__errno());
783 (void)(_pw_db->close)(_pw_db);
784 _pw_db = NULL((void *)0);
785 errno(*__errno()) = tmp_errno;
786 }
787fail:
788 if (pwretp)
789 *pwretp = pwret;
790 if (pwret == NULL((void *)0))
791 my_errno = errno(*__errno());
792 errno(*__errno()) = saved_errno;
793 _THREAD_PRIVATE_MUTEX_UNLOCK(pw)do { if (_thread_cb.tc_tag_unlock != ((void *)0)) _thread_cb.
tc_tag_unlock(&(_thread_tagname_pw)); } while (0)
;
794 return (my_errno);
795}
796
797int
798getpwnam_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, false0, true1);
802}
803DEF_WEAK(getpwnam_r)__asm__(".weak " "getpwnam_r" " ; " "getpwnam_r" " = " "_libc_getpwnam_r"
)
;
804
805struct passwd *
806getpwnam(const char *name)
807{
808 struct passwd *pw = NULL((void *)0);
809 int my_errno;
810
811 my_errno = getpwnam_internal(name, NULL((void *)0), NULL((void *)0), 0, &pw, false0, false0);
812 if (my_errno) {
813 pw = NULL((void *)0);
814 errno(*__errno()) = my_errno;
815 }
816 return (pw);
817}
818
819struct passwd *
820getpwnam_shadow(const char *name)
821{
822 struct passwd *pw = NULL((void *)0);
823 int my_errno;
824
825 my_errno = getpwnam_internal(name, NULL((void *)0), NULL((void *)0), 0, &pw, true1, false0);
826 if (my_errno) {
827 pw = NULL((void *)0);
828 errno(*__errno()) = my_errno;
829 }
830 return (pw);
831}
832DEF_WEAK(getpwnam_shadow)__asm__(".weak " "getpwnam_shadow" " ; " "getpwnam_shadow" " = "
"_libc_getpwnam_shadow")
;
833
834static int
835getpwuid_internal(uid_t uid, struct passwd *pw, char *buf, size_t buflen,
836 struct passwd **pwretp, bool_Bool shadow, bool_Bool reentrant)
837{
838 struct passwd *pwret = NULL((void *)0);
839 int flags = 0, *flagsp = &flags;
840 int my_errno = 0;
841 int saved_errno, tmp_errno;
842
843 _THREAD_PRIVATE_MUTEX_LOCK(pw)do { if (_thread_cb.tc_tag_lock != ((void *)0)) _thread_cb.tc_tag_lock
(&(_thread_tagname_pw)); } while (0)
;
844 saved_errno = errno(*__errno());
845 errno(*__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((void *)0))) == NULL((void *)0))
852 goto fail;
853 flagsp = &_pw_flags;
854 }
855
856#ifdef YP1
857 if (__has_yppw())
858 pwret = __yppwlookup(LOOKUP_BYUID1, NULL((void *)0), 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(*__errno());
866 (void)(_pw_db->close)(_pw_db);
867 _pw_db = NULL((void *)0);
868 errno(*__errno()) = tmp_errno;
869 }
870fail:
871 if (pwretp)
872 *pwretp = pwret;
873 if (pwret == NULL((void *)0))
874 my_errno = errno(*__errno());
875 errno(*__errno()) = saved_errno;
876 _THREAD_PRIVATE_MUTEX_UNLOCK(pw)do { if (_thread_cb.tc_tag_unlock != ((void *)0)) _thread_cb.
tc_tag_unlock(&(_thread_tagname_pw)); } while (0)
;
877 return (my_errno);
878}
879
880
881int
882getpwuid_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, false0, true1);
886}
887DEF_WEAK(getpwuid_r)__asm__(".weak " "getpwuid_r" " ; " "getpwuid_r" " = " "_libc_getpwuid_r"
)
;
888
889struct passwd *
890getpwuid(uid_t uid)
891{
892 struct passwd *pw = NULL((void *)0);
893 int my_errno;
894
895 my_errno = getpwuid_internal(uid, NULL((void *)0), NULL((void *)0), 0, &pw, false0, false0);
896 if (my_errno) {
897 pw = NULL((void *)0);
898 errno(*__errno()) = my_errno;
899 }
900 return (pw);
901}
902
903struct passwd *
904getpwuid_shadow(uid_t uid)
905{
906 struct passwd *pw = NULL((void *)0);
907 int my_errno;
908
909 my_errno = getpwuid_internal(uid, NULL((void *)0), NULL((void *)0), 0, &pw, true1, false0);
910 if (my_errno) {
911 pw = NULL((void *)0);
912 errno(*__errno()) = my_errno;
913 }
914 return (pw);
915}
916DEF_WEAK(getpwuid_shadow)__asm__(".weak " "getpwuid_shadow" " ; " "getpwuid_shadow" " = "
"_libc_getpwuid_shadow")
;
917
918int
919setpassent(int stayopen)
920{
921 _THREAD_PRIVATE_MUTEX_LOCK(pw)do { if (_thread_cb.tc_tag_lock != ((void *)0)) _thread_cb.tc_tag_lock
(&(_thread_tagname_pw)); } while (0)
;
922 _pw_keynum = 0;
923 _pw_stayopen = stayopen;
924#ifdef YP1
925 __ypmode = YPMODE_NONE;
926 free(__ypcurrent);
927 __ypcurrent = NULL((void *)0);
928 __ypexclude_free(&__ypexhead);
929 __ypproto = NULL((void *)0);
930#endif
931 _THREAD_PRIVATE_MUTEX_UNLOCK(pw)do { if (_thread_cb.tc_tag_unlock != ((void *)0)) _thread_cb.
tc_tag_unlock(&(_thread_tagname_pw)); } while (0)
;
932 return (1);
933}
934DEF_WEAK(setpassent)__asm__(".weak " "setpassent" " ; " "setpassent" " = " "_libc_setpassent"
)
;
935
936void
937setpwent(void)
938{
939 (void) setpassent(0);
940}
941
942void
943endpwent(void)
944{
945 int saved_errno;
946
947 _THREAD_PRIVATE_MUTEX_LOCK(pw)do { if (_thread_cb.tc_tag_lock != ((void *)0)) _thread_cb.tc_tag_lock
(&(_thread_tagname_pw)); } while (0)
;
948 saved_errno = errno(*__errno());
949 _pw_keynum = 0;
950 if (_pw_db) {
951 (void)(_pw_db->close)(_pw_db);
952 _pw_db = NULL((void *)0);
953 }
954#ifdef YP1
955 __ypmode = YPMODE_NONE;
956 free(__ypcurrent);
957 __ypcurrent = NULL((void *)0);
958 __ypexclude_free(&__ypexhead);
959 __ypproto = NULL((void *)0);
960#endif
961 errno(*__errno()) = saved_errno;
962 _THREAD_PRIVATE_MUTEX_UNLOCK(pw)do { if (_thread_cb.tc_tag_unlock != ((void *)0)) _thread_cb.
tc_tag_unlock(&(_thread_tagname_pw)); } while (0)
;
963}
964
965static int
966__initdb(int shadow)
967{
968 static int warned;
969 int saved_errno = errno(*__errno());
970
971#ifdef YP1
972 /*
973 * Hint to the kernel that a passwd database operation is happening.
974 */
975 (void)access("/var/run/ypbind.lock", R_OK0x04);
976 errno(*__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"/etc/spwd.db", O_RDONLY0x0000, 0, DB_HASH, NULL((void *)0));
983 if (!_pw_db)
984 _pw_db = dbopen(_PATH_MP_DB"/etc/pwd.db", O_RDONLY0x0000, 0, DB_HASH, NULL((void *)0));
985 if (_pw_db) {
986 errno(*__errno()) = saved_errno;
987 return (1);
988 }
989 if (!warned) {
990 saved_errno = errno(*__errno());
991 errno(*__errno()) = saved_errno;
992 warned = 1;
993 }
994 return (0);
995}
996
997static int
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(*__errno()) = ERANGE34;
1009 return (0);
1010 }
1011
1012 t = buf;
1013#define EXPAND(e)e = t; while ((*t++ = *p++)); e = t; while ((*t++ = *p++));
1014 EXPAND(pw->pw_name)pw->pw_name = t; while ((*t++ = *p++));;
1015 EXPAND(pw->pw_passwd)pw->pw_passwd = t; while ((*t++ = *p++));;
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)pw->pw_class = t; while ((*t++ = *p++));;
1023 EXPAND(pw->pw_gecos)pw->pw_gecos = t; while ((*t++ = *p++));;
1024 EXPAND(pw->pw_dir)pw->pw_dir = t; while ((*t++ = *p++));;
1025 EXPAND(pw->pw_shell)pw->pw_shell = t; while ((*t++ = *p++));;
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_NOUID0x01|_PASSWORD_NOGID0x02; /* default */
1035 return (1);
1036}