getgrent.c revision 1.49 1 /* $NetBSD: getgrent.c,v 1.49 2004/10/04 04:11:33 lukem Exp $ */
2
3 /*-
4 * Copyright (c) 1999, 2000, 2004 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.49 2004/10/04 04:11:33 lukem Exp $");
99 #endif
100 #endif /* LIBC_SCCS and not lint */
101
102 #include "namespace.h"
103
104 #include <sys/param.h>
105
106 #include <assert.h>
107 #include <errno.h>
108 #include <grp.h>
109 #include <limits.h>
110 #include <nsswitch.h>
111 #include <stdio.h>
112 #include <stdlib.h>
113 #include <string.h>
114 #include <syslog.h>
115
116 #include <stdarg.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 #define _GROUP_COMPAT /* "group" defaults to compat, so always provide it */
129
130 #define GETGR_R_SIZE_MAX 1024 /* XXXLUKEM: move to {grp,unistd}.h ? */
131
132 #ifdef __weak_alias
133 __weak_alias(endgrent,_endgrent)
134 __weak_alias(getgrent,_getgrent)
135 __weak_alias(getgrgid,_getgrgid)
136 __weak_alias(getgrgid_r,_getgrgid_r)
137 __weak_alias(getgrnam,_getgrnam)
138 __weak_alias(getgrnam_r,_getgrnam_r)
139 __weak_alias(setgrent,_setgrent)
140 __weak_alias(setgroupent,_setgroupent)
141 #endif
142
143 static const ns_src defaultcompat[] = {
144 { NSSRC_COMPAT, NS_SUCCESS },
145 { 0 }
146 };
147
148 static const ns_src defaultcompat_forceall[] = {
149 { NSSRC_COMPAT, NS_SUCCESS | NS_FORCEALL },
150 { 0 }
151 };
152
153 static const ns_src defaultnis[] = {
154 { NSSRC_NIS, NS_SUCCESS },
155 { 0 }
156 };
157
158 static const ns_src defaultnis_forceall[] = {
159 { NSSRC_NIS, NS_SUCCESS | NS_FORCEALL },
160 { 0 }
161 };
162
163
164 /*
165 * _gr_memfrombuf
166 * Obtain want bytes from buffer (of size buflen) and return a pointer
167 * to the available memory after adjusting buffer/buflen.
168 * Returns NULL if there is insufficient space.
169 */
170 static char *
171 _gr_memfrombuf(size_t want, char **buffer, size_t *buflen)
172 {
173 char *rv;
174
175 if (want > *buflen) {
176 errno = ERANGE;
177 return NULL;
178 }
179 rv = *buffer;
180 *buffer += want;
181 *buflen -= want;
182 return rv;
183 }
184
185 /*
186 * _gr_parse
187 * Parses entry as a line per group(5) (without the trailing \n)
188 * and fills in grp with corresponding values; memory for strings
189 * and arrays will be allocated from buf (of size buflen).
190 * Returns 1 if parsed successfully, 0 on parse failure.
191 */
192 static int
193 _gr_parse(const char *entry, struct group *grp, char *buf, size_t buflen)
194 {
195 unsigned long id;
196 const char *bp;
197 char *ep;
198 size_t count;
199 int memc;
200
201 _DIAGASSERT(entry != NULL);
202 _DIAGASSERT(grp != NULL);
203 _DIAGASSERT(buf != NULL);
204
205 #define COPYTOBUF(to) \
206 do { \
207 (to) = _gr_memfrombuf(count+1, &buf, &buflen); \
208 if ((to) == NULL) \
209 return 0; \
210 memmove((to), entry, count); \
211 to[count] = '\0'; \
212 } while (0) /* LINTED */
213
214 #if 0
215 if (*entry == '+') /* fail on compat `+' token */
216 return 0;
217 #endif
218
219 count = strcspn(entry, ":"); /* parse gr_name */
220 if (entry[count] == '\0')
221 return 0;
222 COPYTOBUF(grp->gr_name);
223 entry += count + 1;
224
225 count = strcspn(entry, ":"); /* parse gr_passwd */
226 if (entry[count] == '\0')
227 return 0;
228 COPYTOBUF(grp->gr_passwd);
229 entry += count + 1;
230
231 count = strcspn(entry, ":"); /* parse gr_gid */
232 if (entry[count] == '\0')
233 return 0;
234 id = strtoul(entry, &ep, 10);
235 if (id > GID_MAX || *ep != ':')
236 return 0;
237 grp->gr_gid = (gid_t)id;
238 entry += count + 1;
239
240 memc = 1; /* for final NULL */
241 if (*entry != '\0')
242 memc++; /* for first item */
243 for (bp = entry; *bp != '\0'; bp++) {
244 if (*bp == ',')
245 memc++;
246 }
247 /* grab ALIGNed char **gr_mem from buf */
248 ep = _gr_memfrombuf(memc * sizeof(char *) + ALIGNBYTES, &buf, &buflen);
249 grp->gr_mem = (char **)ALIGN(ep);
250 if (grp->gr_mem == NULL)
251 return 0;
252
253 for (memc = 0; *entry != '\0'; memc++) {
254 count = strcspn(entry, ","); /* parse member */
255 COPYTOBUF(grp->gr_mem[memc]);
256 entry += count;
257 if (*entry == ',')
258 entry++;
259 }
260
261 #undef COPYTOBUF
262
263 grp->gr_mem[memc] = NULL;
264 return 1;
265 }
266
267 /*
268 * _gr_copy
269 * Copy the contents of fromgrp to grp; memory for strings
270 * and arrays will be allocated from buf (of size buflen).
271 * Returns 1 if copied successfully, 0 on copy failure.
272 * NOTE: fromgrp must not use buf for its own pointers.
273 */
274 static int
275 _gr_copy(struct group *fromgrp, struct group *grp, char *buf, size_t buflen)
276 {
277 char *ep;
278 int memc;
279
280 _DIAGASSERT(fromgrp != NULL);
281 _DIAGASSERT(grp != NULL);
282 _DIAGASSERT(buf != NULL);
283
284 #define COPYSTR(to, from) \
285 do { \
286 size_t count = strlen((from)); \
287 (to) = _gr_memfrombuf(count+1, &buf, &buflen); \
288 if ((to) == NULL) \
289 return 0; \
290 memmove((to), (from), count); \
291 to[count] = '\0'; \
292 } while (0) /* LINTED */
293
294 COPYSTR(grp->gr_name, fromgrp->gr_name);
295 COPYSTR(grp->gr_passwd, fromgrp->gr_passwd);
296 grp->gr_gid = fromgrp->gr_gid;
297
298 for (memc = 0; fromgrp->gr_mem[memc]; memc++)
299 continue;
300 memc++; /* for final NULL */
301
302 /* grab ALIGNed char **gr_mem from buf */
303 ep = _gr_memfrombuf(memc * sizeof(char *) + ALIGNBYTES, &buf, &buflen);
304 grp->gr_mem = (char **)ALIGN(ep);
305 if (grp->gr_mem == NULL)
306 return 0;
307
308 for (memc = 0; fromgrp->gr_mem[memc]; memc++) {
309 COPYSTR(grp->gr_mem[memc], fromgrp->gr_mem[memc]);
310 }
311
312 #undef COPYSTR
313
314 grp->gr_mem[memc] = NULL;
315 return 1;
316 }
317
318
319 /*
320 * files methods
321 */
322
323 /* state shared between files methods */
324 struct files_state {
325 int stayopen; /* see getgroupent(3) */
326 FILE *fp; /* groups file handle */
327 };
328
329 static struct files_state _files_state;
330 /* storage for non _r functions */
331 static struct group _files_group;
332 static char _files_groupbuf[GETGR_R_SIZE_MAX];
333
334 static int
335 _files_start(struct files_state *state)
336 {
337
338 _DIAGASSERT(state != NULL);
339
340 if (state->fp == NULL) {
341 state->fp = fopen(_PATH_GROUP, "r");
342 if (state->fp == NULL)
343 return NS_UNAVAIL;
344 } else {
345 rewind(state->fp);
346 }
347 return NS_SUCCESS;
348 }
349
350 static int
351 _files_end(struct files_state *state)
352 {
353
354 _DIAGASSERT(state != NULL);
355
356 if (state->fp) {
357 (void) fclose(state->fp);
358 state->fp = NULL;
359 }
360 return NS_SUCCESS;
361 }
362
363 /*
364 * _files_grscan
365 * Scan state->fp for the next desired entry.
366 * If search is zero, return the next entry.
367 * If search is non-zero, look for a specific name (if name != NULL),
368 * or a specific gid (if name == NULL).
369 * Sets *retval to the errno if the result is not NS_SUCCESS.
370 */
371 static int
372 _files_grscan(int *retval, struct group *grp, char *buffer, size_t buflen,
373 struct files_state *state, int search, const char *name, gid_t gid)
374 {
375 int rv;
376 char filebuf[GETGR_R_SIZE_MAX], *ep;
377
378 _DIAGASSERT(retval != NULL);
379 _DIAGASSERT(grp != NULL);
380 _DIAGASSERT(buffer != NULL);
381 _DIAGASSERT(state != NULL);
382 /* name is NULL to indicate searching for gid */
383
384 *retval = 0;
385
386 if (state->fp == NULL) { /* only start if file not open yet */
387 rv = _files_start(state);
388 if (rv != NS_SUCCESS)
389 goto filesgrscan_out;
390 }
391
392 rv = NS_NOTFOUND;
393
394 /* scan line by line */
395 while (fgets(filebuf, sizeof(filebuf), state->fp) != NULL) {
396 ep = strchr(filebuf, '\n');
397 if (ep == NULL) { /* fail on lines that are too big */
398 int ch;
399
400 while ((ch = getc(state->fp)) != '\n' && ch != EOF)
401 continue;
402 rv = NS_UNAVAIL;
403 break;
404 }
405 *ep = '\0'; /* clear trailing \n */
406
407 if (filebuf[0] == '+') /* skip compat line */
408 continue;
409
410 /* validate line */
411 if (! _gr_parse(filebuf, grp, buffer, buflen)) {
412 rv = NS_UNAVAIL;
413 break;
414 }
415 if (! search) { /* just want this one */
416 rv = NS_SUCCESS;
417 break;
418 }
419 /* want specific */
420 if ((name && strcmp(name, grp->gr_name) == 0) ||
421 (!name && gid == grp->gr_gid)) {
422 rv = NS_SUCCESS;
423 break;
424 }
425 }
426
427 filesgrscan_out:
428 if (rv != NS_SUCCESS)
429 *retval = errno;
430 return rv;
431 }
432
433 /*ARGSUSED*/
434 static int
435 _files_setgrent(void *nsrv, void *nscb, va_list ap)
436 {
437
438 _files_state.stayopen = 0;
439 return _files_start(&_files_state);
440 }
441
442 /*ARGSUSED*/
443 static int
444 _files_setgroupent(void *nsrv, void *nscb, va_list ap)
445 {
446 int *retval = va_arg(ap, int *);
447 int stayopen = va_arg(ap, int);
448
449 int rv;
450
451 _files_state.stayopen = stayopen;
452 rv = _files_start(&_files_state);
453 *retval = (rv == NS_SUCCESS);
454 return rv;
455 }
456
457 /*ARGSUSED*/
458 static int
459 _files_endgrent(void *nsrv, void *nscb, va_list ap)
460 {
461
462 _files_state.stayopen = 0;
463 return _files_end(&_files_state);
464 }
465
466 /*ARGSUSED*/
467 static int
468 _files_getgrent(void *nsrv, void *nscb, va_list ap)
469 {
470 struct group **retval = va_arg(ap, struct group **);
471
472 int rv, rerror;
473
474 _DIAGASSERT(retval != NULL);
475
476 *retval = NULL;
477 rv = _files_grscan(&rerror, &_files_group,
478 _files_groupbuf, sizeof(_files_groupbuf),
479 &_files_state, 0, NULL, 0);
480 if (rv == NS_SUCCESS)
481 *retval = &_files_group;
482 return rv;
483 }
484
485 /*ARGSUSED*/
486 static int
487 _files_getgrgid(void *nsrv, void *nscb, va_list ap)
488 {
489 struct group **retval = va_arg(ap, struct group **);
490 gid_t gid = va_arg(ap, gid_t);
491
492 int rv, rerror;
493
494 _DIAGASSERT(retval != NULL);
495
496 *retval = NULL;
497 rv = _files_start(&_files_state);
498 if (rv != NS_SUCCESS)
499 return rv;
500 rv = _files_grscan(&rerror, &_files_group,
501 _files_groupbuf, sizeof(_files_groupbuf),
502 &_files_state, 1, NULL, gid);
503 if (!_files_state.stayopen)
504 _files_end(&_files_state);
505 if (rv == NS_SUCCESS)
506 *retval = &_files_group;
507 return rv;
508 }
509
510 /*ARGSUSED*/
511 static int
512 _files_getgrgid_r(void *nsrv, void *nscb, va_list ap)
513 {
514 int *retval = va_arg(ap, int *);
515 gid_t gid = va_arg(ap, gid_t);
516 struct group *grp = va_arg(ap, struct group *);
517 char *buffer = va_arg(ap, char *);
518 size_t buflen = va_arg(ap, size_t);
519 struct group **result = va_arg(ap, struct group **);
520
521 struct files_state state;
522 int rv;
523
524 _DIAGASSERT(retval != NULL);
525 _DIAGASSERT(grp != NULL);
526 _DIAGASSERT(buffer != NULL);
527 _DIAGASSERT(result != NULL);
528
529 *result = NULL;
530 memset(&state, 0, sizeof(state));
531 rv = _files_grscan(retval, grp, buffer, buflen, &state, 1, NULL, gid);
532 _files_end(&state);
533 if (rv == NS_SUCCESS)
534 *result = grp;
535 return rv;
536 }
537
538 /*ARGSUSED*/
539 static int
540 _files_getgrnam(void *nsrv, void *nscb, va_list ap)
541 {
542 struct group **retval = va_arg(ap, struct group **);
543 const char *name = va_arg(ap, const char *);
544
545 int rv, rerror;
546
547 _DIAGASSERT(retval != NULL);
548
549 *retval = NULL;
550 rv = _files_start(&_files_state);
551 if (rv != NS_SUCCESS)
552 return rv;
553 rv = _files_grscan(&rerror, &_files_group,
554 _files_groupbuf, sizeof(_files_groupbuf),
555 &_files_state, 1, name, 0);
556 if (!_files_state.stayopen)
557 _files_end(&_files_state);
558 if (rv == NS_SUCCESS)
559 *retval = &_files_group;
560 return rv;
561 }
562
563 /*ARGSUSED*/
564 static int
565 _files_getgrnam_r(void *nsrv, void *nscb, va_list ap)
566 {
567 int *retval = va_arg(ap, int *);
568 const char *name = va_arg(ap, const char *);
569 struct group *grp = va_arg(ap, struct group *);
570 char *buffer = va_arg(ap, char *);
571 size_t buflen = va_arg(ap, size_t);
572 struct group **result = va_arg(ap, struct group **);
573
574 struct files_state state;
575 int rv;
576
577 _DIAGASSERT(retval != NULL);
578 _DIAGASSERT(grp != NULL);
579 _DIAGASSERT(buffer != NULL);
580 _DIAGASSERT(result != NULL);
581
582 *result = NULL;
583 memset(&state, 0, sizeof(state));
584 rv = _files_grscan(retval, grp, buffer, buflen, &state, 1, name, 0);
585 _files_end(&state);
586 if (rv == NS_SUCCESS)
587 *result = grp;
588 return rv;
589 }
590
591
592 #ifdef HESIOD
593 /*
594 * dns methods
595 */
596
597 /* state shared between dns methods */
598 struct dns_state {
599 int stayopen; /* see getgroupent(3) */
600 void *context; /* Hesiod context */
601 int num; /* group index, -1 if no more */
602 };
603
604 static struct dns_state _dns_state;
605 /* storage for non _r functions */
606 static struct group _dns_group;
607 static char _dns_groupbuf[GETGR_R_SIZE_MAX];
608
609 static int
610 _dns_start(struct dns_state *state)
611 {
612
613 _DIAGASSERT(state != NULL);
614
615 state->num = 0;
616 if (state->context == NULL) { /* setup Hesiod */
617 if (hesiod_init(&state->context) == -1)
618 return NS_UNAVAIL;
619 }
620
621 return NS_SUCCESS;
622 }
623
624 static int
625 _dns_end(struct dns_state *state)
626 {
627
628 _DIAGASSERT(state != NULL);
629
630 state->num = 0;
631 if (state->context) {
632 hesiod_end(state->context);
633 state->context = NULL;
634 }
635 return NS_SUCCESS;
636 }
637
638 /*
639 * _dns_grscan
640 * Look for the Hesiod name provided in buffer in the NULL-terminated
641 * list of zones,
642 * and decode into grp/buffer/buflen.
643 */
644 static int
645 _dns_grscan(int *retval, struct group *grp, char *buffer, size_t buflen,
646 struct dns_state *state, const char **zones)
647 {
648 const char **curzone;
649 char **hp, *ep;
650 int rv;
651
652 _DIAGASSERT(retval != NULL);
653 _DIAGASSERT(grp != NULL);
654 _DIAGASSERT(buffer != NULL);
655 _DIAGASSERT(state != NULL);
656 _DIAGASSERT(zones != NULL);
657
658 *retval = 0;
659
660 if (state->context == NULL) { /* only start if Hesiod not setup */
661 rv = _dns_start(state);
662 if (rv != NS_SUCCESS)
663 return rv;
664 }
665
666 hp = NULL;
667 rv = NS_NOTFOUND;
668
669 for (curzone = zones; *curzone; curzone++) { /* search zones */
670 hp = hesiod_resolve(state->context, buffer, *curzone);
671 if (hp != NULL)
672 break;
673 if (errno != ENOENT) {
674 rv = NS_UNAVAIL;
675 goto dnsgrscan_out;
676 }
677 }
678 if (*curzone == NULL)
679 goto dnsgrscan_out;
680
681 if ((ep = strchr(hp[0], '\n')) != NULL)
682 *ep = '\0'; /* clear trailing \n */
683 if (_gr_parse(hp[0], grp, buffer, buflen)) /* validate line */
684 rv = NS_SUCCESS;
685 else
686 rv = NS_UNAVAIL;
687
688 dnsgrscan_out:
689 if (rv != NS_SUCCESS)
690 *retval = errno;
691 if (hp)
692 hesiod_free_list(state->context, hp);
693 return rv;
694 }
695
696 /*ARGSUSED*/
697 static int
698 _dns_setgrent(void *nsrv, void *nscb, va_list ap)
699 {
700
701 _dns_state.stayopen = 0;
702 return _dns_start(&_dns_state);
703 }
704
705 /*ARGSUSED*/
706 static int
707 _dns_setgroupent(void *nsrv, void *nscb, va_list ap)
708 {
709 int *retval = va_arg(ap, int *);
710 int stayopen = va_arg(ap, int);
711
712 int rv;
713
714 _dns_state.stayopen = stayopen;
715 rv = _dns_start(&_dns_state);
716 *retval = (rv == NS_SUCCESS);
717 return rv;
718 }
719
720 /*ARGSUSED*/
721 static int
722 _dns_endgrent(void *nsrv, void *nscb, va_list ap)
723 {
724
725 _dns_state.stayopen = 0;
726 return _dns_end(&_dns_state);
727 }
728
729 /*ARGSUSED*/
730 static int
731 _dns_getgrent(void *nsrv, void *nscb, va_list ap)
732 {
733 struct group **retval = va_arg(ap, struct group **);
734
735 char **hp, *ep;
736 int rv;
737
738 _DIAGASSERT(retval != NULL);
739
740 *retval = NULL;
741
742 if (_dns_state.num == -1) /* exhausted search */
743 return NS_NOTFOUND;
744
745 if (_dns_state.context == NULL) {
746 /* only start if Hesiod not setup */
747 rv = _dns_start(&_dns_state);
748 if (rv != NS_SUCCESS)
749 return rv;
750 }
751
752 hp = NULL;
753 rv = NS_NOTFOUND;
754
755 /* find group-NNN */
756 snprintf(_dns_groupbuf, sizeof(_dns_groupbuf),
757 "group-%u", _dns_state.num);
758 _dns_state.num++;
759
760 hp = hesiod_resolve(_dns_state.context, _dns_groupbuf, "group");
761 if (hp == NULL) {
762 if (errno == ENOENT)
763 _dns_state.num = -1;
764 else
765 rv = NS_UNAVAIL;
766 } else {
767 if ((ep = strchr(hp[0], '\n')) != NULL)
768 *ep = '\0'; /* clear trailing \n */
769 /* validate line */
770 if (_gr_parse(hp[0], &_dns_group,
771 _dns_groupbuf, sizeof(_dns_groupbuf)))
772 rv = NS_SUCCESS;
773 else
774 rv = NS_UNAVAIL;
775 }
776
777 if (hp)
778 hesiod_free_list(_dns_state.context, hp);
779 if (rv == NS_SUCCESS)
780 *retval = &_dns_group;
781 return rv;
782 }
783
784 static const char *_dns_gid_zones[] = {
785 "gid",
786 "group",
787 NULL
788 };
789
790 /*ARGSUSED*/
791 static int
792 _dns_getgrgid(void *nsrv, void *nscb, va_list ap)
793 {
794 struct group **retval = va_arg(ap, struct group **);
795 gid_t gid = va_arg(ap, gid_t);
796
797 int rv, rerror;
798
799 _DIAGASSERT(retval != NULL);
800
801 *retval = NULL;
802 rv = _dns_start(&_dns_state);
803 if (rv != NS_SUCCESS)
804 return rv;
805 snprintf(_dns_groupbuf, sizeof(_dns_groupbuf), "%u", (unsigned int)gid);
806 rv = _dns_grscan(&rerror, &_dns_group,
807 _dns_groupbuf, sizeof(_dns_groupbuf), &_dns_state, _dns_gid_zones);
808 if (!_dns_state.stayopen)
809 _dns_end(&_dns_state);
810 if (rv == NS_SUCCESS && gid == _dns_group.gr_gid)
811 *retval = &_dns_group;
812 return rv;
813 }
814
815 /*ARGSUSED*/
816 static int
817 _dns_getgrgid_r(void *nsrv, void *nscb, va_list ap)
818 {
819 int *retval = va_arg(ap, int *);
820 gid_t gid = va_arg(ap, gid_t);
821 struct group *grp = va_arg(ap, struct group *);
822 char *buffer = va_arg(ap, char *);
823 size_t buflen = va_arg(ap, size_t);
824 struct group **result = va_arg(ap, struct group **);
825
826 struct dns_state state;
827 int rv;
828
829 _DIAGASSERT(retval != NULL);
830 _DIAGASSERT(grp != NULL);
831 _DIAGASSERT(buffer != NULL);
832 _DIAGASSERT(result != NULL);
833
834 *result = NULL;
835 memset(&state, 0, sizeof(state));
836 snprintf(buffer, buflen, "%u", (unsigned int)gid);
837 rv = _dns_grscan(retval, grp, buffer, buflen, &state, _dns_gid_zones);
838 _dns_end(&state);
839 if (rv != NS_SUCCESS)
840 return rv;
841 if (gid == grp->gr_gid) {
842 *result = grp;
843 return NS_SUCCESS;
844 } else
845 return NS_NOTFOUND;
846 }
847
848 static const char *_dns_nam_zones[] = {
849 "group",
850 NULL
851 };
852
853 /*ARGSUSED*/
854 static int
855 _dns_getgrnam(void *nsrv, void *nscb, va_list ap)
856 {
857 struct group **retval = va_arg(ap, struct group **);
858 const char *name = va_arg(ap, const char *);
859
860 int rv, rerror;
861
862 _DIAGASSERT(retval != NULL);
863
864 *retval = NULL;
865 rv = _dns_start(&_dns_state);
866 if (rv != NS_SUCCESS)
867 return rv;
868 snprintf(_dns_groupbuf, sizeof(_dns_groupbuf), "%s", name);
869 rv = _dns_grscan(&rerror, &_dns_group,
870 _dns_groupbuf, sizeof(_dns_groupbuf), &_dns_state, _dns_nam_zones);
871 if (!_dns_state.stayopen)
872 _dns_end(&_dns_state);
873 if (rv == NS_SUCCESS && strcmp(name, _dns_group.gr_name) == 0)
874 *retval = &_dns_group;
875 return rv;
876 }
877
878 /*ARGSUSED*/
879 static int
880 _dns_getgrnam_r(void *nsrv, void *nscb, va_list ap)
881 {
882 int *retval = va_arg(ap, int *);
883 const char *name = va_arg(ap, const char *);
884 struct group *grp = va_arg(ap, struct group *);
885 char *buffer = va_arg(ap, char *);
886 size_t buflen = va_arg(ap, size_t);
887 struct group **result = va_arg(ap, struct group **);
888
889 struct dns_state state;
890 int rv;
891
892 _DIAGASSERT(retval != NULL);
893 _DIAGASSERT(grp != NULL);
894 _DIAGASSERT(buffer != NULL);
895 _DIAGASSERT(result != NULL);
896
897 *result = NULL;
898 memset(&state, 0, sizeof(state));
899 snprintf(buffer, buflen, "%s", name);
900 rv = _dns_grscan(retval, grp, buffer, buflen, &state, _dns_nam_zones);
901 _dns_end(&state);
902 if (rv != NS_SUCCESS)
903 return rv;
904 if (strcmp(name, grp->gr_name) == 0) {
905 *result = grp;
906 return NS_SUCCESS;
907 } else
908 return NS_NOTFOUND;
909 }
910
911 #endif /* HESIOD */
912
913
914 #ifdef YP
915 /*
916 * nis methods
917 */
918 /* state shared between nis methods */
919 struct nis_state {
920 int stayopen; /* see getgroupent(3) */
921 char *domain; /* NIS domain */
922 int done; /* non-zero if search exhausted */
923 char *current; /* current first/next match */
924 int currentlen; /* length of _nis_current */
925 };
926
927 static struct nis_state _nis_state;
928 /* storage for non _r functions */
929 static struct group _nis_group;
930 static char _nis_groupbuf[GETGR_R_SIZE_MAX];
931
932 static int
933 _nis_start(struct nis_state *state)
934 {
935
936 _DIAGASSERT(state != NULL);
937
938 state->done = 0;
939 if (state->current) {
940 free(state->current);
941 state->current = NULL;
942 }
943 if (state->domain == NULL) { /* setup NIS */
944 switch (yp_get_default_domain(&state->domain)) {
945 case 0:
946 break;
947 case YPERR_RESRC:
948 return NS_TRYAGAIN;
949 default:
950 return NS_UNAVAIL;
951 }
952 }
953 return NS_SUCCESS;
954 }
955
956 static int
957 _nis_end(struct nis_state *state)
958 {
959
960 _DIAGASSERT(state != NULL);
961
962 if (state->domain) {
963 state->domain = NULL;
964 }
965 state->done = 0;
966 if (state->current) {
967 free(state->current);
968 state->current = NULL;
969 }
970 return NS_SUCCESS;
971 }
972
973 /*
974 * _nis_grscan
975 * Look for the yp key provided in buffer from map,
976 * and decode into grp/buffer/buflen.
977 */
978 static int
979 _nis_grscan(int *retval, struct group *grp, char *buffer, size_t buflen,
980 struct nis_state *state, const char *map)
981 {
982 char *data;
983 int nisr, rv, datalen;
984
985 _DIAGASSERT(retval != NULL);
986 _DIAGASSERT(grp != NULL);
987 _DIAGASSERT(buffer != NULL);
988 _DIAGASSERT(state != NULL);
989 _DIAGASSERT(map != NULL);
990
991 *retval = 0;
992
993 if (state->domain == NULL) { /* only start if NIS not setup */
994 rv = _nis_start(state);
995 if (rv != NS_SUCCESS)
996 return rv;
997 }
998
999 data = NULL;
1000 rv = NS_NOTFOUND;
1001
1002 /* search map */
1003 nisr = yp_match(state->domain, map, buffer, (int)strlen(buffer),
1004 &data, &datalen);
1005 switch (nisr) {
1006 case 0:
1007 data[datalen] = '\0'; /* clear trailing \n */
1008 if (_gr_parse(data, grp, buffer, buflen))
1009 rv = NS_SUCCESS; /* validate line */
1010 else
1011 rv = NS_UNAVAIL;
1012 break;
1013 case YPERR_KEY:
1014 break;
1015 default:
1016 rv = NS_UNAVAIL;
1017 break;
1018 }
1019
1020 if (rv != NS_SUCCESS)
1021 *retval = errno;
1022 if (data)
1023 free(data);
1024 return rv;
1025 }
1026
1027 /*ARGSUSED*/
1028 static int
1029 _nis_setgrent(void *nsrv, void *nscb, va_list ap)
1030 {
1031
1032 _nis_state.stayopen = 0;
1033 return _nis_start(&_nis_state);
1034 }
1035
1036 /*ARGSUSED*/
1037 static int
1038 _nis_setgroupent(void *nsrv, void *nscb, va_list ap)
1039 {
1040 int *retval = va_arg(ap, int *);
1041 int stayopen = va_arg(ap, int);
1042
1043 int rv;
1044
1045 _nis_state.stayopen = stayopen;
1046 rv = _nis_start(&_nis_state);
1047 *retval = (rv == NS_SUCCESS);
1048 return rv;
1049 }
1050
1051 /*ARGSUSED*/
1052 static int
1053 _nis_endgrent(void *nsrv, void *nscb, va_list ap)
1054 {
1055
1056 return _nis_end(&_nis_state);
1057 }
1058
1059
1060 /*ARGSUSED*/
1061 static int
1062 _nis_getgrent(void *nsrv, void *nscb, va_list ap)
1063 {
1064 struct group **retval = va_arg(ap, struct group **);
1065
1066 char *key, *data;
1067 int keylen, datalen, rv, nisr;
1068
1069 _DIAGASSERT(retval != NULL);
1070
1071 *retval = NULL;
1072
1073 if (_nis_state.done) /* exhausted search */
1074 return NS_NOTFOUND;
1075 if (_nis_state.domain == NULL) {
1076 /* only start if NIS not setup */
1077 rv = _nis_start(&_nis_state);
1078 if (rv != NS_SUCCESS)
1079 return rv;
1080 }
1081
1082 key = NULL;
1083 data = NULL;
1084 rv = NS_NOTFOUND;
1085
1086 if (_nis_state.current) { /* already searching */
1087 nisr = yp_next(_nis_state.domain, "group.byname",
1088 _nis_state.current, _nis_state.currentlen,
1089 &key, &keylen, &data, &datalen);
1090 free(_nis_state.current);
1091 _nis_state.current = NULL;
1092 switch (nisr) {
1093 case 0:
1094 _nis_state.current = key;
1095 _nis_state.currentlen = keylen;
1096 key = NULL;
1097 break;
1098 case YPERR_NOMORE:
1099 _nis_state.done = 1;
1100 goto nisent_out;
1101 default:
1102 rv = NS_UNAVAIL;
1103 goto nisent_out;
1104 }
1105 } else { /* new search */
1106 if (yp_first(_nis_state.domain, "group.byname",
1107 &_nis_state.current, &_nis_state.currentlen,
1108 &data, &datalen)) {
1109 rv = NS_UNAVAIL;
1110 goto nisent_out;
1111 }
1112 }
1113
1114 data[datalen] = '\0'; /* clear trailing \n */
1115 /* validate line */
1116 if (_gr_parse(data, &_nis_group, _nis_groupbuf, sizeof(_nis_groupbuf)))
1117 rv = NS_SUCCESS;
1118 else
1119 rv = NS_UNAVAIL;
1120
1121 nisent_out:
1122 if (key)
1123 free(key);
1124 if (data)
1125 free(data);
1126 if (rv == NS_SUCCESS)
1127 *retval = &_nis_group;
1128 return rv;
1129 }
1130
1131 /*ARGSUSED*/
1132 static int
1133 _nis_getgrgid(void *nsrv, void *nscb, va_list ap)
1134 {
1135 struct group **retval = va_arg(ap, struct group **);
1136 gid_t gid = va_arg(ap, gid_t);
1137
1138 int rv, rerror;
1139
1140 _DIAGASSERT(retval != NULL);
1141
1142 *retval = NULL;
1143 rv = _nis_start(&_nis_state);
1144 if (rv != NS_SUCCESS)
1145 return rv;
1146 snprintf(_nis_groupbuf, sizeof(_nis_groupbuf), "%u", (unsigned int)gid);
1147 rv = _nis_grscan(&rerror, &_nis_group,
1148 _nis_groupbuf, sizeof(_nis_groupbuf), &_nis_state, "group.bygid");
1149 if (!_nis_state.stayopen)
1150 _nis_end(&_nis_state);
1151 if (rv == NS_SUCCESS && gid == _nis_group.gr_gid)
1152 *retval = &_nis_group;
1153 return rv;
1154 }
1155
1156 /*ARGSUSED*/
1157 static int
1158 _nis_getgrgid_r(void *nsrv, void *nscb, va_list ap)
1159 {
1160 int *retval = va_arg(ap, int *);
1161 gid_t gid = va_arg(ap, gid_t);
1162 struct group *grp = va_arg(ap, struct group *);
1163 char *buffer = va_arg(ap, char *);
1164 size_t buflen = va_arg(ap, size_t);
1165 struct group **result = va_arg(ap, struct group **);
1166
1167 struct nis_state state;
1168 int rv;
1169
1170 _DIAGASSERT(retval != NULL);
1171 _DIAGASSERT(grp != NULL);
1172 _DIAGASSERT(buffer != NULL);
1173 _DIAGASSERT(result != NULL);
1174
1175 *result = NULL;
1176 memset(&state, 0, sizeof(state));
1177 snprintf(buffer, buflen, "%u", (unsigned int)gid);
1178 rv = _nis_grscan(retval, grp, buffer, buflen, &state, "group.bygid");
1179 _nis_end(&state);
1180 if (rv != NS_SUCCESS)
1181 return rv;
1182 if (gid == grp->gr_gid) {
1183 *result = grp;
1184 return NS_SUCCESS;
1185 } else
1186 return NS_NOTFOUND;
1187 }
1188
1189 /*ARGSUSED*/
1190 static int
1191 _nis_getgrnam(void *nsrv, void *nscb, va_list ap)
1192 {
1193 struct group **retval = va_arg(ap, struct group **);
1194 const char *name = va_arg(ap, const char *);
1195
1196 int rv, rerror;
1197
1198 _DIAGASSERT(retval != NULL);
1199
1200 *retval = NULL;
1201 rv = _nis_start(&_nis_state);
1202 if (rv != NS_SUCCESS)
1203 return rv;
1204 snprintf(_nis_groupbuf, sizeof(_nis_groupbuf), "%s", name);
1205 rv = _nis_grscan(&rerror, &_nis_group,
1206 _nis_groupbuf, sizeof(_nis_groupbuf), &_nis_state, "group.byname");
1207 if (!_nis_state.stayopen)
1208 _nis_end(&_nis_state);
1209 if (rv == NS_SUCCESS && strcmp(name, _nis_group.gr_name) == 0)
1210 *retval = &_nis_group;
1211 return rv;
1212 }
1213
1214 /*ARGSUSED*/
1215 static int
1216 _nis_getgrnam_r(void *nsrv, void *nscb, va_list ap)
1217 {
1218 int *retval = va_arg(ap, int *);
1219 const char *name = va_arg(ap, const char *);
1220 struct group *grp = va_arg(ap, struct group *);
1221 char *buffer = va_arg(ap, char *);
1222 size_t buflen = va_arg(ap, size_t);
1223 struct group **result = va_arg(ap, struct group **);
1224
1225 struct nis_state state;
1226 int rv;
1227
1228 _DIAGASSERT(retval != NULL);
1229 _DIAGASSERT(grp != NULL);
1230 _DIAGASSERT(buffer != NULL);
1231 _DIAGASSERT(result != NULL);
1232
1233 *result = NULL;
1234 snprintf(buffer, buflen, "%s", name);
1235 memset(&state, 0, sizeof(state));
1236 rv = _nis_grscan(retval, grp, buffer, buflen, &state, "group.byname");
1237 _nis_end(&state);
1238 if (rv != NS_SUCCESS)
1239 return rv;
1240 if (strcmp(name, grp->gr_name) == 0) {
1241 *result = grp;
1242 return NS_SUCCESS;
1243 } else
1244 return NS_NOTFOUND;
1245 }
1246
1247 #endif /* YP */
1248
1249
1250 #ifdef _GROUP_COMPAT
1251 /*
1252 * compat methods
1253 */
1254
1255 /* state shared between compat methods */
1256 struct compat_state {
1257 int stayopen; /* see getgroupent(3) */
1258 FILE *fp; /* file handle */
1259 char *name; /* NULL if reading file, */
1260 /* "" if compat "+", */
1261 /* name if compat "+name" */
1262 };
1263
1264 static struct compat_state _compat_state;
1265 /* storage for non _r functions */
1266 static struct group _compat_group;
1267 static char _compat_groupbuf[GETGR_R_SIZE_MAX];
1268
1269 static int
1270 _compat_start(struct compat_state *state)
1271 {
1272
1273 _DIAGASSERT(state != NULL);
1274
1275 if (state->fp == NULL) {
1276 state->fp = fopen(_PATH_GROUP, "r");
1277 if (state->fp == NULL)
1278 return NS_UNAVAIL;
1279 } else {
1280 rewind(state->fp);
1281 }
1282 return NS_SUCCESS;
1283 }
1284
1285 static int
1286 _compat_end(struct compat_state *state)
1287 {
1288
1289 _DIAGASSERT(state != NULL);
1290
1291 if (state->name) {
1292 free(state->name);
1293 state->name = NULL;
1294 }
1295 if (state->fp) {
1296 (void) fclose(state->fp);
1297 state->fp = NULL;
1298 }
1299 return NS_SUCCESS;
1300 }
1301
1302
1303 /*
1304 * _compat_grbad
1305 * log an error if "files" or "compat" is specified in
1306 * group_compat database
1307 */
1308 /*ARGSUSED*/
1309 static int
1310 _compat_grbad(void *nsrv, void *nscb, va_list ap)
1311 {
1312 static int warned;
1313
1314 _DIAGASSERT(cb_data != NULL);
1315
1316 if (!warned) {
1317 syslog(LOG_ERR,
1318 "nsswitch.conf group_compat database can't use '%s'",
1319 (char *)nscb);
1320 }
1321 warned = 1;
1322 return NS_UNAVAIL;
1323 }
1324
1325 /*
1326 * _compat_grscan
1327 * Scan state->fp for the next desired entry.
1328 * If search is zero, return the next entry.
1329 * If search is non-zero, look for a specific name (if name != NULL),
1330 * or a specific gid (if name == NULL).
1331 * Sets *retval to the errno if the result is not NS_SUCCESS.
1332 */
1333 static int
1334 _compat_grscan(int *retval, struct group *grp, char *buffer, size_t buflen,
1335 struct compat_state *state, int search, const char *name, gid_t gid)
1336 {
1337 int rv;
1338 char filebuf[GETGR_R_SIZE_MAX], *ep;
1339
1340 static const ns_dtab compatentdtab[] = {
1341 NS_FILES_CB(_compat_grbad, "files")
1342 NS_DNS_CB(_dns_getgrent, NULL)
1343 NS_NIS_CB(_nis_getgrent, NULL)
1344 NS_COMPAT_CB(_compat_grbad, "compat")
1345 { 0 }
1346 };
1347 static const ns_dtab compatgiddtab[] = {
1348 NS_FILES_CB(_compat_grbad, "files")
1349 NS_DNS_CB(_dns_getgrgid_r, NULL)
1350 NS_NIS_CB(_nis_getgrgid_r, NULL)
1351 NS_COMPAT_CB(_compat_grbad, "compat")
1352 { 0 }
1353 };
1354 static const ns_dtab compatnamdtab[] = {
1355 NS_FILES_CB(_compat_grbad, "files")
1356 NS_DNS_CB(_dns_getgrnam_r, NULL)
1357 NS_NIS_CB(_nis_getgrnam_r, NULL)
1358 NS_COMPAT_CB(_compat_grbad, "compat")
1359 { 0 }
1360 };
1361
1362 _DIAGASSERT(retval != NULL);
1363 _DIAGASSERT(grp != NULL);
1364 _DIAGASSERT(buffer != NULL);
1365 _DIAGASSERT(state != NULL);
1366 /* name is NULL to indicate searching for gid */
1367
1368 *retval = 0;
1369
1370 if (state->fp == NULL) { /* only start if file not open yet */
1371 rv = _compat_start(state);
1372 if (rv != NS_SUCCESS)
1373 goto compatgrscan_out;
1374 }
1375 rv = NS_NOTFOUND;
1376
1377 for (;;) { /* loop through file */
1378 if (state->name != NULL) {
1379 /* processing compat entry */
1380 int crv, cretval;
1381 struct group cgrp, *cgrpres;
1382
1383 if (state->name[0]) { /* specific +group: */
1384 crv = nsdispatch(NULL, compatnamdtab,
1385 NSDB_GROUP_COMPAT, "getgrnam_r", defaultnis,
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 /* XXXLUKEM: need to implement and use getgrent_r() */
1392 crv = nsdispatch(NULL, compatentdtab,
1393 NSDB_GROUP_COMPAT, "getgrent", defaultnis,
1394 &cgrpres);
1395 } else if (name) { /* specific group */
1396 crv = nsdispatch(NULL, compatnamdtab,
1397 NSDB_GROUP_COMPAT, "getgrnam_r", defaultnis,
1398 &cretval, name,
1399 &cgrp, filebuf, sizeof(filebuf), &cgrpres);
1400 } else { /* specific gid */
1401 crv = nsdispatch(NULL, compatgiddtab,
1402 NSDB_GROUP_COMPAT, "getgrgid_r", defaultnis,
1403 &cretval, gid,
1404 &cgrp, filebuf, sizeof(filebuf), &cgrpres);
1405 }
1406 if (crv != NS_SUCCESS) { /* not found */
1407 free(state->name);
1408 state->name = NULL;
1409 continue; /* try next line */
1410 }
1411 if (!_gr_copy(cgrpres, grp, buffer, buflen)) {
1412 rv = NS_UNAVAIL;
1413 break;
1414 }
1415 goto compatgrscan_cmpgrp; /* skip to grp test */
1416 }
1417
1418 /* get next file line */
1419 if (fgets(filebuf, sizeof(filebuf), state->fp) == NULL)
1420 break;
1421
1422 ep = strchr(filebuf, '\n');
1423 if (ep == NULL) { /* fail on lines that are too big */
1424 int ch;
1425
1426 while ((ch = getc(state->fp)) != '\n' && ch != EOF)
1427 continue;
1428 rv = NS_UNAVAIL;
1429 break;
1430 }
1431 *ep = '\0'; /* clear trailing \n */
1432
1433 if (filebuf[0] == '+') { /* parse compat line */
1434 if (state->name)
1435 free(state->name);
1436 state->name = NULL;
1437 switch(filebuf[1]) {
1438 case ':':
1439 case '\0':
1440 state->name = strdup("");
1441 break;
1442 default:
1443 ep = strchr(filebuf + 1, ':');
1444 if (ep == NULL)
1445 break;
1446 *ep = '\0';
1447 state->name = strdup(filebuf + 1);
1448 break;
1449 }
1450 if (state->name == NULL) {
1451 rv = NS_UNAVAIL;
1452 break;
1453 }
1454 continue;
1455 }
1456
1457 /* validate line */
1458 if (! _gr_parse(filebuf, grp, buffer, buflen)) {
1459 rv = NS_UNAVAIL;
1460 break;
1461 }
1462
1463 compatgrscan_cmpgrp:
1464 if (! search) { /* just want this one */
1465 rv = NS_SUCCESS;
1466 break;
1467 }
1468 /* want specific */
1469 if ((name && strcmp(name, grp->gr_name) == 0) ||
1470 (!name && gid == grp->gr_gid)) {
1471 rv = NS_SUCCESS;
1472 break;
1473 }
1474
1475 }
1476
1477 compatgrscan_out:
1478 if (rv != NS_SUCCESS)
1479 *retval = errno;
1480 return rv;
1481 }
1482
1483 /*ARGSUSED*/
1484 static int
1485 _compat_setgrent(void *nsrv, void *nscb, va_list ap)
1486 {
1487 static const ns_dtab dtab[] = {
1488 NS_FILES_CB(_compat_grbad, "files")
1489 NS_DNS_CB(_dns_setgrent, NULL)
1490 NS_NIS_CB(_nis_setgrent, NULL)
1491 NS_COMPAT_CB(_compat_grbad, "compat")
1492 { 0 }
1493 };
1494
1495 /* force group_compat setgrent() */
1496 (void) nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "setgrent",
1497 defaultnis_forceall);
1498
1499 /* reset state, keep fp open */
1500 _compat_state.stayopen = 0;
1501 return _compat_start(&_compat_state);
1502 }
1503
1504 /*ARGSUSED*/
1505 static int
1506 _compat_setgroupent(void *nsrv, void *nscb, va_list ap)
1507 {
1508 int *retval = va_arg(ap, int *);
1509 int stayopen = va_arg(ap, int);
1510
1511 int rv;
1512
1513 static const ns_dtab dtab[] = {
1514 NS_FILES_CB(_compat_grbad, "files")
1515 NS_DNS_CB(_dns_setgroupent, NULL)
1516 NS_NIS_CB(_nis_setgroupent, NULL)
1517 NS_COMPAT_CB(_compat_grbad, "compat")
1518 { 0 }
1519 };
1520
1521 /* force group_compat setgroupent() */
1522 (void) nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "setgroupent",
1523 defaultnis_forceall, &rv, stayopen);
1524
1525 _compat_state.stayopen = stayopen;
1526 rv = _compat_start(&_compat_state);
1527 *retval = (rv == NS_SUCCESS);
1528 return rv;
1529 }
1530
1531 /*ARGSUSED*/
1532 static int
1533 _compat_endgrent(void *nsrv, void *nscb, va_list ap)
1534 {
1535 static const ns_dtab dtab[] = {
1536 NS_FILES_CB(_compat_grbad, "files")
1537 NS_DNS_CB(_dns_endgrent, NULL)
1538 NS_NIS_CB(_nis_endgrent, NULL)
1539 NS_COMPAT_CB(_compat_grbad, "compat")
1540 { 0 }
1541 };
1542
1543 /* force group_compat endgrent() */
1544 (void) nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "endgrent",
1545 defaultnis_forceall);
1546
1547 /* reset state, close fp */
1548 _compat_state.stayopen = 0;
1549 return _compat_end(&_compat_state);
1550 }
1551
1552 /*ARGSUSED*/
1553 static int
1554 _compat_getgrent(void *nsrv, void *nscb, va_list ap)
1555 {
1556 struct group **retval = va_arg(ap, struct group **);
1557
1558 int rv, rerror;
1559
1560 _DIAGASSERT(retval != NULL);
1561
1562 *retval = NULL;
1563 rv = _compat_grscan(&rerror, &_compat_group,
1564 _compat_groupbuf, sizeof(_compat_groupbuf),
1565 &_compat_state, 0, NULL, 0);
1566 if (rv == NS_SUCCESS)
1567 *retval = &_compat_group;
1568 return rv;
1569 }
1570
1571 /*ARGSUSED*/
1572 static int
1573 _compat_getgrgid(void *nsrv, void *nscb, va_list ap)
1574 {
1575 struct group **retval = va_arg(ap, struct group **);
1576 gid_t gid = va_arg(ap, gid_t);
1577
1578 int rv, rerror;
1579
1580 _DIAGASSERT(retval != NULL);
1581
1582 *retval = NULL;
1583 rv = _compat_start(&_compat_state);
1584 if (rv != NS_SUCCESS)
1585 return rv;
1586 rv = _compat_grscan(&rerror, &_compat_group,
1587 _compat_groupbuf, sizeof(_compat_groupbuf),
1588 &_compat_state, 1, NULL, gid);
1589 if (!_compat_state.stayopen)
1590 _compat_end(&_compat_state);
1591 if (rv == NS_SUCCESS)
1592 *retval = &_compat_group;
1593 return rv;
1594 }
1595
1596 /*ARGSUSED*/
1597 static int
1598 _compat_getgrgid_r(void *nsrv, void *nscb, va_list ap)
1599 {
1600 int *retval = va_arg(ap, int *);
1601 gid_t gid = va_arg(ap, gid_t);
1602 struct group *grp = va_arg(ap, struct group *);
1603 char *buffer = va_arg(ap, char *);
1604 size_t buflen = va_arg(ap, size_t);
1605 struct group **result = va_arg(ap, struct group **);
1606
1607 struct compat_state state;
1608 int rv;
1609
1610 _DIAGASSERT(retval != NULL);
1611 _DIAGASSERT(grp != NULL);
1612 _DIAGASSERT(buffer != NULL);
1613 _DIAGASSERT(result != NULL);
1614
1615 *result = NULL;
1616 memset(&state, 0, sizeof(state));
1617 rv = _compat_grscan(retval, grp, buffer, buflen, &state, 1, NULL, gid);
1618 _compat_end(&state);
1619 if (rv == NS_SUCCESS)
1620 *result = grp;
1621 return rv;
1622 }
1623
1624 /*ARGSUSED*/
1625 static int
1626 _compat_getgrnam(void *nsrv, void *nscb, va_list ap)
1627 {
1628 struct group **retval = va_arg(ap, struct group **);
1629 const char *name = va_arg(ap, const char *);
1630
1631 int rv, rerror;
1632
1633 _DIAGASSERT(retval != NULL);
1634
1635 *retval = NULL;
1636 rv = _compat_start(&_compat_state);
1637 if (rv != NS_SUCCESS)
1638 return rv;
1639 rv = _compat_grscan(&rerror, &_compat_group,
1640 _compat_groupbuf, sizeof(_compat_groupbuf),
1641 &_compat_state, 1, name, 0);
1642 if (!_compat_state.stayopen)
1643 _compat_end(&_compat_state);
1644 if (rv == NS_SUCCESS)
1645 *retval = &_compat_group;
1646 return rv;
1647 }
1648
1649 /*ARGSUSED*/
1650 static int
1651 _compat_getgrnam_r(void *nsrv, void *nscb, va_list ap)
1652 {
1653 int *retval = va_arg(ap, int *);
1654 const char *name = va_arg(ap, const char *);
1655 struct group *grp = va_arg(ap, struct group *);
1656 char *buffer = va_arg(ap, char *);
1657 size_t buflen = va_arg(ap, size_t);
1658 struct group **result = va_arg(ap, struct group **);
1659
1660 struct compat_state state;
1661 int rv;
1662
1663 _DIAGASSERT(retval != NULL);
1664 _DIAGASSERT(grp != NULL);
1665 _DIAGASSERT(buffer != NULL);
1666 _DIAGASSERT(result != NULL);
1667
1668 *result = NULL;
1669 memset(&state, 0, sizeof(state));
1670 rv = _compat_grscan(retval, grp, buffer, buflen, &state, 1, name, 0);
1671 _compat_end(&state);
1672 if (rv == NS_SUCCESS)
1673 *result = grp;
1674 return rv;
1675 }
1676
1677 #endif /* _GROUP_COMPAT */
1678
1679
1680 /*
1681 * public functions
1682 */
1683
1684 struct group *
1685 getgrent(void)
1686 {
1687 int rv;
1688 struct group *retval;
1689
1690 static const ns_dtab dtab[] = {
1691 NS_FILES_CB(_files_getgrent, NULL)
1692 NS_DNS_CB(_dns_getgrent, NULL)
1693 NS_NIS_CB(_nis_getgrent, NULL)
1694 NS_COMPAT_CB(_compat_getgrent, NULL)
1695 { 0 }
1696 };
1697
1698 rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrent", defaultcompat,
1699 &retval);
1700 return (rv == NS_SUCCESS) ? retval : NULL;
1701 }
1702
1703 struct group *
1704 getgrgid(gid_t gid)
1705 {
1706 int rv;
1707 struct group *retval;
1708
1709 static const ns_dtab dtab[] = {
1710 NS_FILES_CB(_files_getgrgid, NULL)
1711 NS_DNS_CB(_dns_getgrgid, NULL)
1712 NS_NIS_CB(_nis_getgrgid, NULL)
1713 NS_COMPAT_CB(_compat_getgrgid, NULL)
1714 { 0 }
1715 };
1716
1717 rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrgid", defaultcompat,
1718 &retval, gid);
1719 return (rv == NS_SUCCESS) ? retval : NULL;
1720 }
1721
1722 int
1723 getgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t buflen,
1724 struct group **result)
1725 {
1726 int rv, retval;
1727
1728 static const ns_dtab dtab[] = {
1729 NS_FILES_CB(_files_getgrgid_r, NULL)
1730 NS_DNS_CB(_dns_getgrgid_r, NULL)
1731 NS_NIS_CB(_nis_getgrgid_r, NULL)
1732 NS_COMPAT_CB(_compat_getgrgid_r, NULL)
1733 { 0 }
1734 };
1735
1736 _DIAGASSERT(grp != NULL);
1737 _DIAGASSERT(buffer != NULL);
1738 _DIAGASSERT(result != NULL);
1739
1740 *result = NULL;
1741 retval = 0;
1742 rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrgid_r", defaultcompat,
1743 &retval, gid, grp, buffer, buflen, result);
1744 return (rv == NS_SUCCESS) ? 0 : retval ? retval : ENOENT;
1745 }
1746
1747 struct group *
1748 getgrnam(const char *name)
1749 {
1750 int rv;
1751 struct group *retval;
1752
1753 static const ns_dtab dtab[] = {
1754 NS_FILES_CB(_files_getgrnam, NULL)
1755 NS_DNS_CB(_dns_getgrnam, NULL)
1756 NS_NIS_CB(_nis_getgrnam, NULL)
1757 NS_COMPAT_CB(_compat_getgrnam, NULL)
1758 { 0 }
1759 };
1760
1761 rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrnam", defaultcompat,
1762 &retval, name);
1763 return (rv == NS_SUCCESS) ? retval : NULL;
1764 }
1765
1766 int
1767 getgrnam_r(const char *name, struct group *grp, char *buffer, size_t buflen,
1768 struct group **result)
1769 {
1770 int rv, retval;
1771
1772 static const ns_dtab dtab[] = {
1773 NS_FILES_CB(_files_getgrnam_r, NULL)
1774 NS_DNS_CB(_dns_getgrnam_r, NULL)
1775 NS_NIS_CB(_nis_getgrnam_r, NULL)
1776 NS_COMPAT_CB(_compat_getgrnam_r, NULL)
1777 { 0 }
1778 };
1779
1780 _DIAGASSERT(name != NULL);
1781 _DIAGASSERT(grp != NULL);
1782 _DIAGASSERT(buffer != NULL);
1783 _DIAGASSERT(result != NULL);
1784
1785 *result = NULL;
1786 retval = 0;
1787 rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrnam_r", defaultcompat,
1788 &retval, name, grp, buffer, buflen, result);
1789 return (rv == NS_SUCCESS) ? 0 : retval ? retval : ENOENT;
1790 }
1791
1792 void
1793 endgrent(void)
1794 {
1795 static const ns_dtab dtab[] = {
1796 NS_FILES_CB(_files_endgrent, NULL)
1797 NS_DNS_CB(_dns_endgrent, NULL)
1798 NS_NIS_CB(_nis_endgrent, NULL)
1799 NS_COMPAT_CB(_compat_endgrent, NULL)
1800 { 0 }
1801 };
1802
1803 /* force all endgrent() methods */
1804 (void) nsdispatch(NULL, dtab, NSDB_GROUP, "endgrent",
1805 defaultcompat_forceall);
1806 }
1807
1808 int
1809 setgroupent(int stayopen)
1810 {
1811 static const ns_dtab dtab[] = {
1812 NS_FILES_CB(_files_setgroupent, NULL)
1813 NS_DNS_CB(_dns_setgroupent, NULL)
1814 NS_NIS_CB(_nis_setgroupent, NULL)
1815 NS_COMPAT_CB(_compat_setgroupent, NULL)
1816 { 0 }
1817 };
1818 int rv, retval;
1819
1820 /* force all setgroupent() methods */
1821 rv = nsdispatch(NULL, dtab, NSDB_GROUP, "setgroupent",
1822 defaultcompat_forceall, &retval, stayopen);
1823 return (rv == NS_SUCCESS) ? retval : 0;
1824 }
1825
1826 void
1827 setgrent(void)
1828 {
1829 static const ns_dtab dtab[] = {
1830 NS_FILES_CB(_files_setgrent, NULL)
1831 NS_DNS_CB(_dns_setgrent, NULL)
1832 NS_NIS_CB(_nis_setgrent, NULL)
1833 NS_COMPAT_CB(_compat_setgrent, NULL)
1834 { 0 }
1835 };
1836
1837 /* force all setgrent() methods */
1838 (void) nsdispatch(NULL, dtab, NSDB_GROUP, "setgrent",
1839 defaultcompat_forceall);
1840 }
1841