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