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