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