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