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