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