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