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