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