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