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

Last change on this file was 1500, checked in by (none), 21 years ago

This commit was manufactured by cvs2svn to create branch 'FREEBSD'.

  • Property cvs2svn:cvs-rev set to 1.1
  • 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.31 2003/05/01 19:03:13 nectar 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 return (NULL);
311 }
312 grp_storage_size <<= 1;
313 grp_storage = malloc(grp_storage_size);
314 if (grp_storage == NULL)
315 return (NULL);
316 }
317 } while (res == NULL && rv == ERANGE);
318 return (res);
319}
320
321
322static int
323wrap_getgrnam_r(union key key, struct group *grp, char *buffer, size_t bufsize,
324 struct group **res)
325{
326 return (getgrnam_r(key.name, grp, buffer, bufsize, res));
327}
328
329
330static int
331wrap_getgrgid_r(union key key, struct group *grp, char *buffer, size_t bufsize,
332 struct group **res)
333{
334 return (getgrgid_r(key.gid, grp, buffer, bufsize, res));
335}
336
337
338static int
339wrap_getgrent_r(union key key __unused, struct group *grp, char *buffer,
340 size_t bufsize, struct group **res)
341{
342 return (getgrent_r(grp, buffer, bufsize, res));
343}
344
345
346struct group *
347getgrnam(const char *name)
348{
349 union key key;
350
351 key.name = name;
352 return (getgr(wrap_getgrnam_r, key));
353}
354
355
356struct group *
357getgrgid(gid_t gid)
358{
359 union key key;
360
361 key.gid = gid;
362 return (getgr(wrap_getgrgid_r, key));
363}
364
365
366struct group *
367getgrent(void)
368{
369 union key key;
370
371 key.gid = 0; /* not used */
372 return (getgr(wrap_getgrent_r, key));
373}
374
375
376static int
377is_comment_line(const char *s, size_t n)
378{
379 const char *eom;
380
381 eom = &s[n];
382
383 for (; s < eom; s++)
384 if (*s == '#' || !isspace((unsigned char)*s))
385 break;
386 return (*s == '#' || s == eom);
387}
388
389
390/*
391 * files backend
392 */
393static void
394files_endstate(void *p)
395{
396
397 if (p == NULL)
398 return;
399 if (((struct files_state *)p)->fp != NULL)
400 fclose(((struct files_state *)p)->fp);
401 free(p);
402}
403
404
405static int
406files_setgrent(void *retval, void *mdata, va_list ap)
407{
408 struct files_state *st;
409 int rv, stayopen;
410
411 rv = files_getstate(&st);
412 if (rv != 0)
413 return (NS_UNAVAIL);
414 switch ((enum constants)mdata) {
415 case SETGRENT:
416 stayopen = va_arg(ap, int);
417 if (st->fp != NULL)
418 rewind(st->fp);
419 else if (stayopen)
420 st->fp = fopen(_PATH_GROUP, "r");
421 break;
422 case ENDGRENT:
423 if (st->fp != NULL) {
424 fclose(st->fp);
425 st->fp = NULL;
426 }
427 break;
428 default:
429 break;
430 }
431 return (NS_UNAVAIL);
432}
433
434
435static int
436files_group(void *retval, void *mdata, va_list ap)
437{
438 struct files_state *st;
439 enum nss_lookup_type how;
440 const char *name, *line;
441 struct group *grp;
442 gid_t gid;
443 char *buffer;
444 size_t bufsize, linesize;
445 int rv, stayopen, *errnop;
446
447 name = NULL;
448 gid = (gid_t)-1;
449 how = (enum nss_lookup_type)mdata;
450 switch (how) {
451 case nss_lt_name:
452 name = va_arg(ap, const char *);
453 break;
454 case nss_lt_id:
455 gid = va_arg(ap, gid_t);
456 break;
457 case nss_lt_all:
458 break;
459 default:
460 return (NS_NOTFOUND);
461 }
462 grp = va_arg(ap, struct group *);
463 buffer = va_arg(ap, char *);
464 bufsize = va_arg(ap, size_t);
465 errnop = va_arg(ap, int *);
466 *errnop = files_getstate(&st);
467 if (*errnop != 0)
468 return (NS_UNAVAIL);
469 if (st->fp == NULL &&
470 ((st->fp = fopen(_PATH_GROUP, "r")) == NULL)) {
471 *errnop = errno;
472 return (NS_UNAVAIL);
473 }
474 if (how == nss_lt_all)
475 stayopen = 1;
476 else {
477 rewind(st->fp);
478 stayopen = st->stayopen;
479 }
480 rv = NS_NOTFOUND;
481 while ((line = fgetln(st->fp, &linesize)) != NULL) {
482 if (line[linesize-1] == '\n')
483 linesize--;
484 rv = __gr_match_entry(line, linesize, how, name, gid);
485 if (rv != NS_SUCCESS)
486 continue;
487 /* We need room at least for the line, a string NUL
488 * terminator, alignment padding, and one (char *)
489 * pointer for the member list terminator.
490 */
491 if (bufsize <= linesize + _ALIGNBYTES + sizeof(char *)) {
492 *errnop = ERANGE;
493 rv = NS_RETURN;
494 break;
495 }
496 memcpy(buffer, line, linesize);
497 buffer[linesize] = '\0';
498 rv = __gr_parse_entry(buffer, linesize, grp,
499 &buffer[linesize + 1], bufsize - linesize - 1, errnop);
500 if (rv & NS_TERMINATE)
501 break;
502 }
503 if (!stayopen && st->fp != NULL) {
504 fclose(st->fp);
505 st->fp = NULL;
506 }
507 if (rv == NS_SUCCESS && retval != NULL)
508 *(struct group **)retval = grp;
509 return (rv);
510}
511
512
513#ifdef HESIOD
514/*
515 * dns backend
516 */
517static void
518dns_endstate(void *p)
519{
520
521 free(p);
522}
523
524
525static int
526dns_setgrent(void *retval, void *cb_data, va_list ap)
527{
528 struct dns_state *st;
529 int rv;
530
531 rv = dns_getstate(&st);
532 if (rv != 0)
533 return (NS_UNAVAIL);
534 st->counter = 0;
535 return (NS_UNAVAIL);
536}
537
538
539static int
540dns_group(void *retval, void *mdata, va_list ap)
541{
542 char buf[HESIOD_NAME_MAX];
543 struct dns_state *st;
544 struct group *grp;
545 const char *name, *label;
546 void *ctx;
547 char *buffer, **hes;
548 size_t bufsize, adjsize, linesize;
549 gid_t gid;
550 enum nss_lookup_type how;
551 int rv, *errnop;
552
553 ctx = NULL;
554 hes = NULL;
555 name = NULL;
556 gid = (gid_t)-1;
557 how = (enum nss_lookup_type)mdata;
558 switch (how) {
559 case nss_lt_name:
560 name = va_arg(ap, const char *);
561 break;
562 case nss_lt_id:
563 gid = va_arg(ap, gid_t);
564 break;
565 case nss_lt_all:
566 break;
567 }
568 grp = va_arg(ap, struct group *);
569 buffer = va_arg(ap, char *);
570 bufsize = va_arg(ap, size_t);
571 errnop = va_arg(ap, int *);
572 *errnop = dns_getstate(&st);
573 if (*errnop != 0)
574 return (NS_UNAVAIL);
575 if (hesiod_init(&ctx) != 0) {
576 *errnop = errno;
577 rv = NS_UNAVAIL;
578 goto fin;
579 }
580 do {
581 rv = NS_NOTFOUND;
582 switch (how) {
583 case nss_lt_name:
584 label = name;
585 break;
586 case nss_lt_id:
587 if (snprintf(buf, sizeof(buf), "%lu",
588 (unsigned long)gid) >= sizeof(buf))
589 goto fin;
590 label = buf;
591 break;
592 case nss_lt_all:
593 if (st->counter < 0)
594 goto fin;
595 if (snprintf(buf, sizeof(buf), "group-%ld",
596 st->counter++) >= sizeof(buf))
597 goto fin;
598 label = buf;
599 break;
600 }
601 hes = hesiod_resolve(ctx, label,
602 how == nss_lt_id ? "gid" : "group");
603 if ((how == nss_lt_id && hes == NULL &&
604 (hes = hesiod_resolve(ctx, buf, "group")) == NULL) ||
605 hes == NULL) {
606 if (how == nss_lt_all)
607 st->counter = -1;
608 if (errno != ENOENT)
609 *errnop = errno;
610 goto fin;
611 }
612 rv = __gr_match_entry(hes[0], strlen(hes[0]), how, name, gid);
613 if (rv != NS_SUCCESS) {
614 hesiod_free_list(ctx, hes);
615 hes = NULL;
616 continue;
617 }
618 /* We need room at least for the line, a string NUL
619 * terminator, alignment padding, and one (char *)
620 * pointer for the member list terminator.
621 */
622 adjsize = bufsize - _ALIGNBYTES - sizeof(char *);
623 linesize = strlcpy(buffer, hes[0], adjsize);
624 if (linesize >= adjsize) {
625 *errnop = ERANGE;
626 rv = NS_RETURN;
627 goto fin;
628 }
629 hesiod_free_list(ctx, hes);
630 hes = NULL;
631 rv = __gr_parse_entry(buffer, linesize, grp,
632 &buffer[linesize + 1], bufsize - linesize - 1, errnop);
633 } while (how == nss_lt_all && !(rv & NS_TERMINATE));
634fin:
635 if (hes != NULL)
636 hesiod_free_list(ctx, hes);
637 if (ctx != NULL)
638 hesiod_end(ctx);
639 if (rv == NS_SUCCESS && retval != NULL)
640 *(struct group **)retval = grp;
641 return (rv);
642}
643#endif /* HESIOD */
644
645
646#ifdef YP
647/*
648 * nis backend
649 */
650static void
651nis_endstate(void *p)
652{
653
654 if (p == NULL)
655 return;
656 free(((struct nis_state *)p)->key);
657 free(p);
658}
659
660
661static int
662nis_setgrent(void *retval, void *cb_data, va_list ap)
663{
664 struct nis_state *st;
665 int rv;
666
667 rv = nis_getstate(&st);
668 if (rv != 0)
669 return (NS_UNAVAIL);
670 st->done = 0;
671 free(st->key);
672 st->key = NULL;
673 return (NS_UNAVAIL);
674}
675
676
677static int
678nis_group(void *retval, void *mdata, va_list ap)
679{
680 char *map;
681 struct nis_state *st;
682 struct group *grp;
683 const char *name;
684 char *buffer, *key, *result;
685 size_t bufsize;
686 gid_t gid;
687 enum nss_lookup_type how;
688 int *errnop, keylen, resultlen, rv;
689
690 name = NULL;
691 gid = (gid_t)-1;
692 how = (enum nss_lookup_type)mdata;
693 switch (how) {
694 case nss_lt_name:
695 name = va_arg(ap, const char *);
696 map = "group.byname";
697 break;
698 case nss_lt_id:
699 gid = va_arg(ap, gid_t);
700 map = "group.bygid";
701 break;
702 case nss_lt_all:
703 map = "group.byname";
704 break;
705 }
706 grp = va_arg(ap, struct group *);
707 buffer = va_arg(ap, char *);
708 bufsize = va_arg(ap, size_t);
709 errnop = va_arg(ap, int *);
710 *errnop = nis_getstate(&st);
711 if (*errnop != 0)
712 return (NS_UNAVAIL);
713 if (st->domain[0] == '\0') {
714 if (getdomainname(st->domain, sizeof(st->domain)) != 0) {
715 *errnop = errno;
716 return (NS_UNAVAIL);
717 }
718 }
719 result = NULL;
720 do {
721 rv = NS_NOTFOUND;
722 switch (how) {
723 case nss_lt_name:
724 if (strlcpy(buffer, name, bufsize) >= bufsize)
725 goto erange;
726 break;
727 case nss_lt_id:
728 if (snprintf(buffer, bufsize, "%lu",
729 (unsigned long)gid) >= bufsize)
730 goto erange;
731 break;
732 case nss_lt_all:
733 if (st->done)
734 goto fin;
735 break;
736 }
737 result = NULL;
738 if (how == nss_lt_all) {
739 if (st->key == NULL)
740 rv = yp_first(st->domain, map, &st->key,
741 &st->keylen, &result, &resultlen);
742 else {
743 key = st->key;
744 keylen = st->keylen;
745 st->key = NULL;
746 rv = yp_next(st->domain, map, key, keylen,
747 &st->key, &st->keylen, &result,
748 &resultlen);
749 free(key);
750 }
751 if (rv != 0) {
752 free(result);
753 free(st->key);
754 st->key = NULL;
755 if (rv == YPERR_NOMORE) {
756 st->done = 1;
757 rv = NS_NOTFOUND;
758 } else
759 rv = NS_UNAVAIL;
760 goto fin;
761 }
762 } else {
763 rv = yp_match(st->domain, map, buffer, strlen(buffer),
764 &result, &resultlen);
765 if (rv == YPERR_KEY) {
766 rv = NS_NOTFOUND;
767 continue;
768 } else if (rv != 0) {
769 free(result);
770 rv = NS_UNAVAIL;
771 continue;
772 }
773 }
774 /* We need room at least for the line, a string NUL
775 * terminator, alignment padding, and one (char *)
776 * pointer for the member list terminator.
777 */
778 if (resultlen >= bufsize - _ALIGNBYTES - sizeof(char *))
779 goto erange;
780 memcpy(buffer, result, resultlen);
781 buffer[resultlen] = '\0';
782 free(result);
783 rv = __gr_match_entry(buffer, resultlen, how, name, gid);
784 if (rv == NS_SUCCESS)
785 rv = __gr_parse_entry(buffer, resultlen, grp,
786 &buffer[resultlen+1], bufsize - resultlen - 1,
787 errnop);
788 } while (how == nss_lt_all && !(rv & NS_TERMINATE));
789fin:
790 if (rv == NS_SUCCESS && retval != NULL)
791 *(struct group **)retval = grp;
792 return (rv);
793erange:
794 *errnop = ERANGE;
795 return (NS_RETURN);
796}
797#endif /* YP */
798
799
800
801/*
802 * compat backend
803 */
804static void
805compat_endstate(void *p)
806{
807 struct compat_state *st;
808
809 if (p == NULL)
810 return;
811 st = (struct compat_state *)p;
812 free(st->name);
813 if (st->fp != NULL)
814 fclose(st->fp);
815 free(p);
816}
817
818
819static int
820compat_setgrent(void *retval, void *mdata, va_list ap)
821{
822 static const ns_src compatsrc[] = {
823#ifdef YP
824 { NSSRC_NIS, NS_SUCCESS },
825#endif
826 { NULL, 0 }
827 };
828 ns_dtab dtab[] = {
829#ifdef HESIOD
830 { NSSRC_DNS, dns_setgrent, NULL },
831#endif
832#ifdef YP
833 { NSSRC_NIS, nis_setgrent, NULL },
834#endif
835 { NULL, NULL, NULL }
836 };
837 struct compat_state *st;
838 int rv, stayopen;
839
840#define set_setent(x, y) do { \
841 int i; \
842 \
843 for (i = 0; i < (sizeof(x)/sizeof(x[0])) - 1; i++) \
844 x[i].mdata = (void *)y; \
845} while (0)
846
847 rv = compat_getstate(&st);
848 if (rv != 0)
849 return (NS_UNAVAIL);
850 switch ((enum constants)mdata) {
851 case SETGRENT:
852 stayopen = va_arg(ap, int);
853 if (st->fp != NULL)
854 rewind(st->fp);
855 else if (stayopen)
856 st->fp = fopen(_PATH_GROUP, "r");
857 set_setent(dtab, mdata);
858 (void)_nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "setgrent",
859 compatsrc, 0);
860 break;
861 case ENDGRENT:
862 if (st->fp != NULL) {
863 fclose(st->fp);
864 st->fp = NULL;
865 }
866 set_setent(dtab, mdata);
867 (void)_nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "endgrent",
868 compatsrc, 0);
869 break;
870 default:
871 break;
872 }
873 st->compat = COMPAT_MODE_OFF;
874 free(st->name);
875 st->name = NULL;
876 return (NS_UNAVAIL);
877#undef set_setent
878}
879
880
881static int
882compat_group(void *retval, void *mdata, va_list ap)
883{
884 static const ns_src compatsrc[] = {
885#ifdef YP
886 { NSSRC_NIS, NS_SUCCESS },
887#endif
888 { NULL, 0 }
889 };
890 ns_dtab dtab[] = {
891#ifdef YP
892 { NSSRC_NIS, nis_group, NULL },
893#endif
894#ifdef HESIOD
895 { NSSRC_DNS, dns_group, NULL },
896#endif
897 { NULL, NULL, NULL }
898 };
899 struct compat_state *st;
900 enum nss_lookup_type how;
901 const char *name, *line;
902 struct group *grp;
903 gid_t gid;
904 char *buffer, *p;
905 void *discard;
906 size_t bufsize, linesize;
907 int rv, stayopen, *errnop;
908
909#define set_lookup_type(x, y) do { \
910 int i; \
911 \
912 for (i = 0; i < (sizeof(x)/sizeof(x[0])) - 1; i++) \
913 x[i].mdata = (void *)y; \
914} while (0)
915
916 name = NULL;
917 gid = (gid_t)-1;
918 how = (enum nss_lookup_type)mdata;
919 switch (how) {
920 case nss_lt_name:
921 name = va_arg(ap, const char *);
922 break;
923 case nss_lt_id:
924 gid = va_arg(ap, gid_t);
925 break;
926 case nss_lt_all:
927 break;
928 default:
929 return (NS_NOTFOUND);
930 }
931 grp = va_arg(ap, struct group *);
932 buffer = va_arg(ap, char *);
933 bufsize = va_arg(ap, size_t);
934 errnop = va_arg(ap, int *);
935 *errnop = compat_getstate(&st);
936 if (*errnop != 0)
937 return (NS_UNAVAIL);
938 if (st->fp == NULL &&
939 ((st->fp = fopen(_PATH_GROUP, "r")) == NULL)) {
940 *errnop = errno;
941 rv = NS_UNAVAIL;
942 goto fin;
943 }
944 if (how == nss_lt_all)
945 stayopen = 1;
946 else {
947 rewind(st->fp);
948 stayopen = st->stayopen;
949 }
950docompat:
951 switch (st->compat) {
952 case COMPAT_MODE_ALL:
953 set_lookup_type(dtab, how);
954 switch (how) {
955 case nss_lt_all:
956 rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT,
957 "getgrent_r", compatsrc, grp, buffer, bufsize,
958 errnop);
959 break;
960 case nss_lt_id:
961 rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT,
962 "getgrgid_r", compatsrc, gid, grp, buffer, bufsize,
963 errnop);
964 break;
965 case nss_lt_name:
966 rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT,
967 "getgrnam_r", compatsrc, name, grp, buffer,
968 bufsize, errnop);
969 break;
970 }
971 if (rv & NS_TERMINATE)
972 goto fin;
973 st->compat = COMPAT_MODE_OFF;
974 break;
975 case COMPAT_MODE_NAME:
976 set_lookup_type(dtab, nss_lt_name);
977 rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT,
978 "getgrnam_r", compatsrc, st->name, grp, buffer, bufsize,
979 errnop);
980 switch (rv) {
981 case NS_SUCCESS:
982 switch (how) {
983 case nss_lt_name:
984 if (strcmp(name, grp->gr_name) != 0)
985 rv = NS_NOTFOUND;
986 break;
987 case nss_lt_id:
988 if (gid != grp->gr_gid)
989 rv = NS_NOTFOUND;
990 break;
991 default:
992 break;
993 }
994 break;
995 case NS_RETURN:
996 goto fin;
997 default:
998 break;
999 }
1000 free(st->name);
1001 st->name = NULL;
1002 st->compat = COMPAT_MODE_OFF;
1003 if (rv == NS_SUCCESS)
1004 goto fin;
1005 break;
1006 default:
1007 break;
1008 }
1009 rv = NS_NOTFOUND;
1010 while ((line = fgetln(st->fp, &linesize)) != NULL) {
1011 if (line[linesize-1] == '\n')
1012 linesize--;
1013 if (linesize > 2 && line[0] == '+') {
1014 p = memchr(&line[1], ':', linesize);
1015 if (p == NULL || p == &line[1])
1016 st->compat = COMPAT_MODE_ALL;
1017 else {
1018 st->name = malloc(p - line);
1019 if (st->name == NULL) {
1020 syslog(LOG_ERR,
1021 "getgrent memory allocation failure");
1022 *errnop = ENOMEM;
1023 rv = NS_UNAVAIL;
1024 break;
1025 }
1026 memcpy(st->name, &line[1], p - line - 1);
1027 st->name[p - line - 1] = '\0';
1028 st->compat = COMPAT_MODE_NAME;
1029 }
1030 goto docompat;
1031 }
1032 rv = __gr_match_entry(line, linesize, how, name, gid);
1033 if (rv != NS_SUCCESS)
1034 continue;
1035 /* We need room at least for the line, a string NUL
1036 * terminator, alignment padding, and one (char *)
1037 * pointer for the member list terminator.
1038 */
1039 if (bufsize <= linesize + _ALIGNBYTES + sizeof(char *)) {
1040 *errnop = ERANGE;
1041 rv = NS_RETURN;
1042 break;
1043 }
1044 memcpy(buffer, line, linesize);
1045 buffer[linesize] = '\0';
1046 rv = __gr_parse_entry(buffer, linesize, grp,
1047 &buffer[linesize + 1], bufsize - linesize - 1, errnop);
1048 if (rv & NS_TERMINATE)
1049 break;
1050 }
1051fin:
1052 if (!stayopen && st->fp != NULL) {
1053 fclose(st->fp);
1054 st->fp = NULL;
1055 }
1056 if (rv == NS_SUCCESS && retval != NULL)
1057 *(struct group **)retval = grp;
1058 return (rv);
1059#undef set_lookup_type
1060}
1061
1062
1063/*
1064 * common group line matching and parsing
1065 */
1066int
1067__gr_match_entry(const char *line, size_t linesize, enum nss_lookup_type how,
1068 const char *name, gid_t gid)
1069{
1070 size_t namesize;
1071 const char *p, *eol;
1072 char *q;
1073 unsigned long n;
1074 int i, needed;
1075
1076 if (linesize == 0 || is_comment_line(line, linesize))
1077 return (NS_NOTFOUND);
1078 switch (how) {
1079 case nss_lt_name: needed = 1; break;
1080 case nss_lt_id: needed = 2; break;
1081 default: needed = 2; break;
1082 }
1083 eol = &line[linesize];
1084 for (p = line, i = 0; i < needed && p < eol; p++)
1085 if (*p == ':')
1086 i++;
1087 if (i < needed)
1088 return (NS_NOTFOUND);
1089 switch (how) {
1090 case nss_lt_name:
1091 namesize = strlen(name);
1092 if (namesize + 1 == (size_t)(p - line) &&
1093 memcmp(line, name, namesize) == 0)
1094 return (NS_SUCCESS);
1095 break;
1096 case nss_lt_id:
1097 n = strtoul(p, &q, 10);
1098 if (q < eol && *q == ':' && gid == (gid_t)n)
1099 return (NS_SUCCESS);
1100 break;
1101 case nss_lt_all:
1102 return (NS_SUCCESS);
1103 default:
1104 break;
1105 }
1106 return (NS_NOTFOUND);
1107}
1108
1109
1110int
1111__gr_parse_entry(char *line, size_t linesize, struct group *grp, char *membuf,
1112 size_t membufsize, int *errnop)
1113{
1114 char *s_gid, *s_mem, *p, **members;
1115 unsigned long n;
1116 int maxmembers;
1117
1118 memset(grp, 0, sizeof(*grp));
1119 members = (char **)_ALIGN(membuf);
1120 membufsize -= (char *)members - membuf;
1121 maxmembers = membufsize / sizeof(*members);
1122 if (maxmembers <= 0 ||
1123 (grp->gr_name = strsep(&line, ":")) == NULL ||
1124 grp->gr_name[0] == '\0' ||
1125 (grp->gr_passwd = strsep(&line, ":")) == NULL ||
1126 (s_gid = strsep(&line, ":")) == NULL ||
1127 s_gid[0] == '\0')
1128 return (NS_NOTFOUND);
1129 s_mem = line;
1130 n = strtoul(s_gid, &s_gid, 10);
1131 if (s_gid[0] != '\0')
1132 return (NS_NOTFOUND);
1133 grp->gr_gid = (gid_t)n;
1134 grp->gr_mem = members;
1135 while (maxmembers > 1 && s_mem != NULL) {
1136 p = strsep(&s_mem, ",");
1137 if (p != NULL && *p != '\0') {
1138 *members++ = p;
1139 maxmembers--;
1140 }
1141 }
1142 *members = NULL;
1143 if (s_mem == NULL)
1144 return (NS_SUCCESS);
1145 else {
1146 *errnop = ERANGE;
1147 return (NS_RETURN);
1148 }
1149}
Note: See TracBrowser for help on using the repository browser.