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