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