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