Fix mdoc(7)/man(7) mix up.
[netbsd-mini2440.git] / lib / libc / gen / getpwent.c
blob3403e997efe5feba6e51a5865f2f395fccfc5604
1 /* $NetBSD: getpwent.c,v 1.75.8.2 2008/12/28 01:18:11 christos Exp $ */
3 /*-
4 * Copyright (c) 1997-2000, 2004-2005 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Luke Mewburn.
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Copyright (c) 1988, 1993
34 * The Regents of the University of California. All rights reserved.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
62 * Portions Copyright (c) 1994, 1995, Jason Downs. All rights reserved.
64 * Redistribution and use in source and binary forms, with or without
65 * modification, are permitted provided that the following conditions
66 * are met:
67 * 1. Redistributions of source code must retain the above copyright
68 * notice, this list of conditions and the following disclaimer.
69 * 2. Redistributions in binary form must reproduce the above copyright
70 * notice, this list of conditions and the following disclaimer in the
71 * documentation and/or other materials provided with the distribution.
73 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
74 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
75 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
76 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
77 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
78 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
79 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
80 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
81 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
82 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
83 * SUCH DAMAGE.
86 #include <sys/cdefs.h>
87 #if defined(LIBC_SCCS) && !defined(lint)
88 #if 0
89 static char sccsid[] = "@(#)getpwent.c 8.2 (Berkeley) 4/27/95";
90 #else
91 __RCSID("$NetBSD: getpwent.c,v 1.75.8.2 2008/12/28 01:18:11 christos Exp $");
92 #endif
93 #endif /* LIBC_SCCS and not lint */
95 #include "namespace.h"
96 #include "reentrant.h"
98 #include <sys/param.h>
100 #include <assert.h>
101 #include <db.h>
102 #include <errno.h>
103 #include <fcntl.h>
104 #include <limits.h>
105 #include <netgroup.h>
106 #include <nsswitch.h>
107 #include <pwd.h>
108 #include <stdarg.h>
109 #include <stdio.h>
110 #include <stdlib.h>
111 #include <string.h>
112 #include <syslog.h>
113 #include <unistd.h>
115 #ifdef HESIOD
116 #include <hesiod.h>
117 #endif
119 #ifdef YP
120 #include <machine/param.h>
121 #include <rpc/rpc.h>
122 #include <rpcsvc/yp_prot.h>
123 #include <rpcsvc/ypclnt.h>
124 #endif
126 #include "pw_private.h"
128 #define _PASSWD_COMPAT /* "passwd" defaults to compat, so always provide it */
130 #ifdef __weak_alias
131 __weak_alias(endpwent,_endpwent)
132 __weak_alias(getpwent,_getpwent)
133 __weak_alias(getpwent_r,_getpwent_r)
134 __weak_alias(getpwnam,_getpwnam)
135 __weak_alias(getpwnam_r,_getpwnam_r)
136 __weak_alias(getpwuid,_getpwuid)
137 __weak_alias(getpwuid_r,_getpwuid_r)
138 __weak_alias(setpassent,_setpassent)
139 __weak_alias(setpwent,_setpwent)
140 #endif
142 #ifdef _REENTRANT
143 static mutex_t _pwmutex = MUTEX_INITIALIZER;
144 #endif
146 const char __yp_token[] = "__YP!"; /* Let pwd_mkdb pull this in. */
150 * The pwd.db lookup techniques and data extraction code here must be kept
151 * in sync with that in `pwd_mkdb'.
154 #if defined(YP) || defined(HESIOD)
156 * _pw_parse
157 * Parses entry using pw_scan(3) (without the trailing \n)
158 * after copying to buf, and fills in pw with corresponding values.
159 * If old is non-zero, entry is in _PASSWORD_OLDFMT.
160 * Returns 1 if parsed successfully, 0 on parse failure.
162 static int
163 _pw_parse(const char *entry, struct passwd *pw, char *buf, size_t buflen,
164 int old)
166 int flags;
168 _DIAGASSERT(entry != NULL);
169 _DIAGASSERT(pw != NULL);
170 _DIAGASSERT(buf != NULL);
172 if (strlcpy(buf, entry, buflen) >= buflen)
173 return 0;
174 flags = _PASSWORD_NOWARN;
175 if (old)
176 flags |= _PASSWORD_OLDFMT;
177 return __pw_scan(buf, pw, &flags);
179 #endif /* YP || HESIOD */
182 * _pw_opendb
183 * if *db is NULL, dbopen(3) /etc/spwd.db or /etc/pwd.db (depending
184 * upon permissions, etc)
186 static int
187 _pw_opendb(DB **db, int *version)
189 static int warned;
190 DBT key;
191 DBT value;
193 const char *dbfile = NULL;
195 _DIAGASSERT(db != NULL);
196 _DIAGASSERT(version != NULL);
197 if (*db != NULL) /* open *db */
198 return NS_SUCCESS;
200 if (geteuid() == 0) {
201 dbfile = _PATH_SMP_DB;
202 *db = dbopen(dbfile, O_RDONLY, 0, DB_HASH, NULL);
204 if (*db == NULL) {
205 dbfile = _PATH_MP_DB;
206 *db = dbopen(dbfile, O_RDONLY, 0, DB_HASH, NULL);
208 if (*db == NULL) {
209 if (!warned) {
210 int serrno = errno;
211 syslog(LOG_ERR, "%s: %m", dbfile);
212 errno = serrno;
214 warned = 1;
215 return NS_UNAVAIL;
217 key.data = __UNCONST("VERSION");
218 key.size = strlen((char *)key.data) + 1;
219 switch ((*(*db)->get)(*db, &key, &value, 0)) {
220 case 0:
221 if (sizeof(*version) != value.size)
222 return NS_UNAVAIL;
223 (void)memcpy(version, value.data, value.size);
224 break; /* found */
225 case 1:
226 *version = 0; /* not found */
227 break;
228 case -1:
229 return NS_UNAVAIL; /* error in db routines */
230 default:
231 abort();
233 return NS_SUCCESS;
237 * _pw_getkey
238 * Lookup key in *db, filling in pw
239 * with the result, allocating memory from buffer (size buflen).
240 * (The caller may point key.data to buffer on entry; the contents
241 * of key.data will be invalid on exit.)
243 static int
244 _pw_getkey(DB *db, DBT *key,
245 struct passwd *pw, char *buffer, size_t buflen, int *pwflags,
246 int version)
248 char *p, *t;
249 DBT data;
251 _DIAGASSERT(db != NULL);
252 _DIAGASSERT(key != NULL);
253 _DIAGASSERT(pw != NULL);
254 _DIAGASSERT(buffer != NULL);
255 /* pwflags may be NULL (if we don't care about them */
257 if (db == NULL) /* this shouldn't happen */
258 return NS_UNAVAIL;
260 switch ((db->get)(db, key, &data, 0)) {
261 case 0:
262 break; /* found */
263 case 1:
264 return NS_NOTFOUND; /* not found */
265 case -1:
266 return NS_UNAVAIL; /* error in db routines */
267 default:
268 abort();
271 p = (char *)data.data;
272 if (data.size > buflen) {
273 errno = ERANGE;
274 return NS_UNAVAIL;
278 * THE DECODING BELOW MUST MATCH THAT IN pwd_mkdb.
280 t = buffer;
281 #define MACRO(a) do { a } while (/*CONSTCOND*/0)
282 #define EXPAND(e) MACRO(e = t; while ((*t++ = *p++));)
283 #define SCALAR(v) MACRO(memmove(&(v), p, sizeof v); p += sizeof v;)
284 EXPAND(pw->pw_name);
285 EXPAND(pw->pw_passwd);
286 SCALAR(pw->pw_uid);
287 SCALAR(pw->pw_gid);
288 if (version == 0) {
289 int32_t tmp;
290 SCALAR(tmp);
291 pw->pw_change = tmp;
292 } else
293 SCALAR(pw->pw_change);
294 EXPAND(pw->pw_class);
295 EXPAND(pw->pw_gecos);
296 EXPAND(pw->pw_dir);
297 EXPAND(pw->pw_shell);
298 if (version == 0) {
299 int32_t tmp;
300 SCALAR(tmp);
301 pw->pw_expire = tmp;
302 } else
303 SCALAR(pw->pw_expire);
304 if (pwflags) {
305 /* See if there's any data left. If so, read in flags. */
306 if (data.size > (size_t) (p - (char *)data.data)) {
307 SCALAR(*pwflags);
308 } else { /* default */
309 *pwflags = _PASSWORD_NOUID|_PASSWORD_NOGID;
313 return NS_SUCCESS;
317 * _pw_memfrombuf
318 * Obtain want bytes from buffer (of size buflen) and return a pointer
319 * to the available memory after adjusting buffer/buflen.
320 * Returns NULL if there is insufficient space.
322 static char *
323 _pw_memfrombuf(size_t want, char **buffer, size_t *buflen)
325 char *rv;
327 if (want > *buflen) {
328 errno = ERANGE;
329 return NULL;
331 rv = *buffer;
332 *buffer += want;
333 *buflen -= want;
334 return rv;
338 * _pw_copy
339 * Copy the contents of frompw to pw; memory for strings
340 * and arrays will be allocated from buf (of size buflen).
341 * If proto != NULL, use various fields in proto in preference to frompw.
342 * Returns 1 if copied successfully, 0 on copy failure.
343 * NOTE: frompw must not use buf for its own pointers.
345 static int
346 _pw_copy(const struct passwd *frompw, struct passwd *pw,
347 char *buf, size_t buflen, const struct passwd *protopw, int protoflags)
349 size_t count;
350 int useproto;
352 _DIAGASSERT(frompw != NULL);
353 _DIAGASSERT(pw != NULL);
354 _DIAGASSERT(buf != NULL);
355 /* protopw may be NULL */
357 useproto = protopw && protopw->pw_name;
359 #define COPYSTR(to, from) \
360 do { \
361 count = strlen((from)); \
362 (to) = _pw_memfrombuf(count+1, &buf, &buflen); \
363 if ((to) == NULL) \
364 return 0; \
365 memmove((to), (from), count); \
366 to[count] = '\0'; \
367 } while (0) /* LINTED */
369 #define COPYFIELD(field) COPYSTR(pw->field, frompw->field)
371 #define COPYPROTOFIELD(field) COPYSTR(pw->field, \
372 (useproto && *protopw->field ? protopw->field : frompw->field))
374 COPYFIELD(pw_name);
376 #ifdef PW_OVERRIDE_PASSWD
377 COPYPROTOFIELD(pw_passwd);
378 #else
379 COPYFIELD(pw_passwd);
380 #endif
382 if (useproto && !(protoflags & _PASSWORD_NOUID))
383 pw->pw_uid = protopw->pw_uid;
384 else
385 pw->pw_uid = frompw->pw_uid;
387 if (useproto && !(protoflags & _PASSWORD_NOGID))
388 pw->pw_gid = protopw->pw_gid;
389 else
390 pw->pw_gid = frompw->pw_gid;
392 pw->pw_change = frompw->pw_change;
393 COPYFIELD(pw_class);
394 COPYPROTOFIELD(pw_gecos);
395 COPYPROTOFIELD(pw_dir);
396 COPYPROTOFIELD(pw_shell);
398 #undef COPYSTR
399 #undef COPYFIELD
400 #undef COPYPROTOFIELD
402 return 1;
407 * files methods
410 /* state shared between files methods */
411 struct files_state {
412 int stayopen; /* see getpassent(3) */
413 DB *db; /* passwd file handle */
414 int keynum; /* key counter, -1 if no more */
415 int version;
418 static struct files_state _files_state;
419 /* storage for non _r functions */
420 static struct passwd _files_passwd;
421 static char _files_passwdbuf[_GETPW_R_SIZE_MAX];
423 static int
424 _files_start(struct files_state *state)
426 int rv;
428 _DIAGASSERT(state != NULL);
430 state->keynum = 0;
431 rv = _pw_opendb(&state->db, &state->version);
432 if (rv != NS_SUCCESS)
433 return rv;
434 return NS_SUCCESS;
437 static int
438 _files_end(struct files_state *state)
441 _DIAGASSERT(state != NULL);
443 state->keynum = 0;
444 if (state->db) {
445 (void)(state->db->close)(state->db);
446 state->db = NULL;
448 return NS_SUCCESS;
452 * _files_pwscan
453 * Search state->db for the next desired entry.
454 * If search is _PW_KEYBYNUM, look for state->keynum.
455 * If search is _PW_KEYBYNAME, look for name.
456 * If search is _PW_KEYBYUID, look for uid.
457 * Sets *retval to the errno if the result is not NS_SUCCESS
458 * or NS_NOTFOUND.
460 static int
461 _files_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen,
462 struct files_state *state, int search, const char *name, uid_t uid)
464 const void *from;
465 size_t fromlen;
466 DBT key;
467 int rv;
469 _DIAGASSERT(retval != NULL);
470 _DIAGASSERT(pw != NULL);
471 _DIAGASSERT(buffer != NULL);
472 _DIAGASSERT(state != NULL);
473 /* name is NULL to indicate searching for uid */
475 *retval = 0;
477 if (state->db == NULL) { /* only start if file not open yet */
478 rv = _files_start(state);
479 if (rv != NS_SUCCESS)
480 goto filespwscan_out;
483 for (;;) { /* search for a match */
484 switch (search) {
485 case _PW_KEYBYNUM:
486 if (state->keynum == -1)
487 return NS_NOTFOUND; /* no more records */
488 state->keynum++;
489 from = &state->keynum;
490 fromlen = sizeof(state->keynum);
491 break;
492 case _PW_KEYBYNAME:
493 from = name;
494 fromlen = strlen(name);
495 break;
496 case _PW_KEYBYUID:
497 from = &uid;
498 fromlen = sizeof(uid);
499 break;
500 default:
501 abort();
504 if (buflen <= fromlen) { /* buffer too small */
505 *retval = ERANGE;
506 return NS_UNAVAIL;
508 buffer[0] = search; /* setup key */
509 memmove(buffer + 1, from, fromlen);
510 key.size = fromlen + 1;
511 key.data = (u_char *)buffer;
513 /* search for key */
514 rv = _pw_getkey(state->db, &key, pw, buffer, buflen, NULL,
515 state->version);
516 if (rv != NS_SUCCESS) /* no match */
517 break;
518 if (pw->pw_name[0] == '+' || pw->pw_name[0] == '-') {
519 /* if a compat line */
520 if (search == _PW_KEYBYNUM)
521 continue; /* read next if pwent */
522 rv = NS_NOTFOUND; /* don't match if pw{nam,uid} */
523 break;
525 break;
528 if (rv == NS_NOTFOUND && search == _PW_KEYBYNUM)
529 state->keynum = -1; /* flag `no more records' */
531 if (rv == NS_SUCCESS) {
532 if ((search == _PW_KEYBYUID && pw->pw_uid != uid) ||
533 (search == _PW_KEYBYNAME && strcmp(pw->pw_name, name) != 0))
534 rv = NS_NOTFOUND;
537 filespwscan_out:
538 if (rv != NS_SUCCESS && rv != NS_NOTFOUND)
539 *retval = errno;
540 return rv;
543 /*ARGSUSED*/
544 static int
545 _files_setpwent(void *nsrv, void *nscb, va_list ap)
548 _files_state.stayopen = 0;
549 return _files_start(&_files_state);
552 /*ARGSUSED*/
553 static int
554 _files_setpassent(void *nsrv, void *nscb, va_list ap)
556 int *retval = va_arg(ap, int *);
557 int stayopen = va_arg(ap, int);
559 int rv;
561 _files_state.stayopen = stayopen;
562 rv = _files_start(&_files_state);
563 *retval = (rv == NS_SUCCESS);
564 return rv;
567 /*ARGSUSED*/
568 static int
569 _files_endpwent(void *nsrv, void *nscb, va_list ap)
572 _files_state.stayopen = 0;
573 return _files_end(&_files_state);
576 /*ARGSUSED*/
577 static int
578 _files_getpwent(void *nsrv, void *nscb, va_list ap)
580 struct passwd **retval = va_arg(ap, struct passwd **);
582 int rv, rerror;
584 _DIAGASSERT(retval != NULL);
586 *retval = NULL;
587 rv = _files_pwscan(&rerror, &_files_passwd,
588 _files_passwdbuf, sizeof(_files_passwdbuf),
589 &_files_state, _PW_KEYBYNUM, NULL, 0);
590 if (rv == NS_SUCCESS)
591 *retval = &_files_passwd;
592 return rv;
595 /*ARGSUSED*/
596 static int
597 _files_getpwent_r(void *nsrv, void *nscb, va_list ap)
599 int *retval = va_arg(ap, int *);
600 struct passwd *pw = va_arg(ap, struct passwd *);
601 char *buffer = va_arg(ap, char *);
602 size_t buflen = va_arg(ap, size_t);
603 struct passwd **result = va_arg(ap, struct passwd **);
605 int rv;
607 _DIAGASSERT(retval != NULL);
608 _DIAGASSERT(pw != NULL);
609 _DIAGASSERT(buffer != NULL);
610 _DIAGASSERT(result != NULL);
612 rv = _files_pwscan(retval, pw, buffer, buflen, &_files_state,
613 _PW_KEYBYNUM, NULL, 0);
614 if (rv == NS_SUCCESS)
615 *result = pw;
616 else
617 *result = NULL;
618 return rv;
621 /*ARGSUSED*/
622 static int
623 _files_getpwnam(void *nsrv, void *nscb, va_list ap)
625 struct passwd **retval = va_arg(ap, struct passwd **);
626 const char *name = va_arg(ap, const char *);
628 int rv, rerror;
630 _DIAGASSERT(retval != NULL);
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_KEYBYNAME, name, 0);
639 if (!_files_state.stayopen)
640 _files_end(&_files_state);
641 if (rv == NS_SUCCESS)
642 *retval = &_files_passwd;
643 return rv;
646 /*ARGSUSED*/
647 static int
648 _files_getpwnam_r(void *nsrv, void *nscb, va_list ap)
650 int *retval = va_arg(ap, int *);
651 const char *name = va_arg(ap, const char *);
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 **);
657 struct files_state state;
658 int rv;
660 _DIAGASSERT(retval != NULL);
661 _DIAGASSERT(pw != NULL);
662 _DIAGASSERT(buffer != NULL);
663 _DIAGASSERT(result != NULL);
665 *result = NULL;
666 memset(&state, 0, sizeof(state));
667 rv = _files_pwscan(retval, pw, buffer, buflen, &state,
668 _PW_KEYBYNAME, name, 0);
669 _files_end(&state);
670 if (rv == NS_SUCCESS)
671 *result = pw;
672 return rv;
675 /*ARGSUSED*/
676 static int
677 _files_getpwuid(void *nsrv, void *nscb, va_list ap)
679 struct passwd **retval = va_arg(ap, struct passwd **);
680 uid_t uid = va_arg(ap, uid_t);
682 int rv, rerror;
684 _DIAGASSERT(retval != NULL);
686 *retval = NULL;
687 rv = _files_start(&_files_state);
688 if (rv != NS_SUCCESS)
689 return rv;
690 rv = _files_pwscan(&rerror, &_files_passwd,
691 _files_passwdbuf, sizeof(_files_passwdbuf),
692 &_files_state, _PW_KEYBYUID, NULL, uid);
693 if (!_files_state.stayopen)
694 _files_end(&_files_state);
695 if (rv == NS_SUCCESS)
696 *retval = &_files_passwd;
697 return rv;
700 /*ARGSUSED*/
701 static int
702 _files_getpwuid_r(void *nsrv, void *nscb, va_list ap)
704 int *retval = va_arg(ap, int *);
705 uid_t uid = va_arg(ap, uid_t);
706 struct passwd *pw = va_arg(ap, struct passwd *);
707 char *buffer = va_arg(ap, char *);
708 size_t buflen = va_arg(ap, size_t);
709 struct passwd **result = va_arg(ap, struct passwd **);
711 struct files_state state;
712 int rv;
714 _DIAGASSERT(retval != NULL);
715 _DIAGASSERT(pw != NULL);
716 _DIAGASSERT(buffer != NULL);
717 _DIAGASSERT(result != NULL);
719 *result = NULL;
720 memset(&state, 0, sizeof(state));
721 rv = _files_pwscan(retval, pw, buffer, buflen, &state,
722 _PW_KEYBYUID, NULL, uid);
723 _files_end(&state);
724 if (rv == NS_SUCCESS)
725 *result = pw;
726 return rv;
730 #ifdef HESIOD
732 * dns methods
735 /* state shared between dns methods */
736 struct dns_state {
737 int stayopen; /* see getpassent(3) */
738 void *context; /* Hesiod context */
739 int num; /* passwd index, -1 if no more */
742 static struct dns_state _dns_state;
743 /* storage for non _r functions */
744 static struct passwd _dns_passwd;
745 static char _dns_passwdbuf[_GETPW_R_SIZE_MAX];
747 static int
748 _dns_start(struct dns_state *state)
751 _DIAGASSERT(state != NULL);
753 state->num = 0;
754 if (state->context == NULL) { /* setup Hesiod */
755 if (hesiod_init(&state->context) == -1)
756 return NS_UNAVAIL;
759 return NS_SUCCESS;
762 static int
763 _dns_end(struct dns_state *state)
766 _DIAGASSERT(state != NULL);
768 state->num = 0;
769 if (state->context) {
770 hesiod_end(state->context);
771 state->context = NULL;
773 return NS_SUCCESS;
777 * _dns_pwscan
778 * Look for the Hesiod name provided in buffer in the NULL-terminated
779 * list of zones,
780 * and decode into pw/buffer/buflen.
782 static int
783 _dns_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen,
784 struct dns_state *state, const char **zones)
786 const char **curzone;
787 char **hp, *ep;
788 int rv;
790 _DIAGASSERT(retval != NULL);
791 _DIAGASSERT(pw != NULL);
792 _DIAGASSERT(buffer != NULL);
793 _DIAGASSERT(state != NULL);
794 _DIAGASSERT(zones != NULL);
796 *retval = 0;
798 if (state->context == NULL) { /* only start if Hesiod not setup */
799 rv = _dns_start(state);
800 if (rv != NS_SUCCESS)
801 return rv;
804 hp = NULL;
805 rv = NS_NOTFOUND;
807 for (curzone = zones; *curzone; curzone++) { /* search zones */
808 hp = hesiod_resolve(state->context, buffer, *curzone);
809 if (hp != NULL)
810 break;
811 if (errno != ENOENT) {
812 rv = NS_UNAVAIL;
813 goto dnspwscan_out;
816 if (*curzone == NULL)
817 goto dnspwscan_out;
819 if ((ep = strchr(hp[0], '\n')) != NULL)
820 *ep = '\0'; /* clear trailing \n */
821 if (_pw_parse(hp[0], pw, buffer, buflen, 1)) /* validate line */
822 rv = NS_SUCCESS;
823 else
824 rv = NS_UNAVAIL;
826 dnspwscan_out:
827 if (rv != NS_SUCCESS && rv != NS_NOTFOUND)
828 *retval = errno;
829 if (hp)
830 hesiod_free_list(state->context, hp);
831 return rv;
834 /*ARGSUSED*/
835 static int
836 _dns_setpwent(void *nsrv, void *nscb, va_list ap)
839 _dns_state.stayopen = 0;
840 return _dns_start(&_dns_state);
843 /*ARGSUSED*/
844 static int
845 _dns_setpassent(void *nsrv, void *nscb, va_list ap)
847 int *retval = va_arg(ap, int *);
848 int stayopen = va_arg(ap, int);
850 int rv;
852 _dns_state.stayopen = stayopen;
853 rv = _dns_start(&_dns_state);
854 *retval = (rv == NS_SUCCESS);
855 return rv;
858 /*ARGSUSED*/
859 static int
860 _dns_endpwent(void *nsrv, void *nscb, va_list ap)
863 _dns_state.stayopen = 0;
864 return _dns_end(&_dns_state);
867 /*ARGSUSED*/
868 static int
869 _dns_getpwent(void *nsrv, void *nscb, va_list ap)
871 struct passwd **retval = va_arg(ap, struct passwd **);
873 char **hp, *ep;
874 int rv;
876 _DIAGASSERT(retval != NULL);
878 *retval = NULL;
880 if (_dns_state.num == -1) /* exhausted search */
881 return NS_NOTFOUND;
883 if (_dns_state.context == NULL) {
884 /* only start if Hesiod not setup */
885 rv = _dns_start(&_dns_state);
886 if (rv != NS_SUCCESS)
887 return rv;
890 next_dns_entry:
891 hp = NULL;
892 rv = NS_NOTFOUND;
894 /* find passwd-NNN */
895 snprintf(_dns_passwdbuf, sizeof(_dns_passwdbuf),
896 "passwd-%u", _dns_state.num);
897 _dns_state.num++;
899 hp = hesiod_resolve(_dns_state.context, _dns_passwdbuf, "passwd");
900 if (hp == NULL) {
901 if (errno == ENOENT)
902 _dns_state.num = -1;
903 else
904 rv = NS_UNAVAIL;
905 } else {
906 if ((ep = strchr(hp[0], '\n')) != NULL)
907 *ep = '\0'; /* clear trailing \n */
908 /* validate line */
909 if (_pw_parse(hp[0], &_dns_passwd,
910 _dns_passwdbuf, sizeof(_dns_passwdbuf), 1))
911 rv = NS_SUCCESS;
912 else { /* dodgy entry, try again */
913 hesiod_free_list(_dns_state.context, hp);
914 goto next_dns_entry;
918 if (hp)
919 hesiod_free_list(_dns_state.context, hp);
920 if (rv == NS_SUCCESS)
921 *retval = &_dns_passwd;
922 return rv;
925 /*ARGSUSED*/
926 static int
927 _dns_getpwent_r(void *nsrv, void *nscb, va_list ap)
929 int *retval = va_arg(ap, int *);
930 struct passwd *pw = va_arg(ap, struct passwd *);
931 char *buffer = va_arg(ap, char *);
932 size_t buflen = va_arg(ap, size_t);
933 struct passwd **result = va_arg(ap, struct passwd **);
935 char **hp, *ep;
936 int rv;
938 _DIAGASSERT(retval != NULL);
939 _DIAGASSERT(pw != NULL);
940 _DIAGASSERT(buffer != NULL);
941 _DIAGASSERT(result != NULL);
943 *retval = 0;
945 if (_dns_state.num == -1) /* exhausted search */
946 return NS_NOTFOUND;
948 if (_dns_state.context == NULL) {
949 /* only start if Hesiod not setup */
950 rv = _dns_start(&_dns_state);
951 if (rv != NS_SUCCESS)
952 return rv;
955 next_dns_entry:
956 hp = NULL;
957 rv = NS_NOTFOUND;
959 /* find passwd-NNN */
960 snprintf(buffer, buflen, "passwd-%u", _dns_state.num);
961 _dns_state.num++;
963 hp = hesiod_resolve(_dns_state.context, buffer, "passwd");
964 if (hp == NULL) {
965 if (errno == ENOENT)
966 _dns_state.num = -1;
967 else
968 rv = NS_UNAVAIL;
969 } else {
970 if ((ep = strchr(hp[0], '\n')) != NULL)
971 *ep = '\0'; /* clear trailing \n */
972 /* validate line */
973 if (_pw_parse(hp[0], pw, buffer, buflen, 1))
974 rv = NS_SUCCESS;
975 else { /* dodgy entry, try again */
976 hesiod_free_list(_dns_state.context, hp);
977 goto next_dns_entry;
981 if (hp)
982 hesiod_free_list(_dns_state.context, hp);
983 if (rv == NS_SUCCESS)
984 *result = pw;
985 else
986 *result = NULL;
987 return rv;
990 static const char *_dns_uid_zones[] = {
991 "uid",
992 "passwd",
993 NULL
996 /*ARGSUSED*/
997 static int
998 _dns_getpwuid(void *nsrv, void *nscb, va_list ap)
1000 struct passwd **retval = va_arg(ap, struct passwd **);
1001 uid_t uid = va_arg(ap, uid_t);
1003 int rv, rerror;
1005 _DIAGASSERT(retval != NULL);
1007 *retval = NULL;
1008 rv = _dns_start(&_dns_state);
1009 if (rv != NS_SUCCESS)
1010 return rv;
1011 snprintf(_dns_passwdbuf, sizeof(_dns_passwdbuf),
1012 "%u", (unsigned int)uid);
1013 rv = _dns_pwscan(&rerror, &_dns_passwd,
1014 _dns_passwdbuf, sizeof(_dns_passwdbuf),
1015 &_dns_state, _dns_uid_zones);
1016 if (!_dns_state.stayopen)
1017 _dns_end(&_dns_state);
1018 if (rv == NS_SUCCESS && uid == _dns_passwd.pw_uid)
1019 *retval = &_dns_passwd;
1020 return rv;
1023 /*ARGSUSED*/
1024 static int
1025 _dns_getpwuid_r(void *nsrv, void *nscb, va_list ap)
1027 int *retval = va_arg(ap, int *);
1028 uid_t uid = va_arg(ap, uid_t);
1029 struct passwd *pw = va_arg(ap, struct passwd *);
1030 char *buffer = va_arg(ap, char *);
1031 size_t buflen = va_arg(ap, size_t);
1032 struct passwd **result = va_arg(ap, struct passwd **);
1034 struct dns_state state;
1035 int rv;
1037 _DIAGASSERT(retval != NULL);
1038 _DIAGASSERT(pw != NULL);
1039 _DIAGASSERT(buffer != NULL);
1040 _DIAGASSERT(result != NULL);
1042 *result = NULL;
1043 memset(&state, 0, sizeof(state));
1044 snprintf(buffer, buflen, "%u", (unsigned int)uid);
1045 rv = _dns_pwscan(retval, pw, buffer, buflen, &state, _dns_uid_zones);
1046 _dns_end(&state);
1047 if (rv != NS_SUCCESS)
1048 return rv;
1049 if (uid == pw->pw_uid) {
1050 *result = pw;
1051 return NS_SUCCESS;
1052 } else
1053 return NS_NOTFOUND;
1056 static const char *_dns_nam_zones[] = {
1057 "passwd",
1058 NULL
1061 /*ARGSUSED*/
1062 static int
1063 _dns_getpwnam(void *nsrv, void *nscb, va_list ap)
1065 struct passwd **retval = va_arg(ap, struct passwd **);
1066 const char *name = va_arg(ap, const char *);
1068 int rv, rerror;
1070 _DIAGASSERT(retval != NULL);
1072 *retval = NULL;
1073 rv = _dns_start(&_dns_state);
1074 if (rv != NS_SUCCESS)
1075 return rv;
1076 snprintf(_dns_passwdbuf, sizeof(_dns_passwdbuf), "%s", name);
1077 rv = _dns_pwscan(&rerror, &_dns_passwd,
1078 _dns_passwdbuf, sizeof(_dns_passwdbuf),
1079 &_dns_state, _dns_nam_zones);
1080 if (!_dns_state.stayopen)
1081 _dns_end(&_dns_state);
1082 if (rv == NS_SUCCESS && strcmp(name, _dns_passwd.pw_name) == 0)
1083 *retval = &_dns_passwd;
1084 return rv;
1087 /*ARGSUSED*/
1088 static int
1089 _dns_getpwnam_r(void *nsrv, void *nscb, va_list ap)
1091 int *retval = va_arg(ap, int *);
1092 const char *name = va_arg(ap, const char *);
1093 struct passwd *pw = va_arg(ap, struct passwd *);
1094 char *buffer = va_arg(ap, char *);
1095 size_t buflen = va_arg(ap, size_t);
1096 struct passwd **result = va_arg(ap, struct passwd **);
1098 struct dns_state state;
1099 int rv;
1101 _DIAGASSERT(retval != NULL);
1102 _DIAGASSERT(pw != NULL);
1103 _DIAGASSERT(buffer != NULL);
1104 _DIAGASSERT(result != NULL);
1106 *result = NULL;
1107 memset(&state, 0, sizeof(state));
1108 snprintf(buffer, buflen, "%s", name);
1109 rv = _dns_pwscan(retval, pw, buffer, buflen, &state, _dns_nam_zones);
1110 _dns_end(&state);
1111 if (rv != NS_SUCCESS)
1112 return rv;
1113 if (strcmp(name, pw->pw_name) == 0) {
1114 *result = pw;
1115 return NS_SUCCESS;
1116 } else
1117 return NS_NOTFOUND;
1120 #endif /* HESIOD */
1123 #ifdef YP
1125 * nis methods
1127 /* state shared between nis methods */
1128 struct nis_state {
1129 int stayopen; /* see getpassent(3) */
1130 char *domain; /* NIS domain */
1131 int done; /* non-zero if search exhausted */
1132 char *current; /* current first/next match */
1133 int currentlen; /* length of _nis_current */
1134 enum { /* shadow map type */
1135 NISMAP_UNKNOWN, /* unknown ... */
1136 NISMAP_NONE, /* none: use "passwd.by*" */
1137 NISMAP_ADJUNCT, /* pw_passwd from "passwd.adjunct.*" */
1138 NISMAP_MASTER /* all from "master.passwd.by*" */
1139 } maptype;
1142 static struct nis_state _nis_state;
1143 /* storage for non _r functions */
1144 static struct passwd _nis_passwd;
1145 static char _nis_passwdbuf[_GETPW_R_SIZE_MAX];
1147 /* macros for deciding which NIS maps to use. */
1148 #define PASSWD_BYNAME(x) ((x)->maptype == NISMAP_MASTER \
1149 ? "master.passwd.byname" : "passwd.byname")
1150 #define PASSWD_BYUID(x) ((x)->maptype == NISMAP_MASTER \
1151 ? "master.passwd.byuid" : "passwd.byuid")
1153 static int
1154 _nis_start(struct nis_state *state)
1157 _DIAGASSERT(state != NULL);
1159 state->done = 0;
1160 if (state->current) {
1161 free(state->current);
1162 state->current = NULL;
1164 if (state->domain == NULL) { /* setup NIS */
1165 switch (yp_get_default_domain(&state->domain)) {
1166 case 0:
1167 break;
1168 case YPERR_RESRC:
1169 return NS_TRYAGAIN;
1170 default:
1171 return NS_UNAVAIL;
1175 /* determine where to get pw_passwd from */
1176 if (state->maptype == NISMAP_UNKNOWN) {
1177 int r, order;
1179 state->maptype = NISMAP_NONE; /* default to no adjunct */
1180 if (geteuid() != 0) /* non-root can't use adjunct */
1181 return NS_SUCCESS;
1183 /* look for "master.passwd.*" */
1184 r = yp_order(state->domain, "master.passwd.byname", &order);
1185 if (r == 0) {
1186 state->maptype = NISMAP_MASTER;
1187 return NS_SUCCESS;
1190 /* master.passwd doesn't exist, try passwd.adjunct */
1191 if (r == YPERR_MAP) {
1192 r = yp_order(state->domain, "passwd.adjunct.byname",
1193 &order);
1194 if (r == 0)
1195 state->maptype = NISMAP_ADJUNCT;
1198 return NS_SUCCESS;
1201 static int
1202 _nis_end(struct nis_state *state)
1205 _DIAGASSERT(state != NULL);
1207 if (state->domain)
1208 state->domain = NULL;
1209 state->done = 0;
1210 if (state->current)
1211 free(state->current);
1212 state->current = NULL;
1213 state->maptype = NISMAP_UNKNOWN;
1214 return NS_SUCCESS;
1218 * nis_parse
1219 * wrapper to _pw_parse that obtains the real password from the
1220 * "passwd.adjunct.byname" NIS map if the maptype is NISMAP_ADJUNCT.
1222 static int
1223 _nis_parse(const char *entry, struct passwd *pw, char *buf, size_t buflen,
1224 struct nis_state *state)
1226 size_t elen;
1228 _DIAGASSERT(entry != NULL);
1229 _DIAGASSERT(pw != NULL);
1230 _DIAGASSERT(buf != NULL);
1231 _DIAGASSERT(state != NULL);
1233 elen = strlen(entry);
1234 if (elen >= buflen)
1235 return 0;
1236 if (! _pw_parse(entry, pw, buf, buflen,
1237 !(state->maptype == NISMAP_MASTER)))
1238 return 0;
1240 if ((state->maptype == NISMAP_ADJUNCT) &&
1241 (strstr(pw->pw_passwd, "##") != NULL)) {
1242 char *data;
1243 int datalen;
1245 if (yp_match(state->domain, "passwd.adjunct.byname",
1246 pw->pw_name, (int)strlen(pw->pw_name),
1247 &data, &datalen) == 0) {
1248 char *bp, *ep;
1249 /* skip name to get password */
1250 ep = data;
1251 if ((bp = strsep(&ep, ":")) != NULL &&
1252 (bp = strsep(&ep, ":")) != NULL) {
1253 /* store new pw_passwd after entry */
1254 strlcpy(buf + elen, bp, buflen - elen);
1255 pw->pw_passwd = &buf[elen];
1257 free(data);
1261 return 1;
1266 * _nis_pwscan
1267 * Look for the yp key provided in buffer from map,
1268 * and decode into pw/buffer/buflen.
1270 static int
1271 _nis_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen,
1272 struct nis_state *state, const char *map)
1274 char *data;
1275 int nisr, rv, datalen;
1277 _DIAGASSERT(retval != NULL);
1278 _DIAGASSERT(pw != NULL);
1279 _DIAGASSERT(buffer != NULL);
1280 _DIAGASSERT(state != NULL);
1281 _DIAGASSERT(map != NULL);
1283 *retval = 0;
1285 if (state->domain == NULL) { /* only start if NIS not setup */
1286 rv = _nis_start(state);
1287 if (rv != NS_SUCCESS)
1288 return rv;
1291 data = NULL;
1292 rv = NS_NOTFOUND;
1294 /* search map */
1295 nisr = yp_match(state->domain, map, buffer, (int)strlen(buffer),
1296 &data, &datalen);
1297 switch (nisr) {
1298 case 0:
1299 data[datalen] = '\0'; /* clear trailing \n */
1300 if (_nis_parse(data, pw, buffer, buflen, state))
1301 rv = NS_SUCCESS; /* validate line */
1302 else
1303 rv = NS_UNAVAIL;
1304 break;
1305 case YPERR_KEY:
1306 break;
1307 default:
1308 rv = NS_UNAVAIL;
1309 break;
1312 if (rv != NS_SUCCESS && rv != NS_NOTFOUND)
1313 *retval = errno;
1314 if (data)
1315 free(data);
1316 return rv;
1319 /*ARGSUSED*/
1320 static int
1321 _nis_setpwent(void *nsrv, void *nscb, va_list ap)
1324 _nis_state.stayopen = 0;
1325 return _nis_start(&_nis_state);
1328 /*ARGSUSED*/
1329 static int
1330 _nis_setpassent(void *nsrv, void *nscb, va_list ap)
1332 int *retval = va_arg(ap, int *);
1333 int stayopen = va_arg(ap, int);
1335 int rv;
1337 _nis_state.stayopen = stayopen;
1338 rv = _nis_start(&_nis_state);
1339 *retval = (rv == NS_SUCCESS);
1340 return rv;
1343 /*ARGSUSED*/
1344 static int
1345 _nis_endpwent(void *nsrv, void *nscb, va_list ap)
1348 return _nis_end(&_nis_state);
1352 /*ARGSUSED*/
1353 static int
1354 _nis_getpwent(void *nsrv, void *nscb, va_list ap)
1356 struct passwd **retval = va_arg(ap, struct passwd **);
1358 char *key, *data;
1359 int keylen, datalen, rv, nisr;
1361 _DIAGASSERT(retval != NULL);
1363 *retval = NULL;
1365 if (_nis_state.done) /* exhausted search */
1366 return NS_NOTFOUND;
1367 if (_nis_state.domain == NULL) {
1368 /* only start if NIS not setup */
1369 rv = _nis_start(&_nis_state);
1370 if (rv != NS_SUCCESS)
1371 return rv;
1374 next_nis_entry:
1375 key = NULL;
1376 data = NULL;
1377 rv = NS_NOTFOUND;
1379 if (_nis_state.current) { /* already searching */
1380 nisr = yp_next(_nis_state.domain, PASSWD_BYNAME(&_nis_state),
1381 _nis_state.current, _nis_state.currentlen,
1382 &key, &keylen, &data, &datalen);
1383 free(_nis_state.current);
1384 _nis_state.current = NULL;
1385 switch (nisr) {
1386 case 0:
1387 _nis_state.current = key;
1388 _nis_state.currentlen = keylen;
1389 key = NULL;
1390 break;
1391 case YPERR_NOMORE:
1392 _nis_state.done = 1;
1393 goto nisent_out;
1394 default:
1395 rv = NS_UNAVAIL;
1396 goto nisent_out;
1398 } else { /* new search */
1399 if (yp_first(_nis_state.domain, PASSWD_BYNAME(&_nis_state),
1400 &_nis_state.current, &_nis_state.currentlen,
1401 &data, &datalen)) {
1402 rv = NS_UNAVAIL;
1403 goto nisent_out;
1407 data[datalen] = '\0'; /* clear trailing \n */
1408 /* validate line */
1409 if (_nis_parse(data, &_nis_passwd,
1410 _nis_passwdbuf, sizeof(_nis_passwdbuf), &_nis_state))
1411 rv = NS_SUCCESS;
1412 else { /* dodgy entry, try again */
1413 free(data);
1414 goto next_nis_entry;
1417 nisent_out:
1418 if (key)
1419 free(key);
1420 if (data)
1421 free(data);
1422 if (rv == NS_SUCCESS)
1423 *retval = &_nis_passwd;
1424 return rv;
1427 /*ARGSUSED*/
1428 static int
1429 _nis_getpwent_r(void *nsrv, void *nscb, va_list ap)
1431 int *retval = va_arg(ap, int *);
1432 struct passwd *pw = va_arg(ap, struct passwd *);
1433 char *buffer = va_arg(ap, char *);
1434 size_t buflen = va_arg(ap, size_t);
1435 struct passwd **result = va_arg(ap, struct passwd **);
1437 char *key, *data;
1438 int keylen, datalen, rv, nisr;
1440 _DIAGASSERT(retval != NULL);
1441 _DIAGASSERT(pw != NULL);
1442 _DIAGASSERT(buffer != NULL);
1443 _DIAGASSERT(result != NULL);
1445 *retval = 0;
1447 if (_nis_state.done) /* exhausted search */
1448 return NS_NOTFOUND;
1449 if (_nis_state.domain == NULL) {
1450 /* only start if NIS not setup */
1451 rv = _nis_start(&_nis_state);
1452 if (rv != NS_SUCCESS)
1453 return rv;
1456 next_nis_entry:
1457 key = NULL;
1458 data = NULL;
1459 rv = NS_NOTFOUND;
1461 if (_nis_state.current) { /* already searching */
1462 nisr = yp_next(_nis_state.domain, PASSWD_BYNAME(&_nis_state),
1463 _nis_state.current, _nis_state.currentlen,
1464 &key, &keylen, &data, &datalen);
1465 free(_nis_state.current);
1466 _nis_state.current = NULL;
1467 switch (nisr) {
1468 case 0:
1469 _nis_state.current = key;
1470 _nis_state.currentlen = keylen;
1471 key = NULL;
1472 break;
1473 case YPERR_NOMORE:
1474 _nis_state.done = 1;
1475 goto nisent_out;
1476 default:
1477 rv = NS_UNAVAIL;
1478 goto nisent_out;
1480 } else { /* new search */
1481 if (yp_first(_nis_state.domain, PASSWD_BYNAME(&_nis_state),
1482 &_nis_state.current, &_nis_state.currentlen,
1483 &data, &datalen)) {
1484 rv = NS_UNAVAIL;
1485 goto nisent_out;
1489 data[datalen] = '\0'; /* clear trailing \n */
1490 /* validate line */
1491 if (_nis_parse(data, pw, buffer, buflen, &_nis_state))
1492 rv = NS_SUCCESS;
1493 else { /* dodgy entry, try again */
1494 if (key)
1495 free(key);
1496 free(data);
1497 goto next_nis_entry;
1500 nisent_out:
1501 if (key)
1502 free(key);
1503 if (data)
1504 free(data);
1505 if (rv == NS_SUCCESS)
1506 *result = pw;
1507 else
1508 *result = NULL;
1509 return rv;
1512 /*ARGSUSED*/
1513 static int
1514 _nis_getpwuid(void *nsrv, void *nscb, va_list ap)
1516 struct passwd **retval = va_arg(ap, struct passwd **);
1517 uid_t uid = va_arg(ap, uid_t);
1519 int rv, rerror;
1521 _DIAGASSERT(retval != NULL);
1523 *retval = NULL;
1524 rv = _nis_start(&_nis_state);
1525 if (rv != NS_SUCCESS)
1526 return rv;
1527 snprintf(_nis_passwdbuf, sizeof(_nis_passwdbuf), "%u", (unsigned int)uid);
1528 rv = _nis_pwscan(&rerror, &_nis_passwd,
1529 _nis_passwdbuf, sizeof(_nis_passwdbuf),
1530 &_nis_state, PASSWD_BYUID(&_nis_state));
1531 if (!_nis_state.stayopen)
1532 _nis_end(&_nis_state);
1533 if (rv == NS_SUCCESS && uid == _nis_passwd.pw_uid)
1534 *retval = &_nis_passwd;
1535 return rv;
1538 /*ARGSUSED*/
1539 static int
1540 _nis_getpwuid_r(void *nsrv, void *nscb, va_list ap)
1542 int *retval = va_arg(ap, int *);
1543 uid_t uid = va_arg(ap, uid_t);
1544 struct passwd *pw = va_arg(ap, struct passwd *);
1545 char *buffer = va_arg(ap, char *);
1546 size_t buflen = va_arg(ap, size_t);
1547 struct passwd **result = va_arg(ap, struct passwd **);
1549 struct nis_state state;
1550 int rv;
1552 _DIAGASSERT(retval != NULL);
1553 _DIAGASSERT(pw != NULL);
1554 _DIAGASSERT(buffer != NULL);
1555 _DIAGASSERT(result != NULL);
1557 *result = NULL;
1558 memset(&state, 0, sizeof(state));
1559 rv = _nis_start(&state);
1560 if (rv != NS_SUCCESS)
1561 return rv;
1562 snprintf(buffer, buflen, "%u", (unsigned int)uid);
1563 rv = _nis_pwscan(retval, pw, buffer, buflen,
1564 &state, PASSWD_BYUID(&state));
1565 _nis_end(&state);
1566 if (rv != NS_SUCCESS)
1567 return rv;
1568 if (uid == pw->pw_uid) {
1569 *result = pw;
1570 return NS_SUCCESS;
1571 } else
1572 return NS_NOTFOUND;
1575 /*ARGSUSED*/
1576 static int
1577 _nis_getpwnam(void *nsrv, void *nscb, va_list ap)
1579 struct passwd **retval = va_arg(ap, struct passwd **);
1580 const char *name = va_arg(ap, const char *);
1582 int rv, rerror;
1584 _DIAGASSERT(retval != NULL);
1586 *retval = NULL;
1587 rv = _nis_start(&_nis_state);
1588 if (rv != NS_SUCCESS)
1589 return rv;
1590 snprintf(_nis_passwdbuf, sizeof(_nis_passwdbuf), "%s", name);
1591 rv = _nis_pwscan(&rerror, &_nis_passwd,
1592 _nis_passwdbuf, sizeof(_nis_passwdbuf),
1593 &_nis_state, PASSWD_BYNAME(&_nis_state));
1594 if (!_nis_state.stayopen)
1595 _nis_end(&_nis_state);
1596 if (rv == NS_SUCCESS && strcmp(name, _nis_passwd.pw_name) == 0)
1597 *retval = &_nis_passwd;
1598 return rv;
1601 /*ARGSUSED*/
1602 static int
1603 _nis_getpwnam_r(void *nsrv, void *nscb, va_list ap)
1605 int *retval = va_arg(ap, int *);
1606 const char *name = va_arg(ap, const char *);
1607 struct passwd *pw = va_arg(ap, struct passwd *);
1608 char *buffer = va_arg(ap, char *);
1609 size_t buflen = va_arg(ap, size_t);
1610 struct passwd **result = va_arg(ap, struct passwd **);
1612 struct nis_state state;
1613 int rv;
1615 _DIAGASSERT(retval != NULL);
1616 _DIAGASSERT(pw != NULL);
1617 _DIAGASSERT(buffer != NULL);
1618 _DIAGASSERT(result != NULL);
1620 *result = NULL;
1621 snprintf(buffer, buflen, "%s", name);
1622 memset(&state, 0, sizeof(state));
1623 rv = _nis_start(&state);
1624 if (rv != NS_SUCCESS)
1625 return rv;
1626 rv = _nis_pwscan(retval, pw, buffer, buflen,
1627 &state, PASSWD_BYNAME(&state));
1628 _nis_end(&state);
1629 if (rv != NS_SUCCESS)
1630 return rv;
1631 if (strcmp(name, pw->pw_name) == 0) {
1632 *result = pw;
1633 return NS_SUCCESS;
1634 } else
1635 return NS_NOTFOUND;
1638 #endif /* YP */
1641 #ifdef _PASSWD_COMPAT
1643 * compat methods
1646 /* state shared between compat methods */
1648 struct compat_state {
1649 int stayopen; /* see getpassent(3) */
1650 DB *db; /* passwd DB */
1651 int keynum; /* key counter, -1 if no more */
1652 enum { /* current compat mode */
1653 COMPAT_NOTOKEN = 0, /* no compat token present */
1654 COMPAT_NONE, /* parsing normal pwd.db line */
1655 COMPAT_FULL, /* parsing `+' entries */
1656 COMPAT_USER, /* parsing `+name' entries */
1657 COMPAT_NETGROUP /* parsing `+@netgroup' entries */
1658 } mode;
1659 char *user; /* COMPAT_USER "+name" */
1660 DB *exclude; /* compat exclude DB */
1661 struct passwd proto; /* proto passwd entry */
1662 char protobuf[_GETPW_R_SIZE_MAX];
1663 /* buffer for proto ptrs */
1664 int protoflags; /* proto passwd flags */
1665 int version;
1668 static struct compat_state _compat_state;
1669 /* storage for non _r functions */
1670 static struct passwd _compat_passwd;
1671 static char _compat_passwdbuf[_GETPW_R_SIZE_MAX];
1673 static int
1674 _compat_start(struct compat_state *state)
1676 int rv;
1678 _DIAGASSERT(state != NULL);
1680 state->keynum = 0;
1681 if (state->db == NULL) { /* not open yet */
1682 DBT key, data;
1683 DBT pkey, pdata;
1684 char bf[MAXLOGNAME];
1686 rv = _pw_opendb(&state->db, &state->version);
1687 if (rv != NS_SUCCESS)
1688 return rv;
1690 state->mode = COMPAT_NOTOKEN;
1693 * Determine if the "compat" token is present in pwd.db;
1694 * either "__YP!" or PW_KEYBYNAME+"+".
1695 * Only works if pwd_mkdb installs the token.
1697 key.data = (u_char *)__UNCONST(__yp_token);
1698 key.size = strlen(__yp_token);
1700 bf[0] = _PW_KEYBYNAME; /* Pre-token database support. */
1701 bf[1] = '+';
1702 pkey.data = (u_char *)bf;
1703 pkey.size = 2;
1705 if ((state->db->get)(state->db, &key, &data, 0) == 0
1706 || (state->db->get)(state->db, &pkey, &pdata, 0) == 0)
1707 state->mode = COMPAT_NONE;
1709 return NS_SUCCESS;
1712 static int
1713 _compat_end(struct compat_state *state)
1716 _DIAGASSERT(state != NULL);
1718 state->keynum = 0;
1719 if (state->db) {
1720 (void)(state->db->close)(state->db);
1721 state->db = NULL;
1723 state->mode = COMPAT_NOTOKEN;
1724 if (state->user)
1725 free(state->user);
1726 state->user = NULL;
1727 if (state->exclude != NULL)
1728 (void)(state->exclude->close)(state->exclude);
1729 state->exclude = NULL;
1730 state->proto.pw_name = NULL;
1731 state->protoflags = 0;
1732 return NS_SUCCESS;
1736 * _compat_add_exclude
1737 * add the name to the exclude list in state->exclude.
1739 static int
1740 _compat_add_exclude(struct compat_state *state, const char *name)
1742 DBT key, data;
1744 _DIAGASSERT(state != NULL);
1745 _DIAGASSERT(name != NULL);
1747 /* initialize the exclusion table if needed */
1748 if (state->exclude == NULL) {
1749 state->exclude = dbopen(NULL, O_RDWR, 600, DB_HASH, NULL);
1750 if (state->exclude == NULL)
1751 return 0;
1754 key.size = strlen(name); /* set up the key */
1755 key.data = (u_char *)__UNCONST(name);
1757 data.data = NULL; /* data is nothing */
1758 data.size = 0;
1760 /* store it */
1761 if ((state->exclude->put)(state->exclude, &key, &data, 0) == -1)
1762 return 0;
1764 return 1;
1768 * _compat_is_excluded
1769 * test if a name is on the compat mode exclude list
1771 static int
1772 _compat_is_excluded(struct compat_state *state, const char *name)
1774 DBT key, data;
1776 _DIAGASSERT(state != NULL);
1777 _DIAGASSERT(name != NULL);
1779 if (state->exclude == NULL)
1780 return 0; /* nothing excluded */
1782 key.size = strlen(name); /* set up the key */
1783 key.data = (u_char *)__UNCONST(name);
1785 if ((state->exclude->get)(state->exclude, &key, &data, 0) == 0)
1786 return 1; /* is excluded */
1788 return 0;
1793 * _passwdcompat_bad
1794 * log an error if "files" or "compat" is specified in
1795 * passwd_compat database
1797 /*ARGSUSED*/
1798 static int
1799 _passwdcompat_bad(void *nsrv, void *nscb, va_list ap)
1801 static int warned;
1803 _DIAGASSERT(nsrv != NULL);
1804 _DIAGASSERT(nscb != NULL);
1806 if (!warned) {
1807 syslog(LOG_ERR,
1808 "nsswitch.conf passwd_compat database can't use '%s'",
1809 (char *)nscb);
1811 warned = 1;
1812 return NS_UNAVAIL;
1816 * _passwdcompat_setpassent
1817 * Call setpassent for all passwd_compat sources.
1819 static int
1820 _passwdcompat_setpassent(int stayopen)
1822 static const ns_dtab dtab[] = {
1823 NS_FILES_CB(_passwdcompat_bad, "files")
1824 NS_DNS_CB(_dns_setpassent, NULL)
1825 NS_NIS_CB(_nis_setpassent, NULL)
1826 NS_COMPAT_CB(_passwdcompat_bad, "compat")
1827 NS_NULL_CB
1830 int rv, result;
1832 rv = nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "setpassent",
1833 __nsdefaultnis_forceall, &result, stayopen);
1834 return rv;
1838 * _passwdcompat_endpwent
1839 * Call endpwent for all passwd_compat sources.
1841 static int
1842 _passwdcompat_endpwent(void)
1844 static const ns_dtab dtab[] = {
1845 NS_FILES_CB(_passwdcompat_bad, "files")
1846 NS_DNS_CB(_dns_endpwent, NULL)
1847 NS_NIS_CB(_nis_endpwent, NULL)
1848 NS_COMPAT_CB(_passwdcompat_bad, "compat")
1849 NS_NULL_CB
1852 return nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "endpwent",
1853 __nsdefaultnis_forceall);
1857 * _passwdcompat_pwscan
1858 * When a name lookup in compat mode is required (e.g., `+name', or a
1859 * name in `+@netgroup'), look it up in the 'passwd_compat' nsswitch
1860 * database.
1861 * Fail if passwd_compat contains files or compat.
1863 static int
1864 _passwdcompat_pwscan(struct passwd *pw, char *buffer, size_t buflen,
1865 int search, const char *name, uid_t uid)
1867 static const ns_dtab compatentdtab[] = {
1868 NS_FILES_CB(_passwdcompat_bad, "files")
1869 NS_DNS_CB(_dns_getpwent_r, NULL)
1870 NS_NIS_CB(_nis_getpwent_r, NULL)
1871 NS_COMPAT_CB(_passwdcompat_bad, "compat")
1872 NS_NULL_CB
1874 static const ns_dtab compatuiddtab[] = {
1875 NS_FILES_CB(_passwdcompat_bad, "files")
1876 NS_DNS_CB(_dns_getpwuid_r, NULL)
1877 NS_NIS_CB(_nis_getpwuid_r, NULL)
1878 NS_COMPAT_CB(_passwdcompat_bad, "compat")
1879 NS_NULL_CB
1881 static const ns_dtab compatnamdtab[] = {
1882 NS_FILES_CB(_passwdcompat_bad, "files")
1883 NS_DNS_CB(_dns_getpwnam_r, NULL)
1884 NS_NIS_CB(_nis_getpwnam_r, NULL)
1885 NS_COMPAT_CB(_passwdcompat_bad, "compat")
1886 NS_NULL_CB
1889 int rv, crv;
1890 struct passwd *cpw;
1892 switch (search) {
1893 case _PW_KEYBYNUM:
1894 rv = nsdispatch(NULL, compatentdtab,
1895 NSDB_PASSWD_COMPAT, "getpwent_r", __nsdefaultnis,
1896 &crv, pw, buffer, buflen, &cpw);
1897 break;
1898 case _PW_KEYBYNAME:
1899 _DIAGASSERT(name != NULL);
1900 rv = nsdispatch(NULL, compatnamdtab,
1901 NSDB_PASSWD_COMPAT, "getpwnam_r", __nsdefaultnis,
1902 &crv, name, pw, buffer, buflen, &cpw);
1903 break;
1904 case _PW_KEYBYUID:
1905 rv = nsdispatch(NULL, compatuiddtab,
1906 NSDB_PASSWD_COMPAT, "getpwuid_r", __nsdefaultnis,
1907 &crv, uid, pw, buffer, buflen, &cpw);
1908 break;
1909 default:
1910 abort();
1911 /*NOTREACHED*/
1913 return rv;
1917 * _compat_pwscan
1918 * Search state->db for the next desired entry.
1919 * If search is _PW_KEYBYNUM, look for state->keynum.
1920 * If search is _PW_KEYBYNAME, look for name.
1921 * If search is _PW_KEYBYUID, look for uid.
1922 * Sets *retval to the errno if the result is not NS_SUCCESS
1923 * or NS_NOTFOUND.
1925 static int
1926 _compat_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen,
1927 struct compat_state *state, int search, const char *name, uid_t uid)
1929 DBT key;
1930 int rv, r, pwflags;
1931 const char *user, *host, *dom;
1932 const void *from;
1933 size_t fromlen;
1935 _DIAGASSERT(retval != NULL);
1936 _DIAGASSERT(pw != NULL);
1937 _DIAGASSERT(buffer != NULL);
1938 _DIAGASSERT(state != NULL);
1939 /* name may be NULL */
1941 *retval = 0;
1943 if (state->db == NULL) {
1944 rv = _compat_start(state);
1945 if (rv != NS_SUCCESS)
1946 return rv;
1948 if (buflen <= 1) { /* buffer too small */
1949 *retval = ERANGE;
1950 return NS_UNAVAIL;
1953 for (;;) { /* loop over pwd.db */
1954 rv = NS_NOTFOUND;
1955 if (state->mode != COMPAT_NOTOKEN &&
1956 state->mode != COMPAT_NONE) {
1957 /* doing a compat lookup */
1958 struct passwd cpw;
1959 char cbuf[_GETPW_R_SIZE_MAX];
1961 switch (state->mode) {
1963 case COMPAT_FULL:
1964 /* get next user or lookup by key */
1965 rv = _passwdcompat_pwscan(&cpw,
1966 cbuf, sizeof(cbuf), search, name, uid);
1967 if (rv != NS_SUCCESS)
1968 state->mode = COMPAT_NONE;
1969 break;
1971 case COMPAT_NETGROUP:
1972 /* XXXREENTRANT: getnetgrent is not thread safe */
1973 /* get next user from netgroup */
1974 r = getnetgrent(&host, &user, &dom);
1975 if (r == 0) { /* end of group */
1976 endnetgrent();
1977 state->mode = COMPAT_NONE;
1978 break;
1980 if (!user || !*user)
1981 break;
1982 rv = _passwdcompat_pwscan(&cpw,
1983 cbuf, sizeof(cbuf),
1984 _PW_KEYBYNAME, user, 0);
1985 break;
1987 case COMPAT_USER:
1988 /* get specific user */
1989 if (state->user == NULL) {
1990 state->mode = COMPAT_NONE;
1991 break;
1993 rv = _passwdcompat_pwscan(&cpw,
1994 cbuf, sizeof(cbuf),
1995 _PW_KEYBYNAME, state->user, 0);
1996 free(state->user);
1997 state->user = NULL;
1998 state->mode = COMPAT_NONE;
1999 break;
2001 case COMPAT_NOTOKEN:
2002 case COMPAT_NONE:
2003 abort();
2006 if (rv != NS_SUCCESS) /* if not matched, next loop */
2007 continue;
2009 /* copy cpw to pw, applying prototype */
2010 if (! _pw_copy(&cpw, pw, buffer, buflen,
2011 &state->proto, state->protoflags)) {
2012 rv = NS_UNAVAIL;
2013 break;
2016 if (_compat_is_excluded(state, pw->pw_name))
2017 continue; /* excluded; next loop */
2019 if ((search == _PW_KEYBYNAME
2020 && strcmp(pw->pw_name, name) != 0)
2021 || (search == _PW_KEYBYUID && pw->pw_uid != uid)) {
2022 continue; /* not specific; next loop */
2025 break; /* exit loop if found */
2026 } else { /* not a compat line */
2027 state->proto.pw_name = NULL;
2028 /* clear prototype */
2031 if (state->mode == COMPAT_NOTOKEN) {
2032 /* no compat token; do direct lookup */
2033 switch (search) {
2034 case _PW_KEYBYNUM:
2035 if (state->keynum == -1) /* no more records */
2036 return NS_NOTFOUND;
2037 state->keynum++;
2038 from = &state->keynum;
2039 fromlen = sizeof(state->keynum);
2040 break;
2041 case _PW_KEYBYNAME:
2042 from = name;
2043 fromlen = strlen(name);
2044 break;
2045 case _PW_KEYBYUID:
2046 from = &uid;
2047 fromlen = sizeof(uid);
2048 break;
2049 default:
2050 abort();
2052 buffer[0] = search;
2053 } else {
2054 /* compat token; do line by line */
2055 if (state->keynum == -1) /* no more records */
2056 return NS_NOTFOUND;
2057 state->keynum++;
2058 from = &state->keynum;
2059 fromlen = sizeof(state->keynum);
2060 buffer[0] = _PW_KEYBYNUM;
2063 if (buflen <= fromlen) { /* buffer too small */
2064 *retval = ERANGE;
2065 return NS_UNAVAIL;
2067 memmove(buffer + 1, from, fromlen); /* setup key */
2068 key.size = fromlen + 1;
2069 key.data = (u_char *)buffer;
2071 rv = _pw_getkey(state->db, &key, pw, buffer, buflen, &pwflags,
2072 state->version);
2073 if (rv != NS_SUCCESS) /* stop on error */
2074 break;
2076 if (state->mode == COMPAT_NOTOKEN)
2077 break; /* stop if no compat token */
2079 if (pw->pw_name[0] == '+') {
2080 /* compat inclusion */
2081 switch(pw->pw_name[1]) {
2082 case '\0': /* `+' */
2083 state->mode = COMPAT_FULL;
2084 /* reset passwd_compat search */
2085 /* XXXREENTRANT: setpassent is not thread safe ? */
2086 (void) _passwdcompat_setpassent(0);
2087 break;
2088 case '@': /* `+@netgroup' */
2089 state->mode = COMPAT_NETGROUP;
2090 /* reset netgroup search */
2091 /* XXXREENTRANT: setnetgrent is not thread safe */
2092 setnetgrent(pw->pw_name + 2);
2093 break;
2094 default: /* `+name' */
2095 state->mode = COMPAT_USER;
2096 if (state->user)
2097 free(state->user);
2098 state->user = strdup(pw->pw_name + 1);
2099 break;
2101 /* save the prototype */
2102 state->protoflags = pwflags;
2103 if (! _pw_copy(pw, &state->proto, state->protobuf,
2104 sizeof(state->protobuf), NULL, 0)) {
2105 rv = NS_UNAVAIL;
2106 break;
2108 continue; /* loop again after inclusion */
2109 } else if (pw->pw_name[0] == '-') {
2110 /* compat exclusion */
2111 rv = NS_SUCCESS;
2112 switch(pw->pw_name[1]) {
2113 case '\0': /* `-' */
2114 break;
2115 case '@': /* `-@netgroup' */
2116 /* XXXREENTRANT: {set,get,end}netgrent is not thread safe */
2117 setnetgrent(pw->pw_name + 2);
2118 while (getnetgrent(&host, &user, &dom)) {
2119 if (!user || !*user)
2120 continue;
2121 if (! _compat_add_exclude(state,user)) {
2122 rv = NS_UNAVAIL;
2123 break;
2126 endnetgrent();
2127 break;
2128 default: /* `-name' */
2129 if (! _compat_add_exclude(state,
2130 pw->pw_name + 1)) {
2131 rv = NS_UNAVAIL;
2133 break;
2135 if (rv != NS_SUCCESS) /* exclusion failure */
2136 break;
2137 continue; /* loop again after exclusion */
2139 if (search == _PW_KEYBYNUM ||
2140 (search == _PW_KEYBYUID && pw->pw_uid == uid) ||
2141 (search == _PW_KEYBYNAME && strcmp(pw->pw_name, name) == 0))
2142 break; /* token mode match found */
2145 if (rv == NS_NOTFOUND &&
2146 (search == _PW_KEYBYNUM || state->mode != COMPAT_NOTOKEN))
2147 state->keynum = -1; /* flag `no more records' */
2149 if (rv == NS_SUCCESS) {
2150 if ((search == _PW_KEYBYNAME && strcmp(pw->pw_name, name) != 0)
2151 || (search == _PW_KEYBYUID && pw->pw_uid != uid))
2152 rv = NS_NOTFOUND;
2155 if (rv != NS_SUCCESS && rv != NS_NOTFOUND)
2156 *retval = errno;
2157 return rv;
2160 /*ARGSUSED*/
2161 static int
2162 _compat_setpwent(void *nsrv, void *nscb, va_list ap)
2165 /* force passwd_compat setpwent() */
2166 (void) _passwdcompat_setpassent(0);
2168 /* reset state, keep db open */
2169 _compat_state.stayopen = 0;
2170 return _compat_start(&_compat_state);
2173 /*ARGSUSED*/
2174 static int
2175 _compat_setpassent(void *nsrv, void *nscb, va_list ap)
2177 int *retval = va_arg(ap, int *);
2178 int stayopen = va_arg(ap, int);
2180 int rv;
2182 /* force passwd_compat setpassent() */
2183 (void) _passwdcompat_setpassent(stayopen);
2185 _compat_state.stayopen = stayopen;
2186 rv = _compat_start(&_compat_state);
2187 *retval = (rv == NS_SUCCESS);
2188 return rv;
2191 /*ARGSUSED*/
2192 static int
2193 _compat_endpwent(void *nsrv, void *nscb, va_list ap)
2196 /* force passwd_compat endpwent() */
2197 (void) _passwdcompat_endpwent();
2199 /* reset state, close db */
2200 _compat_state.stayopen = 0;
2201 return _compat_end(&_compat_state);
2205 /*ARGSUSED*/
2206 static int
2207 _compat_getpwent(void *nsrv, void *nscb, va_list ap)
2209 struct passwd **retval = va_arg(ap, struct passwd **);
2211 int rv, rerror;
2213 _DIAGASSERT(retval != NULL);
2215 *retval = NULL;
2216 rv = _compat_pwscan(&rerror, &_compat_passwd,
2217 _compat_passwdbuf, sizeof(_compat_passwdbuf),
2218 &_compat_state, _PW_KEYBYNUM, NULL, 0);
2219 if (rv == NS_SUCCESS)
2220 *retval = &_compat_passwd;
2221 return rv;
2224 /*ARGSUSED*/
2225 static int
2226 _compat_getpwent_r(void *nsrv, void *nscb, va_list ap)
2228 int *retval = va_arg(ap, int *);
2229 struct passwd *pw = va_arg(ap, struct passwd *);
2230 char *buffer = va_arg(ap, char *);
2231 size_t buflen = va_arg(ap, size_t);
2232 struct passwd **result = va_arg(ap, struct passwd **);
2234 int rv;
2236 _DIAGASSERT(retval != NULL);
2237 _DIAGASSERT(pw != NULL);
2238 _DIAGASSERT(buffer != NULL);
2239 _DIAGASSERT(result != NULL);
2241 rv = _compat_pwscan(retval, pw, buffer, buflen, &_compat_state,
2242 _PW_KEYBYNUM, NULL, 0);
2243 if (rv == NS_SUCCESS)
2244 *result = pw;
2245 else
2246 *result = NULL;
2247 return rv;
2251 /*ARGSUSED*/
2252 static int
2253 _compat_getpwnam(void *nsrv, void *nscb, va_list ap)
2255 struct passwd **retval = va_arg(ap, struct passwd **);
2256 const char *name = va_arg(ap, const char *);
2258 int rv, rerror;
2260 _DIAGASSERT(retval != NULL);
2262 *retval = NULL;
2263 rv = _compat_start(&_compat_state);
2264 if (rv != NS_SUCCESS)
2265 return rv;
2266 rv = _compat_pwscan(&rerror, &_compat_passwd,
2267 _compat_passwdbuf, sizeof(_compat_passwdbuf),
2268 &_compat_state, _PW_KEYBYNAME, name, 0);
2269 if (!_compat_state.stayopen)
2270 _compat_end(&_compat_state);
2271 if (rv == NS_SUCCESS)
2272 *retval = &_compat_passwd;
2273 return rv;
2276 /*ARGSUSED*/
2277 static int
2278 _compat_getpwnam_r(void *nsrv, void *nscb, va_list ap)
2280 int *retval = va_arg(ap, int *);
2281 const char *name = va_arg(ap, const char *);
2282 struct passwd *pw = va_arg(ap, struct passwd *);
2283 char *buffer = va_arg(ap, char *);
2284 size_t buflen = va_arg(ap, size_t);
2285 struct passwd **result = va_arg(ap, struct passwd **);
2287 struct compat_state state;
2288 int rv;
2290 _DIAGASSERT(retval != NULL);
2291 _DIAGASSERT(pw != NULL);
2292 _DIAGASSERT(buffer != NULL);
2293 _DIAGASSERT(result != NULL);
2295 *result = NULL;
2296 memset(&state, 0, sizeof(state));
2297 rv = _compat_pwscan(retval, pw, buffer, buflen, &state,
2298 _PW_KEYBYNAME, name, 0);
2299 _compat_end(&state);
2300 if (rv == NS_SUCCESS)
2301 *result = pw;
2302 return rv;
2305 /*ARGSUSED*/
2306 static int
2307 _compat_getpwuid(void *nsrv, void *nscb, va_list ap)
2309 struct passwd **retval = va_arg(ap, struct passwd **);
2310 uid_t uid = va_arg(ap, uid_t);
2312 int rv, rerror;
2314 _DIAGASSERT(retval != NULL);
2316 *retval = NULL;
2317 rv = _compat_start(&_compat_state);
2318 if (rv != NS_SUCCESS)
2319 return rv;
2320 rv = _compat_pwscan(&rerror, &_compat_passwd,
2321 _compat_passwdbuf, sizeof(_compat_passwdbuf),
2322 &_compat_state, _PW_KEYBYUID, NULL, uid);
2323 if (!_compat_state.stayopen)
2324 _compat_end(&_compat_state);
2325 if (rv == NS_SUCCESS)
2326 *retval = &_compat_passwd;
2327 return rv;
2330 /*ARGSUSED*/
2331 static int
2332 _compat_getpwuid_r(void *nsrv, void *nscb, va_list ap)
2334 int *retval = va_arg(ap, int *);
2335 uid_t uid = va_arg(ap, uid_t);
2336 struct passwd *pw = va_arg(ap, struct passwd *);
2337 char *buffer = va_arg(ap, char *);
2338 size_t buflen = va_arg(ap, size_t);
2339 struct passwd **result = va_arg(ap, struct passwd **);
2341 struct compat_state state;
2342 int rv;
2344 _DIAGASSERT(retval != NULL);
2345 _DIAGASSERT(pw != NULL);
2346 _DIAGASSERT(buffer != NULL);
2347 _DIAGASSERT(result != NULL);
2349 *result = NULL;
2350 memset(&state, 0, sizeof(state));
2351 rv = _compat_pwscan(retval, pw, buffer, buflen, &state,
2352 _PW_KEYBYUID, NULL, uid);
2353 _compat_end(&state);
2354 if (rv == NS_SUCCESS)
2355 *result = pw;
2356 return rv;
2359 #endif /* _PASSWD_COMPAT */
2363 * public functions
2366 struct passwd *
2367 getpwent(void)
2369 int r;
2370 struct passwd *retval;
2372 static const ns_dtab dtab[] = {
2373 NS_FILES_CB(_files_getpwent, NULL)
2374 NS_DNS_CB(_dns_getpwent, NULL)
2375 NS_NIS_CB(_nis_getpwent, NULL)
2376 NS_COMPAT_CB(_compat_getpwent, NULL)
2377 NS_NULL_CB
2380 mutex_lock(&_pwmutex);
2381 r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwent", __nsdefaultcompat,
2382 &retval);
2383 mutex_unlock(&_pwmutex);
2384 return (r == NS_SUCCESS) ? retval : NULL;
2388 getpwent_r(struct passwd *pwd, char *buffer, size_t buflen,
2389 struct passwd **result)
2391 int r, retval;
2393 static const ns_dtab dtab[] = {
2394 NS_FILES_CB(_files_getpwent_r, NULL)
2395 NS_DNS_CB(_dns_getpwent_r, NULL)
2396 NS_NIS_CB(_nis_getpwent_r, NULL)
2397 NS_COMPAT_CB(_compat_getpwent_r, NULL)
2398 NS_NULL_CB
2401 _DIAGASSERT(pwd != NULL);
2402 _DIAGASSERT(buffer != NULL);
2403 _DIAGASSERT(result != NULL);
2405 *result = NULL;
2406 retval = 0;
2407 mutex_lock(&_pwmutex);
2408 r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwent_r", __nsdefaultcompat,
2409 &retval, pwd, buffer, buflen, result);
2410 mutex_unlock(&_pwmutex);
2411 switch (r) {
2412 case NS_SUCCESS:
2413 case NS_NOTFOUND:
2414 return 0;
2415 default:
2416 return retval;
2421 struct passwd *
2422 getpwnam(const char *name)
2424 int rv;
2425 struct passwd *retval;
2427 static const ns_dtab dtab[] = {
2428 NS_FILES_CB(_files_getpwnam, NULL)
2429 NS_DNS_CB(_dns_getpwnam, NULL)
2430 NS_NIS_CB(_nis_getpwnam, NULL)
2431 NS_COMPAT_CB(_compat_getpwnam, NULL)
2432 NS_NULL_CB
2435 mutex_lock(&_pwmutex);
2436 rv = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwnam", __nsdefaultcompat,
2437 &retval, name);
2438 mutex_unlock(&_pwmutex);
2439 return (rv == NS_SUCCESS) ? retval : NULL;
2443 getpwnam_r(const char *name, struct passwd *pwd, char *buffer, size_t buflen,
2444 struct passwd **result)
2446 int r, retval;
2448 static const ns_dtab dtab[] = {
2449 NS_FILES_CB(_files_getpwnam_r, NULL)
2450 NS_DNS_CB(_dns_getpwnam_r, NULL)
2451 NS_NIS_CB(_nis_getpwnam_r, NULL)
2452 NS_COMPAT_CB(_compat_getpwnam_r, NULL)
2453 NS_NULL_CB
2456 _DIAGASSERT(name != NULL);
2457 _DIAGASSERT(pwd != NULL);
2458 _DIAGASSERT(buffer != NULL);
2459 _DIAGASSERT(result != NULL);
2461 *result = NULL;
2462 retval = 0;
2463 mutex_lock(&_pwmutex);
2464 r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwnam_r", __nsdefaultcompat,
2465 &retval, name, pwd, buffer, buflen, result);
2466 mutex_unlock(&_pwmutex);
2467 switch (r) {
2468 case NS_SUCCESS:
2469 case NS_NOTFOUND:
2470 return 0;
2471 default:
2472 return retval;
2476 struct passwd *
2477 getpwuid(uid_t uid)
2479 int rv;
2480 struct passwd *retval;
2482 static const ns_dtab dtab[] = {
2483 NS_FILES_CB(_files_getpwuid, NULL)
2484 NS_DNS_CB(_dns_getpwuid, NULL)
2485 NS_NIS_CB(_nis_getpwuid, NULL)
2486 NS_COMPAT_CB(_compat_getpwuid, NULL)
2487 NS_NULL_CB
2490 mutex_lock(&_pwmutex);
2491 rv = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwuid", __nsdefaultcompat,
2492 &retval, uid);
2493 mutex_unlock(&_pwmutex);
2494 return (rv == NS_SUCCESS) ? retval : NULL;
2498 getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, size_t buflen,
2499 struct passwd **result)
2501 int r, retval;
2503 static const ns_dtab dtab[] = {
2504 NS_FILES_CB(_files_getpwuid_r, NULL)
2505 NS_DNS_CB(_dns_getpwuid_r, NULL)
2506 NS_NIS_CB(_nis_getpwuid_r, NULL)
2507 NS_COMPAT_CB(_compat_getpwuid_r, NULL)
2508 NS_NULL_CB
2511 _DIAGASSERT(pwd != NULL);
2512 _DIAGASSERT(buffer != NULL);
2513 _DIAGASSERT(result != NULL);
2515 *result = NULL;
2516 retval = 0;
2517 mutex_lock(&_pwmutex);
2518 r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwuid_r", __nsdefaultcompat,
2519 &retval, uid, pwd, buffer, buflen, result);
2520 mutex_unlock(&_pwmutex);
2521 switch (r) {
2522 case NS_SUCCESS:
2523 case NS_NOTFOUND:
2524 return 0;
2525 default:
2526 return retval;
2530 void
2531 endpwent(void)
2533 static const ns_dtab dtab[] = {
2534 NS_FILES_CB(_files_endpwent, NULL)
2535 NS_DNS_CB(_dns_endpwent, NULL)
2536 NS_NIS_CB(_nis_endpwent, NULL)
2537 NS_COMPAT_CB(_compat_endpwent, NULL)
2538 NS_NULL_CB
2541 mutex_lock(&_pwmutex);
2542 /* force all endpwent() methods */
2543 (void) nsdispatch(NULL, dtab, NSDB_PASSWD, "endpwent",
2544 __nsdefaultcompat_forceall);
2545 mutex_unlock(&_pwmutex);
2548 /*ARGSUSED*/
2550 setpassent(int stayopen)
2552 static const ns_dtab dtab[] = {
2553 NS_FILES_CB(_files_setpassent, NULL)
2554 NS_DNS_CB(_dns_setpassent, NULL)
2555 NS_NIS_CB(_nis_setpassent, NULL)
2556 NS_COMPAT_CB(_compat_setpassent, NULL)
2557 NS_NULL_CB
2559 int rv, retval;
2561 mutex_lock(&_pwmutex);
2562 /* force all setpassent() methods */
2563 rv = nsdispatch(NULL, dtab, NSDB_PASSWD, "setpassent",
2564 __nsdefaultcompat_forceall, &retval, stayopen);
2565 mutex_unlock(&_pwmutex);
2566 return (rv == NS_SUCCESS) ? retval : 0;
2569 void
2570 setpwent(void)
2572 static const ns_dtab dtab[] = {
2573 NS_FILES_CB(_files_setpwent, NULL)
2574 NS_DNS_CB(_dns_setpwent, NULL)
2575 NS_NIS_CB(_nis_setpwent, NULL)
2576 NS_COMPAT_CB(_compat_setpwent, NULL)
2577 NS_NULL_CB
2580 mutex_lock(&_pwmutex);
2581 /* force all setpwent() methods */
2582 (void) nsdispatch(NULL, dtab, NSDB_PASSWD, "setpwent",
2583 __nsdefaultcompat_forceall);
2584 mutex_unlock(&_pwmutex);