Sync usage with man page.
[netbsd-mini2440.git] / lib / libc / gen / getgrent.c
blob890ad838f78730e753d3cccbcb3e64b1420df2af
1 /* $NetBSD: getgrent.c,v 1.61 2007/02/03 16:12:47 christos Exp $ */
3 /*-
4 * Copyright (c) 1999-2000, 2004-2005 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Luke Mewburn.
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.
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.
33 * Copyright (c) 1989, 1993
34 * The Regents of the University of California. All rights reserved.
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.
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.
62 * Portions Copyright (c) 1994, Jason Downs. All Rights Reserved.
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.
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.
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.61 2007/02/03 16:12:47 christos Exp $");
92 #endif
93 #endif /* LIBC_SCCS and not lint */
95 #include "namespace.h"
96 #include "reentrant.h"
98 #include <sys/param.h>
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>
111 #ifdef HESIOD
112 #include <hesiod.h>
113 #endif
115 #ifdef YP
116 #include <rpc/rpc.h>
117 #include <rpcsvc/yp_prot.h>
118 #include <rpcsvc/ypclnt.h>
119 #endif
121 #include "gr_private.h"
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
135 #ifdef _REENTRANT
136 mutex_t __grmutex = MUTEX_INITIALIZER;
137 #endif
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.
145 static char *
146 _gr_memfrombuf(size_t want, char **buffer, size_t *buflen)
148 char *rv;
150 if (want > *buflen) {
151 errno = ERANGE;
152 return NULL;
154 rv = *buffer;
155 *buffer += want;
156 *buflen -= want;
157 return rv;
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.
167 static int
168 _gr_parse(const char *entry, struct group *grp, char *buf, size_t buflen)
170 unsigned long id;
171 const char *bp;
172 char *ep;
173 size_t count;
174 int memc;
176 _DIAGASSERT(entry != NULL);
177 _DIAGASSERT(grp != NULL);
178 _DIAGASSERT(buf != NULL);
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 */
189 #if 0
190 if (*entry == '+') /* fail on compat `+' token */
191 return 0;
192 #endif
194 count = strcspn(entry, ":"); /* parse gr_name */
195 if (entry[count] == '\0')
196 return 0;
197 COPYTOBUF(grp->gr_name);
198 entry += count + 1;
200 count = strcspn(entry, ":"); /* parse gr_passwd */
201 if (entry[count] == '\0')
202 return 0;
203 COPYTOBUF(grp->gr_passwd);
204 entry += count + 1;
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;
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++;
222 /* grab ALIGNed char **gr_mem from buf */
223 ep = _gr_memfrombuf(memc * sizeof(char *) + ALIGNBYTES, &buf, &buflen);
224 grp->gr_mem = (char **)ALIGN(ep);
225 if (grp->gr_mem == NULL)
226 return 0;
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++;
236 #undef COPYTOBUF
238 grp->gr_mem[memc] = NULL;
239 return 1;
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.
249 static int
250 _gr_copy(struct group *fromgrp, struct group *grp, char *buf, size_t buflen)
252 char *ep;
253 int memc;
255 _DIAGASSERT(fromgrp != NULL);
256 _DIAGASSERT(grp != NULL);
257 _DIAGASSERT(buf != NULL);
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 */
269 COPYSTR(grp->gr_name, fromgrp->gr_name);
270 COPYSTR(grp->gr_passwd, fromgrp->gr_passwd);
271 grp->gr_gid = fromgrp->gr_gid;
273 for (memc = 0; fromgrp->gr_mem[memc]; memc++)
274 continue;
275 memc++; /* for final NULL */
277 /* grab ALIGNed char **gr_mem from buf */
278 ep = _gr_memfrombuf(memc * sizeof(char *) + ALIGNBYTES, &buf, &buflen);
279 grp->gr_mem = (char **)ALIGN(ep);
280 if (grp->gr_mem == NULL)
281 return 0;
283 for (memc = 0; fromgrp->gr_mem[memc]; memc++) {
284 COPYSTR(grp->gr_mem[memc], fromgrp->gr_mem[memc]);
287 #undef COPYSTR
289 grp->gr_mem[memc] = NULL;
290 return 1;
294 * files methods
298 __grstart_files(struct __grstate_files *state)
301 _DIAGASSERT(state != NULL);
303 if (state->fp == NULL) {
304 state->fp = fopen(_PATH_GROUP, "r");
305 if (state->fp == NULL)
306 return NS_UNAVAIL;
307 } else {
308 rewind(state->fp);
310 return NS_SUCCESS;
314 __grend_files(struct __grstate_files *state)
317 _DIAGASSERT(state != NULL);
319 if (state->fp) {
320 (void) fclose(state->fp);
321 state->fp = NULL;
323 return NS_SUCCESS;
327 * __grscan_files
328 * Scan state->fp for the next desired entry.
329 * If search is zero, return the next entry.
330 * If search is non-zero, look for a specific name (if name != NULL),
331 * or a specific gid (if name == NULL).
332 * Sets *retval to the errno if the result is not NS_SUCCESS
333 * or NS_NOTFOUND.
336 __grscan_files(int *retval, struct group *grp, char *buffer, size_t buflen,
337 struct __grstate_files *state, int search, const char *name, gid_t gid)
339 int rv;
340 char filebuf[_GETGR_R_SIZE_MAX], *ep;
342 _DIAGASSERT(retval != NULL);
343 _DIAGASSERT(grp != NULL);
344 _DIAGASSERT(buffer != NULL);
345 _DIAGASSERT(state != NULL);
346 /* name is NULL to indicate searching for gid */
348 *retval = 0;
350 if (state->fp == NULL) { /* only start if file not open yet */
351 rv = __grstart_files(state);
352 if (rv != NS_SUCCESS)
353 goto filesgrscan_out;
356 rv = NS_NOTFOUND;
358 /* scan line by line */
359 while (fgets(filebuf, sizeof(filebuf), state->fp) != NULL) {
360 ep = strchr(filebuf, '\n');
361 if (ep == NULL) { /* skip lines that are too big */
362 int ch;
364 while ((ch = getc(state->fp)) != '\n' && ch != EOF)
365 continue;
366 continue;
368 *ep = '\0'; /* clear trailing \n */
370 if (filebuf[0] == '+') /* skip compat line */
371 continue;
373 /* validate line */
374 if (! _gr_parse(filebuf, grp, buffer, buflen)) {
375 continue; /* skip bad lines */
377 if (! search) { /* just want this one */
378 rv = NS_SUCCESS;
379 break;
381 /* want specific */
382 if ((name && strcmp(name, grp->gr_name) == 0) ||
383 (!name && gid == grp->gr_gid)) {
384 rv = NS_SUCCESS;
385 break;
389 filesgrscan_out:
390 if (rv != NS_SUCCESS && rv != NS_NOTFOUND)
391 *retval = errno;
392 return rv;
396 static struct __grstate_files _files_state;
397 /* storage for non _r functions */
398 static struct group _files_group;
399 static char _files_groupbuf[_GETGR_R_SIZE_MAX];
401 /*ARGSUSED*/
402 static int
403 _files_setgrent(void *nsrv, void *nscb, va_list ap)
406 _files_state.stayopen = 0;
407 return __grstart_files(&_files_state);
410 /*ARGSUSED*/
411 static int
412 _files_setgroupent(void *nsrv, void *nscb, va_list ap)
414 int *retval = va_arg(ap, int *);
415 int stayopen = va_arg(ap, int);
417 int rv;
419 _files_state.stayopen = stayopen;
420 rv = __grstart_files(&_files_state);
421 *retval = (rv == NS_SUCCESS);
422 return rv;
425 /*ARGSUSED*/
426 static int
427 _files_endgrent(void *nsrv, void *nscb, va_list ap)
430 _files_state.stayopen = 0;
431 return __grend_files(&_files_state);
434 /*ARGSUSED*/
435 static int
436 _files_getgrent(void *nsrv, void *nscb, va_list ap)
438 struct group **retval = va_arg(ap, struct group **);
440 int rv, rerror;
442 _DIAGASSERT(retval != NULL);
444 *retval = NULL;
445 rv = __grscan_files(&rerror, &_files_group,
446 _files_groupbuf, sizeof(_files_groupbuf),
447 &_files_state, 0, NULL, 0);
448 if (rv == NS_SUCCESS)
449 *retval = &_files_group;
450 return rv;
453 /*ARGSUSED*/
454 static int
455 _files_getgrent_r(void *nsrv, void *nscb, va_list ap)
457 int *retval = va_arg(ap, int *);
458 struct group *grp = va_arg(ap, struct group *);
459 char *buffer = va_arg(ap, char *);
460 size_t buflen = va_arg(ap, size_t);
461 struct group **result = va_arg(ap, struct group **);
463 int rv;
465 _DIAGASSERT(retval != NULL);
466 _DIAGASSERT(grp != NULL);
467 _DIAGASSERT(buffer != NULL);
468 _DIAGASSERT(result != NULL);
470 rv = __grscan_files(retval, grp, buffer, buflen,
471 &_files_state, 0, NULL, 0);
472 if (rv == NS_SUCCESS)
473 *result = grp;
474 else
475 *result = NULL;
476 return rv;
479 /*ARGSUSED*/
480 static int
481 _files_getgrgid(void *nsrv, void *nscb, va_list ap)
483 struct group **retval = va_arg(ap, struct group **);
484 gid_t gid = va_arg(ap, gid_t);
486 int rv, rerror;
488 _DIAGASSERT(retval != NULL);
490 *retval = NULL;
491 rv = __grstart_files(&_files_state);
492 if (rv != NS_SUCCESS)
493 return rv;
494 rv = __grscan_files(&rerror, &_files_group,
495 _files_groupbuf, sizeof(_files_groupbuf),
496 &_files_state, 1, NULL, gid);
497 if (!_files_state.stayopen)
498 __grend_files(&_files_state);
499 if (rv == NS_SUCCESS)
500 *retval = &_files_group;
501 return rv;
504 /*ARGSUSED*/
505 static int
506 _files_getgrgid_r(void *nsrv, void *nscb, va_list ap)
508 int *retval = va_arg(ap, int *);
509 gid_t gid = va_arg(ap, gid_t);
510 struct group *grp = va_arg(ap, struct group *);
511 char *buffer = va_arg(ap, char *);
512 size_t buflen = va_arg(ap, size_t);
513 struct group **result = va_arg(ap, struct group **);
515 struct __grstate_files state;
516 int rv;
518 _DIAGASSERT(retval != NULL);
519 _DIAGASSERT(grp != NULL);
520 _DIAGASSERT(buffer != NULL);
521 _DIAGASSERT(result != NULL);
523 *result = NULL;
524 memset(&state, 0, sizeof(state));
525 rv = __grscan_files(retval, grp, buffer, buflen, &state, 1, NULL, gid);
526 __grend_files(&state);
527 if (rv == NS_SUCCESS)
528 *result = grp;
529 return rv;
532 /*ARGSUSED*/
533 static int
534 _files_getgrnam(void *nsrv, void *nscb, va_list ap)
536 struct group **retval = va_arg(ap, struct group **);
537 const char *name = va_arg(ap, const char *);
539 int rv, rerror;
541 _DIAGASSERT(retval != NULL);
543 *retval = NULL;
544 rv = __grstart_files(&_files_state);
545 if (rv != NS_SUCCESS)
546 return rv;
547 rv = __grscan_files(&rerror, &_files_group,
548 _files_groupbuf, sizeof(_files_groupbuf),
549 &_files_state, 1, name, 0);
550 if (!_files_state.stayopen)
551 __grend_files(&_files_state);
552 if (rv == NS_SUCCESS)
553 *retval = &_files_group;
554 return rv;
557 /*ARGSUSED*/
558 static int
559 _files_getgrnam_r(void *nsrv, void *nscb, va_list ap)
561 int *retval = va_arg(ap, int *);
562 const char *name = va_arg(ap, const char *);
563 struct group *grp = va_arg(ap, struct group *);
564 char *buffer = va_arg(ap, char *);
565 size_t buflen = va_arg(ap, size_t);
566 struct group **result = va_arg(ap, struct group **);
568 struct __grstate_files state;
569 int rv;
571 _DIAGASSERT(retval != NULL);
572 _DIAGASSERT(grp != NULL);
573 _DIAGASSERT(buffer != NULL);
574 _DIAGASSERT(result != NULL);
576 *result = NULL;
577 memset(&state, 0, sizeof(state));
578 rv = __grscan_files(retval, grp, buffer, buflen, &state, 1, name, 0);
579 __grend_files(&state);
580 if (rv == NS_SUCCESS)
581 *result = grp;
582 return rv;
586 #ifdef HESIOD
588 * dns methods
592 __grstart_dns(struct __grstate_dns *state)
595 _DIAGASSERT(state != NULL);
597 state->num = 0;
598 if (state->context == NULL) { /* setup Hesiod */
599 if (hesiod_init(&state->context) == -1)
600 return NS_UNAVAIL;
603 return NS_SUCCESS;
607 __grend_dns(struct __grstate_dns *state)
610 _DIAGASSERT(state != NULL);
612 state->num = 0;
613 if (state->context) {
614 hesiod_end(state->context);
615 state->context = NULL;
617 return NS_SUCCESS;
621 * __grscan_dns
622 * Search Hesiod for the next desired entry.
623 * If search is zero, return the next entry.
624 * If search is non-zero, look for a specific name (if name != NULL),
625 * or a specific gid (if name == NULL).
628 __grscan_dns(int *retval, struct group *grp, char *buffer, size_t buflen,
629 struct __grstate_dns *state, int search, const char *name, gid_t gid)
631 const char **curzone;
632 char **hp, *ep;
633 int rv;
635 static const char *zones_gid_group[] = {
636 "gid",
637 "group",
638 NULL
641 static const char *zones_group[] = {
642 "group",
643 NULL
646 _DIAGASSERT(retval != NULL);
647 _DIAGASSERT(grp != NULL);
648 _DIAGASSERT(buffer != NULL);
649 _DIAGASSERT(state != NULL);
650 /* name is NULL to indicate searching for gid */
652 *retval = 0;
654 if (state->context == NULL) { /* only start if Hesiod not setup */
655 rv = __grstart_dns(state);
656 if (rv != NS_SUCCESS)
657 return rv;
660 next_dns_entry:
661 hp = NULL;
662 rv = NS_NOTFOUND;
664 if (! search) { /* find next entry */
665 if (state->num == -1) /* exhausted search */
666 return NS_NOTFOUND;
667 /* find group-NNN */
668 snprintf(buffer, buflen, "group-%u", state->num);
669 state->num++;
670 curzone = zones_group;
671 } else if (name) { /* find group name */
672 snprintf(buffer, buflen, "%s", name);
673 curzone = zones_group;
674 } else { /* find gid */
675 snprintf(buffer, buflen, "%u", (unsigned int)gid);
676 curzone = zones_gid_group;
679 for (; *curzone; curzone++) { /* search zones */
680 hp = hesiod_resolve(state->context, buffer, *curzone);
681 if (hp != NULL)
682 break;
683 if (errno != ENOENT) {
684 rv = NS_UNAVAIL;
685 goto dnsgrscan_out;
688 if (*curzone == NULL) {
689 if (! search)
690 state->num = -1;
691 goto dnsgrscan_out;
694 if ((ep = strchr(hp[0], '\n')) != NULL)
695 *ep = '\0'; /* clear trailing \n */
696 if (_gr_parse(hp[0], grp, buffer, buflen)) { /* validate line */
697 if (! search) { /* just want this one */
698 rv = NS_SUCCESS;
699 } else if ((name && strcmp(name, grp->gr_name) == 0) ||
700 (!name && gid == grp->gr_gid)) { /* want specific */
701 rv = NS_SUCCESS;
703 } else { /* dodgy entry */
704 if (!search) { /* try again if ! searching */
705 hesiod_free_list(state->context, hp);
706 goto next_dns_entry;
710 dnsgrscan_out:
711 if (rv != NS_SUCCESS && rv != NS_NOTFOUND)
712 *retval = errno;
713 if (hp)
714 hesiod_free_list(state->context, hp);
715 return rv;
718 static struct __grstate_dns _dns_state;
719 /* storage for non _r functions */
720 static struct group _dns_group;
721 static char _dns_groupbuf[_GETGR_R_SIZE_MAX];
723 /*ARGSUSED*/
724 static int
725 _dns_setgrent(void *nsrv, void *nscb, va_list ap)
728 _dns_state.stayopen = 0;
729 return __grstart_dns(&_dns_state);
732 /*ARGSUSED*/
733 static int
734 _dns_setgroupent(void *nsrv, void *nscb, va_list ap)
736 int *retval = va_arg(ap, int *);
737 int stayopen = va_arg(ap, int);
739 int rv;
741 _dns_state.stayopen = stayopen;
742 rv = __grstart_dns(&_dns_state);
743 *retval = (rv == NS_SUCCESS);
744 return rv;
747 /*ARGSUSED*/
748 static int
749 _dns_endgrent(void *nsrv, void *nscb, va_list ap)
752 _dns_state.stayopen = 0;
753 return __grend_dns(&_dns_state);
756 /*ARGSUSED*/
757 static int
758 _dns_getgrent(void *nsrv, void *nscb, va_list ap)
760 struct group **retval = va_arg(ap, struct group **);
762 int rv, rerror;
764 _DIAGASSERT(retval != NULL);
766 *retval = NULL;
767 rv = __grscan_dns(&rerror, &_dns_group,
768 _dns_groupbuf, sizeof(_dns_groupbuf), &_dns_state, 0, NULL, 0);
769 if (rv == NS_SUCCESS)
770 *retval = &_dns_group;
771 return rv;
774 /*ARGSUSED*/
775 static int
776 _dns_getgrent_r(void *nsrv, void *nscb, va_list ap)
778 int *retval = va_arg(ap, int *);
779 struct group *grp = va_arg(ap, struct group *);
780 char *buffer = va_arg(ap, char *);
781 size_t buflen = va_arg(ap, size_t);
782 struct group **result = va_arg(ap, struct group **);
784 int rv;
786 _DIAGASSERT(retval != NULL);
787 _DIAGASSERT(grp != NULL);
788 _DIAGASSERT(buffer != NULL);
789 _DIAGASSERT(result != NULL);
791 rv = __grscan_dns(retval, grp, buffer, buflen,
792 &_dns_state, 0, NULL, 0);
793 if (rv == NS_SUCCESS)
794 *result = grp;
795 else
796 *result = NULL;
797 return rv;
799 /*ARGSUSED*/
800 static int
801 _dns_getgrgid(void *nsrv, void *nscb, va_list ap)
803 struct group **retval = va_arg(ap, struct group **);
804 gid_t gid = va_arg(ap, gid_t);
806 int rv, rerror;
808 _DIAGASSERT(retval != NULL);
810 *retval = NULL;
811 rv = __grstart_dns(&_dns_state);
812 if (rv != NS_SUCCESS)
813 return rv;
814 rv = __grscan_dns(&rerror, &_dns_group,
815 _dns_groupbuf, sizeof(_dns_groupbuf), &_dns_state, 1, NULL, gid);
816 if (!_dns_state.stayopen)
817 __grend_dns(&_dns_state);
818 if (rv == NS_SUCCESS)
819 *retval = &_dns_group;
820 return rv;
823 /*ARGSUSED*/
824 static int
825 _dns_getgrgid_r(void *nsrv, void *nscb, va_list ap)
827 int *retval = va_arg(ap, int *);
828 gid_t gid = va_arg(ap, gid_t);
829 struct group *grp = va_arg(ap, struct group *);
830 char *buffer = va_arg(ap, char *);
831 size_t buflen = va_arg(ap, size_t);
832 struct group **result = va_arg(ap, struct group **);
834 struct __grstate_dns state;
835 int rv;
837 _DIAGASSERT(retval != NULL);
838 _DIAGASSERT(grp != NULL);
839 _DIAGASSERT(buffer != NULL);
840 _DIAGASSERT(result != NULL);
842 *result = NULL;
843 memset(&state, 0, sizeof(state));
844 rv = __grscan_dns(retval, grp, buffer, buflen, &state, 1, NULL, gid);
845 __grend_dns(&state);
846 if (rv == NS_SUCCESS)
847 *result = grp;
848 return rv;
851 /*ARGSUSED*/
852 static int
853 _dns_getgrnam(void *nsrv, void *nscb, va_list ap)
855 struct group **retval = va_arg(ap, struct group **);
856 const char *name = va_arg(ap, const char *);
858 int rv, rerror;
860 _DIAGASSERT(retval != NULL);
862 *retval = NULL;
863 rv = __grstart_dns(&_dns_state);
864 if (rv != NS_SUCCESS)
865 return rv;
866 rv = __grscan_dns(&rerror, &_dns_group,
867 _dns_groupbuf, sizeof(_dns_groupbuf), &_dns_state, 1, name, 0);
868 if (!_dns_state.stayopen)
869 __grend_dns(&_dns_state);
870 if (rv == NS_SUCCESS)
871 *retval = &_dns_group;
872 return rv;
875 /*ARGSUSED*/
876 static int
877 _dns_getgrnam_r(void *nsrv, void *nscb, va_list ap)
879 int *retval = va_arg(ap, int *);
880 const char *name = va_arg(ap, const char *);
881 struct group *grp = va_arg(ap, struct group *);
882 char *buffer = va_arg(ap, char *);
883 size_t buflen = va_arg(ap, size_t);
884 struct group **result = va_arg(ap, struct group **);
886 struct __grstate_dns state;
887 int rv;
889 _DIAGASSERT(retval != NULL);
890 _DIAGASSERT(grp != NULL);
891 _DIAGASSERT(buffer != NULL);
892 _DIAGASSERT(result != NULL);
894 *result = NULL;
895 memset(&state, 0, sizeof(state));
896 rv = __grscan_dns(retval, grp, buffer, buflen, &state, 1, name, 0);
897 __grend_dns(&state);
898 if (rv == NS_SUCCESS)
899 *result = grp;
900 return rv;
903 #endif /* HESIOD */
906 #ifdef YP
908 * nis methods
912 __grstart_nis(struct __grstate_nis *state)
915 _DIAGASSERT(state != NULL);
917 state->done = 0;
918 if (state->current) {
919 free(state->current);
920 state->current = NULL;
922 if (state->domain == NULL) { /* setup NIS */
923 switch (yp_get_default_domain(&state->domain)) {
924 case 0:
925 break;
926 case YPERR_RESRC:
927 return NS_TRYAGAIN;
928 default:
929 return NS_UNAVAIL;
932 return NS_SUCCESS;
936 __grend_nis(struct __grstate_nis *state)
939 _DIAGASSERT(state != NULL);
941 if (state->domain) {
942 state->domain = NULL;
944 state->done = 0;
945 if (state->current) {
946 free(state->current);
947 state->current = NULL;
949 return NS_SUCCESS;
953 * __grscan_nis
954 * Search NIS for the next desired entry.
955 * If search is zero, return the next entry.
956 * If search is non-zero, look for a specific name (if name != NULL),
957 * or a specific gid (if name == NULL).
960 __grscan_nis(int *retval, struct group *grp, char *buffer, size_t buflen,
961 struct __grstate_nis *state, int search, const char *name, gid_t gid)
963 const char *map;
964 char *key, *data;
965 int nisr, rv, keylen, datalen;
967 _DIAGASSERT(retval != NULL);
968 _DIAGASSERT(grp != NULL);
969 _DIAGASSERT(buffer != NULL);
970 _DIAGASSERT(state != NULL);
971 /* name is NULL to indicate searching for gid */
973 *retval = 0;
975 if (state->domain == NULL) { /* only start if NIS not setup */
976 rv = __grstart_nis(state);
977 if (rv != NS_SUCCESS)
978 return rv;
981 next_nis_entry:
982 key = NULL;
983 data = NULL;
984 rv = NS_SUCCESS;
986 if (! search) { /* find next entry */
987 if (state->done) /* exhausted search */
988 return NS_NOTFOUND;
989 map = "group.byname";
990 if (state->current) { /* already searching */
991 nisr = yp_next(state->domain, map,
992 state->current, state->currentlen,
993 &key, &keylen, &data, &datalen);
994 free(state->current);
995 state->current = NULL;
996 switch (nisr) {
997 case 0:
998 state->current = key;
999 state->currentlen = keylen;
1000 key = NULL;
1001 break;
1002 case YPERR_NOMORE:
1003 rv = NS_NOTFOUND;
1004 state->done = 1;
1005 break;
1006 default:
1007 rv = NS_UNAVAIL;
1008 break;
1010 } else { /* new search */
1011 if (yp_first(state->domain, map,
1012 &state->current, &state->currentlen,
1013 &data, &datalen)) {
1014 rv = NS_UNAVAIL;
1017 } else { /* search for specific item */
1018 if (name) { /* find group name */
1019 snprintf(buffer, buflen, "%s", name);
1020 map = "group.byname";
1021 } else { /* find gid */
1022 snprintf(buffer, buflen, "%u", (unsigned int)gid);
1023 map = "group.bygid";
1025 nisr = yp_match(state->domain, map, buffer, (int)strlen(buffer),
1026 &data, &datalen);
1027 switch (nisr) {
1028 case 0:
1029 break;
1030 case YPERR_KEY:
1031 rv = NS_NOTFOUND;
1032 break;
1033 default:
1034 rv = NS_UNAVAIL;
1035 break;
1038 if (rv == NS_SUCCESS) { /* validate data */
1039 data[datalen] = '\0'; /* clear trailing \n */
1040 if (_gr_parse(data, grp, buffer, buflen)) {
1041 if (! search) { /* just want this one */
1042 rv = NS_SUCCESS;
1043 } else if ((name && strcmp(name, grp->gr_name) == 0) ||
1044 (!name && gid == grp->gr_gid)) {
1045 /* want specific */
1046 rv = NS_SUCCESS;
1048 } else { /* dodgy entry */
1049 if (!search) { /* try again if ! searching */
1050 free(data);
1051 goto next_nis_entry;
1056 if (rv != NS_SUCCESS && rv != NS_NOTFOUND)
1057 *retval = errno;
1058 if (key)
1059 free(key);
1060 if (data)
1061 free(data);
1062 return rv;
1065 static struct __grstate_nis _nis_state;
1066 /* storage for non _r functions */
1067 static struct group _nis_group;
1068 static char _nis_groupbuf[_GETGR_R_SIZE_MAX];
1070 /*ARGSUSED*/
1071 static int
1072 _nis_setgrent(void *nsrv, void *nscb, va_list ap)
1075 _nis_state.stayopen = 0;
1076 return __grstart_nis(&_nis_state);
1079 /*ARGSUSED*/
1080 static int
1081 _nis_setgroupent(void *nsrv, void *nscb, va_list ap)
1083 int *retval = va_arg(ap, int *);
1084 int stayopen = va_arg(ap, int);
1086 int rv;
1088 _nis_state.stayopen = stayopen;
1089 rv = __grstart_nis(&_nis_state);
1090 *retval = (rv == NS_SUCCESS);
1091 return rv;
1094 /*ARGSUSED*/
1095 static int
1096 _nis_endgrent(void *nsrv, void *nscb, va_list ap)
1099 return __grend_nis(&_nis_state);
1102 /*ARGSUSED*/
1103 static int
1104 _nis_getgrent(void *nsrv, void *nscb, va_list ap)
1106 struct group **retval = va_arg(ap, struct group **);
1108 int rv, rerror;
1110 _DIAGASSERT(retval != NULL);
1112 *retval = NULL;
1113 rv = __grscan_nis(&rerror, &_nis_group,
1114 _nis_groupbuf, sizeof(_nis_groupbuf), &_nis_state, 0, NULL, 0);
1115 if (rv == NS_SUCCESS)
1116 *retval = &_nis_group;
1117 return rv;
1120 /*ARGSUSED*/
1121 static int
1122 _nis_getgrent_r(void *nsrv, void *nscb, va_list ap)
1124 int *retval = va_arg(ap, int *);
1125 struct group *grp = va_arg(ap, struct group *);
1126 char *buffer = va_arg(ap, char *);
1127 size_t buflen = va_arg(ap, size_t);
1128 struct group **result = va_arg(ap, struct group **);
1130 int rv;
1132 _DIAGASSERT(retval != NULL);
1133 _DIAGASSERT(grp != NULL);
1134 _DIAGASSERT(buffer != NULL);
1135 _DIAGASSERT(result != NULL);
1137 rv = __grscan_nis(retval, grp, buffer, buflen,
1138 &_nis_state, 0, NULL, 0);
1139 if (rv == NS_SUCCESS)
1140 *result = grp;
1141 else
1142 *result = NULL;
1143 return rv;
1146 /*ARGSUSED*/
1147 static int
1148 _nis_getgrgid(void *nsrv, void *nscb, va_list ap)
1150 struct group **retval = va_arg(ap, struct group **);
1151 gid_t gid = va_arg(ap, gid_t);
1153 int rv, rerror;
1155 _DIAGASSERT(retval != NULL);
1157 *retval = NULL;
1158 rv = __grstart_nis(&_nis_state);
1159 if (rv != NS_SUCCESS)
1160 return rv;
1161 rv = __grscan_nis(&rerror, &_nis_group,
1162 _nis_groupbuf, sizeof(_nis_groupbuf), &_nis_state, 1, NULL, gid);
1163 if (!_nis_state.stayopen)
1164 __grend_nis(&_nis_state);
1165 if (rv == NS_SUCCESS)
1166 *retval = &_nis_group;
1167 return rv;
1170 /*ARGSUSED*/
1171 static int
1172 _nis_getgrgid_r(void *nsrv, void *nscb, va_list ap)
1174 int *retval = va_arg(ap, int *);
1175 gid_t gid = va_arg(ap, gid_t);
1176 struct group *grp = va_arg(ap, struct group *);
1177 char *buffer = va_arg(ap, char *);
1178 size_t buflen = va_arg(ap, size_t);
1179 struct group **result = va_arg(ap, struct group **);
1181 struct __grstate_nis state;
1182 int rv;
1184 _DIAGASSERT(retval != NULL);
1185 _DIAGASSERT(grp != NULL);
1186 _DIAGASSERT(buffer != NULL);
1187 _DIAGASSERT(result != NULL);
1189 *result = NULL;
1190 memset(&state, 0, sizeof(state));
1191 rv = __grscan_nis(retval, grp, buffer, buflen, &state, 1, NULL, gid);
1192 __grend_nis(&state);
1193 if (rv == NS_SUCCESS)
1194 *result = grp;
1195 return rv;
1198 /*ARGSUSED*/
1199 static int
1200 _nis_getgrnam(void *nsrv, void *nscb, va_list ap)
1202 struct group **retval = va_arg(ap, struct group **);
1203 const char *name = va_arg(ap, const char *);
1205 int rv, rerror;
1207 _DIAGASSERT(retval != NULL);
1209 *retval = NULL;
1210 rv = __grstart_nis(&_nis_state);
1211 if (rv != NS_SUCCESS)
1212 return rv;
1213 rv = __grscan_nis(&rerror, &_nis_group,
1214 _nis_groupbuf, sizeof(_nis_groupbuf), &_nis_state, 1, name, 0);
1215 if (!_nis_state.stayopen)
1216 __grend_nis(&_nis_state);
1217 if (rv == NS_SUCCESS)
1218 *retval = &_nis_group;
1219 return rv;
1222 /*ARGSUSED*/
1223 static int
1224 _nis_getgrnam_r(void *nsrv, void *nscb, va_list ap)
1226 int *retval = va_arg(ap, int *);
1227 const char *name = va_arg(ap, const char *);
1228 struct group *grp = va_arg(ap, struct group *);
1229 char *buffer = va_arg(ap, char *);
1230 size_t buflen = va_arg(ap, size_t);
1231 struct group **result = va_arg(ap, struct group **);
1233 struct __grstate_nis state;
1234 int rv;
1236 _DIAGASSERT(retval != NULL);
1237 _DIAGASSERT(grp != NULL);
1238 _DIAGASSERT(buffer != NULL);
1239 _DIAGASSERT(result != NULL);
1241 *result = NULL;
1242 memset(&state, 0, sizeof(state));
1243 rv = __grscan_nis(retval, grp, buffer, buflen, &state, 1, name, 0);
1244 __grend_nis(&state);
1245 if (rv == NS_SUCCESS)
1246 *result = grp;
1247 return rv;
1250 #endif /* YP */
1253 #ifdef _GROUP_COMPAT
1255 * compat methods
1259 __grstart_compat(struct __grstate_compat *state)
1262 _DIAGASSERT(state != NULL);
1264 if (state->fp == NULL) {
1265 state->fp = fopen(_PATH_GROUP, "r");
1266 if (state->fp == NULL)
1267 return NS_UNAVAIL;
1268 } else {
1269 rewind(state->fp);
1271 return NS_SUCCESS;
1275 __grend_compat(struct __grstate_compat *state)
1278 _DIAGASSERT(state != NULL);
1280 if (state->name) {
1281 free(state->name);
1282 state->name = NULL;
1284 if (state->fp) {
1285 (void) fclose(state->fp);
1286 state->fp = NULL;
1288 return NS_SUCCESS;
1293 * __grbad_compat
1294 * log an error if "files" or "compat" is specified in
1295 * group_compat database
1297 /*ARGSUSED*/
1299 __grbad_compat(void *nsrv, void *nscb, va_list ap)
1301 static int warned;
1303 _DIAGASSERT(nsrv != NULL);
1304 _DIAGASSERT(nscb != NULL);
1306 if (!warned) {
1307 syslog(LOG_ERR,
1308 "nsswitch.conf group_compat database can't use '%s'",
1309 (const char *)nscb);
1311 warned = 1;
1312 return NS_UNAVAIL;
1316 * __grscan_compat
1317 * Scan state->fp for the next desired entry.
1318 * If search is zero, return the next entry.
1319 * If search is non-zero, look for a specific name (if name != NULL),
1320 * or a specific gid (if name == NULL).
1321 * Sets *retval to the errno if the result is not NS_SUCCESS or
1322 * NS_NOTFOUND.
1324 * searchfunc is invoked when a compat "+" lookup is required;
1325 * searchcookie is passed as the first argument to searchfunc,
1326 * the second argument is the group result.
1327 * This should return NS_NOTFOUND when "no more groups" from compat src.
1328 * If searchfunc is NULL then nsdispatch of getgrent is used.
1329 * This is primarily intended for getgroupmembership(3)'s compat backend.
1332 __grscan_compat(int *retval, struct group *grp, char *buffer, size_t buflen,
1333 struct __grstate_compat *state, int search, const char *name, gid_t gid,
1334 int (*searchfunc)(void *, struct group **), void *searchcookie)
1336 int rv;
1337 char filebuf[_GETGR_R_SIZE_MAX], *ep;
1339 static const ns_dtab compatentdtab[] = {
1340 NS_FILES_CB(__grbad_compat, "files")
1341 NS_DNS_CB(_dns_getgrent_r, NULL)
1342 NS_NIS_CB(_nis_getgrent_r, NULL)
1343 NS_COMPAT_CB(__grbad_compat, "compat")
1344 NS_NULL_CB
1346 static const ns_dtab compatgiddtab[] = {
1347 NS_FILES_CB(__grbad_compat, "files")
1348 NS_DNS_CB(_dns_getgrgid_r, NULL)
1349 NS_NIS_CB(_nis_getgrgid_r, NULL)
1350 NS_COMPAT_CB(__grbad_compat, "compat")
1351 NS_NULL_CB
1353 static const ns_dtab compatnamdtab[] = {
1354 NS_FILES_CB(__grbad_compat, "files")
1355 NS_DNS_CB(_dns_getgrnam_r, NULL)
1356 NS_NIS_CB(_nis_getgrnam_r, NULL)
1357 NS_COMPAT_CB(__grbad_compat, "compat")
1358 NS_NULL_CB
1361 _DIAGASSERT(retval != NULL);
1362 _DIAGASSERT(grp != NULL);
1363 _DIAGASSERT(buffer != NULL);
1364 _DIAGASSERT(state != NULL);
1365 /* name is NULL to indicate searching for gid */
1367 *retval = 0;
1369 if (state->fp == NULL) { /* only start if file not open yet */
1370 rv = __grstart_compat(state);
1371 if (rv != NS_SUCCESS)
1372 goto compatgrscan_out;
1374 rv = NS_NOTFOUND;
1376 for (;;) { /* loop through file */
1377 if (state->name != NULL) {
1378 /* processing compat entry */
1379 int crv, cretval;
1380 struct group cgrp, *cgrpres;
1382 if (state->name[0]) { /* specific +group: */
1383 crv = nsdispatch(NULL, compatnamdtab,
1384 NSDB_GROUP_COMPAT, "getgrnam_r",
1385 __nsdefaultnis,
1386 &cretval, state->name,
1387 &cgrp, filebuf, sizeof(filebuf), &cgrpres);
1388 free(state->name); /* (only check 1 grp) */
1389 state->name = NULL;
1390 } else if (!search) { /* any group */
1391 if (searchfunc) {
1392 crv = searchfunc(searchcookie,
1393 &cgrpres);
1394 } else {
1395 crv = nsdispatch(NULL, compatentdtab,
1396 NSDB_GROUP_COMPAT, "getgrent_r",
1397 __nsdefaultnis,
1398 &cretval, &cgrp, filebuf,
1399 sizeof(filebuf), &cgrpres);
1401 } else if (name) { /* specific group */
1402 crv = nsdispatch(NULL, compatnamdtab,
1403 NSDB_GROUP_COMPAT, "getgrnam_r",
1404 __nsdefaultnis,
1405 &cretval, name,
1406 &cgrp, filebuf, sizeof(filebuf), &cgrpres);
1407 } else { /* specific gid */
1408 crv = nsdispatch(NULL, compatgiddtab,
1409 NSDB_GROUP_COMPAT, "getgrgid_r",
1410 __nsdefaultnis,
1411 &cretval, gid,
1412 &cgrp, filebuf, sizeof(filebuf), &cgrpres);
1414 if (crv != NS_SUCCESS) { /* not found */
1415 free(state->name);
1416 state->name = NULL;
1417 continue; /* try next line */
1419 if (!_gr_copy(cgrpres, grp, buffer, buflen)) {
1420 rv = NS_UNAVAIL;
1421 break;
1423 goto compatgrscan_cmpgrp; /* skip to grp test */
1426 /* get next file line */
1427 if (fgets(filebuf, sizeof(filebuf), state->fp) == NULL)
1428 break;
1430 ep = strchr(filebuf, '\n');
1431 if (ep == NULL) { /* skip lines that are too big */
1432 int ch;
1434 while ((ch = getc(state->fp)) != '\n' && ch != EOF)
1435 continue;
1436 continue;
1438 *ep = '\0'; /* clear trailing \n */
1440 if (filebuf[0] == '+') { /* parse compat line */
1441 if (state->name)
1442 free(state->name);
1443 state->name = NULL;
1444 switch(filebuf[1]) {
1445 case ':':
1446 case '\0':
1447 state->name = strdup("");
1448 break;
1449 default:
1450 ep = strchr(filebuf + 1, ':');
1451 if (ep == NULL)
1452 break;
1453 *ep = '\0';
1454 state->name = strdup(filebuf + 1);
1455 break;
1457 if (state->name == NULL) {
1458 rv = NS_UNAVAIL;
1459 break;
1461 continue;
1464 /* validate line */
1465 if (! _gr_parse(filebuf, grp, buffer, buflen)) {
1466 continue; /* skip bad lines */
1469 compatgrscan_cmpgrp:
1470 if (! search) { /* just want this one */
1471 rv = NS_SUCCESS;
1472 break;
1474 /* want specific */
1475 if ((name && strcmp(name, grp->gr_name) == 0) ||
1476 (!name && gid == grp->gr_gid)) {
1477 rv = NS_SUCCESS;
1478 break;
1483 compatgrscan_out:
1484 if (rv != NS_SUCCESS && rv != NS_NOTFOUND)
1485 *retval = errno;
1486 return rv;
1489 static struct __grstate_compat _compat_state;
1490 /* storage for non _r functions */
1491 static struct group _compat_group;
1492 static char _compat_groupbuf[_GETGR_R_SIZE_MAX];
1494 /*ARGSUSED*/
1495 static int
1496 _compat_setgrent(void *nsrv, void *nscb, va_list ap)
1498 static const ns_dtab dtab[] = {
1499 NS_FILES_CB(__grbad_compat, "files")
1500 NS_DNS_CB(_dns_setgrent, NULL)
1501 NS_NIS_CB(_nis_setgrent, NULL)
1502 NS_COMPAT_CB(__grbad_compat, "compat")
1503 NS_NULL_CB
1506 /* force group_compat setgrent() */
1507 (void) nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "setgrent",
1508 __nsdefaultnis_forceall);
1510 /* reset state, keep fp open */
1511 _compat_state.stayopen = 0;
1512 return __grstart_compat(&_compat_state);
1515 /*ARGSUSED*/
1516 static int
1517 _compat_setgroupent(void *nsrv, void *nscb, va_list ap)
1519 int *retval = va_arg(ap, int *);
1520 int stayopen = va_arg(ap, int);
1522 int rv;
1524 static const ns_dtab dtab[] = {
1525 NS_FILES_CB(__grbad_compat, "files")
1526 NS_DNS_CB(_dns_setgroupent, NULL)
1527 NS_NIS_CB(_nis_setgroupent, NULL)
1528 NS_COMPAT_CB(__grbad_compat, "compat")
1529 NS_NULL_CB
1532 /* force group_compat setgroupent() */
1533 (void) nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "setgroupent",
1534 __nsdefaultnis_forceall, &rv, stayopen);
1536 _compat_state.stayopen = stayopen;
1537 rv = __grstart_compat(&_compat_state);
1538 *retval = (rv == NS_SUCCESS);
1539 return rv;
1542 /*ARGSUSED*/
1543 static int
1544 _compat_endgrent(void *nsrv, void *nscb, va_list ap)
1546 static const ns_dtab dtab[] = {
1547 NS_FILES_CB(__grbad_compat, "files")
1548 NS_DNS_CB(_dns_endgrent, NULL)
1549 NS_NIS_CB(_nis_endgrent, NULL)
1550 NS_COMPAT_CB(__grbad_compat, "compat")
1551 NS_NULL_CB
1554 /* force group_compat endgrent() */
1555 (void) nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "endgrent",
1556 __nsdefaultnis_forceall);
1558 /* reset state, close fp */
1559 _compat_state.stayopen = 0;
1560 return __grend_compat(&_compat_state);
1563 /*ARGSUSED*/
1564 static int
1565 _compat_getgrent(void *nsrv, void *nscb, va_list ap)
1567 struct group **retval = va_arg(ap, struct group **);
1569 int rv, rerror;
1571 _DIAGASSERT(retval != NULL);
1573 *retval = NULL;
1574 rv = __grscan_compat(&rerror, &_compat_group,
1575 _compat_groupbuf, sizeof(_compat_groupbuf),
1576 &_compat_state, 0, NULL, 0, NULL, NULL);
1577 if (rv == NS_SUCCESS)
1578 *retval = &_compat_group;
1579 return rv;
1582 /*ARGSUSED*/
1583 static int
1584 _compat_getgrent_r(void *nsrv, void *nscb, va_list ap)
1586 int *retval = va_arg(ap, int *);
1587 struct group *grp = va_arg(ap, struct group *);
1588 char *buffer = va_arg(ap, char *);
1589 size_t buflen = va_arg(ap, size_t);
1590 struct group **result = va_arg(ap, struct group **);
1592 int rv;
1594 _DIAGASSERT(retval != NULL);
1595 _DIAGASSERT(grp != NULL);
1596 _DIAGASSERT(buffer != NULL);
1597 _DIAGASSERT(result != NULL);
1599 rv = __grscan_compat(retval, grp, buffer, buflen,
1600 &_compat_state, 0, NULL, 0, NULL, NULL);
1601 if (rv == NS_SUCCESS)
1602 *result = grp;
1603 else
1604 *result = NULL;
1605 return rv;
1608 /*ARGSUSED*/
1609 static int
1610 _compat_getgrgid(void *nsrv, void *nscb, va_list ap)
1612 struct group **retval = va_arg(ap, struct group **);
1613 gid_t gid = va_arg(ap, gid_t);
1615 int rv, rerror;
1617 _DIAGASSERT(retval != NULL);
1619 *retval = NULL;
1620 rv = __grstart_compat(&_compat_state);
1621 if (rv != NS_SUCCESS)
1622 return rv;
1623 rv = __grscan_compat(&rerror, &_compat_group,
1624 _compat_groupbuf, sizeof(_compat_groupbuf),
1625 &_compat_state, 1, NULL, gid, NULL, NULL);
1626 if (!_compat_state.stayopen)
1627 __grend_compat(&_compat_state);
1628 if (rv == NS_SUCCESS)
1629 *retval = &_compat_group;
1630 return rv;
1633 /*ARGSUSED*/
1634 static int
1635 _compat_getgrgid_r(void *nsrv, void *nscb, va_list ap)
1637 int *retval = va_arg(ap, int *);
1638 gid_t gid = va_arg(ap, gid_t);
1639 struct group *grp = va_arg(ap, struct group *);
1640 char *buffer = va_arg(ap, char *);
1641 size_t buflen = va_arg(ap, size_t);
1642 struct group **result = va_arg(ap, struct group **);
1644 struct __grstate_compat state;
1645 int rv;
1647 _DIAGASSERT(retval != NULL);
1648 _DIAGASSERT(grp != NULL);
1649 _DIAGASSERT(buffer != NULL);
1650 _DIAGASSERT(result != NULL);
1652 *result = NULL;
1653 memset(&state, 0, sizeof(state));
1654 rv = __grscan_compat(retval, grp, buffer, buflen, &state,
1655 1, NULL, gid, NULL, NULL);
1656 __grend_compat(&state);
1657 if (rv == NS_SUCCESS)
1658 *result = grp;
1659 return rv;
1662 /*ARGSUSED*/
1663 static int
1664 _compat_getgrnam(void *nsrv, void *nscb, va_list ap)
1666 struct group **retval = va_arg(ap, struct group **);
1667 const char *name = va_arg(ap, const char *);
1669 int rv, rerror;
1671 _DIAGASSERT(retval != NULL);
1673 *retval = NULL;
1674 rv = __grstart_compat(&_compat_state);
1675 if (rv != NS_SUCCESS)
1676 return rv;
1677 rv = __grscan_compat(&rerror, &_compat_group,
1678 _compat_groupbuf, sizeof(_compat_groupbuf),
1679 &_compat_state, 1, name, 0, NULL, NULL);
1680 if (!_compat_state.stayopen)
1681 __grend_compat(&_compat_state);
1682 if (rv == NS_SUCCESS)
1683 *retval = &_compat_group;
1684 return rv;
1687 /*ARGSUSED*/
1688 static int
1689 _compat_getgrnam_r(void *nsrv, void *nscb, va_list ap)
1691 int *retval = va_arg(ap, int *);
1692 const char *name = va_arg(ap, const char *);
1693 struct group *grp = va_arg(ap, struct group *);
1694 char *buffer = va_arg(ap, char *);
1695 size_t buflen = va_arg(ap, size_t);
1696 struct group **result = va_arg(ap, struct group **);
1698 struct __grstate_compat state;
1699 int rv;
1701 _DIAGASSERT(retval != NULL);
1702 _DIAGASSERT(grp != NULL);
1703 _DIAGASSERT(buffer != NULL);
1704 _DIAGASSERT(result != NULL);
1706 *result = NULL;
1707 memset(&state, 0, sizeof(state));
1708 rv = __grscan_compat(retval, grp, buffer, buflen, &state,
1709 1, name, 0, NULL, NULL);
1710 __grend_compat(&state);
1711 if (rv == NS_SUCCESS)
1712 *result = grp;
1713 return rv;
1716 #endif /* _GROUP_COMPAT */
1720 * public functions
1723 struct group *
1724 getgrent(void)
1726 int rv;
1727 struct group *retval;
1729 static const ns_dtab dtab[] = {
1730 NS_FILES_CB(_files_getgrent, NULL)
1731 NS_DNS_CB(_dns_getgrent, NULL)
1732 NS_NIS_CB(_nis_getgrent, NULL)
1733 NS_COMPAT_CB(_compat_getgrent, NULL)
1734 NS_NULL_CB
1737 mutex_lock(&__grmutex);
1738 rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrent", __nsdefaultcompat,
1739 &retval);
1740 mutex_unlock(&__grmutex);
1741 return (rv == NS_SUCCESS) ? retval : NULL;
1745 getgrent_r(struct group *grp, char *buffer, size_t buflen,
1746 struct group **result)
1748 int rv, retval;
1750 static const ns_dtab dtab[] = {
1751 NS_FILES_CB(_files_getgrent_r, NULL)
1752 NS_DNS_CB(_dns_getgrent_r, NULL)
1753 NS_NIS_CB(_nis_getgrent_r, NULL)
1754 NS_COMPAT_CB(_compat_getgrent_r, NULL)
1755 NS_NULL_CB
1758 mutex_lock(&__grmutex);
1759 rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrent_r", __nsdefaultcompat,
1760 &retval, grp, buffer, buflen, result);
1761 mutex_unlock(&__grmutex);
1762 switch (rv) {
1763 case NS_SUCCESS:
1764 case NS_NOTFOUND:
1765 return 0;
1766 default:
1767 return retval;
1772 struct group *
1773 getgrgid(gid_t gid)
1775 int rv;
1776 struct group *retval;
1778 static const ns_dtab dtab[] = {
1779 NS_FILES_CB(_files_getgrgid, NULL)
1780 NS_DNS_CB(_dns_getgrgid, NULL)
1781 NS_NIS_CB(_nis_getgrgid, NULL)
1782 NS_COMPAT_CB(_compat_getgrgid, NULL)
1783 NS_NULL_CB
1786 mutex_lock(&__grmutex);
1787 rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrgid", __nsdefaultcompat,
1788 &retval, gid);
1789 mutex_unlock(&__grmutex);
1790 return (rv == NS_SUCCESS) ? retval : NULL;
1794 getgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t buflen,
1795 struct group **result)
1797 int rv, retval;
1799 static const ns_dtab dtab[] = {
1800 NS_FILES_CB(_files_getgrgid_r, NULL)
1801 NS_DNS_CB(_dns_getgrgid_r, NULL)
1802 NS_NIS_CB(_nis_getgrgid_r, NULL)
1803 NS_COMPAT_CB(_compat_getgrgid_r, NULL)
1804 NS_NULL_CB
1807 _DIAGASSERT(grp != NULL);
1808 _DIAGASSERT(buffer != NULL);
1809 _DIAGASSERT(result != NULL);
1811 *result = NULL;
1812 retval = 0;
1813 mutex_lock(&__grmutex);
1814 rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrgid_r", __nsdefaultcompat,
1815 &retval, gid, grp, buffer, buflen, result);
1816 mutex_unlock(&__grmutex);
1817 switch (rv) {
1818 case NS_SUCCESS:
1819 case NS_NOTFOUND:
1820 return 0;
1821 default:
1822 return retval;
1826 struct group *
1827 getgrnam(const char *name)
1829 int rv;
1830 struct group *retval;
1832 static const ns_dtab dtab[] = {
1833 NS_FILES_CB(_files_getgrnam, NULL)
1834 NS_DNS_CB(_dns_getgrnam, NULL)
1835 NS_NIS_CB(_nis_getgrnam, NULL)
1836 NS_COMPAT_CB(_compat_getgrnam, NULL)
1837 NS_NULL_CB
1840 mutex_lock(&__grmutex);
1841 rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrnam", __nsdefaultcompat,
1842 &retval, name);
1843 mutex_unlock(&__grmutex);
1844 return (rv == NS_SUCCESS) ? retval : NULL;
1848 getgrnam_r(const char *name, struct group *grp, char *buffer, size_t buflen,
1849 struct group **result)
1851 int rv, retval;
1853 static const ns_dtab dtab[] = {
1854 NS_FILES_CB(_files_getgrnam_r, NULL)
1855 NS_DNS_CB(_dns_getgrnam_r, NULL)
1856 NS_NIS_CB(_nis_getgrnam_r, NULL)
1857 NS_COMPAT_CB(_compat_getgrnam_r, NULL)
1858 NS_NULL_CB
1861 _DIAGASSERT(name != NULL);
1862 _DIAGASSERT(grp != NULL);
1863 _DIAGASSERT(buffer != NULL);
1864 _DIAGASSERT(result != NULL);
1866 *result = NULL;
1867 retval = 0;
1868 mutex_lock(&__grmutex);
1869 rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrnam_r", __nsdefaultcompat,
1870 &retval, name, grp, buffer, buflen, result);
1871 mutex_unlock(&__grmutex);
1872 switch (rv) {
1873 case NS_SUCCESS:
1874 case NS_NOTFOUND:
1875 return 0;
1876 default:
1877 return retval;
1881 void
1882 endgrent(void)
1884 static const ns_dtab dtab[] = {
1885 NS_FILES_CB(_files_endgrent, NULL)
1886 NS_DNS_CB(_dns_endgrent, NULL)
1887 NS_NIS_CB(_nis_endgrent, NULL)
1888 NS_COMPAT_CB(_compat_endgrent, NULL)
1889 NS_NULL_CB
1892 mutex_lock(&__grmutex);
1893 /* force all endgrent() methods */
1894 (void) nsdispatch(NULL, dtab, NSDB_GROUP, "endgrent",
1895 __nsdefaultcompat_forceall);
1896 mutex_unlock(&__grmutex);
1900 setgroupent(int stayopen)
1902 static const ns_dtab dtab[] = {
1903 NS_FILES_CB(_files_setgroupent, NULL)
1904 NS_DNS_CB(_dns_setgroupent, NULL)
1905 NS_NIS_CB(_nis_setgroupent, NULL)
1906 NS_COMPAT_CB(_compat_setgroupent, NULL)
1907 NS_NULL_CB
1909 int rv, retval;
1911 mutex_lock(&__grmutex);
1912 /* force all setgroupent() methods */
1913 rv = nsdispatch(NULL, dtab, NSDB_GROUP, "setgroupent",
1914 __nsdefaultcompat_forceall, &retval, stayopen);
1915 mutex_unlock(&__grmutex);
1916 return (rv == NS_SUCCESS) ? retval : 0;
1919 void
1920 setgrent(void)
1922 static const ns_dtab dtab[] = {
1923 NS_FILES_CB(_files_setgrent, NULL)
1924 NS_DNS_CB(_dns_setgrent, NULL)
1925 NS_NIS_CB(_nis_setgrent, NULL)
1926 NS_COMPAT_CB(_compat_setgrent, NULL)
1927 NS_NULL_CB
1930 mutex_lock(&__grmutex);
1931 /* force all setgrent() methods */
1932 (void) nsdispatch(NULL, dtab, NSDB_GROUP, "setgrent",
1933 __nsdefaultcompat_forceall);
1934 mutex_unlock(&__grmutex);