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