Home | History | Annotate | Line # | Download | only in gen
      1 /*	$NetBSD: getgrent.c,v 1.67 2012/08/29 18:50:35 dholland Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1999-2000, 2004-2005 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Luke Mewburn.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 /*
     33  * Copyright (c) 1989, 1993
     34  *	The Regents of the University of California.  All rights reserved.
     35  *
     36  * Redistribution and use in source and binary forms, with or without
     37  * modification, are permitted provided that the following conditions
     38  * are met:
     39  * 1. Redistributions of source code must retain the above copyright
     40  *    notice, this list of conditions and the following disclaimer.
     41  * 2. Redistributions in binary form must reproduce the above copyright
     42  *    notice, this list of conditions and the following disclaimer in the
     43  *    documentation and/or other materials provided with the distribution.
     44  * 3. Neither the name of the University nor the names of its contributors
     45  *    may be used to endorse or promote products derived from this software
     46  *    without specific prior written permission.
     47  *
     48  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     49  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     50  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     51  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     52  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     53  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     54  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     55  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     56  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     57  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     58  * SUCH DAMAGE.
     59  */
     60 
     61 /*
     62  * Portions Copyright (c) 1994, Jason Downs. All Rights Reserved.
     63  *
     64  * Redistribution and use in source and binary forms, with or without
     65  * modification, are permitted provided that the following conditions
     66  * are met:
     67  * 1. Redistributions of source code must retain the above copyright
     68  *    notice, this list of conditions and the following disclaimer.
     69  * 2. Redistributions in binary form must reproduce the above copyright
     70  *    notice, this list of conditions and the following disclaimer in the
     71  *    documentation and/or other materials provided with the distribution.
     72  *
     73  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
     74  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     75  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     76  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
     77  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     78  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     79  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     80  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     81  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     82  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     83  * SUCH DAMAGE.
     84  */
     85 
     86 #include <sys/cdefs.h>
     87 #if defined(LIBC_SCCS) && !defined(lint)
     88 #if 0
     89 static char sccsid[] = "@(#)getgrent.c	8.2 (Berkeley) 3/21/94";
     90 #else
     91 __RCSID("$NetBSD: getgrent.c,v 1.67 2012/08/29 18:50:35 dholland Exp $");
     92 #endif
     93 #endif /* LIBC_SCCS and not lint */
     94 
     95 #include "namespace.h"
     96 #include "reentrant.h"
     97 
     98 #include <sys/param.h>
     99 
    100 #include <assert.h>
    101 #include <errno.h>
    102 #include <grp.h>
    103 #include <limits.h>
    104 #include <nsswitch.h>
    105 #include <stdarg.h>
    106 #include <stdio.h>
    107 #include <stdlib.h>
    108 #include <string.h>
    109 #include <syslog.h>
    110 
    111 #ifdef HESIOD
    112 #include <hesiod.h>
    113 #endif
    114 
    115 #ifdef YP
    116 #include <rpc/rpc.h>
    117 #include <rpcsvc/yp_prot.h>
    118 #include <rpcsvc/ypclnt.h>
    119 #endif
    120 
    121 #include "gr_private.h"
    122 
    123 #ifdef __weak_alias
    124 __weak_alias(endgrent,_endgrent)
    125 __weak_alias(getgrent,_getgrent)
    126 __weak_alias(getgrent_r,_getgrent_r)
    127 __weak_alias(getgrgid,_getgrgid)
    128 __weak_alias(getgrgid_r,_getgrgid_r)
    129 __weak_alias(getgrnam,_getgrnam)
    130 __weak_alias(getgrnam_r,_getgrnam_r)
    131 __weak_alias(setgrent,_setgrent)
    132 __weak_alias(setgroupent,_setgroupent)
    133 #endif
    134 
    135 #ifdef _REENTRANT
    136 mutex_t	__grmutex = MUTEX_INITIALIZER;
    137 #endif
    138 
    139 /*
    140  * _gr_memfrombuf
    141  *	Obtain want bytes from buffer (of size buflen) and return a pointer
    142  *	to the available memory after adjusting buffer/buflen.
    143  *	Returns NULL if there is insufficient space.
    144  */
    145 static char *
    146 _gr_memfrombuf(size_t want, char **buffer, size_t *buflen)
    147 {
    148 	char	*rv;
    149 
    150 	if (want > *buflen) {
    151 		errno = ERANGE;
    152 		return NULL;
    153 	}
    154 	rv = *buffer;
    155 	*buffer += want;
    156 	*buflen -= want;
    157 	return rv;
    158 }
    159 
    160 /*
    161  * _gr_parse
    162  *	Parses entry as a line per group(5) (without the trailing \n)
    163  *	and fills in grp with corresponding values; memory for strings
    164  *	and arrays will be allocated from buf (of size buflen).
    165  *	Returns 1 if parsed successfully, 0 on parse failure.
    166  */
    167 static int
    168 _gr_parse(const char *entry, struct group *grp, char *buf, size_t buflen)
    169 {
    170 	unsigned long	id;
    171 	const char	*bp;
    172 	char		*ep;
    173 	size_t		count;
    174 	int		memc;
    175 
    176 	_DIAGASSERT(entry != NULL);
    177 	_DIAGASSERT(grp != NULL);
    178 	_DIAGASSERT(buf != NULL);
    179 
    180 #define COPYTOBUF(to) \
    181 	do { \
    182 		(to) = _gr_memfrombuf(count+1, &buf, &buflen); \
    183 		if ((to) == NULL) \
    184 			return 0; \
    185 		memmove((to), entry, count); \
    186 		to[count] = '\0'; \
    187 	} while (0)	/* LINTED */
    188 
    189 #if 0
    190 	if (*entry == '+')			/* fail on compat `+' token */
    191 		return 0;
    192 #endif
    193 
    194 	count = strcspn(entry, ":");		/* parse gr_name */
    195 	if (entry[count] == '\0')
    196 		return 0;
    197 	COPYTOBUF(grp->gr_name);
    198 	entry += count + 1;
    199 
    200 	count = strcspn(entry, ":");		/* parse gr_passwd */
    201 	if (entry[count] == '\0')
    202 		return 0;
    203 	COPYTOBUF(grp->gr_passwd);
    204 	entry += count + 1;
    205 
    206 	count = strcspn(entry, ":");		/* parse gr_gid */
    207 	if (entry[count] == '\0')
    208 		return 0;
    209 	id = strtoul(entry, &ep, 10);
    210 	if (id > GID_MAX || *ep != ':')
    211 		return 0;
    212 	grp->gr_gid = (gid_t)id;
    213 	entry += count + 1;
    214 
    215 	memc = 1;				/* for final NULL */
    216 	if (*entry != '\0')
    217 		memc++;				/* for first item */
    218 	for (bp = entry; *bp != '\0'; bp++) {
    219 		if (*bp == ',')
    220 			memc++;
    221 	}
    222 				/* grab ALIGNed char **gr_mem from buf */
    223 	ep = _gr_memfrombuf(memc * sizeof(char *) + ALIGNBYTES, &buf, &buflen);
    224 	if (ep == NULL)
    225 		return 0;
    226 	grp->gr_mem = (char **)ALIGN(ep);
    227 
    228 	for (memc = 0; *entry != '\0'; memc++) {
    229 		count = strcspn(entry, ",");	/* parse member */
    230 		COPYTOBUF(grp->gr_mem[memc]);
    231 		entry += count;
    232 		if (*entry == ',')
    233 			entry++;
    234 	}
    235 
    236 #undef COPYTOBUF
    237 
    238 	grp->gr_mem[memc] = NULL;
    239 	return 1;
    240 }
    241 
    242 /*
    243  * _gr_copy
    244  *	Copy the contents of fromgrp to grp; memory for strings
    245  *	and arrays will be allocated from buf (of size buflen).
    246  *	Returns 1 if copied successfully, 0 on copy failure.
    247  *	NOTE: fromgrp must not use buf for its own pointers.
    248  */
    249 static int
    250 _gr_copy(struct group *fromgrp, struct group *grp, char *buf, size_t buflen)
    251 {
    252 	char	*ep;
    253 	int	memc;
    254 
    255 	_DIAGASSERT(fromgrp != NULL);
    256 	_DIAGASSERT(grp != NULL);
    257 	_DIAGASSERT(buf != NULL);
    258 
    259 #define COPYSTR(to, from) \
    260 	do { \
    261 		size_t count = strlen((from)); \
    262 		(to) = _gr_memfrombuf(count+1, &buf, &buflen); \
    263 		if ((to) == NULL) \
    264 			return 0; \
    265 		memmove((to), (from), count); \
    266 		to[count] = '\0'; \
    267 	} while (0)	/* LINTED */
    268 
    269 	COPYSTR(grp->gr_name, fromgrp->gr_name);
    270 	COPYSTR(grp->gr_passwd, fromgrp->gr_passwd);
    271 	grp->gr_gid = fromgrp->gr_gid;
    272 
    273 	if (fromgrp->gr_mem == NULL)
    274 		return 0;
    275 
    276 	for (memc = 0; fromgrp->gr_mem[memc]; memc++)
    277 		continue;
    278 	memc++;					/* for final NULL */
    279 
    280 				/* grab ALIGNed char **gr_mem from buf */
    281 	ep = _gr_memfrombuf(memc * sizeof(char *) + ALIGNBYTES, &buf, &buflen);
    282 	grp->gr_mem = (char **)ALIGN(ep);
    283 	if (grp->gr_mem == NULL)
    284 		return 0;
    285 
    286 	for (memc = 0; fromgrp->gr_mem[memc]; memc++) {
    287 		COPYSTR(grp->gr_mem[memc], fromgrp->gr_mem[memc]);
    288 	}
    289 
    290 #undef COPYSTR
    291 
    292 	grp->gr_mem[memc] = NULL;
    293 	return 1;
    294 }
    295 
    296 		/*
    297 		 *	files methods
    298 		 */
    299 
    300 int
    301 __grstart_files(struct __grstate_files *state)
    302 {
    303 
    304 	_DIAGASSERT(state != NULL);
    305 
    306 	if (state->fp == NULL) {
    307 		state->fp = fopen(_PATH_GROUP, "re");
    308 		if (state->fp == NULL)
    309 			return NS_UNAVAIL;
    310 	} else {
    311 		rewind(state->fp);
    312 	}
    313 	return NS_SUCCESS;
    314 }
    315 
    316 int
    317 __grend_files(struct __grstate_files *state)
    318 {
    319 
    320 	_DIAGASSERT(state != NULL);
    321 
    322 	if (state->fp) {
    323 		(void) fclose(state->fp);
    324 		state->fp = NULL;
    325 	}
    326 	return NS_SUCCESS;
    327 }
    328 
    329 /*
    330  * __grscan_files
    331  *	Scan state->fp for the next desired entry.
    332  *	If search is zero, return the next entry.
    333  *	If search is non-zero, look for a specific name (if name != NULL),
    334  *	or a specific gid (if name == NULL).
    335  *	Sets *retval to the errno if the result is not NS_SUCCESS
    336  *	or NS_NOTFOUND.
    337  */
    338 int
    339 __grscan_files(int *retval, struct group *grp, char *buffer, size_t buflen,
    340 	struct __grstate_files *state, int search, const char *name, gid_t gid)
    341 {
    342 	int	rv;
    343 	char	filebuf[_GETGR_R_SIZE_MAX], *ep;
    344 
    345 	_DIAGASSERT(retval != NULL);
    346 	_DIAGASSERT(grp != NULL);
    347 	_DIAGASSERT(buffer != NULL);
    348 	_DIAGASSERT(state != NULL);
    349 	/* name is NULL to indicate searching for gid */
    350 
    351 	*retval = 0;
    352 
    353 	if (state->fp == NULL) {	/* only start if file not open yet */
    354 		rv = __grstart_files(state);
    355 		if (rv != NS_SUCCESS)
    356 			goto filesgrscan_out;
    357 	}
    358 
    359 	rv = NS_NOTFOUND;
    360 
    361 							/* scan line by line */
    362 	while (fgets(filebuf, (int)sizeof(filebuf), state->fp) != NULL) {
    363 		ep = strchr(filebuf, '\n');
    364 		if (ep == NULL) {	/* skip lines that are too big */
    365 			int ch;
    366 
    367 			while ((ch = getc(state->fp)) != '\n' && ch != EOF)
    368 				continue;
    369 			continue;
    370 		}
    371 		*ep = '\0';				/* clear trailing \n */
    372 
    373 		if (filebuf[0] == '+')			/* skip compat line */
    374 			continue;
    375 
    376 							/* validate line */
    377 		if (! _gr_parse(filebuf, grp, buffer, buflen)) {
    378 			continue;			/* skip bad lines */
    379 		}
    380 		if (! search) {				/* just want this one */
    381 			rv = NS_SUCCESS;
    382 			break;
    383 		}
    384 							/* want specific */
    385 		if ((name && strcmp(name, grp->gr_name) == 0) ||
    386 		    (!name && gid == grp->gr_gid)) {
    387 			rv = NS_SUCCESS;
    388 			break;
    389 		}
    390 	}
    391 
    392  filesgrscan_out:
    393 	if (rv != NS_SUCCESS && rv != NS_NOTFOUND)
    394 		*retval = errno;
    395 	return rv;
    396 }
    397 
    398 
    399 static struct __grstate_files	_files_state;
    400 					/* storage for non _r functions */
    401 static struct group		_files_group;
    402 static char			_files_groupbuf[_GETGR_R_SIZE_MAX];
    403 
    404 /*ARGSUSED*/
    405 static int
    406 _files_setgrent(void *nsrv, void *nscb, va_list ap)
    407 {
    408 
    409 	_files_state.stayopen = 0;
    410 	return __grstart_files(&_files_state);
    411 }
    412 
    413 /*ARGSUSED*/
    414 static int
    415 _files_setgroupent(void *nsrv, void *nscb, va_list ap)
    416 {
    417 	int	*retval		= va_arg(ap, int *);
    418 	int	 stayopen	= va_arg(ap, int);
    419 
    420 	int	rv;
    421 
    422 	_files_state.stayopen = stayopen;
    423 	rv = __grstart_files(&_files_state);
    424 	*retval = (rv == NS_SUCCESS);
    425 	return rv;
    426 }
    427 
    428 /*ARGSUSED*/
    429 static int
    430 _files_endgrent(void *nsrv, void *nscb, va_list ap)
    431 {
    432 
    433 	_files_state.stayopen = 0;
    434 	return __grend_files(&_files_state);
    435 }
    436 
    437 /*ARGSUSED*/
    438 static int
    439 _files_getgrent(void *nsrv, void *nscb, va_list ap)
    440 {
    441 	struct group	**retval = va_arg(ap, struct group **);
    442 
    443 	int	rv, rerror;
    444 
    445 	_DIAGASSERT(retval != NULL);
    446 
    447 	*retval = NULL;
    448 	rv = __grscan_files(&rerror, &_files_group,
    449 	    _files_groupbuf, sizeof(_files_groupbuf),
    450 	    &_files_state, 0, NULL, 0);
    451 	if (rv == NS_SUCCESS)
    452 		*retval = &_files_group;
    453 	return rv;
    454 }
    455 
    456 /*ARGSUSED*/
    457 static int
    458 _files_getgrent_r(void *nsrv, void *nscb, va_list ap)
    459 {
    460 	int		*retval	= va_arg(ap, int *);
    461 	struct group	*grp	= va_arg(ap, struct group *);
    462 	char		*buffer	= va_arg(ap, char *);
    463 	size_t		 buflen	= va_arg(ap, size_t);
    464 	struct group   **result	= va_arg(ap, struct group **);
    465 
    466 	int	rv;
    467 
    468 	_DIAGASSERT(retval != NULL);
    469 	_DIAGASSERT(grp != NULL);
    470 	_DIAGASSERT(buffer != NULL);
    471 	_DIAGASSERT(result != NULL);
    472 
    473 	rv = __grscan_files(retval, grp, buffer, buflen,
    474 	    &_files_state, 0, NULL, 0);
    475 	if (rv == NS_SUCCESS)
    476 		*result = grp;
    477 	else
    478 		*result = NULL;
    479 	return rv;
    480 }
    481 
    482 /*ARGSUSED*/
    483 static int
    484 _files_getgrgid(void *nsrv, void *nscb, va_list ap)
    485 {
    486 	struct group	**retval = va_arg(ap, struct group **);
    487 	gid_t		 gid	= va_arg(ap, gid_t);
    488 
    489 	int	rv, rerror;
    490 
    491 	_DIAGASSERT(retval != NULL);
    492 
    493 	*retval = NULL;
    494 	rv = __grstart_files(&_files_state);
    495 	if (rv != NS_SUCCESS)
    496 		return rv;
    497 	rv = __grscan_files(&rerror, &_files_group,
    498 	    _files_groupbuf, sizeof(_files_groupbuf),
    499 	    &_files_state, 1, NULL, gid);
    500 	if (!_files_state.stayopen)
    501 		__grend_files(&_files_state);
    502 	if (rv == NS_SUCCESS)
    503 		*retval = &_files_group;
    504 	return rv;
    505 }
    506 
    507 /*ARGSUSED*/
    508 static int
    509 _files_getgrgid_r(void *nsrv, void *nscb, va_list ap)
    510 {
    511 	int		*retval	= va_arg(ap, int *);
    512 	gid_t		 gid	= va_arg(ap, gid_t);
    513 	struct group	*grp	= va_arg(ap, struct group *);
    514 	char		*buffer	= va_arg(ap, char *);
    515 	size_t		 buflen	= va_arg(ap, size_t);
    516 	struct group   **result	= va_arg(ap, struct group **);
    517 
    518 	struct __grstate_files state;
    519 	int	rv;
    520 
    521 	_DIAGASSERT(retval != NULL);
    522 	_DIAGASSERT(grp != NULL);
    523 	_DIAGASSERT(buffer != NULL);
    524 	_DIAGASSERT(result != NULL);
    525 
    526 	*result = NULL;
    527 	memset(&state, 0, sizeof(state));
    528 	rv = __grscan_files(retval, grp, buffer, buflen, &state, 1, NULL, gid);
    529 	__grend_files(&state);
    530 	if (rv == NS_SUCCESS)
    531 		*result = grp;
    532 	return rv;
    533 }
    534 
    535 /*ARGSUSED*/
    536 static int
    537 _files_getgrnam(void *nsrv, void *nscb, va_list ap)
    538 {
    539 	struct group	**retval = va_arg(ap, struct group **);
    540 	const char	*name	= va_arg(ap, const char *);
    541 
    542 	int	rv, rerror;
    543 
    544 	_DIAGASSERT(retval != NULL);
    545 
    546 	*retval = NULL;
    547 	rv = __grstart_files(&_files_state);
    548 	if (rv != NS_SUCCESS)
    549 		return rv;
    550 	rv = __grscan_files(&rerror, &_files_group,
    551 	    _files_groupbuf, sizeof(_files_groupbuf),
    552 	    &_files_state, 1, name, 0);
    553 	if (!_files_state.stayopen)
    554 		__grend_files(&_files_state);
    555 	if (rv == NS_SUCCESS)
    556 		*retval = &_files_group;
    557 	return rv;
    558 }
    559 
    560 /*ARGSUSED*/
    561 static int
    562 _files_getgrnam_r(void *nsrv, void *nscb, va_list ap)
    563 {
    564 	int		*retval	= va_arg(ap, int *);
    565 	const char	*name	= va_arg(ap, const char *);
    566 	struct group	*grp	= va_arg(ap, struct group *);
    567 	char		*buffer	= va_arg(ap, char *);
    568 	size_t		 buflen	= va_arg(ap, size_t);
    569 	struct group   **result	= va_arg(ap, struct group **);
    570 
    571 	struct __grstate_files state;
    572 	int	rv;
    573 
    574 	_DIAGASSERT(retval != NULL);
    575 	_DIAGASSERT(grp != NULL);
    576 	_DIAGASSERT(buffer != NULL);
    577 	_DIAGASSERT(result != NULL);
    578 
    579 	*result = NULL;
    580 	memset(&state, 0, sizeof(state));
    581 	rv = __grscan_files(retval, grp, buffer, buflen, &state, 1, name, 0);
    582 	__grend_files(&state);
    583 	if (rv == NS_SUCCESS)
    584 		*result = grp;
    585 	return rv;
    586 }
    587 
    588 
    589 #ifdef HESIOD
    590 		/*
    591 		 *	dns methods
    592 		 */
    593 
    594 int
    595 __grstart_dns(struct __grstate_dns *state)
    596 {
    597 
    598 	_DIAGASSERT(state != NULL);
    599 
    600 	state->num = 0;
    601 	if (state->context == NULL) {			/* setup Hesiod */
    602 		if (hesiod_init(&state->context) == -1)
    603 			return NS_UNAVAIL;
    604 	}
    605 
    606 	return NS_SUCCESS;
    607 }
    608 
    609 int
    610 __grend_dns(struct __grstate_dns *state)
    611 {
    612 
    613 	_DIAGASSERT(state != NULL);
    614 
    615 	state->num = 0;
    616 	if (state->context) {
    617 		hesiod_end(state->context);
    618 		state->context = NULL;
    619 	}
    620 	return NS_SUCCESS;
    621 }
    622 
    623 /*
    624  * __grscan_dns
    625  *	Search Hesiod for the next desired entry.
    626  *	If search is zero, return the next entry.
    627  *	If search is non-zero, look for a specific name (if name != NULL),
    628  *	or a specific gid (if name == NULL).
    629  */
    630 int
    631 __grscan_dns(int *retval, struct group *grp, char *buffer, size_t buflen,
    632 	struct __grstate_dns *state, int search, const char *name, gid_t gid)
    633 {
    634 	const char	**curzone;
    635 	char		**hp, *ep;
    636 	int		rv;
    637 
    638 	static const char *zones_gid_group[] = {
    639 		"gid",
    640 		"group",
    641 		NULL
    642 	};
    643 
    644 	static const char *zones_group[] = {
    645 		"group",
    646 		NULL
    647 	};
    648 
    649 	_DIAGASSERT(retval != NULL);
    650 	_DIAGASSERT(grp != NULL);
    651 	_DIAGASSERT(buffer != NULL);
    652 	_DIAGASSERT(state != NULL);
    653 	/* name is NULL to indicate searching for gid */
    654 
    655 	*retval = 0;
    656 
    657 	if (state->context == NULL) {	/* only start if Hesiod not setup */
    658 		rv = __grstart_dns(state);
    659 		if (rv != NS_SUCCESS)
    660 			return rv;
    661 	}
    662 
    663  next_dns_entry:
    664 	hp = NULL;
    665 	rv = NS_NOTFOUND;
    666 
    667 	if (! search) {			/* find next entry */
    668 		if (state->num == -1)		/* exhausted search */
    669 			return NS_NOTFOUND;
    670 						/* find group-NNN */
    671 		snprintf(buffer, buflen, "group-%u", state->num);
    672 		state->num++;
    673 		curzone = zones_group;
    674 	} else if (name) {		/* find group name */
    675 		snprintf(buffer, buflen, "%s", name);
    676 		curzone = zones_group;
    677 	} else {			/* find gid */
    678 		snprintf(buffer, buflen, "%u", (unsigned int)gid);
    679 		curzone = zones_gid_group;
    680 	}
    681 
    682 	for (; *curzone; curzone++) {		/* search zones */
    683 		hp = hesiod_resolve(state->context, buffer, *curzone);
    684 		if (hp != NULL)
    685 			break;
    686 		if (errno != ENOENT) {
    687 			rv = NS_UNAVAIL;
    688 			goto dnsgrscan_out;
    689 		}
    690 	}
    691 	if (*curzone == NULL) {
    692 		if (! search)
    693 			state->num = -1;
    694 		goto dnsgrscan_out;
    695 	}
    696 
    697 	if ((ep = strchr(hp[0], '\n')) != NULL)
    698 		*ep = '\0';				/* clear trailing \n */
    699 	if (_gr_parse(hp[0], grp, buffer, buflen)) {	/* validate line */
    700 		if (! search) {				/* just want this one */
    701 			rv = NS_SUCCESS;
    702 		} else if ((name && strcmp(name, grp->gr_name) == 0) ||
    703 		    (!name && gid == grp->gr_gid)) {	/* want specific */
    704 			rv = NS_SUCCESS;
    705 		}
    706 	} else {					/* dodgy entry */
    707 		if (!search) {			/* try again if ! searching */
    708 			hesiod_free_list(state->context, hp);
    709 			goto next_dns_entry;
    710 		}
    711 	}
    712 
    713  dnsgrscan_out:
    714 	if (rv != NS_SUCCESS && rv != NS_NOTFOUND)
    715 		*retval = errno;
    716 	if (hp)
    717 		hesiod_free_list(state->context, hp);
    718 	return rv;
    719 }
    720 
    721 static struct __grstate_dns	_dns_state;
    722 					/* storage for non _r functions */
    723 static struct group		_dns_group;
    724 static char			_dns_groupbuf[_GETGR_R_SIZE_MAX];
    725 
    726 /*ARGSUSED*/
    727 static int
    728 _dns_setgrent(void *nsrv, void *nscb, va_list ap)
    729 {
    730 
    731 	_dns_state.stayopen = 0;
    732 	return __grstart_dns(&_dns_state);
    733 }
    734 
    735 /*ARGSUSED*/
    736 static int
    737 _dns_setgroupent(void *nsrv, void *nscb, va_list ap)
    738 {
    739 	int	*retval		= va_arg(ap, int *);
    740 	int	 stayopen	= va_arg(ap, int);
    741 
    742 	int	rv;
    743 
    744 	_dns_state.stayopen = stayopen;
    745 	rv = __grstart_dns(&_dns_state);
    746 	*retval = (rv == NS_SUCCESS);
    747 	return rv;
    748 }
    749 
    750 /*ARGSUSED*/
    751 static int
    752 _dns_endgrent(void *nsrv, void *nscb, va_list ap)
    753 {
    754 
    755 	_dns_state.stayopen = 0;
    756 	return __grend_dns(&_dns_state);
    757 }
    758 
    759 /*ARGSUSED*/
    760 static int
    761 _dns_getgrent(void *nsrv, void *nscb, va_list ap)
    762 {
    763 	struct group	**retval = va_arg(ap, struct group **);
    764 
    765 	int	  rv, rerror;
    766 
    767 	_DIAGASSERT(retval != NULL);
    768 
    769 	*retval = NULL;
    770 	rv = __grscan_dns(&rerror, &_dns_group,
    771 	    _dns_groupbuf, sizeof(_dns_groupbuf), &_dns_state, 0, NULL, 0);
    772 	if (rv == NS_SUCCESS)
    773 		*retval = &_dns_group;
    774 	return rv;
    775 }
    776 
    777 /*ARGSUSED*/
    778 static int
    779 _dns_getgrent_r(void *nsrv, void *nscb, va_list ap)
    780 {
    781 	int		*retval	= va_arg(ap, int *);
    782 	struct group	*grp	= va_arg(ap, struct group *);
    783 	char		*buffer	= va_arg(ap, char *);
    784 	size_t		 buflen	= va_arg(ap, size_t);
    785 	struct group   **result	= va_arg(ap, struct group **);
    786 
    787 	int	rv;
    788 
    789 	_DIAGASSERT(retval != NULL);
    790 	_DIAGASSERT(grp != NULL);
    791 	_DIAGASSERT(buffer != NULL);
    792 	_DIAGASSERT(result != NULL);
    793 
    794 	rv = __grscan_dns(retval, grp, buffer, buflen,
    795 	    &_dns_state, 0, NULL, 0);
    796 	if (rv == NS_SUCCESS)
    797 		*result = grp;
    798 	else
    799 		*result = NULL;
    800 	return rv;
    801 }
    802 /*ARGSUSED*/
    803 static int
    804 _dns_getgrgid(void *nsrv, void *nscb, va_list ap)
    805 {
    806 	struct group	**retval = va_arg(ap, struct group **);
    807 	gid_t		 gid	= va_arg(ap, gid_t);
    808 
    809 	int	rv, rerror;
    810 
    811 	_DIAGASSERT(retval != NULL);
    812 
    813 	*retval = NULL;
    814 	rv = __grstart_dns(&_dns_state);
    815 	if (rv != NS_SUCCESS)
    816 		return rv;
    817 	rv = __grscan_dns(&rerror, &_dns_group,
    818 	    _dns_groupbuf, sizeof(_dns_groupbuf), &_dns_state, 1, NULL, gid);
    819 	if (!_dns_state.stayopen)
    820 		__grend_dns(&_dns_state);
    821 	if (rv == NS_SUCCESS)
    822 		*retval = &_dns_group;
    823 	return rv;
    824 }
    825 
    826 /*ARGSUSED*/
    827 static int
    828 _dns_getgrgid_r(void *nsrv, void *nscb, va_list ap)
    829 {
    830 	int		*retval	= va_arg(ap, int *);
    831 	gid_t		 gid	= va_arg(ap, gid_t);
    832 	struct group	*grp	= va_arg(ap, struct group *);
    833 	char		*buffer	= va_arg(ap, char *);
    834 	size_t		 buflen	= va_arg(ap, size_t);
    835 	struct group   **result	= va_arg(ap, struct group **);
    836 
    837 	struct __grstate_dns state;
    838 	int	rv;
    839 
    840 	_DIAGASSERT(retval != NULL);
    841 	_DIAGASSERT(grp != NULL);
    842 	_DIAGASSERT(buffer != NULL);
    843 	_DIAGASSERT(result != NULL);
    844 
    845 	*result = NULL;
    846 	memset(&state, 0, sizeof(state));
    847 	rv = __grscan_dns(retval, grp, buffer, buflen, &state, 1, NULL, gid);
    848 	__grend_dns(&state);
    849 	if (rv == NS_SUCCESS)
    850 		*result = grp;
    851 	return rv;
    852 }
    853 
    854 /*ARGSUSED*/
    855 static int
    856 _dns_getgrnam(void *nsrv, void *nscb, va_list ap)
    857 {
    858 	struct group	**retval = va_arg(ap, struct group **);
    859 	const char	*name	= va_arg(ap, const char *);
    860 
    861 	int	rv, rerror;
    862 
    863 	_DIAGASSERT(retval != NULL);
    864 
    865 	*retval = NULL;
    866 	rv = __grstart_dns(&_dns_state);
    867 	if (rv != NS_SUCCESS)
    868 		return rv;
    869 	rv = __grscan_dns(&rerror, &_dns_group,
    870 	    _dns_groupbuf, sizeof(_dns_groupbuf), &_dns_state, 1, name, 0);
    871 	if (!_dns_state.stayopen)
    872 		__grend_dns(&_dns_state);
    873 	if (rv == NS_SUCCESS)
    874 		*retval = &_dns_group;
    875 	return rv;
    876 }
    877 
    878 /*ARGSUSED*/
    879 static int
    880 _dns_getgrnam_r(void *nsrv, void *nscb, va_list ap)
    881 {
    882 	int		*retval	= va_arg(ap, int *);
    883 	const char	*name	= va_arg(ap, const char *);
    884 	struct group	*grp	= va_arg(ap, struct group *);
    885 	char		*buffer	= va_arg(ap, char *);
    886 	size_t		 buflen	= va_arg(ap, size_t);
    887 	struct group   **result	= va_arg(ap, struct group **);
    888 
    889 	struct __grstate_dns state;
    890 	int	rv;
    891 
    892 	_DIAGASSERT(retval != NULL);
    893 	_DIAGASSERT(grp != NULL);
    894 	_DIAGASSERT(buffer != NULL);
    895 	_DIAGASSERT(result != NULL);
    896 
    897 	*result = NULL;
    898 	memset(&state, 0, sizeof(state));
    899 	rv = __grscan_dns(retval, grp, buffer, buflen, &state, 1, name, 0);
    900 	__grend_dns(&state);
    901 	if (rv == NS_SUCCESS)
    902 		*result = grp;
    903 	return rv;
    904 }
    905 
    906 #endif /* HESIOD */
    907 
    908 
    909 #ifdef YP
    910 		/*
    911 		 *	nis methods
    912 		 */
    913 
    914 int
    915 __grstart_nis(struct __grstate_nis *state)
    916 {
    917 
    918 	_DIAGASSERT(state != NULL);
    919 
    920 	state->done = 0;
    921 	if (state->current) {
    922 		free(state->current);
    923 		state->current = NULL;
    924 	}
    925 	if (state->domain == NULL) {			/* setup NIS */
    926 		switch (yp_get_default_domain(&state->domain)) {
    927 		case 0:
    928 			break;
    929 		case YPERR_RESRC:
    930 			return NS_TRYAGAIN;
    931 		default:
    932 			return NS_UNAVAIL;
    933 		}
    934 	}
    935 	return NS_SUCCESS;
    936 }
    937 
    938 int
    939 __grend_nis(struct __grstate_nis *state)
    940 {
    941 
    942 	_DIAGASSERT(state != NULL);
    943 
    944 	if (state->domain) {
    945 		state->domain = NULL;
    946 	}
    947 	state->done = 0;
    948 	if (state->current) {
    949 		free(state->current);
    950 		state->current = NULL;
    951 	}
    952 	return NS_SUCCESS;
    953 }
    954 
    955 /*
    956  * __grscan_nis
    957  *	Search NIS for the next desired entry.
    958  *	If search is zero, return the next entry.
    959  *	If search is non-zero, look for a specific name (if name != NULL),
    960  *	or a specific gid (if name == NULL).
    961  */
    962 int
    963 __grscan_nis(int *retval, struct group *grp, char *buffer, size_t buflen,
    964 	struct __grstate_nis *state, int search, const char *name, gid_t gid)
    965 {
    966 	const char *map;
    967 	char	*key, *data;
    968 	int	nisr, rv, keylen, datalen;
    969 
    970 	_DIAGASSERT(retval != NULL);
    971 	_DIAGASSERT(grp != NULL);
    972 	_DIAGASSERT(buffer != NULL);
    973 	_DIAGASSERT(state != NULL);
    974 	/* name is NULL to indicate searching for gid */
    975 
    976 	*retval = 0;
    977 
    978 	if (state->domain == NULL) {	/* only start if NIS not setup */
    979 		rv = __grstart_nis(state);
    980 		if (rv != NS_SUCCESS)
    981 			return rv;
    982 	}
    983 
    984  next_nis_entry:
    985 	key = NULL;
    986 	data = NULL;
    987 	rv = NS_SUCCESS;
    988 
    989 	if (! search) 	{			/* find next entry */
    990 		if (state->done)			/* exhausted search */
    991 			return NS_NOTFOUND;
    992 		map = "group.byname";
    993 		if (state->current) {			/* already searching */
    994 			nisr = yp_next(state->domain, map,
    995 			    state->current, state->currentlen,
    996 			    &key, &keylen, &data, &datalen);
    997 			free(state->current);
    998 			state->current = NULL;
    999 			switch (nisr) {
   1000 			case 0:
   1001 				state->current = key;
   1002 				state->currentlen = keylen;
   1003 				key = NULL;
   1004 				break;
   1005 			case YPERR_NOMORE:
   1006 				rv = NS_NOTFOUND;
   1007 				state->done = 1;
   1008 				break;
   1009 			default:
   1010 				rv = NS_UNAVAIL;
   1011 				break;
   1012 			}
   1013 		} else {				/* new search */
   1014 			if (yp_first(state->domain, map,
   1015 			    &state->current, &state->currentlen,
   1016 			    &data, &datalen)) {
   1017 				rv = NS_UNAVAIL;
   1018 			}
   1019 		}
   1020 	} else {				/* search for specific item */
   1021 		if (name) {			/* find group name */
   1022 			snprintf(buffer, buflen, "%s", name);
   1023 			map = "group.byname";
   1024 		} else {			/* find gid */
   1025 			snprintf(buffer, buflen, "%u", (unsigned int)gid);
   1026 			map = "group.bygid";
   1027 		}
   1028 		nisr = yp_match(state->domain, map, buffer, (int)strlen(buffer),
   1029 		    &data, &datalen);
   1030 		switch (nisr) {
   1031 		case 0:
   1032 			break;
   1033 		case YPERR_KEY:
   1034 			rv = NS_NOTFOUND;
   1035 			break;
   1036 		default:
   1037 			rv = NS_UNAVAIL;
   1038 			break;
   1039 		}
   1040 	}
   1041 	if (rv == NS_SUCCESS) {				/* validate data */
   1042 		data[datalen] = '\0';			/* clear trailing \n */
   1043 		if (_gr_parse(data, grp, buffer, buflen)) {
   1044 			if (! search) {			/* just want this one */
   1045 				rv = NS_SUCCESS;
   1046 			} else if ((name && strcmp(name, grp->gr_name) == 0) ||
   1047 			    (!name && gid == grp->gr_gid)) {
   1048 							/* want specific */
   1049 				rv = NS_SUCCESS;
   1050 			}
   1051 		} else {				/* dodgy entry */
   1052 			if (!search) {		/* try again if ! searching */
   1053 				free(data);
   1054 				goto next_nis_entry;
   1055 			}
   1056 		}
   1057 	}
   1058 
   1059 	if (rv != NS_SUCCESS && rv != NS_NOTFOUND)
   1060 		*retval = errno;
   1061 	if (key)
   1062 		free(key);
   1063 	if (data)
   1064 		free(data);
   1065 	return rv;
   1066 }
   1067 
   1068 static struct __grstate_nis	_nis_state;
   1069 					/* storage for non _r functions */
   1070 static struct group		_nis_group;
   1071 static char			_nis_groupbuf[_GETGR_R_SIZE_MAX];
   1072 
   1073 /*ARGSUSED*/
   1074 static int
   1075 _nis_setgrent(void *nsrv, void *nscb, va_list ap)
   1076 {
   1077 
   1078 	_nis_state.stayopen = 0;
   1079 	return __grstart_nis(&_nis_state);
   1080 }
   1081 
   1082 /*ARGSUSED*/
   1083 static int
   1084 _nis_setgroupent(void *nsrv, void *nscb, va_list ap)
   1085 {
   1086 	int	*retval		= va_arg(ap, int *);
   1087 	int	 stayopen	= va_arg(ap, int);
   1088 
   1089 	int	rv;
   1090 
   1091 	_nis_state.stayopen = stayopen;
   1092 	rv = __grstart_nis(&_nis_state);
   1093 	*retval = (rv == NS_SUCCESS);
   1094 	return rv;
   1095 }
   1096 
   1097 /*ARGSUSED*/
   1098 static int
   1099 _nis_endgrent(void *nsrv, void *nscb, va_list ap)
   1100 {
   1101 
   1102 	return __grend_nis(&_nis_state);
   1103 }
   1104 
   1105 /*ARGSUSED*/
   1106 static int
   1107 _nis_getgrent(void *nsrv, void *nscb, va_list ap)
   1108 {
   1109 	struct group	**retval = va_arg(ap, struct group **);
   1110 
   1111 	int	rv, rerror;
   1112 
   1113 	_DIAGASSERT(retval != NULL);
   1114 
   1115 	*retval = NULL;
   1116 	rv = __grscan_nis(&rerror, &_nis_group,
   1117 	    _nis_groupbuf, sizeof(_nis_groupbuf), &_nis_state, 0, NULL, 0);
   1118 	if (rv == NS_SUCCESS)
   1119 		*retval = &_nis_group;
   1120 	return rv;
   1121 }
   1122 
   1123 /*ARGSUSED*/
   1124 static int
   1125 _nis_getgrent_r(void *nsrv, void *nscb, va_list ap)
   1126 {
   1127 	int		*retval	= va_arg(ap, int *);
   1128 	struct group	*grp	= va_arg(ap, struct group *);
   1129 	char		*buffer	= va_arg(ap, char *);
   1130 	size_t		 buflen	= va_arg(ap, size_t);
   1131 	struct group   **result	= va_arg(ap, struct group **);
   1132 
   1133 	int	rv;
   1134 
   1135 	_DIAGASSERT(retval != NULL);
   1136 	_DIAGASSERT(grp != NULL);
   1137 	_DIAGASSERT(buffer != NULL);
   1138 	_DIAGASSERT(result != NULL);
   1139 
   1140 	rv = __grscan_nis(retval, grp, buffer, buflen,
   1141 	    &_nis_state, 0, NULL, 0);
   1142 	if (rv == NS_SUCCESS)
   1143 		*result = grp;
   1144 	else
   1145 		*result = NULL;
   1146 	return rv;
   1147 }
   1148 
   1149 /*ARGSUSED*/
   1150 static int
   1151 _nis_getgrgid(void *nsrv, void *nscb, va_list ap)
   1152 {
   1153 	struct group	**retval = va_arg(ap, struct group **);
   1154 	gid_t		 gid	= va_arg(ap, gid_t);
   1155 
   1156 	int	rv, rerror;
   1157 
   1158 	_DIAGASSERT(retval != NULL);
   1159 
   1160 	*retval = NULL;
   1161 	rv = __grstart_nis(&_nis_state);
   1162 	if (rv != NS_SUCCESS)
   1163 		return rv;
   1164 	rv = __grscan_nis(&rerror, &_nis_group,
   1165 	    _nis_groupbuf, sizeof(_nis_groupbuf), &_nis_state, 1, NULL, gid);
   1166 	if (!_nis_state.stayopen)
   1167 		__grend_nis(&_nis_state);
   1168 	if (rv == NS_SUCCESS)
   1169 		*retval = &_nis_group;
   1170 	return rv;
   1171 }
   1172 
   1173 /*ARGSUSED*/
   1174 static int
   1175 _nis_getgrgid_r(void *nsrv, void *nscb, va_list ap)
   1176 {
   1177 	int		*retval	= va_arg(ap, int *);
   1178 	gid_t		 gid	= va_arg(ap, gid_t);
   1179 	struct group	*grp	= va_arg(ap, struct group *);
   1180 	char		*buffer	= va_arg(ap, char *);
   1181 	size_t		 buflen	= va_arg(ap, size_t);
   1182 	struct group   **result	= va_arg(ap, struct group **);
   1183 
   1184 	struct __grstate_nis state;
   1185 	int	rv;
   1186 
   1187 	_DIAGASSERT(retval != NULL);
   1188 	_DIAGASSERT(grp != NULL);
   1189 	_DIAGASSERT(buffer != NULL);
   1190 	_DIAGASSERT(result != NULL);
   1191 
   1192 	*result = NULL;
   1193 /* remark: we run under a global mutex inside of this module ... */
   1194 	if (_nis_state.stayopen)
   1195 	  { /* use global state only if stayopen is set - otherwiese we would blow up getgrent_r() ... */
   1196 	     rv = __grscan_nis(retval, grp, buffer, buflen, &_nis_state, 1, NULL, gid);
   1197 	  }
   1198 	else
   1199 	  {
   1200 	    memset(&state, 0, sizeof(state));
   1201 	    rv = __grscan_nis(retval, grp, buffer, buflen, &state, 1, NULL, gid);
   1202 	    __grend_nis(&state);
   1203 	  }
   1204 	if (rv == NS_SUCCESS)
   1205 		*result = grp;
   1206 	return rv;
   1207 }
   1208 
   1209 /*ARGSUSED*/
   1210 static int
   1211 _nis_getgrnam(void *nsrv, void *nscb, va_list ap)
   1212 {
   1213 	struct group	**retval = va_arg(ap, struct group **);
   1214 	const char	*name	= va_arg(ap, const char *);
   1215 
   1216 	int	rv, rerror;
   1217 
   1218 	_DIAGASSERT(retval != NULL);
   1219 
   1220 	*retval = NULL;
   1221 	rv = __grstart_nis(&_nis_state);
   1222 	if (rv != NS_SUCCESS)
   1223 		return rv;
   1224 	rv = __grscan_nis(&rerror, &_nis_group,
   1225 	    _nis_groupbuf, sizeof(_nis_groupbuf), &_nis_state, 1, name, 0);
   1226 	if (!_nis_state.stayopen)
   1227 		__grend_nis(&_nis_state);
   1228 	if (rv == NS_SUCCESS)
   1229 		*retval = &_nis_group;
   1230 	return rv;
   1231 }
   1232 
   1233 /*ARGSUSED*/
   1234 static int
   1235 _nis_getgrnam_r(void *nsrv, void *nscb, va_list ap)
   1236 {
   1237 	int		*retval	= va_arg(ap, int *);
   1238 	const char	*name	= va_arg(ap, const char *);
   1239 	struct group	*grp	= va_arg(ap, struct group *);
   1240 	char		*buffer	= va_arg(ap, char *);
   1241 	size_t		 buflen	= va_arg(ap, size_t);
   1242 	struct group   **result	= va_arg(ap, struct group **);
   1243 
   1244 	struct __grstate_nis state;
   1245 	int	rv;
   1246 
   1247 	_DIAGASSERT(retval != NULL);
   1248 	_DIAGASSERT(grp != NULL);
   1249 	_DIAGASSERT(buffer != NULL);
   1250 	_DIAGASSERT(result != NULL);
   1251 
   1252 	*result = NULL;
   1253 /* remark: we run under a global mutex inside of this module ... */
   1254 	if (_nis_state.stayopen)
   1255 	  { /* use global state only if stayopen is set - otherwiese we would blow up getgrent_r() ... */
   1256 	     rv = __grscan_nis(retval, grp, buffer, buflen, &_nis_state, 1, name, 0);
   1257 	  }
   1258 	else
   1259 	  {
   1260 	    memset(&state, 0, sizeof(state));
   1261 	    rv = __grscan_nis(retval, grp, buffer, buflen, &state, 1, name, 0);
   1262 	    __grend_nis(&state);
   1263 	  }
   1264 	if (rv == NS_SUCCESS)
   1265 		*result = grp;
   1266 	return rv;
   1267 }
   1268 
   1269 #endif /* YP */
   1270 
   1271 
   1272 #ifdef _GROUP_COMPAT
   1273 		/*
   1274 		 *	compat methods
   1275 		 */
   1276 
   1277 int
   1278 __grstart_compat(struct __grstate_compat *state)
   1279 {
   1280 
   1281 	_DIAGASSERT(state != NULL);
   1282 
   1283 	if (state->fp == NULL) {
   1284 		state->fp = fopen(_PATH_GROUP, "re");
   1285 		if (state->fp == NULL)
   1286 			return NS_UNAVAIL;
   1287 	} else {
   1288 		rewind(state->fp);
   1289 	}
   1290 	return NS_SUCCESS;
   1291 }
   1292 
   1293 int
   1294 __grend_compat(struct __grstate_compat *state)
   1295 {
   1296 
   1297 	_DIAGASSERT(state != NULL);
   1298 
   1299 	if (state->name) {
   1300 		free(state->name);
   1301 		state->name = NULL;
   1302 	}
   1303 	if (state->fp) {
   1304 		(void) fclose(state->fp);
   1305 		state->fp = NULL;
   1306 	}
   1307 	return NS_SUCCESS;
   1308 }
   1309 
   1310 
   1311 /*
   1312  * __grbad_compat
   1313  *	log an error if "files" or "compat" is specified in
   1314  *	group_compat database
   1315  */
   1316 /*ARGSUSED*/
   1317 int
   1318 __grbad_compat(void *nsrv, void *nscb, va_list ap)
   1319 {
   1320 	static int warned;
   1321 
   1322 	_DIAGASSERT(nsrv != NULL);
   1323 	_DIAGASSERT(nscb != NULL);
   1324 
   1325 	if (!warned) {
   1326 		syslog(LOG_ERR,
   1327 			"nsswitch.conf group_compat database can't use '%s'",
   1328 			(const char *)nscb);
   1329 	}
   1330 	warned = 1;
   1331 	return NS_UNAVAIL;
   1332 }
   1333 
   1334 /*
   1335  * __grscan_compat
   1336  *	Scan state->fp for the next desired entry.
   1337  *	If search is zero, return the next entry.
   1338  *	If search is non-zero, look for a specific name (if name != NULL),
   1339  *	or a specific gid (if name == NULL).
   1340  *	Sets *retval to the errno if the result is not NS_SUCCESS or
   1341  *	NS_NOTFOUND.
   1342  *
   1343  *	searchfunc is invoked when a compat "+" lookup is required;
   1344  *	searchcookie is passed as the first argument to searchfunc,
   1345  *	the second argument is the group result.
   1346  *	This should return NS_NOTFOUND when "no more groups" from compat src.
   1347  *	If searchfunc is NULL then nsdispatch of getgrent is used.
   1348  *	This is primarily intended for getgroupmembership(3)'s compat backend.
   1349  */
   1350 int
   1351 __grscan_compat(int *retval, struct group *grp, char *buffer, size_t buflen,
   1352 	struct __grstate_compat *state, int search, const char *name, gid_t gid,
   1353 	int (*searchfunc)(void *, struct group **), void *searchcookie)
   1354 {
   1355 	int		rv;
   1356 	char		filebuf[_GETGR_R_SIZE_MAX], *ep;
   1357 
   1358 	static const ns_dtab compatentdtab[] = {
   1359 		NS_FILES_CB(__grbad_compat, "files")
   1360 		NS_DNS_CB(_dns_getgrent_r, NULL)
   1361 		NS_NIS_CB(_nis_getgrent_r, NULL)
   1362 		NS_COMPAT_CB(__grbad_compat, "compat")
   1363 		NS_NULL_CB
   1364 	};
   1365 	static const ns_dtab compatgiddtab[] = {
   1366 		NS_FILES_CB(__grbad_compat, "files")
   1367 		NS_DNS_CB(_dns_getgrgid_r, NULL)
   1368 		NS_NIS_CB(_nis_getgrgid_r, NULL)
   1369 		NS_COMPAT_CB(__grbad_compat, "compat")
   1370 		NS_NULL_CB
   1371 	};
   1372 	static const ns_dtab compatnamdtab[] = {
   1373 		NS_FILES_CB(__grbad_compat, "files")
   1374 		NS_DNS_CB(_dns_getgrnam_r, NULL)
   1375 		NS_NIS_CB(_nis_getgrnam_r, NULL)
   1376 		NS_COMPAT_CB(__grbad_compat, "compat")
   1377 		NS_NULL_CB
   1378 	};
   1379 
   1380 	_DIAGASSERT(retval != NULL);
   1381 	_DIAGASSERT(grp != NULL);
   1382 	_DIAGASSERT(buffer != NULL);
   1383 	_DIAGASSERT(state != NULL);
   1384 	/* name is NULL to indicate searching for gid */
   1385 
   1386 	*retval = 0;
   1387 
   1388 	if (state->fp == NULL) {	/* only start if file not open yet */
   1389 		rv = __grstart_compat(state);
   1390 		if (rv != NS_SUCCESS)
   1391 			goto compatgrscan_out;
   1392 	}
   1393 	rv = NS_NOTFOUND;
   1394 
   1395 	for (;;) {					/* loop through file */
   1396 		if (state->name != NULL) {
   1397 					/* processing compat entry */
   1398 			int		crv, cretval;
   1399 			struct group	cgrp, *cgrpres;
   1400 
   1401 			if (state->name[0]) {		/* specific +group: */
   1402 				crv = nsdispatch(NULL, compatnamdtab,
   1403 				    NSDB_GROUP_COMPAT, "getgrnam_r",
   1404 				    __nsdefaultnis,
   1405 				    &cretval, state->name,
   1406 				    &cgrp, filebuf, sizeof(filebuf), &cgrpres);
   1407 				free(state->name);	/* (only check 1 grp) */
   1408 				state->name = NULL;
   1409 			} else if (!search) {		/* any group */
   1410 				if (searchfunc) {
   1411 					crv = searchfunc(searchcookie,
   1412 					    &cgrpres);
   1413 				} else {
   1414 					crv = nsdispatch(NULL, compatentdtab,
   1415 					    NSDB_GROUP_COMPAT, "getgrent_r",
   1416 					    __nsdefaultnis,
   1417 					    &cretval, &cgrp, filebuf,
   1418 					    sizeof(filebuf), &cgrpres);
   1419 				}
   1420 			} else if (name) {		/* specific group */
   1421 				crv = nsdispatch(NULL, compatnamdtab,
   1422 				    NSDB_GROUP_COMPAT, "getgrnam_r",
   1423 				    __nsdefaultnis,
   1424 				    &cretval, name,
   1425 				    &cgrp, filebuf, sizeof(filebuf), &cgrpres);
   1426 			} else {			/* specific gid */
   1427 				crv = nsdispatch(NULL, compatgiddtab,
   1428 				    NSDB_GROUP_COMPAT, "getgrgid_r",
   1429 				    __nsdefaultnis,
   1430 				    &cretval, gid,
   1431 				    &cgrp, filebuf, sizeof(filebuf), &cgrpres);
   1432 			}
   1433 			if (crv != NS_SUCCESS) {	/* not found */
   1434 				free(state->name);
   1435 				state->name = NULL;
   1436 				continue;		/* try next line */
   1437 			}
   1438 			if (!_gr_copy(cgrpres, grp, buffer, buflen)) {
   1439 				rv = NS_UNAVAIL;
   1440 				break;
   1441 			}
   1442 			goto compatgrscan_cmpgrp;	/* skip to grp test */
   1443 		}
   1444 
   1445 							/* get next file line */
   1446 		if (fgets(filebuf, (int)sizeof(filebuf), state->fp) == NULL)
   1447 			break;
   1448 
   1449 		ep = strchr(filebuf, '\n');
   1450 		if (ep == NULL) {	/* skip lines that are too big */
   1451 			int ch;
   1452 
   1453 			while ((ch = getc(state->fp)) != '\n' && ch != EOF)
   1454 				continue;
   1455 			continue;
   1456 		}
   1457 		*ep = '\0';				/* clear trailing \n */
   1458 
   1459 		if (filebuf[0] == '+') {		/* parse compat line */
   1460 			if (state->name)
   1461 				free(state->name);
   1462 			state->name = NULL;
   1463 			switch(filebuf[1]) {
   1464 			case ':':
   1465 			case '\0':
   1466 				state->name = strdup("");
   1467 				break;
   1468 			default:
   1469 				ep = strchr(filebuf + 1, ':');
   1470 				if (ep == NULL)
   1471 					break;
   1472 				*ep = '\0';
   1473 				state->name = strdup(filebuf + 1);
   1474 				break;
   1475 			}
   1476 			if (state->name == NULL) {
   1477 				rv = NS_UNAVAIL;
   1478 				break;
   1479 			}
   1480 			continue;
   1481 		}
   1482 
   1483 							/* validate line */
   1484 		if (! _gr_parse(filebuf, grp, buffer, buflen)) {
   1485 			continue;			/* skip bad lines */
   1486 		}
   1487 
   1488  compatgrscan_cmpgrp:
   1489 		if (! search) {				/* just want this one */
   1490 			rv = NS_SUCCESS;
   1491 			break;
   1492 		}
   1493 							/* want specific */
   1494 		if ((name && strcmp(name, grp->gr_name) == 0) ||
   1495 		    (!name && gid == grp->gr_gid)) {
   1496 			rv = NS_SUCCESS;
   1497 			break;
   1498 		}
   1499 
   1500 	}
   1501 
   1502  compatgrscan_out:
   1503 	if (rv != NS_SUCCESS && rv != NS_NOTFOUND)
   1504 		*retval = errno;
   1505 	return rv;
   1506 }
   1507 
   1508 static struct __grstate_compat	_compat_state;
   1509 					/* storage for non _r functions */
   1510 static struct group		_compat_group;
   1511 static char			_compat_groupbuf[_GETGR_R_SIZE_MAX];
   1512 
   1513 /*ARGSUSED*/
   1514 static int
   1515 _compat_setgrent(void *nsrv, void *nscb, va_list ap)
   1516 {
   1517 	static const ns_dtab dtab[] = {
   1518 		NS_FILES_CB(__grbad_compat, "files")
   1519 		NS_DNS_CB(_dns_setgrent, NULL)
   1520 		NS_NIS_CB(_nis_setgrent, NULL)
   1521 		NS_COMPAT_CB(__grbad_compat, "compat")
   1522 		NS_NULL_CB
   1523 	};
   1524 
   1525 					/* force group_compat setgrent() */
   1526 	(void) nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "setgrent",
   1527 	    __nsdefaultnis_forceall);
   1528 
   1529 					/* reset state, keep fp open */
   1530 	_compat_state.stayopen = 0;
   1531 	return __grstart_compat(&_compat_state);
   1532 }
   1533 
   1534 /*ARGSUSED*/
   1535 static int
   1536 _compat_setgroupent(void *nsrv, void *nscb, va_list ap)
   1537 {
   1538 	int	*retval		= va_arg(ap, int *);
   1539 	int	 stayopen	= va_arg(ap, int);
   1540 
   1541 	int	rv;
   1542 
   1543 	static const ns_dtab dtab[] = {
   1544 		NS_FILES_CB(__grbad_compat, "files")
   1545 		NS_DNS_CB(_dns_setgroupent, NULL)
   1546 		NS_NIS_CB(_nis_setgroupent, NULL)
   1547 		NS_COMPAT_CB(__grbad_compat, "compat")
   1548 		NS_NULL_CB
   1549 	};
   1550 
   1551 					/* force group_compat setgroupent() */
   1552 	(void) nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "setgroupent",
   1553 	    __nsdefaultnis_forceall, &rv, stayopen);
   1554 
   1555 	_compat_state.stayopen = stayopen;
   1556 	rv = __grstart_compat(&_compat_state);
   1557 	*retval = (rv == NS_SUCCESS);
   1558 	return rv;
   1559 }
   1560 
   1561 /*ARGSUSED*/
   1562 static int
   1563 _compat_endgrent(void *nsrv, void *nscb, va_list ap)
   1564 {
   1565 	static const ns_dtab dtab[] = {
   1566 		NS_FILES_CB(__grbad_compat, "files")
   1567 		NS_DNS_CB(_dns_endgrent, NULL)
   1568 		NS_NIS_CB(_nis_endgrent, NULL)
   1569 		NS_COMPAT_CB(__grbad_compat, "compat")
   1570 		NS_NULL_CB
   1571 	};
   1572 
   1573 					/* force group_compat endgrent() */
   1574 	(void) nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "endgrent",
   1575 	    __nsdefaultnis_forceall);
   1576 
   1577 					/* reset state, close fp */
   1578 	_compat_state.stayopen = 0;
   1579 	return __grend_compat(&_compat_state);
   1580 }
   1581 
   1582 /*ARGSUSED*/
   1583 static int
   1584 _compat_getgrent(void *nsrv, void *nscb, va_list ap)
   1585 {
   1586 	struct group	**retval = va_arg(ap, struct group **);
   1587 
   1588 	int	rv, rerror;
   1589 
   1590 	_DIAGASSERT(retval != NULL);
   1591 
   1592 	*retval = NULL;
   1593 	rv = __grscan_compat(&rerror, &_compat_group,
   1594 	    _compat_groupbuf, sizeof(_compat_groupbuf),
   1595 	    &_compat_state, 0, NULL, 0, NULL, NULL);
   1596 	if (rv == NS_SUCCESS)
   1597 		*retval = &_compat_group;
   1598 	return rv;
   1599 }
   1600 
   1601 /*ARGSUSED*/
   1602 static int
   1603 _compat_getgrent_r(void *nsrv, void *nscb, va_list ap)
   1604 {
   1605 	int		*retval	= va_arg(ap, int *);
   1606 	struct group	*grp	= va_arg(ap, struct group *);
   1607 	char		*buffer	= va_arg(ap, char *);
   1608 	size_t		 buflen	= va_arg(ap, size_t);
   1609 	struct group   **result	= va_arg(ap, struct group **);
   1610 
   1611 	int	rv;
   1612 
   1613 	_DIAGASSERT(retval != NULL);
   1614 	_DIAGASSERT(grp != NULL);
   1615 	_DIAGASSERT(buffer != NULL);
   1616 	_DIAGASSERT(result != NULL);
   1617 
   1618 	rv = __grscan_compat(retval, grp, buffer, buflen,
   1619 	    &_compat_state, 0, NULL, 0, NULL, NULL);
   1620 	if (rv == NS_SUCCESS)
   1621 		*result = grp;
   1622 	else
   1623 		*result = NULL;
   1624 	return rv;
   1625 }
   1626 
   1627 /*ARGSUSED*/
   1628 static int
   1629 _compat_getgrgid(void *nsrv, void *nscb, va_list ap)
   1630 {
   1631 	struct group	**retval = va_arg(ap, struct group **);
   1632 	gid_t		 gid	= va_arg(ap, gid_t);
   1633 
   1634 	int	rv, rerror;
   1635 
   1636 	_DIAGASSERT(retval != NULL);
   1637 
   1638 	*retval = NULL;
   1639 	rv = __grstart_compat(&_compat_state);
   1640 	if (rv != NS_SUCCESS)
   1641 		return rv;
   1642 	rv = __grscan_compat(&rerror, &_compat_group,
   1643 	    _compat_groupbuf, sizeof(_compat_groupbuf),
   1644 	    &_compat_state, 1, NULL, gid, NULL, NULL);
   1645 	if (!_compat_state.stayopen)
   1646 		__grend_compat(&_compat_state);
   1647 	if (rv == NS_SUCCESS)
   1648 		*retval = &_compat_group;
   1649 	return rv;
   1650 }
   1651 
   1652 /*ARGSUSED*/
   1653 static int
   1654 _compat_getgrgid_r(void *nsrv, void *nscb, va_list ap)
   1655 {
   1656 	int		*retval	= va_arg(ap, int *);
   1657 	gid_t		 gid	= va_arg(ap, gid_t);
   1658 	struct group	*grp	= va_arg(ap, struct group *);
   1659 	char		*buffer	= va_arg(ap, char *);
   1660 	size_t		 buflen	= va_arg(ap, size_t);
   1661 	struct group   **result	= va_arg(ap, struct group **);
   1662 
   1663 	struct __grstate_compat	state;
   1664 	int		rv;
   1665 
   1666 	_DIAGASSERT(retval != NULL);
   1667 	_DIAGASSERT(grp != NULL);
   1668 	_DIAGASSERT(buffer != NULL);
   1669 	_DIAGASSERT(result != NULL);
   1670 
   1671 	*result = NULL;
   1672 	memset(&state, 0, sizeof(state));
   1673 	rv = __grscan_compat(retval, grp, buffer, buflen, &state,
   1674 	    1, NULL, gid, NULL, NULL);
   1675 	__grend_compat(&state);
   1676 	if (rv == NS_SUCCESS)
   1677 		*result = grp;
   1678 	return rv;
   1679 }
   1680 
   1681 /*ARGSUSED*/
   1682 static int
   1683 _compat_getgrnam(void *nsrv, void *nscb, va_list ap)
   1684 {
   1685 	struct group	**retval = va_arg(ap, struct group **);
   1686 	const char	*name	= va_arg(ap, const char *);
   1687 
   1688 	int	rv, rerror;
   1689 
   1690 	_DIAGASSERT(retval != NULL);
   1691 
   1692 	*retval = NULL;
   1693 	rv = __grstart_compat(&_compat_state);
   1694 	if (rv != NS_SUCCESS)
   1695 		return rv;
   1696 	rv = __grscan_compat(&rerror, &_compat_group,
   1697 	    _compat_groupbuf, sizeof(_compat_groupbuf),
   1698 	    &_compat_state, 1, name, 0, NULL, NULL);
   1699 	if (!_compat_state.stayopen)
   1700 		__grend_compat(&_compat_state);
   1701 	if (rv == NS_SUCCESS)
   1702 		*retval = &_compat_group;
   1703 	return rv;
   1704 }
   1705 
   1706 /*ARGSUSED*/
   1707 static int
   1708 _compat_getgrnam_r(void *nsrv, void *nscb, va_list ap)
   1709 {
   1710 	int		*retval	= va_arg(ap, int *);
   1711 	const char	*name	= va_arg(ap, const char *);
   1712 	struct group	*grp	= va_arg(ap, struct group *);
   1713 	char		*buffer	= va_arg(ap, char *);
   1714 	size_t		 buflen	= va_arg(ap, size_t);
   1715 	struct group   **result	= va_arg(ap, struct group **);
   1716 
   1717 	struct __grstate_compat	state;
   1718 	int		rv;
   1719 
   1720 	_DIAGASSERT(retval != NULL);
   1721 	_DIAGASSERT(grp != NULL);
   1722 	_DIAGASSERT(buffer != NULL);
   1723 	_DIAGASSERT(result != NULL);
   1724 
   1725 	*result = NULL;
   1726 	memset(&state, 0, sizeof(state));
   1727 	rv = __grscan_compat(retval, grp, buffer, buflen, &state,
   1728 	    1, name, 0, NULL, NULL);
   1729 	__grend_compat(&state);
   1730 	if (rv == NS_SUCCESS)
   1731 		*result = grp;
   1732 	return rv;
   1733 }
   1734 
   1735 #endif	/* _GROUP_COMPAT */
   1736 
   1737 
   1738 		/*
   1739 		 *	public functions
   1740 		 */
   1741 
   1742 struct group *
   1743 getgrent(void)
   1744 {
   1745 	int		rv;
   1746 	struct group	*retval;
   1747 
   1748 	static const ns_dtab dtab[] = {
   1749 		NS_FILES_CB(_files_getgrent, NULL)
   1750 		NS_DNS_CB(_dns_getgrent, NULL)
   1751 		NS_NIS_CB(_nis_getgrent, NULL)
   1752 		NS_COMPAT_CB(_compat_getgrent, NULL)
   1753 		NS_NULL_CB
   1754 	};
   1755 
   1756 	mutex_lock(&__grmutex);
   1757 	rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrent", __nsdefaultcompat,
   1758 	    &retval);
   1759 	mutex_unlock(&__grmutex);
   1760 	return (rv == NS_SUCCESS) ? retval : NULL;
   1761 }
   1762 
   1763 int
   1764 getgrent_r(struct group *grp, char *buffer, size_t buflen,
   1765     struct group **result)
   1766 {
   1767 	int		rv, retval;
   1768 
   1769 	static const ns_dtab dtab[] = {
   1770 		NS_FILES_CB(_files_getgrent_r, NULL)
   1771 		NS_DNS_CB(_dns_getgrent_r, NULL)
   1772 		NS_NIS_CB(_nis_getgrent_r, NULL)
   1773 		NS_COMPAT_CB(_compat_getgrent_r, NULL)
   1774 		NS_NULL_CB
   1775 	};
   1776 
   1777 	mutex_lock(&__grmutex);
   1778 	rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrent_r", __nsdefaultcompat,
   1779 	    &retval, grp, buffer, buflen, result);
   1780 	mutex_unlock(&__grmutex);
   1781 	switch (rv) {
   1782 	case NS_SUCCESS:
   1783 	case NS_NOTFOUND:
   1784 		return 0;
   1785 	default:
   1786 		return retval;
   1787 	}
   1788 }
   1789 
   1790 
   1791 struct group *
   1792 getgrgid(gid_t gid)
   1793 {
   1794 	int		rv;
   1795 	struct group	*retval;
   1796 
   1797 	static const ns_dtab dtab[] = {
   1798 		NS_FILES_CB(_files_getgrgid, NULL)
   1799 		NS_DNS_CB(_dns_getgrgid, NULL)
   1800 		NS_NIS_CB(_nis_getgrgid, NULL)
   1801 		NS_COMPAT_CB(_compat_getgrgid, NULL)
   1802 		NS_NULL_CB
   1803 	};
   1804 
   1805 	mutex_lock(&__grmutex);
   1806 	rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrgid", __nsdefaultcompat,
   1807 	    &retval, gid);
   1808 	mutex_unlock(&__grmutex);
   1809 	return (rv == NS_SUCCESS) ? retval : NULL;
   1810 }
   1811 
   1812 int
   1813 getgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t buflen,
   1814 	struct group **result)
   1815 {
   1816 	int	rv, retval;
   1817 
   1818 	static const ns_dtab dtab[] = {
   1819 		NS_FILES_CB(_files_getgrgid_r, NULL)
   1820 		NS_DNS_CB(_dns_getgrgid_r, NULL)
   1821 		NS_NIS_CB(_nis_getgrgid_r, NULL)
   1822 		NS_COMPAT_CB(_compat_getgrgid_r, NULL)
   1823 		NS_NULL_CB
   1824 	};
   1825 
   1826 	_DIAGASSERT(grp != NULL);
   1827 	_DIAGASSERT(buffer != NULL);
   1828 	_DIAGASSERT(result != NULL);
   1829 
   1830 	*result = NULL;
   1831 	retval = 0;
   1832 	mutex_lock(&__grmutex);
   1833 	rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrgid_r", __nsdefaultcompat,
   1834 	    &retval, gid, grp, buffer, buflen, result);
   1835 	mutex_unlock(&__grmutex);
   1836 	switch (rv) {
   1837 	case NS_SUCCESS:
   1838 	case NS_NOTFOUND:
   1839 		return 0;
   1840 	default:
   1841 		return retval;
   1842 	}
   1843 }
   1844 
   1845 struct group *
   1846 getgrnam(const char *name)
   1847 {
   1848 	int		rv;
   1849 	struct group	*retval;
   1850 
   1851 	static const ns_dtab dtab[] = {
   1852 		NS_FILES_CB(_files_getgrnam, NULL)
   1853 		NS_DNS_CB(_dns_getgrnam, NULL)
   1854 		NS_NIS_CB(_nis_getgrnam, NULL)
   1855 		NS_COMPAT_CB(_compat_getgrnam, NULL)
   1856 		NS_NULL_CB
   1857 	};
   1858 
   1859 	mutex_lock(&__grmutex);
   1860 	rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrnam", __nsdefaultcompat,
   1861 	    &retval, name);
   1862 	mutex_unlock(&__grmutex);
   1863 	return (rv == NS_SUCCESS) ? retval : NULL;
   1864 }
   1865 
   1866 int
   1867 getgrnam_r(const char *name, struct group *grp, char *buffer, size_t buflen,
   1868 	struct group **result)
   1869 {
   1870 	int	rv, retval;
   1871 
   1872 	static const ns_dtab dtab[] = {
   1873 		NS_FILES_CB(_files_getgrnam_r, NULL)
   1874 		NS_DNS_CB(_dns_getgrnam_r, NULL)
   1875 		NS_NIS_CB(_nis_getgrnam_r, NULL)
   1876 		NS_COMPAT_CB(_compat_getgrnam_r, NULL)
   1877 		NS_NULL_CB
   1878 	};
   1879 
   1880 	_DIAGASSERT(name != NULL);
   1881 	_DIAGASSERT(grp != NULL);
   1882 	_DIAGASSERT(buffer != NULL);
   1883 	_DIAGASSERT(result != NULL);
   1884 
   1885 	*result = NULL;
   1886 	retval = 0;
   1887 	mutex_lock(&__grmutex);
   1888 	rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrnam_r", __nsdefaultcompat,
   1889 	    &retval, name, grp, buffer, buflen, result);
   1890 	mutex_unlock(&__grmutex);
   1891 	switch (rv) {
   1892 	case NS_SUCCESS:
   1893 	case NS_NOTFOUND:
   1894 		return 0;
   1895 	default:
   1896 		return retval;
   1897 	}
   1898 }
   1899 
   1900 void
   1901 endgrent(void)
   1902 {
   1903 	static const ns_dtab dtab[] = {
   1904 		NS_FILES_CB(_files_endgrent, NULL)
   1905 		NS_DNS_CB(_dns_endgrent, NULL)
   1906 		NS_NIS_CB(_nis_endgrent, NULL)
   1907 		NS_COMPAT_CB(_compat_endgrent, NULL)
   1908 		NS_NULL_CB
   1909 	};
   1910 
   1911 	mutex_lock(&__grmutex);
   1912 					/* force all endgrent() methods */
   1913 	(void) nsdispatch(NULL, dtab, NSDB_GROUP, "endgrent",
   1914 	    __nsdefaultcompat_forceall);
   1915 	mutex_unlock(&__grmutex);
   1916 }
   1917 
   1918 int
   1919 setgroupent(int stayopen)
   1920 {
   1921 	static const ns_dtab dtab[] = {
   1922 		NS_FILES_CB(_files_setgroupent, NULL)
   1923 		NS_DNS_CB(_dns_setgroupent, NULL)
   1924 		NS_NIS_CB(_nis_setgroupent, NULL)
   1925 		NS_COMPAT_CB(_compat_setgroupent, NULL)
   1926 		NS_NULL_CB
   1927 	};
   1928 	int	rv, retval;
   1929 
   1930 	mutex_lock(&__grmutex);
   1931 					/* force all setgroupent() methods */
   1932 	rv = nsdispatch(NULL, dtab, NSDB_GROUP, "setgroupent",
   1933 	    __nsdefaultcompat_forceall, &retval, stayopen);
   1934 	mutex_unlock(&__grmutex);
   1935 	return (rv == NS_SUCCESS) ? retval : 0;
   1936 }
   1937 
   1938 void
   1939 setgrent(void)
   1940 {
   1941 	static const ns_dtab dtab[] = {
   1942 		NS_FILES_CB(_files_setgrent, NULL)
   1943 		NS_DNS_CB(_dns_setgrent, NULL)
   1944 		NS_NIS_CB(_nis_setgrent, NULL)
   1945 		NS_COMPAT_CB(_compat_setgrent, NULL)
   1946 		NS_NULL_CB
   1947 	};
   1948 
   1949 	mutex_lock(&__grmutex);
   1950 					/* force all setgrent() methods */
   1951 	(void) nsdispatch(NULL, dtab, NSDB_GROUP, "setgrent",
   1952 	    __nsdefaultcompat_forceall);
   1953 	mutex_unlock(&__grmutex);
   1954 }
   1955