1 /* 2 * Copyright (c) 1992, 1995 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.57 (Berkeley) 04/24/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 auto int xstat; 601 datum old; 602 603 old.dptr = ndbm_map_lookup(map, key.dptr, NULL, &xstat); 604 if (old.dptr != NULL && *old.dptr != '\0') 605 { 606 old.dsize = strlen(old.dptr); 607 if (data.dsize + old.dsize + 2 > bufsiz) 608 { 609 if (buf != NULL) 610 (void) free(buf); 611 bufsiz = data.dsize + old.dsize + 2; 612 buf = xalloc(bufsiz); 613 } 614 sprintf(buf, "%s,%s", data.dptr, old.dptr); 615 data.dsize = data.dsize + old.dsize + 1; 616 data.dptr = buf; 617 if (tTd(38, 9)) 618 printf("ndbm_map_store append=%s\n", data.dptr); 619 } 620 } 621 stat = dbm_store((DBM *) map->map_db1, key, data, DBM_REPLACE); 622 } 623 if (stat != 0) 624 syserr("readaliases: dbm put (%s)", lhs); 625 } 626 627 628 /* 629 ** NDBM_MAP_CLOSE -- close the database 630 */ 631 632 void 633 ndbm_map_close(map) 634 register MAP *map; 635 { 636 if (tTd(38, 9)) 637 printf("ndbm_map_close(%s, %s, %x)\n", 638 map->map_mname, map->map_file, map->map_mflags); 639 640 if (bitset(MF_WRITABLE, map->map_mflags)) 641 { 642 #ifdef NIS 643 bool inclnull; 644 char buf[200]; 645 646 inclnull = bitset(MF_INCLNULL, map->map_mflags); 647 map->map_mflags &= ~MF_INCLNULL; 648 649 (void) sprintf(buf, "%010ld", curtime()); 650 ndbm_map_store(map, "YP_LAST_MODIFIED", buf); 651 652 (void) gethostname(buf, sizeof buf); 653 ndbm_map_store(map, "YP_MASTER_NAME", buf); 654 655 if (inclnull) 656 map->map_mflags |= MF_INCLNULL; 657 #endif 658 659 /* write out the distinguished alias */ 660 ndbm_map_store(map, "@", "@"); 661 } 662 dbm_close((DBM *) map->map_db1); 663 } 664 665 #endif 666 /* 667 ** NEWDB (Hash and BTree) Modules 668 */ 669 670 #ifdef NEWDB 671 672 /* 673 ** BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives. 674 ** 675 ** These do rather bizarre locking. If you can lock on open, 676 ** do that to avoid the condition of opening a database that 677 ** is being rebuilt. If you don't, we'll try to fake it, but 678 ** there will be a race condition. If opening for read-only, 679 ** we immediately release the lock to avoid freezing things up. 680 ** We really ought to hold the lock, but guarantee that we won't 681 ** be pokey about it. That's hard to do. 682 */ 683 684 bool 685 bt_map_open(map, mode) 686 MAP *map; 687 int mode; 688 { 689 DB *db; 690 int i; 691 int omode; 692 int fd; 693 struct stat st; 694 char buf[MAXNAME + 1]; 695 696 if (tTd(38, 2)) 697 printf("bt_map_open(%s, %s, %d)\n", 698 map->map_mname, map->map_file, mode); 699 700 omode = mode; 701 if (omode == O_RDWR) 702 { 703 omode |= O_CREAT|O_TRUNC; 704 #if defined(O_EXLOCK) && HASFLOCK 705 omode |= O_EXLOCK; 706 # if !OLD_NEWDB 707 } 708 else 709 { 710 omode |= O_SHLOCK; 711 # endif 712 #endif 713 } 714 715 (void) strcpy(buf, map->map_file); 716 i = strlen(buf); 717 if (i < 3 || strcmp(&buf[i - 3], ".db") != 0) 718 (void) strcat(buf, ".db"); 719 db = dbopen(buf, omode, DBMMODE, DB_BTREE, NULL); 720 if (db == NULL) 721 { 722 #ifdef MAYBENEXTRELEASE 723 if (aliaswait(map, ".db", FALSE)) 724 return TRUE; 725 #endif 726 if (!bitset(MF_OPTIONAL, map->map_mflags)) 727 syserr("Cannot open BTREE database %s", map->map_file); 728 return FALSE; 729 } 730 #if !OLD_NEWDB 731 fd = db->fd(db); 732 # if defined(O_EXLOCK) && HASFLOCK 733 if (fd >= 0) 734 { 735 if (mode == O_RDONLY) 736 (void) lockfile(fd, map->map_file, ".db", LOCK_UN); 737 else 738 map->map_mflags |= MF_LOCKED; 739 } 740 # else 741 if (mode == O_RDWR && fd >= 0) 742 { 743 if (lockfile(fd, map->map_file, ".db", LOCK_EX)) 744 map->map_mflags |= MF_LOCKED; 745 } 746 # endif 747 #endif 748 749 /* try to make sure that at least the database header is on disk */ 750 if (mode == O_RDWR) 751 #if OLD_NEWDB 752 (void) db->sync(db); 753 #else 754 (void) db->sync(db, 0); 755 756 if (fd >= 0 && fstat(fd, &st) >= 0) 757 map->map_mtime = st.st_mtime; 758 #endif 759 760 map->map_db2 = (void *) db; 761 if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags)) 762 if (!aliaswait(map, ".db", TRUE)) 763 return FALSE; 764 return TRUE; 765 } 766 767 768 /* 769 ** HASH_MAP_INIT -- HASH-style map initialization 770 */ 771 772 bool 773 hash_map_open(map, mode) 774 MAP *map; 775 int mode; 776 { 777 DB *db; 778 int i; 779 int omode; 780 int fd; 781 struct stat st; 782 char buf[MAXNAME + 1]; 783 784 if (tTd(38, 2)) 785 printf("hash_map_open(%s, %s, %d)\n", 786 map->map_mname, map->map_file, mode); 787 788 omode = mode; 789 if (omode == O_RDWR) 790 { 791 omode |= O_CREAT|O_TRUNC; 792 #if defined(O_EXLOCK) && HASFLOCK 793 omode |= O_EXLOCK; 794 # if !OLD_NEWDB 795 } 796 else 797 { 798 omode |= O_SHLOCK; 799 # endif 800 #endif 801 } 802 803 (void) strcpy(buf, map->map_file); 804 i = strlen(buf); 805 if (i < 3 || strcmp(&buf[i - 3], ".db") != 0) 806 (void) strcat(buf, ".db"); 807 db = dbopen(buf, omode, DBMMODE, DB_HASH, NULL); 808 if (db == NULL) 809 { 810 #ifdef MAYBENEXTRELEASE 811 if (aliaswait(map, ".db", FALSE)) 812 return TRUE; 813 #endif 814 if (!bitset(MF_OPTIONAL, map->map_mflags)) 815 syserr("Cannot open HASH database %s", map->map_file); 816 return FALSE; 817 } 818 #if !OLD_NEWDB 819 fd = db->fd(db); 820 # if defined(O_EXLOCK) && HASFLOCK 821 if (fd >= 0) 822 { 823 if (mode == O_RDONLY) 824 (void) lockfile(fd, map->map_file, ".db", LOCK_UN); 825 else 826 map->map_mflags |= MF_LOCKED; 827 } 828 # else 829 if (mode == O_RDWR && fd >= 0) 830 { 831 if (lockfile(fd, map->map_file, ".db", LOCK_EX)) 832 map->map_mflags |= MF_LOCKED; 833 } 834 # endif 835 #endif 836 837 /* try to make sure that at least the database header is on disk */ 838 if (mode == O_RDWR) 839 #if OLD_NEWDB 840 (void) db->sync(db); 841 #else 842 (void) db->sync(db, 0); 843 844 if (fd >= 0 && fstat(fd, &st) >= 0) 845 map->map_mtime = st.st_mtime; 846 #endif 847 848 map->map_db2 = (void *) db; 849 if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags)) 850 if (!aliaswait(map, ".db", TRUE)) 851 return FALSE; 852 return TRUE; 853 } 854 855 856 /* 857 ** DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map 858 */ 859 860 char * 861 db_map_lookup(map, name, av, statp) 862 MAP *map; 863 char *name; 864 char **av; 865 int *statp; 866 { 867 DBT key, val; 868 register DB *db = (DB *) map->map_db2; 869 int st; 870 int saveerrno; 871 int fd; 872 char keybuf[MAXNAME + 1]; 873 874 if (tTd(38, 20)) 875 printf("db_map_lookup(%s, %s)\n", 876 map->map_mname, name); 877 878 key.size = strlen(name); 879 if (key.size > sizeof keybuf - 1) 880 key.size = sizeof keybuf - 1; 881 key.data = keybuf; 882 bcopy(name, keybuf, key.size + 1); 883 if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 884 makelower(keybuf); 885 #if !OLD_NEWDB 886 fd = db->fd(db); 887 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 888 (void) lockfile(db->fd(db), map->map_file, ".db", LOCK_SH); 889 #endif 890 st = 1; 891 if (bitset(MF_TRY0NULL, map->map_mflags)) 892 { 893 st = db->get(db, &key, &val, 0); 894 if (st == 0) 895 map->map_mflags &= ~MF_TRY1NULL; 896 } 897 if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags)) 898 { 899 key.size++; 900 st = db->get(db, &key, &val, 0); 901 if (st == 0) 902 map->map_mflags &= ~MF_TRY0NULL; 903 } 904 saveerrno = errno; 905 #if !OLD_NEWDB 906 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 907 (void) lockfile(fd, map->map_file, ".db", LOCK_UN); 908 #endif 909 if (st != 0) 910 { 911 errno = saveerrno; 912 if (st < 0) 913 syserr("db_map_lookup: get (%s)", name); 914 return NULL; 915 } 916 if (bitset(MF_MATCHONLY, map->map_mflags)) 917 return map_rewrite(map, name, strlen(name), NULL); 918 else 919 return map_rewrite(map, val.data, val.size, av); 920 } 921 922 923 /* 924 ** DB_MAP_STORE -- store a datum in the NEWDB database 925 */ 926 927 void 928 db_map_store(map, lhs, rhs) 929 register MAP *map; 930 char *lhs; 931 char *rhs; 932 { 933 int stat; 934 DBT key; 935 DBT data; 936 register DB *db = map->map_db2; 937 938 if (tTd(38, 20)) 939 printf("db_map_store(%s, %s, %s)\n", 940 map->map_mname, lhs, rhs); 941 942 key.size = strlen(lhs); 943 key.data = lhs; 944 945 data.size = strlen(rhs); 946 data.data = rhs; 947 948 if (bitset(MF_INCLNULL, map->map_mflags)) 949 { 950 key.size++; 951 data.size++; 952 } 953 954 stat = db->put(db, &key, &data, R_NOOVERWRITE); 955 if (stat > 0) 956 { 957 if (!bitset(MF_APPEND, map->map_mflags)) 958 usrerr("050 Warning: duplicate alias name %s", lhs); 959 else 960 { 961 static char *buf = NULL; 962 static int bufsiz = 0; 963 DBT old; 964 965 old.data = db_map_lookup(map, key.data, NULL, &stat); 966 if (old.data != NULL) 967 { 968 old.size = strlen(old.data); 969 if (data.size + old.size + 2 > bufsiz) 970 { 971 if (buf != NULL) 972 (void) free(buf); 973 bufsiz = data.size + old.size + 2; 974 buf = xalloc(bufsiz); 975 } 976 sprintf(buf, "%s,%s", data.data, old.data); 977 data.size = data.size + old.size + 1; 978 data.data = buf; 979 if (tTd(38, 9)) 980 printf("db_map_store append=%s\n", data.data); 981 } 982 } 983 stat = db->put(db, &key, &data, 0); 984 } 985 if (stat != 0) 986 syserr("readaliases: db put (%s)", lhs); 987 } 988 989 990 /* 991 ** DB_MAP_CLOSE -- add distinguished entries and close the database 992 */ 993 994 void 995 db_map_close(map) 996 MAP *map; 997 { 998 register DB *db = map->map_db2; 999 1000 if (tTd(38, 9)) 1001 printf("db_map_close(%s, %s, %x)\n", 1002 map->map_mname, map->map_file, map->map_mflags); 1003 1004 if (bitset(MF_WRITABLE, map->map_mflags)) 1005 { 1006 /* write out the distinguished alias */ 1007 db_map_store(map, "@", "@"); 1008 } 1009 1010 if (db->close(db) != 0) 1011 syserr("readaliases: db close failure"); 1012 } 1013 1014 #endif 1015 /* 1016 ** NIS Modules 1017 */ 1018 1019 # ifdef NIS 1020 1021 # ifndef YPERR_BUSY 1022 # define YPERR_BUSY 16 1023 # endif 1024 1025 /* 1026 ** NIS_MAP_OPEN -- open DBM map 1027 */ 1028 1029 bool 1030 nis_map_open(map, mode) 1031 MAP *map; 1032 int mode; 1033 { 1034 int yperr; 1035 register char *p; 1036 auto char *vp; 1037 auto int vsize; 1038 char *master; 1039 1040 if (tTd(38, 2)) 1041 printf("nis_map_open(%s, %s)\n", 1042 map->map_mname, map->map_file); 1043 1044 if (mode != O_RDONLY) 1045 { 1046 /* issue a pseudo-error message */ 1047 #ifdef ENOSYS 1048 errno = ENOSYS; 1049 #else 1050 # ifdef EFTYPE 1051 errno = EFTYPE; 1052 # else 1053 errno = ENXIO; 1054 # endif 1055 #endif 1056 return FALSE; 1057 } 1058 1059 p = strchr(map->map_file, '@'); 1060 if (p != NULL) 1061 { 1062 *p++ = '\0'; 1063 if (*p != '\0') 1064 map->map_domain = p; 1065 } 1066 1067 if (*map->map_file == '\0') 1068 map->map_file = "mail.aliases"; 1069 1070 if (map->map_domain == NULL) 1071 { 1072 yperr = yp_get_default_domain(&map->map_domain); 1073 if (yperr != 0) 1074 { 1075 if (!bitset(MF_OPTIONAL, map->map_mflags)) 1076 syserr("421 NIS map %s specified, but NIS not running\n", 1077 map->map_file); 1078 return FALSE; 1079 } 1080 } 1081 1082 /* check to see if this map actually exists */ 1083 yperr = yp_match(map->map_domain, map->map_file, "@", 1, 1084 &vp, &vsize); 1085 if (tTd(38, 10)) 1086 printf("nis_map_open: yp_match(%s, %s) => %s\n", 1087 map->map_domain, map->map_file, yperr_string(yperr)); 1088 if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY) 1089 { 1090 if (!bitset(MF_ALIAS, map->map_mflags) || 1091 aliaswait(map, NULL, TRUE)) 1092 return TRUE; 1093 } 1094 1095 if (!bitset(MF_OPTIONAL, map->map_mflags)) 1096 { 1097 syserr("421 Cannot bind to map %s in domain %s: %s", 1098 map->map_file, map->map_domain, yperr_string(yperr)); 1099 } 1100 1101 return FALSE; 1102 } 1103 1104 1105 /* 1106 ** NIS_MAP_LOOKUP -- look up a datum in a NIS map 1107 */ 1108 1109 char * 1110 nis_map_lookup(map, name, av, statp) 1111 MAP *map; 1112 char *name; 1113 char **av; 1114 int *statp; 1115 { 1116 char *vp; 1117 auto int vsize; 1118 int buflen; 1119 int yperr; 1120 char keybuf[MAXNAME + 1]; 1121 1122 if (tTd(38, 20)) 1123 printf("nis_map_lookup(%s, %s)\n", 1124 map->map_mname, name); 1125 1126 buflen = strlen(name); 1127 if (buflen > sizeof keybuf - 1) 1128 buflen = sizeof keybuf - 1; 1129 bcopy(name, keybuf, buflen + 1); 1130 if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 1131 makelower(keybuf); 1132 yperr = YPERR_KEY; 1133 if (bitset(MF_TRY0NULL, map->map_mflags)) 1134 { 1135 yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen, 1136 &vp, &vsize); 1137 if (yperr == 0) 1138 map->map_mflags &= ~MF_TRY1NULL; 1139 } 1140 if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags)) 1141 { 1142 buflen++; 1143 yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen, 1144 &vp, &vsize); 1145 if (yperr == 0) 1146 map->map_mflags &= ~MF_TRY0NULL; 1147 } 1148 if (yperr != 0) 1149 { 1150 if (yperr != YPERR_KEY && yperr != YPERR_BUSY) 1151 map->map_mflags &= ~(MF_VALID|MF_OPEN); 1152 return NULL; 1153 } 1154 if (bitset(MF_MATCHONLY, map->map_mflags)) 1155 return map_rewrite(map, name, strlen(name), NULL); 1156 else 1157 return map_rewrite(map, vp, vsize, av); 1158 } 1159 1160 #endif 1161 /* 1162 ** NISPLUS Modules 1163 ** 1164 ** This code donated by Sun Microsystems. 1165 */ 1166 1167 #ifdef NISPLUS 1168 1169 #undef NIS /* symbol conflict in nis.h */ 1170 #include <rpcsvc/nis.h> 1171 #include <rpcsvc/nislib.h> 1172 1173 #define EN_col(col) zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val 1174 #define COL_NAME(res,i) ((res->objects.objects_val)->TA_data.ta_cols.ta_cols_val)[i].tc_name 1175 #define COL_MAX(res) ((res->objects.objects_val)->TA_data.ta_cols.ta_cols_len) 1176 #define PARTIAL_NAME(x) ((x)[strlen(x) - 1] != '.') 1177 1178 /* 1179 ** NISPLUS_MAP_OPEN -- open nisplus table 1180 */ 1181 1182 bool 1183 nisplus_map_open(map, mode) 1184 MAP *map; 1185 int mode; 1186 { 1187 register char *p; 1188 char qbuf[MAXLINE + NIS_MAXNAMELEN]; 1189 nis_result *res = NULL; 1190 u_int objs_len; 1191 nis_object *obj_ptr; 1192 int retry_cnt, max_col, i; 1193 1194 if (tTd(38, 2)) 1195 printf("nisplus_map_open(%s, %s, %d)\n", 1196 map->map_mname, map->map_file, mode); 1197 1198 if (mode != O_RDONLY) 1199 { 1200 errno = ENODEV; 1201 return FALSE; 1202 } 1203 1204 if (*map->map_file == '\0') 1205 map->map_file = "mail_aliases.org_dir"; 1206 1207 if (PARTIAL_NAME(map->map_file) && map->map_domain == NULL) 1208 { 1209 /* set default NISPLUS Domain to $m */ 1210 extern char *nisplus_default_domain(); 1211 1212 map->map_domain = newstr(nisplus_default_domain()); 1213 if (tTd(38, 2)) 1214 printf("nisplus_map_open(%s): using domain %s\n", 1215 map->map_file, map->map_domain); 1216 } 1217 if (!PARTIAL_NAME(map->map_file)) 1218 map->map_domain = newstr(""); 1219 1220 /* check to see if this map actually exists */ 1221 if (PARTIAL_NAME(map->map_file)) 1222 sprintf(qbuf, "%s.%s", map->map_file, map->map_domain); 1223 else 1224 strcpy(qbuf, map->map_file); 1225 1226 retry_cnt = 0; 1227 while (res == NULL || res->status != NIS_SUCCESS) 1228 { 1229 res = nis_lookup(qbuf, FOLLOW_LINKS); 1230 switch (res->status) 1231 { 1232 case NIS_SUCCESS: 1233 case NIS_TRYAGAIN: 1234 case NIS_RPCERROR: 1235 case NIS_NAMEUNREACHABLE: 1236 break; 1237 1238 default: /* all other nisplus errors */ 1239 #if 0 1240 if (!bitset(MF_OPTIONAL, map->map_mflags)) 1241 syserr("421 Cannot find table %s.%s: %s", 1242 map->map_file, map->map_domain, 1243 nis_sperrno(res->status)); 1244 #endif 1245 errno = EBADR; 1246 return FALSE; 1247 } 1248 sleep(2); /* try not to overwhelm hosed server */ 1249 if (retry_cnt++ > 4) 1250 { 1251 errno = EBADR; 1252 return FALSE; 1253 } 1254 } 1255 1256 if (NIS_RES_NUMOBJ(res) != 1 || 1257 (NIS_RES_OBJECT(res)->zo_data.zo_type != TABLE_OBJ)) 1258 { 1259 if (tTd(38, 10)) 1260 printf("nisplus_map_open: %s is not a table\n", qbuf); 1261 #if 0 1262 if (!bitset(MF_OPTIONAL, map->map_mflags)) 1263 syserr("421 %s.%s: %s is not a table", 1264 map->map_file, map->map_domain, 1265 nis_sperrno(res->status)); 1266 #endif 1267 errno = EBADR; 1268 return FALSE; 1269 } 1270 /* default key column is column 0 */ 1271 if (map->map_keycolnm == NULL) 1272 map->map_keycolnm = newstr(COL_NAME(res,0)); 1273 1274 max_col = COL_MAX(res); 1275 1276 /* verify the key column exist */ 1277 for (i=0; i< max_col; i++) 1278 { 1279 if (!strcmp(map->map_keycolnm, COL_NAME(res,i))) 1280 break; 1281 } 1282 if (i == max_col) 1283 { 1284 if (tTd(38, 2)) 1285 printf("nisplus_map_open(%s): can not find key column %s\n", 1286 map->map_file, map->map_keycolnm); 1287 errno = EBADR; 1288 return FALSE; 1289 } 1290 1291 /* default value column is the last column */ 1292 if (map->map_valcolnm == NULL) 1293 { 1294 map->map_valcolno = max_col - 1; 1295 return TRUE; 1296 } 1297 1298 for (i=0; i< max_col; i++) 1299 { 1300 if (strcmp(map->map_valcolnm, COL_NAME(res,i)) == 0) 1301 { 1302 map->map_valcolno = i; 1303 return TRUE; 1304 } 1305 } 1306 1307 if (tTd(38, 2)) 1308 printf("nisplus_map_open(%s): can not find column %s\n", 1309 map->map_file, map->map_keycolnm); 1310 errno = EBADR; 1311 return FALSE; 1312 } 1313 1314 1315 /* 1316 ** NISPLUS_MAP_LOOKUP -- look up a datum in a NISPLUS table 1317 */ 1318 1319 char * 1320 nisplus_map_lookup(map, name, av, statp) 1321 MAP *map; 1322 char *name; 1323 char **av; 1324 int *statp; 1325 { 1326 char *vp; 1327 auto int vsize; 1328 int buflen; 1329 char search_key[MAXNAME + 1]; 1330 char qbuf[MAXLINE + NIS_MAXNAMELEN]; 1331 nis_result *result; 1332 1333 if (tTd(38, 20)) 1334 printf("nisplus_map_lookup(%s, %s)\n", 1335 map->map_mname, name); 1336 1337 if (!bitset(MF_OPEN, map->map_mflags)) 1338 { 1339 if (nisplus_map_open(map, O_RDONLY)) 1340 map->map_mflags |= MF_OPEN; 1341 else 1342 { 1343 *statp = EX_UNAVAILABLE; 1344 return NULL; 1345 } 1346 } 1347 1348 buflen = strlen(name); 1349 if (buflen > sizeof search_key - 1) 1350 buflen = sizeof search_key - 1; 1351 bcopy(name, search_key, buflen + 1); 1352 if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 1353 makelower(search_key); 1354 1355 /* construct the query */ 1356 if (PARTIAL_NAME(map->map_file)) 1357 sprintf(qbuf, "[%s=%s],%s.%s", map->map_keycolnm, 1358 search_key, map->map_file, map->map_domain); 1359 else 1360 sprintf(qbuf, "[%s=%s],%s", map->map_keycolnm, 1361 search_key, map->map_file); 1362 1363 if (tTd(38, 20)) 1364 printf("qbuf=%s\n", qbuf); 1365 result = nis_list(qbuf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL); 1366 if (result->status == NIS_SUCCESS) 1367 { 1368 int count; 1369 char *str; 1370 1371 if ((count = NIS_RES_NUMOBJ(result)) != 1) 1372 { 1373 if (LogLevel > 10) 1374 syslog(LOG_WARNING, 1375 "%s:Lookup error, expected 1 entry, got (%d)", 1376 map->map_file, count); 1377 1378 /* ignore second entry */ 1379 if (tTd(38, 20)) 1380 printf("nisplus_map_lookup(%s), got %d entries, additional entries ignored\n", 1381 name, count); 1382 } 1383 1384 vp = ((NIS_RES_OBJECT(result))->EN_col(map->map_valcolno)); 1385 /* set the length of the result */ 1386 if (vp == NULL) 1387 vp = ""; 1388 vsize = strlen(vp); 1389 if (tTd(38, 20)) 1390 printf("nisplus_map_lookup(%s), found %s\n", 1391 name, vp); 1392 if (bitset(MF_MATCHONLY, map->map_mflags)) 1393 str = map_rewrite(map, name, strlen(name), NULL); 1394 else 1395 str = map_rewrite(map, vp, vsize, av); 1396 nis_freeresult(result); 1397 #ifdef MAP_EXIT_STAT 1398 *statp = EX_OK; 1399 #endif 1400 return str; 1401 } 1402 else 1403 { 1404 #ifdef MAP_EXIT_STAT 1405 if (result->status == NIS_NOTFOUND) 1406 *statp = EX_NOTFOUND; 1407 else if (result->status == NIS_TRYAGAIN) 1408 *statp = EX_TEMPFAIL; 1409 else 1410 { 1411 *statp = EX_UNAVAILABLE; 1412 map->map_mflags &= ~(MF_VALID|MF_OPEN); 1413 } 1414 #else 1415 if ((result->status != NIS_NOTFOUND) && 1416 (result->status != NIS_TRYAGAIN)) 1417 map->map_mflags &= ~(MF_VALID|MF_OPEN); 1418 #endif 1419 } 1420 if (tTd(38, 20)) 1421 printf("nisplus_map_lookup(%s), failed\n", name); 1422 nis_freeresult(result); 1423 return NULL; 1424 } 1425 1426 1427 char * 1428 nisplus_default_domain() 1429 { 1430 static char default_domain[MAXNAME + 1] = ""; 1431 char *p; 1432 1433 if (default_domain[0] != '\0') 1434 return(default_domain); 1435 1436 p = nis_local_directory(); 1437 strcpy(default_domain, p); 1438 return default_domain; 1439 } 1440 1441 #endif /* NISPLUS */ 1442 /* 1443 ** HESIOD Modules 1444 */ 1445 1446 #ifdef HESIOD 1447 1448 #include <hesiod.h> 1449 1450 char * 1451 hes_map_lookup(map, name, av, statp) 1452 MAP *map; 1453 char *name; 1454 char **av; 1455 int *statp; 1456 { 1457 char **hp; 1458 char *retdata = NULL; 1459 int i; 1460 1461 if (tTd(38, 20)) 1462 printf("hes_map_lookup(%s, %s)\n", map->map_file, name); 1463 1464 hp = hes_resolve(name, map->map_file); 1465 if (hp == NULL) 1466 return NULL; 1467 1468 if (hp[0] != NULL) 1469 { 1470 if (bitset(MF_MATCHONLY, map->map_mflags)) 1471 retdata = map_rewrite(map, name, strlen(name), NULL); 1472 else 1473 retdata = map_rewrite(map, hp[0], strlen(hp[0]), av); 1474 } 1475 1476 for (i = 0; hp[i] != NULL; i++) 1477 free(hp[i]); 1478 free(hp); 1479 return retdata; 1480 } 1481 1482 #endif 1483 /* 1484 ** NeXT NETINFO Modules 1485 */ 1486 1487 #ifdef NETINFO 1488 1489 #define NETINFO_DEFAULT_DIR "/aliases" 1490 #define NETINFO_DEFAULT_PROPERTY "members" 1491 1492 1493 /* 1494 ** NI_MAP_OPEN -- open NetInfo Aliases 1495 */ 1496 1497 bool 1498 ni_map_open(map, mode) 1499 MAP *map; 1500 int mode; 1501 { 1502 char *p; 1503 1504 if (tTd(38, 20)) 1505 printf("ni_map_open: %s\n", map->map_file); 1506 1507 if (*map->map_file == '\0') 1508 map->map_file = NETINFO_DEFAULT_DIR; 1509 1510 if (map->map_valcolnm == NULL) 1511 map->map_valcolnm = NETINFO_DEFAULT_PROPERTY; 1512 1513 if (map->map_coldelim == '\0' && bitset(MF_ALIAS, map->map_mflags)) 1514 map->map_coldelim = ','; 1515 1516 return TRUE; 1517 } 1518 1519 1520 /* 1521 ** NI_MAP_LOOKUP -- look up a datum in NetInfo 1522 */ 1523 1524 char * 1525 ni_map_lookup(map, name, av, statp) 1526 MAP *map; 1527 char *name; 1528 char **av; 1529 int *statp; 1530 { 1531 char *res; 1532 char *propval; 1533 extern char *ni_propval(); 1534 1535 if (tTd(38, 20)) 1536 printf("ni_map_lookup(%s, %s)\n", 1537 map->map_mname, name); 1538 1539 propval = ni_propval(map->map_file, map->map_keycolnm, name, 1540 map->map_valcolnm, map->map_coldelim); 1541 1542 if (propval == NULL) 1543 return NULL; 1544 1545 if (bitset(MF_MATCHONLY, map->map_mflags)) 1546 res = map_rewrite(map, name, strlen(name), NULL); 1547 else 1548 res = map_rewrite(map, propval, strlen(propval), av); 1549 free(propval); 1550 return res; 1551 } 1552 1553 #endif 1554 /* 1555 ** TEXT (unindexed text file) Modules 1556 ** 1557 ** This code donated by Sun Microsystems. 1558 */ 1559 1560 1561 /* 1562 ** TEXT_MAP_OPEN -- open text table 1563 */ 1564 1565 bool 1566 text_map_open(map, mode) 1567 MAP *map; 1568 int mode; 1569 { 1570 struct stat sbuf; 1571 1572 if (tTd(38, 2)) 1573 printf("text_map_open(%s, %s, %d)\n", 1574 map->map_mname, map->map_file, mode); 1575 1576 if (mode != O_RDONLY) 1577 { 1578 errno = ENODEV; 1579 return FALSE; 1580 } 1581 1582 if (*map->map_file == '\0') 1583 { 1584 if (tTd(38, 2)) 1585 printf("text_map_open: file name required\n"); 1586 return FALSE; 1587 } 1588 1589 if (map->map_file[0] != '/') 1590 { 1591 if (tTd(38, 2)) 1592 printf("text_map_open(%s): file name must be fully qualified\n", 1593 map->map_file); 1594 return FALSE; 1595 } 1596 /* check to see if this map actually accessable */ 1597 if (access(map->map_file, R_OK) <0) 1598 return FALSE; 1599 1600 /* check to see if this map actually exist */ 1601 if (stat(map->map_file, &sbuf) <0) 1602 { 1603 if (tTd(38, 2)) 1604 printf("text_map_open(%s): can not stat %s\n", 1605 map->map_file, map->map_file); 1606 return FALSE; 1607 } 1608 1609 if (!S_ISREG(sbuf.st_mode)) 1610 { 1611 if (tTd(38, 2)) 1612 printf("text_map_open(%s): %s is not a file\n", 1613 map->map_file, map->map_file); 1614 return FALSE; 1615 } 1616 1617 if (map->map_keycolnm == NULL) 1618 map->map_keycolno = 0; 1619 else 1620 { 1621 if (!isdigit(*map->map_keycolnm)) 1622 { 1623 if (tTd(38, 2)) 1624 printf("text_map_open(%s): -k should specify a number, not %s\n", 1625 map->map_file, map->map_keycolnm); 1626 return FALSE; 1627 } 1628 map->map_keycolno = atoi(map->map_keycolnm); 1629 } 1630 1631 if (map->map_valcolnm == NULL) 1632 map->map_valcolno = 0; 1633 else 1634 { 1635 if (!isdigit(*map->map_valcolnm)) 1636 { 1637 if (tTd(38, 2)) 1638 printf("text_map_open(%s): -v should specify a number, not %s\n", 1639 map->map_file, map->map_valcolnm); 1640 return FALSE; 1641 } 1642 map->map_valcolno = atoi(map->map_valcolnm); 1643 } 1644 1645 if (tTd(38, 2)) 1646 { 1647 printf("text_map_open(%s): delimiter = ", 1648 map->map_file); 1649 if (map->map_coldelim == '\0') 1650 printf("(white space)\n"); 1651 else 1652 printf("%c\n", map->map_coldelim); 1653 } 1654 1655 return TRUE; 1656 } 1657 1658 1659 /* 1660 ** TEXT_MAP_LOOKUP -- look up a datum in a TEXT table 1661 */ 1662 1663 char * 1664 text_map_lookup(map, name, av, statp) 1665 MAP *map; 1666 char *name; 1667 char **av; 1668 int *statp; 1669 { 1670 char *vp; 1671 auto int vsize; 1672 int buflen; 1673 char search_key[MAXNAME + 1]; 1674 char linebuf[MAXLINE]; 1675 FILE *f; 1676 char buf[MAXNAME + 1]; 1677 char delim; 1678 int key_idx; 1679 bool found_it; 1680 extern char *get_column(); 1681 1682 1683 found_it = FALSE; 1684 if (tTd(38, 20)) 1685 printf("text_map_lookup(%s)\n", name); 1686 1687 buflen = strlen(name); 1688 if (buflen > sizeof search_key - 1) 1689 buflen = sizeof search_key - 1; 1690 bcopy(name, search_key, buflen + 1); 1691 if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 1692 makelower(search_key); 1693 1694 f = fopen(map->map_file, "r"); 1695 if (f == NULL) 1696 { 1697 map->map_mflags &= ~(MF_VALID|MF_OPEN); 1698 *statp = EX_UNAVAILABLE; 1699 return NULL; 1700 } 1701 key_idx = map->map_keycolno; 1702 delim = map->map_coldelim; 1703 while (fgets(linebuf, MAXLINE, f)) 1704 { 1705 char *lf; 1706 if (linebuf[0] == '#') 1707 continue; /* skip comment line */ 1708 if (lf = strchr(linebuf, '\n')) 1709 *lf = '\0'; 1710 if (!strcasecmp(search_key, 1711 get_column(linebuf, key_idx, delim, buf))) 1712 { 1713 found_it = TRUE; 1714 break; 1715 } 1716 } 1717 fclose(f); 1718 if (!found_it) 1719 { 1720 #ifdef MAP_EXIT_STAT 1721 *statp = EX_NOTFOUND; 1722 #endif 1723 return(NULL); 1724 } 1725 vp = get_column(linebuf, map->map_valcolno, delim, buf); 1726 vsize = strlen(vp); 1727 #ifdef MAP_EXIT_STAT 1728 *statp = EX_OK; 1729 #endif 1730 if (bitset(MF_MATCHONLY, map->map_mflags)) 1731 return map_rewrite(map, name, strlen(name), NULL); 1732 else 1733 return map_rewrite(map, vp, vsize, av); 1734 } 1735 /* 1736 ** STAB (Symbol Table) Modules 1737 */ 1738 1739 1740 /* 1741 ** STAB_MAP_LOOKUP -- look up alias in symbol table 1742 */ 1743 1744 char * 1745 stab_map_lookup(map, name, av, pstat) 1746 register MAP *map; 1747 char *name; 1748 char **av; 1749 int *pstat; 1750 { 1751 register STAB *s; 1752 1753 if (tTd(38, 20)) 1754 printf("stab_lookup(%s, %s)\n", 1755 map->map_mname, name); 1756 1757 s = stab(name, ST_ALIAS, ST_FIND); 1758 if (s != NULL) 1759 return (s->s_alias); 1760 return (NULL); 1761 } 1762 1763 1764 /* 1765 ** STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild) 1766 */ 1767 1768 void 1769 stab_map_store(map, lhs, rhs) 1770 register MAP *map; 1771 char *lhs; 1772 char *rhs; 1773 { 1774 register STAB *s; 1775 1776 s = stab(lhs, ST_ALIAS, ST_ENTER); 1777 s->s_alias = newstr(rhs); 1778 } 1779 1780 1781 /* 1782 ** STAB_MAP_OPEN -- initialize (reads data file) 1783 ** 1784 ** This is a wierd case -- it is only intended as a fallback for 1785 ** aliases. For this reason, opens for write (only during a 1786 ** "newaliases") always fails, and opens for read open the 1787 ** actual underlying text file instead of the database. 1788 */ 1789 1790 bool 1791 stab_map_open(map, mode) 1792 register MAP *map; 1793 int mode; 1794 { 1795 FILE *af; 1796 struct stat st; 1797 1798 if (tTd(38, 2)) 1799 printf("stab_map_open(%s, %s)\n", 1800 map->map_mname, map->map_file); 1801 1802 if (mode != O_RDONLY) 1803 { 1804 errno = ENODEV; 1805 return FALSE; 1806 } 1807 1808 af = fopen(map->map_file, "r"); 1809 if (af == NULL) 1810 return FALSE; 1811 readaliases(map, af, FALSE, FALSE); 1812 1813 if (fstat(fileno(af), &st) >= 0) 1814 map->map_mtime = st.st_mtime; 1815 fclose(af); 1816 1817 return TRUE; 1818 } 1819 /* 1820 ** Implicit Modules 1821 ** 1822 ** Tries several types. For back compatibility of aliases. 1823 */ 1824 1825 1826 /* 1827 ** IMPL_MAP_LOOKUP -- lookup in best open database 1828 */ 1829 1830 char * 1831 impl_map_lookup(map, name, av, pstat) 1832 MAP *map; 1833 char *name; 1834 char **av; 1835 int *pstat; 1836 { 1837 if (tTd(38, 20)) 1838 printf("impl_map_lookup(%s, %s)\n", 1839 map->map_mname, name); 1840 1841 #ifdef NEWDB 1842 if (bitset(MF_IMPL_HASH, map->map_mflags)) 1843 return db_map_lookup(map, name, av, pstat); 1844 #endif 1845 #ifdef NDBM 1846 if (bitset(MF_IMPL_NDBM, map->map_mflags)) 1847 return ndbm_map_lookup(map, name, av, pstat); 1848 #endif 1849 return stab_map_lookup(map, name, av, pstat); 1850 } 1851 1852 /* 1853 ** IMPL_MAP_STORE -- store in open databases 1854 */ 1855 1856 void 1857 impl_map_store(map, lhs, rhs) 1858 MAP *map; 1859 char *lhs; 1860 char *rhs; 1861 { 1862 #ifdef NEWDB 1863 if (bitset(MF_IMPL_HASH, map->map_mflags)) 1864 db_map_store(map, lhs, rhs); 1865 #endif 1866 #ifdef NDBM 1867 if (bitset(MF_IMPL_NDBM, map->map_mflags)) 1868 ndbm_map_store(map, lhs, rhs); 1869 #endif 1870 stab_map_store(map, lhs, rhs); 1871 } 1872 1873 /* 1874 ** IMPL_MAP_OPEN -- implicit database open 1875 */ 1876 1877 bool 1878 impl_map_open(map, mode) 1879 MAP *map; 1880 int mode; 1881 { 1882 struct stat stb; 1883 1884 if (tTd(38, 2)) 1885 printf("impl_map_open(%s, %s, %d)\n", 1886 map->map_mname, map->map_file, mode); 1887 1888 if (stat(map->map_file, &stb) < 0) 1889 { 1890 /* no alias file at all */ 1891 if (tTd(38, 3)) 1892 printf("no map file\n"); 1893 return FALSE; 1894 } 1895 1896 #ifdef NEWDB 1897 map->map_mflags |= MF_IMPL_HASH; 1898 if (hash_map_open(map, mode)) 1899 { 1900 #if defined(NDBM) && defined(NIS) 1901 if (mode == O_RDONLY || access("/var/yp/Makefile", R_OK) != 0) 1902 #endif 1903 return TRUE; 1904 } 1905 else 1906 map->map_mflags &= ~MF_IMPL_HASH; 1907 #endif 1908 #ifdef NDBM 1909 map->map_mflags |= MF_IMPL_NDBM; 1910 if (ndbm_map_open(map, mode)) 1911 { 1912 return TRUE; 1913 } 1914 else 1915 map->map_mflags &= ~MF_IMPL_NDBM; 1916 #endif 1917 1918 #if defined(NEWDB) || defined(NDBM) 1919 if (Verbose) 1920 message("WARNING: cannot open alias database %s", map->map_file); 1921 #else 1922 if (mode != O_RDONLY) 1923 usrerr("Cannot rebuild aliases: no database format defined"); 1924 #endif 1925 1926 return stab_map_open(map, mode); 1927 } 1928 1929 1930 /* 1931 ** IMPL_MAP_CLOSE -- close any open database(s) 1932 */ 1933 1934 void 1935 impl_map_close(map) 1936 MAP *map; 1937 { 1938 if (tTd(38, 20)) 1939 printf("impl_map_close(%s, %s, %x)\n", 1940 map->map_mname, map->map_file, map->map_mflags); 1941 #ifdef NEWDB 1942 if (bitset(MF_IMPL_HASH, map->map_mflags)) 1943 { 1944 db_map_close(map); 1945 map->map_mflags &= ~MF_IMPL_HASH; 1946 } 1947 #endif 1948 1949 #ifdef NDBM 1950 if (bitset(MF_IMPL_NDBM, map->map_mflags)) 1951 { 1952 ndbm_map_close(map); 1953 map->map_mflags &= ~MF_IMPL_NDBM; 1954 } 1955 #endif 1956 } 1957 /* 1958 ** User map class. 1959 ** 1960 ** Provides access to the system password file. 1961 */ 1962 1963 /* 1964 ** USER_MAP_OPEN -- open user map 1965 ** 1966 ** Really just binds field names to field numbers. 1967 */ 1968 1969 bool 1970 user_map_open(map, mode) 1971 MAP *map; 1972 int mode; 1973 { 1974 if (tTd(38, 2)) 1975 printf("user_map_open(%s)\n", map->map_mname); 1976 1977 if (mode != O_RDONLY) 1978 { 1979 /* issue a pseudo-error message */ 1980 #ifdef ENOSYS 1981 errno = ENOSYS; 1982 #else 1983 # ifdef EFTYPE 1984 errno = EFTYPE; 1985 # else 1986 errno = ENXIO; 1987 # endif 1988 #endif 1989 return FALSE; 1990 } 1991 if (map->map_valcolnm == NULL) 1992 /* nothing */ ; 1993 else if (strcasecmp(map->map_valcolnm, "name") == 0) 1994 map->map_valcolno = 1; 1995 else if (strcasecmp(map->map_valcolnm, "passwd") == 0) 1996 map->map_valcolno = 2; 1997 else if (strcasecmp(map->map_valcolnm, "uid") == 0) 1998 map->map_valcolno = 3; 1999 else if (strcasecmp(map->map_valcolnm, "gid") == 0) 2000 map->map_valcolno = 4; 2001 else if (strcasecmp(map->map_valcolnm, "gecos") == 0) 2002 map->map_valcolno = 5; 2003 else if (strcasecmp(map->map_valcolnm, "dir") == 0) 2004 map->map_valcolno = 6; 2005 else if (strcasecmp(map->map_valcolnm, "shell") == 0) 2006 map->map_valcolno = 7; 2007 else 2008 { 2009 syserr("User map %s: unknown column name %s", 2010 map->map_mname, map->map_valcolnm); 2011 return FALSE; 2012 } 2013 return TRUE; 2014 } 2015 2016 2017 /* 2018 ** USER_MAP_LOOKUP -- look up a user in the passwd file. 2019 */ 2020 2021 char * 2022 user_map_lookup(map, key, av, statp) 2023 MAP *map; 2024 char *key; 2025 char **av; 2026 int *statp; 2027 { 2028 struct passwd *pw; 2029 2030 if (tTd(38, 20)) 2031 printf("user_map_lookup(%s, %s)\n", 2032 map->map_mname, key); 2033 2034 pw = sm_getpwnam(key); 2035 if (pw == NULL) 2036 return NULL; 2037 if (bitset(MF_MATCHONLY, map->map_mflags)) 2038 return map_rewrite(map, key, strlen(key), NULL); 2039 else 2040 { 2041 char *rwval = NULL; 2042 char buf[30]; 2043 2044 switch (map->map_valcolno) 2045 { 2046 case 0: 2047 case 1: 2048 rwval = pw->pw_name; 2049 break; 2050 2051 case 2: 2052 rwval = pw->pw_passwd; 2053 break; 2054 2055 case 3: 2056 sprintf(buf, "%d", pw->pw_uid); 2057 rwval = buf; 2058 break; 2059 2060 case 4: 2061 sprintf(buf, "%d", pw->pw_gid); 2062 rwval = buf; 2063 break; 2064 2065 case 5: 2066 rwval = pw->pw_gecos; 2067 break; 2068 2069 case 6: 2070 rwval = pw->pw_dir; 2071 break; 2072 2073 case 7: 2074 rwval = pw->pw_shell; 2075 break; 2076 } 2077 return map_rewrite(map, rwval, strlen(rwval), av); 2078 } 2079 } 2080 /* 2081 ** BESTMX -- find the best MX for a name 2082 ** 2083 ** This is really a hack, but I don't see any obvious way 2084 ** to generalize it at the moment. 2085 */ 2086 2087 #if NAMED_BIND 2088 2089 char * 2090 bestmx_map_lookup(map, name, av, statp) 2091 MAP *map; 2092 char *name; 2093 char **av; 2094 int *statp; 2095 { 2096 int nmx; 2097 auto int rcode; 2098 char *mxhosts[MAXMXHOSTS + 1]; 2099 2100 nmx = getmxrr(name, mxhosts, FALSE, &rcode); 2101 if (nmx <= 0) 2102 return NULL; 2103 if (bitset(MF_MATCHONLY, map->map_mflags)) 2104 return map_rewrite(map, name, strlen(name), NULL); 2105 else 2106 return map_rewrite(map, mxhosts[0], strlen(mxhosts[0]), av); 2107 } 2108 2109 #endif 2110 /* 2111 ** Sequenced map type. 2112 ** 2113 ** Tries each map in order until something matches, much like 2114 ** implicit. Stores go to the first map in the list that can 2115 ** support storing. 2116 ** 2117 ** This is slightly unusual in that there are two interfaces. 2118 ** The "sequence" interface lets you stack maps arbitrarily. 2119 ** The "switch" interface builds a sequence map by looking 2120 ** at a system-dependent configuration file such as 2121 ** /etc/nsswitch.conf on Solaris or /etc/svc.conf on Ultrix. 2122 ** 2123 ** We don't need an explicit open, since all maps are 2124 ** opened during startup, including underlying maps. 2125 */ 2126 2127 /* 2128 ** SEQ_MAP_PARSE -- Sequenced map parsing 2129 */ 2130 2131 bool 2132 seq_map_parse(map, ap) 2133 MAP *map; 2134 char *ap; 2135 { 2136 int maxmap; 2137 2138 if (tTd(38, 2)) 2139 printf("seq_map_parse(%s, %s)\n", map->map_mname, ap); 2140 maxmap = 0; 2141 while (*ap != '\0') 2142 { 2143 register char *p; 2144 STAB *s; 2145 2146 /* find beginning of map name */ 2147 while (isascii(*ap) && isspace(*ap)) 2148 ap++; 2149 for (p = ap; isascii(*p) && isalnum(*p); p++) 2150 continue; 2151 if (*p != '\0') 2152 *p++ = '\0'; 2153 while (*p != '\0' && (!isascii(*p) || !isalnum(*p))) 2154 p++; 2155 if (*ap == '\0') 2156 { 2157 ap = p; 2158 continue; 2159 } 2160 s = stab(ap, ST_MAP, ST_FIND); 2161 if (s == NULL) 2162 { 2163 syserr("Sequence map %s: unknown member map %s", 2164 map->map_mname, ap); 2165 } 2166 else if (maxmap == MAXMAPSTACK) 2167 { 2168 syserr("Sequence map %s: too many member maps (%d max)", 2169 map->map_mname, MAXMAPSTACK); 2170 maxmap++; 2171 } 2172 else if (maxmap < MAXMAPSTACK) 2173 { 2174 map->map_stack[maxmap++] = &s->s_map; 2175 } 2176 ap = p; 2177 } 2178 return TRUE; 2179 } 2180 2181 2182 /* 2183 ** SWITCH_MAP_OPEN -- open a switched map 2184 ** 2185 ** This looks at the system-dependent configuration and builds 2186 ** a sequence map that does the same thing. 2187 ** 2188 ** Every system must define a switch_map_find routine in conf.c 2189 ** that will return the list of service types associated with a 2190 ** given service class. 2191 */ 2192 2193 bool 2194 switch_map_open(map, mode) 2195 MAP *map; 2196 int mode; 2197 { 2198 int mapno; 2199 int nmaps; 2200 char *maptype[MAXMAPSTACK]; 2201 2202 if (tTd(38, 2)) 2203 printf("switch_map_open(%s, %s, %d)\n", 2204 map->map_mname, map->map_file, mode); 2205 2206 nmaps = switch_map_find(map->map_file, maptype, map->map_return); 2207 if (tTd(38, 19)) 2208 { 2209 printf("\tswitch_map_find => %d\n", nmaps); 2210 for (mapno = 0; mapno < nmaps; mapno++) 2211 printf("\t\t%s\n", maptype[mapno]); 2212 } 2213 if (nmaps <= 0 || nmaps > MAXMAPSTACK) 2214 return FALSE; 2215 2216 for (mapno = 0; mapno < nmaps; mapno++) 2217 { 2218 register STAB *s; 2219 char nbuf[MAXNAME + 1]; 2220 2221 if (maptype[mapno] == NULL) 2222 continue; 2223 (void) sprintf(nbuf, "%s.%s", map->map_file, maptype[mapno]); 2224 s = stab(nbuf, ST_MAP, ST_FIND); 2225 if (s == NULL) 2226 { 2227 syserr("Switch map %s: unknown member map %s", 2228 map->map_mname, nbuf); 2229 } 2230 else 2231 { 2232 map->map_stack[mapno] = &s->s_map; 2233 if (tTd(38, 4)) 2234 printf("\tmap_stack[%d] = %s:%s\n", 2235 mapno, s->s_map.map_class->map_cname, 2236 nbuf); 2237 } 2238 } 2239 return TRUE; 2240 } 2241 2242 2243 /* 2244 ** SEQ_MAP_CLOSE -- close all underlying maps 2245 */ 2246 2247 seq_map_close(map) 2248 MAP *map; 2249 { 2250 int mapno; 2251 2252 if (tTd(38, 20)) 2253 printf("seq_map_close(%s)\n", map->map_mname); 2254 for (mapno = 0; mapno < MAXMAPSTACK; mapno++) 2255 { 2256 MAP *mm = map->map_stack[mapno]; 2257 2258 if (mm == NULL || !bitset(MF_OPEN, mm->map_mflags)) 2259 continue; 2260 mm->map_class->map_close(mm); 2261 mm->map_mflags &= ~(MF_OPEN|MF_WRITABLE); 2262 } 2263 } 2264 2265 2266 /* 2267 ** SEQ_MAP_LOOKUP -- sequenced map lookup 2268 */ 2269 2270 char * 2271 seq_map_lookup(map, key, args, pstat) 2272 MAP *map; 2273 char *key; 2274 char **args; 2275 int *pstat; 2276 { 2277 int mapno; 2278 int mapbit = 0x01; 2279 2280 if (tTd(38, 20)) 2281 printf("seq_map_lookup(%s, %s)\n", map->map_mname, key); 2282 2283 for (mapno = 0; mapno < MAXMAPSTACK; mapbit <<= 1, mapno++) 2284 { 2285 MAP *mm = map->map_stack[mapno]; 2286 int stat = 0; 2287 char *rv; 2288 2289 if (mm == NULL) 2290 continue; 2291 if (!bitset(MF_OPEN, mm->map_mflags)) 2292 { 2293 if (bitset(mapbit, map->map_return[MA_UNAVAIL])) 2294 { 2295 *pstat = EX_UNAVAILABLE; 2296 return NULL; 2297 } 2298 continue; 2299 } 2300 rv = mm->map_class->map_lookup(mm, key, args, &stat); 2301 if (rv != NULL) 2302 return rv; 2303 if (stat == 0 && bitset(mapbit, map->map_return[MA_NOTFOUND])) 2304 return NULL; 2305 if (stat != 0 && bitset(mapbit, map->map_return[MA_TRYAGAIN])) 2306 { 2307 *pstat = stat; 2308 return NULL; 2309 } 2310 } 2311 return NULL; 2312 } 2313 2314 2315 /* 2316 ** SEQ_MAP_STORE -- sequenced map store 2317 */ 2318 2319 void 2320 seq_map_store(map, key, val) 2321 MAP *map; 2322 char *key; 2323 char *val; 2324 { 2325 int mapno; 2326 2327 if (tTd(38, 12)) 2328 printf("seq_map_store(%s, %s, %s)\n", 2329 map->map_mname, key, val); 2330 2331 for (mapno = 0; mapno < MAXMAPSTACK; mapno++) 2332 { 2333 MAP *mm = map->map_stack[mapno]; 2334 2335 if (mm == NULL || !bitset(MF_WRITABLE, mm->map_mflags)) 2336 continue; 2337 2338 mm->map_class->map_store(mm, key, val); 2339 return; 2340 } 2341 syserr("seq_map_store(%s, %s, %s): no writable map", 2342 map->map_mname, key, val); 2343 } 2344 /* 2345 ** NULL stubs 2346 */ 2347 2348 bool 2349 null_map_open(map, mode) 2350 MAP *map; 2351 int mode; 2352 { 2353 return TRUE; 2354 } 2355 2356 void 2357 null_map_close(map) 2358 MAP *map; 2359 { 2360 return; 2361 } 2362 2363 void 2364 null_map_store(map, key, val) 2365 MAP *map; 2366 char *key; 2367 char *val; 2368 { 2369 return; 2370 } 2371 2372 2373 /* 2374 ** BOGUS stubs 2375 */ 2376 2377 char * 2378 bogus_map_lookup(map, key, args, pstat) 2379 MAP *map; 2380 char *key; 2381 char **args; 2382 int *pstat; 2383 { 2384 *pstat = EX_TEMPFAIL; 2385 return NULL; 2386 } 2387 2388 MAPCLASS BogusMapClass = 2389 { 2390 "bogus-map", NULL, 0, 2391 NULL, bogus_map_lookup, null_map_store, 2392 null_map_open, null_map_close, 2393 }; 2394