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