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