getnetgrent.c revision 1.8 1 /* $NetBSD: getnetgrent.c,v 1.8 1995/02/25 08:51:19 cgd Exp $ */
2
3 /*
4 * Copyright (c) 1994 Christos Zoulas
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Christos Zoulas.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
22 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
25 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #if defined(LIBC_SCCS) && !defined(lint)
35 static char *rcsid = "$NetBSD: getnetgrent.c,v 1.8 1995/02/25 08:51:19 cgd Exp $";
36 #endif /* LIBC_SCCS and not lint */
37
38 #include <stdio.h>
39 #include <netgroup.h>
40 #include <string.h>
41 #include <fcntl.h>
42 #include <err.h>
43 #include <ctype.h>
44 #include <stdlib.h>
45 #include <db.h>
46
47 #define _NG_STAR(s) (((s) == NULL || *(s) == '\0') ? _ngstar : s)
48 #define _NG_ISSPACE(p) (isspace((unsigned char) (p)) || (p) == '\n')
49
50 static const char _ngstar[] = "*";
51 static const char _ngoomem[] = "netgroup: %m";
52 static struct netgroup *_nghead = (struct netgroup *)NULL;
53 static struct netgroup *_nglist = (struct netgroup *)NULL;
54 static DB *_ng_db;
55
56 /*
57 * Simple string list
58 */
59 struct stringlist {
60 char **sl_str;
61 size_t sl_max;
62 size_t sl_cur;
63 };
64
65 static int getstring __P((char **, int, char **));
66 static struct netgroup *getnetgroup __P((char **));
67 static int lookup __P((const char *, char *, char **, int));
68 static void addgroup __P((char *, struct stringlist *, char *));
69 static int in_check __P((const char *, const char *,
70 const char *, struct netgroup *));
71 static int in_find __P((char *, struct stringlist *,
72 char *, const char *,
73 const char *, const char *));
74 static char *in_lookup1 __P((const char *, const char *,
75 const char *, int));
76 static int in_lookup __P((const char *, const char *,
77 const char *, const char *, int));
78
79 /*
80 * _ng_sl_init(): Initialize a string list
81 */
82 struct stringlist *
83 _ng_sl_init()
84 {
85 struct stringlist *sl = malloc(sizeof(struct stringlist));
86 if (sl == NULL)
87 _err(1, _ngoomem);
88
89 sl->sl_cur = 0;
90 sl->sl_max = 20;
91 sl->sl_str = malloc(sl->sl_max * sizeof(char *));
92 if (sl->sl_str == NULL)
93 _err(1, _ngoomem);
94 return sl;
95 }
96
97
98 /*
99 * _ng_sl_add(): Add an item to the string list
100 */
101 void
102 _ng_sl_add(sl, name)
103 struct stringlist *sl;
104 char *name;
105 {
106 if (sl->sl_cur == sl->sl_max - 1) {
107 sl->sl_max += 20;
108 sl->sl_str = realloc(sl->sl_str, sl->sl_max * sizeof(char *));
109 if (sl->sl_str == NULL)
110 _err(1, _ngoomem);
111 }
112 sl->sl_str[sl->sl_cur++] = name;
113 }
114
115
116 /*
117 * _ng_sl_free(): Free a stringlist
118 */
119 void
120 _ng_sl_free(sl, all)
121 struct stringlist *sl;
122 int all;
123 {
124 size_t i;
125
126 if (all)
127 for (i = 0; i < sl->sl_cur; i++)
128 free(sl->sl_str[i]);
129 free(sl->sl_str);
130 free(sl);
131 }
132
133
134 /*
135 * sl_find(): Find a name in the string list
136 */
137 char *
138 _ng_sl_find(sl, name)
139 struct stringlist *sl;
140 char *name;
141 {
142 size_t i;
143
144 for (i = 0; i < sl->sl_cur; i++)
145 if (strcmp(sl->sl_str[i], name) == 0)
146 return sl->sl_str[i];
147
148 return NULL;
149 }
150
151
152 /*
153 * getstring(): Get a string delimited by the character, skipping leading and
154 * trailing blanks and advancing the pointer
155 */
156 static int
157 getstring(pp, del, str)
158 char **pp;
159 int del;
160 char **str;
161 {
162 char *sp, *ep, *dp;
163
164 /* skip leading blanks */
165 for (sp = *pp; *sp && _NG_ISSPACE(*sp); sp++)
166 continue;
167
168 /* accumulate till delimiter or space */
169 for (ep = sp; *ep && *ep != del && !_NG_ISSPACE(*ep); ep++)
170 continue;
171
172 /* hunt for the delimiter */
173 for (dp = ep; *dp && *dp != del && _NG_ISSPACE(*dp); dp++)
174 continue;
175
176 if (*dp != del) {
177 *str = NULL;
178 return 0;
179 }
180
181 *pp = ++dp;
182
183 del = (ep - sp) + 1;
184 if (del > 1) {
185 dp = malloc(del);
186 if (dp == NULL)
187 _err(1, _ngoomem);
188 memcpy(dp, sp, del);
189 dp[del - 1] = '\0';
190 } else
191 dp = NULL;
192
193 *str = dp;
194 return 1;
195 }
196
197
198 /*
199 * getnetgroup(): Parse a netgroup, and advance the pointer
200 */
201 static struct netgroup *
202 getnetgroup(pp)
203 char **pp;
204 {
205 struct netgroup *ng = malloc(sizeof(struct netgroup));
206
207 if (ng == NULL)
208 _err(1, _ngoomem);
209
210 (*pp)++; /* skip '(' */
211 if (!getstring(pp, ',', &ng->ng_host))
212 goto badhost;
213
214 if (!getstring(pp, ',', &ng->ng_user))
215 goto baduser;
216
217 if (!getstring(pp, ')', &ng->ng_domain))
218 goto baddomain;
219
220 #ifdef DEBUG_NG
221 (void) fprintf(stderr, "netgroup(%s,%s,%s)\n",
222 _NG_STAR(ng->ng_host), _NG_STAR(ng->ng_user),
223 _NG_STAR(ng->ng_domain));
224 #endif
225 return ng;
226
227 baddomain:
228 if (ng->ng_user)
229 free(ng->ng_user);
230 baduser:
231 if (ng->ng_host)
232 free(ng->ng_host);
233 badhost:
234 free(ng);
235 return NULL;
236 }
237
238
239 /*
240 * lookup(): Find the given key in the database or yp, and return its value
241 * in *line; returns 1 if key was found, 0 otherwise
242 */
243 static int
244 lookup(ypdom, name, line, bywhat)
245 const char *ypdom;
246 char *name;
247 char **line;
248 int bywhat;
249 {
250 #ifdef YP
251 int i;
252 char *map = NULL;
253 #endif
254
255 if (_ng_db) {
256 DBT key, data;
257 size_t len = strlen(name) + 2;
258 char *ks = malloc(len);
259
260 ks[0] = bywhat;
261 memcpy(&ks[1], name, len - 1);
262
263 key.data = (u_char *) ks;
264 key.size = len;
265
266 switch ((_ng_db->get) (_ng_db, &key, &data, 0)) {
267 case 0:
268 free(ks);
269 *line = strdup(data.data);
270 if (*line == NULL)
271 _err(1, _ngoomem);
272 return 1;
273
274 case 1:
275 break;
276
277 case -1:
278 _warn("netgroup: db get");
279 break;
280 }
281 free(ks);
282 }
283 #ifdef YP
284 if (ypdom) {
285 switch (bywhat) {
286 case _NG_KEYBYNAME:
287 map = "netgroup";
288 break;
289
290 case _NG_KEYBYUSER:
291 map = "netgroup.byuser";
292 break;
293
294 case _NG_KEYBYHOST:
295 map = "netgroup.byhost";
296 break;
297
298 default:
299 abort();
300 break;
301 }
302
303
304 if (yp_match(ypdom, map, name, strlen(name), line, &i) == 0)
305 return 1;
306 }
307 #endif
308
309 return 0;
310 }
311
312
313 /*
314 * _ng_parse(): Parse a line and return: _NG_ERROR: Syntax Error _NG_NONE:
315 * line was empty or a comment _NG_GROUP: line had a netgroup definition,
316 * returned in ng _NG_NAME: line had a netgroup name, returned in name
317 *
318 * Public since used by netgroup_mkdb
319 */
320 int
321 _ng_parse(p, name, ng)
322 char **p;
323 char **name;
324 struct netgroup **ng;
325 {
326 while (**p) {
327 if (**p == '#')
328 /* comment */
329 return _NG_NONE;
330
331 while (**p && _NG_ISSPACE(**p))
332 /* skipblank */
333 (*p)++;
334
335 if (**p == '(') {
336 if ((*ng = getnetgroup(p)) == NULL) {
337 _warnx("netgroup: Syntax error `%s'", *p);
338 return _NG_ERROR;
339 }
340 return _NG_GROUP;
341 } else {
342 char *np;
343 int i;
344
345 for (np = *p; **p && !_NG_ISSPACE(**p); (*p)++)
346 continue;
347 if (np != *p) {
348 i = (*p - np) + 1;
349 *name = malloc(i);
350 if (*name == NULL)
351 _err(1, _ngoomem);
352 memcpy(*name, np, i);
353 (*name)[i - 1] = '\0';
354 return _NG_NAME;
355 }
356 }
357 }
358 return _NG_NONE;
359 }
360
361
362 /*
363 * addgroup(): Recursively add all the members of the netgroup to this group
364 */
365 static void
366 addgroup(ypdom, sl, grp)
367 char *ypdom;
368 struct stringlist *sl;
369 char *grp;
370 {
371 char *line, *p;
372 struct netgroup *ng;
373 char *name;
374
375 #ifdef DEBUG_NG
376 (void) fprintf(stderr, "addgroup(%s)\n", grp);
377 #endif
378 /* check for cycles */
379 if (_ng_sl_find(sl, grp) != NULL) {
380 free(grp);
381 _warnx("netgroup: Cycle in group `%s'", grp);
382 return;
383 }
384 _ng_sl_add(sl, grp);
385
386 /* Lookup this netgroup */
387 if (!lookup(ypdom, grp, &line, _NG_KEYBYNAME))
388 return;
389
390 p = line;
391
392 for (;;) {
393 switch (_ng_parse(&p, &name, &ng)) {
394 case _NG_NONE:
395 /* Done with the line */
396 free(line);
397 return;
398
399 case _NG_GROUP:
400 /* new netgroup */
401 /* add to the list */
402 ng->ng_next = _nglist;
403 _nglist = ng;
404 break;
405
406 case _NG_NAME:
407 /* netgroup name */
408 addgroup(ypdom, sl, name);
409 break;
410
411 case _NG_ERROR:
412 return;
413
414 default:
415 abort();
416 return;
417 }
418 }
419 }
420
421
422 /*
423 * in_check(): Compare the spec with the netgroup
424 */
425 static int
426 in_check(host, user, domain, ng)
427 const char *host;
428 const char *user;
429 const char *domain;
430 struct netgroup *ng;
431 {
432 if ((host != NULL) && (ng->ng_host != NULL)
433 && strcmp(ng->ng_host, host) != 0)
434 return 0;
435
436 if ((user != NULL) && (ng->ng_user != NULL)
437 && strcmp(ng->ng_user, user) != 0)
438 return 0;
439
440 if ((domain != NULL) && (ng->ng_domain != NULL)
441 && strcmp(ng->ng_domain, domain) != 0)
442 return 0;
443
444 return 1;
445 }
446
447
448 /*
449 * in_find(): Find a match for the host, user, domain spec
450 */
451 static int
452 in_find(ypdom, sl, grp, host, user, domain)
453 char *ypdom;
454 struct stringlist *sl;
455 char *grp;
456 const char *host;
457 const char *user;
458 const char *domain;
459 {
460 char *line, *p;
461 int i;
462 struct netgroup *ng;
463 char *name;
464
465 #ifdef DEBUG_NG
466 (void) fprintf(stderr, "in_find(%s)\n", grp);
467 #endif
468 /* check for cycles */
469 if (_ng_sl_find(sl, grp) != NULL) {
470 free(grp);
471 _warnx("netgroup: Cycle in group `%s'", grp);
472 return 0;
473 }
474 _ng_sl_add(sl, grp);
475
476 /* Lookup this netgroup */
477 if (!lookup(ypdom, grp, &line, _NG_KEYBYNAME))
478 return 0;
479
480 p = line;
481
482 for (;;) {
483 switch (_ng_parse(&p, &name, &ng)) {
484 case _NG_NONE:
485 /* Done with the line */
486 free(line);
487 return 0;
488
489 case _NG_GROUP:
490 /* new netgroup */
491 i = in_check(host, user, domain, ng);
492 if (ng->ng_host != NULL)
493 free(ng->ng_host);
494 if (ng->ng_user != NULL)
495 free(ng->ng_user);
496 if (ng->ng_domain != NULL)
497 free(ng->ng_domain);
498 free(ng);
499 if (i) {
500 free(line);
501 return 1;
502 }
503 break;
504
505 case _NG_NAME:
506 /* netgroup name */
507 if (in_find(ypdom, sl, name, host, user, domain)) {
508 free(line);
509 return 1;
510 }
511 break;
512
513 case _NG_ERROR:
514 free(line);
515 return 0;
516
517 default:
518 abort();
519 return 0;
520 }
521 }
522 }
523
524
525 /*
526 * _ng_makekey(): Make a key from the two names given. The key is of the form
527 * <name1>.<name2> Names strings are replaced with * if they are empty;
528 */
529 char *
530 _ng_makekey(s1, s2, len)
531 const char *s1, *s2;
532 size_t len;
533 {
534 char *buf = malloc(len);
535 if (buf == NULL)
536 _err(1, _ngoomem);
537 (void) snprintf(buf, len, "%s.%s", _NG_STAR(s1), _NG_STAR(s2));
538 return buf;
539 }
540
541
542 /*
543 * in_lookup1(): Fast lookup for a key in the appropriate map
544 */
545 static char *
546 in_lookup1(ypdom, key, domain, map)
547 const char *ypdom;
548 const char *key;
549 const char *domain;
550 int map;
551 {
552 char *line;
553 size_t len;
554 char *ptr;
555 int res;
556
557 len = (key ? strlen(key) : 1) + (domain ? strlen(domain) : 1) + 2;
558 ptr = _ng_makekey(key, domain, len);
559 res = lookup(ypdom, ptr, &line, map);
560 free(ptr);
561 return res ? line : NULL;
562 }
563
564
565 /*
566 * in_lookup(): Fast lookup for a key in the appropriate map
567 */
568 static int
569 in_lookup(ypdom, group, key, domain, map)
570 const char *ypdom;
571 const char *group;
572 const char *key;
573 const char *domain;
574 int map;
575 {
576 size_t len;
577 char *ptr, *line;
578
579 if (domain != NULL) {
580 /* Domain specified; look in "group.domain" and "*.domain" */
581 if ((line = in_lookup1(ypdom, key, domain, map)) == NULL)
582 line = in_lookup1(ypdom, NULL, domain, map);
583 }
584 else
585 line = NULL;
586
587 if (line == NULL) {
588 /*
589 * domain not specified or domain lookup failed; look in
590 * "group.*" and "*.*"
591 */
592 if (((line = in_lookup1(ypdom, key, NULL, map)) == NULL) &&
593 ((line = in_lookup1(ypdom, NULL, NULL, map)) == NULL))
594 return 0;
595 }
596
597 len = strlen(group);
598
599 for (ptr = line; (ptr = strstr(ptr, group)) != NULL;)
600 /* Make sure we did not find a substring */
601 if ((ptr != line && ptr[-1] != ',') ||
602 (ptr[len] != '\0' && strchr("\n\t ,", ptr[len]) == NULL))
603 ptr++;
604 else {
605 free(line);
606 return 1;
607 }
608
609 free(line);
610 return 0;
611 }
612
613
614 void
615 endnetgrent()
616 {
617 for (_nglist = _nghead; _nglist != NULL; _nglist = _nghead) {
618 _nghead = _nglist->ng_next;
619 if (_nglist->ng_host != NULL)
620 free(_nglist->ng_host);
621 if (_nglist->ng_user != NULL)
622 free(_nglist->ng_user);
623 if (_nglist->ng_domain != NULL)
624 free(_nglist->ng_domain);
625 free(_nglist);
626 }
627
628 if (_ng_db) {
629 (void) (_ng_db->close) (_ng_db);
630 _ng_db = NULL;
631 }
632 }
633
634
635 void
636 setnetgrent(ng)
637 const char *ng;
638 {
639 struct stringlist *sl = _ng_sl_init();
640 #ifdef YP
641 char *line;
642 #endif
643 char *ng_copy, *ypdom = NULL;
644
645 /* Cleanup any previous storage */
646 if (_nghead != NULL)
647 endnetgrent();
648
649 if (_ng_db == NULL)
650 _ng_db = dbopen(_PATH_NETGROUP_DB, O_RDONLY, 0, DB_HASH, NULL);
651
652 #ifdef YP
653 /*
654 * We use yp if there is a "+" in the netgroup file, or if there is
655 * no netgroup file at all
656 */
657 if (_ng_db == NULL || lookup(NULL, "+", &line, _NG_KEYBYNAME) == 0)
658 yp_get_default_domain(&ypdom);
659 else
660 free(line);
661 #endif
662 ng_copy = strdup(ng);
663 if (ng_copy == NULL)
664 _err(1, _ngoomem);
665 addgroup(ypdom, sl, ng_copy);
666 _nghead = _nglist;
667 _ng_sl_free(sl, 1);
668 }
669
670
671 int
672 getnetgrent(host, user, domain)
673 const char **host;
674 const char **user;
675 const char **domain;
676 {
677 if (_nglist == NULL)
678 return 0;
679
680 *host = _nglist->ng_host;
681 *user = _nglist->ng_user;
682 *domain = _nglist->ng_domain;
683
684 _nglist = _nglist->ng_next;
685
686 return 1;
687 }
688
689
690 int
691 innetgr(grp, host, user, domain)
692 const char *grp, *host, *user, *domain;
693 {
694 char *ypdom = NULL;
695 #ifdef YP
696 char *line;
697 #endif
698 int found;
699 struct stringlist *sl;
700
701 if (_ng_db == NULL)
702 _ng_db = dbopen(_PATH_NETGROUP_DB, O_RDONLY, 0, DB_HASH, NULL);
703
704 #ifdef YP
705 /*
706 * We use yp if there is a "+" in the netgroup file, or if there is
707 * no netgroup file at all
708 */
709 if (_ng_db == NULL)
710 yp_get_default_domain(&ypdom);
711 else if (lookup(NULL, "+", &line, _NG_KEYBYNAME) == 0) {
712 yp_get_default_domain(&ypdom);
713 free(line);
714 }
715 #endif
716
717 /* Try the fast lookup first */
718 if (host != NULL && user == NULL) {
719 if (in_lookup(ypdom, grp, host, domain, _NG_KEYBYHOST))
720 return 1;
721 } else if (host == NULL && user != NULL) {
722 if (in_lookup(ypdom, grp, user, domain, _NG_KEYBYUSER))
723 return 1;
724 }
725 /* If a domainname is given, we would have found a match */
726 if (domain != NULL)
727 return 0;
728
729 /* Too bad need the slow recursive way */
730 sl = _ng_sl_init();
731 found = in_find(ypdom, sl, strdup(grp), host, user, domain);
732 _ng_sl_free(sl, 1);
733
734 return found;
735 }
736