1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 static char sccsid[] = "@(#)parseaddr.c 8.23 (Berkeley) 12/10/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 ** flags -- describe detail for parsing. See RF_ definitions 34 ** in sendmail.h. 35 ** delim -- the character to terminate the address, passed 36 ** to prescan. 37 ** delimptr -- if non-NULL, set to the location of the 38 ** delim character that was found. 39 ** e -- the envelope that will contain this address. 40 ** 41 ** Returns: 42 ** A pointer to the address descriptor header (`a' if 43 ** `a' is non-NULL). 44 ** NULL on error. 45 ** 46 ** Side Effects: 47 ** none 48 */ 49 50 /* following delimiters are inherent to the internal algorithms */ 51 # define DELIMCHARS "()<>,;\r\n" /* default word delimiters */ 52 53 ADDRESS * 54 parseaddr(addr, a, flags, delim, delimptr, e) 55 char *addr; 56 register ADDRESS *a; 57 int flags; 58 int delim; 59 char **delimptr; 60 register ENVELOPE *e; 61 { 62 register char **pvp; 63 auto char *delimptrbuf; 64 bool queueup; 65 char pvpbuf[PSBUFSIZE]; 66 extern ADDRESS *buildaddr(); 67 extern bool invalidaddr(); 68 69 /* 70 ** Initialize and prescan address. 71 */ 72 73 e->e_to = addr; 74 if (tTd(20, 1)) 75 printf("\n--parseaddr(%s)\n", addr); 76 77 if (delimptr == NULL) 78 delimptr = &delimptrbuf; 79 80 pvp = prescan(addr, delim, pvpbuf, sizeof pvpbuf, delimptr); 81 if (pvp == NULL) 82 { 83 if (tTd(20, 1)) 84 printf("parseaddr-->NULL\n"); 85 return (NULL); 86 } 87 88 if (invalidaddr(addr, delim == '\0' ? NULL : *delimptr)) 89 { 90 if (tTd(20, 1)) 91 printf("parseaddr-->bad address\n"); 92 return NULL; 93 } 94 95 /* 96 ** Save addr if we are going to have to. 97 ** 98 ** We have to do this early because there is a chance that 99 ** the map lookups in the rewriting rules could clobber 100 ** static memory somewhere. 101 */ 102 103 if (bitset(RF_COPYPADDR, flags) && addr != NULL) 104 { 105 char savec = **delimptr; 106 107 if (savec != '\0') 108 **delimptr = '\0'; 109 addr = newstr(addr); 110 if (savec != '\0') 111 **delimptr = savec; 112 } 113 114 /* 115 ** Apply rewriting rules. 116 ** Ruleset 0 does basic parsing. It must resolve. 117 */ 118 119 queueup = FALSE; 120 if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 121 queueup = TRUE; 122 if (rewrite(pvp, 0, 0, e) == EX_TEMPFAIL) 123 queueup = TRUE; 124 125 126 /* 127 ** Build canonical address from pvp. 128 */ 129 130 a = buildaddr(pvp, a, flags, e); 131 132 /* 133 ** Make local copies of the host & user and then 134 ** transport them out. 135 */ 136 137 allocaddr(a, flags, addr); 138 if (bitset(QBADADDR, a->q_flags)) 139 return a; 140 141 /* 142 ** If there was a parsing failure, mark it for queueing. 143 */ 144 145 if (queueup) 146 { 147 char *msg = "Transient parse error -- message queued for future delivery"; 148 149 if (tTd(20, 1)) 150 printf("parseaddr: queuing message\n"); 151 message(msg); 152 if (e->e_message == NULL) 153 e->e_message = newstr(msg); 154 a->q_flags |= QQUEUEUP; 155 } 156 157 /* 158 ** Compute return value. 159 */ 160 161 if (tTd(20, 1)) 162 { 163 printf("parseaddr-->"); 164 printaddr(a, FALSE); 165 } 166 167 return (a); 168 } 169 /* 170 ** INVALIDADDR -- check for address containing meta-characters 171 ** 172 ** Parameters: 173 ** addr -- the address to check. 174 ** 175 ** Returns: 176 ** TRUE -- if the address has any "wierd" characters 177 ** FALSE -- otherwise. 178 */ 179 180 bool 181 invalidaddr(addr, delimptr) 182 register char *addr; 183 char *delimptr; 184 { 185 char savedelim; 186 187 if (delimptr != NULL) 188 { 189 savedelim = *delimptr; 190 if (savedelim != '\0') 191 *delimptr = '\0'; 192 } 193 #if 0 194 /* for testing.... */ 195 if (strcmp(addr, "INvalidADDR") == 0) 196 { 197 usrerr("553 INvalid ADDRess"); 198 goto addrfailure; 199 } 200 #endif 201 for (; *addr != '\0'; addr++) 202 { 203 if ((*addr & 0340) == 0200) 204 break; 205 } 206 if (*addr == '\0') 207 { 208 if (savedelim != '\0' && delimptr != NULL) 209 *delimptr = savedelim; 210 return FALSE; 211 } 212 setstat(EX_USAGE); 213 usrerr("553 Address contained invalid control characters"); 214 addrfailure: 215 if (savedelim != '\0' && delimptr != NULL) 216 *delimptr = savedelim; 217 return TRUE; 218 } 219 /* 220 ** ALLOCADDR -- do local allocations of address on demand. 221 ** 222 ** Also lowercases the host name if requested. 223 ** 224 ** Parameters: 225 ** a -- the address to reallocate. 226 ** flags -- the copy flag (see RF_ definitions in sendmail.h 227 ** for a description). 228 ** paddr -- the printname of the address. 229 ** 230 ** Returns: 231 ** none. 232 ** 233 ** Side Effects: 234 ** Copies portions of a into local buffers as requested. 235 */ 236 237 allocaddr(a, flags, paddr) 238 register ADDRESS *a; 239 int flags; 240 char *paddr; 241 { 242 if (tTd(24, 4)) 243 printf("allocaddr(flags=%o, paddr=%s)\n", flags, paddr); 244 245 a->q_paddr = paddr; 246 247 if (a->q_user == NULL) 248 a->q_user = ""; 249 if (a->q_host == NULL) 250 a->q_host = ""; 251 252 if (bitset(RF_COPYPARSE, flags)) 253 { 254 a->q_host = newstr(a->q_host); 255 if (a->q_user != a->q_paddr) 256 a->q_user = newstr(a->q_user); 257 } 258 259 if (a->q_paddr == NULL) 260 a->q_paddr = a->q_user; 261 } 262 /* 263 ** PRESCAN -- Prescan name and make it canonical 264 ** 265 ** Scans a name and turns it into a set of tokens. This process 266 ** deletes blanks and comments (in parentheses). 267 ** 268 ** This routine knows about quoted strings and angle brackets. 269 ** 270 ** There are certain subtleties to this routine. The one that 271 ** comes to mind now is that backslashes on the ends of names 272 ** are silently stripped off; this is intentional. The problem 273 ** is that some versions of sndmsg (like at LBL) set the kill 274 ** character to something other than @ when reading addresses; 275 ** so people type "csvax.eric\@berkeley" -- which screws up the 276 ** berknet mailer. 277 ** 278 ** Parameters: 279 ** addr -- the name to chomp. 280 ** delim -- the delimiter for the address, normally 281 ** '\0' or ','; \0 is accepted in any case. 282 ** If '\t' then we are reading the .cf file. 283 ** pvpbuf -- place to put the saved text -- note that 284 ** the pointers are static. 285 ** pvpbsize -- size of pvpbuf. 286 ** delimptr -- if non-NULL, set to the location of the 287 ** terminating delimiter. 288 ** 289 ** Returns: 290 ** A pointer to a vector of tokens. 291 ** NULL on error. 292 */ 293 294 /* states and character types */ 295 # define OPR 0 /* operator */ 296 # define ATM 1 /* atom */ 297 # define QST 2 /* in quoted string */ 298 # define SPC 3 /* chewing up spaces */ 299 # define ONE 4 /* pick up one character */ 300 301 # define NSTATES 5 /* number of states */ 302 # define TYPE 017 /* mask to select state type */ 303 304 /* meta bits for table */ 305 # define M 020 /* meta character; don't pass through */ 306 # define B 040 /* cause a break */ 307 # define MB M|B /* meta-break */ 308 309 static short StateTab[NSTATES][NSTATES] = 310 { 311 /* oldst chtype> OPR ATM QST SPC ONE */ 312 /*OPR*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, 313 /*ATM*/ OPR|B, ATM, QST|B, SPC|MB, ONE|B, 314 /*QST*/ QST, QST, OPR, QST, QST, 315 /*SPC*/ OPR, ATM, QST, SPC|M, ONE, 316 /*ONE*/ OPR, OPR, OPR, OPR, OPR, 317 }; 318 319 # define NOCHAR -1 /* signal nothing in lookahead token */ 320 321 char ** 322 prescan(addr, delim, pvpbuf, pvpbsize, delimptr) 323 char *addr; 324 char delim; 325 char pvpbuf[]; 326 char **delimptr; 327 { 328 register char *p; 329 register char *q; 330 register int c; 331 char **avp; 332 bool bslashmode; 333 int cmntcnt; 334 int anglecnt; 335 char *tok; 336 int state; 337 int newstate; 338 char *saveto = CurEnv->e_to; 339 static char *av[MAXATOM+1]; 340 extern int errno; 341 342 /* make sure error messages don't have garbage on them */ 343 errno = 0; 344 345 q = pvpbuf; 346 bslashmode = FALSE; 347 cmntcnt = 0; 348 anglecnt = 0; 349 avp = av; 350 state = ATM; 351 c = NOCHAR; 352 p = addr; 353 CurEnv->e_to = p; 354 if (tTd(22, 11)) 355 { 356 printf("prescan: "); 357 xputs(p); 358 (void) putchar('\n'); 359 } 360 361 do 362 { 363 /* read a token */ 364 tok = q; 365 for (;;) 366 { 367 /* store away any old lookahead character */ 368 if (c != NOCHAR && !bslashmode) 369 { 370 /* see if there is room */ 371 if (q >= &pvpbuf[pvpbsize - 5]) 372 { 373 usrerr("553 Address too long"); 374 returnnull: 375 if (delimptr != NULL) 376 *delimptr = p; 377 CurEnv->e_to = saveto; 378 return (NULL); 379 } 380 381 /* squirrel it away */ 382 *q++ = c; 383 } 384 385 /* read a new input character */ 386 c = *p++; 387 if (c == '\0') 388 { 389 /* diagnose and patch up bad syntax */ 390 if (state == QST) 391 { 392 usrerr("653 Unbalanced '\"'"); 393 c = '"'; 394 } 395 else if (cmntcnt > 0) 396 { 397 usrerr("653 Unbalanced '('"); 398 c = ')'; 399 } 400 else if (anglecnt > 0) 401 { 402 c = '>'; 403 usrerr("653 Unbalanced '<'"); 404 } 405 else 406 break; 407 408 p--; 409 } 410 else if (c == delim && anglecnt <= 0 && 411 cmntcnt <= 0 && state != QST) 412 break; 413 414 if (tTd(22, 101)) 415 printf("c=%c, s=%d; ", c, state); 416 417 /* chew up special characters */ 418 *q = '\0'; 419 if (bslashmode) 420 { 421 bslashmode = FALSE; 422 423 /* kludge \! for naive users */ 424 if (cmntcnt > 0) 425 { 426 c = NOCHAR; 427 continue; 428 } 429 else if (c != '!' || state == QST) 430 { 431 *q++ = '\\'; 432 continue; 433 } 434 } 435 436 if (c == '\\') 437 { 438 bslashmode = TRUE; 439 } 440 else if (state == QST) 441 { 442 /* do nothing, just avoid next clauses */ 443 } 444 else if (c == '(') 445 { 446 cmntcnt++; 447 c = NOCHAR; 448 } 449 else if (c == ')') 450 { 451 if (cmntcnt <= 0) 452 { 453 usrerr("653 Unbalanced ')'"); 454 c = NOCHAR; 455 } 456 else 457 cmntcnt--; 458 } 459 else if (cmntcnt > 0) 460 c = NOCHAR; 461 else if (c == '<') 462 anglecnt++; 463 else if (c == '>') 464 { 465 if (anglecnt <= 0) 466 { 467 usrerr("653 Unbalanced '>'"); 468 c = NOCHAR; 469 } 470 else 471 anglecnt--; 472 } 473 else if (delim == ' ' && isascii(c) && isspace(c)) 474 c = ' '; 475 476 if (c == NOCHAR) 477 continue; 478 479 /* see if this is end of input */ 480 if (c == delim && anglecnt <= 0 && state != QST) 481 break; 482 483 newstate = StateTab[state][toktype(c)]; 484 if (tTd(22, 101)) 485 printf("ns=%02o\n", newstate); 486 state = newstate & TYPE; 487 if (bitset(M, newstate)) 488 c = NOCHAR; 489 if (bitset(B, newstate)) 490 break; 491 } 492 493 /* new token */ 494 if (tok != q) 495 { 496 *q++ = '\0'; 497 if (tTd(22, 36)) 498 { 499 printf("tok="); 500 xputs(tok); 501 (void) putchar('\n'); 502 } 503 if (avp >= &av[MAXATOM]) 504 { 505 syserr("553 prescan: too many tokens"); 506 goto returnnull; 507 } 508 if (q - tok > MAXNAME) 509 { 510 syserr("553 prescan: token too long"); 511 goto returnnull; 512 } 513 *avp++ = tok; 514 } 515 } while (c != '\0' && (c != delim || anglecnt > 0)); 516 *avp = NULL; 517 p--; 518 if (delimptr != NULL) 519 *delimptr = p; 520 if (tTd(22, 12)) 521 { 522 printf("prescan==>"); 523 printav(av); 524 } 525 CurEnv->e_to = saveto; 526 if (av[0] == NULL) 527 { 528 if (tTd(22, 1)) 529 printf("prescan: null leading token\n"); 530 return (NULL); 531 } 532 return (av); 533 } 534 /* 535 ** TOKTYPE -- return token type 536 ** 537 ** Parameters: 538 ** c -- the character in question. 539 ** 540 ** Returns: 541 ** Its type. 542 ** 543 ** Side Effects: 544 ** none. 545 */ 546 547 toktype(c) 548 register int c; 549 { 550 static char buf[50]; 551 static bool firstime = TRUE; 552 553 if (firstime) 554 { 555 firstime = FALSE; 556 expand("\201o", buf, &buf[sizeof buf - 1], CurEnv); 557 (void) strcat(buf, DELIMCHARS); 558 } 559 c &= 0377; 560 if (c == MATCHCLASS || c == MATCHREPL || c == MATCHNCLASS) 561 return (ONE); 562 if (c == MACRODEXPAND) 563 return (ONE); 564 if (c == '"') 565 return (QST); 566 if ((c & 0340) == 0200) 567 return (OPR); 568 if (!isascii(c)) 569 return (ATM); 570 if (isspace(c) || c == ')') 571 return (SPC); 572 if (strchr(buf, c) != NULL) 573 return (OPR); 574 return (ATM); 575 } 576 /* 577 ** REWRITE -- apply rewrite rules to token vector. 578 ** 579 ** This routine is an ordered production system. Each rewrite 580 ** rule has a LHS (called the pattern) and a RHS (called the 581 ** rewrite); 'rwr' points the the current rewrite rule. 582 ** 583 ** For each rewrite rule, 'avp' points the address vector we 584 ** are trying to match against, and 'pvp' points to the pattern. 585 ** If pvp points to a special match value (MATCHZANY, MATCHANY, 586 ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp 587 ** matched is saved away in the match vector (pointed to by 'mvp'). 588 ** 589 ** When a match between avp & pvp does not match, we try to 590 ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS 591 ** we must also back out the match in mvp. If we reach a 592 ** MATCHANY or MATCHZANY we just extend the match and start 593 ** over again. 594 ** 595 ** When we finally match, we rewrite the address vector 596 ** and try over again. 597 ** 598 ** Parameters: 599 ** pvp -- pointer to token vector. 600 ** ruleset -- the ruleset to use for rewriting. 601 ** reclevel -- recursion level (to catch loops). 602 ** e -- the current envelope. 603 ** 604 ** Returns: 605 ** A status code. If EX_TEMPFAIL, higher level code should 606 ** attempt recovery. 607 ** 608 ** Side Effects: 609 ** pvp is modified. 610 */ 611 612 struct match 613 { 614 char **first; /* first token matched */ 615 char **last; /* last token matched */ 616 char **pattern; /* pointer to pattern */ 617 }; 618 619 # define MAXMATCH 9 /* max params per rewrite */ 620 621 622 int 623 rewrite(pvp, ruleset, reclevel, e) 624 char **pvp; 625 int ruleset; 626 int reclevel; 627 register ENVELOPE *e; 628 { 629 register char *ap; /* address pointer */ 630 register char *rp; /* rewrite pointer */ 631 register char **avp; /* address vector pointer */ 632 register char **rvp; /* rewrite vector pointer */ 633 register struct match *mlp; /* cur ptr into mlist */ 634 register struct rewrite *rwr; /* pointer to current rewrite rule */ 635 int ruleno; /* current rule number */ 636 int rstat = EX_OK; /* return status */ 637 int loopcount; 638 struct match mlist[MAXMATCH]; /* stores match on LHS */ 639 char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 640 641 if (OpMode == MD_TEST || tTd(21, 2)) 642 { 643 printf("rewrite: ruleset %2d input:", ruleset); 644 printav(pvp); 645 } 646 if (ruleset < 0 || ruleset >= MAXRWSETS) 647 { 648 syserr("554 rewrite: illegal ruleset number %d", ruleset); 649 return EX_CONFIG; 650 } 651 if (reclevel++ > 50) 652 { 653 syserr("rewrite: infinite recursion, ruleset %d", ruleset); 654 return EX_CONFIG; 655 } 656 if (pvp == NULL) 657 return EX_USAGE; 658 659 /* 660 ** Run through the list of rewrite rules, applying 661 ** any that match. 662 */ 663 664 ruleno = 1; 665 loopcount = 0; 666 for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 667 { 668 if (tTd(21, 12)) 669 { 670 printf("-----trying rule:"); 671 printav(rwr->r_lhs); 672 } 673 674 /* try to match on this rule */ 675 mlp = mlist; 676 rvp = rwr->r_lhs; 677 avp = pvp; 678 if (++loopcount > 100) 679 { 680 syserr("554 Infinite loop in ruleset %d, rule %d", 681 ruleset, ruleno); 682 if (tTd(21, 1)) 683 { 684 printf("workspace: "); 685 printav(pvp); 686 } 687 break; 688 } 689 690 while ((ap = *avp) != NULL || *rvp != NULL) 691 { 692 rp = *rvp; 693 if (tTd(21, 35)) 694 { 695 printf("ADVANCE rp="); 696 xputs(rp); 697 printf(", ap="); 698 xputs(ap); 699 printf("\n"); 700 } 701 if (rp == NULL) 702 { 703 /* end-of-pattern before end-of-address */ 704 goto backup; 705 } 706 if (ap == NULL && (*rp & 0377) != MATCHZANY && 707 (*rp & 0377) != MATCHZERO) 708 { 709 /* end-of-input with patterns left */ 710 goto backup; 711 } 712 713 switch (*rp & 0377) 714 { 715 register STAB *s; 716 char buf[MAXLINE]; 717 718 case MATCHCLASS: 719 /* match any phrase in a class */ 720 mlp->pattern = rvp; 721 mlp->first = avp; 722 extendclass: 723 ap = *avp; 724 if (ap == NULL) 725 goto backup; 726 mlp->last = avp++; 727 cataddr(mlp->first, mlp->last, buf, sizeof buf, '\0'); 728 s = stab(buf, ST_CLASS, ST_FIND); 729 if (s == NULL || !bitnset(rp[1], s->s_class)) 730 { 731 if (tTd(21, 36)) 732 { 733 printf("EXTEND rp="); 734 xputs(rp); 735 printf(", ap="); 736 xputs(ap); 737 printf("\n"); 738 } 739 goto extendclass; 740 } 741 if (tTd(21, 36)) 742 printf("CLMATCH\n"); 743 mlp++; 744 break; 745 746 case MATCHNCLASS: 747 /* match any token not in a class */ 748 s = stab(ap, ST_CLASS, ST_FIND); 749 if (s != NULL && bitnset(rp[1], s->s_class)) 750 goto backup; 751 752 /* fall through */ 753 754 case MATCHONE: 755 case MATCHANY: 756 /* match exactly one token */ 757 mlp->pattern = rvp; 758 mlp->first = avp; 759 mlp->last = avp++; 760 mlp++; 761 break; 762 763 case MATCHZANY: 764 /* match zero or more tokens */ 765 mlp->pattern = rvp; 766 mlp->first = avp; 767 mlp->last = avp - 1; 768 mlp++; 769 break; 770 771 case MATCHZERO: 772 /* match zero tokens */ 773 break; 774 775 case MACRODEXPAND: 776 /* 777 ** Match against run-time macro. 778 ** This algorithm is broken for the 779 ** general case (no recursive macros, 780 ** improper tokenization) but should 781 ** work for the usual cases. 782 */ 783 784 ap = macvalue(rp[1], e); 785 mlp->first = avp; 786 if (tTd(21, 2)) 787 printf("rewrite: LHS $&%c => \"%s\"\n", 788 rp[1], 789 ap == NULL ? "(NULL)" : ap); 790 791 if (ap == NULL) 792 break; 793 while (*ap != '\0') 794 { 795 if (*avp == NULL || 796 strncasecmp(ap, *avp, strlen(*avp)) != 0) 797 { 798 /* no match */ 799 avp = mlp->first; 800 goto backup; 801 } 802 ap += strlen(*avp++); 803 } 804 805 /* match */ 806 break; 807 808 default: 809 /* must have exact match */ 810 if (strcasecmp(rp, ap)) 811 goto backup; 812 avp++; 813 break; 814 } 815 816 /* successful match on this token */ 817 rvp++; 818 continue; 819 820 backup: 821 /* match failed -- back up */ 822 while (--mlp >= mlist) 823 { 824 rvp = mlp->pattern; 825 rp = *rvp; 826 avp = mlp->last + 1; 827 ap = *avp; 828 829 if (tTd(21, 36)) 830 { 831 printf("BACKUP rp="); 832 xputs(rp); 833 printf(", ap="); 834 xputs(ap); 835 printf("\n"); 836 } 837 838 if (ap == NULL) 839 { 840 /* run off the end -- back up again */ 841 continue; 842 } 843 if ((*rp & 0377) == MATCHANY || 844 (*rp & 0377) == MATCHZANY) 845 { 846 /* extend binding and continue */ 847 mlp->last = avp++; 848 rvp++; 849 mlp++; 850 break; 851 } 852 if ((*rp & 0377) == MATCHCLASS) 853 { 854 /* extend binding and try again */ 855 mlp->last = avp; 856 goto extendclass; 857 } 858 } 859 860 if (mlp < mlist) 861 { 862 /* total failure to match */ 863 break; 864 } 865 } 866 867 /* 868 ** See if we successfully matched 869 */ 870 871 if (mlp < mlist || *rvp != NULL) 872 { 873 if (tTd(21, 10)) 874 printf("----- rule fails\n"); 875 rwr = rwr->r_next; 876 ruleno++; 877 loopcount = 0; 878 continue; 879 } 880 881 rvp = rwr->r_rhs; 882 if (tTd(21, 12)) 883 { 884 printf("-----rule matches:"); 885 printav(rvp); 886 } 887 888 rp = *rvp; 889 if ((*rp & 0377) == CANONUSER) 890 { 891 rvp++; 892 rwr = rwr->r_next; 893 ruleno++; 894 loopcount = 0; 895 } 896 else if ((*rp & 0377) == CANONHOST) 897 { 898 rvp++; 899 rwr = NULL; 900 } 901 else if ((*rp & 0377) == CANONNET) 902 rwr = NULL; 903 904 /* substitute */ 905 for (avp = npvp; *rvp != NULL; rvp++) 906 { 907 register struct match *m; 908 register char **pp; 909 910 rp = *rvp; 911 if ((*rp & 0377) == MATCHREPL) 912 { 913 /* substitute from LHS */ 914 m = &mlist[rp[1] - '1']; 915 if (m < mlist || m >= mlp) 916 { 917 syserr("554 rewrite: ruleset %d: replacement $%c out of bounds", 918 ruleset, rp[1]); 919 return EX_CONFIG; 920 } 921 if (tTd(21, 15)) 922 { 923 printf("$%c:", rp[1]); 924 pp = m->first; 925 while (pp <= m->last) 926 { 927 printf(" %x=\"", *pp); 928 (void) fflush(stdout); 929 printf("%s\"", *pp++); 930 } 931 printf("\n"); 932 } 933 pp = m->first; 934 while (pp <= m->last) 935 { 936 if (avp >= &npvp[MAXATOM]) 937 { 938 syserr("554 rewrite: expansion too long"); 939 return EX_DATAERR; 940 } 941 *avp++ = *pp++; 942 } 943 } 944 else 945 { 946 /* vanilla replacement */ 947 if (avp >= &npvp[MAXATOM]) 948 { 949 toolong: 950 syserr("554 rewrite: expansion too long"); 951 return EX_DATAERR; 952 } 953 if ((*rp & 0377) != MACRODEXPAND) 954 *avp++ = rp; 955 else 956 { 957 *avp = macvalue(rp[1], e); 958 if (tTd(21, 2)) 959 printf("rewrite: RHS $&%c => \"%s\"\n", 960 rp[1], 961 *avp == NULL ? "(NULL)" : *avp); 962 if (*avp != NULL) 963 avp++; 964 } 965 } 966 } 967 *avp++ = NULL; 968 969 /* 970 ** Check for any hostname/keyword lookups. 971 */ 972 973 for (rvp = npvp; *rvp != NULL; rvp++) 974 { 975 char **hbrvp; 976 char **xpvp; 977 int trsize; 978 char *replac; 979 int endtoken; 980 STAB *map; 981 char *mapname; 982 char **key_rvp; 983 char **arg_rvp; 984 char **default_rvp; 985 char buf[MAXNAME + 1]; 986 char *pvpb1[MAXATOM + 1]; 987 char *argvect[10]; 988 char pvpbuf[PSBUFSIZE]; 989 char *nullpvp[1]; 990 991 if ((**rvp & 0377) != HOSTBEGIN && 992 (**rvp & 0377) != LOOKUPBEGIN) 993 continue; 994 995 /* 996 ** Got a hostname/keyword lookup. 997 ** 998 ** This could be optimized fairly easily. 999 */ 1000 1001 hbrvp = rvp; 1002 if ((**rvp & 0377) == HOSTBEGIN) 1003 { 1004 endtoken = HOSTEND; 1005 mapname = "host"; 1006 } 1007 else 1008 { 1009 endtoken = LOOKUPEND; 1010 mapname = *++rvp; 1011 } 1012 map = stab(mapname, ST_MAP, ST_FIND); 1013 if (map == NULL) 1014 syserr("554 rewrite: map %s not found", mapname); 1015 1016 /* extract the match part */ 1017 key_rvp = ++rvp; 1018 default_rvp = NULL; 1019 arg_rvp = argvect; 1020 xpvp = NULL; 1021 replac = pvpbuf; 1022 while (*rvp != NULL && (**rvp & 0377) != endtoken) 1023 { 1024 int nodetype = **rvp & 0377; 1025 1026 if (nodetype != CANONHOST && nodetype != CANONUSER) 1027 { 1028 rvp++; 1029 continue; 1030 } 1031 1032 *rvp++ = NULL; 1033 1034 if (xpvp != NULL) 1035 { 1036 cataddr(xpvp, NULL, replac, 1037 &pvpbuf[sizeof pvpbuf] - replac, 1038 '\0'); 1039 *++arg_rvp = replac; 1040 replac += strlen(replac) + 1; 1041 xpvp = NULL; 1042 } 1043 switch (nodetype) 1044 { 1045 case CANONHOST: 1046 xpvp = rvp; 1047 break; 1048 1049 case CANONUSER: 1050 default_rvp = rvp; 1051 break; 1052 } 1053 } 1054 if (*rvp != NULL) 1055 *rvp++ = NULL; 1056 if (xpvp != NULL) 1057 { 1058 cataddr(xpvp, NULL, replac, 1059 &pvpbuf[sizeof pvpbuf] - replac, 1060 '\0'); 1061 *++arg_rvp = replac; 1062 } 1063 *++arg_rvp = NULL; 1064 1065 /* save the remainder of the input string */ 1066 trsize = (int) (avp - rvp + 1) * sizeof *rvp; 1067 bcopy((char *) rvp, (char *) pvpb1, trsize); 1068 1069 /* look it up */ 1070 cataddr(key_rvp, NULL, buf, sizeof buf, '\0'); 1071 argvect[0] = buf; 1072 if (map != NULL && bitset(MF_OPEN, map->s_map.map_mflags)) 1073 { 1074 auto int stat = EX_OK; 1075 1076 /* XXX should try to auto-open the map here */ 1077 1078 if (tTd(60, 1)) 1079 printf("map_lookup(%s, %s) => ", 1080 mapname, buf); 1081 replac = (*map->s_map.map_class->map_lookup)(&map->s_map, 1082 buf, argvect, &stat); 1083 if (tTd(60, 1)) 1084 printf("%s (%d)\n", 1085 replac ? replac : "NOT FOUND", 1086 stat); 1087 1088 /* should recover if stat == EX_TEMPFAIL */ 1089 if (stat == EX_TEMPFAIL) 1090 rstat = stat; 1091 } 1092 else 1093 replac = NULL; 1094 1095 /* if no replacement, use default */ 1096 if (replac == NULL && default_rvp != NULL) 1097 { 1098 /* create the default */ 1099 cataddr(default_rvp, NULL, buf, sizeof buf, '\0'); 1100 replac = buf; 1101 } 1102 1103 if (replac == NULL) 1104 { 1105 xpvp = key_rvp; 1106 } 1107 else if (*replac == '\0') 1108 { 1109 /* null replacement */ 1110 nullpvp[0] = NULL; 1111 xpvp = nullpvp; 1112 } 1113 else 1114 { 1115 /* scan the new replacement */ 1116 xpvp = prescan(replac, '\0', pvpbuf, 1117 sizeof pvpbuf, NULL); 1118 if (xpvp == NULL) 1119 { 1120 /* prescan already printed error */ 1121 return EX_DATAERR; 1122 } 1123 } 1124 1125 /* append it to the token list */ 1126 for (avp = hbrvp; *xpvp != NULL; xpvp++) 1127 { 1128 *avp++ = newstr(*xpvp); 1129 if (avp >= &npvp[MAXATOM]) 1130 goto toolong; 1131 } 1132 1133 /* restore the old trailing information */ 1134 for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) 1135 if (avp >= &npvp[MAXATOM]) 1136 goto toolong; 1137 1138 break; 1139 } 1140 1141 /* 1142 ** Check for subroutine calls. 1143 */ 1144 1145 if (*npvp != NULL && (**npvp & 0377) == CALLSUBR) 1146 { 1147 int stat; 1148 1149 bcopy((char *) &npvp[2], (char *) pvp, 1150 (int) (avp - npvp - 2) * sizeof *avp); 1151 if (tTd(21, 3)) 1152 printf("-----callsubr %s\n", npvp[1]); 1153 stat = rewrite(pvp, atoi(npvp[1]), reclevel, e); 1154 if (rstat == EX_OK || stat == EX_TEMPFAIL) 1155 rstat = stat; 1156 if (*pvp != NULL && (**pvp & 0377) == CANONNET) 1157 rwr = NULL; 1158 } 1159 else 1160 { 1161 bcopy((char *) npvp, (char *) pvp, 1162 (int) (avp - npvp) * sizeof *avp); 1163 } 1164 if (tTd(21, 4)) 1165 { 1166 printf("rewritten as:"); 1167 printav(pvp); 1168 } 1169 } 1170 1171 if (OpMode == MD_TEST || tTd(21, 2)) 1172 { 1173 printf("rewrite: ruleset %2d returns:", ruleset); 1174 printav(pvp); 1175 } 1176 1177 return rstat; 1178 } 1179 /* 1180 ** BUILDADDR -- build address from token vector. 1181 ** 1182 ** Parameters: 1183 ** tv -- token vector. 1184 ** a -- pointer to address descriptor to fill. 1185 ** If NULL, one will be allocated. 1186 ** flags -- info regarding whether this is a sender or 1187 ** a recipient. 1188 ** e -- the current envelope. 1189 ** 1190 ** Returns: 1191 ** NULL if there was an error. 1192 ** 'a' otherwise. 1193 ** 1194 ** Side Effects: 1195 ** fills in 'a' 1196 */ 1197 1198 struct errcodes 1199 { 1200 char *ec_name; /* name of error code */ 1201 int ec_code; /* numeric code */ 1202 } ErrorCodes[] = 1203 { 1204 "usage", EX_USAGE, 1205 "nouser", EX_NOUSER, 1206 "nohost", EX_NOHOST, 1207 "unavailable", EX_UNAVAILABLE, 1208 "software", EX_SOFTWARE, 1209 "tempfail", EX_TEMPFAIL, 1210 "protocol", EX_PROTOCOL, 1211 #ifdef EX_CONFIG 1212 "config", EX_CONFIG, 1213 #endif 1214 NULL, EX_UNAVAILABLE, 1215 }; 1216 1217 ADDRESS * 1218 buildaddr(tv, a, flags, e) 1219 register char **tv; 1220 register ADDRESS *a; 1221 int flags; 1222 register ENVELOPE *e; 1223 { 1224 struct mailer **mp; 1225 register struct mailer *m; 1226 char *bp; 1227 int spaceleft; 1228 static MAILER errormailer; 1229 static char *errorargv[] = { "ERROR", NULL }; 1230 static char buf[MAXNAME]; 1231 1232 if (tTd(24, 5)) 1233 { 1234 printf("buildaddr, flags=%o, tv=", flags); 1235 printav(tv); 1236 } 1237 1238 if (a == NULL) 1239 a = (ADDRESS *) xalloc(sizeof *a); 1240 bzero((char *) a, sizeof *a); 1241 1242 /* figure out what net/mailer to use */ 1243 if (*tv == NULL || (**tv & 0377) != CANONNET) 1244 { 1245 syserr("554 buildaddr: no net"); 1246 badaddr: 1247 a->q_flags |= QBADADDR; 1248 a->q_mailer = &errormailer; 1249 if (errormailer.m_name == NULL) 1250 { 1251 /* initialize the bogus mailer */ 1252 errormailer.m_name = "*error*"; 1253 errormailer.m_mailer = "ERROR"; 1254 errormailer.m_argv = errorargv; 1255 } 1256 return a; 1257 } 1258 tv++; 1259 if (strcasecmp(*tv, "error") == 0) 1260 { 1261 if ((**++tv & 0377) == CANONHOST) 1262 { 1263 register struct errcodes *ep; 1264 1265 if (isascii(**++tv) && isdigit(**tv)) 1266 { 1267 setstat(atoi(*tv)); 1268 } 1269 else 1270 { 1271 for (ep = ErrorCodes; ep->ec_name != NULL; ep++) 1272 if (strcasecmp(ep->ec_name, *tv) == 0) 1273 break; 1274 setstat(ep->ec_code); 1275 } 1276 tv++; 1277 } 1278 else 1279 setstat(EX_UNAVAILABLE); 1280 if ((**tv & 0377) != CANONUSER) 1281 syserr("554 buildaddr: error: no user"); 1282 cataddr(++tv, NULL, buf, sizeof buf, ' '); 1283 stripquotes(buf); 1284 if (isascii(buf[0]) && isdigit(buf[0]) && 1285 isascii(buf[1]) && isdigit(buf[1]) && 1286 isascii(buf[2]) && isdigit(buf[2]) && 1287 buf[3] == ' ') 1288 { 1289 char fmt[10]; 1290 1291 strncpy(fmt, buf, 3); 1292 strcpy(&fmt[3], " %s"); 1293 usrerr(fmt, buf + 4); 1294 } 1295 else 1296 { 1297 usrerr("%s", buf); 1298 } 1299 goto badaddr; 1300 } 1301 1302 for (mp = Mailer; (m = *mp++) != NULL; ) 1303 { 1304 if (strcasecmp(m->m_name, *tv) == 0) 1305 break; 1306 } 1307 if (m == NULL) 1308 { 1309 syserr("554 buildaddr: unknown mailer %s", *tv); 1310 goto badaddr; 1311 } 1312 a->q_mailer = m; 1313 1314 /* figure out what host (if any) */ 1315 tv++; 1316 if ((**tv & 0377) == CANONHOST) 1317 { 1318 bp = buf; 1319 spaceleft = sizeof buf - 1; 1320 while (*++tv != NULL && (**tv & 0377) != CANONUSER) 1321 { 1322 int i = strlen(*tv); 1323 1324 if (i > spaceleft) 1325 { 1326 /* out of space for this address */ 1327 if (spaceleft >= 0) 1328 syserr("554 buildaddr: host too long (%.40s...)", 1329 buf); 1330 i = spaceleft; 1331 spaceleft = 0; 1332 } 1333 if (i <= 0) 1334 continue; 1335 bcopy(*tv, bp, i); 1336 bp += i; 1337 spaceleft -= i; 1338 } 1339 *bp = '\0'; 1340 a->q_host = newstr(buf); 1341 } 1342 else 1343 { 1344 if (!bitnset(M_LOCALMAILER, m->m_flags)) 1345 { 1346 syserr("554 buildaddr: no host"); 1347 goto badaddr; 1348 } 1349 a->q_host = NULL; 1350 } 1351 1352 /* figure out the user */ 1353 if (*tv == NULL || (**tv & 0377) != CANONUSER) 1354 { 1355 syserr("554 buildaddr: no user"); 1356 goto badaddr; 1357 } 1358 tv++; 1359 1360 /* do special mapping for local mailer */ 1361 if (m == LocalMailer && *tv != NULL) 1362 { 1363 register char *p = *tv; 1364 1365 if (*p == '"') 1366 p++; 1367 if (*p == '|') 1368 a->q_mailer = m = ProgMailer; 1369 else if (*p == '/') 1370 a->q_mailer = m = FileMailer; 1371 else if (*p == ':') 1372 { 1373 /* may be :include: */ 1374 cataddr(tv, NULL, buf, sizeof buf, '\0'); 1375 stripquotes(buf); 1376 if (strncasecmp(buf, ":include:", 9) == 0) 1377 { 1378 /* if :include:, don't need further rewriting */ 1379 a->q_mailer = m = InclMailer; 1380 a->q_user = &buf[9]; 1381 return (a); 1382 } 1383 } 1384 } 1385 1386 if (m == LocalMailer && *tv != NULL && strcmp(*tv, "@") == 0) 1387 { 1388 tv++; 1389 a->q_flags |= QNOTREMOTE; 1390 } 1391 1392 /* rewrite according recipient mailer rewriting rules */ 1393 define('h', a->q_host, e); 1394 if (!bitset(RF_SENDERADDR|RF_HEADERADDR, flags)) 1395 { 1396 /* sender addresses done later */ 1397 (void) rewrite(tv, 2, 0, e); 1398 if (m->m_re_rwset > 0) 1399 (void) rewrite(tv, m->m_re_rwset, 0, e); 1400 } 1401 (void) rewrite(tv, 4, 0, e); 1402 1403 /* save the result for the command line/RCPT argument */ 1404 cataddr(tv, NULL, buf, sizeof buf, '\0'); 1405 a->q_user = buf; 1406 1407 /* 1408 ** Do mapping to lower case as requested by mailer 1409 */ 1410 1411 if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags)) 1412 makelower(a->q_host); 1413 if (!bitnset(M_USR_UPPER, m->m_flags)) 1414 makelower(a->q_user); 1415 1416 return (a); 1417 } 1418 /* 1419 ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 1420 ** 1421 ** Parameters: 1422 ** pvp -- parameter vector to rebuild. 1423 ** evp -- last parameter to include. Can be NULL to 1424 ** use entire pvp. 1425 ** buf -- buffer to build the string into. 1426 ** sz -- size of buf. 1427 ** spacesub -- the space separator character; if null, 1428 ** use SpaceSub. 1429 ** 1430 ** Returns: 1431 ** none. 1432 ** 1433 ** Side Effects: 1434 ** Destroys buf. 1435 */ 1436 1437 cataddr(pvp, evp, buf, sz, spacesub) 1438 char **pvp; 1439 char **evp; 1440 char *buf; 1441 register int sz; 1442 char spacesub; 1443 { 1444 bool oatomtok = FALSE; 1445 bool natomtok = FALSE; 1446 register int i; 1447 register char *p; 1448 1449 if (spacesub == '\0') 1450 spacesub = SpaceSub; 1451 1452 if (pvp == NULL) 1453 { 1454 (void) strcpy(buf, ""); 1455 return; 1456 } 1457 p = buf; 1458 sz -= 2; 1459 while (*pvp != NULL && (i = strlen(*pvp)) < sz) 1460 { 1461 natomtok = (toktype(**pvp) == ATM); 1462 if (oatomtok && natomtok) 1463 *p++ = spacesub; 1464 (void) strcpy(p, *pvp); 1465 oatomtok = natomtok; 1466 p += i; 1467 sz -= i + 1; 1468 if (pvp++ == evp) 1469 break; 1470 } 1471 *p = '\0'; 1472 } 1473 /* 1474 ** SAMEADDR -- Determine if two addresses are the same 1475 ** 1476 ** This is not just a straight comparison -- if the mailer doesn't 1477 ** care about the host we just ignore it, etc. 1478 ** 1479 ** Parameters: 1480 ** a, b -- pointers to the internal forms to compare. 1481 ** 1482 ** Returns: 1483 ** TRUE -- they represent the same mailbox. 1484 ** FALSE -- they don't. 1485 ** 1486 ** Side Effects: 1487 ** none. 1488 */ 1489 1490 bool 1491 sameaddr(a, b) 1492 register ADDRESS *a; 1493 register ADDRESS *b; 1494 { 1495 /* if they don't have the same mailer, forget it */ 1496 if (a->q_mailer != b->q_mailer) 1497 return (FALSE); 1498 1499 /* if the user isn't the same, we can drop out */ 1500 if (strcmp(a->q_user, b->q_user) != 0) 1501 return (FALSE); 1502 1503 /* if we have good uids for both but the differ, these are different */ 1504 if (bitset(QGOODUID, a->q_flags & b->q_flags) && a->q_uid != b->q_uid) 1505 return (FALSE); 1506 1507 /* otherwise compare hosts (but be careful for NULL ptrs) */ 1508 if (a->q_host == b->q_host) 1509 { 1510 /* probably both null pointers */ 1511 return (TRUE); 1512 } 1513 if (a->q_host == NULL || b->q_host == NULL) 1514 { 1515 /* only one is a null pointer */ 1516 return (FALSE); 1517 } 1518 if (strcmp(a->q_host, b->q_host) != 0) 1519 return (FALSE); 1520 1521 return (TRUE); 1522 } 1523 /* 1524 ** PRINTADDR -- print address (for debugging) 1525 ** 1526 ** Parameters: 1527 ** a -- the address to print 1528 ** follow -- follow the q_next chain. 1529 ** 1530 ** Returns: 1531 ** none. 1532 ** 1533 ** Side Effects: 1534 ** none. 1535 */ 1536 1537 printaddr(a, follow) 1538 register ADDRESS *a; 1539 bool follow; 1540 { 1541 bool first = TRUE; 1542 register MAILER *m; 1543 MAILER pseudomailer; 1544 1545 while (a != NULL) 1546 { 1547 first = FALSE; 1548 printf("%x=", a); 1549 (void) fflush(stdout); 1550 1551 /* find the mailer -- carefully */ 1552 m = a->q_mailer; 1553 if (m == NULL) 1554 { 1555 m = &pseudomailer; 1556 m->m_mno = -1; 1557 m->m_name = "NULL"; 1558 } 1559 1560 printf("%s:\n\tmailer %d (%s), host `%s', user `%s', ruser `%s'\n", 1561 a->q_paddr, m->m_mno, m->m_name, 1562 a->q_host, a->q_user, 1563 a->q_ruser ? a->q_ruser : "<null>"); 1564 printf("\tnext=%x, flags=%o, alias %x, uid %d, gid %d\n", 1565 a->q_next, a->q_flags, a->q_alias, a->q_uid, a->q_gid); 1566 printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n", 1567 a->q_owner == NULL ? "(none)" : a->q_owner, 1568 a->q_home == NULL ? "(none)" : a->q_home, 1569 a->q_fullname == NULL ? "(none)" : a->q_fullname); 1570 1571 if (!follow) 1572 return; 1573 a = a->q_next; 1574 } 1575 if (first) 1576 printf("[NULL]\n"); 1577 } 1578 1579 /* 1580 ** REMOTENAME -- return the name relative to the current mailer 1581 ** 1582 ** Parameters: 1583 ** name -- the name to translate. 1584 ** m -- the mailer that we want to do rewriting relative 1585 ** to. 1586 ** flags -- fine tune operations. 1587 ** pstat -- pointer to status word. 1588 ** e -- the current envelope. 1589 ** 1590 ** Returns: 1591 ** the text string representing this address relative to 1592 ** the receiving mailer. 1593 ** 1594 ** Side Effects: 1595 ** none. 1596 ** 1597 ** Warnings: 1598 ** The text string returned is tucked away locally; 1599 ** copy it if you intend to save it. 1600 */ 1601 1602 char * 1603 remotename(name, m, flags, pstat, e) 1604 char *name; 1605 struct mailer *m; 1606 int flags; 1607 int *pstat; 1608 register ENVELOPE *e; 1609 { 1610 register char **pvp; 1611 char *fancy; 1612 char *oldg = macvalue('g', e); 1613 int rwset; 1614 static char buf[MAXNAME]; 1615 char lbuf[MAXNAME]; 1616 char pvpbuf[PSBUFSIZE]; 1617 extern char *crackaddr(); 1618 1619 if (tTd(12, 1)) 1620 printf("remotename(%s)\n", name); 1621 1622 /* don't do anything if we are tagging it as special */ 1623 if (bitset(RF_SENDERADDR, flags)) 1624 rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset 1625 : m->m_se_rwset; 1626 else 1627 rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset 1628 : m->m_re_rwset; 1629 if (rwset < 0) 1630 return (name); 1631 1632 /* 1633 ** Do a heuristic crack of this name to extract any comment info. 1634 ** This will leave the name as a comment and a $g macro. 1635 */ 1636 1637 if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) 1638 fancy = "\201g"; 1639 else 1640 fancy = crackaddr(name); 1641 1642 /* 1643 ** Turn the name into canonical form. 1644 ** Normally this will be RFC 822 style, i.e., "user@domain". 1645 ** If this only resolves to "user", and the "C" flag is 1646 ** specified in the sending mailer, then the sender's 1647 ** domain will be appended. 1648 */ 1649 1650 pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL); 1651 if (pvp == NULL) 1652 return (name); 1653 if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 1654 *pstat = EX_TEMPFAIL; 1655 if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) 1656 { 1657 /* append from domain to this address */ 1658 register char **pxp = pvp; 1659 1660 /* see if there is an "@domain" in the current name */ 1661 while (*pxp != NULL && strcmp(*pxp, "@") != 0) 1662 pxp++; 1663 if (*pxp == NULL) 1664 { 1665 /* no.... append the "@domain" from the sender */ 1666 register char **qxq = e->e_fromdomain; 1667 1668 while ((*pxp++ = *qxq++) != NULL) 1669 continue; 1670 if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 1671 *pstat = EX_TEMPFAIL; 1672 } 1673 } 1674 1675 /* 1676 ** Do more specific rewriting. 1677 ** Rewrite using ruleset 1 or 2 depending on whether this is 1678 ** a sender address or not. 1679 ** Then run it through any receiving-mailer-specific rulesets. 1680 */ 1681 1682 if (bitset(RF_SENDERADDR, flags)) 1683 { 1684 if (rewrite(pvp, 1, 0, e) == EX_TEMPFAIL) 1685 *pstat = EX_TEMPFAIL; 1686 } 1687 else 1688 { 1689 if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL) 1690 *pstat = EX_TEMPFAIL; 1691 } 1692 if (rwset > 0) 1693 { 1694 if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL) 1695 *pstat = EX_TEMPFAIL; 1696 } 1697 1698 /* 1699 ** Do any final sanitation the address may require. 1700 ** This will normally be used to turn internal forms 1701 ** (e.g., user@host.LOCAL) into external form. This 1702 ** may be used as a default to the above rules. 1703 */ 1704 1705 if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL) 1706 *pstat = EX_TEMPFAIL; 1707 1708 /* 1709 ** Now restore the comment information we had at the beginning. 1710 */ 1711 1712 cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0'); 1713 define('g', lbuf, e); 1714 expand(fancy, buf, &buf[sizeof buf - 1], e); 1715 define('g', oldg, e); 1716 1717 if (tTd(12, 1)) 1718 printf("remotename => `%s'\n", buf); 1719 return (buf); 1720 } 1721 /* 1722 ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 1723 ** 1724 ** Parameters: 1725 ** a -- the address to map (but just the user name part). 1726 ** sendq -- the sendq in which to install any replacement 1727 ** addresses. 1728 ** 1729 ** Returns: 1730 ** none. 1731 */ 1732 1733 maplocaluser(a, sendq, e) 1734 register ADDRESS *a; 1735 ADDRESS **sendq; 1736 ENVELOPE *e; 1737 { 1738 register char **pvp; 1739 register ADDRESS *a1 = NULL; 1740 auto char *delimptr; 1741 char pvpbuf[PSBUFSIZE]; 1742 1743 if (tTd(29, 1)) 1744 { 1745 printf("maplocaluser: "); 1746 printaddr(a, FALSE); 1747 } 1748 pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr); 1749 if (pvp == NULL) 1750 return; 1751 1752 (void) rewrite(pvp, 5, 0, e); 1753 if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 1754 return; 1755 1756 /* if non-null, mailer destination specified -- has it changed? */ 1757 a1 = buildaddr(pvp, NULL, 0, e); 1758 if (a1 == NULL || sameaddr(a, a1)) 1759 return; 1760 1761 /* mark old address as dead; insert new address */ 1762 a->q_flags |= QDONTSEND; 1763 if (tTd(29, 5)) 1764 { 1765 printf("maplocaluser: QDONTSEND "); 1766 printaddr(a, FALSE); 1767 } 1768 a1->q_alias = a; 1769 allocaddr(a1, RF_COPYALL, NULL); 1770 (void) recipient(a1, sendq, e); 1771 } 1772 /* 1773 ** DEQUOTE_INIT -- initialize dequote map 1774 ** 1775 ** This is a no-op. 1776 ** 1777 ** Parameters: 1778 ** map -- the internal map structure. 1779 ** args -- arguments. 1780 ** 1781 ** Returns: 1782 ** TRUE. 1783 */ 1784 1785 bool 1786 dequote_init(map, args) 1787 MAP *map; 1788 char *args; 1789 { 1790 register char *p = args; 1791 1792 for (;;) 1793 { 1794 while (isascii(*p) && isspace(*p)) 1795 p++; 1796 if (*p != '-') 1797 break; 1798 switch (*++p) 1799 { 1800 case 'a': 1801 map->map_app = ++p; 1802 break; 1803 } 1804 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 1805 p++; 1806 if (*p != '\0') 1807 *p = '\0'; 1808 } 1809 if (map->map_app != NULL) 1810 map->map_app = newstr(map->map_app); 1811 1812 return TRUE; 1813 } 1814 /* 1815 ** DEQUOTE_MAP -- unquote an address 1816 ** 1817 ** Parameters: 1818 ** map -- the internal map structure (ignored). 1819 ** name -- the name to dequote. 1820 ** av -- arguments (ignored). 1821 ** statp -- pointer to status out-parameter. 1822 ** 1823 ** Returns: 1824 ** NULL -- if there were no quotes, or if the resulting 1825 ** unquoted buffer would not be acceptable to prescan. 1826 ** else -- The dequoted buffer. 1827 */ 1828 1829 char * 1830 dequote_map(map, name, av, statp) 1831 MAP *map; 1832 char *name; 1833 char **av; 1834 int *statp; 1835 { 1836 register char *p; 1837 register char *q; 1838 register char c; 1839 int anglecnt; 1840 int cmntcnt; 1841 int quotecnt; 1842 int spacecnt; 1843 bool quotemode; 1844 bool bslashmode; 1845 1846 anglecnt = 0; 1847 cmntcnt = 0; 1848 quotecnt = 0; 1849 spacecnt = 0; 1850 quotemode = FALSE; 1851 bslashmode = FALSE; 1852 1853 for (p = q = name; (c = *p++) != '\0'; ) 1854 { 1855 if (bslashmode) 1856 { 1857 bslashmode = FALSE; 1858 *q++ = c; 1859 continue; 1860 } 1861 1862 switch (c) 1863 { 1864 case '\\': 1865 bslashmode = TRUE; 1866 break; 1867 1868 case '(': 1869 cmntcnt++; 1870 break; 1871 1872 case ')': 1873 if (cmntcnt-- <= 0) 1874 return NULL; 1875 break; 1876 1877 case ' ': 1878 spacecnt++; 1879 break; 1880 } 1881 1882 if (cmntcnt > 0) 1883 { 1884 *q++ = c; 1885 continue; 1886 } 1887 1888 switch (c) 1889 { 1890 case '"': 1891 quotemode = !quotemode; 1892 quotecnt++; 1893 continue; 1894 1895 case '<': 1896 anglecnt++; 1897 break; 1898 1899 case '>': 1900 if (anglecnt-- <= 0) 1901 return NULL; 1902 break; 1903 } 1904 *q++ = c; 1905 } 1906 1907 if (anglecnt != 0 || cmntcnt != 0 || bslashmode || 1908 quotemode || quotecnt <= 0 || spacecnt != 0) 1909 return NULL; 1910 *q++ = '\0'; 1911 return name; 1912 } 1913