1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988 Regents of the University of California. 4 * All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 static char sccsid[] = "@(#)parseaddr.c 6.1 (Berkeley) 12/21/92"; 11 #endif /* not lint */ 12 13 # include "sendmail.h" 14 15 /* 16 ** PARSEADDR -- Parse an address 17 ** 18 ** Parses an address and breaks it up into three parts: a 19 ** net to transmit the message on, the host to transmit it 20 ** to, and a user on that host. These are loaded into an 21 ** ADDRESS header with the values squirreled away if necessary. 22 ** The "user" part may not be a real user; the process may 23 ** just reoccur on that machine. For example, on a machine 24 ** with an arpanet connection, the address 25 ** csvax.bill@berkeley 26 ** will break up to a "user" of 'csvax.bill' and a host 27 ** of 'berkeley' -- to be transmitted over the arpanet. 28 ** 29 ** Parameters: 30 ** addr -- the address to parse. 31 ** a -- a pointer to the address descriptor buffer. 32 ** If NULL, a header will be created. 33 ** copyf -- determines what shall be copied: 34 ** -1 -- don't copy anything. The printname 35 ** (q_paddr) is just addr, and the 36 ** user & host are allocated internally 37 ** to parse. 38 ** 0 -- copy out the parsed user & host, but 39 ** don't copy the printname. 40 ** +1 -- copy everything. 41 ** delim -- the character to terminate the address, passed 42 ** to prescan. 43 ** e -- the envelope that will contain this address. 44 ** 45 ** Returns: 46 ** A pointer to the address descriptor header (`a' if 47 ** `a' is non-NULL). 48 ** NULL on error. 49 ** 50 ** Side Effects: 51 ** none 52 */ 53 54 /* following delimiters are inherent to the internal algorithms */ 55 # define DELIMCHARS "\001()<>,;\\\"\r\n" /* word delimiters */ 56 57 ADDRESS * 58 parseaddr(addr, a, copyf, delim, e) 59 char *addr; 60 register ADDRESS *a; 61 int copyf; 62 char delim; 63 register ENVELOPE *e; 64 { 65 register char **pvp; 66 char pvpbuf[PSBUFSIZE]; 67 extern char **prescan(); 68 extern ADDRESS *buildaddr(); 69 70 /* 71 ** Initialize and prescan address. 72 */ 73 74 e->e_to = addr; 75 if (tTd(20, 1)) 76 printf("\n--parseaddr(%s)\n", addr); 77 78 pvp = prescan(addr, delim, pvpbuf); 79 if (pvp == NULL) 80 { 81 if (tTd(20, 1)) 82 printf("parseaddr-->NULL\n"); 83 return (NULL); 84 } 85 86 /* 87 ** Apply rewriting rules. 88 ** Ruleset 0 does basic parsing. It must resolve. 89 */ 90 91 rewrite(pvp, 3); 92 rewrite(pvp, 0); 93 94 /* 95 ** See if we resolved to a real mailer. 96 */ 97 98 if (pvp[0][0] != CANONNET) 99 { 100 setstat(EX_USAGE); 101 usrerr("cannot resolve name"); 102 return (NULL); 103 } 104 105 /* 106 ** Build canonical address from pvp. 107 */ 108 109 a = buildaddr(pvp, a); 110 if (a == NULL) 111 return (NULL); 112 113 /* 114 ** Make local copies of the host & user and then 115 ** transport them out. 116 */ 117 118 allocaddr(a, copyf, addr); 119 120 /* 121 ** Compute return value. 122 */ 123 124 if (tTd(20, 1)) 125 { 126 printf("parseaddr-->"); 127 printaddr(a, FALSE); 128 } 129 130 return (a); 131 } 132 /* 133 ** ALLOCADDR -- do local allocations of address on demand. 134 ** 135 ** Also lowercases the host name if requested. 136 ** 137 ** Parameters: 138 ** a -- the address to reallocate. 139 ** copyf -- the copy flag (see parseaddr for description). 140 ** paddr -- the printname of the address. 141 ** 142 ** Returns: 143 ** none. 144 ** 145 ** Side Effects: 146 ** Copies portions of a into local buffers as requested. 147 */ 148 149 allocaddr(a, copyf, paddr) 150 register ADDRESS *a; 151 int copyf; 152 char *paddr; 153 { 154 register MAILER *m = a->q_mailer; 155 156 if (copyf > 0 && paddr != NULL) 157 { 158 extern char *DelimChar; 159 char savec = *DelimChar; 160 161 *DelimChar = '\0'; 162 a->q_paddr = newstr(paddr); 163 *DelimChar = savec; 164 } 165 else 166 a->q_paddr = paddr; 167 168 if (a->q_user == NULL) 169 a->q_user = ""; 170 if (a->q_host == NULL) 171 a->q_host = ""; 172 173 if (copyf >= 0) 174 { 175 a->q_host = newstr(a->q_host); 176 if (a->q_user != a->q_paddr) 177 a->q_user = newstr(a->q_user); 178 } 179 180 if (a->q_paddr == NULL) 181 a->q_paddr = a->q_user; 182 183 /* 184 ** Convert host name to lower case if requested. 185 ** User name will be done later. 186 */ 187 188 if (!bitnset(M_HST_UPPER, m->m_flags)) 189 makelower(a->q_host); 190 } 191 /* 192 ** LOWERADDR -- map UPPER->lower case on addresses as requested. 193 ** 194 ** Parameters: 195 ** a -- address to be mapped. 196 ** 197 ** Returns: 198 ** none. 199 ** 200 ** Side Effects: 201 ** none. 202 */ 203 204 loweraddr(a) 205 register ADDRESS *a; 206 { 207 register MAILER *m = a->q_mailer; 208 209 if (!bitnset(M_USR_UPPER, m->m_flags)) 210 makelower(a->q_user); 211 } 212 /* 213 ** PRESCAN -- Prescan name and make it canonical 214 ** 215 ** Scans a name and turns it into a set of tokens. This process 216 ** deletes blanks and comments (in parentheses). 217 ** 218 ** This routine knows about quoted strings and angle brackets. 219 ** 220 ** There are certain subtleties to this routine. The one that 221 ** comes to mind now is that backslashes on the ends of names 222 ** are silently stripped off; this is intentional. The problem 223 ** is that some versions of sndmsg (like at LBL) set the kill 224 ** character to something other than @ when reading addresses; 225 ** so people type "csvax.eric\@berkeley" -- which screws up the 226 ** berknet mailer. 227 ** 228 ** Parameters: 229 ** addr -- the name to chomp. 230 ** delim -- the delimiter for the address, normally 231 ** '\0' or ','; \0 is accepted in any case. 232 ** If '\t' then we are reading the .cf file. 233 ** pvpbuf -- place to put the saved text -- note that 234 ** the pointers are static. 235 ** 236 ** Returns: 237 ** A pointer to a vector of tokens. 238 ** NULL on error. 239 ** 240 ** Side Effects: 241 ** sets DelimChar to point to the character matching 'delim'. 242 */ 243 244 /* states and character types */ 245 # define OPR 0 /* operator */ 246 # define ATM 1 /* atom */ 247 # define QST 2 /* in quoted string */ 248 # define SPC 3 /* chewing up spaces */ 249 # define ONE 4 /* pick up one character */ 250 251 # define NSTATES 5 /* number of states */ 252 # define TYPE 017 /* mask to select state type */ 253 254 /* meta bits for table */ 255 # define M 020 /* meta character; don't pass through */ 256 # define B 040 /* cause a break */ 257 # define MB M|B /* meta-break */ 258 259 static short StateTab[NSTATES][NSTATES] = 260 { 261 /* oldst chtype> OPR ATM QST SPC ONE */ 262 /*OPR*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, 263 /*ATM*/ OPR|B, ATM, QST|B, SPC|MB, ONE|B, 264 /*QST*/ QST, QST, OPR, QST, QST, 265 /*SPC*/ OPR, ATM, QST, SPC|M, ONE, 266 /*ONE*/ OPR, OPR, OPR, OPR, OPR, 267 }; 268 269 # define NOCHAR -1 /* signal nothing in lookahead token */ 270 271 char *DelimChar; /* set to point to the delimiter */ 272 273 char ** 274 prescan(addr, delim, pvpbuf) 275 char *addr; 276 char delim; 277 char pvpbuf[]; 278 { 279 register char *p; 280 register char *q; 281 register int c; 282 char **avp; 283 bool bslashmode; 284 int cmntcnt; 285 int anglecnt; 286 char *tok; 287 int state; 288 int newstate; 289 static char *av[MAXATOM+1]; 290 extern int errno; 291 292 /* make sure error messages don't have garbage on them */ 293 errno = 0; 294 295 q = pvpbuf; 296 bslashmode = FALSE; 297 cmntcnt = 0; 298 anglecnt = 0; 299 avp = av; 300 state = ATM; 301 c = NOCHAR; 302 p = addr; 303 if (tTd(22, 11)) 304 { 305 printf("prescan: "); 306 xputs(p); 307 (void) putchar('\n'); 308 } 309 310 do 311 { 312 /* read a token */ 313 tok = q; 314 for (;;) 315 { 316 /* store away any old lookahead character */ 317 if (c != NOCHAR) 318 { 319 /* see if there is room */ 320 if (q >= &pvpbuf[PSBUFSIZE - 5]) 321 { 322 usrerr("Address too long"); 323 DelimChar = p; 324 return (NULL); 325 } 326 327 /* squirrel it away */ 328 *q++ = c; 329 } 330 331 /* read a new input character */ 332 c = *p++; 333 if (c == '\0' || (c == delim && anglecnt <= 0)) 334 { 335 /* diagnose and patch up bad syntax */ 336 if (state == QST) 337 { 338 usrerr("Unbalanced '\"'"); 339 c = '"'; 340 } 341 else if (cmntcnt > 0) 342 { 343 usrerr("Unbalanced '('"); 344 c = ')'; 345 } 346 else if (anglecnt > 0) 347 { 348 c = '>'; 349 usrerr("Unbalanced '<'"); 350 } 351 else 352 break; 353 354 p--; 355 } 356 357 if (tTd(22, 101)) 358 printf("c=%c, s=%d; ", c, state); 359 360 /* chew up special characters */ 361 *q = '\0'; 362 if (bslashmode) 363 { 364 /* kludge \! for naive users */ 365 if (c != '!') 366 *q++ = '\\'; 367 bslashmode = FALSE; 368 continue; 369 } 370 371 if (c == '\\') 372 { 373 bslashmode = TRUE; 374 c = NOCHAR; 375 continue; 376 } 377 else if (state == QST) 378 { 379 /* do nothing, just avoid next clauses */ 380 } 381 else if (c == '(') 382 { 383 cmntcnt++; 384 c = NOCHAR; 385 } 386 else if (c == ')') 387 { 388 if (cmntcnt <= 0) 389 { 390 usrerr("Unbalanced ')'"); 391 DelimChar = p; 392 return (NULL); 393 } 394 else 395 cmntcnt--; 396 } 397 else if (cmntcnt > 0) 398 c = NOCHAR; 399 else if (c == '<') 400 anglecnt++; 401 else if (c == '>') 402 { 403 if (anglecnt <= 0) 404 { 405 usrerr("Unbalanced '>'"); 406 DelimChar = p; 407 return (NULL); 408 } 409 anglecnt--; 410 } 411 else if (delim == ' ' && isspace(c)) 412 c = ' '; 413 414 if (c == NOCHAR) 415 continue; 416 417 /* see if this is end of input */ 418 if (c == delim && anglecnt <= 0 && state != QST) 419 break; 420 421 newstate = StateTab[state][toktype(c)]; 422 if (tTd(22, 101)) 423 printf("ns=%02o\n", newstate); 424 state = newstate & TYPE; 425 if (bitset(M, newstate)) 426 c = NOCHAR; 427 if (bitset(B, newstate)) 428 break; 429 } 430 431 /* new token */ 432 if (tok != q) 433 { 434 *q++ = '\0'; 435 if (tTd(22, 36)) 436 { 437 printf("tok="); 438 xputs(tok); 439 (void) putchar('\n'); 440 } 441 if (avp >= &av[MAXATOM]) 442 { 443 syserr("prescan: too many tokens"); 444 DelimChar = p; 445 return (NULL); 446 } 447 *avp++ = tok; 448 } 449 } while (c != '\0' && (c != delim || anglecnt > 0)); 450 *avp = NULL; 451 DelimChar = --p; 452 if (tTd(22, 12)) 453 { 454 printf("prescan==>"); 455 printav(av); 456 } 457 if (av[0] != NULL) 458 return (av); 459 return (NULL); 460 } 461 /* 462 ** TOKTYPE -- return token type 463 ** 464 ** Parameters: 465 ** c -- the character in question. 466 ** 467 ** Returns: 468 ** Its type. 469 ** 470 ** Side Effects: 471 ** none. 472 */ 473 474 toktype(c) 475 register char c; 476 { 477 static char buf[50]; 478 static bool firstime = TRUE; 479 480 if (firstime) 481 { 482 firstime = FALSE; 483 expand("\001o", buf, &buf[sizeof buf - 1], CurEnv); 484 (void) strcat(buf, DELIMCHARS); 485 } 486 if (c == MATCHCLASS || c == MATCHREPL || c == MATCHNCLASS) 487 return (ONE); 488 if (c == '"') 489 return (QST); 490 if (!isascii(c)) 491 return (ATM); 492 if (isspace(c) || c == ')') 493 return (SPC); 494 if (iscntrl(c) || strchr(buf, c) != NULL) 495 return (OPR); 496 return (ATM); 497 } 498 /* 499 ** REWRITE -- apply rewrite rules to token vector. 500 ** 501 ** This routine is an ordered production system. Each rewrite 502 ** rule has a LHS (called the pattern) and a RHS (called the 503 ** rewrite); 'rwr' points the the current rewrite rule. 504 ** 505 ** For each rewrite rule, 'avp' points the address vector we 506 ** are trying to match against, and 'pvp' points to the pattern. 507 ** If pvp points to a special match value (MATCHZANY, MATCHANY, 508 ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp 509 ** matched is saved away in the match vector (pointed to by 'mvp'). 510 ** 511 ** When a match between avp & pvp does not match, we try to 512 ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS 513 ** we must also back out the match in mvp. If we reach a 514 ** MATCHANY or MATCHZANY we just extend the match and start 515 ** over again. 516 ** 517 ** When we finally match, we rewrite the address vector 518 ** and try over again. 519 ** 520 ** Parameters: 521 ** pvp -- pointer to token vector. 522 ** 523 ** Returns: 524 ** none. 525 ** 526 ** Side Effects: 527 ** pvp is modified. 528 */ 529 530 struct match 531 { 532 char **first; /* first token matched */ 533 char **last; /* last token matched */ 534 }; 535 536 # define MAXMATCH 9 /* max params per rewrite */ 537 538 539 rewrite(pvp, ruleset) 540 char **pvp; 541 int ruleset; 542 { 543 register char *ap; /* address pointer */ 544 register char *rp; /* rewrite pointer */ 545 register char **avp; /* address vector pointer */ 546 register char **rvp; /* rewrite vector pointer */ 547 register struct match *mlp; /* cur ptr into mlist */ 548 register struct rewrite *rwr; /* pointer to current rewrite rule */ 549 struct match mlist[MAXMATCH]; /* stores match on LHS */ 550 char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 551 552 if (OpMode == MD_TEST || tTd(21, 2)) 553 { 554 printf("rewrite: ruleset %2d input:", ruleset); 555 printav(pvp); 556 } 557 if (ruleset < 0 || ruleset >= MAXRWSETS) 558 { 559 syserr("rewrite: illegal ruleset number %d", ruleset); 560 return; 561 } 562 if (pvp == NULL) 563 return; 564 565 /* 566 ** Run through the list of rewrite rules, applying 567 ** any that match. 568 */ 569 570 for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 571 { 572 int loopcount = 0; 573 574 if (tTd(21, 12)) 575 { 576 printf("-----trying rule:"); 577 printav(rwr->r_lhs); 578 } 579 580 /* try to match on this rule */ 581 mlp = mlist; 582 rvp = rwr->r_lhs; 583 avp = pvp; 584 while ((ap = *avp) != NULL || *rvp != NULL) 585 { 586 if (++loopcount > 100) 587 { 588 syserr("Infinite loop in ruleset %d", ruleset); 589 printf("workspace: "); 590 printav(pvp); 591 break; 592 } 593 rp = *rvp; 594 if (tTd(21, 35)) 595 { 596 printf("operator="); 597 xputs(ap); 598 printf(", token="); 599 xputs(rp); 600 printf("\n"); 601 } 602 if (rp == NULL) 603 { 604 /* end-of-pattern before end-of-address */ 605 goto backup; 606 } 607 if (ap == NULL && *rp != MATCHZANY) 608 { 609 /* end-of-input */ 610 break; 611 } 612 613 switch (*rp) 614 { 615 register STAB *s; 616 617 case MATCHCLASS: 618 case MATCHNCLASS: 619 /* match any token in (not in) a class */ 620 s = stab(ap, ST_CLASS, ST_FIND); 621 if (s == NULL || !bitnset(rp[1], s->s_class)) 622 { 623 if (*rp == MATCHCLASS) 624 goto backup; 625 } 626 else if (*rp == MATCHNCLASS) 627 goto backup; 628 629 /* explicit fall-through */ 630 631 case MATCHONE: 632 case MATCHANY: 633 /* match exactly one token */ 634 mlp->first = avp; 635 mlp->last = avp++; 636 mlp++; 637 break; 638 639 case MATCHZANY: 640 /* match zero or more tokens */ 641 mlp->first = avp; 642 mlp->last = avp - 1; 643 mlp++; 644 break; 645 646 default: 647 /* must have exact match */ 648 if (strcasecmp(rp, ap)) 649 goto backup; 650 avp++; 651 break; 652 } 653 654 /* successful match on this token */ 655 rvp++; 656 continue; 657 658 backup: 659 /* match failed -- back up */ 660 while (--rvp >= rwr->r_lhs) 661 { 662 rp = *rvp; 663 if (*rp == MATCHANY || *rp == MATCHZANY) 664 { 665 /* extend binding and continue */ 666 avp = ++mlp[-1].last; 667 avp++; 668 rvp++; 669 break; 670 } 671 avp--; 672 if (*rp == MATCHONE || *rp == MATCHCLASS || 673 *rp == MATCHNCLASS) 674 { 675 /* back out binding */ 676 mlp--; 677 } 678 } 679 680 if (rvp < rwr->r_lhs) 681 { 682 /* total failure to match */ 683 break; 684 } 685 } 686 687 /* 688 ** See if we successfully matched 689 */ 690 691 if (rvp < rwr->r_lhs || *rvp != NULL) 692 { 693 if (tTd(21, 10)) 694 printf("----- rule fails\n"); 695 rwr = rwr->r_next; 696 continue; 697 } 698 699 rvp = rwr->r_rhs; 700 if (tTd(21, 12)) 701 { 702 printf("-----rule matches:"); 703 printav(rvp); 704 } 705 706 rp = *rvp; 707 if (*rp == CANONUSER) 708 { 709 rvp++; 710 rwr = rwr->r_next; 711 } 712 else if (*rp == CANONHOST) 713 { 714 rvp++; 715 rwr = NULL; 716 } 717 else if (*rp == CANONNET) 718 rwr = NULL; 719 720 /* substitute */ 721 for (avp = npvp; *rvp != NULL; rvp++) 722 { 723 register struct match *m; 724 register char **pp; 725 726 rp = *rvp; 727 if (*rp == MATCHREPL) 728 { 729 /* substitute from LHS */ 730 m = &mlist[rp[1] - '1']; 731 if (m < mlist || m >= mlp) 732 { 733 syserr("rewrite: ruleset %d: replacement $%c out of bounds", 734 ruleset, rp[1]); 735 return; 736 } 737 if (tTd(21, 15)) 738 { 739 printf("$%c:", rp[1]); 740 pp = m->first; 741 while (pp <= m->last) 742 { 743 printf(" %x=\"", *pp); 744 (void) fflush(stdout); 745 printf("%s\"", *pp++); 746 } 747 printf("\n"); 748 } 749 pp = m->first; 750 while (pp <= m->last) 751 { 752 if (avp >= &npvp[MAXATOM]) 753 { 754 syserr("rewrite: expansion too long"); 755 return; 756 } 757 *avp++ = *pp++; 758 } 759 } 760 else 761 { 762 /* vanilla replacement */ 763 if (avp >= &npvp[MAXATOM]) 764 { 765 toolong: 766 syserr("rewrite: expansion too long"); 767 return; 768 } 769 *avp++ = rp; 770 } 771 } 772 *avp++ = NULL; 773 774 /* 775 ** Check for any hostname/keyword lookups. 776 */ 777 778 for (rvp = npvp; *rvp != NULL; rvp++) 779 { 780 char **hbrvp; 781 char **xpvp; 782 int trsize; 783 char *olddelimchar; 784 char *replac; 785 int endtoken; 786 STAB *map; 787 char *mapname; 788 char **key_rvp; 789 char **arg_rvp; 790 char **default_rvp; 791 char buf[MAXNAME + 1]; 792 char *pvpb1[MAXATOM + 1]; 793 char *argvect[10]; 794 char pvpbuf[PSBUFSIZE]; 795 extern char *DelimChar; 796 797 if (**rvp != HOSTBEGIN && **rvp != LOOKUPBEGIN) 798 continue; 799 800 /* 801 ** Got a hostname/keyword lookup. 802 ** 803 ** This could be optimized fairly easily. 804 */ 805 806 hbrvp = rvp; 807 if (**rvp == HOSTBEGIN) 808 { 809 endtoken = HOSTEND; 810 mapname = "host"; 811 } 812 else 813 { 814 endtoken = LOOKUPEND; 815 mapname = *++rvp; 816 } 817 map = stab(mapname, ST_MAP, ST_FIND); 818 if (map == NULL) 819 syserr("rewrite: map %s not found", mapname); 820 821 /* extract the match part */ 822 key_rvp = ++rvp; 823 default_rvp = NULL; 824 arg_rvp = argvect; 825 xpvp = NULL; 826 replac = pvpbuf; 827 while (*rvp != NULL && **rvp != endtoken) 828 { 829 int nodetype = **rvp; 830 831 if (nodetype != CANONHOST && nodetype != CANONUSER) 832 { 833 rvp++; 834 continue; 835 } 836 837 *rvp++ = NULL; 838 839 if (xpvp != NULL) 840 { 841 cataddr(xpvp, replac, 842 &pvpbuf[sizeof pvpbuf] - replac); 843 *++arg_rvp = replac; 844 replac += strlen(replac) + 1; 845 xpvp = NULL; 846 } 847 switch (nodetype) 848 { 849 case CANONHOST: 850 xpvp = rvp; 851 break; 852 853 case CANONUSER: 854 default_rvp = rvp; 855 break; 856 } 857 } 858 if (*rvp != NULL) 859 *rvp++ = NULL; 860 if (xpvp != NULL) 861 { 862 cataddr(xpvp, replac, 863 &pvpbuf[sizeof pvpbuf] - replac); 864 *++arg_rvp = replac; 865 } 866 *++arg_rvp = NULL; 867 868 /* save the remainder of the input string */ 869 trsize = (int) (avp - rvp + 1) * sizeof *rvp; 870 bcopy((char *) rvp, (char *) pvpb1, trsize); 871 872 /* look it up */ 873 cataddr(key_rvp, buf, sizeof buf); 874 argvect[0] = buf; 875 if (map != NULL && bitset(MF_VALID, map->s_map.map_flags)) 876 { 877 int bsize = sizeof buf - 1; 878 879 if (map->s_map.map_app != NULL) 880 bsize -= strlen(map->s_map.map_app); 881 replac = (*map->s_map.map_class->map_lookup)(&map->s_map, 882 buf, sizeof buf - 1, argvect); 883 if (replac != NULL && map->s_map.map_app != NULL) 884 strcat(replac, map->s_map.map_app); 885 } 886 else 887 replac = NULL; 888 889 /* if no replacement, use default */ 890 if (replac == NULL && default_rvp != NULL) 891 { 892 char buf2[sizeof buf]; 893 894 /* rewrite the default with % translations */ 895 cataddr(default_rvp, buf2, sizeof buf2); 896 map_rewrite(buf2, sizeof buf2, buf, sizeof buf, 897 argvect); 898 replac = buf; 899 } 900 901 if (replac == NULL) 902 { 903 xpvp = key_rvp; 904 } 905 else 906 { 907 /* scan the new replacement */ 908 olddelimchar = DelimChar; 909 xpvp = prescan(replac, '\0', pvpbuf); 910 DelimChar = olddelimchar; 911 if (xpvp == NULL) 912 { 913 syserr("rewrite: cannot prescan map value: %s", replac); 914 return; 915 } 916 } 917 918 /* append it to the token list */ 919 for (avp = hbrvp; *xpvp != NULL; xpvp++) 920 { 921 *avp++ = newstr(*xpvp); 922 if (avp >= &npvp[MAXATOM]) 923 goto toolong; 924 } 925 926 /* restore the old trailing information */ 927 for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) 928 if (avp >= &npvp[MAXATOM]) 929 goto toolong; 930 931 break; 932 } 933 934 /* 935 ** Check for subroutine calls. 936 */ 937 938 if (*npvp != NULL && **npvp == CALLSUBR) 939 { 940 bcopy((char *) &npvp[2], (char *) pvp, 941 (int) (avp - npvp - 2) * sizeof *avp); 942 if (tTd(21, 3)) 943 printf("-----callsubr %s\n", npvp[1]); 944 rewrite(pvp, atoi(npvp[1])); 945 } 946 else 947 { 948 bcopy((char *) npvp, (char *) pvp, 949 (int) (avp - npvp) * sizeof *avp); 950 } 951 if (tTd(21, 4)) 952 { 953 printf("rewritten as:"); 954 printav(pvp); 955 } 956 } 957 958 if (OpMode == MD_TEST || tTd(21, 2)) 959 { 960 printf("rewrite: ruleset %2d returns:", ruleset); 961 printav(pvp); 962 } 963 } 964 /* 965 ** BUILDADDR -- build address from token vector. 966 ** 967 ** Parameters: 968 ** tv -- token vector. 969 ** a -- pointer to address descriptor to fill. 970 ** If NULL, one will be allocated. 971 ** 972 ** Returns: 973 ** NULL if there was an error. 974 ** 'a' otherwise. 975 ** 976 ** Side Effects: 977 ** fills in 'a' 978 */ 979 980 struct errcodes 981 { 982 char *ec_name; /* name of error code */ 983 int ec_code; /* numeric code */ 984 } ErrorCodes[] = 985 { 986 "usage", EX_USAGE, 987 "nouser", EX_NOUSER, 988 "nohost", EX_NOHOST, 989 "unavailable", EX_UNAVAILABLE, 990 "software", EX_SOFTWARE, 991 "tempfail", EX_TEMPFAIL, 992 "protocol", EX_PROTOCOL, 993 #ifdef EX_CONFIG 994 "config", EX_CONFIG, 995 #endif 996 NULL, EX_UNAVAILABLE, 997 }; 998 999 ADDRESS * 1000 buildaddr(tv, a) 1001 register char **tv; 1002 register ADDRESS *a; 1003 { 1004 static char buf[MAXNAME]; 1005 struct mailer **mp; 1006 register struct mailer *m; 1007 1008 if (a == NULL) 1009 a = (ADDRESS *) xalloc(sizeof *a); 1010 bzero((char *) a, sizeof *a); 1011 1012 /* figure out what net/mailer to use */ 1013 if (**tv != CANONNET) 1014 { 1015 syserr("buildaddr: no net"); 1016 return (NULL); 1017 } 1018 tv++; 1019 if (!strcasecmp(*tv, "error")) 1020 { 1021 if (**++tv == CANONHOST) 1022 { 1023 register struct errcodes *ep; 1024 1025 if (isdigit(**++tv)) 1026 { 1027 setstat(atoi(*tv)); 1028 } 1029 else 1030 { 1031 for (ep = ErrorCodes; ep->ec_name != NULL; ep++) 1032 if (strcasecmp(ep->ec_name, *tv) == 0) 1033 break; 1034 setstat(ep->ec_code); 1035 } 1036 tv++; 1037 } 1038 if (**tv != CANONUSER) 1039 syserr("buildaddr: error: no user"); 1040 buf[0] = '\0'; 1041 while (*++tv != NULL) 1042 { 1043 if (buf[0] != '\0') 1044 (void) strcat(buf, " "); 1045 (void) strcat(buf, *tv); 1046 } 1047 usrerr(buf); 1048 return (NULL); 1049 } 1050 for (mp = Mailer; (m = *mp++) != NULL; ) 1051 { 1052 if (!strcasecmp(m->m_name, *tv)) 1053 break; 1054 } 1055 if (m == NULL) 1056 { 1057 syserr("buildaddr: unknown mailer %s", *tv); 1058 return (NULL); 1059 } 1060 a->q_mailer = m; 1061 1062 /* figure out what host (if any) */ 1063 tv++; 1064 if (!bitnset(M_LOCAL, m->m_flags)) 1065 { 1066 if (**tv++ != CANONHOST) 1067 { 1068 syserr("buildaddr: no host"); 1069 return (NULL); 1070 } 1071 buf[0] = '\0'; 1072 while (*tv != NULL && **tv != CANONUSER) 1073 (void) strcat(buf, *tv++); 1074 a->q_host = newstr(buf); 1075 } 1076 else 1077 a->q_host = NULL; 1078 1079 /* figure out the user */ 1080 if (*tv == NULL || **tv != CANONUSER) 1081 { 1082 syserr("buildaddr: no user"); 1083 return (NULL); 1084 } 1085 1086 if (m == LocalMailer && tv[1] != NULL && strcmp(tv[1], "@") == 0) 1087 { 1088 tv++; 1089 a->q_flags |= QNOTREMOTE; 1090 } 1091 1092 /* rewrite according recipient mailer rewriting rules */ 1093 rewrite(++tv, 2); 1094 if (m->m_r_rwset > 0) 1095 rewrite(tv, m->m_r_rwset); 1096 rewrite(tv, 4); 1097 1098 /* save the result for the command line/RCPT argument */ 1099 cataddr(tv, buf, sizeof buf); 1100 a->q_user = buf; 1101 1102 return (a); 1103 } 1104 /* 1105 ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 1106 ** 1107 ** Parameters: 1108 ** pvp -- parameter vector to rebuild. 1109 ** buf -- buffer to build the string into. 1110 ** sz -- size of buf. 1111 ** 1112 ** Returns: 1113 ** none. 1114 ** 1115 ** Side Effects: 1116 ** Destroys buf. 1117 */ 1118 1119 cataddr(pvp, buf, sz) 1120 char **pvp; 1121 char *buf; 1122 register int sz; 1123 { 1124 bool oatomtok = FALSE; 1125 bool natomtok = FALSE; 1126 register int i; 1127 register char *p; 1128 1129 if (pvp == NULL) 1130 { 1131 (void) strcpy(buf, ""); 1132 return; 1133 } 1134 p = buf; 1135 sz -= 2; 1136 while (*pvp != NULL && (i = strlen(*pvp)) < sz) 1137 { 1138 natomtok = (toktype(**pvp) == ATM); 1139 if (oatomtok && natomtok) 1140 *p++ = SpaceSub; 1141 (void) strcpy(p, *pvp); 1142 oatomtok = natomtok; 1143 p += i; 1144 sz -= i + 1; 1145 pvp++; 1146 } 1147 *p = '\0'; 1148 } 1149 /* 1150 ** SAMEADDR -- Determine if two addresses are the same 1151 ** 1152 ** This is not just a straight comparison -- if the mailer doesn't 1153 ** care about the host we just ignore it, etc. 1154 ** 1155 ** Parameters: 1156 ** a, b -- pointers to the internal forms to compare. 1157 ** 1158 ** Returns: 1159 ** TRUE -- they represent the same mailbox. 1160 ** FALSE -- they don't. 1161 ** 1162 ** Side Effects: 1163 ** none. 1164 */ 1165 1166 bool 1167 sameaddr(a, b) 1168 register ADDRESS *a; 1169 register ADDRESS *b; 1170 { 1171 /* if they don't have the same mailer, forget it */ 1172 if (a->q_mailer != b->q_mailer) 1173 return (FALSE); 1174 1175 /* if the user isn't the same, we can drop out */ 1176 if (strcmp(a->q_user, b->q_user) != 0) 1177 return (FALSE); 1178 1179 /* if the mailer ignores hosts, we have succeeded! */ 1180 if (bitnset(M_LOCAL, a->q_mailer->m_flags)) 1181 return (TRUE); 1182 1183 /* otherwise compare hosts (but be careful for NULL ptrs) */ 1184 if (a->q_host == NULL || b->q_host == NULL) 1185 return (FALSE); 1186 if (strcmp(a->q_host, b->q_host) != 0) 1187 return (FALSE); 1188 1189 return (TRUE); 1190 } 1191 /* 1192 ** PRINTADDR -- print address (for debugging) 1193 ** 1194 ** Parameters: 1195 ** a -- the address to print 1196 ** follow -- follow the q_next chain. 1197 ** 1198 ** Returns: 1199 ** none. 1200 ** 1201 ** Side Effects: 1202 ** none. 1203 */ 1204 1205 printaddr(a, follow) 1206 register ADDRESS *a; 1207 bool follow; 1208 { 1209 bool first = TRUE; 1210 1211 while (a != NULL) 1212 { 1213 first = FALSE; 1214 printf("%x=", a); 1215 (void) fflush(stdout); 1216 printf("%s: mailer %d (%s), host `%s', user `%s', ruser `%s'\n", 1217 a->q_paddr, a->q_mailer->m_mno, a->q_mailer->m_name, 1218 a->q_host, a->q_user, a->q_ruser? a->q_ruser: "<null>"); 1219 printf("\tnext=%x, flags=%o, alias %x\n", a->q_next, a->q_flags, 1220 a->q_alias); 1221 printf("\thome=\"%s\", fullname=\"%s\"\n", a->q_home, 1222 a->q_fullname); 1223 1224 if (!follow) 1225 return; 1226 a = a->q_next; 1227 } 1228 if (first) 1229 printf("[NULL]\n"); 1230 } 1231 1232 /* 1233 ** REMOTENAME -- return the name relative to the current mailer 1234 ** 1235 ** Parameters: 1236 ** name -- the name to translate. 1237 ** m -- the mailer that we want to do rewriting relative 1238 ** to. 1239 ** senderaddress -- if set, uses the sender rewriting rules 1240 ** rather than the recipient rewriting rules. 1241 ** canonical -- if set, strip out any comment information, 1242 ** etc. 1243 ** 1244 ** Returns: 1245 ** the text string representing this address relative to 1246 ** the receiving mailer. 1247 ** 1248 ** Side Effects: 1249 ** none. 1250 ** 1251 ** Warnings: 1252 ** The text string returned is tucked away locally; 1253 ** copy it if you intend to save it. 1254 */ 1255 1256 char * 1257 remotename(name, m, senderaddress, canonical, e) 1258 char *name; 1259 struct mailer *m; 1260 bool senderaddress; 1261 bool canonical; 1262 register ENVELOPE *e; 1263 { 1264 register char **pvp; 1265 char *fancy; 1266 extern char *macvalue(); 1267 char *oldg = macvalue('g', e); 1268 static char buf[MAXNAME]; 1269 char lbuf[MAXNAME]; 1270 char pvpbuf[PSBUFSIZE]; 1271 extern char **prescan(); 1272 extern char *crackaddr(); 1273 1274 if (tTd(12, 1)) 1275 printf("remotename(%s)\n", name); 1276 1277 /* don't do anything if we are tagging it as special */ 1278 if ((senderaddress ? m->m_s_rwset : m->m_r_rwset) < 0) 1279 return (name); 1280 1281 /* 1282 ** Do a heuristic crack of this name to extract any comment info. 1283 ** This will leave the name as a comment and a $g macro. 1284 */ 1285 1286 if (canonical) 1287 fancy = "\001g"; 1288 else 1289 fancy = crackaddr(name); 1290 1291 /* 1292 ** Turn the name into canonical form. 1293 ** Normally this will be RFC 822 style, i.e., "user@domain". 1294 ** If this only resolves to "user", and the "C" flag is 1295 ** specified in the sending mailer, then the sender's 1296 ** domain will be appended. 1297 */ 1298 1299 pvp = prescan(name, '\0', pvpbuf); 1300 if (pvp == NULL) 1301 return (name); 1302 rewrite(pvp, 3); 1303 if (e->e_fromdomain != NULL) 1304 { 1305 /* append from domain to this address */ 1306 register char **pxp = pvp; 1307 1308 /* see if there is an "@domain" in the current name */ 1309 while (*pxp != NULL && strcmp(*pxp, "@") != 0) 1310 pxp++; 1311 if (*pxp == NULL) 1312 { 1313 /* no.... append the "@domain" from the sender */ 1314 register char **qxq = e->e_fromdomain; 1315 1316 while ((*pxp++ = *qxq++) != NULL) 1317 continue; 1318 rewrite(pvp, 3); 1319 } 1320 } 1321 1322 /* 1323 ** Do more specific rewriting. 1324 ** Rewrite using ruleset 1 or 2 depending on whether this is 1325 ** a sender address or not. 1326 ** Then run it through any receiving-mailer-specific rulesets. 1327 */ 1328 1329 if (senderaddress) 1330 { 1331 rewrite(pvp, 1); 1332 if (m->m_s_rwset > 0) 1333 rewrite(pvp, m->m_s_rwset); 1334 } 1335 else 1336 { 1337 rewrite(pvp, 2); 1338 if (m->m_r_rwset > 0) 1339 rewrite(pvp, m->m_r_rwset); 1340 } 1341 1342 /* 1343 ** Do any final sanitation the address may require. 1344 ** This will normally be used to turn internal forms 1345 ** (e.g., user@host.LOCAL) into external form. This 1346 ** may be used as a default to the above rules. 1347 */ 1348 1349 rewrite(pvp, 4); 1350 1351 /* 1352 ** Now restore the comment information we had at the beginning. 1353 */ 1354 1355 cataddr(pvp, lbuf, sizeof lbuf); 1356 define('g', lbuf, e); 1357 expand(fancy, buf, &buf[sizeof buf - 1], e); 1358 define('g', oldg, e); 1359 1360 if (tTd(12, 1)) 1361 printf("remotename => `%s'\n", buf); 1362 return (buf); 1363 } 1364 /* 1365 ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 1366 ** 1367 ** Parameters: 1368 ** a -- the address to map (but just the user name part). 1369 ** sendq -- the sendq in which to install any replacement 1370 ** addresses. 1371 ** 1372 ** Returns: 1373 ** none. 1374 */ 1375 1376 maplocaluser(a, sendq, e) 1377 register ADDRESS *a; 1378 ADDRESS **sendq; 1379 ENVELOPE *e; 1380 { 1381 register char **pvp; 1382 register ADDRESS *a1 = NULL; 1383 char pvpbuf[PSBUFSIZE]; 1384 1385 if (tTd(29, 1)) 1386 { 1387 printf("maplocaluser: "); 1388 printaddr(a, FALSE); 1389 } 1390 pvp = prescan(a->q_user, '\0', pvpbuf); 1391 if (pvp == NULL) 1392 return; 1393 1394 rewrite(pvp, 5); 1395 if (pvp[0] == NULL || pvp[0][0] != CANONNET) 1396 return; 1397 1398 /* if non-null, mailer destination specified -- has it changed? */ 1399 a1 = buildaddr(pvp, NULL); 1400 if (a1 == NULL || sameaddr(a, a1)) 1401 return; 1402 1403 /* mark old address as dead; insert new address */ 1404 a->q_flags |= QDONTSEND; 1405 a1->q_alias = a; 1406 allocaddr(a1, 1, NULL); 1407 (void) recipient(a1, sendq, e); 1408 } 1409