File: | src/usr.bin/chpass/../../lib/libc/gen/getpwent.c |
Warning: | line 1032, column 3 Value stored to 'p' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 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)) (((a) < (b)) ? (a) : (b)) |
57 | |
58 | struct 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 | |
67 | static DB *_pw_db; /* password database */ |
68 | |
69 | /* mmap'd password storage */ |
70 | static struct pw_storage *_pw_storage = MAP_FAILED((void *)-1); |
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 |
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 | |
181 | static 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 | |
255 | static 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 | |
302 | struct passwd * |
303 | getpwent(void) |
304 | { |
305 | #ifdef YP |
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 {} while (0); |
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((void *)0))) == NULL((void *)0)) |
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((void *)0); |
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((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; |
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'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 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)do {} while (0); |
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 |
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 | */ |
518 | static 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 | |
566 | static 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_BYNAME) { |
593 | if ((name = strdup(name)) == NULL((void *)0)) { |
594 | pw = NULL((void *)0); |
595 | goto done; |
596 | } |
597 | map = PASSWD_BYNAME; |
598 | } else { |
599 | if (asprintf(&name, "%u", uid) == -1) { |
600 | pw = NULL((void *)0); |
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((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 '@': |
621 | pwnam_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_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((void *)0); |
700 | done: |
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 | |
711 | static 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 | |
733 | static 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 | |
751 | static int |
752 | getpwnam_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 {} 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 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(*__errno()); |
783 | (void)(_pw_db->close)(_pw_db); |
784 | _pw_db = NULL((void *)0); |
785 | errno(*__errno()) = tmp_errno; |
786 | } |
787 | fail: |
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 {} while (0); |
794 | return (my_errno); |
795 | } |
796 | |
797 | int |
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, false0, true1); |
802 | } |
803 | DEF_WEAK(getpwnam_r)asm(""); |
804 | |
805 | struct passwd * |
806 | getpwnam(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 | |
819 | struct passwd * |
820 | getpwnam_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 | } |
832 | DEF_WEAK(getpwnam_shadow)asm(""); |
833 | |
834 | static int |
835 | getpwuid_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 {} 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 YP |
857 | if (__has_yppw()) |
858 | pwret = __yppwlookup(LOOKUP_BYUID, 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 | } |
870 | fail: |
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 {} while (0); |
877 | return (my_errno); |
878 | } |
879 | |
880 | |
881 | int |
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, false0, true1); |
886 | } |
887 | DEF_WEAK(getpwuid_r)asm(""); |
888 | |
889 | struct passwd * |
890 | getpwuid(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 | |
903 | struct passwd * |
904 | getpwuid_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 | } |
916 | DEF_WEAK(getpwuid_shadow)asm(""); |
917 | |
918 | int |
919 | setpassent(int stayopen) |
920 | { |
921 | _THREAD_PRIVATE_MUTEX_LOCK(pw)do {} while (0); |
922 | _pw_keynum = 0; |
923 | _pw_stayopen = stayopen; |
924 | #ifdef YP |
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 {} while (0); |
932 | return (1); |
933 | } |
934 | DEF_WEAK(setpassent)asm(""); |
935 | |
936 | void |
937 | setpwent(void) |
938 | { |
939 | (void) setpassent(0); |
940 | } |
941 | |
942 | void |
943 | endpwent(void) |
944 | { |
945 | int saved_errno; |
946 | |
947 | _THREAD_PRIVATE_MUTEX_LOCK(pw)do {} 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 YP |
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 {} while (0); |
963 | } |
964 | |
965 | static int |
966 | __initdb(int shadow) |
967 | { |
968 | static int warned; |
969 | int saved_errno = 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_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 | |
997 | static 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); |
Value stored to 'p' is never read | |
1033 | } else |
1034 | *flagsp = _PASSWORD_NOUID0x01|_PASSWORD_NOGID0x02; /* default */ |
1035 | return (1); |
1036 | } |