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