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