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