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