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