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