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