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