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