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