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