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.54 (Berkeley) 04/11/95"; 11 #endif /* not lint */ 12 13 #include "sendmail.h" 14 15 #ifdef NDBM 16 # include <ndbm.h> 17 #endif 18 #ifdef NEWDB 19 # include <db.h> 20 #endif 21 #ifdef NIS 22 struct dom_binding { int dummy; }; /* needed on IRIX */ 23 # include <rpcsvc/ypclnt.h> 24 #endif 25 26 /* 27 ** MAP.C -- implementations for various map classes. 28 ** 29 ** Each map class implements a series of functions: 30 ** 31 ** bool map_parse(MAP *map, char *args) 32 ** Parse the arguments from the config file. Return TRUE 33 ** if they were ok, FALSE otherwise. Fill in map with the 34 ** values. 35 ** 36 ** char *map_lookup(MAP *map, char *key, char **args, int *pstat) 37 ** Look up the key in the given map. If found, do any 38 ** rewriting the map wants (including "args" if desired) 39 ** and return the value. Set *pstat to the appropriate status 40 ** on error and return NULL. Args will be NULL if called 41 ** from the alias routines, although this should probably 42 ** not be relied upon. It is suggested you call map_rewrite 43 ** to return the results -- it takes care of null termination 44 ** and uses a dynamically expanded buffer as needed. 45 ** 46 ** void map_store(MAP *map, char *key, char *value) 47 ** Store the key:value pair in the map. 48 ** 49 ** bool map_open(MAP *map, int mode) 50 ** Open the map for the indicated mode. Mode should 51 ** be either O_RDONLY or O_RDWR. Return TRUE if it 52 ** was opened successfully, FALSE otherwise. If the open 53 ** failed an the MF_OPTIONAL flag is not set, it should 54 ** also print an error. If the MF_ALIAS bit is set 55 ** and this map class understands the @:@ convention, it 56 ** should call aliaswait() before returning. 57 ** 58 ** void map_close(MAP *map) 59 ** Close the map. 60 */ 61 62 #define DBMMODE 0644 63 64 extern bool aliaswait __P((MAP *, char *, int)); 65 /* 66 ** MAP_PARSEARGS -- parse config line arguments for database lookup 67 ** 68 ** This is a generic version of the map_parse method. 69 ** 70 ** Parameters: 71 ** map -- the map being initialized. 72 ** ap -- a pointer to the args on the config line. 73 ** 74 ** Returns: 75 ** TRUE -- if everything parsed OK. 76 ** FALSE -- otherwise. 77 ** 78 ** Side Effects: 79 ** null terminates the filename; stores it in map 80 */ 81 82 bool 83 map_parseargs(map, ap) 84 MAP *map; 85 char *ap; 86 { 87 register char *p = ap; 88 89 map->map_mflags |= MF_TRY0NULL | MF_TRY1NULL; 90 for (;;) 91 { 92 while (isascii(*p) && isspace(*p)) 93 p++; 94 if (*p != '-') 95 break; 96 switch (*++p) 97 { 98 case 'N': 99 map->map_mflags |= MF_INCLNULL; 100 map->map_mflags &= ~MF_TRY0NULL; 101 break; 102 103 case 'O': 104 map->map_mflags &= ~MF_TRY1NULL; 105 break; 106 107 case 'o': 108 map->map_mflags |= MF_OPTIONAL; 109 break; 110 111 case 'f': 112 map->map_mflags |= MF_NOFOLDCASE; 113 break; 114 115 case 'm': 116 map->map_mflags |= MF_MATCHONLY; 117 break; 118 119 case 'A': 120 map->map_mflags |= MF_APPEND; 121 break; 122 123 case 'a': 124 map->map_app = ++p; 125 break; 126 127 case 'k': 128 while (isascii(*++p) && isspace(*p)) 129 continue; 130 map->map_keycolnm = p; 131 break; 132 133 case 'v': 134 while (isascii(*++p) && isspace(*p)) 135 continue; 136 map->map_valcolnm = p; 137 break; 138 139 case 'z': 140 if (*++p != '\\') 141 map->map_coldelim = *p; 142 else 143 { 144 switch (*++p) 145 { 146 case 'n': 147 map->map_coldelim = '\n'; 148 break; 149 150 case 't': 151 map->map_coldelim = '\t'; 152 break; 153 154 default: 155 map->map_coldelim = '\\'; 156 } 157 } 158 break; 159 #ifdef RESERVED_FOR_SUN 160 case 'd': 161 map->map_mflags |= MF_DOMAIN_WIDE; 162 break; 163 164 case 's': 165 /* info type */ 166 break; 167 #endif 168 } 169 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 170 p++; 171 if (*p != '\0') 172 *p++ = '\0'; 173 } 174 if (map->map_app != NULL) 175 map->map_app = newstr(map->map_app); 176 if (map->map_keycolnm != NULL) 177 map->map_keycolnm = newstr(map->map_keycolnm); 178 if (map->map_valcolnm != NULL) 179 map->map_valcolnm = newstr(map->map_valcolnm); 180 181 if (*p != '\0') 182 { 183 map->map_file = p; 184 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 185 p++; 186 if (*p != '\0') 187 *p++ = '\0'; 188 map->map_file = newstr(map->map_file); 189 } 190 191 while (*p != '\0' && isascii(*p) && isspace(*p)) 192 p++; 193 if (*p != '\0') 194 map->map_rebuild = newstr(p); 195 196 if (map->map_file == NULL && 197 !bitset(MCF_OPTFILE, map->map_class->map_cflags)) 198 { 199 syserr("No file name for %s map %s", 200 map->map_class->map_cname, map->map_mname); 201 return FALSE; 202 } 203 return TRUE; 204 } 205 /* 206 ** MAP_REWRITE -- rewrite a database key, interpolating %n indications. 207 ** 208 ** It also adds the map_app string. It can be used as a utility 209 ** in the map_lookup method. 210 ** 211 ** Parameters: 212 ** map -- the map that causes this. 213 ** s -- the string to rewrite, NOT necessarily null terminated. 214 ** slen -- the length of s. 215 ** av -- arguments to interpolate into buf. 216 ** 217 ** Returns: 218 ** Pointer to rewritten result. This is static data that 219 ** should be copied if it is to be saved! 220 ** 221 ** Side Effects: 222 ** none. 223 */ 224 225 char * 226 map_rewrite(map, s, slen, av) 227 register MAP *map; 228 register char *s; 229 int slen; 230 char **av; 231 { 232 register char *bp; 233 register char c; 234 char **avp; 235 register char *ap; 236 int i; 237 int len; 238 static int buflen = -1; 239 static char *buf = NULL; 240 241 if (tTd(39, 1)) 242 { 243 printf("map_rewrite(%.*s), av =", slen, s); 244 if (av == NULL) 245 printf(" (nullv)"); 246 else 247 { 248 for (avp = av; *avp != NULL; avp++) 249 printf("\n\t%s", *avp); 250 } 251 printf("\n"); 252 } 253 254 /* count expected size of output (can safely overestimate) */ 255 i = len = slen; 256 if (av != NULL) 257 { 258 bp = s; 259 for (i = slen; --i >= 0 && (c = *bp++) != 0; ) 260 { 261 if (c != '%') 262 continue; 263 if (--i < 0) 264 break; 265 c = *bp++; 266 if (!(isascii(c) && isdigit(c))) 267 continue; 268 for (avp = av; --c >= '0' && *avp != NULL; avp++) 269 continue; 270 if (*avp == NULL) 271 continue; 272 len += strlen(*avp); 273 } 274 } 275 if (map->map_app != NULL) 276 len += strlen(map->map_app); 277 if (buflen < ++len) 278 { 279 /* need to malloc additional space */ 280 buflen = len; 281 if (buf != NULL) 282 free(buf); 283 buf = xalloc(buflen); 284 } 285 286 bp = buf; 287 if (av == NULL) 288 { 289 bcopy(s, bp, slen); 290 bp += slen; 291 } 292 else 293 { 294 while (--slen >= 0 && (c = *s++) != '\0') 295 { 296 if (c != '%') 297 { 298 pushc: 299 *bp++ = c; 300 continue; 301 } 302 if (--slen < 0 || (c = *s++) == '\0') 303 c = '%'; 304 if (c == '%') 305 goto pushc; 306 if (!(isascii(c) && isdigit(c))) 307 { 308 *bp++ = '%'; 309 goto pushc; 310 } 311 for (avp = av; --c >= '0' && *avp != NULL; avp++) 312 continue; 313 if (*avp == NULL) 314 continue; 315 316 /* transliterate argument into output string */ 317 for (ap = *avp; (c = *ap++) != '\0'; ) 318 *bp++ = c; 319 } 320 } 321 if (map->map_app != NULL) 322 strcpy(bp, map->map_app); 323 else 324 *bp = '\0'; 325 if (tTd(39, 1)) 326 printf("map_rewrite => %s\n", buf); 327 return buf; 328 } 329 /* 330 ** INITMAPS -- initialize for aliasing 331 ** 332 ** Parameters: 333 ** rebuild -- if TRUE, this rebuilds the cached versions. 334 ** e -- current envelope. 335 ** 336 ** Returns: 337 ** none. 338 ** 339 ** Side Effects: 340 ** initializes aliases: 341 ** if NDBM: opens the database. 342 ** if ~NDBM: reads the aliases into the symbol table. 343 */ 344 345 initmaps(rebuild, e) 346 bool rebuild; 347 register ENVELOPE *e; 348 { 349 extern void map_init(); 350 351 #ifdef XDEBUG 352 checkfd012("entering initmaps"); 353 #endif 354 CurEnv = e; 355 if (rebuild) 356 { 357 stabapply(map_init, 1); 358 stabapply(map_init, 2); 359 } 360 else 361 { 362 stabapply(map_init, 0); 363 } 364 #ifdef XDEBUG 365 checkfd012("exiting initmaps"); 366 #endif 367 } 368 369 void 370 map_init(s, rebuild) 371 register STAB *s; 372 int rebuild; 373 { 374 register MAP *map; 375 376 /* has to be a map */ 377 if (s->s_type != ST_MAP) 378 return; 379 380 map = &s->s_map; 381 if (!bitset(MF_VALID, map->map_mflags)) 382 return; 383 384 if (tTd(38, 2)) 385 printf("map_init(%s:%s, %s, %d)\n", 386 map->map_class->map_cname == NULL ? "NULL" : 387 map->map_class->map_cname, 388 map->map_mname == NULL ? "NULL" : map->map_mname, 389 map->map_file == NULL ? "NULL" : map->map_file, 390 rebuild); 391 392 if (rebuild == (bitset(MF_ALIAS, map->map_mflags) && 393 bitset(MCF_REBUILDABLE, map->map_class->map_cflags) ? 1 : 2)) 394 { 395 if (tTd(38, 3)) 396 printf("\twrong pass\n"); 397 return; 398 } 399 400 /* if already open, close it (for nested open) */ 401 if (bitset(MF_OPEN, map->map_mflags)) 402 { 403 map->map_class->map_close(map); 404 map->map_mflags &= ~(MF_OPEN|MF_WRITABLE); 405 } 406 407 if (rebuild == 2) 408 { 409 rebuildaliases(map, FALSE); 410 } 411 else 412 { 413 if (map->map_class->map_open(map, O_RDONLY)) 414 { 415 if (tTd(38, 4)) 416 printf("\t%s:%s %s: valid\n", 417 map->map_class->map_cname == NULL ? "NULL" : 418 map->map_class->map_cname, 419 map->map_mname == NULL ? "NULL" : 420 map->map_mname, 421 map->map_file == NULL ? "NULL" : 422 map->map_file); 423 map->map_mflags |= MF_OPEN; 424 } 425 else 426 { 427 if (tTd(38, 4)) 428 printf("\t%s:%s %s: invalid: %s\n", 429 map->map_class->map_cname == NULL ? "NULL" : 430 map->map_class->map_cname, 431 map->map_mname == NULL ? "NULL" : 432 map->map_mname, 433 map->map_file == NULL ? "NULL" : 434 map->map_file, 435 errstring(errno)); 436 if (!bitset(MF_OPTIONAL, map->map_mflags)) 437 { 438 extern MAPCLASS BogusMapClass; 439 440 map->map_class = &BogusMapClass; 441 map->map_mflags |= MF_OPEN; 442 } 443 } 444 } 445 } 446 /* 447 ** NDBM modules 448 */ 449 450 #ifdef NDBM 451 452 /* 453 ** DBM_MAP_OPEN -- DBM-style map open 454 */ 455 456 bool 457 ndbm_map_open(map, mode) 458 MAP *map; 459 int mode; 460 { 461 register DBM *dbm; 462 struct stat st; 463 464 if (tTd(38, 2)) 465 printf("ndbm_map_open(%s, %s, %d)\n", 466 map->map_mname, map->map_file, mode); 467 468 if (mode == O_RDWR) 469 mode |= O_CREAT|O_TRUNC; 470 471 /* open the database */ 472 dbm = dbm_open(map->map_file, mode, DBMMODE); 473 if (dbm == NULL) 474 { 475 if (aliaswait(map, ".pag", FALSE)) 476 return TRUE; 477 if (!bitset(MF_OPTIONAL, map->map_mflags)) 478 syserr("Cannot open DBM database %s", map->map_file); 479 return FALSE; 480 } 481 map->map_db1 = (void *) dbm; 482 if (mode == O_RDONLY) 483 { 484 if (bitset(MF_ALIAS, map->map_mflags) && 485 !aliaswait(map, ".pag", TRUE)) 486 return FALSE; 487 } 488 else 489 { 490 int fd; 491 492 /* exclusive lock for duration of rebuild */ 493 fd = dbm_dirfno((DBM *) map->map_db1); 494 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags) && 495 lockfile(fd, map->map_file, ".dir", LOCK_EX)) 496 map->map_mflags |= MF_LOCKED; 497 } 498 if (fstat(dbm_dirfno((DBM *) map->map_db1), &st) >= 0) 499 map->map_mtime = st.st_mtime; 500 return TRUE; 501 } 502 503 504 /* 505 ** DBM_MAP_LOOKUP -- look up a datum in a DBM-type map 506 */ 507 508 char * 509 ndbm_map_lookup(map, name, av, statp) 510 MAP *map; 511 char *name; 512 char **av; 513 int *statp; 514 { 515 datum key, val; 516 int fd; 517 char keybuf[MAXNAME + 1]; 518 519 if (tTd(38, 20)) 520 printf("ndbm_map_lookup(%s, %s)\n", 521 map->map_mname, name); 522 523 key.dptr = name; 524 key.dsize = strlen(name); 525 if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 526 { 527 if (key.dsize > sizeof keybuf - 1) 528 key.dsize = sizeof keybuf - 1; 529 bcopy(key.dptr, keybuf, key.dsize + 1); 530 makelower(keybuf); 531 key.dptr = keybuf; 532 } 533 fd = dbm_dirfno((DBM *) map->map_db1); 534 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 535 (void) lockfile(fd, map->map_file, ".dir", LOCK_SH); 536 val.dptr = NULL; 537 if (bitset(MF_TRY0NULL, map->map_mflags)) 538 { 539 val = dbm_fetch((DBM *) map->map_db1, key); 540 if (val.dptr != NULL) 541 map->map_mflags &= ~MF_TRY1NULL; 542 } 543 if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags)) 544 { 545 key.dsize++; 546 val = dbm_fetch((DBM *) map->map_db1, key); 547 if (val.dptr != NULL) 548 map->map_mflags &= ~MF_TRY0NULL; 549 } 550 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 551 (void) lockfile(fd, map->map_file, ".dir", LOCK_UN); 552 if (val.dptr == NULL) 553 return NULL; 554 if (bitset(MF_MATCHONLY, map->map_mflags)) 555 return map_rewrite(map, name, strlen(name), NULL); 556 else 557 return map_rewrite(map, val.dptr, val.dsize, av); 558 } 559 560 561 /* 562 ** DBM_MAP_STORE -- store a datum in the database 563 */ 564 565 void 566 ndbm_map_store(map, lhs, rhs) 567 register MAP *map; 568 char *lhs; 569 char *rhs; 570 { 571 datum key; 572 datum data; 573 int stat; 574 575 if (tTd(38, 12)) 576 printf("ndbm_map_store(%s, %s, %s)\n", 577 map->map_mname, lhs, rhs); 578 579 key.dsize = strlen(lhs); 580 key.dptr = lhs; 581 582 data.dsize = strlen(rhs); 583 data.dptr = rhs; 584 585 if (bitset(MF_INCLNULL, map->map_mflags)) 586 { 587 key.dsize++; 588 data.dsize++; 589 } 590 591 stat = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT); 592 if (stat > 0) 593 { 594 if (!bitset(MF_APPEND, map->map_mflags)) 595 usrerr("050 Warning: duplicate alias name %s", lhs); 596 else 597 { 598 static char *buf = NULL; 599 static int bufsiz = 0; 600 datum old; 601 602 old.dptr = ndbm_map_lookup(map, key.dptr, NULL); 603 if (old.dptr != NULL && *old.dptr != '\0') 604 { 605 old.dsize = strlen(old.dptr); 606 if (data.dsize + old.dsize + 2 > bufsiz) 607 { 608 if (buf != NULL) 609 (void) free(buf); 610 bufsiz = data.dsize + old.dsize + 2; 611 buf = xalloc(bufsiz); 612 } 613 sprintf(buf, "%s,%s", data.dptr, old.dptr); 614 data.dsize = data.dsize + old.dsize + 1; 615 data.dptr = buf; 616 if (tTd(38, 9)) 617 printf("ndbm_map_store append=%s\n", data.dptr); 618 } 619 } 620 stat = dbm_store((DBM *) map->map_db1, key, data, DBM_REPLACE); 621 } 622 if (stat != 0) 623 syserr("readaliases: dbm put (%s)", lhs); 624 } 625 626 627 /* 628 ** NDBM_MAP_CLOSE -- close the database 629 */ 630 631 void 632 ndbm_map_close(map) 633 register MAP *map; 634 { 635 if (tTd(38, 9)) 636 printf("ndbm_map_close(%s, %s, %x)\n", 637 map->map_mname, map->map_file, map->map_mflags); 638 639 if (bitset(MF_WRITABLE, map->map_mflags)) 640 { 641 #ifdef NIS 642 bool inclnull; 643 char buf[200]; 644 645 inclnull = bitset(MF_INCLNULL, map->map_mflags); 646 map->map_mflags &= ~MF_INCLNULL; 647 648 (void) sprintf(buf, "%010ld", curtime()); 649 ndbm_map_store(map, "YP_LAST_MODIFIED", buf); 650 651 (void) gethostname(buf, sizeof buf); 652 ndbm_map_store(map, "YP_MASTER_NAME", buf); 653 654 if (inclnull) 655 map->map_mflags |= MF_INCLNULL; 656 #endif 657 658 /* write out the distinguished alias */ 659 ndbm_map_store(map, "@", "@"); 660 } 661 dbm_close((DBM *) map->map_db1); 662 } 663 664 #endif 665 /* 666 ** NEWDB (Hash and BTree) Modules 667 */ 668 669 #ifdef NEWDB 670 671 /* 672 ** BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives. 673 ** 674 ** These do rather bizarre locking. If you can lock on open, 675 ** do that to avoid the condition of opening a database that 676 ** is being rebuilt. If you don't, we'll try to fake it, but 677 ** there will be a race condition. If opening for read-only, 678 ** we immediately release the lock to avoid freezing things up. 679 ** We really ought to hold the lock, but guarantee that we won't 680 ** be pokey about it. That's hard to do. 681 */ 682 683 bool 684 bt_map_open(map, mode) 685 MAP *map; 686 int mode; 687 { 688 DB *db; 689 int i; 690 int omode; 691 int fd; 692 struct stat st; 693 char buf[MAXNAME + 1]; 694 695 if (tTd(38, 2)) 696 printf("bt_map_open(%s, %s, %d)\n", 697 map->map_mname, map->map_file, mode); 698 699 omode = mode; 700 if (omode == O_RDWR) 701 { 702 omode |= O_CREAT|O_TRUNC; 703 #if defined(O_EXLOCK) && HASFLOCK 704 omode |= O_EXLOCK; 705 # if !OLD_NEWDB 706 } 707 else 708 { 709 omode |= O_SHLOCK; 710 # endif 711 #endif 712 } 713 714 (void) strcpy(buf, map->map_file); 715 i = strlen(buf); 716 if (i < 3 || strcmp(&buf[i - 3], ".db") != 0) 717 (void) strcat(buf, ".db"); 718 db = dbopen(buf, omode, DBMMODE, DB_BTREE, NULL); 719 if (db == NULL) 720 { 721 #ifdef MAYBENEXTRELEASE 722 if (aliaswait(map, ".db", FALSE)) 723 return TRUE; 724 #endif 725 if (!bitset(MF_OPTIONAL, map->map_mflags)) 726 syserr("Cannot open BTREE database %s", map->map_file); 727 return FALSE; 728 } 729 #if !OLD_NEWDB 730 fd = db->fd(db); 731 # if defined(O_EXLOCK) && HASFLOCK 732 if (fd >= 0) 733 { 734 if (mode == O_RDONLY) 735 (void) lockfile(fd, map->map_file, ".db", LOCK_UN); 736 else 737 map->map_mflags |= MF_LOCKED; 738 } 739 # else 740 if (mode == O_RDWR && fd >= 0) 741 { 742 if (lockfile(fd, map->map_file, ".db", LOCK_EX)) 743 map->map_mflags |= MF_LOCKED; 744 } 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 ** HASH_MAP_INIT -- HASH-style map initialization 769 */ 770 771 bool 772 hash_map_open(map, mode) 773 MAP *map; 774 int mode; 775 { 776 DB *db; 777 int i; 778 int omode; 779 int fd; 780 struct stat st; 781 char buf[MAXNAME + 1]; 782 783 if (tTd(38, 2)) 784 printf("hash_map_open(%s, %s, %d)\n", 785 map->map_mname, map->map_file, mode); 786 787 omode = mode; 788 if (omode == O_RDWR) 789 { 790 omode |= O_CREAT|O_TRUNC; 791 #if defined(O_EXLOCK) && HASFLOCK 792 omode |= O_EXLOCK; 793 # if !OLD_NEWDB 794 } 795 else 796 { 797 omode |= O_SHLOCK; 798 # endif 799 #endif 800 } 801 802 (void) strcpy(buf, map->map_file); 803 i = strlen(buf); 804 if (i < 3 || strcmp(&buf[i - 3], ".db") != 0) 805 (void) strcat(buf, ".db"); 806 db = dbopen(buf, omode, DBMMODE, DB_HASH, NULL); 807 if (db == NULL) 808 { 809 #ifdef MAYBENEXTRELEASE 810 if (aliaswait(map, ".db", FALSE)) 811 return TRUE; 812 #endif 813 if (!bitset(MF_OPTIONAL, map->map_mflags)) 814 syserr("Cannot open HASH database %s", map->map_file); 815 return FALSE; 816 } 817 #if !OLD_NEWDB 818 fd = db->fd(db); 819 # if defined(O_EXLOCK) && HASFLOCK 820 if (fd >= 0) 821 { 822 if (mode == O_RDONLY) 823 (void) lockfile(fd, map->map_file, ".db", LOCK_UN); 824 else 825 map->map_mflags |= MF_LOCKED; 826 } 827 # else 828 if (mode == O_RDWR && fd >= 0) 829 { 830 if (lockfile(fd, map->map_file, ".db", LOCK_EX)) 831 map->map_mflags |= MF_LOCKED; 832 } 833 # endif 834 #endif 835 836 /* try to make sure that at least the database header is on disk */ 837 if (mode == O_RDWR) 838 #if OLD_NEWDB 839 (void) db->sync(db); 840 #else 841 (void) db->sync(db, 0); 842 843 if (fd >= 0 && fstat(fd, &st) >= 0) 844 map->map_mtime = st.st_mtime; 845 #endif 846 847 map->map_db2 = (void *) db; 848 if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags)) 849 if (!aliaswait(map, ".db", TRUE)) 850 return FALSE; 851 return TRUE; 852 } 853 854 855 /* 856 ** DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map 857 */ 858 859 char * 860 db_map_lookup(map, name, av, statp) 861 MAP *map; 862 char *name; 863 char **av; 864 int *statp; 865 { 866 DBT key, val; 867 register DB *db = (DB *) map->map_db2; 868 int st; 869 int saveerrno; 870 int fd; 871 char keybuf[MAXNAME + 1]; 872 873 if (tTd(38, 20)) 874 printf("db_map_lookup(%s, %s)\n", 875 map->map_mname, name); 876 877 key.size = strlen(name); 878 if (key.size > sizeof keybuf - 1) 879 key.size = sizeof keybuf - 1; 880 key.data = keybuf; 881 bcopy(name, keybuf, key.size + 1); 882 if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 883 makelower(keybuf); 884 #if !OLD_NEWDB 885 fd = db->fd(db); 886 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 887 (void) lockfile(db->fd(db), map->map_file, ".db", LOCK_SH); 888 #endif 889 st = 1; 890 if (bitset(MF_TRY0NULL, map->map_mflags)) 891 { 892 st = db->get(db, &key, &val, 0); 893 if (st == 0) 894 map->map_mflags &= ~MF_TRY1NULL; 895 } 896 if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags)) 897 { 898 key.size++; 899 st = db->get(db, &key, &val, 0); 900 if (st == 0) 901 map->map_mflags &= ~MF_TRY0NULL; 902 } 903 saveerrno = errno; 904 #if !OLD_NEWDB 905 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 906 (void) lockfile(fd, map->map_file, ".db", LOCK_UN); 907 #endif 908 if (st != 0) 909 { 910 errno = saveerrno; 911 if (st < 0) 912 syserr("db_map_lookup: get (%s)", name); 913 return NULL; 914 } 915 if (bitset(MF_MATCHONLY, map->map_mflags)) 916 return map_rewrite(map, name, strlen(name), NULL); 917 else 918 return map_rewrite(map, val.data, val.size, av); 919 } 920 921 922 /* 923 ** DB_MAP_STORE -- store a datum in the NEWDB database 924 */ 925 926 void 927 db_map_store(map, lhs, rhs) 928 register MAP *map; 929 char *lhs; 930 char *rhs; 931 { 932 int stat; 933 DBT key; 934 DBT data; 935 register DB *db = map->map_db2; 936 937 if (tTd(38, 20)) 938 printf("db_map_store(%s, %s, %s)\n", 939 map->map_mname, lhs, rhs); 940 941 key.size = strlen(lhs); 942 key.data = lhs; 943 944 data.size = strlen(rhs); 945 data.data = rhs; 946 947 if (bitset(MF_INCLNULL, map->map_mflags)) 948 { 949 key.size++; 950 data.size++; 951 } 952 953 stat = db->put(db, &key, &data, R_NOOVERWRITE); 954 if (stat > 0) 955 { 956 if (!bitset(MF_APPEND, map->map_mflags)) 957 usrerr("050 Warning: duplicate alias name %s", lhs); 958 else 959 { 960 static char *buf = NULL; 961 static int bufsiz = 0; 962 DBT old; 963 964 old.data = db_map_lookup(map, key.data, NULL, &stat); 965 if (old.data != NULL) 966 { 967 old.size = strlen(old.data); 968 if (data.size + old.size + 2 > bufsiz) 969 { 970 if (buf != NULL) 971 (void) free(buf); 972 bufsiz = data.size + old.size + 2; 973 buf = xalloc(bufsiz); 974 } 975 sprintf(buf, "%s,%s", data.data, old.data); 976 data.size = data.size + old.size + 1; 977 data.data = buf; 978 if (tTd(38, 9)) 979 printf("db_map_store append=%s\n", data.data); 980 } 981 } 982 stat = db->put(db, &key, &data, 0); 983 } 984 if (stat != 0) 985 syserr("readaliases: db put (%s)", lhs); 986 } 987 988 989 /* 990 ** DB_MAP_CLOSE -- add distinguished entries and close the database 991 */ 992 993 void 994 db_map_close(map) 995 MAP *map; 996 { 997 register DB *db = map->map_db2; 998 999 if (tTd(38, 9)) 1000 printf("db_map_close(%s, %s, %x)\n", 1001 map->map_mname, map->map_file, map->map_mflags); 1002 1003 if (bitset(MF_WRITABLE, map->map_mflags)) 1004 { 1005 /* write out the distinguished alias */ 1006 db_map_store(map, "@", "@"); 1007 } 1008 1009 if (db->close(db) != 0) 1010 syserr("readaliases: db close failure"); 1011 } 1012 1013 #endif 1014 /* 1015 ** NIS Modules 1016 */ 1017 1018 # ifdef NIS 1019 1020 # ifndef YPERR_BUSY 1021 # define YPERR_BUSY 16 1022 # endif 1023 1024 /* 1025 ** NIS_MAP_OPEN -- open DBM map 1026 */ 1027 1028 bool 1029 nis_map_open(map, mode) 1030 MAP *map; 1031 int mode; 1032 { 1033 int yperr; 1034 register char *p; 1035 auto char *vp; 1036 auto int vsize; 1037 char *master; 1038 1039 if (tTd(38, 2)) 1040 printf("nis_map_open(%s, %s)\n", 1041 map->map_mname, map->map_file); 1042 1043 if (mode != O_RDONLY) 1044 { 1045 /* issue a pseudo-error message */ 1046 #ifdef ENOSYS 1047 errno = ENOSYS; 1048 #else 1049 # ifdef EFTYPE 1050 errno = EFTYPE; 1051 # else 1052 errno = ENXIO; 1053 # endif 1054 #endif 1055 return FALSE; 1056 } 1057 1058 p = strchr(map->map_file, '@'); 1059 if (p != NULL) 1060 { 1061 *p++ = '\0'; 1062 if (*p != '\0') 1063 map->map_domain = p; 1064 } 1065 1066 if (*map->map_file == '\0') 1067 map->map_file = "mail.aliases"; 1068 1069 if (map->map_domain == NULL) 1070 { 1071 yperr = yp_get_default_domain(&map->map_domain); 1072 if (yperr != 0) 1073 { 1074 if (!bitset(MF_OPTIONAL, map->map_mflags)) 1075 syserr("421 NIS map %s specified, but NIS not running\n", 1076 map->map_file); 1077 return FALSE; 1078 } 1079 } 1080 1081 /* check to see if this map actually exists */ 1082 yperr = yp_match(map->map_domain, map->map_file, "@", 1, 1083 &vp, &vsize); 1084 if (tTd(38, 10)) 1085 printf("nis_map_open: yp_match(%s, %s) => %s\n", 1086 map->map_domain, map->map_file, yperr_string(yperr)); 1087 if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY) 1088 { 1089 if (!bitset(MF_ALIAS, map->map_mflags) || 1090 aliaswait(map, NULL, TRUE)) 1091 return TRUE; 1092 } 1093 1094 if (!bitset(MF_OPTIONAL, map->map_mflags)) 1095 { 1096 syserr("421 Cannot bind to map %s in domain %s: %s", 1097 map->map_file, map->map_domain, yperr_string(yperr)); 1098 } 1099 1100 return FALSE; 1101 } 1102 1103 1104 /* 1105 ** NIS_MAP_LOOKUP -- look up a datum in a NIS map 1106 */ 1107 1108 char * 1109 nis_map_lookup(map, name, av, statp) 1110 MAP *map; 1111 char *name; 1112 char **av; 1113 int *statp; 1114 { 1115 char *vp; 1116 auto int vsize; 1117 int buflen; 1118 int yperr; 1119 char keybuf[MAXNAME + 1]; 1120 1121 if (tTd(38, 20)) 1122 printf("nis_map_lookup(%s, %s)\n", 1123 map->map_mname, name); 1124 1125 buflen = strlen(name); 1126 if (buflen > sizeof keybuf - 1) 1127 buflen = sizeof keybuf - 1; 1128 bcopy(name, keybuf, buflen + 1); 1129 if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 1130 makelower(keybuf); 1131 yperr = YPERR_KEY; 1132 if (bitset(MF_TRY0NULL, map->map_mflags)) 1133 { 1134 yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen, 1135 &vp, &vsize); 1136 if (yperr == 0) 1137 map->map_mflags &= ~MF_TRY1NULL; 1138 } 1139 if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags)) 1140 { 1141 buflen++; 1142 yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen, 1143 &vp, &vsize); 1144 if (yperr == 0) 1145 map->map_mflags &= ~MF_TRY0NULL; 1146 } 1147 if (yperr != 0) 1148 { 1149 if (yperr != YPERR_KEY && yperr != YPERR_BUSY) 1150 map->map_mflags &= ~(MF_VALID|MF_OPEN); 1151 return NULL; 1152 } 1153 if (bitset(MF_MATCHONLY, map->map_mflags)) 1154 return map_rewrite(map, name, strlen(name), NULL); 1155 else 1156 return map_rewrite(map, vp, vsize, av); 1157 } 1158 1159 #endif 1160 /* 1161 ** NISPLUS Modules 1162 ** 1163 ** This code donated by Sun Microsystems. 1164 */ 1165 1166 #ifdef NISPLUS 1167 1168 #undef NIS /* symbol conflict in nis.h */ 1169 #include <rpcsvc/nis.h> 1170 #include <rpcsvc/nislib.h> 1171 1172 #define EN_col(col) zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val 1173 #define COL_NAME(res,i) ((res->objects.objects_val)->TA_data.ta_cols.ta_cols_val)[i].tc_name 1174 #define COL_MAX(res) ((res->objects.objects_val)->TA_data.ta_cols.ta_cols_len) 1175 #define PARTIAL_NAME(x) ((x)[strlen(x) - 1] != '.') 1176 1177 /* 1178 ** NISPLUS_MAP_OPEN -- open nisplus table 1179 */ 1180 1181 bool 1182 nisplus_map_open(map, mode) 1183 MAP *map; 1184 int mode; 1185 { 1186 register char *p; 1187 char qbuf[MAXLINE + NIS_MAXNAMELEN]; 1188 nis_result *res = NULL; 1189 u_int objs_len; 1190 nis_object *obj_ptr; 1191 int retry_cnt, max_col, i; 1192 1193 if (tTd(38, 2)) 1194 printf("nisplus_map_open(%s, %s, %d)\n", 1195 map->map_mname, map->map_file, mode); 1196 1197 if (mode != O_RDONLY) 1198 { 1199 errno = ENODEV; 1200 return FALSE; 1201 } 1202 1203 if (*map->map_file == '\0') 1204 map->map_file = "mail_aliases.org_dir"; 1205 1206 if (PARTIAL_NAME(map->map_file) && map->map_domain == NULL) 1207 { 1208 /* set default NISPLUS Domain to $m */ 1209 extern char *nisplus_default_domain(); 1210 1211 map->map_domain = newstr(nisplus_default_domain()); 1212 if (tTd(38, 2)) 1213 printf("nisplus_map_open(%s): using domain %s\n", 1214 map->map_file, map->map_domain); 1215 } 1216 if (!PARTIAL_NAME(map->map_file)) 1217 map->map_domain = newstr(""); 1218 1219 /* check to see if this map actually exists */ 1220 if (PARTIAL_NAME(map->map_file)) 1221 sprintf(qbuf, "%s.%s", map->map_file, map->map_domain); 1222 else 1223 strcpy(qbuf, map->map_file); 1224 1225 retry_cnt = 0; 1226 while (res == NULL || res->status != NIS_SUCCESS) 1227 { 1228 res = nis_lookup(qbuf, FOLLOW_LINKS); 1229 switch (res->status) 1230 { 1231 case NIS_SUCCESS: 1232 case NIS_TRYAGAIN: 1233 case NIS_RPCERROR: 1234 case NIS_NAMEUNREACHABLE: 1235 break; 1236 1237 default: /* all other nisplus errors */ 1238 #if 0 1239 if (!bitset(MF_OPTIONAL, map->map_mflags)) 1240 syserr("421 Cannot find table %s.%s: %s", 1241 map->map_file, map->map_domain, 1242 nis_sperrno(res->status)); 1243 #endif 1244 errno = EBADR; 1245 return FALSE; 1246 } 1247 sleep(2); /* try not to overwhelm hosed server */ 1248 if (retry_cnt++ > 4) 1249 { 1250 errno = EBADR; 1251 return FALSE; 1252 } 1253 } 1254 1255 if (NIS_RES_NUMOBJ(res) != 1 || 1256 (NIS_RES_OBJECT(res)->zo_data.zo_type != TABLE_OBJ)) 1257 { 1258 if (tTd(38, 10)) 1259 printf("nisplus_map_open: %s is not a table\n", qbuf); 1260 #if 0 1261 if (!bitset(MF_OPTIONAL, map->map_mflags)) 1262 syserr("421 %s.%s: %s is not a table", 1263 map->map_file, map->map_domain, 1264 nis_sperrno(res->status)); 1265 #endif 1266 errno = EBADR; 1267 return FALSE; 1268 } 1269 /* default key column is column 0 */ 1270 if (map->map_keycolnm == NULL) 1271 map->map_keycolnm = newstr(COL_NAME(res,0)); 1272 1273 max_col = COL_MAX(res); 1274 1275 /* verify the key column exist */ 1276 for (i=0; i< max_col; i++) 1277 { 1278 if (!strcmp(map->map_keycolnm, COL_NAME(res,i))) 1279 break; 1280 } 1281 if (i == max_col) 1282 { 1283 if (tTd(38, 2)) 1284 printf("nisplus_map_open(%s): can not find key column %s\n", 1285 map->map_file, map->map_keycolnm); 1286 errno = EBADR; 1287 return FALSE; 1288 } 1289 1290 /* default value column is the last column */ 1291 if (map->map_valcolnm == NULL) 1292 { 1293 map->map_valcolno = max_col - 1; 1294 return TRUE; 1295 } 1296 1297 for (i=0; i< max_col; i++) 1298 { 1299 if (strcmp(map->map_valcolnm, COL_NAME(res,i)) == 0) 1300 { 1301 map->map_valcolno = i; 1302 return TRUE; 1303 } 1304 } 1305 1306 if (tTd(38, 2)) 1307 printf("nisplus_map_open(%s): can not find column %s\n", 1308 map->map_file, map->map_keycolnm); 1309 errno = EBADR; 1310 return FALSE; 1311 } 1312 1313 1314 /* 1315 ** NISPLUS_MAP_LOOKUP -- look up a datum in a NISPLUS table 1316 */ 1317 1318 char * 1319 nisplus_map_lookup(map, name, av, statp) 1320 MAP *map; 1321 char *name; 1322 char **av; 1323 int *statp; 1324 { 1325 char *vp; 1326 auto int vsize; 1327 int buflen; 1328 char search_key[MAXNAME + 1]; 1329 char qbuf[MAXLINE + NIS_MAXNAMELEN]; 1330 nis_result *result; 1331 1332 if (tTd(38, 20)) 1333 printf("nisplus_map_lookup(%s, %s)\n", 1334 map->map_mname, name); 1335 1336 if (!bitset(MF_OPEN, map->map_mflags)) 1337 { 1338 if (nisplus_map_open(map, O_RDONLY)) 1339 map->map_mflags |= MF_OPEN; 1340 else 1341 { 1342 *statp = EX_UNAVAILABLE; 1343 return NULL; 1344 } 1345 } 1346 1347 buflen = strlen(name); 1348 if (buflen > sizeof search_key - 1) 1349 buflen = sizeof search_key - 1; 1350 bcopy(name, search_key, buflen + 1); 1351 if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 1352 makelower(search_key); 1353 1354 /* construct the query */ 1355 if (PARTIAL_NAME(map->map_file)) 1356 sprintf(qbuf, "[%s=%s],%s.%s", map->map_keycolnm, 1357 search_key, map->map_file, map->map_domain); 1358 else 1359 sprintf(qbuf, "[%s=%s],%s", map->map_keycolnm, 1360 search_key, map->map_file); 1361 1362 if (tTd(38, 20)) 1363 printf("qbuf=%s\n", qbuf); 1364 result = nis_list(qbuf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL); 1365 if (result->status == NIS_SUCCESS) 1366 { 1367 int count; 1368 char *str; 1369 1370 if ((count = NIS_RES_NUMOBJ(result)) != 1) 1371 { 1372 if (LogLevel > 10) 1373 syslog(LOG_WARNING, 1374 "%s:Lookup error, expected 1 entry, got (%d)", 1375 map->map_file, count); 1376 1377 /* ignore second entry */ 1378 if (tTd(38, 20)) 1379 printf("nisplus_map_lookup(%s), got %d entries, additional entries ignored\n", 1380 name, count); 1381 } 1382 1383 vp = ((NIS_RES_OBJECT(result))->EN_col(map->map_valcolno)); 1384 /* set the length of the result */ 1385 if (vp == NULL) 1386 vp = ""; 1387 vsize = strlen(vp); 1388 if (tTd(38, 20)) 1389 printf("nisplus_map_lookup(%s), found %s\n", 1390 name, vp); 1391 if (bitset(MF_MATCHONLY, map->map_mflags)) 1392 str = map_rewrite(map, name, strlen(name), NULL); 1393 else 1394 str = map_rewrite(map, vp, vsize, av); 1395 nis_freeresult(result); 1396 #ifdef MAP_EXIT_STAT 1397 *statp = EX_OK; 1398 #endif 1399 return str; 1400 } 1401 else 1402 { 1403 #ifdef MAP_EXIT_STAT 1404 if (result->status == NIS_NOTFOUND) 1405 *statp = EX_NOTFOUND; 1406 else if (result->status == NIS_TRYAGAIN) 1407 *statp = EX_TEMPFAIL; 1408 else 1409 { 1410 *statp = EX_UNAVAILABLE; 1411 map->map_mflags &= ~(MF_VALID|MF_OPEN); 1412 } 1413 #else 1414 if ((result->status != NIS_NOTFOUND) && 1415 (result->status != NIS_TRYAGAIN)) 1416 map->map_mflags &= ~(MF_VALID|MF_OPEN); 1417 #endif 1418 } 1419 if (tTd(38, 20)) 1420 printf("nisplus_map_lookup(%s), failed\n", name); 1421 nis_freeresult(result); 1422 return NULL; 1423 } 1424 1425 1426 char * 1427 nisplus_default_domain() 1428 { 1429 static char default_domain[MAXNAME + 1] = ""; 1430 char *p; 1431 1432 if (default_domain[0] != '\0') 1433 return(default_domain); 1434 1435 p = nis_local_directory(); 1436 strcpy(default_domain, p); 1437 return default_domain; 1438 } 1439 1440 #endif /* NISPLUS */ 1441 /* 1442 ** HESIOD Modules 1443 */ 1444 1445 #ifdef HESIOD 1446 1447 #include <hesiod.h> 1448 1449 char * 1450 hes_map_lookup(map, name, av, statp) 1451 MAP *map; 1452 char *name; 1453 char **av; 1454 int *statp; 1455 { 1456 char **hp; 1457 char *retdata = NULL; 1458 int i; 1459 1460 if (tTd(38, 20)) 1461 printf("hes_map_lookup(%s, %s)\n", map->map_file, name); 1462 1463 hp = hes_resolve(name, map->map_file); 1464 if (hp == NULL) 1465 return NULL; 1466 1467 if (hp[0] != NULL) 1468 { 1469 if (bitset(MF_MATCHONLY, map->map_mflags)) 1470 retdata = map_rewrite(map, name, strlen(name), NULL); 1471 else 1472 retdata = map_rewrite(map, hp[0], strlen(hp[0]), av); 1473 } 1474 1475 for (i = 0; hp[i] != NULL; i++) 1476 free(hp[i]); 1477 free(hp); 1478 return retdata; 1479 } 1480 1481 #endif 1482 /* 1483 ** NeXT NETINFO Modules 1484 */ 1485 1486 #ifdef NETINFO 1487 1488 #define NETINFO_DEFAULT_DIR "/aliases" 1489 #define NETINFO_DEFAULT_PROPERTY "members" 1490 1491 1492 /* 1493 ** NI_MAP_OPEN -- open NetInfo Aliases 1494 */ 1495 1496 bool 1497 ni_map_open(map, mode) 1498 MAP *map; 1499 int mode; 1500 { 1501 char *p; 1502 1503 if (tTd(38, 20)) 1504 printf("ni_map_open: %s\n", map->map_file); 1505 1506 if (*map->map_file == '\0') 1507 map->map_file = NETINFO_DEFAULT_DIR; 1508 1509 if (map->map_valcolnm == NULL) 1510 map->map_valcolnm = NETINFO_DEFAULT_PROPERTY; 1511 1512 if (map->map_coldelim == '\0' && bitset(MF_ALIAS, map->map_mflags)) 1513 map->map_coldelim = ','; 1514 1515 return TRUE; 1516 } 1517 1518 1519 /* 1520 ** NI_MAP_LOOKUP -- look up a datum in NetInfo 1521 */ 1522 1523 char * 1524 ni_map_lookup(map, name, av, statp) 1525 MAP *map; 1526 char *name; 1527 char **av; 1528 int *statp; 1529 { 1530 char *res; 1531 char *propval; 1532 extern char *ni_propval(); 1533 1534 if (tTd(38, 20)) 1535 printf("ni_map_lookup(%s, %s)\n", 1536 map->map_mname, name); 1537 1538 propval = ni_propval(map->map_file, map->map_keycolnm, name, 1539 map->map_valcolnm, map->map_coldelim); 1540 1541 if (propval == NULL) 1542 return NULL; 1543 1544 if (bitset(MF_MATCHONLY, map->map_mflags)) 1545 res = map_rewrite(map, name, strlen(name), NULL); 1546 else 1547 res = map_rewrite(map, propval, strlen(propval), av); 1548 free(propval); 1549 return res; 1550 } 1551 1552 #endif 1553 /* 1554 ** TEXT (unindexed text file) Modules 1555 ** 1556 ** This code donated by Sun Microsystems. 1557 */ 1558 1559 1560 /* 1561 ** TEXT_MAP_OPEN -- open text table 1562 */ 1563 1564 bool 1565 text_map_open(map, mode) 1566 MAP *map; 1567 int mode; 1568 { 1569 struct stat sbuf; 1570 1571 if (tTd(38, 2)) 1572 printf("text_map_open(%s, %s, %d)\n", 1573 map->map_mname, map->map_file, mode); 1574 1575 if (mode != O_RDONLY) 1576 { 1577 errno = ENODEV; 1578 return FALSE; 1579 } 1580 1581 if (*map->map_file == '\0') 1582 { 1583 if (tTd(38, 2)) 1584 printf("text_map_open: file name required\n"); 1585 return FALSE; 1586 } 1587 1588 if (map->map_file[0] != '/') 1589 { 1590 if (tTd(38, 2)) 1591 printf("text_map_open(%s): file name must be fully qualified\n", 1592 map->map_file); 1593 return FALSE; 1594 } 1595 /* check to see if this map actually accessable */ 1596 if (access(map->map_file, R_OK) <0) 1597 return FALSE; 1598 1599 /* check to see if this map actually exist */ 1600 if (stat(map->map_file, &sbuf) <0) 1601 { 1602 if (tTd(38, 2)) 1603 printf("text_map_open(%s): can not stat %s\n", 1604 map->map_file, map->map_file); 1605 return FALSE; 1606 } 1607 1608 if (!S_ISREG(sbuf.st_mode)) 1609 { 1610 if (tTd(38, 2)) 1611 printf("text_map_open(%s): %s is not a file\n", 1612 map->map_file, map->map_file); 1613 return FALSE; 1614 } 1615 1616 if (map->map_keycolnm == NULL) 1617 map->map_keycolno = 0; 1618 else 1619 { 1620 if (!isdigit(*map->map_keycolnm)) 1621 { 1622 if (tTd(38, 2)) 1623 printf("text_map_open(%s): -k should specify a number, not %s\n", 1624 map->map_file, map->map_keycolnm); 1625 return FALSE; 1626 } 1627 map->map_keycolno = atoi(map->map_keycolnm); 1628 } 1629 1630 if (map->map_valcolnm == NULL) 1631 map->map_valcolno = 0; 1632 else 1633 { 1634 if (!isdigit(*map->map_valcolnm)) 1635 { 1636 if (tTd(38, 2)) 1637 printf("text_map_open(%s): -v should specify a number, not %s\n", 1638 map->map_file, map->map_valcolnm); 1639 return FALSE; 1640 } 1641 map->map_valcolno = atoi(map->map_valcolnm); 1642 } 1643 1644 if (tTd(38, 2)) 1645 { 1646 printf("text_map_open(%s): delimiter = ", 1647 map->map_file); 1648 if (map->map_coldelim == '\0') 1649 printf("(white space)\n"); 1650 else 1651 printf("%c\n", map->map_coldelim); 1652 } 1653 1654 return TRUE; 1655 } 1656 1657 1658 /* 1659 ** TEXT_MAP_LOOKUP -- look up a datum in a TEXT table 1660 */ 1661 1662 char * 1663 text_map_lookup(map, name, av, statp) 1664 MAP *map; 1665 char *name; 1666 char **av; 1667 int *statp; 1668 { 1669 char *vp; 1670 auto int vsize; 1671 int buflen; 1672 char search_key[MAXNAME + 1]; 1673 char linebuf[MAXLINE]; 1674 FILE *f; 1675 char buf[MAXNAME + 1]; 1676 char delim; 1677 int key_idx; 1678 bool found_it; 1679 extern char *get_column(); 1680 1681 1682 found_it = FALSE; 1683 if (tTd(38, 20)) 1684 printf("text_map_lookup(%s)\n", name); 1685 1686 buflen = strlen(name); 1687 if (buflen > sizeof search_key - 1) 1688 buflen = sizeof search_key - 1; 1689 bcopy(name, search_key, buflen + 1); 1690 if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 1691 makelower(search_key); 1692 1693 f = fopen(map->map_file, "r"); 1694 if (f == NULL) 1695 { 1696 map->map_mflags &= ~(MF_VALID|MF_OPEN); 1697 *statp = EX_UNAVAILABLE; 1698 return NULL; 1699 } 1700 key_idx = map->map_keycolno; 1701 delim = map->map_coldelim; 1702 while (fgets(linebuf, MAXLINE, f)) 1703 { 1704 char *lf; 1705 if (linebuf[0] == '#') 1706 continue; /* skip comment line */ 1707 if (lf = strchr(linebuf, '\n')) 1708 *lf = '\0'; 1709 if (!strcasecmp(search_key, 1710 get_column(linebuf, key_idx, delim, buf))) 1711 { 1712 found_it = TRUE; 1713 break; 1714 } 1715 } 1716 fclose(f); 1717 if (!found_it) 1718 { 1719 #ifdef MAP_EXIT_STAT 1720 *statp = EX_NOTFOUND; 1721 #endif 1722 return(NULL); 1723 } 1724 vp = get_column(linebuf, map->map_valcolno, delim, buf); 1725 vsize = strlen(vp); 1726 #ifdef MAP_EXIT_STAT 1727 *statp = EX_OK; 1728 #endif 1729 if (bitset(MF_MATCHONLY, map->map_mflags)) 1730 return map_rewrite(map, name, strlen(name), NULL); 1731 else 1732 return map_rewrite(map, vp, vsize, av); 1733 } 1734 /* 1735 ** STAB (Symbol Table) Modules 1736 */ 1737 1738 1739 /* 1740 ** STAB_MAP_LOOKUP -- look up alias in symbol table 1741 */ 1742 1743 char * 1744 stab_map_lookup(map, name, av, pstat) 1745 register MAP *map; 1746 char *name; 1747 char **av; 1748 int *pstat; 1749 { 1750 register STAB *s; 1751 1752 if (tTd(38, 20)) 1753 printf("stab_lookup(%s, %s)\n", 1754 map->map_mname, name); 1755 1756 s = stab(name, ST_ALIAS, ST_FIND); 1757 if (s != NULL) 1758 return (s->s_alias); 1759 return (NULL); 1760 } 1761 1762 1763 /* 1764 ** STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild) 1765 */ 1766 1767 void 1768 stab_map_store(map, lhs, rhs) 1769 register MAP *map; 1770 char *lhs; 1771 char *rhs; 1772 { 1773 register STAB *s; 1774 1775 s = stab(lhs, ST_ALIAS, ST_ENTER); 1776 s->s_alias = newstr(rhs); 1777 } 1778 1779 1780 /* 1781 ** STAB_MAP_OPEN -- initialize (reads data file) 1782 ** 1783 ** This is a wierd case -- it is only intended as a fallback for 1784 ** aliases. For this reason, opens for write (only during a 1785 ** "newaliases") always fails, and opens for read open the 1786 ** actual underlying text file instead of the database. 1787 */ 1788 1789 bool 1790 stab_map_open(map, mode) 1791 register MAP *map; 1792 int mode; 1793 { 1794 FILE *af; 1795 struct stat st; 1796 1797 if (tTd(38, 2)) 1798 printf("stab_map_open(%s, %s)\n", 1799 map->map_mname, map->map_file); 1800 1801 if (mode != O_RDONLY) 1802 { 1803 errno = ENODEV; 1804 return FALSE; 1805 } 1806 1807 af = fopen(map->map_file, "r"); 1808 if (af == NULL) 1809 return FALSE; 1810 readaliases(map, af, FALSE, FALSE); 1811 1812 if (fstat(fileno(af), &st) >= 0) 1813 map->map_mtime = st.st_mtime; 1814 fclose(af); 1815 1816 return TRUE; 1817 } 1818 /* 1819 ** Implicit Modules 1820 ** 1821 ** Tries several types. For back compatibility of aliases. 1822 */ 1823 1824 1825 /* 1826 ** IMPL_MAP_LOOKUP -- lookup in best open database 1827 */ 1828 1829 char * 1830 impl_map_lookup(map, name, av, pstat) 1831 MAP *map; 1832 char *name; 1833 char **av; 1834 int *pstat; 1835 { 1836 if (tTd(38, 20)) 1837 printf("impl_map_lookup(%s, %s)\n", 1838 map->map_mname, name); 1839 1840 #ifdef NEWDB 1841 if (bitset(MF_IMPL_HASH, map->map_mflags)) 1842 return db_map_lookup(map, name, av, pstat); 1843 #endif 1844 #ifdef NDBM 1845 if (bitset(MF_IMPL_NDBM, map->map_mflags)) 1846 return ndbm_map_lookup(map, name, av, pstat); 1847 #endif 1848 return stab_map_lookup(map, name, av, pstat); 1849 } 1850 1851 /* 1852 ** IMPL_MAP_STORE -- store in open databases 1853 */ 1854 1855 void 1856 impl_map_store(map, lhs, rhs) 1857 MAP *map; 1858 char *lhs; 1859 char *rhs; 1860 { 1861 #ifdef NEWDB 1862 if (bitset(MF_IMPL_HASH, map->map_mflags)) 1863 db_map_store(map, lhs, rhs); 1864 #endif 1865 #ifdef NDBM 1866 if (bitset(MF_IMPL_NDBM, map->map_mflags)) 1867 ndbm_map_store(map, lhs, rhs); 1868 #endif 1869 stab_map_store(map, lhs, rhs); 1870 } 1871 1872 /* 1873 ** IMPL_MAP_OPEN -- implicit database open 1874 */ 1875 1876 bool 1877 impl_map_open(map, mode) 1878 MAP *map; 1879 int mode; 1880 { 1881 struct stat stb; 1882 1883 if (tTd(38, 2)) 1884 printf("impl_map_open(%s, %s, %d)\n", 1885 map->map_mname, map->map_file, mode); 1886 1887 if (stat(map->map_file, &stb) < 0) 1888 { 1889 /* no alias file at all */ 1890 if (tTd(38, 3)) 1891 printf("no map file\n"); 1892 return FALSE; 1893 } 1894 1895 #ifdef NEWDB 1896 map->map_mflags |= MF_IMPL_HASH; 1897 if (hash_map_open(map, mode)) 1898 { 1899 #if defined(NDBM) && defined(NIS) 1900 if (mode == O_RDONLY || access("/var/yp/Makefile", R_OK) != 0) 1901 #endif 1902 return TRUE; 1903 } 1904 else 1905 map->map_mflags &= ~MF_IMPL_HASH; 1906 #endif 1907 #ifdef NDBM 1908 map->map_mflags |= MF_IMPL_NDBM; 1909 if (ndbm_map_open(map, mode)) 1910 { 1911 return TRUE; 1912 } 1913 else 1914 map->map_mflags &= ~MF_IMPL_NDBM; 1915 #endif 1916 1917 #if defined(NEWDB) || defined(NDBM) 1918 if (Verbose) 1919 message("WARNING: cannot open alias database %s", map->map_file); 1920 #else 1921 if (mode != O_RDONLY) 1922 usrerr("Cannot rebuild aliases: no database format defined"); 1923 #endif 1924 1925 return stab_map_open(map, mode); 1926 } 1927 1928 1929 /* 1930 ** IMPL_MAP_CLOSE -- close any open database(s) 1931 */ 1932 1933 void 1934 impl_map_close(map) 1935 MAP *map; 1936 { 1937 if (tTd(38, 20)) 1938 printf("impl_map_close(%s, %s, %x)\n", 1939 map->map_mname, map->map_file, map->map_mflags); 1940 #ifdef NEWDB 1941 if (bitset(MF_IMPL_HASH, map->map_mflags)) 1942 { 1943 db_map_close(map); 1944 map->map_mflags &= ~MF_IMPL_HASH; 1945 } 1946 #endif 1947 1948 #ifdef NDBM 1949 if (bitset(MF_IMPL_NDBM, map->map_mflags)) 1950 { 1951 ndbm_map_close(map); 1952 map->map_mflags &= ~MF_IMPL_NDBM; 1953 } 1954 #endif 1955 } 1956 /* 1957 ** User map class. 1958 ** 1959 ** Provides access to the system password file. 1960 */ 1961 1962 /* 1963 ** USER_MAP_OPEN -- open user map 1964 ** 1965 ** Really just binds field names to field numbers. 1966 */ 1967 1968 bool 1969 user_map_open(map, mode) 1970 MAP *map; 1971 int mode; 1972 { 1973 if (tTd(38, 2)) 1974 printf("user_map_open(%s)\n", map->map_mname); 1975 1976 if (mode != O_RDONLY) 1977 { 1978 /* issue a pseudo-error message */ 1979 #ifdef ENOSYS 1980 errno = ENOSYS; 1981 #else 1982 # ifdef EFTYPE 1983 errno = EFTYPE; 1984 # else 1985 errno = ENXIO; 1986 # endif 1987 #endif 1988 return FALSE; 1989 } 1990 if (map->map_valcolnm == NULL) 1991 /* nothing */ ; 1992 else if (strcasecmp(map->map_valcolnm, "name") == 0) 1993 map->map_valcolno = 1; 1994 else if (strcasecmp(map->map_valcolnm, "passwd") == 0) 1995 map->map_valcolno = 2; 1996 else if (strcasecmp(map->map_valcolnm, "uid") == 0) 1997 map->map_valcolno = 3; 1998 else if (strcasecmp(map->map_valcolnm, "gid") == 0) 1999 map->map_valcolno = 4; 2000 else if (strcasecmp(map->map_valcolnm, "gecos") == 0) 2001 map->map_valcolno = 5; 2002 else if (strcasecmp(map->map_valcolnm, "dir") == 0) 2003 map->map_valcolno = 6; 2004 else if (strcasecmp(map->map_valcolnm, "shell") == 0) 2005 map->map_valcolno = 7; 2006 else 2007 { 2008 syserr("User map %s: unknown column name %s", 2009 map->map_mname, map->map_valcolnm); 2010 return FALSE; 2011 } 2012 return TRUE; 2013 } 2014 2015 2016 /* 2017 ** USER_MAP_LOOKUP -- look up a user in the passwd file. 2018 */ 2019 2020 char * 2021 user_map_lookup(map, key, av, statp) 2022 MAP *map; 2023 char *key; 2024 char **av; 2025 int *statp; 2026 { 2027 struct passwd *pw; 2028 2029 if (tTd(38, 20)) 2030 printf("user_map_lookup(%s, %s)\n", 2031 map->map_mname, key); 2032 2033 pw = sm_getpwnam(key); 2034 if (pw == NULL) 2035 return NULL; 2036 if (bitset(MF_MATCHONLY, map->map_mflags)) 2037 return map_rewrite(map, key, strlen(key), NULL); 2038 else 2039 { 2040 char *rwval = NULL; 2041 char buf[30]; 2042 2043 switch (map->map_valcolno) 2044 { 2045 case 0: 2046 case 1: 2047 rwval = pw->pw_name; 2048 break; 2049 2050 case 2: 2051 rwval = pw->pw_passwd; 2052 break; 2053 2054 case 3: 2055 sprintf(buf, "%d", pw->pw_uid); 2056 rwval = buf; 2057 break; 2058 2059 case 4: 2060 sprintf(buf, "%d", pw->pw_gid); 2061 rwval = buf; 2062 break; 2063 2064 case 5: 2065 rwval = pw->pw_gecos; 2066 break; 2067 2068 case 6: 2069 rwval = pw->pw_dir; 2070 break; 2071 2072 case 7: 2073 rwval = pw->pw_shell; 2074 break; 2075 } 2076 return map_rewrite(map, rwval, strlen(rwval), av); 2077 } 2078 } 2079 /* 2080 ** BESTMX -- find the best MX for a name 2081 ** 2082 ** This is really a hack, but I don't see any obvious way 2083 ** to generalize it at the moment. 2084 */ 2085 2086 #if NAMED_BIND 2087 2088 char * 2089 bestmx_map_lookup(map, name, av, statp) 2090 MAP *map; 2091 char *name; 2092 char **av; 2093 int *statp; 2094 { 2095 int nmx; 2096 auto int rcode; 2097 char *mxhosts[MAXMXHOSTS + 1]; 2098 2099 nmx = getmxrr(name, mxhosts, FALSE, &rcode); 2100 if (nmx <= 0) 2101 return NULL; 2102 if (bitset(MF_MATCHONLY, map->map_mflags)) 2103 return map_rewrite(map, name, strlen(name), NULL); 2104 else 2105 return map_rewrite(map, mxhosts[0], strlen(mxhosts[0]), av); 2106 } 2107 2108 #endif 2109 /* 2110 ** Sequenced map type. 2111 ** 2112 ** Tries each map in order until something matches, much like 2113 ** implicit. Stores go to the first map in the list that can 2114 ** support storing. 2115 ** 2116 ** This is slightly unusual in that there are two interfaces. 2117 ** The "sequence" interface lets you stack maps arbitrarily. 2118 ** The "switch" interface builds a sequence map by looking 2119 ** at a system-dependent configuration file such as 2120 ** /etc/nsswitch.conf on Solaris or /etc/svc.conf on Ultrix. 2121 ** 2122 ** We don't need an explicit open, since all maps are 2123 ** opened during startup, including underlying maps. 2124 */ 2125 2126 /* 2127 ** SEQ_MAP_PARSE -- Sequenced map parsing 2128 */ 2129 2130 bool 2131 seq_map_parse(map, ap) 2132 MAP *map; 2133 char *ap; 2134 { 2135 int maxmap; 2136 2137 if (tTd(38, 2)) 2138 printf("seq_map_parse(%s, %s)\n", map->map_mname, ap); 2139 maxmap = 0; 2140 while (*ap != '\0') 2141 { 2142 register char *p; 2143 STAB *s; 2144 2145 /* find beginning of map name */ 2146 while (isascii(*ap) && isspace(*ap)) 2147 ap++; 2148 for (p = ap; isascii(*p) && isalnum(*p); p++) 2149 continue; 2150 if (*p != '\0') 2151 *p++ = '\0'; 2152 while (*p != '\0' && (!isascii(*p) || !isalnum(*p))) 2153 p++; 2154 if (*ap == '\0') 2155 { 2156 ap = p; 2157 continue; 2158 } 2159 s = stab(ap, ST_MAP, ST_FIND); 2160 if (s == NULL) 2161 { 2162 syserr("Sequence map %s: unknown member map %s", 2163 map->map_mname, ap); 2164 } 2165 else if (maxmap == MAXMAPSTACK) 2166 { 2167 syserr("Sequence map %s: too many member maps (%d max)", 2168 map->map_mname, MAXMAPSTACK); 2169 maxmap++; 2170 } 2171 else if (maxmap < MAXMAPSTACK) 2172 { 2173 map->map_stack[maxmap++] = &s->s_map; 2174 } 2175 ap = p; 2176 } 2177 return TRUE; 2178 } 2179 2180 2181 /* 2182 ** SWITCH_MAP_OPEN -- open a switched map 2183 ** 2184 ** This looks at the system-dependent configuration and builds 2185 ** a sequence map that does the same thing. 2186 ** 2187 ** Every system must define a switch_map_find routine in conf.c 2188 ** that will return the list of service types associated with a 2189 ** given service class. 2190 */ 2191 2192 bool 2193 switch_map_open(map, mode) 2194 MAP *map; 2195 int mode; 2196 { 2197 int mapno; 2198 int nmaps; 2199 char *maptype[MAXMAPSTACK]; 2200 2201 if (tTd(38, 2)) 2202 printf("switch_map_open(%s, %s, %d)\n", 2203 map->map_mname, map->map_file, mode); 2204 2205 nmaps = switch_map_find(map->map_file, maptype, map->map_return); 2206 if (tTd(38, 19)) 2207 { 2208 printf("\tswitch_map_find => %d\n", nmaps); 2209 for (mapno = 0; mapno < nmaps; mapno++) 2210 printf("\t\t%s\n", maptype[mapno]); 2211 } 2212 if (nmaps <= 0 || nmaps > MAXMAPSTACK) 2213 return FALSE; 2214 2215 for (mapno = 0; mapno < nmaps; mapno++) 2216 { 2217 register STAB *s; 2218 char nbuf[MAXNAME + 1]; 2219 2220 if (maptype[mapno] == NULL) 2221 continue; 2222 (void) sprintf(nbuf, "%s.%s", map->map_file, maptype[mapno]); 2223 s = stab(nbuf, ST_MAP, ST_FIND); 2224 if (s == NULL) 2225 { 2226 syserr("Switch map %s: unknown member map %s", 2227 map->map_mname, nbuf); 2228 } 2229 else 2230 { 2231 map->map_stack[mapno] = &s->s_map; 2232 if (tTd(38, 4)) 2233 printf("\tmap_stack[%d] = %s:%s\n", 2234 mapno, s->s_map.map_class->map_cname, 2235 nbuf); 2236 } 2237 } 2238 return TRUE; 2239 } 2240 2241 2242 /* 2243 ** SEQ_MAP_CLOSE -- close all underlying maps 2244 */ 2245 2246 seq_map_close(map) 2247 MAP *map; 2248 { 2249 int mapno; 2250 2251 if (tTd(38, 20)) 2252 printf("seq_map_close(%s)\n", map->map_mname); 2253 for (mapno = 0; mapno < MAXMAPSTACK; mapno++) 2254 { 2255 MAP *mm = map->map_stack[mapno]; 2256 2257 if (mm == NULL || !bitset(MF_OPEN, mm->map_mflags)) 2258 continue; 2259 mm->map_class->map_close(mm); 2260 } 2261 } 2262 2263 2264 /* 2265 ** SEQ_MAP_LOOKUP -- sequenced map lookup 2266 */ 2267 2268 char * 2269 seq_map_lookup(map, key, args, pstat) 2270 MAP *map; 2271 char *key; 2272 char **args; 2273 int *pstat; 2274 { 2275 int mapno; 2276 int mapbit = 0x01; 2277 2278 if (tTd(38, 20)) 2279 printf("seq_map_lookup(%s, %s)\n", map->map_mname, key); 2280 2281 for (mapno = 0; mapno < MAXMAPSTACK; mapbit <<= 1, mapno++) 2282 { 2283 MAP *mm = map->map_stack[mapno]; 2284 int stat = 0; 2285 char *rv; 2286 2287 if (mm == NULL) 2288 continue; 2289 if (!bitset(MF_OPEN, mm->map_mflags)) 2290 { 2291 if (bitset(mapbit, map->map_return[MA_UNAVAIL])) 2292 { 2293 *pstat = EX_UNAVAILABLE; 2294 return NULL; 2295 } 2296 continue; 2297 } 2298 rv = mm->map_class->map_lookup(mm, key, args, &stat); 2299 if (rv != NULL) 2300 return rv; 2301 if (stat == 0 && bitset(mapbit, map->map_return[MA_NOTFOUND])) 2302 return NULL; 2303 if (stat != 0 && bitset(mapbit, map->map_return[MA_TRYAGAIN])) 2304 { 2305 *pstat = stat; 2306 return NULL; 2307 } 2308 } 2309 return NULL; 2310 } 2311 2312 2313 /* 2314 ** SEQ_MAP_STORE -- sequenced map store 2315 */ 2316 2317 void 2318 seq_map_store(map, key, val) 2319 MAP *map; 2320 char *key; 2321 char *val; 2322 { 2323 int mapno; 2324 2325 if (tTd(38, 12)) 2326 printf("seq_map_store(%s, %s, %s)\n", 2327 map->map_mname, key, val); 2328 2329 for (mapno = 0; mapno < MAXMAPSTACK; mapno++) 2330 { 2331 MAP *mm = map->map_stack[mapno]; 2332 2333 if (mm == NULL || !bitset(MF_WRITABLE, mm->map_mflags)) 2334 continue; 2335 2336 mm->map_class->map_store(mm, key, val); 2337 return; 2338 } 2339 syserr("seq_map_store(%s, %s, %s): no writable map", 2340 map->map_mname, key, val); 2341 } 2342 /* 2343 ** NULL stubs 2344 */ 2345 2346 bool 2347 null_map_open(map, mode) 2348 MAP *map; 2349 int mode; 2350 { 2351 return TRUE; 2352 } 2353 2354 void 2355 null_map_close(map) 2356 MAP *map; 2357 { 2358 return; 2359 } 2360 2361 void 2362 null_map_store(map, key, val) 2363 MAP *map; 2364 char *key; 2365 char *val; 2366 { 2367 return; 2368 } 2369 2370 2371 /* 2372 ** BOGUS stubs 2373 */ 2374 2375 char * 2376 bogus_map_lookup(map, key, args, pstat) 2377 MAP *map; 2378 char *key; 2379 char **args; 2380 int *pstat; 2381 { 2382 *pstat = EX_TEMPFAIL; 2383 return NULL; 2384 } 2385 2386 MAPCLASS BogusMapClass = 2387 { 2388 "bogus-map", NULL, 0, 2389 NULL, bogus_map_lookup, null_map_store, 2390 null_map_open, null_map_close, 2391 }; 2392