getnetgrent.c revision 1.20
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 69static const char _ngstar[] = "*"; 70static const char _ngoomem[] = "netgroup: %m"; 71static struct netgroup *_nghead = (struct netgroup *)NULL; 72static struct netgroup *_nglist = (struct netgroup *)NULL; 73static DB *_ng_db; 74 75static int getstring __P((char **, int, __aconst char **)); 76static struct netgroup *getnetgroup __P((char **)); 77static int lookup __P((char *, char **, int)); 78static void addgroup __P((StringList *, char *)); 79static int in_check __P((const char *, const char *, 80 const char *, struct netgroup *)); 81static int in_find __P((StringList *, char *, const char *, 82 const char *, const char *)); 83static char *in_lookup1 __P((const char *, const char *, int)); 84static 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 */ 91static int 92getstring(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 */ 137static struct netgroup * 138getnetgroup(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 165baddomain: 166 if (ng->ng_user) 167 free((char *)ng->ng_user); 168baduser: 169 if (ng->ng_host) 170 free((char *)ng->ng_host); 171badhost: 172 free(ng); 173 return NULL; 174} 175 176 177static int _local_lookup __P((void *, void *, va_list)); 178 179/*ARGSUSED*/ 180static 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 227static int _nis_lookup __P((void *, void *, va_list)); 228 229/*ARGSUSED*/ 230static 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 */ 295static int 296lookup(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 */ 320int 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 */ 365static void 366addgroup(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 */ 428static int 429in_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 */ 454static int 455in_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 */ 535char * 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 547void 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 */ 561static char * 562in_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 */ 583static int 584in_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 628void 629endnetgrent() 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 649void 650setnetgrent(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 672int 673getnetgrent(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 691int 692innetgr(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