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