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.50 (Berkeley) 03/14/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 HASFLOCK 732 # if !defined(O_EXLOCK) 733 if (mode == O_RDWR && fd >= 0) 734 { 735 if (lockfile(fd, map->map_file, ".db", LOCK_EX)) 736 map->map_mflags |= MF_LOCKED; 737 } 738 # else 739 if (mode == O_RDONLY && fd >= 0) 740 (void) lockfile(fd, map->map_file, ".db", LOCK_UN); 741 else 742 map->map_mflags |= MF_LOCKED; 743 # endif 744 # endif 745 #endif 746 747 /* try to make sure that at least the database header is on disk */ 748 if (mode == O_RDWR) 749 #if OLD_NEWDB 750 (void) db->sync(db); 751 #else 752 (void) db->sync(db, 0); 753 754 if (fd >= 0 && fstat(fd, &st) >= 0) 755 map->map_mtime = st.st_mtime; 756 #endif 757 758 map->map_db2 = (void *) db; 759 if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags)) 760 if (!aliaswait(map, ".db", TRUE)) 761 return FALSE; 762 return TRUE; 763 } 764 765 766 /* 767 ** HASH_MAP_INIT -- HASH-style map initialization 768 */ 769 770 bool 771 hash_map_open(map, mode) 772 MAP *map; 773 int mode; 774 { 775 DB *db; 776 int i; 777 int omode; 778 int fd; 779 struct stat st; 780 char buf[MAXNAME + 1]; 781 782 if (tTd(38, 2)) 783 printf("hash_map_open(%s, %s, %d)\n", 784 map->map_mname, map->map_file, mode); 785 786 omode = mode; 787 if (omode == O_RDWR) 788 { 789 omode |= O_CREAT|O_TRUNC; 790 #if defined(O_EXLOCK) && HASFLOCK 791 omode |= O_EXLOCK; 792 # if !OLD_NEWDB 793 } 794 else 795 { 796 omode |= O_SHLOCK; 797 # endif 798 #endif 799 } 800 801 (void) strcpy(buf, map->map_file); 802 i = strlen(buf); 803 if (i < 3 || strcmp(&buf[i - 3], ".db") != 0) 804 (void) strcat(buf, ".db"); 805 db = dbopen(buf, omode, DBMMODE, DB_HASH, NULL); 806 if (db == NULL) 807 { 808 #ifdef MAYBENEXTRELEASE 809 if (aliaswait(map, ".db", FALSE)) 810 return TRUE; 811 #endif 812 if (!bitset(MF_OPTIONAL, map->map_mflags)) 813 syserr("Cannot open HASH database %s", map->map_file); 814 return FALSE; 815 } 816 #if !OLD_NEWDB 817 fd = db->fd(db); 818 # if HASFLOCK 819 # if !defined(O_EXLOCK) 820 if (mode == O_RDWR && fd >= 0) 821 { 822 if (lockfile(fd, map->map_file, ".db", LOCK_EX)) 823 map->map_mflags |= MF_LOCKED; 824 } 825 # else 826 if (mode == O_RDONLY && fd >= 0) 827 (void) lockfile(fd, map->map_file, ".db", LOCK_UN); 828 else 829 map->map_mflags |= MF_LOCKED; 830 # endif 831 # endif 832 #endif 833 834 /* try to make sure that at least the database header is on disk */ 835 if (mode == O_RDWR) 836 #if OLD_NEWDB 837 (void) db->sync(db); 838 #else 839 (void) db->sync(db, 0); 840 841 if (fd >= 0 && fstat(fd, &st) >= 0) 842 map->map_mtime = st.st_mtime; 843 #endif 844 845 map->map_db2 = (void *) db; 846 if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags)) 847 if (!aliaswait(map, ".db", TRUE)) 848 return FALSE; 849 return TRUE; 850 } 851 852 853 /* 854 ** DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map 855 */ 856 857 char * 858 db_map_lookup(map, name, av, statp) 859 MAP *map; 860 char *name; 861 char **av; 862 int *statp; 863 { 864 DBT key, val; 865 register DB *db = (DB *) map->map_db2; 866 int st; 867 int saveerrno; 868 int fd; 869 char keybuf[MAXNAME + 1]; 870 871 if (tTd(38, 20)) 872 printf("db_map_lookup(%s, %s)\n", 873 map->map_mname, name); 874 875 key.size = strlen(name); 876 if (key.size > sizeof keybuf - 1) 877 key.size = sizeof keybuf - 1; 878 key.data = keybuf; 879 bcopy(name, keybuf, key.size + 1); 880 if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 881 makelower(keybuf); 882 #if !OLD_NEWDB 883 fd = db->fd(db); 884 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 885 (void) lockfile(db->fd(db), map->map_file, ".db", LOCK_SH); 886 #endif 887 st = 1; 888 if (bitset(MF_TRY0NULL, map->map_mflags)) 889 { 890 st = db->get(db, &key, &val, 0); 891 if (st == 0) 892 map->map_mflags &= ~MF_TRY1NULL; 893 } 894 if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags)) 895 { 896 key.size++; 897 st = db->get(db, &key, &val, 0); 898 if (st == 0) 899 map->map_mflags &= ~MF_TRY0NULL; 900 } 901 saveerrno = errno; 902 #if !OLD_NEWDB 903 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 904 (void) lockfile(fd, map->map_file, ".db", LOCK_UN); 905 #endif 906 if (st != 0) 907 { 908 errno = saveerrno; 909 if (st < 0) 910 syserr("db_map_lookup: get (%s)", name); 911 return NULL; 912 } 913 if (bitset(MF_MATCHONLY, map->map_mflags)) 914 return map_rewrite(map, name, strlen(name), NULL); 915 else 916 return map_rewrite(map, val.data, val.size, av); 917 } 918 919 920 /* 921 ** DB_MAP_STORE -- store a datum in the NEWDB database 922 */ 923 924 void 925 db_map_store(map, lhs, rhs) 926 register MAP *map; 927 char *lhs; 928 char *rhs; 929 { 930 int stat; 931 DBT key; 932 DBT data; 933 register DB *db = map->map_db2; 934 935 if (tTd(38, 20)) 936 printf("db_map_store(%s, %s, %s)\n", 937 map->map_mname, lhs, rhs); 938 939 key.size = strlen(lhs); 940 key.data = lhs; 941 942 data.size = strlen(rhs); 943 data.data = rhs; 944 945 if (bitset(MF_INCLNULL, map->map_mflags)) 946 { 947 key.size++; 948 data.size++; 949 } 950 951 stat = db->put(db, &key, &data, R_NOOVERWRITE); 952 if (stat > 0) 953 { 954 if (!bitset(MF_APPEND, map->map_mflags)) 955 usrerr("050 Warning: duplicate alias name %s", lhs); 956 else 957 { 958 static char *buf = NULL; 959 static int bufsiz = 0; 960 DBT old; 961 962 old.data = db_map_lookup(map, key.data, NULL, &stat); 963 if (old.data != NULL) 964 { 965 old.size = strlen(old.data); 966 if (data.size + old.size + 2 > bufsiz) 967 { 968 if (buf != NULL) 969 (void) free(buf); 970 bufsiz = data.size + old.size + 2; 971 buf = xalloc(bufsiz); 972 } 973 sprintf(buf, "%s,%s", data.data, old.data); 974 data.size = data.size + old.size + 1; 975 data.data = buf; 976 if (tTd(38, 9)) 977 printf("db_map_store append=%s\n", data.data); 978 } 979 } 980 stat = db->put(db, &key, &data, 0); 981 } 982 if (stat != 0) 983 syserr("readaliases: db put (%s)", lhs); 984 } 985 986 987 /* 988 ** DB_MAP_CLOSE -- add distinguished entries and close the database 989 */ 990 991 void 992 db_map_close(map) 993 MAP *map; 994 { 995 register DB *db = map->map_db2; 996 997 if (tTd(38, 9)) 998 printf("db_map_close(%s, %s, %x)\n", 999 map->map_mname, map->map_file, map->map_mflags); 1000 1001 if (bitset(MF_WRITABLE, map->map_mflags)) 1002 { 1003 /* write out the distinguished alias */ 1004 db_map_store(map, "@", "@"); 1005 } 1006 1007 if (db->close(db) != 0) 1008 syserr("readaliases: db close failure"); 1009 } 1010 1011 #endif 1012 /* 1013 ** NIS Modules 1014 */ 1015 1016 # ifdef NIS 1017 1018 # ifndef YPERR_BUSY 1019 # define YPERR_BUSY 16 1020 # endif 1021 1022 /* 1023 ** NIS_MAP_OPEN -- open DBM map 1024 */ 1025 1026 bool 1027 nis_map_open(map, mode) 1028 MAP *map; 1029 int mode; 1030 { 1031 int yperr; 1032 register char *p; 1033 auto char *vp; 1034 auto int vsize; 1035 char *master; 1036 1037 if (tTd(38, 2)) 1038 printf("nis_map_open(%s, %s)\n", 1039 map->map_mname, map->map_file); 1040 1041 if (mode != O_RDONLY) 1042 { 1043 /* issue a pseudo-error message */ 1044 #ifdef ENOSYS 1045 errno = ENOSYS; 1046 #else 1047 # ifdef EFTYPE 1048 errno = EFTYPE; 1049 # else 1050 errno = ENXIO; 1051 # endif 1052 #endif 1053 return FALSE; 1054 } 1055 1056 p = strchr(map->map_file, '@'); 1057 if (p != NULL) 1058 { 1059 *p++ = '\0'; 1060 if (*p != '\0') 1061 map->map_domain = p; 1062 } 1063 1064 if (*map->map_file == '\0') 1065 map->map_file = "mail.aliases"; 1066 1067 if (map->map_domain == NULL) 1068 { 1069 yperr = yp_get_default_domain(&map->map_domain); 1070 if (yperr != 0) 1071 { 1072 if (!bitset(MF_OPTIONAL, map->map_mflags)) 1073 syserr("421 NIS map %s specified, but NIS not running\n", 1074 map->map_file); 1075 return FALSE; 1076 } 1077 } 1078 1079 /* check to see if this map actually exists */ 1080 yperr = yp_match(map->map_domain, map->map_file, "@", 1, 1081 &vp, &vsize); 1082 if (tTd(38, 10)) 1083 printf("nis_map_open: yp_match(%s, %s) => %s\n", 1084 map->map_domain, map->map_file, yperr_string(yperr)); 1085 if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY) 1086 { 1087 if (!bitset(MF_ALIAS, map->map_mflags) || 1088 aliaswait(map, NULL, TRUE)) 1089 return TRUE; 1090 } 1091 1092 if (!bitset(MF_OPTIONAL, map->map_mflags)) 1093 syserr("421 Cannot bind to domain %s: %s", map->map_domain, 1094 yperr_string(yperr)); 1095 1096 return FALSE; 1097 } 1098 1099 1100 /* 1101 ** NIS_MAP_LOOKUP -- look up a datum in a NIS map 1102 */ 1103 1104 char * 1105 nis_map_lookup(map, name, av, statp) 1106 MAP *map; 1107 char *name; 1108 char **av; 1109 int *statp; 1110 { 1111 char *vp; 1112 auto int vsize; 1113 int buflen; 1114 int yperr; 1115 char keybuf[MAXNAME + 1]; 1116 1117 if (tTd(38, 20)) 1118 printf("nis_map_lookup(%s, %s)\n", 1119 map->map_mname, name); 1120 1121 buflen = strlen(name); 1122 if (buflen > sizeof keybuf - 1) 1123 buflen = sizeof keybuf - 1; 1124 bcopy(name, keybuf, buflen + 1); 1125 if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 1126 makelower(keybuf); 1127 yperr = YPERR_KEY; 1128 if (bitset(MF_TRY0NULL, map->map_mflags)) 1129 { 1130 yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen, 1131 &vp, &vsize); 1132 if (yperr == 0) 1133 map->map_mflags &= ~MF_TRY1NULL; 1134 } 1135 if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags)) 1136 { 1137 buflen++; 1138 yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen, 1139 &vp, &vsize); 1140 if (yperr == 0) 1141 map->map_mflags &= ~MF_TRY0NULL; 1142 } 1143 if (yperr != 0) 1144 { 1145 if (yperr != YPERR_KEY && yperr != YPERR_BUSY) 1146 map->map_mflags &= ~(MF_VALID|MF_OPEN); 1147 return NULL; 1148 } 1149 if (bitset(MF_MATCHONLY, map->map_mflags)) 1150 return map_rewrite(map, name, strlen(name), NULL); 1151 else 1152 return map_rewrite(map, vp, vsize, av); 1153 } 1154 1155 #endif 1156 /* 1157 ** NISPLUS Modules 1158 ** 1159 ** This code donated by Sun Microsystems. 1160 */ 1161 1162 #ifdef NISPLUS 1163 1164 #undef NIS /* symbol conflict in nis.h */ 1165 #include <rpcsvc/nis.h> 1166 #include <rpcsvc/nislib.h> 1167 1168 #define EN_col(col) zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val 1169 #define COL_NAME(res,i) ((res->objects.objects_val)->TA_data.ta_cols.ta_cols_val)[i].tc_name 1170 #define COL_MAX(res) ((res->objects.objects_val)->TA_data.ta_cols.ta_cols_len) 1171 #define PARTIAL_NAME(x) ((x)[strlen(x) - 1] != '.') 1172 1173 /* 1174 ** NISPLUS_MAP_OPEN -- open nisplus table 1175 */ 1176 1177 bool 1178 nisplus_map_open(map, mode) 1179 MAP *map; 1180 int mode; 1181 { 1182 register char *p; 1183 char qbuf[MAXLINE + NIS_MAXNAMELEN]; 1184 nis_result *res = NULL; 1185 u_int objs_len; 1186 nis_object *obj_ptr; 1187 int retry_cnt, max_col, i; 1188 1189 if (tTd(38, 2)) 1190 printf("nisplus_map_open(%s, %s, %d)\n", 1191 map->map_mname, map->map_file, mode); 1192 1193 if (mode != O_RDONLY) 1194 { 1195 errno = ENODEV; 1196 return FALSE; 1197 } 1198 1199 if (*map->map_file == '\0') 1200 map->map_file = "mail_aliases.org_dir"; 1201 1202 if (PARTIAL_NAME(map->map_file) && map->map_domain == NULL) 1203 { 1204 /* set default NISPLUS Domain to $m */ 1205 extern char *nisplus_default_domain(); 1206 1207 map->map_domain = newstr(nisplus_default_domain()); 1208 if (tTd(38, 2)) 1209 printf("nisplus_map_open(%s): using domain %s\n", 1210 map->map_file, map->map_domain); 1211 } 1212 if (!PARTIAL_NAME(map->map_file)) 1213 map->map_domain = newstr(""); 1214 1215 /* check to see if this map actually exists */ 1216 if (PARTIAL_NAME(map->map_file)) 1217 sprintf(qbuf, "%s.%s", map->map_file, map->map_domain); 1218 else 1219 strcpy(qbuf, map->map_file); 1220 1221 retry_cnt = 0; 1222 while (res == NULL || res->status != NIS_SUCCESS) 1223 { 1224 res = nis_lookup(qbuf, FOLLOW_LINKS); 1225 switch (res->status) 1226 { 1227 case NIS_SUCCESS: 1228 case NIS_TRYAGAIN: 1229 case NIS_RPCERROR: 1230 case NIS_NAMEUNREACHABLE: 1231 break; 1232 1233 default: /* all other nisplus errors */ 1234 #if 0 1235 if (!bitset(MF_OPTIONAL, map->map_mflags)) 1236 syserr("421 Cannot find table %s.%s: %s", 1237 map->map_file, map->map_domain, 1238 nis_sperrno(res->status)); 1239 #endif 1240 errno = EBADR; 1241 return FALSE; 1242 } 1243 sleep(2); /* try not to overwhelm hosed server */ 1244 if (retry_cnt++ > 4) 1245 { 1246 errno = EBADR; 1247 return FALSE; 1248 } 1249 } 1250 1251 if (NIS_RES_NUMOBJ(res) != 1 || 1252 (NIS_RES_OBJECT(res)->zo_data.zo_type != TABLE_OBJ)) 1253 { 1254 if (tTd(38, 10)) 1255 printf("nisplus_map_open: %s is not a table\n", qbuf); 1256 #if 0 1257 if (!bitset(MF_OPTIONAL, map->map_mflags)) 1258 syserr("421 %s.%s: %s is not a table", 1259 map->map_file, map->map_domain, 1260 nis_sperrno(res->status)); 1261 #endif 1262 errno = EBADR; 1263 return FALSE; 1264 } 1265 /* default key column is column 0 */ 1266 if (map->map_keycolnm == NULL) 1267 map->map_keycolnm = newstr(COL_NAME(res,0)); 1268 1269 max_col = COL_MAX(res); 1270 1271 /* verify the key column exist */ 1272 for (i=0; i< max_col; i++) 1273 { 1274 if (!strcmp(map->map_keycolnm, COL_NAME(res,i))) 1275 break; 1276 } 1277 if (i == max_col) 1278 { 1279 if (tTd(38, 2)) 1280 printf("nisplus_map_open(%s): can not find key column %s\n", 1281 map->map_file, map->map_keycolnm); 1282 errno = EBADR; 1283 return FALSE; 1284 } 1285 1286 /* default value column is the last column */ 1287 if (map->map_valcolnm == NULL) 1288 { 1289 map->map_valcolno = max_col - 1; 1290 return TRUE; 1291 } 1292 1293 for (i=0; i< max_col; i++) 1294 { 1295 if (strcmp(map->map_valcolnm, COL_NAME(res,i)) == 0) 1296 { 1297 map->map_valcolno = i; 1298 return TRUE; 1299 } 1300 } 1301 1302 if (tTd(38, 2)) 1303 printf("nisplus_map_open(%s): can not find column %s\n", 1304 map->map_file, map->map_keycolnm); 1305 errno = EBADR; 1306 return FALSE; 1307 } 1308 1309 1310 /* 1311 ** NISPLUS_MAP_LOOKUP -- look up a datum in a NISPLUS table 1312 */ 1313 1314 char * 1315 nisplus_map_lookup(map, name, av, statp) 1316 MAP *map; 1317 char *name; 1318 char **av; 1319 int *statp; 1320 { 1321 char *vp; 1322 auto int vsize; 1323 int buflen; 1324 char search_key[MAXNAME + 1]; 1325 char qbuf[MAXLINE + NIS_MAXNAMELEN]; 1326 nis_result *result; 1327 1328 if (tTd(38, 20)) 1329 printf("nisplus_map_lookup(%s, %s)\n", 1330 map->map_mname, name); 1331 1332 if (!bitset(MF_OPEN, map->map_mflags)) 1333 { 1334 if (nisplus_map_open(map, O_RDONLY)) 1335 map->map_mflags |= MF_OPEN; 1336 else 1337 { 1338 *statp = EX_UNAVAILABLE; 1339 return NULL; 1340 } 1341 } 1342 1343 buflen = strlen(name); 1344 if (buflen > sizeof search_key - 1) 1345 buflen = sizeof search_key - 1; 1346 bcopy(name, search_key, buflen + 1); 1347 if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 1348 makelower(search_key); 1349 1350 /* construct the query */ 1351 if (PARTIAL_NAME(map->map_file)) 1352 sprintf(qbuf, "[%s=%s],%s.%s", map->map_keycolnm, 1353 search_key, map->map_file, map->map_domain); 1354 else 1355 sprintf(qbuf, "[%s=%s],%s", map->map_keycolnm, 1356 search_key, map->map_file); 1357 1358 if (tTd(38, 20)) 1359 printf("qbuf=%s\n", qbuf); 1360 result = nis_list(qbuf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL); 1361 if (result->status == NIS_SUCCESS) 1362 { 1363 int count; 1364 char *str; 1365 1366 if ((count = NIS_RES_NUMOBJ(result)) != 1) 1367 { 1368 if (LogLevel > 10) 1369 syslog(LOG_WARNING, 1370 "%s:Lookup error, expected 1 entry, got (%d)", 1371 map->map_file, count); 1372 1373 /* ignore second entry */ 1374 if (tTd(38, 20)) 1375 printf("nisplus_map_lookup(%s), got %d entries, additional entries ignored\n", 1376 name, count); 1377 } 1378 1379 vp = ((NIS_RES_OBJECT(result))->EN_col(map->map_valcolno)); 1380 /* set the length of the result */ 1381 if (vp == NULL) 1382 vp = ""; 1383 vsize = strlen(vp); 1384 if (tTd(38, 20)) 1385 printf("nisplus_map_lookup(%s), found %s\n", 1386 name, vp); 1387 if (bitset(MF_MATCHONLY, map->map_mflags)) 1388 str = map_rewrite(map, name, strlen(name), NULL); 1389 else 1390 str = map_rewrite(map, vp, vsize, av); 1391 nis_freeresult(result); 1392 #ifdef MAP_EXIT_STAT 1393 *statp = EX_OK; 1394 #endif 1395 return str; 1396 } 1397 else 1398 { 1399 #ifdef MAP_EXIT_STAT 1400 if (result->status == NIS_NOTFOUND) 1401 *statp = EX_NOTFOUND; 1402 else if (result->status == NIS_TRYAGAIN) 1403 *statp = EX_TEMPFAIL; 1404 else 1405 { 1406 *statp = EX_UNAVAILABLE; 1407 map->map_mflags &= ~(MF_VALID|MF_OPEN); 1408 } 1409 #else 1410 if ((result->status != NIS_NOTFOUND) && 1411 (result->status != NIS_TRYAGAIN)) 1412 map->map_mflags &= ~(MF_VALID|MF_OPEN); 1413 #endif 1414 } 1415 if (tTd(38, 20)) 1416 printf("nisplus_map_lookup(%s), failed\n", name); 1417 nis_freeresult(result); 1418 return NULL; 1419 } 1420 1421 1422 char * 1423 nisplus_default_domain() 1424 { 1425 static char default_domain[MAXNAME + 1] = ""; 1426 char *p; 1427 1428 if (default_domain[0] != '\0') 1429 return(default_domain); 1430 1431 p = nis_local_directory(); 1432 strcpy(default_domain, p); 1433 return default_domain; 1434 } 1435 1436 #endif /* NISPLUS */ 1437 /* 1438 ** HESIOD Modules 1439 */ 1440 1441 #ifdef HESIOD 1442 1443 #include <hesiod.h> 1444 1445 char * 1446 hes_map_lookup(map, name, av, statp) 1447 MAP *map; 1448 char *name; 1449 char **av; 1450 int *statp; 1451 { 1452 char **hp; 1453 char *retdata = NULL; 1454 int i; 1455 1456 if (tTd(38, 20)) 1457 printf("hes_map_lookup(%s, %s)\n", map->map_file, name); 1458 1459 hp = hes_resolve(name, map->map_file); 1460 if (hp == NULL) 1461 return NULL; 1462 1463 if (hp[0] != NULL) 1464 { 1465 if (tTd(38, 20)) 1466 printf(" %d %s\n", i, hp[0]); 1467 if (bitset(MF_MATCHONLY, map->map_mflags)) 1468 retdata = map_rewrite(map, name, strlen(name), NULL); 1469 else 1470 retdata = map_rewrite(map, hp[0], strlen(hp[0]), av); 1471 } 1472 1473 for (i = 0; hp[i] != NULL; i++) 1474 free(hp[i]); 1475 free(hp); 1476 return retdata; 1477 } 1478 1479 #endif 1480 /* 1481 ** NeXT NETINFO Modules 1482 */ 1483 1484 #ifdef NETINFO 1485 1486 #define NETINFO_DEFAULT_DIR "/aliases" 1487 #define NETINFO_DEFAULT_PROPERTY "members" 1488 1489 1490 /* 1491 ** NI_MAP_OPEN -- open NetInfo Aliases 1492 */ 1493 1494 bool 1495 ni_map_open(map, mode) 1496 MAP *map; 1497 int mode; 1498 { 1499 char *p; 1500 1501 if (tTd(38, 20)) 1502 printf("ni_map_open: %s\n", map->map_file); 1503 1504 if (*map->map_file == '\0') 1505 map->map_file = NETINFO_DEFAULT_DIR; 1506 1507 if (map->map_valcolnm == NULL) 1508 map->map_valcolnm = NETINFO_DEFAULT_PROPERTY; 1509 1510 if (map->map_coldelim == '\0' && bitset(MF_ALIAS, map->map_mflags)) 1511 map->map_coldelim = ','; 1512 1513 return TRUE; 1514 } 1515 1516 1517 /* 1518 ** NI_MAP_LOOKUP -- look up a datum in NetInfo 1519 */ 1520 1521 char * 1522 ni_map_lookup(map, name, av, statp) 1523 MAP *map; 1524 char *name; 1525 char **av; 1526 int *statp; 1527 { 1528 char *res; 1529 char *propval; 1530 extern char *ni_propval(); 1531 1532 if (tTd(38, 20)) 1533 printf("ni_map_lookup(%s, %s)\n", 1534 map->map_mname, name); 1535 1536 propval = ni_propval(map->map_file, map->map_keycolnm, name, 1537 map->map_valcolnm, map->map_coldelim); 1538 1539 if (propval == NULL) 1540 return NULL; 1541 1542 if (bitset(MF_MATCHONLY, map->map_mflags)) 1543 res = map_rewrite(map, name, strlen(name), NULL); 1544 else 1545 res = map_rewrite(map, propval, strlen(propval), av); 1546 free(propval); 1547 return res; 1548 } 1549 1550 #endif 1551 /* 1552 ** TEXT (unindexed text file) Modules 1553 ** 1554 ** This code donated by Sun Microsystems. 1555 */ 1556 1557 1558 /* 1559 ** TEXT_MAP_OPEN -- open text table 1560 */ 1561 1562 bool 1563 text_map_open(map, mode) 1564 MAP *map; 1565 int mode; 1566 { 1567 struct stat sbuf; 1568 1569 if (tTd(38, 2)) 1570 printf("text_map_open(%s, %s, %d)\n", 1571 map->map_mname, map->map_file, mode); 1572 1573 if (mode != O_RDONLY) 1574 { 1575 errno = ENODEV; 1576 return FALSE; 1577 } 1578 1579 if (*map->map_file == '\0') 1580 { 1581 if (tTd(38, 2)) 1582 printf("text_map_open: file name required\n"); 1583 return FALSE; 1584 } 1585 1586 if (map->map_file[0] != '/') 1587 { 1588 if (tTd(38, 2)) 1589 printf("text_map_open(%s): file name must be fully qualified\n", 1590 map->map_file); 1591 return FALSE; 1592 } 1593 /* check to see if this map actually accessable */ 1594 if (access(map->map_file, R_OK) <0) 1595 return FALSE; 1596 1597 /* check to see if this map actually exist */ 1598 if (stat(map->map_file, &sbuf) <0) 1599 { 1600 if (tTd(38, 2)) 1601 printf("text_map_open(%s): can not stat %s\n", 1602 map->map_file, map->map_file); 1603 return FALSE; 1604 } 1605 1606 if (!S_ISREG(sbuf.st_mode)) 1607 { 1608 if (tTd(38, 2)) 1609 printf("text_map_open(%s): %s is not a file\n", 1610 map->map_file, map->map_file); 1611 return FALSE; 1612 } 1613 1614 if (map->map_keycolnm == NULL) 1615 map->map_keycolno = 0; 1616 else 1617 { 1618 if (!isdigit(*map->map_keycolnm)) 1619 { 1620 if (tTd(38, 2)) 1621 printf("text_map_open(%s): -k should specify a number, not %s\n", 1622 map->map_file, map->map_keycolnm); 1623 return FALSE; 1624 } 1625 map->map_keycolno = atoi(map->map_keycolnm); 1626 } 1627 1628 if (map->map_valcolnm == NULL) 1629 map->map_valcolno = 0; 1630 else 1631 { 1632 if (!isdigit(*map->map_valcolnm)) 1633 { 1634 if (tTd(38, 2)) 1635 printf("text_map_open(%s): -v should specify a number, not %s\n", 1636 map->map_file, map->map_valcolnm); 1637 return FALSE; 1638 } 1639 map->map_valcolno = atoi(map->map_valcolnm); 1640 } 1641 1642 if (tTd(38, 2)) 1643 { 1644 printf("text_map_open(%s): delimiter = ", 1645 map->map_file); 1646 if (map->map_coldelim == '\0') 1647 printf("(white space)\n"); 1648 else 1649 printf("%c\n", map->map_coldelim); 1650 } 1651 1652 return TRUE; 1653 } 1654 1655 1656 /* 1657 ** TEXT_MAP_LOOKUP -- look up a datum in a TEXT table 1658 */ 1659 1660 char * 1661 text_map_lookup(map, name, av, statp) 1662 MAP *map; 1663 char *name; 1664 char **av; 1665 int *statp; 1666 { 1667 char *vp; 1668 auto int vsize; 1669 int buflen; 1670 char search_key[MAXNAME + 1]; 1671 char linebuf[MAXLINE]; 1672 FILE *f; 1673 char buf[MAXNAME + 1]; 1674 char delim; 1675 int key_idx; 1676 bool found_it; 1677 extern char *get_column(); 1678 1679 1680 found_it = FALSE; 1681 if (tTd(38, 20)) 1682 printf("text_map_lookup(%s)\n", name); 1683 1684 buflen = strlen(name); 1685 if (buflen > sizeof search_key - 1) 1686 buflen = sizeof search_key - 1; 1687 bcopy(name, search_key, buflen + 1); 1688 if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 1689 makelower(search_key); 1690 1691 f = fopen(map->map_file, "r"); 1692 if (f == NULL) 1693 { 1694 map->map_mflags &= ~(MF_VALID|MF_OPEN); 1695 *statp = EX_UNAVAILABLE; 1696 return NULL; 1697 } 1698 key_idx = map->map_keycolno; 1699 delim = map->map_coldelim; 1700 while (fgets(linebuf, MAXLINE, f)) 1701 { 1702 char *lf; 1703 if (linebuf[0] == '#') 1704 continue; /* skip comment line */ 1705 if (lf = strchr(linebuf, '\n')) 1706 *lf = '\0'; 1707 if (!strcasecmp(search_key, 1708 get_column(linebuf, key_idx, delim, buf))) 1709 { 1710 found_it = TRUE; 1711 break; 1712 } 1713 } 1714 fclose(f); 1715 if (!found_it) 1716 { 1717 #ifdef MAP_EXIT_STAT 1718 *statp = EX_NOTFOUND; 1719 #endif 1720 return(NULL); 1721 } 1722 vp = get_column(linebuf, map->map_valcolno, delim, buf); 1723 vsize = strlen(vp); 1724 #ifdef MAP_EXIT_STAT 1725 *statp = EX_OK; 1726 #endif 1727 if (bitset(MF_MATCHONLY, map->map_mflags)) 1728 return map_rewrite(map, name, strlen(name), NULL); 1729 else 1730 return map_rewrite(map, vp, vsize, av); 1731 } 1732 /* 1733 ** STAB (Symbol Table) Modules 1734 */ 1735 1736 1737 /* 1738 ** STAB_MAP_LOOKUP -- look up alias in symbol table 1739 */ 1740 1741 char * 1742 stab_map_lookup(map, name, av, pstat) 1743 register MAP *map; 1744 char *name; 1745 char **av; 1746 int *pstat; 1747 { 1748 register STAB *s; 1749 1750 if (tTd(38, 20)) 1751 printf("stab_lookup(%s, %s)\n", 1752 map->map_mname, name); 1753 1754 s = stab(name, ST_ALIAS, ST_FIND); 1755 if (s != NULL) 1756 return (s->s_alias); 1757 return (NULL); 1758 } 1759 1760 1761 /* 1762 ** STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild) 1763 */ 1764 1765 void 1766 stab_map_store(map, lhs, rhs) 1767 register MAP *map; 1768 char *lhs; 1769 char *rhs; 1770 { 1771 register STAB *s; 1772 1773 s = stab(lhs, ST_ALIAS, ST_ENTER); 1774 s->s_alias = newstr(rhs); 1775 } 1776 1777 1778 /* 1779 ** STAB_MAP_OPEN -- initialize (reads data file) 1780 ** 1781 ** This is a wierd case -- it is only intended as a fallback for 1782 ** aliases. For this reason, opens for write (only during a 1783 ** "newaliases") always fails, and opens for read open the 1784 ** actual underlying text file instead of the database. 1785 */ 1786 1787 bool 1788 stab_map_open(map, mode) 1789 register MAP *map; 1790 int mode; 1791 { 1792 FILE *af; 1793 struct stat st; 1794 1795 if (tTd(38, 2)) 1796 printf("stab_map_open(%s, %s)\n", 1797 map->map_mname, map->map_file); 1798 1799 if (mode != O_RDONLY) 1800 { 1801 errno = ENODEV; 1802 return FALSE; 1803 } 1804 1805 af = fopen(map->map_file, "r"); 1806 if (af == NULL) 1807 return FALSE; 1808 readaliases(map, af, FALSE, FALSE); 1809 1810 if (fstat(fileno(af), &st) >= 0) 1811 map->map_mtime = st.st_mtime; 1812 fclose(af); 1813 1814 return TRUE; 1815 } 1816 /* 1817 ** Implicit Modules 1818 ** 1819 ** Tries several types. For back compatibility of aliases. 1820 */ 1821 1822 1823 /* 1824 ** IMPL_MAP_LOOKUP -- lookup in best open database 1825 */ 1826 1827 char * 1828 impl_map_lookup(map, name, av, pstat) 1829 MAP *map; 1830 char *name; 1831 char **av; 1832 int *pstat; 1833 { 1834 if (tTd(38, 20)) 1835 printf("impl_map_lookup(%s, %s)\n", 1836 map->map_mname, name); 1837 1838 #ifdef NEWDB 1839 if (bitset(MF_IMPL_HASH, map->map_mflags)) 1840 return db_map_lookup(map, name, av, pstat); 1841 #endif 1842 #ifdef NDBM 1843 if (bitset(MF_IMPL_NDBM, map->map_mflags)) 1844 return ndbm_map_lookup(map, name, av, pstat); 1845 #endif 1846 return stab_map_lookup(map, name, av, pstat); 1847 } 1848 1849 /* 1850 ** IMPL_MAP_STORE -- store in open databases 1851 */ 1852 1853 void 1854 impl_map_store(map, lhs, rhs) 1855 MAP *map; 1856 char *lhs; 1857 char *rhs; 1858 { 1859 #ifdef NEWDB 1860 if (bitset(MF_IMPL_HASH, map->map_mflags)) 1861 db_map_store(map, lhs, rhs); 1862 #endif 1863 #ifdef NDBM 1864 if (bitset(MF_IMPL_NDBM, map->map_mflags)) 1865 ndbm_map_store(map, lhs, rhs); 1866 #endif 1867 stab_map_store(map, lhs, rhs); 1868 } 1869 1870 /* 1871 ** IMPL_MAP_OPEN -- implicit database open 1872 */ 1873 1874 bool 1875 impl_map_open(map, mode) 1876 MAP *map; 1877 int mode; 1878 { 1879 struct stat stb; 1880 1881 if (tTd(38, 2)) 1882 printf("impl_map_open(%s, %s, %d)\n", 1883 map->map_mname, map->map_file, mode); 1884 1885 if (stat(map->map_file, &stb) < 0) 1886 { 1887 /* no alias file at all */ 1888 if (tTd(38, 3)) 1889 printf("no map file\n"); 1890 return FALSE; 1891 } 1892 1893 #ifdef NEWDB 1894 map->map_mflags |= MF_IMPL_HASH; 1895 if (hash_map_open(map, mode)) 1896 { 1897 #if defined(NDBM) && defined(NIS) 1898 if (mode == O_RDONLY || access("/var/yp/Makefile", R_OK) != 0) 1899 #endif 1900 return TRUE; 1901 } 1902 else 1903 map->map_mflags &= ~MF_IMPL_HASH; 1904 #endif 1905 #ifdef NDBM 1906 map->map_mflags |= MF_IMPL_NDBM; 1907 if (ndbm_map_open(map, mode)) 1908 { 1909 return TRUE; 1910 } 1911 else 1912 map->map_mflags &= ~MF_IMPL_NDBM; 1913 #endif 1914 1915 #if defined(NEWDB) || defined(NDBM) 1916 if (Verbose) 1917 message("WARNING: cannot open alias database %s", map->map_file); 1918 #else 1919 if (mode != O_RDONLY) 1920 usrerr("Cannot rebuild aliases: no database format defined"); 1921 #endif 1922 1923 return stab_map_open(map, mode); 1924 } 1925 1926 1927 /* 1928 ** IMPL_MAP_CLOSE -- close any open database(s) 1929 */ 1930 1931 void 1932 impl_map_close(map) 1933 MAP *map; 1934 { 1935 if (tTd(38, 20)) 1936 printf("impl_map_close(%s, %s, %x)\n", 1937 map->map_mname, map->map_file, map->map_mflags); 1938 #ifdef NEWDB 1939 if (bitset(MF_IMPL_HASH, map->map_mflags)) 1940 { 1941 db_map_close(map); 1942 map->map_mflags &= ~MF_IMPL_HASH; 1943 } 1944 #endif 1945 1946 #ifdef NDBM 1947 if (bitset(MF_IMPL_NDBM, map->map_mflags)) 1948 { 1949 ndbm_map_close(map); 1950 map->map_mflags &= ~MF_IMPL_NDBM; 1951 } 1952 #endif 1953 } 1954 /* 1955 ** User map class. 1956 ** 1957 ** Provides access to the system password file. 1958 */ 1959 1960 /* 1961 ** USER_MAP_OPEN -- open user map 1962 ** 1963 ** Really just binds field names to field numbers. 1964 */ 1965 1966 bool 1967 user_map_open(map, mode) 1968 MAP *map; 1969 int mode; 1970 { 1971 if (tTd(38, 2)) 1972 printf("user_map_open(%s)\n", map->map_mname); 1973 1974 if (mode != O_RDONLY) 1975 { 1976 /* issue a pseudo-error message */ 1977 #ifdef ENOSYS 1978 errno = ENOSYS; 1979 #else 1980 # ifdef EFTYPE 1981 errno = EFTYPE; 1982 # else 1983 errno = ENXIO; 1984 # endif 1985 #endif 1986 return FALSE; 1987 } 1988 if (map->map_valcolnm == NULL) 1989 /* nothing */ ; 1990 else if (strcasecmp(map->map_valcolnm, "name") == 0) 1991 map->map_valcolno = 1; 1992 else if (strcasecmp(map->map_valcolnm, "passwd") == 0) 1993 map->map_valcolno = 2; 1994 else if (strcasecmp(map->map_valcolnm, "uid") == 0) 1995 map->map_valcolno = 3; 1996 else if (strcasecmp(map->map_valcolnm, "gid") == 0) 1997 map->map_valcolno = 4; 1998 else if (strcasecmp(map->map_valcolnm, "gecos") == 0) 1999 map->map_valcolno = 5; 2000 else if (strcasecmp(map->map_valcolnm, "dir") == 0) 2001 map->map_valcolno = 6; 2002 else if (strcasecmp(map->map_valcolnm, "shell") == 0) 2003 map->map_valcolno = 7; 2004 else 2005 { 2006 syserr("User map %s: unknown column name %s", 2007 map->map_mname, map->map_valcolnm); 2008 return FALSE; 2009 } 2010 return TRUE; 2011 } 2012 2013 2014 /* 2015 ** USER_MAP_LOOKUP -- look up a user in the passwd file. 2016 */ 2017 2018 #include <pwd.h> 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 = 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