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