getpwent.c revision 1.65 1 /* $NetBSD: getpwent.c,v 1.65 2004/11/10 12:57:32 lukem Exp $ */
2
3 /*-
4 * Copyright (c) 1997-2000, 2004 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Luke Mewburn.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * Copyright (c) 1988, 1993
41 * The Regents of the University of California. All rights reserved.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution.
51 * 3. Neither the name of the University nor the names of its contributors
52 * may be used to endorse or promote products derived from this software
53 * without specific prior written permission.
54 *
55 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
56 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
57 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
58 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
59 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
60 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
61 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
62 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
63 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
64 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65 * SUCH DAMAGE.
66 */
67
68 /*
69 * Portions Copyright (c) 1994, 1995, Jason Downs. All rights reserved.
70 *
71 * Redistribution and use in source and binary forms, with or without
72 * modification, are permitted provided that the following conditions
73 * are met:
74 * 1. Redistributions of source code must retain the above copyright
75 * notice, this list of conditions and the following disclaimer.
76 * 2. Redistributions in binary form must reproduce the above copyright
77 * notice, this list of conditions and the following disclaimer in the
78 * documentation and/or other materials provided with the distribution.
79 *
80 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
81 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
82 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
83 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
84 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
85 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
86 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
87 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
88 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
89 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
90 * SUCH DAMAGE.
91 */
92
93 #include <sys/cdefs.h>
94 #if defined(LIBC_SCCS) && !defined(lint)
95 #if 0
96 static char sccsid[] = "@(#)getpwent.c 8.2 (Berkeley) 4/27/95";
97 #else
98 __RCSID("$NetBSD: getpwent.c,v 1.65 2004/11/10 12:57:32 lukem Exp $");
99 #endif
100 #endif /* LIBC_SCCS and not lint */
101
102 #include "namespace.h"
103 #include "reentrant.h"
104
105 #include <sys/param.h>
106
107 #include <assert.h>
108 #include <db.h>
109 #include <errno.h>
110 #include <fcntl.h>
111 #include <limits.h>
112 #include <netgroup.h>
113 #include <nsswitch.h>
114 #include <pwd.h>
115 #include <stdarg.h>
116 #include <stdio.h>
117 #include <stdlib.h>
118 #include <string.h>
119 #include <syslog.h>
120 #include <unistd.h>
121
122 #ifdef HESIOD
123 #include <hesiod.h>
124 #endif
125
126 #ifdef YP
127 #include <machine/param.h>
128 #include <rpc/rpc.h>
129 #include <rpcsvc/yp_prot.h>
130 #include <rpcsvc/ypclnt.h>
131 #endif
132
133 #include "pw_private.h"
134
135 #define _PASSWD_COMPAT /* "passwd" defaults to compat, so always provide it */
136
137 #ifdef __weak_alias
138 __weak_alias(endpwent,_endpwent)
139 __weak_alias(getpwent,_getpwent)
140 __weak_alias(getpwnam,_getpwnam)
141 __weak_alias(getpwnam_r,_getpwnam_r)
142 __weak_alias(getpwuid,_getpwuid)
143 __weak_alias(getpwuid_r,_getpwuid_r)
144 __weak_alias(setpassent,_setpassent)
145 __weak_alias(setpwent,_setpwent)
146 #endif
147
148 #ifdef _REENTRANT
149 static mutex_t _pwmutex = MUTEX_INITIALIZER;
150 #endif
151
152 const char __yp_token[] = "__YP!"; /* Let pwd_mkdb pull this in. */
153
154
155 /*
156 * The pwd.db lookup techniques and data extraction code here must be kept
157 * in sync with that in `pwd_mkdb'.
158 */
159
160 #if defined(YP) || defined(HESIOD)
161 /*
162 * _pw_parse
163 * Parses entry using pw_scan(3) (without the trailing \n)
164 * after copying to buf, and fills in pw with corresponding values.
165 * If old is non-zero, entry is in _PASSWORD_OLDFMT.
166 * Returns 1 if parsed successfully, 0 on parse failure.
167 */
168 static int
169 _pw_parse(const char *entry, struct passwd *pw, char *buf, size_t buflen,
170 int old)
171 {
172 int flags;
173
174 _DIAGASSERT(entry != NULL);
175 _DIAGASSERT(pw != NULL);
176 _DIAGASSERT(buf != NULL);
177
178 if (strlcpy(buf, entry, buflen) >= buflen)
179 return 0;
180 flags = _PASSWORD_NOWARN;
181 if (old)
182 flags |= _PASSWORD_OLDFMT;
183 return __pw_scan(buf, pw, &flags);
184 }
185 #endif /* YP || HESIOD */
186
187 /*
188 * _pw_opendb
189 * if *db is NULL, dbopen(3) /etc/spwd.db or /etc/pwd.db (depending
190 * upon permissions, etc)
191 */
192 static int
193 _pw_opendb(DB **db)
194 {
195 static int warned;
196
197 const char *dbfile;
198
199 _DIAGASSERT(db != NULL);
200 if (*db != NULL) /* open *db */
201 return NS_SUCCESS;
202
203 if (geteuid() == 0) {
204 dbfile = _PATH_SMP_DB;
205 *db = dbopen(dbfile, O_RDONLY, 0, DB_HASH, NULL);
206 }
207 if (*db == NULL) {
208 dbfile = _PATH_MP_DB;
209 *db = dbopen(dbfile, O_RDONLY, 0, DB_HASH, NULL);
210 }
211 if (*db == NULL) {
212 if (!warned) {
213 int serrno = errno;
214 syslog(LOG_ERR, "%s: %m", dbfile);
215 errno = serrno;
216 }
217 warned = 1;
218 return NS_UNAVAIL;
219 }
220 return NS_SUCCESS;
221 }
222
223 /*
224 * _pw_getkey
225 * Lookup key in *db, filling in pw
226 * with the result, allocating memory from buffer (size buflen).
227 * (The caller may point key.data to buffer on entry; the contents
228 * of key.data will be invalid on exit.)
229 */
230 static int
231 _pw_getkey(DB *db, DBT *key,
232 struct passwd *pw, char *buffer, size_t buflen, int *pwflags)
233 {
234 char *p, *t;
235 DBT data;
236
237 _DIAGASSERT(db != NULL);
238 _DIAGASSERT(key != NULL);
239 _DIAGASSERT(pw != NULL);
240 _DIAGASSERT(buffer != NULL);
241 /* pwflags may be NULL (if we don't care about them */
242
243 if (db == NULL) /* this shouldn't happen */
244 return NS_UNAVAIL;
245
246 switch ((db->get)(db, key, &data, 0)) {
247 case 0:
248 break; /* found */
249 case 1:
250 return NS_NOTFOUND;
251 case -1:
252 return NS_UNAVAIL; /* error in db routines */
253 default:
254 abort();
255 }
256
257 p = (char *)data.data;
258 if (data.size > buflen) {
259 errno = ERANGE;
260 return NS_UNAVAIL;
261 }
262
263 /*
264 * THE DECODING BELOW MUST MATCH THAT IN pwd_mkdb.
265 */
266 t = buffer;
267 #define EXPAND(e) e = t; while ((*t++ = *p++));
268 #define SCALAR(v) memmove(&(v), p, sizeof v); p += sizeof v
269 EXPAND(pw->pw_name);
270 EXPAND(pw->pw_passwd);
271 SCALAR(pw->pw_uid);
272 SCALAR(pw->pw_gid);
273 SCALAR(pw->pw_change);
274 EXPAND(pw->pw_class);
275 EXPAND(pw->pw_gecos);
276 EXPAND(pw->pw_dir);
277 EXPAND(pw->pw_shell);
278 SCALAR(pw->pw_expire);
279 if (pwflags) {
280 /* See if there's any data left. If so, read in flags. */
281 if (data.size > (size_t) (p - (char *)data.data)) {
282 SCALAR(*pwflags);
283 } else { /* default */
284 *pwflags = _PASSWORD_NOUID|_PASSWORD_NOGID;
285 }
286 }
287
288 return NS_SUCCESS;
289 }
290
291 /*
292 * _pw_memfrombuf
293 * Obtain want bytes from buffer (of size buflen) and return a pointer
294 * to the available memory after adjusting buffer/buflen.
295 * Returns NULL if there is insufficient space.
296 */
297 static char *
298 _pw_memfrombuf(size_t want, char **buffer, size_t *buflen)
299 {
300 char *rv;
301
302 if (want > *buflen) {
303 errno = ERANGE;
304 return NULL;
305 }
306 rv = *buffer;
307 *buffer += want;
308 *buflen -= want;
309 return rv;
310 }
311
312 /*
313 * _pw_copy
314 * Copy the contents of frompw to pw; memory for strings
315 * and arrays will be allocated from buf (of size buflen).
316 * If proto != NULL, use various fields in proto in preference to frompw.
317 * Returns 1 if copied successfully, 0 on copy failure.
318 * NOTE: frompw must not use buf for its own pointers.
319 */
320 static int
321 _pw_copy(const struct passwd *frompw, struct passwd *pw,
322 char *buf, size_t buflen, const struct passwd *protopw, int protoflags)
323 {
324 size_t count;
325 int useproto;
326
327 _DIAGASSERT(frompw != NULL);
328 _DIAGASSERT(pw != NULL);
329 _DIAGASSERT(buf != NULL);
330 /* protopw may be NULL */
331
332 useproto = protopw && protopw->pw_name;
333
334 #define COPYSTR(to, from) \
335 do { \
336 count = strlen((from)); \
337 (to) = _pw_memfrombuf(count+1, &buf, &buflen); \
338 if ((to) == NULL) \
339 return 0; \
340 memmove((to), (from), count); \
341 to[count] = '\0'; \
342 } while (0) /* LINTED */
343
344 #define COPYFIELD(field) COPYSTR(pw->field, frompw->field)
345
346 #define COPYPROTOFIELD(field) COPYSTR(pw->field, \
347 (useproto && *protopw->field ? protopw->field : frompw->field))
348
349 COPYFIELD(pw_name);
350
351 #ifdef PW_OVERRIDE_PASSWD
352 COPYPROTOFIELD(pw_passwd);
353 #else
354 COPYFIELD(pw_passwd);
355 #endif
356
357 if (useproto && !(protoflags & _PASSWORD_NOUID))
358 pw->pw_uid = protopw->pw_uid;
359 else
360 pw->pw_uid = frompw->pw_uid;
361
362 if (useproto && !(protoflags & _PASSWORD_NOGID))
363 pw->pw_gid = protopw->pw_gid;
364 else
365 pw->pw_gid = frompw->pw_gid;
366
367 pw->pw_change = frompw->pw_change;
368 COPYFIELD(pw_class);
369 COPYPROTOFIELD(pw_gecos);
370 COPYPROTOFIELD(pw_dir);
371 COPYPROTOFIELD(pw_shell);
372
373 #undef COPYSTR
374 #undef COPYFIELD
375 #undef COPYPROTOFIELD
376
377 return 1;
378 }
379
380
381 /*
382 * files methods
383 */
384
385 /* state shared between files methods */
386 struct files_state {
387 int stayopen; /* see getpassent(3) */
388 DB *db; /* passwd file handle */
389 int keynum; /* key counter, -1 if no more */
390 };
391
392 static struct files_state _files_state;
393 /* storage for non _r functions */
394 static struct passwd _files_passwd;
395 static char _files_passwdbuf[_GETPW_R_SIZE_MAX];
396
397 static int
398 _files_start(struct files_state *state)
399 {
400 int rv;
401
402 _DIAGASSERT(state != NULL);
403
404 state->keynum = 0;
405 rv = _pw_opendb(&state->db);
406 if (rv != NS_SUCCESS)
407 return rv;
408 return NS_SUCCESS;
409 }
410
411 static int
412 _files_end(struct files_state *state)
413 {
414
415 _DIAGASSERT(state != NULL);
416
417 state->keynum = 0;
418 if (state->db) {
419 (void)(state->db->close)(state->db);
420 state->db = NULL;
421 }
422 return NS_SUCCESS;
423 }
424
425 /*
426 * _files_pwscan
427 * Search state->db for the next desired entry.
428 * If search is _PW_KEYBYNUM, look for state->keynum.
429 * If search is _PW_KEYBYNAME, look for name.
430 * If search is _PW_KEYBYUID, look for uid.
431 * Sets *retval to the errno if the result is not NS_SUCCESS.
432 */
433 static int
434 _files_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen,
435 struct files_state *state, int search, const char *name, uid_t uid)
436 {
437 const void *from;
438 size_t fromlen;
439 DBT key;
440 int rv;
441
442 _DIAGASSERT(retval != NULL);
443 _DIAGASSERT(pw != NULL);
444 _DIAGASSERT(buffer != NULL);
445 _DIAGASSERT(state != NULL);
446 /* name is NULL to indicate searching for uid */
447
448 *retval = 0;
449
450 if (state->db == NULL) { /* only start if file not open yet */
451 rv = _files_start(state);
452 if (rv != NS_SUCCESS)
453 goto filespwscan_out;
454 }
455
456 for (;;) { /* search for a match */
457 switch (search) {
458 case _PW_KEYBYNUM:
459 if (state->keynum == -1)
460 return NS_NOTFOUND; /* no more records */
461 state->keynum++;
462 from = &state->keynum;
463 fromlen = sizeof(state->keynum);
464 break;
465 case _PW_KEYBYNAME:
466 from = name;
467 fromlen = strlen(name);
468 break;
469 case _PW_KEYBYUID:
470 from = &uid;
471 fromlen = sizeof(uid);
472 break;
473 default:
474 abort();
475 }
476
477 if (buflen <= fromlen) { /* buffer too small */
478 *retval = ERANGE;
479 return NS_UNAVAIL;
480 }
481 buffer[0] = search; /* setup key */
482 memmove(buffer + 1, from, fromlen);
483 key.size = fromlen + 1;
484 key.data = (u_char *)buffer;
485
486 /* search for key */
487 rv = _pw_getkey(state->db, &key, pw, buffer, buflen, NULL);
488 if (rv != NS_SUCCESS) /* no match */
489 break;
490 if (pw->pw_name[0] == '+' || pw->pw_name[0] == '-') {
491 /* if a compat line */
492 if (search == _PW_KEYBYNUM)
493 continue; /* read next if pwent */
494 rv = NS_NOTFOUND; /* don't match if pw{nam,uid} */
495 break;
496 }
497 break;
498 }
499
500 if (rv == NS_NOTFOUND && search == _PW_KEYBYNUM)
501 state->keynum = -1; /* flag `no more records' */
502
503 if (rv == NS_SUCCESS) {
504 if ((search == _PW_KEYBYUID && pw->pw_uid != uid) ||
505 (search == _PW_KEYBYNAME && strcmp(pw->pw_name, name) != 0))
506 rv = NS_NOTFOUND;
507 }
508
509 filespwscan_out:
510 if (rv != NS_SUCCESS)
511 *retval = errno;
512 return rv;
513 }
514
515 /*ARGSUSED*/
516 static int
517 _files_setpwent(void *nsrv, void *nscb, va_list ap)
518 {
519
520 _files_state.stayopen = 0;
521 return _files_start(&_files_state);
522 }
523
524 /*ARGSUSED*/
525 static int
526 _files_setpassent(void *nsrv, void *nscb, va_list ap)
527 {
528 int *retval = va_arg(ap, int *);
529 int stayopen = va_arg(ap, int);
530
531 int rv;
532
533 _files_state.stayopen = stayopen;
534 rv = _files_start(&_files_state);
535 *retval = (rv == NS_SUCCESS);
536 return rv;
537 }
538
539 /*ARGSUSED*/
540 static int
541 _files_endpwent(void *nsrv, void *nscb, va_list ap)
542 {
543
544 _files_state.stayopen = 0;
545 return _files_end(&_files_state);
546 }
547
548 /*ARGSUSED*/
549 static int
550 _files_getpwent(void *nsrv, void *nscb, va_list ap)
551 {
552 struct passwd **retval = va_arg(ap, struct passwd **);
553
554 int rv, rerror;
555
556 _DIAGASSERT(retval != NULL);
557
558 *retval = NULL;
559 rv = _files_pwscan(&rerror, &_files_passwd,
560 _files_passwdbuf, sizeof(_files_passwdbuf),
561 &_files_state, _PW_KEYBYNUM, NULL, 0);
562 if (rv == NS_SUCCESS)
563 *retval = &_files_passwd;
564 return rv;
565 }
566
567 /*ARGSUSED*/
568 static int
569 _files_getpwnam(void *nsrv, void *nscb, va_list ap)
570 {
571 struct passwd **retval = va_arg(ap, struct passwd **);
572 const char *name = va_arg(ap, const char *);
573
574 int rv, rerror;
575
576 _DIAGASSERT(retval != NULL);
577
578 *retval = NULL;
579 rv = _files_start(&_files_state);
580 if (rv != NS_SUCCESS)
581 return rv;
582 rv = _files_pwscan(&rerror, &_files_passwd,
583 _files_passwdbuf, sizeof(_files_passwdbuf),
584 &_files_state, _PW_KEYBYNAME, name, 0);
585 if (!_files_state.stayopen)
586 _files_end(&_files_state);
587 if (rv == NS_SUCCESS)
588 *retval = &_files_passwd;
589 return rv;
590 }
591
592 /*ARGSUSED*/
593 static int
594 _files_getpwnam_r(void *nsrv, void *nscb, va_list ap)
595 {
596 int *retval = va_arg(ap, int *);
597 const char *name = va_arg(ap, const char *);
598 struct passwd *pw = va_arg(ap, struct passwd *);
599 char *buffer = va_arg(ap, char *);
600 size_t buflen = va_arg(ap, size_t);
601 struct passwd **result = va_arg(ap, struct passwd **);
602
603 struct files_state state;
604 int rv;
605
606 _DIAGASSERT(retval != NULL);
607 _DIAGASSERT(pw != NULL);
608 _DIAGASSERT(buffer != NULL);
609 _DIAGASSERT(result != NULL);
610
611 *result = NULL;
612 memset(&state, 0, sizeof(state));
613 rv = _files_pwscan(retval, pw, buffer, buflen, &state,
614 _PW_KEYBYNAME, name, 0);
615 _files_end(&state);
616 if (rv == NS_SUCCESS)
617 *result = pw;
618 return rv;
619 }
620
621 /*ARGSUSED*/
622 static int
623 _files_getpwuid(void *nsrv, void *nscb, va_list ap)
624 {
625 struct passwd **retval = va_arg(ap, struct passwd **);
626 uid_t uid = va_arg(ap, uid_t);
627
628 int rv, rerror;
629
630 _DIAGASSERT(retval != NULL);
631
632 *retval = NULL;
633 rv = _files_start(&_files_state);
634 if (rv != NS_SUCCESS)
635 return rv;
636 rv = _files_pwscan(&rerror, &_files_passwd,
637 _files_passwdbuf, sizeof(_files_passwdbuf),
638 &_files_state, _PW_KEYBYUID, NULL, uid);
639 if (!_files_state.stayopen)
640 _files_end(&_files_state);
641 if (rv == NS_SUCCESS)
642 *retval = &_files_passwd;
643 return rv;
644 }
645
646 /*ARGSUSED*/
647 static int
648 _files_getpwuid_r(void *nsrv, void *nscb, va_list ap)
649 {
650 int *retval = va_arg(ap, int *);
651 uid_t uid = va_arg(ap, uid_t);
652 struct passwd *pw = va_arg(ap, struct passwd *);
653 char *buffer = va_arg(ap, char *);
654 size_t buflen = va_arg(ap, size_t);
655 struct passwd **result = va_arg(ap, struct passwd **);
656
657 struct files_state state;
658 int rv;
659
660 _DIAGASSERT(retval != NULL);
661 _DIAGASSERT(pw != NULL);
662 _DIAGASSERT(buffer != NULL);
663 _DIAGASSERT(result != NULL);
664
665 *result = NULL;
666 memset(&state, 0, sizeof(state));
667 rv = _files_pwscan(retval, pw, buffer, buflen, &state,
668 _PW_KEYBYUID, NULL, uid);
669 _files_end(&state);
670 if (rv == NS_SUCCESS)
671 *result = pw;
672 return rv;
673 }
674
675
676 #ifdef HESIOD
677 /*
678 * dns methods
679 */
680
681 /* state shared between dns methods */
682 struct dns_state {
683 int stayopen; /* see getpassent(3) */
684 void *context; /* Hesiod context */
685 int num; /* passwd index, -1 if no more */
686 };
687
688 static struct dns_state _dns_state;
689 /* storage for non _r functions */
690 static struct passwd _dns_passwd;
691 static char _dns_passwdbuf[_GETPW_R_SIZE_MAX];
692
693 static int
694 _dns_start(struct dns_state *state)
695 {
696
697 _DIAGASSERT(state != NULL);
698
699 state->num = 0;
700 if (state->context == NULL) { /* setup Hesiod */
701 if (hesiod_init(&state->context) == -1)
702 return NS_UNAVAIL;
703 }
704
705 return NS_SUCCESS;
706 }
707
708 static int
709 _dns_end(struct dns_state *state)
710 {
711
712 _DIAGASSERT(state != NULL);
713
714 state->num = 0;
715 if (state->context) {
716 hesiod_end(state->context);
717 state->context = NULL;
718 }
719 return NS_SUCCESS;
720 }
721
722 /*
723 * _dns_pwscan
724 * Look for the Hesiod name provided in buffer in the NULL-terminated
725 * list of zones,
726 * and decode into pw/buffer/buflen.
727 */
728 static int
729 _dns_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen,
730 struct dns_state *state, const char **zones)
731 {
732 const char **curzone;
733 char **hp, *ep;
734 int rv;
735
736 _DIAGASSERT(retval != NULL);
737 _DIAGASSERT(pw != NULL);
738 _DIAGASSERT(buffer != NULL);
739 _DIAGASSERT(state != NULL);
740 _DIAGASSERT(zones != NULL);
741
742 *retval = 0;
743
744 if (state->context == NULL) { /* only start if Hesiod not setup */
745 rv = _dns_start(state);
746 if (rv != NS_SUCCESS)
747 return rv;
748 }
749
750 hp = NULL;
751 rv = NS_NOTFOUND;
752
753 for (curzone = zones; *curzone; curzone++) { /* search zones */
754 hp = hesiod_resolve(state->context, buffer, *curzone);
755 if (hp != NULL)
756 break;
757 if (errno != ENOENT) {
758 rv = NS_UNAVAIL;
759 goto dnspwscan_out;
760 }
761 }
762 if (*curzone == NULL)
763 goto dnspwscan_out;
764
765 if ((ep = strchr(hp[0], '\n')) != NULL)
766 *ep = '\0'; /* clear trailing \n */
767 if (_pw_parse(hp[0], pw, buffer, buflen, 1)) /* validate line */
768 rv = NS_SUCCESS;
769 else
770 rv = NS_UNAVAIL;
771
772 dnspwscan_out:
773 if (rv != NS_SUCCESS)
774 *retval = errno;
775 if (hp)
776 hesiod_free_list(state->context, hp);
777 return rv;
778 }
779
780 /*ARGSUSED*/
781 static int
782 _dns_setpwent(void *nsrv, void *nscb, va_list ap)
783 {
784
785 _dns_state.stayopen = 0;
786 return _dns_start(&_dns_state);
787 }
788
789 /*ARGSUSED*/
790 static int
791 _dns_setpassent(void *nsrv, void *nscb, va_list ap)
792 {
793 int *retval = va_arg(ap, int *);
794 int stayopen = va_arg(ap, int);
795
796 int rv;
797
798 _dns_state.stayopen = stayopen;
799 rv = _dns_start(&_dns_state);
800 *retval = (rv == NS_SUCCESS);
801 return rv;
802 }
803
804 /*ARGSUSED*/
805 static int
806 _dns_endpwent(void *nsrv, void *nscb, va_list ap)
807 {
808
809 _dns_state.stayopen = 0;
810 return _dns_end(&_dns_state);
811 }
812
813 /*ARGSUSED*/
814 static int
815 _dns_getpwent(void *nsrv, void *nscb, va_list ap)
816 {
817 struct passwd **retval = va_arg(ap, struct passwd **);
818
819 char **hp, *ep;
820 int rv;
821
822 _DIAGASSERT(retval != NULL);
823
824 *retval = NULL;
825
826 if (_dns_state.num == -1) /* exhausted search */
827 return NS_NOTFOUND;
828
829 if (_dns_state.context == NULL) {
830 /* only start if Hesiod not setup */
831 rv = _dns_start(&_dns_state);
832 if (rv != NS_SUCCESS)
833 return rv;
834 }
835
836 hp = NULL;
837 rv = NS_NOTFOUND;
838
839 /* find passwd-NNN */
840 snprintf(_dns_passwdbuf, sizeof(_dns_passwdbuf),
841 "passwd-%u", _dns_state.num);
842 _dns_state.num++;
843
844 hp = hesiod_resolve(_dns_state.context, _dns_passwdbuf, "passwd");
845 if (hp == NULL) {
846 if (errno == ENOENT)
847 _dns_state.num = -1;
848 else
849 rv = NS_UNAVAIL;
850 } else {
851 if ((ep = strchr(hp[0], '\n')) != NULL)
852 *ep = '\0'; /* clear trailing \n */
853 /* validate line */
854 if (_pw_parse(hp[0], &_dns_passwd,
855 _dns_passwdbuf, sizeof(_dns_passwdbuf), 1))
856 rv = NS_SUCCESS;
857 else
858 rv = NS_UNAVAIL;
859 }
860
861 if (hp)
862 hesiod_free_list(_dns_state.context, hp);
863 if (rv == NS_SUCCESS)
864 *retval = &_dns_passwd;
865 return rv;
866 }
867
868 static const char *_dns_uid_zones[] = {
869 "uid",
870 "passwd",
871 NULL
872 };
873
874 /*ARGSUSED*/
875 static int
876 _dns_getpwuid(void *nsrv, void *nscb, va_list ap)
877 {
878 struct passwd **retval = va_arg(ap, struct passwd **);
879 uid_t uid = va_arg(ap, uid_t);
880
881 int rv, rerror;
882
883 _DIAGASSERT(retval != NULL);
884
885 *retval = NULL;
886 rv = _dns_start(&_dns_state);
887 if (rv != NS_SUCCESS)
888 return rv;
889 snprintf(_dns_passwdbuf, sizeof(_dns_passwdbuf),
890 "%u", (unsigned int)uid);
891 rv = _dns_pwscan(&rerror, &_dns_passwd,
892 _dns_passwdbuf, sizeof(_dns_passwdbuf),
893 &_dns_state, _dns_uid_zones);
894 if (!_dns_state.stayopen)
895 _dns_end(&_dns_state);
896 if (rv == NS_SUCCESS && uid == _dns_passwd.pw_uid)
897 *retval = &_dns_passwd;
898 return rv;
899 }
900
901 /*ARGSUSED*/
902 static int
903 _dns_getpwuid_r(void *nsrv, void *nscb, va_list ap)
904 {
905 int *retval = va_arg(ap, int *);
906 uid_t uid = va_arg(ap, uid_t);
907 struct passwd *pw = va_arg(ap, struct passwd *);
908 char *buffer = va_arg(ap, char *);
909 size_t buflen = va_arg(ap, size_t);
910 struct passwd **result = va_arg(ap, struct passwd **);
911
912 struct dns_state state;
913 int rv;
914
915 _DIAGASSERT(retval != NULL);
916 _DIAGASSERT(pw != NULL);
917 _DIAGASSERT(buffer != NULL);
918 _DIAGASSERT(result != NULL);
919
920 *result = NULL;
921 memset(&state, 0, sizeof(state));
922 snprintf(buffer, buflen, "%u", (unsigned int)uid);
923 rv = _dns_pwscan(retval, pw, buffer, buflen, &state, _dns_uid_zones);
924 _dns_end(&state);
925 if (rv != NS_SUCCESS)
926 return rv;
927 if (uid == pw->pw_uid) {
928 *result = pw;
929 return NS_SUCCESS;
930 } else
931 return NS_NOTFOUND;
932 }
933
934 static const char *_dns_nam_zones[] = {
935 "passwd",
936 NULL
937 };
938
939 /*ARGSUSED*/
940 static int
941 _dns_getpwnam(void *nsrv, void *nscb, va_list ap)
942 {
943 struct passwd **retval = va_arg(ap, struct passwd **);
944 const char *name = va_arg(ap, const char *);
945
946 int rv, rerror;
947
948 _DIAGASSERT(retval != NULL);
949
950 *retval = NULL;
951 rv = _dns_start(&_dns_state);
952 if (rv != NS_SUCCESS)
953 return rv;
954 snprintf(_dns_passwdbuf, sizeof(_dns_passwdbuf), "%s", name);
955 rv = _dns_pwscan(&rerror, &_dns_passwd,
956 _dns_passwdbuf, sizeof(_dns_passwdbuf),
957 &_dns_state, _dns_nam_zones);
958 if (!_dns_state.stayopen)
959 _dns_end(&_dns_state);
960 if (rv == NS_SUCCESS && strcmp(name, _dns_passwd.pw_name) == 0)
961 *retval = &_dns_passwd;
962 return rv;
963 }
964
965 /*ARGSUSED*/
966 static int
967 _dns_getpwnam_r(void *nsrv, void *nscb, va_list ap)
968 {
969 int *retval = va_arg(ap, int *);
970 const char *name = va_arg(ap, const char *);
971 struct passwd *pw = va_arg(ap, struct passwd *);
972 char *buffer = va_arg(ap, char *);
973 size_t buflen = va_arg(ap, size_t);
974 struct passwd **result = va_arg(ap, struct passwd **);
975
976 struct dns_state state;
977 int rv;
978
979 _DIAGASSERT(retval != NULL);
980 _DIAGASSERT(pw != NULL);
981 _DIAGASSERT(buffer != NULL);
982 _DIAGASSERT(result != NULL);
983
984 *result = NULL;
985 memset(&state, 0, sizeof(state));
986 snprintf(buffer, buflen, "%s", name);
987 rv = _dns_pwscan(retval, pw, buffer, buflen, &state, _dns_nam_zones);
988 _dns_end(&state);
989 if (rv != NS_SUCCESS)
990 return rv;
991 if (strcmp(name, pw->pw_name) == 0) {
992 *result = pw;
993 return NS_SUCCESS;
994 } else
995 return NS_NOTFOUND;
996 }
997
998 #endif /* HESIOD */
999
1000
1001 #ifdef YP
1002 /*
1003 * nis methods
1004 */
1005 /* state shared between nis methods */
1006 struct nis_state {
1007 int stayopen; /* see getpassent(3) */
1008 char *domain; /* NIS domain */
1009 int done; /* non-zero if search exhausted */
1010 char *current; /* current first/next match */
1011 int currentlen; /* length of _nis_current */
1012 enum { /* shadow map type */
1013 NISMAP_UNKNOWN, /* unknown ... */
1014 NISMAP_NONE, /* none: use "passwd.by*" */
1015 NISMAP_ADJUNCT, /* pw_passwd from "passwd.adjunct.*" */
1016 NISMAP_MASTER /* all from "master.passwd.by*" */
1017 } maptype;
1018 };
1019
1020 static struct nis_state _nis_state;
1021 /* storage for non _r functions */
1022 static struct passwd _nis_passwd;
1023 static char _nis_passwdbuf[_GETPW_R_SIZE_MAX];
1024
1025 /* macros for deciding which NIS maps to use. */
1026 #define PASSWD_BYNAME(x) ((x)->maptype == NISMAP_MASTER \
1027 ? "master.passwd.byname" : "passwd.byname")
1028 #define PASSWD_BYUID(x) ((x)->maptype == NISMAP_MASTER \
1029 ? "master.passwd.byuid" : "passwd.byuid")
1030
1031 static int
1032 _nis_start(struct nis_state *state)
1033 {
1034
1035 _DIAGASSERT(state != NULL);
1036
1037 state->done = 0;
1038 if (state->current) {
1039 free(state->current);
1040 state->current = NULL;
1041 }
1042 if (state->domain == NULL) { /* setup NIS */
1043 switch (yp_get_default_domain(&state->domain)) {
1044 case 0:
1045 break;
1046 case YPERR_RESRC:
1047 return NS_TRYAGAIN;
1048 default:
1049 return NS_UNAVAIL;
1050 }
1051 }
1052
1053 /* determine where to get pw_passwd from */
1054 if (state->maptype == NISMAP_UNKNOWN) {
1055 int r, order;
1056
1057 state->maptype = NISMAP_NONE; /* default to no adjunct */
1058 if (geteuid() != 0) /* non-root can't use adjunct */
1059 return NS_SUCCESS;
1060
1061 /* look for "master.passwd.*" */
1062 r = yp_order(state->domain, "master.passwd.byname", &order);
1063 if (r == 0) {
1064 state->maptype = NISMAP_MASTER;
1065 return NS_SUCCESS;
1066 }
1067
1068 /* master.passwd doesn't exist, try passwd.adjunct */
1069 if (r == YPERR_MAP) {
1070 r = yp_order(state->domain, "passwd.adjunct.byname",
1071 &order);
1072 if (r == 0)
1073 state->maptype = NISMAP_ADJUNCT;
1074 }
1075 }
1076 return NS_SUCCESS;
1077 }
1078
1079 static int
1080 _nis_end(struct nis_state *state)
1081 {
1082
1083 _DIAGASSERT(state != NULL);
1084
1085 if (state->domain)
1086 state->domain = NULL;
1087 state->done = 0;
1088 if (state->current)
1089 free(state->current);
1090 state->current = NULL;
1091 state->maptype = NISMAP_UNKNOWN;
1092 return NS_SUCCESS;
1093 }
1094
1095 /*
1096 * nis_parse
1097 * wrapper to _pw_parse that obtains the real password from the
1098 * "passwd.adjunct.byname" NIS map if the maptype is NISMAP_ADJUNCT.
1099 */
1100 static int
1101 _nis_parse(const char *entry, struct passwd *pw, char *buf, size_t buflen,
1102 struct nis_state *state)
1103 {
1104 size_t elen;
1105
1106 _DIAGASSERT(entry != NULL);
1107 _DIAGASSERT(pw != NULL);
1108 _DIAGASSERT(buf != NULL);
1109 _DIAGASSERT(state != NULL);
1110
1111 elen = strlen(entry);
1112 if (elen >= buflen)
1113 return 0;
1114 if (! _pw_parse(entry, pw, buf, buflen,
1115 !(state->maptype == NISMAP_MASTER)))
1116 return 0;
1117
1118 if ((state->maptype == NISMAP_ADJUNCT) &&
1119 (strstr(pw->pw_passwd, "##") != NULL)) {
1120 char *data;
1121 int datalen;
1122
1123 if (yp_match(state->domain, "passwd.adjunct.byname",
1124 pw->pw_name, (int)strlen(pw->pw_name),
1125 &data, &datalen) == 0) {
1126 char *bp, *ep;
1127 /* skip name to get password */
1128 ep = data;
1129 if ((bp = strsep(&ep, ":")) != NULL &&
1130 (bp = strsep(&ep, ":")) != NULL) {
1131 /* store new pw_passwd after entry */
1132 strlcpy(buf + elen, bp, buflen - elen);
1133 pw->pw_passwd = &buf[elen];
1134 }
1135 free(data);
1136 }
1137 }
1138
1139 return 1;
1140 }
1141
1142
1143 /*
1144 * _nis_pwscan
1145 * Look for the yp key provided in buffer from map,
1146 * and decode into pw/buffer/buflen.
1147 */
1148 static int
1149 _nis_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen,
1150 struct nis_state *state, const char *map)
1151 {
1152 char *data;
1153 int nisr, rv, datalen;
1154
1155 _DIAGASSERT(retval != NULL);
1156 _DIAGASSERT(pw != NULL);
1157 _DIAGASSERT(buffer != NULL);
1158 _DIAGASSERT(state != NULL);
1159 _DIAGASSERT(map != NULL);
1160
1161 *retval = 0;
1162
1163 if (state->domain == NULL) { /* only start if NIS not setup */
1164 rv = _nis_start(state);
1165 if (rv != NS_SUCCESS)
1166 return rv;
1167 }
1168
1169 data = NULL;
1170 rv = NS_NOTFOUND;
1171
1172 /* search map */
1173 nisr = yp_match(state->domain, map, buffer, (int)strlen(buffer),
1174 &data, &datalen);
1175 switch (nisr) {
1176 case 0:
1177 data[datalen] = '\0'; /* clear trailing \n */
1178 if (_nis_parse(data, pw, buffer, buflen, state))
1179 rv = NS_SUCCESS; /* validate line */
1180 else
1181 rv = NS_UNAVAIL;
1182 break;
1183 case YPERR_KEY:
1184 break;
1185 default:
1186 rv = NS_UNAVAIL;
1187 break;
1188 }
1189
1190 if (rv != NS_SUCCESS)
1191 *retval = errno;
1192 if (data)
1193 free(data);
1194 return rv;
1195 }
1196
1197 /*ARGSUSED*/
1198 static int
1199 _nis_setpwent(void *nsrv, void *nscb, va_list ap)
1200 {
1201
1202 _nis_state.stayopen = 0;
1203 return _nis_start(&_nis_state);
1204 }
1205
1206 /*ARGSUSED*/
1207 static int
1208 _nis_setpassent(void *nsrv, void *nscb, va_list ap)
1209 {
1210 int *retval = va_arg(ap, int *);
1211 int stayopen = va_arg(ap, int);
1212
1213 int rv;
1214
1215 _nis_state.stayopen = stayopen;
1216 rv = _nis_start(&_nis_state);
1217 *retval = (rv == NS_SUCCESS);
1218 return rv;
1219 }
1220
1221 /*ARGSUSED*/
1222 static int
1223 _nis_endpwent(void *nsrv, void *nscb, va_list ap)
1224 {
1225
1226 return _nis_end(&_nis_state);
1227 }
1228
1229
1230 /*ARGSUSED*/
1231 static int
1232 _nis_getpwent(void *nsrv, void *nscb, va_list ap)
1233 {
1234 struct passwd **retval = va_arg(ap, struct passwd **);
1235
1236 char *key, *data;
1237 int keylen, datalen, rv, nisr;
1238
1239 _DIAGASSERT(retval != NULL);
1240
1241 *retval = NULL;
1242
1243 if (_nis_state.done) /* exhausted search */
1244 return NS_NOTFOUND;
1245 if (_nis_state.domain == NULL) {
1246 /* only start if NIS not setup */
1247 rv = _nis_start(&_nis_state);
1248 if (rv != NS_SUCCESS)
1249 return rv;
1250 }
1251
1252 key = NULL;
1253 data = NULL;
1254 rv = NS_NOTFOUND;
1255
1256 if (_nis_state.current) { /* already searching */
1257 nisr = yp_next(_nis_state.domain, PASSWD_BYNAME(&_nis_state),
1258 _nis_state.current, _nis_state.currentlen,
1259 &key, &keylen, &data, &datalen);
1260 free(_nis_state.current);
1261 _nis_state.current = NULL;
1262 switch (nisr) {
1263 case 0:
1264 _nis_state.current = key;
1265 _nis_state.currentlen = keylen;
1266 key = NULL;
1267 break;
1268 case YPERR_NOMORE:
1269 _nis_state.done = 1;
1270 goto nisent_out;
1271 default:
1272 rv = NS_UNAVAIL;
1273 goto nisent_out;
1274 }
1275 } else { /* new search */
1276 if (yp_first(_nis_state.domain, PASSWD_BYNAME(&_nis_state),
1277 &_nis_state.current, &_nis_state.currentlen,
1278 &data, &datalen)) {
1279 rv = NS_UNAVAIL;
1280 goto nisent_out;
1281 }
1282 }
1283
1284 data[datalen] = '\0'; /* clear trailing \n */
1285 /* validate line */
1286 if (_nis_parse(data, &_nis_passwd,
1287 _nis_passwdbuf, sizeof(_nis_passwdbuf), &_nis_state))
1288 rv = NS_SUCCESS;
1289 else
1290 rv = NS_UNAVAIL;
1291
1292 nisent_out:
1293 if (key)
1294 free(key);
1295 if (data)
1296 free(data);
1297 if (rv == NS_SUCCESS)
1298 *retval = &_nis_passwd;
1299 return rv;
1300 }
1301
1302 /*ARGSUSED*/
1303 static int
1304 _nis_getpwuid(void *nsrv, void *nscb, va_list ap)
1305 {
1306 struct passwd **retval = va_arg(ap, struct passwd **);
1307 uid_t uid = va_arg(ap, uid_t);
1308
1309 int rv, rerror;
1310
1311 _DIAGASSERT(retval != NULL);
1312
1313 *retval = NULL;
1314 rv = _nis_start(&_nis_state);
1315 if (rv != NS_SUCCESS)
1316 return rv;
1317 snprintf(_nis_passwdbuf, sizeof(_nis_passwdbuf), "%u", (unsigned int)uid);
1318 rv = _nis_pwscan(&rerror, &_nis_passwd,
1319 _nis_passwdbuf, sizeof(_nis_passwdbuf),
1320 &_nis_state, PASSWD_BYUID(&_nis_state));
1321 if (!_nis_state.stayopen)
1322 _nis_end(&_nis_state);
1323 if (rv == NS_SUCCESS && uid == _nis_passwd.pw_uid)
1324 *retval = &_nis_passwd;
1325 return rv;
1326 }
1327
1328 /*ARGSUSED*/
1329 static int
1330 _nis_getpwuid_r(void *nsrv, void *nscb, va_list ap)
1331 {
1332 int *retval = va_arg(ap, int *);
1333 uid_t uid = va_arg(ap, uid_t);
1334 struct passwd *pw = va_arg(ap, struct passwd *);
1335 char *buffer = va_arg(ap, char *);
1336 size_t buflen = va_arg(ap, size_t);
1337 struct passwd **result = va_arg(ap, struct passwd **);
1338
1339 struct nis_state state;
1340 int rv;
1341
1342 _DIAGASSERT(retval != NULL);
1343 _DIAGASSERT(pw != NULL);
1344 _DIAGASSERT(buffer != NULL);
1345 _DIAGASSERT(result != NULL);
1346
1347 *result = NULL;
1348 memset(&state, 0, sizeof(state));
1349 rv = _nis_start(&state);
1350 if (rv != NS_SUCCESS)
1351 return rv;
1352 snprintf(buffer, buflen, "%u", (unsigned int)uid);
1353 rv = _nis_pwscan(retval, pw, buffer, buflen,
1354 &state, PASSWD_BYUID(&state));
1355 _nis_end(&state);
1356 if (rv != NS_SUCCESS)
1357 return rv;
1358 if (uid == pw->pw_uid) {
1359 *result = pw;
1360 return NS_SUCCESS;
1361 } else
1362 return NS_NOTFOUND;
1363 }
1364
1365 /*ARGSUSED*/
1366 static int
1367 _nis_getpwnam(void *nsrv, void *nscb, va_list ap)
1368 {
1369 struct passwd **retval = va_arg(ap, struct passwd **);
1370 const char *name = va_arg(ap, const char *);
1371
1372 int rv, rerror;
1373
1374 _DIAGASSERT(retval != NULL);
1375
1376 *retval = NULL;
1377 rv = _nis_start(&_nis_state);
1378 if (rv != NS_SUCCESS)
1379 return rv;
1380 snprintf(_nis_passwdbuf, sizeof(_nis_passwdbuf), "%s", name);
1381 rv = _nis_pwscan(&rerror, &_nis_passwd,
1382 _nis_passwdbuf, sizeof(_nis_passwdbuf),
1383 &_nis_state, PASSWD_BYNAME(&_nis_state));
1384 if (!_nis_state.stayopen)
1385 _nis_end(&_nis_state);
1386 if (rv == NS_SUCCESS && strcmp(name, _nis_passwd.pw_name) == 0)
1387 *retval = &_nis_passwd;
1388 return rv;
1389 }
1390
1391 /*ARGSUSED*/
1392 static int
1393 _nis_getpwnam_r(void *nsrv, void *nscb, va_list ap)
1394 {
1395 int *retval = va_arg(ap, int *);
1396 const char *name = va_arg(ap, const char *);
1397 struct passwd *pw = va_arg(ap, struct passwd *);
1398 char *buffer = va_arg(ap, char *);
1399 size_t buflen = va_arg(ap, size_t);
1400 struct passwd **result = va_arg(ap, struct passwd **);
1401
1402 struct nis_state state;
1403 int rv;
1404
1405 _DIAGASSERT(retval != NULL);
1406 _DIAGASSERT(pw != NULL);
1407 _DIAGASSERT(buffer != NULL);
1408 _DIAGASSERT(result != NULL);
1409
1410 *result = NULL;
1411 snprintf(buffer, buflen, "%s", name);
1412 memset(&state, 0, sizeof(state));
1413 rv = _nis_start(&state);
1414 if (rv != NS_SUCCESS)
1415 return rv;
1416 rv = _nis_pwscan(retval, pw, buffer, buflen,
1417 &state, PASSWD_BYNAME(&state));
1418 _nis_end(&state);
1419 if (rv != NS_SUCCESS)
1420 return rv;
1421 if (strcmp(name, pw->pw_name) == 0) {
1422 *result = pw;
1423 return NS_SUCCESS;
1424 } else
1425 return NS_NOTFOUND;
1426 }
1427
1428 #endif /* YP */
1429
1430
1431 #ifdef _PASSWD_COMPAT
1432 /*
1433 * compat methods
1434 */
1435
1436 /* state shared between compat methods */
1437
1438 struct compat_state {
1439 int stayopen; /* see getpassent(3) */
1440 DB *db; /* passwd DB */
1441 int keynum; /* key counter, -1 if no more */
1442 enum { /* current compat mode */
1443 COMPAT_NOTOKEN = 0, /* no compat token present */
1444 COMPAT_NONE, /* parsing normal pwd.db line */
1445 COMPAT_FULL, /* parsing `+' entries */
1446 COMPAT_USER, /* parsing `+name' entries */
1447 COMPAT_NETGROUP /* parsing `+@netgroup' entries */
1448 } mode;
1449 char *user; /* COMPAT_USER "+name" */
1450 DB *exclude; /* compat exclude DB */
1451 struct passwd proto; /* proto passwd entry */
1452 char protobuf[_GETPW_R_SIZE_MAX];
1453 /* buffer for proto ptrs */
1454 int protoflags; /* proto passwd flags */
1455 };
1456
1457 static struct compat_state _compat_state;
1458 /* storage for non _r functions */
1459 static struct passwd _compat_passwd;
1460 static char _compat_passwdbuf[_GETPW_R_SIZE_MAX];
1461
1462 static int
1463 _compat_start(struct compat_state *state)
1464 {
1465 int rv;
1466
1467 _DIAGASSERT(state != NULL);
1468
1469 state->keynum = 0;
1470 if (state->db == NULL) { /* not open yet */
1471 DBT key, data;
1472 DBT pkey, pdata;
1473 char bf[MAXLOGNAME];
1474
1475 rv = _pw_opendb(&state->db);
1476 if (rv != NS_SUCCESS)
1477 return rv;
1478
1479 state->mode = COMPAT_NOTOKEN;
1480
1481 /*
1482 * Determine if the "compat" token is present in pwd.db;
1483 * either "__YP!" or PW_KEYBYNAME+"+".
1484 * Only works if pwd_mkdb installs the token.
1485 */
1486 key.data = (u_char *)__UNCONST(__yp_token);
1487 key.size = strlen(__yp_token);
1488
1489 bf[0] = _PW_KEYBYNAME; /* Pre-token database support. */
1490 bf[1] = '+';
1491 pkey.data = (u_char *)bf;
1492 pkey.size = 2;
1493
1494 if ((state->db->get)(state->db, &key, &data, 0) == 0
1495 || (state->db->get)(state->db, &pkey, &pdata, 0) == 0)
1496 state->mode = COMPAT_NONE;
1497 }
1498 return NS_SUCCESS;
1499 }
1500
1501 static int
1502 _compat_end(struct compat_state *state)
1503 {
1504
1505 _DIAGASSERT(state != NULL);
1506
1507 state->keynum = 0;
1508 if (state->db) {
1509 (void)(state->db->close)(state->db);
1510 state->db = NULL;
1511 }
1512 state->mode = COMPAT_NOTOKEN;
1513 if (state->user)
1514 free(state->user);
1515 state->user = NULL;
1516 if (state->exclude != NULL)
1517 (void)(state->exclude->close)(state->exclude);
1518 state->exclude = NULL;
1519 state->proto.pw_name = NULL;
1520 state->protoflags = 0;
1521 return NS_SUCCESS;
1522 }
1523
1524 /*
1525 * _compat_add_exclude
1526 * add the name to the exclude list in state->exclude.
1527 */
1528 static int
1529 _compat_add_exclude(struct compat_state *state, const char *name)
1530 {
1531 DBT key, data;
1532
1533 _DIAGASSERT(state != NULL);
1534 _DIAGASSERT(name != NULL);
1535
1536 /* initialize the exclusion table if needed */
1537 if (state->exclude == NULL) {
1538 state->exclude = dbopen(NULL, O_RDWR, 600, DB_HASH, NULL);
1539 if (state->exclude == NULL)
1540 return 0;
1541 }
1542
1543 key.size = strlen(name); /* set up the key */
1544 key.data = (u_char *)__UNCONST(name);
1545
1546 data.data = NULL; /* data is nothing */
1547 data.size = 0;
1548
1549 /* store it */
1550 if ((state->exclude->put)(state->exclude, &key, &data, 0) == -1)
1551 return 0;
1552
1553 return 1;
1554 }
1555
1556 /*
1557 * _compat_is_excluded
1558 * test if a name is on the compat mode exclude list
1559 */
1560 static int
1561 _compat_is_excluded(struct compat_state *state, const char *name)
1562 {
1563 DBT key, data;
1564
1565 _DIAGASSERT(state != NULL);
1566 _DIAGASSERT(name != NULL);
1567
1568 if (state->exclude == NULL)
1569 return 0; /* nothing excluded */
1570
1571 key.size = strlen(name); /* set up the key */
1572 key.data = (u_char *)__UNCONST(name);
1573
1574 if ((state->exclude->get)(state->exclude, &key, &data, 0) == 0)
1575 return 1; /* is excluded */
1576
1577 return 0;
1578 }
1579
1580
1581 /*
1582 * _passwdcompat_bad
1583 * log an error if "files" or "compat" is specified in
1584 * passwd_compat database
1585 */
1586 /*ARGSUSED*/
1587 static int
1588 _passwdcompat_bad(void *nsrv, void *nscb, va_list ap)
1589 {
1590 static int warned;
1591
1592 _DIAGASSERT(cb_data != NULL);
1593
1594 if (!warned) {
1595 syslog(LOG_ERR,
1596 "nsswitch.conf passwd_compat database can't use '%s'",
1597 (char *)nscb);
1598 }
1599 warned = 1;
1600 return NS_UNAVAIL;
1601 }
1602
1603 /*
1604 * _passwdcompat_setpassent
1605 * Call setpassent for all passwd_compat sources.
1606 */
1607 static int
1608 _passwdcompat_setpassent(int stayopen)
1609 {
1610 static const ns_dtab dtab[] = {
1611 NS_FILES_CB(_passwdcompat_bad, "files")
1612 NS_DNS_CB(_dns_setpassent, NULL)
1613 NS_NIS_CB(_nis_setpassent, NULL)
1614 NS_COMPAT_CB(_passwdcompat_bad, "compat")
1615 { 0 }
1616 };
1617
1618 int rv, result;
1619
1620 rv = nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "setpassent",
1621 __nsdefaultnis_forceall, &result, stayopen);
1622 return rv;
1623 }
1624
1625 /*
1626 * _passwdcompat_endpwent
1627 * Call endpwent for all passwd_compat sources.
1628 */
1629 static int
1630 _passwdcompat_endpwent(void)
1631 {
1632 static const ns_dtab dtab[] = {
1633 NS_FILES_CB(_passwdcompat_bad, "files")
1634 NS_DNS_CB(_dns_endpwent, NULL)
1635 NS_NIS_CB(_nis_endpwent, NULL)
1636 NS_COMPAT_CB(_passwdcompat_bad, "compat")
1637 { 0 }
1638 };
1639
1640 return nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "endpwent",
1641 __nsdefaultnis_forceall);
1642 }
1643
1644 /*
1645 * _passwdcompat_pwscan
1646 * When a name lookup in compat mode is required (e.g., `+name', or a
1647 * name in `+@netgroup'), look it up in the 'passwd_compat' nsswitch
1648 * database.
1649 * Fail if passwd_compat contains files or compat.
1650 */
1651 static int
1652 _passwdcompat_pwscan(struct passwd *pw, char *buffer, size_t buflen,
1653 int search, const char *name, uid_t uid)
1654 {
1655 static const ns_dtab compatentdtab[] = {
1656 NS_FILES_CB(_passwdcompat_bad, "files")
1657 NS_DNS_CB(_dns_getpwent, NULL)
1658 NS_NIS_CB(_nis_getpwent, NULL)
1659 NS_COMPAT_CB(_passwdcompat_bad, "compat")
1660 { 0 }
1661 };
1662 static const ns_dtab compatuiddtab[] = {
1663 NS_FILES_CB(_passwdcompat_bad, "files")
1664 NS_DNS_CB(_dns_getpwuid_r, NULL)
1665 NS_NIS_CB(_nis_getpwuid_r, NULL)
1666 NS_COMPAT_CB(_passwdcompat_bad, "compat")
1667 { 0 }
1668 };
1669 static const ns_dtab compatnamdtab[] = {
1670 NS_FILES_CB(_passwdcompat_bad, "files")
1671 NS_DNS_CB(_dns_getpwnam_r, NULL)
1672 NS_NIS_CB(_nis_getpwnam_r, NULL)
1673 NS_COMPAT_CB(_passwdcompat_bad, "compat")
1674 { 0 }
1675 };
1676
1677 int rv, crv;
1678 struct passwd *cpw;
1679
1680 switch (search) {
1681 case _PW_KEYBYNUM:
1682 /* XXXREENTRANT: implement & use getpwent_r */
1683 rv = nsdispatch(NULL, compatentdtab,
1684 NSDB_PASSWD_COMPAT, "getpwent", __nsdefaultnis,
1685 &cpw);
1686 if (rv == NS_SUCCESS &&
1687 ! _pw_copy(cpw, pw, buffer, buflen, NULL, 0)) {
1688 errno = ERANGE;
1689 rv = NS_UNAVAIL;
1690 }
1691 break;
1692 case _PW_KEYBYNAME:
1693 _DIAGASSERT(name != NULL);
1694 rv = nsdispatch(NULL, compatnamdtab,
1695 NSDB_PASSWD_COMPAT, "getpwnam_r", __nsdefaultnis,
1696 &crv, name, pw, buffer, buflen, &cpw);
1697 break;
1698 case _PW_KEYBYUID:
1699 rv = nsdispatch(NULL, compatuiddtab,
1700 NSDB_PASSWD_COMPAT, "getpwuid_r", __nsdefaultnis,
1701 &crv, uid, pw, buffer, buflen, &cpw);
1702 break;
1703 default:
1704 abort();
1705 /*NOTREACHED*/
1706 }
1707 return rv;
1708 }
1709
1710 /*
1711 * _compat_pwscan
1712 * Search state->db for the next desired entry.
1713 * If search is _PW_KEYBYNUM, look for state->keynum.
1714 * If search is _PW_KEYBYNAME, look for name.
1715 * If search is _PW_KEYBYUID, look for uid.
1716 * Sets *retval to the errno if the result is not NS_SUCCESS.
1717 */
1718 static int
1719 _compat_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen,
1720 struct compat_state *state, int search, const char *name, uid_t uid)
1721 {
1722 DBT key;
1723 int rv, r, pwflags;
1724 const char *user, *host, *dom;
1725 const void *from;
1726 size_t fromlen;
1727
1728 _DIAGASSERT(retval != NULL);
1729 _DIAGASSERT(pw != NULL);
1730 _DIAGASSERT(buffer != NULL);
1731 _DIAGASSERT(state != NULL);
1732 /* name may be NULL */
1733
1734 *retval = 0;
1735
1736 if (state->db == NULL) {
1737 rv = _compat_start(state);
1738 if (rv != NS_SUCCESS)
1739 return rv;
1740 }
1741 if (buflen <= 1) { /* buffer too small */
1742 *retval = ERANGE;
1743 return NS_UNAVAIL;
1744 }
1745
1746 for (;;) { /* loop over pwd.db */
1747 rv = NS_NOTFOUND;
1748 if (state->mode != COMPAT_NOTOKEN &&
1749 state->mode != COMPAT_NONE) {
1750 /* doing a compat lookup */
1751 struct passwd cpw;
1752 char cbuf[_GETPW_R_SIZE_MAX];
1753
1754 switch (state->mode) {
1755
1756 case COMPAT_FULL:
1757 /* get next user */
1758 rv = _passwdcompat_pwscan(&cpw,
1759 cbuf, sizeof(cbuf),
1760 _PW_KEYBYNUM, NULL, 0);
1761 if (rv != NS_SUCCESS)
1762 state->mode = COMPAT_NONE;
1763 break;
1764
1765 case COMPAT_NETGROUP:
1766 /* XXXREENTRANT: getnetgrent is not thread safe */
1767 /* get next user from netgroup */
1768 r = getnetgrent(&host, &user, &dom);
1769 if (r == 0) { /* end of group */
1770 endnetgrent();
1771 state->mode = COMPAT_NONE;
1772 break;
1773 }
1774 if (!user || !*user)
1775 break;
1776 rv = _passwdcompat_pwscan(&cpw,
1777 cbuf, sizeof(cbuf),
1778 _PW_KEYBYNAME, user, 0);
1779 break;
1780
1781 case COMPAT_USER:
1782 /* get specific user */
1783 if (state->user == NULL) {
1784 state->mode = COMPAT_NONE;
1785 break;
1786 }
1787 rv = _passwdcompat_pwscan(&cpw,
1788 cbuf, sizeof(cbuf),
1789 _PW_KEYBYNAME, state->user, 0);
1790 free(state->user);
1791 state->user = NULL;
1792 state->mode = COMPAT_NONE;
1793 break;
1794
1795 case COMPAT_NOTOKEN:
1796 case COMPAT_NONE:
1797 abort();
1798
1799 }
1800 if (rv != NS_SUCCESS) /* if not matched, next loop */
1801 continue;
1802
1803 /* copy cpw to pw, applying prototype */
1804 if (! _pw_copy(&cpw, pw, buffer, buflen,
1805 &state->proto, state->protoflags)) {
1806 rv = NS_UNAVAIL;
1807 break;
1808 }
1809
1810 if (_compat_is_excluded(state, pw->pw_name))
1811 continue; /* excluded; next loop */
1812
1813 if ((search == _PW_KEYBYNAME
1814 && strcmp(pw->pw_name, name) != 0)
1815 || (search == _PW_KEYBYUID && pw->pw_uid != uid)) {
1816 continue; /* not specific; next loop */
1817 }
1818
1819 break; /* exit loop if found */
1820 } else { /* not a compat line */
1821 state->proto.pw_name = NULL;
1822 /* clear prototype */
1823 }
1824
1825 if (state->mode == COMPAT_NOTOKEN) {
1826 /* no compat token; do direct lookup */
1827 switch (search) {
1828 case _PW_KEYBYNUM:
1829 if (state->keynum == -1) /* no more records */
1830 return NS_NOTFOUND;
1831 state->keynum++;
1832 from = &state->keynum;
1833 fromlen = sizeof(state->keynum);
1834 break;
1835 case _PW_KEYBYNAME:
1836 from = name;
1837 fromlen = strlen(name);
1838 break;
1839 case _PW_KEYBYUID:
1840 from = &uid;
1841 fromlen = sizeof(uid);
1842 break;
1843 default:
1844 abort();
1845 }
1846 buffer[0] = search;
1847 } else {
1848 /* compat token; do line by line */
1849 if (state->keynum == -1) /* no more records */
1850 return NS_NOTFOUND;
1851 state->keynum++;
1852 from = &state->keynum;
1853 fromlen = sizeof(state->keynum);
1854 buffer[0] = _PW_KEYBYNUM;
1855 }
1856
1857 if (buflen <= fromlen) { /* buffer too small */
1858 *retval = ERANGE;
1859 return NS_UNAVAIL;
1860 }
1861 memmove(buffer + 1, from, fromlen); /* setup key */
1862 key.size = fromlen + 1;
1863 key.data = (u_char *)buffer;
1864
1865 rv = _pw_getkey(state->db, &key, pw, buffer, buflen, &pwflags);
1866 if (rv != NS_SUCCESS) /* stop on error */
1867 break;
1868
1869 if (state->mode == COMPAT_NOTOKEN)
1870 break; /* stop if no compat token */
1871
1872 if (pw->pw_name[0] == '+') {
1873 /* compat inclusion */
1874 switch(pw->pw_name[1]) {
1875 case '\0': /* `+' */
1876 state->mode = COMPAT_FULL;
1877 /* reset passwd_compat search */
1878 /* XXXREENTRANT: setpassent is not thread safe ? */
1879 (void) _passwdcompat_setpassent(0);
1880 break;
1881 case '@': /* `+@netgroup' */
1882 state->mode = COMPAT_NETGROUP;
1883 /* reset netgroup search */
1884 /* XXXREENTRANT: setnetgrent is not thread safe */
1885 setnetgrent(pw->pw_name + 2);
1886 break;
1887 default: /* `+name' */
1888 state->mode = COMPAT_USER;
1889 if (state->user)
1890 free(state->user);
1891 state->user = strdup(pw->pw_name + 1);
1892 break;
1893 }
1894 /* save the prototype */
1895 state->protoflags = pwflags;
1896 if (! _pw_copy(pw, &state->proto, state->protobuf,
1897 sizeof(state->protobuf), NULL, 0)) {
1898 rv = NS_UNAVAIL;
1899 break;
1900 }
1901 continue; /* loop again after inclusion */
1902 } else if (pw->pw_name[0] == '-') {
1903 /* compat exclusion */
1904 rv = NS_SUCCESS;
1905 switch(pw->pw_name[1]) {
1906 case '\0': /* `-' */
1907 break;
1908 case '@': /* `-@netgroup' */
1909 /* XXXREENTRANT: {set,get,end}netgrent is not thread safe */
1910 setnetgrent(pw->pw_name + 2);
1911 while (getnetgrent(&host, &user, &dom)) {
1912 if (!user || !*user)
1913 continue;
1914 if (! _compat_add_exclude(state,user)) {
1915 rv = NS_UNAVAIL;
1916 break;
1917 }
1918 }
1919 endnetgrent();
1920 break;
1921 default: /* `-name' */
1922 if (! _compat_add_exclude(state,
1923 pw->pw_name + 1)) {
1924 rv = NS_UNAVAIL;
1925 }
1926 break;
1927 }
1928 if (rv != NS_SUCCESS) /* exclusion failure */
1929 break;
1930 continue; /* loop again after exclusion */
1931 }
1932 if (search == _PW_KEYBYNUM ||
1933 (search == _PW_KEYBYUID && pw->pw_uid == uid) ||
1934 (search == _PW_KEYBYNAME && strcmp(pw->pw_name, name) == 0))
1935 break; /* token mode match found */
1936 }
1937
1938 if (rv == NS_NOTFOUND &&
1939 (search == _PW_KEYBYNUM || state->mode != COMPAT_NOTOKEN))
1940 state->keynum = -1; /* flag `no more records' */
1941
1942 if (rv == NS_SUCCESS) {
1943 if ((search == _PW_KEYBYNAME && strcmp(pw->pw_name, name) != 0)
1944 || (search == _PW_KEYBYUID && pw->pw_uid != uid))
1945 rv = NS_NOTFOUND;
1946 }
1947
1948 if (rv != NS_SUCCESS)
1949 *retval = errno;
1950 return rv;
1951 }
1952
1953 /*ARGSUSED*/
1954 static int
1955 _compat_setpwent(void *nsrv, void *nscb, va_list ap)
1956 {
1957
1958 /* force passwd_compat setpwent() */
1959 (void) _passwdcompat_setpassent(0);
1960
1961 /* reset state, keep db open */
1962 _compat_state.stayopen = 0;
1963 return _compat_start(&_compat_state);
1964 }
1965
1966 /*ARGSUSED*/
1967 static int
1968 _compat_setpassent(void *nsrv, void *nscb, va_list ap)
1969 {
1970 int *retval = va_arg(ap, int *);
1971 int stayopen = va_arg(ap, int);
1972
1973 int rv;
1974
1975 /* force passwd_compat setpassent() */
1976 (void) _passwdcompat_setpassent(stayopen);
1977
1978 _compat_state.stayopen = stayopen;
1979 rv = _compat_start(&_compat_state);
1980 *retval = (rv == NS_SUCCESS);
1981 return rv;
1982 }
1983
1984 /*ARGSUSED*/
1985 static int
1986 _compat_endpwent(void *nsrv, void *nscb, va_list ap)
1987 {
1988
1989 /* force passwd_compat endpwent() */
1990 (void) _passwdcompat_endpwent();
1991
1992 /* reset state, close db */
1993 _compat_state.stayopen = 0;
1994 return _compat_end(&_compat_state);
1995 }
1996
1997
1998 /*ARGSUSED*/
1999 static int
2000 _compat_getpwent(void *nsrv, void *nscb, va_list ap)
2001 {
2002 struct passwd **retval = va_arg(ap, struct passwd **);
2003
2004 int rv, rerror;
2005
2006 _DIAGASSERT(retval != NULL);
2007
2008 *retval = NULL;
2009 rv = _compat_pwscan(&rerror, &_compat_passwd,
2010 _compat_passwdbuf, sizeof(_compat_passwdbuf),
2011 &_compat_state, _PW_KEYBYNUM, NULL, 0);
2012 if (rv == NS_SUCCESS)
2013 *retval = &_compat_passwd;
2014 return rv;
2015 }
2016
2017 /*ARGSUSED*/
2018 static int
2019 _compat_getpwnam(void *nsrv, void *nscb, va_list ap)
2020 {
2021 struct passwd **retval = va_arg(ap, struct passwd **);
2022 const char *name = va_arg(ap, const char *);
2023
2024 int rv, rerror;
2025
2026 _DIAGASSERT(retval != NULL);
2027
2028 *retval = NULL;
2029 rv = _compat_start(&_compat_state);
2030 if (rv != NS_SUCCESS)
2031 return rv;
2032 rv = _compat_pwscan(&rerror, &_compat_passwd,
2033 _compat_passwdbuf, sizeof(_compat_passwdbuf),
2034 &_compat_state, _PW_KEYBYNAME, name, 0);
2035 if (!_compat_state.stayopen)
2036 _compat_end(&_compat_state);
2037 if (rv == NS_SUCCESS)
2038 *retval = &_compat_passwd;
2039 return rv;
2040 }
2041
2042 /*ARGSUSED*/
2043 static int
2044 _compat_getpwnam_r(void *nsrv, void *nscb, va_list ap)
2045 {
2046 int *retval = va_arg(ap, int *);
2047 const char *name = va_arg(ap, const char *);
2048 struct passwd *pw = va_arg(ap, struct passwd *);
2049 char *buffer = va_arg(ap, char *);
2050 size_t buflen = va_arg(ap, size_t);
2051 struct passwd **result = va_arg(ap, struct passwd **);
2052
2053 struct compat_state state;
2054 int rv;
2055
2056 _DIAGASSERT(retval != NULL);
2057 _DIAGASSERT(pw != NULL);
2058 _DIAGASSERT(buffer != NULL);
2059 _DIAGASSERT(result != NULL);
2060
2061 *result = NULL;
2062 memset(&state, 0, sizeof(state));
2063 rv = _compat_pwscan(retval, pw, buffer, buflen, &state,
2064 _PW_KEYBYNAME, name, 0);
2065 _compat_end(&state);
2066 if (rv == NS_SUCCESS)
2067 *result = pw;
2068 return rv;
2069 }
2070
2071 /*ARGSUSED*/
2072 static int
2073 _compat_getpwuid(void *nsrv, void *nscb, va_list ap)
2074 {
2075 struct passwd **retval = va_arg(ap, struct passwd **);
2076 uid_t uid = va_arg(ap, uid_t);
2077
2078 int rv, rerror;
2079
2080 _DIAGASSERT(retval != NULL);
2081
2082 *retval = NULL;
2083 rv = _compat_start(&_compat_state);
2084 if (rv != NS_SUCCESS)
2085 return rv;
2086 rv = _compat_pwscan(&rerror, &_compat_passwd,
2087 _compat_passwdbuf, sizeof(_compat_passwdbuf),
2088 &_compat_state, _PW_KEYBYUID, NULL, uid);
2089 if (!_compat_state.stayopen)
2090 _compat_end(&_compat_state);
2091 if (rv == NS_SUCCESS)
2092 *retval = &_compat_passwd;
2093 return rv;
2094 }
2095
2096 /*ARGSUSED*/
2097 static int
2098 _compat_getpwuid_r(void *nsrv, void *nscb, va_list ap)
2099 {
2100 int *retval = va_arg(ap, int *);
2101 uid_t uid = va_arg(ap, uid_t);
2102 struct passwd *pw = va_arg(ap, struct passwd *);
2103 char *buffer = va_arg(ap, char *);
2104 size_t buflen = va_arg(ap, size_t);
2105 struct passwd **result = va_arg(ap, struct passwd **);
2106
2107 struct compat_state state;
2108 int rv;
2109
2110 _DIAGASSERT(retval != NULL);
2111 _DIAGASSERT(pw != NULL);
2112 _DIAGASSERT(buffer != NULL);
2113 _DIAGASSERT(result != NULL);
2114
2115 *result = NULL;
2116 memset(&state, 0, sizeof(state));
2117 rv = _compat_pwscan(retval, pw, buffer, buflen, &state,
2118 _PW_KEYBYUID, NULL, uid);
2119 _compat_end(&state);
2120 if (rv == NS_SUCCESS)
2121 *result = pw;
2122 return rv;
2123 }
2124
2125 #endif /* _PASSWD_COMPAT */
2126
2127
2128 /*
2129 * public functions
2130 */
2131
2132 struct passwd *
2133 getpwent(void)
2134 {
2135 int r;
2136 struct passwd *retval;
2137
2138 static const ns_dtab dtab[] = {
2139 NS_FILES_CB(_files_getpwent, NULL)
2140 NS_DNS_CB(_dns_getpwent, NULL)
2141 NS_NIS_CB(_nis_getpwent, NULL)
2142 NS_COMPAT_CB(_compat_getpwent, NULL)
2143 { 0 }
2144 };
2145
2146 mutex_lock(&_pwmutex);
2147 r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwent", __nsdefaultcompat,
2148 &retval);
2149 mutex_unlock(&_pwmutex);
2150 return (r == NS_SUCCESS) ? retval : NULL;
2151 }
2152
2153 struct passwd *
2154 getpwnam(const char *name)
2155 {
2156 int rv;
2157 struct passwd *retval;
2158
2159 static const ns_dtab dtab[] = {
2160 NS_FILES_CB(_files_getpwnam, NULL)
2161 NS_DNS_CB(_dns_getpwnam, NULL)
2162 NS_NIS_CB(_nis_getpwnam, NULL)
2163 NS_COMPAT_CB(_compat_getpwnam, NULL)
2164 { 0 }
2165 };
2166
2167 mutex_lock(&_pwmutex);
2168 rv = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwnam", __nsdefaultcompat,
2169 &retval, name);
2170 mutex_unlock(&_pwmutex);
2171 return (rv == NS_SUCCESS) ? retval : NULL;
2172 }
2173
2174 int
2175 getpwnam_r(const char *name, struct passwd *pwd, char *buffer, size_t buflen,
2176 struct passwd **result)
2177 {
2178 int r, retval;
2179
2180 static const ns_dtab dtab[] = {
2181 NS_FILES_CB(_files_getpwnam_r, NULL)
2182 NS_DNS_CB(_dns_getpwnam_r, NULL)
2183 NS_NIS_CB(_nis_getpwnam_r, NULL)
2184 NS_COMPAT_CB(_compat_getpwnam_r, NULL)
2185 { 0 }
2186 };
2187
2188 _DIAGASSERT(name != NULL);
2189 _DIAGASSERT(pwd != NULL);
2190 _DIAGASSERT(buffer != NULL);
2191 _DIAGASSERT(result != NULL);
2192
2193 *result = NULL;
2194 retval = 0;
2195 mutex_lock(&_pwmutex);
2196 r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwnam_r", __nsdefaultcompat,
2197 &retval, name, pwd, buffer, buflen, result);
2198 mutex_unlock(&_pwmutex);
2199 return (r == NS_SUCCESS) ? 0 : retval ? retval : ENOENT;
2200 }
2201
2202 struct passwd *
2203 getpwuid(uid_t uid)
2204 {
2205 int rv;
2206 struct passwd *retval;
2207
2208 static const ns_dtab dtab[] = {
2209 NS_FILES_CB(_files_getpwuid, NULL)
2210 NS_DNS_CB(_dns_getpwuid, NULL)
2211 NS_NIS_CB(_nis_getpwuid, NULL)
2212 NS_COMPAT_CB(_compat_getpwuid, NULL)
2213 { 0 }
2214 };
2215
2216 mutex_lock(&_pwmutex);
2217 rv = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwuid", __nsdefaultcompat,
2218 &retval, uid);
2219 mutex_unlock(&_pwmutex);
2220 return (rv == NS_SUCCESS) ? retval : NULL;
2221 }
2222
2223 int
2224 getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, size_t buflen,
2225 struct passwd **result)
2226 {
2227 int r, retval;
2228
2229 static const ns_dtab dtab[] = {
2230 NS_FILES_CB(_files_getpwuid_r, NULL)
2231 NS_DNS_CB(_dns_getpwuid_r, NULL)
2232 NS_NIS_CB(_nis_getpwuid_r, NULL)
2233 NS_COMPAT_CB(_compat_getpwuid_r, NULL)
2234 { 0 }
2235 };
2236
2237 _DIAGASSERT(pwd != NULL);
2238 _DIAGASSERT(buffer != NULL);
2239 _DIAGASSERT(result != NULL);
2240
2241 *result = NULL;
2242 retval = 0;
2243 mutex_lock(&_pwmutex);
2244 r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwuid_r", __nsdefaultcompat,
2245 &retval, uid, pwd, buffer, buflen, result);
2246 mutex_unlock(&_pwmutex);
2247 return (r == NS_SUCCESS) ? 0 : retval ? retval : ENOENT;
2248 }
2249
2250 void
2251 endpwent(void)
2252 {
2253 static const ns_dtab dtab[] = {
2254 NS_FILES_CB(_files_endpwent, NULL)
2255 NS_DNS_CB(_dns_endpwent, NULL)
2256 NS_NIS_CB(_nis_endpwent, NULL)
2257 NS_COMPAT_CB(_compat_endpwent, NULL)
2258 { 0 }
2259 };
2260
2261 mutex_lock(&_pwmutex);
2262 /* force all endpwent() methods */
2263 (void) nsdispatch(NULL, dtab, NSDB_PASSWD, "endpwent",
2264 __nsdefaultcompat_forceall);
2265 mutex_unlock(&_pwmutex);
2266 }
2267
2268 /*ARGSUSED*/
2269 int
2270 setpassent(int stayopen)
2271 {
2272 static const ns_dtab dtab[] = {
2273 NS_FILES_CB(_files_setpassent, NULL)
2274 NS_DNS_CB(_dns_setpassent, NULL)
2275 NS_NIS_CB(_nis_setpassent, NULL)
2276 NS_COMPAT_CB(_compat_setpassent, NULL)
2277 { 0 }
2278 };
2279 int rv, retval;
2280
2281 mutex_lock(&_pwmutex);
2282 /* force all setpassent() methods */
2283 rv = nsdispatch(NULL, dtab, NSDB_PASSWD, "setpassent",
2284 __nsdefaultcompat_forceall, &retval, stayopen);
2285 mutex_unlock(&_pwmutex);
2286 return (rv == NS_SUCCESS) ? retval : 0;
2287 }
2288
2289 void
2290 setpwent(void)
2291 {
2292 static const ns_dtab dtab[] = {
2293 NS_FILES_CB(_files_setpwent, NULL)
2294 NS_DNS_CB(_dns_setpwent, NULL)
2295 NS_NIS_CB(_nis_setpwent, NULL)
2296 NS_COMPAT_CB(_compat_setpwent, NULL)
2297 { 0 }
2298 };
2299
2300 mutex_lock(&_pwmutex);
2301 /* force all setpwent() methods */
2302 (void) nsdispatch(NULL, dtab, NSDB_PASSWD, "setpwent",
2303 __nsdefaultcompat_forceall);
2304 mutex_unlock(&_pwmutex);
2305 }
2306