Home | History | Annotate | Line # | Download | only in gen
getgrent.c revision 1.62
      1 /*	$NetBSD: getgrent.c,v 1.62 2008/04/28 20:22:59 martin 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.62 2008/04/28 20:22:59 martin 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 	grp->gr_mem = (char **)ALIGN(ep);
    225 	if (grp->gr_mem == NULL)
    226 		return 0;
    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 	for (memc = 0; fromgrp->gr_mem[memc]; memc++)
    274 		continue;
    275 	memc++;					/* for final NULL */
    276 
    277 				/* grab ALIGNed char **gr_mem from buf */
    278 	ep = _gr_memfrombuf(memc * sizeof(char *) + ALIGNBYTES, &buf, &buflen);
    279 	grp->gr_mem = (char **)ALIGN(ep);
    280 	if (grp->gr_mem == NULL)
    281 		return 0;
    282 
    283 	for (memc = 0; fromgrp->gr_mem[memc]; memc++) {
    284 		COPYSTR(grp->gr_mem[memc], fromgrp->gr_mem[memc]);
    285 	}
    286 
    287 #undef COPYSTR
    288 
    289 	grp->gr_mem[memc] = NULL;
    290 	return 1;
    291 }
    292 
    293 		/*
    294 		 *	files methods
    295 		 */
    296 
    297 int
    298 __grstart_files(struct __grstate_files *state)
    299 {
    300 
    301 	_DIAGASSERT(state != NULL);
    302 
    303 	if (state->fp == NULL) {
    304 		state->fp = fopen(_PATH_GROUP, "r");
    305 		if (state->fp == NULL)
    306 			return NS_UNAVAIL;
    307 	} else {
    308 		rewind(state->fp);
    309 	}
    310 	return NS_SUCCESS;
    311 }
    312 
    313 int
    314 __grend_files(struct __grstate_files *state)
    315 {
    316 
    317 	_DIAGASSERT(state != NULL);
    318 
    319 	if (state->fp) {
    320 		(void) fclose(state->fp);
    321 		state->fp = NULL;
    322 	}
    323 	return NS_SUCCESS;
    324 }
    325 
    326 /*
    327  * __grscan_files
    328  *	Scan state->fp for the next desired entry.
    329  *	If search is zero, return the next entry.
    330  *	If search is non-zero, look for a specific name (if name != NULL),
    331  *	or a specific gid (if name == NULL).
    332  *	Sets *retval to the errno if the result is not NS_SUCCESS
    333  *	or NS_NOTFOUND.
    334  */
    335 int
    336 __grscan_files(int *retval, struct group *grp, char *buffer, size_t buflen,
    337 	struct __grstate_files *state, int search, const char *name, gid_t gid)
    338 {
    339 	int	rv;
    340 	char	filebuf[_GETGR_R_SIZE_MAX], *ep;
    341 
    342 	_DIAGASSERT(retval != NULL);
    343 	_DIAGASSERT(grp != NULL);
    344 	_DIAGASSERT(buffer != NULL);
    345 	_DIAGASSERT(state != NULL);
    346 	/* name is NULL to indicate searching for gid */
    347 
    348 	*retval = 0;
    349 
    350 	if (state->fp == NULL) {	/* only start if file not open yet */
    351 		rv = __grstart_files(state);
    352 		if (rv != NS_SUCCESS)
    353 			goto filesgrscan_out;
    354 	}
    355 
    356 	rv = NS_NOTFOUND;
    357 
    358 							/* scan line by line */
    359 	while (fgets(filebuf, sizeof(filebuf), state->fp) != NULL) {
    360 		ep = strchr(filebuf, '\n');
    361 		if (ep == NULL) {	/* skip lines that are too big */
    362 			int ch;
    363 
    364 			while ((ch = getc(state->fp)) != '\n' && ch != EOF)
    365 				continue;
    366 			continue;
    367 		}
    368 		*ep = '\0';				/* clear trailing \n */
    369 
    370 		if (filebuf[0] == '+')			/* skip compat line */
    371 			continue;
    372 
    373 							/* validate line */
    374 		if (! _gr_parse(filebuf, grp, buffer, buflen)) {
    375 			continue;			/* skip bad lines */
    376 		}
    377 		if (! search) {				/* just want this one */
    378 			rv = NS_SUCCESS;
    379 			break;
    380 		}
    381 							/* want specific */
    382 		if ((name && strcmp(name, grp->gr_name) == 0) ||
    383 		    (!name && gid == grp->gr_gid)) {
    384 			rv = NS_SUCCESS;
    385 			break;
    386 		}
    387 	}
    388 
    389  filesgrscan_out:
    390 	if (rv != NS_SUCCESS && rv != NS_NOTFOUND)
    391 		*retval = errno;
    392 	return rv;
    393 }
    394 
    395 
    396 static struct __grstate_files	_files_state;
    397 					/* storage for non _r functions */
    398 static struct group		_files_group;
    399 static char			_files_groupbuf[_GETGR_R_SIZE_MAX];
    400 
    401 /*ARGSUSED*/
    402 static int
    403 _files_setgrent(void *nsrv, void *nscb, va_list ap)
    404 {
    405 
    406 	_files_state.stayopen = 0;
    407 	return __grstart_files(&_files_state);
    408 }
    409 
    410 /*ARGSUSED*/
    411 static int
    412 _files_setgroupent(void *nsrv, void *nscb, va_list ap)
    413 {
    414 	int	*retval		= va_arg(ap, int *);
    415 	int	 stayopen	= va_arg(ap, int);
    416 
    417 	int	rv;
    418 
    419 	_files_state.stayopen = stayopen;
    420 	rv = __grstart_files(&_files_state);
    421 	*retval = (rv == NS_SUCCESS);
    422 	return rv;
    423 }
    424 
    425 /*ARGSUSED*/
    426 static int
    427 _files_endgrent(void *nsrv, void *nscb, va_list ap)
    428 {
    429 
    430 	_files_state.stayopen = 0;
    431 	return __grend_files(&_files_state);
    432 }
    433 
    434 /*ARGSUSED*/
    435 static int
    436 _files_getgrent(void *nsrv, void *nscb, va_list ap)
    437 {
    438 	struct group	**retval = va_arg(ap, struct group **);
    439 
    440 	int	rv, rerror;
    441 
    442 	_DIAGASSERT(retval != NULL);
    443 
    444 	*retval = NULL;
    445 	rv = __grscan_files(&rerror, &_files_group,
    446 	    _files_groupbuf, sizeof(_files_groupbuf),
    447 	    &_files_state, 0, NULL, 0);
    448 	if (rv == NS_SUCCESS)
    449 		*retval = &_files_group;
    450 	return rv;
    451 }
    452 
    453 /*ARGSUSED*/
    454 static int
    455 _files_getgrent_r(void *nsrv, void *nscb, va_list ap)
    456 {
    457 	int		*retval	= va_arg(ap, int *);
    458 	struct group	*grp	= va_arg(ap, struct group *);
    459 	char		*buffer	= va_arg(ap, char *);
    460 	size_t		 buflen	= va_arg(ap, size_t);
    461 	struct group   **result	= va_arg(ap, struct group **);
    462 
    463 	int	rv;
    464 
    465 	_DIAGASSERT(retval != NULL);
    466 	_DIAGASSERT(grp != NULL);
    467 	_DIAGASSERT(buffer != NULL);
    468 	_DIAGASSERT(result != NULL);
    469 
    470 	rv = __grscan_files(retval, grp, buffer, buflen,
    471 	    &_files_state, 0, NULL, 0);
    472 	if (rv == NS_SUCCESS)
    473 		*result = grp;
    474 	else
    475 		*result = NULL;
    476 	return rv;
    477 }
    478 
    479 /*ARGSUSED*/
    480 static int
    481 _files_getgrgid(void *nsrv, void *nscb, va_list ap)
    482 {
    483 	struct group	**retval = va_arg(ap, struct group **);
    484 	gid_t		 gid	= va_arg(ap, gid_t);
    485 
    486 	int	rv, rerror;
    487 
    488 	_DIAGASSERT(retval != NULL);
    489 
    490 	*retval = NULL;
    491 	rv = __grstart_files(&_files_state);
    492 	if (rv != NS_SUCCESS)
    493 		return rv;
    494 	rv = __grscan_files(&rerror, &_files_group,
    495 	    _files_groupbuf, sizeof(_files_groupbuf),
    496 	    &_files_state, 1, NULL, gid);
    497 	if (!_files_state.stayopen)
    498 		__grend_files(&_files_state);
    499 	if (rv == NS_SUCCESS)
    500 		*retval = &_files_group;
    501 	return rv;
    502 }
    503 
    504 /*ARGSUSED*/
    505 static int
    506 _files_getgrgid_r(void *nsrv, void *nscb, va_list ap)
    507 {
    508 	int		*retval	= va_arg(ap, int *);
    509 	gid_t		 gid	= va_arg(ap, gid_t);
    510 	struct group	*grp	= va_arg(ap, struct group *);
    511 	char		*buffer	= va_arg(ap, char *);
    512 	size_t		 buflen	= va_arg(ap, size_t);
    513 	struct group   **result	= va_arg(ap, struct group **);
    514 
    515 	struct __grstate_files state;
    516 	int	rv;
    517 
    518 	_DIAGASSERT(retval != NULL);
    519 	_DIAGASSERT(grp != NULL);
    520 	_DIAGASSERT(buffer != NULL);
    521 	_DIAGASSERT(result != NULL);
    522 
    523 	*result = NULL;
    524 	memset(&state, 0, sizeof(state));
    525 	rv = __grscan_files(retval, grp, buffer, buflen, &state, 1, NULL, gid);
    526 	__grend_files(&state);
    527 	if (rv == NS_SUCCESS)
    528 		*result = grp;
    529 	return rv;
    530 }
    531 
    532 /*ARGSUSED*/
    533 static int
    534 _files_getgrnam(void *nsrv, void *nscb, va_list ap)
    535 {
    536 	struct group	**retval = va_arg(ap, struct group **);
    537 	const char	*name	= va_arg(ap, const char *);
    538 
    539 	int	rv, rerror;
    540 
    541 	_DIAGASSERT(retval != NULL);
    542 
    543 	*retval = NULL;
    544 	rv = __grstart_files(&_files_state);
    545 	if (rv != NS_SUCCESS)
    546 		return rv;
    547 	rv = __grscan_files(&rerror, &_files_group,
    548 	    _files_groupbuf, sizeof(_files_groupbuf),
    549 	    &_files_state, 1, name, 0);
    550 	if (!_files_state.stayopen)
    551 		__grend_files(&_files_state);
    552 	if (rv == NS_SUCCESS)
    553 		*retval = &_files_group;
    554 	return rv;
    555 }
    556 
    557 /*ARGSUSED*/
    558 static int
    559 _files_getgrnam_r(void *nsrv, void *nscb, va_list ap)
    560 {
    561 	int		*retval	= va_arg(ap, int *);
    562 	const char	*name	= va_arg(ap, const char *);
    563 	struct group	*grp	= va_arg(ap, struct group *);
    564 	char		*buffer	= va_arg(ap, char *);
    565 	size_t		 buflen	= va_arg(ap, size_t);
    566 	struct group   **result	= va_arg(ap, struct group **);
    567 
    568 	struct __grstate_files state;
    569 	int	rv;
    570 
    571 	_DIAGASSERT(retval != NULL);
    572 	_DIAGASSERT(grp != NULL);
    573 	_DIAGASSERT(buffer != NULL);
    574 	_DIAGASSERT(result != NULL);
    575 
    576 	*result = NULL;
    577 	memset(&state, 0, sizeof(state));
    578 	rv = __grscan_files(retval, grp, buffer, buflen, &state, 1, name, 0);
    579 	__grend_files(&state);
    580 	if (rv == NS_SUCCESS)
    581 		*result = grp;
    582 	return rv;
    583 }
    584 
    585 
    586 #ifdef HESIOD
    587 		/*
    588 		 *	dns methods
    589 		 */
    590 
    591 int
    592 __grstart_dns(struct __grstate_dns *state)
    593 {
    594 
    595 	_DIAGASSERT(state != NULL);
    596 
    597 	state->num = 0;
    598 	if (state->context == NULL) {			/* setup Hesiod */
    599 		if (hesiod_init(&state->context) == -1)
    600 			return NS_UNAVAIL;
    601 	}
    602 
    603 	return NS_SUCCESS;
    604 }
    605 
    606 int
    607 __grend_dns(struct __grstate_dns *state)
    608 {
    609 
    610 	_DIAGASSERT(state != NULL);
    611 
    612 	state->num = 0;
    613 	if (state->context) {
    614 		hesiod_end(state->context);
    615 		state->context = NULL;
    616 	}
    617 	return NS_SUCCESS;
    618 }
    619 
    620 /*
    621  * __grscan_dns
    622  *	Search Hesiod for the next desired entry.
    623  *	If search is zero, return the next entry.
    624  *	If search is non-zero, look for a specific name (if name != NULL),
    625  *	or a specific gid (if name == NULL).
    626  */
    627 int
    628 __grscan_dns(int *retval, struct group *grp, char *buffer, size_t buflen,
    629 	struct __grstate_dns *state, int search, const char *name, gid_t gid)
    630 {
    631 	const char	**curzone;
    632 	char		**hp, *ep;
    633 	int		rv;
    634 
    635 	static const char *zones_gid_group[] = {
    636 		"gid",
    637 		"group",
    638 		NULL
    639 	};
    640 
    641 	static const char *zones_group[] = {
    642 		"group",
    643 		NULL
    644 	};
    645 
    646 	_DIAGASSERT(retval != NULL);
    647 	_DIAGASSERT(grp != NULL);
    648 	_DIAGASSERT(buffer != NULL);
    649 	_DIAGASSERT(state != NULL);
    650 	/* name is NULL to indicate searching for gid */
    651 
    652 	*retval = 0;
    653 
    654 	if (state->context == NULL) {	/* only start if Hesiod not setup */
    655 		rv = __grstart_dns(state);
    656 		if (rv != NS_SUCCESS)
    657 			return rv;
    658 	}
    659 
    660  next_dns_entry:
    661 	hp = NULL;
    662 	rv = NS_NOTFOUND;
    663 
    664 	if (! search) {			/* find next entry */
    665 		if (state->num == -1)		/* exhausted search */
    666 			return NS_NOTFOUND;
    667 						/* find group-NNN */
    668 		snprintf(buffer, buflen, "group-%u", state->num);
    669 		state->num++;
    670 		curzone = zones_group;
    671 	} else if (name) {		/* find group name */
    672 		snprintf(buffer, buflen, "%s", name);
    673 		curzone = zones_group;
    674 	} else {			/* find gid */
    675 		snprintf(buffer, buflen, "%u", (unsigned int)gid);
    676 		curzone = zones_gid_group;
    677 	}
    678 
    679 	for (; *curzone; curzone++) {		/* search zones */
    680 		hp = hesiod_resolve(state->context, buffer, *curzone);
    681 		if (hp != NULL)
    682 			break;
    683 		if (errno != ENOENT) {
    684 			rv = NS_UNAVAIL;
    685 			goto dnsgrscan_out;
    686 		}
    687 	}
    688 	if (*curzone == NULL) {
    689 		if (! search)
    690 			state->num = -1;
    691 		goto dnsgrscan_out;
    692 	}
    693 
    694 	if ((ep = strchr(hp[0], '\n')) != NULL)
    695 		*ep = '\0';				/* clear trailing \n */
    696 	if (_gr_parse(hp[0], grp, buffer, buflen)) {	/* validate line */
    697 		if (! search) {				/* just want this one */
    698 			rv = NS_SUCCESS;
    699 		} else if ((name && strcmp(name, grp->gr_name) == 0) ||
    700 		    (!name && gid == grp->gr_gid)) {	/* want specific */
    701 			rv = NS_SUCCESS;
    702 		}
    703 	} else {					/* dodgy entry */
    704 		if (!search) {			/* try again if ! searching */
    705 			hesiod_free_list(state->context, hp);
    706 			goto next_dns_entry;
    707 		}
    708 	}
    709 
    710  dnsgrscan_out:
    711 	if (rv != NS_SUCCESS && rv != NS_NOTFOUND)
    712 		*retval = errno;
    713 	if (hp)
    714 		hesiod_free_list(state->context, hp);
    715 	return rv;
    716 }
    717 
    718 static struct __grstate_dns	_dns_state;
    719 					/* storage for non _r functions */
    720 static struct group		_dns_group;
    721 static char			_dns_groupbuf[_GETGR_R_SIZE_MAX];
    722 
    723 /*ARGSUSED*/
    724 static int
    725 _dns_setgrent(void *nsrv, void *nscb, va_list ap)
    726 {
    727 
    728 	_dns_state.stayopen = 0;
    729 	return __grstart_dns(&_dns_state);
    730 }
    731 
    732 /*ARGSUSED*/
    733 static int
    734 _dns_setgroupent(void *nsrv, void *nscb, va_list ap)
    735 {
    736 	int	*retval		= va_arg(ap, int *);
    737 	int	 stayopen	= va_arg(ap, int);
    738 
    739 	int	rv;
    740 
    741 	_dns_state.stayopen = stayopen;
    742 	rv = __grstart_dns(&_dns_state);
    743 	*retval = (rv == NS_SUCCESS);
    744 	return rv;
    745 }
    746 
    747 /*ARGSUSED*/
    748 static int
    749 _dns_endgrent(void *nsrv, void *nscb, va_list ap)
    750 {
    751 
    752 	_dns_state.stayopen = 0;
    753 	return __grend_dns(&_dns_state);
    754 }
    755 
    756 /*ARGSUSED*/
    757 static int
    758 _dns_getgrent(void *nsrv, void *nscb, va_list ap)
    759 {
    760 	struct group	**retval = va_arg(ap, struct group **);
    761 
    762 	int	  rv, rerror;
    763 
    764 	_DIAGASSERT(retval != NULL);
    765 
    766 	*retval = NULL;
    767 	rv = __grscan_dns(&rerror, &_dns_group,
    768 	    _dns_groupbuf, sizeof(_dns_groupbuf), &_dns_state, 0, NULL, 0);
    769 	if (rv == NS_SUCCESS)
    770 		*retval = &_dns_group;
    771 	return rv;
    772 }
    773 
    774 /*ARGSUSED*/
    775 static int
    776 _dns_getgrent_r(void *nsrv, void *nscb, va_list ap)
    777 {
    778 	int		*retval	= va_arg(ap, int *);
    779 	struct group	*grp	= va_arg(ap, struct group *);
    780 	char		*buffer	= va_arg(ap, char *);
    781 	size_t		 buflen	= va_arg(ap, size_t);
    782 	struct group   **result	= va_arg(ap, struct group **);
    783 
    784 	int	rv;
    785 
    786 	_DIAGASSERT(retval != NULL);
    787 	_DIAGASSERT(grp != NULL);
    788 	_DIAGASSERT(buffer != NULL);
    789 	_DIAGASSERT(result != NULL);
    790 
    791 	rv = __grscan_dns(retval, grp, buffer, buflen,
    792 	    &_dns_state, 0, NULL, 0);
    793 	if (rv == NS_SUCCESS)
    794 		*result = grp;
    795 	else
    796 		*result = NULL;
    797 	return rv;
    798 }
    799 /*ARGSUSED*/
    800 static int
    801 _dns_getgrgid(void *nsrv, void *nscb, va_list ap)
    802 {
    803 	struct group	**retval = va_arg(ap, struct group **);
    804 	gid_t		 gid	= va_arg(ap, gid_t);
    805 
    806 	int	rv, rerror;
    807 
    808 	_DIAGASSERT(retval != NULL);
    809 
    810 	*retval = NULL;
    811 	rv = __grstart_dns(&_dns_state);
    812 	if (rv != NS_SUCCESS)
    813 		return rv;
    814 	rv = __grscan_dns(&rerror, &_dns_group,
    815 	    _dns_groupbuf, sizeof(_dns_groupbuf), &_dns_state, 1, NULL, gid);
    816 	if (!_dns_state.stayopen)
    817 		__grend_dns(&_dns_state);
    818 	if (rv == NS_SUCCESS)
    819 		*retval = &_dns_group;
    820 	return rv;
    821 }
    822 
    823 /*ARGSUSED*/
    824 static int
    825 _dns_getgrgid_r(void *nsrv, void *nscb, va_list ap)
    826 {
    827 	int		*retval	= va_arg(ap, int *);
    828 	gid_t		 gid	= va_arg(ap, gid_t);
    829 	struct group	*grp	= va_arg(ap, struct group *);
    830 	char		*buffer	= va_arg(ap, char *);
    831 	size_t		 buflen	= va_arg(ap, size_t);
    832 	struct group   **result	= va_arg(ap, struct group **);
    833 
    834 	struct __grstate_dns state;
    835 	int	rv;
    836 
    837 	_DIAGASSERT(retval != NULL);
    838 	_DIAGASSERT(grp != NULL);
    839 	_DIAGASSERT(buffer != NULL);
    840 	_DIAGASSERT(result != NULL);
    841 
    842 	*result = NULL;
    843 	memset(&state, 0, sizeof(state));
    844 	rv = __grscan_dns(retval, grp, buffer, buflen, &state, 1, NULL, gid);
    845 	__grend_dns(&state);
    846 	if (rv == NS_SUCCESS)
    847 		*result = grp;
    848 	return rv;
    849 }
    850 
    851 /*ARGSUSED*/
    852 static int
    853 _dns_getgrnam(void *nsrv, void *nscb, va_list ap)
    854 {
    855 	struct group	**retval = va_arg(ap, struct group **);
    856 	const char	*name	= va_arg(ap, const char *);
    857 
    858 	int	rv, rerror;
    859 
    860 	_DIAGASSERT(retval != NULL);
    861 
    862 	*retval = NULL;
    863 	rv = __grstart_dns(&_dns_state);
    864 	if (rv != NS_SUCCESS)
    865 		return rv;
    866 	rv = __grscan_dns(&rerror, &_dns_group,
    867 	    _dns_groupbuf, sizeof(_dns_groupbuf), &_dns_state, 1, name, 0);
    868 	if (!_dns_state.stayopen)
    869 		__grend_dns(&_dns_state);
    870 	if (rv == NS_SUCCESS)
    871 		*retval = &_dns_group;
    872 	return rv;
    873 }
    874 
    875 /*ARGSUSED*/
    876 static int
    877 _dns_getgrnam_r(void *nsrv, void *nscb, va_list ap)
    878 {
    879 	int		*retval	= va_arg(ap, int *);
    880 	const char	*name	= va_arg(ap, const char *);
    881 	struct group	*grp	= va_arg(ap, struct group *);
    882 	char		*buffer	= va_arg(ap, char *);
    883 	size_t		 buflen	= va_arg(ap, size_t);
    884 	struct group   **result	= va_arg(ap, struct group **);
    885 
    886 	struct __grstate_dns state;
    887 	int	rv;
    888 
    889 	_DIAGASSERT(retval != NULL);
    890 	_DIAGASSERT(grp != NULL);
    891 	_DIAGASSERT(buffer != NULL);
    892 	_DIAGASSERT(result != NULL);
    893 
    894 	*result = NULL;
    895 	memset(&state, 0, sizeof(state));
    896 	rv = __grscan_dns(retval, grp, buffer, buflen, &state, 1, name, 0);
    897 	__grend_dns(&state);
    898 	if (rv == NS_SUCCESS)
    899 		*result = grp;
    900 	return rv;
    901 }
    902 
    903 #endif /* HESIOD */
    904 
    905 
    906 #ifdef YP
    907 		/*
    908 		 *	nis methods
    909 		 */
    910 
    911 int
    912 __grstart_nis(struct __grstate_nis *state)
    913 {
    914 
    915 	_DIAGASSERT(state != NULL);
    916 
    917 	state->done = 0;
    918 	if (state->current) {
    919 		free(state->current);
    920 		state->current = NULL;
    921 	}
    922 	if (state->domain == NULL) {			/* setup NIS */
    923 		switch (yp_get_default_domain(&state->domain)) {
    924 		case 0:
    925 			break;
    926 		case YPERR_RESRC:
    927 			return NS_TRYAGAIN;
    928 		default:
    929 			return NS_UNAVAIL;
    930 		}
    931 	}
    932 	return NS_SUCCESS;
    933 }
    934 
    935 int
    936 __grend_nis(struct __grstate_nis *state)
    937 {
    938 
    939 	_DIAGASSERT(state != NULL);
    940 
    941 	if (state->domain) {
    942 		state->domain = NULL;
    943 	}
    944 	state->done = 0;
    945 	if (state->current) {
    946 		free(state->current);
    947 		state->current = NULL;
    948 	}
    949 	return NS_SUCCESS;
    950 }
    951 
    952 /*
    953  * __grscan_nis
    954  *	Search NIS for the next desired entry.
    955  *	If search is zero, return the next entry.
    956  *	If search is non-zero, look for a specific name (if name != NULL),
    957  *	or a specific gid (if name == NULL).
    958  */
    959 int
    960 __grscan_nis(int *retval, struct group *grp, char *buffer, size_t buflen,
    961 	struct __grstate_nis *state, int search, const char *name, gid_t gid)
    962 {
    963 	const char *map;
    964 	char	*key, *data;
    965 	int	nisr, rv, keylen, datalen;
    966 
    967 	_DIAGASSERT(retval != NULL);
    968 	_DIAGASSERT(grp != NULL);
    969 	_DIAGASSERT(buffer != NULL);
    970 	_DIAGASSERT(state != NULL);
    971 	/* name is NULL to indicate searching for gid */
    972 
    973 	*retval = 0;
    974 
    975 	if (state->domain == NULL) {	/* only start if NIS not setup */
    976 		rv = __grstart_nis(state);
    977 		if (rv != NS_SUCCESS)
    978 			return rv;
    979 	}
    980 
    981  next_nis_entry:
    982 	key = NULL;
    983 	data = NULL;
    984 	rv = NS_SUCCESS;
    985 
    986 	if (! search) 	{			/* find next entry */
    987 		if (state->done)			/* exhausted search */
    988 			return NS_NOTFOUND;
    989 		map = "group.byname";
    990 		if (state->current) {			/* already searching */
    991 			nisr = yp_next(state->domain, map,
    992 			    state->current, state->currentlen,
    993 			    &key, &keylen, &data, &datalen);
    994 			free(state->current);
    995 			state->current = NULL;
    996 			switch (nisr) {
    997 			case 0:
    998 				state->current = key;
    999 				state->currentlen = keylen;
   1000 				key = NULL;
   1001 				break;
   1002 			case YPERR_NOMORE:
   1003 				rv = NS_NOTFOUND;
   1004 				state->done = 1;
   1005 				break;
   1006 			default:
   1007 				rv = NS_UNAVAIL;
   1008 				break;
   1009 			}
   1010 		} else {				/* new search */
   1011 			if (yp_first(state->domain, map,
   1012 			    &state->current, &state->currentlen,
   1013 			    &data, &datalen)) {
   1014 				rv = NS_UNAVAIL;
   1015 			}
   1016 		}
   1017 	} else {				/* search for specific item */
   1018 		if (name) {			/* find group name */
   1019 			snprintf(buffer, buflen, "%s", name);
   1020 			map = "group.byname";
   1021 		} else {			/* find gid */
   1022 			snprintf(buffer, buflen, "%u", (unsigned int)gid);
   1023 			map = "group.bygid";
   1024 		}
   1025 		nisr = yp_match(state->domain, map, buffer, (int)strlen(buffer),
   1026 		    &data, &datalen);
   1027 		switch (nisr) {
   1028 		case 0:
   1029 			break;
   1030 		case YPERR_KEY:
   1031 			rv = NS_NOTFOUND;
   1032 			break;
   1033 		default:
   1034 			rv = NS_UNAVAIL;
   1035 			break;
   1036 		}
   1037 	}
   1038 	if (rv == NS_SUCCESS) {				/* validate data */
   1039 		data[datalen] = '\0';			/* clear trailing \n */
   1040 		if (_gr_parse(data, grp, buffer, buflen)) {
   1041 			if (! search) {			/* just want this one */
   1042 				rv = NS_SUCCESS;
   1043 			} else if ((name && strcmp(name, grp->gr_name) == 0) ||
   1044 			    (!name && gid == grp->gr_gid)) {
   1045 							/* want specific */
   1046 				rv = NS_SUCCESS;
   1047 			}
   1048 		} else {				/* dodgy entry */
   1049 			if (!search) {		/* try again if ! searching */
   1050 				free(data);
   1051 				goto next_nis_entry;
   1052 			}
   1053 		}
   1054 	}
   1055 
   1056 	if (rv != NS_SUCCESS && rv != NS_NOTFOUND)
   1057 		*retval = errno;
   1058 	if (key)
   1059 		free(key);
   1060 	if (data)
   1061 		free(data);
   1062 	return rv;
   1063 }
   1064 
   1065 static struct __grstate_nis	_nis_state;
   1066 					/* storage for non _r functions */
   1067 static struct group		_nis_group;
   1068 static char			_nis_groupbuf[_GETGR_R_SIZE_MAX];
   1069 
   1070 /*ARGSUSED*/
   1071 static int
   1072 _nis_setgrent(void *nsrv, void *nscb, va_list ap)
   1073 {
   1074 
   1075 	_nis_state.stayopen = 0;
   1076 	return __grstart_nis(&_nis_state);
   1077 }
   1078 
   1079 /*ARGSUSED*/
   1080 static int
   1081 _nis_setgroupent(void *nsrv, void *nscb, va_list ap)
   1082 {
   1083 	int	*retval		= va_arg(ap, int *);
   1084 	int	 stayopen	= va_arg(ap, int);
   1085 
   1086 	int	rv;
   1087 
   1088 	_nis_state.stayopen = stayopen;
   1089 	rv = __grstart_nis(&_nis_state);
   1090 	*retval = (rv == NS_SUCCESS);
   1091 	return rv;
   1092 }
   1093 
   1094 /*ARGSUSED*/
   1095 static int
   1096 _nis_endgrent(void *nsrv, void *nscb, va_list ap)
   1097 {
   1098 
   1099 	return __grend_nis(&_nis_state);
   1100 }
   1101 
   1102 /*ARGSUSED*/
   1103 static int
   1104 _nis_getgrent(void *nsrv, void *nscb, va_list ap)
   1105 {
   1106 	struct group	**retval = va_arg(ap, struct group **);
   1107 
   1108 	int	rv, rerror;
   1109 
   1110 	_DIAGASSERT(retval != NULL);
   1111 
   1112 	*retval = NULL;
   1113 	rv = __grscan_nis(&rerror, &_nis_group,
   1114 	    _nis_groupbuf, sizeof(_nis_groupbuf), &_nis_state, 0, NULL, 0);
   1115 	if (rv == NS_SUCCESS)
   1116 		*retval = &_nis_group;
   1117 	return rv;
   1118 }
   1119 
   1120 /*ARGSUSED*/
   1121 static int
   1122 _nis_getgrent_r(void *nsrv, void *nscb, va_list ap)
   1123 {
   1124 	int		*retval	= va_arg(ap, int *);
   1125 	struct group	*grp	= va_arg(ap, struct group *);
   1126 	char		*buffer	= va_arg(ap, char *);
   1127 	size_t		 buflen	= va_arg(ap, size_t);
   1128 	struct group   **result	= va_arg(ap, struct group **);
   1129 
   1130 	int	rv;
   1131 
   1132 	_DIAGASSERT(retval != NULL);
   1133 	_DIAGASSERT(grp != NULL);
   1134 	_DIAGASSERT(buffer != NULL);
   1135 	_DIAGASSERT(result != NULL);
   1136 
   1137 	rv = __grscan_nis(retval, grp, buffer, buflen,
   1138 	    &_nis_state, 0, NULL, 0);
   1139 	if (rv == NS_SUCCESS)
   1140 		*result = grp;
   1141 	else
   1142 		*result = NULL;
   1143 	return rv;
   1144 }
   1145 
   1146 /*ARGSUSED*/
   1147 static int
   1148 _nis_getgrgid(void *nsrv, void *nscb, va_list ap)
   1149 {
   1150 	struct group	**retval = va_arg(ap, struct group **);
   1151 	gid_t		 gid	= va_arg(ap, gid_t);
   1152 
   1153 	int	rv, rerror;
   1154 
   1155 	_DIAGASSERT(retval != NULL);
   1156 
   1157 	*retval = NULL;
   1158 	rv = __grstart_nis(&_nis_state);
   1159 	if (rv != NS_SUCCESS)
   1160 		return rv;
   1161 	rv = __grscan_nis(&rerror, &_nis_group,
   1162 	    _nis_groupbuf, sizeof(_nis_groupbuf), &_nis_state, 1, NULL, gid);
   1163 	if (!_nis_state.stayopen)
   1164 		__grend_nis(&_nis_state);
   1165 	if (rv == NS_SUCCESS)
   1166 		*retval = &_nis_group;
   1167 	return rv;
   1168 }
   1169 
   1170 /*ARGSUSED*/
   1171 static int
   1172 _nis_getgrgid_r(void *nsrv, void *nscb, va_list ap)
   1173 {
   1174 	int		*retval	= va_arg(ap, int *);
   1175 	gid_t		 gid	= va_arg(ap, gid_t);
   1176 	struct group	*grp	= va_arg(ap, struct group *);
   1177 	char		*buffer	= va_arg(ap, char *);
   1178 	size_t		 buflen	= va_arg(ap, size_t);
   1179 	struct group   **result	= va_arg(ap, struct group **);
   1180 
   1181 	struct __grstate_nis state;
   1182 	int	rv;
   1183 
   1184 	_DIAGASSERT(retval != NULL);
   1185 	_DIAGASSERT(grp != NULL);
   1186 	_DIAGASSERT(buffer != NULL);
   1187 	_DIAGASSERT(result != NULL);
   1188 
   1189 	*result = NULL;
   1190 	memset(&state, 0, sizeof(state));
   1191 	rv = __grscan_nis(retval, grp, buffer, buflen, &state, 1, NULL, gid);
   1192 	__grend_nis(&state);
   1193 	if (rv == NS_SUCCESS)
   1194 		*result = grp;
   1195 	return rv;
   1196 }
   1197 
   1198 /*ARGSUSED*/
   1199 static int
   1200 _nis_getgrnam(void *nsrv, void *nscb, va_list ap)
   1201 {
   1202 	struct group	**retval = va_arg(ap, struct group **);
   1203 	const char	*name	= va_arg(ap, const char *);
   1204 
   1205 	int	rv, rerror;
   1206 
   1207 	_DIAGASSERT(retval != NULL);
   1208 
   1209 	*retval = NULL;
   1210 	rv = __grstart_nis(&_nis_state);
   1211 	if (rv != NS_SUCCESS)
   1212 		return rv;
   1213 	rv = __grscan_nis(&rerror, &_nis_group,
   1214 	    _nis_groupbuf, sizeof(_nis_groupbuf), &_nis_state, 1, name, 0);
   1215 	if (!_nis_state.stayopen)
   1216 		__grend_nis(&_nis_state);
   1217 	if (rv == NS_SUCCESS)
   1218 		*retval = &_nis_group;
   1219 	return rv;
   1220 }
   1221 
   1222 /*ARGSUSED*/
   1223 static int
   1224 _nis_getgrnam_r(void *nsrv, void *nscb, va_list ap)
   1225 {
   1226 	int		*retval	= va_arg(ap, int *);
   1227 	const char	*name	= va_arg(ap, const char *);
   1228 	struct group	*grp	= va_arg(ap, struct group *);
   1229 	char		*buffer	= va_arg(ap, char *);
   1230 	size_t		 buflen	= va_arg(ap, size_t);
   1231 	struct group   **result	= va_arg(ap, struct group **);
   1232 
   1233 	struct __grstate_nis state;
   1234 	int	rv;
   1235 
   1236 	_DIAGASSERT(retval != NULL);
   1237 	_DIAGASSERT(grp != NULL);
   1238 	_DIAGASSERT(buffer != NULL);
   1239 	_DIAGASSERT(result != NULL);
   1240 
   1241 	*result = NULL;
   1242 	memset(&state, 0, sizeof(state));
   1243 	rv = __grscan_nis(retval, grp, buffer, buflen, &state, 1, name, 0);
   1244 	__grend_nis(&state);
   1245 	if (rv == NS_SUCCESS)
   1246 		*result = grp;
   1247 	return rv;
   1248 }
   1249 
   1250 #endif /* YP */
   1251 
   1252 
   1253 #ifdef _GROUP_COMPAT
   1254 		/*
   1255 		 *	compat methods
   1256 		 */
   1257 
   1258 int
   1259 __grstart_compat(struct __grstate_compat *state)
   1260 {
   1261 
   1262 	_DIAGASSERT(state != NULL);
   1263 
   1264 	if (state->fp == NULL) {
   1265 		state->fp = fopen(_PATH_GROUP, "r");
   1266 		if (state->fp == NULL)
   1267 			return NS_UNAVAIL;
   1268 	} else {
   1269 		rewind(state->fp);
   1270 	}
   1271 	return NS_SUCCESS;
   1272 }
   1273 
   1274 int
   1275 __grend_compat(struct __grstate_compat *state)
   1276 {
   1277 
   1278 	_DIAGASSERT(state != NULL);
   1279 
   1280 	if (state->name) {
   1281 		free(state->name);
   1282 		state->name = NULL;
   1283 	}
   1284 	if (state->fp) {
   1285 		(void) fclose(state->fp);
   1286 		state->fp = NULL;
   1287 	}
   1288 	return NS_SUCCESS;
   1289 }
   1290 
   1291 
   1292 /*
   1293  * __grbad_compat
   1294  *	log an error if "files" or "compat" is specified in
   1295  *	group_compat database
   1296  */
   1297 /*ARGSUSED*/
   1298 int
   1299 __grbad_compat(void *nsrv, void *nscb, va_list ap)
   1300 {
   1301 	static int warned;
   1302 
   1303 	_DIAGASSERT(nsrv != NULL);
   1304 	_DIAGASSERT(nscb != NULL);
   1305 
   1306 	if (!warned) {
   1307 		syslog(LOG_ERR,
   1308 			"nsswitch.conf group_compat database can't use '%s'",
   1309 			(const char *)nscb);
   1310 	}
   1311 	warned = 1;
   1312 	return NS_UNAVAIL;
   1313 }
   1314 
   1315 /*
   1316  * __grscan_compat
   1317  *	Scan state->fp for the next desired entry.
   1318  *	If search is zero, return the next entry.
   1319  *	If search is non-zero, look for a specific name (if name != NULL),
   1320  *	or a specific gid (if name == NULL).
   1321  *	Sets *retval to the errno if the result is not NS_SUCCESS or
   1322  *	NS_NOTFOUND.
   1323  *
   1324  *	searchfunc is invoked when a compat "+" lookup is required;
   1325  *	searchcookie is passed as the first argument to searchfunc,
   1326  *	the second argument is the group result.
   1327  *	This should return NS_NOTFOUND when "no more groups" from compat src.
   1328  *	If searchfunc is NULL then nsdispatch of getgrent is used.
   1329  *	This is primarily intended for getgroupmembership(3)'s compat backend.
   1330  */
   1331 int
   1332 __grscan_compat(int *retval, struct group *grp, char *buffer, size_t buflen,
   1333 	struct __grstate_compat *state, int search, const char *name, gid_t gid,
   1334 	int (*searchfunc)(void *, struct group **), void *searchcookie)
   1335 {
   1336 	int		rv;
   1337 	char		filebuf[_GETGR_R_SIZE_MAX], *ep;
   1338 
   1339 	static const ns_dtab compatentdtab[] = {
   1340 		NS_FILES_CB(__grbad_compat, "files")
   1341 		NS_DNS_CB(_dns_getgrent_r, NULL)
   1342 		NS_NIS_CB(_nis_getgrent_r, NULL)
   1343 		NS_COMPAT_CB(__grbad_compat, "compat")
   1344 		NS_NULL_CB
   1345 	};
   1346 	static const ns_dtab compatgiddtab[] = {
   1347 		NS_FILES_CB(__grbad_compat, "files")
   1348 		NS_DNS_CB(_dns_getgrgid_r, NULL)
   1349 		NS_NIS_CB(_nis_getgrgid_r, NULL)
   1350 		NS_COMPAT_CB(__grbad_compat, "compat")
   1351 		NS_NULL_CB
   1352 	};
   1353 	static const ns_dtab compatnamdtab[] = {
   1354 		NS_FILES_CB(__grbad_compat, "files")
   1355 		NS_DNS_CB(_dns_getgrnam_r, NULL)
   1356 		NS_NIS_CB(_nis_getgrnam_r, NULL)
   1357 		NS_COMPAT_CB(__grbad_compat, "compat")
   1358 		NS_NULL_CB
   1359 	};
   1360 
   1361 	_DIAGASSERT(retval != NULL);
   1362 	_DIAGASSERT(grp != NULL);
   1363 	_DIAGASSERT(buffer != NULL);
   1364 	_DIAGASSERT(state != NULL);
   1365 	/* name is NULL to indicate searching for gid */
   1366 
   1367 	*retval = 0;
   1368 
   1369 	if (state->fp == NULL) {	/* only start if file not open yet */
   1370 		rv = __grstart_compat(state);
   1371 		if (rv != NS_SUCCESS)
   1372 			goto compatgrscan_out;
   1373 	}
   1374 	rv = NS_NOTFOUND;
   1375 
   1376 	for (;;) {					/* loop through file */
   1377 		if (state->name != NULL) {
   1378 					/* processing compat entry */
   1379 			int		crv, cretval;
   1380 			struct group	cgrp, *cgrpres;
   1381 
   1382 			if (state->name[0]) {		/* specific +group: */
   1383 				crv = nsdispatch(NULL, compatnamdtab,
   1384 				    NSDB_GROUP_COMPAT, "getgrnam_r",
   1385 				    __nsdefaultnis,
   1386 				    &cretval, state->name,
   1387 				    &cgrp, filebuf, sizeof(filebuf), &cgrpres);
   1388 				free(state->name);	/* (only check 1 grp) */
   1389 				state->name = NULL;
   1390 			} else if (!search) {		/* any group */
   1391 				if (searchfunc) {
   1392 					crv = searchfunc(searchcookie,
   1393 					    &cgrpres);
   1394 				} else {
   1395 					crv = nsdispatch(NULL, compatentdtab,
   1396 					    NSDB_GROUP_COMPAT, "getgrent_r",
   1397 					    __nsdefaultnis,
   1398 					    &cretval, &cgrp, filebuf,
   1399 					    sizeof(filebuf), &cgrpres);
   1400 				}
   1401 			} else if (name) {		/* specific group */
   1402 				crv = nsdispatch(NULL, compatnamdtab,
   1403 				    NSDB_GROUP_COMPAT, "getgrnam_r",
   1404 				    __nsdefaultnis,
   1405 				    &cretval, name,
   1406 				    &cgrp, filebuf, sizeof(filebuf), &cgrpres);
   1407 			} else {			/* specific gid */
   1408 				crv = nsdispatch(NULL, compatgiddtab,
   1409 				    NSDB_GROUP_COMPAT, "getgrgid_r",
   1410 				    __nsdefaultnis,
   1411 				    &cretval, gid,
   1412 				    &cgrp, filebuf, sizeof(filebuf), &cgrpres);
   1413 			}
   1414 			if (crv != NS_SUCCESS) {	/* not found */
   1415 				free(state->name);
   1416 				state->name = NULL;
   1417 				continue;		/* try next line */
   1418 			}
   1419 			if (!_gr_copy(cgrpres, grp, buffer, buflen)) {
   1420 				rv = NS_UNAVAIL;
   1421 				break;
   1422 			}
   1423 			goto compatgrscan_cmpgrp;	/* skip to grp test */
   1424 		}
   1425 
   1426 							/* get next file line */
   1427 		if (fgets(filebuf, sizeof(filebuf), state->fp) == NULL)
   1428 			break;
   1429 
   1430 		ep = strchr(filebuf, '\n');
   1431 		if (ep == NULL) {	/* skip lines that are too big */
   1432 			int ch;
   1433 
   1434 			while ((ch = getc(state->fp)) != '\n' && ch != EOF)
   1435 				continue;
   1436 			continue;
   1437 		}
   1438 		*ep = '\0';				/* clear trailing \n */
   1439 
   1440 		if (filebuf[0] == '+') {		/* parse compat line */
   1441 			if (state->name)
   1442 				free(state->name);
   1443 			state->name = NULL;
   1444 			switch(filebuf[1]) {
   1445 			case ':':
   1446 			case '\0':
   1447 				state->name = strdup("");
   1448 				break;
   1449 			default:
   1450 				ep = strchr(filebuf + 1, ':');
   1451 				if (ep == NULL)
   1452 					break;
   1453 				*ep = '\0';
   1454 				state->name = strdup(filebuf + 1);
   1455 				break;
   1456 			}
   1457 			if (state->name == NULL) {
   1458 				rv = NS_UNAVAIL;
   1459 				break;
   1460 			}
   1461 			continue;
   1462 		}
   1463 
   1464 							/* validate line */
   1465 		if (! _gr_parse(filebuf, grp, buffer, buflen)) {
   1466 			continue;			/* skip bad lines */
   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 		NS_NULL_CB
   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 		NS_NULL_CB
   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 		NS_NULL_CB
   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 		NS_NULL_CB
   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 		NS_NULL_CB
   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 		NS_NULL_CB
   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 		NS_NULL_CB
   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 		NS_NULL_CB
   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 		NS_NULL_CB
   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 		NS_NULL_CB
   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 		NS_NULL_CB
   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 		NS_NULL_CB
   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