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