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