Annotation of src/lib/libc/gen/getpwent.c, Revision 1.62
1.62 ! lukem 1: /* $NetBSD: getpwent.c,v 1.61 2004/10/24 14:46:23 lukem Exp $ */
1.57 lukem 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: */
1.12 cgd 38:
1.1 cgd 39: /*
1.12 cgd 40: * Copyright (c) 1988, 1993
41: * The Regents of the University of California. All rights reserved.
1.54 agc 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: /*
1.14 phil 69: * Portions Copyright (c) 1994, 1995, Jason Downs. All rights reserved.
1.1 cgd 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: *
1.55 agc 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
1.1 cgd 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:
1.22 christos 93: #include <sys/cdefs.h>
1.1 cgd 94: #if defined(LIBC_SCCS) && !defined(lint)
1.12 cgd 95: #if 0
1.24 perry 96: static char sccsid[] = "@(#)getpwent.c 8.2 (Berkeley) 4/27/95";
1.12 cgd 97: #else
1.62 ! lukem 98: __RCSID("$NetBSD: getpwent.c,v 1.61 2004/10/24 14:46:23 lukem Exp $");
1.12 cgd 99: #endif
1.1 cgd 100: #endif /* LIBC_SCCS and not lint */
101:
1.23 jtc 102: #include "namespace.h"
1.62 ! lukem 103: #include "reentrant.h"
! 104:
1.1 cgd 105: #include <sys/param.h>
1.45 lukem 106:
107: #include <assert.h>
1.1 cgd 108: #include <db.h>
109: #include <errno.h>
1.45 lukem 110: #include <fcntl.h>
1.1 cgd 111: #include <limits.h>
1.14 phil 112: #include <netgroup.h>
1.32 lukem 113: #include <nsswitch.h>
1.45 lukem 114: #include <pwd.h>
1.51 wiz 115: #include <stdarg.h>
1.56 lukem 116: #include <stdio.h>
1.45 lukem 117: #include <stdlib.h>
118: #include <string.h>
119: #include <syslog.h>
120: #include <unistd.h>
121:
1.32 lukem 122: #ifdef HESIOD
123: #include <hesiod.h>
124: #endif
1.57 lukem 125:
1.4 deraadt 126: #ifdef YP
1.14 phil 127: #include <machine/param.h>
1.4 deraadt 128: #include <rpc/rpc.h>
129: #include <rpcsvc/yp_prot.h>
130: #include <rpcsvc/ypclnt.h>
1.23 jtc 131: #endif
132:
1.27 thorpej 133: #include "pw_private.h"
134:
1.57 lukem 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 ? */
1.40 lukem 138:
1.23 jtc 139: #ifdef __weak_alias
1.46 mycroft 140: __weak_alias(endpwent,_endpwent)
141: __weak_alias(getpwent,_getpwent)
142: __weak_alias(getpwnam,_getpwnam)
1.57 lukem 143: __weak_alias(getpwnam_r,_getpwnam_r)
1.46 mycroft 144: __weak_alias(getpwuid,_getpwuid)
1.57 lukem 145: __weak_alias(getpwuid_r,_getpwuid_r)
1.46 mycroft 146: __weak_alias(setpassent,_setpassent)
147: __weak_alias(setpwent,_setpwent)
1.4 deraadt 148: #endif
1.1 cgd 149:
1.61 lukem 150: #ifdef _REENTRANT
151: static mutex_t _pwmutex = MUTEX_INITIALIZER;
152: #endif
153:
1.57 lukem 154: const char __yp_token[] = "__YP!"; /* Let pwd_mkdb pull this in. */
1.24 perry 155:
1.57 lukem 156: static const ns_src defaultcompat[] = {
157: { NSSRC_FILES, NS_SUCCESS },
158: { 0 }
159: };
1.24 perry 160:
1.57 lukem 161: static const ns_src defaultcompat_forceall[] = {
162: { NSSRC_FILES, NS_SUCCESS | NS_FORCEALL },
163: { 0 }
164: };
1.32 lukem 165:
1.57 lukem 166: static const ns_src defaultnis[] = {
167: { NSSRC_NIS, NS_SUCCESS },
168: { 0 }
169: };
1.14 phil 170:
1.57 lukem 171: static const ns_src defaultnis_forceall[] = {
172: { NSSRC_NIS, NS_SUCCESS | NS_FORCEALL },
1.36 lukem 173: { 0 }
174: };
1.1 cgd 175:
1.32 lukem 176:
1.57 lukem 177: /*
178: * The pwd.db lookup techniques and data extraction code here must be kept
179: * in sync with that in `pwd_mkdb'.
180: */
1.26 lukem 181:
1.60 lukem 182: #if defined(YP) || defined(HESIOD)
1.32 lukem 183: /*
1.57 lukem 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.
1.32 lukem 189: */
1.14 phil 190: static int
1.57 lukem 191: _pw_parse(const char *entry, struct passwd *pw, char *buf, size_t buflen,
192: int old)
1.14 phil 193: {
1.57 lukem 194: int flags;
1.14 phil 195:
1.57 lukem 196: _DIAGASSERT(entry != NULL);
197: _DIAGASSERT(pw != NULL);
198: _DIAGASSERT(buf != NULL);
1.45 lukem 199:
1.57 lukem 200: if (strlcpy(buf, entry, buflen) >= buflen)
201: return 0;
1.59 lukem 202: flags = _PASSWORD_NOWARN;
1.57 lukem 203: if (old)
204: flags |= _PASSWORD_OLDFMT;
205: return __pw_scan(buf, pw, &flags);
1.14 phil 206: }
1.60 lukem 207: #endif /* YP || HESIOD */
1.14 phil 208:
1.32 lukem 209: /*
1.57 lukem 210: * _pw_opendb
211: * if *db is NULL, dbopen(3) /etc/spwd.db or /etc/pwd.db (depending
212: * upon permissions, etc)
1.32 lukem 213: */
1.14 phil 214: static int
1.57 lukem 215: _pw_opendb(DB **db)
1.14 phil 216: {
1.57 lukem 217: static int warned;
1.14 phil 218:
1.57 lukem 219: const char *dbfile;
1.45 lukem 220:
1.57 lukem 221: _DIAGASSERT(db != NULL);
222: if (*db != NULL) /* open *db */
223: return NS_SUCCESS;
1.14 phil 224:
1.57 lukem 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;
1.14 phil 243: }
244:
1.32 lukem 245: /*
1.57 lukem 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.)
1.32 lukem 251: */
1.57 lukem 252: static int
253: _pw_getkey(DB *db, DBT *key,
254: struct passwd *pw, char *buffer, size_t buflen, int *pwflags)
1.14 phil 255: {
1.57 lukem 256: char *p, *t;
257: DBT data;
1.14 phil 258:
1.57 lukem 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 */
1.14 phil 264:
1.57 lukem 265: if (db == NULL) /* this shouldn't happen */
266: return NS_UNAVAIL;
1.14 phil 267:
1.57 lukem 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: }
1.14 phil 278:
1.57 lukem 279: p = (char *)data.data;
280: if (data.size > buflen) {
281: errno = ERANGE;
282: return NS_UNAVAIL;
283: }
1.14 phil 284:
1.57 lukem 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: }
1.14 phil 309:
1.57 lukem 310: return NS_SUCCESS;
1.14 phil 311: }
1.4 deraadt 312:
1.57 lukem 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)
1.26 lukem 321: {
1.57 lukem 322: char *rv;
1.26 lukem 323:
1.57 lukem 324: if (want > *buflen) {
325: errno = ERANGE;
326: return NULL;
327: }
328: rv = *buffer;
329: *buffer += want;
330: *buflen -= want;
331: return rv;
1.26 lukem 332: }
333:
1.32 lukem 334: /*
1.57 lukem 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.
1.32 lukem 341: */
1.26 lukem 342: static int
1.57 lukem 343: _pw_copy(const struct passwd *frompw, struct passwd *pw,
344: char *buf, size_t buflen, const struct passwd *protopw, int protoflags)
1.4 deraadt 345: {
1.57 lukem 346: size_t count;
347: int useproto;
1.4 deraadt 348:
1.57 lukem 349: _DIAGASSERT(frompw != NULL);
1.45 lukem 350: _DIAGASSERT(pw != NULL);
1.57 lukem 351: _DIAGASSERT(buf != NULL);
352: /* protopw may be NULL */
1.45 lukem 353:
1.57 lukem 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);
1.14 phil 372:
1.32 lukem 373: #ifdef PW_OVERRIDE_PASSWD
1.57 lukem 374: COPYPROTOFIELD(pw_passwd);
375: #else
376: COPYFIELD(pw_passwd);
1.14 phil 377: #endif
1.26 lukem 378:
1.57 lukem 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;
1.4 deraadt 400: }
1.32 lukem 401:
1.4 deraadt 402:
1.57 lukem 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:
1.32 lukem 419: static int
1.57 lukem 420: _files_start(struct files_state *state)
1.1 cgd 421: {
1.57 lukem 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: }
1.1 cgd 432:
1.57 lukem 433: static int
434: _files_end(struct files_state *state)
435: {
1.32 lukem 436:
1.57 lukem 437: _DIAGASSERT(state != NULL);
1.32 lukem 438:
1.57 lukem 439: state->keynum = 0;
440: if (state->db) {
441: (void)(state->db->close)(state->db);
442: state->db = NULL;
1.32 lukem 443: }
1.57 lukem 444: return NS_SUCCESS;
1.32 lukem 445: }
446:
447: /*
1.57 lukem 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.
1.32 lukem 454: */
455: static int
1.57 lukem 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)
1.32 lukem 458: {
1.57 lukem 459: const void *from;
460: size_t fromlen;
461: DBT key;
462: int rv;
1.39 lukem 463:
1.57 lukem 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: }
1.32 lukem 498:
1.57 lukem 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: }
1.32 lukem 519: break;
520: }
521:
1.57 lukem 522: if (rv == NS_NOTFOUND && search == _PW_KEYBYNUM)
523: state->keynum = -1; /* flag `no more records' */
1.39 lukem 524:
1.57 lukem 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;
1.32 lukem 529: }
530:
1.57 lukem 531: filespwscan_out:
532: if (rv != NS_SUCCESS)
533: *retval = errno;
534: return rv;
1.32 lukem 535: }
1.1 cgd 536:
1.57 lukem 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: }
1.14 phil 545:
1.37 christos 546: /*ARGSUSED*/
1.32 lukem 547: static int
1.57 lukem 548: _files_setpassent(void *nsrv, void *nscb, va_list ap)
1.32 lukem 549: {
1.57 lukem 550: int *retval = va_arg(ap, int *);
551: int stayopen = va_arg(ap, int);
1.32 lukem 552:
1.57 lukem 553: int rv;
1.32 lukem 554:
1.57 lukem 555: _files_state.stayopen = stayopen;
556: rv = _files_start(&_files_state);
557: *retval = (rv == NS_SUCCESS);
558: return rv;
559: }
1.32 lukem 560:
1.57 lukem 561: /*ARGSUSED*/
562: static int
563: _files_endpwent(void *nsrv, void *nscb, va_list ap)
564: {
1.32 lukem 565:
1.57 lukem 566: _files_state.stayopen = 0;
567: return _files_end(&_files_state);
568: }
1.32 lukem 569:
1.57 lukem 570: /*ARGSUSED*/
1.32 lukem 571: static int
1.57 lukem 572: _files_getpwent(void *nsrv, void *nscb, va_list ap)
1.32 lukem 573: {
1.57 lukem 574: struct passwd **retval = va_arg(ap, struct passwd **);
1.32 lukem 575:
1.57 lukem 576: int rv, rerror;
1.32 lukem 577:
1.57 lukem 578: _DIAGASSERT(retval != NULL);
1.32 lukem 579:
1.57 lukem 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;
1.32 lukem 587: }
588:
1.37 christos 589: /*ARGSUSED*/
1.32 lukem 590: static int
1.57 lukem 591: _files_getpwnam(void *nsrv, void *nscb, va_list ap)
1.32 lukem 592: {
1.57 lukem 593: struct passwd **retval = va_arg(ap, struct passwd **);
594: const char *name = va_arg(ap, const char *);
595:
596: int rv, rerror;
1.45 lukem 597:
1.57 lukem 598: _DIAGASSERT(retval != NULL);
1.45 lukem 599:
1.57 lukem 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;
1.32 lukem 612: }
613:
1.57 lukem 614: /*ARGSUSED*/
1.32 lukem 615: static int
1.57 lukem 616: _files_getpwnam_r(void *nsrv, void *nscb, va_list ap)
1.32 lukem 617: {
1.57 lukem 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);
1.32 lukem 632:
1.57 lukem 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;
1.32 lukem 641: }
642:
1.37 christos 643: /*ARGSUSED*/
1.32 lukem 644: static int
1.57 lukem 645: _files_getpwuid(void *nsrv, void *nscb, va_list ap)
1.32 lukem 646: {
1.57 lukem 647: struct passwd **retval = va_arg(ap, struct passwd **);
648: uid_t uid = va_arg(ap, uid_t);
1.32 lukem 649:
1.57 lukem 650: int rv, rerror;
1.32 lukem 651:
1.57 lukem 652: _DIAGASSERT(retval != NULL);
1.32 lukem 653:
1.57 lukem 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)
1.14 phil 778: break;
1.57 lukem 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);
1.32 lukem 906:
1.57 lukem 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:
1.14 phil 1067: break;
1.57 lukem 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;
1.32 lukem 1078:
1.57 lukem 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];
1.4 deraadt 1156: }
1.57 lukem 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 */
1.58 lukem 1279: nisr = yp_next(_nis_state.domain, PASSWD_BYNAME(&_nis_state),
1.57 lukem 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;
1.14 phil 1289: break;
1.57 lukem 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 */
1.58 lukem 1298: if (yp_first(_nis_state.domain, PASSWD_BYNAME(&_nis_state),
1.57 lukem 1299: &_nis_state.current, &_nis_state.currentlen,
1300: &data, &datalen)) {
1301: rv = NS_UNAVAIL;
1302: goto nisent_out;
1.4 deraadt 1303: }
1304: }
1305:
1.57 lukem 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,
1.58 lukem 1341: _nis_passwdbuf, sizeof(_nis_passwdbuf),
1342: &_nis_state, PASSWD_BYUID(&_nis_state));
1.57 lukem 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));
1.59 lukem 1371: rv = _nis_start(&state);
1372: if (rv != NS_SUCCESS)
1373: return rv;
1.57 lukem 1374: snprintf(buffer, buflen, "%u", (unsigned int)uid);
1.58 lukem 1375: rv = _nis_pwscan(retval, pw, buffer, buflen,
1376: &state, PASSWD_BYUID(&state));
1.57 lukem 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,
1.58 lukem 1404: _nis_passwdbuf, sizeof(_nis_passwdbuf),
1405: &_nis_state, PASSWD_BYNAME(&_nis_state));
1.57 lukem 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));
1.59 lukem 1435: rv = _nis_start(&state);
1436: if (rv != NS_SUCCESS)
1437: return rv;
1.58 lukem 1438: rv = _nis_pwscan(retval, pw, buffer, buflen,
1439: &state, PASSWD_BYNAME(&state));
1.57 lukem 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:
1.40 lukem 1453: #ifdef _PASSWD_COMPAT
1.57 lukem 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);
1.14 phil 1614:
1.57 lukem 1615: if (!warned) {
1616: syslog(LOG_ERR,
1617: "nsswitch.conf passwd_compat database can't use '%s'",
1618: (char *)nscb);
1.4 deraadt 1619: }
1.57 lukem 1620: warned = 1;
1621: return NS_UNAVAIL;
1.1 cgd 1622: }
1623:
1.14 phil 1624: /*
1.57 lukem 1625: * _passwdcompat_setpassent
1626: * Call setpassent for all passwd_compat sources.
1.14 phil 1627: */
1.57 lukem 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: };
1.32 lukem 1638:
1.57 lukem 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: */
1.14 phil 1650: static int
1.57 lukem 1651: _passwdcompat_endpwent(void)
1.14 phil 1652: {
1.57 lukem 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: }
1.34 lukem 1664:
1.57 lukem 1665: /*
1.60 lukem 1666: * _passwdcompat_pwscan
1.57 lukem 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
1.60 lukem 1673: _passwdcompat_pwscan(struct passwd *pw, char *buffer, size_t buflen,
1.57 lukem 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: };
1.34 lukem 1697:
1.57 lukem 1698: int rv, crv;
1699: struct passwd *cpw;
1.32 lukem 1700:
1701: switch (search) {
1.57 lukem 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;
1.32 lukem 1713: case _PW_KEYBYNAME:
1.57 lukem 1714: _DIAGASSERT(name != NULL);
1715: rv = nsdispatch(NULL, compatnamdtab,
1716: NSDB_PASSWD_COMPAT, "getpwnam_r", defaultnis,
1717: &crv, name, pw, buffer, buflen, &cpw);
1.32 lukem 1718: break;
1719: case _PW_KEYBYUID:
1.57 lukem 1720: rv = nsdispatch(NULL, compatuiddtab,
1721: NSDB_PASSWD_COMPAT, "getpwuid_r", defaultnis,
1722: &crv, uid, pw, buffer, buflen, &cpw);
1.32 lukem 1723: break;
1724: default:
1725: abort();
1.57 lukem 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;
1.32 lukem 1765: }
1.14 phil 1766:
1.57 lukem 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 */
1.60 lukem 1779: rv = _passwdcompat_pwscan(&cpw,
1.57 lukem 1780: cbuf, sizeof(cbuf),
1781: _PW_KEYBYNUM, NULL, 0);
1782: if (rv != NS_SUCCESS)
1783: state->mode = COMPAT_NONE;
1.10 deraadt 1784: break;
1.57 lukem 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 */
1.34 lukem 1791: endnetgrent();
1.57 lukem 1792: state->mode = COMPAT_NONE;
1793: break;
1.34 lukem 1794: }
1795: if (!user || !*user)
1.57 lukem 1796: break;
1.60 lukem 1797: rv = _passwdcompat_pwscan(&cpw,
1.57 lukem 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: }
1.60 lukem 1808: rv = _passwdcompat_pwscan(&cpw,
1.57 lukem 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: }
1.32 lukem 1830:
1.57 lukem 1831: if (_compat_is_excluded(state, pw->pw_name))
1832: continue; /* excluded; next loop */
1.32 lukem 1833:
1.57 lukem 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);
1.34 lukem 1863: break;
1864: default:
1.57 lukem 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 */
1.34 lukem 1892:
1.57 lukem 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);
1.14 phil 1913: break;
1.34 lukem 1914: }
1.57 lukem 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;
1.34 lukem 1921: }
1.57 lukem 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': /* `-' */
1.34 lukem 1928: break;
1.57 lukem 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: }
1.14 phil 1939: }
1.34 lukem 1940: endnetgrent();
1.14 phil 1941: break;
1.57 lukem 1942: default: /* `-name' */
1943: if (! _compat_add_exclude(state,
1944: pw->pw_name + 1)) {
1945: rv = NS_UNAVAIL;
1946: }
1.32 lukem 1947: break;
1.4 deraadt 1948: }
1.57 lukem 1949: if (rv != NS_SUCCESS) /* exclusion failure */
1950: break;
1951: continue; /* loop again after exclusion */
1.4 deraadt 1952: }
1.57 lukem 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 */
1.4 deraadt 1957: }
1.1 cgd 1958:
1.57 lukem 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;
1.1 cgd 1967: }
1.57 lukem 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:
1.40 lukem 2146: #endif /* _PASSWD_COMPAT */
1.57 lukem 2147:
2148:
2149: /*
2150: * public functions
2151: */
1.1 cgd 2152:
2153: struct passwd *
1.57 lukem 2154: getpwent(void)
1.1 cgd 2155: {
1.32 lukem 2156: int r;
1.57 lukem 2157: struct passwd *retval;
2158:
1.36 lukem 2159: static const ns_dtab dtab[] = {
1.57 lukem 2160: NS_FILES_CB(_files_getpwent, NULL)
2161: NS_DNS_CB(_dns_getpwent, NULL)
2162: NS_NIS_CB(_nis_getpwent, NULL)
1.35 lukem 2163: NS_COMPAT_CB(_compat_getpwent, NULL)
2164: { 0 }
1.32 lukem 2165: };
2166:
1.61 lukem 2167: mutex_lock(&_pwmutex);
1.57 lukem 2168: r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwent", defaultcompat,
2169: &retval);
1.61 lukem 2170: mutex_unlock(&_pwmutex);
1.57 lukem 2171: return (r == NS_SUCCESS) ? retval : NULL;
1.32 lukem 2172: }
1.10 deraadt 2173:
1.32 lukem 2174: struct passwd *
1.57 lukem 2175: getpwnam(const char *name)
1.32 lukem 2176: {
1.57 lukem 2177: int rv;
2178: struct passwd *retval;
2179:
1.36 lukem 2180: static const ns_dtab dtab[] = {
1.57 lukem 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)
1.35 lukem 2185: { 0 }
1.32 lukem 2186: };
1.4 deraadt 2187:
1.61 lukem 2188: mutex_lock(&_pwmutex);
1.57 lukem 2189: rv = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwnam", defaultcompat,
2190: &retval, name);
1.61 lukem 2191: mutex_unlock(&_pwmutex);
1.57 lukem 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: };
1.4 deraadt 2208:
1.57 lukem 2209: _DIAGASSERT(name != NULL);
2210: _DIAGASSERT(pwd != NULL);
2211: _DIAGASSERT(buffer != NULL);
2212: _DIAGASSERT(result != NULL);
2213:
2214: *result = NULL;
2215: retval = 0;
1.61 lukem 2216: mutex_lock(&_pwmutex);
1.57 lukem 2217: r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwnam_r", defaultcompat,
2218: &retval, name, pwd, buffer, buflen, result);
1.61 lukem 2219: mutex_unlock(&_pwmutex);
1.57 lukem 2220: return (r == NS_SUCCESS) ? 0 : retval ? retval : ENOENT;
1.32 lukem 2221: }
1.14 phil 2222:
1.32 lukem 2223: struct passwd *
1.57 lukem 2224: getpwuid(uid_t uid)
1.32 lukem 2225: {
1.57 lukem 2226: int rv;
2227: struct passwd *retval;
2228:
1.36 lukem 2229: static const ns_dtab dtab[] = {
1.57 lukem 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)
1.35 lukem 2234: { 0 }
1.32 lukem 2235: };
1.1 cgd 2236:
1.61 lukem 2237: mutex_lock(&_pwmutex);
1.57 lukem 2238: rv = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwuid", defaultcompat,
2239: &retval, uid);
1.61 lukem 2240: mutex_unlock(&_pwmutex);
1.57 lukem 2241: return (rv == NS_SUCCESS) ? retval : NULL;
1.1 cgd 2242: }
2243:
2244: int
1.57 lukem 2245: getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, size_t buflen,
2246: struct passwd **result)
1.1 cgd 2247: {
1.57 lukem 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;
1.61 lukem 2264: mutex_lock(&_pwmutex);
1.57 lukem 2265: r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwuid_r", defaultcompat,
2266: &retval, uid, pwd, buffer, buflen, result);
1.61 lukem 2267: mutex_unlock(&_pwmutex);
1.57 lukem 2268: return (r == NS_SUCCESS) ? 0 : retval ? retval : ENOENT;
1.1 cgd 2269: }
2270:
1.8 jtc 2271: void
1.57 lukem 2272: endpwent(void)
1.1 cgd 2273: {
1.57 lukem 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: };
1.1 cgd 2281:
1.61 lukem 2282: mutex_lock(&_pwmutex);
1.57 lukem 2283: /* force all endpwent() methods */
2284: (void) nsdispatch(NULL, dtab, NSDB_PASSWD, "endpwent",
2285: defaultcompat_forceall);
1.61 lukem 2286: mutex_unlock(&_pwmutex);
1.1 cgd 2287: }
2288:
1.57 lukem 2289: /*ARGSUSED*/
2290: int
2291: setpassent(int stayopen)
1.1 cgd 2292: {
1.57 lukem 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;
1.1 cgd 2301:
1.61 lukem 2302: mutex_lock(&_pwmutex);
1.57 lukem 2303: /* force all setpassent() methods */
2304: rv = nsdispatch(NULL, dtab, NSDB_PASSWD, "setpassent",
2305: defaultcompat_forceall, &retval, stayopen);
1.61 lukem 2306: mutex_unlock(&_pwmutex);
1.57 lukem 2307: return (rv == NS_SUCCESS) ? retval : 0;
1.1 cgd 2308: }
2309:
1.57 lukem 2310: void
2311: setpwent(void)
1.1 cgd 2312: {
1.57 lukem 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: };
1.14 phil 2320:
1.61 lukem 2321: mutex_lock(&_pwmutex);
1.57 lukem 2322: /* force all setpwent() methods */
2323: (void) nsdispatch(NULL, dtab, NSDB_PASSWD, "setpwent",
2324: defaultcompat_forceall);
1.61 lukem 2325: mutex_unlock(&_pwmutex);
1.1 cgd 2326: }
CVSweb <webmaster@jp.NetBSD.org>