File: | src/lib/libc/gen/getpwent.c |
Warning: | line 1014, column 3 Value stored to 'p' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: getpwent.c,v 1.66 2022/08/02 17:00:15 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 | |
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 YP1 |
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_BYNAME0 0 |
101 | #define LOOKUP_BYUID1 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(__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 | |
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_MAX0xffffffffU) |
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_MAX0xffffffffU) |
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_MAX0x7fffffff || l <= INT_MIN(-0x7fffffff-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_MAX0x7fffffff || l <= INT_MIN(-0x7fffffff-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 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); |
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 YP1 |
324 | map = PASSWD_BYNAME(__has_ypmaster() ? "master.passwd.byname" : "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 | 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((void *)0); |
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((void *)0); |
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'2'; |
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 YP1 |
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)do { if (_thread_cb.tc_tag_unlock != ((void *)0)) _thread_cb. tc_tag_unlock(&(_thread_tagname_pw)); } while (0); |
482 | return (ret); |
483 | } |
484 | |
485 | #ifdef YP1 |
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 |
491 | __has_yppw(void) |
492 | { |
493 | DBT key, data, pkey, pdata; |
494 | char bf[2]; |
495 | |
496 | key.data = (u_char *)_PW_YPTOKEN"__YP!"; |
497 | key.size = strlen(_PW_YPTOKEN"__YP!"); |
498 | |
499 | /* Pre-token database support. */ |
500 | bf[0] = _PW_KEYBYNAME'1'; |
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 |
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 * |
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_LEN31], *ypcurrent = NULL((void *)0), *map = NULL((void *)0); |
561 | int yp_pw_flags = 0, ypcurrentlen, r, s = -1, pw_keynum; |
562 | static struct pw_storage __yppbuf; |
563 | struct _ypexclude *ypexhead = NULL((void *)0); |
564 | const char *host, *user, *dom; |
565 | DBT key; |
566 | |
567 | for (pw_keynum = 1; pw_keynum; pw_keynum++) { |
568 | bf[0] = _PW_KEYBYNUM'2'; |
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_BYNAME0) { |
581 | if ((name = strdup(name)) == NULL((void *)0)) { |
582 | pw = NULL((void *)0); |
583 | goto done; |
584 | } |
585 | map = PASSWD_BYNAME(__has_ypmaster() ? "master.passwd.byname" : "passwd.byname"); |
586 | } else { |
587 | if (asprintf(&name, "%u", uid) == -1) { |
588 | pw = NULL((void *)0); |
589 | goto done; |
590 | } |
591 | map = PASSWD_BYUID(__has_ypmaster() ? "master.passwd.byuid" : "passwd.byuid"); |
592 | } |
593 | } |
594 | |
595 | switch (pw->pw_name[1]) { |
596 | case '\0': |
597 | free(ypcurrent); |
598 | ypcurrent = NULL((void *)0); |
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((void *)0); |
605 | continue; |
606 | } |
607 | break; |
608 | case '@': |
609 | pwnam_netgrp: |
610 | free(ypcurrent); |
611 | ypcurrent = NULL((void *)0); |
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((void *)0); |
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((void *)0); |
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((void *)0); |
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_BYUID1 && pw->pw_uid == uid) || |
681 | (lookup == LOOKUP_BYNAME0 && 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((void *)0); |
688 | done: |
689 | __ypexclude_free(&ypexhead); |
690 | __ypproto = NULL((void *)0); |
691 | free(ypcurrent); |
692 | ypcurrent = NULL((void *)0); |
693 | if (map) |
694 | free(name); |
695 | return (pw); |
696 | } |
697 | #endif /* YP */ |
698 | |
699 | static struct passwd * |
700 | _pwhashbyname(const char *name, char *buf, size_t buflen, struct passwd *pw, |
701 | int *flagsp) |
702 | { |
703 | char bf[1 + _PW_NAME_LEN31]; |
704 | size_t len; |
705 | DBT key; |
706 | int r; |
707 | |
708 | len = strlen(name); |
709 | if (len > _PW_NAME_LEN31) |
710 | return (NULL((void *)0)); |
711 | bf[0] = _PW_KEYBYNAME'1'; |
712 | bcopy(name, &bf[1], MINIMUM(len, _PW_NAME_LEN)(((len) < (31)) ? (len) : (31))); |
713 | key.data = (u_char *)bf; |
714 | key.size = 1 + MINIMUM(len, _PW_NAME_LEN)(((len) < (31)) ? (len) : (31)); |
715 | r = __hashpw(&key, buf, buflen, pw, flagsp); |
716 | if (r) |
717 | return (pw); |
718 | return (NULL((void *)0)); |
719 | } |
720 | |
721 | static struct passwd * |
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'3'; |
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((void *)0)); |
737 | } |
738 | |
739 | static int |
740 | getpwnam_internal(const char *name, struct passwd *pw, char *buf, size_t buflen, |
741 | struct passwd **pwretp, bool_Bool shadow, bool_Bool reentrant) |
742 | { |
743 | struct passwd *pwret = NULL((void *)0); |
744 | int flags = 0, *flagsp = &flags; |
745 | int my_errno = 0; |
746 | int saved_errno, tmp_errno; |
747 | |
748 | _THREAD_PRIVATE_MUTEX_LOCK(pw)do { if (_thread_cb.tc_tag_lock != ((void *)0)) _thread_cb.tc_tag_lock (&(_thread_tagname_pw)); } while (0); |
749 | saved_errno = errno(*__errno()); |
750 | errno(*__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((void *)0)) |
757 | goto fail; |
758 | flagsp = &_pw_flags; |
759 | } |
760 | |
761 | #ifdef YP1 |
762 | if (__has_yppw()) |
763 | pwret = __yppwlookup(LOOKUP_BYNAME0, (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(*__errno()); |
771 | (void)(_pw_db->close)(_pw_db); |
772 | _pw_db = NULL((void *)0); |
773 | errno(*__errno()) = tmp_errno; |
774 | } |
775 | fail: |
776 | if (pwretp) |
777 | *pwretp = pwret; |
778 | if (pwret == NULL((void *)0)) |
779 | my_errno = errno(*__errno()); |
780 | errno(*__errno()) = saved_errno; |
781 | _THREAD_PRIVATE_MUTEX_UNLOCK(pw)do { if (_thread_cb.tc_tag_unlock != ((void *)0)) _thread_cb. tc_tag_unlock(&(_thread_tagname_pw)); } while (0); |
782 | return (my_errno); |
783 | } |
784 | |
785 | int |
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, false0, true1); |
790 | } |
791 | DEF_WEAK(getpwnam_r)__asm__(".weak " "getpwnam_r" " ; " "getpwnam_r" " = " "_libc_getpwnam_r" ); |
792 | |
793 | struct passwd * |
794 | getpwnam(const char *name) |
795 | { |
796 | struct passwd *pw = NULL((void *)0); |
797 | int my_errno; |
798 | |
799 | my_errno = getpwnam_internal(name, NULL((void *)0), NULL((void *)0), 0, &pw, false0, false0); |
800 | if (my_errno) { |
801 | pw = NULL((void *)0); |
802 | errno(*__errno()) = my_errno; |
803 | } |
804 | return (pw); |
805 | } |
806 | |
807 | struct passwd * |
808 | getpwnam_shadow(const char *name) |
809 | { |
810 | struct passwd *pw = NULL((void *)0); |
811 | int my_errno; |
812 | |
813 | my_errno = getpwnam_internal(name, NULL((void *)0), NULL((void *)0), 0, &pw, true1, false0); |
814 | if (my_errno) { |
815 | pw = NULL((void *)0); |
816 | errno(*__errno()) = my_errno; |
817 | } |
818 | return (pw); |
819 | } |
820 | DEF_WEAK(getpwnam_shadow)__asm__(".weak " "getpwnam_shadow" " ; " "getpwnam_shadow" " = " "_libc_getpwnam_shadow"); |
821 | |
822 | static int |
823 | getpwuid_internal(uid_t uid, struct passwd *pw, char *buf, size_t buflen, |
824 | struct passwd **pwretp, bool_Bool shadow, bool_Bool reentrant) |
825 | { |
826 | struct passwd *pwret = NULL((void *)0); |
827 | int flags = 0, *flagsp = &flags; |
828 | int my_errno = 0; |
829 | int saved_errno, tmp_errno; |
830 | |
831 | _THREAD_PRIVATE_MUTEX_LOCK(pw)do { if (_thread_cb.tc_tag_lock != ((void *)0)) _thread_cb.tc_tag_lock (&(_thread_tagname_pw)); } while (0); |
832 | saved_errno = errno(*__errno()); |
833 | errno(*__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((void *)0))) == NULL((void *)0)) |
840 | goto fail; |
841 | flagsp = &_pw_flags; |
842 | } |
843 | |
844 | #ifdef YP1 |
845 | if (__has_yppw()) |
846 | pwret = __yppwlookup(LOOKUP_BYUID1, NULL((void *)0), 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(*__errno()); |
854 | (void)(_pw_db->close)(_pw_db); |
855 | _pw_db = NULL((void *)0); |
856 | errno(*__errno()) = tmp_errno; |
857 | } |
858 | fail: |
859 | if (pwretp) |
860 | *pwretp = pwret; |
861 | if (pwret == NULL((void *)0)) |
862 | my_errno = errno(*__errno()); |
863 | errno(*__errno()) = saved_errno; |
864 | _THREAD_PRIVATE_MUTEX_UNLOCK(pw)do { if (_thread_cb.tc_tag_unlock != ((void *)0)) _thread_cb. tc_tag_unlock(&(_thread_tagname_pw)); } while (0); |
865 | return (my_errno); |
866 | } |
867 | |
868 | |
869 | int |
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, false0, true1); |
874 | } |
875 | DEF_WEAK(getpwuid_r)__asm__(".weak " "getpwuid_r" " ; " "getpwuid_r" " = " "_libc_getpwuid_r" ); |
876 | |
877 | struct passwd * |
878 | getpwuid(uid_t uid) |
879 | { |
880 | struct passwd *pw = NULL((void *)0); |
881 | int my_errno; |
882 | |
883 | my_errno = getpwuid_internal(uid, NULL((void *)0), NULL((void *)0), 0, &pw, false0, false0); |
884 | if (my_errno) { |
885 | pw = NULL((void *)0); |
886 | errno(*__errno()) = my_errno; |
887 | } |
888 | return (pw); |
889 | } |
890 | |
891 | struct passwd * |
892 | getpwuid_shadow(uid_t uid) |
893 | { |
894 | struct passwd *pw = NULL((void *)0); |
895 | int my_errno; |
896 | |
897 | my_errno = getpwuid_internal(uid, NULL((void *)0), NULL((void *)0), 0, &pw, true1, false0); |
898 | if (my_errno) { |
899 | pw = NULL((void *)0); |
900 | errno(*__errno()) = my_errno; |
901 | } |
902 | return (pw); |
903 | } |
904 | DEF_WEAK(getpwuid_shadow)__asm__(".weak " "getpwuid_shadow" " ; " "getpwuid_shadow" " = " "_libc_getpwuid_shadow"); |
905 | |
906 | int |
907 | setpassent(int stayopen) |
908 | { |
909 | _THREAD_PRIVATE_MUTEX_LOCK(pw)do { if (_thread_cb.tc_tag_lock != ((void *)0)) _thread_cb.tc_tag_lock (&(_thread_tagname_pw)); } while (0); |
910 | _pw_keynum = 0; |
911 | _pw_stayopen = stayopen; |
912 | #ifdef YP1 |
913 | __ypmode = YPMODE_NONE; |
914 | free(__ypcurrent); |
915 | __ypcurrent = NULL((void *)0); |
916 | __ypexclude_free(&__ypexhead); |
917 | __ypproto = NULL((void *)0); |
918 | #endif |
919 | _THREAD_PRIVATE_MUTEX_UNLOCK(pw)do { if (_thread_cb.tc_tag_unlock != ((void *)0)) _thread_cb. tc_tag_unlock(&(_thread_tagname_pw)); } while (0); |
920 | return (1); |
921 | } |
922 | DEF_WEAK(setpassent)__asm__(".weak " "setpassent" " ; " "setpassent" " = " "_libc_setpassent" ); |
923 | |
924 | void |
925 | setpwent(void) |
926 | { |
927 | (void) setpassent(0); |
928 | } |
929 | |
930 | void |
931 | endpwent(void) |
932 | { |
933 | int saved_errno; |
934 | |
935 | _THREAD_PRIVATE_MUTEX_LOCK(pw)do { if (_thread_cb.tc_tag_lock != ((void *)0)) _thread_cb.tc_tag_lock (&(_thread_tagname_pw)); } while (0); |
936 | saved_errno = errno(*__errno()); |
937 | _pw_keynum = 0; |
938 | if (_pw_db) { |
939 | (void)(_pw_db->close)(_pw_db); |
940 | _pw_db = NULL((void *)0); |
941 | } |
942 | #ifdef YP1 |
943 | __ypmode = YPMODE_NONE; |
944 | free(__ypcurrent); |
945 | __ypcurrent = NULL((void *)0); |
946 | __ypexclude_free(&__ypexhead); |
947 | __ypproto = NULL((void *)0); |
948 | #endif |
949 | errno(*__errno()) = saved_errno; |
950 | _THREAD_PRIVATE_MUTEX_UNLOCK(pw)do { if (_thread_cb.tc_tag_unlock != ((void *)0)) _thread_cb. tc_tag_unlock(&(_thread_tagname_pw)); } while (0); |
951 | } |
952 | |
953 | static int |
954 | __initdb(int shadow) |
955 | { |
956 | static int warned; |
957 | int saved_errno = errno(*__errno()); |
958 | |
959 | #ifdef YP1 |
960 | __ypmode = YPMODE_NONE; |
961 | __getpwent_has_yppw = -1; |
962 | #endif |
963 | if (shadow) |
964 | _pw_db = dbopen(_PATH_SMP_DB"/etc/spwd.db", O_RDONLY0x0000, 0, DB_HASH, NULL((void *)0)); |
965 | if (!_pw_db) |
966 | _pw_db = dbopen(_PATH_MP_DB"/etc/pwd.db", O_RDONLY0x0000, 0, DB_HASH, NULL((void *)0)); |
967 | if (_pw_db) { |
968 | errno(*__errno()) = saved_errno; |
969 | return (1); |
970 | } |
971 | if (!warned) { |
972 | saved_errno = errno(*__errno()); |
973 | errno(*__errno()) = saved_errno; |
974 | warned = 1; |
975 | } |
976 | return (0); |
977 | } |
978 | |
979 | static int |
980 | __hashpw(DBT *key, char *buf, size_t buflen, struct passwd *pw, |
981 | int *flagsp) |
982 | { |
983 | char *p, *t; |
984 | DBT data; |
985 | |
986 | if ((_pw_db->get)(_pw_db, key, &data, 0)) |
987 | return (0); |
988 | p = (char *)data.data; |
989 | if (data.size > buflen) { |
990 | errno(*__errno()) = ERANGE34; |
991 | return (0); |
992 | } |
993 | |
994 | t = buf; |
995 | #define EXPAND(e)e = t; while ((*t++ = *p++)); e = t; while ((*t++ = *p++)); |
996 | EXPAND(pw->pw_name)pw->pw_name = t; while ((*t++ = *p++));; |
997 | EXPAND(pw->pw_passwd)pw->pw_passwd = t; while ((*t++ = *p++));; |
998 | bcopy(p, (char *)&pw->pw_uid, sizeof(int)); |
999 | p += sizeof(int); |
1000 | bcopy(p, (char *)&pw->pw_gid, sizeof(int)); |
1001 | p += sizeof(int); |
1002 | bcopy(p, (char *)&pw->pw_change, sizeof(time_t)); |
1003 | p += sizeof(time_t); |
1004 | EXPAND(pw->pw_class)pw->pw_class = t; while ((*t++ = *p++));; |
1005 | EXPAND(pw->pw_gecos)pw->pw_gecos = t; while ((*t++ = *p++));; |
1006 | EXPAND(pw->pw_dir)pw->pw_dir = t; while ((*t++ = *p++));; |
1007 | EXPAND(pw->pw_shell)pw->pw_shell = t; while ((*t++ = *p++));; |
1008 | bcopy(p, (char *)&pw->pw_expire, sizeof(time_t)); |
1009 | p += sizeof(time_t); |
1010 | |
1011 | /* See if there's any data left. If so, read in flags. */ |
1012 | if (data.size > (p - (char *)data.data)) { |
1013 | bcopy(p, (char *)flagsp, sizeof(int)); |
1014 | p += sizeof(int); |
Value stored to 'p' is never read | |
1015 | } else |
1016 | *flagsp = _PASSWORD_NOUID0x01|_PASSWORD_NOGID0x02; /* default */ |
1017 | return (1); |
1018 | } |