1 /* 2 * Copyright (c) 1992 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.27 (Berkeley) 05/20/94"; 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 #include <rpcsvc/ypclnt.h> 23 #endif 24 25 /* 26 ** MAP.C -- implementations for various map classes. 27 ** 28 ** Each map class implements a series of functions: 29 ** 30 ** bool map_parse(MAP *map, char *args) 31 ** Parse the arguments from the config file. Return TRUE 32 ** if they were ok, FALSE otherwise. Fill in map with the 33 ** values. 34 ** 35 ** char *map_lookup(MAP *map, char *key, char **args, int *pstat) 36 ** Look up the key in the given map. If found, do any 37 ** rewriting the map wants (including "args" if desired) 38 ** and return the value. Set *pstat to the appropriate status 39 ** on error and return NULL. Args will be NULL if called 40 ** from the alias routines, although this should probably 41 ** not be relied upon. It is suggested you call map_rewrite 42 ** to return the results -- it takes care of null termination 43 ** and uses a dynamically expanded buffer as needed. 44 ** 45 ** void map_store(MAP *map, char *key, char *value) 46 ** Store the key:value pair in the map. 47 ** 48 ** bool map_open(MAP *map, int mode) 49 ** Open the map for the indicated mode. Mode should 50 ** be either O_RDONLY or O_RDWR. Return TRUE if it 51 ** was opened successfully, FALSE otherwise. If the open 52 ** failed an the MF_OPTIONAL flag is not set, it should 53 ** also print an error. If the MF_ALIAS bit is set 54 ** and this map class understands the @:@ convention, it 55 ** should call aliaswait() before returning. 56 ** 57 ** void map_close(MAP *map) 58 ** Close the map. 59 */ 60 61 #define DBMMODE 0644 62 63 extern bool aliaswait __P((MAP *, char *, int)); 64 /* 65 ** MAP_PARSEARGS -- parse config line arguments for database lookup 66 ** 67 ** This is a generic version of the map_parse method. 68 ** 69 ** Parameters: 70 ** map -- the map being initialized. 71 ** ap -- a pointer to the args on the config line. 72 ** 73 ** Returns: 74 ** TRUE -- if everything parsed OK. 75 ** FALSE -- otherwise. 76 ** 77 ** Side Effects: 78 ** null terminates the filename; stores it in map 79 */ 80 81 bool 82 map_parseargs(map, ap) 83 MAP *map; 84 char *ap; 85 { 86 register char *p = ap; 87 88 map->map_mflags |= MF_TRY0NULL | MF_TRY1NULL; 89 for (;;) 90 { 91 while (isascii(*p) && isspace(*p)) 92 p++; 93 if (*p != '-') 94 break; 95 switch (*++p) 96 { 97 case 'N': 98 map->map_mflags |= MF_INCLNULL; 99 map->map_mflags &= ~MF_TRY0NULL; 100 break; 101 102 case 'O': 103 map->map_mflags &= ~MF_TRY1NULL; 104 break; 105 106 case 'o': 107 map->map_mflags |= MF_OPTIONAL; 108 break; 109 110 case 'f': 111 map->map_mflags |= MF_NOFOLDCASE; 112 break; 113 114 case 'm': 115 map->map_mflags |= MF_MATCHONLY; 116 break; 117 118 case 'a': 119 map->map_app = ++p; 120 break; 121 } 122 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 123 p++; 124 if (*p != '\0') 125 *p++ = '\0'; 126 } 127 if (map->map_app != NULL) 128 map->map_app = newstr(map->map_app); 129 130 if (*p != '\0') 131 { 132 map->map_file = p; 133 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 134 p++; 135 if (*p != '\0') 136 *p++ = '\0'; 137 map->map_file = newstr(map->map_file); 138 } 139 140 while (*p != '\0' && isascii(*p) && isspace(*p)) 141 p++; 142 if (*p != '\0') 143 map->map_rebuild = newstr(p); 144 145 if (map->map_file == NULL) 146 { 147 syserr("No file name for %s map %s", 148 map->map_class->map_cname, map->map_mname); 149 return FALSE; 150 } 151 return TRUE; 152 } 153 /* 154 ** MAP_REWRITE -- rewrite a database key, interpolating %n indications. 155 ** 156 ** It also adds the map_app string. It can be used as a utility 157 ** in the map_lookup method. 158 ** 159 ** Parameters: 160 ** map -- the map that causes this. 161 ** s -- the string to rewrite, NOT necessarily null terminated. 162 ** slen -- the length of s. 163 ** av -- arguments to interpolate into buf. 164 ** 165 ** Returns: 166 ** Pointer to rewritten result. 167 ** 168 ** Side Effects: 169 ** none. 170 */ 171 172 struct rwbuf 173 { 174 int rwb_len; /* size of buffer */ 175 char *rwb_buf; /* ptr to buffer */ 176 }; 177 178 struct rwbuf RwBufs[2]; /* buffers for rewriting output */ 179 180 char * 181 map_rewrite(map, s, slen, av) 182 register MAP *map; 183 register char *s; 184 int slen; 185 char **av; 186 { 187 register char *bp; 188 register char c; 189 char **avp; 190 register char *ap; 191 register struct rwbuf *rwb; 192 int i; 193 int len; 194 195 if (tTd(39, 1)) 196 { 197 printf("map_rewrite(%.*s), av =", slen, s); 198 if (av == NULL) 199 printf(" (nullv)"); 200 else 201 { 202 for (avp = av; *avp != NULL; avp++) 203 printf("\n\t%s", *avp); 204 } 205 printf("\n"); 206 } 207 208 rwb = RwBufs; 209 if (av == NULL) 210 rwb++; 211 212 /* count expected size of output (can safely overestimate) */ 213 i = len = slen; 214 if (av != NULL) 215 { 216 bp = s; 217 for (i = slen; --i >= 0 && (c = *bp++) != 0; ) 218 { 219 if (c != '%') 220 continue; 221 if (--i < 0) 222 break; 223 c = *bp++; 224 if (!(isascii(c) && isdigit(c))) 225 continue; 226 for (avp = av; --c >= '0' && *avp != NULL; avp++) 227 continue; 228 if (*avp == NULL) 229 continue; 230 len += strlen(*avp); 231 } 232 } 233 if (map->map_app != NULL) 234 len += strlen(map->map_app); 235 if (rwb->rwb_len < ++len) 236 { 237 /* need to malloc additional space */ 238 rwb->rwb_len = len; 239 if (rwb->rwb_buf != NULL) 240 free(rwb->rwb_buf); 241 rwb->rwb_buf = xalloc(rwb->rwb_len); 242 } 243 244 bp = rwb->rwb_buf; 245 if (av == NULL) 246 { 247 bcopy(s, bp, slen); 248 bp += slen; 249 } 250 else 251 { 252 while (--slen >= 0 && (c = *s++) != '\0') 253 { 254 if (c != '%') 255 { 256 pushc: 257 *bp++ = c; 258 continue; 259 } 260 if (--slen < 0 || (c = *s++) == '\0') 261 c = '%'; 262 if (c == '%') 263 goto pushc; 264 if (!(isascii(c) && isdigit(c))) 265 { 266 *bp++ = '%'; 267 goto pushc; 268 } 269 for (avp = av; --c >= '0' && *avp != NULL; avp++) 270 continue; 271 if (*avp == NULL) 272 continue; 273 274 /* transliterate argument into output string */ 275 for (ap = *avp; (c = *ap++) != '\0'; ) 276 *bp++ = c; 277 } 278 } 279 if (map->map_app != NULL) 280 strcpy(bp, map->map_app); 281 else 282 *bp = '\0'; 283 if (tTd(39, 1)) 284 printf("map_rewrite => %s\n", rwb->rwb_buf); 285 return rwb->rwb_buf; 286 } 287 /* 288 ** INITMAPS -- initialize for aliasing 289 ** 290 ** Parameters: 291 ** rebuild -- if TRUE, this rebuilds the cached versions. 292 ** e -- current envelope. 293 ** 294 ** Returns: 295 ** none. 296 ** 297 ** Side Effects: 298 ** initializes aliases: 299 ** if NDBM: opens the database. 300 ** if ~NDBM: reads the aliases into the symbol table. 301 */ 302 303 initmaps(rebuild, e) 304 bool rebuild; 305 register ENVELOPE *e; 306 { 307 extern void map_init(); 308 309 #ifdef XDEBUG 310 checkfd012("entering initmaps"); 311 #endif 312 CurEnv = e; 313 if (rebuild) 314 { 315 stabapply(map_init, 1); 316 stabapply(map_init, 2); 317 } 318 else 319 { 320 stabapply(map_init, 0); 321 } 322 #ifdef XDEBUG 323 checkfd012("exiting initmaps"); 324 #endif 325 } 326 327 void 328 map_init(s, rebuild) 329 register STAB *s; 330 int rebuild; 331 { 332 register MAP *map; 333 334 /* has to be a map */ 335 if (s->s_type != ST_MAP) 336 return; 337 338 map = &s->s_map; 339 if (!bitset(MF_VALID, map->map_mflags)) 340 return; 341 342 if (tTd(38, 2)) 343 printf("map_init(%s:%s, %d)\n", 344 map->map_class->map_cname == NULL ? "NULL" : 345 map->map_class->map_cname, 346 map->map_file == NULL ? "NULL" : map->map_file, 347 rebuild); 348 349 if (rebuild == (bitset(MF_ALIAS, map->map_mflags) && 350 bitset(MCF_REBUILDABLE, map->map_class->map_cflags) ? 1 : 2)) 351 { 352 if (tTd(38, 3)) 353 printf("\twrong pass\n"); 354 return; 355 } 356 357 /* if already open, close it (for nested open) */ 358 if (bitset(MF_OPEN, map->map_mflags)) 359 { 360 map->map_class->map_close(map); 361 map->map_mflags &= ~(MF_OPEN|MF_WRITABLE); 362 } 363 364 if (rebuild == 2) 365 { 366 rebuildaliases(map, FALSE); 367 } 368 else 369 { 370 if (map->map_class->map_open(map, O_RDONLY)) 371 { 372 if (tTd(38, 4)) 373 printf("\t%s:%s: valid\n", 374 map->map_class->map_cname == NULL ? "NULL" : 375 map->map_class->map_cname, 376 map->map_file == NULL ? "NULL" : 377 map->map_file); 378 map->map_mflags |= MF_OPEN; 379 } 380 else if (tTd(38, 4)) 381 printf("\t%s:%s: invalid: %s\n", 382 map->map_class->map_cname == NULL ? "NULL" : 383 map->map_class->map_cname, 384 map->map_file == NULL ? "NULL" : 385 map->map_file, 386 errstring(errno)); 387 } 388 } 389 /* 390 ** NDBM modules 391 */ 392 393 #ifdef NDBM 394 395 /* 396 ** DBM_MAP_OPEN -- DBM-style map open 397 */ 398 399 bool 400 ndbm_map_open(map, mode) 401 MAP *map; 402 int mode; 403 { 404 register DBM *dbm; 405 struct stat st; 406 407 if (tTd(38, 2)) 408 printf("ndbm_map_open(%s, %d)\n", map->map_file, mode); 409 410 if (mode == O_RDWR) 411 mode |= O_CREAT|O_TRUNC; 412 413 /* open the database */ 414 dbm = dbm_open(map->map_file, mode, DBMMODE); 415 if (dbm == NULL) 416 { 417 #ifdef MAYBENEXTRELEASE 418 if (aliaswait(map, ".pag", FALSE)) 419 return TRUE; 420 #endif 421 if (!bitset(MF_OPTIONAL, map->map_mflags)) 422 syserr("Cannot open DBM database %s", map->map_file); 423 return FALSE; 424 } 425 map->map_db1 = (void *) dbm; 426 if (mode == O_RDONLY) 427 { 428 if (bitset(MF_ALIAS, map->map_mflags) && 429 !aliaswait(map, ".pag", TRUE)) 430 return FALSE; 431 } 432 else 433 { 434 int fd; 435 436 /* exclusive lock for duration of rebuild */ 437 fd = dbm_dirfno((DBM *) map->map_db1); 438 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags) && 439 lockfile(fd, map->map_file, ".dir", LOCK_EX)) 440 map->map_mflags |= MF_LOCKED; 441 } 442 if (fstat(dbm_dirfno((DBM *) map->map_db1), &st) >= 0) 443 map->map_mtime = st.st_mtime; 444 return TRUE; 445 } 446 447 448 /* 449 ** DBM_MAP_LOOKUP -- look up a datum in a DBM-type map 450 */ 451 452 char * 453 ndbm_map_lookup(map, name, av, statp) 454 MAP *map; 455 char *name; 456 char **av; 457 int *statp; 458 { 459 datum key, val; 460 int fd; 461 char keybuf[MAXNAME + 1]; 462 463 if (tTd(38, 20)) 464 printf("ndbm_map_lookup(%s)\n", name); 465 466 key.dptr = name; 467 key.dsize = strlen(name); 468 if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 469 { 470 if (key.dsize > sizeof keybuf - 1) 471 key.dsize = sizeof keybuf - 1; 472 bcopy(key.dptr, keybuf, key.dsize + 1); 473 makelower(keybuf); 474 key.dptr = keybuf; 475 } 476 fd = dbm_dirfno((DBM *) map->map_db1); 477 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 478 (void) lockfile(fd, map->map_file, ".dir", LOCK_SH); 479 val.dptr = NULL; 480 if (bitset(MF_TRY0NULL, map->map_mflags)) 481 { 482 val = dbm_fetch((DBM *) map->map_db1, key); 483 if (val.dptr != NULL) 484 map->map_mflags &= ~MF_TRY1NULL; 485 } 486 if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags)) 487 { 488 key.dsize++; 489 val = dbm_fetch((DBM *) map->map_db1, key); 490 if (val.dptr != NULL) 491 map->map_mflags &= ~MF_TRY0NULL; 492 } 493 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 494 (void) lockfile(fd, map->map_file, ".dir", LOCK_UN); 495 if (val.dptr == NULL) 496 return NULL; 497 if (bitset(MF_MATCHONLY, map->map_mflags)) 498 return map_rewrite(map, name, strlen(name), NULL); 499 else 500 return map_rewrite(map, val.dptr, val.dsize, av); 501 } 502 503 504 /* 505 ** DBM_MAP_STORE -- store a datum in the database 506 */ 507 508 void 509 ndbm_map_store(map, lhs, rhs) 510 register MAP *map; 511 char *lhs; 512 char *rhs; 513 { 514 datum key; 515 datum data; 516 int stat; 517 518 if (tTd(38, 12)) 519 printf("ndbm_map_store(%s, %s)\n", lhs, rhs); 520 521 key.dsize = strlen(lhs); 522 key.dptr = lhs; 523 524 data.dsize = strlen(rhs); 525 data.dptr = rhs; 526 527 if (bitset(MF_INCLNULL, map->map_mflags)) 528 { 529 key.dsize++; 530 data.dsize++; 531 } 532 533 stat = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT); 534 if (stat > 0) 535 { 536 usrerr("050 Warning: duplicate alias name %s", lhs); 537 stat = dbm_store((DBM *) map->map_db1, key, data, DBM_REPLACE); 538 } 539 if (stat != 0) 540 syserr("readaliases: dbm put (%s)", lhs); 541 } 542 543 544 /* 545 ** NDBM_MAP_CLOSE -- close the database 546 */ 547 548 void 549 ndbm_map_close(map) 550 register MAP *map; 551 { 552 if (tTd(38, 9)) 553 printf("ndbm_map_close(%s, %x)\n", map->map_file, map->map_mflags); 554 555 if (bitset(MF_WRITABLE, map->map_mflags)) 556 { 557 #ifdef NIS 558 bool inclnull; 559 char buf[200]; 560 561 inclnull = bitset(MF_INCLNULL, map->map_mflags); 562 map->map_mflags &= ~MF_INCLNULL; 563 564 (void) sprintf(buf, "%010ld", curtime()); 565 ndbm_map_store(map, "YP_LAST_MODIFIED", buf); 566 567 (void) gethostname(buf, sizeof buf); 568 ndbm_map_store(map, "YP_MASTER_NAME", buf); 569 570 if (inclnull) 571 map->map_mflags |= MF_INCLNULL; 572 #endif 573 574 /* write out the distinguished alias */ 575 ndbm_map_store(map, "@", "@"); 576 } 577 dbm_close((DBM *) map->map_db1); 578 } 579 580 #endif 581 /* 582 ** NEWDB (Hash and BTree) Modules 583 */ 584 585 #ifdef NEWDB 586 587 /* 588 ** BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives. 589 ** 590 ** These do rather bizarre locking. If you can lock on open, 591 ** do that to avoid the condition of opening a database that 592 ** is being rebuilt. If you don't, we'll try to fake it, but 593 ** there will be a race condition. If opening for read-only, 594 ** we immediately release the lock to avoid freezing things up. 595 ** We really ought to hold the lock, but guarantee that we won't 596 ** be pokey about it. That's hard to do. 597 */ 598 599 bool 600 bt_map_open(map, mode) 601 MAP *map; 602 int mode; 603 { 604 DB *db; 605 int i; 606 int omode; 607 int fd; 608 struct stat st; 609 char buf[MAXNAME]; 610 611 if (tTd(38, 2)) 612 printf("bt_map_open(%s, %d)\n", map->map_file, mode); 613 614 omode = mode; 615 if (omode == O_RDWR) 616 { 617 omode |= O_CREAT|O_TRUNC; 618 #if defined(O_EXLOCK) && HASFLOCK 619 omode |= O_EXLOCK; 620 # if !OLD_NEWDB 621 } 622 else 623 { 624 omode |= O_SHLOCK; 625 # endif 626 #endif 627 } 628 629 (void) strcpy(buf, map->map_file); 630 i = strlen(buf); 631 if (i < 3 || strcmp(&buf[i - 3], ".db") != 0) 632 (void) strcat(buf, ".db"); 633 db = dbopen(buf, omode, DBMMODE, DB_BTREE, NULL); 634 if (db == NULL) 635 { 636 #ifdef MAYBENEXTRELEASE 637 if (aliaswait(map, ".db", FALSE)) 638 return TRUE; 639 #endif 640 if (!bitset(MF_OPTIONAL, map->map_mflags)) 641 syserr("Cannot open BTREE database %s", map->map_file); 642 return FALSE; 643 } 644 #if !OLD_NEWDB 645 fd = db->fd(db); 646 # if HASFLOCK 647 # if !defined(O_EXLOCK) 648 if (mode == O_RDWR && fd >= 0) 649 { 650 if (lockfile(fd, map->map_file, ".db", LOCK_EX)) 651 map->map_mflags |= MF_LOCKED; 652 } 653 # else 654 if (mode == O_RDONLY && fd >= 0) 655 (void) lockfile(fd, map->map_file, ".db", LOCK_UN); 656 else 657 map->map_mflags |= MF_LOCKED; 658 # endif 659 # endif 660 #endif 661 662 /* try to make sure that at least the database header is on disk */ 663 if (mode == O_RDWR) 664 #if OLD_NEWDB 665 (void) db->sync(db); 666 #else 667 (void) db->sync(db, 0); 668 669 if (fd >= 0 && fstat(fd, &st) >= 0) 670 map->map_mtime = st.st_mtime; 671 #endif 672 673 map->map_db2 = (void *) db; 674 if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags)) 675 if (!aliaswait(map, ".db", TRUE)) 676 return FALSE; 677 return TRUE; 678 } 679 680 681 /* 682 ** HASH_MAP_INIT -- HASH-style map initialization 683 */ 684 685 bool 686 hash_map_open(map, mode) 687 MAP *map; 688 int mode; 689 { 690 DB *db; 691 int i; 692 int omode; 693 int fd; 694 struct stat st; 695 char buf[MAXNAME]; 696 697 if (tTd(38, 2)) 698 printf("hash_map_open(%s, %d)\n", map->map_file, mode); 699 700 omode = mode; 701 if (omode == O_RDWR) 702 { 703 omode |= O_CREAT|O_TRUNC; 704 #if defined(O_EXLOCK) && HASFLOCK 705 omode |= O_EXLOCK; 706 # if !OLD_NEWDB 707 } 708 else 709 { 710 omode |= O_SHLOCK; 711 # endif 712 #endif 713 } 714 715 (void) strcpy(buf, map->map_file); 716 i = strlen(buf); 717 if (i < 3 || strcmp(&buf[i - 3], ".db") != 0) 718 (void) strcat(buf, ".db"); 719 db = dbopen(buf, omode, DBMMODE, DB_HASH, NULL); 720 if (db == NULL) 721 { 722 #ifdef MAYBENEXTRELEASE 723 if (aliaswait(map, ".db", FALSE)) 724 return TRUE; 725 #endif 726 if (!bitset(MF_OPTIONAL, map->map_mflags)) 727 syserr("Cannot open HASH database %s", map->map_file); 728 return FALSE; 729 } 730 #if !OLD_NEWDB 731 fd = db->fd(db); 732 # if HASFLOCK 733 # if !defined(O_EXLOCK) 734 if (mode == O_RDWR && fd >= 0) 735 { 736 if (lockfile(fd, map->map_file, ".db", LOCK_EX)) 737 map->map_mflags |= MF_LOCKED; 738 } 739 # else 740 if (mode == O_RDONLY && fd >= 0) 741 (void) lockfile(fd, map->map_file, ".db", LOCK_UN); 742 else 743 map->map_mflags |= MF_LOCKED; 744 # endif 745 # endif 746 #endif 747 748 /* try to make sure that at least the database header is on disk */ 749 if (mode == O_RDWR) 750 #if OLD_NEWDB 751 (void) db->sync(db); 752 #else 753 (void) db->sync(db, 0); 754 755 if (fd >= 0 && fstat(fd, &st) >= 0) 756 map->map_mtime = st.st_mtime; 757 #endif 758 759 map->map_db2 = (void *) db; 760 if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags)) 761 if (!aliaswait(map, ".db", TRUE)) 762 return FALSE; 763 return TRUE; 764 } 765 766 767 /* 768 ** DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map 769 */ 770 771 char * 772 db_map_lookup(map, name, av, statp) 773 MAP *map; 774 char *name; 775 char **av; 776 int *statp; 777 { 778 DBT key, val; 779 register DB *db = (DB *) map->map_db2; 780 int st; 781 int saveerrno; 782 int fd; 783 char keybuf[MAXNAME + 1]; 784 785 if (tTd(38, 20)) 786 printf("db_map_lookup(%s)\n", name); 787 788 key.size = strlen(name); 789 if (key.size > sizeof keybuf - 1) 790 key.size = sizeof keybuf - 1; 791 key.data = keybuf; 792 bcopy(name, keybuf, key.size + 1); 793 if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 794 makelower(keybuf); 795 #if !OLD_NEWDB 796 fd = db->fd(db); 797 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 798 (void) lockfile(db->fd(db), map->map_file, ".db", LOCK_SH); 799 #endif 800 st = 1; 801 if (bitset(MF_TRY0NULL, map->map_mflags)) 802 { 803 st = db->get(db, &key, &val, 0); 804 if (st == 0) 805 map->map_mflags &= ~MF_TRY1NULL; 806 } 807 if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags)) 808 { 809 key.size++; 810 st = db->get(db, &key, &val, 0); 811 if (st == 0) 812 map->map_mflags &= ~MF_TRY0NULL; 813 } 814 saveerrno = errno; 815 #if !OLD_NEWDB 816 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 817 (void) lockfile(fd, map->map_file, ".db", LOCK_UN); 818 #endif 819 if (st != 0) 820 { 821 errno = saveerrno; 822 if (st < 0) 823 syserr("db_map_lookup: get (%s)", name); 824 return NULL; 825 } 826 if (bitset(MF_MATCHONLY, map->map_mflags)) 827 return map_rewrite(map, name, strlen(name), NULL); 828 else 829 return map_rewrite(map, val.data, val.size, av); 830 } 831 832 833 /* 834 ** DB_MAP_STORE -- store a datum in the NEWDB database 835 */ 836 837 void 838 db_map_store(map, lhs, rhs) 839 register MAP *map; 840 char *lhs; 841 char *rhs; 842 { 843 int stat; 844 DBT key; 845 DBT data; 846 register DB *db = map->map_db2; 847 848 if (tTd(38, 20)) 849 printf("db_map_store(%s, %s)\n", lhs, rhs); 850 851 key.size = strlen(lhs); 852 key.data = lhs; 853 854 data.size = strlen(rhs); 855 data.data = rhs; 856 857 if (bitset(MF_INCLNULL, map->map_mflags)) 858 { 859 key.size++; 860 data.size++; 861 } 862 863 stat = db->put(db, &key, &data, R_NOOVERWRITE); 864 if (stat > 0) 865 { 866 usrerr("050 Warning: duplicate alias name %s", lhs); 867 stat = db->put(db, &key, &data, 0); 868 } 869 if (stat != 0) 870 syserr("readaliases: db put (%s)", lhs); 871 } 872 873 874 /* 875 ** DB_MAP_CLOSE -- add distinguished entries and close the database 876 */ 877 878 void 879 db_map_close(map) 880 MAP *map; 881 { 882 register DB *db = map->map_db2; 883 884 if (tTd(38, 9)) 885 printf("db_map_close(%s, %x)\n", map->map_file, map->map_mflags); 886 887 if (bitset(MF_WRITABLE, map->map_mflags)) 888 { 889 /* write out the distinguished alias */ 890 db_map_store(map, "@", "@"); 891 } 892 893 if (db->close(db) != 0) 894 syserr("readaliases: db close failure"); 895 } 896 897 #endif 898 /* 899 ** NIS Modules 900 */ 901 902 # ifdef NIS 903 904 # ifndef YPERR_BUSY 905 # define YPERR_BUSY 16 906 # endif 907 908 /* 909 ** NIS_MAP_OPEN -- open DBM map 910 */ 911 912 bool 913 nis_map_open(map, mode) 914 MAP *map; 915 int mode; 916 { 917 int yperr; 918 register char *p; 919 auto char *vp; 920 auto int vsize; 921 char *master; 922 923 if (tTd(38, 2)) 924 printf("nis_map_open(%s)\n", map->map_file); 925 926 if (mode != O_RDONLY) 927 { 928 /* issue a pseudo-error message */ 929 #ifdef ENOSYS 930 errno = ENOSYS; 931 #else 932 # ifdef EFTYPE 933 errno = EFTYPE; 934 # else 935 errno = ENXIO; 936 # endif 937 #endif 938 return FALSE; 939 } 940 941 p = strchr(map->map_file, '@'); 942 if (p != NULL) 943 { 944 *p++ = '\0'; 945 if (*p != '\0') 946 map->map_domain = p; 947 } 948 949 if (*map->map_file == '\0') 950 map->map_file = "mail.aliases"; 951 952 if (map->map_domain == NULL) 953 { 954 yperr = yp_get_default_domain(&map->map_domain); 955 if (yperr != 0) 956 { 957 if (!bitset(MF_OPTIONAL, map->map_mflags)) 958 syserr("NIS map %s specified, but NIS not running\n", 959 map->map_file); 960 return FALSE; 961 } 962 } 963 964 /* check to see if this map actually exists */ 965 yperr = yp_match(map->map_domain, map->map_file, "@", 1, 966 &vp, &vsize); 967 if (tTd(38, 10)) 968 printf("nis_map_open: yp_match(%s, %s) => %s\n", 969 map->map_domain, map->map_file, yperr_string(yperr)); 970 if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY) 971 return TRUE; 972 973 if (!bitset(MF_OPTIONAL, map->map_mflags)) 974 syserr("Cannot bind to domain %s: %s", map->map_domain, 975 yperr_string(yperr)); 976 977 return FALSE; 978 } 979 980 981 /* 982 ** NIS_MAP_LOOKUP -- look up a datum in a NIS map 983 */ 984 985 char * 986 nis_map_lookup(map, name, av, statp) 987 MAP *map; 988 char *name; 989 char **av; 990 int *statp; 991 { 992 char *vp; 993 auto int vsize; 994 int buflen; 995 int yperr; 996 char keybuf[MAXNAME + 1]; 997 998 if (tTd(38, 20)) 999 printf("nis_map_lookup(%s)\n", name); 1000 1001 buflen = strlen(name); 1002 if (buflen > sizeof keybuf - 1) 1003 buflen = sizeof keybuf - 1; 1004 bcopy(name, keybuf, buflen + 1); 1005 if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 1006 makelower(keybuf); 1007 yperr = YPERR_KEY; 1008 if (bitset(MF_TRY0NULL, map->map_mflags)) 1009 { 1010 yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen, 1011 &vp, &vsize); 1012 if (yperr == 0) 1013 map->map_mflags &= ~MF_TRY1NULL; 1014 } 1015 if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags)) 1016 { 1017 buflen++; 1018 yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen, 1019 &vp, &vsize); 1020 if (yperr == 0) 1021 map->map_mflags &= ~MF_TRY0NULL; 1022 } 1023 if (yperr != 0) 1024 { 1025 if (yperr != YPERR_KEY && yperr != YPERR_BUSY) 1026 map->map_mflags &= ~(MF_VALID|MF_OPEN); 1027 return NULL; 1028 } 1029 if (bitset(MF_MATCHONLY, map->map_mflags)) 1030 return map_rewrite(map, name, strlen(name), NULL); 1031 else 1032 return map_rewrite(map, vp, vsize, av); 1033 } 1034 1035 1036 /* 1037 ** NIS_MAP_STORE 1038 */ 1039 1040 void 1041 nis_map_store(map, lhs, rhs) 1042 MAP *map; 1043 char *lhs; 1044 char *rhs; 1045 { 1046 /* nothing */ 1047 } 1048 1049 1050 /* 1051 ** NIS_MAP_CLOSE 1052 */ 1053 1054 void 1055 nis_map_close(map) 1056 MAP *map; 1057 { 1058 /* nothing */ 1059 } 1060 1061 #endif /* NIS */ 1062 /* 1063 ** STAB (Symbol Table) Modules 1064 */ 1065 1066 1067 /* 1068 ** STAB_MAP_LOOKUP -- look up alias in symbol table 1069 */ 1070 1071 char * 1072 stab_map_lookup(map, name, av, pstat) 1073 register MAP *map; 1074 char *name; 1075 char **av; 1076 int *pstat; 1077 { 1078 register STAB *s; 1079 1080 if (tTd(38, 20)) 1081 printf("stab_lookup(%s)\n", name); 1082 1083 s = stab(name, ST_ALIAS, ST_FIND); 1084 if (s != NULL) 1085 return (s->s_alias); 1086 return (NULL); 1087 } 1088 1089 1090 /* 1091 ** STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild) 1092 */ 1093 1094 void 1095 stab_map_store(map, lhs, rhs) 1096 register MAP *map; 1097 char *lhs; 1098 char *rhs; 1099 { 1100 register STAB *s; 1101 1102 s = stab(lhs, ST_ALIAS, ST_ENTER); 1103 s->s_alias = newstr(rhs); 1104 } 1105 1106 1107 /* 1108 ** STAB_MAP_OPEN -- initialize (reads data file) 1109 ** 1110 ** This is a wierd case -- it is only intended as a fallback for 1111 ** aliases. For this reason, opens for write (only during a 1112 ** "newaliases") always fails, and opens for read open the 1113 ** actual underlying text file instead of the database. 1114 */ 1115 1116 bool 1117 stab_map_open(map, mode) 1118 register MAP *map; 1119 int mode; 1120 { 1121 FILE *af; 1122 struct stat st; 1123 1124 if (tTd(38, 2)) 1125 printf("stab_map_open(%s)\n", map->map_file); 1126 1127 if (mode != O_RDONLY) 1128 { 1129 errno = ENODEV; 1130 return FALSE; 1131 } 1132 1133 af = fopen(map->map_file, "r"); 1134 if (af == NULL) 1135 return FALSE; 1136 readaliases(map, af, TRUE); 1137 1138 if (fstat(fileno(af), &st) >= 0) 1139 map->map_mtime = st.st_mtime; 1140 fclose(af); 1141 1142 return TRUE; 1143 } 1144 1145 1146 /* 1147 ** STAB_MAP_CLOSE -- close symbol table. 1148 ** 1149 ** Since this is in memory, there is nothing to do. 1150 */ 1151 1152 void 1153 stab_map_close(map) 1154 MAP *map; 1155 { 1156 /* ignore it */ 1157 } 1158 /* 1159 ** Implicit Modules 1160 ** 1161 ** Tries several types. For back compatibility of aliases. 1162 */ 1163 1164 1165 /* 1166 ** IMPL_MAP_LOOKUP -- lookup in best open database 1167 */ 1168 1169 char * 1170 impl_map_lookup(map, name, av, pstat) 1171 MAP *map; 1172 char *name; 1173 char **av; 1174 int *pstat; 1175 { 1176 if (tTd(38, 20)) 1177 printf("impl_map_lookup(%s)\n", name); 1178 1179 #ifdef NEWDB 1180 if (bitset(MF_IMPL_HASH, map->map_mflags)) 1181 return db_map_lookup(map, name, av, pstat); 1182 #endif 1183 #ifdef NDBM 1184 if (bitset(MF_IMPL_NDBM, map->map_mflags)) 1185 return ndbm_map_lookup(map, name, av, pstat); 1186 #endif 1187 return stab_map_lookup(map, name, av, pstat); 1188 } 1189 1190 /* 1191 ** IMPL_MAP_STORE -- store in open databases 1192 */ 1193 1194 void 1195 impl_map_store(map, lhs, rhs) 1196 MAP *map; 1197 char *lhs; 1198 char *rhs; 1199 { 1200 #ifdef NEWDB 1201 if (bitset(MF_IMPL_HASH, map->map_mflags)) 1202 db_map_store(map, lhs, rhs); 1203 #endif 1204 #ifdef NDBM 1205 if (bitset(MF_IMPL_NDBM, map->map_mflags)) 1206 ndbm_map_store(map, lhs, rhs); 1207 #endif 1208 stab_map_store(map, lhs, rhs); 1209 } 1210 1211 /* 1212 ** IMPL_MAP_OPEN -- implicit database open 1213 */ 1214 1215 bool 1216 impl_map_open(map, mode) 1217 MAP *map; 1218 int mode; 1219 { 1220 struct stat stb; 1221 1222 if (tTd(38, 2)) 1223 printf("impl_map_open(%s, %d)\n", map->map_file, mode); 1224 1225 if (stat(map->map_file, &stb) < 0) 1226 { 1227 /* no alias file at all */ 1228 if (tTd(38, 3)) 1229 printf("no map file\n"); 1230 return FALSE; 1231 } 1232 1233 #ifdef NEWDB 1234 map->map_mflags |= MF_IMPL_HASH; 1235 if (hash_map_open(map, mode)) 1236 { 1237 #if defined(NDBM) && defined(NIS) 1238 if (mode == O_RDONLY || access("/var/yp/Makefile", R_OK) != 0) 1239 #endif 1240 return TRUE; 1241 } 1242 else 1243 map->map_mflags &= ~MF_IMPL_HASH; 1244 #endif 1245 #ifdef NDBM 1246 map->map_mflags |= MF_IMPL_NDBM; 1247 if (ndbm_map_open(map, mode)) 1248 { 1249 return TRUE; 1250 } 1251 else 1252 map->map_mflags &= ~MF_IMPL_NDBM; 1253 #endif 1254 1255 #if defined(NEWDB) || defined(NDBM) 1256 if (Verbose) 1257 message("WARNING: cannot open alias database %s", map->map_file); 1258 #else 1259 if (mode != O_RDONLY) 1260 usrerr("Cannot rebuild aliases: no database format defined"); 1261 #endif 1262 1263 return stab_map_open(map, mode); 1264 } 1265 1266 1267 /* 1268 ** IMPL_MAP_CLOSE -- close any open database(s) 1269 */ 1270 1271 void 1272 impl_map_close(map) 1273 MAP *map; 1274 { 1275 #ifdef NEWDB 1276 if (bitset(MF_IMPL_HASH, map->map_mflags)) 1277 { 1278 db_map_close(map); 1279 map->map_mflags &= ~MF_IMPL_HASH; 1280 } 1281 #endif 1282 1283 #ifdef NDBM 1284 if (bitset(MF_IMPL_NDBM, map->map_mflags)) 1285 { 1286 ndbm_map_close(map); 1287 map->map_mflags &= ~MF_IMPL_NDBM; 1288 } 1289 #endif 1290 } 1291 /* 1292 ** NULL stubs 1293 */ 1294 1295 bool 1296 null_map_open(map, mode) 1297 MAP *map; 1298 int mode; 1299 { 1300 return TRUE; 1301 } 1302 1303 void 1304 null_map_close(map) 1305 MAP *map; 1306 { 1307 return; 1308 } 1309 1310 void 1311 null_map_store(map, key, val) 1312 MAP *map; 1313 char *key; 1314 char *val; 1315 { 1316 return; 1317 } 1318