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