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