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