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