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