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