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