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