getpwent.c revision 1.76 1 /* $NetBSD: getpwent.c,v 1.76 2009/01/11 02:46:27 christos 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 *
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.
30 */
31
32 /*
33 * Copyright (c) 1988, 1993
34 * The Regents of the University of California. All rights reserved.
35 *
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.
47 *
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.
59 */
60
61 /*
62 * Portions Copyright (c) 1994, 1995, Jason Downs. All rights reserved.
63 *
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.
72 *
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.
84 */
85
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.76 2009/01/11 02:46:27 christos Exp $");
92 #endif
93 #endif /* LIBC_SCCS and not lint */
94
95 #include "namespace.h"
96 #include "reentrant.h"
97
98 #include <sys/param.h>
99
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>
114
115 #ifdef HESIOD
116 #include <hesiod.h>
117 #endif
118
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
125
126 #include "pw_private.h"
127
128 #define _PASSWD_COMPAT /* "passwd" defaults to compat, so always provide it */
129
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
141
142 #ifdef _REENTRANT
143 static mutex_t _pwmutex = MUTEX_INITIALIZER;
144 #endif
145
146 const char __yp_token[] = "__YP!"; /* Let pwd_mkdb pull this in. */
147
148
149 /*
150 * The pwd.db lookup techniques and data extraction code here must be kept
151 * in sync with that in `pwd_mkdb'.
152 */
153
154 #if defined(YP) || defined(HESIOD)
155 /*
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.
161 */
162 static int
163 _pw_parse(const char *entry, struct passwd *pw, char *buf, size_t buflen,
164 int old)
165 {
166 int flags;
167
168 _DIAGASSERT(entry != NULL);
169 _DIAGASSERT(pw != NULL);
170 _DIAGASSERT(buf != NULL);
171
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);
178 }
179 #endif /* YP || HESIOD */
180
181 /*
182 * _pw_opendb
183 * if *db is NULL, dbopen(3) /etc/spwd.db or /etc/pwd.db (depending
184 * upon permissions, etc)
185 */
186 static int
187 _pw_opendb(DB **db, int *version)
188 {
189 static int warned;
190 DBT key;
191 DBT value;
192
193 const char *dbfile = NULL;
194
195 _DIAGASSERT(db != NULL);
196 _DIAGASSERT(version != NULL);
197 if (*db != NULL) /* open *db */
198 return NS_SUCCESS;
199
200 if (geteuid() == 0) {
201 dbfile = _PATH_SMP_DB;
202 *db = dbopen(dbfile, O_RDONLY, 0, DB_HASH, NULL);
203 }
204 if (*db == NULL) {
205 dbfile = _PATH_MP_DB;
206 *db = dbopen(dbfile, O_RDONLY, 0, DB_HASH, NULL);
207 }
208 if (*db == NULL) {
209 if (!warned) {
210 int serrno = errno;
211 syslog(LOG_ERR, "%s: %m", dbfile);
212 errno = serrno;
213 }
214 warned = 1;
215 return NS_UNAVAIL;
216 }
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();
232 }
233 return NS_SUCCESS;
234 }
235
236 /*
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.)
242 */
243 static int
244 _pw_getkey(DB *db, DBT *key,
245 struct passwd *pw, char *buffer, size_t buflen, int *pwflags,
246 int version)
247 {
248 char *p, *t;
249 DBT data;
250
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 */
256
257 if (db == NULL) /* this shouldn't happen */
258 return NS_UNAVAIL;
259
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();
269 }
270
271 p = (char *)data.data;
272 if (data.size > buflen) {
273 errno = ERANGE;
274 return NS_UNAVAIL;
275 }
276
277 /*
278 * THE DECODING BELOW MUST MATCH THAT IN pwd_mkdb.
279 */
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;
310 }
311 }
312
313 return NS_SUCCESS;
314 }
315
316 /*
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.
321 */
322 static char *
323 _pw_memfrombuf(size_t want, char **buffer, size_t *buflen)
324 {
325 char *rv;
326
327 if (want > *buflen) {
328 errno = ERANGE;
329 return NULL;
330 }
331 rv = *buffer;
332 *buffer += want;
333 *buflen -= want;
334 return rv;
335 }
336
337 /*
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.
344 */
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)
348 {
349 size_t count;
350 int useproto;
351
352 _DIAGASSERT(frompw != NULL);
353 _DIAGASSERT(pw != NULL);
354 _DIAGASSERT(buf != NULL);
355 /* protopw may be NULL */
356
357 useproto = protopw && protopw->pw_name;
358
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 */
368
369 #define COPYFIELD(field) COPYSTR(pw->field, frompw->field)
370
371 #define COPYPROTOFIELD(field) COPYSTR(pw->field, \
372 (useproto && *protopw->field ? protopw->field : frompw->field))
373
374 COPYFIELD(pw_name);
375
376 #ifdef PW_OVERRIDE_PASSWD
377 COPYPROTOFIELD(pw_passwd);
378 #else
379 COPYFIELD(pw_passwd);
380 #endif
381
382 if (useproto && !(protoflags & _PASSWORD_NOUID))
383 pw->pw_uid = protopw->pw_uid;
384 else
385 pw->pw_uid = frompw->pw_uid;
386
387 if (useproto && !(protoflags & _PASSWORD_NOGID))
388 pw->pw_gid = protopw->pw_gid;
389 else
390 pw->pw_gid = frompw->pw_gid;
391
392 pw->pw_change = frompw->pw_change;
393 COPYFIELD(pw_class);
394 COPYPROTOFIELD(pw_gecos);
395 COPYPROTOFIELD(pw_dir);
396 COPYPROTOFIELD(pw_shell);
397
398 #undef COPYSTR
399 #undef COPYFIELD
400 #undef COPYPROTOFIELD
401
402 return 1;
403 }
404
405
406 /*
407 * files methods
408 */
409
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;
416 };
417
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];
422
423 static int
424 _files_start(struct files_state *state)
425 {
426 int rv;
427
428 _DIAGASSERT(state != NULL);
429
430 state->keynum = 0;
431 rv = _pw_opendb(&state->db, &state->version);
432 if (rv != NS_SUCCESS)
433 return rv;
434 return NS_SUCCESS;
435 }
436
437 static int
438 _files_end(struct files_state *state)
439 {
440
441 _DIAGASSERT(state != NULL);
442
443 state->keynum = 0;
444 if (state->db) {
445 (void)(state->db->close)(state->db);
446 state->db = NULL;
447 }
448 return NS_SUCCESS;
449 }
450
451 /*
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.
459 */
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)
463 {
464 const void *from;
465 size_t fromlen;
466 DBT key;
467 int rv;
468
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 */
474
475 *retval = 0;
476
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;
481 }
482
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();
502 }
503
504 if (buflen <= fromlen) { /* buffer too small */
505 *retval = ERANGE;
506 return NS_UNAVAIL;
507 }
508 buffer[0] = search; /* setup key */
509 memmove(buffer + 1, from, fromlen);
510 key.size = fromlen + 1;
511 key.data = (u_char *)buffer;
512
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;
524 }
525 break;
526 }
527
528 if (rv == NS_NOTFOUND && search == _PW_KEYBYNUM)
529 state->keynum = -1; /* flag `no more records' */
530
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;
535 }
536
537 filespwscan_out:
538 if (rv != NS_SUCCESS && rv != NS_NOTFOUND)
539 *retval = errno;
540 return rv;
541 }
542
543 /*ARGSUSED*/
544 static int
545 _files_setpwent(void *nsrv, void *nscb, va_list ap)
546 {
547
548 _files_state.stayopen = 0;
549 return _files_start(&_files_state);
550 }
551
552 /*ARGSUSED*/
553 static int
554 _files_setpassent(void *nsrv, void *nscb, va_list ap)
555 {
556 int *retval = va_arg(ap, int *);
557 int stayopen = va_arg(ap, int);
558
559 int rv;
560
561 _files_state.stayopen = stayopen;
562 rv = _files_start(&_files_state);
563 *retval = (rv == NS_SUCCESS);
564 return rv;
565 }
566
567 /*ARGSUSED*/
568 static int
569 _files_endpwent(void *nsrv, void *nscb, va_list ap)
570 {
571
572 _files_state.stayopen = 0;
573 return _files_end(&_files_state);
574 }
575
576 /*ARGSUSED*/
577 static int
578 _files_getpwent(void *nsrv, void *nscb, va_list ap)
579 {
580 struct passwd **retval = va_arg(ap, struct passwd **);
581
582 int rv, rerror;
583
584 _DIAGASSERT(retval != NULL);
585
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;
593 }
594
595 /*ARGSUSED*/
596 static int
597 _files_getpwent_r(void *nsrv, void *nscb, va_list ap)
598 {
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 **);
604
605 int rv;
606
607 _DIAGASSERT(retval != NULL);
608 _DIAGASSERT(pw != NULL);
609 _DIAGASSERT(buffer != NULL);
610 _DIAGASSERT(result != NULL);
611
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;
619 }
620
621 /*ARGSUSED*/
622 static int
623 _files_getpwnam(void *nsrv, void *nscb, va_list ap)
624 {
625 struct passwd **retval = va_arg(ap, struct passwd **);
626 const char *name = va_arg(ap, const char *);
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_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;
644 }
645
646 /*ARGSUSED*/
647 static int
648 _files_getpwnam_r(void *nsrv, void *nscb, va_list ap)
649 {
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 **);
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_KEYBYNAME, name, 0);
669 _files_end(&state);
670 if (rv == NS_SUCCESS)
671 *result = pw;
672 return rv;
673 }
674
675 /*ARGSUSED*/
676 static int
677 _files_getpwuid(void *nsrv, void *nscb, va_list ap)
678 {
679 struct passwd **retval = va_arg(ap, struct passwd **);
680 uid_t uid = va_arg(ap, uid_t);
681
682 int rv, rerror;
683
684 _DIAGASSERT(retval != NULL);
685
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;
698 }
699
700 /*ARGSUSED*/
701 static int
702 _files_getpwuid_r(void *nsrv, void *nscb, va_list ap)
703 {
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 **);
710
711 struct files_state state;
712 int rv;
713
714 _DIAGASSERT(retval != NULL);
715 _DIAGASSERT(pw != NULL);
716 _DIAGASSERT(buffer != NULL);
717 _DIAGASSERT(result != NULL);
718
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;
727 }
728
729
730 #ifdef HESIOD
731 /*
732 * dns methods
733 */
734
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 */
740 };
741
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];
746
747 static int
748 _dns_start(struct dns_state *state)
749 {
750
751 _DIAGASSERT(state != NULL);
752
753 state->num = 0;
754 if (state->context == NULL) { /* setup Hesiod */
755 if (hesiod_init(&state->context) == -1)
756 return NS_UNAVAIL;
757 }
758
759 return NS_SUCCESS;
760 }
761
762 static int
763 _dns_end(struct dns_state *state)
764 {
765
766 _DIAGASSERT(state != NULL);
767
768 state->num = 0;
769 if (state->context) {
770 hesiod_end(state->context);
771 state->context = NULL;
772 }
773 return NS_SUCCESS;
774 }
775
776 /*
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.
781 */
782 static int
783 _dns_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen,
784 struct dns_state *state, const char **zones)
785 {
786 const char **curzone;
787 char **hp, *ep;
788 int rv;
789
790 _DIAGASSERT(retval != NULL);
791 _DIAGASSERT(pw != NULL);
792 _DIAGASSERT(buffer != NULL);
793 _DIAGASSERT(state != NULL);
794 _DIAGASSERT(zones != NULL);
795
796 *retval = 0;
797
798 if (state->context == NULL) { /* only start if Hesiod not setup */
799 rv = _dns_start(state);
800 if (rv != NS_SUCCESS)
801 return rv;
802 }
803
804 hp = NULL;
805 rv = NS_NOTFOUND;
806
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;
814 }
815 }
816 if (*curzone == NULL)
817 goto dnspwscan_out;
818
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;
825
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;
832 }
833
834 /*ARGSUSED*/
835 static int
836 _dns_setpwent(void *nsrv, void *nscb, va_list ap)
837 {
838
839 _dns_state.stayopen = 0;
840 return _dns_start(&_dns_state);
841 }
842
843 /*ARGSUSED*/
844 static int
845 _dns_setpassent(void *nsrv, void *nscb, va_list ap)
846 {
847 int *retval = va_arg(ap, int *);
848 int stayopen = va_arg(ap, int);
849
850 int rv;
851
852 _dns_state.stayopen = stayopen;
853 rv = _dns_start(&_dns_state);
854 *retval = (rv == NS_SUCCESS);
855 return rv;
856 }
857
858 /*ARGSUSED*/
859 static int
860 _dns_endpwent(void *nsrv, void *nscb, va_list ap)
861 {
862
863 _dns_state.stayopen = 0;
864 return _dns_end(&_dns_state);
865 }
866
867 /*ARGSUSED*/
868 static int
869 _dns_getpwent(void *nsrv, void *nscb, va_list ap)
870 {
871 struct passwd **retval = va_arg(ap, struct passwd **);
872
873 char **hp, *ep;
874 int rv;
875
876 _DIAGASSERT(retval != NULL);
877
878 *retval = NULL;
879
880 if (_dns_state.num == -1) /* exhausted search */
881 return NS_NOTFOUND;
882
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;
888 }
889
890 next_dns_entry:
891 hp = NULL;
892 rv = NS_NOTFOUND;
893
894 /* find passwd-NNN */
895 snprintf(_dns_passwdbuf, sizeof(_dns_passwdbuf),
896 "passwd-%u", _dns_state.num);
897 _dns_state.num++;
898
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;
915 }
916 }
917
918 if (hp)
919 hesiod_free_list(_dns_state.context, hp);
920 if (rv == NS_SUCCESS)
921 *retval = &_dns_passwd;
922 return rv;
923 }
924
925 /*ARGSUSED*/
926 static int
927 _dns_getpwent_r(void *nsrv, void *nscb, va_list ap)
928 {
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 **);
934
935 char **hp, *ep;
936 int rv;
937
938 _DIAGASSERT(retval != NULL);
939 _DIAGASSERT(pw != NULL);
940 _DIAGASSERT(buffer != NULL);
941 _DIAGASSERT(result != NULL);
942
943 *retval = 0;
944
945 if (_dns_state.num == -1) /* exhausted search */
946 return NS_NOTFOUND;
947
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;
953 }
954
955 next_dns_entry:
956 hp = NULL;
957 rv = NS_NOTFOUND;
958
959 /* find passwd-NNN */
960 snprintf(buffer, buflen, "passwd-%u", _dns_state.num);
961 _dns_state.num++;
962
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;
978 }
979 }
980
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;
988 }
989
990 static const char *_dns_uid_zones[] = {
991 "uid",
992 "passwd",
993 NULL
994 };
995
996 /*ARGSUSED*/
997 static int
998 _dns_getpwuid(void *nsrv, void *nscb, va_list ap)
999 {
1000 struct passwd **retval = va_arg(ap, struct passwd **);
1001 uid_t uid = va_arg(ap, uid_t);
1002
1003 int rv, rerror;
1004
1005 _DIAGASSERT(retval != NULL);
1006
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;
1021 }
1022
1023 /*ARGSUSED*/
1024 static int
1025 _dns_getpwuid_r(void *nsrv, void *nscb, va_list ap)
1026 {
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 **);
1033
1034 struct dns_state state;
1035 int rv;
1036
1037 _DIAGASSERT(retval != NULL);
1038 _DIAGASSERT(pw != NULL);
1039 _DIAGASSERT(buffer != NULL);
1040 _DIAGASSERT(result != NULL);
1041
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;
1054 }
1055
1056 static const char *_dns_nam_zones[] = {
1057 "passwd",
1058 NULL
1059 };
1060
1061 /*ARGSUSED*/
1062 static int
1063 _dns_getpwnam(void *nsrv, void *nscb, va_list ap)
1064 {
1065 struct passwd **retval = va_arg(ap, struct passwd **);
1066 const char *name = va_arg(ap, const char *);
1067
1068 int rv, rerror;
1069
1070 _DIAGASSERT(retval != NULL);
1071
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;
1085 }
1086
1087 /*ARGSUSED*/
1088 static int
1089 _dns_getpwnam_r(void *nsrv, void *nscb, va_list ap)
1090 {
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 **);
1097
1098 struct dns_state state;
1099 int rv;
1100
1101 _DIAGASSERT(retval != NULL);
1102 _DIAGASSERT(pw != NULL);
1103 _DIAGASSERT(buffer != NULL);
1104 _DIAGASSERT(result != NULL);
1105
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;
1118 }
1119
1120 #endif /* HESIOD */
1121
1122
1123 #ifdef YP
1124 /*
1125 * nis methods
1126 */
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;
1140 };
1141
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];
1146
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")
1152
1153 static int
1154 _nis_start(struct nis_state *state)
1155 {
1156
1157 _DIAGASSERT(state != NULL);
1158
1159 state->done = 0;
1160 if (state->current) {
1161 free(state->current);
1162 state->current = NULL;
1163 }
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;
1172 }
1173 }
1174
1175 /* determine where to get pw_passwd from */
1176 if (state->maptype == NISMAP_UNKNOWN) {
1177 int r, order;
1178
1179 state->maptype = NISMAP_NONE; /* default to no adjunct */
1180 if (geteuid() != 0) /* non-root can't use adjunct */
1181 return NS_SUCCESS;
1182
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;
1188 }
1189
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;
1196 }
1197 }
1198 return NS_SUCCESS;
1199 }
1200
1201 static int
1202 _nis_end(struct nis_state *state)
1203 {
1204
1205 _DIAGASSERT(state != NULL);
1206
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;
1215 }
1216
1217 /*
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.
1221 */
1222 static int
1223 _nis_parse(const char *entry, struct passwd *pw, char *buf, size_t buflen,
1224 struct nis_state *state)
1225 {
1226 size_t elen;
1227
1228 _DIAGASSERT(entry != NULL);
1229 _DIAGASSERT(pw != NULL);
1230 _DIAGASSERT(buf != NULL);
1231 _DIAGASSERT(state != NULL);
1232
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;
1239
1240 if ((state->maptype == NISMAP_ADJUNCT) &&
1241 (strstr(pw->pw_passwd, "##") != NULL)) {
1242 char *data;
1243 int datalen;
1244
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];
1256 }
1257 free(data);
1258 }
1259 }
1260
1261 return 1;
1262 }
1263
1264
1265 /*
1266 * _nis_pwscan
1267 * Look for the yp key provided in buffer from map,
1268 * and decode into pw/buffer/buflen.
1269 */
1270 static int
1271 _nis_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen,
1272 struct nis_state *state, const char *map)
1273 {
1274 char *data;
1275 int nisr, rv, datalen;
1276
1277 _DIAGASSERT(retval != NULL);
1278 _DIAGASSERT(pw != NULL);
1279 _DIAGASSERT(buffer != NULL);
1280 _DIAGASSERT(state != NULL);
1281 _DIAGASSERT(map != NULL);
1282
1283 *retval = 0;
1284
1285 if (state->domain == NULL) { /* only start if NIS not setup */
1286 rv = _nis_start(state);
1287 if (rv != NS_SUCCESS)
1288 return rv;
1289 }
1290
1291 data = NULL;
1292 rv = NS_NOTFOUND;
1293
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;
1310 }
1311
1312 if (rv != NS_SUCCESS && rv != NS_NOTFOUND)
1313 *retval = errno;
1314 if (data)
1315 free(data);
1316 return rv;
1317 }
1318
1319 /*ARGSUSED*/
1320 static int
1321 _nis_setpwent(void *nsrv, void *nscb, va_list ap)
1322 {
1323
1324 _nis_state.stayopen = 0;
1325 return _nis_start(&_nis_state);
1326 }
1327
1328 /*ARGSUSED*/
1329 static int
1330 _nis_setpassent(void *nsrv, void *nscb, va_list ap)
1331 {
1332 int *retval = va_arg(ap, int *);
1333 int stayopen = va_arg(ap, int);
1334
1335 int rv;
1336
1337 _nis_state.stayopen = stayopen;
1338 rv = _nis_start(&_nis_state);
1339 *retval = (rv == NS_SUCCESS);
1340 return rv;
1341 }
1342
1343 /*ARGSUSED*/
1344 static int
1345 _nis_endpwent(void *nsrv, void *nscb, va_list ap)
1346 {
1347
1348 return _nis_end(&_nis_state);
1349 }
1350
1351
1352 /*ARGSUSED*/
1353 static int
1354 _nis_getpwent(void *nsrv, void *nscb, va_list ap)
1355 {
1356 struct passwd **retval = va_arg(ap, struct passwd **);
1357
1358 char *key, *data;
1359 int keylen, datalen, rv, nisr;
1360
1361 _DIAGASSERT(retval != NULL);
1362
1363 *retval = NULL;
1364
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;
1372 }
1373
1374 next_nis_entry:
1375 key = NULL;
1376 data = NULL;
1377 rv = NS_NOTFOUND;
1378
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;
1397 }
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;
1404 }
1405 }
1406
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;
1415 }
1416
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;
1425 }
1426
1427 /*ARGSUSED*/
1428 static int
1429 _nis_getpwent_r(void *nsrv, void *nscb, va_list ap)
1430 {
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 **);
1436
1437 char *key, *data;
1438 int keylen, datalen, rv, nisr;
1439
1440 _DIAGASSERT(retval != NULL);
1441 _DIAGASSERT(pw != NULL);
1442 _DIAGASSERT(buffer != NULL);
1443 _DIAGASSERT(result != NULL);
1444
1445 *retval = 0;
1446
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;
1454 }
1455
1456 next_nis_entry:
1457 key = NULL;
1458 data = NULL;
1459 rv = NS_NOTFOUND;
1460
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;
1479 }
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;
1486 }
1487 }
1488
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;
1498 }
1499
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;
1510 }
1511
1512 /*ARGSUSED*/
1513 static int
1514 _nis_getpwuid(void *nsrv, void *nscb, va_list ap)
1515 {
1516 struct passwd **retval = va_arg(ap, struct passwd **);
1517 uid_t uid = va_arg(ap, uid_t);
1518
1519 int rv, rerror;
1520
1521 _DIAGASSERT(retval != NULL);
1522
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;
1536 }
1537
1538 /*ARGSUSED*/
1539 static int
1540 _nis_getpwuid_r(void *nsrv, void *nscb, va_list ap)
1541 {
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 **);
1548
1549 struct nis_state state;
1550 int rv;
1551
1552 _DIAGASSERT(retval != NULL);
1553 _DIAGASSERT(pw != NULL);
1554 _DIAGASSERT(buffer != NULL);
1555 _DIAGASSERT(result != NULL);
1556
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;
1573 }
1574
1575 /*ARGSUSED*/
1576 static int
1577 _nis_getpwnam(void *nsrv, void *nscb, va_list ap)
1578 {
1579 struct passwd **retval = va_arg(ap, struct passwd **);
1580 const char *name = va_arg(ap, const char *);
1581
1582 int rv, rerror;
1583
1584 _DIAGASSERT(retval != NULL);
1585
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;
1599 }
1600
1601 /*ARGSUSED*/
1602 static int
1603 _nis_getpwnam_r(void *nsrv, void *nscb, va_list ap)
1604 {
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 **);
1611
1612 struct nis_state state;
1613 int rv;
1614
1615 _DIAGASSERT(retval != NULL);
1616 _DIAGASSERT(pw != NULL);
1617 _DIAGASSERT(buffer != NULL);
1618 _DIAGASSERT(result != NULL);
1619
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;
1636 }
1637
1638 #endif /* YP */
1639
1640
1641 #ifdef _PASSWD_COMPAT
1642 /*
1643 * compat methods
1644 */
1645
1646 /* state shared between compat methods */
1647
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;
1666 };
1667
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];
1672
1673 static int
1674 _compat_start(struct compat_state *state)
1675 {
1676 int rv;
1677
1678 _DIAGASSERT(state != NULL);
1679
1680 state->keynum = 0;
1681 if (state->db == NULL) { /* not open yet */
1682 DBT key, data;
1683 DBT pkey, pdata;
1684 char bf[MAXLOGNAME];
1685
1686 rv = _pw_opendb(&state->db, &state->version);
1687 if (rv != NS_SUCCESS)
1688 return rv;
1689
1690 state->mode = COMPAT_NOTOKEN;
1691
1692 /*
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.
1696 */
1697 key.data = (u_char *)__UNCONST(__yp_token);
1698 key.size = strlen(__yp_token);
1699
1700 bf[0] = _PW_KEYBYNAME; /* Pre-token database support. */
1701 bf[1] = '+';
1702 pkey.data = (u_char *)bf;
1703 pkey.size = 2;
1704
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;
1708 }
1709 return NS_SUCCESS;
1710 }
1711
1712 static int
1713 _compat_end(struct compat_state *state)
1714 {
1715
1716 _DIAGASSERT(state != NULL);
1717
1718 state->keynum = 0;
1719 if (state->db) {
1720 (void)(state->db->close)(state->db);
1721 state->db = NULL;
1722 }
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;
1733 }
1734
1735 /*
1736 * _compat_add_exclude
1737 * add the name to the exclude list in state->exclude.
1738 */
1739 static int
1740 _compat_add_exclude(struct compat_state *state, const char *name)
1741 {
1742 DBT key, data;
1743
1744 _DIAGASSERT(state != NULL);
1745 _DIAGASSERT(name != NULL);
1746
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;
1752 }
1753
1754 key.size = strlen(name); /* set up the key */
1755 key.data = (u_char *)__UNCONST(name);
1756
1757 data.data = NULL; /* data is nothing */
1758 data.size = 0;
1759
1760 /* store it */
1761 if ((state->exclude->put)(state->exclude, &key, &data, 0) == -1)
1762 return 0;
1763
1764 return 1;
1765 }
1766
1767 /*
1768 * _compat_is_excluded
1769 * test if a name is on the compat mode exclude list
1770 */
1771 static int
1772 _compat_is_excluded(struct compat_state *state, const char *name)
1773 {
1774 DBT key, data;
1775
1776 _DIAGASSERT(state != NULL);
1777 _DIAGASSERT(name != NULL);
1778
1779 if (state->exclude == NULL)
1780 return 0; /* nothing excluded */
1781
1782 key.size = strlen(name); /* set up the key */
1783 key.data = (u_char *)__UNCONST(name);
1784
1785 if ((state->exclude->get)(state->exclude, &key, &data, 0) == 0)
1786 return 1; /* is excluded */
1787
1788 return 0;
1789 }
1790
1791
1792 /*
1793 * _passwdcompat_bad
1794 * log an error if "files" or "compat" is specified in
1795 * passwd_compat database
1796 */
1797 /*ARGSUSED*/
1798 static int
1799 _passwdcompat_bad(void *nsrv, void *nscb, va_list ap)
1800 {
1801 static int warned;
1802
1803 _DIAGASSERT(nsrv != NULL);
1804 _DIAGASSERT(nscb != NULL);
1805
1806 if (!warned) {
1807 syslog(LOG_ERR,
1808 "nsswitch.conf passwd_compat database can't use '%s'",
1809 (char *)nscb);
1810 }
1811 warned = 1;
1812 return NS_UNAVAIL;
1813 }
1814
1815 /*
1816 * _passwdcompat_setpassent
1817 * Call setpassent for all passwd_compat sources.
1818 */
1819 static int
1820 _passwdcompat_setpassent(int stayopen)
1821 {
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
1828 };
1829
1830 int rv, result;
1831
1832 rv = nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "setpassent",
1833 __nsdefaultnis_forceall, &result, stayopen);
1834 return rv;
1835 }
1836
1837 /*
1838 * _passwdcompat_endpwent
1839 * Call endpwent for all passwd_compat sources.
1840 */
1841 static int
1842 _passwdcompat_endpwent(void)
1843 {
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
1850 };
1851
1852 return nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "endpwent",
1853 __nsdefaultnis_forceall);
1854 }
1855
1856 /*
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.
1862 */
1863 static int
1864 _passwdcompat_pwscan(struct passwd *pw, char *buffer, size_t buflen,
1865 int search, const char *name, uid_t uid)
1866 {
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
1873 };
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
1880 };
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
1887 };
1888
1889 int rv, crv;
1890 struct passwd *cpw;
1891
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*/
1912 }
1913 return rv;
1914 }
1915
1916 /*
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.
1924 */
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)
1928 {
1929 DBT key;
1930 int rv, r, pwflags;
1931 const char *user, *host, *dom;
1932 const void *from;
1933 size_t fromlen;
1934
1935 _DIAGASSERT(retval != NULL);
1936 _DIAGASSERT(pw != NULL);
1937 _DIAGASSERT(buffer != NULL);
1938 _DIAGASSERT(state != NULL);
1939 /* name may be NULL */
1940
1941 *retval = 0;
1942
1943 if (state->db == NULL) {
1944 rv = _compat_start(state);
1945 if (rv != NS_SUCCESS)
1946 return rv;
1947 }
1948 if (buflen <= 1) { /* buffer too small */
1949 *retval = ERANGE;
1950 return NS_UNAVAIL;
1951 }
1952
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];
1960
1961 switch (state->mode) {
1962
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;
1970
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;
1979 }
1980 if (!user || !*user)
1981 break;
1982 rv = _passwdcompat_pwscan(&cpw,
1983 cbuf, sizeof(cbuf),
1984 _PW_KEYBYNAME, user, 0);
1985 break;
1986
1987 case COMPAT_USER:
1988 /* get specific user */
1989 if (state->user == NULL) {
1990 state->mode = COMPAT_NONE;
1991 break;
1992 }
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;
2000
2001 case COMPAT_NOTOKEN:
2002 case COMPAT_NONE:
2003 abort();
2004
2005 }
2006 if (rv != NS_SUCCESS) /* if not matched, next loop */
2007 continue;
2008
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;
2014 }
2015
2016 if (_compat_is_excluded(state, pw->pw_name))
2017 continue; /* excluded; next loop */
2018
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 */
2023 }
2024
2025 break; /* exit loop if found */
2026 } else { /* not a compat line */
2027 state->proto.pw_name = NULL;
2028 /* clear prototype */
2029 }
2030
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();
2051 }
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;
2061 }
2062
2063 if (buflen <= fromlen) { /* buffer too small */
2064 *retval = ERANGE;
2065 return NS_UNAVAIL;
2066 }
2067 memmove(buffer + 1, from, fromlen); /* setup key */
2068 key.size = fromlen + 1;
2069 key.data = (u_char *)buffer;
2070
2071 rv = _pw_getkey(state->db, &key, pw, buffer, buflen, &pwflags,
2072 state->version);
2073 if (rv != NS_SUCCESS) /* stop on error */
2074 break;
2075
2076 if (state->mode == COMPAT_NOTOKEN)
2077 break; /* stop if no compat token */
2078
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;
2100 }
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;
2107 }
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;
2124 }
2125 }
2126 endnetgrent();
2127 break;
2128 default: /* `-name' */
2129 if (! _compat_add_exclude(state,
2130 pw->pw_name + 1)) {
2131 rv = NS_UNAVAIL;
2132 }
2133 break;
2134 }
2135 if (rv != NS_SUCCESS) /* exclusion failure */
2136 break;
2137 continue; /* loop again after exclusion */
2138 }
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 */
2143 }
2144
2145 if (rv == NS_NOTFOUND &&
2146 (search == _PW_KEYBYNUM || state->mode != COMPAT_NOTOKEN))
2147 state->keynum = -1; /* flag `no more records' */
2148
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;
2153 }
2154
2155 if (rv != NS_SUCCESS && rv != NS_NOTFOUND)
2156 *retval = errno;
2157 return rv;
2158 }
2159
2160 /*ARGSUSED*/
2161 static int
2162 _compat_setpwent(void *nsrv, void *nscb, va_list ap)
2163 {
2164
2165 /* force passwd_compat setpwent() */
2166 (void) _passwdcompat_setpassent(0);
2167
2168 /* reset state, keep db open */
2169 _compat_state.stayopen = 0;
2170 return _compat_start(&_compat_state);
2171 }
2172
2173 /*ARGSUSED*/
2174 static int
2175 _compat_setpassent(void *nsrv, void *nscb, va_list ap)
2176 {
2177 int *retval = va_arg(ap, int *);
2178 int stayopen = va_arg(ap, int);
2179
2180 int rv;
2181
2182 /* force passwd_compat setpassent() */
2183 (void) _passwdcompat_setpassent(stayopen);
2184
2185 _compat_state.stayopen = stayopen;
2186 rv = _compat_start(&_compat_state);
2187 *retval = (rv == NS_SUCCESS);
2188 return rv;
2189 }
2190
2191 /*ARGSUSED*/
2192 static int
2193 _compat_endpwent(void *nsrv, void *nscb, va_list ap)
2194 {
2195
2196 /* force passwd_compat endpwent() */
2197 (void) _passwdcompat_endpwent();
2198
2199 /* reset state, close db */
2200 _compat_state.stayopen = 0;
2201 return _compat_end(&_compat_state);
2202 }
2203
2204
2205 /*ARGSUSED*/
2206 static int
2207 _compat_getpwent(void *nsrv, void *nscb, va_list ap)
2208 {
2209 struct passwd **retval = va_arg(ap, struct passwd **);
2210
2211 int rv, rerror;
2212
2213 _DIAGASSERT(retval != NULL);
2214
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;
2222 }
2223
2224 /*ARGSUSED*/
2225 static int
2226 _compat_getpwent_r(void *nsrv, void *nscb, va_list ap)
2227 {
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 **);
2233
2234 int rv;
2235
2236 _DIAGASSERT(retval != NULL);
2237 _DIAGASSERT(pw != NULL);
2238 _DIAGASSERT(buffer != NULL);
2239 _DIAGASSERT(result != NULL);
2240
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;
2248 }
2249
2250
2251 /*ARGSUSED*/
2252 static int
2253 _compat_getpwnam(void *nsrv, void *nscb, va_list ap)
2254 {
2255 struct passwd **retval = va_arg(ap, struct passwd **);
2256 const char *name = va_arg(ap, const char *);
2257
2258 int rv, rerror;
2259
2260 _DIAGASSERT(retval != NULL);
2261
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;
2274 }
2275
2276 /*ARGSUSED*/
2277 static int
2278 _compat_getpwnam_r(void *nsrv, void *nscb, va_list ap)
2279 {
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 **);
2286
2287 struct compat_state state;
2288 int rv;
2289
2290 _DIAGASSERT(retval != NULL);
2291 _DIAGASSERT(pw != NULL);
2292 _DIAGASSERT(buffer != NULL);
2293 _DIAGASSERT(result != NULL);
2294
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;
2303 }
2304
2305 /*ARGSUSED*/
2306 static int
2307 _compat_getpwuid(void *nsrv, void *nscb, va_list ap)
2308 {
2309 struct passwd **retval = va_arg(ap, struct passwd **);
2310 uid_t uid = va_arg(ap, uid_t);
2311
2312 int rv, rerror;
2313
2314 _DIAGASSERT(retval != NULL);
2315
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;
2328 }
2329
2330 /*ARGSUSED*/
2331 static int
2332 _compat_getpwuid_r(void *nsrv, void *nscb, va_list ap)
2333 {
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 **);
2340
2341 struct compat_state state;
2342 int rv;
2343
2344 _DIAGASSERT(retval != NULL);
2345 _DIAGASSERT(pw != NULL);
2346 _DIAGASSERT(buffer != NULL);
2347 _DIAGASSERT(result != NULL);
2348
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;
2357 }
2358
2359 #endif /* _PASSWD_COMPAT */
2360
2361
2362 /*
2363 * public functions
2364 */
2365
2366 struct passwd *
2367 getpwent(void)
2368 {
2369 int r;
2370 struct passwd *retval;
2371
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
2378 };
2379
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;
2385 }
2386
2387 int
2388 getpwent_r(struct passwd *pwd, char *buffer, size_t buflen,
2389 struct passwd **result)
2390 {
2391 int r, retval;
2392
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
2399 };
2400
2401 _DIAGASSERT(pwd != NULL);
2402 _DIAGASSERT(buffer != NULL);
2403 _DIAGASSERT(result != NULL);
2404
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;
2417 }
2418 }
2419
2420
2421 struct passwd *
2422 getpwnam(const char *name)
2423 {
2424 int rv;
2425 struct passwd *retval;
2426
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
2433 };
2434
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;
2440 }
2441
2442 int
2443 getpwnam_r(const char *name, struct passwd *pwd, char *buffer, size_t buflen,
2444 struct passwd **result)
2445 {
2446 int r, retval;
2447
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
2454 };
2455
2456 _DIAGASSERT(name != NULL);
2457 _DIAGASSERT(pwd != NULL);
2458 _DIAGASSERT(buffer != NULL);
2459 _DIAGASSERT(result != NULL);
2460
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;
2473 }
2474 }
2475
2476 struct passwd *
2477 getpwuid(uid_t uid)
2478 {
2479 int rv;
2480 struct passwd *retval;
2481
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
2488 };
2489
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;
2495 }
2496
2497 int
2498 getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, size_t buflen,
2499 struct passwd **result)
2500 {
2501 int r, retval;
2502
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
2509 };
2510
2511 _DIAGASSERT(pwd != NULL);
2512 _DIAGASSERT(buffer != NULL);
2513 _DIAGASSERT(result != NULL);
2514
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;
2527 }
2528 }
2529
2530 void
2531 endpwent(void)
2532 {
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
2539 };
2540
2541 mutex_lock(&_pwmutex);
2542 /* force all endpwent() methods */
2543 (void) nsdispatch(NULL, dtab, NSDB_PASSWD, "endpwent",
2544 __nsdefaultcompat_forceall);
2545 mutex_unlock(&_pwmutex);
2546 }
2547
2548 /*ARGSUSED*/
2549 int
2550 setpassent(int stayopen)
2551 {
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
2558 };
2559 int rv, retval;
2560
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;
2567 }
2568
2569 void
2570 setpwent(void)
2571 {
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
2578 };
2579
2580 mutex_lock(&_pwmutex);
2581 /* force all setpwent() methods */
2582 (void) nsdispatch(NULL, dtab, NSDB_PASSWD, "setpwent",
2583 __nsdefaultcompat_forceall);
2584 mutex_unlock(&_pwmutex);
2585 }
2586