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