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