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