getnetgrent.c revision 1.11.2.1 1 /* $NetBSD: getnetgrent.c,v 1.11.2.1 1997/05/24 04:51:54 lukem Exp $ */
2
3 /*
4 * Copyright (c) 1994 Christos Zoulas
5 * All rights reserved.
6 * Portions Copyright (c) 1997 Luke Mewburn. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Christos Zoulas.
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
23 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
26 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #if defined(LIBC_SCCS) && !defined(lint)
36 static char *rcsid = "$NetBSD: getnetgrent.c,v 1.11.2.1 1997/05/24 04:51:54 lukem Exp $";
37 #endif /* LIBC_SCCS and not lint */
38
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 <nsswitch.h>
48 #include <stdlib.h>
49 #include <stringlist.h>
50 #include <db.h>
51 #ifdef YP
52 #include <rpc/rpc.h>
53 #include <rpcsvc/ypclnt.h>
54 #include <rpcsvc/yp_prot.h>
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 static int getstring __P((char **, int, char **));
68 static struct netgroup *getnetgroup __P((char **));
69 static int lookup __P((char *, char **, int));
70 static void addgroup __P((StringList *, char *));
71 static int in_check __P((const char *, const char *,
72 const char *, struct netgroup *));
73 static int in_find __P((StringList *, char *, const char *,
74 const char *, const char *));
75 static char *in_lookup1 __P((const char *, const char *, int));
76 static int in_lookup __P((const char *, const char *,
77 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 static int
169 _local_lookup(rv, cb_data, ap)
170 void *rv;
171 void *cb_data;
172 va_list ap;
173 {
174 char *name = va_arg(ap, char *);
175 char **line = va_arg(ap, char **);
176 int bywhat = va_arg(ap, int);
177
178 DBT key, data;
179 size_t len;
180 char *ks;
181 int r;
182
183 if (_ng_db == NULL)
184 return NS_UNAVAIL;
185
186 len = strlen(name) + 2;
187 ks = malloc(len);
188 if (ks == NULL)
189 _err(1, _ngoomem);
190
191 ks[0] = bywhat;
192 memcpy(&ks[1], name, len - 1);
193
194 key.data = (u_char *) ks;
195 key.size = len;
196
197 r = (_ng_db->get) (_ng_db, &key, &data, 0);
198 free(ks);
199 switch (r) {
200 case 0:
201 break;
202 case 1:
203 return NS_NOTFOUND;
204 case -1:
205 return NS_UNAVAIL;
206 }
207
208 *line = strdup(data.data);
209 if (*line == NULL)
210 return NS_UNAVAIL;
211 return NS_SUCCESS;
212 }
213
214 #ifdef YP
215 static int
216 _nis_lookup(rv, cb_data, ap)
217 void *rv;
218 void *cb_data;
219 va_list ap;
220 {
221 char *name = va_arg(ap, char *);
222 char **line = va_arg(ap, char **);
223 int bywhat = va_arg(ap, int);
224
225 static char *__ypdomain;
226 int i;
227 char *map = NULL;
228
229 if(__ypdomain == NULL) {
230 switch (yp_get_default_domain(&__ypdomain)) {
231 case 0:
232 break;
233 case YPERR_RESRC:
234 return NS_TRYAGAIN;
235 default:
236 return NS_UNAVAIL;
237 }
238 }
239
240 switch (bywhat) {
241 case _NG_KEYBYNAME:
242 map = "netgroup";
243 break;
244
245 case _NG_KEYBYUSER:
246 map = "netgroup.byuser";
247 break;
248
249 case _NG_KEYBYHOST:
250 map = "netgroup.byhost";
251 break;
252
253 default:
254 abort();
255 break;
256 }
257
258
259 *line = NULL;
260 switch (yp_match(__ypdomain, map, name, strlen(name), line, &i)) {
261 case 0:
262 return NS_SUCCESS;
263 case YPERR_KEY:
264 if (*line)
265 free(*line);
266 return NS_NOTFOUND;
267 default:
268 if (*line)
269 free(*line);
270 return NS_UNAVAIL;
271 }
272 /* NOTREACHED */
273 }
274 #endif
275
276 /*
277 * lookup(): Find the given key in the database or yp, and return its value
278 * in *line; returns 1 if key was found, 0 otherwise
279 */
280 static int
281 lookup(name, line, bywhat)
282 char *name;
283 char **line;
284 int bywhat;
285 {
286 int r;
287 static ns_dtab dtab;
288
289 NS_FILES_CB(dtab, _local_lookup, NULL);
290 NS_NIS_CB(dtab, _nis_lookup, NULL);
291
292 r = nsdispatch(NULL, dtab, NSDB_NETGROUP, name, line, bywhat);
293 return (r == NS_SUCCESS) ? 1 : 0;
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(sl, grp)
350 StringList *sl;
351 char *grp;
352 {
353 char *line, *p;
354 struct netgroup *ng;
355 char *name;
356
357 #ifdef DEBUG_NG
358 (void) fprintf(stderr, "addgroup(%s)\n", grp);
359 #endif
360 /* check for cycles */
361 if (sl_find(sl, grp) != NULL) {
362 free(grp);
363 _warnx("netgroup: Cycle in group `%s'", grp);
364 return;
365 }
366 sl_add(sl, grp);
367
368 /* Lookup this netgroup */
369 line = NULL;
370 if (!lookup(grp, &line, _NG_KEYBYNAME)) {
371 if (line != NULL)
372 free(line);
373 return;
374 }
375
376 p = line;
377
378 for (;;) {
379 switch (_ng_parse(&p, &name, &ng)) {
380 case _NG_NONE:
381 /* Done with the line */
382 free(line);
383 return;
384
385 case _NG_GROUP:
386 /* new netgroup */
387 /* add to the list */
388 ng->ng_next = _nglist;
389 _nglist = ng;
390 break;
391
392 case _NG_NAME:
393 /* netgroup name */
394 addgroup(sl, name);
395 break;
396
397 case _NG_ERROR:
398 return;
399
400 default:
401 abort();
402 return;
403 }
404 }
405 }
406
407
408 /*
409 * in_check(): Compare the spec with the netgroup
410 */
411 static int
412 in_check(host, user, domain, ng)
413 const char *host;
414 const char *user;
415 const char *domain;
416 struct netgroup *ng;
417 {
418 if ((host != NULL) && (ng->ng_host != NULL)
419 && strcmp(ng->ng_host, host) != 0)
420 return 0;
421
422 if ((user != NULL) && (ng->ng_user != NULL)
423 && strcmp(ng->ng_user, user) != 0)
424 return 0;
425
426 if ((domain != NULL) && (ng->ng_domain != NULL)
427 && strcmp(ng->ng_domain, domain) != 0)
428 return 0;
429
430 return 1;
431 }
432
433
434 /*
435 * in_find(): Find a match for the host, user, domain spec
436 */
437 static int
438 in_find(sl, grp, host, user, domain)
439 StringList *sl;
440 char *grp;
441 const char *host;
442 const char *user;
443 const char *domain;
444 {
445 char *line, *p;
446 int i;
447 struct netgroup *ng;
448 char *name;
449
450 #ifdef DEBUG_NG
451 (void) fprintf(stderr, "in_find(%s)\n", grp);
452 #endif
453 /* check for cycles */
454 if (sl_find(sl, grp) != NULL) {
455 free(grp);
456 _warnx("netgroup: Cycle in group `%s'", grp);
457 return 0;
458 }
459 sl_add(sl, grp);
460
461 /* Lookup this netgroup */
462 line = NULL;
463 if (!lookup(grp, &line, _NG_KEYBYNAME)) {
464 if (line)
465 free(line);
466 return 0;
467 }
468
469 p = line;
470
471 for (;;) {
472 switch (_ng_parse(&p, &name, &ng)) {
473 case _NG_NONE:
474 /* Done with the line */
475 free(line);
476 return 0;
477
478 case _NG_GROUP:
479 /* new netgroup */
480 i = in_check(host, user, domain, ng);
481 if (ng->ng_host != NULL)
482 free(ng->ng_host);
483 if (ng->ng_user != NULL)
484 free(ng->ng_user);
485 if (ng->ng_domain != NULL)
486 free(ng->ng_domain);
487 free(ng);
488 if (i) {
489 free(line);
490 return 1;
491 }
492 break;
493
494 case _NG_NAME:
495 /* netgroup name */
496 if (in_find(sl, name, host, user, domain)) {
497 free(line);
498 return 1;
499 }
500 break;
501
502 case _NG_ERROR:
503 free(line);
504 return 0;
505
506 default:
507 abort();
508 return 0;
509 }
510 }
511 }
512
513
514 /*
515 * _ng_makekey(): Make a key from the two names given. The key is of the form
516 * <name1>.<name2> Names strings are replaced with * if they are empty;
517 */
518 char *
519 _ng_makekey(s1, s2, len)
520 const char *s1, *s2;
521 size_t len;
522 {
523 char *buf = malloc(len);
524 if (buf == NULL)
525 _err(1, _ngoomem);
526 (void) snprintf(buf, len, "%s.%s", _NG_STAR(s1), _NG_STAR(s2));
527 return buf;
528 }
529
530 void
531 _ng_print(buf, len, ng)
532 char *buf;
533 size_t len;
534 const struct netgroup *ng;
535 {
536 (void) snprintf(buf, len, "(%s,%s,%s)", _NG_EMPTY(ng->ng_host),
537 _NG_EMPTY(ng->ng_user), _NG_EMPTY(ng->ng_domain));
538 }
539
540
541 /*
542 * in_lookup1(): Fast lookup for a key in the appropriate map
543 */
544 static char *
545 in_lookup1(key, domain, map)
546 const char *key;
547 const char *domain;
548 int map;
549 {
550 char *line;
551 size_t len;
552 char *ptr;
553 int res;
554
555 len = (key ? strlen(key) : 1) + (domain ? strlen(domain) : 1) + 2;
556 ptr = _ng_makekey(key, domain, len);
557 res = lookup(ptr, &line, map);
558 free(ptr);
559 return res ? line : NULL;
560 }
561
562
563 /*
564 * in_lookup(): Fast lookup for a key in the appropriate map
565 */
566 static int
567 in_lookup(group, key, domain, map)
568 const char *group;
569 const char *key;
570 const char *domain;
571 int map;
572 {
573 size_t len;
574 char *ptr, *line;
575
576 if (domain != NULL) {
577 /* Domain specified; look in "group.domain" and "*.domain" */
578 if ((line = in_lookup1(key, domain, map)) == NULL)
579 line = in_lookup1(NULL, domain, map);
580 }
581 else
582 line = NULL;
583
584 if (line == NULL) {
585 /*
586 * domain not specified or domain lookup failed; look in
587 * "group.*" and "*.*"
588 */
589 if (((line = in_lookup1(key, NULL, map)) == NULL) &&
590 ((line = in_lookup1(NULL, NULL, map)) == NULL))
591 return 0;
592 }
593
594 len = strlen(group);
595
596 for (ptr = line; (ptr = strstr(ptr, group)) != NULL;)
597 /* Make sure we did not find a substring */
598 if ((ptr != line && ptr[-1] != ',') ||
599 (ptr[len] != '\0' && strchr("\n\t ,", ptr[len]) == NULL))
600 ptr++;
601 else {
602 free(line);
603 return 1;
604 }
605
606 free(line);
607 return 0;
608 }
609
610
611 void
612 endnetgrent()
613 {
614 for (_nglist = _nghead; _nglist != NULL; _nglist = _nghead) {
615 _nghead = _nglist->ng_next;
616 if (_nglist->ng_host != NULL)
617 free(_nglist->ng_host);
618 if (_nglist->ng_user != NULL)
619 free(_nglist->ng_user);
620 if (_nglist->ng_domain != NULL)
621 free(_nglist->ng_domain);
622 free(_nglist);
623 }
624
625 if (_ng_db) {
626 (void) (_ng_db->close) (_ng_db);
627 _ng_db = NULL;
628 }
629 }
630
631
632 void
633 setnetgrent(ng)
634 const char *ng;
635 {
636 StringList *sl = sl_init();
637 char *ng_copy;
638
639 /* Cleanup any previous storage */
640 if (_nghead != NULL)
641 endnetgrent();
642
643 if (_ng_db == NULL)
644 _ng_db = dbopen(_PATH_NETGROUP_DB, O_RDONLY, 0, DB_HASH, NULL);
645
646 ng_copy = strdup(ng);
647 if (ng_copy == NULL)
648 _err(1, _ngoomem);
649 addgroup(sl, ng_copy);
650 _nghead = _nglist;
651 sl_free(sl, 1);
652 }
653
654
655 int
656 getnetgrent(host, user, domain)
657 const char **host;
658 const char **user;
659 const char **domain;
660 {
661 if (_nglist == NULL)
662 return 0;
663
664 *host = _nglist->ng_host;
665 *user = _nglist->ng_user;
666 *domain = _nglist->ng_domain;
667
668 _nglist = _nglist->ng_next;
669
670 return 1;
671 }
672
673
674 int
675 innetgr(grp, host, user, domain)
676 const char *grp, *host, *user, *domain;
677 {
678 int found;
679 StringList *sl;
680
681 if (_ng_db == NULL)
682 _ng_db = dbopen(_PATH_NETGROUP_DB, O_RDONLY, 0, DB_HASH, NULL);
683
684 /* Try the fast lookup first */
685 if (host != NULL && user == NULL) {
686 if (in_lookup(grp, host, domain, _NG_KEYBYHOST))
687 return 1;
688 } else if (host == NULL && user != NULL) {
689 if (in_lookup(grp, user, domain, _NG_KEYBYUSER))
690 return 1;
691 }
692 /* If a domainname is given, we would have found a match */
693 if (domain != NULL)
694 return 0;
695
696 /* Too bad need the slow recursive way */
697 sl = sl_init();
698 found = in_find(sl, strdup(grp), host, user, domain);
699 sl_free(sl, 1);
700
701 return found;
702 }
703