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