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