1 /* 2 * Copyright (c) 1992, 1995 Eric P. Allman. 3 * Copyright (c) 1992, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 static char sccsid[] = "@(#)map.c 8.59 (Berkeley) 05/14/95"; 11 #endif /* not lint */ 12 13 #include "sendmail.h" 14 15 #ifdef NDBM 16 # include <ndbm.h> 17 #endif 18 #ifdef NEWDB 19 # include <db.h> 20 #endif 21 #ifdef NIS 22 struct dom_binding { int dummy; }; /* needed on IRIX */ 23 # include <rpcsvc/ypclnt.h> 24 #endif 25 26 /* 27 ** MAP.C -- implementations for various map classes. 28 ** 29 ** Each map class implements a series of functions: 30 ** 31 ** bool map_parse(MAP *map, char *args) 32 ** Parse the arguments from the config file. Return TRUE 33 ** if they were ok, FALSE otherwise. Fill in map with the 34 ** values. 35 ** 36 ** char *map_lookup(MAP *map, char *key, char **args, int *pstat) 37 ** Look up the key in the given map. If found, do any 38 ** rewriting the map wants (including "args" if desired) 39 ** and return the value. Set *pstat to the appropriate status 40 ** on error and return NULL. Args will be NULL if called 41 ** from the alias routines, although this should probably 42 ** not be relied upon. It is suggested you call map_rewrite 43 ** to return the results -- it takes care of null termination 44 ** and uses a dynamically expanded buffer as needed. 45 ** 46 ** void map_store(MAP *map, char *key, char *value) 47 ** Store the key:value pair in the map. 48 ** 49 ** bool map_open(MAP *map, int mode) 50 ** Open the map for the indicated mode. Mode should 51 ** be either O_RDONLY or O_RDWR. Return TRUE if it 52 ** was opened successfully, FALSE otherwise. If the open 53 ** failed an the MF_OPTIONAL flag is not set, it should 54 ** also print an error. If the MF_ALIAS bit is set 55 ** and this map class understands the @:@ convention, it 56 ** should call aliaswait() before returning. 57 ** 58 ** void map_close(MAP *map) 59 ** Close the map. 60 ** 61 ** This file also includes the implementation for getcanonname. 62 ** It is currently implemented in a pretty ad-hoc manner; it ought 63 ** to be more properly integrated into the map structure. 64 */ 65 66 #define DBMMODE 0644 67 68 extern bool aliaswait __P((MAP *, char *, int)); 69 /* 70 ** MAP_PARSEARGS -- parse config line arguments for database lookup 71 ** 72 ** This is a generic version of the map_parse method. 73 ** 74 ** Parameters: 75 ** map -- the map being initialized. 76 ** ap -- a pointer to the args on the config line. 77 ** 78 ** Returns: 79 ** TRUE -- if everything parsed OK. 80 ** FALSE -- otherwise. 81 ** 82 ** Side Effects: 83 ** null terminates the filename; stores it in map 84 */ 85 86 bool 87 map_parseargs(map, ap) 88 MAP *map; 89 char *ap; 90 { 91 register char *p = ap; 92 93 map->map_mflags |= MF_TRY0NULL | MF_TRY1NULL; 94 for (;;) 95 { 96 while (isascii(*p) && isspace(*p)) 97 p++; 98 if (*p != '-') 99 break; 100 switch (*++p) 101 { 102 case 'N': 103 map->map_mflags |= MF_INCLNULL; 104 map->map_mflags &= ~MF_TRY0NULL; 105 break; 106 107 case 'O': 108 map->map_mflags &= ~MF_TRY1NULL; 109 break; 110 111 case 'o': 112 map->map_mflags |= MF_OPTIONAL; 113 break; 114 115 case 'f': 116 map->map_mflags |= MF_NOFOLDCASE; 117 break; 118 119 case 'm': 120 map->map_mflags |= MF_MATCHONLY; 121 break; 122 123 case 'A': 124 map->map_mflags |= MF_APPEND; 125 break; 126 127 case 'a': 128 map->map_app = ++p; 129 break; 130 131 case 'k': 132 while (isascii(*++p) && isspace(*p)) 133 continue; 134 map->map_keycolnm = p; 135 break; 136 137 case 'v': 138 while (isascii(*++p) && isspace(*p)) 139 continue; 140 map->map_valcolnm = p; 141 break; 142 143 case 'z': 144 if (*++p != '\\') 145 map->map_coldelim = *p; 146 else 147 { 148 switch (*++p) 149 { 150 case 'n': 151 map->map_coldelim = '\n'; 152 break; 153 154 case 't': 155 map->map_coldelim = '\t'; 156 break; 157 158 default: 159 map->map_coldelim = '\\'; 160 } 161 } 162 break; 163 #ifdef RESERVED_FOR_SUN 164 case 'd': 165 map->map_mflags |= MF_DOMAIN_WIDE; 166 break; 167 168 case 's': 169 /* info type */ 170 break; 171 #endif 172 } 173 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 174 p++; 175 if (*p != '\0') 176 *p++ = '\0'; 177 } 178 if (map->map_app != NULL) 179 map->map_app = newstr(map->map_app); 180 if (map->map_keycolnm != NULL) 181 map->map_keycolnm = newstr(map->map_keycolnm); 182 if (map->map_valcolnm != NULL) 183 map->map_valcolnm = newstr(map->map_valcolnm); 184 185 if (*p != '\0') 186 { 187 map->map_file = p; 188 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 189 p++; 190 if (*p != '\0') 191 *p++ = '\0'; 192 map->map_file = newstr(map->map_file); 193 } 194 195 while (*p != '\0' && isascii(*p) && isspace(*p)) 196 p++; 197 if (*p != '\0') 198 map->map_rebuild = newstr(p); 199 200 if (map->map_file == NULL && 201 !bitset(MCF_OPTFILE, map->map_class->map_cflags)) 202 { 203 syserr("No file name for %s map %s", 204 map->map_class->map_cname, map->map_mname); 205 return FALSE; 206 } 207 return TRUE; 208 } 209 /* 210 ** MAP_REWRITE -- rewrite a database key, interpolating %n indications. 211 ** 212 ** It also adds the map_app string. It can be used as a utility 213 ** in the map_lookup method. 214 ** 215 ** Parameters: 216 ** map -- the map that causes this. 217 ** s -- the string to rewrite, NOT necessarily null terminated. 218 ** slen -- the length of s. 219 ** av -- arguments to interpolate into buf. 220 ** 221 ** Returns: 222 ** Pointer to rewritten result. This is static data that 223 ** should be copied if it is to be saved! 224 ** 225 ** Side Effects: 226 ** none. 227 */ 228 229 char * 230 map_rewrite(map, s, slen, av) 231 register MAP *map; 232 register char *s; 233 int slen; 234 char **av; 235 { 236 register char *bp; 237 register char c; 238 char **avp; 239 register char *ap; 240 int i; 241 int len; 242 static int buflen = -1; 243 static char *buf = NULL; 244 245 if (tTd(39, 1)) 246 { 247 printf("map_rewrite(%.*s), av =", slen, s); 248 if (av == NULL) 249 printf(" (nullv)"); 250 else 251 { 252 for (avp = av; *avp != NULL; avp++) 253 printf("\n\t%s", *avp); 254 } 255 printf("\n"); 256 } 257 258 /* count expected size of output (can safely overestimate) */ 259 i = len = slen; 260 if (av != NULL) 261 { 262 bp = s; 263 for (i = slen; --i >= 0 && (c = *bp++) != 0; ) 264 { 265 if (c != '%') 266 continue; 267 if (--i < 0) 268 break; 269 c = *bp++; 270 if (!(isascii(c) && isdigit(c))) 271 continue; 272 for (avp = av; --c >= '0' && *avp != NULL; avp++) 273 continue; 274 if (*avp == NULL) 275 continue; 276 len += strlen(*avp); 277 } 278 } 279 if (map->map_app != NULL) 280 len += strlen(map->map_app); 281 if (buflen < ++len) 282 { 283 /* need to malloc additional space */ 284 buflen = len; 285 if (buf != NULL) 286 free(buf); 287 buf = xalloc(buflen); 288 } 289 290 bp = buf; 291 if (av == NULL) 292 { 293 bcopy(s, bp, slen); 294 bp += slen; 295 } 296 else 297 { 298 while (--slen >= 0 && (c = *s++) != '\0') 299 { 300 if (c != '%') 301 { 302 pushc: 303 *bp++ = c; 304 continue; 305 } 306 if (--slen < 0 || (c = *s++) == '\0') 307 c = '%'; 308 if (c == '%') 309 goto pushc; 310 if (!(isascii(c) && isdigit(c))) 311 { 312 *bp++ = '%'; 313 goto pushc; 314 } 315 for (avp = av; --c >= '0' && *avp != NULL; avp++) 316 continue; 317 if (*avp == NULL) 318 continue; 319 320 /* transliterate argument into output string */ 321 for (ap = *avp; (c = *ap++) != '\0'; ) 322 *bp++ = c; 323 } 324 } 325 if (map->map_app != NULL) 326 strcpy(bp, map->map_app); 327 else 328 *bp = '\0'; 329 if (tTd(39, 1)) 330 printf("map_rewrite => %s\n", buf); 331 return buf; 332 } 333 /* 334 ** INITMAPS -- initialize for aliasing 335 ** 336 ** Parameters: 337 ** rebuild -- if TRUE, this rebuilds the cached versions. 338 ** e -- current envelope. 339 ** 340 ** Returns: 341 ** none. 342 ** 343 ** Side Effects: 344 ** initializes aliases: 345 ** if NDBM: opens the database. 346 ** if ~NDBM: reads the aliases into the symbol table. 347 */ 348 349 initmaps(rebuild, e) 350 bool rebuild; 351 register ENVELOPE *e; 352 { 353 extern void map_init(); 354 355 #ifdef XDEBUG 356 checkfd012("entering initmaps"); 357 #endif 358 CurEnv = e; 359 if (rebuild) 360 { 361 stabapply(map_init, 1); 362 stabapply(map_init, 2); 363 } 364 else 365 { 366 stabapply(map_init, 0); 367 } 368 #ifdef XDEBUG 369 checkfd012("exiting initmaps"); 370 #endif 371 } 372 373 void 374 map_init(s, rebuild) 375 register STAB *s; 376 int rebuild; 377 { 378 register MAP *map; 379 380 /* has to be a map */ 381 if (s->s_type != ST_MAP) 382 return; 383 384 map = &s->s_map; 385 if (!bitset(MF_VALID, map->map_mflags)) 386 return; 387 388 if (tTd(38, 2)) 389 printf("map_init(%s:%s, %s, %d)\n", 390 map->map_class->map_cname == NULL ? "NULL" : 391 map->map_class->map_cname, 392 map->map_mname == NULL ? "NULL" : map->map_mname, 393 map->map_file == NULL ? "NULL" : map->map_file, 394 rebuild); 395 396 if (rebuild == (bitset(MF_ALIAS, map->map_mflags) && 397 bitset(MCF_REBUILDABLE, map->map_class->map_cflags) ? 1 : 2)) 398 { 399 if (tTd(38, 3)) 400 printf("\twrong pass\n"); 401 return; 402 } 403 404 /* if already open, close it (for nested open) */ 405 if (bitset(MF_OPEN, map->map_mflags)) 406 { 407 map->map_class->map_close(map); 408 map->map_mflags &= ~(MF_OPEN|MF_WRITABLE); 409 } 410 411 if (rebuild == 2) 412 { 413 rebuildaliases(map, FALSE); 414 } 415 else 416 { 417 if (map->map_class->map_open(map, O_RDONLY)) 418 { 419 if (tTd(38, 4)) 420 printf("\t%s:%s %s: valid\n", 421 map->map_class->map_cname == NULL ? "NULL" : 422 map->map_class->map_cname, 423 map->map_mname == NULL ? "NULL" : 424 map->map_mname, 425 map->map_file == NULL ? "NULL" : 426 map->map_file); 427 map->map_mflags |= MF_OPEN; 428 } 429 else 430 { 431 if (tTd(38, 4)) 432 printf("\t%s:%s %s: invalid: %s\n", 433 map->map_class->map_cname == NULL ? "NULL" : 434 map->map_class->map_cname, 435 map->map_mname == NULL ? "NULL" : 436 map->map_mname, 437 map->map_file == NULL ? "NULL" : 438 map->map_file, 439 errstring(errno)); 440 if (!bitset(MF_OPTIONAL, map->map_mflags)) 441 { 442 extern MAPCLASS BogusMapClass; 443 444 map->map_class = &BogusMapClass; 445 map->map_mflags |= MF_OPEN; 446 } 447 } 448 } 449 } 450 /* 451 ** NDBM modules 452 */ 453 454 #ifdef NDBM 455 456 /* 457 ** DBM_MAP_OPEN -- DBM-style map open 458 */ 459 460 bool 461 ndbm_map_open(map, mode) 462 MAP *map; 463 int mode; 464 { 465 register DBM *dbm; 466 struct stat st; 467 468 if (tTd(38, 2)) 469 printf("ndbm_map_open(%s, %s, %d)\n", 470 map->map_mname, map->map_file, mode); 471 472 if (mode == O_RDWR) 473 mode |= O_CREAT|O_TRUNC; 474 475 /* open the database */ 476 dbm = dbm_open(map->map_file, mode, DBMMODE); 477 if (dbm == NULL) 478 { 479 if (aliaswait(map, ".pag", FALSE)) 480 return TRUE; 481 if (!bitset(MF_OPTIONAL, map->map_mflags)) 482 syserr("Cannot open DBM database %s", map->map_file); 483 return FALSE; 484 } 485 map->map_db1 = (void *) dbm; 486 if (mode == O_RDONLY) 487 { 488 if (bitset(MF_ALIAS, map->map_mflags) && 489 !aliaswait(map, ".pag", TRUE)) 490 return FALSE; 491 } 492 else 493 { 494 int fd; 495 496 /* exclusive lock for duration of rebuild */ 497 fd = dbm_dirfno((DBM *) map->map_db1); 498 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags) && 499 lockfile(fd, map->map_file, ".dir", LOCK_EX)) 500 map->map_mflags |= MF_LOCKED; 501 } 502 if (fstat(dbm_dirfno((DBM *) map->map_db1), &st) >= 0) 503 map->map_mtime = st.st_mtime; 504 return TRUE; 505 } 506 507 508 /* 509 ** DBM_MAP_LOOKUP -- look up a datum in a DBM-type map 510 */ 511 512 char * 513 ndbm_map_lookup(map, name, av, statp) 514 MAP *map; 515 char *name; 516 char **av; 517 int *statp; 518 { 519 datum key, val; 520 int fd; 521 char keybuf[MAXNAME + 1]; 522 523 if (tTd(38, 20)) 524 printf("ndbm_map_lookup(%s, %s)\n", 525 map->map_mname, name); 526 527 key.dptr = name; 528 key.dsize = strlen(name); 529 if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 530 { 531 if (key.dsize > sizeof keybuf - 1) 532 key.dsize = sizeof keybuf - 1; 533 bcopy(key.dptr, keybuf, key.dsize + 1); 534 makelower(keybuf); 535 key.dptr = keybuf; 536 } 537 fd = dbm_dirfno((DBM *) map->map_db1); 538 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 539 (void) lockfile(fd, map->map_file, ".dir", LOCK_SH); 540 val.dptr = NULL; 541 if (bitset(MF_TRY0NULL, map->map_mflags)) 542 { 543 val = dbm_fetch((DBM *) map->map_db1, key); 544 if (val.dptr != NULL) 545 map->map_mflags &= ~MF_TRY1NULL; 546 } 547 if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags)) 548 { 549 key.dsize++; 550 val = dbm_fetch((DBM *) map->map_db1, key); 551 if (val.dptr != NULL) 552 map->map_mflags &= ~MF_TRY0NULL; 553 } 554 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 555 (void) lockfile(fd, map->map_file, ".dir", LOCK_UN); 556 if (val.dptr == NULL) 557 return NULL; 558 if (bitset(MF_MATCHONLY, map->map_mflags)) 559 return map_rewrite(map, name, strlen(name), NULL); 560 else 561 return map_rewrite(map, val.dptr, val.dsize, av); 562 } 563 564 565 /* 566 ** DBM_MAP_STORE -- store a datum in the database 567 */ 568 569 void 570 ndbm_map_store(map, lhs, rhs) 571 register MAP *map; 572 char *lhs; 573 char *rhs; 574 { 575 datum key; 576 datum data; 577 int stat; 578 579 if (tTd(38, 12)) 580 printf("ndbm_map_store(%s, %s, %s)\n", 581 map->map_mname, lhs, rhs); 582 583 key.dsize = strlen(lhs); 584 key.dptr = lhs; 585 586 data.dsize = strlen(rhs); 587 data.dptr = rhs; 588 589 if (bitset(MF_INCLNULL, map->map_mflags)) 590 { 591 key.dsize++; 592 data.dsize++; 593 } 594 595 stat = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT); 596 if (stat > 0) 597 { 598 if (!bitset(MF_APPEND, map->map_mflags)) 599 usrerr("050 Warning: duplicate alias name %s", lhs); 600 else 601 { 602 static char *buf = NULL; 603 static int bufsiz = 0; 604 auto int xstat; 605 datum old; 606 607 old.dptr = ndbm_map_lookup(map, key.dptr, NULL, &xstat); 608 if (old.dptr != NULL && *old.dptr != '\0') 609 { 610 old.dsize = strlen(old.dptr); 611 if (data.dsize + old.dsize + 2 > bufsiz) 612 { 613 if (buf != NULL) 614 (void) free(buf); 615 bufsiz = data.dsize + old.dsize + 2; 616 buf = xalloc(bufsiz); 617 } 618 sprintf(buf, "%s,%s", data.dptr, old.dptr); 619 data.dsize = data.dsize + old.dsize + 1; 620 data.dptr = buf; 621 if (tTd(38, 9)) 622 printf("ndbm_map_store append=%s\n", data.dptr); 623 } 624 } 625 stat = dbm_store((DBM *) map->map_db1, key, data, DBM_REPLACE); 626 } 627 if (stat != 0) 628 syserr("readaliases: dbm put (%s)", lhs); 629 } 630 631 632 /* 633 ** NDBM_MAP_CLOSE -- close the database 634 */ 635 636 void 637 ndbm_map_close(map) 638 register MAP *map; 639 { 640 if (tTd(38, 9)) 641 printf("ndbm_map_close(%s, %s, %x)\n", 642 map->map_mname, map->map_file, map->map_mflags); 643 644 if (bitset(MF_WRITABLE, map->map_mflags)) 645 { 646 #ifdef NIS 647 bool inclnull; 648 char buf[200]; 649 650 inclnull = bitset(MF_INCLNULL, map->map_mflags); 651 map->map_mflags &= ~MF_INCLNULL; 652 653 (void) sprintf(buf, "%010ld", curtime()); 654 ndbm_map_store(map, "YP_LAST_MODIFIED", buf); 655 656 (void) gethostname(buf, sizeof buf); 657 ndbm_map_store(map, "YP_MASTER_NAME", buf); 658 659 if (inclnull) 660 map->map_mflags |= MF_INCLNULL; 661 #endif 662 663 /* write out the distinguished alias */ 664 ndbm_map_store(map, "@", "@"); 665 } 666 dbm_close((DBM *) map->map_db1); 667 } 668 669 #endif 670 /* 671 ** NEWDB (Hash and BTree) Modules 672 */ 673 674 #ifdef NEWDB 675 676 /* 677 ** BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives. 678 ** 679 ** These do rather bizarre locking. If you can lock on open, 680 ** do that to avoid the condition of opening a database that 681 ** is being rebuilt. If you don't, we'll try to fake it, but 682 ** there will be a race condition. If opening for read-only, 683 ** we immediately release the lock to avoid freezing things up. 684 ** We really ought to hold the lock, but guarantee that we won't 685 ** be pokey about it. That's hard to do. 686 */ 687 688 bool 689 bt_map_open(map, mode) 690 MAP *map; 691 int mode; 692 { 693 DB *db; 694 int i; 695 int omode; 696 int fd; 697 struct stat st; 698 char buf[MAXNAME + 1]; 699 700 if (tTd(38, 2)) 701 printf("bt_map_open(%s, %s, %d)\n", 702 map->map_mname, map->map_file, mode); 703 704 omode = mode; 705 if (omode == O_RDWR) 706 { 707 omode |= O_CREAT|O_TRUNC; 708 #if defined(O_EXLOCK) && HASFLOCK 709 omode |= O_EXLOCK; 710 # if !OLD_NEWDB 711 } 712 else 713 { 714 omode |= O_SHLOCK; 715 # endif 716 #endif 717 } 718 719 (void) strcpy(buf, map->map_file); 720 i = strlen(buf); 721 if (i < 3 || strcmp(&buf[i - 3], ".db") != 0) 722 (void) strcat(buf, ".db"); 723 db = dbopen(buf, omode, DBMMODE, DB_BTREE, NULL); 724 if (db == NULL) 725 { 726 #ifdef MAYBENEXTRELEASE 727 if (aliaswait(map, ".db", FALSE)) 728 return TRUE; 729 #endif 730 if (!bitset(MF_OPTIONAL, map->map_mflags)) 731 syserr("Cannot open BTREE database %s", map->map_file); 732 return FALSE; 733 } 734 #if !OLD_NEWDB 735 fd = db->fd(db); 736 # if defined(O_EXLOCK) && HASFLOCK 737 if (fd >= 0) 738 { 739 if (mode == O_RDONLY) 740 (void) lockfile(fd, map->map_file, ".db", LOCK_UN); 741 else 742 map->map_mflags |= MF_LOCKED; 743 } 744 # else 745 if (mode == O_RDWR && fd >= 0) 746 { 747 if (lockfile(fd, map->map_file, ".db", LOCK_EX)) 748 map->map_mflags |= MF_LOCKED; 749 } 750 # endif 751 #endif 752 753 /* try to make sure that at least the database header is on disk */ 754 if (mode == O_RDWR) 755 #if OLD_NEWDB 756 (void) db->sync(db); 757 #else 758 (void) db->sync(db, 0); 759 760 if (fd >= 0 && fstat(fd, &st) >= 0) 761 map->map_mtime = st.st_mtime; 762 #endif 763 764 map->map_db2 = (void *) db; 765 if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags)) 766 if (!aliaswait(map, ".db", TRUE)) 767 return FALSE; 768 return TRUE; 769 } 770 771 772 /* 773 ** HASH_MAP_INIT -- HASH-style map initialization 774 */ 775 776 bool 777 hash_map_open(map, mode) 778 MAP *map; 779 int mode; 780 { 781 DB *db; 782 int i; 783 int omode; 784 int fd; 785 struct stat st; 786 char buf[MAXNAME + 1]; 787 788 if (tTd(38, 2)) 789 printf("hash_map_open(%s, %s, %d)\n", 790 map->map_mname, map->map_file, mode); 791 792 omode = mode; 793 if (omode == O_RDWR) 794 { 795 omode |= O_CREAT|O_TRUNC; 796 #if defined(O_EXLOCK) && HASFLOCK 797 omode |= O_EXLOCK; 798 # if !OLD_NEWDB 799 } 800 else 801 { 802 omode |= O_SHLOCK; 803 # endif 804 #endif 805 } 806 807 (void) strcpy(buf, map->map_file); 808 i = strlen(buf); 809 if (i < 3 || strcmp(&buf[i - 3], ".db") != 0) 810 (void) strcat(buf, ".db"); 811 db = dbopen(buf, omode, DBMMODE, DB_HASH, NULL); 812 if (db == NULL) 813 { 814 #ifdef MAYBENEXTRELEASE 815 if (aliaswait(map, ".db", FALSE)) 816 return TRUE; 817 #endif 818 if (!bitset(MF_OPTIONAL, map->map_mflags)) 819 syserr("Cannot open HASH database %s", map->map_file); 820 return FALSE; 821 } 822 #if !OLD_NEWDB 823 fd = db->fd(db); 824 # if defined(O_EXLOCK) && HASFLOCK 825 if (fd >= 0) 826 { 827 if (mode == O_RDONLY) 828 (void) lockfile(fd, map->map_file, ".db", LOCK_UN); 829 else 830 map->map_mflags |= MF_LOCKED; 831 } 832 # else 833 if (mode == O_RDWR && fd >= 0) 834 { 835 if (lockfile(fd, map->map_file, ".db", LOCK_EX)) 836 map->map_mflags |= MF_LOCKED; 837 } 838 # endif 839 #endif 840 841 /* try to make sure that at least the database header is on disk */ 842 if (mode == O_RDWR) 843 #if OLD_NEWDB 844 (void) db->sync(db); 845 #else 846 (void) db->sync(db, 0); 847 848 if (fd >= 0 && fstat(fd, &st) >= 0) 849 map->map_mtime = st.st_mtime; 850 #endif 851 852 map->map_db2 = (void *) db; 853 if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags)) 854 if (!aliaswait(map, ".db", TRUE)) 855 return FALSE; 856 return TRUE; 857 } 858 859 860 /* 861 ** DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map 862 */ 863 864 char * 865 db_map_lookup(map, name, av, statp) 866 MAP *map; 867 char *name; 868 char **av; 869 int *statp; 870 { 871 DBT key, val; 872 register DB *db = (DB *) map->map_db2; 873 int st; 874 int saveerrno; 875 int fd; 876 char keybuf[MAXNAME + 1]; 877 878 if (tTd(38, 20)) 879 printf("db_map_lookup(%s, %s)\n", 880 map->map_mname, name); 881 882 key.size = strlen(name); 883 if (key.size > sizeof keybuf - 1) 884 key.size = sizeof keybuf - 1; 885 key.data = keybuf; 886 bcopy(name, keybuf, key.size + 1); 887 if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 888 makelower(keybuf); 889 #if !OLD_NEWDB 890 fd = db->fd(db); 891 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 892 (void) lockfile(db->fd(db), map->map_file, ".db", LOCK_SH); 893 #endif 894 st = 1; 895 if (bitset(MF_TRY0NULL, map->map_mflags)) 896 { 897 st = db->get(db, &key, &val, 0); 898 if (st == 0) 899 map->map_mflags &= ~MF_TRY1NULL; 900 } 901 if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags)) 902 { 903 key.size++; 904 st = db->get(db, &key, &val, 0); 905 if (st == 0) 906 map->map_mflags &= ~MF_TRY0NULL; 907 } 908 saveerrno = errno; 909 #if !OLD_NEWDB 910 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 911 (void) lockfile(fd, map->map_file, ".db", LOCK_UN); 912 #endif 913 if (st != 0) 914 { 915 errno = saveerrno; 916 if (st < 0) 917 syserr("db_map_lookup: get (%s)", name); 918 return NULL; 919 } 920 if (bitset(MF_MATCHONLY, map->map_mflags)) 921 return map_rewrite(map, name, strlen(name), NULL); 922 else 923 return map_rewrite(map, val.data, val.size, av); 924 } 925 926 927 /* 928 ** DB_MAP_STORE -- store a datum in the NEWDB database 929 */ 930 931 void 932 db_map_store(map, lhs, rhs) 933 register MAP *map; 934 char *lhs; 935 char *rhs; 936 { 937 int stat; 938 DBT key; 939 DBT data; 940 register DB *db = map->map_db2; 941 942 if (tTd(38, 20)) 943 printf("db_map_store(%s, %s, %s)\n", 944 map->map_mname, lhs, rhs); 945 946 key.size = strlen(lhs); 947 key.data = lhs; 948 949 data.size = strlen(rhs); 950 data.data = rhs; 951 952 if (bitset(MF_INCLNULL, map->map_mflags)) 953 { 954 key.size++; 955 data.size++; 956 } 957 958 stat = db->put(db, &key, &data, R_NOOVERWRITE); 959 if (stat > 0) 960 { 961 if (!bitset(MF_APPEND, map->map_mflags)) 962 usrerr("050 Warning: duplicate alias name %s", lhs); 963 else 964 { 965 static char *buf = NULL; 966 static int bufsiz = 0; 967 DBT old; 968 969 old.data = db_map_lookup(map, key.data, NULL, &stat); 970 if (old.data != NULL) 971 { 972 old.size = strlen(old.data); 973 if (data.size + old.size + 2 > bufsiz) 974 { 975 if (buf != NULL) 976 (void) free(buf); 977 bufsiz = data.size + old.size + 2; 978 buf = xalloc(bufsiz); 979 } 980 sprintf(buf, "%s,%s", data.data, old.data); 981 data.size = data.size + old.size + 1; 982 data.data = buf; 983 if (tTd(38, 9)) 984 printf("db_map_store append=%s\n", data.data); 985 } 986 } 987 stat = db->put(db, &key, &data, 0); 988 } 989 if (stat != 0) 990 syserr("readaliases: db put (%s)", lhs); 991 } 992 993 994 /* 995 ** DB_MAP_CLOSE -- add distinguished entries and close the database 996 */ 997 998 void 999 db_map_close(map) 1000 MAP *map; 1001 { 1002 register DB *db = map->map_db2; 1003 1004 if (tTd(38, 9)) 1005 printf("db_map_close(%s, %s, %x)\n", 1006 map->map_mname, map->map_file, map->map_mflags); 1007 1008 if (bitset(MF_WRITABLE, map->map_mflags)) 1009 { 1010 /* write out the distinguished alias */ 1011 db_map_store(map, "@", "@"); 1012 } 1013 1014 if (db->close(db) != 0) 1015 syserr("readaliases: db close failure"); 1016 } 1017 1018 #endif 1019 /* 1020 ** NIS Modules 1021 */ 1022 1023 # ifdef NIS 1024 1025 # ifndef YPERR_BUSY 1026 # define YPERR_BUSY 16 1027 # endif 1028 1029 /* 1030 ** NIS_MAP_OPEN -- open DBM map 1031 */ 1032 1033 bool 1034 nis_map_open(map, mode) 1035 MAP *map; 1036 int mode; 1037 { 1038 int yperr; 1039 register char *p; 1040 auto char *vp; 1041 auto int vsize; 1042 char *master; 1043 1044 if (tTd(38, 2)) 1045 printf("nis_map_open(%s, %s)\n", 1046 map->map_mname, map->map_file); 1047 1048 if (mode != O_RDONLY) 1049 { 1050 /* issue a pseudo-error message */ 1051 #ifdef ENOSYS 1052 errno = ENOSYS; 1053 #else 1054 # ifdef EFTYPE 1055 errno = EFTYPE; 1056 # else 1057 errno = ENXIO; 1058 # endif 1059 #endif 1060 return FALSE; 1061 } 1062 1063 p = strchr(map->map_file, '@'); 1064 if (p != NULL) 1065 { 1066 *p++ = '\0'; 1067 if (*p != '\0') 1068 map->map_domain = p; 1069 } 1070 1071 if (*map->map_file == '\0') 1072 map->map_file = "mail.aliases"; 1073 1074 if (map->map_domain == NULL) 1075 { 1076 yperr = yp_get_default_domain(&map->map_domain); 1077 if (yperr != 0) 1078 { 1079 if (!bitset(MF_OPTIONAL, map->map_mflags)) 1080 syserr("421 NIS map %s specified, but NIS not running\n", 1081 map->map_file); 1082 return FALSE; 1083 } 1084 } 1085 1086 /* check to see if this map actually exists */ 1087 yperr = yp_match(map->map_domain, map->map_file, "@", 1, 1088 &vp, &vsize); 1089 if (tTd(38, 10)) 1090 printf("nis_map_open: yp_match(%s, %s) => %s\n", 1091 map->map_domain, map->map_file, yperr_string(yperr)); 1092 if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY) 1093 { 1094 if (!bitset(MF_ALIAS, map->map_mflags) || 1095 aliaswait(map, NULL, TRUE)) 1096 return TRUE; 1097 } 1098 1099 if (!bitset(MF_OPTIONAL, map->map_mflags)) 1100 { 1101 syserr("421 Cannot bind to map %s in domain %s: %s", 1102 map->map_file, map->map_domain, yperr_string(yperr)); 1103 } 1104 1105 return FALSE; 1106 } 1107 1108 1109 /* 1110 ** NIS_MAP_LOOKUP -- look up a datum in a NIS map 1111 */ 1112 1113 char * 1114 nis_map_lookup(map, name, av, statp) 1115 MAP *map; 1116 char *name; 1117 char **av; 1118 int *statp; 1119 { 1120 char *vp; 1121 auto int vsize; 1122 int buflen; 1123 int yperr; 1124 char keybuf[MAXNAME + 1]; 1125 1126 if (tTd(38, 20)) 1127 printf("nis_map_lookup(%s, %s)\n", 1128 map->map_mname, name); 1129 1130 buflen = strlen(name); 1131 if (buflen > sizeof keybuf - 1) 1132 buflen = sizeof keybuf - 1; 1133 bcopy(name, keybuf, buflen + 1); 1134 if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 1135 makelower(keybuf); 1136 yperr = YPERR_KEY; 1137 if (bitset(MF_TRY0NULL, map->map_mflags)) 1138 { 1139 yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen, 1140 &vp, &vsize); 1141 if (yperr == 0) 1142 map->map_mflags &= ~MF_TRY1NULL; 1143 } 1144 if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags)) 1145 { 1146 buflen++; 1147 yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen, 1148 &vp, &vsize); 1149 if (yperr == 0) 1150 map->map_mflags &= ~MF_TRY0NULL; 1151 } 1152 if (yperr != 0) 1153 { 1154 if (yperr != YPERR_KEY && yperr != YPERR_BUSY) 1155 map->map_mflags &= ~(MF_VALID|MF_OPEN); 1156 return NULL; 1157 } 1158 if (bitset(MF_MATCHONLY, map->map_mflags)) 1159 return map_rewrite(map, name, strlen(name), NULL); 1160 else 1161 return map_rewrite(map, vp, vsize, av); 1162 } 1163 1164 1165 /* 1166 ** NIS_GETCANONNAME -- look up canonical name in NIS 1167 */ 1168 1169 bool 1170 nis_getcanonname(name, hbsize, statp) 1171 char *name; 1172 int hbsize; 1173 int *statp; 1174 { 1175 char *vp; 1176 auto int vsize; 1177 int keylen; 1178 int yperr; 1179 static bool try0null = TRUE; 1180 static bool try1null = TRUE; 1181 static char *yp_domain = NULL; 1182 char *domain, *p; 1183 char host_record[MAXLINE]; 1184 char buf[MAXNAME]; 1185 char *cname; 1186 extern char *get_column(); 1187 1188 if (tTd(38, 20)) 1189 printf("nis_getcanonname(%s)\n", name); 1190 1191 shorten_hostname(name); 1192 1193 /* we only accept single token search key */ 1194 if (strchr(name, '.')) 1195 { 1196 *statp = EX_NOHOST; 1197 return FALSE; 1198 } 1199 1200 keylen = strlen(name); 1201 1202 if (yp_domain == NULL) 1203 yp_get_default_domain(&yp_domain); 1204 makelower(name); 1205 yperr = YPERR_KEY; 1206 if (try0null) 1207 { 1208 yperr = yp_match(yp_domain, "hosts.byname", name, keylen, 1209 &vp, &vsize); 1210 if (yperr == 0) 1211 try1null = FALSE; 1212 } 1213 if (yperr == YPERR_KEY && try1null) 1214 { 1215 keylen++; 1216 yperr = yp_match(yp_domain, "hosts.byname", name, keylen, 1217 &vp, &vsize); 1218 if (yperr == 0) 1219 try0null = FALSE; 1220 } 1221 if (yperr != 0) 1222 { 1223 if (yperr == YPERR_KEY) 1224 *statp = EX_NOHOST; 1225 else if (yperr == YPERR_BUSY) 1226 *statp = EX_TEMPFAIL; 1227 else 1228 *statp = EX_UNAVAILABLE; 1229 return FALSE; 1230 } 1231 strncpy(host_record, vp, vsize); 1232 host_record[vsize] = '\0'; 1233 cname = get_column(host_record, 1, '\t', buf); 1234 if (cname == NULL) 1235 { 1236 /* this should not happen, but.... */ 1237 *statp = EX_NOHOST; 1238 return FALSE; 1239 } 1240 1241 if (hbsize >= strlen(cname)) 1242 { 1243 strcpy(name, cname); 1244 *statp = EX_OK; 1245 return TRUE; 1246 } 1247 *statp = EX_UNAVAILABLE; 1248 return FALSE; 1249 } 1250 1251 #endif 1252 /* 1253 ** NISPLUS Modules 1254 ** 1255 ** This code donated by Sun Microsystems. 1256 */ 1257 1258 #ifdef NISPLUS 1259 1260 #undef NIS /* symbol conflict in nis.h */ 1261 #include <rpcsvc/nis.h> 1262 #include <rpcsvc/nislib.h> 1263 1264 #define EN_col(col) zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val 1265 #define COL_NAME(res,i) ((res->objects.objects_val)->TA_data.ta_cols.ta_cols_val)[i].tc_name 1266 #define COL_MAX(res) ((res->objects.objects_val)->TA_data.ta_cols.ta_cols_len) 1267 #define PARTIAL_NAME(x) ((x)[strlen(x) - 1] != '.') 1268 1269 /* 1270 ** NISPLUS_MAP_OPEN -- open nisplus table 1271 */ 1272 1273 bool 1274 nisplus_map_open(map, mode) 1275 MAP *map; 1276 int mode; 1277 { 1278 register char *p; 1279 char qbuf[MAXLINE + NIS_MAXNAMELEN]; 1280 nis_result *res = NULL; 1281 u_int objs_len; 1282 nis_object *obj_ptr; 1283 int retry_cnt, max_col, i; 1284 1285 if (tTd(38, 2)) 1286 printf("nisplus_map_open(%s, %s, %d)\n", 1287 map->map_mname, map->map_file, mode); 1288 1289 if (mode != O_RDONLY) 1290 { 1291 errno = ENODEV; 1292 return FALSE; 1293 } 1294 1295 if (*map->map_file == '\0') 1296 map->map_file = "mail_aliases.org_dir"; 1297 1298 if (PARTIAL_NAME(map->map_file) && map->map_domain == NULL) 1299 { 1300 /* set default NISPLUS Domain to $m */ 1301 extern char *nisplus_default_domain(); 1302 1303 map->map_domain = newstr(nisplus_default_domain()); 1304 if (tTd(38, 2)) 1305 printf("nisplus_map_open(%s): using domain %s\n", 1306 map->map_file, map->map_domain); 1307 } 1308 if (!PARTIAL_NAME(map->map_file)) 1309 map->map_domain = newstr(""); 1310 1311 /* check to see if this map actually exists */ 1312 if (PARTIAL_NAME(map->map_file)) 1313 sprintf(qbuf, "%s.%s", map->map_file, map->map_domain); 1314 else 1315 strcpy(qbuf, map->map_file); 1316 1317 retry_cnt = 0; 1318 while (res == NULL || res->status != NIS_SUCCESS) 1319 { 1320 res = nis_lookup(qbuf, FOLLOW_LINKS); 1321 switch (res->status) 1322 { 1323 case NIS_SUCCESS: 1324 case NIS_TRYAGAIN: 1325 case NIS_RPCERROR: 1326 case NIS_NAMEUNREACHABLE: 1327 break; 1328 1329 default: /* all other nisplus errors */ 1330 #if 0 1331 if (!bitset(MF_OPTIONAL, map->map_mflags)) 1332 syserr("421 Cannot find table %s.%s: %s", 1333 map->map_file, map->map_domain, 1334 nis_sperrno(res->status)); 1335 #endif 1336 errno = EBADR; 1337 return FALSE; 1338 } 1339 sleep(2); /* try not to overwhelm hosed server */ 1340 if (retry_cnt++ > 4) 1341 { 1342 errno = EBADR; 1343 return FALSE; 1344 } 1345 } 1346 1347 if (NIS_RES_NUMOBJ(res) != 1 || 1348 (NIS_RES_OBJECT(res)->zo_data.zo_type != TABLE_OBJ)) 1349 { 1350 if (tTd(38, 10)) 1351 printf("nisplus_map_open: %s is not a table\n", qbuf); 1352 #if 0 1353 if (!bitset(MF_OPTIONAL, map->map_mflags)) 1354 syserr("421 %s.%s: %s is not a table", 1355 map->map_file, map->map_domain, 1356 nis_sperrno(res->status)); 1357 #endif 1358 errno = EBADR; 1359 return FALSE; 1360 } 1361 /* default key column is column 0 */ 1362 if (map->map_keycolnm == NULL) 1363 map->map_keycolnm = newstr(COL_NAME(res,0)); 1364 1365 max_col = COL_MAX(res); 1366 1367 /* verify the key column exist */ 1368 for (i=0; i< max_col; i++) 1369 { 1370 if (!strcmp(map->map_keycolnm, COL_NAME(res,i))) 1371 break; 1372 } 1373 if (i == max_col) 1374 { 1375 if (tTd(38, 2)) 1376 printf("nisplus_map_open(%s): can not find key column %s\n", 1377 map->map_file, map->map_keycolnm); 1378 errno = EBADR; 1379 return FALSE; 1380 } 1381 1382 /* default value column is the last column */ 1383 if (map->map_valcolnm == NULL) 1384 { 1385 map->map_valcolno = max_col - 1; 1386 return TRUE; 1387 } 1388 1389 for (i=0; i< max_col; i++) 1390 { 1391 if (strcmp(map->map_valcolnm, COL_NAME(res,i)) == 0) 1392 { 1393 map->map_valcolno = i; 1394 return TRUE; 1395 } 1396 } 1397 1398 if (tTd(38, 2)) 1399 printf("nisplus_map_open(%s): can not find column %s\n", 1400 map->map_file, map->map_keycolnm); 1401 errno = EBADR; 1402 return FALSE; 1403 } 1404 1405 1406 /* 1407 ** NISPLUS_MAP_LOOKUP -- look up a datum in a NISPLUS table 1408 */ 1409 1410 char * 1411 nisplus_map_lookup(map, name, av, statp) 1412 MAP *map; 1413 char *name; 1414 char **av; 1415 int *statp; 1416 { 1417 char *vp; 1418 auto int vsize; 1419 int buflen; 1420 char search_key[MAXNAME + 1]; 1421 char qbuf[MAXLINE + NIS_MAXNAMELEN]; 1422 nis_result *result; 1423 1424 if (tTd(38, 20)) 1425 printf("nisplus_map_lookup(%s, %s)\n", 1426 map->map_mname, name); 1427 1428 if (!bitset(MF_OPEN, map->map_mflags)) 1429 { 1430 if (nisplus_map_open(map, O_RDONLY)) 1431 map->map_mflags |= MF_OPEN; 1432 else 1433 { 1434 *statp = EX_UNAVAILABLE; 1435 return NULL; 1436 } 1437 } 1438 1439 buflen = strlen(name); 1440 if (buflen > sizeof search_key - 1) 1441 buflen = sizeof search_key - 1; 1442 bcopy(name, search_key, buflen + 1); 1443 if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 1444 makelower(search_key); 1445 1446 /* construct the query */ 1447 if (PARTIAL_NAME(map->map_file)) 1448 sprintf(qbuf, "[%s=%s],%s.%s", map->map_keycolnm, 1449 search_key, map->map_file, map->map_domain); 1450 else 1451 sprintf(qbuf, "[%s=%s],%s", map->map_keycolnm, 1452 search_key, map->map_file); 1453 1454 if (tTd(38, 20)) 1455 printf("qbuf=%s\n", qbuf); 1456 result = nis_list(qbuf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL); 1457 if (result->status == NIS_SUCCESS) 1458 { 1459 int count; 1460 char *str; 1461 1462 if ((count = NIS_RES_NUMOBJ(result)) != 1) 1463 { 1464 if (LogLevel > 10) 1465 syslog(LOG_WARNING, 1466 "%s:Lookup error, expected 1 entry, got (%d)", 1467 map->map_file, count); 1468 1469 /* ignore second entry */ 1470 if (tTd(38, 20)) 1471 printf("nisplus_map_lookup(%s), got %d entries, additional entries ignored\n", 1472 name, count); 1473 } 1474 1475 vp = ((NIS_RES_OBJECT(result))->EN_col(map->map_valcolno)); 1476 /* set the length of the result */ 1477 if (vp == NULL) 1478 vp = ""; 1479 vsize = strlen(vp); 1480 if (tTd(38, 20)) 1481 printf("nisplus_map_lookup(%s), found %s\n", 1482 name, vp); 1483 if (bitset(MF_MATCHONLY, map->map_mflags)) 1484 str = map_rewrite(map, name, strlen(name), NULL); 1485 else 1486 str = map_rewrite(map, vp, vsize, av); 1487 nis_freeresult(result); 1488 #ifdef MAP_EXIT_STAT 1489 *statp = EX_OK; 1490 #endif 1491 return str; 1492 } 1493 else 1494 { 1495 #ifdef MAP_EXIT_STAT 1496 if (result->status == NIS_NOTFOUND) 1497 *statp = EX_NOTFOUND; 1498 else if (result->status == NIS_TRYAGAIN) 1499 *statp = EX_TEMPFAIL; 1500 else 1501 { 1502 *statp = EX_UNAVAILABLE; 1503 map->map_mflags &= ~(MF_VALID|MF_OPEN); 1504 } 1505 #else 1506 if ((result->status != NIS_NOTFOUND) && 1507 (result->status != NIS_TRYAGAIN)) 1508 map->map_mflags &= ~(MF_VALID|MF_OPEN); 1509 #endif 1510 } 1511 if (tTd(38, 20)) 1512 printf("nisplus_map_lookup(%s), failed\n", name); 1513 nis_freeresult(result); 1514 return NULL; 1515 } 1516 1517 1518 1519 /* 1520 ** NISPLUS_GETCANONNAME -- look up canonical name in NIS+ 1521 */ 1522 1523 bool 1524 nisplus_getcanonname(name, hbsize, statp) 1525 char *name; 1526 int hbsize; 1527 int *statp; 1528 { 1529 char *vp; 1530 auto int vsize; 1531 int buflen; 1532 char buf1[MAXLINE + NIS_MAXNAMELEN]; 1533 static char *nis_path = NULL; 1534 static char nis_path_buf[MAXLINE]; 1535 nis_result *result; 1536 char *p; 1537 int len; 1538 1539 if (nis_path == NULL) 1540 { 1541 char *ptr; 1542 char pathbuf[MAXLINE]; 1543 1544 strcpy(buf1, macvalue('m', CurEnv)); 1545 strcat(buf1, "."); 1546 /* try the host tabe in $m */ 1547 if (hosts_table_ok(buf1)) 1548 strcpy(pathbuf, buf1); 1549 else 1550 strcpy(pathbuf, "$"); 1551 1552 nis_path = nis_path_buf; 1553 sprintf(nis_path, "NIS_PATH=%s", pathbuf); 1554 } 1555 1556 if (nis_path[0] != '\0') 1557 putenv(nis_path); 1558 else 1559 syslog(LOG_WARNING, "no NIS+ path defined"); 1560 1561 shorten_hostname(name); 1562 1563 p = strchr(name, '.'); 1564 if (p == NULL) 1565 { 1566 /* single token */ 1567 sprintf(buf1, "[name=%s],hosts.org_dir", name); 1568 } 1569 else if (p[1] != '\0') 1570 { 1571 /* multi token -- take only first token in name buf */ 1572 *p = '\0'; 1573 sprintf(buf1, "[name=%s],hosts.org_dir.%s", name, &p[1]); 1574 } 1575 else 1576 { 1577 *statp = EX_NOHOST; 1578 return FALSE; 1579 } 1580 1581 if (tTd(38, 20)) 1582 printf("\nnisplus_getcanoname(%s), qbuf=%s\n%s\n", 1583 name, buf1, nis_path); 1584 1585 result = nis_list(buf1, EXPAND_NAME|FOLLOW_LINKS|FOLLOW_PATH, 1586 NULL, NULL); 1587 1588 /* unset NIS_PATH, just in case */ 1589 unsetenv("NIS_PATH"); 1590 1591 if (result->status == NIS_SUCCESS) 1592 { 1593 int count; 1594 char *str; 1595 char *domain; 1596 1597 if ((count = NIS_RES_NUMOBJ(result)) != 1) 1598 { 1599 #ifdef LOG 1600 if (LogLevel > 10) 1601 syslog(LOG_WARNING, 1602 "nisplus_getcanonname: Lookup error, expected 1 entry, got (%d)", 1603 count); 1604 #endif 1605 1606 /* ignore second entry */ 1607 if (tTd(38, 20)) 1608 printf("nisplus_getcanoname(%s), got %d entries, addtional entries ignores\n", name); 1609 } 1610 1611 if (tTd(38, 20)) 1612 printf("nisplus_getcanoname(%s), found in directory \"%s\"\n", 1613 name, (NIS_RES_OBJECT(result))->zo_domain); 1614 1615 1616 vp = ((NIS_RES_OBJECT(result))->EN_col(0)); 1617 vsize = strlen(vp); 1618 if (tTd(38, 20)) 1619 printf("nisplus_getcanonname(%s), found %s\n", 1620 name, vp); 1621 domain = macvalue('m', CurEnv); 1622 if (hbsize > (vsize + ((int) strlen(domain)))) 1623 { 1624 sprintf(name, "%s.%s", vp, domain); 1625 *statp = EX_OK; 1626 } 1627 else 1628 *statp = EX_NOHOST; 1629 nis_freeresult(result); 1630 return TRUE; 1631 } 1632 else 1633 { 1634 if (result->status == NIS_NOTFOUND) 1635 *statp = EX_NOHOST; 1636 else if (result->status == NIS_TRYAGAIN) 1637 *statp = EX_TEMPFAIL; 1638 else 1639 { 1640 *statp = EX_UNAVAILABLE; 1641 } 1642 } 1643 if (tTd(38, 20)) 1644 printf("nisplus_getcanonname(%s), failed, status=%d, nsw_stat=%d\n", 1645 name, result->status, *statp); 1646 nis_freeresult(result); 1647 return FALSE; 1648 } 1649 1650 1651 char * 1652 nisplus_default_domain() 1653 { 1654 static char default_domain[MAXNAME + 1] = ""; 1655 char *p; 1656 1657 if (default_domain[0] != '\0') 1658 return(default_domain); 1659 1660 p = nis_local_directory(); 1661 strcpy(default_domain, p); 1662 return default_domain; 1663 } 1664 1665 #endif /* NISPLUS */ 1666 /* 1667 ** HESIOD Modules 1668 */ 1669 1670 #ifdef HESIOD 1671 1672 #include <hesiod.h> 1673 1674 char * 1675 hes_map_lookup(map, name, av, statp) 1676 MAP *map; 1677 char *name; 1678 char **av; 1679 int *statp; 1680 { 1681 char **hp; 1682 char *retdata = NULL; 1683 int i; 1684 1685 if (tTd(38, 20)) 1686 printf("hes_map_lookup(%s, %s)\n", map->map_file, name); 1687 1688 hp = hes_resolve(name, map->map_file); 1689 if (hp == NULL) 1690 return NULL; 1691 1692 if (hp[0] != NULL) 1693 { 1694 if (bitset(MF_MATCHONLY, map->map_mflags)) 1695 retdata = map_rewrite(map, name, strlen(name), NULL); 1696 else 1697 retdata = map_rewrite(map, hp[0], strlen(hp[0]), av); 1698 } 1699 1700 for (i = 0; hp[i] != NULL; i++) 1701 free(hp[i]); 1702 free(hp); 1703 return retdata; 1704 } 1705 1706 #endif 1707 /* 1708 ** NeXT NETINFO Modules 1709 */ 1710 1711 #ifdef NETINFO 1712 1713 #define NETINFO_DEFAULT_DIR "/aliases" 1714 #define NETINFO_DEFAULT_PROPERTY "members" 1715 1716 1717 /* 1718 ** NI_MAP_OPEN -- open NetInfo Aliases 1719 */ 1720 1721 bool 1722 ni_map_open(map, mode) 1723 MAP *map; 1724 int mode; 1725 { 1726 char *p; 1727 1728 if (tTd(38, 20)) 1729 printf("ni_map_open: %s\n", map->map_file); 1730 1731 if (*map->map_file == '\0') 1732 map->map_file = NETINFO_DEFAULT_DIR; 1733 1734 if (map->map_valcolnm == NULL) 1735 map->map_valcolnm = NETINFO_DEFAULT_PROPERTY; 1736 1737 if (map->map_coldelim == '\0' && bitset(MF_ALIAS, map->map_mflags)) 1738 map->map_coldelim = ','; 1739 1740 return TRUE; 1741 } 1742 1743 1744 /* 1745 ** NI_MAP_LOOKUP -- look up a datum in NetInfo 1746 */ 1747 1748 char * 1749 ni_map_lookup(map, name, av, statp) 1750 MAP *map; 1751 char *name; 1752 char **av; 1753 int *statp; 1754 { 1755 char *res; 1756 char *propval; 1757 extern char *ni_propval(); 1758 1759 if (tTd(38, 20)) 1760 printf("ni_map_lookup(%s, %s)\n", 1761 map->map_mname, name); 1762 1763 propval = ni_propval(map->map_file, map->map_keycolnm, name, 1764 map->map_valcolnm, map->map_coldelim); 1765 1766 if (propval == NULL) 1767 return NULL; 1768 1769 if (bitset(MF_MATCHONLY, map->map_mflags)) 1770 res = map_rewrite(map, name, strlen(name), NULL); 1771 else 1772 res = map_rewrite(map, propval, strlen(propval), av); 1773 free(propval); 1774 return res; 1775 } 1776 1777 #endif 1778 /* 1779 ** TEXT (unindexed text file) Modules 1780 ** 1781 ** This code donated by Sun Microsystems. 1782 */ 1783 1784 1785 /* 1786 ** TEXT_MAP_OPEN -- open text table 1787 */ 1788 1789 bool 1790 text_map_open(map, mode) 1791 MAP *map; 1792 int mode; 1793 { 1794 struct stat sbuf; 1795 1796 if (tTd(38, 2)) 1797 printf("text_map_open(%s, %s, %d)\n", 1798 map->map_mname, map->map_file, mode); 1799 1800 if (mode != O_RDONLY) 1801 { 1802 errno = ENODEV; 1803 return FALSE; 1804 } 1805 1806 if (*map->map_file == '\0') 1807 { 1808 if (tTd(38, 2)) 1809 printf("text_map_open: file name required\n"); 1810 return FALSE; 1811 } 1812 1813 if (map->map_file[0] != '/') 1814 { 1815 if (tTd(38, 2)) 1816 printf("text_map_open(%s): file name must be fully qualified\n", 1817 map->map_file); 1818 return FALSE; 1819 } 1820 /* check to see if this map actually accessable */ 1821 if (access(map->map_file, R_OK) <0) 1822 return FALSE; 1823 1824 /* check to see if this map actually exist */ 1825 if (stat(map->map_file, &sbuf) <0) 1826 { 1827 if (tTd(38, 2)) 1828 printf("text_map_open(%s): can not stat %s\n", 1829 map->map_file, map->map_file); 1830 return FALSE; 1831 } 1832 1833 if (!S_ISREG(sbuf.st_mode)) 1834 { 1835 if (tTd(38, 2)) 1836 printf("text_map_open(%s): %s is not a file\n", 1837 map->map_file, map->map_file); 1838 return FALSE; 1839 } 1840 1841 if (map->map_keycolnm == NULL) 1842 map->map_keycolno = 0; 1843 else 1844 { 1845 if (!isdigit(*map->map_keycolnm)) 1846 { 1847 if (tTd(38, 2)) 1848 printf("text_map_open(%s): -k should specify a number, not %s\n", 1849 map->map_file, map->map_keycolnm); 1850 return FALSE; 1851 } 1852 map->map_keycolno = atoi(map->map_keycolnm); 1853 } 1854 1855 if (map->map_valcolnm == NULL) 1856 map->map_valcolno = 0; 1857 else 1858 { 1859 if (!isdigit(*map->map_valcolnm)) 1860 { 1861 if (tTd(38, 2)) 1862 printf("text_map_open(%s): -v should specify a number, not %s\n", 1863 map->map_file, map->map_valcolnm); 1864 return FALSE; 1865 } 1866 map->map_valcolno = atoi(map->map_valcolnm); 1867 } 1868 1869 if (tTd(38, 2)) 1870 { 1871 printf("text_map_open(%s): delimiter = ", 1872 map->map_file); 1873 if (map->map_coldelim == '\0') 1874 printf("(white space)\n"); 1875 else 1876 printf("%c\n", map->map_coldelim); 1877 } 1878 1879 return TRUE; 1880 } 1881 1882 1883 /* 1884 ** TEXT_MAP_LOOKUP -- look up a datum in a TEXT table 1885 */ 1886 1887 char * 1888 text_map_lookup(map, name, av, statp) 1889 MAP *map; 1890 char *name; 1891 char **av; 1892 int *statp; 1893 { 1894 char *vp; 1895 auto int vsize; 1896 int buflen; 1897 char search_key[MAXNAME + 1]; 1898 char linebuf[MAXLINE]; 1899 FILE *f; 1900 char buf[MAXNAME + 1]; 1901 char delim; 1902 int key_idx; 1903 bool found_it; 1904 extern char *get_column(); 1905 1906 1907 found_it = FALSE; 1908 if (tTd(38, 20)) 1909 printf("text_map_lookup(%s)\n", name); 1910 1911 buflen = strlen(name); 1912 if (buflen > sizeof search_key - 1) 1913 buflen = sizeof search_key - 1; 1914 bcopy(name, search_key, buflen + 1); 1915 if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 1916 makelower(search_key); 1917 1918 f = fopen(map->map_file, "r"); 1919 if (f == NULL) 1920 { 1921 map->map_mflags &= ~(MF_VALID|MF_OPEN); 1922 *statp = EX_UNAVAILABLE; 1923 return NULL; 1924 } 1925 key_idx = map->map_keycolno; 1926 delim = map->map_coldelim; 1927 while (fgets(linebuf, MAXLINE, f)) 1928 { 1929 char *lf; 1930 if (linebuf[0] == '#') 1931 continue; /* skip comment line */ 1932 if (lf = strchr(linebuf, '\n')) 1933 *lf = '\0'; 1934 if (!strcasecmp(search_key, 1935 get_column(linebuf, key_idx, delim, buf))) 1936 { 1937 found_it = TRUE; 1938 break; 1939 } 1940 } 1941 fclose(f); 1942 if (!found_it) 1943 { 1944 #ifdef MAP_EXIT_STAT 1945 *statp = EX_NOTFOUND; 1946 #endif 1947 return(NULL); 1948 } 1949 vp = get_column(linebuf, map->map_valcolno, delim, buf); 1950 vsize = strlen(vp); 1951 #ifdef MAP_EXIT_STAT 1952 *statp = EX_OK; 1953 #endif 1954 if (bitset(MF_MATCHONLY, map->map_mflags)) 1955 return map_rewrite(map, name, strlen(name), NULL); 1956 else 1957 return map_rewrite(map, vp, vsize, av); 1958 } 1959 1960 1961 /* 1962 ** TEXT_GETCANONNAME -- look up canonical name in hosts file 1963 */ 1964 1965 bool 1966 text_getcanonname(name, hbsize, statp) 1967 char *name; 1968 int hbsize; 1969 int *statp; 1970 { 1971 int buflen; 1972 char delim; 1973 int key_idx; 1974 char *cname; 1975 bool found; 1976 char *domain; 1977 FILE *f; 1978 char linebuf[MAXLINE]; 1979 char cbuf[MAXNAME + 1]; 1980 char buf[MAXNAME + 1]; 1981 extern char *get_column(); 1982 1983 shorten_hostname(name); 1984 1985 /* we only accept single token search key */ 1986 if (strchr(name, '.') != NULL) 1987 { 1988 *statp = EX_NOHOST; 1989 return FALSE; 1990 } 1991 1992 found = FALSE; 1993 1994 f = fopen(HostsFile, "r"); 1995 if (f == NULL) 1996 { 1997 #ifdef MAP_EXIT_STAT 1998 *statp = EX_UNAVAILABLE; 1999 #endif 2000 return FALSE; 2001 } 2002 delim = '\t'; 2003 while (!found && fgets(linebuf, MAXLINE, f) != NULL) 2004 { 2005 char *p; 2006 2007 if (linebuf[0] == '#') 2008 continue; 2009 if ((p = strchr(linebuf, '\n')) != NULL) 2010 *p = '\0'; 2011 cname = get_column(linebuf, 1, delim, cbuf); 2012 if (cname != NULL && strcasecmp(name, cname) == 0) 2013 { 2014 found = TRUE; 2015 break; 2016 } 2017 2018 key_idx = 2; 2019 while ((p = get_column(linebuf, key_idx, delim, buf)) != NULL) 2020 { 2021 if (strcasecmp(name, p) == 0) 2022 { 2023 found = TRUE; 2024 break; 2025 } 2026 key_idx++; 2027 } 2028 } 2029 fclose(f); 2030 if (!found) 2031 { 2032 *statp = EX_NOHOST; 2033 return FALSE; 2034 } 2035 2036 if (hbsize >= strlen(cname)) 2037 { 2038 strcpy(name, cname); 2039 *statp = EX_OK; 2040 return TRUE; 2041 } 2042 *statp = EX_UNAVAILABLE; 2043 return FALSE; 2044 } 2045 /* 2046 ** STAB (Symbol Table) Modules 2047 */ 2048 2049 2050 /* 2051 ** STAB_MAP_LOOKUP -- look up alias in symbol table 2052 */ 2053 2054 char * 2055 stab_map_lookup(map, name, av, pstat) 2056 register MAP *map; 2057 char *name; 2058 char **av; 2059 int *pstat; 2060 { 2061 register STAB *s; 2062 2063 if (tTd(38, 20)) 2064 printf("stab_lookup(%s, %s)\n", 2065 map->map_mname, name); 2066 2067 s = stab(name, ST_ALIAS, ST_FIND); 2068 if (s != NULL) 2069 return (s->s_alias); 2070 return (NULL); 2071 } 2072 2073 2074 /* 2075 ** STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild) 2076 */ 2077 2078 void 2079 stab_map_store(map, lhs, rhs) 2080 register MAP *map; 2081 char *lhs; 2082 char *rhs; 2083 { 2084 register STAB *s; 2085 2086 s = stab(lhs, ST_ALIAS, ST_ENTER); 2087 s->s_alias = newstr(rhs); 2088 } 2089 2090 2091 /* 2092 ** STAB_MAP_OPEN -- initialize (reads data file) 2093 ** 2094 ** This is a wierd case -- it is only intended as a fallback for 2095 ** aliases. For this reason, opens for write (only during a 2096 ** "newaliases") always fails, and opens for read open the 2097 ** actual underlying text file instead of the database. 2098 */ 2099 2100 bool 2101 stab_map_open(map, mode) 2102 register MAP *map; 2103 int mode; 2104 { 2105 FILE *af; 2106 struct stat st; 2107 2108 if (tTd(38, 2)) 2109 printf("stab_map_open(%s, %s)\n", 2110 map->map_mname, map->map_file); 2111 2112 if (mode != O_RDONLY) 2113 { 2114 errno = ENODEV; 2115 return FALSE; 2116 } 2117 2118 af = fopen(map->map_file, "r"); 2119 if (af == NULL) 2120 return FALSE; 2121 readaliases(map, af, FALSE, FALSE); 2122 2123 if (fstat(fileno(af), &st) >= 0) 2124 map->map_mtime = st.st_mtime; 2125 fclose(af); 2126 2127 return TRUE; 2128 } 2129 /* 2130 ** Implicit Modules 2131 ** 2132 ** Tries several types. For back compatibility of aliases. 2133 */ 2134 2135 2136 /* 2137 ** IMPL_MAP_LOOKUP -- lookup in best open database 2138 */ 2139 2140 char * 2141 impl_map_lookup(map, name, av, pstat) 2142 MAP *map; 2143 char *name; 2144 char **av; 2145 int *pstat; 2146 { 2147 if (tTd(38, 20)) 2148 printf("impl_map_lookup(%s, %s)\n", 2149 map->map_mname, name); 2150 2151 #ifdef NEWDB 2152 if (bitset(MF_IMPL_HASH, map->map_mflags)) 2153 return db_map_lookup(map, name, av, pstat); 2154 #endif 2155 #ifdef NDBM 2156 if (bitset(MF_IMPL_NDBM, map->map_mflags)) 2157 return ndbm_map_lookup(map, name, av, pstat); 2158 #endif 2159 return stab_map_lookup(map, name, av, pstat); 2160 } 2161 2162 /* 2163 ** IMPL_MAP_STORE -- store in open databases 2164 */ 2165 2166 void 2167 impl_map_store(map, lhs, rhs) 2168 MAP *map; 2169 char *lhs; 2170 char *rhs; 2171 { 2172 #ifdef NEWDB 2173 if (bitset(MF_IMPL_HASH, map->map_mflags)) 2174 db_map_store(map, lhs, rhs); 2175 #endif 2176 #ifdef NDBM 2177 if (bitset(MF_IMPL_NDBM, map->map_mflags)) 2178 ndbm_map_store(map, lhs, rhs); 2179 #endif 2180 stab_map_store(map, lhs, rhs); 2181 } 2182 2183 /* 2184 ** IMPL_MAP_OPEN -- implicit database open 2185 */ 2186 2187 bool 2188 impl_map_open(map, mode) 2189 MAP *map; 2190 int mode; 2191 { 2192 struct stat stb; 2193 2194 if (tTd(38, 2)) 2195 printf("impl_map_open(%s, %s, %d)\n", 2196 map->map_mname, map->map_file, mode); 2197 2198 if (stat(map->map_file, &stb) < 0) 2199 { 2200 /* no alias file at all */ 2201 if (tTd(38, 3)) 2202 printf("no map file\n"); 2203 return FALSE; 2204 } 2205 2206 #ifdef NEWDB 2207 map->map_mflags |= MF_IMPL_HASH; 2208 if (hash_map_open(map, mode)) 2209 { 2210 #if defined(NDBM) && defined(NIS) 2211 if (mode == O_RDONLY || access("/var/yp/Makefile", R_OK) != 0) 2212 #endif 2213 return TRUE; 2214 } 2215 else 2216 map->map_mflags &= ~MF_IMPL_HASH; 2217 #endif 2218 #ifdef NDBM 2219 map->map_mflags |= MF_IMPL_NDBM; 2220 if (ndbm_map_open(map, mode)) 2221 { 2222 return TRUE; 2223 } 2224 else 2225 map->map_mflags &= ~MF_IMPL_NDBM; 2226 #endif 2227 2228 #if defined(NEWDB) || defined(NDBM) 2229 if (Verbose) 2230 message("WARNING: cannot open alias database %s", map->map_file); 2231 #else 2232 if (mode != O_RDONLY) 2233 usrerr("Cannot rebuild aliases: no database format defined"); 2234 #endif 2235 2236 return stab_map_open(map, mode); 2237 } 2238 2239 2240 /* 2241 ** IMPL_MAP_CLOSE -- close any open database(s) 2242 */ 2243 2244 void 2245 impl_map_close(map) 2246 MAP *map; 2247 { 2248 if (tTd(38, 20)) 2249 printf("impl_map_close(%s, %s, %x)\n", 2250 map->map_mname, map->map_file, map->map_mflags); 2251 #ifdef NEWDB 2252 if (bitset(MF_IMPL_HASH, map->map_mflags)) 2253 { 2254 db_map_close(map); 2255 map->map_mflags &= ~MF_IMPL_HASH; 2256 } 2257 #endif 2258 2259 #ifdef NDBM 2260 if (bitset(MF_IMPL_NDBM, map->map_mflags)) 2261 { 2262 ndbm_map_close(map); 2263 map->map_mflags &= ~MF_IMPL_NDBM; 2264 } 2265 #endif 2266 } 2267 /* 2268 ** User map class. 2269 ** 2270 ** Provides access to the system password file. 2271 */ 2272 2273 /* 2274 ** USER_MAP_OPEN -- open user map 2275 ** 2276 ** Really just binds field names to field numbers. 2277 */ 2278 2279 bool 2280 user_map_open(map, mode) 2281 MAP *map; 2282 int mode; 2283 { 2284 if (tTd(38, 2)) 2285 printf("user_map_open(%s)\n", map->map_mname); 2286 2287 if (mode != O_RDONLY) 2288 { 2289 /* issue a pseudo-error message */ 2290 #ifdef ENOSYS 2291 errno = ENOSYS; 2292 #else 2293 # ifdef EFTYPE 2294 errno = EFTYPE; 2295 # else 2296 errno = ENXIO; 2297 # endif 2298 #endif 2299 return FALSE; 2300 } 2301 if (map->map_valcolnm == NULL) 2302 /* nothing */ ; 2303 else if (strcasecmp(map->map_valcolnm, "name") == 0) 2304 map->map_valcolno = 1; 2305 else if (strcasecmp(map->map_valcolnm, "passwd") == 0) 2306 map->map_valcolno = 2; 2307 else if (strcasecmp(map->map_valcolnm, "uid") == 0) 2308 map->map_valcolno = 3; 2309 else if (strcasecmp(map->map_valcolnm, "gid") == 0) 2310 map->map_valcolno = 4; 2311 else if (strcasecmp(map->map_valcolnm, "gecos") == 0) 2312 map->map_valcolno = 5; 2313 else if (strcasecmp(map->map_valcolnm, "dir") == 0) 2314 map->map_valcolno = 6; 2315 else if (strcasecmp(map->map_valcolnm, "shell") == 0) 2316 map->map_valcolno = 7; 2317 else 2318 { 2319 syserr("User map %s: unknown column name %s", 2320 map->map_mname, map->map_valcolnm); 2321 return FALSE; 2322 } 2323 return TRUE; 2324 } 2325 2326 2327 /* 2328 ** USER_MAP_LOOKUP -- look up a user in the passwd file. 2329 */ 2330 2331 char * 2332 user_map_lookup(map, key, av, statp) 2333 MAP *map; 2334 char *key; 2335 char **av; 2336 int *statp; 2337 { 2338 struct passwd *pw; 2339 2340 if (tTd(38, 20)) 2341 printf("user_map_lookup(%s, %s)\n", 2342 map->map_mname, key); 2343 2344 pw = sm_getpwnam(key); 2345 if (pw == NULL) 2346 return NULL; 2347 if (bitset(MF_MATCHONLY, map->map_mflags)) 2348 return map_rewrite(map, key, strlen(key), NULL); 2349 else 2350 { 2351 char *rwval = NULL; 2352 char buf[30]; 2353 2354 switch (map->map_valcolno) 2355 { 2356 case 0: 2357 case 1: 2358 rwval = pw->pw_name; 2359 break; 2360 2361 case 2: 2362 rwval = pw->pw_passwd; 2363 break; 2364 2365 case 3: 2366 sprintf(buf, "%d", pw->pw_uid); 2367 rwval = buf; 2368 break; 2369 2370 case 4: 2371 sprintf(buf, "%d", pw->pw_gid); 2372 rwval = buf; 2373 break; 2374 2375 case 5: 2376 rwval = pw->pw_gecos; 2377 break; 2378 2379 case 6: 2380 rwval = pw->pw_dir; 2381 break; 2382 2383 case 7: 2384 rwval = pw->pw_shell; 2385 break; 2386 } 2387 return map_rewrite(map, rwval, strlen(rwval), av); 2388 } 2389 } 2390 /* 2391 ** BESTMX -- find the best MX for a name 2392 ** 2393 ** This is really a hack, but I don't see any obvious way 2394 ** to generalize it at the moment. 2395 */ 2396 2397 #if NAMED_BIND 2398 2399 char * 2400 bestmx_map_lookup(map, name, av, statp) 2401 MAP *map; 2402 char *name; 2403 char **av; 2404 int *statp; 2405 { 2406 int nmx; 2407 auto int rcode; 2408 char *mxhosts[MAXMXHOSTS + 1]; 2409 2410 nmx = getmxrr(name, mxhosts, FALSE, &rcode); 2411 if (nmx <= 0) 2412 return NULL; 2413 if (bitset(MF_MATCHONLY, map->map_mflags)) 2414 return map_rewrite(map, name, strlen(name), NULL); 2415 else 2416 return map_rewrite(map, mxhosts[0], strlen(mxhosts[0]), av); 2417 } 2418 2419 #endif 2420 /* 2421 ** Program map type. 2422 ** 2423 ** This provides access to arbitrary programs. It should be used 2424 ** only very sparingly, since there is no way to bound the cost 2425 ** of invoking an arbitrary program. 2426 */ 2427 2428 char * 2429 prog_map_lookup(map, name, av, statp) 2430 MAP *map; 2431 char *name; 2432 char **av; 2433 int *statp; 2434 { 2435 int i; 2436 register char *p; 2437 int fd; 2438 auto pid_t pid; 2439 char *argv[MAXPV + 1]; 2440 char buf[MAXLINE]; 2441 2442 if (tTd(38, 20)) 2443 printf("prog_map_lookup(%s, %s) %s\n", 2444 map->map_mname, name, map->map_file); 2445 2446 i = 0; 2447 argv[i++] = map->map_file; 2448 strcpy(buf, map->map_rebuild); 2449 for (p = strtok(buf, " \t"); p != NULL; p = strtok(NULL, " \t")) 2450 { 2451 if (i >= MAXPV - 1) 2452 break; 2453 argv[i++] = p; 2454 } 2455 argv[i++] = name; 2456 argv[i] = NULL; 2457 pid = prog_open(argv, &fd, CurEnv); 2458 if (pid < 0) 2459 { 2460 if (tTd(38, 9)) 2461 printf("prog_map_lookup(%s) failed (%s) -- closing", 2462 map->map_mname, errstring(errno)); 2463 map->map_mflags &= ~(MF_VALID|MF_OPEN); 2464 return NULL; 2465 } 2466 i = read(fd, buf, sizeof buf - 1); 2467 if (i <= 0 && tTd(38, 2)) 2468 printf("prog_map_lookup(%s): read error %s\n", 2469 map->map_mname, strerror(errno)); 2470 if (i > 0) 2471 { 2472 char *rval; 2473 2474 buf[i] = '\0'; 2475 p = strchr(buf, '\n'); 2476 if (p != NULL) 2477 *p = '\0'; 2478 2479 /* collect the return value */ 2480 if (bitset(MF_MATCHONLY, map->map_mflags)) 2481 rval = map_rewrite(map, name, strlen(name), NULL); 2482 else 2483 rval = map_rewrite(map, buf, strlen(buf), NULL); 2484 2485 /* now flush any additional output */ 2486 while ((i = read(fd, buf, sizeof buf)) > 0) 2487 continue; 2488 close(fd); 2489 2490 /* and wait for the process to terminate */ 2491 *statp = waitfor(pid); 2492 2493 return rval; 2494 } 2495 2496 close(fd); 2497 *statp = waitfor(pid); 2498 return NULL; 2499 } 2500 /* 2501 ** Sequenced map type. 2502 ** 2503 ** Tries each map in order until something matches, much like 2504 ** implicit. Stores go to the first map in the list that can 2505 ** support storing. 2506 ** 2507 ** This is slightly unusual in that there are two interfaces. 2508 ** The "sequence" interface lets you stack maps arbitrarily. 2509 ** The "switch" interface builds a sequence map by looking 2510 ** at a system-dependent configuration file such as 2511 ** /etc/nsswitch.conf on Solaris or /etc/svc.conf on Ultrix. 2512 ** 2513 ** We don't need an explicit open, since all maps are 2514 ** opened during startup, including underlying maps. 2515 */ 2516 2517 /* 2518 ** SEQ_MAP_PARSE -- Sequenced map parsing 2519 */ 2520 2521 bool 2522 seq_map_parse(map, ap) 2523 MAP *map; 2524 char *ap; 2525 { 2526 int maxmap; 2527 2528 if (tTd(38, 2)) 2529 printf("seq_map_parse(%s, %s)\n", map->map_mname, ap); 2530 maxmap = 0; 2531 while (*ap != '\0') 2532 { 2533 register char *p; 2534 STAB *s; 2535 2536 /* find beginning of map name */ 2537 while (isascii(*ap) && isspace(*ap)) 2538 ap++; 2539 for (p = ap; isascii(*p) && isalnum(*p); p++) 2540 continue; 2541 if (*p != '\0') 2542 *p++ = '\0'; 2543 while (*p != '\0' && (!isascii(*p) || !isalnum(*p))) 2544 p++; 2545 if (*ap == '\0') 2546 { 2547 ap = p; 2548 continue; 2549 } 2550 s = stab(ap, ST_MAP, ST_FIND); 2551 if (s == NULL) 2552 { 2553 syserr("Sequence map %s: unknown member map %s", 2554 map->map_mname, ap); 2555 } 2556 else if (maxmap == MAXMAPSTACK) 2557 { 2558 syserr("Sequence map %s: too many member maps (%d max)", 2559 map->map_mname, MAXMAPSTACK); 2560 maxmap++; 2561 } 2562 else if (maxmap < MAXMAPSTACK) 2563 { 2564 map->map_stack[maxmap++] = &s->s_map; 2565 } 2566 ap = p; 2567 } 2568 return TRUE; 2569 } 2570 2571 2572 /* 2573 ** SWITCH_MAP_OPEN -- open a switched map 2574 ** 2575 ** This looks at the system-dependent configuration and builds 2576 ** a sequence map that does the same thing. 2577 ** 2578 ** Every system must define a switch_map_find routine in conf.c 2579 ** that will return the list of service types associated with a 2580 ** given service class. 2581 */ 2582 2583 bool 2584 switch_map_open(map, mode) 2585 MAP *map; 2586 int mode; 2587 { 2588 int mapno; 2589 int nmaps; 2590 char *maptype[MAXMAPSTACK]; 2591 2592 if (tTd(38, 2)) 2593 printf("switch_map_open(%s, %s, %d)\n", 2594 map->map_mname, map->map_file, mode); 2595 2596 nmaps = switch_map_find(map->map_file, maptype, map->map_return); 2597 if (tTd(38, 19)) 2598 { 2599 printf("\tswitch_map_find => %d\n", nmaps); 2600 for (mapno = 0; mapno < nmaps; mapno++) 2601 printf("\t\t%s\n", maptype[mapno]); 2602 } 2603 if (nmaps <= 0 || nmaps > MAXMAPSTACK) 2604 return FALSE; 2605 2606 for (mapno = 0; mapno < nmaps; mapno++) 2607 { 2608 register STAB *s; 2609 char nbuf[MAXNAME + 1]; 2610 2611 if (maptype[mapno] == NULL) 2612 continue; 2613 (void) sprintf(nbuf, "%s.%s", map->map_file, maptype[mapno]); 2614 s = stab(nbuf, ST_MAP, ST_FIND); 2615 if (s == NULL) 2616 { 2617 syserr("Switch map %s: unknown member map %s", 2618 map->map_mname, nbuf); 2619 } 2620 else 2621 { 2622 map->map_stack[mapno] = &s->s_map; 2623 if (tTd(38, 4)) 2624 printf("\tmap_stack[%d] = %s:%s\n", 2625 mapno, s->s_map.map_class->map_cname, 2626 nbuf); 2627 } 2628 } 2629 return TRUE; 2630 } 2631 2632 2633 /* 2634 ** SEQ_MAP_CLOSE -- close all underlying maps 2635 */ 2636 2637 seq_map_close(map) 2638 MAP *map; 2639 { 2640 int mapno; 2641 2642 if (tTd(38, 20)) 2643 printf("seq_map_close(%s)\n", map->map_mname); 2644 for (mapno = 0; mapno < MAXMAPSTACK; mapno++) 2645 { 2646 MAP *mm = map->map_stack[mapno]; 2647 2648 if (mm == NULL || !bitset(MF_OPEN, mm->map_mflags)) 2649 continue; 2650 mm->map_class->map_close(mm); 2651 mm->map_mflags &= ~(MF_OPEN|MF_WRITABLE); 2652 } 2653 } 2654 2655 2656 /* 2657 ** SEQ_MAP_LOOKUP -- sequenced map lookup 2658 */ 2659 2660 char * 2661 seq_map_lookup(map, key, args, pstat) 2662 MAP *map; 2663 char *key; 2664 char **args; 2665 int *pstat; 2666 { 2667 int mapno; 2668 int mapbit = 0x01; 2669 2670 if (tTd(38, 20)) 2671 printf("seq_map_lookup(%s, %s)\n", map->map_mname, key); 2672 2673 for (mapno = 0; mapno < MAXMAPSTACK; mapbit <<= 1, mapno++) 2674 { 2675 MAP *mm = map->map_stack[mapno]; 2676 int stat = 0; 2677 char *rv; 2678 2679 if (mm == NULL) 2680 continue; 2681 if (!bitset(MF_OPEN, mm->map_mflags)) 2682 { 2683 if (bitset(mapbit, map->map_return[MA_UNAVAIL])) 2684 { 2685 *pstat = EX_UNAVAILABLE; 2686 return NULL; 2687 } 2688 continue; 2689 } 2690 rv = mm->map_class->map_lookup(mm, key, args, &stat); 2691 if (rv != NULL) 2692 return rv; 2693 if (stat == 0 && bitset(mapbit, map->map_return[MA_NOTFOUND])) 2694 return NULL; 2695 if (stat != 0 && bitset(mapbit, map->map_return[MA_TRYAGAIN])) 2696 { 2697 *pstat = stat; 2698 return NULL; 2699 } 2700 } 2701 return NULL; 2702 } 2703 2704 2705 /* 2706 ** SEQ_MAP_STORE -- sequenced map store 2707 */ 2708 2709 void 2710 seq_map_store(map, key, val) 2711 MAP *map; 2712 char *key; 2713 char *val; 2714 { 2715 int mapno; 2716 2717 if (tTd(38, 12)) 2718 printf("seq_map_store(%s, %s, %s)\n", 2719 map->map_mname, key, val); 2720 2721 for (mapno = 0; mapno < MAXMAPSTACK; mapno++) 2722 { 2723 MAP *mm = map->map_stack[mapno]; 2724 2725 if (mm == NULL || !bitset(MF_WRITABLE, mm->map_mflags)) 2726 continue; 2727 2728 mm->map_class->map_store(mm, key, val); 2729 return; 2730 } 2731 syserr("seq_map_store(%s, %s, %s): no writable map", 2732 map->map_mname, key, val); 2733 } 2734 /* 2735 ** GETCANONNAME -- look up name using service switch 2736 ** 2737 ** Parameters: 2738 ** host -- the host name to look up. 2739 ** hbsize -- the size of the host buffer. 2740 ** trymx -- if set, try MX records. 2741 ** 2742 ** Returns: 2743 ** TRUE -- if the host was found. 2744 ** FALSE -- otherwise. 2745 */ 2746 2747 bool 2748 getcanonname(host, hbsize, trymx) 2749 char *host; 2750 int hbsize; 2751 bool trymx; 2752 { 2753 int nmaps; 2754 int mapno; 2755 bool found = FALSE; 2756 auto int stat; 2757 char *maptype[MAXMAPSTACK]; 2758 short mapreturn[MAXMAPACTIONS]; 2759 extern int h_errno; 2760 2761 nmaps = switch_map_find("hosts", maptype, mapreturn); 2762 for (mapno = 0; mapno < nmaps; mapno++) 2763 { 2764 int i; 2765 2766 if (tTd(38, 20)) 2767 printf("getcanonname(%s), trying %s\n", 2768 host, maptype[mapno]); 2769 if (strcmp("files", maptype[mapno]) == 0) 2770 found = text_getcanonname(host, hbsize, &stat); 2771 #ifdef NIS 2772 else if (strcmp("nis", maptype[mapno]) == 0) 2773 found = nis_getcanonname(host, hbsize, &stat); 2774 #endif 2775 #ifdef NISPLUS 2776 else if (strcmp("nisplus", maptype[mapno]) == 0) 2777 found = nisplus_getcanonname(host, hbsize, &stat); 2778 #endif 2779 #if NAMED_BIND 2780 else if (strcmp("dns", maptype[mapno]) == 0) 2781 found = dns_getcanonname(host, hbsize, trymx, &stat); 2782 #endif 2783 else 2784 { 2785 found = FALSE; 2786 stat = EX_UNAVAILABLE; 2787 } 2788 if (found) 2789 break; 2790 2791 /* see if we should continue */ 2792 if (stat == EX_TEMPFAIL) 2793 i = MA_TRYAGAIN; 2794 else if (stat == EX_NOHOST) 2795 i = MA_NOTFOUND; 2796 else 2797 i = MA_UNAVAIL; 2798 if (bitset(1 << mapno, mapreturn[i])) 2799 break; 2800 } 2801 2802 if (found) 2803 { 2804 char *d; 2805 2806 if (tTd(38, 20)) 2807 printf("getcanonname(%s), found\n", host); 2808 2809 /* 2810 ** If returned name is still single token, compensate 2811 ** by tagging on $m. This is because some sites set 2812 ** up their DNS or NIS databases wrong. 2813 */ 2814 2815 if ((d = strchr(host, '.')) == NULL || d[1] == '\0') 2816 { 2817 d = macvalue('m', CurEnv); 2818 if (d != NULL && 2819 hbsize > (int) (strlen(host) + strlen(d) + 1)) 2820 { 2821 if (host[strlen(host) - 1] != '.') 2822 strcat(host, "."); 2823 strcat(host, d); 2824 } 2825 else 2826 { 2827 return FALSE; 2828 } 2829 } 2830 return TRUE; 2831 } 2832 2833 if (tTd(38, 20)) 2834 printf("getcanonname(%s), failed, stat=%d\n", host, stat); 2835 2836 #if NAMED_BIND 2837 if (stat == EX_NOHOST) 2838 h_errno = HOST_NOT_FOUND; 2839 else 2840 h_errno = TRY_AGAIN; 2841 #endif 2842 2843 return FALSE; 2844 } 2845 /* 2846 ** NULL stubs 2847 */ 2848 2849 bool 2850 null_map_open(map, mode) 2851 MAP *map; 2852 int mode; 2853 { 2854 return TRUE; 2855 } 2856 2857 void 2858 null_map_close(map) 2859 MAP *map; 2860 { 2861 return; 2862 } 2863 2864 void 2865 null_map_store(map, key, val) 2866 MAP *map; 2867 char *key; 2868 char *val; 2869 { 2870 return; 2871 } 2872 2873 2874 /* 2875 ** BOGUS stubs 2876 */ 2877 2878 char * 2879 bogus_map_lookup(map, key, args, pstat) 2880 MAP *map; 2881 char *key; 2882 char **args; 2883 int *pstat; 2884 { 2885 *pstat = EX_TEMPFAIL; 2886 return NULL; 2887 } 2888 2889 MAPCLASS BogusMapClass = 2890 { 2891 "bogus-map", NULL, 0, 2892 NULL, bogus_map_lookup, null_map_store, 2893 null_map_open, null_map_close, 2894 }; 2895