Home | History | Annotate | Line # | Download | only in gen
getgrent.c revision 1.58
      1 /*	$NetBSD: getgrent.c,v 1.58 2005/04/19 05:27:58 lukem 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.58 2005/04/19 05:27:58 lukem 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) {	/* skip lines that are too big */
    369 			int ch;
    370 
    371 			while ((ch = getc(state->fp)) != '\n' && ch != EOF)
    372 				continue;
    373 			continue;
    374 		}
    375 		*ep = '\0';				/* clear trailing \n */
    376 
    377 		if (filebuf[0] == '+')			/* skip compat line */
    378 			continue;
    379 
    380 							/* validate line */
    381 		if (! _gr_parse(filebuf, grp, buffer, buflen)) {
    382 			continue;			/* skip bad lines */
    383 		}
    384 		if (! search) {				/* just want this one */
    385 			rv = NS_SUCCESS;
    386 			break;
    387 		}
    388 							/* want specific */
    389 		if ((name && strcmp(name, grp->gr_name) == 0) ||
    390 		    (!name && gid == grp->gr_gid)) {
    391 			rv = NS_SUCCESS;
    392 			break;
    393 		}
    394 	}
    395 
    396  filesgrscan_out:
    397 	if (rv != NS_SUCCESS && rv != NS_NOTFOUND)
    398 		*retval = errno;
    399 	return rv;
    400 }
    401 
    402 
    403 static struct __grstate_files	_files_state;
    404 					/* storage for non _r functions */
    405 static struct group		_files_group;
    406 static char			_files_groupbuf[_GETGR_R_SIZE_MAX];
    407 
    408 /*ARGSUSED*/
    409 static int
    410 _files_setgrent(void *nsrv, void *nscb, va_list ap)
    411 {
    412 
    413 	_files_state.stayopen = 0;
    414 	return __grstart_files(&_files_state);
    415 }
    416 
    417 /*ARGSUSED*/
    418 static int
    419 _files_setgroupent(void *nsrv, void *nscb, va_list ap)
    420 {
    421 	int	*retval		= va_arg(ap, int *);
    422 	int	 stayopen	= va_arg(ap, int);
    423 
    424 	int	rv;
    425 
    426 	_files_state.stayopen = stayopen;
    427 	rv = __grstart_files(&_files_state);
    428 	*retval = (rv == NS_SUCCESS);
    429 	return rv;
    430 }
    431 
    432 /*ARGSUSED*/
    433 static int
    434 _files_endgrent(void *nsrv, void *nscb, va_list ap)
    435 {
    436 
    437 	_files_state.stayopen = 0;
    438 	return __grend_files(&_files_state);
    439 }
    440 
    441 /*ARGSUSED*/
    442 static int
    443 _files_getgrent(void *nsrv, void *nscb, va_list ap)
    444 {
    445 	struct group	**retval = va_arg(ap, struct group **);
    446 
    447 	int	rv, rerror;
    448 
    449 	_DIAGASSERT(retval != NULL);
    450 
    451 	*retval = NULL;
    452 	rv = __grscan_files(&rerror, &_files_group,
    453 	    _files_groupbuf, sizeof(_files_groupbuf),
    454 	    &_files_state, 0, NULL, 0);
    455 	if (rv == NS_SUCCESS)
    456 		*retval = &_files_group;
    457 	return rv;
    458 }
    459 
    460 /*ARGSUSED*/
    461 static int
    462 _files_getgrent_r(void *nsrv, void *nscb, va_list ap)
    463 {
    464 	int		*retval	= va_arg(ap, int *);
    465 	struct group	*grp	= va_arg(ap, struct group *);
    466 	char		*buffer	= va_arg(ap, char *);
    467 	size_t		 buflen	= va_arg(ap, size_t);
    468 	struct group   **result	= va_arg(ap, struct group **);
    469 
    470 	int	rv;
    471 
    472 	_DIAGASSERT(retval != NULL);
    473 	_DIAGASSERT(grp != NULL);
    474 	_DIAGASSERT(buffer != NULL);
    475 	_DIAGASSERT(result != NULL);
    476 
    477 	rv = __grscan_files(retval, grp, buffer, buflen,
    478 	    &_files_state, 0, NULL, 0);
    479 	if (rv == NS_SUCCESS)
    480 		*result = grp;
    481 	else
    482 		*result = NULL;
    483 	return rv;
    484 }
    485 
    486 /*ARGSUSED*/
    487 static int
    488 _files_getgrgid(void *nsrv, void *nscb, va_list ap)
    489 {
    490 	struct group	**retval = va_arg(ap, struct group **);
    491 	gid_t		 gid	= va_arg(ap, gid_t);
    492 
    493 	int	rv, rerror;
    494 
    495 	_DIAGASSERT(retval != NULL);
    496 
    497 	*retval = NULL;
    498 	rv = __grstart_files(&_files_state);
    499 	if (rv != NS_SUCCESS)
    500 		return rv;
    501 	rv = __grscan_files(&rerror, &_files_group,
    502 	    _files_groupbuf, sizeof(_files_groupbuf),
    503 	    &_files_state, 1, NULL, gid);
    504 	if (!_files_state.stayopen)
    505 		__grend_files(&_files_state);
    506 	if (rv == NS_SUCCESS)
    507 		*retval = &_files_group;
    508 	return rv;
    509 }
    510 
    511 /*ARGSUSED*/
    512 static int
    513 _files_getgrgid_r(void *nsrv, void *nscb, va_list ap)
    514 {
    515 	int		*retval	= va_arg(ap, int *);
    516 	gid_t		 gid	= va_arg(ap, gid_t);
    517 	struct group	*grp	= va_arg(ap, struct group *);
    518 	char		*buffer	= va_arg(ap, char *);
    519 	size_t		 buflen	= va_arg(ap, size_t);
    520 	struct group   **result	= va_arg(ap, struct group **);
    521 
    522 	struct __grstate_files state;
    523 	int	rv;
    524 
    525 	_DIAGASSERT(retval != NULL);
    526 	_DIAGASSERT(grp != NULL);
    527 	_DIAGASSERT(buffer != NULL);
    528 	_DIAGASSERT(result != NULL);
    529 
    530 	*result = NULL;
    531 	memset(&state, 0, sizeof(state));
    532 	rv = __grscan_files(retval, grp, buffer, buflen, &state, 1, NULL, gid);
    533 	__grend_files(&state);
    534 	if (rv == NS_SUCCESS)
    535 		*result = grp;
    536 	return rv;
    537 }
    538 
    539 /*ARGSUSED*/
    540 static int
    541 _files_getgrnam(void *nsrv, void *nscb, va_list ap)
    542 {
    543 	struct group	**retval = va_arg(ap, struct group **);
    544 	const char	*name	= va_arg(ap, const char *);
    545 
    546 	int	rv, rerror;
    547 
    548 	_DIAGASSERT(retval != NULL);
    549 
    550 	*retval = NULL;
    551 	rv = __grstart_files(&_files_state);
    552 	if (rv != NS_SUCCESS)
    553 		return rv;
    554 	rv = __grscan_files(&rerror, &_files_group,
    555 	    _files_groupbuf, sizeof(_files_groupbuf),
    556 	    &_files_state, 1, name, 0);
    557 	if (!_files_state.stayopen)
    558 		__grend_files(&_files_state);
    559 	if (rv == NS_SUCCESS)
    560 		*retval = &_files_group;
    561 	return rv;
    562 }
    563 
    564 /*ARGSUSED*/
    565 static int
    566 _files_getgrnam_r(void *nsrv, void *nscb, va_list ap)
    567 {
    568 	int		*retval	= va_arg(ap, int *);
    569 	const char	*name	= va_arg(ap, const char *);
    570 	struct group	*grp	= va_arg(ap, struct group *);
    571 	char		*buffer	= va_arg(ap, char *);
    572 	size_t		 buflen	= va_arg(ap, size_t);
    573 	struct group   **result	= va_arg(ap, struct group **);
    574 
    575 	struct __grstate_files state;
    576 	int	rv;
    577 
    578 	_DIAGASSERT(retval != NULL);
    579 	_DIAGASSERT(grp != NULL);
    580 	_DIAGASSERT(buffer != NULL);
    581 	_DIAGASSERT(result != NULL);
    582 
    583 	*result = NULL;
    584 	memset(&state, 0, sizeof(state));
    585 	rv = __grscan_files(retval, grp, buffer, buflen, &state, 1, name, 0);
    586 	__grend_files(&state);
    587 	if (rv == NS_SUCCESS)
    588 		*result = grp;
    589 	return rv;
    590 }
    591 
    592 
    593 #ifdef HESIOD
    594 		/*
    595 		 *	dns methods
    596 		 */
    597 
    598 int
    599 __grstart_dns(struct __grstate_dns *state)
    600 {
    601 
    602 	_DIAGASSERT(state != NULL);
    603 
    604 	state->num = 0;
    605 	if (state->context == NULL) {			/* setup Hesiod */
    606 		if (hesiod_init(&state->context) == -1)
    607 			return NS_UNAVAIL;
    608 	}
    609 
    610 	return NS_SUCCESS;
    611 }
    612 
    613 int
    614 __grend_dns(struct __grstate_dns *state)
    615 {
    616 
    617 	_DIAGASSERT(state != NULL);
    618 
    619 	state->num = 0;
    620 	if (state->context) {
    621 		hesiod_end(state->context);
    622 		state->context = NULL;
    623 	}
    624 	return NS_SUCCESS;
    625 }
    626 
    627 /*
    628  * __grscan_dns
    629  *	Search Hesiod for the next desired entry.
    630  *	If search is zero, return the next entry.
    631  *	If search is non-zero, look for a specific name (if name != NULL),
    632  *	or a specific gid (if name == NULL).
    633  */
    634 int
    635 __grscan_dns(int *retval, struct group *grp, char *buffer, size_t buflen,
    636 	struct __grstate_dns *state, int search, const char *name, gid_t gid)
    637 {
    638 	const char	**curzone;
    639 	char		**hp, *ep;
    640 	int		rv;
    641 
    642 	static const char *zones_gid_group[] = {
    643 		"gid",
    644 		"group",
    645 		NULL
    646 	};
    647 
    648 	static const char *zones_group[] = {
    649 		"group",
    650 		NULL
    651 	};
    652 
    653 	_DIAGASSERT(retval != NULL);
    654 	_DIAGASSERT(grp != NULL);
    655 	_DIAGASSERT(buffer != NULL);
    656 	_DIAGASSERT(state != NULL);
    657 	/* name is NULL to indicate searching for gid */
    658 
    659 	*retval = 0;
    660 
    661 	if (state->context == NULL) {	/* only start if Hesiod not setup */
    662 		rv = __grstart_dns(state);
    663 		if (rv != NS_SUCCESS)
    664 			return rv;
    665 	}
    666 
    667  next_dns_entry:
    668 	hp = NULL;
    669 	rv = NS_NOTFOUND;
    670 
    671 	if (! search) {			/* find next entry */
    672 		if (state->num == -1)		/* exhausted search */
    673 			return NS_NOTFOUND;
    674 						/* find group-NNN */
    675 		snprintf(buffer, buflen, "group-%u", state->num);
    676 		state->num++;
    677 		curzone = zones_group;
    678 	} else if (name) {		/* find group name */
    679 		snprintf(buffer, buflen, "%s", name);
    680 		curzone = zones_group;
    681 	} else {			/* find gid */
    682 		snprintf(buffer, buflen, "%u", (unsigned int)gid);
    683 		curzone = zones_gid_group;
    684 	}
    685 
    686 	for (; *curzone; curzone++) {		/* search zones */
    687 		hp = hesiod_resolve(state->context, buffer, *curzone);
    688 		if (hp != NULL)
    689 			break;
    690 		if (errno != ENOENT) {
    691 			rv = NS_UNAVAIL;
    692 			goto dnsgrscan_out;
    693 		}
    694 	}
    695 	if (*curzone == NULL) {
    696 		if (! search)
    697 			state->num = -1;
    698 		goto dnsgrscan_out;
    699 	}
    700 
    701 	if ((ep = strchr(hp[0], '\n')) != NULL)
    702 		*ep = '\0';				/* clear trailing \n */
    703 	if (_gr_parse(hp[0], grp, buffer, buflen)) {	/* validate line */
    704 		if (! search) {				/* just want this one */
    705 			rv = NS_SUCCESS;
    706 		} else if ((name && strcmp(name, grp->gr_name) == 0) ||
    707 		    (!name && gid == grp->gr_gid)) {	/* want specific */
    708 			rv = NS_SUCCESS;
    709 		}
    710 	} else {					/* dodgy entry */
    711 		if (!search) {			/* try again if ! searching */
    712 			hesiod_free_list(state->context, hp);
    713 			goto next_dns_entry;
    714 		}
    715 	}
    716 
    717  dnsgrscan_out:
    718 	if (rv != NS_SUCCESS && rv != NS_NOTFOUND)
    719 		*retval = errno;
    720 	if (hp)
    721 		hesiod_free_list(state->context, hp);
    722 	return rv;
    723 }
    724 
    725 static struct __grstate_dns	_dns_state;
    726 					/* storage for non _r functions */
    727 static struct group		_dns_group;
    728 static char			_dns_groupbuf[_GETGR_R_SIZE_MAX];
    729 
    730 /*ARGSUSED*/
    731 static int
    732 _dns_setgrent(void *nsrv, void *nscb, va_list ap)
    733 {
    734 
    735 	_dns_state.stayopen = 0;
    736 	return __grstart_dns(&_dns_state);
    737 }
    738 
    739 /*ARGSUSED*/
    740 static int
    741 _dns_setgroupent(void *nsrv, void *nscb, va_list ap)
    742 {
    743 	int	*retval		= va_arg(ap, int *);
    744 	int	 stayopen	= va_arg(ap, int);
    745 
    746 	int	rv;
    747 
    748 	_dns_state.stayopen = stayopen;
    749 	rv = __grstart_dns(&_dns_state);
    750 	*retval = (rv == NS_SUCCESS);
    751 	return rv;
    752 }
    753 
    754 /*ARGSUSED*/
    755 static int
    756 _dns_endgrent(void *nsrv, void *nscb, va_list ap)
    757 {
    758 
    759 	_dns_state.stayopen = 0;
    760 	return __grend_dns(&_dns_state);
    761 }
    762 
    763 /*ARGSUSED*/
    764 static int
    765 _dns_getgrent(void *nsrv, void *nscb, va_list ap)
    766 {
    767 	struct group	**retval = va_arg(ap, struct group **);
    768 
    769 	int	  rv, rerror;
    770 
    771 	_DIAGASSERT(retval != NULL);
    772 
    773 	*retval = NULL;
    774 	rv = __grscan_dns(&rerror, &_dns_group,
    775 	    _dns_groupbuf, sizeof(_dns_groupbuf), &_dns_state, 0, NULL, 0);
    776 	if (rv == NS_SUCCESS)
    777 		*retval = &_dns_group;
    778 	return rv;
    779 }
    780 
    781 /*ARGSUSED*/
    782 static int
    783 _dns_getgrent_r(void *nsrv, void *nscb, va_list ap)
    784 {
    785 	int		*retval	= va_arg(ap, int *);
    786 	struct group	*grp	= va_arg(ap, struct group *);
    787 	char		*buffer	= va_arg(ap, char *);
    788 	size_t		 buflen	= va_arg(ap, size_t);
    789 	struct group   **result	= va_arg(ap, struct group **);
    790 
    791 	int	rv;
    792 
    793 	_DIAGASSERT(retval != NULL);
    794 	_DIAGASSERT(grp != NULL);
    795 	_DIAGASSERT(buffer != NULL);
    796 	_DIAGASSERT(result != NULL);
    797 
    798 	rv = __grscan_dns(retval, grp, buffer, buflen,
    799 	    &_dns_state, 0, NULL, 0);
    800 	if (rv == NS_SUCCESS)
    801 		*result = grp;
    802 	else
    803 		*result = NULL;
    804 	return rv;
    805 }
    806 /*ARGSUSED*/
    807 static int
    808 _dns_getgrgid(void *nsrv, void *nscb, va_list ap)
    809 {
    810 	struct group	**retval = va_arg(ap, struct group **);
    811 	gid_t		 gid	= va_arg(ap, gid_t);
    812 
    813 	int	rv, rerror;
    814 
    815 	_DIAGASSERT(retval != NULL);
    816 
    817 	*retval = NULL;
    818 	rv = __grstart_dns(&_dns_state);
    819 	if (rv != NS_SUCCESS)
    820 		return rv;
    821 	rv = __grscan_dns(&rerror, &_dns_group,
    822 	    _dns_groupbuf, sizeof(_dns_groupbuf), &_dns_state, 1, NULL, gid);
    823 	if (!_dns_state.stayopen)
    824 		__grend_dns(&_dns_state);
    825 	if (rv == NS_SUCCESS)
    826 		*retval = &_dns_group;
    827 	return rv;
    828 }
    829 
    830 /*ARGSUSED*/
    831 static int
    832 _dns_getgrgid_r(void *nsrv, void *nscb, va_list ap)
    833 {
    834 	int		*retval	= va_arg(ap, int *);
    835 	gid_t		 gid	= va_arg(ap, gid_t);
    836 	struct group	*grp	= va_arg(ap, struct group *);
    837 	char		*buffer	= va_arg(ap, char *);
    838 	size_t		 buflen	= va_arg(ap, size_t);
    839 	struct group   **result	= va_arg(ap, struct group **);
    840 
    841 	struct __grstate_dns state;
    842 	int	rv;
    843 
    844 	_DIAGASSERT(retval != NULL);
    845 	_DIAGASSERT(grp != NULL);
    846 	_DIAGASSERT(buffer != NULL);
    847 	_DIAGASSERT(result != NULL);
    848 
    849 	*result = NULL;
    850 	memset(&state, 0, sizeof(state));
    851 	rv = __grscan_dns(retval, grp, buffer, buflen, &state, 1, NULL, gid);
    852 	__grend_dns(&state);
    853 	if (rv == NS_SUCCESS)
    854 		*result = grp;
    855 	return rv;
    856 }
    857 
    858 /*ARGSUSED*/
    859 static int
    860 _dns_getgrnam(void *nsrv, void *nscb, va_list ap)
    861 {
    862 	struct group	**retval = va_arg(ap, struct group **);
    863 	const char	*name	= va_arg(ap, const char *);
    864 
    865 	int	rv, rerror;
    866 
    867 	_DIAGASSERT(retval != NULL);
    868 
    869 	*retval = NULL;
    870 	rv = __grstart_dns(&_dns_state);
    871 	if (rv != NS_SUCCESS)
    872 		return rv;
    873 	rv = __grscan_dns(&rerror, &_dns_group,
    874 	    _dns_groupbuf, sizeof(_dns_groupbuf), &_dns_state, 1, name, 0);
    875 	if (!_dns_state.stayopen)
    876 		__grend_dns(&_dns_state);
    877 	if (rv == NS_SUCCESS)
    878 		*retval = &_dns_group;
    879 	return rv;
    880 }
    881 
    882 /*ARGSUSED*/
    883 static int
    884 _dns_getgrnam_r(void *nsrv, void *nscb, va_list ap)
    885 {
    886 	int		*retval	= va_arg(ap, int *);
    887 	const char	*name	= va_arg(ap, const char *);
    888 	struct group	*grp	= va_arg(ap, struct group *);
    889 	char		*buffer	= va_arg(ap, char *);
    890 	size_t		 buflen	= va_arg(ap, size_t);
    891 	struct group   **result	= va_arg(ap, struct group **);
    892 
    893 	struct __grstate_dns state;
    894 	int	rv;
    895 
    896 	_DIAGASSERT(retval != NULL);
    897 	_DIAGASSERT(grp != NULL);
    898 	_DIAGASSERT(buffer != NULL);
    899 	_DIAGASSERT(result != NULL);
    900 
    901 	*result = NULL;
    902 	memset(&state, 0, sizeof(state));
    903 	rv = __grscan_dns(retval, grp, buffer, buflen, &state, 1, name, 0);
    904 	__grend_dns(&state);
    905 	if (rv == NS_SUCCESS)
    906 		*result = grp;
    907 	return rv;
    908 }
    909 
    910 #endif /* HESIOD */
    911 
    912 
    913 #ifdef YP
    914 		/*
    915 		 *	nis methods
    916 		 */
    917 
    918 int
    919 __grstart_nis(struct __grstate_nis *state)
    920 {
    921 
    922 	_DIAGASSERT(state != NULL);
    923 
    924 	state->done = 0;
    925 	if (state->current) {
    926 		free(state->current);
    927 		state->current = NULL;
    928 	}
    929 	if (state->domain == NULL) {			/* setup NIS */
    930 		switch (yp_get_default_domain(&state->domain)) {
    931 		case 0:
    932 			break;
    933 		case YPERR_RESRC:
    934 			return NS_TRYAGAIN;
    935 		default:
    936 			return NS_UNAVAIL;
    937 		}
    938 	}
    939 	return NS_SUCCESS;
    940 }
    941 
    942 int
    943 __grend_nis(struct __grstate_nis *state)
    944 {
    945 
    946 	_DIAGASSERT(state != NULL);
    947 
    948 	if (state->domain) {
    949 		state->domain = NULL;
    950 	}
    951 	state->done = 0;
    952 	if (state->current) {
    953 		free(state->current);
    954 		state->current = NULL;
    955 	}
    956 	return NS_SUCCESS;
    957 }
    958 
    959 /*
    960  * __grscan_nis
    961  *	Search NIS for the next desired entry.
    962  *	If search is zero, return the next entry.
    963  *	If search is non-zero, look for a specific name (if name != NULL),
    964  *	or a specific gid (if name == NULL).
    965  */
    966 int
    967 __grscan_nis(int *retval, struct group *grp, char *buffer, size_t buflen,
    968 	struct __grstate_nis *state, int search, const char *name, gid_t gid)
    969 {
    970 	const char *map;
    971 	char	*key, *data;
    972 	int	nisr, rv, keylen, datalen;
    973 
    974 	_DIAGASSERT(retval != NULL);
    975 	_DIAGASSERT(grp != NULL);
    976 	_DIAGASSERT(buffer != NULL);
    977 	_DIAGASSERT(state != NULL);
    978 	/* name is NULL to indicate searching for gid */
    979 
    980 	*retval = 0;
    981 
    982 	if (state->domain == NULL) {	/* only start if NIS not setup */
    983 		rv = __grstart_nis(state);
    984 		if (rv != NS_SUCCESS)
    985 			return rv;
    986 	}
    987 
    988  next_nis_entry:
    989 	key = NULL;
    990 	data = NULL;
    991 	rv = NS_SUCCESS;
    992 
    993 	if (! search) 	{			/* find next entry */
    994 		if (state->done)			/* exhausted search */
    995 			return NS_NOTFOUND;
    996 		map = "group.byname";
    997 		if (state->current) {			/* already searching */
    998 			nisr = yp_next(state->domain, map,
    999 			    state->current, state->currentlen,
   1000 			    &key, &keylen, &data, &datalen);
   1001 			free(state->current);
   1002 			state->current = NULL;
   1003 			switch (nisr) {
   1004 			case 0:
   1005 				state->current = key;
   1006 				state->currentlen = keylen;
   1007 				key = NULL;
   1008 				break;
   1009 			case YPERR_NOMORE:
   1010 				rv = NS_NOTFOUND;
   1011 				state->done = 1;
   1012 				break;
   1013 			default:
   1014 				rv = NS_UNAVAIL;
   1015 				break;
   1016 			}
   1017 		} else {				/* new search */
   1018 			if (yp_first(state->domain, map,
   1019 			    &state->current, &state->currentlen,
   1020 			    &data, &datalen)) {
   1021 				rv = NS_UNAVAIL;
   1022 			}
   1023 		}
   1024 	} else {				/* search for specific item */
   1025 		if (name) {			/* find group name */
   1026 			snprintf(buffer, buflen, "%s", name);
   1027 			map = "group.byname";
   1028 		} else {			/* find gid */
   1029 			snprintf(buffer, buflen, "%u", (unsigned int)gid);
   1030 			map = "group.bygid";
   1031 		}
   1032 		nisr = yp_match(state->domain, map, buffer, (int)strlen(buffer),
   1033 		    &data, &datalen);
   1034 		switch (nisr) {
   1035 		case 0:
   1036 			break;
   1037 		case YPERR_KEY:
   1038 			rv = NS_NOTFOUND;
   1039 			break;
   1040 		default:
   1041 			rv = NS_UNAVAIL;
   1042 			break;
   1043 		}
   1044 	}
   1045 	if (rv == NS_SUCCESS) {				/* validate data */
   1046 		data[datalen] = '\0';			/* clear trailing \n */
   1047 		if (_gr_parse(data, grp, buffer, buflen)) {
   1048 			if (! search) {			/* just want this one */
   1049 				rv = NS_SUCCESS;
   1050 			} else if ((name && strcmp(name, grp->gr_name) == 0) ||
   1051 			    (!name && gid == grp->gr_gid)) {
   1052 							/* want specific */
   1053 				rv = NS_SUCCESS;
   1054 			}
   1055 		} else {				/* dodgy entry */
   1056 			if (!search) {		/* try again if ! searching */
   1057 				if (key)
   1058 					free(key);
   1059 				free(data);
   1060 				goto next_nis_entry;
   1061 			}
   1062 		}
   1063 	}
   1064 
   1065 	if (rv != NS_SUCCESS && rv != NS_NOTFOUND)
   1066 		*retval = errno;
   1067 	if (key)
   1068 		free(key);
   1069 	if (data)
   1070 		free(data);
   1071 	return rv;
   1072 }
   1073 
   1074 static struct __grstate_nis	_nis_state;
   1075 					/* storage for non _r functions */
   1076 static struct group		_nis_group;
   1077 static char			_nis_groupbuf[_GETGR_R_SIZE_MAX];
   1078 
   1079 /*ARGSUSED*/
   1080 static int
   1081 _nis_setgrent(void *nsrv, void *nscb, va_list ap)
   1082 {
   1083 
   1084 	_nis_state.stayopen = 0;
   1085 	return __grstart_nis(&_nis_state);
   1086 }
   1087 
   1088 /*ARGSUSED*/
   1089 static int
   1090 _nis_setgroupent(void *nsrv, void *nscb, va_list ap)
   1091 {
   1092 	int	*retval		= va_arg(ap, int *);
   1093 	int	 stayopen	= va_arg(ap, int);
   1094 
   1095 	int	rv;
   1096 
   1097 	_nis_state.stayopen = stayopen;
   1098 	rv = __grstart_nis(&_nis_state);
   1099 	*retval = (rv == NS_SUCCESS);
   1100 	return rv;
   1101 }
   1102 
   1103 /*ARGSUSED*/
   1104 static int
   1105 _nis_endgrent(void *nsrv, void *nscb, va_list ap)
   1106 {
   1107 
   1108 	return __grend_nis(&_nis_state);
   1109 }
   1110 
   1111 /*ARGSUSED*/
   1112 static int
   1113 _nis_getgrent(void *nsrv, void *nscb, va_list ap)
   1114 {
   1115 	struct group	**retval = va_arg(ap, struct group **);
   1116 
   1117 	int	rv, rerror;
   1118 
   1119 	_DIAGASSERT(retval != NULL);
   1120 
   1121 	*retval = NULL;
   1122 	rv = __grscan_nis(&rerror, &_nis_group,
   1123 	    _nis_groupbuf, sizeof(_nis_groupbuf), &_nis_state, 0, NULL, 0);
   1124 	if (rv == NS_SUCCESS)
   1125 		*retval = &_nis_group;
   1126 	return rv;
   1127 }
   1128 
   1129 /*ARGSUSED*/
   1130 static int
   1131 _nis_getgrent_r(void *nsrv, void *nscb, va_list ap)
   1132 {
   1133 	int		*retval	= va_arg(ap, int *);
   1134 	struct group	*grp	= va_arg(ap, struct group *);
   1135 	char		*buffer	= va_arg(ap, char *);
   1136 	size_t		 buflen	= va_arg(ap, size_t);
   1137 	struct group   **result	= va_arg(ap, struct group **);
   1138 
   1139 	int	rv;
   1140 
   1141 	_DIAGASSERT(retval != NULL);
   1142 	_DIAGASSERT(grp != NULL);
   1143 	_DIAGASSERT(buffer != NULL);
   1144 	_DIAGASSERT(result != NULL);
   1145 
   1146 	rv = __grscan_nis(retval, grp, buffer, buflen,
   1147 	    &_nis_state, 0, NULL, 0);
   1148 	if (rv == NS_SUCCESS)
   1149 		*result = grp;
   1150 	else
   1151 		*result = NULL;
   1152 	return rv;
   1153 }
   1154 
   1155 /*ARGSUSED*/
   1156 static int
   1157 _nis_getgrgid(void *nsrv, void *nscb, va_list ap)
   1158 {
   1159 	struct group	**retval = va_arg(ap, struct group **);
   1160 	gid_t		 gid	= va_arg(ap, gid_t);
   1161 
   1162 	int	rv, rerror;
   1163 
   1164 	_DIAGASSERT(retval != NULL);
   1165 
   1166 	*retval = NULL;
   1167 	rv = __grstart_nis(&_nis_state);
   1168 	if (rv != NS_SUCCESS)
   1169 		return rv;
   1170 	rv = __grscan_nis(&rerror, &_nis_group,
   1171 	    _nis_groupbuf, sizeof(_nis_groupbuf), &_nis_state, 1, NULL, gid);
   1172 	if (!_nis_state.stayopen)
   1173 		__grend_nis(&_nis_state);
   1174 	if (rv == NS_SUCCESS)
   1175 		*retval = &_nis_group;
   1176 	return rv;
   1177 }
   1178 
   1179 /*ARGSUSED*/
   1180 static int
   1181 _nis_getgrgid_r(void *nsrv, void *nscb, va_list ap)
   1182 {
   1183 	int		*retval	= va_arg(ap, int *);
   1184 	gid_t		 gid	= va_arg(ap, gid_t);
   1185 	struct group	*grp	= va_arg(ap, struct group *);
   1186 	char		*buffer	= va_arg(ap, char *);
   1187 	size_t		 buflen	= va_arg(ap, size_t);
   1188 	struct group   **result	= va_arg(ap, struct group **);
   1189 
   1190 	struct __grstate_nis state;
   1191 	int	rv;
   1192 
   1193 	_DIAGASSERT(retval != NULL);
   1194 	_DIAGASSERT(grp != NULL);
   1195 	_DIAGASSERT(buffer != NULL);
   1196 	_DIAGASSERT(result != NULL);
   1197 
   1198 	*result = NULL;
   1199 	memset(&state, 0, sizeof(state));
   1200 	rv = __grscan_nis(retval, grp, buffer, buflen, &state, 1, NULL, gid);
   1201 	__grend_nis(&state);
   1202 	if (rv == NS_SUCCESS)
   1203 		*result = grp;
   1204 	return rv;
   1205 }
   1206 
   1207 /*ARGSUSED*/
   1208 static int
   1209 _nis_getgrnam(void *nsrv, void *nscb, va_list ap)
   1210 {
   1211 	struct group	**retval = va_arg(ap, struct group **);
   1212 	const char	*name	= va_arg(ap, const char *);
   1213 
   1214 	int	rv, rerror;
   1215 
   1216 	_DIAGASSERT(retval != NULL);
   1217 
   1218 	*retval = NULL;
   1219 	rv = __grstart_nis(&_nis_state);
   1220 	if (rv != NS_SUCCESS)
   1221 		return rv;
   1222 	rv = __grscan_nis(&rerror, &_nis_group,
   1223 	    _nis_groupbuf, sizeof(_nis_groupbuf), &_nis_state, 1, name, 0);
   1224 	if (!_nis_state.stayopen)
   1225 		__grend_nis(&_nis_state);
   1226 	if (rv == NS_SUCCESS)
   1227 		*retval = &_nis_group;
   1228 	return rv;
   1229 }
   1230 
   1231 /*ARGSUSED*/
   1232 static int
   1233 _nis_getgrnam_r(void *nsrv, void *nscb, va_list ap)
   1234 {
   1235 	int		*retval	= va_arg(ap, int *);
   1236 	const char	*name	= va_arg(ap, const char *);
   1237 	struct group	*grp	= va_arg(ap, struct group *);
   1238 	char		*buffer	= va_arg(ap, char *);
   1239 	size_t		 buflen	= va_arg(ap, size_t);
   1240 	struct group   **result	= va_arg(ap, struct group **);
   1241 
   1242 	struct __grstate_nis state;
   1243 	int	rv;
   1244 
   1245 	_DIAGASSERT(retval != NULL);
   1246 	_DIAGASSERT(grp != NULL);
   1247 	_DIAGASSERT(buffer != NULL);
   1248 	_DIAGASSERT(result != NULL);
   1249 
   1250 	*result = NULL;
   1251 	memset(&state, 0, sizeof(state));
   1252 	rv = __grscan_nis(retval, grp, buffer, buflen, &state, 1, name, 0);
   1253 	__grend_nis(&state);
   1254 	if (rv == NS_SUCCESS)
   1255 		*result = grp;
   1256 	return rv;
   1257 }
   1258 
   1259 #endif /* YP */
   1260 
   1261 
   1262 #ifdef _GROUP_COMPAT
   1263 		/*
   1264 		 *	compat methods
   1265 		 */
   1266 
   1267 int
   1268 __grstart_compat(struct __grstate_compat *state)
   1269 {
   1270 
   1271 	_DIAGASSERT(state != NULL);
   1272 
   1273 	if (state->fp == NULL) {
   1274 		state->fp = fopen(_PATH_GROUP, "r");
   1275 		if (state->fp == NULL)
   1276 			return NS_UNAVAIL;
   1277 	} else {
   1278 		rewind(state->fp);
   1279 	}
   1280 	return NS_SUCCESS;
   1281 }
   1282 
   1283 int
   1284 __grend_compat(struct __grstate_compat *state)
   1285 {
   1286 
   1287 	_DIAGASSERT(state != NULL);
   1288 
   1289 	if (state->name) {
   1290 		free(state->name);
   1291 		state->name = NULL;
   1292 	}
   1293 	if (state->fp) {
   1294 		(void) fclose(state->fp);
   1295 		state->fp = NULL;
   1296 	}
   1297 	return NS_SUCCESS;
   1298 }
   1299 
   1300 
   1301 /*
   1302  * __grbad_compat
   1303  *	log an error if "files" or "compat" is specified in
   1304  *	group_compat database
   1305  */
   1306 /*ARGSUSED*/
   1307 int
   1308 __grbad_compat(void *nsrv, void *nscb, va_list ap)
   1309 {
   1310 	static int warned;
   1311 
   1312 	_DIAGASSERT(cb_data != NULL);
   1313 
   1314 	if (!warned) {
   1315 		syslog(LOG_ERR,
   1316 			"nsswitch.conf group_compat database can't use '%s'",
   1317 			(const char *)nscb);
   1318 	}
   1319 	warned = 1;
   1320 	return NS_UNAVAIL;
   1321 }
   1322 
   1323 /*
   1324  * __grscan_compat
   1325  *	Scan state->fp for the next desired entry.
   1326  *	If search is zero, return the next entry.
   1327  *	If search is non-zero, look for a specific name (if name != NULL),
   1328  *	or a specific gid (if name == NULL).
   1329  *	Sets *retval to the errno if the result is not NS_SUCCESS or
   1330  *	NS_NOTFOUND.
   1331  *
   1332  *	searchfunc is invoked when a compat "+" lookup is required;
   1333  *	searchcookie is passed as the first argument to searchfunc,
   1334  *	the second argument is the group result.
   1335  *	This should return NS_NOTFOUND when "no more groups" from compat src.
   1336  *	If searchfunc is NULL then nsdispatch of getgrent is used.
   1337  *	This is primarily intended for getgroupmembership(3)'s compat backend.
   1338  */
   1339 int
   1340 __grscan_compat(int *retval, struct group *grp, char *buffer, size_t buflen,
   1341 	struct __grstate_compat *state, int search, const char *name, gid_t gid,
   1342 	int (*searchfunc)(void *, struct group **), void *searchcookie)
   1343 {
   1344 	int		rv;
   1345 	char		filebuf[_GETGR_R_SIZE_MAX], *ep;
   1346 
   1347 	static const ns_dtab compatentdtab[] = {
   1348 		NS_FILES_CB(__grbad_compat, "files")
   1349 		NS_DNS_CB(_dns_getgrent_r, NULL)
   1350 		NS_NIS_CB(_nis_getgrent_r, NULL)
   1351 		NS_COMPAT_CB(__grbad_compat, "compat")
   1352 		{ 0 }
   1353 	};
   1354 	static const ns_dtab compatgiddtab[] = {
   1355 		NS_FILES_CB(__grbad_compat, "files")
   1356 		NS_DNS_CB(_dns_getgrgid_r, NULL)
   1357 		NS_NIS_CB(_nis_getgrgid_r, NULL)
   1358 		NS_COMPAT_CB(__grbad_compat, "compat")
   1359 		{ 0 }
   1360 	};
   1361 	static const ns_dtab compatnamdtab[] = {
   1362 		NS_FILES_CB(__grbad_compat, "files")
   1363 		NS_DNS_CB(_dns_getgrnam_r, NULL)
   1364 		NS_NIS_CB(_nis_getgrnam_r, NULL)
   1365 		NS_COMPAT_CB(__grbad_compat, "compat")
   1366 		{ 0 }
   1367 	};
   1368 
   1369 	_DIAGASSERT(retval != NULL);
   1370 	_DIAGASSERT(grp != NULL);
   1371 	_DIAGASSERT(buffer != NULL);
   1372 	_DIAGASSERT(state != NULL);
   1373 	/* name is NULL to indicate searching for gid */
   1374 
   1375 	*retval = 0;
   1376 
   1377 	if (state->fp == NULL) {	/* only start if file not open yet */
   1378 		rv = __grstart_compat(state);
   1379 		if (rv != NS_SUCCESS)
   1380 			goto compatgrscan_out;
   1381 	}
   1382 	rv = NS_NOTFOUND;
   1383 
   1384 	for (;;) {					/* loop through file */
   1385 		if (state->name != NULL) {
   1386 					/* processing compat entry */
   1387 			int		crv, cretval;
   1388 			struct group	cgrp, *cgrpres;
   1389 
   1390 			if (state->name[0]) {		/* specific +group: */
   1391 				crv = nsdispatch(NULL, compatnamdtab,
   1392 				    NSDB_GROUP_COMPAT, "getgrnam_r",
   1393 				    __nsdefaultnis,
   1394 				    &cretval, state->name,
   1395 				    &cgrp, filebuf, sizeof(filebuf), &cgrpres);
   1396 				free(state->name);	/* (only check 1 grp) */
   1397 				state->name = NULL;
   1398 			} else if (!search) {		/* any group */
   1399 				if (searchfunc) {
   1400 					crv = searchfunc(searchcookie,
   1401 					    &cgrpres);
   1402 				} else {
   1403 					crv = nsdispatch(NULL, compatentdtab,
   1404 					    NSDB_GROUP_COMPAT, "getgrent_r",
   1405 					    __nsdefaultnis,
   1406 					    &cretval, &cgrp, filebuf,
   1407 					    sizeof(filebuf), &cgrpres);
   1408 				}
   1409 			} else if (name) {		/* specific group */
   1410 				crv = nsdispatch(NULL, compatnamdtab,
   1411 				    NSDB_GROUP_COMPAT, "getgrnam_r",
   1412 				    __nsdefaultnis,
   1413 				    &cretval, name,
   1414 				    &cgrp, filebuf, sizeof(filebuf), &cgrpres);
   1415 			} else {			/* specific gid */
   1416 				crv = nsdispatch(NULL, compatgiddtab,
   1417 				    NSDB_GROUP_COMPAT, "getgrgid_r",
   1418 				    __nsdefaultnis,
   1419 				    &cretval, gid,
   1420 				    &cgrp, filebuf, sizeof(filebuf), &cgrpres);
   1421 			}
   1422 			if (crv != NS_SUCCESS) {	/* not found */
   1423 				free(state->name);
   1424 				state->name = NULL;
   1425 				continue;		/* try next line */
   1426 			}
   1427 			if (!_gr_copy(cgrpres, grp, buffer, buflen)) {
   1428 				rv = NS_UNAVAIL;
   1429 				break;
   1430 			}
   1431 			goto compatgrscan_cmpgrp;	/* skip to grp test */
   1432 		}
   1433 
   1434 							/* get next file line */
   1435 		if (fgets(filebuf, sizeof(filebuf), state->fp) == NULL)
   1436 			break;
   1437 
   1438 		ep = strchr(filebuf, '\n');
   1439 		if (ep == NULL) {	/* skip lines that are too big */
   1440 			int ch;
   1441 
   1442 			while ((ch = getc(state->fp)) != '\n' && ch != EOF)
   1443 				continue;
   1444 			continue;
   1445 		}
   1446 		*ep = '\0';				/* clear trailing \n */
   1447 
   1448 		if (filebuf[0] == '+') {		/* parse compat line */
   1449 			if (state->name)
   1450 				free(state->name);
   1451 			state->name = NULL;
   1452 			switch(filebuf[1]) {
   1453 			case ':':
   1454 			case '\0':
   1455 				state->name = strdup("");
   1456 				break;
   1457 			default:
   1458 				ep = strchr(filebuf + 1, ':');
   1459 				if (ep == NULL)
   1460 					break;
   1461 				*ep = '\0';
   1462 				state->name = strdup(filebuf + 1);
   1463 				break;
   1464 			}
   1465 			if (state->name == NULL) {
   1466 				rv = NS_UNAVAIL;
   1467 				break;
   1468 			}
   1469 			continue;
   1470 		}
   1471 
   1472 							/* validate line */
   1473 		if (! _gr_parse(filebuf, grp, buffer, buflen)) {
   1474 			continue;			/* skip bad lines */
   1475 		}
   1476 
   1477  compatgrscan_cmpgrp:
   1478 		if (! search) {				/* just want this one */
   1479 			rv = NS_SUCCESS;
   1480 			break;
   1481 		}
   1482 							/* want specific */
   1483 		if ((name && strcmp(name, grp->gr_name) == 0) ||
   1484 		    (!name && gid == grp->gr_gid)) {
   1485 			rv = NS_SUCCESS;
   1486 			break;
   1487 		}
   1488 
   1489 	}
   1490 
   1491  compatgrscan_out:
   1492 	if (rv != NS_SUCCESS && rv != NS_NOTFOUND)
   1493 		*retval = errno;
   1494 	return rv;
   1495 }
   1496 
   1497 static struct __grstate_compat	_compat_state;
   1498 					/* storage for non _r functions */
   1499 static struct group		_compat_group;
   1500 static char			_compat_groupbuf[_GETGR_R_SIZE_MAX];
   1501 
   1502 /*ARGSUSED*/
   1503 static int
   1504 _compat_setgrent(void *nsrv, void *nscb, va_list ap)
   1505 {
   1506 	static const ns_dtab dtab[] = {
   1507 		NS_FILES_CB(__grbad_compat, "files")
   1508 		NS_DNS_CB(_dns_setgrent, NULL)
   1509 		NS_NIS_CB(_nis_setgrent, NULL)
   1510 		NS_COMPAT_CB(__grbad_compat, "compat")
   1511 		{ 0 }
   1512 	};
   1513 
   1514 					/* force group_compat setgrent() */
   1515 	(void) nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "setgrent",
   1516 	    __nsdefaultnis_forceall);
   1517 
   1518 					/* reset state, keep fp open */
   1519 	_compat_state.stayopen = 0;
   1520 	return __grstart_compat(&_compat_state);
   1521 }
   1522 
   1523 /*ARGSUSED*/
   1524 static int
   1525 _compat_setgroupent(void *nsrv, void *nscb, va_list ap)
   1526 {
   1527 	int	*retval		= va_arg(ap, int *);
   1528 	int	 stayopen	= va_arg(ap, int);
   1529 
   1530 	int	rv;
   1531 
   1532 	static const ns_dtab dtab[] = {
   1533 		NS_FILES_CB(__grbad_compat, "files")
   1534 		NS_DNS_CB(_dns_setgroupent, NULL)
   1535 		NS_NIS_CB(_nis_setgroupent, NULL)
   1536 		NS_COMPAT_CB(__grbad_compat, "compat")
   1537 		{ 0 }
   1538 	};
   1539 
   1540 					/* force group_compat setgroupent() */
   1541 	(void) nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "setgroupent",
   1542 	    __nsdefaultnis_forceall, &rv, stayopen);
   1543 
   1544 	_compat_state.stayopen = stayopen;
   1545 	rv = __grstart_compat(&_compat_state);
   1546 	*retval = (rv == NS_SUCCESS);
   1547 	return rv;
   1548 }
   1549 
   1550 /*ARGSUSED*/
   1551 static int
   1552 _compat_endgrent(void *nsrv, void *nscb, va_list ap)
   1553 {
   1554 	static const ns_dtab dtab[] = {
   1555 		NS_FILES_CB(__grbad_compat, "files")
   1556 		NS_DNS_CB(_dns_endgrent, NULL)
   1557 		NS_NIS_CB(_nis_endgrent, NULL)
   1558 		NS_COMPAT_CB(__grbad_compat, "compat")
   1559 		{ 0 }
   1560 	};
   1561 
   1562 					/* force group_compat endgrent() */
   1563 	(void) nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "endgrent",
   1564 	    __nsdefaultnis_forceall);
   1565 
   1566 					/* reset state, close fp */
   1567 	_compat_state.stayopen = 0;
   1568 	return __grend_compat(&_compat_state);
   1569 }
   1570 
   1571 /*ARGSUSED*/
   1572 static int
   1573 _compat_getgrent(void *nsrv, void *nscb, va_list ap)
   1574 {
   1575 	struct group	**retval = va_arg(ap, struct group **);
   1576 
   1577 	int	rv, rerror;
   1578 
   1579 	_DIAGASSERT(retval != NULL);
   1580 
   1581 	*retval = NULL;
   1582 	rv = __grscan_compat(&rerror, &_compat_group,
   1583 	    _compat_groupbuf, sizeof(_compat_groupbuf),
   1584 	    &_compat_state, 0, NULL, 0, NULL, NULL);
   1585 	if (rv == NS_SUCCESS)
   1586 		*retval = &_compat_group;
   1587 	return rv;
   1588 }
   1589 
   1590 /*ARGSUSED*/
   1591 static int
   1592 _compat_getgrent_r(void *nsrv, void *nscb, va_list ap)
   1593 {
   1594 	int		*retval	= va_arg(ap, int *);
   1595 	struct group	*grp	= va_arg(ap, struct group *);
   1596 	char		*buffer	= va_arg(ap, char *);
   1597 	size_t		 buflen	= va_arg(ap, size_t);
   1598 	struct group   **result	= va_arg(ap, struct group **);
   1599 
   1600 	int	rv;
   1601 
   1602 	_DIAGASSERT(retval != NULL);
   1603 	_DIAGASSERT(grp != NULL);
   1604 	_DIAGASSERT(buffer != NULL);
   1605 	_DIAGASSERT(result != NULL);
   1606 
   1607 	rv = __grscan_compat(retval, grp, buffer, buflen,
   1608 	    &_compat_state, 0, NULL, 0, NULL, NULL);
   1609 	if (rv == NS_SUCCESS)
   1610 		*result = grp;
   1611 	else
   1612 		*result = NULL;
   1613 	return rv;
   1614 }
   1615 
   1616 /*ARGSUSED*/
   1617 static int
   1618 _compat_getgrgid(void *nsrv, void *nscb, va_list ap)
   1619 {
   1620 	struct group	**retval = va_arg(ap, struct group **);
   1621 	gid_t		 gid	= va_arg(ap, gid_t);
   1622 
   1623 	int	rv, rerror;
   1624 
   1625 	_DIAGASSERT(retval != NULL);
   1626 
   1627 	*retval = NULL;
   1628 	rv = __grstart_compat(&_compat_state);
   1629 	if (rv != NS_SUCCESS)
   1630 		return rv;
   1631 	rv = __grscan_compat(&rerror, &_compat_group,
   1632 	    _compat_groupbuf, sizeof(_compat_groupbuf),
   1633 	    &_compat_state, 1, NULL, gid, NULL, NULL);
   1634 	if (!_compat_state.stayopen)
   1635 		__grend_compat(&_compat_state);
   1636 	if (rv == NS_SUCCESS)
   1637 		*retval = &_compat_group;
   1638 	return rv;
   1639 }
   1640 
   1641 /*ARGSUSED*/
   1642 static int
   1643 _compat_getgrgid_r(void *nsrv, void *nscb, va_list ap)
   1644 {
   1645 	int		*retval	= va_arg(ap, int *);
   1646 	gid_t		 gid	= va_arg(ap, gid_t);
   1647 	struct group	*grp	= va_arg(ap, struct group *);
   1648 	char		*buffer	= va_arg(ap, char *);
   1649 	size_t		 buflen	= va_arg(ap, size_t);
   1650 	struct group   **result	= va_arg(ap, struct group **);
   1651 
   1652 	struct __grstate_compat	state;
   1653 	int		rv;
   1654 
   1655 	_DIAGASSERT(retval != NULL);
   1656 	_DIAGASSERT(grp != NULL);
   1657 	_DIAGASSERT(buffer != NULL);
   1658 	_DIAGASSERT(result != NULL);
   1659 
   1660 	*result = NULL;
   1661 	memset(&state, 0, sizeof(state));
   1662 	rv = __grscan_compat(retval, grp, buffer, buflen, &state,
   1663 	    1, NULL, gid, NULL, NULL);
   1664 	__grend_compat(&state);
   1665 	if (rv == NS_SUCCESS)
   1666 		*result = grp;
   1667 	return rv;
   1668 }
   1669 
   1670 /*ARGSUSED*/
   1671 static int
   1672 _compat_getgrnam(void *nsrv, void *nscb, va_list ap)
   1673 {
   1674 	struct group	**retval = va_arg(ap, struct group **);
   1675 	const char	*name	= va_arg(ap, const char *);
   1676 
   1677 	int	rv, rerror;
   1678 
   1679 	_DIAGASSERT(retval != NULL);
   1680 
   1681 	*retval = NULL;
   1682 	rv = __grstart_compat(&_compat_state);
   1683 	if (rv != NS_SUCCESS)
   1684 		return rv;
   1685 	rv = __grscan_compat(&rerror, &_compat_group,
   1686 	    _compat_groupbuf, sizeof(_compat_groupbuf),
   1687 	    &_compat_state, 1, name, 0, NULL, NULL);
   1688 	if (!_compat_state.stayopen)
   1689 		__grend_compat(&_compat_state);
   1690 	if (rv == NS_SUCCESS)
   1691 		*retval = &_compat_group;
   1692 	return rv;
   1693 }
   1694 
   1695 /*ARGSUSED*/
   1696 static int
   1697 _compat_getgrnam_r(void *nsrv, void *nscb, va_list ap)
   1698 {
   1699 	int		*retval	= va_arg(ap, int *);
   1700 	const char	*name	= va_arg(ap, const char *);
   1701 	struct group	*grp	= va_arg(ap, struct group *);
   1702 	char		*buffer	= va_arg(ap, char *);
   1703 	size_t		 buflen	= va_arg(ap, size_t);
   1704 	struct group   **result	= va_arg(ap, struct group **);
   1705 
   1706 	struct __grstate_compat	state;
   1707 	int		rv;
   1708 
   1709 	_DIAGASSERT(retval != NULL);
   1710 	_DIAGASSERT(grp != NULL);
   1711 	_DIAGASSERT(buffer != NULL);
   1712 	_DIAGASSERT(result != NULL);
   1713 
   1714 	*result = NULL;
   1715 	memset(&state, 0, sizeof(state));
   1716 	rv = __grscan_compat(retval, grp, buffer, buflen, &state,
   1717 	    1, name, 0, NULL, NULL);
   1718 	__grend_compat(&state);
   1719 	if (rv == NS_SUCCESS)
   1720 		*result = grp;
   1721 	return rv;
   1722 }
   1723 
   1724 #endif	/* _GROUP_COMPAT */
   1725 
   1726 
   1727 		/*
   1728 		 *	public functions
   1729 		 */
   1730 
   1731 struct group *
   1732 getgrent(void)
   1733 {
   1734 	int		rv;
   1735 	struct group	*retval;
   1736 
   1737 	static const ns_dtab dtab[] = {
   1738 		NS_FILES_CB(_files_getgrent, NULL)
   1739 		NS_DNS_CB(_dns_getgrent, NULL)
   1740 		NS_NIS_CB(_nis_getgrent, NULL)
   1741 		NS_COMPAT_CB(_compat_getgrent, NULL)
   1742 		{ 0 }
   1743 	};
   1744 
   1745 	mutex_lock(&__grmutex);
   1746 	rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrent", __nsdefaultcompat,
   1747 	    &retval);
   1748 	mutex_unlock(&__grmutex);
   1749 	return (rv == NS_SUCCESS) ? retval : NULL;
   1750 }
   1751 
   1752 int
   1753 getgrent_r(struct group *grp, char *buffer, size_t buflen,
   1754     struct group **result)
   1755 {
   1756 	int		rv, retval;
   1757 
   1758 	static const ns_dtab dtab[] = {
   1759 		NS_FILES_CB(_files_getgrent_r, NULL)
   1760 		NS_DNS_CB(_dns_getgrent_r, NULL)
   1761 		NS_NIS_CB(_nis_getgrent_r, NULL)
   1762 		NS_COMPAT_CB(_compat_getgrent_r, NULL)
   1763 		{ 0 }
   1764 	};
   1765 
   1766 	mutex_lock(&__grmutex);
   1767 	rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrent_r", __nsdefaultcompat,
   1768 	    &retval, grp, buffer, buflen, result);
   1769 	mutex_unlock(&__grmutex);
   1770 	switch (rv) {
   1771 	case NS_SUCCESS:
   1772 	case NS_NOTFOUND:
   1773 		return 0;
   1774 	default:
   1775 		return retval;
   1776 	}
   1777 }
   1778 
   1779 
   1780 struct group *
   1781 getgrgid(gid_t gid)
   1782 {
   1783 	int		rv;
   1784 	struct group	*retval;
   1785 
   1786 	static const ns_dtab dtab[] = {
   1787 		NS_FILES_CB(_files_getgrgid, NULL)
   1788 		NS_DNS_CB(_dns_getgrgid, NULL)
   1789 		NS_NIS_CB(_nis_getgrgid, NULL)
   1790 		NS_COMPAT_CB(_compat_getgrgid, NULL)
   1791 		{ 0 }
   1792 	};
   1793 
   1794 	mutex_lock(&__grmutex);
   1795 	rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrgid", __nsdefaultcompat,
   1796 	    &retval, gid);
   1797 	mutex_unlock(&__grmutex);
   1798 	return (rv == NS_SUCCESS) ? retval : NULL;
   1799 }
   1800 
   1801 int
   1802 getgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t buflen,
   1803 	struct group **result)
   1804 {
   1805 	int	rv, retval;
   1806 
   1807 	static const ns_dtab dtab[] = {
   1808 		NS_FILES_CB(_files_getgrgid_r, NULL)
   1809 		NS_DNS_CB(_dns_getgrgid_r, NULL)
   1810 		NS_NIS_CB(_nis_getgrgid_r, NULL)
   1811 		NS_COMPAT_CB(_compat_getgrgid_r, NULL)
   1812 		{ 0 }
   1813 	};
   1814 
   1815 	_DIAGASSERT(grp != NULL);
   1816 	_DIAGASSERT(buffer != NULL);
   1817 	_DIAGASSERT(result != NULL);
   1818 
   1819 	*result = NULL;
   1820 	retval = 0;
   1821 	mutex_lock(&__grmutex);
   1822 	rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrgid_r", __nsdefaultcompat,
   1823 	    &retval, gid, grp, buffer, buflen, result);
   1824 	mutex_unlock(&__grmutex);
   1825 	switch (rv) {
   1826 	case NS_SUCCESS:
   1827 	case NS_NOTFOUND:
   1828 		return 0;
   1829 	default:
   1830 		return retval;
   1831 	}
   1832 }
   1833 
   1834 struct group *
   1835 getgrnam(const char *name)
   1836 {
   1837 	int		rv;
   1838 	struct group	*retval;
   1839 
   1840 	static const ns_dtab dtab[] = {
   1841 		NS_FILES_CB(_files_getgrnam, NULL)
   1842 		NS_DNS_CB(_dns_getgrnam, NULL)
   1843 		NS_NIS_CB(_nis_getgrnam, NULL)
   1844 		NS_COMPAT_CB(_compat_getgrnam, NULL)
   1845 		{ 0 }
   1846 	};
   1847 
   1848 	mutex_lock(&__grmutex);
   1849 	rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrnam", __nsdefaultcompat,
   1850 	    &retval, name);
   1851 	mutex_unlock(&__grmutex);
   1852 	return (rv == NS_SUCCESS) ? retval : NULL;
   1853 }
   1854 
   1855 int
   1856 getgrnam_r(const char *name, struct group *grp, char *buffer, size_t buflen,
   1857 	struct group **result)
   1858 {
   1859 	int	rv, retval;
   1860 
   1861 	static const ns_dtab dtab[] = {
   1862 		NS_FILES_CB(_files_getgrnam_r, NULL)
   1863 		NS_DNS_CB(_dns_getgrnam_r, NULL)
   1864 		NS_NIS_CB(_nis_getgrnam_r, NULL)
   1865 		NS_COMPAT_CB(_compat_getgrnam_r, NULL)
   1866 		{ 0 }
   1867 	};
   1868 
   1869 	_DIAGASSERT(name != NULL);
   1870 	_DIAGASSERT(grp != NULL);
   1871 	_DIAGASSERT(buffer != NULL);
   1872 	_DIAGASSERT(result != NULL);
   1873 
   1874 	*result = NULL;
   1875 	retval = 0;
   1876 	mutex_lock(&__grmutex);
   1877 	rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrnam_r", __nsdefaultcompat,
   1878 	    &retval, name, grp, buffer, buflen, result);
   1879 	mutex_unlock(&__grmutex);
   1880 	switch (rv) {
   1881 	case NS_SUCCESS:
   1882 	case NS_NOTFOUND:
   1883 		return 0;
   1884 	default:
   1885 		return retval;
   1886 	}
   1887 }
   1888 
   1889 void
   1890 endgrent(void)
   1891 {
   1892 	static const ns_dtab dtab[] = {
   1893 		NS_FILES_CB(_files_endgrent, NULL)
   1894 		NS_DNS_CB(_dns_endgrent, NULL)
   1895 		NS_NIS_CB(_nis_endgrent, NULL)
   1896 		NS_COMPAT_CB(_compat_endgrent, NULL)
   1897 		{ 0 }
   1898 	};
   1899 
   1900 	mutex_lock(&__grmutex);
   1901 					/* force all endgrent() methods */
   1902 	(void) nsdispatch(NULL, dtab, NSDB_GROUP, "endgrent",
   1903 	    __nsdefaultcompat_forceall);
   1904 	mutex_unlock(&__grmutex);
   1905 }
   1906 
   1907 int
   1908 setgroupent(int stayopen)
   1909 {
   1910 	static const ns_dtab dtab[] = {
   1911 		NS_FILES_CB(_files_setgroupent, NULL)
   1912 		NS_DNS_CB(_dns_setgroupent, NULL)
   1913 		NS_NIS_CB(_nis_setgroupent, NULL)
   1914 		NS_COMPAT_CB(_compat_setgroupent, NULL)
   1915 		{ 0 }
   1916 	};
   1917 	int	rv, retval;
   1918 
   1919 	mutex_lock(&__grmutex);
   1920 					/* force all setgroupent() methods */
   1921 	rv = nsdispatch(NULL, dtab, NSDB_GROUP, "setgroupent",
   1922 	    __nsdefaultcompat_forceall, &retval, stayopen);
   1923 	mutex_unlock(&__grmutex);
   1924 	return (rv == NS_SUCCESS) ? retval : 0;
   1925 }
   1926 
   1927 void
   1928 setgrent(void)
   1929 {
   1930 	static const ns_dtab dtab[] = {
   1931 		NS_FILES_CB(_files_setgrent, NULL)
   1932 		NS_DNS_CB(_dns_setgrent, NULL)
   1933 		NS_NIS_CB(_nis_setgrent, NULL)
   1934 		NS_COMPAT_CB(_compat_setgrent, NULL)
   1935 		{ 0 }
   1936 	};
   1937 
   1938 	mutex_lock(&__grmutex);
   1939 					/* force all setgrent() methods */
   1940 	(void) nsdispatch(NULL, dtab, NSDB_GROUP, "setgrent",
   1941 	    __nsdefaultcompat_forceall);
   1942 	mutex_unlock(&__grmutex);
   1943 }
   1944