source: vendor/FreeBSD-libc/current/gen/getgrent.c

Last change on this file was 1695, checked in by bird, 21 years ago

FreeBSD 5.3 libc sources.

  • Property cvs2svn:cvs-rev set to 1.1.1.2
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 24.8 KB
Line 
1/*-
2 * Copyright (c) 2003 Networks Associates Technology, Inc.
3 * All rights reserved.
4 *
5 * This software was developed for the FreeBSD Project by
6 * Jacques A. Vidrine, Safeport Network Services, and Network
7 * Associates Laboratories, the Security Research Division of Network
8 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
9 * ("CBOSS"), as part of the DARPA CHATS research program.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 */
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD: src/lib/libc/gen/getgrent.c,v 1.32 2004/05/17 22:15:49 kientzle Exp $");
35
36#include "namespace.h"
37#include <sys/param.h>
38#ifdef YP
39#include <rpc/rpc.h>
40#include <rpcsvc/yp_prot.h>
41#include <rpcsvc/ypclnt.h>
42#endif
43#include <ctype.h>
44#include <errno.h>
45#ifdef HESIOD
46#include <hesiod.h>
47#endif
48#include <grp.h>
49#include <nsswitch.h>
50#include <pthread.h>
51#include <pthread_np.h>
52#include <stdio.h>
53#include <stdlib.h>
54#include <string.h>
55#include <syslog.h>
56#include <unistd.h>
57#include "un-namespace.h"
58#include "libc_private.h"
59#include "nss_tls.h"
60
61
62enum constants {
63 GRP_STORAGE_INITIAL = 1 << 10, /* 1 KByte */
64 GRP_STORAGE_MAX = 1 << 20, /* 1 MByte */
65 SETGRENT = 1,
66 ENDGRENT = 2,
67 HESIOD_NAME_MAX = 256,
68};
69
70static const ns_src defaultsrc[] = {
71 { NSSRC_COMPAT, NS_SUCCESS },
72 { NULL, 0 }
73};
74
75int __gr_match_entry(const char *, size_t, enum nss_lookup_type,
76 const char *, gid_t);
77int __gr_parse_entry(char *, size_t, struct group *, char *, size_t,
78 int *);
79
80static int is_comment_line(const char *, size_t);
81
82union key {
83 const char *name;
84 gid_t gid;
85};
86static struct group *getgr(int (*)(union key, struct group *, char *, size_t,
87 struct group **), union key);
88static int wrap_getgrnam_r(union key, struct group *, char *, size_t,
89 struct group **);
90static int wrap_getgrgid_r(union key, struct group *, char *, size_t,
91 struct group **);
92static int wrap_getgrent_r(union key, struct group *, char *, size_t,
93 struct group **);
94
95struct files_state {
96 FILE *fp;
97 int stayopen;
98};
99static void files_endstate(void *);
100NSS_TLS_HANDLING(files);
101static int files_setgrent(void *, void *, va_list);
102static int files_group(void *, void *, va_list);
103
104
105#ifdef HESIOD
106struct dns_state {
107 long counter;
108};
109static void dns_endstate(void *);
110NSS_TLS_HANDLING(dns);
111static int dns_setgrent(void *, void *, va_list);
112static int dns_group(void *, void *, va_list);
113#endif
114
115
116#ifdef YP
117struct nis_state {
118 char domain[MAXHOSTNAMELEN];
119 int done;
120 char *key;
121 int keylen;
122};
123static void nis_endstate(void *);
124NSS_TLS_HANDLING(nis);
125static int nis_setgrent(void *, void *, va_list);
126static int nis_group(void *, void *, va_list);
127#endif
128
129struct compat_state {
130 FILE *fp;
131 int stayopen;
132 char *name;
133 enum _compat {
134 COMPAT_MODE_OFF = 0,
135 COMPAT_MODE_ALL,
136 COMPAT_MODE_NAME
137 } compat;
138};
139static void compat_endstate(void *);
140NSS_TLS_HANDLING(compat);
141static int compat_setgrent(void *, void *, va_list);
142static int compat_group(void *, void *, va_list);
143
144
145/* XXX IEEE Std 1003.1, 2003 specifies `void setgrent(void)' */
146int
147setgrent(void)
148{
149 static const ns_dtab dtab[] = {
150 { NSSRC_FILES, files_setgrent, (void *)SETGRENT },
151#ifdef HESIOD
152 { NSSRC_DNS, dns_setgrent, (void *)SETGRENT },
153#endif
154#ifdef YP
155 { NSSRC_NIS, nis_setgrent, (void *)SETGRENT },
156#endif
157 { NSSRC_COMPAT, compat_setgrent, (void *)SETGRENT },
158 { NULL, NULL, NULL }
159 };
160 (void)_nsdispatch(NULL, dtab, NSDB_GROUP, "setgrent", defaultsrc, 0);
161 return (1);
162}
163
164
165int
166setgroupent(int stayopen)
167{
168 static const ns_dtab dtab[] = {
169 { NSSRC_FILES, files_setgrent, (void *)SETGRENT },
170#ifdef HESIOD
171 { NSSRC_DNS, dns_setgrent, (void *)SETGRENT },
172#endif
173#ifdef YP
174 { NSSRC_NIS, nis_setgrent, (void *)SETGRENT },
175#endif
176 { NSSRC_COMPAT, compat_setgrent, (void *)SETGRENT },
177 { NULL, NULL, NULL }
178 };
179 (void)_nsdispatch(NULL, dtab, NSDB_GROUP, "setgrent", defaultsrc,
180 stayopen);
181 return (1);
182}
183
184
185void
186endgrent(void)
187{
188 static const ns_dtab dtab[] = {
189 { NSSRC_FILES, files_setgrent, (void *)ENDGRENT },
190#ifdef HESIOD
191 { NSSRC_DNS, dns_setgrent, (void *)ENDGRENT },
192#endif
193#ifdef YP
194 { NSSRC_NIS, nis_setgrent, (void *)ENDGRENT },
195#endif
196 { NSSRC_COMPAT, compat_setgrent, (void *)ENDGRENT },
197 { NULL, NULL, NULL }
198 };
199 (void)_nsdispatch(NULL, dtab, NSDB_GROUP, "endgrent", defaultsrc);
200}
201
202
203int
204getgrent_r(struct group *grp, char *buffer, size_t bufsize,
205 struct group **result)
206{
207 static const ns_dtab dtab[] = {
208 { NSSRC_FILES, files_group, (void *)nss_lt_all },
209#ifdef HESIOD
210 { NSSRC_DNS, dns_group, (void *)nss_lt_all },
211#endif
212#ifdef YP
213 { NSSRC_NIS, nis_group, (void *)nss_lt_all },
214#endif
215 { NSSRC_COMPAT, compat_group, (void *)nss_lt_all },
216 { NULL, NULL, NULL }
217 };
218 int rv, ret_errno;
219
220 ret_errno = 0;
221 *result = NULL;
222 rv = _nsdispatch(result, dtab, NSDB_GROUP, "getgrent_r", defaultsrc,
223 grp, buffer, bufsize, &ret_errno);
224 if (rv == NS_SUCCESS)
225 return (0);
226 else
227 return (ret_errno);
228}
229
230
231int
232getgrnam_r(const char *name, struct group *grp, char *buffer, size_t bufsize,
233 struct group **result)
234{
235 static const ns_dtab dtab[] = {
236 { NSSRC_FILES, files_group, (void *)nss_lt_name },
237#ifdef HESIOD
238 { NSSRC_DNS, dns_group, (void *)nss_lt_name },
239#endif
240#ifdef YP
241 { NSSRC_NIS, nis_group, (void *)nss_lt_name },
242#endif
243 { NSSRC_COMPAT, compat_group, (void *)nss_lt_name },
244 { NULL, NULL, NULL }
245 };
246 int rv, ret_errno;
247
248 ret_errno = 0;
249 *result = NULL;
250 rv = _nsdispatch(result, dtab, NSDB_GROUP, "getgrnam_r", defaultsrc,
251 name, grp, buffer, bufsize, &ret_errno);
252 if (rv == NS_SUCCESS)
253 return (0);
254 else
255 return (ret_errno);
256}
257
258
259int
260getgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t bufsize,
261 struct group **result)
262{
263 static const ns_dtab dtab[] = {
264 { NSSRC_FILES, files_group, (void *)nss_lt_id },
265#ifdef HESIOD
266 { NSSRC_DNS, dns_group, (void *)nss_lt_id },
267#endif
268#ifdef YP
269 { NSSRC_NIS, nis_group, (void *)nss_lt_id },
270#endif
271 { NSSRC_COMPAT, compat_group, (void *)nss_lt_id },
272 { NULL, NULL, NULL }
273 };
274 int rv, ret_errno;
275
276 ret_errno = 0;
277 *result = NULL;
278 rv = _nsdispatch(result, dtab, NSDB_GROUP, "getgrgid_r", defaultsrc,
279 gid, grp, buffer, bufsize, &ret_errno);
280 if (rv == NS_SUCCESS)
281 return (0);
282 else
283 return (ret_errno);
284}
285
286
287static struct group grp;
288static char *grp_storage;
289static size_t grp_storage_size;
290
291static struct group *
292getgr(int (*fn)(union key, struct group *, char *, size_t, struct group **),
293 union key key)
294{
295 int rv;
296 struct group *res;
297
298 if (grp_storage == NULL) {
299 grp_storage = malloc(GRP_STORAGE_INITIAL);
300 if (grp_storage == NULL)
301 return (NULL);
302 grp_storage_size = GRP_STORAGE_INITIAL;
303 }
304 do {
305 rv = fn(key, &grp, grp_storage, grp_storage_size, &res);
306 if (res == NULL && rv == ERANGE) {
307 free(grp_storage);
308 if ((grp_storage_size << 1) > GRP_STORAGE_MAX) {
309 grp_storage = NULL;
310 errno = ERANGE;
311 return (NULL);
312 }
313 grp_storage_size <<= 1;
314 grp_storage = malloc(grp_storage_size);
315 if (grp_storage == NULL)
316 return (NULL);
317 }
318 } while (res == NULL && rv == ERANGE);
319 if (rv != 0)
320 errno = rv;
321 return (res);
322}
323
324
325static int
326wrap_getgrnam_r(union key key, struct group *grp, char *buffer, size_t bufsize,
327 struct group **res)
328{
329 return (getgrnam_r(key.name, grp, buffer, bufsize, res));
330}
331
332
333static int
334wrap_getgrgid_r(union key key, struct group *grp, char *buffer, size_t bufsize,
335 struct group **res)
336{
337 return (getgrgid_r(key.gid, grp, buffer, bufsize, res));
338}
339
340
341static int
342wrap_getgrent_r(union key key __unused, struct group *grp, char *buffer,
343 size_t bufsize, struct group **res)
344{
345 return (getgrent_r(grp, buffer, bufsize, res));
346}
347
348
349struct group *
350getgrnam(const char *name)
351{
352 union key key;
353
354 key.name = name;
355 return (getgr(wrap_getgrnam_r, key));
356}
357
358
359struct group *
360getgrgid(gid_t gid)
361{
362 union key key;
363
364 key.gid = gid;
365 return (getgr(wrap_getgrgid_r, key));
366}
367
368
369struct group *
370getgrent(void)
371{
372 union key key;
373
374 key.gid = 0; /* not used */
375 return (getgr(wrap_getgrent_r, key));
376}
377
378
379static int
380is_comment_line(const char *s, size_t n)
381{
382 const char *eom;
383
384 eom = &s[n];
385
386 for (; s < eom; s++)
387 if (*s == '#' || !isspace((unsigned char)*s))
388 break;
389 return (*s == '#' || s == eom);
390}
391
392
393/*
394 * files backend
395 */
396static void
397files_endstate(void *p)
398{
399
400 if (p == NULL)
401 return;
402 if (((struct files_state *)p)->fp != NULL)
403 fclose(((struct files_state *)p)->fp);
404 free(p);
405}
406
407
408static int
409files_setgrent(void *retval, void *mdata, va_list ap)
410{
411 struct files_state *st;
412 int rv, stayopen;
413
414 rv = files_getstate(&st);
415 if (rv != 0)
416 return (NS_UNAVAIL);
417 switch ((enum constants)mdata) {
418 case SETGRENT:
419 stayopen = va_arg(ap, int);
420 if (st->fp != NULL)
421 rewind(st->fp);
422 else if (stayopen)
423 st->fp = fopen(_PATH_GROUP, "r");
424 break;
425 case ENDGRENT:
426 if (st->fp != NULL) {
427 fclose(st->fp);
428 st->fp = NULL;
429 }
430 break;
431 default:
432 break;
433 }
434 return (NS_UNAVAIL);
435}
436
437
438static int
439files_group(void *retval, void *mdata, va_list ap)
440{
441 struct files_state *st;
442 enum nss_lookup_type how;
443 const char *name, *line;
444 struct group *grp;
445 gid_t gid;
446 char *buffer;
447 size_t bufsize, linesize;
448 int rv, stayopen, *errnop;
449
450 name = NULL;
451 gid = (gid_t)-1;
452 how = (enum nss_lookup_type)mdata;
453 switch (how) {
454 case nss_lt_name:
455 name = va_arg(ap, const char *);
456 break;
457 case nss_lt_id:
458 gid = va_arg(ap, gid_t);
459 break;
460 case nss_lt_all:
461 break;
462 default:
463 return (NS_NOTFOUND);
464 }
465 grp = va_arg(ap, struct group *);
466 buffer = va_arg(ap, char *);
467 bufsize = va_arg(ap, size_t);
468 errnop = va_arg(ap, int *);
469 *errnop = files_getstate(&st);
470 if (*errnop != 0)
471 return (NS_UNAVAIL);
472 if (st->fp == NULL &&
473 ((st->fp = fopen(_PATH_GROUP, "r")) == NULL)) {
474 *errnop = errno;
475 return (NS_UNAVAIL);
476 }
477 if (how == nss_lt_all)
478 stayopen = 1;
479 else {
480 rewind(st->fp);
481 stayopen = st->stayopen;
482 }
483 rv = NS_NOTFOUND;
484 while ((line = fgetln(st->fp, &linesize)) != NULL) {
485 if (line[linesize-1] == '\n')
486 linesize--;
487 rv = __gr_match_entry(line, linesize, how, name, gid);
488 if (rv != NS_SUCCESS)
489 continue;
490 /* We need room at least for the line, a string NUL
491 * terminator, alignment padding, and one (char *)
492 * pointer for the member list terminator.
493 */
494 if (bufsize <= linesize + _ALIGNBYTES + sizeof(char *)) {
495 *errnop = ERANGE;
496 rv = NS_RETURN;
497 break;
498 }
499 memcpy(buffer, line, linesize);
500 buffer[linesize] = '\0';
501 rv = __gr_parse_entry(buffer, linesize, grp,
502 &buffer[linesize + 1], bufsize - linesize - 1, errnop);
503 if (rv & NS_TERMINATE)
504 break;
505 }
506 if (!stayopen && st->fp != NULL) {
507 fclose(st->fp);
508 st->fp = NULL;
509 }
510 if (rv == NS_SUCCESS && retval != NULL)
511 *(struct group **)retval = grp;
512 return (rv);
513}
514
515
516#ifdef HESIOD
517/*
518 * dns backend
519 */
520static void
521dns_endstate(void *p)
522{
523
524 free(p);
525}
526
527
528static int
529dns_setgrent(void *retval, void *cb_data, va_list ap)
530{
531 struct dns_state *st;
532 int rv;
533
534 rv = dns_getstate(&st);
535 if (rv != 0)
536 return (NS_UNAVAIL);
537 st->counter = 0;
538 return (NS_UNAVAIL);
539}
540
541
542static int
543dns_group(void *retval, void *mdata, va_list ap)
544{
545 char buf[HESIOD_NAME_MAX];
546 struct dns_state *st;
547 struct group *grp;
548 const char *name, *label;
549 void *ctx;
550 char *buffer, **hes;
551 size_t bufsize, adjsize, linesize;
552 gid_t gid;
553 enum nss_lookup_type how;
554 int rv, *errnop;
555
556 ctx = NULL;
557 hes = NULL;
558 name = NULL;
559 gid = (gid_t)-1;
560 how = (enum nss_lookup_type)mdata;
561 switch (how) {
562 case nss_lt_name:
563 name = va_arg(ap, const char *);
564 break;
565 case nss_lt_id:
566 gid = va_arg(ap, gid_t);
567 break;
568 case nss_lt_all:
569 break;
570 }
571 grp = va_arg(ap, struct group *);
572 buffer = va_arg(ap, char *);
573 bufsize = va_arg(ap, size_t);
574 errnop = va_arg(ap, int *);
575 *errnop = dns_getstate(&st);
576 if (*errnop != 0)
577 return (NS_UNAVAIL);
578 if (hesiod_init(&ctx) != 0) {
579 *errnop = errno;
580 rv = NS_UNAVAIL;
581 goto fin;
582 }
583 do {
584 rv = NS_NOTFOUND;
585 switch (how) {
586 case nss_lt_name:
587 label = name;
588 break;
589 case nss_lt_id:
590 if (snprintf(buf, sizeof(buf), "%lu",
591 (unsigned long)gid) >= sizeof(buf))
592 goto fin;
593 label = buf;
594 break;
595 case nss_lt_all:
596 if (st->counter < 0)
597 goto fin;
598 if (snprintf(buf, sizeof(buf), "group-%ld",
599 st->counter++) >= sizeof(buf))
600 goto fin;
601 label = buf;
602 break;
603 }
604 hes = hesiod_resolve(ctx, label,
605 how == nss_lt_id ? "gid" : "group");
606 if ((how == nss_lt_id && hes == NULL &&
607 (hes = hesiod_resolve(ctx, buf, "group")) == NULL) ||
608 hes == NULL) {
609 if (how == nss_lt_all)
610 st->counter = -1;
611 if (errno != ENOENT)
612 *errnop = errno;
613 goto fin;
614 }
615 rv = __gr_match_entry(hes[0], strlen(hes[0]), how, name, gid);
616 if (rv != NS_SUCCESS) {
617 hesiod_free_list(ctx, hes);
618 hes = NULL;
619 continue;
620 }
621 /* We need room at least for the line, a string NUL
622 * terminator, alignment padding, and one (char *)
623 * pointer for the member list terminator.
624 */
625 adjsize = bufsize - _ALIGNBYTES - sizeof(char *);
626 linesize = strlcpy(buffer, hes[0], adjsize);
627 if (linesize >= adjsize) {
628 *errnop = ERANGE;
629 rv = NS_RETURN;
630 goto fin;
631 }
632 hesiod_free_list(ctx, hes);
633 hes = NULL;
634 rv = __gr_parse_entry(buffer, linesize, grp,
635 &buffer[linesize + 1], bufsize - linesize - 1, errnop);
636 } while (how == nss_lt_all && !(rv & NS_TERMINATE));
637fin:
638 if (hes != NULL)
639 hesiod_free_list(ctx, hes);
640 if (ctx != NULL)
641 hesiod_end(ctx);
642 if (rv == NS_SUCCESS && retval != NULL)
643 *(struct group **)retval = grp;
644 return (rv);
645}
646#endif /* HESIOD */
647
648
649#ifdef YP
650/*
651 * nis backend
652 */
653static void
654nis_endstate(void *p)
655{
656
657 if (p == NULL)
658 return;
659 free(((struct nis_state *)p)->key);
660 free(p);
661}
662
663
664static int
665nis_setgrent(void *retval, void *cb_data, va_list ap)
666{
667 struct nis_state *st;
668 int rv;
669
670 rv = nis_getstate(&st);
671 if (rv != 0)
672 return (NS_UNAVAIL);
673 st->done = 0;
674 free(st->key);
675 st->key = NULL;
676 return (NS_UNAVAIL);
677}
678
679
680static int
681nis_group(void *retval, void *mdata, va_list ap)
682{
683 char *map;
684 struct nis_state *st;
685 struct group *grp;
686 const char *name;
687 char *buffer, *key, *result;
688 size_t bufsize;
689 gid_t gid;
690 enum nss_lookup_type how;
691 int *errnop, keylen, resultlen, rv;
692
693 name = NULL;
694 gid = (gid_t)-1;
695 how = (enum nss_lookup_type)mdata;
696 switch (how) {
697 case nss_lt_name:
698 name = va_arg(ap, const char *);
699 map = "group.byname";
700 break;
701 case nss_lt_id:
702 gid = va_arg(ap, gid_t);
703 map = "group.bygid";
704 break;
705 case nss_lt_all:
706 map = "group.byname";
707 break;
708 }
709 grp = va_arg(ap, struct group *);
710 buffer = va_arg(ap, char *);
711 bufsize = va_arg(ap, size_t);
712 errnop = va_arg(ap, int *);
713 *errnop = nis_getstate(&st);
714 if (*errnop != 0)
715 return (NS_UNAVAIL);
716 if (st->domain[0] == '\0') {
717 if (getdomainname(st->domain, sizeof(st->domain)) != 0) {
718 *errnop = errno;
719 return (NS_UNAVAIL);
720 }
721 }
722 result = NULL;
723 do {
724 rv = NS_NOTFOUND;
725 switch (how) {
726 case nss_lt_name:
727 if (strlcpy(buffer, name, bufsize) >= bufsize)
728 goto erange;
729 break;
730 case nss_lt_id:
731 if (snprintf(buffer, bufsize, "%lu",
732 (unsigned long)gid) >= bufsize)
733 goto erange;
734 break;
735 case nss_lt_all:
736 if (st->done)
737 goto fin;
738 break;
739 }
740 result = NULL;
741 if (how == nss_lt_all) {
742 if (st->key == NULL)
743 rv = yp_first(st->domain, map, &st->key,
744 &st->keylen, &result, &resultlen);
745 else {
746 key = st->key;
747 keylen = st->keylen;
748 st->key = NULL;
749 rv = yp_next(st->domain, map, key, keylen,
750 &st->key, &st->keylen, &result,
751 &resultlen);
752 free(key);
753 }
754 if (rv != 0) {
755 free(result);
756 free(st->key);
757 st->key = NULL;
758 if (rv == YPERR_NOMORE) {
759 st->done = 1;
760 rv = NS_NOTFOUND;
761 } else
762 rv = NS_UNAVAIL;
763 goto fin;
764 }
765 } else {
766 rv = yp_match(st->domain, map, buffer, strlen(buffer),
767 &result, &resultlen);
768 if (rv == YPERR_KEY) {
769 rv = NS_NOTFOUND;
770 continue;
771 } else if (rv != 0) {
772 free(result);
773 rv = NS_UNAVAIL;
774 continue;
775 }
776 }
777 /* We need room at least for the line, a string NUL
778 * terminator, alignment padding, and one (char *)
779 * pointer for the member list terminator.
780 */
781 if (resultlen >= bufsize - _ALIGNBYTES - sizeof(char *))
782 goto erange;
783 memcpy(buffer, result, resultlen);
784 buffer[resultlen] = '\0';
785 free(result);
786 rv = __gr_match_entry(buffer, resultlen, how, name, gid);
787 if (rv == NS_SUCCESS)
788 rv = __gr_parse_entry(buffer, resultlen, grp,
789 &buffer[resultlen+1], bufsize - resultlen - 1,
790 errnop);
791 } while (how == nss_lt_all && !(rv & NS_TERMINATE));
792fin:
793 if (rv == NS_SUCCESS && retval != NULL)
794 *(struct group **)retval = grp;
795 return (rv);
796erange:
797 *errnop = ERANGE;
798 return (NS_RETURN);
799}
800#endif /* YP */
801
802
803
804/*
805 * compat backend
806 */
807static void
808compat_endstate(void *p)
809{
810 struct compat_state *st;
811
812 if (p == NULL)
813 return;
814 st = (struct compat_state *)p;
815 free(st->name);
816 if (st->fp != NULL)
817 fclose(st->fp);
818 free(p);
819}
820
821
822static int
823compat_setgrent(void *retval, void *mdata, va_list ap)
824{
825 static const ns_src compatsrc[] = {
826#ifdef YP
827 { NSSRC_NIS, NS_SUCCESS },
828#endif
829 { NULL, 0 }
830 };
831 ns_dtab dtab[] = {
832#ifdef HESIOD
833 { NSSRC_DNS, dns_setgrent, NULL },
834#endif
835#ifdef YP
836 { NSSRC_NIS, nis_setgrent, NULL },
837#endif
838 { NULL, NULL, NULL }
839 };
840 struct compat_state *st;
841 int rv, stayopen;
842
843#define set_setent(x, y) do { \
844 int i; \
845 \
846 for (i = 0; i < (sizeof(x)/sizeof(x[0])) - 1; i++) \
847 x[i].mdata = (void *)y; \
848} while (0)
849
850 rv = compat_getstate(&st);
851 if (rv != 0)
852 return (NS_UNAVAIL);
853 switch ((enum constants)mdata) {
854 case SETGRENT:
855 stayopen = va_arg(ap, int);
856 if (st->fp != NULL)
857 rewind(st->fp);
858 else if (stayopen)
859 st->fp = fopen(_PATH_GROUP, "r");
860 set_setent(dtab, mdata);
861 (void)_nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "setgrent",
862 compatsrc, 0);
863 break;
864 case ENDGRENT:
865 if (st->fp != NULL) {
866 fclose(st->fp);
867 st->fp = NULL;
868 }
869 set_setent(dtab, mdata);
870 (void)_nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "endgrent",
871 compatsrc, 0);
872 break;
873 default:
874 break;
875 }
876 st->compat = COMPAT_MODE_OFF;
877 free(st->name);
878 st->name = NULL;
879 return (NS_UNAVAIL);
880#undef set_setent
881}
882
883
884static int
885compat_group(void *retval, void *mdata, va_list ap)
886{
887 static const ns_src compatsrc[] = {
888#ifdef YP
889 { NSSRC_NIS, NS_SUCCESS },
890#endif
891 { NULL, 0 }
892 };
893 ns_dtab dtab[] = {
894#ifdef YP
895 { NSSRC_NIS, nis_group, NULL },
896#endif
897#ifdef HESIOD
898 { NSSRC_DNS, dns_group, NULL },
899#endif
900 { NULL, NULL, NULL }
901 };
902 struct compat_state *st;
903 enum nss_lookup_type how;
904 const char *name, *line;
905 struct group *grp;
906 gid_t gid;
907 char *buffer, *p;
908 void *discard;
909 size_t bufsize, linesize;
910 int rv, stayopen, *errnop;
911
912#define set_lookup_type(x, y) do { \
913 int i; \
914 \
915 for (i = 0; i < (sizeof(x)/sizeof(x[0])) - 1; i++) \
916 x[i].mdata = (void *)y; \
917} while (0)
918
919 name = NULL;
920 gid = (gid_t)-1;
921 how = (enum nss_lookup_type)mdata;
922 switch (how) {
923 case nss_lt_name:
924 name = va_arg(ap, const char *);
925 break;
926 case nss_lt_id:
927 gid = va_arg(ap, gid_t);
928 break;
929 case nss_lt_all:
930 break;
931 default:
932 return (NS_NOTFOUND);
933 }
934 grp = va_arg(ap, struct group *);
935 buffer = va_arg(ap, char *);
936 bufsize = va_arg(ap, size_t);
937 errnop = va_arg(ap, int *);
938 *errnop = compat_getstate(&st);
939 if (*errnop != 0)
940 return (NS_UNAVAIL);
941 if (st->fp == NULL &&
942 ((st->fp = fopen(_PATH_GROUP, "r")) == NULL)) {
943 *errnop = errno;
944 rv = NS_UNAVAIL;
945 goto fin;
946 }
947 if (how == nss_lt_all)
948 stayopen = 1;
949 else {
950 rewind(st->fp);
951 stayopen = st->stayopen;
952 }
953docompat:
954 switch (st->compat) {
955 case COMPAT_MODE_ALL:
956 set_lookup_type(dtab, how);
957 switch (how) {
958 case nss_lt_all:
959 rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT,
960 "getgrent_r", compatsrc, grp, buffer, bufsize,
961 errnop);
962 break;
963 case nss_lt_id:
964 rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT,
965 "getgrgid_r", compatsrc, gid, grp, buffer, bufsize,
966 errnop);
967 break;
968 case nss_lt_name:
969 rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT,
970 "getgrnam_r", compatsrc, name, grp, buffer,
971 bufsize, errnop);
972 break;
973 }
974 if (rv & NS_TERMINATE)
975 goto fin;
976 st->compat = COMPAT_MODE_OFF;
977 break;
978 case COMPAT_MODE_NAME:
979 set_lookup_type(dtab, nss_lt_name);
980 rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT,
981 "getgrnam_r", compatsrc, st->name, grp, buffer, bufsize,
982 errnop);
983 switch (rv) {
984 case NS_SUCCESS:
985 switch (how) {
986 case nss_lt_name:
987 if (strcmp(name, grp->gr_name) != 0)
988 rv = NS_NOTFOUND;
989 break;
990 case nss_lt_id:
991 if (gid != grp->gr_gid)
992 rv = NS_NOTFOUND;
993 break;
994 default:
995 break;
996 }
997 break;
998 case NS_RETURN:
999 goto fin;
1000 default:
1001 break;
1002 }
1003 free(st->name);
1004 st->name = NULL;
1005 st->compat = COMPAT_MODE_OFF;
1006 if (rv == NS_SUCCESS)
1007 goto fin;
1008 break;
1009 default:
1010 break;
1011 }
1012 rv = NS_NOTFOUND;
1013 while ((line = fgetln(st->fp, &linesize)) != NULL) {
1014 if (line[linesize-1] == '\n')
1015 linesize--;
1016 if (linesize > 2 && line[0] == '+') {
1017 p = memchr(&line[1], ':', linesize);
1018 if (p == NULL || p == &line[1])
1019 st->compat = COMPAT_MODE_ALL;
1020 else {
1021 st->name = malloc(p - line);
1022 if (st->name == NULL) {
1023 syslog(LOG_ERR,
1024 "getgrent memory allocation failure");
1025 *errnop = ENOMEM;
1026 rv = NS_UNAVAIL;
1027 break;
1028 }
1029 memcpy(st->name, &line[1], p - line - 1);
1030 st->name[p - line - 1] = '\0';
1031 st->compat = COMPAT_MODE_NAME;
1032 }
1033 goto docompat;
1034 }
1035 rv = __gr_match_entry(line, linesize, how, name, gid);
1036 if (rv != NS_SUCCESS)
1037 continue;
1038 /* We need room at least for the line, a string NUL
1039 * terminator, alignment padding, and one (char *)
1040 * pointer for the member list terminator.
1041 */
1042 if (bufsize <= linesize + _ALIGNBYTES + sizeof(char *)) {
1043 *errnop = ERANGE;
1044 rv = NS_RETURN;
1045 break;
1046 }
1047 memcpy(buffer, line, linesize);
1048 buffer[linesize] = '\0';
1049 rv = __gr_parse_entry(buffer, linesize, grp,
1050 &buffer[linesize + 1], bufsize - linesize - 1, errnop);
1051 if (rv & NS_TERMINATE)
1052 break;
1053 }
1054fin:
1055 if (!stayopen && st->fp != NULL) {
1056 fclose(st->fp);
1057 st->fp = NULL;
1058 }
1059 if (rv == NS_SUCCESS && retval != NULL)
1060 *(struct group **)retval = grp;
1061 return (rv);
1062#undef set_lookup_type
1063}
1064
1065
1066/*
1067 * common group line matching and parsing
1068 */
1069int
1070__gr_match_entry(const char *line, size_t linesize, enum nss_lookup_type how,
1071 const char *name, gid_t gid)
1072{
1073 size_t namesize;
1074 const char *p, *eol;
1075 char *q;
1076 unsigned long n;
1077 int i, needed;
1078
1079 if (linesize == 0 || is_comment_line(line, linesize))
1080 return (NS_NOTFOUND);
1081 switch (how) {
1082 case nss_lt_name: needed = 1; break;
1083 case nss_lt_id: needed = 2; break;
1084 default: needed = 2; break;
1085 }
1086 eol = &line[linesize];
1087 for (p = line, i = 0; i < needed && p < eol; p++)
1088 if (*p == ':')
1089 i++;
1090 if (i < needed)
1091 return (NS_NOTFOUND);
1092 switch (how) {
1093 case nss_lt_name:
1094 namesize = strlen(name);
1095 if (namesize + 1 == (size_t)(p - line) &&
1096 memcmp(line, name, namesize) == 0)
1097 return (NS_SUCCESS);
1098 break;
1099 case nss_lt_id:
1100 n = strtoul(p, &q, 10);
1101 if (q < eol && *q == ':' && gid == (gid_t)n)
1102 return (NS_SUCCESS);
1103 break;
1104 case nss_lt_all:
1105 return (NS_SUCCESS);
1106 default:
1107 break;
1108 }
1109 return (NS_NOTFOUND);
1110}
1111
1112
1113int
1114__gr_parse_entry(char *line, size_t linesize, struct group *grp, char *membuf,
1115 size_t membufsize, int *errnop)
1116{
1117 char *s_gid, *s_mem, *p, **members;
1118 unsigned long n;
1119 int maxmembers;
1120
1121 memset(grp, 0, sizeof(*grp));
1122 members = (char **)_ALIGN(membuf);
1123 membufsize -= (char *)members - membuf;
1124 maxmembers = membufsize / sizeof(*members);
1125 if (maxmembers <= 0 ||
1126 (grp->gr_name = strsep(&line, ":")) == NULL ||
1127 grp->gr_name[0] == '\0' ||
1128 (grp->gr_passwd = strsep(&line, ":")) == NULL ||
1129 (s_gid = strsep(&line, ":")) == NULL ||
1130 s_gid[0] == '\0')
1131 return (NS_NOTFOUND);
1132 s_mem = line;
1133 n = strtoul(s_gid, &s_gid, 10);
1134 if (s_gid[0] != '\0')
1135 return (NS_NOTFOUND);
1136 grp->gr_gid = (gid_t)n;
1137 grp->gr_mem = members;
1138 while (maxmembers > 1 && s_mem != NULL) {
1139 p = strsep(&s_mem, ",");
1140 if (p != NULL && *p != '\0') {
1141 *members++ = p;
1142 maxmembers--;
1143 }
1144 }
1145 *members = NULL;
1146 if (s_mem == NULL)
1147 return (NS_SUCCESS);
1148 else {
1149 *errnop = ERANGE;
1150 return (NS_RETURN);
1151 }
1152}
Note: See TracBrowser for help on using the repository browser.