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