Annotation of src/lib/libc/gen/getgrent.c, Revision 1.33
1.33 ! lukem 1: /* $NetBSD: getgrent.c,v 1.32 1999/01/20 02:59:37 lukem Exp $ */
1.11 cgd 2:
1.1 cgd 3: /*
1.11 cgd 4: * Copyright (c) 1989, 1993
5: * The Regents of the University of California. All rights reserved.
1.13 phil 6: * Portions Copyright (c) 1994, Jason Downs. All Rights Reserved.
1.1 cgd 7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by the University of
19: * California, Berkeley and its contributors.
20: * 4. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: */
36:
1.20 christos 37: #include <sys/cdefs.h>
1.1 cgd 38: #if defined(LIBC_SCCS) && !defined(lint)
1.11 cgd 39: #if 0
40: static char sccsid[] = "@(#)getgrent.c 8.2 (Berkeley) 3/21/94";
41: #else
1.33 ! lukem 42: __RCSID("$NetBSD: getgrent.c,v 1.32 1999/01/20 02:59:37 lukem Exp $");
1.11 cgd 43: #endif
1.1 cgd 44: #endif /* LIBC_SCCS and not lint */
45:
1.21 jtc 46: #include "namespace.h"
1.33 ! lukem 47:
1.1 cgd 48: #include <sys/types.h>
1.33 ! lukem 49:
! 50: #include <errno.h>
1.27 lukem 51: #include <grp.h>
1.18 lukem 52: #include <limits.h>
1.27 lukem 53: #include <nsswitch.h>
1.1 cgd 54: #include <stdio.h>
55: #include <stdlib.h>
1.2 deraadt 56: #include <string.h>
1.27 lukem 57: #include <syslog.h>
1.33 ! lukem 58:
1.27 lukem 59: #ifdef HESIOD
60: #include <hesiod.h>
61: #endif
1.2 deraadt 62: #ifdef YP
63: #include <rpc/rpc.h>
64: #include <rpcsvc/yp_prot.h>
65: #include <rpcsvc/ypclnt.h>
1.21 jtc 66: #endif
67:
68: #ifdef __weak_alias
69: __weak_alias(endgrent,_endgrent);
70: __weak_alias(getgrent,_getgrent);
71: __weak_alias(getgrgid,_getgrgid);
72: __weak_alias(getgrnam,_getgrnam);
73: __weak_alias(setgrent,_setgrent);
74: __weak_alias(setgroupent,_setgroupent);
1.2 deraadt 75: #endif
1.1 cgd 76:
1.27 lukem 77: static FILE *_gr_fp;
78: static struct group _gr_group;
79: static int _gr_stayopen;
80: static int _gr_nomore;
81:
82: static int grscan __P((int, gid_t, const char *));
83: static int matchline __P((int, gid_t, const char *));
84: static int start_gr __P((void));
1.1 cgd 85:
86: #define MAXGRP 200
87: #define MAXLINELENGTH 1024
1.27 lukem 88:
89: static __aconst char *members[MAXGRP];
90: static char line[MAXLINELENGTH];
1.1 cgd 91:
1.2 deraadt 92: #ifdef YP
1.27 lukem 93: enum _grmode { GRMODE_NONE, GRMODE_FULL, GRMODE_NAME };
94: static enum _grmode __grmode;
95: static char *__ypcurrent, *__ypdomain;
96: static int __ypcurrentlen;
97: #endif
98:
99: #ifdef HESIOD
100: static int __gr_hesnum;
1.2 deraadt 101: #endif
102:
1.1 cgd 103: struct group *
104: getgrent()
105: {
1.27 lukem 106: _gr_nomore = 0;
107: if ((!_gr_fp && !start_gr()) || !grscan(0, 0, NULL) || _gr_nomore)
108: return(NULL);
109: return &_gr_group;
1.1 cgd 110: }
111:
112: struct group *
113: getgrnam(name)
114: const char *name;
115: {
116: int rval;
117:
118: if (!start_gr())
1.27 lukem 119: return NULL;
1.1 cgd 120: rval = grscan(1, 0, name);
121: if (!_gr_stayopen)
122: endgrent();
1.27 lukem 123: return (rval) ? &_gr_group : NULL;
1.1 cgd 124: }
125:
126: struct group *
127: getgrgid(gid)
128: gid_t gid;
129: {
130: int rval;
131:
132: if (!start_gr())
1.27 lukem 133: return NULL;
1.1 cgd 134: rval = grscan(1, gid, NULL);
135: if (!_gr_stayopen)
136: endgrent();
1.27 lukem 137: return (rval) ? &_gr_group : NULL;
1.1 cgd 138: }
139:
1.2 deraadt 140: static int
1.1 cgd 141: start_gr()
142: {
1.27 lukem 143: #ifdef YP
144: __grmode = GRMODE_NONE;
145: if (__ypcurrent)
146: free(__ypcurrent);
147: __ypcurrent = NULL;
148: #endif
149: #ifdef HESIOD
150: __gr_hesnum = 0;
151: #endif
1.1 cgd 152: if (_gr_fp) {
153: rewind(_gr_fp);
1.27 lukem 154: return 1;
1.1 cgd 155: }
1.27 lukem 156: return (_gr_fp = fopen(_PATH_GROUP, "r")) ? 1 : 0;
1.1 cgd 157: }
158:
1.5 jtc 159: void
1.1 cgd 160: setgrent()
161: {
1.5 jtc 162: (void) setgroupent(0);
1.1 cgd 163: }
164:
165: int
166: setgroupent(stayopen)
167: int stayopen;
168: {
169: if (!start_gr())
1.27 lukem 170: return 0;
1.1 cgd 171: _gr_stayopen = stayopen;
1.27 lukem 172: return 1;
1.1 cgd 173: }
174:
175: void
176: endgrent()
177: {
1.27 lukem 178: #ifdef YP
179: __grmode = GRMODE_NONE;
180: if (__ypcurrent)
181: free(__ypcurrent);
182: __ypcurrent = NULL;
183: #endif
184: #ifdef HESIOD
185: __gr_hesnum = 0;
186: #endif
1.1 cgd 187: if (_gr_fp) {
188: (void)fclose(_gr_fp);
189: _gr_fp = NULL;
190: }
191: }
192:
1.27 lukem 193:
194: static int _local_grscan __P((void *, void *, va_list));
195:
1.29 christos 196: /*ARGSUSED*/
1.27 lukem 197: static int
198: _local_grscan(rv, cb_data, ap)
199: void *rv;
200: void *cb_data;
201: va_list ap;
202: {
203: int search = va_arg(ap, int);
204: gid_t gid = va_arg(ap, gid_t);
205: const char *name = va_arg(ap, const char *);
206:
207: for (;;) {
208: if (!fgets(line, sizeof(line), _gr_fp)) {
209: if (!search) {
210: _gr_nomore = 1;
211: return NS_SUCCESS;
212: }
213: return NS_NOTFOUND;
214: }
215: /* skip lines that are too big */
216: if (!strchr(line, '\n')) {
217: int ch;
218:
219: while ((ch = getc(_gr_fp)) != '\n' && ch != EOF)
220: ;
221: continue;
222: }
223: if (matchline(search, gid, name))
224: return NS_SUCCESS;
225: }
226: /* NOTREACHED */
227: }
228:
229: #ifdef HESIOD
230: static int _dns_grscan __P((void *, void *, va_list));
231:
1.29 christos 232: /*ARGSUSED*/
1.2 deraadt 233: static int
1.27 lukem 234: _dns_grscan(rv, cb_data, ap)
235: void *rv;
236: void *cb_data;
237: va_list ap;
1.1 cgd 238: {
1.27 lukem 239: int search = va_arg(ap, int);
240: gid_t gid = va_arg(ap, gid_t);
241: const char *name = va_arg(ap, const char *);
242:
243: char **hp;
1.33 ! lukem 244: void *context;
! 245: int r;
! 246:
! 247: r = NS_UNAVAIL;
! 248: if (hesiod_init(&context) == -1)
! 249: return (r);
1.1 cgd 250:
251: for (;;) {
1.27 lukem 252: if (search) {
253: if (name)
254: strncpy(line, name, sizeof(line));
255: else
1.28 lukem 256: snprintf(line, sizeof(line), "%u",
257: (unsigned int)gid);
1.27 lukem 258: } else {
259: snprintf(line, sizeof(line), "group-%u", __gr_hesnum);
260: __gr_hesnum++;
261: }
1.2 deraadt 262:
1.27 lukem 263: line[sizeof(line) - 1] = '\0';
1.33 ! lukem 264: hp = hesiod_resolve(context, line, "group");
1.27 lukem 265: if (hp == NULL) {
1.33 ! lukem 266: if (errno == ENOENT) {
1.27 lukem 267: if (!search) {
268: __gr_hesnum = 0;
269: _gr_nomore = 1;
1.33 ! lukem 270: r = NS_SUCCESS;
! 271: } else
! 272: r = NS_NOTFOUND;
1.2 deraadt 273: }
1.33 ! lukem 274: break;
1.27 lukem 275: }
276:
277: /* only check first elem */
278: strncpy(line, hp[0], sizeof(line));
279: line[sizeof(line) - 1] = '\0';
1.33 ! lukem 280: hesiod_free_list(context, hp);
! 281: if (matchline(search, gid, name)) {
! 282: r = NS_SUCCESS;
! 283: break;
! 284: } else if (search) {
! 285: r = NS_NOTFOUND;
! 286: break;
! 287: }
1.27 lukem 288: }
1.33 ! lukem 289: hesiod_end(context);
! 290: return (r);
1.27 lukem 291: }
292: #endif
293:
294: #ifdef YP
295: static int _nis_grscan __P((void *, void *, va_list));
296:
1.29 christos 297: /*ARGSUSED*/
1.27 lukem 298: static int
299: _nis_grscan(rv, cb_data, ap)
300: void *rv;
301: void *cb_data;
302: va_list ap;
303: {
304: int search = va_arg(ap, int);
305: gid_t gid = va_arg(ap, gid_t);
306: const char *name = va_arg(ap, const char *);
307:
308: char *key, *data;
309: int keylen, datalen;
310: int r;
311:
312: if(__ypdomain == NULL) {
313: switch (yp_get_default_domain(&__ypdomain)) {
314: case 0:
315: break;
316: case YPERR_RESRC:
317: return NS_TRYAGAIN;
318: default:
319: return NS_UNAVAIL;
320: }
321: }
322:
323: if (search) { /* specific group or gid */
324: if (name)
325: strncpy(line, name, sizeof(line));
326: else
1.28 lukem 327: snprintf(line, sizeof(line), "%u", (unsigned int)gid);
1.27 lukem 328: line[sizeof(line) - 1] = '\0';
329: data = NULL;
330: r = yp_match(__ypdomain,
331: (name) ? "group.byname" : "group.bygid",
332: line, (int)strlen(line), &data, &datalen);
333: switch (r) {
334: case 0:
335: break;
336: case YPERR_KEY:
337: if (data)
338: free(data);
339: return NS_NOTFOUND;
340: default:
341: if (data)
1.16 lukem 342: free(data);
1.27 lukem 343: return NS_UNAVAIL;
344: }
345: data[datalen] = '\0'; /* clear trailing \n */
346: strncpy(line, data, sizeof(line));
347: line[sizeof(line) - 1] = '\0';
348: free(data);
349: if (matchline(search, gid, name))
350: return NS_SUCCESS;
351: else
352: return NS_NOTFOUND;
353: }
354:
355: for (;;) { /* ! search */
356: data = NULL;
357: if(__ypcurrent) {
358: key = NULL;
359: r = yp_next(__ypdomain, "group.byname",
360: __ypcurrent, __ypcurrentlen,
361: &key, &keylen, &data, &datalen);
362: free(__ypcurrent);
363: switch (r) {
364: case 0:
1.13 phil 365: break;
1.27 lukem 366: case YPERR_NOMORE:
367: __ypcurrent = NULL;
368: if (key)
369: free(key);
370: if (data)
1.2 deraadt 371: free(data);
1.27 lukem 372: _gr_nomore = 1;
373: return NS_SUCCESS;
374: default:
375: if (key)
376: free(key);
377: if (data)
378: free(data);
379: return NS_UNAVAIL;
380: }
381: __ypcurrent = key;
382: __ypcurrentlen = keylen;
383: } else {
384: if (yp_first(__ypdomain, "group.byname",
385: &__ypcurrent, &__ypcurrentlen,
386: &data, &datalen)) {
387: if (data);
388: free(data);
389: return NS_UNAVAIL;
390: }
391: }
392: data[datalen] = '\0'; /* clear trailing \n */
393: strncpy(line, data, sizeof(line));
394: line[sizeof(line) - 1] = '\0';
395: free(data);
396: if (matchline(search, gid, name))
397: return NS_SUCCESS;
398: }
399: /* NOTREACHED */
400: }
401: #endif
402:
403: #if defined(YP) || defined(HESIOD)
404: /*
405: * log an error if "files" or "compat" is specified in group_compat database
406: */
407: static int _bad_grscan __P((void *, void *, va_list));
408:
1.29 christos 409: /*ARGSUSED*/
1.27 lukem 410: static int
411: _bad_grscan(rv, cb_data, ap)
412: void *rv;
413: void *cb_data;
414: va_list ap;
415: {
416: static int warned;
417:
418: if (!warned) {
419: syslog(LOG_ERR,
420: "nsswitch.conf group_compat database can't use '%s'",
421: (char *)cb_data);
422: }
423: warned = 1;
424: return NS_UNAVAIL;
425: }
426:
427: /*
428: * when a name lookup in compat mode is required, look it up in group_compat
429: * nsswitch database. only Hesiod and NIS is supported - it doesn't make
430: * sense to lookup compat names from 'files' or 'compat'
431: */
432:
433: static int __grscancompat __P((int, gid_t, const char *));
434:
435: static int
436: __grscancompat(search, gid, name)
437: int search;
438: gid_t gid;
439: const char *name;
440: {
1.31 lukem 441: static const ns_dtab dtab[] = {
1.30 lukem 442: NS_FILES_CB(_bad_grscan, "files")
443: NS_DNS_CB(_dns_grscan, NULL)
444: NS_NIS_CB(_nis_grscan, NULL)
445: NS_COMPAT_CB(_bad_grscan, "compat")
1.27 lukem 446: { 0 }
447: };
1.32 lukem 448: static const ns_src defaultnis[] = {
449: { NSSRC_NIS, NS_SUCCESS },
450: { 0 }
451: };
1.27 lukem 452:
1.30 lukem 453: return (nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "grscancompat",
1.32 lukem 454: defaultnis, search, gid, name));
1.27 lukem 455: }
456:
457:
458: static int _compat_grscan __P((void *, void *, va_list));
459:
1.29 christos 460: /*ARGSUSED*/
1.27 lukem 461: static int
462: _compat_grscan(rv, cb_data, ap)
463: void *rv;
464: void *cb_data;
465: va_list ap;
466: {
467: int search = va_arg(ap, int);
468: gid_t gid = va_arg(ap, gid_t);
469: const char *name = va_arg(ap, const char *);
470:
471: static char *grname = NULL;
472:
473: for (;;) {
474: if(__grmode != GRMODE_NONE) {
475: int r;
476:
477: switch(__grmode) {
478: case GRMODE_FULL:
479: r = __grscancompat(search, gid, name);
480: if (r == NS_SUCCESS)
481: return r;
482: __grmode = GRMODE_NONE;
483: break;
484: case GRMODE_NAME:
485: if(grname == (char *)NULL) {
486: __grmode = GRMODE_NONE;
487: break;
488: }
489: r = __grscancompat(1, 0, grname);
490: free(grname);
491: grname = (char *)NULL;
492: if (r != NS_SUCCESS)
493: break;
494: if (!search)
495: return NS_SUCCESS;
496: if (name) {
497: if (! strcmp(_gr_group.gr_name, name))
498: return NS_SUCCESS;
1.13 phil 499: } else {
1.27 lukem 500: if (_gr_group.gr_gid == gid)
501: return NS_SUCCESS;
1.2 deraadt 502: }
1.20 christos 503: break;
1.27 lukem 504: case GRMODE_NONE:
505: abort();
1.2 deraadt 506: }
1.27 lukem 507: continue;
1.2 deraadt 508: }
1.27 lukem 509:
1.1 cgd 510: if (!fgets(line, sizeof(line), _gr_fp))
1.27 lukem 511: return NS_NOTFOUND;
1.1 cgd 512: /* skip lines that are too big */
1.6 jtc 513: if (!strchr(line, '\n')) {
1.1 cgd 514: int ch;
515:
516: while ((ch = getc(_gr_fp)) != '\n' && ch != EOF)
517: ;
518: continue;
519: }
1.27 lukem 520:
1.13 phil 521: if (line[0] == '+') {
1.27 lukem 522: char *tptr, *bp;
523:
1.13 phil 524: switch(line[1]) {
525: case ':':
526: case '\0':
527: case '\n':
1.27 lukem 528: __grmode = GRMODE_FULL;
1.13 phil 529: break;
530: default:
1.27 lukem 531: __grmode = GRMODE_NAME;
532: bp = line;
533: tptr = strsep(&bp, ":\n");
534: grname = strdup(tptr + 1);
1.13 phil 535: break;
1.2 deraadt 536: }
1.9 deraadt 537: continue;
1.1 cgd 538: }
1.27 lukem 539: if (matchline(search, gid, name))
540: return NS_SUCCESS;
1.1 cgd 541: }
542: /* NOTREACHED */
1.27 lukem 543: }
544: #endif /* YP || HESIOD */
545:
546: static int
547: grscan(search, gid, name)
548: int search;
549: gid_t gid;
550: const char *name;
551: {
552: int r;
1.31 lukem 553: static const ns_dtab dtab[] = {
1.30 lukem 554: NS_FILES_CB(_local_grscan, NULL)
555: NS_DNS_CB(_dns_grscan, NULL)
556: NS_NIS_CB(_nis_grscan, NULL)
557: NS_COMPAT_CB(_compat_grscan, NULL)
1.27 lukem 558: { 0 }
559: };
1.32 lukem 560: static const ns_src compatsrc[] = {
561: { NSSRC_COMPAT, NS_SUCCESS },
562: { 0 }
563: };
1.27 lukem 564:
1.32 lukem 565: r = nsdispatch(NULL, dtab, NSDB_GROUP, "grscan", compatsrc,
1.30 lukem 566: search, gid, name);
1.27 lukem 567: return (r == NS_SUCCESS) ? 1 : 0;
568: }
569:
570: static int
571: matchline(search, gid, name)
572: int search;
573: gid_t gid;
574: const char *name;
575: {
576: unsigned long id;
577: __aconst char **m;
578: char *cp, *bp, *ep;
579:
580: if (line[0] == '+')
581: return 0; /* sanity check to prevent recursion */
582: bp = line;
583: _gr_group.gr_name = strsep(&bp, ":\n");
584: if (search && name && strcmp(_gr_group.gr_name, name))
585: return 0;
586: _gr_group.gr_passwd = strsep(&bp, ":\n");
587: if (!(cp = strsep(&bp, ":\n")))
588: return 0;
589: id = strtoul(cp, &ep, 10);
590: if (id > GID_MAX || *ep != '\0')
591: return 0;
592: _gr_group.gr_gid = (gid_t)id;
593: if (search && name == NULL && _gr_group.gr_gid != gid)
594: return 0;
595: cp = NULL;
596: if (bp == NULL)
597: return 0;
598: for (_gr_group.gr_mem = m = members;; bp++) {
599: if (m == &members[MAXGRP - 1])
600: break;
601: if (*bp == ',') {
602: if (cp) {
603: *bp = '\0';
604: *m++ = cp;
605: cp = NULL;
606: }
607: } else if (*bp == '\0' || *bp == '\n' || *bp == ' ') {
608: if (cp) {
609: *bp = '\0';
610: *m++ = cp;
611: }
612: break;
613: } else if (cp == NULL)
614: cp = bp;
615: }
616: *m = NULL;
617: return 1;
1.1 cgd 618: }
CVSweb <webmaster@jp.NetBSD.org>