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