xref: /freebsd/lib/libc/gen/getpwent.c (revision 2ba1d4970a06a1660b46f6fd99351d154b295683)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2003 Networks Associates Technology, Inc.
5  * All rights reserved.
6  *
7  * This software was developed for the FreeBSD Project by
8  * Jacques A. Vidrine, Safeport Network Services, and Network
9  * Associates Laboratories, the Security Research Division of Network
10  * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
11  * ("CBOSS"), as part of the DARPA CHATS research program.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  */
35 #include <sys/cdefs.h>
36 #include "namespace.h"
37 #include <sys/param.h>
38 #ifdef YP
39 #include <rpc/rpc.h>
40 #include <rpcsvc/yp_prot.h>
41 #include <rpcsvc/ypclnt.h>
42 #endif
43 #include <arpa/inet.h>
44 #include <errno.h>
45 #include <fcntl.h>
46 #ifdef HESIOD
47 #include <hesiod.h>
48 #endif
49 #include <netdb.h>
50 #include <nsswitch.h>
51 #include <pthread.h>
52 #include <pthread_np.h>
53 #include <pwd.h>
54 #include <stdlib.h>
55 #include <stdio.h>
56 #include <string.h>
57 #include <syslog.h>
58 #include <unistd.h>
59 #include "un-namespace.h"
60 #include <db.h>
61 #include "libc_private.h"
62 #include "pw_scan.h"
63 #include "nss_tls.h"
64 #ifdef NS_CACHING
65 #include "nscache.h"
66 #endif
67 
68 #ifndef CTASSERT
69 #define CTASSERT(x)		_CTASSERT(x, __LINE__)
70 #define _CTASSERT(x, y)		__CTASSERT(x, y)
71 #define __CTASSERT(x, y)	typedef char __assert_ ## y [(x) ? 1 : -1]
72 #endif
73 
74 /* Counter as stored in /etc/pwd.db */
75 typedef	int		pwkeynum;
76 
77 CTASSERT(MAXLOGNAME > sizeof(uid_t));
78 CTASSERT(MAXLOGNAME > sizeof(pwkeynum));
79 
80 enum constants {
81 	PWD_STORAGE_INITIAL	= 1 << 10, /* 1 KByte */
82 	PWD_STORAGE_MAX		= 1 << 20, /* 1 MByte */
83 	SETPWENT		= 1,
84 	ENDPWENT		= 2,
85 	HESIOD_NAME_MAX		= 256
86 };
87 
88 static const ns_src defaultsrc[] = {
89 	{ NSSRC_COMPAT, NS_SUCCESS },
90 	{ NULL, 0 }
91 };
92 
93 int	__pw_match_entry(const char *, size_t, enum nss_lookup_type,
94 	    const char *, uid_t);
95 int	__pw_parse_entry(char *, size_t, struct passwd *, int, int *errnop);
96 
97 union key {
98 	const char	*name;
99 	uid_t		 uid;
100 };
101 
102 static	struct passwd *getpw(int (*fn)(union key, struct passwd *, char *,
103 		    size_t, struct passwd **), union key);
104 static	int	 wrap_getpwnam_r(union key, struct passwd *, char *,
105 		    size_t, struct passwd **);
106 static	int	 wrap_getpwuid_r(union key, struct passwd *, char *, size_t,
107 		    struct passwd **);
108 static	int	 wrap_getpwent_r(union key, struct passwd *, char *, size_t,
109 		    struct passwd **);
110 
111 static	int	 pwdb_match_entry_v3(char *, size_t, enum nss_lookup_type,
112 		    const char *, uid_t);
113 static	int	 pwdb_parse_entry_v3(char *, size_t, struct passwd *, int *);
114 static	int	 pwdb_match_entry_v4(char *, size_t, enum nss_lookup_type,
115 		    const char *, uid_t);
116 static	int	 pwdb_parse_entry_v4(char *, size_t, struct passwd *, int *);
117 
118 
119 struct {
120 	int	(*match)(char *, size_t, enum nss_lookup_type, const char *,
121 		    uid_t);
122 	int	(*parse)(char *, size_t, struct passwd *, int *);
123 } pwdb_versions[] = {
124 	{ NULL, NULL },					/* version 0 */
125 	{ NULL, NULL },					/* version 1 */
126 	{ NULL, NULL },					/* version 2 */
127 	{ pwdb_match_entry_v3, pwdb_parse_entry_v3 },	/* version 3 */
128 	{ pwdb_match_entry_v4, pwdb_parse_entry_v4 },	/* version 4 */
129 };
130 
131 
132 struct files_state {
133 	DB		*db;
134 	pwkeynum	 keynum;
135 	int		 stayopen;
136 	int		 version;
137 };
138 static	void	files_endstate(void *);
139 NSS_TLS_HANDLING(files);
140 static	DB	*pwdbopen(int *);
141 static	void	 files_endstate(void *);
142 static	int	 files_setpwent(void *, void *, va_list);
143 static	int	 files_passwd(void *, void *, va_list);
144 
145 
146 #ifdef HESIOD
147 struct dns_state {
148 	long	counter;
149 };
150 static	void	dns_endstate(void *);
151 NSS_TLS_HANDLING(dns);
152 static	int	 dns_setpwent(void *, void *, va_list);
153 static	int	 dns_passwd(void *, void *, va_list);
154 #endif
155 
156 
157 #ifdef YP
158 struct nis_state {
159 	char	 domain[MAXHOSTNAMELEN];
160 	int	 done;
161 	char	*key;
162 	int	 keylen;
163 };
164 static	void	 nis_endstate(void *);
165 NSS_TLS_HANDLING(nis);
166 static	int	 nis_setpwent(void *, void *, va_list);
167 static	int	 nis_passwd(void *, void *, va_list);
168 static	int	 nis_map(char *, enum nss_lookup_type, char *, size_t, int *);
169 static	int	 nis_adjunct(char *, const char *, char *, size_t);
170 #endif
171 
172 
173 struct compat_state {
174 	DB		*db;
175 	pwkeynum	 keynum;
176 	int		 stayopen;
177 	int		 version;
178 	DB		*exclude;
179 	struct passwd	 template;
180 	char		*name;
181 	enum _compat {
182 		COMPAT_MODE_OFF = 0,
183 		COMPAT_MODE_ALL,
184 		COMPAT_MODE_NAME,
185 		COMPAT_MODE_NETGROUP
186 	}		 compat;
187 };
188 static	void	 compat_endstate(void *);
189 NSS_TLS_HANDLING(compat);
190 static	int	 compat_setpwent(void *, void *, va_list);
191 static	int	 compat_passwd(void *, void *, va_list);
192 static	void	 compat_clear_template(struct passwd *);
193 static	int	 compat_set_template(struct passwd *, struct passwd *);
194 static	int	 compat_use_template(struct passwd *, struct passwd *, char *,
195 		    size_t);
196 static	int	 compat_redispatch(struct compat_state *, enum nss_lookup_type,
197 		    enum nss_lookup_type, const char *, const char *, uid_t,
198 		    struct passwd *, char *, size_t, int *);
199 
200 #ifdef NS_CACHING
201 static	int	 pwd_id_func(char *, size_t *, va_list ap, void *);
202 static	int	 pwd_marshal_func(char *, size_t *, void *, va_list, void *);
203 static	int	 pwd_unmarshal_func(char *, size_t, void *, va_list, void *);
204 
205 static int
206 pwd_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata)
207 {
208 	char	*name;
209 	uid_t	uid;
210 	size_t	size, desired_size;
211 	int	res = NS_UNAVAIL;
212 	enum nss_lookup_type lookup_type;
213 
214 	lookup_type = (enum nss_lookup_type)(uintptr_t)cache_mdata;
215 	switch (lookup_type) {
216 	case nss_lt_name:
217 		name = va_arg(ap, char *);
218 		size = strlen(name);
219 		desired_size = sizeof(enum nss_lookup_type) + size + 1;
220 		if (desired_size > *buffer_size) {
221 			res = NS_RETURN;
222 			goto fin;
223 		}
224 
225 		memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
226 		memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1);
227 
228 		res = NS_SUCCESS;
229 		break;
230 	case nss_lt_id:
231 		uid = va_arg(ap, uid_t);
232 		desired_size = sizeof(enum nss_lookup_type) + sizeof(uid_t);
233 		if (desired_size > *buffer_size) {
234 			res = NS_RETURN;
235 			goto fin;
236 		}
237 
238 		memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
239 		memcpy(buffer + sizeof(enum nss_lookup_type), &uid,
240 		    sizeof(uid_t));
241 
242 		res = NS_SUCCESS;
243 		break;
244 	default:
245 		/* should be unreachable */
246 		return (NS_UNAVAIL);
247 	}
248 
249 fin:
250 	*buffer_size = desired_size;
251 	return (res);
252 }
253 
254 static int
255 pwd_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap,
256     void *cache_mdata)
257 {
258 	char *name __unused;
259 	uid_t uid __unused;
260 	struct passwd *pwd;
261 	char *orig_buf __unused;
262 	size_t orig_buf_size __unused;
263 
264 	struct passwd new_pwd;
265 	size_t desired_size, size;
266 	char *p;
267 
268 	switch ((enum nss_lookup_type)(uintptr_t)cache_mdata) {
269 	case nss_lt_name:
270 		name = va_arg(ap, char *);
271 		break;
272 	case nss_lt_id:
273 		uid = va_arg(ap, uid_t);
274 		break;
275 	case nss_lt_all:
276 		break;
277 	default:
278 		/* should be unreachable */
279 		return (NS_UNAVAIL);
280 	}
281 
282 	pwd = va_arg(ap, struct passwd *);
283 	orig_buf = va_arg(ap, char *);
284 	orig_buf_size = va_arg(ap, size_t);
285 
286 	desired_size = sizeof(struct passwd) + sizeof(char *) +
287 	    strlen(pwd->pw_name) + 1;
288 	if (pwd->pw_passwd != NULL)
289 		desired_size += strlen(pwd->pw_passwd) + 1;
290 	if (pwd->pw_class != NULL)
291 		desired_size += strlen(pwd->pw_class) + 1;
292 	if (pwd->pw_gecos != NULL)
293 		desired_size += strlen(pwd->pw_gecos) + 1;
294 	if (pwd->pw_dir != NULL)
295 		desired_size += strlen(pwd->pw_dir) + 1;
296 	if (pwd->pw_shell != NULL)
297 		desired_size += strlen(pwd->pw_shell) + 1;
298 
299 	if (*buffer_size < desired_size) {
300 		/* this assignment is here for future use */
301 		*buffer_size = desired_size;
302 		return (NS_RETURN);
303 	}
304 
305 	memcpy(&new_pwd, pwd, sizeof(struct passwd));
306 	memset(buffer, 0, desired_size);
307 
308 	*buffer_size = desired_size;
309 	p = buffer + sizeof(struct passwd) + sizeof(char *);
310 	memcpy(buffer + sizeof(struct passwd), &p, sizeof(char *));
311 
312 	if (new_pwd.pw_name != NULL) {
313 		size = strlen(new_pwd.pw_name);
314 		memcpy(p, new_pwd.pw_name, size);
315 		new_pwd.pw_name = p;
316 		p += size + 1;
317 	}
318 
319 	if (new_pwd.pw_passwd != NULL) {
320 		size = strlen(new_pwd.pw_passwd);
321 		memcpy(p, new_pwd.pw_passwd, size);
322 		new_pwd.pw_passwd = p;
323 		p += size + 1;
324 	}
325 
326 	if (new_pwd.pw_class != NULL) {
327 		size = strlen(new_pwd.pw_class);
328 		memcpy(p, new_pwd.pw_class, size);
329 		new_pwd.pw_class = p;
330 		p += size + 1;
331 	}
332 
333 	if (new_pwd.pw_gecos != NULL) {
334 		size = strlen(new_pwd.pw_gecos);
335 		memcpy(p, new_pwd.pw_gecos, size);
336 		new_pwd.pw_gecos = p;
337 		p += size + 1;
338 	}
339 
340 	if (new_pwd.pw_dir != NULL) {
341 		size = strlen(new_pwd.pw_dir);
342 		memcpy(p, new_pwd.pw_dir, size);
343 		new_pwd.pw_dir = p;
344 		p += size + 1;
345 	}
346 
347 	if (new_pwd.pw_shell != NULL) {
348 		size = strlen(new_pwd.pw_shell);
349 		memcpy(p, new_pwd.pw_shell, size);
350 		new_pwd.pw_shell = p;
351 		p += size + 1;
352 	}
353 
354 	memcpy(buffer, &new_pwd, sizeof(struct passwd));
355 	return (NS_SUCCESS);
356 }
357 
358 static int
359 pwd_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap,
360     void *cache_mdata)
361 {
362 	char *name __unused;
363 	uid_t uid __unused;
364 	struct passwd *pwd;
365 	char *orig_buf;
366 	size_t orig_buf_size;
367 	int *ret_errno;
368 
369 	char *p;
370 
371 	switch ((enum nss_lookup_type)(uintptr_t)cache_mdata) {
372 	case nss_lt_name:
373 		name = va_arg(ap, char *);
374 		break;
375 	case nss_lt_id:
376 		uid = va_arg(ap, uid_t);
377 		break;
378 	case nss_lt_all:
379 		break;
380 	default:
381 		/* should be unreachable */
382 		return (NS_UNAVAIL);
383 	}
384 
385 	pwd = va_arg(ap, struct passwd *);
386 	orig_buf = va_arg(ap, char *);
387 	orig_buf_size = va_arg(ap, size_t);
388 	ret_errno = va_arg(ap, int *);
389 
390 	if (orig_buf_size + sizeof(struct passwd) + sizeof(char *) <
391 	    buffer_size) {
392 		*ret_errno = ERANGE;
393 		return (NS_RETURN);
394 	} else if (buffer_size < sizeof(struct passwd) + sizeof(char *)) {
395 		/*
396 		 * nscd(8) sometimes returns buffer_size=1 for nonexistent
397 		 * entries.
398 		 */
399 		*ret_errno = 0;
400 		return (NS_NOTFOUND);
401 	}
402 
403 	memcpy(pwd, buffer, sizeof(struct passwd));
404 	memcpy(&p, buffer + sizeof(struct passwd), sizeof(char *));
405 	memcpy(orig_buf, buffer + sizeof(struct passwd) + sizeof(char *),
406 	    buffer_size - sizeof(struct passwd) - sizeof(char *));
407 
408 	NS_APPLY_OFFSET(pwd->pw_name, orig_buf, p, char *);
409 	NS_APPLY_OFFSET(pwd->pw_passwd, orig_buf, p, char *);
410 	NS_APPLY_OFFSET(pwd->pw_class, orig_buf, p, char *);
411 	NS_APPLY_OFFSET(pwd->pw_gecos, orig_buf, p, char *);
412 	NS_APPLY_OFFSET(pwd->pw_dir, orig_buf, p, char *);
413 	NS_APPLY_OFFSET(pwd->pw_shell, orig_buf, p, char *);
414 
415 	if (retval != NULL)
416 		*((struct passwd **)retval) = pwd;
417 
418 	return (NS_SUCCESS);
419 }
420 
421 NSS_MP_CACHE_HANDLING(passwd);
422 #endif /* NS_CACHING */
423 
424 void
425 setpwent(void)
426 {
427 #ifdef NS_CACHING
428 	static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
429 		passwd, (void *)nss_lt_all,
430 		NULL, NULL);
431 #endif
432 
433 	static const ns_dtab dtab[] = {
434 		{ NSSRC_FILES, files_setpwent, (void *)SETPWENT },
435 #ifdef HESIOD
436 		{ NSSRC_DNS, dns_setpwent, (void *)SETPWENT },
437 #endif
438 #ifdef YP
439 		{ NSSRC_NIS, nis_setpwent, (void *)SETPWENT },
440 #endif
441 		{ NSSRC_COMPAT, compat_setpwent, (void *)SETPWENT },
442 #ifdef NS_CACHING
443 		NS_CACHE_CB(&cache_info)
444 #endif
445 		{ NULL, NULL, NULL }
446 	};
447 	(void)_nsdispatch(NULL, dtab, NSDB_PASSWD, "setpwent", defaultsrc, 0);
448 }
449 
450 
451 int
452 setpassent(int stayopen)
453 {
454 #ifdef NS_CACHING
455 	static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
456 		passwd, (void *)nss_lt_all,
457 		NULL, NULL);
458 #endif
459 
460 	static const ns_dtab dtab[] = {
461 		{ NSSRC_FILES, files_setpwent, (void *)SETPWENT },
462 #ifdef HESIOD
463 		{ NSSRC_DNS, dns_setpwent, (void *)SETPWENT },
464 #endif
465 #ifdef YP
466 		{ NSSRC_NIS, nis_setpwent, (void *)SETPWENT },
467 #endif
468 		{ NSSRC_COMPAT, compat_setpwent, (void *)SETPWENT },
469 #ifdef NS_CACHING
470 		NS_CACHE_CB(&cache_info)
471 #endif
472 		{ NULL, NULL, NULL }
473 	};
474 	(void)_nsdispatch(NULL, dtab, NSDB_PASSWD, "setpwent", defaultsrc,
475 	    stayopen);
476 	return (1);
477 }
478 
479 
480 void
481 endpwent(void)
482 {
483 #ifdef NS_CACHING
484 	static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
485 		passwd, (void *)nss_lt_all,
486 		NULL, NULL);
487 #endif
488 
489 	static const ns_dtab dtab[] = {
490 		{ NSSRC_FILES, files_setpwent, (void *)ENDPWENT },
491 #ifdef HESIOD
492 		{ NSSRC_DNS, dns_setpwent, (void *)ENDPWENT },
493 #endif
494 #ifdef YP
495 		{ NSSRC_NIS, nis_setpwent, (void *)ENDPWENT },
496 #endif
497 		{ NSSRC_COMPAT, compat_setpwent, (void *)ENDPWENT },
498 #ifdef NS_CACHING
499 		NS_CACHE_CB(&cache_info)
500 #endif
501 		{ NULL, NULL, NULL }
502 	};
503 	(void)_nsdispatch(NULL, dtab, NSDB_PASSWD, "endpwent", defaultsrc);
504 }
505 
506 
507 int
508 getpwent_r(struct passwd *pwd, char *buffer, size_t bufsize,
509     struct passwd **result)
510 {
511 #ifdef NS_CACHING
512 	static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
513 		passwd, (void *)nss_lt_all,
514 		pwd_marshal_func, pwd_unmarshal_func);
515 #endif
516 
517 	static const ns_dtab dtab[] = {
518 		{ NSSRC_FILES, files_passwd, (void *)nss_lt_all },
519 #ifdef HESIOD
520 		{ NSSRC_DNS, dns_passwd, (void *)nss_lt_all },
521 #endif
522 #ifdef YP
523 		{ NSSRC_NIS, nis_passwd, (void *)nss_lt_all },
524 #endif
525 		{ NSSRC_COMPAT, compat_passwd, (void *)nss_lt_all },
526 #ifdef NS_CACHING
527 		NS_CACHE_CB(&cache_info)
528 #endif
529 		{ NULL, NULL, NULL }
530 	};
531 	int	rv, ret_errno;
532 
533 	__pw_initpwd(pwd);
534 	ret_errno = 0;
535 	*result = NULL;
536 	rv = _nsdispatch(result, dtab, NSDB_PASSWD, "getpwent_r", defaultsrc,
537 	    pwd, buffer, bufsize, &ret_errno);
538 	if (rv == NS_SUCCESS)
539 		return (0);
540 	else
541 		return (ret_errno);
542 }
543 
544 
545 int
546 getpwnam_r(const char *name, struct passwd *pwd, char *buffer, size_t bufsize,
547     struct passwd **result)
548 {
549 #ifdef NS_CACHING
550 	static const nss_cache_info cache_info =
551     		NS_COMMON_CACHE_INFO_INITIALIZER(
552 		passwd, (void *)nss_lt_name,
553 		pwd_id_func, pwd_marshal_func, pwd_unmarshal_func);
554 #endif
555 
556 	static const ns_dtab dtab[] = {
557 		{ NSSRC_FILES, files_passwd, (void *)nss_lt_name },
558 #ifdef HESIOD
559 		{ NSSRC_DNS, dns_passwd, (void *)nss_lt_name },
560 #endif
561 #ifdef YP
562 		{ NSSRC_NIS, nis_passwd, (void *)nss_lt_name },
563 #endif
564 		{ NSSRC_COMPAT, compat_passwd, (void *)nss_lt_name },
565 #ifdef NS_CACHING
566 		NS_CACHE_CB(&cache_info)
567 #endif
568 		{ NULL, NULL, NULL }
569 	};
570 	int	rv, ret_errno;
571 
572 	__pw_initpwd(pwd);
573 	ret_errno = 0;
574 	*result = NULL;
575 	rv = _nsdispatch(result, dtab, NSDB_PASSWD, "getpwnam_r", defaultsrc,
576 	    name, pwd, buffer, bufsize, &ret_errno);
577 	if (rv == NS_SUCCESS)
578 		return (0);
579 	else
580 		return (ret_errno);
581 }
582 
583 
584 int
585 getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize,
586     struct passwd **result)
587 {
588 #ifdef NS_CACHING
589 	static const nss_cache_info cache_info =
590     		NS_COMMON_CACHE_INFO_INITIALIZER(
591 		passwd, (void *)nss_lt_id,
592 		pwd_id_func, pwd_marshal_func, pwd_unmarshal_func);
593 #endif
594 
595 	static const ns_dtab dtab[] = {
596 		{ NSSRC_FILES, files_passwd, (void *)nss_lt_id },
597 #ifdef HESIOD
598 		{ NSSRC_DNS, dns_passwd, (void *)nss_lt_id },
599 #endif
600 #ifdef YP
601 		{ NSSRC_NIS, nis_passwd, (void *)nss_lt_id },
602 #endif
603 		{ NSSRC_COMPAT, compat_passwd, (void *)nss_lt_id },
604 #ifdef NS_CACHING
605 		NS_CACHE_CB(&cache_info)
606 #endif
607 		{ NULL, NULL, NULL }
608 	};
609 	int	rv, ret_errno;
610 
611 	__pw_initpwd(pwd);
612 	ret_errno = 0;
613 	*result = NULL;
614 	rv = _nsdispatch(result, dtab, NSDB_PASSWD, "getpwuid_r", defaultsrc,
615 	    uid, pwd, buffer, bufsize, &ret_errno);
616 	if (rv == NS_SUCCESS)
617 		return (0);
618 	else
619 		return (ret_errno);
620 }
621 
622 
623 static struct passwd	 pwd;
624 static char		*pwd_storage;
625 static size_t		 pwd_storage_size;
626 
627 
628 static struct passwd *
629 getpw(int (*fn)(union key, struct passwd *, char *, size_t, struct passwd **),
630     union key key)
631 {
632 	int		 rv;
633 	struct passwd	*res;
634 
635 	if (pwd_storage == NULL) {
636 		pwd_storage = malloc(PWD_STORAGE_INITIAL);
637 		if (pwd_storage == NULL)
638 			return (NULL);
639 		pwd_storage_size = PWD_STORAGE_INITIAL;
640 	}
641 	do {
642 		rv = fn(key, &pwd, pwd_storage, pwd_storage_size, &res);
643 		if (res == NULL && rv == ERANGE) {
644 			free(pwd_storage);
645 			if ((pwd_storage_size << 1) > PWD_STORAGE_MAX) {
646 				pwd_storage = NULL;
647 				errno = ERANGE;
648 				return (NULL);
649 			}
650 			pwd_storage_size <<= 1;
651 			pwd_storage = malloc(pwd_storage_size);
652 			if (pwd_storage == NULL)
653 				return (NULL);
654 		}
655 	} while (res == NULL && rv == ERANGE);
656 	if (rv != 0)
657 		errno = rv;
658 	return (res);
659 }
660 
661 
662 static int
663 wrap_getpwnam_r(union key key, struct passwd *pwd, char *buffer,
664     size_t bufsize, struct passwd **res)
665 {
666 	return (getpwnam_r(key.name, pwd, buffer, bufsize, res));
667 }
668 
669 
670 static int
671 wrap_getpwuid_r(union key key, struct passwd *pwd, char *buffer,
672     size_t bufsize, struct passwd **res)
673 {
674 	return (getpwuid_r(key.uid, pwd, buffer, bufsize, res));
675 }
676 
677 
678 static int
679 wrap_getpwent_r(union key key __unused, struct passwd *pwd, char *buffer,
680     size_t bufsize, struct passwd **res)
681 {
682 	return (getpwent_r(pwd, buffer, bufsize, res));
683 }
684 
685 
686 struct passwd *
687 getpwnam(const char *name)
688 {
689 	union key key;
690 
691 	key.name = name;
692 	return (getpw(wrap_getpwnam_r, key));
693 }
694 
695 
696 struct passwd *
697 getpwuid(uid_t uid)
698 {
699 	union key key;
700 
701 	key.uid = uid;
702 	return (getpw(wrap_getpwuid_r, key));
703 }
704 
705 
706 struct passwd *
707 getpwent(void)
708 {
709 	union key key;
710 
711 	key.uid = 0; /* not used */
712 	return (getpw(wrap_getpwent_r, key));
713 }
714 
715 
716 /*
717  * files backend
718  */
719 static DB *
720 pwdbopen(int *version)
721 {
722 	DB	*res;
723 	DBT	 key, entry;
724 	int	 rv;
725 
726 	if (geteuid() != 0 ||
727 	    (res = dbopen(_PATH_SMP_DB, O_RDONLY, 0, DB_HASH, NULL)) == NULL)
728 		res = dbopen(_PATH_MP_DB, O_RDONLY, 0, DB_HASH, NULL);
729 	if (res == NULL)
730 		return (NULL);
731 	key.data = _PWD_VERSION_KEY;
732 	key.size = strlen(_PWD_VERSION_KEY);
733 	rv = res->get(res, &key, &entry, 0);
734 	if (rv == 0)
735 		*version = *(unsigned char *)entry.data;
736 	else
737 		*version = 3;
738 	if (*version < 3 ||
739 	    *version >= nitems(pwdb_versions)) {
740 		syslog(LOG_CRIT, "Unsupported password database version %d",
741 		    *version);
742 		res->close(res);
743 		res = NULL;
744 	}
745 	return (res);
746 }
747 
748 
749 static void
750 files_endstate(void *p)
751 {
752 	DB	*db;
753 
754 	if (p == NULL)
755 		return;
756 	db = ((struct files_state *)p)->db;
757 	if (db != NULL)
758 		db->close(db);
759 	free(p);
760 }
761 
762 
763 static int
764 files_setpwent(void *retval, void *mdata, va_list ap)
765 {
766 	struct files_state	*st;
767 	int			 rv, stayopen;
768 
769 	rv = files_getstate(&st);
770 	if (rv != 0)
771 		return (NS_UNAVAIL);
772 	switch ((enum constants)(uintptr_t)mdata) {
773 	case SETPWENT:
774 		stayopen = va_arg(ap, int);
775 		st->keynum = 0;
776 		if (stayopen)
777 			st->db = pwdbopen(&st->version);
778 		st->stayopen = stayopen;
779 		break;
780 	case ENDPWENT:
781 		if (st->db != NULL) {
782 			(void)st->db->close(st->db);
783 			st->db = NULL;
784 		}
785 		break;
786 	default:
787 		break;
788 	}
789 	return (NS_UNAVAIL);
790 }
791 
792 
793 static int
794 files_passwd(void *retval, void *mdata, va_list ap)
795 {
796 	char			 keybuf[MAXLOGNAME + 1];
797 	DBT			 key, entry;
798 	struct files_state	*st;
799 	enum nss_lookup_type	 how;
800 	const char		*name;
801 	struct passwd		*pwd;
802 	char			*buffer;
803 	size_t			 bufsize, namesize;
804 	uid_t			 uid;
805 	uint32_t		 store;
806 	int			 rv, stayopen = 0, *errnop;
807 
808 	name = NULL;
809 	uid = (uid_t)-1;
810 	how = (enum nss_lookup_type)(uintptr_t)mdata;
811 	switch (how) {
812 	case nss_lt_name:
813 		name = va_arg(ap, const char *);
814 		keybuf[0] = _PW_KEYBYNAME;
815 		break;
816 	case nss_lt_id:
817 		uid = va_arg(ap, uid_t);
818 		keybuf[0] = _PW_KEYBYUID;
819 		break;
820 	case nss_lt_all:
821 		keybuf[0] = _PW_KEYBYNUM;
822 		break;
823 	default:
824 		rv = NS_NOTFOUND;
825 		goto fin;
826 	}
827 	pwd = va_arg(ap, struct passwd *);
828 	buffer = va_arg(ap, char *);
829 	bufsize = va_arg(ap, size_t);
830 	errnop = va_arg(ap, int *);
831 	*errnop = files_getstate(&st);
832 	if (*errnop != 0)
833 		return (NS_UNAVAIL);
834 	if (how == nss_lt_all && st->keynum < 0) {
835 		rv = NS_NOTFOUND;
836 		goto fin;
837 	}
838 	if (st->db == NULL &&
839 	    (st->db = pwdbopen(&st->version)) == NULL) {
840 		*errnop = errno;
841 		rv = NS_UNAVAIL;
842 		goto fin;
843 	}
844 	if (how == nss_lt_all)
845 		stayopen = 1;
846 	else
847 		stayopen = st->stayopen;
848 	key.data = keybuf;
849 	do {
850 		switch (how) {
851 		case nss_lt_name:
852 			/* MAXLOGNAME includes NUL byte, but we do not
853 			 * include the NUL byte in the key.
854 			 */
855 			namesize = strlcpy(&keybuf[1], name, sizeof(keybuf)-1);
856 			if (namesize >= sizeof(keybuf)-1) {
857 				*errnop = EINVAL;
858 				rv = NS_NOTFOUND;
859 				goto fin;
860 			}
861 			key.size = namesize + 1;
862 			break;
863 		case nss_lt_id:
864 			if (st->version < _PWD_CURRENT_VERSION) {
865 				memcpy(&keybuf[1], &uid, sizeof(uid));
866 				key.size = sizeof(uid) + 1;
867 			} else {
868 				store = htonl(uid);
869 				memcpy(&keybuf[1], &store, sizeof(store));
870 				key.size = sizeof(store) + 1;
871 			}
872 			break;
873 		case nss_lt_all:
874 			st->keynum++;
875 			if (st->version < _PWD_CURRENT_VERSION) {
876 				memcpy(&keybuf[1], &st->keynum,
877 				    sizeof(st->keynum));
878 				key.size = sizeof(st->keynum) + 1;
879 			} else {
880 				store = htonl(st->keynum);
881 				memcpy(&keybuf[1], &store, sizeof(store));
882 				key.size = sizeof(store) + 1;
883 			}
884 			break;
885 		}
886 		keybuf[0] = _PW_VERSIONED(keybuf[0], st->version);
887 		rv = st->db->get(st->db, &key, &entry, 0);
888 		if (rv < 0 || rv > 1) { /* should never return > 1 */
889 			*errnop = errno;
890 			rv = NS_UNAVAIL;
891 			goto fin;
892 		} else if (rv == 1) {
893 			if (how == nss_lt_all)
894 				st->keynum = -1;
895 			rv = NS_NOTFOUND;
896 			goto fin;
897 		}
898 		rv = pwdb_versions[st->version].match(entry.data, entry.size,
899 		    how, name, uid);
900 		if (rv != NS_SUCCESS)
901 			continue;
902 		if (entry.size > bufsize) {
903 			*errnop = ERANGE;
904 			rv = NS_RETURN;
905 			break;
906 		}
907 		memcpy(buffer, entry.data, entry.size);
908 		rv = pwdb_versions[st->version].parse(buffer, entry.size, pwd,
909 		    errnop);
910 	} while (how == nss_lt_all && !(rv & NS_TERMINATE));
911 fin:
912 	if (st->db != NULL && !stayopen) {
913 		(void)st->db->close(st->db);
914 		st->db = NULL;
915 	}
916 	if (rv == NS_SUCCESS) {
917 		pwd->pw_fields &= ~_PWF_SOURCE;
918 		pwd->pw_fields |= _PWF_FILES;
919 		if (retval != NULL)
920 			*(struct passwd **)retval = pwd;
921 	}
922 	return (rv);
923 }
924 
925 
926 static int
927 pwdb_match_entry_v3(char *entry, size_t entrysize, enum nss_lookup_type how,
928     const char *name, uid_t uid)
929 {
930 	const char	*p, *eom;
931 	uid_t		 uid2;
932 
933 	eom = &entry[entrysize];
934 	for (p = entry; p < eom; p++)
935 		if (*p == '\0')
936 			break;
937 	if (*p != '\0')
938 		return (NS_NOTFOUND);
939 	if (how == nss_lt_all)
940 		return (NS_SUCCESS);
941 	if (how == nss_lt_name)
942 		return (strcmp(name, entry) == 0 ? NS_SUCCESS : NS_NOTFOUND);
943 	for (p++; p < eom; p++)
944 		if (*p == '\0')
945 			break;
946 	if (*p != '\0' || (++p) + sizeof(uid) >= eom)
947 		return (NS_NOTFOUND);
948 	memcpy(&uid2, p, sizeof(uid2));
949 	return (uid == uid2 ? NS_SUCCESS : NS_NOTFOUND);
950 }
951 
952 
953 static int
954 pwdb_parse_entry_v3(char *buffer, size_t bufsize, struct passwd *pwd,
955     int *errnop)
956 {
957 	char		*p, *eom;
958 	int32_t		 pw_change, pw_expire;
959 
960 	/* THIS CODE MUST MATCH THAT IN pwd_mkdb. */
961 	p = buffer;
962 	eom = &buffer[bufsize];
963 #define STRING(field)	do {			\
964 		(field) = p;			\
965 		while (p < eom && *p != '\0')	\
966 			p++;			\
967 		if (p >= eom)			\
968 			return (NS_NOTFOUND);	\
969 		p++;				\
970 	} while (0)
971 #define SCALAR(field)	do {				\
972 		if (p + sizeof(field) > eom)		\
973 			return (NS_NOTFOUND);		\
974 		memcpy(&(field), p, sizeof(field));	\
975 		p += sizeof(field);			\
976 	} while (0)
977 	STRING(pwd->pw_name);
978 	STRING(pwd->pw_passwd);
979 	SCALAR(pwd->pw_uid);
980 	SCALAR(pwd->pw_gid);
981 	SCALAR(pw_change);
982 	STRING(pwd->pw_class);
983 	STRING(pwd->pw_gecos);
984 	STRING(pwd->pw_dir);
985 	STRING(pwd->pw_shell);
986 	SCALAR(pw_expire);
987 	SCALAR(pwd->pw_fields);
988 #undef STRING
989 #undef SCALAR
990 	pwd->pw_change = pw_change;
991 	pwd->pw_expire = pw_expire;
992 	return (NS_SUCCESS);
993 }
994 
995 
996 static int
997 pwdb_match_entry_v4(char *entry, size_t entrysize, enum nss_lookup_type how,
998     const char *name, uid_t uid)
999 {
1000 	const char	*p, *eom;
1001 	uint32_t	 uid2;
1002 
1003 	eom = &entry[entrysize];
1004 	for (p = entry; p < eom; p++)
1005 		if (*p == '\0')
1006 			break;
1007 	if (*p != '\0')
1008 		return (NS_NOTFOUND);
1009 	if (how == nss_lt_all)
1010 		return (NS_SUCCESS);
1011 	if (how == nss_lt_name)
1012 		return (strcmp(name, entry) == 0 ? NS_SUCCESS : NS_NOTFOUND);
1013 	for (p++; p < eom; p++)
1014 		if (*p == '\0')
1015 			break;
1016 	if (*p != '\0' || (++p) + sizeof(uid) >= eom)
1017 		return (NS_NOTFOUND);
1018 	memcpy(&uid2, p, sizeof(uid2));
1019 	uid2 = ntohl(uid2);
1020 	return (uid == (uid_t)uid2 ? NS_SUCCESS : NS_NOTFOUND);
1021 }
1022 
1023 
1024 static int
1025 pwdb_parse_entry_v4(char *buffer, size_t bufsize, struct passwd *pwd,
1026     int *errnop)
1027 {
1028 	char		*p, *eom;
1029 	uint32_t	 n;
1030 
1031 	/* THIS CODE MUST MATCH THAT IN pwd_mkdb. */
1032 	p = buffer;
1033 	eom = &buffer[bufsize];
1034 #define STRING(field)	do {			\
1035 		(field) = p;			\
1036 		while (p < eom && *p != '\0')	\
1037 			p++;			\
1038 		if (p >= eom)			\
1039 			return (NS_NOTFOUND);	\
1040 		p++;				\
1041 	} while (0)
1042 #define SCALAR(field)	do {				\
1043 		if (p + sizeof(n) > eom)		\
1044 			return (NS_NOTFOUND);		\
1045 		memcpy(&n, p, sizeof(n));		\
1046 		(field) = ntohl(n);			\
1047 		p += sizeof(n);				\
1048 	} while (0)
1049 	STRING(pwd->pw_name);
1050 	STRING(pwd->pw_passwd);
1051 	SCALAR(pwd->pw_uid);
1052 	SCALAR(pwd->pw_gid);
1053 	SCALAR(pwd->pw_change);
1054 	STRING(pwd->pw_class);
1055 	STRING(pwd->pw_gecos);
1056 	STRING(pwd->pw_dir);
1057 	STRING(pwd->pw_shell);
1058 	SCALAR(pwd->pw_expire);
1059 	SCALAR(pwd->pw_fields);
1060 #undef STRING
1061 #undef SCALAR
1062 	return (NS_SUCCESS);
1063 }
1064 
1065 
1066 #ifdef HESIOD
1067 /*
1068  * dns backend
1069  */
1070 static void
1071 dns_endstate(void *p)
1072 {
1073 	free(p);
1074 }
1075 
1076 
1077 static int
1078 dns_setpwent(void *retval, void *mdata, va_list ap)
1079 {
1080 	struct dns_state	*st;
1081 	int			 rv;
1082 
1083 	rv = dns_getstate(&st);
1084 	if (rv != 0)
1085 		return (NS_UNAVAIL);
1086 	st->counter = 0;
1087 	return (NS_UNAVAIL);
1088 }
1089 
1090 
1091 static int
1092 dns_passwd(void *retval, void *mdata, va_list ap)
1093 {
1094 	char			 buf[HESIOD_NAME_MAX];
1095 	struct dns_state	*st;
1096 	struct passwd		*pwd;
1097 	const char		*name, *label;
1098 	void			*ctx;
1099 	char			*buffer, **hes;
1100 	size_t			 bufsize, linesize;
1101 	uid_t			 uid;
1102 	enum nss_lookup_type	 how;
1103 	int			 rv, *errnop;
1104 
1105 	ctx = NULL;
1106 	hes = NULL;
1107 	name = NULL;
1108 	uid = (uid_t)-1;
1109 	how = (enum nss_lookup_type)(uintptr_t)mdata;
1110 	switch (how) {
1111 	case nss_lt_name:
1112 		name = va_arg(ap, const char *);
1113 		break;
1114 	case nss_lt_id:
1115 		uid = va_arg(ap, uid_t);
1116 		break;
1117 	case nss_lt_all:
1118 		break;
1119 	}
1120 	pwd     = va_arg(ap, struct passwd *);
1121 	buffer  = va_arg(ap, char *);
1122 	bufsize = va_arg(ap, size_t);
1123 	errnop  = va_arg(ap, int *);
1124 	*errnop = dns_getstate(&st);
1125 	if (*errnop != 0)
1126 		return (NS_UNAVAIL);
1127 	if (hesiod_init(&ctx) != 0) {
1128 		*errnop = errno;
1129 		rv = NS_UNAVAIL;
1130 		goto fin;
1131 	}
1132 	do {
1133 		rv = NS_NOTFOUND;
1134 		switch (how) {
1135 		case nss_lt_name:
1136 			label = name;
1137 			break;
1138 		case nss_lt_id:
1139 			if (snprintf(buf, sizeof(buf), "%lu",
1140 			    (unsigned long)uid) >= sizeof(buf))
1141 				goto fin;
1142 			label = buf;
1143 			break;
1144 		case nss_lt_all:
1145 			if (st->counter < 0)
1146 				goto fin;
1147 			if (snprintf(buf, sizeof(buf), "passwd-%ld",
1148 			    st->counter++) >= sizeof(buf))
1149 				goto fin;
1150 			label = buf;
1151 			break;
1152 		}
1153 		hes = hesiod_resolve(ctx, label,
1154 		    how == nss_lt_id ? "uid" : "passwd");
1155 		if (hes == NULL) {
1156 			if (how == nss_lt_all)
1157 				st->counter = -1;
1158 			if (errno != ENOENT)
1159 				*errnop = errno;
1160 			goto fin;
1161 		}
1162 		rv = __pw_match_entry(hes[0], strlen(hes[0]), how, name, uid);
1163 		if (rv != NS_SUCCESS) {
1164 			hesiod_free_list(ctx, hes);
1165 			hes = NULL;
1166 			continue;
1167 		}
1168 		linesize = strlcpy(buffer, hes[0], bufsize);
1169 		if (linesize >= bufsize) {
1170 			*errnop = ERANGE;
1171 			rv = NS_RETURN;
1172 			continue;
1173 		}
1174 		hesiod_free_list(ctx, hes);
1175 		hes = NULL;
1176 		rv = __pw_parse_entry(buffer, bufsize, pwd, 0, errnop);
1177 	} while (how == nss_lt_all && !(rv & NS_TERMINATE));
1178 fin:
1179 	if (hes != NULL)
1180 		hesiod_free_list(ctx, hes);
1181 	if (ctx != NULL)
1182 		hesiod_end(ctx);
1183 	if (rv == NS_SUCCESS) {
1184 		pwd->pw_fields &= ~_PWF_SOURCE;
1185 		pwd->pw_fields |= _PWF_HESIOD;
1186 		if (retval != NULL)
1187 			*(struct passwd **)retval = pwd;
1188 	}
1189 	return (rv);
1190 }
1191 #endif /* HESIOD */
1192 
1193 
1194 #ifdef YP
1195 /*
1196  * nis backend
1197  */
1198 static void
1199 nis_endstate(void *p)
1200 {
1201 	free(((struct nis_state *)p)->key);
1202 	free(p);
1203 }
1204 
1205 /*
1206  * Test for the presence of special FreeBSD-specific master.passwd.by*
1207  * maps. We do this using yp_order(). If it fails, then either the server
1208  * doesn't have the map, or the YPPROC_ORDER procedure isn't supported by
1209  * the server (Sun NIS+ servers in YP compat mode behave this way). If
1210  * the master.passwd.by* maps don't exist, then let the lookup routine try
1211  * the regular passwd.by* maps instead. If the lookup routine fails, it
1212  * can return an error as needed.
1213  */
1214 static int
1215 nis_map(char *domain, enum nss_lookup_type how, char *buffer, size_t bufsize,
1216     int *master)
1217 {
1218 	int	rv, order;
1219 
1220 	*master = 0;
1221 	if (geteuid() == 0) {
1222 		if (snprintf(buffer, bufsize, "master.passwd.by%s",
1223 		    (how == nss_lt_id) ? "uid" : "name") >= bufsize)
1224 			return (NS_UNAVAIL);
1225 		rv = yp_order(domain, buffer, &order);
1226 		if (rv == 0) {
1227 			*master = 1;
1228 			return (NS_SUCCESS);
1229 		}
1230 	}
1231 
1232 	if (snprintf(buffer, bufsize, "passwd.by%s",
1233 	    (how == nss_lt_id) ? "uid" : "name") >= bufsize)
1234 		return (NS_UNAVAIL);
1235 
1236 	return (NS_SUCCESS);
1237 }
1238 
1239 
1240 static int
1241 nis_adjunct(char *domain, const char *name, char *buffer, size_t bufsize)
1242 {
1243 	int	 rv;
1244 	char	*result, *p, *q, *eor;
1245 	int	 resultlen;
1246 
1247 	result = NULL;
1248 	rv = yp_match(domain, "passwd.adjunct.byname", name, strlen(name),
1249 	    &result, &resultlen);
1250 	if (rv != 0)
1251 		rv = 1;
1252 	else {
1253 		eor = &result[resultlen];
1254 		p = memchr(result, ':', eor - result);
1255 		if (p != NULL && ++p < eor &&
1256 		    (q = memchr(p, ':', eor - p)) != NULL) {
1257 			if (q - p >= bufsize)
1258 				rv = -1;
1259 			else {
1260 				memcpy(buffer, p, q - p);
1261 				buffer[q - p] ='\0';
1262 			}
1263 		} else
1264 			rv = 1;
1265 	}
1266 	free(result);
1267 	return (rv);
1268 }
1269 
1270 
1271 static int
1272 nis_setpwent(void *retval, void *mdata, va_list ap)
1273 {
1274 	struct nis_state	*st;
1275 	int			 rv;
1276 
1277 	rv = nis_getstate(&st);
1278 	if (rv != 0)
1279 		return (NS_UNAVAIL);
1280 	st->done = 0;
1281 	free(st->key);
1282 	st->key = NULL;
1283 	return (NS_UNAVAIL);
1284 }
1285 
1286 
1287 static int
1288 nis_passwd(void *retval, void *mdata, va_list ap)
1289 {
1290 	char		 map[YPMAXMAP];
1291 	struct nis_state *st;
1292 	struct passwd	*pwd;
1293 	const char	*name;
1294 	char		*buffer, *key, *result;
1295 	size_t		 bufsize;
1296 	uid_t		 uid;
1297 	enum nss_lookup_type how;
1298 	int		*errnop, keylen, resultlen, rv, master;
1299 
1300 	name = NULL;
1301 	uid = (uid_t)-1;
1302 	how = (enum nss_lookup_type)(uintptr_t)mdata;
1303 	switch (how) {
1304 	case nss_lt_name:
1305 		name = va_arg(ap, const char *);
1306 		break;
1307 	case nss_lt_id:
1308 		uid = va_arg(ap, uid_t);
1309 		break;
1310 	case nss_lt_all:
1311 		break;
1312 	}
1313 	pwd     = va_arg(ap, struct passwd *);
1314 	buffer  = va_arg(ap, char *);
1315 	bufsize = va_arg(ap, size_t);
1316 	errnop  = va_arg(ap, int *);
1317 	*errnop = nis_getstate(&st);
1318 	if (*errnop != 0)
1319 		return (NS_UNAVAIL);
1320 	if (st->domain[0] == '\0') {
1321 		if (getdomainname(st->domain, sizeof(st->domain)) != 0) {
1322 			*errnop = errno;
1323 			return (NS_UNAVAIL);
1324 		}
1325 	}
1326 	rv = nis_map(st->domain, how, map, sizeof(map), &master);
1327 	if (rv != NS_SUCCESS)
1328 		return (rv);
1329 	result = NULL;
1330 	do {
1331 		rv = NS_NOTFOUND;
1332 		switch (how) {
1333 		case nss_lt_name:
1334 			if (strlcpy(buffer, name, bufsize) >= bufsize)
1335 				goto erange;
1336 			break;
1337 		case nss_lt_id:
1338 			if (snprintf(buffer, bufsize, "%lu",
1339 			    (unsigned long)uid) >= bufsize)
1340 				goto erange;
1341 			break;
1342 		case nss_lt_all:
1343 			if (st->done)
1344 				goto fin;
1345 			break;
1346 		}
1347 		result = NULL;
1348 		if (how == nss_lt_all) {
1349 			if (st->key == NULL)
1350 				rv = yp_first(st->domain, map, &st->key,
1351 				    &st->keylen, &result, &resultlen);
1352 			else {
1353 				key = st->key;
1354 				keylen = st->keylen;
1355 				st->key = NULL;
1356 				rv = yp_next(st->domain, map, key, keylen,
1357 				    &st->key, &st->keylen, &result,
1358 				    &resultlen);
1359 				free(key);
1360 			}
1361 			if (rv != 0) {
1362 				free(result);
1363 				free(st->key);
1364 				st->key = NULL;
1365 				if (rv == YPERR_NOMORE)
1366 					st->done = 1;
1367 				else
1368 					rv = NS_UNAVAIL;
1369 				goto fin;
1370 			}
1371 		} else {
1372 			rv = yp_match(st->domain, map, buffer, strlen(buffer),
1373 			    &result, &resultlen);
1374 			if (rv == YPERR_KEY) {
1375 				rv = NS_NOTFOUND;
1376 				continue;
1377 			} else if (rv != 0) {
1378 				free(result);
1379 				rv = NS_UNAVAIL;
1380 				continue;
1381 			}
1382 		}
1383 		if (resultlen >= bufsize) {
1384 			free(result);
1385 			goto erange;
1386 		}
1387 		memcpy(buffer, result, resultlen);
1388 		buffer[resultlen] = '\0';
1389 		free(result);
1390 		rv = __pw_match_entry(buffer, resultlen, how, name, uid);
1391 		if (rv == NS_SUCCESS)
1392 			rv = __pw_parse_entry(buffer, resultlen, pwd, master,
1393 			    errnop);
1394 	} while (how == nss_lt_all && !(rv & NS_TERMINATE));
1395 fin:
1396 	if (rv == NS_SUCCESS) {
1397 		if (strstr(pwd->pw_passwd, "##") != NULL) {
1398 			rv = nis_adjunct(st->domain, pwd->pw_name,
1399 			    &buffer[resultlen+1], bufsize-resultlen-1);
1400 			if (rv < 0)
1401 				goto erange;
1402 			else if (rv == 0)
1403 				pwd->pw_passwd = &buffer[resultlen+1];
1404 		}
1405 		pwd->pw_fields &= ~_PWF_SOURCE;
1406 		pwd->pw_fields |= _PWF_NIS;
1407 		if (retval != NULL)
1408 			*(struct passwd **)retval = pwd;
1409 		rv = NS_SUCCESS;
1410 	}
1411 	return (rv);
1412 erange:
1413 	*errnop = ERANGE;
1414 	return (NS_RETURN);
1415 }
1416 #endif /* YP */
1417 
1418 
1419 /*
1420  * compat backend
1421  */
1422 static void
1423 compat_clear_template(struct passwd *template)
1424 {
1425 
1426 	free(template->pw_passwd);
1427 	free(template->pw_gecos);
1428 	free(template->pw_dir);
1429 	free(template->pw_shell);
1430 	memset(template, 0, sizeof(*template));
1431 }
1432 
1433 
1434 static int
1435 compat_set_template(struct passwd *src, struct passwd *template)
1436 {
1437 
1438 	compat_clear_template(template);
1439 #ifdef PW_OVERRIDE_PASSWD
1440 	if ((src->pw_fields & _PWF_PASSWD) &&
1441 	    (template->pw_passwd = strdup(src->pw_passwd)) == NULL)
1442 		goto enomem;
1443 #endif
1444 	if (src->pw_fields & _PWF_UID)
1445 		template->pw_uid = src->pw_uid;
1446 	if (src->pw_fields & _PWF_GID)
1447 		template->pw_gid = src->pw_gid;
1448 	if ((src->pw_fields & _PWF_GECOS) &&
1449 	    (template->pw_gecos = strdup(src->pw_gecos)) == NULL)
1450 		goto enomem;
1451 	if ((src->pw_fields & _PWF_DIR) &&
1452 	    (template->pw_dir = strdup(src->pw_dir)) == NULL)
1453 		goto enomem;
1454 	if ((src->pw_fields & _PWF_SHELL) &&
1455 	    (template->pw_shell = strdup(src->pw_shell)) == NULL)
1456 		goto enomem;
1457 	template->pw_fields = src->pw_fields;
1458 	return (0);
1459 enomem:
1460 	syslog(LOG_ERR, "getpwent memory allocation failure");
1461 	return (-1);
1462 }
1463 
1464 
1465 static int
1466 compat_use_template(struct passwd *pwd, struct passwd *template, char *buffer,
1467     size_t bufsize)
1468 {
1469 	struct passwd hold;
1470 	char	*copy, *p, *q, *eob;
1471 	size_t	 n;
1472 
1473 	/* We cannot know the layout of the password fields in `buffer',
1474 	 * so we have to copy everything.
1475 	 */
1476 	if (template->pw_fields == 0) /* nothing to fill-in */
1477 		return (0);
1478 	n = 0;
1479 	n += pwd->pw_name != NULL ? strlen(pwd->pw_name) + 1 : 0;
1480 	n += pwd->pw_passwd != NULL ? strlen(pwd->pw_passwd) + 1 : 0;
1481 	n += pwd->pw_class != NULL ? strlen(pwd->pw_class) + 1 : 0;
1482 	n += pwd->pw_gecos != NULL ? strlen(pwd->pw_gecos) + 1 : 0;
1483 	n += pwd->pw_dir != NULL ? strlen(pwd->pw_dir) + 1 : 0;
1484 	n += pwd->pw_shell != NULL ? strlen(pwd->pw_shell) + 1 : 0;
1485 	copy = malloc(n);
1486 	if (copy == NULL) {
1487 		syslog(LOG_ERR, "getpwent memory allocation failure");
1488 		return (ENOMEM);
1489 	}
1490 	p = copy;
1491 	eob = &copy[n];
1492 #define COPY(field) do {				\
1493 	if (pwd->field == NULL)				\
1494 		hold.field = NULL;			\
1495 	else {						\
1496 		hold.field = p;				\
1497 		p += strlcpy(p, pwd->field, eob-p) + 1;	\
1498 	}						\
1499 } while (0)
1500 	COPY(pw_name);
1501 	COPY(pw_passwd);
1502 	COPY(pw_class);
1503 	COPY(pw_gecos);
1504 	COPY(pw_dir);
1505 	COPY(pw_shell);
1506 #undef COPY
1507 	p = buffer;
1508 	eob = &buffer[bufsize];
1509 #define COPY(field, flag) do {						 \
1510 	q = (template->pw_fields & flag) ? template->field : hold.field; \
1511 	if (q == NULL)							 \
1512 		pwd->field = NULL;					 \
1513 	else {								 \
1514 		pwd->field = p;						 \
1515 		if ((n = strlcpy(p, q, eob-p)) >= eob-p) {		 \
1516 			free(copy);					 \
1517 			return (ERANGE);				 \
1518 		}							 \
1519 		p += n + 1;						 \
1520 	}								 \
1521 } while (0)
1522 	COPY(pw_name, 0);
1523 #ifdef PW_OVERRIDE_PASSWD
1524 	COPY(pw_passwd, _PWF_PASSWD);
1525 #else
1526 	COPY(pw_passwd, 0);
1527 #endif
1528 	COPY(pw_class, 0);
1529 	COPY(pw_gecos, _PWF_GECOS);
1530 	COPY(pw_dir, _PWF_DIR);
1531 	COPY(pw_shell, _PWF_SHELL);
1532 #undef COPY
1533 #define COPY(field, flag) do {			\
1534 	if (template->pw_fields & flag)		\
1535 		pwd->field = template->field;	\
1536 } while (0)
1537 	COPY(pw_uid, _PWF_UID);
1538 	COPY(pw_gid, _PWF_GID);
1539 #undef COPY
1540 	free(copy);
1541 	return (0);
1542 }
1543 
1544 
1545 static int
1546 compat_exclude(const char *name, DB **db)
1547 {
1548 	DBT	key, data;
1549 
1550 	if (*db == NULL &&
1551 	    (*db = dbopen(NULL, O_RDWR, 600, DB_HASH, 0)) == NULL)
1552 		return (errno);
1553 	key.size = strlen(name);
1554 	key.data = (char *)name;
1555 	data.size = 0;
1556 	data.data = NULL;
1557 
1558 	if ((*db)->put(*db, &key, &data, 0) == -1)
1559 		return (errno);
1560 	return (0);
1561 }
1562 
1563 
1564 static int
1565 compat_is_excluded(const char *name, DB *db)
1566 {
1567 	DBT	key, data;
1568 
1569 	if (db == NULL)
1570 		return (0);
1571 	key.size = strlen(name);
1572 	key.data = (char *)name;
1573 	return (db->get(db, &key, &data, 0) == 0);
1574 }
1575 
1576 
1577 static int
1578 compat_redispatch(struct compat_state *st, enum nss_lookup_type how,
1579     enum nss_lookup_type lookup_how, const char *name, const char *lookup_name,
1580     uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize, int *errnop)
1581 {
1582 	static const ns_src compatsrc[] = {
1583 #ifdef YP
1584 		{ NSSRC_NIS, NS_SUCCESS },
1585 #endif
1586 		{ NULL, 0 }
1587 	};
1588 	ns_dtab dtab[] = {
1589 #ifdef YP
1590 		{ NSSRC_NIS, nis_passwd, NULL },
1591 #endif
1592 #ifdef HESIOD
1593 		{ NSSRC_DNS, dns_passwd, NULL },
1594 #endif
1595 		{ NULL, NULL, NULL }
1596 	};
1597 	void		*discard;
1598 	int		 e, i, rv;
1599 
1600 	for (i = 0; i < (int)(nitems(dtab) - 1); i++)
1601 		dtab[i].mdata = (void *)lookup_how;
1602 more:
1603 	__pw_initpwd(pwd);
1604 	switch (lookup_how) {
1605 	case nss_lt_all:
1606 		rv = _nsdispatch(&discard, dtab, NSDB_PASSWD_COMPAT,
1607 		    "getpwent_r", compatsrc, pwd, buffer, bufsize,
1608 		    errnop);
1609 		break;
1610 	case nss_lt_id:
1611 		rv = _nsdispatch(&discard, dtab, NSDB_PASSWD_COMPAT,
1612 		    "getpwuid_r", compatsrc, uid, pwd, buffer,
1613 		    bufsize, errnop);
1614 		break;
1615 	case nss_lt_name:
1616 		rv = _nsdispatch(&discard, dtab, NSDB_PASSWD_COMPAT,
1617 		    "getpwnam_r", compatsrc, lookup_name, pwd, buffer,
1618 		    bufsize, errnop);
1619 		break;
1620 	default:
1621 		return (NS_UNAVAIL);
1622 	}
1623 	if (rv != NS_SUCCESS)
1624 		return (rv);
1625 	if (compat_is_excluded(pwd->pw_name, st->exclude)) {
1626 		if (how == nss_lt_all)
1627 			goto more;
1628 		return (NS_NOTFOUND);
1629 	}
1630 	e = compat_use_template(pwd, &st->template, buffer, bufsize);
1631 	if (e != 0) {
1632 		*errnop = e;
1633 		if (e == ERANGE)
1634 			return (NS_RETURN);
1635 		else
1636 			return (NS_UNAVAIL);
1637 	}
1638 	switch (how) {
1639 	case nss_lt_name:
1640 		if (strcmp(name, pwd->pw_name) != 0)
1641 			return (NS_NOTFOUND);
1642 		break;
1643 	case nss_lt_id:
1644 		if (uid != pwd->pw_uid)
1645 			return (NS_NOTFOUND);
1646 		break;
1647 	default:
1648 		break;
1649 	}
1650 	return (NS_SUCCESS);
1651 }
1652 
1653 
1654 static void
1655 compat_endstate(void *p)
1656 {
1657 	struct compat_state *st;
1658 
1659 	if (p == NULL)
1660 		return;
1661 	st = (struct compat_state *)p;
1662 	if (st->db != NULL)
1663 		st->db->close(st->db);
1664 	if (st->exclude != NULL)
1665 		st->exclude->close(st->exclude);
1666 	compat_clear_template(&st->template);
1667 	free(p);
1668 }
1669 
1670 
1671 static int
1672 compat_setpwent(void *retval, void *mdata, va_list ap)
1673 {
1674 	static const ns_src compatsrc[] = {
1675 #ifdef YP
1676 		{ NSSRC_NIS, NS_SUCCESS },
1677 #endif
1678 		{ NULL, 0 }
1679 	};
1680 	ns_dtab dtab[] = {
1681 #ifdef YP
1682 		{ NSSRC_NIS, nis_setpwent, NULL },
1683 #endif
1684 #ifdef HESIOD
1685 		{ NSSRC_DNS, dns_setpwent, NULL },
1686 #endif
1687 		{ NULL, NULL, NULL }
1688 	};
1689 	struct compat_state	*st;
1690 	int			 rv, stayopen;
1691 
1692 #define set_setent(x, y) do {	 				\
1693 	int i;							\
1694 	for (i = 0; i < (int)(nitems(x) - 1); i++)		\
1695 		x[i].mdata = (void *)y;				\
1696 } while (0)
1697 
1698 	rv = compat_getstate(&st);
1699 	if (rv != 0)
1700 		return (NS_UNAVAIL);
1701 	switch ((enum constants)(uintptr_t)mdata) {
1702 	case SETPWENT:
1703 		stayopen = va_arg(ap, int);
1704 		st->keynum = 0;
1705 		if (stayopen)
1706 			st->db = pwdbopen(&st->version);
1707 		st->stayopen = stayopen;
1708 		set_setent(dtab, mdata);
1709 		(void)_nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "setpwent",
1710 		    compatsrc, 0);
1711 		break;
1712 	case ENDPWENT:
1713 		if (st->db != NULL) {
1714 			(void)st->db->close(st->db);
1715 			st->db = NULL;
1716 		}
1717 		set_setent(dtab, mdata);
1718 		(void)_nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "endpwent",
1719 		    compatsrc, 0);
1720 		break;
1721 	default:
1722 		break;
1723 	}
1724 	return (NS_UNAVAIL);
1725 #undef set_setent
1726 }
1727 
1728 
1729 static int
1730 compat_passwd(void *retval, void *mdata, va_list ap)
1731 {
1732 	char			 keybuf[MAXLOGNAME + 1];
1733 	DBT			 key, entry;
1734 	pwkeynum		 keynum;
1735 	struct compat_state	*st;
1736 	enum nss_lookup_type	 how;
1737 	const char		*name;
1738 	struct passwd		*pwd;
1739 	char			*buffer, *pw_name;
1740 	char			*host, *user, *domain;
1741 	size_t			 bufsize;
1742 	uid_t			 uid;
1743 	uint32_t		 store;
1744 	int			 rv, from_compat, stayopen, *errnop;
1745 
1746 	from_compat = 0;
1747 	name = NULL;
1748 	uid = (uid_t)-1;
1749 	how = (enum nss_lookup_type)(uintptr_t)mdata;
1750 	switch (how) {
1751 	case nss_lt_name:
1752 		name = va_arg(ap, const char *);
1753 		break;
1754 	case nss_lt_id:
1755 		uid = va_arg(ap, uid_t);
1756 		break;
1757 	case nss_lt_all:
1758 		break;
1759 	default:
1760 		rv = NS_NOTFOUND;
1761 		goto fin;
1762 	}
1763 	pwd = va_arg(ap, struct passwd *);
1764 	buffer = va_arg(ap, char *);
1765 	bufsize = va_arg(ap, size_t);
1766 	errnop = va_arg(ap, int *);
1767 	*errnop = compat_getstate(&st);
1768 	if (*errnop != 0)
1769 		return (NS_UNAVAIL);
1770 	if (how == nss_lt_all && st->keynum < 0) {
1771 		rv = NS_NOTFOUND;
1772 		goto fin;
1773 	}
1774 	if (st->db == NULL &&
1775 	    (st->db = pwdbopen(&st->version)) == NULL) {
1776 		*errnop = errno;
1777 		rv = NS_UNAVAIL;
1778 		goto fin;
1779 	}
1780 	if (how == nss_lt_all) {
1781 		if (st->keynum < 0) {
1782 			rv = NS_NOTFOUND;
1783 			goto fin;
1784 		}
1785 		keynum = st->keynum;
1786 		stayopen = 1;
1787 	} else {
1788 		keynum = 0;
1789 		stayopen = st->stayopen;
1790 	}
1791 docompat:
1792 	rv = NS_NOTFOUND;
1793 	switch (st->compat) {
1794 	case COMPAT_MODE_ALL:
1795 		rv = compat_redispatch(st, how, how, name, name, uid, pwd,
1796 		    buffer, bufsize, errnop);
1797 		if (rv != NS_SUCCESS)
1798 			st->compat = COMPAT_MODE_OFF;
1799 		break;
1800 	case COMPAT_MODE_NETGROUP:
1801 		/* XXX getnetgrent is not thread-safe. */
1802 		do {
1803 			rv = getnetgrent(&host, &user, &domain);
1804 			if (rv == 0) {
1805 				endnetgrent();
1806 				st->compat = COMPAT_MODE_OFF;
1807 				rv = NS_NOTFOUND;
1808 				continue;
1809 			} else if (user == NULL || user[0] == '\0')
1810 				continue;
1811 			rv = compat_redispatch(st, how, nss_lt_name, name,
1812 			    user, uid, pwd, buffer, bufsize, errnop);
1813 		} while (st->compat == COMPAT_MODE_NETGROUP &&
1814 		    !(rv & NS_TERMINATE));
1815 		break;
1816 	case COMPAT_MODE_NAME:
1817 		rv = compat_redispatch(st, how, nss_lt_name, name, st->name,
1818 		    uid, pwd, buffer, bufsize, errnop);
1819 		free(st->name);
1820 		st->name = NULL;
1821 		st->compat = COMPAT_MODE_OFF;
1822 		break;
1823 	default:
1824 		break;
1825 	}
1826 	if (rv & NS_TERMINATE) {
1827 		from_compat = 1;
1828 		goto fin;
1829 	}
1830 	key.data = keybuf;
1831 	rv = NS_NOTFOUND;
1832 	while (keynum >= 0) {
1833 		keynum++;
1834 		if (st->version < _PWD_CURRENT_VERSION) {
1835 			memcpy(&keybuf[1], &keynum, sizeof(keynum));
1836 			key.size = sizeof(keynum) + 1;
1837 		} else {
1838 			store = htonl(keynum);
1839 			memcpy(&keybuf[1], &store, sizeof(store));
1840 			key.size = sizeof(store) + 1;
1841 		}
1842 		keybuf[0] = _PW_VERSIONED(_PW_KEYBYNUM, st->version);
1843 		rv = st->db->get(st->db, &key, &entry, 0);
1844 		if (rv < 0 || rv > 1) { /* should never return > 1 */
1845 			*errnop = errno;
1846 			rv = NS_UNAVAIL;
1847 			goto fin;
1848 		} else if (rv == 1) {
1849 			keynum = -1;
1850 			rv = NS_NOTFOUND;
1851 			goto fin;
1852 		}
1853 		pw_name = (char *)entry.data;
1854 		switch (pw_name[0]) {
1855 		case '+':
1856 			switch (pw_name[1]) {
1857 			case '\0':
1858 				st->compat = COMPAT_MODE_ALL;
1859 				break;
1860 			case '@':
1861 				setnetgrent(&pw_name[2]);
1862 				st->compat = COMPAT_MODE_NETGROUP;
1863 				break;
1864 			default:
1865 				st->name = strdup(&pw_name[1]);
1866 				if (st->name == NULL) {
1867 					syslog(LOG_ERR,
1868 					 "getpwent memory allocation failure");
1869 					*errnop = ENOMEM;
1870 					rv = NS_UNAVAIL;
1871 					break;
1872 				}
1873 				st->compat = COMPAT_MODE_NAME;
1874 			}
1875 			if (entry.size > bufsize) {
1876 				*errnop = ERANGE;
1877 				rv = NS_RETURN;
1878 				goto fin;
1879 			}
1880 			memcpy(buffer, entry.data, entry.size);
1881 			rv = pwdb_versions[st->version].parse(buffer,
1882 			    entry.size, pwd, errnop);
1883 			if (rv != NS_SUCCESS)
1884 				;
1885 			else if (compat_set_template(pwd, &st->template) < 0) {
1886 				*errnop = ENOMEM;
1887 				rv = NS_UNAVAIL;
1888 				goto fin;
1889 			}
1890 			goto docompat;
1891 		case '-':
1892 			switch (pw_name[1]) {
1893 			case '\0':
1894 				/* XXX Maybe syslog warning */
1895 				continue;
1896 			case '@':
1897 				setnetgrent(&pw_name[2]);
1898 				while (getnetgrent(&host, &user, &domain) !=
1899 				    0) {
1900 					if (user != NULL && user[0] != '\0')
1901 						compat_exclude(user,
1902 						    &st->exclude);
1903 				}
1904 				endnetgrent();
1905 				continue;
1906 			default:
1907 				compat_exclude(&pw_name[1], &st->exclude);
1908 				continue;
1909 			}
1910 			break;
1911 		default:
1912 			break;
1913 		}
1914 		if (compat_is_excluded((char *)entry.data, st->exclude))
1915 			continue;
1916 		rv = pwdb_versions[st->version].match(entry.data, entry.size,
1917 		    how, name, uid);
1918 		if (rv == NS_RETURN)
1919 			break;
1920 		else if (rv != NS_SUCCESS)
1921 			continue;
1922 		if (entry.size > bufsize) {
1923 			*errnop = ERANGE;
1924 			rv = NS_RETURN;
1925 			break;
1926 		}
1927 		memcpy(buffer, entry.data, entry.size);
1928 		rv = pwdb_versions[st->version].parse(buffer, entry.size, pwd,
1929 		    errnop);
1930 		if (rv & NS_TERMINATE)
1931 			break;
1932 	}
1933 fin:
1934 	if (how == nss_lt_all)
1935 		st->keynum = keynum;
1936 	if (st->db != NULL && !stayopen) {
1937 		(void)st->db->close(st->db);
1938 		st->db = NULL;
1939 	}
1940 	if (rv == NS_SUCCESS) {
1941 		if (!from_compat) {
1942 			pwd->pw_fields &= ~_PWF_SOURCE;
1943 			pwd->pw_fields |= _PWF_FILES;
1944 		}
1945 		if (retval != NULL)
1946 			*(struct passwd **)retval = pwd;
1947 	}
1948 	return (rv);
1949 }
1950 
1951 
1952 /*
1953  * common passwd line matching and parsing
1954  */
1955 int
1956 __pw_match_entry(const char *entry, size_t entrysize, enum nss_lookup_type how,
1957     const char *name, uid_t uid)
1958 {
1959 	const char	*p, *eom;
1960 	char		*q;
1961 	size_t		 len;
1962 	unsigned long	 m;
1963 
1964 	eom = entry + entrysize;
1965 	for (p = entry; p < eom; p++)
1966 		if (*p == ':')
1967 			break;
1968 	if (*p != ':')
1969 		return (NS_NOTFOUND);
1970 	if (how == nss_lt_all)
1971 		return (NS_SUCCESS);
1972 	if (how == nss_lt_name) {
1973 		len = strlen(name);
1974 		if (len == (p - entry) && memcmp(name, entry, len) == 0)
1975 			return (NS_SUCCESS);
1976 		else
1977 			return (NS_NOTFOUND);
1978 	}
1979 	for (p++; p < eom; p++)
1980 		if (*p == ':')
1981 			break;
1982 	if (*p != ':')
1983 		return (NS_NOTFOUND);
1984 	m = strtoul(++p, &q, 10);
1985 	if (q[0] != ':' || (uid_t)m != uid)
1986 		return (NS_NOTFOUND);
1987 	else
1988 		return (NS_SUCCESS);
1989 }
1990 
1991 
1992 /* XXX buffer must be NUL-terminated.  errnop is not set correctly. */
1993 int
1994 __pw_parse_entry(char *buffer, size_t bufsize __unused, struct passwd *pwd,
1995     int master, int *errnop __unused)
1996 {
1997 
1998 	if (__pw_scan(buffer, pwd, master ? _PWSCAN_MASTER : 0) == 0)
1999 		return (NS_NOTFOUND);
2000 	else
2001 		return (NS_SUCCESS);
2002 }
2003