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