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