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