getnetgrent.c revision 1.11.2.2 1 /* $NetBSD: getnetgrent.c,v 1.11.2.2 1997/05/26 16:33:34 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.2 1997/05/26 16:33:34 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 if (dtab[NS_FILES].cb == NULL) {
290 NS_FILES_CB(dtab, _local_lookup, NULL);
291 NS_NIS_CB(dtab, _nis_lookup, NULL);
292 }
293
294 r = nsdispatch(NULL, dtab, NSDB_NETGROUP, name, line, bywhat);
295 return (r == NS_SUCCESS) ? 1 : 0;
296 }
297
298 /*
299 * _ng_parse(): Parse a line and return: _NG_ERROR: Syntax Error _NG_NONE:
300 * line was empty or a comment _NG_GROUP: line had a netgroup definition,
301 * returned in ng _NG_NAME: line had a netgroup name, returned in name
302 *
303 * Public since used by netgroup_mkdb
304 */
305 int
306 _ng_parse(p, name, ng)
307 char **p;
308 char **name;
309 struct netgroup **ng;
310 {
311 while (**p) {
312 if (**p == '#')
313 /* comment */
314 return _NG_NONE;
315
316 while (**p && _NG_ISSPACE(**p))
317 /* skipblank */
318 (*p)++;
319
320 if (**p == '(') {
321 if ((*ng = getnetgroup(p)) == NULL) {
322 _warnx("netgroup: Syntax error `%s'", *p);
323 return _NG_ERROR;
324 }
325 return _NG_GROUP;
326 } else {
327 char *np;
328 int i;
329
330 for (np = *p; **p && !_NG_ISSPACE(**p); (*p)++)
331 continue;
332 if (np != *p) {
333 i = (*p - np) + 1;
334 *name = malloc(i);
335 if (*name == NULL)
336 _err(1, _ngoomem);
337 memcpy(*name, np, i);
338 (*name)[i - 1] = '\0';
339 return _NG_NAME;
340 }
341 }
342 }
343 return _NG_NONE;
344 }
345
346
347 /*
348 * addgroup(): Recursively add all the members of the netgroup to this group
349 */
350 static void
351 addgroup(sl, grp)
352 StringList *sl;
353 char *grp;
354 {
355 char *line, *p;
356 struct netgroup *ng;
357 char *name;
358
359 #ifdef DEBUG_NG
360 (void) fprintf(stderr, "addgroup(%s)\n", grp);
361 #endif
362 /* check for cycles */
363 if (sl_find(sl, grp) != NULL) {
364 free(grp);
365 _warnx("netgroup: Cycle in group `%s'", grp);
366 return;
367 }
368 sl_add(sl, grp);
369
370 /* Lookup this netgroup */
371 line = NULL;
372 if (!lookup(grp, &line, _NG_KEYBYNAME)) {
373 if (line != NULL)
374 free(line);
375 return;
376 }
377
378 p = line;
379
380 for (;;) {
381 switch (_ng_parse(&p, &name, &ng)) {
382 case _NG_NONE:
383 /* Done with the line */
384 free(line);
385 return;
386
387 case _NG_GROUP:
388 /* new netgroup */
389 /* add to the list */
390 ng->ng_next = _nglist;
391 _nglist = ng;
392 break;
393
394 case _NG_NAME:
395 /* netgroup name */
396 addgroup(sl, name);
397 break;
398
399 case _NG_ERROR:
400 return;
401
402 default:
403 abort();
404 return;
405 }
406 }
407 }
408
409
410 /*
411 * in_check(): Compare the spec with the netgroup
412 */
413 static int
414 in_check(host, user, domain, ng)
415 const char *host;
416 const char *user;
417 const char *domain;
418 struct netgroup *ng;
419 {
420 if ((host != NULL) && (ng->ng_host != NULL)
421 && strcmp(ng->ng_host, host) != 0)
422 return 0;
423
424 if ((user != NULL) && (ng->ng_user != NULL)
425 && strcmp(ng->ng_user, user) != 0)
426 return 0;
427
428 if ((domain != NULL) && (ng->ng_domain != NULL)
429 && strcmp(ng->ng_domain, domain) != 0)
430 return 0;
431
432 return 1;
433 }
434
435
436 /*
437 * in_find(): Find a match for the host, user, domain spec
438 */
439 static int
440 in_find(sl, grp, host, user, domain)
441 StringList *sl;
442 char *grp;
443 const char *host;
444 const char *user;
445 const char *domain;
446 {
447 char *line, *p;
448 int i;
449 struct netgroup *ng;
450 char *name;
451
452 #ifdef DEBUG_NG
453 (void) fprintf(stderr, "in_find(%s)\n", grp);
454 #endif
455 /* check for cycles */
456 if (sl_find(sl, grp) != NULL) {
457 free(grp);
458 _warnx("netgroup: Cycle in group `%s'", grp);
459 return 0;
460 }
461 sl_add(sl, grp);
462
463 /* Lookup this netgroup */
464 line = NULL;
465 if (!lookup(grp, &line, _NG_KEYBYNAME)) {
466 if (line)
467 free(line);
468 return 0;
469 }
470
471 p = line;
472
473 for (;;) {
474 switch (_ng_parse(&p, &name, &ng)) {
475 case _NG_NONE:
476 /* Done with the line */
477 free(line);
478 return 0;
479
480 case _NG_GROUP:
481 /* new netgroup */
482 i = in_check(host, user, domain, ng);
483 if (ng->ng_host != NULL)
484 free(ng->ng_host);
485 if (ng->ng_user != NULL)
486 free(ng->ng_user);
487 if (ng->ng_domain != NULL)
488 free(ng->ng_domain);
489 free(ng);
490 if (i) {
491 free(line);
492 return 1;
493 }
494 break;
495
496 case _NG_NAME:
497 /* netgroup name */
498 if (in_find(sl, name, host, user, domain)) {
499 free(line);
500 return 1;
501 }
502 break;
503
504 case _NG_ERROR:
505 free(line);
506 return 0;
507
508 default:
509 abort();
510 return 0;
511 }
512 }
513 }
514
515
516 /*
517 * _ng_makekey(): Make a key from the two names given. The key is of the form
518 * <name1>.<name2> Names strings are replaced with * if they are empty;
519 */
520 char *
521 _ng_makekey(s1, s2, len)
522 const char *s1, *s2;
523 size_t len;
524 {
525 char *buf = malloc(len);
526 if (buf == NULL)
527 _err(1, _ngoomem);
528 (void) snprintf(buf, len, "%s.%s", _NG_STAR(s1), _NG_STAR(s2));
529 return buf;
530 }
531
532 void
533 _ng_print(buf, len, ng)
534 char *buf;
535 size_t len;
536 const struct netgroup *ng;
537 {
538 (void) snprintf(buf, len, "(%s,%s,%s)", _NG_EMPTY(ng->ng_host),
539 _NG_EMPTY(ng->ng_user), _NG_EMPTY(ng->ng_domain));
540 }
541
542
543 /*
544 * in_lookup1(): Fast lookup for a key in the appropriate map
545 */
546 static char *
547 in_lookup1(key, domain, map)
548 const char *key;
549 const char *domain;
550 int map;
551 {
552 char *line;
553 size_t len;
554 char *ptr;
555 int res;
556
557 len = (key ? strlen(key) : 1) + (domain ? strlen(domain) : 1) + 2;
558 ptr = _ng_makekey(key, domain, len);
559 res = lookup(ptr, &line, map);
560 free(ptr);
561 return res ? line : NULL;
562 }
563
564
565 /*
566 * in_lookup(): Fast lookup for a key in the appropriate map
567 */
568 static int
569 in_lookup(group, key, domain, map)
570 const char *group;
571 const char *key;
572 const char *domain;
573 int map;
574 {
575 size_t len;
576 char *ptr, *line;
577
578 if (domain != NULL) {
579 /* Domain specified; look in "group.domain" and "*.domain" */
580 if ((line = in_lookup1(key, domain, map)) == NULL)
581 line = in_lookup1(NULL, domain, map);
582 }
583 else
584 line = NULL;
585
586 if (line == NULL) {
587 /*
588 * domain not specified or domain lookup failed; look in
589 * "group.*" and "*.*"
590 */
591 if (((line = in_lookup1(key, NULL, map)) == NULL) &&
592 ((line = in_lookup1(NULL, NULL, map)) == NULL))
593 return 0;
594 }
595
596 len = strlen(group);
597
598 for (ptr = line; (ptr = strstr(ptr, group)) != NULL;)
599 /* Make sure we did not find a substring */
600 if ((ptr != line && ptr[-1] != ',') ||
601 (ptr[len] != '\0' && strchr("\n\t ,", ptr[len]) == NULL))
602 ptr++;
603 else {
604 free(line);
605 return 1;
606 }
607
608 free(line);
609 return 0;
610 }
611
612
613 void
614 endnetgrent()
615 {
616 for (_nglist = _nghead; _nglist != NULL; _nglist = _nghead) {
617 _nghead = _nglist->ng_next;
618 if (_nglist->ng_host != NULL)
619 free(_nglist->ng_host);
620 if (_nglist->ng_user != NULL)
621 free(_nglist->ng_user);
622 if (_nglist->ng_domain != NULL)
623 free(_nglist->ng_domain);
624 free(_nglist);
625 }
626
627 if (_ng_db) {
628 (void) (_ng_db->close) (_ng_db);
629 _ng_db = NULL;
630 }
631 }
632
633
634 void
635 setnetgrent(ng)
636 const char *ng;
637 {
638 StringList *sl = sl_init();
639 char *ng_copy;
640
641 /* Cleanup any previous storage */
642 if (_nghead != NULL)
643 endnetgrent();
644
645 if (_ng_db == NULL)
646 _ng_db = dbopen(_PATH_NETGROUP_DB, O_RDONLY, 0, DB_HASH, NULL);
647
648 ng_copy = strdup(ng);
649 if (ng_copy == NULL)
650 _err(1, _ngoomem);
651 addgroup(sl, ng_copy);
652 _nghead = _nglist;
653 sl_free(sl, 1);
654 }
655
656
657 int
658 getnetgrent(host, user, domain)
659 const char **host;
660 const char **user;
661 const char **domain;
662 {
663 if (_nglist == NULL)
664 return 0;
665
666 *host = _nglist->ng_host;
667 *user = _nglist->ng_user;
668 *domain = _nglist->ng_domain;
669
670 _nglist = _nglist->ng_next;
671
672 return 1;
673 }
674
675
676 int
677 innetgr(grp, host, user, domain)
678 const char *grp, *host, *user, *domain;
679 {
680 int found;
681 StringList *sl;
682
683 if (_ng_db == NULL)
684 _ng_db = dbopen(_PATH_NETGROUP_DB, O_RDONLY, 0, DB_HASH, NULL);
685
686 /* Try the fast lookup first */
687 if (host != NULL && user == NULL) {
688 if (in_lookup(grp, host, domain, _NG_KEYBYHOST))
689 return 1;
690 } else if (host == NULL && user != NULL) {
691 if (in_lookup(grp, user, domain, _NG_KEYBYUSER))
692 return 1;
693 }
694 /* If a domainname is given, we would have found a match */
695 if (domain != NULL)
696 return 0;
697
698 /* Too bad need the slow recursive way */
699 sl = sl_init();
700 found = in_find(sl, strdup(grp), host, user, domain);
701 sl_free(sl, 1);
702
703 return found;
704 }
705