1 /* $NetBSD: getnetgrent.c,v 1.20 1999/01/19 08:30:47 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.20 1999/01/19 08:30:47 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 __weak_alias 59 __weak_alias(endnetgrent,_endnetgrent); 60 __weak_alias(getnetgrent,_getnetgrent); 61 __weak_alias(innetgr,_innetgr); 62 __weak_alias(setnetgrent,_setnetgrent); 63 #endif 64 65 #define _NG_STAR(s) (((s) == NULL || *(s) == '\0') ? _ngstar : s) 66 #define _NG_EMPTY(s) ((s) == NULL ? "" : s) 67 #define _NG_ISSPACE(p) (isspace((unsigned char) (p)) || (p) == '\n') 68 69 static const char _ngstar[] = "*"; 70 static const char _ngoomem[] = "netgroup: %m"; 71 static struct netgroup *_nghead = (struct netgroup *)NULL; 72 static struct netgroup *_nglist = (struct netgroup *)NULL; 73 static DB *_ng_db; 74 75 static int getstring __P((char **, int, __aconst char **)); 76 static struct netgroup *getnetgroup __P((char **)); 77 static int lookup __P((char *, char **, int)); 78 static void addgroup __P((StringList *, char *)); 79 static int in_check __P((const char *, const char *, 80 const char *, struct netgroup *)); 81 static int in_find __P((StringList *, char *, const char *, 82 const char *, const char *)); 83 static char *in_lookup1 __P((const char *, const char *, int)); 84 static int in_lookup __P((const char *, const char *, 85 const char *, int)); 86 87 /* 88 * getstring(): Get a string delimited by the character, skipping leading and 89 * trailing blanks and advancing the pointer 90 */ 91 static int 92 getstring(pp, del, str) 93 char **pp; 94 int del; 95 char __aconst **str; 96 { 97 size_t len; 98 char *sp, *ep, *dp; 99 100 /* skip leading blanks */ 101 for (sp = *pp; *sp && _NG_ISSPACE(*sp); sp++) 102 continue; 103 104 /* accumulate till delimiter or space */ 105 for (ep = sp; *ep && *ep != del && !_NG_ISSPACE(*ep); ep++) 106 continue; 107 108 /* hunt for the delimiter */ 109 for (dp = ep; *dp && *dp != del && _NG_ISSPACE(*dp); dp++) 110 continue; 111 112 if (*dp != del) { 113 *str = NULL; 114 return 0; 115 } 116 117 *pp = ++dp; 118 119 len = (ep - sp) + 1; 120 if (len > 1) { 121 dp = malloc(len); 122 if (dp == NULL) 123 err(1, _ngoomem); 124 memcpy(dp, sp, len); 125 dp[len - 1] = '\0'; 126 } else 127 dp = NULL; 128 129 *str = dp; 130 return 1; 131 } 132 133 134 /* 135 * getnetgroup(): Parse a netgroup, and advance the pointer 136 */ 137 static struct netgroup * 138 getnetgroup(pp) 139 char **pp; 140 { 141 struct netgroup *ng = malloc(sizeof(struct netgroup)); 142 143 if (ng == NULL) 144 err(1, _ngoomem); 145 146 (*pp)++; /* skip '(' */ 147 if (!getstring(pp, ',', &ng->ng_host)) 148 goto badhost; 149 150 if (!getstring(pp, ',', &ng->ng_user)) 151 goto baduser; 152 153 if (!getstring(pp, ')', &ng->ng_domain)) 154 goto baddomain; 155 156 #ifdef DEBUG_NG 157 { 158 char buf[1024]; 159 (void) fprintf(stderr, "netgroup %s\n", 160 _ng_print(buf, sizeof(buf), ng)); 161 } 162 #endif 163 return ng; 164 165 baddomain: 166 if (ng->ng_user) 167 free((char *)ng->ng_user); 168 baduser: 169 if (ng->ng_host) 170 free((char *)ng->ng_host); 171 badhost: 172 free(ng); 173 return NULL; 174 } 175 176 177 static int _local_lookup __P((void *, void *, va_list)); 178 179 /*ARGSUSED*/ 180 static int 181 _local_lookup(rv, cb_data, ap) 182 void *rv; 183 void *cb_data; 184 va_list ap; 185 { 186 char *name = va_arg(ap, char *); 187 char **line = va_arg(ap, char **); 188 int bywhat = va_arg(ap, int); 189 190 DBT key, data; 191 size_t len; 192 char *ks; 193 int r; 194 195 if (_ng_db == NULL) 196 return NS_UNAVAIL; 197 198 len = strlen(name) + 2; 199 ks = malloc(len); 200 if (ks == NULL) 201 err(1, _ngoomem); 202 203 ks[0] = bywhat; 204 memcpy(&ks[1], name, len - 1); 205 206 key.data = (u_char *) ks; 207 key.size = len; 208 209 r = (_ng_db->get) (_ng_db, &key, &data, 0); 210 free(ks); 211 switch (r) { 212 case 0: 213 break; 214 case 1: 215 return NS_NOTFOUND; 216 case -1: 217 return NS_UNAVAIL; 218 } 219 220 *line = strdup(data.data); 221 if (*line == NULL) 222 return NS_UNAVAIL; 223 return NS_SUCCESS; 224 } 225 226 #ifdef YP 227 static int _nis_lookup __P((void *, void *, va_list)); 228 229 /*ARGSUSED*/ 230 static int 231 _nis_lookup(rv, cb_data, ap) 232 void *rv; 233 void *cb_data; 234 va_list ap; 235 { 236 char *name = va_arg(ap, char *); 237 char **line = va_arg(ap, char **); 238 int bywhat = va_arg(ap, int); 239 240 static char *__ypdomain; 241 int i; 242 char *map = NULL; 243 244 if(__ypdomain == NULL) { 245 switch (yp_get_default_domain(&__ypdomain)) { 246 case 0: 247 break; 248 case YPERR_RESRC: 249 return NS_TRYAGAIN; 250 default: 251 return NS_UNAVAIL; 252 } 253 } 254 255 switch (bywhat) { 256 case _NG_KEYBYNAME: 257 map = "netgroup"; 258 break; 259 260 case _NG_KEYBYUSER: 261 map = "netgroup.byuser"; 262 break; 263 264 case _NG_KEYBYHOST: 265 map = "netgroup.byhost"; 266 break; 267 268 default: 269 abort(); 270 break; 271 } 272 273 274 *line = NULL; 275 switch (yp_match(__ypdomain, map, name, (int)strlen(name), line, &i)) { 276 case 0: 277 return NS_SUCCESS; 278 case YPERR_KEY: 279 if (*line) 280 free(*line); 281 return NS_NOTFOUND; 282 default: 283 if (*line) 284 free(*line); 285 return NS_UNAVAIL; 286 } 287 /* NOTREACHED */ 288 } 289 #endif 290 291 /* 292 * lookup(): Find the given key in the database or yp, and return its value 293 * in *line; returns 1 if key was found, 0 otherwise 294 */ 295 static int 296 lookup(name, line, bywhat) 297 char *name; 298 char **line; 299 int bywhat; 300 { 301 int r; 302 static const ns_dtab dtab[] = { 303 NS_FILES_CB(_local_lookup, NULL) 304 NS_DNS_CB(_nis_lookup, NULL) 305 { 0 } 306 }; 307 308 r = nsdispatch(NULL, dtab, NSDB_NETGROUP, "lookup", __nsdefaultsrc, 309 name, line, bywhat); 310 return (r == NS_SUCCESS) ? 1 : 0; 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 size_t 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(sl, grp) 367 StringList *sl; 368 char *grp; 369 { 370 char *line, *p; 371 struct netgroup *ng; 372 char *name; 373 374 #ifdef DEBUG_NG 375 (void) fprintf(stderr, "addgroup(%s)\n", grp); 376 #endif 377 /* check for cycles */ 378 if (sl_find(sl, grp) != NULL) { 379 free(grp); 380 warnx("netgroup: Cycle in group `%s'", grp); 381 return; 382 } 383 sl_add(sl, grp); 384 385 /* Lookup this netgroup */ 386 line = NULL; 387 if (!lookup(grp, &line, _NG_KEYBYNAME)) { 388 if (line != NULL) 389 free(line); 390 return; 391 } 392 393 p = line; 394 395 for (;;) { 396 switch (_ng_parse(&p, &name, &ng)) { 397 case _NG_NONE: 398 /* Done with the line */ 399 free(line); 400 return; 401 402 case _NG_GROUP: 403 /* new netgroup */ 404 /* add to the list */ 405 ng->ng_next = _nglist; 406 _nglist = ng; 407 break; 408 409 case _NG_NAME: 410 /* netgroup name */ 411 addgroup(sl, name); 412 break; 413 414 case _NG_ERROR: 415 return; 416 417 default: 418 abort(); 419 return; 420 } 421 } 422 } 423 424 425 /* 426 * in_check(): Compare the spec with the netgroup 427 */ 428 static int 429 in_check(host, user, domain, ng) 430 const char *host; 431 const char *user; 432 const char *domain; 433 struct netgroup *ng; 434 { 435 if ((host != NULL) && (ng->ng_host != NULL) 436 && strcmp(ng->ng_host, host) != 0) 437 return 0; 438 439 if ((user != NULL) && (ng->ng_user != NULL) 440 && strcmp(ng->ng_user, user) != 0) 441 return 0; 442 443 if ((domain != NULL) && (ng->ng_domain != NULL) 444 && strcmp(ng->ng_domain, domain) != 0) 445 return 0; 446 447 return 1; 448 } 449 450 451 /* 452 * in_find(): Find a match for the host, user, domain spec 453 */ 454 static int 455 in_find(sl, grp, host, user, domain) 456 StringList *sl; 457 char *grp; 458 const char *host; 459 const char *user; 460 const char *domain; 461 { 462 char *line, *p; 463 int i; 464 struct netgroup *ng; 465 char *name; 466 467 #ifdef DEBUG_NG 468 (void) fprintf(stderr, "in_find(%s)\n", grp); 469 #endif 470 /* check for cycles */ 471 if (sl_find(sl, grp) != NULL) { 472 free(grp); 473 warnx("netgroup: Cycle in group `%s'", grp); 474 return 0; 475 } 476 sl_add(sl, grp); 477 478 /* Lookup this netgroup */ 479 line = NULL; 480 if (!lookup(grp, &line, _NG_KEYBYNAME)) { 481 if (line) 482 free(line); 483 return 0; 484 } 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((char *)ng->ng_host); 500 if (ng->ng_user != NULL) 501 free((char *)ng->ng_user); 502 if (ng->ng_domain != NULL) 503 free((char *)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(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 default: 524 abort(); 525 return 0; 526 } 527 } 528 } 529 530 531 /* 532 * _ng_makekey(): Make a key from the two names given. The key is of the form 533 * <name1>.<name2> Names strings are replaced with * if they are empty; 534 */ 535 char * 536 _ng_makekey(s1, s2, len) 537 const char *s1, *s2; 538 size_t len; 539 { 540 char *buf = malloc(len); 541 if (buf == NULL) 542 err(1, _ngoomem); 543 (void) snprintf(buf, len, "%s.%s", _NG_STAR(s1), _NG_STAR(s2)); 544 return buf; 545 } 546 547 void 548 _ng_print(buf, len, ng) 549 char *buf; 550 size_t len; 551 const struct netgroup *ng; 552 { 553 (void) snprintf(buf, len, "(%s,%s,%s)", _NG_EMPTY(ng->ng_host), 554 _NG_EMPTY(ng->ng_user), _NG_EMPTY(ng->ng_domain)); 555 } 556 557 558 /* 559 * in_lookup1(): Fast lookup for a key in the appropriate map 560 */ 561 static char * 562 in_lookup1(key, domain, map) 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(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(group, key, domain, map) 585 const char *group; 586 const char *key; 587 const char *domain; 588 int map; 589 { 590 size_t len; 591 char *ptr, *line; 592 593 if (domain != NULL) { 594 /* Domain specified; look in "group.domain" and "*.domain" */ 595 if ((line = in_lookup1(key, domain, map)) == NULL) 596 line = in_lookup1(NULL, domain, map); 597 } 598 else 599 line = NULL; 600 601 if (line == NULL) { 602 /* 603 * domain not specified or domain lookup failed; look in 604 * "group.*" and "*.*" 605 */ 606 if (((line = in_lookup1(key, NULL, map)) == NULL) && 607 ((line = in_lookup1(NULL, NULL, map)) == NULL)) 608 return 0; 609 } 610 611 len = strlen(group); 612 613 for (ptr = line; (ptr = strstr(ptr, group)) != NULL;) 614 /* Make sure we did not find a substring */ 615 if ((ptr != line && ptr[-1] != ',') || 616 (ptr[len] != '\0' && strchr("\n\t ,", ptr[len]) == NULL)) 617 ptr++; 618 else { 619 free(line); 620 return 1; 621 } 622 623 free(line); 624 return 0; 625 } 626 627 628 void 629 endnetgrent() 630 { 631 for (_nglist = _nghead; _nglist != NULL; _nglist = _nghead) { 632 _nghead = _nglist->ng_next; 633 if (_nglist->ng_host != NULL) 634 free((char *)_nglist->ng_host); 635 if (_nglist->ng_user != NULL) 636 free((char *)_nglist->ng_user); 637 if (_nglist->ng_domain != NULL) 638 free((char *)_nglist->ng_domain); 639 free(_nglist); 640 } 641 642 if (_ng_db) { 643 (void) (_ng_db->close) (_ng_db); 644 _ng_db = NULL; 645 } 646 } 647 648 649 void 650 setnetgrent(ng) 651 const char *ng; 652 { 653 StringList *sl = sl_init(); 654 char *ng_copy; 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 ng_copy = strdup(ng); 664 if (ng_copy == NULL) 665 err(1, _ngoomem); 666 addgroup(sl, ng_copy); 667 _nghead = _nglist; 668 sl_free(sl, 1); 669 } 670 671 672 int 673 getnetgrent(host, user, domain) 674 const char **host; 675 const char **user; 676 const char **domain; 677 { 678 if (_nglist == NULL) 679 return 0; 680 681 *host = _nglist->ng_host; 682 *user = _nglist->ng_user; 683 *domain = _nglist->ng_domain; 684 685 _nglist = _nglist->ng_next; 686 687 return 1; 688 } 689 690 691 int 692 innetgr(grp, host, user, domain) 693 const char *grp, *host, *user, *domain; 694 { 695 int found; 696 StringList *sl; 697 698 if (_ng_db == NULL) 699 _ng_db = dbopen(_PATH_NETGROUP_DB, O_RDONLY, 0, DB_HASH, NULL); 700 701 /* Try the fast lookup first */ 702 if (host != NULL && user == NULL) { 703 if (in_lookup(grp, host, domain, _NG_KEYBYHOST)) 704 return 1; 705 } else if (host == NULL && user != NULL) { 706 if (in_lookup(grp, user, domain, _NG_KEYBYUSER)) 707 return 1; 708 } 709 /* If a domainname is given, we would have found a match */ 710 if (domain != NULL) 711 return 0; 712 713 /* Too bad need the slow recursive way */ 714 sl = sl_init(); 715 found = in_find(sl, strdup(grp), host, user, domain); 716 sl_free(sl, 1); 717 718 return found; 719 } 720