getpwent.c revision 113670
1113596Snectar/*-
2113596Snectar * Copyright (c) 2003 Networks Associates Technology, Inc.
3113596Snectar * All rights reserved.
41573Srgrimes *
5113596Snectar * This software was developed for the FreeBSD Project by
6113596Snectar * Jacques A. Vidrine, Safeport Network Services, and Network
7113596Snectar * Associates Laboratories, the Security Research Division of Network
8113596Snectar * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
9113596Snectar * ("CBOSS"), as part of the DARPA CHATS research program.
10113596Snectar *
111573Srgrimes * Redistribution and use in source and binary forms, with or without
121573Srgrimes * modification, are permitted provided that the following conditions
131573Srgrimes * are met:
141573Srgrimes * 1. Redistributions of source code must retain the above copyright
151573Srgrimes *    notice, this list of conditions and the following disclaimer.
161573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
171573Srgrimes *    notice, this list of conditions and the following disclaimer in the
181573Srgrimes *    documentation and/or other materials provided with the distribution.
191573Srgrimes *
20113596Snectar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
211573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23113596Snectar * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
241573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301573Srgrimes * SUCH DAMAGE.
31113596Snectar *
321573Srgrimes */
3390016Sbde#include <sys/cdefs.h>
3489999Sobrien__FBSDID("$FreeBSD: head/lib/libc/gen/getpwent.c 113670 2003-04-18 16:24:25Z nectar $");
351573Srgrimes
36113596Snectar#include "namespace.h"
371573Srgrimes#include <sys/param.h>
38113596Snectar#ifdef YP
39113596Snectar#include <rpc/rpc.h>
40113596Snectar#include <rpcsvc/yp_prot.h>
41113596Snectar#include <rpcsvc/ypclnt.h>
42113596Snectar#endif
43113596Snectar#include <arpa/inet.h>
44113596Snectar#include <errno.h>
451573Srgrimes#include <fcntl.h>
4665532Snectar#ifdef HESIOD
4765532Snectar#include <hesiod.h>
4865532Snectar#endif
49113596Snectar#include <netdb.h>
50113596Snectar#include <nsswitch.h>
51113596Snectar#include <pthread.h>
52113596Snectar#include <pthread_np.h>
53113596Snectar#include <pwd.h>
54113596Snectar#include <stdlib.h>
5565532Snectar#include <stdio.h>
56113596Snectar#include <string.h>
57113596Snectar#include <syslog.h>
58113596Snectar#include <unistd.h>
5971579Sdeischen#include "un-namespace.h"
60113596Snectar#include <db.h>
61111618Snectar#include "libc_private.h"
6265532Snectar#include "pw_scan.h"
63113596Snectar#include "nss_tls.h"
6465532Snectar
65113596Snectar#ifndef CTASSERT
66113596Snectar#define CTASSERT(x)		_CTASSERT(x, __LINE__)
67113596Snectar#define _CTASSERT(x, y)		__CTASSERT(x, y)
68113596Snectar#define __CTASSERT(x, y)	typedef char __assert_ ## y [(x) ? 1 : -1]
6965532Snectar#endif
7065532Snectar
71113596Snectar/* Counter as stored in /etc/pwd.db */
72113596Snectartypedef	int		pwkeynum;
7323668Speter
74113596SnectarCTASSERT(MAXLOGNAME > sizeof(uid_t));
75113596SnectarCTASSERT(MAXLOGNAME > sizeof(pwkeynum));
7665532Snectar
77113596Snectarenum constants {
78113596Snectar	PWD_STORAGE_INITIAL	= 1 << 10, /* 1 KByte */
79113596Snectar	PWD_STORAGE_MAX		= 1 << 20, /* 1 MByte */
80113596Snectar	SETPWENT		= 1,
81113596Snectar	ENDPWENT		= 2,
82113596Snectar	HESIOD_NAME_MAX		= 256
83113596Snectar};
8465532Snectar
85113596Snectarstatic const ns_src defaultsrc[] = {
86113643Snectar	{ NSSRC_COMPAT, NS_SUCCESS },
87113596Snectar	{ NULL, 0 }
8865532Snectar};
8965532Snectar
90113596Snectarint	__pw_match_entry(const char *, size_t, enum nss_lookup_type,
91113596Snectar	    const char *, uid_t);
92113596Snectarint	__pw_parse_entry(char *, size_t, struct passwd *, int, int *errnop);
9315267Swpaul
94113596Snectarunion key {
95113596Snectar	const char	*name;
96113596Snectar	uid_t		 uid;
97113596Snectar};
98113596Snectar
99113596Snectarstatic	struct passwd *getpw(int (*fn)(union key, struct passwd *, char *,
100113596Snectar		    size_t, struct passwd **), union key);
101113596Snectarstatic	int	 wrap_getpwnam_r(union key, struct passwd *, char *,
102113596Snectar		    size_t, struct passwd **);
103113596Snectarstatic	int	 wrap_getpwuid_r(union key, struct passwd *, char *, size_t,
104113596Snectar		    struct passwd **);
105113596Snectarstatic	int	 wrap_getpwent_r(union key, struct passwd *, char *, size_t,
106113596Snectar		    struct passwd **);
107113596Snectar
108113596Snectarstatic	int	 pwdb_match_entry_v3(char *, size_t, enum nss_lookup_type,
109113596Snectar		    const char *, uid_t);
110113596Snectarstatic	int	 pwdb_parse_entry_v3(char *, size_t, struct passwd *, int *);
111113596Snectarstatic	int	 pwdb_match_entry_v4(char *, size_t, enum nss_lookup_type,
112113596Snectar		    const char *, uid_t);
113113596Snectarstatic	int	 pwdb_parse_entry_v4(char *, size_t, struct passwd *, int *);
114113596Snectar
115113596Snectar
116113596Snectarstruct {
117113596Snectar	int	(*match)(char *, size_t, enum nss_lookup_type, const char *,
118113596Snectar		    uid_t);
119113596Snectar	int	(*parse)(char *, size_t, struct passwd *, int *);
120113596Snectar} pwdb_versions[] = {
121113596Snectar	{ NULL, NULL },					/* version 0 */
122113596Snectar	{ NULL, NULL },					/* version 1 */
123113596Snectar	{ NULL, NULL },					/* version 2 */
124113596Snectar	{ pwdb_match_entry_v3, pwdb_parse_entry_v3 },	/* version 3 */
125113596Snectar	{ pwdb_match_entry_v4, pwdb_parse_entry_v4 },	/* version 4 */
126113596Snectar};
127113596Snectar
128113596Snectar
129113596Snectarstruct files_state {
130113596Snectar	DB		*db;
131113596Snectar	pwkeynum	 keynum;
132113596Snectar	int		 stayopen;
133113596Snectar	int		 version;
134113596Snectar};
135113596Snectarstatic	void	files_endstate(void *);
136113596SnectarNSS_TLS_HANDLING(files);
137113596Snectarstatic	DB	*pwdbopen(int *);
138113596Snectarstatic	void	 files_endstate(void *);
139113596Snectarstatic	int	 files_setpwent(void *, void *, va_list);
140113596Snectarstatic	int	 files_passwd(void *, void *, va_list);
141113596Snectar
142113596Snectar
14365532Snectar#ifdef HESIOD
144113596Snectarstruct dns_state {
145113596Snectar	long	counter;
146113596Snectar};
147113596Snectarstatic	void	dns_endstate(void *);
148113596SnectarNSS_TLS_HANDLING(dns);
149113596Snectarstatic	int	 dns_setpwent(void *, void *, va_list);
150113596Snectarstatic	int	 dns_passwd(void *, void *, va_list);
15111436Swpaul#endif
1522917Swollman
15365532Snectar
154113596Snectar#ifdef YP
155113596Snectarstruct nis_state {
156113596Snectar	char	 domain[MAXHOSTNAMELEN];
157113596Snectar	int	 done;
158113596Snectar	char	*key;
159113596Snectar	int	 keylen;
160113596Snectar};
161113596Snectarstatic	void	 nis_endstate(void *);
162113596SnectarNSS_TLS_HANDLING(nis);
163113596Snectarstatic	int	 nis_setpwent(void *, void *, va_list);
164113596Snectarstatic	int	 nis_passwd(void *, void *, va_list);
165113596Snectarstatic	int	 nis_map(char *, enum nss_lookup_type, char *, size_t, int *);
166113596Snectarstatic	int	 nis_adjunct(char *, const char *, char *, size_t);
167113596Snectar#endif
16865532Snectar
16965532Snectar
170113596Snectarstruct compat_state {
171113596Snectar	DB		*db;
172113596Snectar	pwkeynum	 keynum;
173113596Snectar	int		 stayopen;
174113596Snectar	int		 version;
175113596Snectar	DB		*exclude;
176113596Snectar	struct passwd	 template;
177113596Snectar	char		*name;
178113596Snectar	enum _compat {
179113596Snectar		COMPAT_MODE_OFF = 0,
180113596Snectar		COMPAT_MODE_ALL,
181113596Snectar		COMPAT_MODE_NAME,
182113596Snectar		COMPAT_MODE_NETGROUP
183113596Snectar	}		 compat;
184113596Snectar};
185113596Snectarstatic	void	 compat_endstate(void *);
186113596SnectarNSS_TLS_HANDLING(compat);
187113596Snectarstatic	int	 compat_setpwent(void *, void *, va_list);
188113596Snectarstatic	int	 compat_passwd(void *, void *, va_list);
189113596Snectarstatic	void	 compat_clear_template(struct passwd *);
190113596Snectarstatic	int	 compat_set_template(struct passwd *, struct passwd *);
191113596Snectarstatic	int	 compat_use_template(struct passwd *, struct passwd *, char *,
192113596Snectar		    size_t);
193113596Snectarstatic	int	 compat_redispatch(struct compat_state *, enum nss_lookup_type,
194113596Snectar		    enum nss_lookup_type, const char *, const char *, uid_t,
195113596Snectar		    struct passwd *, char *, size_t, int *);
196113596Snectarvoid
197113596Snectarsetpwent(void)
1981573Srgrimes{
199113596Snectar	static const ns_dtab dtab[] = {
200113596Snectar		{ NSSRC_FILES, files_setpwent, (void *)SETPWENT },
201113596Snectar#ifdef HESIOD
202113596Snectar		{ NSSRC_DNS, dns_setpwent, (void *)SETPWENT },
203113596Snectar#endif
204113596Snectar#ifdef YP
205113596Snectar		{ NSSRC_NIS, nis_setpwent, (void *)SETPWENT },
206113596Snectar#endif
207113596Snectar		{ NSSRC_COMPAT, compat_setpwent, (void *)SETPWENT },
208113596Snectar		{ NULL, NULL, NULL }
209113596Snectar	};
210113596Snectar	(void)_nsdispatch(NULL, dtab, NSDB_PASSWD, "setpwent", defaultsrc, 0);
211113596Snectar}
2121573Srgrimes
21310521Swpaul
214113596Snectarint
215113596Snectarsetpassent(int stayopen)
216113596Snectar{
217113596Snectar	static const ns_dtab dtab[] = {
218113596Snectar		{ NSSRC_FILES, files_setpwent, (void *)SETPWENT },
219113596Snectar#ifdef HESIOD
220113596Snectar		{ NSSRC_DNS, dns_setpwent, (void *)SETPWENT },
221113596Snectar#endif
222113596Snectar#ifdef YP
223113596Snectar		{ NSSRC_NIS, nis_setpwent, (void *)SETPWENT },
224113596Snectar#endif
225113596Snectar		{ NSSRC_COMPAT, compat_setpwent, (void *)SETPWENT },
226113596Snectar		{ NULL, NULL, NULL }
227113596Snectar	};
228113596Snectar	(void)_nsdispatch(NULL, dtab, NSDB_PASSWD, "setpwent", defaultsrc,
229113596Snectar	    stayopen);
230113596Snectar	return (1);
231113596Snectar}
23265532Snectar
23365532Snectar
234113596Snectarvoid
235113596Snectarendpwent(void)
236113596Snectar{
237113596Snectar	static const ns_dtab dtab[] = {
238113596Snectar		{ NSSRC_FILES, files_setpwent, (void *)ENDPWENT },
239113596Snectar#ifdef HESIOD
240113596Snectar		{ NSSRC_DNS, dns_setpwent, (void *)ENDPWENT },
241113596Snectar#endif
242113596Snectar#ifdef YP
243113596Snectar		{ NSSRC_NIS, nis_setpwent, (void *)ENDPWENT },
244113596Snectar#endif
245113596Snectar		{ NSSRC_COMPAT, compat_setpwent, (void *)ENDPWENT },
246113596Snectar		{ NULL, NULL, NULL }
247113596Snectar	};
248113596Snectar	(void)_nsdispatch(NULL, dtab, NSDB_PASSWD, "endpwent", defaultsrc);
2491573Srgrimes}
2501573Srgrimes
251113596Snectar
252113596Snectarint
253113596Snectargetpwent_r(struct passwd *pwd, char *buffer, size_t bufsize,
254113596Snectar    struct passwd **result)
2551573Srgrimes{
256113596Snectar	static const ns_dtab dtab[] = {
257113596Snectar		{ NSSRC_FILES, files_passwd, (void *)nss_lt_all },
258113596Snectar#ifdef HESIOD
259113596Snectar		{ NSSRC_DNS, dns_passwd, (void *)nss_lt_all },
260113596Snectar#endif
261113596Snectar#ifdef YP
262113596Snectar		{ NSSRC_NIS, nis_passwd, (void *)nss_lt_all },
263113596Snectar#endif
264113596Snectar		{ NSSRC_COMPAT, compat_passwd, (void *)nss_lt_all },
265113596Snectar		{ NULL, NULL, NULL }
266113596Snectar	};
267113596Snectar	int	rv, ret_errno;
2681573Srgrimes
269113596Snectar	ret_errno = 0;
270113596Snectar	*result = NULL;
271113596Snectar	rv = _nsdispatch(result, dtab, NSDB_PASSWD, "getpwent_r", defaultsrc,
272113596Snectar	    pwd, buffer, bufsize, &ret_errno);
273113596Snectar	if (rv == NS_SUCCESS)
274113596Snectar		return (0);
275113596Snectar	else
276113596Snectar		return (ret_errno);
277113596Snectar}
2781573Srgrimes
2791573Srgrimes
280113596Snectarint
281113596Snectargetpwnam_r(const char *name, struct passwd *pwd, char *buffer, size_t bufsize,
282113596Snectar    struct passwd **result)
283113596Snectar{
284113596Snectar	static const ns_dtab dtab[] = {
285113596Snectar		{ NSSRC_FILES, files_passwd, (void *)nss_lt_name },
286113596Snectar#ifdef HESIOD
287113596Snectar		{ NSSRC_DNS, dns_passwd, (void *)nss_lt_name },
288113596Snectar#endif
289113596Snectar#ifdef YP
290113596Snectar		{ NSSRC_NIS, nis_passwd, (void *)nss_lt_name },
291113596Snectar#endif
292113596Snectar		{ NSSRC_COMPAT, compat_passwd, (void *)nss_lt_name },
293113596Snectar		{ NULL, NULL, NULL }
294113596Snectar	};
295113596Snectar	int	rv, ret_errno;
296113596Snectar
297113596Snectar	ret_errno = 0;
298113596Snectar	*result = NULL;
299113596Snectar	rv = _nsdispatch(result, dtab, NSDB_PASSWD, "getpwnam_r", defaultsrc,
300113596Snectar	    name, pwd, buffer, bufsize, &ret_errno);
301113596Snectar	if (rv == NS_SUCCESS)
302113596Snectar		return (0);
303113596Snectar	else
304113596Snectar		return (ret_errno);
30565532Snectar}
3065714Swollman
307113596Snectar
308113596Snectarint
309113596Snectargetpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize,
310113596Snectar    struct passwd **result)
31165532Snectar{
312113596Snectar	static const ns_dtab dtab[] = {
313113596Snectar		{ NSSRC_FILES, files_passwd, (void *)nss_lt_id },
314113596Snectar#ifdef HESIOD
315113596Snectar		{ NSSRC_DNS, dns_passwd, (void *)nss_lt_id },
316113596Snectar#endif
317113596Snectar#ifdef YP
318113596Snectar		{ NSSRC_NIS, nis_passwd, (void *)nss_lt_id },
319113596Snectar#endif
320113596Snectar		{ NSSRC_COMPAT, compat_passwd, (void *)nss_lt_id },
321113596Snectar		{ NULL, NULL, NULL }
322113596Snectar	};
323113596Snectar	int	rv, ret_errno;
32465532Snectar
325113596Snectar	ret_errno = 0;
326113596Snectar	*result = NULL;
327113596Snectar	rv = _nsdispatch(result, dtab, NSDB_PASSWD, "getpwuid_r", defaultsrc,
328113596Snectar	    uid, pwd, buffer, bufsize, &ret_errno);
329113596Snectar	if (rv == NS_SUCCESS)
330113596Snectar		return (0);
331113596Snectar	else
332113596Snectar		return (ret_errno);
333113596Snectar}
33465532Snectar
33565532Snectar
336113596Snectarstatic struct passwd	 pwd;
337113596Snectarstatic char		*pwd_storage;
338113596Snectarstatic size_t		 pwd_storage_size;
33968577Snectar
34065532Snectar
341113596Snectarstatic struct passwd *
342113596Snectargetpw(int (*fn)(union key, struct passwd *, char *, size_t, struct passwd **),
343113596Snectar    union key key)
344113596Snectar{
345113596Snectar	int		 rv;
346113596Snectar	struct passwd	*res;
34765532Snectar
348113596Snectar	if (pwd_storage == NULL) {
349113596Snectar		pwd_storage = malloc(PWD_STORAGE_INITIAL);
350113596Snectar		if (pwd_storage == NULL)
351113596Snectar			return (NULL);
352113596Snectar		pwd_storage_size = PWD_STORAGE_INITIAL;
35368577Snectar	}
354113596Snectar	do {
355113596Snectar		rv = fn(key, &pwd, pwd_storage, pwd_storage_size, &res);
356113596Snectar		if (res == NULL && rv == ERANGE) {
357113596Snectar			free(pwd_storage);
358113596Snectar			if ((pwd_storage_size << 1) > PWD_STORAGE_MAX) {
359113596Snectar				pwd_storage = NULL;
360113596Snectar				return (NULL);
361113596Snectar			}
362113596Snectar			pwd_storage_size <<= 1;
363113596Snectar			pwd_storage = malloc(pwd_storage_size);
364113596Snectar			if (pwd_storage == NULL)
365113596Snectar				return (NULL);
366113596Snectar		}
367113596Snectar	} while (res == NULL && rv == ERANGE);
368113596Snectar	return (res);
369113596Snectar}
37065532Snectar
371113596Snectar
372113596Snectarstatic int
373113596Snectarwrap_getpwnam_r(union key key, struct passwd *pwd, char *buffer,
374113596Snectar    size_t bufsize, struct passwd **res)
375113596Snectar{
376113596Snectar	return (getpwnam_r(key.name, pwd, buffer, bufsize, res));
3771573Srgrimes}
3781573Srgrimes
379113596Snectar
38065532Snectarstatic int
381113596Snectarwrap_getpwuid_r(union key key, struct passwd *pwd, char *buffer,
382113596Snectar    size_t bufsize, struct passwd **res)
3831573Srgrimes{
384113596Snectar	return (getpwuid_r(key.uid, pwd, buffer, bufsize, res));
385113596Snectar}
3861573Srgrimes
3871573Srgrimes
388113596Snectarstatic int
389113596Snectarwrap_getpwent_r(union key key __unused, struct passwd *pwd, char *buffer,
390113596Snectar    size_t bufsize, struct passwd **res)
391113596Snectar{
392113596Snectar	return (getpwent_r(pwd, buffer, bufsize, res));
393113596Snectar}
3941573Srgrimes
39565532Snectar
396113596Snectarstruct passwd *
397113596Snectargetpwnam(const char *name)
398113596Snectar{
399113596Snectar	union key key;
40065532Snectar
401113596Snectar	key.name = name;
402113596Snectar	return (getpw(wrap_getpwnam_r, key));
403113596Snectar}
4047258Swpaul
4051573Srgrimes
406113596Snectarstruct passwd *
407113596Snectargetpwuid(uid_t uid)
408113596Snectar{
409113596Snectar	union key key;
410113596Snectar
411113596Snectar	key.uid = uid;
412113596Snectar	return (getpw(wrap_getpwuid_r, key));
4131573Srgrimes}
4141573Srgrimes
415113596Snectar
416113596Snectarstruct passwd *
417113596Snectargetpwent(void)
418113596Snectar{
419113596Snectar	union key key;
420113596Snectar
421113596Snectar	key.uid = 0; /* not used */
422113596Snectar	return (getpw(wrap_getpwent_r, key));
423113596Snectar}
424113596Snectar
425113596Snectar
42665532Snectar/*
427113596Snectar * files backend
42865532Snectar */
429113596Snectarstatic DB *
430113596Snectarpwdbopen(int *version)
4311573Srgrimes{
432113596Snectar	DB	*res;
433113596Snectar	DBT	 key, entry;
434113596Snectar	int	 rv;
4351573Srgrimes
436113596Snectar	if (geteuid() != 0 ||
437113596Snectar	    (res = dbopen(_PATH_SMP_DB, O_RDONLY, 0, DB_HASH, NULL)) == NULL)
438113596Snectar		res = dbopen(_PATH_MP_DB, O_RDONLY, 0, DB_HASH, NULL);
439113596Snectar	if (res == NULL)
440113596Snectar		return (NULL);
441113596Snectar	key.data = _PWD_VERSION_KEY;
442113596Snectar	key.size = strlen(_PWD_VERSION_KEY);
443113596Snectar	rv = res->get(res, &key, &entry, 0);
444113596Snectar	if (rv == 0)
445113596Snectar		*version = *(unsigned char *)entry.data;
446113596Snectar	else
447113596Snectar		*version = 3;
448113596Snectar	if (*version < 3 ||
449113596Snectar	    *version >= sizeof(pwdb_versions)/sizeof(pwdb_versions[0])) {
450113596Snectar		syslog(LOG_CRIT, "Unsupported password database version %d",
451113596Snectar		    *version);
452113596Snectar		res->close(res);
453113596Snectar		res = NULL;
45415267Swpaul	}
455113596Snectar	return (res);
456113596Snectar}
45765532Snectar
45865532Snectar
459113596Snectarstatic void
460113596Snectarfiles_endstate(void *p)
461113596Snectar{
462113596Snectar	DB	*db;
463113596Snectar
464113596Snectar	if (p == NULL)
465113596Snectar		return;
466113596Snectar	db = ((struct files_state *)p)->db;
467113596Snectar	if (db != NULL)
468113596Snectar		db->close(db);
469113596Snectar	free(p);
470113596Snectar}
471113596Snectar
472113596Snectar
473113596Snectarstatic int
474113596Snectarfiles_setpwent(void *retval, void *mdata, va_list ap)
475113596Snectar{
476113596Snectar	struct files_state	*st;
477113596Snectar	int			 rv, stayopen;
478113596Snectar
479113596Snectar	rv = files_getstate(&st);
480113596Snectar	if (rv != 0)
481113596Snectar		return (NS_UNAVAIL);
482113596Snectar	switch ((enum constants)mdata) {
483113596Snectar	case SETPWENT:
484113596Snectar		stayopen = va_arg(ap, int);
485113596Snectar		st->keynum = 0;
486113596Snectar		if (stayopen)
487113596Snectar			st->db = pwdbopen(&st->version);
488113596Snectar		st->stayopen = stayopen;
489113596Snectar		break;
490113596Snectar	case ENDPWENT:
491113596Snectar		if (st->db != NULL) {
492113596Snectar			(void)st->db->close(st->db);
493113596Snectar			st->db = NULL;
49465532Snectar		}
495113596Snectar		break;
496113596Snectar	default:
497113596Snectar		break;
49815267Swpaul	}
499113596Snectar	return (NS_UNAVAIL);
5001573Srgrimes}
5011573Srgrimes
50265532Snectar
50317141Sjkhstatic int
504113596Snectarfiles_passwd(void *retval, void *mdata, va_list ap)
5051573Srgrimes{
506113596Snectar	char			 keybuf[MAXLOGNAME + 1];
507113596Snectar	DBT			 key, entry;
508113596Snectar	struct files_state	*st;
509113596Snectar	enum nss_lookup_type	 how;
510113596Snectar	const char		*name;
511113596Snectar	struct passwd		*pwd;
512113596Snectar	char			*buffer;
513113596Snectar	size_t			 bufsize, namesize;
514113596Snectar	uid_t			 uid;
515113596Snectar	uint32_t		 store;
516113596Snectar	int			 rv, stayopen, *errnop;
5171573Srgrimes
518113596Snectar	name = NULL;
519113596Snectar	uid = (uid_t)-1;
520113596Snectar	how = (enum nss_lookup_type)mdata;
521113596Snectar	switch (how) {
522113596Snectar	case nss_lt_name:
52365532Snectar		name = va_arg(ap, const char *);
524113596Snectar		keybuf[0] = _PW_KEYBYNAME;
52565532Snectar		break;
526113596Snectar	case nss_lt_id:
52765532Snectar		uid = va_arg(ap, uid_t);
528113596Snectar		keybuf[0] = _PW_KEYBYUID;
52965532Snectar		break;
530113596Snectar	case nss_lt_all:
531113596Snectar		keybuf[0] = _PW_KEYBYNUM;
532113596Snectar		break;
53365532Snectar	default:
534113596Snectar		rv = NS_NOTFOUND;
535113596Snectar		goto fin;
53665532Snectar	}
537113596Snectar	pwd = va_arg(ap, struct passwd *);
538113596Snectar	buffer = va_arg(ap, char *);
539113596Snectar	bufsize = va_arg(ap, size_t);
540113596Snectar	errnop = va_arg(ap, int *);
541113596Snectar	*errnop = files_getstate(&st);
542113596Snectar	if (*errnop != 0)
543113596Snectar		return (NS_UNAVAIL);
544113596Snectar	if (how == nss_lt_all && st->keynum < 0) {
545113596Snectar		rv = NS_NOTFOUND;
546113596Snectar		goto fin;
54765532Snectar	}
548113596Snectar	if (st->db == NULL &&
549113596Snectar	    (st->db = pwdbopen(&st->version)) == NULL) {
550113596Snectar		*errnop = errno;
551113596Snectar		rv = NS_UNAVAIL;
552113596Snectar		goto fin;
55394688Sdes	}
554113596Snectar	if (how == nss_lt_all)
555113596Snectar		stayopen = 1;
556113596Snectar	else
557113596Snectar		stayopen = st->stayopen;
558113596Snectar	key.data = keybuf;
559113596Snectar	do {
560113596Snectar		switch (how) {
561113596Snectar		case nss_lt_name:
562113596Snectar			/* MAXLOGNAME includes NUL byte, but we do not
563113596Snectar			 * include the NUL byte in the key.
564113596Snectar			 */
565113596Snectar			namesize = strlcpy(&keybuf[1], name, sizeof(keybuf)-1);
566113596Snectar			if (namesize >= sizeof(keybuf)-1) {
567113596Snectar				*errnop = EINVAL;
568113596Snectar				rv = NS_NOTFOUND;
569113596Snectar				goto fin;
570113596Snectar			}
571113596Snectar			key.size = namesize + 1;
572113596Snectar			break;
573113596Snectar		case nss_lt_id:
574113596Snectar			if (st->version < _PWD_CURRENT_VERSION) {
575113596Snectar				memcpy(&keybuf[1], &uid, sizeof(uid));
576113596Snectar				key.size = sizeof(uid) + 1;
577113596Snectar			} else {
578113596Snectar				store = htonl(uid);
579113596Snectar				memcpy(&keybuf[1], &store, sizeof(store));
580113596Snectar				key.size = sizeof(store) + 1;
581113596Snectar			}
582113596Snectar			break;
583113596Snectar		case nss_lt_all:
584113596Snectar			st->keynum++;
585113596Snectar			if (st->version < _PWD_CURRENT_VERSION) {
586113596Snectar				memcpy(&keybuf[1], &st->keynum,
587113596Snectar				    sizeof(st->keynum));
588113596Snectar				key.size = sizeof(st->keynum) + 1;
589113596Snectar			} else {
590113596Snectar				store = htonl(st->keynum);
591113596Snectar				memcpy(&keybuf[1], &store, sizeof(store));
592113596Snectar				key.size = sizeof(store) + 1;
593113596Snectar			}
594113596Snectar			break;
595113596Snectar		}
596113666Snectar		keybuf[0] = _PW_VERSIONED(keybuf[0], st->version);
597113596Snectar		rv = st->db->get(st->db, &key, &entry, 0);
598113596Snectar		if (rv < 0 || rv > 1) { /* should never return > 1 */
599113596Snectar			*errnop = errno;
600113596Snectar			rv = NS_UNAVAIL;
601113596Snectar			goto fin;
602113596Snectar		} else if (rv == 1) {
603113596Snectar			if (how == nss_lt_all)
604113596Snectar				st->keynum = -1;
605113596Snectar			rv = NS_NOTFOUND;
606113596Snectar			goto fin;
607113596Snectar		}
608113596Snectar		rv = pwdb_versions[st->version].match(entry.data, entry.size,
609113596Snectar		    how, name, uid);
610113596Snectar		if (rv != NS_SUCCESS)
611113596Snectar			continue;
612113596Snectar		if (entry.size > bufsize) {
613113596Snectar			*errnop = ERANGE;
614113596Snectar			rv = NS_RETURN;
615113596Snectar			break;
616113596Snectar		}
617113596Snectar		memcpy(buffer, entry.data, entry.size);
618113596Snectar		rv = pwdb_versions[st->version].parse(buffer, entry.size, pwd,
619113596Snectar		    errnop);
620113596Snectar	} while (how == nss_lt_all && !(rv & NS_TERMINATE));
621113596Snectarfin:
622113596Snectar	if (!stayopen && st->db != NULL) {
623113596Snectar		(void)st->db->close(st->db);
624113596Snectar		st->db = NULL;
625113596Snectar	}
626113670Snectar	if (rv == NS_SUCCESS) {
627113670Snectar		pwd->pw_fields &= ~_PWF_SOURCE;
628113670Snectar		pwd->pw_fields |= _PWF_FILES;
629113670Snectar		if (retval != NULL)
630113670Snectar			*(struct passwd **)retval = pwd;
631113670Snectar	}
632113596Snectar	return (rv);
6331573Srgrimes}
6341573Srgrimes
635113596Snectar
636113596Snectarstatic int
637113596Snectarpwdb_match_entry_v3(char *entry, size_t entrysize, enum nss_lookup_type how,
638113596Snectar    const char *name, uid_t uid)
639113596Snectar{
640113596Snectar	const char	*p, *eom;
641113596Snectar	uid_t		 uid2;
642113596Snectar
643113596Snectar	eom = &entry[entrysize];
644113596Snectar	for (p = entry; p < eom; p++)
645113596Snectar		if (*p == '\0')
646113596Snectar			break;
647113596Snectar	if (*p != '\0')
648113596Snectar		return (NS_NOTFOUND);
649113596Snectar	if (how == nss_lt_all)
650113596Snectar		return (NS_SUCCESS);
651113596Snectar	if (how == nss_lt_name)
652113596Snectar		return (strcmp(name, entry) == 0 ? NS_SUCCESS : NS_NOTFOUND);
653113596Snectar	for (p++; p < eom; p++)
654113596Snectar		if (*p == '\0')
655113596Snectar			break;
656113596Snectar	if (*p != '\0' || (++p) + sizeof(uid) >= eom)
657113596Snectar		return (NS_NOTFOUND);
658113596Snectar	memcpy(&uid2, p, sizeof(uid2));
659113596Snectar	return (uid == uid2 ? NS_SUCCESS : NS_NOTFOUND);
660113596Snectar}
661113596Snectar
662113596Snectar
663113596Snectarstatic int
664113596Snectarpwdb_parse_entry_v3(char *buffer, size_t bufsize, struct passwd *pwd,
665113596Snectar    int *errnop)
666113596Snectar{
667113596Snectar	char		*p, *eom;
668113596Snectar	int32_t		 pw_change, pw_expire;
669113596Snectar
670113596Snectar	memset(pwd, 0, sizeof(*pwd));
671113596Snectar	/* THIS CODE MUST MATCH THAT IN pwd_mkdb. */
672113596Snectar	p = buffer;
673113596Snectar	eom = &buffer[bufsize];
674113596Snectar#define STRING(field)	do {			\
675113596Snectar		(field) = p;			\
676113596Snectar		while (p < eom && *p != '\0')	\
677113596Snectar			p++;			\
678113596Snectar		if (p >= eom)			\
679113596Snectar			return (NS_NOTFOUND);	\
680113596Snectar		p++;				\
681113596Snectar	} while (0)
682113596Snectar#define SCALAR(field)	do {				\
683113596Snectar		if (p + sizeof(field) > eom)		\
684113596Snectar			return (NS_NOTFOUND);		\
685113596Snectar		memcpy(&(field), p, sizeof(field));	\
686113596Snectar		p += sizeof(field);			\
687113596Snectar	} while (0)
688113596Snectar	STRING(pwd->pw_name);
689113596Snectar	STRING(pwd->pw_passwd);
690113596Snectar	SCALAR(pwd->pw_uid);
691113596Snectar	SCALAR(pwd->pw_gid);
692113596Snectar	SCALAR(pw_change);
693113596Snectar	STRING(pwd->pw_class);
694113596Snectar	STRING(pwd->pw_gecos);
695113596Snectar	STRING(pwd->pw_dir);
696113596Snectar	STRING(pwd->pw_shell);
697113596Snectar	SCALAR(pw_expire);
698113596Snectar	SCALAR(pwd->pw_fields);
699113596Snectar#undef STRING
700113596Snectar#undef SCALAR
701113596Snectar	pwd->pw_change = pw_change;
702113596Snectar	pwd->pw_expire = pw_expire;
703113596Snectar	return (NS_SUCCESS);
704113596Snectar}
705113596Snectar
706113596Snectar
707113596Snectarstatic int
708113596Snectarpwdb_match_entry_v4(char *entry, size_t entrysize, enum nss_lookup_type how,
709113596Snectar    const char *name, uid_t uid)
710113596Snectar{
711113596Snectar	const char	*p, *eom;
712113596Snectar	uint32_t	 uid2;
713113596Snectar
714113596Snectar	eom = &entry[entrysize];
715113596Snectar	for (p = entry; p < eom; p++)
716113596Snectar		if (*p == '\0')
717113596Snectar			break;
718113596Snectar	if (*p != '\0')
719113596Snectar		return (NS_NOTFOUND);
720113596Snectar	if (how == nss_lt_all)
721113596Snectar		return (NS_SUCCESS);
722113596Snectar	if (how == nss_lt_name)
723113596Snectar		return (strcmp(name, entry) == 0 ? NS_SUCCESS : NS_NOTFOUND);
724113596Snectar	for (p++; p < eom; p++)
725113596Snectar		if (*p == '\0')
726113596Snectar			break;
727113596Snectar	if (*p != '\0' || (++p) + sizeof(uid) >= eom)
728113596Snectar		return (NS_NOTFOUND);
729113596Snectar	memcpy(&uid2, p, sizeof(uid2));
730113596Snectar	uid2 = ntohl(uid2);
731113596Snectar	return (uid == (uid_t)uid2 ? NS_SUCCESS : NS_NOTFOUND);
732113596Snectar}
733113596Snectar
734113596Snectar
735113596Snectarstatic int
736113596Snectarpwdb_parse_entry_v4(char *buffer, size_t bufsize, struct passwd *pwd,
737113596Snectar    int *errnop)
738113596Snectar{
739113596Snectar	char		*p, *eom;
740113596Snectar	uint32_t	 n;
741113596Snectar
742113596Snectar	memset(pwd, 0, sizeof(*pwd));
743113596Snectar	/* THIS CODE MUST MATCH THAT IN pwd_mkdb. */
744113596Snectar	p = buffer;
745113596Snectar	eom = &buffer[bufsize];
746113596Snectar#define STRING(field)	do {			\
747113596Snectar		(field) = p;			\
748113596Snectar		while (p < eom && *p != '\0')	\
749113596Snectar			p++;			\
750113596Snectar		if (p >= eom)			\
751113596Snectar			return (NS_NOTFOUND);	\
752113596Snectar		p++;				\
753113596Snectar	} while (0)
754113596Snectar#define SCALAR(field)	do {				\
755113596Snectar		if (p + sizeof(n) > eom)		\
756113596Snectar			return (NS_NOTFOUND);		\
757113596Snectar		memcpy(&n, p, sizeof(n));		\
758113596Snectar		(field) = ntohl(n);			\
759113596Snectar		p += sizeof(n);				\
760113596Snectar	} while (0)
761113596Snectar	STRING(pwd->pw_name);
762113596Snectar	STRING(pwd->pw_passwd);
763113596Snectar	SCALAR(pwd->pw_uid);
764113596Snectar	SCALAR(pwd->pw_gid);
765113596Snectar	SCALAR(pwd->pw_change);
766113596Snectar	STRING(pwd->pw_class);
767113596Snectar	STRING(pwd->pw_gecos);
768113596Snectar	STRING(pwd->pw_dir);
769113596Snectar	STRING(pwd->pw_shell);
770113596Snectar	SCALAR(pwd->pw_expire);
771113596Snectar	SCALAR(pwd->pw_fields);
772113596Snectar#undef STRING
773113596Snectar#undef SCALAR
774113596Snectar	return (NS_SUCCESS);
775113596Snectar}
776113596Snectar
777113596Snectar
77865532Snectar#ifdef HESIOD
77965532Snectar/*
780113596Snectar * dns backend
78165532Snectar */
782113596Snectarstatic void
783113596Snectardns_endstate(void *p)
784113596Snectar{
785113596Snectar	free(p);
786113596Snectar}
78765532Snectar
788113596Snectar
78917141Sjkhstatic int
790113596Snectardns_setpwent(void *retval, void *mdata, va_list ap)
7911573Srgrimes{
792113596Snectar	struct dns_state	*st;
793113596Snectar	int			 rv;
7941573Srgrimes
795113596Snectar	rv = dns_getstate(&st);
796113596Snectar	if (rv != 0)
797113596Snectar		return (NS_UNAVAIL);
798113596Snectar	st->counter = 0;
799113596Snectar	return (NS_UNAVAIL);
800113596Snectar}
8011573Srgrimes
802113596Snectar
803113596Snectarstatic int
804113596Snectardns_passwd(void *retval, void *mdata, va_list ap)
805113596Snectar{
806113596Snectar	char			 buf[HESIOD_NAME_MAX];
807113596Snectar	struct dns_state	*st;
808113596Snectar	struct passwd		*pwd;
809113596Snectar	const char		*name, *label;
810113596Snectar	void			*ctx;
811113596Snectar	char			*buffer, **hes;
812113596Snectar	size_t			 bufsize, linesize;
813113596Snectar	uid_t			 uid;
814113596Snectar	enum nss_lookup_type	 how;
815113596Snectar	int			 rv, *errnop;
816113596Snectar
817113596Snectar	ctx = NULL;
818113596Snectar	hes = NULL;
819113596Snectar	name = NULL;
820113596Snectar	uid = (uid_t)-1;
821113596Snectar	how = (enum nss_lookup_type)mdata;
822113596Snectar	switch (how) {
823113596Snectar	case nss_lt_name:
82465532Snectar		name = va_arg(ap, const char *);
82565532Snectar		break;
826113596Snectar	case nss_lt_id:
82765532Snectar		uid = va_arg(ap, uid_t);
82865532Snectar		break;
829113596Snectar	case nss_lt_all:
830113596Snectar		break;
83129479Swosch	}
832113596Snectar	pwd     = va_arg(ap, struct passwd *);
833113596Snectar	buffer  = va_arg(ap, char *);
834113596Snectar	bufsize = va_arg(ap, size_t);
835113596Snectar	errnop  = va_arg(ap, int *);
836113596Snectar	*errnop = dns_getstate(&st);
837113596Snectar	if (*errnop != 0)
838113596Snectar		return (NS_UNAVAIL);
839113596Snectar	if (hesiod_init(&ctx) != 0) {
840113596Snectar		*errnop = errno;
841113596Snectar		rv = NS_UNAVAIL;
842113596Snectar		goto fin;
843113596Snectar	}
844113596Snectar	do {
845113596Snectar		rv = NS_NOTFOUND;
846113596Snectar		switch (how) {
847113596Snectar		case nss_lt_name:
848113596Snectar			label = name;
849113596Snectar			break;
850113596Snectar		case nss_lt_id:
851113596Snectar			if (snprintf(buf, sizeof(buf), "%lu",
852113596Snectar			    (unsigned long)uid) >= sizeof(buf))
853113596Snectar				goto fin;
854113596Snectar			label = buf;
855113596Snectar			break;
856113596Snectar		case nss_lt_all:
857113596Snectar			if (st->counter < 0)
858113596Snectar				goto fin;
859113596Snectar			if (snprintf(buf, sizeof(buf), "passwd-%ld",
860113596Snectar			    st->counter++) >= sizeof(buf))
861113596Snectar				goto fin;
862113596Snectar			label = buf;
863113596Snectar			break;
86465532Snectar		}
865113596Snectar		hes = hesiod_resolve(ctx, label,
866113596Snectar		    how == nss_lt_id ? "uid" : "passwd");
867113596Snectar		if (hes == NULL) {
868113596Snectar			if (how == nss_lt_all)
869113596Snectar				st->counter = -1;
870113596Snectar			if (errno != ENOENT)
871113596Snectar				*errnop = errno;
872113596Snectar			goto fin;
873113596Snectar		}
874113596Snectar		rv = __pw_match_entry(hes[0], strlen(hes[0]), how, name, uid);
875113596Snectar		if (rv != NS_SUCCESS) {
876113596Snectar			hesiod_free_list(ctx, hes);
877113596Snectar			hes = NULL;
878113596Snectar			continue;
879113596Snectar		}
880113596Snectar		linesize = strlcpy(buffer, hes[0], bufsize);
881113596Snectar		if (linesize >= bufsize) {
882113596Snectar			*errnop = ERANGE;
883113596Snectar			rv = NS_RETURN;
884113596Snectar			continue;
885113596Snectar		}
886113596Snectar		hesiod_free_list(ctx, hes);
887113596Snectar		hes = NULL;
888113596Snectar		rv = __pw_parse_entry(buffer, bufsize, pwd, 0, errnop);
889113596Snectar	} while (how == nss_lt_all && !(rv & NS_TERMINATE));
890113596Snectarfin:
891113596Snectar	if (hes != NULL)
892113596Snectar		hesiod_free_list(ctx, hes);
893113596Snectar	if (ctx != NULL)
894113596Snectar		hesiod_end(ctx);
895113596Snectar	if (rv == NS_SUCCESS) {
896113596Snectar		pwd->pw_fields &= ~_PWF_SOURCE;
897113596Snectar		pwd->pw_fields |= _PWF_HESIOD;
898113596Snectar		if (retval != NULL)
899113596Snectar			*(struct passwd **)retval = pwd;
90065532Snectar	}
901113596Snectar	return (rv);
90215267Swpaul}
903113596Snectar#endif /* HESIOD */
9047258Swpaul
905113596Snectar
90665532Snectar#ifdef YP
90715267Swpaul/*
908113596Snectar * nis backend
90915267Swpaul */
910113596Snectarstatic void
911113596Snectarnis_endstate(void *p)
912113596Snectar{
913113596Snectar	free(((struct nis_state *)p)->key);
914113596Snectar	free(p);
915113596Snectar}
91665532Snectar
91765532Snectarstatic int
918113596Snectarnis_map(char *domain, enum nss_lookup_type how, char *buffer, size_t bufsize,
919113596Snectar    int *master)
92015267Swpaul{
921113596Snectar	int	rv, order;
9227258Swpaul
923113596Snectar	*master = 0;
924113596Snectar	if (snprintf(buffer, bufsize, "master.passwd.by%s",
925113596Snectar	    (how == nss_lt_id) ? "uid" : "name") >= bufsize)
926113596Snectar		return (NS_UNAVAIL);
927113596Snectar	rv = yp_order(domain, buffer, &order);
928113596Snectar	if (rv == 0) {
929113596Snectar		*master = 1;
930113596Snectar		return (NS_SUCCESS);
93165532Snectar	}
932113596Snectar	if (snprintf(buffer, bufsize, "passwd.by%s",
933113596Snectar	    (how == nss_lt_id) ? "uid" : "name") >= bufsize)
934113596Snectar		return (NS_UNAVAIL);
935113596Snectar	rv = yp_order(domain, buffer, &order);
936113596Snectar	if (rv == 0)
937113596Snectar		return (NS_SUCCESS);
938113596Snectar	return (NS_UNAVAIL);
939113596Snectar}
94015267Swpaul
941113596Snectar
942113596Snectarstatic int
943113596Snectarnis_adjunct(char *domain, const char *name, char *buffer, size_t bufsize)
944113596Snectar{
945113596Snectar	int	 rv;
946113596Snectar	char	*result, *p, *q, *eor;
947113596Snectar	int	 resultlen;
948113596Snectar
949113596Snectar	result = NULL;
950113596Snectar	rv = yp_match(domain, "passwd.adjunct.byname", name, strlen(name),
951113596Snectar	    &result, &resultlen);
952113596Snectar	if (rv != 0)
953113596Snectar		rv = 1;
954113596Snectar	else {
955113596Snectar		eor = &result[resultlen];
956113596Snectar		p = memchr(result, ':', eor - result);
957113596Snectar		if (p != NULL && ++p < eor &&
958113596Snectar		    (q = memchr(p, ':', eor - p)) != NULL) {
959113596Snectar			if (q - p >= bufsize)
960113596Snectar				rv = -1;
961113596Snectar			else {
962113596Snectar				memcpy(buffer, p, q - p);
963113596Snectar				buffer[q - p] ='\0';
964113596Snectar			}
965113596Snectar		} else
966113596Snectar			rv = 1;
967113596Snectar	}
968113596Snectar	free(result);
969113596Snectar	return (rv);
970113596Snectar}
971113596Snectar
972113596Snectar
973113596Snectarstatic int
974113596Snectarnis_setpwent(void *retval, void *mdata, va_list ap)
975113596Snectar{
976113596Snectar	struct nis_state	*st;
977113596Snectar	int			 rv;
978113596Snectar
979113596Snectar	rv = nis_getstate(&st);
980113596Snectar	if (rv != 0)
981113596Snectar		return (NS_UNAVAIL);
982113596Snectar	st->done = 0;
983113596Snectar	free(st->key);
984113596Snectar	st->key = NULL;
985113596Snectar	return (NS_UNAVAIL);
986113596Snectar}
987113596Snectar
988113596Snectar
989113596Snectarstatic int
990113596Snectarnis_passwd(void *retval, void *mdata, va_list ap)
991113596Snectar{
992113596Snectar	char		 map[YPMAXMAP];
993113596Snectar	struct nis_state *st;
994113596Snectar	struct passwd	*pwd;
995113596Snectar	const char	*name;
996113596Snectar	char		*buffer, *key, *result;
997113596Snectar	size_t		 bufsize;
998113596Snectar	uid_t		 uid;
999113596Snectar	enum nss_lookup_type how;
1000113596Snectar	int		*errnop, keylen, resultlen, rv, master;
1001113596Snectar
1002113596Snectar	name = NULL;
1003113596Snectar	uid = (uid_t)-1;
1004113596Snectar	how = (enum nss_lookup_type)mdata;
1005113596Snectar	switch (how) {
1006113596Snectar	case nss_lt_name:
100765532Snectar		name = va_arg(ap, const char *);
100865532Snectar		break;
1009113596Snectar	case nss_lt_id:
101065532Snectar		uid = va_arg(ap, uid_t);
101165532Snectar		break;
1012113596Snectar	case nss_lt_all:
1013113596Snectar		break;
101465532Snectar	}
1015113596Snectar	pwd     = va_arg(ap, struct passwd *);
1016113596Snectar	buffer  = va_arg(ap, char *);
1017113596Snectar	bufsize = va_arg(ap, size_t);
1018113596Snectar	errnop  = va_arg(ap, int *);
1019113596Snectar	*errnop = nis_getstate(&st);
1020113596Snectar	if (*errnop != 0)
1021113596Snectar		return (NS_UNAVAIL);
1022113596Snectar	if (st->domain[0] == '\0') {
1023113596Snectar		if (getdomainname(st->domain, sizeof(st->domain)) != 0) {
1024113596Snectar			*errnop = errno;
1025113596Snectar			return (NS_UNAVAIL);
102665532Snectar		}
102765532Snectar	}
1028113596Snectar	rv = nis_map(st->domain, how, map, sizeof(map), &master);
1029113596Snectar	if (rv != NS_SUCCESS)
1030113596Snectar		return (rv);
1031113596Snectar	result = NULL;
1032113596Snectar	do {
1033113596Snectar		rv = NS_NOTFOUND;
1034113596Snectar		switch (how) {
1035113596Snectar		case nss_lt_name:
1036113596Snectar			if (strlcpy(buffer, name, bufsize) >= bufsize)
1037113596Snectar				goto erange;
1038113596Snectar			break;
1039113596Snectar		case nss_lt_id:
1040113596Snectar			if (snprintf(buffer, bufsize, "%lu",
1041113596Snectar			    (unsigned long)uid) >= bufsize)
1042113596Snectar				goto erange;
1043113596Snectar			break;
1044113596Snectar		case nss_lt_all:
1045113596Snectar			if (st->done)
1046113596Snectar				goto fin;
1047113596Snectar			break;
1048113596Snectar		}
1049113596Snectar		result = NULL;
1050113596Snectar		if (how == nss_lt_all) {
1051113596Snectar			if (st->key == NULL)
1052113596Snectar				rv = yp_first(st->domain, map, &st->key,
1053113596Snectar				    &st->keylen, &result, &resultlen);
1054113596Snectar			else {
1055113596Snectar				key = st->key;
1056113596Snectar				keylen = st->keylen;
1057113596Snectar				st->key = NULL;
1058113596Snectar				rv = yp_next(st->domain, map, key, keylen,
1059113596Snectar				    &st->key, &st->keylen, &result,
1060113596Snectar				    &resultlen);
1061113596Snectar				free(key);
106265532Snectar			}
1063113596Snectar			if (rv != 0) {
1064113596Snectar				free(result);
1065113596Snectar				free(st->key);
1066113596Snectar				st->key = NULL;
1067113596Snectar				if (rv == YPERR_NOMORE)
1068113596Snectar					st->done = 1;
1069113596Snectar				else
1070113596Snectar					rv = NS_UNAVAIL;
1071113596Snectar				goto fin;
1072113596Snectar			}
107365532Snectar		} else {
1074113596Snectar			rv = yp_match(st->domain, map, buffer, strlen(buffer),
1075113596Snectar			    &result, &resultlen);
1076113596Snectar			if (rv == YPERR_KEY) {
1077113596Snectar				rv = NS_NOTFOUND;
1078113596Snectar				continue;
1079113596Snectar			} else if (rv != 0) {
1080113596Snectar				free(result);
1081113596Snectar				rv = NS_UNAVAIL;
1082113596Snectar				continue;
1083113596Snectar			}
108465532Snectar		}
1085113596Snectar		if (resultlen >= bufsize)
1086113596Snectar			goto erange;
1087113596Snectar		memcpy(buffer, result, resultlen);
1088113596Snectar		buffer[resultlen] = '\0';
1089113596Snectar		free(result);
1090113596Snectar		rv = __pw_match_entry(buffer, resultlen, how, name, uid);
1091113596Snectar		if (rv == NS_SUCCESS)
1092113596Snectar			rv = __pw_parse_entry(buffer, resultlen, pwd, master,
1093113596Snectar			    errnop);
1094113596Snectar	} while (how == nss_lt_all && !(rv & NS_TERMINATE));
1095113596Snectarfin:
1096113596Snectar	if (rv == NS_SUCCESS) {
1097113596Snectar		if (strstr(pwd->pw_passwd, "##") != NULL) {
1098113596Snectar			rv = nis_adjunct(st->domain, name,
1099113596Snectar			    &buffer[resultlen+1], bufsize-resultlen-1);
1100113596Snectar			if (rv < 0)
1101113596Snectar				goto erange;
1102113596Snectar			else if (rv == 0)
1103113596Snectar				pwd->pw_passwd = &buffer[resultlen+1];
110465532Snectar		}
1105113596Snectar		pwd->pw_fields &= ~_PWF_SOURCE;
1106113596Snectar		pwd->pw_fields |= _PWF_NIS;
1107113596Snectar		if (retval != NULL)
1108113596Snectar			*(struct passwd **)retval = pwd;
110915267Swpaul	}
1110113596Snectar	return (rv);
1111113596Snectarerange:
1112113596Snectar	*errnop = ERANGE;
1113113596Snectar	return (NS_RETURN);
1114113596Snectar}
1115113596Snectar#endif /* YP */
111615267Swpaul
1117113596Snectar
111815267Swpaul/*
1119113596Snectar * compat backend
112015267Swpaul */
1121113596Snectarstatic void
1122113596Snectarcompat_clear_template(struct passwd *template)
1123113596Snectar{
112465532Snectar
1125113596Snectar	free(template->pw_passwd);
1126113596Snectar	free(template->pw_gecos);
1127113596Snectar	free(template->pw_dir);
1128113596Snectar	free(template->pw_shell);
1129113596Snectar	memset(template, 0, sizeof(*template));
1130113596Snectar}
1131113596Snectar
1132113596Snectar
113365532Snectarstatic int
1134113596Snectarcompat_set_template(struct passwd *src, struct passwd *template)
113515267Swpaul{
113615267Swpaul
1137113596Snectar	compat_clear_template(template);
1138113596Snectar#ifdef PW_OVERRIDE_PASSWD
1139113596Snectar	if ((src->pw_fields & _PWF_PASSWD) &&
1140113596Snectar	    (template->pw_passwd = strdup(src->pw_passwd)) == NULL)
1141113596Snectar		goto enomem;
1142113596Snectar#endif
1143113596Snectar	if (src->pw_fields & _PWF_UID)
1144113596Snectar		template->pw_uid = src->pw_uid;
1145113596Snectar	if (src->pw_fields & _PWF_GID)
1146113596Snectar		template->pw_gid = src->pw_gid;
1147113596Snectar	if ((src->pw_fields & _PWF_GECOS) &&
1148113596Snectar	    (template->pw_gecos = strdup(src->pw_gecos)) == NULL)
1149113596Snectar		goto enomem;
1150113596Snectar	if ((src->pw_fields & _PWF_DIR) &&
1151113596Snectar	    (template->pw_dir = strdup(src->pw_dir)) == NULL)
1152113596Snectar		goto enomem;
1153113596Snectar	if ((src->pw_fields & _PWF_SHELL) &&
1154113596Snectar	    (template->pw_shell = strdup(src->pw_shell)) == NULL)
1155113596Snectar		goto enomem;
1156113596Snectar	template->pw_fields = src->pw_fields;
1157113596Snectar	return (0);
1158113596Snectarenomem:
1159113596Snectar	syslog(LOG_ERR, "getpwent memory allocation failure");
1160113596Snectar	return (-1);
1161113596Snectar}
116215267Swpaul
116315267Swpaul
1164113596Snectarstatic int
1165113596Snectarcompat_use_template(struct passwd *pwd, struct passwd *template, char *buffer,
1166113596Snectar    size_t bufsize)
1167113596Snectar{
1168113596Snectar	struct passwd hold;
1169113596Snectar	char	*copy, *p, *q, *eob;
1170113596Snectar	size_t	 n;
1171113596Snectar
1172113596Snectar	/* We cannot know the layout of the password fields in `buffer',
1173113596Snectar	 * so we have to copy everything.
1174113596Snectar	 */
1175113596Snectar	if (template->pw_fields == 0) /* nothing to fill-in */
1176113596Snectar		return (0);
1177113596Snectar	n = 0;
1178113596Snectar	n += pwd->pw_name != NULL ? strlen(pwd->pw_name) + 1 : 0;
1179113596Snectar	n += pwd->pw_passwd != NULL ? strlen(pwd->pw_passwd) + 1 : 0;
1180113596Snectar	n += pwd->pw_class != NULL ? strlen(pwd->pw_class) + 1 : 0;
1181113596Snectar	n += pwd->pw_gecos != NULL ? strlen(pwd->pw_gecos) + 1 : 0;
1182113596Snectar	n += pwd->pw_dir != NULL ? strlen(pwd->pw_dir) + 1 : 0;
1183113596Snectar	n += pwd->pw_shell != NULL ? strlen(pwd->pw_shell) + 1 : 0;
1184113596Snectar	copy = malloc(n);
1185113596Snectar	if (copy == NULL) {
1186113596Snectar		syslog(LOG_ERR, "getpwent memory allocation failure");
1187113596Snectar		return (ENOMEM);
1188113596Snectar	}
1189113596Snectar	p = copy;
1190113596Snectar	eob = &copy[n];
1191113596Snectar#define COPY(field) do {				\
1192113596Snectar	if (pwd->field == NULL)				\
1193113596Snectar		hold.field = NULL;			\
1194113596Snectar	else {						\
1195113596Snectar		hold.field = p;				\
1196113596Snectar		p += strlcpy(p, pwd->field, eob-p) + 1;	\
1197113596Snectar	}						\
1198113596Snectar} while (0)
1199113596Snectar	COPY(pw_name);
1200113596Snectar	COPY(pw_passwd);
1201113596Snectar	COPY(pw_class);
1202113596Snectar	COPY(pw_gecos);
1203113596Snectar	COPY(pw_dir);
1204113596Snectar	COPY(pw_shell);
1205113596Snectar#undef COPY
1206113596Snectar	p = buffer;
1207113596Snectar	eob = &buffer[bufsize];
1208113596Snectar#define COPY(field, flag) do {						 \
1209113596Snectar	q = (template->pw_fields & flag) ? template->field : hold.field; \
1210113596Snectar	if (q == NULL)							 \
1211113596Snectar		pwd->field = NULL;					 \
1212113596Snectar	else {								 \
1213113596Snectar		pwd->field = p;						 \
1214113596Snectar		if ((n = strlcpy(p, q, eob-p)) >= eob-p) {		 \
1215113596Snectar			free(copy);					 \
1216113596Snectar			return (ERANGE);				 \
1217113596Snectar		}							 \
1218113596Snectar		p += n + 1;						 \
1219113596Snectar	}								 \
1220113596Snectar} while (0)
1221113596Snectar	COPY(pw_name, 0);
1222113596Snectar#ifdef PW_OVERRIDE_PASSWD
1223113596Snectar	COPY(pw_passwd, _PWF_PASSWD);
1224113596Snectar#else
1225113596Snectar	COPY(pw_passwd, 0);
1226113596Snectar#endif
1227113596Snectar	COPY(pw_class, 0);
1228113596Snectar	COPY(pw_gecos, _PWF_GECOS);
1229113596Snectar	COPY(pw_dir, _PWF_DIR);
1230113596Snectar	COPY(pw_shell, _PWF_SHELL);
1231113596Snectar#undef COPY
1232113596Snectar#define COPY(field, flag) do {			\
1233113596Snectar	if (template->pw_fields & flag)		\
1234113596Snectar		pwd->field = template->field;	\
1235113596Snectar} while (0)
1236113596Snectar	COPY(pw_uid, _PWF_UID);
1237113596Snectar	COPY(pw_gid, _PWF_GID);
1238113596Snectar#undef COPY
1239113596Snectar	free(copy);
1240113596Snectar	return (0);
124115267Swpaul}
124215267Swpaul
124365532Snectar
124465532Snectarstatic int
1245113596Snectarcompat_exclude(const char *name, DB **db)
124615267Swpaul{
1247113596Snectar	DBT	key, data;
1248113596Snectar
1249113596Snectar	if (*db == NULL &&
1250113596Snectar	    (*db = dbopen(NULL, O_RDWR, 600, DB_HASH, 0)) == NULL)
1251113596Snectar		return (errno);
1252113596Snectar	key.size = strlen(name);
1253113596Snectar	key.data = (char *)name;
1254113596Snectar	data.size = 0;
1255113596Snectar	data.data = NULL;
1256113596Snectar
1257113596Snectar	if ((*db)->put(*db, &key, &data, 0) == -1)
1258113596Snectar		return (errno);
1259113596Snectar	return (0);
12607258Swpaul}
12617258Swpaul
126265532Snectar
126365532Snectarstatic int
1264113596Snectarcompat_is_excluded(const char *name, DB *db)
12657258Swpaul{
1266113596Snectar	DBT	key, data;
12677258Swpaul
1268113596Snectar	if (db == NULL)
1269113596Snectar		return (0);
1270113596Snectar	key.size = strlen(name);
1271113596Snectar	key.data = (char *)name;
1272113596Snectar	return (db->get(db, &key, &data, 0) == 0);
12737258Swpaul}
12747258Swpaul
127565532Snectar
127665532Snectarstatic int
1277113596Snectarcompat_redispatch(struct compat_state *st, enum nss_lookup_type how,
1278113596Snectar    enum nss_lookup_type lookup_how, const char *name, const char *lookup_name,
1279113596Snectar    uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize, int *errnop)
128010521Swpaul{
1281113596Snectar	static const ns_src compatsrc[] = {
1282113596Snectar#ifdef YP
1283113596Snectar		{ NSSRC_NIS, NS_SUCCESS },
128465532Snectar#endif
1285113596Snectar		{ NULL, 0 }
1286113596Snectar	};
1287113596Snectar	ns_dtab dtab[] = {
1288113596Snectar#ifdef YP
1289113596Snectar		{ NSSRC_NIS, nis_passwd, NULL },
1290113596Snectar#endif
1291113596Snectar#ifdef HESIOD
1292113596Snectar		{ NSSRC_DNS, dns_passwd, NULL },
1293113596Snectar#endif
1294113596Snectar		{ NULL, NULL, NULL }
1295113596Snectar	};
1296113596Snectar	void		*discard;
1297113596Snectar	int		 rv, e, i;
129810521Swpaul
1299113596Snectar	for (i = 0; i < sizeof(dtab)/sizeof(dtab[0]) - 1; i++)
1300113596Snectar		dtab[i].mdata = (void *)lookup_how;
1301113596Snectarmore:
1302113596Snectar	switch (lookup_how) {
1303113596Snectar	case nss_lt_all:
1304113596Snectar		rv = _nsdispatch(&discard, dtab, NSDB_PASSWD_COMPAT,
1305113596Snectar		    "getpwent_r", compatsrc, pwd, buffer, bufsize,
1306113596Snectar		    errnop);
1307113596Snectar		break;
1308113596Snectar	case nss_lt_id:
1309113596Snectar		rv = _nsdispatch(&discard, dtab, NSDB_PASSWD_COMPAT,
1310113596Snectar		    "getpwuid_r", compatsrc, uid, pwd, buffer,
1311113596Snectar		    bufsize, errnop);
1312113596Snectar		break;
1313113596Snectar	case nss_lt_name:
1314113596Snectar		rv = _nsdispatch(&discard, dtab, NSDB_PASSWD_COMPAT,
1315113596Snectar		    "getpwnam_r", compatsrc, lookup_name, pwd, buffer,
1316113596Snectar		    bufsize, errnop);
1317113596Snectar		break;
1318113596Snectar	default:
1319113596Snectar		return (NS_UNAVAIL);
1320113596Snectar	}
1321113596Snectar	if (rv != NS_SUCCESS)
1322113596Snectar		return (rv);
1323113596Snectar	if (compat_is_excluded(pwd->pw_name, st->exclude)) {
1324113596Snectar		if (how == nss_lt_all)
1325113596Snectar			goto more;
1326113596Snectar		return (NS_NOTFOUND);
1327113596Snectar	}
1328113596Snectar	e = compat_use_template(pwd, &st->template, buffer, bufsize);
1329113596Snectar	if (e != 0) {
1330113596Snectar		*errnop = e;
1331113596Snectar		if (e == ERANGE)
1332113596Snectar			return (NS_RETURN);
1333113596Snectar		else
1334113596Snectar			return (NS_UNAVAIL);
1335113596Snectar	}
1336113596Snectar	switch (how) {
1337113596Snectar	case nss_lt_name:
1338113596Snectar		if (strcmp(name, pwd->pw_name) != 0)
1339113596Snectar			return (NS_NOTFOUND);
1340113596Snectar		break;
1341113596Snectar	case nss_lt_id:
1342113596Snectar		if (uid != pwd->pw_uid)
1343113596Snectar			return (NS_NOTFOUND);
1344113596Snectar		break;
1345113596Snectar	default:
1346113596Snectar		break;
1347113596Snectar	}
1348113596Snectar	return (NS_SUCCESS);
1349113596Snectar}
135065532Snectar
135165532Snectar
1352113596Snectarstatic void
1353113596Snectarcompat_endstate(void *p)
1354113596Snectar{
1355113596Snectar	struct compat_state *st;
135665532Snectar
1357113596Snectar	if (p == NULL)
1358113596Snectar		return;
1359113596Snectar	st = (struct compat_state *)p;
1360113596Snectar	if (st->db != NULL)
1361113596Snectar		st->db->close(st->db);
1362113596Snectar	if (st->exclude != NULL)
1363113596Snectar		st->exclude->close(st->exclude);
1364113596Snectar	compat_clear_template(&st->template);
1365113596Snectar	free(p);
1366113596Snectar}
136765532Snectar
136865532Snectar
1369113596Snectarstatic int
1370113596Snectarcompat_setpwent(void *retval, void *mdata, va_list ap)
1371113596Snectar{
1372113596Snectar	struct compat_state	*st;
1373113596Snectar	int			 rv, stayopen;
137465532Snectar
1375113596Snectar	rv = compat_getstate(&st);
1376113596Snectar	if (rv != 0)
1377113596Snectar		return (NS_UNAVAIL);
1378113596Snectar	switch ((enum constants)mdata) {
1379113596Snectar	case SETPWENT:
1380113596Snectar		stayopen = va_arg(ap, int);
1381113596Snectar		st->keynum = 0;
1382113596Snectar		if (stayopen)
1383113596Snectar			st->db = pwdbopen(&st->version);
1384113596Snectar		st->stayopen = stayopen;
1385113596Snectar		break;
1386113596Snectar	case ENDPWENT:
1387113596Snectar		if (st->db != NULL) {
1388113596Snectar			(void)st->db->close(st->db);
1389113596Snectar			st->db = NULL;
139065532Snectar		}
1391113596Snectar		break;
1392113596Snectar	default:
1393113596Snectar		break;
139410521Swpaul	}
1395113596Snectar	return (NS_UNAVAIL);
139610521Swpaul}
139720119Swpaul
139820119Swpaul
13999332Swpaulstatic int
1400113596Snectarcompat_passwd(void *retval, void *mdata, va_list ap)
14012917Swollman{
1402113596Snectar	char			 keybuf[MAXLOGNAME + 1];
1403113596Snectar	DBT			 key, entry;
1404113596Snectar	struct compat_state	*st;
1405113596Snectar	enum nss_lookup_type	 how;
1406113596Snectar	const char		*name;
1407113596Snectar	struct passwd		*pwd;
1408113596Snectar	char			*buffer, *pw_name;
1409113596Snectar	char			*host, *user, *domain;
1410113596Snectar	size_t			 bufsize;
1411113596Snectar	uid_t			 uid;
1412113596Snectar	uint32_t		 store;
1413113596Snectar	int			 rv, stayopen, *errnop;
14142917Swollman
141565532Snectar	name = NULL;
1416113596Snectar	uid = (uid_t)-1;
1417113596Snectar	how = (enum nss_lookup_type)mdata;
1418113596Snectar	switch (how) {
1419113596Snectar	case nss_lt_name:
1420113596Snectar		name = va_arg(ap, const char *);
142165532Snectar		break;
1422113596Snectar	case nss_lt_id:
142365532Snectar		uid = va_arg(ap, uid_t);
142465532Snectar		break;
1425113596Snectar	case nss_lt_all:
1426113596Snectar		break;
142765532Snectar	default:
1428113596Snectar		rv = NS_NOTFOUND;
1429113596Snectar		goto fin;
14302917Swollman	}
1431113596Snectar	pwd = va_arg(ap, struct passwd *);
1432113596Snectar	buffer = va_arg(ap, char *);
1433113596Snectar	bufsize = va_arg(ap, size_t);
1434113596Snectar	errnop = va_arg(ap, int *);
1435113596Snectar	*errnop = compat_getstate(&st);
1436113596Snectar	if (*errnop != 0)
1437113596Snectar		return (NS_UNAVAIL);
1438113596Snectar	if (how == nss_lt_all && st->keynum < 0) {
1439113596Snectar		rv = NS_NOTFOUND;
1440113596Snectar		goto fin;
1441113596Snectar	}
1442113596Snectar	if (st->db == NULL &&
1443113596Snectar	    (st->db = pwdbopen(&st->version)) == NULL) {
1444113596Snectar		*errnop = errno;
1445113596Snectar		rv = NS_UNAVAIL;
1446113596Snectar		goto fin;
1447113596Snectar	}
1448113596Snectar	if (how == nss_lt_all) {
1449113596Snectar		if (st->keynum < 0) {
1450113596Snectar			rv = NS_NOTFOUND;
1451113596Snectar			goto fin;
1452113596Snectar		}
1453113596Snectar		stayopen = 1;
1454113596Snectar	} else {
1455113596Snectar		st->keynum = 0;
1456113596Snectar		stayopen = st->stayopen;
1457113596Snectar	}
1458113596Snectardocompat:
1459113596Snectar	rv = NS_NOTFOUND;
1460113596Snectar	switch (st->compat) {
1461113596Snectar	case COMPAT_MODE_ALL:
1462113596Snectar		rv = compat_redispatch(st, how, how, name, name, uid, pwd,
1463113596Snectar		    buffer, bufsize, errnop);
1464113596Snectar		if (rv != NS_SUCCESS)
1465113596Snectar			st->compat = COMPAT_MODE_OFF;
1466113596Snectar		break;
1467113596Snectar	case COMPAT_MODE_NETGROUP:
1468113596Snectar		/* XXX getnetgrent is not thread-safe. */
1469113596Snectar		do {
1470113596Snectar			rv = getnetgrent(&host, &user, &domain);
1471113596Snectar			if (rv == 0) {
1472113596Snectar				endnetgrent();
1473113596Snectar				st->compat = COMPAT_MODE_OFF;
1474113596Snectar				rv = NS_NOTFOUND;
1475113596Snectar				continue;
1476113596Snectar			} else if (user == NULL || user[0] == '\0')
1477113596Snectar				continue;
1478113596Snectar			rv = compat_redispatch(st, how, nss_lt_name, name,
1479113596Snectar			    user, uid, pwd, buffer, bufsize, errnop);
1480113596Snectar		} while (st->compat == COMPAT_MODE_NETGROUP &&
1481113596Snectar		    !(rv & NS_TERMINATE));
1482113596Snectar		break;
1483113596Snectar	case COMPAT_MODE_NAME:
1484113596Snectar		rv = compat_redispatch(st, how, nss_lt_name, name, st->name,
1485113596Snectar		    uid, pwd, buffer, bufsize, errnop);
1486113596Snectar		free(st->name);
1487113596Snectar		st->name = NULL;
1488113596Snectar		st->compat = COMPAT_MODE_OFF;
1489113596Snectar		break;
1490113596Snectar	default:
1491113596Snectar		break;
1492113596Snectar	}
1493113596Snectar	if (rv & NS_TERMINATE)
1494113596Snectar		goto fin;
1495113596Snectar	key.data = keybuf;
1496113596Snectar	rv = NS_NOTFOUND;
1497113596Snectar	while (st->keynum >= 0) {
1498113596Snectar		st->keynum++;
1499113596Snectar		if (st->version < _PWD_CURRENT_VERSION) {
1500113596Snectar			memcpy(&keybuf[1], &st->keynum, sizeof(st->keynum));
1501113596Snectar			key.size = sizeof(st->keynum) + 1;
1502113596Snectar		} else {
1503113596Snectar			store = htonl(st->keynum);
1504113596Snectar			memcpy(&keybuf[1], &store, sizeof(store));
1505113596Snectar			key.size = sizeof(store) + 1;
1506113596Snectar		}
1507113666Snectar		keybuf[0] = _PW_VERSIONED(_PW_KEYBYNUM, st->version);
1508113596Snectar		rv = st->db->get(st->db, &key, &entry, 0);
1509113596Snectar		if (rv < 0 || rv > 1) { /* should never return > 1 */
1510113596Snectar			*errnop = errno;
1511113596Snectar			rv = NS_UNAVAIL;
1512113596Snectar			goto fin;
1513113596Snectar		} else if (rv == 1) {
1514113596Snectar			st->keynum = -1;
1515113596Snectar			rv = NS_NOTFOUND;
1516113596Snectar			goto fin;
1517113596Snectar		}
1518113596Snectar		pw_name = (char *)entry.data;
1519113596Snectar		switch (pw_name[0]) {
152065532Snectar		case '+':
1521113596Snectar			switch (pw_name[1]) {
152265532Snectar			case '\0':
1523113596Snectar				st->compat = COMPAT_MODE_ALL;
152465532Snectar				break;
152565532Snectar			case '@':
1526113596Snectar				setnetgrent(&pw_name[2]);
1527113596Snectar				st->compat = COMPAT_MODE_NETGROUP;
152865532Snectar				break;
152965532Snectar			default:
1530113596Snectar				st->name = strdup(&pw_name[1]);
1531113596Snectar				if (st->name == NULL) {
1532113596Snectar					syslog(LOG_ERR,
1533113596Snectar					 "getpwent memory allocation failure");
1534113596Snectar					*errnop = ENOMEM;
1535113596Snectar					rv = NS_UNAVAIL;
1536113596Snectar					break;
1537113596Snectar				}
1538113596Snectar				st->compat = COMPAT_MODE_NAME;
153965532Snectar			}
1540113596Snectar			if (entry.size > bufsize) {
1541113596Snectar				*errnop = ERANGE;
1542113596Snectar				rv = NS_RETURN;
1543113596Snectar				goto fin;
154465532Snectar			}
1545113596Snectar			memcpy(buffer, entry.data, entry.size);
1546113596Snectar			rv = pwdb_versions[st->version].parse(buffer,
1547113596Snectar			    entry.size, pwd, errnop);
1548113596Snectar			if (rv != NS_SUCCESS)
1549113596Snectar				;
1550113596Snectar			else if (compat_set_template(pwd, &st->template) < 0) {
1551113596Snectar				*errnop = ENOMEM;
1552113596Snectar				rv = NS_UNAVAIL;
1553113596Snectar				goto fin;
1554113596Snectar			}
1555113596Snectar			goto docompat;
155665532Snectar		case '-':
1557113596Snectar			switch (pw_name[1]) {
155865532Snectar			case '\0':
1559113596Snectar				/* XXX Maybe syslog warning */
1560113596Snectar				continue;
156165532Snectar			case '@':
1562113596Snectar				setnetgrent(&pw_name[2]);
1563113596Snectar				while (getnetgrent(&host, &user, &domain) !=
1564113596Snectar				    NULL) {
1565113596Snectar					if (user != NULL && user[0] != '\0')
1566113596Snectar						compat_exclude(user,
1567113596Snectar						    &st->exclude);
156865532Snectar				}
156965532Snectar				endnetgrent();
1570113596Snectar				continue;
157165532Snectar			default:
1572113596Snectar				compat_exclude(&pw_name[1], &st->exclude);
1573113596Snectar				continue;
157465532Snectar			}
157565532Snectar			break;
157696186Sdes		default:
1577113596Snectar			break;
15786190Swpaul		}
1579113596Snectar		if (compat_is_excluded((char *)entry.data, st->exclude))
1580113596Snectar			continue;
1581113596Snectar		rv = pwdb_versions[st->version].match(entry.data, entry.size,
1582113596Snectar		    how, name, uid);
1583113596Snectar		if (rv == NS_RETURN)
158465532Snectar			break;
1585113596Snectar		else if (rv != NS_SUCCESS)
1586113596Snectar			continue;
1587113596Snectar		if (entry.size > bufsize) {
1588113596Snectar			*errnop = ERANGE;
1589113596Snectar			rv = NS_RETURN;
1590113596Snectar			break;
159165532Snectar		}
1592113596Snectar		memcpy(buffer, entry.data, entry.size);
1593113596Snectar		rv = pwdb_versions[st->version].parse(buffer, entry.size, pwd,
1594113596Snectar		    errnop);
1595113596Snectar		if (rv & NS_TERMINATE)
1596113596Snectar			break;
15972917Swollman	}
1598113596Snectarfin:
1599113596Snectar	if (!stayopen && st->db != NULL) {
1600113596Snectar		(void)st->db->close(st->db);
1601113596Snectar		st->db = NULL;
16026076Swpaul	}
1603113596Snectar	if (rv == NS_SUCCESS && retval != NULL)
1604113596Snectar		*(struct passwd **)retval = pwd;
1605113596Snectar	return (rv);
160665532Snectar}
16076076Swpaul
16089332Swpaul
1609113596Snectar/*
1610113596Snectar * common passwd line matching and parsing
1611113596Snectar */
161265532Snectarint
1613113596Snectar__pw_match_entry(const char *entry, size_t entrysize, enum nss_lookup_type how,
1614113596Snectar    const char *name, uid_t uid)
16152917Swollman{
1616113596Snectar	const char	*p, *eom;
1617113596Snectar	char		*q;
1618113596Snectar	size_t		 len;
1619113596Snectar	unsigned long	 m;
16202917Swollman
1621113596Snectar	eom = entry + entrysize;
1622113596Snectar	for (p = entry; p < eom; p++)
1623113596Snectar		if (*p == ':')
1624113596Snectar			break;
1625113596Snectar	if (*p != ':')
1626113596Snectar		return (NS_NOTFOUND);
1627113596Snectar	if (how == nss_lt_all)
1628113596Snectar		return (NS_SUCCESS);
1629113596Snectar	if (how == nss_lt_name) {
1630113596Snectar		len = strlen(name);
1631113596Snectar		if (len == (p - entry) && memcmp(name, entry, len) == 0)
1632113596Snectar			return (NS_SUCCESS);
1633113596Snectar		else
1634113596Snectar			return (NS_NOTFOUND);
163545066Sdes	}
1636113596Snectar	for (p++; p < eom; p++)
1637113596Snectar		if (*p == ':')
1638113596Snectar			break;
1639113596Snectar	if (*p != ':')
1640113596Snectar		return (NS_NOTFOUND);
1641113596Snectar	m = strtoul(++p, &q, 10);
1642113596Snectar	if (q[0] != ':' || (uid_t)m != uid)
1643113596Snectar		return (NS_NOTFOUND);
1644113596Snectar	else
1645113596Snectar		return (NS_SUCCESS);
164665532Snectar}
16472917Swollman
164815267Swpaul
1649113596Snectar/* XXX buffer must be NUL-terminated.  errnop is not set correctly. */
1650113596Snectarint
1651113596Snectar__pw_parse_entry(char *buffer, size_t bufsize __unused, struct passwd *pwd,
1652113596Snectar    int master, int *errnop __unused)
16532917Swollman{
16542917Swollman
1655113596Snectar	memset(pwd, 0, sizeof(*pwd));
1656113596Snectar	if (__pw_scan(buffer, pwd, master ? _PWSCAN_MASTER : 0) == 0)
1657113596Snectar		return (NS_NOTFOUND);
1658113596Snectar	else
1659113596Snectar		return (NS_SUCCESS);
16602917Swollman}
1661