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