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.38 (Berkeley) 12/10/94"; 11 #endif /* not lint */ 12 13 #include "sendmail.h" 14 15 #ifdef NDBM 16 #include <ndbm.h> 17 #endif 18 #ifdef NEWDB 19 #include <db.h> 20 #endif 21 #ifdef NIS 22 #include <rpcsvc/ypclnt.h> 23 #endif 24 25 /* 26 ** MAP.C -- implementations for various map classes. 27 ** 28 ** Each map class implements a series of functions: 29 ** 30 ** bool map_parse(MAP *map, char *args) 31 ** Parse the arguments from the config file. Return TRUE 32 ** if they were ok, FALSE otherwise. Fill in map with the 33 ** values. 34 ** 35 ** char *map_lookup(MAP *map, char *key, char **args, int *pstat) 36 ** Look up the key in the given map. If found, do any 37 ** rewriting the map wants (including "args" if desired) 38 ** and return the value. Set *pstat to the appropriate status 39 ** on error and return NULL. Args will be NULL if called 40 ** from the alias routines, although this should probably 41 ** not be relied upon. It is suggested you call map_rewrite 42 ** to return the results -- it takes care of null termination 43 ** and uses a dynamically expanded buffer as needed. 44 ** 45 ** void map_store(MAP *map, char *key, char *value) 46 ** Store the key:value pair in the map. 47 ** 48 ** bool map_open(MAP *map, int mode) 49 ** Open the map for the indicated mode. Mode should 50 ** be either O_RDONLY or O_RDWR. Return TRUE if it 51 ** was opened successfully, FALSE otherwise. If the open 52 ** failed an the MF_OPTIONAL flag is not set, it should 53 ** also print an error. If the MF_ALIAS bit is set 54 ** and this map class understands the @:@ convention, it 55 ** should call aliaswait() before returning. 56 ** 57 ** void map_close(MAP *map) 58 ** Close the map. 59 */ 60 61 #define DBMMODE 0644 62 63 extern bool aliaswait __P((MAP *, char *, int)); 64 /* 65 ** MAP_PARSEARGS -- parse config line arguments for database lookup 66 ** 67 ** This is a generic version of the map_parse method. 68 ** 69 ** Parameters: 70 ** map -- the map being initialized. 71 ** ap -- a pointer to the args on the config line. 72 ** 73 ** Returns: 74 ** TRUE -- if everything parsed OK. 75 ** FALSE -- otherwise. 76 ** 77 ** Side Effects: 78 ** null terminates the filename; stores it in map 79 */ 80 81 bool 82 map_parseargs(map, ap) 83 MAP *map; 84 char *ap; 85 { 86 register char *p = ap; 87 88 map->map_mflags |= MF_TRY0NULL | MF_TRY1NULL; 89 for (;;) 90 { 91 while (isascii(*p) && isspace(*p)) 92 p++; 93 if (*p != '-') 94 break; 95 switch (*++p) 96 { 97 case 'N': 98 map->map_mflags |= MF_INCLNULL; 99 map->map_mflags &= ~MF_TRY0NULL; 100 break; 101 102 case 'O': 103 map->map_mflags &= ~MF_TRY1NULL; 104 break; 105 106 case 'o': 107 map->map_mflags |= MF_OPTIONAL; 108 break; 109 110 case 'f': 111 map->map_mflags |= MF_NOFOLDCASE; 112 break; 113 114 case 'm': 115 map->map_mflags |= MF_MATCHONLY; 116 break; 117 118 case 'a': 119 map->map_app = ++p; 120 break; 121 122 case 'k': 123 while (isascii(*++p) && isspace(*p)) 124 continue; 125 map->map_keycolnm = p; 126 break; 127 128 case 'v': 129 while (isascii(*++p) && isspace(*p)) 130 continue; 131 map->map_valcolnm = p; 132 break; 133 134 case 'z': 135 if (*++p != '\\') 136 map->map_coldelim = *p; 137 else 138 { 139 switch (*++p) 140 { 141 case 'n': 142 map->map_coldelim = '\n'; 143 break; 144 145 case 't': 146 map->map_coldelim = '\t'; 147 break; 148 149 default: 150 map->map_coldelim = '\\'; 151 } 152 } 153 break; 154 } 155 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 156 p++; 157 if (*p != '\0') 158 *p++ = '\0'; 159 } 160 if (map->map_app != NULL) 161 map->map_app = newstr(map->map_app); 162 if (map->map_keycolnm != NULL) 163 map->map_keycolnm = newstr(map->map_keycolnm); 164 if (map->map_valcolnm != NULL) 165 map->map_valcolnm = newstr(map->map_valcolnm); 166 167 if (*p != '\0') 168 { 169 map->map_file = p; 170 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 171 p++; 172 if (*p != '\0') 173 *p++ = '\0'; 174 map->map_file = newstr(map->map_file); 175 } 176 177 while (*p != '\0' && isascii(*p) && isspace(*p)) 178 p++; 179 if (*p != '\0') 180 map->map_rebuild = newstr(p); 181 182 if (map->map_file == NULL && 183 !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 p = strchr(map->map_file, '@'); 1466 if (p != NULL) 1467 { 1468 *p++ = '\0'; 1469 if (*p != '\0') 1470 map->map_domain = p; 1471 } 1472 if (*map->map_file == '\0') 1473 map->map_file = NETINFO_DEFAULT_DIR; 1474 1475 if (map->map_domain == NULL) 1476 map->map_domain = NETINFO_DEFAULT_PROPERTY; 1477 1478 if (map->map_coldelim == '\0' && bitset(MF_ALIAS, map->map_mflags)) 1479 map->map_coldelim = ','; 1480 1481 return TRUE; 1482 } 1483 1484 1485 /* 1486 ** NI_MAP_LOOKUP -- look up a datum in NetInfo 1487 */ 1488 1489 char * 1490 ni_map_lookup(map, name, av, statp) 1491 MAP *map; 1492 char *name; 1493 char **av; 1494 int *statp; 1495 { 1496 char *res; 1497 char *propval; 1498 extern char *ni_propval(); 1499 1500 if (tTd(38, 20)) 1501 printf("ni_map_lookup(%s, %s)\n", 1502 map->map_mname, name); 1503 1504 propval = ni_propval(map->map_file, map->map_keycolnm, name, 1505 map->map_valcolnm, map->map_coldelim); 1506 1507 if (propval == NULL) 1508 return NULL; 1509 1510 if (bitset(MF_MATCHONLY, map->map_mflags)) 1511 res = map_rewrite(map, name, strlen(name), NULL); 1512 else 1513 res = map_rewrite(map, propval, strlen(propval), av); 1514 free(propval); 1515 return res; 1516 } 1517 1518 #endif 1519 /* 1520 ** TEXT (unindexed text file) Modules 1521 ** 1522 ** This code donated by Sun Microsystems. 1523 */ 1524 1525 1526 /* 1527 ** TEXT_MAP_OPEN -- open text table 1528 */ 1529 1530 bool 1531 text_map_open(map, mode) 1532 MAP *map; 1533 int mode; 1534 { 1535 struct stat sbuf; 1536 1537 if (tTd(38, 2)) 1538 printf("text_map_open(%s, %s, %d)\n", 1539 map->map_mname, map->map_file, mode); 1540 1541 if (mode != O_RDONLY) 1542 { 1543 errno = ENODEV; 1544 return FALSE; 1545 } 1546 1547 if (*map->map_file == '\0') 1548 { 1549 if (tTd(38, 2)) 1550 printf("text_map_open: file name required\n"); 1551 return FALSE; 1552 } 1553 1554 if (map->map_file[0] != '/') 1555 { 1556 if (tTd(38, 2)) 1557 printf("text_map_open(%s): file name must be fully qualified\n", 1558 map->map_file); 1559 return FALSE; 1560 } 1561 /* check to see if this map actually accessable */ 1562 if (access(map->map_file, R_OK) <0) 1563 return FALSE; 1564 1565 /* check to see if this map actually exist */ 1566 if (stat(map->map_file, &sbuf) <0) 1567 { 1568 if (tTd(38, 2)) 1569 printf("text_map_open(%s): can not stat %s\n", 1570 map->map_file, map->map_file); 1571 return FALSE; 1572 } 1573 1574 if (!S_ISREG(sbuf.st_mode)) 1575 { 1576 if (tTd(38, 2)) 1577 printf("text_map_open(%s): %s is not a file\n", 1578 map->map_file, map->map_file); 1579 return FALSE; 1580 } 1581 1582 if (map->map_keycolnm == NULL) 1583 map->map_keycolno = 0; 1584 else 1585 { 1586 if (!isdigit(*map->map_keycolnm)) 1587 { 1588 if (tTd(38, 2)) 1589 printf("text_map_open(%s): -k should specify a number, not %s\n", 1590 map->map_file, map->map_keycolnm); 1591 return FALSE; 1592 } 1593 map->map_keycolno = atoi(map->map_keycolnm); 1594 } 1595 1596 if (map->map_valcolnm == NULL) 1597 map->map_valcolno = 0; 1598 else 1599 { 1600 if (!isdigit(*map->map_valcolnm)) 1601 { 1602 if (tTd(38, 2)) 1603 printf("text_map_open(%s): -v should specify a number, not %s\n", 1604 map->map_file, map->map_valcolnm); 1605 return FALSE; 1606 } 1607 map->map_valcolno = atoi(map->map_valcolnm); 1608 } 1609 1610 if (map->map_coldelim == '\0') 1611 map->map_coldelim = ':'; 1612 1613 if (tTd(38, 2)) 1614 { 1615 printf("text_map_open(%s): delimiter = %c\n", 1616 map->map_file, map->map_coldelim); 1617 } 1618 1619 return TRUE; 1620 } 1621 1622 1623 /* 1624 ** TEXT_MAP_LOOKUP -- look up a datum in a TEXT table 1625 */ 1626 1627 char * 1628 text_map_lookup(map, name, av, statp) 1629 MAP *map; 1630 char *name; 1631 char **av; 1632 int *statp; 1633 { 1634 char *vp; 1635 auto int vsize; 1636 int buflen; 1637 char search_key[MAXNAME + 1]; 1638 char linebuf[MAXLINE]; 1639 FILE *f; 1640 char buf[MAXNAME+1]; 1641 char delim; 1642 int key_idx; 1643 bool found_it; 1644 extern char *get_column(); 1645 1646 1647 found_it = FALSE; 1648 if (tTd(38, 20)) 1649 printf("text_map_lookup(%s)\n", name); 1650 1651 buflen = strlen(name); 1652 if (buflen > sizeof search_key - 1) 1653 buflen = sizeof search_key - 1; 1654 bcopy(name, search_key, buflen + 1); 1655 if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 1656 makelower(search_key); 1657 1658 f = fopen(map->map_file, "r"); 1659 if (f == NULL) 1660 { 1661 map->map_mflags &= ~(MF_VALID|MF_OPEN); 1662 *statp = EX_UNAVAILABLE; 1663 return NULL; 1664 } 1665 key_idx = map->map_keycolno; 1666 delim = map->map_coldelim; 1667 while (fgets(linebuf, MAXLINE, f)) 1668 { 1669 char *lf; 1670 if (linebuf[0] == '#') 1671 continue; /* skip comment line */ 1672 if (lf = strchr(linebuf, '\n')) 1673 *lf = '\0'; 1674 if (!strcasecmp(search_key, 1675 get_column(linebuf, key_idx, delim, buf))) 1676 { 1677 found_it = TRUE; 1678 break; 1679 } 1680 } 1681 fclose(f); 1682 if (!found_it) 1683 { 1684 #ifdef MAP_EXIT_STAT 1685 *statp = EX_NOTFOUND; 1686 #endif 1687 return(NULL); 1688 } 1689 vp = get_column(linebuf, map->map_valcolno, delim, buf); 1690 vsize = strlen(vp); 1691 #ifdef MAP_EXIT_STAT 1692 *statp = EX_OK; 1693 #endif 1694 if (bitset(MF_MATCHONLY, map->map_mflags)) 1695 return map_rewrite(map, name, strlen(name), NULL); 1696 else 1697 return map_rewrite(map, vp, vsize, av); 1698 } 1699 /* 1700 ** STAB (Symbol Table) Modules 1701 */ 1702 1703 1704 /* 1705 ** STAB_MAP_LOOKUP -- look up alias in symbol table 1706 */ 1707 1708 char * 1709 stab_map_lookup(map, name, av, pstat) 1710 register MAP *map; 1711 char *name; 1712 char **av; 1713 int *pstat; 1714 { 1715 register STAB *s; 1716 1717 if (tTd(38, 20)) 1718 printf("stab_lookup(%s, %s)\n", 1719 map->map_mname, name); 1720 1721 s = stab(name, ST_ALIAS, ST_FIND); 1722 if (s != NULL) 1723 return (s->s_alias); 1724 return (NULL); 1725 } 1726 1727 1728 /* 1729 ** STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild) 1730 */ 1731 1732 void 1733 stab_map_store(map, lhs, rhs) 1734 register MAP *map; 1735 char *lhs; 1736 char *rhs; 1737 { 1738 register STAB *s; 1739 1740 s = stab(lhs, ST_ALIAS, ST_ENTER); 1741 s->s_alias = newstr(rhs); 1742 } 1743 1744 1745 /* 1746 ** STAB_MAP_OPEN -- initialize (reads data file) 1747 ** 1748 ** This is a wierd case -- it is only intended as a fallback for 1749 ** aliases. For this reason, opens for write (only during a 1750 ** "newaliases") always fails, and opens for read open the 1751 ** actual underlying text file instead of the database. 1752 */ 1753 1754 bool 1755 stab_map_open(map, mode) 1756 register MAP *map; 1757 int mode; 1758 { 1759 FILE *af; 1760 struct stat st; 1761 1762 if (tTd(38, 2)) 1763 printf("stab_map_open(%s, %s)\n", 1764 map->map_mname, map->map_file); 1765 1766 if (mode != O_RDONLY) 1767 { 1768 errno = ENODEV; 1769 return FALSE; 1770 } 1771 1772 af = fopen(map->map_file, "r"); 1773 if (af == NULL) 1774 return FALSE; 1775 readaliases(map, af, FALSE, FALSE); 1776 1777 if (fstat(fileno(af), &st) >= 0) 1778 map->map_mtime = st.st_mtime; 1779 fclose(af); 1780 1781 return TRUE; 1782 } 1783 /* 1784 ** Implicit Modules 1785 ** 1786 ** Tries several types. For back compatibility of aliases. 1787 */ 1788 1789 1790 /* 1791 ** IMPL_MAP_LOOKUP -- lookup in best open database 1792 */ 1793 1794 char * 1795 impl_map_lookup(map, name, av, pstat) 1796 MAP *map; 1797 char *name; 1798 char **av; 1799 int *pstat; 1800 { 1801 if (tTd(38, 20)) 1802 printf("impl_map_lookup(%s, %s)\n", 1803 map->map_mname, name); 1804 1805 #ifdef NEWDB 1806 if (bitset(MF_IMPL_HASH, map->map_mflags)) 1807 return db_map_lookup(map, name, av, pstat); 1808 #endif 1809 #ifdef NDBM 1810 if (bitset(MF_IMPL_NDBM, map->map_mflags)) 1811 return ndbm_map_lookup(map, name, av, pstat); 1812 #endif 1813 return stab_map_lookup(map, name, av, pstat); 1814 } 1815 1816 /* 1817 ** IMPL_MAP_STORE -- store in open databases 1818 */ 1819 1820 void 1821 impl_map_store(map, lhs, rhs) 1822 MAP *map; 1823 char *lhs; 1824 char *rhs; 1825 { 1826 #ifdef NEWDB 1827 if (bitset(MF_IMPL_HASH, map->map_mflags)) 1828 db_map_store(map, lhs, rhs); 1829 #endif 1830 #ifdef NDBM 1831 if (bitset(MF_IMPL_NDBM, map->map_mflags)) 1832 ndbm_map_store(map, lhs, rhs); 1833 #endif 1834 stab_map_store(map, lhs, rhs); 1835 } 1836 1837 /* 1838 ** IMPL_MAP_OPEN -- implicit database open 1839 */ 1840 1841 bool 1842 impl_map_open(map, mode) 1843 MAP *map; 1844 int mode; 1845 { 1846 struct stat stb; 1847 1848 if (tTd(38, 2)) 1849 printf("impl_map_open(%s, %s, %d)\n", 1850 map->map_mname, map->map_file, mode); 1851 1852 if (stat(map->map_file, &stb) < 0) 1853 { 1854 /* no alias file at all */ 1855 if (tTd(38, 3)) 1856 printf("no map file\n"); 1857 return FALSE; 1858 } 1859 1860 #ifdef NEWDB 1861 map->map_mflags |= MF_IMPL_HASH; 1862 if (hash_map_open(map, mode)) 1863 { 1864 #if defined(NDBM) && defined(NIS) 1865 if (mode == O_RDONLY || access("/var/yp/Makefile", R_OK) != 0) 1866 #endif 1867 return TRUE; 1868 } 1869 else 1870 map->map_mflags &= ~MF_IMPL_HASH; 1871 #endif 1872 #ifdef NDBM 1873 map->map_mflags |= MF_IMPL_NDBM; 1874 if (ndbm_map_open(map, mode)) 1875 { 1876 return TRUE; 1877 } 1878 else 1879 map->map_mflags &= ~MF_IMPL_NDBM; 1880 #endif 1881 1882 #if defined(NEWDB) || defined(NDBM) 1883 if (Verbose) 1884 message("WARNING: cannot open alias database %s", map->map_file); 1885 #else 1886 if (mode != O_RDONLY) 1887 usrerr("Cannot rebuild aliases: no database format defined"); 1888 #endif 1889 1890 return stab_map_open(map, mode); 1891 } 1892 1893 1894 /* 1895 ** IMPL_MAP_CLOSE -- close any open database(s) 1896 */ 1897 1898 void 1899 impl_map_close(map) 1900 MAP *map; 1901 { 1902 if (tTd(38, 20)) 1903 printf("impl_map_close(%s, %s, %x)\n", 1904 map->map_mname, map->map_file, map->map_mflags); 1905 #ifdef NEWDB 1906 if (bitset(MF_IMPL_HASH, map->map_mflags)) 1907 { 1908 db_map_close(map); 1909 map->map_mflags &= ~MF_IMPL_HASH; 1910 } 1911 #endif 1912 1913 #ifdef NDBM 1914 if (bitset(MF_IMPL_NDBM, map->map_mflags)) 1915 { 1916 ndbm_map_close(map); 1917 map->map_mflags &= ~MF_IMPL_NDBM; 1918 } 1919 #endif 1920 } 1921 /* 1922 ** User map class. 1923 ** 1924 ** Provides access to the system password file. 1925 */ 1926 1927 /* 1928 ** USER_MAP_OPEN -- open user map 1929 ** 1930 ** Really just binds field names to field numbers. 1931 */ 1932 1933 bool 1934 user_map_open(map, mode) 1935 MAP *map; 1936 int mode; 1937 { 1938 if (tTd(38, 2)) 1939 printf("user_map_open(%s)\n", map->map_mname); 1940 1941 if (mode != O_RDONLY) 1942 { 1943 /* issue a pseudo-error message */ 1944 #ifdef ENOSYS 1945 errno = ENOSYS; 1946 #else 1947 # ifdef EFTYPE 1948 errno = EFTYPE; 1949 # else 1950 errno = ENXIO; 1951 # endif 1952 #endif 1953 return FALSE; 1954 } 1955 if (map->map_valcolnm == NULL) 1956 /* nothing */ ; 1957 else if (strcasecmp(map->map_valcolnm, "name") == 0) 1958 map->map_valcolno = 1; 1959 else if (strcasecmp(map->map_valcolnm, "passwd") == 0) 1960 map->map_valcolno = 2; 1961 else if (strcasecmp(map->map_valcolnm, "uid") == 0) 1962 map->map_valcolno = 3; 1963 else if (strcasecmp(map->map_valcolnm, "gid") == 0) 1964 map->map_valcolno = 4; 1965 else if (strcasecmp(map->map_valcolnm, "gecos") == 0) 1966 map->map_valcolno = 5; 1967 else if (strcasecmp(map->map_valcolnm, "dir") == 0) 1968 map->map_valcolno = 6; 1969 else if (strcasecmp(map->map_valcolnm, "shell") == 0) 1970 map->map_valcolno = 7; 1971 else 1972 { 1973 syserr("User map %s: unknown column name %s", 1974 map->map_mname, map->map_valcolnm); 1975 return FALSE; 1976 } 1977 return TRUE; 1978 } 1979 1980 1981 /* 1982 ** USER_MAP_LOOKUP -- look up a user in the passwd file. 1983 */ 1984 1985 #include <pwd.h> 1986 1987 char * 1988 user_map_lookup(map, key, av, statp) 1989 MAP *map; 1990 char *key; 1991 char **av; 1992 int *statp; 1993 { 1994 struct passwd *pw; 1995 1996 if (tTd(38, 20)) 1997 printf("user_map_lookup(%s, %s)\n", 1998 map->map_mname, key); 1999 2000 pw = getpwnam(key); 2001 if (pw == NULL) 2002 return NULL; 2003 if (bitset(MF_MATCHONLY, map->map_mflags)) 2004 return map_rewrite(map, key, strlen(key), NULL); 2005 else 2006 { 2007 char *rwval; 2008 char buf[30]; 2009 2010 switch (map->map_valcolno) 2011 { 2012 case 0: 2013 case 1: 2014 rwval = pw->pw_name; 2015 break; 2016 2017 case 2: 2018 rwval = pw->pw_passwd; 2019 break; 2020 2021 case 3: 2022 sprintf(buf, "%d", pw->pw_uid); 2023 rwval = buf; 2024 break; 2025 2026 case 4: 2027 sprintf(buf, "%d", pw->pw_gid); 2028 rwval = buf; 2029 break; 2030 2031 case 5: 2032 rwval = pw->pw_gecos; 2033 break; 2034 2035 case 6: 2036 rwval = pw->pw_dir; 2037 break; 2038 2039 case 7: 2040 rwval = pw->pw_shell; 2041 break; 2042 } 2043 return map_rewrite(map, rwval, strlen(rwval), av); 2044 } 2045 } 2046 /* 2047 ** Sequenced map type. 2048 ** 2049 ** Tries each map in order until something matches, much like 2050 ** implicit. Stores go to the first map in the list that can 2051 ** support storing. 2052 ** 2053 ** This is slightly unusual in that there are two interfaces. 2054 ** The "sequence" interface lets you stack maps arbitrarily. 2055 ** The "switch" interface builds a sequence map by looking 2056 ** at a system-dependent configuration file such as 2057 ** /etc/nsswitch.conf on Solaris or /etc/svc.conf on Ultrix. 2058 ** 2059 ** We don't need an explicit open, since all maps are 2060 ** opened during startup, including underlying maps. 2061 */ 2062 2063 /* 2064 ** SEQ_MAP_PARSE -- Sequenced map parsing 2065 */ 2066 2067 bool 2068 seq_map_parse(map, ap) 2069 MAP *map; 2070 char *ap; 2071 { 2072 int maxmap; 2073 2074 if (tTd(38, 2)) 2075 printf("seq_map_parse(%s, %s)\n", map->map_mname, ap); 2076 maxmap = 0; 2077 while (*ap != '\0') 2078 { 2079 register char *p; 2080 STAB *s; 2081 2082 /* find beginning of map name */ 2083 while (isascii(*ap) && isspace(*ap)) 2084 ap++; 2085 for (p = ap; isascii(*p) && isalnum(*p); p++) 2086 continue; 2087 if (*p != '\0') 2088 *p++ = '\0'; 2089 while (*p != '\0' && (!isascii(*p) || !isalnum(*p))) 2090 p++; 2091 if (*ap == '\0') 2092 { 2093 ap = p; 2094 continue; 2095 } 2096 s = stab(ap, ST_MAP, ST_FIND); 2097 if (s == NULL) 2098 { 2099 syserr("Sequence map %s: unknown member map %s", 2100 map->map_mname, ap); 2101 } 2102 else if (maxmap == MAXMAPSTACK) 2103 { 2104 syserr("Sequence map %s: too many member maps (%d max)", 2105 map->map_mname, MAXMAPSTACK); 2106 maxmap++; 2107 } 2108 else if (maxmap < MAXMAPSTACK) 2109 { 2110 map->map_stack[maxmap++] = &s->s_map; 2111 } 2112 ap = p; 2113 } 2114 return TRUE; 2115 } 2116 2117 2118 /* 2119 ** SWITCH_MAP_OPEN -- open a switched map 2120 ** 2121 ** This looks at the system-dependent configuration and builds 2122 ** a sequence map that does the same thing. 2123 ** 2124 ** Every system must define a switch_map_find routine in conf.c 2125 ** that will return the list of service types associated with a 2126 ** given service class. 2127 */ 2128 2129 bool 2130 switch_map_open(map, mode) 2131 MAP *map; 2132 int mode; 2133 { 2134 int mapno; 2135 int nmaps; 2136 char *maptype[MAXMAPSTACK]; 2137 2138 if (tTd(38, 2)) 2139 printf("switch_map_open(%s, %s, %d)\n", 2140 map->map_mname, map->map_file, mode); 2141 2142 nmaps = switch_map_find(map->map_file, maptype, map->map_return); 2143 if (tTd(38, 19)) 2144 { 2145 printf("\tswitch_map_find => %d\n", nmaps); 2146 for (mapno = 0; mapno < nmaps; mapno++) 2147 printf("\t\t%s\n", maptype[mapno]); 2148 } 2149 if (nmaps <= 0 || nmaps > MAXMAPSTACK) 2150 return FALSE; 2151 2152 for (mapno = 0; mapno < nmaps; mapno++) 2153 { 2154 register STAB *s; 2155 char nbuf[MAXNAME + 1]; 2156 2157 if (maptype[mapno] == NULL) 2158 continue; 2159 (void) sprintf(nbuf, "%s.%s", map->map_file, maptype[mapno]); 2160 s = stab(nbuf, ST_MAP, ST_FIND); 2161 if (s == NULL) 2162 { 2163 syserr("Switch map %s: unknown member map %s", 2164 map->map_mname, nbuf); 2165 } 2166 else 2167 { 2168 map->map_stack[mapno] = &s->s_map; 2169 if (tTd(38, 4)) 2170 printf("\tmap_stack[%d] = %s:%s\n", 2171 mapno, s->s_map.map_class->map_cname, 2172 nbuf); 2173 } 2174 } 2175 return TRUE; 2176 } 2177 2178 2179 /* 2180 ** SEQ_MAP_CLOSE -- close all underlying maps 2181 */ 2182 2183 seq_map_close(map) 2184 MAP *map; 2185 { 2186 int mapno; 2187 2188 if (tTd(38, 20)) 2189 printf("seq_map_close(%s)\n", map->map_mname); 2190 for (mapno = 0; mapno < MAXMAPSTACK; mapno++) 2191 { 2192 MAP *mm = map->map_stack[mapno]; 2193 2194 if (mm == NULL || !bitset(MF_OPEN, mm->map_mflags)) 2195 continue; 2196 mm->map_class->map_close(mm); 2197 } 2198 } 2199 2200 2201 /* 2202 ** SEQ_MAP_LOOKUP -- sequenced map lookup 2203 */ 2204 2205 char * 2206 seq_map_lookup(map, key, args, pstat) 2207 MAP *map; 2208 char *key; 2209 char **args; 2210 int *pstat; 2211 { 2212 int mapno; 2213 int mapbit = 0x01; 2214 2215 if (tTd(38, 20)) 2216 printf("seq_map_lookup(%s, %s)\n", map->map_mname, key); 2217 2218 for (mapno = 0; mapno < MAXMAPSTACK; mapbit <<= 1, mapno++) 2219 { 2220 MAP *mm = map->map_stack[mapno]; 2221 int stat = 0; 2222 char *rv; 2223 2224 if (mm == NULL) 2225 continue; 2226 if (!bitset(MF_OPEN, mm->map_mflags)) 2227 { 2228 if (bitset(mapbit, map->map_return[MA_UNAVAIL])) 2229 { 2230 *pstat = EX_UNAVAILABLE; 2231 return NULL; 2232 } 2233 continue; 2234 } 2235 rv = mm->map_class->map_lookup(mm, key, args, &stat); 2236 if (rv != NULL) 2237 return rv; 2238 if (stat == 0 && bitset(mapbit, map->map_return[MA_NOTFOUND])) 2239 return NULL; 2240 if (stat != 0 && bitset(mapbit, map->map_return[MA_TRYAGAIN])) 2241 { 2242 *pstat = stat; 2243 return NULL; 2244 } 2245 } 2246 return NULL; 2247 } 2248 2249 2250 /* 2251 ** SEQ_MAP_STORE -- sequenced map store 2252 */ 2253 2254 void 2255 seq_map_store(map, key, val) 2256 MAP *map; 2257 char *key; 2258 char *val; 2259 { 2260 int mapno; 2261 2262 if (tTd(38, 12)) 2263 printf("seq_map_store(%s, %s, %s)\n", 2264 map->map_mname, key, val); 2265 2266 for (mapno = 0; mapno < MAXMAPSTACK; mapno++) 2267 { 2268 MAP *mm = map->map_stack[mapno]; 2269 2270 if (mm == NULL || !bitset(MF_WRITABLE, mm->map_mflags)) 2271 continue; 2272 2273 mm->map_class->map_store(mm, key, val); 2274 return; 2275 } 2276 syserr("seq_map_store(%s, %s, %s): no writable map", 2277 map->map_mname, key, val); 2278 } 2279 /* 2280 ** NULL stubs 2281 */ 2282 2283 bool 2284 null_map_open(map, mode) 2285 MAP *map; 2286 int mode; 2287 { 2288 return TRUE; 2289 } 2290 2291 void 2292 null_map_close(map) 2293 MAP *map; 2294 { 2295 return; 2296 } 2297 2298 void 2299 null_map_store(map, key, val) 2300 MAP *map; 2301 char *key; 2302 char *val; 2303 { 2304 return; 2305 } 2306 2307 2308 /* 2309 ** BOGUS stubs 2310 */ 2311 2312 char * 2313 bogus_map_lookup(map, key, args, pstat) 2314 MAP *map; 2315 char *key; 2316 char **args; 2317 int *pstat; 2318 { 2319 *pstat = EX_TEMPFAIL; 2320 return NULL; 2321 } 2322 2323 MAPCLASS BogusMapClass = 2324 { 2325 "bogus-map", NULL, 0, 2326 NULL, bogus_map_lookup, null_map_store, 2327 null_map_open, null_map_close, 2328 }; 2329