getpwent.c revision 128537
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 128537 2004-04-21 21:15:08Z jon $");
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
94113694Snectarstatic	void	 pwd_init(struct passwd *);
95113672Snectar
96113596Snectarunion key {
97113596Snectar	const char	*name;
98113596Snectar	uid_t		 uid;
99113596Snectar};
100113596Snectar
101113596Snectarstatic	struct passwd *getpw(int (*fn)(union key, struct passwd *, char *,
102113596Snectar		    size_t, struct passwd **), union key);
103113596Snectarstatic	int	 wrap_getpwnam_r(union key, struct passwd *, char *,
104113596Snectar		    size_t, struct passwd **);
105113596Snectarstatic	int	 wrap_getpwuid_r(union key, struct passwd *, char *, size_t,
106113596Snectar		    struct passwd **);
107113596Snectarstatic	int	 wrap_getpwent_r(union key, struct passwd *, char *, size_t,
108113596Snectar		    struct passwd **);
109113596Snectar
110113596Snectarstatic	int	 pwdb_match_entry_v3(char *, size_t, enum nss_lookup_type,
111113596Snectar		    const char *, uid_t);
112113596Snectarstatic	int	 pwdb_parse_entry_v3(char *, size_t, struct passwd *, int *);
113113596Snectarstatic	int	 pwdb_match_entry_v4(char *, size_t, enum nss_lookup_type,
114113596Snectar		    const char *, uid_t);
115113596Snectarstatic	int	 pwdb_parse_entry_v4(char *, size_t, struct passwd *, int *);
116113596Snectar
117113596Snectar
118113596Snectarstruct {
119113596Snectar	int	(*match)(char *, size_t, enum nss_lookup_type, const char *,
120113596Snectar		    uid_t);
121113596Snectar	int	(*parse)(char *, size_t, struct passwd *, int *);
122113596Snectar} pwdb_versions[] = {
123113596Snectar	{ NULL, NULL },					/* version 0 */
124113596Snectar	{ NULL, NULL },					/* version 1 */
125113596Snectar	{ NULL, NULL },					/* version 2 */
126113596Snectar	{ pwdb_match_entry_v3, pwdb_parse_entry_v3 },	/* version 3 */
127113596Snectar	{ pwdb_match_entry_v4, pwdb_parse_entry_v4 },	/* version 4 */
128113596Snectar};
129113596Snectar
130113596Snectar
131113596Snectarstruct files_state {
132113596Snectar	DB		*db;
133113596Snectar	pwkeynum	 keynum;
134113596Snectar	int		 stayopen;
135113596Snectar	int		 version;
136113596Snectar};
137113596Snectarstatic	void	files_endstate(void *);
138113596SnectarNSS_TLS_HANDLING(files);
139113596Snectarstatic	DB	*pwdbopen(int *);
140113596Snectarstatic	void	 files_endstate(void *);
141113596Snectarstatic	int	 files_setpwent(void *, void *, va_list);
142113596Snectarstatic	int	 files_passwd(void *, void *, va_list);
143113596Snectar
144113596Snectar
14565532Snectar#ifdef HESIOD
146113596Snectarstruct dns_state {
147113596Snectar	long	counter;
148113596Snectar};
149113596Snectarstatic	void	dns_endstate(void *);
150113596SnectarNSS_TLS_HANDLING(dns);
151113596Snectarstatic	int	 dns_setpwent(void *, void *, va_list);
152113596Snectarstatic	int	 dns_passwd(void *, void *, va_list);
15311436Swpaul#endif
1542917Swollman
15565532Snectar
156113596Snectar#ifdef YP
157113596Snectarstruct nis_state {
158113596Snectar	char	 domain[MAXHOSTNAMELEN];
159113596Snectar	int	 done;
160113596Snectar	char	*key;
161113596Snectar	int	 keylen;
162113596Snectar};
163113596Snectarstatic	void	 nis_endstate(void *);
164113596SnectarNSS_TLS_HANDLING(nis);
165113596Snectarstatic	int	 nis_setpwent(void *, void *, va_list);
166113596Snectarstatic	int	 nis_passwd(void *, void *, va_list);
167113596Snectarstatic	int	 nis_map(char *, enum nss_lookup_type, char *, size_t, int *);
168113596Snectarstatic	int	 nis_adjunct(char *, const char *, char *, size_t);
169113596Snectar#endif
17065532Snectar
17165532Snectar
172113596Snectarstruct compat_state {
173113596Snectar	DB		*db;
174113596Snectar	pwkeynum	 keynum;
175113596Snectar	int		 stayopen;
176113596Snectar	int		 version;
177113596Snectar	DB		*exclude;
178113596Snectar	struct passwd	 template;
179113596Snectar	char		*name;
180113596Snectar	enum _compat {
181113596Snectar		COMPAT_MODE_OFF = 0,
182113596Snectar		COMPAT_MODE_ALL,
183113596Snectar		COMPAT_MODE_NAME,
184113596Snectar		COMPAT_MODE_NETGROUP
185113596Snectar	}		 compat;
186113596Snectar};
187113596Snectarstatic	void	 compat_endstate(void *);
188113596SnectarNSS_TLS_HANDLING(compat);
189113596Snectarstatic	int	 compat_setpwent(void *, void *, va_list);
190113596Snectarstatic	int	 compat_passwd(void *, void *, va_list);
191113596Snectarstatic	void	 compat_clear_template(struct passwd *);
192113596Snectarstatic	int	 compat_set_template(struct passwd *, struct passwd *);
193113596Snectarstatic	int	 compat_use_template(struct passwd *, struct passwd *, char *,
194113596Snectar		    size_t);
195113596Snectarstatic	int	 compat_redispatch(struct compat_state *, enum nss_lookup_type,
196113596Snectar		    enum nss_lookup_type, const char *, const char *, uid_t,
197113596Snectar		    struct passwd *, char *, size_t, int *);
198113596Snectarvoid
199113596Snectarsetpwent(void)
2001573Srgrimes{
201113596Snectar	static const ns_dtab dtab[] = {
202113596Snectar		{ NSSRC_FILES, files_setpwent, (void *)SETPWENT },
203113596Snectar#ifdef HESIOD
204113596Snectar		{ NSSRC_DNS, dns_setpwent, (void *)SETPWENT },
205113596Snectar#endif
206113596Snectar#ifdef YP
207113596Snectar		{ NSSRC_NIS, nis_setpwent, (void *)SETPWENT },
208113596Snectar#endif
209113596Snectar		{ NSSRC_COMPAT, compat_setpwent, (void *)SETPWENT },
210113596Snectar		{ NULL, NULL, NULL }
211113596Snectar	};
212113596Snectar	(void)_nsdispatch(NULL, dtab, NSDB_PASSWD, "setpwent", defaultsrc, 0);
213113596Snectar}
2141573Srgrimes
21510521Swpaul
216113596Snectarint
217113596Snectarsetpassent(int stayopen)
218113596Snectar{
219113596Snectar	static const ns_dtab dtab[] = {
220113596Snectar		{ NSSRC_FILES, files_setpwent, (void *)SETPWENT },
221113596Snectar#ifdef HESIOD
222113596Snectar		{ NSSRC_DNS, dns_setpwent, (void *)SETPWENT },
223113596Snectar#endif
224113596Snectar#ifdef YP
225113596Snectar		{ NSSRC_NIS, nis_setpwent, (void *)SETPWENT },
226113596Snectar#endif
227113596Snectar		{ NSSRC_COMPAT, compat_setpwent, (void *)SETPWENT },
228113596Snectar		{ NULL, NULL, NULL }
229113596Snectar	};
230113596Snectar	(void)_nsdispatch(NULL, dtab, NSDB_PASSWD, "setpwent", defaultsrc,
231113596Snectar	    stayopen);
232113596Snectar	return (1);
233113596Snectar}
23465532Snectar
23565532Snectar
236113596Snectarvoid
237113596Snectarendpwent(void)
238113596Snectar{
239113596Snectar	static const ns_dtab dtab[] = {
240113596Snectar		{ NSSRC_FILES, files_setpwent, (void *)ENDPWENT },
241113596Snectar#ifdef HESIOD
242113596Snectar		{ NSSRC_DNS, dns_setpwent, (void *)ENDPWENT },
243113596Snectar#endif
244113596Snectar#ifdef YP
245113596Snectar		{ NSSRC_NIS, nis_setpwent, (void *)ENDPWENT },
246113596Snectar#endif
247113596Snectar		{ NSSRC_COMPAT, compat_setpwent, (void *)ENDPWENT },
248113596Snectar		{ NULL, NULL, NULL }
249113596Snectar	};
250113596Snectar	(void)_nsdispatch(NULL, dtab, NSDB_PASSWD, "endpwent", defaultsrc);
2511573Srgrimes}
2521573Srgrimes
253113596Snectar
254113596Snectarint
255113596Snectargetpwent_r(struct passwd *pwd, char *buffer, size_t bufsize,
256113596Snectar    struct passwd **result)
2571573Srgrimes{
258113596Snectar	static const ns_dtab dtab[] = {
259113596Snectar		{ NSSRC_FILES, files_passwd, (void *)nss_lt_all },
260113596Snectar#ifdef HESIOD
261113596Snectar		{ NSSRC_DNS, dns_passwd, (void *)nss_lt_all },
262113596Snectar#endif
263113596Snectar#ifdef YP
264113596Snectar		{ NSSRC_NIS, nis_passwd, (void *)nss_lt_all },
265113596Snectar#endif
266113596Snectar		{ NSSRC_COMPAT, compat_passwd, (void *)nss_lt_all },
267113596Snectar		{ NULL, NULL, NULL }
268113596Snectar	};
269113596Snectar	int	rv, ret_errno;
2701573Srgrimes
271113694Snectar	pwd_init(pwd);
272113694Snectar	ret_errno = 0;
273113596Snectar	*result = NULL;
274113596Snectar	rv = _nsdispatch(result, dtab, NSDB_PASSWD, "getpwent_r", defaultsrc,
275113596Snectar	    pwd, buffer, bufsize, &ret_errno);
276113596Snectar	if (rv == NS_SUCCESS)
277113596Snectar		return (0);
278113596Snectar	else
279113596Snectar		return (ret_errno);
280113596Snectar}
2811573Srgrimes
2821573Srgrimes
283113596Snectarint
284113596Snectargetpwnam_r(const char *name, struct passwd *pwd, char *buffer, size_t bufsize,
285113596Snectar    struct passwd **result)
286113596Snectar{
287113596Snectar	static const ns_dtab dtab[] = {
288113596Snectar		{ NSSRC_FILES, files_passwd, (void *)nss_lt_name },
289113596Snectar#ifdef HESIOD
290113596Snectar		{ NSSRC_DNS, dns_passwd, (void *)nss_lt_name },
291113596Snectar#endif
292113596Snectar#ifdef YP
293113596Snectar		{ NSSRC_NIS, nis_passwd, (void *)nss_lt_name },
294113596Snectar#endif
295113596Snectar		{ NSSRC_COMPAT, compat_passwd, (void *)nss_lt_name },
296113596Snectar		{ NULL, NULL, NULL }
297113596Snectar	};
298113596Snectar	int	rv, ret_errno;
299113596Snectar
300113694Snectar	pwd_init(pwd);
301113694Snectar	ret_errno = 0;
302113596Snectar	*result = NULL;
303113596Snectar	rv = _nsdispatch(result, dtab, NSDB_PASSWD, "getpwnam_r", defaultsrc,
304113596Snectar	    name, pwd, buffer, bufsize, &ret_errno);
305113596Snectar	if (rv == NS_SUCCESS)
306113596Snectar		return (0);
307113596Snectar	else
308113596Snectar		return (ret_errno);
30965532Snectar}
3105714Swollman
311113596Snectar
312113596Snectarint
313113596Snectargetpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize,
314113596Snectar    struct passwd **result)
31565532Snectar{
316113596Snectar	static const ns_dtab dtab[] = {
317113596Snectar		{ NSSRC_FILES, files_passwd, (void *)nss_lt_id },
318113596Snectar#ifdef HESIOD
319113596Snectar		{ NSSRC_DNS, dns_passwd, (void *)nss_lt_id },
320113596Snectar#endif
321113596Snectar#ifdef YP
322113596Snectar		{ NSSRC_NIS, nis_passwd, (void *)nss_lt_id },
323113596Snectar#endif
324113596Snectar		{ NSSRC_COMPAT, compat_passwd, (void *)nss_lt_id },
325113596Snectar		{ NULL, NULL, NULL }
326113596Snectar	};
327113596Snectar	int	rv, ret_errno;
32865532Snectar
329113694Snectar	pwd_init(pwd);
330113694Snectar	ret_errno = 0;
331113596Snectar	*result = NULL;
332113596Snectar	rv = _nsdispatch(result, dtab, NSDB_PASSWD, "getpwuid_r", defaultsrc,
333113596Snectar	    uid, pwd, buffer, bufsize, &ret_errno);
334113596Snectar	if (rv == NS_SUCCESS)
335113596Snectar		return (0);
336113596Snectar	else
337113596Snectar		return (ret_errno);
338113596Snectar}
33965532Snectar
34065532Snectar
341113694Snectarstatic void
342113694Snectarpwd_init(struct passwd *pwd)
343113672Snectar{
344113694Snectar	static char nul[] = "";
345113672Snectar
346113672Snectar	memset(pwd, 0, sizeof(*pwd));
347113672Snectar	pwd->pw_uid = (uid_t)-1;  /* Considered least likely to lead to */
348113672Snectar	pwd->pw_gid = (gid_t)-1;  /* a security issue.                  */
349113694Snectar	pwd->pw_name = nul;
350113694Snectar	pwd->pw_passwd = nul;
351113694Snectar	pwd->pw_class = nul;
352113694Snectar	pwd->pw_gecos = nul;
353113694Snectar	pwd->pw_dir = nul;
354113694Snectar	pwd->pw_shell = nul;
355113672Snectar}
356113672Snectar
357113672Snectar
358113596Snectarstatic struct passwd	 pwd;
359113596Snectarstatic char		*pwd_storage;
360113596Snectarstatic size_t		 pwd_storage_size;
36168577Snectar
36265532Snectar
363113596Snectarstatic struct passwd *
364113596Snectargetpw(int (*fn)(union key, struct passwd *, char *, size_t, struct passwd **),
365113596Snectar    union key key)
366113596Snectar{
367113596Snectar	int		 rv;
368113596Snectar	struct passwd	*res;
36965532Snectar
370113596Snectar	if (pwd_storage == NULL) {
371113596Snectar		pwd_storage = malloc(PWD_STORAGE_INITIAL);
372113596Snectar		if (pwd_storage == NULL)
373113596Snectar			return (NULL);
374113596Snectar		pwd_storage_size = PWD_STORAGE_INITIAL;
37568577Snectar	}
376113596Snectar	do {
377113596Snectar		rv = fn(key, &pwd, pwd_storage, pwd_storage_size, &res);
378113596Snectar		if (res == NULL && rv == ERANGE) {
379113596Snectar			free(pwd_storage);
380113596Snectar			if ((pwd_storage_size << 1) > PWD_STORAGE_MAX) {
381113596Snectar				pwd_storage = NULL;
382113596Snectar				return (NULL);
383113596Snectar			}
384113596Snectar			pwd_storage_size <<= 1;
385113596Snectar			pwd_storage = malloc(pwd_storage_size);
386113596Snectar			if (pwd_storage == NULL)
387113596Snectar				return (NULL);
388113596Snectar		}
389113596Snectar	} while (res == NULL && rv == ERANGE);
390113596Snectar	return (res);
391113596Snectar}
39265532Snectar
393113596Snectar
394113596Snectarstatic int
395113596Snectarwrap_getpwnam_r(union key key, struct passwd *pwd, char *buffer,
396113596Snectar    size_t bufsize, struct passwd **res)
397113596Snectar{
398113596Snectar	return (getpwnam_r(key.name, pwd, buffer, bufsize, res));
3991573Srgrimes}
4001573Srgrimes
401113596Snectar
40265532Snectarstatic int
403113596Snectarwrap_getpwuid_r(union key key, struct passwd *pwd, char *buffer,
404113596Snectar    size_t bufsize, struct passwd **res)
4051573Srgrimes{
406113596Snectar	return (getpwuid_r(key.uid, pwd, buffer, bufsize, res));
407113596Snectar}
4081573Srgrimes
4091573Srgrimes
410113596Snectarstatic int
411113596Snectarwrap_getpwent_r(union key key __unused, struct passwd *pwd, char *buffer,
412113596Snectar    size_t bufsize, struct passwd **res)
413113596Snectar{
414113596Snectar	return (getpwent_r(pwd, buffer, bufsize, res));
415113596Snectar}
4161573Srgrimes
41765532Snectar
418113596Snectarstruct passwd *
419113596Snectargetpwnam(const char *name)
420113596Snectar{
421113596Snectar	union key key;
42265532Snectar
423113596Snectar	key.name = name;
424113596Snectar	return (getpw(wrap_getpwnam_r, key));
425113596Snectar}
4267258Swpaul
4271573Srgrimes
428113596Snectarstruct passwd *
429113596Snectargetpwuid(uid_t uid)
430113596Snectar{
431113596Snectar	union key key;
432113596Snectar
433113596Snectar	key.uid = uid;
434113596Snectar	return (getpw(wrap_getpwuid_r, key));
4351573Srgrimes}
4361573Srgrimes
437113596Snectar
438113596Snectarstruct passwd *
439113596Snectargetpwent(void)
440113596Snectar{
441113596Snectar	union key key;
442113596Snectar
443113596Snectar	key.uid = 0; /* not used */
444113596Snectar	return (getpw(wrap_getpwent_r, key));
445113596Snectar}
446113596Snectar
447113596Snectar
44865532Snectar/*
449113596Snectar * files backend
45065532Snectar */
451113596Snectarstatic DB *
452113596Snectarpwdbopen(int *version)
4531573Srgrimes{
454113596Snectar	DB	*res;
455113596Snectar	DBT	 key, entry;
456113596Snectar	int	 rv;
4571573Srgrimes
458113596Snectar	if (geteuid() != 0 ||
459113596Snectar	    (res = dbopen(_PATH_SMP_DB, O_RDONLY, 0, DB_HASH, NULL)) == NULL)
460113596Snectar		res = dbopen(_PATH_MP_DB, O_RDONLY, 0, DB_HASH, NULL);
461113596Snectar	if (res == NULL)
462113596Snectar		return (NULL);
463113596Snectar	key.data = _PWD_VERSION_KEY;
464113596Snectar	key.size = strlen(_PWD_VERSION_KEY);
465113596Snectar	rv = res->get(res, &key, &entry, 0);
466113596Snectar	if (rv == 0)
467113596Snectar		*version = *(unsigned char *)entry.data;
468113596Snectar	else
469113596Snectar		*version = 3;
470113596Snectar	if (*version < 3 ||
471113596Snectar	    *version >= sizeof(pwdb_versions)/sizeof(pwdb_versions[0])) {
472113596Snectar		syslog(LOG_CRIT, "Unsupported password database version %d",
473113596Snectar		    *version);
474113596Snectar		res->close(res);
475113596Snectar		res = NULL;
47615267Swpaul	}
477113596Snectar	return (res);
478113596Snectar}
47965532Snectar
48065532Snectar
481113596Snectarstatic void
482113596Snectarfiles_endstate(void *p)
483113596Snectar{
484113596Snectar	DB	*db;
485113596Snectar
486113596Snectar	if (p == NULL)
487113596Snectar		return;
488113596Snectar	db = ((struct files_state *)p)->db;
489113596Snectar	if (db != NULL)
490113596Snectar		db->close(db);
491113596Snectar	free(p);
492113596Snectar}
493113596Snectar
494113596Snectar
495113596Snectarstatic int
496113596Snectarfiles_setpwent(void *retval, void *mdata, va_list ap)
497113596Snectar{
498113596Snectar	struct files_state	*st;
499113596Snectar	int			 rv, stayopen;
500113596Snectar
501113596Snectar	rv = files_getstate(&st);
502113596Snectar	if (rv != 0)
503113596Snectar		return (NS_UNAVAIL);
504113596Snectar	switch ((enum constants)mdata) {
505113596Snectar	case SETPWENT:
506113596Snectar		stayopen = va_arg(ap, int);
507113596Snectar		st->keynum = 0;
508113596Snectar		if (stayopen)
509113596Snectar			st->db = pwdbopen(&st->version);
510113596Snectar		st->stayopen = stayopen;
511113596Snectar		break;
512113596Snectar	case ENDPWENT:
513113596Snectar		if (st->db != NULL) {
514113596Snectar			(void)st->db->close(st->db);
515113596Snectar			st->db = NULL;
51665532Snectar		}
517113596Snectar		break;
518113596Snectar	default:
519113596Snectar		break;
52015267Swpaul	}
521113596Snectar	return (NS_UNAVAIL);
5221573Srgrimes}
5231573Srgrimes
52465532Snectar
52517141Sjkhstatic int
526113596Snectarfiles_passwd(void *retval, void *mdata, va_list ap)
5271573Srgrimes{
528113596Snectar	char			 keybuf[MAXLOGNAME + 1];
529113596Snectar	DBT			 key, entry;
530113596Snectar	struct files_state	*st;
531113596Snectar	enum nss_lookup_type	 how;
532113596Snectar	const char		*name;
533113596Snectar	struct passwd		*pwd;
534113596Snectar	char			*buffer;
535113596Snectar	size_t			 bufsize, namesize;
536113596Snectar	uid_t			 uid;
537113596Snectar	uint32_t		 store;
538113596Snectar	int			 rv, stayopen, *errnop;
5391573Srgrimes
540113596Snectar	name = NULL;
541113596Snectar	uid = (uid_t)-1;
542113596Snectar	how = (enum nss_lookup_type)mdata;
543113596Snectar	switch (how) {
544113596Snectar	case nss_lt_name:
54565532Snectar		name = va_arg(ap, const char *);
546113596Snectar		keybuf[0] = _PW_KEYBYNAME;
54765532Snectar		break;
548113596Snectar	case nss_lt_id:
54965532Snectar		uid = va_arg(ap, uid_t);
550113596Snectar		keybuf[0] = _PW_KEYBYUID;
55165532Snectar		break;
552113596Snectar	case nss_lt_all:
553113596Snectar		keybuf[0] = _PW_KEYBYNUM;
554113596Snectar		break;
55565532Snectar	default:
556113596Snectar		rv = NS_NOTFOUND;
557113596Snectar		goto fin;
55865532Snectar	}
559113596Snectar	pwd = va_arg(ap, struct passwd *);
560113596Snectar	buffer = va_arg(ap, char *);
561113596Snectar	bufsize = va_arg(ap, size_t);
562113596Snectar	errnop = va_arg(ap, int *);
563113596Snectar	*errnop = files_getstate(&st);
564113596Snectar	if (*errnop != 0)
565113596Snectar		return (NS_UNAVAIL);
566113596Snectar	if (how == nss_lt_all && st->keynum < 0) {
567113596Snectar		rv = NS_NOTFOUND;
568113596Snectar		goto fin;
56965532Snectar	}
570113596Snectar	if (st->db == NULL &&
571113596Snectar	    (st->db = pwdbopen(&st->version)) == NULL) {
572113596Snectar		*errnop = errno;
573113596Snectar		rv = NS_UNAVAIL;
574113596Snectar		goto fin;
57594688Sdes	}
576113596Snectar	if (how == nss_lt_all)
577113596Snectar		stayopen = 1;
578113596Snectar	else
579113596Snectar		stayopen = st->stayopen;
580113596Snectar	key.data = keybuf;
581113596Snectar	do {
582113596Snectar		switch (how) {
583113596Snectar		case nss_lt_name:
584113596Snectar			/* MAXLOGNAME includes NUL byte, but we do not
585113596Snectar			 * include the NUL byte in the key.
586113596Snectar			 */
587114443Snectar			namesize = strlcpy(&keybuf[1], name, sizeof(keybuf)-1);
588113596Snectar			if (namesize >= sizeof(keybuf)-1) {
589113596Snectar				*errnop = EINVAL;
590113596Snectar				rv = NS_NOTFOUND;
591113596Snectar				goto fin;
592113596Snectar			}
593113596Snectar			key.size = namesize + 1;
594113596Snectar			break;
595113596Snectar		case nss_lt_id:
596113596Snectar			if (st->version < _PWD_CURRENT_VERSION) {
597113596Snectar				memcpy(&keybuf[1], &uid, sizeof(uid));
598113596Snectar				key.size = sizeof(uid) + 1;
599113596Snectar			} else {
600113596Snectar				store = htonl(uid);
601113596Snectar				memcpy(&keybuf[1], &store, sizeof(store));
602113596Snectar				key.size = sizeof(store) + 1;
603113596Snectar			}
604113596Snectar			break;
605113596Snectar		case nss_lt_all:
606113596Snectar			st->keynum++;
607113596Snectar			if (st->version < _PWD_CURRENT_VERSION) {
608113596Snectar				memcpy(&keybuf[1], &st->keynum,
609113596Snectar				    sizeof(st->keynum));
610113596Snectar				key.size = sizeof(st->keynum) + 1;
611113596Snectar			} else {
612113596Snectar				store = htonl(st->keynum);
613113596Snectar				memcpy(&keybuf[1], &store, sizeof(store));
614113596Snectar				key.size = sizeof(store) + 1;
615113596Snectar			}
616113596Snectar			break;
617113596Snectar		}
618113666Snectar		keybuf[0] = _PW_VERSIONED(keybuf[0], st->version);
619113596Snectar		rv = st->db->get(st->db, &key, &entry, 0);
620113596Snectar		if (rv < 0 || rv > 1) { /* should never return > 1 */
621113596Snectar			*errnop = errno;
622113596Snectar			rv = NS_UNAVAIL;
623113596Snectar			goto fin;
624113596Snectar		} else if (rv == 1) {
625113596Snectar			if (how == nss_lt_all)
626113596Snectar				st->keynum = -1;
627113596Snectar			rv = NS_NOTFOUND;
628113596Snectar			goto fin;
629113596Snectar		}
630113596Snectar		rv = pwdb_versions[st->version].match(entry.data, entry.size,
631113596Snectar		    how, name, uid);
632113596Snectar		if (rv != NS_SUCCESS)
633113596Snectar			continue;
634113596Snectar		if (entry.size > bufsize) {
635113596Snectar			*errnop = ERANGE;
636113596Snectar			rv = NS_RETURN;
637113596Snectar			break;
638113596Snectar		}
639113596Snectar		memcpy(buffer, entry.data, entry.size);
640113596Snectar		rv = pwdb_versions[st->version].parse(buffer, entry.size, pwd,
641113596Snectar		    errnop);
642113596Snectar	} while (how == nss_lt_all && !(rv & NS_TERMINATE));
643113596Snectarfin:
644113596Snectar	if (!stayopen && st->db != NULL) {
645113596Snectar		(void)st->db->close(st->db);
646113596Snectar		st->db = NULL;
647113596Snectar	}
648113670Snectar	if (rv == NS_SUCCESS) {
649113670Snectar		pwd->pw_fields &= ~_PWF_SOURCE;
650113670Snectar		pwd->pw_fields |= _PWF_FILES;
651113670Snectar		if (retval != NULL)
652113670Snectar			*(struct passwd **)retval = pwd;
653113670Snectar	}
654113596Snectar	return (rv);
6551573Srgrimes}
6561573Srgrimes
657113596Snectar
658113596Snectarstatic int
659124432Snectarpwdb_match_entry_v3(char *entry, size_t entrysize, enum nss_lookup_type how,
660113596Snectar    const char *name, uid_t uid)
661113596Snectar{
662113596Snectar	const char	*p, *eom;
663113596Snectar	uid_t		 uid2;
664113596Snectar
665113596Snectar	eom = &entry[entrysize];
666113596Snectar	for (p = entry; p < eom; p++)
667113596Snectar		if (*p == '\0')
668113596Snectar			break;
669113596Snectar	if (*p != '\0')
670113596Snectar		return (NS_NOTFOUND);
671113596Snectar	if (how == nss_lt_all)
672113596Snectar		return (NS_SUCCESS);
673124432Snectar	if (how == nss_lt_name)
674113596Snectar		return (strcmp(name, entry) == 0 ? NS_SUCCESS : NS_NOTFOUND);
675113596Snectar	for (p++; p < eom; p++)
676113596Snectar		if (*p == '\0')
677113596Snectar			break;
678113596Snectar	if (*p != '\0' || (++p) + sizeof(uid) >= eom)
679113596Snectar		return (NS_NOTFOUND);
680113596Snectar	memcpy(&uid2, p, sizeof(uid2));
681113596Snectar	return (uid == uid2 ? NS_SUCCESS : NS_NOTFOUND);
682113596Snectar}
683113596Snectar
684113596Snectar
685113596Snectarstatic int
686113596Snectarpwdb_parse_entry_v3(char *buffer, size_t bufsize, struct passwd *pwd,
687113596Snectar    int *errnop)
688113596Snectar{
689113596Snectar	char		*p, *eom;
690113596Snectar	int32_t		 pw_change, pw_expire;
691113596Snectar
692113596Snectar	/* THIS CODE MUST MATCH THAT IN pwd_mkdb. */
693113596Snectar	p = buffer;
694113596Snectar	eom = &buffer[bufsize];
695113596Snectar#define STRING(field)	do {			\
696113596Snectar		(field) = p;			\
697113596Snectar		while (p < eom && *p != '\0')	\
698113596Snectar			p++;			\
699113596Snectar		if (p >= eom)			\
700113596Snectar			return (NS_NOTFOUND);	\
701113596Snectar		p++;				\
702113596Snectar	} while (0)
703113596Snectar#define SCALAR(field)	do {				\
704113596Snectar		if (p + sizeof(field) > eom)		\
705113596Snectar			return (NS_NOTFOUND);		\
706113596Snectar		memcpy(&(field), p, sizeof(field));	\
707113596Snectar		p += sizeof(field);			\
708113596Snectar	} while (0)
709113596Snectar	STRING(pwd->pw_name);
710113596Snectar	STRING(pwd->pw_passwd);
711113596Snectar	SCALAR(pwd->pw_uid);
712113596Snectar	SCALAR(pwd->pw_gid);
713113596Snectar	SCALAR(pw_change);
714113596Snectar	STRING(pwd->pw_class);
715113596Snectar	STRING(pwd->pw_gecos);
716113596Snectar	STRING(pwd->pw_dir);
717113596Snectar	STRING(pwd->pw_shell);
718113596Snectar	SCALAR(pw_expire);
719113596Snectar	SCALAR(pwd->pw_fields);
720113596Snectar#undef STRING
721113596Snectar#undef SCALAR
722113596Snectar	pwd->pw_change = pw_change;
723113596Snectar	pwd->pw_expire = pw_expire;
724113596Snectar	return (NS_SUCCESS);
725113596Snectar}
726113596Snectar
727113596Snectar
728113596Snectarstatic int
729124432Snectarpwdb_match_entry_v4(char *entry, size_t entrysize, enum nss_lookup_type how,
730113596Snectar    const char *name, uid_t uid)
731113596Snectar{
732113596Snectar	const char	*p, *eom;
733113596Snectar	uint32_t	 uid2;
734113596Snectar
735113596Snectar	eom = &entry[entrysize];
736113596Snectar	for (p = entry; p < eom; p++)
737113596Snectar		if (*p == '\0')
738113596Snectar			break;
739113596Snectar	if (*p != '\0')
740113596Snectar		return (NS_NOTFOUND);
741113596Snectar	if (how == nss_lt_all)
742113596Snectar		return (NS_SUCCESS);
743124432Snectar	if (how == nss_lt_name)
744113596Snectar		return (strcmp(name, entry) == 0 ? NS_SUCCESS : NS_NOTFOUND);
745113596Snectar	for (p++; p < eom; p++)
746113596Snectar		if (*p == '\0')
747113596Snectar			break;
748113596Snectar	if (*p != '\0' || (++p) + sizeof(uid) >= eom)
749113596Snectar		return (NS_NOTFOUND);
750113596Snectar	memcpy(&uid2, p, sizeof(uid2));
751113596Snectar	uid2 = ntohl(uid2);
752113596Snectar	return (uid == (uid_t)uid2 ? NS_SUCCESS : NS_NOTFOUND);
753113596Snectar}
754113596Snectar
755113596Snectar
756113596Snectarstatic int
757113596Snectarpwdb_parse_entry_v4(char *buffer, size_t bufsize, struct passwd *pwd,
758113596Snectar    int *errnop)
759113596Snectar{
760113596Snectar	char		*p, *eom;
761113596Snectar	uint32_t	 n;
762113596Snectar
763113596Snectar	/* THIS CODE MUST MATCH THAT IN pwd_mkdb. */
764113596Snectar	p = buffer;
765113596Snectar	eom = &buffer[bufsize];
766113596Snectar#define STRING(field)	do {			\
767113596Snectar		(field) = p;			\
768113596Snectar		while (p < eom && *p != '\0')	\
769113596Snectar			p++;			\
770113596Snectar		if (p >= eom)			\
771113596Snectar			return (NS_NOTFOUND);	\
772113596Snectar		p++;				\
773113596Snectar	} while (0)
774113596Snectar#define SCALAR(field)	do {				\
775113596Snectar		if (p + sizeof(n) > eom)		\
776113596Snectar			return (NS_NOTFOUND);		\
777113596Snectar		memcpy(&n, p, sizeof(n));		\
778113596Snectar		(field) = ntohl(n);			\
779113596Snectar		p += sizeof(n);				\
780113596Snectar	} while (0)
781113596Snectar	STRING(pwd->pw_name);
782113596Snectar	STRING(pwd->pw_passwd);
783113596Snectar	SCALAR(pwd->pw_uid);
784113596Snectar	SCALAR(pwd->pw_gid);
785113596Snectar	SCALAR(pwd->pw_change);
786113596Snectar	STRING(pwd->pw_class);
787113596Snectar	STRING(pwd->pw_gecos);
788113596Snectar	STRING(pwd->pw_dir);
789113596Snectar	STRING(pwd->pw_shell);
790113596Snectar	SCALAR(pwd->pw_expire);
791113596Snectar	SCALAR(pwd->pw_fields);
792113596Snectar#undef STRING
793113596Snectar#undef SCALAR
794113596Snectar	return (NS_SUCCESS);
795113596Snectar}
796113596Snectar
797113596Snectar
79865532Snectar#ifdef HESIOD
79965532Snectar/*
800113596Snectar * dns backend
80165532Snectar */
802113596Snectarstatic void
803113596Snectardns_endstate(void *p)
804113596Snectar{
805113596Snectar	free(p);
806113596Snectar}
80765532Snectar
808113596Snectar
80917141Sjkhstatic int
810113596Snectardns_setpwent(void *retval, void *mdata, va_list ap)
8111573Srgrimes{
812113596Snectar	struct dns_state	*st;
813113596Snectar	int			 rv;
8141573Srgrimes
815113596Snectar	rv = dns_getstate(&st);
816113596Snectar	if (rv != 0)
817113596Snectar		return (NS_UNAVAIL);
818113596Snectar	st->counter = 0;
819113596Snectar	return (NS_UNAVAIL);
820113596Snectar}
8211573Srgrimes
822113596Snectar
823113596Snectarstatic int
824113596Snectardns_passwd(void *retval, void *mdata, va_list ap)
825113596Snectar{
826113596Snectar	char			 buf[HESIOD_NAME_MAX];
827113596Snectar	struct dns_state	*st;
828113596Snectar	struct passwd		*pwd;
829113596Snectar	const char		*name, *label;
830113596Snectar	void			*ctx;
831113596Snectar	char			*buffer, **hes;
832113596Snectar	size_t			 bufsize, linesize;
833113596Snectar	uid_t			 uid;
834113596Snectar	enum nss_lookup_type	 how;
835113596Snectar	int			 rv, *errnop;
836113596Snectar
837113596Snectar	ctx = NULL;
838113596Snectar	hes = NULL;
839113596Snectar	name = NULL;
840113596Snectar	uid = (uid_t)-1;
841113596Snectar	how = (enum nss_lookup_type)mdata;
842113596Snectar	switch (how) {
843113596Snectar	case nss_lt_name:
84465532Snectar		name = va_arg(ap, const char *);
84565532Snectar		break;
846113596Snectar	case nss_lt_id:
84765532Snectar		uid = va_arg(ap, uid_t);
84865532Snectar		break;
849113596Snectar	case nss_lt_all:
850113596Snectar		break;
85129479Swosch	}
852113596Snectar	pwd     = va_arg(ap, struct passwd *);
853113596Snectar	buffer  = va_arg(ap, char *);
854113596Snectar	bufsize = va_arg(ap, size_t);
855113596Snectar	errnop  = va_arg(ap, int *);
856113596Snectar	*errnop = dns_getstate(&st);
857113596Snectar	if (*errnop != 0)
858113596Snectar		return (NS_UNAVAIL);
859113596Snectar	if (hesiod_init(&ctx) != 0) {
860113596Snectar		*errnop = errno;
861113596Snectar		rv = NS_UNAVAIL;
862113596Snectar		goto fin;
863113596Snectar	}
864113596Snectar	do {
865113596Snectar		rv = NS_NOTFOUND;
866113596Snectar		switch (how) {
867113596Snectar		case nss_lt_name:
868113596Snectar			label = name;
869113596Snectar			break;
870113596Snectar		case nss_lt_id:
871113596Snectar			if (snprintf(buf, sizeof(buf), "%lu",
872113596Snectar			    (unsigned long)uid) >= sizeof(buf))
873113596Snectar				goto fin;
874113596Snectar			label = buf;
875113596Snectar			break;
876113596Snectar		case nss_lt_all:
877113596Snectar			if (st->counter < 0)
878113596Snectar				goto fin;
879113596Snectar			if (snprintf(buf, sizeof(buf), "passwd-%ld",
880113596Snectar			    st->counter++) >= sizeof(buf))
881113596Snectar				goto fin;
882113596Snectar			label = buf;
883113596Snectar			break;
88465532Snectar		}
885113596Snectar		hes = hesiod_resolve(ctx, label,
886113596Snectar		    how == nss_lt_id ? "uid" : "passwd");
887113596Snectar		if (hes == NULL) {
888113596Snectar			if (how == nss_lt_all)
889113596Snectar				st->counter = -1;
890113596Snectar			if (errno != ENOENT)
891113596Snectar				*errnop = errno;
892113596Snectar			goto fin;
893113596Snectar		}
894113596Snectar		rv = __pw_match_entry(hes[0], strlen(hes[0]), how, name, uid);
895113596Snectar		if (rv != NS_SUCCESS) {
896113596Snectar			hesiod_free_list(ctx, hes);
897113596Snectar			hes = NULL;
898113596Snectar			continue;
899113596Snectar		}
900114443Snectar		linesize = strlcpy(buffer, hes[0], bufsize);
901113596Snectar		if (linesize >= bufsize) {
902113596Snectar			*errnop = ERANGE;
903113596Snectar			rv = NS_RETURN;
904113596Snectar			continue;
905113596Snectar		}
906113596Snectar		hesiod_free_list(ctx, hes);
907113596Snectar		hes = NULL;
908113596Snectar		rv = __pw_parse_entry(buffer, bufsize, pwd, 0, errnop);
909113596Snectar	} while (how == nss_lt_all && !(rv & NS_TERMINATE));
910113596Snectarfin:
911113596Snectar	if (hes != NULL)
912113596Snectar		hesiod_free_list(ctx, hes);
913113596Snectar	if (ctx != NULL)
914113596Snectar		hesiod_end(ctx);
915113596Snectar	if (rv == NS_SUCCESS) {
916113596Snectar		pwd->pw_fields &= ~_PWF_SOURCE;
917113596Snectar		pwd->pw_fields |= _PWF_HESIOD;
918113596Snectar		if (retval != NULL)
919113596Snectar			*(struct passwd **)retval = pwd;
92065532Snectar	}
921113596Snectar	return (rv);
92215267Swpaul}
923113596Snectar#endif /* HESIOD */
9247258Swpaul
925113596Snectar
92665532Snectar#ifdef YP
92715267Swpaul/*
928113596Snectar * nis backend
92915267Swpaul */
930113596Snectarstatic void
931113596Snectarnis_endstate(void *p)
932113596Snectar{
933113596Snectar	free(((struct nis_state *)p)->key);
934113596Snectar	free(p);
935113596Snectar}
93665532Snectar
937117750Swpaul/*
938117750Swpaul * Test for the presence of special FreeBSD-specific master.passwd.by*
939117750Swpaul * maps. We do this using yp_order(). If it fails, then either the server
940117750Swpaul * doesn't have the map, or the YPPROC_ORDER procedure isn't supported by
941117750Swpaul * the server (Sun NIS+ servers in YP compat mode behave this way). If
942117750Swpaul * the master.passwd.by* maps don't exist, then let the lookup routine try
943117750Swpaul * the regular passwd.by* maps instead. If the lookup routine fails, it
944117750Swpaul * can return an error as needed.
945117750Swpaul */
94665532Snectarstatic int
947113596Snectarnis_map(char *domain, enum nss_lookup_type how, char *buffer, size_t bufsize,
948113596Snectar    int *master)
94915267Swpaul{
950117750Swpaul	int	rv, order;
9517258Swpaul
952113596Snectar	*master = 0;
953113794Snectar	if (geteuid() == 0) {
954113794Snectar		if (snprintf(buffer, bufsize, "master.passwd.by%s",
955113794Snectar		    (how == nss_lt_id) ? "uid" : "name") >= bufsize)
956113794Snectar			return (NS_UNAVAIL);
957117750Swpaul		rv = yp_order(domain, buffer, &order);
958113794Snectar		if (rv == 0) {
959113794Snectar			*master = 1;
960113794Snectar			return (NS_SUCCESS);
961113794Snectar		}
96265532Snectar	}
963117750Swpaul
964113596Snectar	if (snprintf(buffer, bufsize, "passwd.by%s",
965113596Snectar	    (how == nss_lt_id) ? "uid" : "name") >= bufsize)
966113596Snectar		return (NS_UNAVAIL);
967117750Swpaul
968117750Swpaul	return (NS_SUCCESS);
969113596Snectar}
97015267Swpaul
971113596Snectar
972113596Snectarstatic int
973113596Snectarnis_adjunct(char *domain, const char *name, char *buffer, size_t bufsize)
974113596Snectar{
975113596Snectar	int	 rv;
976113596Snectar	char	*result, *p, *q, *eor;
977113596Snectar	int	 resultlen;
978113596Snectar
979113596Snectar	result = NULL;
980113596Snectar	rv = yp_match(domain, "passwd.adjunct.byname", name, strlen(name),
981113596Snectar	    &result, &resultlen);
982113596Snectar	if (rv != 0)
983113596Snectar		rv = 1;
984113596Snectar	else {
985113596Snectar		eor = &result[resultlen];
986113596Snectar		p = memchr(result, ':', eor - result);
987113596Snectar		if (p != NULL && ++p < eor &&
988113596Snectar		    (q = memchr(p, ':', eor - p)) != NULL) {
989113596Snectar			if (q - p >= bufsize)
990113596Snectar				rv = -1;
991113596Snectar			else {
992113596Snectar				memcpy(buffer, p, q - p);
993113596Snectar				buffer[q - p] ='\0';
994113596Snectar			}
995113596Snectar		} else
996113596Snectar			rv = 1;
997124432Snectar	}
998113596Snectar	free(result);
999113596Snectar	return (rv);
1000113596Snectar}
1001113596Snectar
1002113596Snectar
1003113596Snectarstatic int
1004113596Snectarnis_setpwent(void *retval, void *mdata, va_list ap)
1005113596Snectar{
1006113596Snectar	struct nis_state	*st;
1007113596Snectar	int			 rv;
1008113596Snectar
1009113596Snectar	rv = nis_getstate(&st);
1010113596Snectar	if (rv != 0)
1011113596Snectar		return (NS_UNAVAIL);
1012113596Snectar	st->done = 0;
1013113596Snectar	free(st->key);
1014113596Snectar	st->key = NULL;
1015113596Snectar	return (NS_UNAVAIL);
1016113596Snectar}
1017113596Snectar
1018113596Snectar
1019113596Snectarstatic int
1020113596Snectarnis_passwd(void *retval, void *mdata, va_list ap)
1021113596Snectar{
1022113596Snectar	char		 map[YPMAXMAP];
1023113596Snectar	struct nis_state *st;
1024113596Snectar	struct passwd	*pwd;
1025113596Snectar	const char	*name;
1026113596Snectar	char		*buffer, *key, *result;
1027113596Snectar	size_t		 bufsize;
1028113596Snectar	uid_t		 uid;
1029113596Snectar	enum nss_lookup_type how;
1030113596Snectar	int		*errnop, keylen, resultlen, rv, master;
1031124432Snectar
1032113596Snectar	name = NULL;
1033113596Snectar	uid = (uid_t)-1;
1034113596Snectar	how = (enum nss_lookup_type)mdata;
1035113596Snectar	switch (how) {
1036113596Snectar	case nss_lt_name:
103765532Snectar		name = va_arg(ap, const char *);
103865532Snectar		break;
1039113596Snectar	case nss_lt_id:
104065532Snectar		uid = va_arg(ap, uid_t);
104165532Snectar		break;
1042113596Snectar	case nss_lt_all:
1043113596Snectar		break;
104465532Snectar	}
1045113596Snectar	pwd     = va_arg(ap, struct passwd *);
1046113596Snectar	buffer  = va_arg(ap, char *);
1047113596Snectar	bufsize = va_arg(ap, size_t);
1048113596Snectar	errnop  = va_arg(ap, int *);
1049113596Snectar	*errnop = nis_getstate(&st);
1050113596Snectar	if (*errnop != 0)
1051113596Snectar		return (NS_UNAVAIL);
1052113596Snectar	if (st->domain[0] == '\0') {
1053113596Snectar		if (getdomainname(st->domain, sizeof(st->domain)) != 0) {
1054113596Snectar			*errnop = errno;
1055113596Snectar			return (NS_UNAVAIL);
105665532Snectar		}
105765532Snectar	}
1058113596Snectar	rv = nis_map(st->domain, how, map, sizeof(map), &master);
1059113596Snectar	if (rv != NS_SUCCESS)
1060113596Snectar		return (rv);
1061113596Snectar	result = NULL;
1062113596Snectar	do {
1063113596Snectar		rv = NS_NOTFOUND;
1064113596Snectar		switch (how) {
1065113596Snectar		case nss_lt_name:
1066114443Snectar			if (strlcpy(buffer, name, bufsize) >= bufsize)
1067113596Snectar				goto erange;
1068113596Snectar			break;
1069113596Snectar		case nss_lt_id:
1070113596Snectar			if (snprintf(buffer, bufsize, "%lu",
1071113596Snectar			    (unsigned long)uid) >= bufsize)
1072113596Snectar				goto erange;
1073113596Snectar			break;
1074113596Snectar		case nss_lt_all:
1075113596Snectar			if (st->done)
1076113596Snectar				goto fin;
1077113596Snectar			break;
1078113596Snectar		}
1079113596Snectar		result = NULL;
1080113596Snectar		if (how == nss_lt_all) {
1081113596Snectar			if (st->key == NULL)
1082113596Snectar				rv = yp_first(st->domain, map, &st->key,
1083113596Snectar				    &st->keylen, &result, &resultlen);
1084113596Snectar			else {
1085113596Snectar				key = st->key;
1086113596Snectar				keylen = st->keylen;
1087113596Snectar				st->key = NULL;
1088113596Snectar				rv = yp_next(st->domain, map, key, keylen,
1089113596Snectar				    &st->key, &st->keylen, &result,
1090113596Snectar				    &resultlen);
1091113596Snectar				free(key);
109265532Snectar			}
1093113596Snectar			if (rv != 0) {
1094113596Snectar				free(result);
1095113596Snectar				free(st->key);
1096113596Snectar				st->key = NULL;
1097113596Snectar				if (rv == YPERR_NOMORE)
1098113596Snectar					st->done = 1;
1099113596Snectar				else
1100113596Snectar					rv = NS_UNAVAIL;
1101113596Snectar				goto fin;
1102113596Snectar			}
110365532Snectar		} else {
1104113596Snectar			rv = yp_match(st->domain, map, buffer, strlen(buffer),
1105113596Snectar			    &result, &resultlen);
1106113596Snectar			if (rv == YPERR_KEY) {
1107113596Snectar				rv = NS_NOTFOUND;
1108113596Snectar				continue;
1109113596Snectar			} else if (rv != 0) {
1110113596Snectar				free(result);
1111113596Snectar				rv = NS_UNAVAIL;
1112113596Snectar				continue;
1113113596Snectar			}
111465532Snectar		}
1115113596Snectar		if (resultlen >= bufsize)
1116113596Snectar			goto erange;
1117113596Snectar		memcpy(buffer, result, resultlen);
1118113596Snectar		buffer[resultlen] = '\0';
1119113596Snectar		free(result);
1120113596Snectar		rv = __pw_match_entry(buffer, resultlen, how, name, uid);
1121113596Snectar		if (rv == NS_SUCCESS)
1122113596Snectar			rv = __pw_parse_entry(buffer, resultlen, pwd, master,
1123113596Snectar			    errnop);
1124113596Snectar	} while (how == nss_lt_all && !(rv & NS_TERMINATE));
1125124432Snectarfin:
1126113596Snectar	if (rv == NS_SUCCESS) {
1127113596Snectar		if (strstr(pwd->pw_passwd, "##") != NULL) {
1128124431Snectar			rv = nis_adjunct(st->domain, pwd->pw_name,
1129113596Snectar			    &buffer[resultlen+1], bufsize-resultlen-1);
1130113596Snectar			if (rv < 0)
1131113596Snectar				goto erange;
1132113596Snectar			else if (rv == 0)
1133113596Snectar				pwd->pw_passwd = &buffer[resultlen+1];
113465532Snectar		}
1135113596Snectar		pwd->pw_fields &= ~_PWF_SOURCE;
1136113596Snectar		pwd->pw_fields |= _PWF_NIS;
1137113596Snectar		if (retval != NULL)
1138113596Snectar			*(struct passwd **)retval = pwd;
1139128537Sjon		rv = NS_SUCCESS;
114015267Swpaul	}
1141124432Snectar	return (rv);
1142113596Snectarerange:
1143113596Snectar	*errnop = ERANGE;
1144113596Snectar	return (NS_RETURN);
1145113596Snectar}
1146113596Snectar#endif /* YP */
114715267Swpaul
1148113596Snectar
114915267Swpaul/*
1150113596Snectar * compat backend
115115267Swpaul */
1152113596Snectarstatic void
1153113596Snectarcompat_clear_template(struct passwd *template)
1154113596Snectar{
115565532Snectar
1156113596Snectar	free(template->pw_passwd);
1157113596Snectar	free(template->pw_gecos);
1158113596Snectar	free(template->pw_dir);
1159113596Snectar	free(template->pw_shell);
1160113596Snectar	memset(template, 0, sizeof(*template));
1161113596Snectar}
1162113596Snectar
1163113596Snectar
116465532Snectarstatic int
1165113596Snectarcompat_set_template(struct passwd *src, struct passwd *template)
116615267Swpaul{
116715267Swpaul
1168113596Snectar	compat_clear_template(template);
1169113596Snectar#ifdef PW_OVERRIDE_PASSWD
1170113596Snectar	if ((src->pw_fields & _PWF_PASSWD) &&
1171113596Snectar	    (template->pw_passwd = strdup(src->pw_passwd)) == NULL)
1172113596Snectar		goto enomem;
1173113596Snectar#endif
1174113596Snectar	if (src->pw_fields & _PWF_UID)
1175113596Snectar		template->pw_uid = src->pw_uid;
1176113596Snectar	if (src->pw_fields & _PWF_GID)
1177113596Snectar		template->pw_gid = src->pw_gid;
1178113596Snectar	if ((src->pw_fields & _PWF_GECOS) &&
1179113596Snectar	    (template->pw_gecos = strdup(src->pw_gecos)) == NULL)
1180113596Snectar		goto enomem;
1181113596Snectar	if ((src->pw_fields & _PWF_DIR) &&
1182113596Snectar	    (template->pw_dir = strdup(src->pw_dir)) == NULL)
1183113596Snectar		goto enomem;
1184113596Snectar	if ((src->pw_fields & _PWF_SHELL) &&
1185113596Snectar	    (template->pw_shell = strdup(src->pw_shell)) == NULL)
1186113596Snectar		goto enomem;
1187113596Snectar	template->pw_fields = src->pw_fields;
1188113596Snectar	return (0);
1189113596Snectarenomem:
1190113596Snectar	syslog(LOG_ERR, "getpwent memory allocation failure");
1191113596Snectar	return (-1);
1192113596Snectar}
119315267Swpaul
119415267Swpaul
1195113596Snectarstatic int
1196113596Snectarcompat_use_template(struct passwd *pwd, struct passwd *template, char *buffer,
1197113596Snectar    size_t bufsize)
1198113596Snectar{
1199113596Snectar	struct passwd hold;
1200113596Snectar	char	*copy, *p, *q, *eob;
1201113596Snectar	size_t	 n;
1202113596Snectar
1203113596Snectar	/* We cannot know the layout of the password fields in `buffer',
1204113596Snectar	 * so we have to copy everything.
1205113596Snectar	 */
1206113596Snectar	if (template->pw_fields == 0) /* nothing to fill-in */
1207113596Snectar		return (0);
1208113596Snectar	n = 0;
1209113596Snectar	n += pwd->pw_name != NULL ? strlen(pwd->pw_name) + 1 : 0;
1210113596Snectar	n += pwd->pw_passwd != NULL ? strlen(pwd->pw_passwd) + 1 : 0;
1211113596Snectar	n += pwd->pw_class != NULL ? strlen(pwd->pw_class) + 1 : 0;
1212113596Snectar	n += pwd->pw_gecos != NULL ? strlen(pwd->pw_gecos) + 1 : 0;
1213113596Snectar	n += pwd->pw_dir != NULL ? strlen(pwd->pw_dir) + 1 : 0;
1214113596Snectar	n += pwd->pw_shell != NULL ? strlen(pwd->pw_shell) + 1 : 0;
1215113596Snectar	copy = malloc(n);
1216113596Snectar	if (copy == NULL) {
1217113596Snectar		syslog(LOG_ERR, "getpwent memory allocation failure");
1218113596Snectar		return (ENOMEM);
1219113596Snectar	}
1220113596Snectar	p = copy;
1221113596Snectar	eob = &copy[n];
1222113596Snectar#define COPY(field) do {				\
1223113596Snectar	if (pwd->field == NULL)				\
1224113596Snectar		hold.field = NULL;			\
1225113596Snectar	else {						\
1226113596Snectar		hold.field = p;				\
1227114443Snectar		p += strlcpy(p, pwd->field, eob-p) + 1;	\
1228113596Snectar	}						\
1229113596Snectar} while (0)
1230113596Snectar	COPY(pw_name);
1231113596Snectar	COPY(pw_passwd);
1232113596Snectar	COPY(pw_class);
1233113596Snectar	COPY(pw_gecos);
1234113596Snectar	COPY(pw_dir);
1235113596Snectar	COPY(pw_shell);
1236113596Snectar#undef COPY
1237113596Snectar	p = buffer;
1238113596Snectar	eob = &buffer[bufsize];
1239113596Snectar#define COPY(field, flag) do {						 \
1240113596Snectar	q = (template->pw_fields & flag) ? template->field : hold.field; \
1241113596Snectar	if (q == NULL)							 \
1242113596Snectar		pwd->field = NULL;					 \
1243113596Snectar	else {								 \
1244113596Snectar		pwd->field = p;						 \
1245114443Snectar		if ((n = strlcpy(p, q, eob-p)) >= eob-p) {		 \
1246113596Snectar			free(copy);					 \
1247113596Snectar			return (ERANGE);				 \
1248113596Snectar		}							 \
1249113596Snectar		p += n + 1;						 \
1250113596Snectar	}								 \
1251113596Snectar} while (0)
1252113596Snectar	COPY(pw_name, 0);
1253113596Snectar#ifdef PW_OVERRIDE_PASSWD
1254113596Snectar	COPY(pw_passwd, _PWF_PASSWD);
1255113596Snectar#else
1256113596Snectar	COPY(pw_passwd, 0);
1257113596Snectar#endif
1258113596Snectar	COPY(pw_class, 0);
1259113596Snectar	COPY(pw_gecos, _PWF_GECOS);
1260113596Snectar	COPY(pw_dir, _PWF_DIR);
1261113596Snectar	COPY(pw_shell, _PWF_SHELL);
1262113596Snectar#undef COPY
1263113596Snectar#define COPY(field, flag) do {			\
1264113596Snectar	if (template->pw_fields & flag)		\
1265113596Snectar		pwd->field = template->field;	\
1266113596Snectar} while (0)
1267113596Snectar	COPY(pw_uid, _PWF_UID);
1268113596Snectar	COPY(pw_gid, _PWF_GID);
1269113596Snectar#undef COPY
1270113596Snectar	free(copy);
1271113596Snectar	return (0);
127215267Swpaul}
127315267Swpaul
127465532Snectar
127565532Snectarstatic int
1276113596Snectarcompat_exclude(const char *name, DB **db)
127715267Swpaul{
1278113596Snectar	DBT	key, data;
1279113596Snectar
1280113596Snectar	if (*db == NULL &&
1281113596Snectar	    (*db = dbopen(NULL, O_RDWR, 600, DB_HASH, 0)) == NULL)
1282113596Snectar		return (errno);
1283113596Snectar	key.size = strlen(name);
1284113596Snectar	key.data = (char *)name;
1285113596Snectar	data.size = 0;
1286113596Snectar	data.data = NULL;
1287113596Snectar
1288113596Snectar	if ((*db)->put(*db, &key, &data, 0) == -1)
1289113596Snectar		return (errno);
1290113596Snectar	return (0);
12917258Swpaul}
12927258Swpaul
129365532Snectar
129465532Snectarstatic int
1295113596Snectarcompat_is_excluded(const char *name, DB *db)
12967258Swpaul{
1297113596Snectar	DBT	key, data;
12987258Swpaul
1299113596Snectar	if (db == NULL)
1300113596Snectar		return (0);
1301113596Snectar	key.size = strlen(name);
1302113596Snectar	key.data = (char *)name;
1303113596Snectar	return (db->get(db, &key, &data, 0) == 0);
13047258Swpaul}
13057258Swpaul
130665532Snectar
130765532Snectarstatic int
1308113596Snectarcompat_redispatch(struct compat_state *st, enum nss_lookup_type how,
1309113596Snectar    enum nss_lookup_type lookup_how, const char *name, const char *lookup_name,
1310113596Snectar    uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize, int *errnop)
131110521Swpaul{
1312113596Snectar	static const ns_src compatsrc[] = {
1313113596Snectar#ifdef YP
1314113596Snectar		{ NSSRC_NIS, NS_SUCCESS },
131565532Snectar#endif
1316113596Snectar		{ NULL, 0 }
1317113596Snectar	};
1318113596Snectar	ns_dtab dtab[] = {
1319113596Snectar#ifdef YP
1320113596Snectar		{ NSSRC_NIS, nis_passwd, NULL },
1321113596Snectar#endif
1322113596Snectar#ifdef HESIOD
1323113596Snectar		{ NSSRC_DNS, dns_passwd, NULL },
1324113596Snectar#endif
1325113596Snectar		{ NULL, NULL, NULL }
1326113596Snectar	};
1327113596Snectar	void		*discard;
1328113596Snectar	int		 rv, e, i;
132910521Swpaul
1330113596Snectar	for (i = 0; i < sizeof(dtab)/sizeof(dtab[0]) - 1; i++)
1331113596Snectar		dtab[i].mdata = (void *)lookup_how;
1332113596Snectarmore:
1333113992Snectar	pwd_init(pwd);
1334113596Snectar	switch (lookup_how) {
1335113596Snectar	case nss_lt_all:
1336113596Snectar		rv = _nsdispatch(&discard, dtab, NSDB_PASSWD_COMPAT,
1337113596Snectar		    "getpwent_r", compatsrc, pwd, buffer, bufsize,
1338113596Snectar		    errnop);
1339113596Snectar		break;
1340113596Snectar	case nss_lt_id:
1341113596Snectar		rv = _nsdispatch(&discard, dtab, NSDB_PASSWD_COMPAT,
1342113596Snectar		    "getpwuid_r", compatsrc, uid, pwd, buffer,
1343113596Snectar		    bufsize, errnop);
1344113596Snectar		break;
1345113596Snectar	case nss_lt_name:
1346113596Snectar		rv = _nsdispatch(&discard, dtab, NSDB_PASSWD_COMPAT,
1347113596Snectar		    "getpwnam_r", compatsrc, lookup_name, pwd, buffer,
1348113596Snectar		    bufsize, errnop);
1349113596Snectar		break;
1350113596Snectar	default:
1351113596Snectar		return (NS_UNAVAIL);
1352113596Snectar	}
1353113596Snectar	if (rv != NS_SUCCESS)
1354113596Snectar		return (rv);
1355113596Snectar	if (compat_is_excluded(pwd->pw_name, st->exclude)) {
1356113596Snectar		if (how == nss_lt_all)
1357113596Snectar			goto more;
1358113596Snectar		return (NS_NOTFOUND);
1359113596Snectar	}
1360113596Snectar	e = compat_use_template(pwd, &st->template, buffer, bufsize);
1361113596Snectar	if (e != 0) {
1362113596Snectar		*errnop = e;
1363113596Snectar		if (e == ERANGE)
1364113596Snectar			return (NS_RETURN);
1365113596Snectar		else
1366113596Snectar			return (NS_UNAVAIL);
1367113596Snectar	}
1368113596Snectar	switch (how) {
1369113596Snectar	case nss_lt_name:
1370113596Snectar		if (strcmp(name, pwd->pw_name) != 0)
1371113596Snectar			return (NS_NOTFOUND);
1372113596Snectar		break;
1373113596Snectar	case nss_lt_id:
1374113596Snectar		if (uid != pwd->pw_uid)
1375113596Snectar			return (NS_NOTFOUND);
1376113596Snectar		break;
1377113596Snectar	default:
1378113596Snectar		break;
1379113596Snectar	}
1380113596Snectar	return (NS_SUCCESS);
1381113596Snectar}
138265532Snectar
138365532Snectar
1384113596Snectarstatic void
1385113596Snectarcompat_endstate(void *p)
1386113596Snectar{
1387113596Snectar	struct compat_state *st;
138865532Snectar
1389113596Snectar	if (p == NULL)
1390113596Snectar		return;
1391113596Snectar	st = (struct compat_state *)p;
1392113596Snectar	if (st->db != NULL)
1393113596Snectar		st->db->close(st->db);
1394113596Snectar	if (st->exclude != NULL)
1395113596Snectar		st->exclude->close(st->exclude);
1396113596Snectar	compat_clear_template(&st->template);
1397113596Snectar	free(p);
1398113596Snectar}
139965532Snectar
140065532Snectar
1401113596Snectarstatic int
1402113596Snectarcompat_setpwent(void *retval, void *mdata, va_list ap)
1403113596Snectar{
1404114021Snectar	static const ns_src compatsrc[] = {
1405114021Snectar#ifdef YP
1406114021Snectar		{ NSSRC_NIS, NS_SUCCESS },
1407114021Snectar#endif
1408114021Snectar		{ NULL, 0 }
1409114021Snectar	};
1410114021Snectar	ns_dtab dtab[] = {
1411114021Snectar#ifdef YP
1412114021Snectar		{ NSSRC_NIS, nis_setpwent, NULL },
1413114021Snectar#endif
1414114021Snectar#ifdef HESIOD
1415114021Snectar		{ NSSRC_DNS, dns_setpwent, NULL },
1416114021Snectar#endif
1417114021Snectar		{ NULL, NULL, NULL }
1418114021Snectar	};
1419113596Snectar	struct compat_state	*st;
1420113596Snectar	int			 rv, stayopen;
142165532Snectar
1422114021Snectar#define set_setent(x, y) do {	 				\
1423114021Snectar	int i;							\
1424114021Snectar								\
1425114021Snectar	for (i = 0; i < (sizeof(x)/sizeof(x[0])) - 1; i++)	\
1426114021Snectar		x[i].mdata = (void *)y;				\
1427114021Snectar} while (0)
1428114021Snectar
1429113596Snectar	rv = compat_getstate(&st);
1430113596Snectar	if (rv != 0)
1431113596Snectar		return (NS_UNAVAIL);
1432113596Snectar	switch ((enum constants)mdata) {
1433113596Snectar	case SETPWENT:
1434113596Snectar		stayopen = va_arg(ap, int);
1435113596Snectar		st->keynum = 0;
1436113596Snectar		if (stayopen)
1437113596Snectar			st->db = pwdbopen(&st->version);
1438113596Snectar		st->stayopen = stayopen;
1439114021Snectar		set_setent(dtab, mdata);
1440114021Snectar		(void)_nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "setpwent",
1441114021Snectar		    compatsrc, 0);
1442113596Snectar		break;
1443113596Snectar	case ENDPWENT:
1444113596Snectar		if (st->db != NULL) {
1445113596Snectar			(void)st->db->close(st->db);
1446113596Snectar			st->db = NULL;
144765532Snectar		}
1448114021Snectar		set_setent(dtab, mdata);
1449114021Snectar		(void)_nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "endpwent",
1450114021Snectar		    compatsrc, 0);
1451113596Snectar		break;
1452113596Snectar	default:
1453113596Snectar		break;
145410521Swpaul	}
1455113596Snectar	return (NS_UNAVAIL);
1456114021Snectar#undef set_setent
145710521Swpaul}
145820119Swpaul
145920119Swpaul
14609332Swpaulstatic int
1461113596Snectarcompat_passwd(void *retval, void *mdata, va_list ap)
14622917Swollman{
1463113596Snectar	char			 keybuf[MAXLOGNAME + 1];
1464113596Snectar	DBT			 key, entry;
1465113596Snectar	struct compat_state	*st;
1466113596Snectar	enum nss_lookup_type	 how;
1467113596Snectar	const char		*name;
1468113596Snectar	struct passwd		*pwd;
1469113596Snectar	char			*buffer, *pw_name;
1470113596Snectar	char			*host, *user, *domain;
1471113596Snectar	size_t			 bufsize;
1472113596Snectar	uid_t			 uid;
1473113596Snectar	uint32_t		 store;
1474113691Snectar	int			 rv, from_compat, stayopen, *errnop;
14752917Swollman
1476113691Snectar	from_compat = 0;
147765532Snectar	name = NULL;
1478113596Snectar	uid = (uid_t)-1;
1479113596Snectar	how = (enum nss_lookup_type)mdata;
1480113596Snectar	switch (how) {
1481113596Snectar	case nss_lt_name:
1482113596Snectar		name = va_arg(ap, const char *);
148365532Snectar		break;
1484113596Snectar	case nss_lt_id:
148565532Snectar		uid = va_arg(ap, uid_t);
148665532Snectar		break;
1487113596Snectar	case nss_lt_all:
1488113596Snectar		break;
148965532Snectar	default:
1490113596Snectar		rv = NS_NOTFOUND;
1491113596Snectar		goto fin;
14922917Swollman	}
1493113596Snectar	pwd = va_arg(ap, struct passwd *);
1494113596Snectar	buffer = va_arg(ap, char *);
1495113596Snectar	bufsize = va_arg(ap, size_t);
1496113596Snectar	errnop = va_arg(ap, int *);
1497113596Snectar	*errnop = compat_getstate(&st);
1498113596Snectar	if (*errnop != 0)
1499113596Snectar		return (NS_UNAVAIL);
1500113596Snectar	if (how == nss_lt_all && st->keynum < 0) {
1501113596Snectar		rv = NS_NOTFOUND;
1502113596Snectar		goto fin;
1503113596Snectar	}
1504113596Snectar	if (st->db == NULL &&
1505113596Snectar	    (st->db = pwdbopen(&st->version)) == NULL) {
1506113596Snectar		*errnop = errno;
1507113596Snectar		rv = NS_UNAVAIL;
1508113596Snectar		goto fin;
1509113596Snectar	}
1510113596Snectar	if (how == nss_lt_all) {
1511113596Snectar		if (st->keynum < 0) {
1512113596Snectar			rv = NS_NOTFOUND;
1513113596Snectar			goto fin;
1514113596Snectar		}
1515113596Snectar		stayopen = 1;
1516113596Snectar	} else {
1517113596Snectar		st->keynum = 0;
1518113596Snectar		stayopen = st->stayopen;
1519113596Snectar	}
1520113596Snectardocompat:
1521113596Snectar	rv = NS_NOTFOUND;
1522113596Snectar	switch (st->compat) {
1523113596Snectar	case COMPAT_MODE_ALL:
1524113596Snectar		rv = compat_redispatch(st, how, how, name, name, uid, pwd,
1525113596Snectar		    buffer, bufsize, errnop);
1526113596Snectar		if (rv != NS_SUCCESS)
1527113596Snectar			st->compat = COMPAT_MODE_OFF;
1528113596Snectar		break;
1529113596Snectar	case COMPAT_MODE_NETGROUP:
1530113596Snectar		/* XXX getnetgrent is not thread-safe. */
1531113596Snectar		do {
1532113596Snectar			rv = getnetgrent(&host, &user, &domain);
1533113596Snectar			if (rv == 0) {
1534113596Snectar				endnetgrent();
1535113596Snectar				st->compat = COMPAT_MODE_OFF;
1536113596Snectar				rv = NS_NOTFOUND;
1537113596Snectar				continue;
1538113596Snectar			} else if (user == NULL || user[0] == '\0')
1539113596Snectar				continue;
1540113596Snectar			rv = compat_redispatch(st, how, nss_lt_name, name,
1541113596Snectar			    user, uid, pwd, buffer, bufsize, errnop);
1542113596Snectar		} while (st->compat == COMPAT_MODE_NETGROUP &&
1543113596Snectar		    !(rv & NS_TERMINATE));
1544113596Snectar		break;
1545113596Snectar	case COMPAT_MODE_NAME:
1546113596Snectar		rv = compat_redispatch(st, how, nss_lt_name, name, st->name,
1547113596Snectar		    uid, pwd, buffer, bufsize, errnop);
1548113596Snectar		free(st->name);
1549113596Snectar		st->name = NULL;
1550113596Snectar		st->compat = COMPAT_MODE_OFF;
1551113596Snectar		break;
1552113596Snectar	default:
1553113596Snectar		break;
1554113596Snectar	}
1555113691Snectar	if (rv & NS_TERMINATE) {
1556113691Snectar		from_compat = 1;
1557113596Snectar		goto fin;
1558113691Snectar	}
1559113596Snectar	key.data = keybuf;
1560113596Snectar	rv = NS_NOTFOUND;
1561113596Snectar	while (st->keynum >= 0) {
1562113596Snectar		st->keynum++;
1563113596Snectar		if (st->version < _PWD_CURRENT_VERSION) {
1564113596Snectar			memcpy(&keybuf[1], &st->keynum, sizeof(st->keynum));
1565113596Snectar			key.size = sizeof(st->keynum) + 1;
1566113596Snectar		} else {
1567113596Snectar			store = htonl(st->keynum);
1568113596Snectar			memcpy(&keybuf[1], &store, sizeof(store));
1569113596Snectar			key.size = sizeof(store) + 1;
1570113596Snectar		}
1571113666Snectar		keybuf[0] = _PW_VERSIONED(_PW_KEYBYNUM, st->version);
1572113596Snectar		rv = st->db->get(st->db, &key, &entry, 0);
1573113596Snectar		if (rv < 0 || rv > 1) { /* should never return > 1 */
1574113596Snectar			*errnop = errno;
1575113596Snectar			rv = NS_UNAVAIL;
1576113596Snectar			goto fin;
1577113596Snectar		} else if (rv == 1) {
1578113596Snectar			st->keynum = -1;
1579113596Snectar			rv = NS_NOTFOUND;
1580113596Snectar			goto fin;
1581113596Snectar		}
1582113596Snectar		pw_name = (char *)entry.data;
1583113596Snectar		switch (pw_name[0]) {
158465532Snectar		case '+':
1585113596Snectar			switch (pw_name[1]) {
158665532Snectar			case '\0':
1587113596Snectar				st->compat = COMPAT_MODE_ALL;
158865532Snectar				break;
158965532Snectar			case '@':
1590113596Snectar				setnetgrent(&pw_name[2]);
1591113596Snectar				st->compat = COMPAT_MODE_NETGROUP;
159265532Snectar				break;
159365532Snectar			default:
1594113596Snectar				st->name = strdup(&pw_name[1]);
1595113596Snectar				if (st->name == NULL) {
1596113596Snectar					syslog(LOG_ERR,
1597113596Snectar					 "getpwent memory allocation failure");
1598113596Snectar					*errnop = ENOMEM;
1599113596Snectar					rv = NS_UNAVAIL;
1600113596Snectar					break;
1601113596Snectar				}
1602113596Snectar				st->compat = COMPAT_MODE_NAME;
160365532Snectar			}
1604113596Snectar			if (entry.size > bufsize) {
1605113596Snectar				*errnop = ERANGE;
1606113596Snectar				rv = NS_RETURN;
1607113596Snectar				goto fin;
160865532Snectar			}
1609113596Snectar			memcpy(buffer, entry.data, entry.size);
1610113596Snectar			rv = pwdb_versions[st->version].parse(buffer,
1611113596Snectar			    entry.size, pwd, errnop);
1612113596Snectar			if (rv != NS_SUCCESS)
1613113596Snectar				;
1614113596Snectar			else if (compat_set_template(pwd, &st->template) < 0) {
1615113596Snectar				*errnop = ENOMEM;
1616113596Snectar				rv = NS_UNAVAIL;
1617113596Snectar				goto fin;
1618113596Snectar			}
1619113596Snectar			goto docompat;
162065532Snectar		case '-':
1621113596Snectar			switch (pw_name[1]) {
162265532Snectar			case '\0':
1623113596Snectar				/* XXX Maybe syslog warning */
1624113596Snectar				continue;
162565532Snectar			case '@':
1626113596Snectar				setnetgrent(&pw_name[2]);
1627113596Snectar				while (getnetgrent(&host, &user, &domain) !=
1628126643Smarkm				    0) {
1629113596Snectar					if (user != NULL && user[0] != '\0')
1630113596Snectar						compat_exclude(user,
1631113596Snectar						    &st->exclude);
163265532Snectar				}
163365532Snectar				endnetgrent();
1634113596Snectar				continue;
163565532Snectar			default:
1636113596Snectar				compat_exclude(&pw_name[1], &st->exclude);
1637113596Snectar				continue;
163865532Snectar			}
163965532Snectar			break;
164096186Sdes		default:
1641113596Snectar			break;
16426190Swpaul		}
1643113596Snectar		if (compat_is_excluded((char *)entry.data, st->exclude))
1644113596Snectar			continue;
1645113596Snectar		rv = pwdb_versions[st->version].match(entry.data, entry.size,
1646113596Snectar		    how, name, uid);
1647113596Snectar		if (rv == NS_RETURN)
164865532Snectar			break;
1649113596Snectar		else if (rv != NS_SUCCESS)
1650113596Snectar			continue;
1651113596Snectar		if (entry.size > bufsize) {
1652113596Snectar			*errnop = ERANGE;
1653113596Snectar			rv = NS_RETURN;
1654113596Snectar			break;
165565532Snectar		}
1656113596Snectar		memcpy(buffer, entry.data, entry.size);
1657113596Snectar		rv = pwdb_versions[st->version].parse(buffer, entry.size, pwd,
1658113596Snectar		    errnop);
1659113596Snectar		if (rv & NS_TERMINATE)
1660113596Snectar			break;
16612917Swollman	}
1662113596Snectarfin:
1663113596Snectar	if (!stayopen && st->db != NULL) {
1664113596Snectar		(void)st->db->close(st->db);
1665113596Snectar		st->db = NULL;
16666076Swpaul	}
1667124432Snectar	if (rv == NS_SUCCESS) {
1668113691Snectar		if (!from_compat) {
1669113691Snectar			pwd->pw_fields &= ~_PWF_SOURCE;
1670113691Snectar			pwd->pw_fields |= _PWF_FILES;
1671113691Snectar		}
1672113691Snectar		if (retval != NULL)
1673113691Snectar			*(struct passwd **)retval = pwd;
1674113691Snectar	}
1675113596Snectar	return (rv);
167665532Snectar}
16776076Swpaul
16789332Swpaul
1679113596Snectar/*
1680113596Snectar * common passwd line matching and parsing
1681113596Snectar */
168265532Snectarint
1683113596Snectar__pw_match_entry(const char *entry, size_t entrysize, enum nss_lookup_type how,
1684113596Snectar    const char *name, uid_t uid)
16852917Swollman{
1686113596Snectar	const char	*p, *eom;
1687113596Snectar	char		*q;
1688113596Snectar	size_t		 len;
1689113596Snectar	unsigned long	 m;
16902917Swollman
1691113596Snectar	eom = entry + entrysize;
1692113596Snectar	for (p = entry; p < eom; p++)
1693113596Snectar		if (*p == ':')
1694113596Snectar			break;
1695113596Snectar	if (*p != ':')
1696113596Snectar		return (NS_NOTFOUND);
1697113596Snectar	if (how == nss_lt_all)
1698113596Snectar		return (NS_SUCCESS);
1699113596Snectar	if (how == nss_lt_name) {
1700113596Snectar		len = strlen(name);
1701113596Snectar		if (len == (p - entry) && memcmp(name, entry, len) == 0)
1702113596Snectar			return (NS_SUCCESS);
1703113596Snectar		else
1704113596Snectar			return (NS_NOTFOUND);
170545066Sdes	}
1706113596Snectar	for (p++; p < eom; p++)
1707113596Snectar		if (*p == ':')
1708113596Snectar			break;
1709113596Snectar	if (*p != ':')
1710113596Snectar		return (NS_NOTFOUND);
1711113596Snectar	m = strtoul(++p, &q, 10);
1712113596Snectar	if (q[0] != ':' || (uid_t)m != uid)
1713113596Snectar		return (NS_NOTFOUND);
1714113596Snectar	else
1715113596Snectar		return (NS_SUCCESS);
171665532Snectar}
17172917Swollman
171815267Swpaul
1719113596Snectar/* XXX buffer must be NUL-terminated.  errnop is not set correctly. */
1720113596Snectarint
1721113596Snectar__pw_parse_entry(char *buffer, size_t bufsize __unused, struct passwd *pwd,
1722113596Snectar    int master, int *errnop __unused)
17232917Swollman{
17242917Swollman
1725113596Snectar	if (__pw_scan(buffer, pwd, master ? _PWSCAN_MASTER : 0) == 0)
1726113596Snectar		return (NS_NOTFOUND);
1727113596Snectar	else
1728113596Snectar		return (NS_SUCCESS);
17292917Swollman}
1730