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