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.29 (Berkeley) 08/21/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 case 'k': 123 while (isascii(*++p) && isspace(*p)) 124 continue; 125 map->map_keycolnm = p; 126 break; 127 128 case 'v': 129 while (isascii(*++p) && isspace(*p)) 130 continue; 131 map->map_valcolnm = p; 132 break; 133 134 case 'z': 135 if (*++p != '\\') 136 map->map_coldelim = *p; 137 else 138 { 139 switch (*++p) 140 { 141 case 'n': 142 map->map_coldelim = '\n'; 143 break; 144 145 case 't': 146 map->map_coldelim = '\t'; 147 break; 148 149 default: 150 map->map_coldelim = '\\'; 151 } 152 } 153 break; 154 } 155 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 156 p++; 157 if (*p != '\0') 158 *p++ = '\0'; 159 } 160 if (map->map_app != NULL) 161 map->map_app = newstr(map->map_app); 162 if (map->map_keycolnm != NULL) 163 map->map_keycolnm = newstr(map->map_keycolnm); 164 if (map->map_valcolnm != NULL) 165 map->map_valcolnm = newstr(map->map_valcolnm); 166 167 if (*p != '\0') 168 { 169 map->map_file = p; 170 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 171 p++; 172 if (*p != '\0') 173 *p++ = '\0'; 174 map->map_file = newstr(map->map_file); 175 } 176 177 while (*p != '\0' && isascii(*p) && isspace(*p)) 178 p++; 179 if (*p != '\0') 180 map->map_rebuild = newstr(p); 181 182 if (map->map_file == NULL) 183 { 184 syserr("No file name for %s map %s", 185 map->map_class->map_cname, map->map_mname); 186 return FALSE; 187 } 188 return TRUE; 189 } 190 /* 191 ** MAP_REWRITE -- rewrite a database key, interpolating %n indications. 192 ** 193 ** It also adds the map_app string. It can be used as a utility 194 ** in the map_lookup method. 195 ** 196 ** Parameters: 197 ** map -- the map that causes this. 198 ** s -- the string to rewrite, NOT necessarily null terminated. 199 ** slen -- the length of s. 200 ** av -- arguments to interpolate into buf. 201 ** 202 ** Returns: 203 ** Pointer to rewritten result. 204 ** 205 ** Side Effects: 206 ** none. 207 */ 208 209 struct rwbuf 210 { 211 int rwb_len; /* size of buffer */ 212 char *rwb_buf; /* ptr to buffer */ 213 }; 214 215 struct rwbuf RwBufs[2]; /* buffers for rewriting output */ 216 217 char * 218 map_rewrite(map, s, slen, av) 219 register MAP *map; 220 register char *s; 221 int slen; 222 char **av; 223 { 224 register char *bp; 225 register char c; 226 char **avp; 227 register char *ap; 228 register struct rwbuf *rwb; 229 int i; 230 int len; 231 232 if (tTd(39, 1)) 233 { 234 printf("map_rewrite(%.*s), av =", slen, s); 235 if (av == NULL) 236 printf(" (nullv)"); 237 else 238 { 239 for (avp = av; *avp != NULL; avp++) 240 printf("\n\t%s", *avp); 241 } 242 printf("\n"); 243 } 244 245 rwb = RwBufs; 246 if (av == NULL) 247 rwb++; 248 249 /* count expected size of output (can safely overestimate) */ 250 i = len = slen; 251 if (av != NULL) 252 { 253 bp = s; 254 for (i = slen; --i >= 0 && (c = *bp++) != 0; ) 255 { 256 if (c != '%') 257 continue; 258 if (--i < 0) 259 break; 260 c = *bp++; 261 if (!(isascii(c) && isdigit(c))) 262 continue; 263 for (avp = av; --c >= '0' && *avp != NULL; avp++) 264 continue; 265 if (*avp == NULL) 266 continue; 267 len += strlen(*avp); 268 } 269 } 270 if (map->map_app != NULL) 271 len += strlen(map->map_app); 272 if (rwb->rwb_len < ++len) 273 { 274 /* need to malloc additional space */ 275 rwb->rwb_len = len; 276 if (rwb->rwb_buf != NULL) 277 free(rwb->rwb_buf); 278 rwb->rwb_buf = xalloc(rwb->rwb_len); 279 } 280 281 bp = rwb->rwb_buf; 282 if (av == NULL) 283 { 284 bcopy(s, bp, slen); 285 bp += slen; 286 } 287 else 288 { 289 while (--slen >= 0 && (c = *s++) != '\0') 290 { 291 if (c != '%') 292 { 293 pushc: 294 *bp++ = c; 295 continue; 296 } 297 if (--slen < 0 || (c = *s++) == '\0') 298 c = '%'; 299 if (c == '%') 300 goto pushc; 301 if (!(isascii(c) && isdigit(c))) 302 { 303 *bp++ = '%'; 304 goto pushc; 305 } 306 for (avp = av; --c >= '0' && *avp != NULL; avp++) 307 continue; 308 if (*avp == NULL) 309 continue; 310 311 /* transliterate argument into output string */ 312 for (ap = *avp; (c = *ap++) != '\0'; ) 313 *bp++ = c; 314 } 315 } 316 if (map->map_app != NULL) 317 strcpy(bp, map->map_app); 318 else 319 *bp = '\0'; 320 if (tTd(39, 1)) 321 printf("map_rewrite => %s\n", rwb->rwb_buf); 322 return rwb->rwb_buf; 323 } 324 /* 325 ** INITMAPS -- initialize for aliasing 326 ** 327 ** Parameters: 328 ** rebuild -- if TRUE, this rebuilds the cached versions. 329 ** e -- current envelope. 330 ** 331 ** Returns: 332 ** none. 333 ** 334 ** Side Effects: 335 ** initializes aliases: 336 ** if NDBM: opens the database. 337 ** if ~NDBM: reads the aliases into the symbol table. 338 */ 339 340 initmaps(rebuild, e) 341 bool rebuild; 342 register ENVELOPE *e; 343 { 344 extern void map_init(); 345 346 #ifdef XDEBUG 347 checkfd012("entering initmaps"); 348 #endif 349 CurEnv = e; 350 if (rebuild) 351 { 352 stabapply(map_init, 1); 353 stabapply(map_init, 2); 354 } 355 else 356 { 357 stabapply(map_init, 0); 358 } 359 #ifdef XDEBUG 360 checkfd012("exiting initmaps"); 361 #endif 362 } 363 364 void 365 map_init(s, rebuild) 366 register STAB *s; 367 int rebuild; 368 { 369 register MAP *map; 370 371 /* has to be a map */ 372 if (s->s_type != ST_MAP) 373 return; 374 375 map = &s->s_map; 376 if (!bitset(MF_VALID, map->map_mflags)) 377 return; 378 379 if (tTd(38, 2)) 380 printf("map_init(%s:%s, %s, %d)\n", 381 map->map_class->map_cname == NULL ? "NULL" : 382 map->map_class->map_cname, 383 map->map_mname == NULL ? "NULL" : map->map_mname, 384 map->map_file == NULL ? "NULL" : map->map_file, 385 rebuild); 386 387 if (rebuild == (bitset(MF_ALIAS, map->map_mflags) && 388 bitset(MCF_REBUILDABLE, map->map_class->map_cflags) ? 1 : 2)) 389 { 390 if (tTd(38, 3)) 391 printf("\twrong pass\n"); 392 return; 393 } 394 395 /* if already open, close it (for nested open) */ 396 if (bitset(MF_OPEN, map->map_mflags)) 397 { 398 map->map_class->map_close(map); 399 map->map_mflags &= ~(MF_OPEN|MF_WRITABLE); 400 } 401 402 if (rebuild == 2) 403 { 404 rebuildaliases(map, FALSE); 405 } 406 else 407 { 408 if (map->map_class->map_open(map, O_RDONLY)) 409 { 410 if (tTd(38, 4)) 411 printf("\t%s:%s %s: valid\n", 412 map->map_class->map_cname == NULL ? "NULL" : 413 map->map_class->map_cname, 414 map->map_mname == NULL ? "NULL" : 415 map->map_mname, 416 map->map_file == NULL ? "NULL" : 417 map->map_file); 418 map->map_mflags |= MF_OPEN; 419 } 420 else if (tTd(38, 4)) 421 printf("\t%s:%s %s: invalid: %s\n", 422 map->map_class->map_cname == NULL ? "NULL" : 423 map->map_class->map_cname, 424 map->map_mname == NULL ? "NULL" : 425 map->map_mname, 426 map->map_file == NULL ? "NULL" : 427 map->map_file, 428 errstring(errno)); 429 } 430 } 431 /* 432 ** NDBM modules 433 */ 434 435 #ifdef NDBM 436 437 /* 438 ** DBM_MAP_OPEN -- DBM-style map open 439 */ 440 441 bool 442 ndbm_map_open(map, mode) 443 MAP *map; 444 int mode; 445 { 446 register DBM *dbm; 447 struct stat st; 448 449 if (tTd(38, 2)) 450 printf("ndbm_map_open(%s, %s, %d)\n", 451 map->map_mname, map->map_file, mode); 452 453 if (mode == O_RDWR) 454 mode |= O_CREAT|O_TRUNC; 455 456 /* open the database */ 457 dbm = dbm_open(map->map_file, mode, DBMMODE); 458 if (dbm == NULL) 459 { 460 #ifdef MAYBENEXTRELEASE 461 if (aliaswait(map, ".pag", FALSE)) 462 return TRUE; 463 #endif 464 if (!bitset(MF_OPTIONAL, map->map_mflags)) 465 syserr("Cannot open DBM database %s", map->map_file); 466 return FALSE; 467 } 468 map->map_db1 = (void *) dbm; 469 if (mode == O_RDONLY) 470 { 471 if (bitset(MF_ALIAS, map->map_mflags) && 472 !aliaswait(map, ".pag", TRUE)) 473 return FALSE; 474 } 475 else 476 { 477 int fd; 478 479 /* exclusive lock for duration of rebuild */ 480 fd = dbm_dirfno((DBM *) map->map_db1); 481 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags) && 482 lockfile(fd, map->map_file, ".dir", LOCK_EX)) 483 map->map_mflags |= MF_LOCKED; 484 } 485 if (fstat(dbm_dirfno((DBM *) map->map_db1), &st) >= 0) 486 map->map_mtime = st.st_mtime; 487 return TRUE; 488 } 489 490 491 /* 492 ** DBM_MAP_LOOKUP -- look up a datum in a DBM-type map 493 */ 494 495 char * 496 ndbm_map_lookup(map, name, av, statp) 497 MAP *map; 498 char *name; 499 char **av; 500 int *statp; 501 { 502 datum key, val; 503 int fd; 504 char keybuf[MAXNAME + 1]; 505 506 if (tTd(38, 20)) 507 printf("ndbm_map_lookup(%s, %s)\n", 508 map->map_mname, name); 509 510 key.dptr = name; 511 key.dsize = strlen(name); 512 if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 513 { 514 if (key.dsize > sizeof keybuf - 1) 515 key.dsize = sizeof keybuf - 1; 516 bcopy(key.dptr, keybuf, key.dsize + 1); 517 makelower(keybuf); 518 key.dptr = keybuf; 519 } 520 fd = dbm_dirfno((DBM *) map->map_db1); 521 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 522 (void) lockfile(fd, map->map_file, ".dir", LOCK_SH); 523 val.dptr = NULL; 524 if (bitset(MF_TRY0NULL, map->map_mflags)) 525 { 526 val = dbm_fetch((DBM *) map->map_db1, key); 527 if (val.dptr != NULL) 528 map->map_mflags &= ~MF_TRY1NULL; 529 } 530 if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags)) 531 { 532 key.dsize++; 533 val = dbm_fetch((DBM *) map->map_db1, key); 534 if (val.dptr != NULL) 535 map->map_mflags &= ~MF_TRY0NULL; 536 } 537 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 538 (void) lockfile(fd, map->map_file, ".dir", LOCK_UN); 539 if (val.dptr == NULL) 540 return NULL; 541 if (bitset(MF_MATCHONLY, map->map_mflags)) 542 return map_rewrite(map, name, strlen(name), NULL); 543 else 544 return map_rewrite(map, val.dptr, val.dsize, av); 545 } 546 547 548 /* 549 ** DBM_MAP_STORE -- store a datum in the database 550 */ 551 552 void 553 ndbm_map_store(map, lhs, rhs) 554 register MAP *map; 555 char *lhs; 556 char *rhs; 557 { 558 datum key; 559 datum data; 560 int stat; 561 562 if (tTd(38, 12)) 563 printf("ndbm_map_store(%s, %s, %s)\n", 564 map->map_mname, lhs, rhs); 565 566 key.dsize = strlen(lhs); 567 key.dptr = lhs; 568 569 data.dsize = strlen(rhs); 570 data.dptr = rhs; 571 572 if (bitset(MF_INCLNULL, map->map_mflags)) 573 { 574 key.dsize++; 575 data.dsize++; 576 } 577 578 stat = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT); 579 if (stat > 0) 580 { 581 usrerr("050 Warning: duplicate alias name %s", lhs); 582 stat = dbm_store((DBM *) map->map_db1, key, data, DBM_REPLACE); 583 } 584 if (stat != 0) 585 syserr("readaliases: dbm put (%s)", lhs); 586 } 587 588 589 /* 590 ** NDBM_MAP_CLOSE -- close the database 591 */ 592 593 void 594 ndbm_map_close(map) 595 register MAP *map; 596 { 597 if (tTd(38, 9)) 598 printf("ndbm_map_close(%s, %s, %x)\n", 599 map->map_mname, map->map_file, map->map_mflags); 600 601 if (bitset(MF_WRITABLE, map->map_mflags)) 602 { 603 #ifdef NIS 604 bool inclnull; 605 char buf[200]; 606 607 inclnull = bitset(MF_INCLNULL, map->map_mflags); 608 map->map_mflags &= ~MF_INCLNULL; 609 610 (void) sprintf(buf, "%010ld", curtime()); 611 ndbm_map_store(map, "YP_LAST_MODIFIED", buf); 612 613 (void) gethostname(buf, sizeof buf); 614 ndbm_map_store(map, "YP_MASTER_NAME", buf); 615 616 if (inclnull) 617 map->map_mflags |= MF_INCLNULL; 618 #endif 619 620 /* write out the distinguished alias */ 621 ndbm_map_store(map, "@", "@"); 622 } 623 dbm_close((DBM *) map->map_db1); 624 } 625 626 #endif 627 /* 628 ** NEWDB (Hash and BTree) Modules 629 */ 630 631 #ifdef NEWDB 632 633 /* 634 ** BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives. 635 ** 636 ** These do rather bizarre locking. If you can lock on open, 637 ** do that to avoid the condition of opening a database that 638 ** is being rebuilt. If you don't, we'll try to fake it, but 639 ** there will be a race condition. If opening for read-only, 640 ** we immediately release the lock to avoid freezing things up. 641 ** We really ought to hold the lock, but guarantee that we won't 642 ** be pokey about it. That's hard to do. 643 */ 644 645 bool 646 bt_map_open(map, mode) 647 MAP *map; 648 int mode; 649 { 650 DB *db; 651 int i; 652 int omode; 653 int fd; 654 struct stat st; 655 char buf[MAXNAME]; 656 657 if (tTd(38, 2)) 658 printf("bt_map_open(%s, %s, %d)\n", 659 map->map_mname, map->map_file, mode); 660 661 omode = mode; 662 if (omode == O_RDWR) 663 { 664 omode |= O_CREAT|O_TRUNC; 665 #if defined(O_EXLOCK) && HASFLOCK 666 omode |= O_EXLOCK; 667 # if !OLD_NEWDB 668 } 669 else 670 { 671 omode |= O_SHLOCK; 672 # endif 673 #endif 674 } 675 676 (void) strcpy(buf, map->map_file); 677 i = strlen(buf); 678 if (i < 3 || strcmp(&buf[i - 3], ".db") != 0) 679 (void) strcat(buf, ".db"); 680 db = dbopen(buf, omode, DBMMODE, DB_BTREE, NULL); 681 if (db == NULL) 682 { 683 #ifdef MAYBENEXTRELEASE 684 if (aliaswait(map, ".db", FALSE)) 685 return TRUE; 686 #endif 687 if (!bitset(MF_OPTIONAL, map->map_mflags)) 688 syserr("Cannot open BTREE database %s", map->map_file); 689 return FALSE; 690 } 691 #if !OLD_NEWDB 692 fd = db->fd(db); 693 # if HASFLOCK 694 # if !defined(O_EXLOCK) 695 if (mode == O_RDWR && fd >= 0) 696 { 697 if (lockfile(fd, map->map_file, ".db", LOCK_EX)) 698 map->map_mflags |= MF_LOCKED; 699 } 700 # else 701 if (mode == O_RDONLY && fd >= 0) 702 (void) lockfile(fd, map->map_file, ".db", LOCK_UN); 703 else 704 map->map_mflags |= MF_LOCKED; 705 # endif 706 # endif 707 #endif 708 709 /* try to make sure that at least the database header is on disk */ 710 if (mode == O_RDWR) 711 #if OLD_NEWDB 712 (void) db->sync(db); 713 #else 714 (void) db->sync(db, 0); 715 716 if (fd >= 0 && fstat(fd, &st) >= 0) 717 map->map_mtime = st.st_mtime; 718 #endif 719 720 map->map_db2 = (void *) db; 721 if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags)) 722 if (!aliaswait(map, ".db", TRUE)) 723 return FALSE; 724 return TRUE; 725 } 726 727 728 /* 729 ** HASH_MAP_INIT -- HASH-style map initialization 730 */ 731 732 bool 733 hash_map_open(map, mode) 734 MAP *map; 735 int mode; 736 { 737 DB *db; 738 int i; 739 int omode; 740 int fd; 741 struct stat st; 742 char buf[MAXNAME]; 743 744 if (tTd(38, 2)) 745 printf("hash_map_open(%s, %s, %d)\n", 746 map->map_mname, map->map_file, mode); 747 748 omode = mode; 749 if (omode == O_RDWR) 750 { 751 omode |= O_CREAT|O_TRUNC; 752 #if defined(O_EXLOCK) && HASFLOCK 753 omode |= O_EXLOCK; 754 # if !OLD_NEWDB 755 } 756 else 757 { 758 omode |= O_SHLOCK; 759 # endif 760 #endif 761 } 762 763 (void) strcpy(buf, map->map_file); 764 i = strlen(buf); 765 if (i < 3 || strcmp(&buf[i - 3], ".db") != 0) 766 (void) strcat(buf, ".db"); 767 db = dbopen(buf, omode, DBMMODE, DB_HASH, NULL); 768 if (db == NULL) 769 { 770 #ifdef MAYBENEXTRELEASE 771 if (aliaswait(map, ".db", FALSE)) 772 return TRUE; 773 #endif 774 if (!bitset(MF_OPTIONAL, map->map_mflags)) 775 syserr("Cannot open HASH database %s", map->map_file); 776 return FALSE; 777 } 778 #if !OLD_NEWDB 779 fd = db->fd(db); 780 # if HASFLOCK 781 # if !defined(O_EXLOCK) 782 if (mode == O_RDWR && fd >= 0) 783 { 784 if (lockfile(fd, map->map_file, ".db", LOCK_EX)) 785 map->map_mflags |= MF_LOCKED; 786 } 787 # else 788 if (mode == O_RDONLY && fd >= 0) 789 (void) lockfile(fd, map->map_file, ".db", LOCK_UN); 790 else 791 map->map_mflags |= MF_LOCKED; 792 # endif 793 # endif 794 #endif 795 796 /* try to make sure that at least the database header is on disk */ 797 if (mode == O_RDWR) 798 #if OLD_NEWDB 799 (void) db->sync(db); 800 #else 801 (void) db->sync(db, 0); 802 803 if (fd >= 0 && fstat(fd, &st) >= 0) 804 map->map_mtime = st.st_mtime; 805 #endif 806 807 map->map_db2 = (void *) db; 808 if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags)) 809 if (!aliaswait(map, ".db", TRUE)) 810 return FALSE; 811 return TRUE; 812 } 813 814 815 /* 816 ** DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map 817 */ 818 819 char * 820 db_map_lookup(map, name, av, statp) 821 MAP *map; 822 char *name; 823 char **av; 824 int *statp; 825 { 826 DBT key, val; 827 register DB *db = (DB *) map->map_db2; 828 int st; 829 int saveerrno; 830 int fd; 831 char keybuf[MAXNAME + 1]; 832 833 if (tTd(38, 20)) 834 printf("db_map_lookup(%s, %s)\n", 835 map->map_mname, name); 836 837 key.size = strlen(name); 838 if (key.size > sizeof keybuf - 1) 839 key.size = sizeof keybuf - 1; 840 key.data = keybuf; 841 bcopy(name, keybuf, key.size + 1); 842 if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 843 makelower(keybuf); 844 #if !OLD_NEWDB 845 fd = db->fd(db); 846 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 847 (void) lockfile(db->fd(db), map->map_file, ".db", LOCK_SH); 848 #endif 849 st = 1; 850 if (bitset(MF_TRY0NULL, map->map_mflags)) 851 { 852 st = db->get(db, &key, &val, 0); 853 if (st == 0) 854 map->map_mflags &= ~MF_TRY1NULL; 855 } 856 if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags)) 857 { 858 key.size++; 859 st = db->get(db, &key, &val, 0); 860 if (st == 0) 861 map->map_mflags &= ~MF_TRY0NULL; 862 } 863 saveerrno = errno; 864 #if !OLD_NEWDB 865 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 866 (void) lockfile(fd, map->map_file, ".db", LOCK_UN); 867 #endif 868 if (st != 0) 869 { 870 errno = saveerrno; 871 if (st < 0) 872 syserr("db_map_lookup: get (%s)", name); 873 return NULL; 874 } 875 if (bitset(MF_MATCHONLY, map->map_mflags)) 876 return map_rewrite(map, name, strlen(name), NULL); 877 else 878 return map_rewrite(map, val.data, val.size, av); 879 } 880 881 882 /* 883 ** DB_MAP_STORE -- store a datum in the NEWDB database 884 */ 885 886 void 887 db_map_store(map, lhs, rhs) 888 register MAP *map; 889 char *lhs; 890 char *rhs; 891 { 892 int stat; 893 DBT key; 894 DBT data; 895 register DB *db = map->map_db2; 896 897 if (tTd(38, 20)) 898 printf("db_map_store(%s, %s, %s)\n", 899 map->map_mname, lhs, rhs); 900 901 key.size = strlen(lhs); 902 key.data = lhs; 903 904 data.size = strlen(rhs); 905 data.data = rhs; 906 907 if (bitset(MF_INCLNULL, map->map_mflags)) 908 { 909 key.size++; 910 data.size++; 911 } 912 913 stat = db->put(db, &key, &data, R_NOOVERWRITE); 914 if (stat > 0) 915 { 916 usrerr("050 Warning: duplicate alias name %s", lhs); 917 stat = db->put(db, &key, &data, 0); 918 } 919 if (stat != 0) 920 syserr("readaliases: db put (%s)", lhs); 921 } 922 923 924 /* 925 ** DB_MAP_CLOSE -- add distinguished entries and close the database 926 */ 927 928 void 929 db_map_close(map) 930 MAP *map; 931 { 932 register DB *db = map->map_db2; 933 934 if (tTd(38, 9)) 935 printf("db_map_close(%s, %s, %x)\n", 936 map->map_mname, map->map_file, map->map_mflags); 937 938 if (bitset(MF_WRITABLE, map->map_mflags)) 939 { 940 /* write out the distinguished alias */ 941 db_map_store(map, "@", "@"); 942 } 943 944 if (db->close(db) != 0) 945 syserr("readaliases: db close failure"); 946 } 947 948 #endif 949 /* 950 ** NIS Modules 951 */ 952 953 # ifdef NIS 954 955 # ifndef YPERR_BUSY 956 # define YPERR_BUSY 16 957 # endif 958 959 /* 960 ** NIS_MAP_OPEN -- open DBM map 961 */ 962 963 bool 964 nis_map_open(map, mode) 965 MAP *map; 966 int mode; 967 { 968 int yperr; 969 register char *p; 970 auto char *vp; 971 auto int vsize; 972 char *master; 973 974 if (tTd(38, 2)) 975 printf("nis_map_open(%s, %s)\n", 976 map->map_mname, map->map_file); 977 978 if (mode != O_RDONLY) 979 { 980 /* issue a pseudo-error message */ 981 #ifdef ENOSYS 982 errno = ENOSYS; 983 #else 984 # ifdef EFTYPE 985 errno = EFTYPE; 986 # else 987 errno = ENXIO; 988 # endif 989 #endif 990 return FALSE; 991 } 992 993 p = strchr(map->map_file, '@'); 994 if (p != NULL) 995 { 996 *p++ = '\0'; 997 if (*p != '\0') 998 map->map_domain = p; 999 } 1000 1001 if (*map->map_file == '\0') 1002 map->map_file = "mail.aliases"; 1003 1004 if (map->map_domain == NULL) 1005 { 1006 yperr = yp_get_default_domain(&map->map_domain); 1007 if (yperr != 0) 1008 { 1009 if (!bitset(MF_OPTIONAL, map->map_mflags)) 1010 syserr("NIS map %s specified, but NIS not running\n", 1011 map->map_file); 1012 return FALSE; 1013 } 1014 } 1015 1016 /* check to see if this map actually exists */ 1017 yperr = yp_match(map->map_domain, map->map_file, "@", 1, 1018 &vp, &vsize); 1019 if (tTd(38, 10)) 1020 printf("nis_map_open: yp_match(%s, %s) => %s\n", 1021 map->map_domain, map->map_file, yperr_string(yperr)); 1022 if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY) 1023 return TRUE; 1024 1025 if (!bitset(MF_OPTIONAL, map->map_mflags)) 1026 syserr("Cannot bind to domain %s: %s", map->map_domain, 1027 yperr_string(yperr)); 1028 1029 return FALSE; 1030 } 1031 1032 1033 /* 1034 ** NIS_MAP_LOOKUP -- look up a datum in a NIS map 1035 */ 1036 1037 char * 1038 nis_map_lookup(map, name, av, statp) 1039 MAP *map; 1040 char *name; 1041 char **av; 1042 int *statp; 1043 { 1044 char *vp; 1045 auto int vsize; 1046 int buflen; 1047 int yperr; 1048 char keybuf[MAXNAME + 1]; 1049 1050 if (tTd(38, 20)) 1051 printf("nis_map_lookup(%s, %s)\n", 1052 map->map_mname, name); 1053 1054 buflen = strlen(name); 1055 if (buflen > sizeof keybuf - 1) 1056 buflen = sizeof keybuf - 1; 1057 bcopy(name, keybuf, buflen + 1); 1058 if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 1059 makelower(keybuf); 1060 yperr = YPERR_KEY; 1061 if (bitset(MF_TRY0NULL, map->map_mflags)) 1062 { 1063 yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen, 1064 &vp, &vsize); 1065 if (yperr == 0) 1066 map->map_mflags &= ~MF_TRY1NULL; 1067 } 1068 if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags)) 1069 { 1070 buflen++; 1071 yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen, 1072 &vp, &vsize); 1073 if (yperr == 0) 1074 map->map_mflags &= ~MF_TRY0NULL; 1075 } 1076 if (yperr != 0) 1077 { 1078 if (yperr != YPERR_KEY && yperr != YPERR_BUSY) 1079 map->map_mflags &= ~(MF_VALID|MF_OPEN); 1080 return NULL; 1081 } 1082 if (bitset(MF_MATCHONLY, map->map_mflags)) 1083 return map_rewrite(map, name, strlen(name), NULL); 1084 else 1085 return map_rewrite(map, vp, vsize, av); 1086 } 1087 1088 #endif 1089 /* 1090 ** STAB (Symbol Table) Modules 1091 */ 1092 1093 1094 /* 1095 ** STAB_MAP_LOOKUP -- look up alias in symbol table 1096 */ 1097 1098 char * 1099 stab_map_lookup(map, name, av, pstat) 1100 register MAP *map; 1101 char *name; 1102 char **av; 1103 int *pstat; 1104 { 1105 register STAB *s; 1106 1107 if (tTd(38, 20)) 1108 printf("stab_lookup(%s, %s)\n", 1109 map->map_mname, name); 1110 1111 s = stab(name, ST_ALIAS, ST_FIND); 1112 if (s != NULL) 1113 return (s->s_alias); 1114 return (NULL); 1115 } 1116 1117 1118 /* 1119 ** STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild) 1120 */ 1121 1122 void 1123 stab_map_store(map, lhs, rhs) 1124 register MAP *map; 1125 char *lhs; 1126 char *rhs; 1127 { 1128 register STAB *s; 1129 1130 s = stab(lhs, ST_ALIAS, ST_ENTER); 1131 s->s_alias = newstr(rhs); 1132 } 1133 1134 1135 /* 1136 ** STAB_MAP_OPEN -- initialize (reads data file) 1137 ** 1138 ** This is a wierd case -- it is only intended as a fallback for 1139 ** aliases. For this reason, opens for write (only during a 1140 ** "newaliases") always fails, and opens for read open the 1141 ** actual underlying text file instead of the database. 1142 */ 1143 1144 bool 1145 stab_map_open(map, mode) 1146 register MAP *map; 1147 int mode; 1148 { 1149 FILE *af; 1150 struct stat st; 1151 1152 if (tTd(38, 2)) 1153 printf("stab_map_open(%s, %s)\n", 1154 map->map_mname, map->map_file); 1155 1156 if (mode != O_RDONLY) 1157 { 1158 errno = ENODEV; 1159 return FALSE; 1160 } 1161 1162 af = fopen(map->map_file, "r"); 1163 if (af == NULL) 1164 return FALSE; 1165 readaliases(map, af, FALSE, FALSE); 1166 1167 if (fstat(fileno(af), &st) >= 0) 1168 map->map_mtime = st.st_mtime; 1169 fclose(af); 1170 1171 return TRUE; 1172 } 1173 /* 1174 ** Implicit Modules 1175 ** 1176 ** Tries several types. For back compatibility of aliases. 1177 */ 1178 1179 1180 /* 1181 ** IMPL_MAP_LOOKUP -- lookup in best open database 1182 */ 1183 1184 char * 1185 impl_map_lookup(map, name, av, pstat) 1186 MAP *map; 1187 char *name; 1188 char **av; 1189 int *pstat; 1190 { 1191 if (tTd(38, 20)) 1192 printf("impl_map_lookup(%s, %s)\n", 1193 map->map_mname, name); 1194 1195 #ifdef NEWDB 1196 if (bitset(MF_IMPL_HASH, map->map_mflags)) 1197 return db_map_lookup(map, name, av, pstat); 1198 #endif 1199 #ifdef NDBM 1200 if (bitset(MF_IMPL_NDBM, map->map_mflags)) 1201 return ndbm_map_lookup(map, name, av, pstat); 1202 #endif 1203 return stab_map_lookup(map, name, av, pstat); 1204 } 1205 1206 /* 1207 ** IMPL_MAP_STORE -- store in open databases 1208 */ 1209 1210 void 1211 impl_map_store(map, lhs, rhs) 1212 MAP *map; 1213 char *lhs; 1214 char *rhs; 1215 { 1216 #ifdef NEWDB 1217 if (bitset(MF_IMPL_HASH, map->map_mflags)) 1218 db_map_store(map, lhs, rhs); 1219 #endif 1220 #ifdef NDBM 1221 if (bitset(MF_IMPL_NDBM, map->map_mflags)) 1222 ndbm_map_store(map, lhs, rhs); 1223 #endif 1224 stab_map_store(map, lhs, rhs); 1225 } 1226 1227 /* 1228 ** IMPL_MAP_OPEN -- implicit database open 1229 */ 1230 1231 bool 1232 impl_map_open(map, mode) 1233 MAP *map; 1234 int mode; 1235 { 1236 struct stat stb; 1237 1238 if (tTd(38, 2)) 1239 printf("impl_map_open(%s, %s, %d)\n", 1240 map->map_mname, map->map_file, mode); 1241 1242 if (stat(map->map_file, &stb) < 0) 1243 { 1244 /* no alias file at all */ 1245 if (tTd(38, 3)) 1246 printf("no map file\n"); 1247 return FALSE; 1248 } 1249 1250 #ifdef NEWDB 1251 map->map_mflags |= MF_IMPL_HASH; 1252 if (hash_map_open(map, mode)) 1253 { 1254 #if defined(NDBM) && defined(NIS) 1255 if (mode == O_RDONLY || access("/var/yp/Makefile", R_OK) != 0) 1256 #endif 1257 return TRUE; 1258 } 1259 else 1260 map->map_mflags &= ~MF_IMPL_HASH; 1261 #endif 1262 #ifdef NDBM 1263 map->map_mflags |= MF_IMPL_NDBM; 1264 if (ndbm_map_open(map, mode)) 1265 { 1266 return TRUE; 1267 } 1268 else 1269 map->map_mflags &= ~MF_IMPL_NDBM; 1270 #endif 1271 1272 #if defined(NEWDB) || defined(NDBM) 1273 if (Verbose) 1274 message("WARNING: cannot open alias database %s", map->map_file); 1275 #else 1276 if (mode != O_RDONLY) 1277 usrerr("Cannot rebuild aliases: no database format defined"); 1278 #endif 1279 1280 return stab_map_open(map, mode); 1281 } 1282 1283 1284 /* 1285 ** IMPL_MAP_CLOSE -- close any open database(s) 1286 */ 1287 1288 void 1289 impl_map_close(map) 1290 MAP *map; 1291 { 1292 #ifdef NEWDB 1293 if (bitset(MF_IMPL_HASH, map->map_mflags)) 1294 { 1295 db_map_close(map); 1296 map->map_mflags &= ~MF_IMPL_HASH; 1297 } 1298 #endif 1299 1300 #ifdef NDBM 1301 if (bitset(MF_IMPL_NDBM, map->map_mflags)) 1302 { 1303 ndbm_map_close(map); 1304 map->map_mflags &= ~MF_IMPL_NDBM; 1305 } 1306 #endif 1307 } 1308 /* 1309 ** User map class. 1310 ** 1311 ** Provides access to the system password file. 1312 */ 1313 1314 /* 1315 ** USER_MAP_OPEN -- open user map 1316 ** 1317 ** Really just binds field names to field numbers. 1318 */ 1319 1320 bool 1321 user_map_open(map, mode) 1322 MAP *map; 1323 int mode; 1324 { 1325 if (tTd(38, 2)) 1326 printf("user_map_open(%s)\n", map->map_mname); 1327 1328 if (mode != O_RDONLY) 1329 { 1330 /* issue a pseudo-error message */ 1331 #ifdef ENOSYS 1332 errno = ENOSYS; 1333 #else 1334 # ifdef EFTYPE 1335 errno = EFTYPE; 1336 # else 1337 errno = ENXIO; 1338 # endif 1339 #endif 1340 return FALSE; 1341 } 1342 if (map->map_valcolnm == NULL) 1343 /* nothing */ ; 1344 else if (strcasecmp(map->map_valcolnm, "name") == 0) 1345 map->map_valcolno = 1; 1346 else if (strcasecmp(map->map_valcolnm, "passwd") == 0) 1347 map->map_valcolno = 2; 1348 else if (strcasecmp(map->map_valcolnm, "uid") == 0) 1349 map->map_valcolno = 3; 1350 else if (strcasecmp(map->map_valcolnm, "gid") == 0) 1351 map->map_valcolno = 4; 1352 else if (strcasecmp(map->map_valcolnm, "gecos") == 0) 1353 map->map_valcolno = 5; 1354 else if (strcasecmp(map->map_valcolnm, "dir") == 0) 1355 map->map_valcolno = 6; 1356 else if (strcasecmp(map->map_valcolnm, "shell") == 0) 1357 map->map_valcolno = 7; 1358 else 1359 { 1360 syserr("User map %s: unknown column name %s", 1361 map->map_mname, map->map_valcolnm); 1362 return FALSE; 1363 } 1364 return TRUE; 1365 } 1366 1367 1368 /* 1369 ** USER_MAP_LOOKUP -- look up a user in the passwd file. 1370 */ 1371 1372 #include <pwd.h> 1373 1374 char * 1375 user_map_lookup(map, key, av, statp) 1376 MAP *map; 1377 char *key; 1378 char **av; 1379 int *statp; 1380 { 1381 struct passwd *pw; 1382 1383 if (tTd(38, 20)) 1384 printf("user_map_lookup(%s, %s)\n", 1385 map->map_mname, key); 1386 1387 pw = getpwnam(key); 1388 if (pw == NULL) 1389 return NULL; 1390 if (bitset(MF_MATCHONLY, map->map_mflags)) 1391 return map_rewrite(map, key, strlen(key), NULL); 1392 else 1393 { 1394 char *rwval; 1395 char buf[30]; 1396 1397 switch (map->map_valcolno) 1398 { 1399 case 0: 1400 case 1: 1401 rwval = key; 1402 break; 1403 1404 case 2: 1405 rwval = pw->pw_passwd; 1406 break; 1407 1408 case 3: 1409 sprintf(buf, "%d", pw->pw_uid); 1410 rwval = buf; 1411 break; 1412 1413 case 4: 1414 sprintf(buf, "%d", pw->pw_gid); 1415 rwval = buf; 1416 break; 1417 1418 case 5: 1419 rwval = pw->pw_gecos; 1420 break; 1421 1422 case 6: 1423 rwval = pw->pw_dir; 1424 break; 1425 1426 case 7: 1427 rwval = pw->pw_shell; 1428 break; 1429 } 1430 return map_rewrite(map, rwval, strlen(rwval), av); 1431 } 1432 } 1433 /* 1434 ** Sequenced map type. 1435 ** 1436 ** Tries each map in order until something matches, much like 1437 ** implicit. Stores go to the first map in the list that can 1438 ** support storing. 1439 */ 1440 1441 /* 1442 ** SEQ_MAP_PARSE -- Sequenced map parsing 1443 */ 1444 1445 bool 1446 seq_map_parse(map, ap) 1447 MAP *map; 1448 char *ap; 1449 { 1450 int maxmap; 1451 1452 if (tTd(38, 2)) 1453 printf("seq_map_parse(%s, %s)\n", map->map_mname, ap); 1454 maxmap = 0; 1455 while (*ap != '\0') 1456 { 1457 register char *p; 1458 STAB *s; 1459 1460 /* find beginning of map name */ 1461 while (isascii(*ap) && isspace(*ap)) 1462 ap++; 1463 for (p = ap; isascii(*p) && isalnum(*p); p++) 1464 continue; 1465 if (*p != '\0') 1466 *p++ = '\0'; 1467 while (*p != '\0' && (!isascii(*p) || !isalnum(*p))) 1468 p++; 1469 if (*ap == '\0') 1470 { 1471 ap = p; 1472 continue; 1473 } 1474 s = stab(ap, ST_MAP, ST_FIND); 1475 if (s == NULL) 1476 { 1477 syserr("Sequence map %s: unknown member map %s", 1478 map->map_mname, ap); 1479 } 1480 else if (maxmap == MAXMAPSTACK) 1481 { 1482 syserr("Sequence map %s: too many member maps (%d max)", 1483 map->map_mname, MAXMAPSTACK); 1484 maxmap++; 1485 } 1486 else if (maxmap < MAXMAPSTACK) 1487 { 1488 map->map_stack[maxmap++] = &s->s_map; 1489 } 1490 ap = p; 1491 } 1492 return TRUE; 1493 } 1494 1495 1496 /* 1497 ** SEQ_MAP_LOOKUP -- sequenced map lookup 1498 */ 1499 1500 char * 1501 seq_map_lookup(map, key, args, pstat) 1502 MAP *map; 1503 char *key; 1504 char **args; 1505 int *pstat; 1506 { 1507 int mapno; 1508 int mapbit = 0x01; 1509 1510 if (tTd(38, 20)) 1511 printf("seq_map_lookup(%s, %s)\n", map->map_mname, key); 1512 1513 for (mapno = 0; mapno < MAXMAPSTACK; mapbit <<= 1, mapno++) 1514 { 1515 MAP *mm = map->map_stack[mapno]; 1516 int stat = 0; 1517 char *rv; 1518 1519 if (mm == NULL) 1520 continue; 1521 if (!bitset(MF_OPEN, mm->map_mflags)) 1522 { 1523 if (bitset(mapbit, map->map_return[MA_UNAVAIL])) 1524 return NULL; 1525 continue; 1526 } 1527 rv = mm->map_class->map_lookup(mm, key, args, &stat); 1528 if (rv != NULL) 1529 return rv; 1530 if (stat == 0 && bitset(mapbit, map->map_return[MA_NOTFOUND])) 1531 return NULL; 1532 if (stat != 0 && bitset(mapbit, map->map_return[MA_TRYAGAIN])) 1533 { 1534 *pstat = stat; 1535 return NULL; 1536 } 1537 } 1538 return NULL; 1539 } 1540 1541 1542 /* 1543 ** SEQ_MAP_STORE -- sequenced map store 1544 */ 1545 1546 void 1547 seq_map_store(map, key, val) 1548 MAP *map; 1549 char *key; 1550 char *val; 1551 { 1552 int mapno; 1553 1554 if (tTd(38, 12)) 1555 printf("seq_map_store(%s, %s, %s)\n", 1556 map->map_mname, key, val); 1557 1558 for (mapno = 0; mapno < MAXMAPSTACK; mapno++) 1559 { 1560 MAP *mm = map->map_stack[mapno]; 1561 1562 if (mm == NULL || !bitset(MF_WRITABLE, mm->map_mflags)) 1563 continue; 1564 1565 mm->map_class->map_store(mm, key, val); 1566 return; 1567 } 1568 syserr("seq_map_store(%s, %s, %s): no writable map", 1569 map->map_mname, key, val); 1570 } 1571 /* 1572 ** NULL stubs 1573 */ 1574 1575 bool 1576 null_map_open(map, mode) 1577 MAP *map; 1578 int mode; 1579 { 1580 return TRUE; 1581 } 1582 1583 void 1584 null_map_close(map) 1585 MAP *map; 1586 { 1587 return; 1588 } 1589 1590 void 1591 null_map_store(map, key, val) 1592 MAP *map; 1593 char *key; 1594 char *val; 1595 { 1596 return; 1597 } 1598