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