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