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