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