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