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