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