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