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