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