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