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.69 (Berkeley) 05/28/95"; 11 #endif /* not lint */ 12 13 #include "sendmail.h" 14 15 #ifdef NDBM 16 # include <ndbm.h> 17 #endif 18 #ifdef NEWDB 19 # include <db.h> 20 #endif 21 #ifdef NIS 22 struct dom_binding; /* forward reference needed on IRIX */ 23 # include <rpcsvc/ypclnt.h> 24 #endif 25 26 /* 27 ** MAP.C -- implementations for various map classes. 28 ** 29 ** Each map class implements a series of functions: 30 ** 31 ** bool map_parse(MAP *map, char *args) 32 ** Parse the arguments from the config file. Return TRUE 33 ** if they were ok, FALSE otherwise. Fill in map with the 34 ** values. 35 ** 36 ** char *map_lookup(MAP *map, char *key, char **args, int *pstat) 37 ** Look up the key in the given map. If found, do any 38 ** rewriting the map wants (including "args" if desired) 39 ** and return the value. Set *pstat to the appropriate status 40 ** on error and return NULL. Args will be NULL if called 41 ** from the alias routines, although this should probably 42 ** not be relied upon. It is suggested you call map_rewrite 43 ** to return the results -- it takes care of null termination 44 ** and uses a dynamically expanded buffer as needed. 45 ** 46 ** void map_store(MAP *map, char *key, char *value) 47 ** Store the key:value pair in the map. 48 ** 49 ** bool map_open(MAP *map, int mode) 50 ** Open the map for the indicated mode. Mode should 51 ** be either O_RDONLY or O_RDWR. Return TRUE if it 52 ** was opened successfully, FALSE otherwise. If the open 53 ** failed an the MF_OPTIONAL flag is not set, it should 54 ** also print an error. If the MF_ALIAS bit is set 55 ** and this map class understands the @:@ convention, it 56 ** should call aliaswait() before returning. 57 ** 58 ** void map_close(MAP *map) 59 ** Close the map. 60 ** 61 ** This file also includes the implementation for getcanonname. 62 ** It is currently implemented in a pretty ad-hoc manner; it ought 63 ** to be more properly integrated into the map structure. 64 */ 65 66 #define DBMMODE 0644 67 68 extern bool aliaswait __P((MAP *, char *, int)); 69 /* 70 ** MAP_PARSEARGS -- parse config line arguments for database lookup 71 ** 72 ** This is a generic version of the map_parse method. 73 ** 74 ** Parameters: 75 ** map -- the map being initialized. 76 ** ap -- a pointer to the args on the config line. 77 ** 78 ** Returns: 79 ** TRUE -- if everything parsed OK. 80 ** FALSE -- otherwise. 81 ** 82 ** Side Effects: 83 ** null terminates the filename; stores it in map 84 */ 85 86 bool 87 map_parseargs(map, ap) 88 MAP *map; 89 char *ap; 90 { 91 register char *p = ap; 92 93 map->map_mflags |= MF_TRY0NULL | MF_TRY1NULL; 94 for (;;) 95 { 96 while (isascii(*p) && isspace(*p)) 97 p++; 98 if (*p != '-') 99 break; 100 switch (*++p) 101 { 102 case 'N': 103 map->map_mflags |= MF_INCLNULL; 104 map->map_mflags &= ~MF_TRY0NULL; 105 break; 106 107 case 'O': 108 map->map_mflags &= ~MF_TRY1NULL; 109 break; 110 111 case 'o': 112 map->map_mflags |= MF_OPTIONAL; 113 break; 114 115 case 'f': 116 map->map_mflags |= MF_NOFOLDCASE; 117 break; 118 119 case 'm': 120 map->map_mflags |= MF_MATCHONLY; 121 break; 122 123 case 'A': 124 map->map_mflags |= MF_APPEND; 125 break; 126 127 case 'q': 128 map->map_mflags |= MF_KEEPQUOTES; 129 break; 130 131 case 'a': 132 map->map_app = ++p; 133 break; 134 135 case 'k': 136 while (isascii(*++p) && isspace(*p)) 137 continue; 138 map->map_keycolnm = p; 139 break; 140 141 case 'v': 142 while (isascii(*++p) && isspace(*p)) 143 continue; 144 map->map_valcolnm = p; 145 break; 146 147 case 'z': 148 if (*++p != '\\') 149 map->map_coldelim = *p; 150 else 151 { 152 switch (*++p) 153 { 154 case 'n': 155 map->map_coldelim = '\n'; 156 break; 157 158 case 't': 159 map->map_coldelim = '\t'; 160 break; 161 162 default: 163 map->map_coldelim = '\\'; 164 } 165 } 166 break; 167 #ifdef RESERVED_FOR_SUN 168 case 'd': 169 map->map_mflags |= MF_DOMAIN_WIDE; 170 break; 171 172 case 's': 173 /* info type */ 174 break; 175 #endif 176 } 177 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 178 p++; 179 if (*p != '\0') 180 *p++ = '\0'; 181 } 182 if (map->map_app != NULL) 183 map->map_app = newstr(map->map_app); 184 if (map->map_keycolnm != NULL) 185 map->map_keycolnm = newstr(map->map_keycolnm); 186 if (map->map_valcolnm != NULL) 187 map->map_valcolnm = newstr(map->map_valcolnm); 188 189 if (*p != '\0') 190 { 191 map->map_file = p; 192 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 193 p++; 194 if (*p != '\0') 195 *p++ = '\0'; 196 map->map_file = newstr(map->map_file); 197 } 198 199 while (*p != '\0' && isascii(*p) && isspace(*p)) 200 p++; 201 if (*p != '\0') 202 map->map_rebuild = newstr(p); 203 204 if (map->map_file == NULL && 205 !bitset(MCF_OPTFILE, map->map_class->map_cflags)) 206 { 207 syserr("No file name for %s map %s", 208 map->map_class->map_cname, map->map_mname); 209 return FALSE; 210 } 211 return TRUE; 212 } 213 /* 214 ** MAP_REWRITE -- rewrite a database key, interpolating %n indications. 215 ** 216 ** It also adds the map_app string. It can be used as a utility 217 ** in the map_lookup method. 218 ** 219 ** Parameters: 220 ** map -- the map that causes this. 221 ** s -- the string to rewrite, NOT necessarily null terminated. 222 ** slen -- the length of s. 223 ** av -- arguments to interpolate into buf. 224 ** 225 ** Returns: 226 ** Pointer to rewritten result. This is static data that 227 ** should be copied if it is to be saved! 228 ** 229 ** Side Effects: 230 ** none. 231 */ 232 233 char * 234 map_rewrite(map, s, slen, av) 235 register MAP *map; 236 register char *s; 237 int slen; 238 char **av; 239 { 240 register char *bp; 241 register char c; 242 char **avp; 243 register char *ap; 244 int i; 245 int len; 246 static int buflen = -1; 247 static char *buf = NULL; 248 249 if (tTd(39, 1)) 250 { 251 printf("map_rewrite(%.*s), av =", slen, s); 252 if (av == NULL) 253 printf(" (nullv)"); 254 else 255 { 256 for (avp = av; *avp != NULL; avp++) 257 printf("\n\t%s", *avp); 258 } 259 printf("\n"); 260 } 261 262 /* count expected size of output (can safely overestimate) */ 263 i = len = slen; 264 if (av != NULL) 265 { 266 bp = s; 267 for (i = slen; --i >= 0 && (c = *bp++) != 0; ) 268 { 269 if (c != '%') 270 continue; 271 if (--i < 0) 272 break; 273 c = *bp++; 274 if (!(isascii(c) && isdigit(c))) 275 continue; 276 for (avp = av; --c >= '0' && *avp != NULL; avp++) 277 continue; 278 if (*avp == NULL) 279 continue; 280 len += strlen(*avp); 281 } 282 } 283 if (map->map_app != NULL) 284 len += strlen(map->map_app); 285 if (buflen < ++len) 286 { 287 /* need to malloc additional space */ 288 buflen = len; 289 if (buf != NULL) 290 free(buf); 291 buf = xalloc(buflen); 292 } 293 294 bp = buf; 295 if (av == NULL) 296 { 297 bcopy(s, bp, slen); 298 bp += slen; 299 } 300 else 301 { 302 while (--slen >= 0 && (c = *s++) != '\0') 303 { 304 if (c != '%') 305 { 306 pushc: 307 *bp++ = c; 308 continue; 309 } 310 if (--slen < 0 || (c = *s++) == '\0') 311 c = '%'; 312 if (c == '%') 313 goto pushc; 314 if (!(isascii(c) && isdigit(c))) 315 { 316 *bp++ = '%'; 317 goto pushc; 318 } 319 for (avp = av; --c >= '0' && *avp != NULL; avp++) 320 continue; 321 if (*avp == NULL) 322 continue; 323 324 /* transliterate argument into output string */ 325 for (ap = *avp; (c = *ap++) != '\0'; ) 326 *bp++ = c; 327 } 328 } 329 if (map->map_app != NULL) 330 strcpy(bp, map->map_app); 331 else 332 *bp = '\0'; 333 if (tTd(39, 1)) 334 printf("map_rewrite => %s\n", buf); 335 return buf; 336 } 337 /* 338 ** INITMAPS -- initialize for aliasing 339 ** 340 ** Parameters: 341 ** rebuild -- if TRUE, this rebuilds the cached versions. 342 ** e -- current envelope. 343 ** 344 ** Returns: 345 ** none. 346 ** 347 ** Side Effects: 348 ** initializes aliases: 349 ** if NDBM: opens the database. 350 ** if ~NDBM: reads the aliases into the symbol table. 351 */ 352 353 void 354 initmaps(rebuild, e) 355 bool rebuild; 356 register ENVELOPE *e; 357 { 358 extern void map_init(); 359 360 #ifdef XDEBUG 361 checkfd012("entering initmaps"); 362 #endif 363 CurEnv = e; 364 if (rebuild) 365 { 366 stabapply(map_init, 1); 367 stabapply(map_init, 2); 368 } 369 else 370 { 371 stabapply(map_init, 0); 372 } 373 #ifdef XDEBUG 374 checkfd012("exiting initmaps"); 375 #endif 376 } 377 378 void 379 map_init(s, rebuild) 380 register STAB *s; 381 int rebuild; 382 { 383 register MAP *map; 384 385 /* has to be a map */ 386 if (s->s_type != ST_MAP) 387 return; 388 389 map = &s->s_map; 390 if (!bitset(MF_VALID, map->map_mflags)) 391 return; 392 393 if (tTd(38, 2)) 394 printf("map_init(%s:%s, %s, %d)\n", 395 map->map_class->map_cname == NULL ? "NULL" : 396 map->map_class->map_cname, 397 map->map_mname == NULL ? "NULL" : map->map_mname, 398 map->map_file == NULL ? "NULL" : map->map_file, 399 rebuild); 400 401 if (rebuild == (bitset(MF_ALIAS, map->map_mflags) && 402 bitset(MCF_REBUILDABLE, map->map_class->map_cflags) ? 1 : 2)) 403 { 404 if (tTd(38, 3)) 405 printf("\twrong pass\n"); 406 return; 407 } 408 409 /* if already open, close it (for nested open) */ 410 if (bitset(MF_OPEN, map->map_mflags)) 411 { 412 map->map_class->map_close(map); 413 map->map_mflags &= ~(MF_OPEN|MF_WRITABLE); 414 } 415 416 if (rebuild == 2) 417 { 418 rebuildaliases(map, FALSE); 419 } 420 else 421 { 422 if (map->map_class->map_open(map, O_RDONLY)) 423 { 424 if (tTd(38, 4)) 425 printf("\t%s:%s %s: valid\n", 426 map->map_class->map_cname == NULL ? "NULL" : 427 map->map_class->map_cname, 428 map->map_mname == NULL ? "NULL" : 429 map->map_mname, 430 map->map_file == NULL ? "NULL" : 431 map->map_file); 432 map->map_mflags |= MF_OPEN; 433 } 434 else 435 { 436 if (tTd(38, 4)) 437 printf("\t%s:%s %s: invalid: %s\n", 438 map->map_class->map_cname == NULL ? "NULL" : 439 map->map_class->map_cname, 440 map->map_mname == NULL ? "NULL" : 441 map->map_mname, 442 map->map_file == NULL ? "NULL" : 443 map->map_file, 444 errstring(errno)); 445 if (!bitset(MF_OPTIONAL, map->map_mflags)) 446 { 447 extern MAPCLASS BogusMapClass; 448 449 map->map_class = &BogusMapClass; 450 map->map_mflags |= MF_OPEN; 451 } 452 } 453 } 454 } 455 /* 456 ** NDBM modules 457 */ 458 459 #ifdef NDBM 460 461 /* 462 ** DBM_MAP_OPEN -- DBM-style map open 463 */ 464 465 bool 466 ndbm_map_open(map, mode) 467 MAP *map; 468 int mode; 469 { 470 register DBM *dbm; 471 struct stat st; 472 473 if (tTd(38, 2)) 474 printf("ndbm_map_open(%s, %s, %d)\n", 475 map->map_mname, map->map_file, mode); 476 477 if (mode == O_RDWR) 478 mode |= O_CREAT|O_TRUNC; 479 480 /* open the database */ 481 dbm = dbm_open(map->map_file, mode, DBMMODE); 482 if (dbm == NULL) 483 { 484 if (aliaswait(map, ".pag", FALSE)) 485 return TRUE; 486 if (!bitset(MF_OPTIONAL, map->map_mflags)) 487 syserr("Cannot open DBM database %s", map->map_file); 488 return FALSE; 489 } 490 map->map_db1 = (void *) dbm; 491 if (mode == O_RDONLY) 492 { 493 if (bitset(MF_ALIAS, map->map_mflags) && 494 !aliaswait(map, ".pag", TRUE)) 495 return FALSE; 496 } 497 else 498 { 499 int fd; 500 501 /* exclusive lock for duration of rebuild */ 502 fd = dbm_dirfno((DBM *) map->map_db1); 503 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags) && 504 lockfile(fd, map->map_file, ".dir", LOCK_EX)) 505 map->map_mflags |= MF_LOCKED; 506 } 507 if (fstat(dbm_dirfno((DBM *) map->map_db1), &st) >= 0) 508 map->map_mtime = st.st_mtime; 509 return TRUE; 510 } 511 512 513 /* 514 ** DBM_MAP_LOOKUP -- look up a datum in a DBM-type map 515 */ 516 517 char * 518 ndbm_map_lookup(map, name, av, statp) 519 MAP *map; 520 char *name; 521 char **av; 522 int *statp; 523 { 524 datum key, val; 525 int fd; 526 char keybuf[MAXNAME + 1]; 527 528 if (tTd(38, 20)) 529 printf("ndbm_map_lookup(%s, %s)\n", 530 map->map_mname, name); 531 532 key.dptr = name; 533 key.dsize = strlen(name); 534 if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 535 { 536 if (key.dsize > sizeof keybuf - 1) 537 key.dsize = sizeof keybuf - 1; 538 bcopy(key.dptr, keybuf, key.dsize + 1); 539 makelower(keybuf); 540 key.dptr = keybuf; 541 } 542 fd = dbm_dirfno((DBM *) map->map_db1); 543 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 544 (void) lockfile(fd, map->map_file, ".dir", LOCK_SH); 545 val.dptr = NULL; 546 if (bitset(MF_TRY0NULL, map->map_mflags)) 547 { 548 val = dbm_fetch((DBM *) map->map_db1, key); 549 if (val.dptr != NULL) 550 map->map_mflags &= ~MF_TRY1NULL; 551 } 552 if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags)) 553 { 554 key.dsize++; 555 val = dbm_fetch((DBM *) map->map_db1, key); 556 if (val.dptr != NULL) 557 map->map_mflags &= ~MF_TRY0NULL; 558 } 559 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 560 (void) lockfile(fd, map->map_file, ".dir", LOCK_UN); 561 if (val.dptr == NULL) 562 return NULL; 563 if (bitset(MF_MATCHONLY, map->map_mflags)) 564 return map_rewrite(map, name, strlen(name), NULL); 565 else 566 return map_rewrite(map, val.dptr, val.dsize, av); 567 } 568 569 570 /* 571 ** DBM_MAP_STORE -- store a datum in the database 572 */ 573 574 void 575 ndbm_map_store(map, lhs, rhs) 576 register MAP *map; 577 char *lhs; 578 char *rhs; 579 { 580 datum key; 581 datum data; 582 int stat; 583 584 if (tTd(38, 12)) 585 printf("ndbm_map_store(%s, %s, %s)\n", 586 map->map_mname, lhs, rhs); 587 588 key.dsize = strlen(lhs); 589 key.dptr = lhs; 590 591 data.dsize = strlen(rhs); 592 data.dptr = rhs; 593 594 if (bitset(MF_INCLNULL, map->map_mflags)) 595 { 596 key.dsize++; 597 data.dsize++; 598 } 599 600 stat = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT); 601 if (stat > 0) 602 { 603 if (!bitset(MF_APPEND, map->map_mflags)) 604 usrerr("050 Warning: duplicate alias name %s", lhs); 605 else 606 { 607 static char *buf = NULL; 608 static int bufsiz = 0; 609 auto int xstat; 610 datum old; 611 612 old.dptr = ndbm_map_lookup(map, key.dptr, NULL, &xstat); 613 if (old.dptr != NULL && *old.dptr != '\0') 614 { 615 old.dsize = strlen(old.dptr); 616 if (data.dsize + old.dsize + 2 > bufsiz) 617 { 618 if (buf != NULL) 619 (void) free(buf); 620 bufsiz = data.dsize + old.dsize + 2; 621 buf = xalloc(bufsiz); 622 } 623 sprintf(buf, "%s,%s", data.dptr, old.dptr); 624 data.dsize = data.dsize + old.dsize + 1; 625 data.dptr = buf; 626 if (tTd(38, 9)) 627 printf("ndbm_map_store append=%s\n", data.dptr); 628 } 629 } 630 stat = dbm_store((DBM *) map->map_db1, key, data, DBM_REPLACE); 631 } 632 if (stat != 0) 633 syserr("readaliases: dbm put (%s)", lhs); 634 } 635 636 637 /* 638 ** NDBM_MAP_CLOSE -- close the database 639 */ 640 641 void 642 ndbm_map_close(map) 643 register MAP *map; 644 { 645 if (tTd(38, 9)) 646 printf("ndbm_map_close(%s, %s, %x)\n", 647 map->map_mname, map->map_file, map->map_mflags); 648 649 if (bitset(MF_WRITABLE, map->map_mflags)) 650 { 651 #ifdef NIS 652 bool inclnull; 653 char buf[200]; 654 655 inclnull = bitset(MF_INCLNULL, map->map_mflags); 656 map->map_mflags &= ~MF_INCLNULL; 657 658 if (strstr(map->map_file, "/yp/") != NULL) 659 { 660 (void) sprintf(buf, "%010ld", curtime()); 661 ndbm_map_store(map, "YP_LAST_MODIFIED", buf); 662 663 (void) gethostname(buf, sizeof buf); 664 ndbm_map_store(map, "YP_MASTER_NAME", buf); 665 } 666 667 if (inclnull) 668 map->map_mflags |= MF_INCLNULL; 669 #endif 670 671 /* write out the distinguished alias */ 672 ndbm_map_store(map, "@", "@"); 673 } 674 dbm_close((DBM *) map->map_db1); 675 } 676 677 #endif 678 /* 679 ** NEWDB (Hash and BTree) Modules 680 */ 681 682 #ifdef NEWDB 683 684 /* 685 ** BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives. 686 ** 687 ** These do rather bizarre locking. If you can lock on open, 688 ** do that to avoid the condition of opening a database that 689 ** is being rebuilt. If you don't, we'll try to fake it, but 690 ** there will be a race condition. If opening for read-only, 691 ** we immediately release the lock to avoid freezing things up. 692 ** We really ought to hold the lock, but guarantee that we won't 693 ** be pokey about it. That's hard to do. 694 */ 695 696 bool 697 bt_map_open(map, mode) 698 MAP *map; 699 int mode; 700 { 701 DB *db; 702 int i; 703 int omode; 704 int fd; 705 struct stat st; 706 char buf[MAXNAME + 1]; 707 708 if (tTd(38, 2)) 709 printf("bt_map_open(%s, %s, %d)\n", 710 map->map_mname, map->map_file, mode); 711 712 omode = mode; 713 if (omode == O_RDWR) 714 { 715 omode |= O_CREAT|O_TRUNC; 716 #if defined(O_EXLOCK) && HASFLOCK 717 omode |= O_EXLOCK; 718 # if !OLD_NEWDB 719 } 720 else 721 { 722 omode |= O_SHLOCK; 723 # endif 724 #endif 725 } 726 727 (void) strcpy(buf, map->map_file); 728 i = strlen(buf); 729 if (i < 3 || strcmp(&buf[i - 3], ".db") != 0) 730 (void) strcat(buf, ".db"); 731 db = dbopen(buf, omode, DBMMODE, DB_BTREE, NULL); 732 if (db == NULL) 733 { 734 #ifdef MAYBENEXTRELEASE 735 if (aliaswait(map, ".db", FALSE)) 736 return TRUE; 737 #endif 738 if (!bitset(MF_OPTIONAL, map->map_mflags)) 739 syserr("Cannot open BTREE database %s", map->map_file); 740 return FALSE; 741 } 742 #if !OLD_NEWDB 743 fd = db->fd(db); 744 # if defined(O_EXLOCK) && HASFLOCK 745 if (fd >= 0) 746 { 747 if (mode == O_RDONLY) 748 (void) lockfile(fd, map->map_file, ".db", LOCK_UN); 749 else 750 map->map_mflags |= MF_LOCKED; 751 } 752 # else 753 if (mode == O_RDWR && fd >= 0) 754 { 755 if (lockfile(fd, map->map_file, ".db", LOCK_EX)) 756 map->map_mflags |= MF_LOCKED; 757 } 758 # endif 759 #endif 760 761 /* try to make sure that at least the database header is on disk */ 762 if (mode == O_RDWR) 763 #if OLD_NEWDB 764 (void) db->sync(db); 765 #else 766 (void) db->sync(db, 0); 767 768 if (fd >= 0 && fstat(fd, &st) >= 0) 769 map->map_mtime = st.st_mtime; 770 #endif 771 772 map->map_db2 = (void *) db; 773 if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags)) 774 if (!aliaswait(map, ".db", TRUE)) 775 return FALSE; 776 return TRUE; 777 } 778 779 780 /* 781 ** HASH_MAP_INIT -- HASH-style map initialization 782 */ 783 784 bool 785 hash_map_open(map, mode) 786 MAP *map; 787 int mode; 788 { 789 DB *db; 790 int i; 791 int omode; 792 int fd; 793 struct stat st; 794 char buf[MAXNAME + 1]; 795 796 if (tTd(38, 2)) 797 printf("hash_map_open(%s, %s, %d)\n", 798 map->map_mname, map->map_file, mode); 799 800 omode = mode; 801 if (omode == O_RDWR) 802 { 803 omode |= O_CREAT|O_TRUNC; 804 #if defined(O_EXLOCK) && HASFLOCK 805 omode |= O_EXLOCK; 806 # if !OLD_NEWDB 807 } 808 else 809 { 810 omode |= O_SHLOCK; 811 # endif 812 #endif 813 } 814 815 (void) strcpy(buf, map->map_file); 816 i = strlen(buf); 817 if (i < 3 || strcmp(&buf[i - 3], ".db") != 0) 818 (void) strcat(buf, ".db"); 819 db = dbopen(buf, omode, DBMMODE, DB_HASH, NULL); 820 if (db == NULL) 821 { 822 #ifdef MAYBENEXTRELEASE 823 if (aliaswait(map, ".db", FALSE)) 824 return TRUE; 825 #endif 826 if (!bitset(MF_OPTIONAL, map->map_mflags)) 827 syserr("Cannot open HASH database %s", map->map_file); 828 return FALSE; 829 } 830 #if !OLD_NEWDB 831 fd = db->fd(db); 832 # if defined(O_EXLOCK) && HASFLOCK 833 if (fd >= 0) 834 { 835 if (mode == O_RDONLY) 836 (void) lockfile(fd, map->map_file, ".db", LOCK_UN); 837 else 838 map->map_mflags |= MF_LOCKED; 839 } 840 # else 841 if (mode == O_RDWR && fd >= 0) 842 { 843 if (lockfile(fd, map->map_file, ".db", LOCK_EX)) 844 map->map_mflags |= MF_LOCKED; 845 } 846 # endif 847 #endif 848 849 /* try to make sure that at least the database header is on disk */ 850 if (mode == O_RDWR) 851 #if OLD_NEWDB 852 (void) db->sync(db); 853 #else 854 (void) db->sync(db, 0); 855 856 if (fd >= 0 && fstat(fd, &st) >= 0) 857 map->map_mtime = st.st_mtime; 858 #endif 859 860 map->map_db2 = (void *) db; 861 if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags)) 862 if (!aliaswait(map, ".db", TRUE)) 863 return FALSE; 864 return TRUE; 865 } 866 867 868 /* 869 ** DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map 870 */ 871 872 char * 873 db_map_lookup(map, name, av, statp) 874 MAP *map; 875 char *name; 876 char **av; 877 int *statp; 878 { 879 DBT key, val; 880 register DB *db = (DB *) map->map_db2; 881 int st; 882 int saveerrno; 883 int fd; 884 char keybuf[MAXNAME + 1]; 885 886 if (tTd(38, 20)) 887 printf("db_map_lookup(%s, %s)\n", 888 map->map_mname, name); 889 890 key.size = strlen(name); 891 if (key.size > sizeof keybuf - 1) 892 key.size = sizeof keybuf - 1; 893 key.data = keybuf; 894 bcopy(name, keybuf, key.size + 1); 895 if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 896 makelower(keybuf); 897 #if !OLD_NEWDB 898 fd = db->fd(db); 899 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 900 (void) lockfile(db->fd(db), map->map_file, ".db", LOCK_SH); 901 #endif 902 st = 1; 903 if (bitset(MF_TRY0NULL, map->map_mflags)) 904 { 905 st = db->get(db, &key, &val, 0); 906 if (st == 0) 907 map->map_mflags &= ~MF_TRY1NULL; 908 } 909 if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags)) 910 { 911 key.size++; 912 st = db->get(db, &key, &val, 0); 913 if (st == 0) 914 map->map_mflags &= ~MF_TRY0NULL; 915 } 916 saveerrno = errno; 917 #if !OLD_NEWDB 918 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 919 (void) lockfile(fd, map->map_file, ".db", LOCK_UN); 920 #endif 921 if (st != 0) 922 { 923 errno = saveerrno; 924 if (st < 0) 925 syserr("db_map_lookup: get (%s)", name); 926 return NULL; 927 } 928 if (bitset(MF_MATCHONLY, map->map_mflags)) 929 return map_rewrite(map, name, strlen(name), NULL); 930 else 931 return map_rewrite(map, val.data, val.size, av); 932 } 933 934 935 /* 936 ** DB_MAP_STORE -- store a datum in the NEWDB database 937 */ 938 939 void 940 db_map_store(map, lhs, rhs) 941 register MAP *map; 942 char *lhs; 943 char *rhs; 944 { 945 int stat; 946 DBT key; 947 DBT data; 948 register DB *db = map->map_db2; 949 950 if (tTd(38, 20)) 951 printf("db_map_store(%s, %s, %s)\n", 952 map->map_mname, lhs, rhs); 953 954 key.size = strlen(lhs); 955 key.data = lhs; 956 957 data.size = strlen(rhs); 958 data.data = rhs; 959 960 if (bitset(MF_INCLNULL, map->map_mflags)) 961 { 962 key.size++; 963 data.size++; 964 } 965 966 stat = db->put(db, &key, &data, R_NOOVERWRITE); 967 if (stat > 0) 968 { 969 if (!bitset(MF_APPEND, map->map_mflags)) 970 usrerr("050 Warning: duplicate alias name %s", lhs); 971 else 972 { 973 static char *buf = NULL; 974 static int bufsiz = 0; 975 DBT old; 976 977 old.data = db_map_lookup(map, key.data, NULL, &stat); 978 if (old.data != NULL) 979 { 980 old.size = strlen(old.data); 981 if (data.size + old.size + 2 > bufsiz) 982 { 983 if (buf != NULL) 984 (void) free(buf); 985 bufsiz = data.size + old.size + 2; 986 buf = xalloc(bufsiz); 987 } 988 sprintf(buf, "%s,%s", data.data, old.data); 989 data.size = data.size + old.size + 1; 990 data.data = buf; 991 if (tTd(38, 9)) 992 printf("db_map_store append=%s\n", data.data); 993 } 994 } 995 stat = db->put(db, &key, &data, 0); 996 } 997 if (stat != 0) 998 syserr("readaliases: db put (%s)", lhs); 999 } 1000 1001 1002 /* 1003 ** DB_MAP_CLOSE -- add distinguished entries and close the database 1004 */ 1005 1006 void 1007 db_map_close(map) 1008 MAP *map; 1009 { 1010 register DB *db = map->map_db2; 1011 1012 if (tTd(38, 9)) 1013 printf("db_map_close(%s, %s, %x)\n", 1014 map->map_mname, map->map_file, map->map_mflags); 1015 1016 if (bitset(MF_WRITABLE, map->map_mflags)) 1017 { 1018 /* write out the distinguished alias */ 1019 db_map_store(map, "@", "@"); 1020 } 1021 1022 if (db->close(db) != 0) 1023 syserr("readaliases: db close failure"); 1024 } 1025 1026 #endif 1027 /* 1028 ** NIS Modules 1029 */ 1030 1031 # ifdef NIS 1032 1033 # ifndef YPERR_BUSY 1034 # define YPERR_BUSY 16 1035 # endif 1036 1037 /* 1038 ** NIS_MAP_OPEN -- open DBM map 1039 */ 1040 1041 bool 1042 nis_map_open(map, mode) 1043 MAP *map; 1044 int mode; 1045 { 1046 int yperr; 1047 register char *p; 1048 auto char *vp; 1049 auto int vsize; 1050 1051 if (tTd(38, 2)) 1052 printf("nis_map_open(%s, %s)\n", 1053 map->map_mname, map->map_file); 1054 1055 if (mode != O_RDONLY) 1056 { 1057 /* issue a pseudo-error message */ 1058 #ifdef ENOSYS 1059 errno = ENOSYS; 1060 #else 1061 # ifdef EFTYPE 1062 errno = EFTYPE; 1063 # else 1064 errno = ENXIO; 1065 # endif 1066 #endif 1067 return FALSE; 1068 } 1069 1070 p = strchr(map->map_file, '@'); 1071 if (p != NULL) 1072 { 1073 *p++ = '\0'; 1074 if (*p != '\0') 1075 map->map_domain = p; 1076 } 1077 1078 if (*map->map_file == '\0') 1079 map->map_file = "mail.aliases"; 1080 1081 if (map->map_domain == NULL) 1082 { 1083 yperr = yp_get_default_domain(&map->map_domain); 1084 if (yperr != 0) 1085 { 1086 if (!bitset(MF_OPTIONAL, map->map_mflags)) 1087 syserr("421 NIS map %s specified, but NIS not running\n", 1088 map->map_file); 1089 return FALSE; 1090 } 1091 } 1092 1093 /* check to see if this map actually exists */ 1094 yperr = yp_match(map->map_domain, map->map_file, "@", 1, 1095 &vp, &vsize); 1096 if (tTd(38, 10)) 1097 printf("nis_map_open: yp_match(%s, %s) => %s\n", 1098 map->map_domain, map->map_file, yperr_string(yperr)); 1099 if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY) 1100 { 1101 if (!bitset(MF_ALIAS, map->map_mflags) || 1102 aliaswait(map, NULL, TRUE)) 1103 return TRUE; 1104 } 1105 1106 if (!bitset(MF_OPTIONAL, map->map_mflags)) 1107 { 1108 syserr("421 Cannot bind to map %s in domain %s: %s", 1109 map->map_file, map->map_domain, yperr_string(yperr)); 1110 } 1111 1112 return FALSE; 1113 } 1114 1115 1116 /* 1117 ** NIS_MAP_LOOKUP -- look up a datum in a NIS map 1118 */ 1119 1120 char * 1121 nis_map_lookup(map, name, av, statp) 1122 MAP *map; 1123 char *name; 1124 char **av; 1125 int *statp; 1126 { 1127 char *vp; 1128 auto int vsize; 1129 int buflen; 1130 int yperr; 1131 char keybuf[MAXNAME + 1]; 1132 1133 if (tTd(38, 20)) 1134 printf("nis_map_lookup(%s, %s)\n", 1135 map->map_mname, name); 1136 1137 buflen = strlen(name); 1138 if (buflen > sizeof keybuf - 1) 1139 buflen = sizeof keybuf - 1; 1140 bcopy(name, keybuf, buflen + 1); 1141 if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 1142 makelower(keybuf); 1143 yperr = YPERR_KEY; 1144 if (bitset(MF_TRY0NULL, map->map_mflags)) 1145 { 1146 yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen, 1147 &vp, &vsize); 1148 if (yperr == 0) 1149 map->map_mflags &= ~MF_TRY1NULL; 1150 } 1151 if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags)) 1152 { 1153 buflen++; 1154 yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen, 1155 &vp, &vsize); 1156 if (yperr == 0) 1157 map->map_mflags &= ~MF_TRY0NULL; 1158 } 1159 if (yperr != 0) 1160 { 1161 if (yperr != YPERR_KEY && yperr != YPERR_BUSY) 1162 map->map_mflags &= ~(MF_VALID|MF_OPEN); 1163 return NULL; 1164 } 1165 if (bitset(MF_MATCHONLY, map->map_mflags)) 1166 return map_rewrite(map, name, strlen(name), NULL); 1167 else 1168 return map_rewrite(map, vp, vsize, av); 1169 } 1170 1171 1172 /* 1173 ** NIS_GETCANONNAME -- look up canonical name in NIS 1174 */ 1175 1176 bool 1177 nis_getcanonname(name, hbsize, statp) 1178 char *name; 1179 int hbsize; 1180 int *statp; 1181 { 1182 char *vp; 1183 auto int vsize; 1184 int keylen; 1185 int yperr; 1186 static bool try0null = TRUE; 1187 static bool try1null = TRUE; 1188 static char *yp_domain = NULL; 1189 char *domain; 1190 char 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 key_idx; 1988 char *cname; 1989 bool found; 1990 FILE *f; 1991 char linebuf[MAXLINE]; 1992 char cbuf[MAXNAME + 1]; 1993 char buf[MAXNAME + 1]; 1994 extern char *get_column(); 1995 1996 shorten_hostname(name); 1997 1998 /* we only accept single token search key */ 1999 if (strchr(name, '.') != NULL) 2000 { 2001 *statp = EX_NOHOST; 2002 return FALSE; 2003 } 2004 2005 found = FALSE; 2006 2007 f = fopen(HostsFile, "r"); 2008 if (f == NULL) 2009 { 2010 #ifdef MAP_EXIT_STAT 2011 *statp = EX_UNAVAILABLE; 2012 #endif 2013 return FALSE; 2014 } 2015 while (!found && fgets(linebuf, MAXLINE, f) != NULL) 2016 { 2017 char *p; 2018 2019 if (linebuf[0] == '#') 2020 continue; 2021 if ((p = strchr(linebuf, '\n')) != NULL) 2022 *p = '\0'; 2023 cname = get_column(linebuf, 1, '\0', cbuf); 2024 if (cname != NULL && strcasecmp(name, cname) == 0) 2025 { 2026 found = TRUE; 2027 break; 2028 } 2029 2030 key_idx = 2; 2031 while ((p = get_column(linebuf, key_idx, '\0', buf)) != NULL) 2032 { 2033 if (strcasecmp(name, p) == 0) 2034 { 2035 found = TRUE; 2036 break; 2037 } 2038 key_idx++; 2039 } 2040 } 2041 fclose(f); 2042 if (!found) 2043 { 2044 *statp = EX_NOHOST; 2045 return FALSE; 2046 } 2047 2048 if (hbsize >= strlen(cname)) 2049 { 2050 strcpy(name, cname); 2051 *statp = EX_OK; 2052 return TRUE; 2053 } 2054 *statp = EX_UNAVAILABLE; 2055 return FALSE; 2056 } 2057 /* 2058 ** STAB (Symbol Table) Modules 2059 */ 2060 2061 2062 /* 2063 ** STAB_MAP_LOOKUP -- look up alias in symbol table 2064 */ 2065 2066 char * 2067 stab_map_lookup(map, name, av, pstat) 2068 register MAP *map; 2069 char *name; 2070 char **av; 2071 int *pstat; 2072 { 2073 register STAB *s; 2074 2075 if (tTd(38, 20)) 2076 printf("stab_lookup(%s, %s)\n", 2077 map->map_mname, name); 2078 2079 s = stab(name, ST_ALIAS, ST_FIND); 2080 if (s != NULL) 2081 return (s->s_alias); 2082 return (NULL); 2083 } 2084 2085 2086 /* 2087 ** STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild) 2088 */ 2089 2090 void 2091 stab_map_store(map, lhs, rhs) 2092 register MAP *map; 2093 char *lhs; 2094 char *rhs; 2095 { 2096 register STAB *s; 2097 2098 s = stab(lhs, ST_ALIAS, ST_ENTER); 2099 s->s_alias = newstr(rhs); 2100 } 2101 2102 2103 /* 2104 ** STAB_MAP_OPEN -- initialize (reads data file) 2105 ** 2106 ** This is a wierd case -- it is only intended as a fallback for 2107 ** aliases. For this reason, opens for write (only during a 2108 ** "newaliases") always fails, and opens for read open the 2109 ** actual underlying text file instead of the database. 2110 */ 2111 2112 bool 2113 stab_map_open(map, mode) 2114 register MAP *map; 2115 int mode; 2116 { 2117 FILE *af; 2118 struct stat st; 2119 2120 if (tTd(38, 2)) 2121 printf("stab_map_open(%s, %s)\n", 2122 map->map_mname, map->map_file); 2123 2124 if (mode != O_RDONLY) 2125 { 2126 errno = ENODEV; 2127 return FALSE; 2128 } 2129 2130 af = fopen(map->map_file, "r"); 2131 if (af == NULL) 2132 return FALSE; 2133 readaliases(map, af, FALSE, FALSE); 2134 2135 if (fstat(fileno(af), &st) >= 0) 2136 map->map_mtime = st.st_mtime; 2137 fclose(af); 2138 2139 return TRUE; 2140 } 2141 /* 2142 ** Implicit Modules 2143 ** 2144 ** Tries several types. For back compatibility of aliases. 2145 */ 2146 2147 2148 /* 2149 ** IMPL_MAP_LOOKUP -- lookup in best open database 2150 */ 2151 2152 char * 2153 impl_map_lookup(map, name, av, pstat) 2154 MAP *map; 2155 char *name; 2156 char **av; 2157 int *pstat; 2158 { 2159 if (tTd(38, 20)) 2160 printf("impl_map_lookup(%s, %s)\n", 2161 map->map_mname, name); 2162 2163 #ifdef NEWDB 2164 if (bitset(MF_IMPL_HASH, map->map_mflags)) 2165 return db_map_lookup(map, name, av, pstat); 2166 #endif 2167 #ifdef NDBM 2168 if (bitset(MF_IMPL_NDBM, map->map_mflags)) 2169 return ndbm_map_lookup(map, name, av, pstat); 2170 #endif 2171 return stab_map_lookup(map, name, av, pstat); 2172 } 2173 2174 /* 2175 ** IMPL_MAP_STORE -- store in open databases 2176 */ 2177 2178 void 2179 impl_map_store(map, lhs, rhs) 2180 MAP *map; 2181 char *lhs; 2182 char *rhs; 2183 { 2184 #ifdef NEWDB 2185 if (bitset(MF_IMPL_HASH, map->map_mflags)) 2186 db_map_store(map, lhs, rhs); 2187 #endif 2188 #ifdef NDBM 2189 if (bitset(MF_IMPL_NDBM, map->map_mflags)) 2190 ndbm_map_store(map, lhs, rhs); 2191 #endif 2192 stab_map_store(map, lhs, rhs); 2193 } 2194 2195 /* 2196 ** IMPL_MAP_OPEN -- implicit database open 2197 */ 2198 2199 bool 2200 impl_map_open(map, mode) 2201 MAP *map; 2202 int mode; 2203 { 2204 struct stat stb; 2205 2206 if (tTd(38, 2)) 2207 printf("impl_map_open(%s, %s, %d)\n", 2208 map->map_mname, map->map_file, mode); 2209 2210 if (stat(map->map_file, &stb) < 0) 2211 { 2212 /* no alias file at all */ 2213 if (tTd(38, 3)) 2214 printf("no map file\n"); 2215 return FALSE; 2216 } 2217 2218 #ifdef NEWDB 2219 map->map_mflags |= MF_IMPL_HASH; 2220 if (hash_map_open(map, mode)) 2221 { 2222 #if defined(NDBM) && defined(NIS) 2223 if (mode == O_RDONLY || strstr(map->map_file, "/yp/") == NULL) 2224 #endif 2225 return TRUE; 2226 } 2227 else 2228 map->map_mflags &= ~MF_IMPL_HASH; 2229 #endif 2230 #ifdef NDBM 2231 map->map_mflags |= MF_IMPL_NDBM; 2232 if (ndbm_map_open(map, mode)) 2233 { 2234 return TRUE; 2235 } 2236 else 2237 map->map_mflags &= ~MF_IMPL_NDBM; 2238 #endif 2239 2240 #if defined(NEWDB) || defined(NDBM) 2241 if (Verbose) 2242 message("WARNING: cannot open alias database %s", map->map_file); 2243 #else 2244 if (mode != O_RDONLY) 2245 usrerr("Cannot rebuild aliases: no database format defined"); 2246 #endif 2247 2248 return stab_map_open(map, mode); 2249 } 2250 2251 2252 /* 2253 ** IMPL_MAP_CLOSE -- close any open database(s) 2254 */ 2255 2256 void 2257 impl_map_close(map) 2258 MAP *map; 2259 { 2260 if (tTd(38, 20)) 2261 printf("impl_map_close(%s, %s, %x)\n", 2262 map->map_mname, map->map_file, map->map_mflags); 2263 #ifdef NEWDB 2264 if (bitset(MF_IMPL_HASH, map->map_mflags)) 2265 { 2266 db_map_close(map); 2267 map->map_mflags &= ~MF_IMPL_HASH; 2268 } 2269 #endif 2270 2271 #ifdef NDBM 2272 if (bitset(MF_IMPL_NDBM, map->map_mflags)) 2273 { 2274 ndbm_map_close(map); 2275 map->map_mflags &= ~MF_IMPL_NDBM; 2276 } 2277 #endif 2278 } 2279 /* 2280 ** User map class. 2281 ** 2282 ** Provides access to the system password file. 2283 */ 2284 2285 /* 2286 ** USER_MAP_OPEN -- open user map 2287 ** 2288 ** Really just binds field names to field numbers. 2289 */ 2290 2291 bool 2292 user_map_open(map, mode) 2293 MAP *map; 2294 int mode; 2295 { 2296 if (tTd(38, 2)) 2297 printf("user_map_open(%s)\n", map->map_mname); 2298 2299 if (mode != O_RDONLY) 2300 { 2301 /* issue a pseudo-error message */ 2302 #ifdef ENOSYS 2303 errno = ENOSYS; 2304 #else 2305 # ifdef EFTYPE 2306 errno = EFTYPE; 2307 # else 2308 errno = ENXIO; 2309 # endif 2310 #endif 2311 return FALSE; 2312 } 2313 if (map->map_valcolnm == NULL) 2314 /* nothing */ ; 2315 else if (strcasecmp(map->map_valcolnm, "name") == 0) 2316 map->map_valcolno = 1; 2317 else if (strcasecmp(map->map_valcolnm, "passwd") == 0) 2318 map->map_valcolno = 2; 2319 else if (strcasecmp(map->map_valcolnm, "uid") == 0) 2320 map->map_valcolno = 3; 2321 else if (strcasecmp(map->map_valcolnm, "gid") == 0) 2322 map->map_valcolno = 4; 2323 else if (strcasecmp(map->map_valcolnm, "gecos") == 0) 2324 map->map_valcolno = 5; 2325 else if (strcasecmp(map->map_valcolnm, "dir") == 0) 2326 map->map_valcolno = 6; 2327 else if (strcasecmp(map->map_valcolnm, "shell") == 0) 2328 map->map_valcolno = 7; 2329 else 2330 { 2331 syserr("User map %s: unknown column name %s", 2332 map->map_mname, map->map_valcolnm); 2333 return FALSE; 2334 } 2335 return TRUE; 2336 } 2337 2338 2339 /* 2340 ** USER_MAP_LOOKUP -- look up a user in the passwd file. 2341 */ 2342 2343 char * 2344 user_map_lookup(map, key, av, statp) 2345 MAP *map; 2346 char *key; 2347 char **av; 2348 int *statp; 2349 { 2350 struct passwd *pw; 2351 2352 if (tTd(38, 20)) 2353 printf("user_map_lookup(%s, %s)\n", 2354 map->map_mname, key); 2355 2356 pw = sm_getpwnam(key); 2357 if (pw == NULL) 2358 return NULL; 2359 if (bitset(MF_MATCHONLY, map->map_mflags)) 2360 return map_rewrite(map, key, strlen(key), NULL); 2361 else 2362 { 2363 char *rwval = NULL; 2364 char buf[30]; 2365 2366 switch (map->map_valcolno) 2367 { 2368 case 0: 2369 case 1: 2370 rwval = pw->pw_name; 2371 break; 2372 2373 case 2: 2374 rwval = pw->pw_passwd; 2375 break; 2376 2377 case 3: 2378 sprintf(buf, "%d", pw->pw_uid); 2379 rwval = buf; 2380 break; 2381 2382 case 4: 2383 sprintf(buf, "%d", pw->pw_gid); 2384 rwval = buf; 2385 break; 2386 2387 case 5: 2388 rwval = pw->pw_gecos; 2389 break; 2390 2391 case 6: 2392 rwval = pw->pw_dir; 2393 break; 2394 2395 case 7: 2396 rwval = pw->pw_shell; 2397 break; 2398 } 2399 return map_rewrite(map, rwval, strlen(rwval), av); 2400 } 2401 } 2402 /* 2403 ** BESTMX -- find the best MX for a name 2404 ** 2405 ** This is really a hack, but I don't see any obvious way 2406 ** to generalize it at the moment. 2407 */ 2408 2409 #if NAMED_BIND 2410 2411 char * 2412 bestmx_map_lookup(map, name, av, statp) 2413 MAP *map; 2414 char *name; 2415 char **av; 2416 int *statp; 2417 { 2418 int nmx; 2419 auto int rcode; 2420 char *mxhosts[MAXMXHOSTS + 1]; 2421 2422 nmx = getmxrr(name, mxhosts, FALSE, &rcode); 2423 if (nmx <= 0) 2424 return NULL; 2425 if (bitset(MF_MATCHONLY, map->map_mflags)) 2426 return map_rewrite(map, name, strlen(name), NULL); 2427 else 2428 return map_rewrite(map, mxhosts[0], strlen(mxhosts[0]), av); 2429 } 2430 2431 #endif 2432 /* 2433 ** Program map type. 2434 ** 2435 ** This provides access to arbitrary programs. It should be used 2436 ** only very sparingly, since there is no way to bound the cost 2437 ** of invoking an arbitrary program. 2438 */ 2439 2440 char * 2441 prog_map_lookup(map, name, av, statp) 2442 MAP *map; 2443 char *name; 2444 char **av; 2445 int *statp; 2446 { 2447 int i; 2448 register char *p; 2449 int fd; 2450 auto pid_t pid; 2451 char *argv[MAXPV + 1]; 2452 char buf[MAXLINE]; 2453 2454 if (tTd(38, 20)) 2455 printf("prog_map_lookup(%s, %s) %s\n", 2456 map->map_mname, name, map->map_file); 2457 2458 i = 0; 2459 argv[i++] = map->map_file; 2460 strcpy(buf, map->map_rebuild); 2461 for (p = strtok(buf, " \t"); p != NULL; p = strtok(NULL, " \t")) 2462 { 2463 if (i >= MAXPV - 1) 2464 break; 2465 argv[i++] = p; 2466 } 2467 argv[i++] = name; 2468 argv[i] = NULL; 2469 pid = prog_open(argv, &fd, CurEnv); 2470 if (pid < 0) 2471 { 2472 if (tTd(38, 9)) 2473 printf("prog_map_lookup(%s) failed (%s) -- closing", 2474 map->map_mname, errstring(errno)); 2475 map->map_mflags &= ~(MF_VALID|MF_OPEN); 2476 return NULL; 2477 } 2478 i = read(fd, buf, sizeof buf - 1); 2479 if (i <= 0 && tTd(38, 2)) 2480 printf("prog_map_lookup(%s): read error %s\n", 2481 map->map_mname, errstring(errno)); 2482 if (i > 0) 2483 { 2484 char *rval; 2485 2486 buf[i] = '\0'; 2487 p = strchr(buf, '\n'); 2488 if (p != NULL) 2489 *p = '\0'; 2490 2491 /* collect the return value */ 2492 if (bitset(MF_MATCHONLY, map->map_mflags)) 2493 rval = map_rewrite(map, name, strlen(name), NULL); 2494 else 2495 rval = map_rewrite(map, buf, strlen(buf), NULL); 2496 2497 /* now flush any additional output */ 2498 while ((i = read(fd, buf, sizeof buf)) > 0) 2499 continue; 2500 close(fd); 2501 2502 /* and wait for the process to terminate */ 2503 *statp = waitfor(pid); 2504 2505 return rval; 2506 } 2507 2508 close(fd); 2509 *statp = waitfor(pid); 2510 return NULL; 2511 } 2512 /* 2513 ** Sequenced map type. 2514 ** 2515 ** Tries each map in order until something matches, much like 2516 ** implicit. Stores go to the first map in the list that can 2517 ** support storing. 2518 ** 2519 ** This is slightly unusual in that there are two interfaces. 2520 ** The "sequence" interface lets you stack maps arbitrarily. 2521 ** The "switch" interface builds a sequence map by looking 2522 ** at a system-dependent configuration file such as 2523 ** /etc/nsswitch.conf on Solaris or /etc/svc.conf on Ultrix. 2524 ** 2525 ** We don't need an explicit open, since all maps are 2526 ** opened during startup, including underlying maps. 2527 */ 2528 2529 /* 2530 ** SEQ_MAP_PARSE -- Sequenced map parsing 2531 */ 2532 2533 bool 2534 seq_map_parse(map, ap) 2535 MAP *map; 2536 char *ap; 2537 { 2538 int maxmap; 2539 2540 if (tTd(38, 2)) 2541 printf("seq_map_parse(%s, %s)\n", map->map_mname, ap); 2542 maxmap = 0; 2543 while (*ap != '\0') 2544 { 2545 register char *p; 2546 STAB *s; 2547 2548 /* find beginning of map name */ 2549 while (isascii(*ap) && isspace(*ap)) 2550 ap++; 2551 for (p = ap; isascii(*p) && isalnum(*p); p++) 2552 continue; 2553 if (*p != '\0') 2554 *p++ = '\0'; 2555 while (*p != '\0' && (!isascii(*p) || !isalnum(*p))) 2556 p++; 2557 if (*ap == '\0') 2558 { 2559 ap = p; 2560 continue; 2561 } 2562 s = stab(ap, ST_MAP, ST_FIND); 2563 if (s == NULL) 2564 { 2565 syserr("Sequence map %s: unknown member map %s", 2566 map->map_mname, ap); 2567 } 2568 else if (maxmap == MAXMAPSTACK) 2569 { 2570 syserr("Sequence map %s: too many member maps (%d max)", 2571 map->map_mname, MAXMAPSTACK); 2572 maxmap++; 2573 } 2574 else if (maxmap < MAXMAPSTACK) 2575 { 2576 map->map_stack[maxmap++] = &s->s_map; 2577 } 2578 ap = p; 2579 } 2580 return TRUE; 2581 } 2582 2583 2584 /* 2585 ** SWITCH_MAP_OPEN -- open a switched map 2586 ** 2587 ** This looks at the system-dependent configuration and builds 2588 ** a sequence map that does the same thing. 2589 ** 2590 ** Every system must define a switch_map_find routine in conf.c 2591 ** that will return the list of service types associated with a 2592 ** given service class. 2593 */ 2594 2595 bool 2596 switch_map_open(map, mode) 2597 MAP *map; 2598 int mode; 2599 { 2600 int mapno; 2601 int nmaps; 2602 char *maptype[MAXMAPSTACK]; 2603 2604 if (tTd(38, 2)) 2605 printf("switch_map_open(%s, %s, %d)\n", 2606 map->map_mname, map->map_file, mode); 2607 2608 nmaps = switch_map_find(map->map_file, maptype, map->map_return); 2609 if (tTd(38, 19)) 2610 { 2611 printf("\tswitch_map_find => %d\n", nmaps); 2612 for (mapno = 0; mapno < nmaps; mapno++) 2613 printf("\t\t%s\n", maptype[mapno]); 2614 } 2615 if (nmaps <= 0 || nmaps > MAXMAPSTACK) 2616 return FALSE; 2617 2618 for (mapno = 0; mapno < nmaps; mapno++) 2619 { 2620 register STAB *s; 2621 char nbuf[MAXNAME + 1]; 2622 2623 if (maptype[mapno] == NULL) 2624 continue; 2625 (void) sprintf(nbuf, "%s.%s", map->map_file, maptype[mapno]); 2626 s = stab(nbuf, ST_MAP, ST_FIND); 2627 if (s == NULL) 2628 { 2629 syserr("Switch map %s: unknown member map %s", 2630 map->map_mname, nbuf); 2631 } 2632 else 2633 { 2634 map->map_stack[mapno] = &s->s_map; 2635 if (tTd(38, 4)) 2636 printf("\tmap_stack[%d] = %s:%s\n", 2637 mapno, s->s_map.map_class->map_cname, 2638 nbuf); 2639 } 2640 } 2641 return TRUE; 2642 } 2643 2644 2645 /* 2646 ** SEQ_MAP_CLOSE -- close all underlying maps 2647 */ 2648 2649 void 2650 seq_map_close(map) 2651 MAP *map; 2652 { 2653 int mapno; 2654 2655 if (tTd(38, 20)) 2656 printf("seq_map_close(%s)\n", map->map_mname); 2657 for (mapno = 0; mapno < MAXMAPSTACK; mapno++) 2658 { 2659 MAP *mm = map->map_stack[mapno]; 2660 2661 if (mm == NULL || !bitset(MF_OPEN, mm->map_mflags)) 2662 continue; 2663 mm->map_class->map_close(mm); 2664 mm->map_mflags &= ~(MF_OPEN|MF_WRITABLE); 2665 } 2666 } 2667 2668 2669 /* 2670 ** SEQ_MAP_LOOKUP -- sequenced map lookup 2671 */ 2672 2673 char * 2674 seq_map_lookup(map, key, args, pstat) 2675 MAP *map; 2676 char *key; 2677 char **args; 2678 int *pstat; 2679 { 2680 int mapno; 2681 int mapbit = 0x01; 2682 2683 if (tTd(38, 20)) 2684 printf("seq_map_lookup(%s, %s)\n", map->map_mname, key); 2685 2686 for (mapno = 0; mapno < MAXMAPSTACK; mapbit <<= 1, mapno++) 2687 { 2688 MAP *mm = map->map_stack[mapno]; 2689 int stat = 0; 2690 char *rv; 2691 2692 if (mm == NULL) 2693 continue; 2694 if (!bitset(MF_OPEN, mm->map_mflags)) 2695 { 2696 if (bitset(mapbit, map->map_return[MA_UNAVAIL])) 2697 { 2698 *pstat = EX_UNAVAILABLE; 2699 return NULL; 2700 } 2701 continue; 2702 } 2703 rv = mm->map_class->map_lookup(mm, key, args, &stat); 2704 if (rv != NULL) 2705 return rv; 2706 if (stat == 0 && bitset(mapbit, map->map_return[MA_NOTFOUND])) 2707 return NULL; 2708 if (stat != 0 && bitset(mapbit, map->map_return[MA_TRYAGAIN])) 2709 { 2710 *pstat = stat; 2711 return NULL; 2712 } 2713 } 2714 return NULL; 2715 } 2716 2717 2718 /* 2719 ** SEQ_MAP_STORE -- sequenced map store 2720 */ 2721 2722 void 2723 seq_map_store(map, key, val) 2724 MAP *map; 2725 char *key; 2726 char *val; 2727 { 2728 int mapno; 2729 2730 if (tTd(38, 12)) 2731 printf("seq_map_store(%s, %s, %s)\n", 2732 map->map_mname, key, val); 2733 2734 for (mapno = 0; mapno < MAXMAPSTACK; mapno++) 2735 { 2736 MAP *mm = map->map_stack[mapno]; 2737 2738 if (mm == NULL || !bitset(MF_WRITABLE, mm->map_mflags)) 2739 continue; 2740 2741 mm->map_class->map_store(mm, key, val); 2742 return; 2743 } 2744 syserr("seq_map_store(%s, %s, %s): no writable map", 2745 map->map_mname, key, val); 2746 } 2747 /* 2748 ** GETCANONNAME -- look up name using service switch 2749 ** 2750 ** Parameters: 2751 ** host -- the host name to look up. 2752 ** hbsize -- the size of the host buffer. 2753 ** trymx -- if set, try MX records. 2754 ** 2755 ** Returns: 2756 ** TRUE -- if the host was found. 2757 ** FALSE -- otherwise. 2758 */ 2759 2760 bool 2761 getcanonname(host, hbsize, trymx) 2762 char *host; 2763 int hbsize; 2764 bool trymx; 2765 { 2766 int nmaps; 2767 int mapno; 2768 bool found = FALSE; 2769 auto int stat; 2770 char *maptype[MAXMAPSTACK]; 2771 short mapreturn[MAXMAPACTIONS]; 2772 extern int h_errno; 2773 2774 nmaps = switch_map_find("hosts", maptype, mapreturn); 2775 for (mapno = 0; mapno < nmaps; mapno++) 2776 { 2777 int i; 2778 2779 if (tTd(38, 20)) 2780 printf("getcanonname(%s), trying %s\n", 2781 host, maptype[mapno]); 2782 if (strcmp("files", maptype[mapno]) == 0) 2783 found = text_getcanonname(host, hbsize, &stat); 2784 #ifdef NIS 2785 else if (strcmp("nis", maptype[mapno]) == 0) 2786 found = nis_getcanonname(host, hbsize, &stat); 2787 #endif 2788 #ifdef NISPLUS 2789 else if (strcmp("nisplus", maptype[mapno]) == 0) 2790 found = nisplus_getcanonname(host, hbsize, &stat); 2791 #endif 2792 #if NAMED_BIND 2793 else if (strcmp("dns", maptype[mapno]) == 0) 2794 found = dns_getcanonname(host, hbsize, trymx, &stat); 2795 #endif 2796 else 2797 { 2798 found = FALSE; 2799 stat = EX_UNAVAILABLE; 2800 } 2801 if (found) 2802 break; 2803 2804 /* see if we should continue */ 2805 if (stat == EX_TEMPFAIL) 2806 i = MA_TRYAGAIN; 2807 else if (stat == EX_NOHOST) 2808 i = MA_NOTFOUND; 2809 else 2810 i = MA_UNAVAIL; 2811 if (bitset(1 << mapno, mapreturn[i])) 2812 break; 2813 } 2814 2815 if (found) 2816 { 2817 char *d; 2818 2819 if (tTd(38, 20)) 2820 printf("getcanonname(%s), found\n", host); 2821 2822 /* 2823 ** If returned name is still single token, compensate 2824 ** by tagging on $m. This is because some sites set 2825 ** up their DNS or NIS databases wrong. 2826 */ 2827 2828 if ((d = strchr(host, '.')) == NULL || d[1] == '\0') 2829 { 2830 d = macvalue('m', CurEnv); 2831 if (d != NULL && 2832 hbsize > (int) (strlen(host) + strlen(d) + 1)) 2833 { 2834 if (host[strlen(host) - 1] != '.') 2835 strcat(host, "."); 2836 strcat(host, d); 2837 } 2838 else 2839 { 2840 return FALSE; 2841 } 2842 } 2843 return TRUE; 2844 } 2845 2846 if (tTd(38, 20)) 2847 printf("getcanonname(%s), failed, stat=%d\n", host, stat); 2848 2849 #if NAMED_BIND 2850 if (stat == EX_NOHOST) 2851 h_errno = HOST_NOT_FOUND; 2852 else 2853 h_errno = TRY_AGAIN; 2854 #endif 2855 2856 return FALSE; 2857 } 2858 /* 2859 ** NULL stubs 2860 */ 2861 2862 bool 2863 null_map_open(map, mode) 2864 MAP *map; 2865 int mode; 2866 { 2867 return TRUE; 2868 } 2869 2870 void 2871 null_map_close(map) 2872 MAP *map; 2873 { 2874 return; 2875 } 2876 2877 void 2878 null_map_store(map, key, val) 2879 MAP *map; 2880 char *key; 2881 char *val; 2882 { 2883 return; 2884 } 2885 2886 2887 /* 2888 ** BOGUS stubs 2889 */ 2890 2891 char * 2892 bogus_map_lookup(map, key, args, pstat) 2893 MAP *map; 2894 char *key; 2895 char **args; 2896 int *pstat; 2897 { 2898 *pstat = EX_TEMPFAIL; 2899 return NULL; 2900 } 2901 2902 MAPCLASS BogusMapClass = 2903 { 2904 "bogus-map", NULL, 0, 2905 NULL, bogus_map_lookup, null_map_store, 2906 null_map_open, null_map_close, 2907 }; 2908