1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988 Regents of the University of California. 4 * All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 static char sccsid[] = "@(#)parseaddr.c 6.24 (Berkeley) 03/06/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 ** copyf -- determines what shall be copied: 34 ** -1 -- don't copy anything. The printname 35 ** (q_paddr) is just addr, and the 36 ** user & host are allocated internally 37 ** to parse. 38 ** 0 -- copy out the parsed user & host, but 39 ** don't copy the printname. 40 ** +1 -- copy everything. 41 ** delim -- the character to terminate the address, passed 42 ** to prescan. 43 ** delimptr -- if non-NULL, set to the location of the 44 ** delim character that was found. 45 ** e -- the envelope that will contain this address. 46 ** 47 ** Returns: 48 ** A pointer to the address descriptor header (`a' if 49 ** `a' is non-NULL). 50 ** NULL on error. 51 ** 52 ** Side Effects: 53 ** none 54 */ 55 56 /* following delimiters are inherent to the internal algorithms */ 57 # define DELIMCHARS "\201()<>,;\\\"\r\n" /* word delimiters */ 58 59 ADDRESS * 60 parseaddr(addr, a, copyf, delim, delimptr, e) 61 char *addr; 62 register ADDRESS *a; 63 int copyf; 64 char delim; 65 char **delimptr; 66 register ENVELOPE *e; 67 { 68 register char **pvp; 69 auto char *delimptrbuf; 70 char pvpbuf[PSBUFSIZE]; 71 extern char **prescan(); 72 extern ADDRESS *buildaddr(); 73 extern bool invalidaddr(); 74 75 /* 76 ** Initialize and prescan address. 77 */ 78 79 e->e_to = addr; 80 if (tTd(20, 1)) 81 printf("\n--parseaddr(%s)\n", addr); 82 83 if (invalidaddr(addr)) 84 { 85 if (tTd(20, 1)) 86 printf("parseaddr-->bad address\n"); 87 return NULL; 88 } 89 90 if (delimptr == NULL) 91 delimptr = &delimptrbuf; 92 93 pvp = prescan(addr, delim, pvpbuf, delimptr); 94 if (pvp == NULL) 95 { 96 if (tTd(20, 1)) 97 printf("parseaddr-->NULL\n"); 98 return (NULL); 99 } 100 101 /* 102 ** Apply rewriting rules. 103 ** Ruleset 0 does basic parsing. It must resolve. 104 */ 105 106 rewrite(pvp, 3); 107 rewrite(pvp, 0); 108 109 /* 110 ** See if we resolved to a real mailer. 111 */ 112 113 if ((pvp[0][0] & 0377) != CANONNET) 114 { 115 setstat(EX_USAGE); 116 syserr("554 cannot resolve name"); 117 return (NULL); 118 } 119 120 /* 121 ** Build canonical address from pvp. 122 */ 123 124 a = buildaddr(pvp, a); 125 if (a == NULL) 126 return (NULL); 127 128 /* 129 ** Make local copies of the host & user and then 130 ** transport them out. 131 */ 132 133 allocaddr(a, copyf, addr, *delimptr); 134 135 /* 136 ** Compute return value. 137 */ 138 139 if (tTd(20, 1)) 140 { 141 printf("parseaddr-->"); 142 printaddr(a, FALSE); 143 } 144 145 return (a); 146 } 147 /* 148 ** INVALIDADDR -- check for address containing meta-characters 149 ** 150 ** Parameters: 151 ** addr -- the address to check. 152 ** 153 ** Returns: 154 ** TRUE -- if the address has any "wierd" characters 155 ** FALSE -- otherwise. 156 */ 157 158 bool 159 invalidaddr(addr) 160 register char *addr; 161 { 162 for (; *addr != '\0'; addr++) 163 { 164 if ((*addr & 0340) != 0200) 165 continue; 166 setstat(EX_USAGE); 167 usrerr("553 Address contained invalid control characters"); 168 return TRUE; 169 } 170 return FALSE; 171 } 172 /* 173 ** ALLOCADDR -- do local allocations of address on demand. 174 ** 175 ** Also lowercases the host name if requested. 176 ** 177 ** Parameters: 178 ** a -- the address to reallocate. 179 ** copyf -- the copy flag (see parseaddr for description). 180 ** paddr -- the printname of the address. 181 ** delimptr -- a pointer to the address delimiter. Must be set. 182 ** 183 ** Returns: 184 ** none. 185 ** 186 ** Side Effects: 187 ** Copies portions of a into local buffers as requested. 188 */ 189 190 allocaddr(a, copyf, paddr, delimptr) 191 register ADDRESS *a; 192 int copyf; 193 char *paddr; 194 char *delimptr; 195 { 196 register MAILER *m = a->q_mailer; 197 198 if (copyf > 0 && paddr != NULL) 199 { 200 char savec = *delimptr; 201 202 *delimptr = '\0'; 203 a->q_paddr = newstr(paddr); 204 *delimptr = savec; 205 } 206 else 207 a->q_paddr = paddr; 208 209 if (a->q_user == NULL) 210 a->q_user = ""; 211 if (a->q_host == NULL) 212 a->q_host = ""; 213 214 if (copyf >= 0) 215 { 216 a->q_host = newstr(a->q_host); 217 if (a->q_user != a->q_paddr) 218 a->q_user = newstr(a->q_user); 219 } 220 221 if (a->q_paddr == NULL) 222 a->q_paddr = a->q_user; 223 224 /* 225 ** Convert host name to lower case if requested. 226 ** User name will be done later. 227 */ 228 229 if (!bitnset(M_HST_UPPER, m->m_flags)) 230 makelower(a->q_host); 231 } 232 /* 233 ** LOWERADDR -- map UPPER->lower case on addresses as requested. 234 ** 235 ** Parameters: 236 ** a -- address to be mapped. 237 ** 238 ** Returns: 239 ** none. 240 ** 241 ** Side Effects: 242 ** none. 243 */ 244 245 loweraddr(a) 246 register ADDRESS *a; 247 { 248 register MAILER *m = a->q_mailer; 249 250 if (!bitnset(M_USR_UPPER, m->m_flags)) 251 makelower(a->q_user); 252 } 253 /* 254 ** PRESCAN -- Prescan name and make it canonical 255 ** 256 ** Scans a name and turns it into a set of tokens. This process 257 ** deletes blanks and comments (in parentheses). 258 ** 259 ** This routine knows about quoted strings and angle brackets. 260 ** 261 ** There are certain subtleties to this routine. The one that 262 ** comes to mind now is that backslashes on the ends of names 263 ** are silently stripped off; this is intentional. The problem 264 ** is that some versions of sndmsg (like at LBL) set the kill 265 ** character to something other than @ when reading addresses; 266 ** so people type "csvax.eric\@berkeley" -- which screws up the 267 ** berknet mailer. 268 ** 269 ** Parameters: 270 ** addr -- the name to chomp. 271 ** delim -- the delimiter for the address, normally 272 ** '\0' or ','; \0 is accepted in any case. 273 ** If '\t' then we are reading the .cf file. 274 ** pvpbuf -- place to put the saved text -- note that 275 ** the pointers are static. 276 ** delimptr -- if non-NULL, set to the location of the 277 ** terminating delimiter. 278 ** 279 ** Returns: 280 ** A pointer to a vector of tokens. 281 ** NULL on error. 282 */ 283 284 /* states and character types */ 285 # define OPR 0 /* operator */ 286 # define ATM 1 /* atom */ 287 # define QST 2 /* in quoted string */ 288 # define SPC 3 /* chewing up spaces */ 289 # define ONE 4 /* pick up one character */ 290 291 # define NSTATES 5 /* number of states */ 292 # define TYPE 017 /* mask to select state type */ 293 294 /* meta bits for table */ 295 # define M 020 /* meta character; don't pass through */ 296 # define B 040 /* cause a break */ 297 # define MB M|B /* meta-break */ 298 299 static short StateTab[NSTATES][NSTATES] = 300 { 301 /* oldst chtype> OPR ATM QST SPC ONE */ 302 /*OPR*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, 303 /*ATM*/ OPR|B, ATM, QST|B, SPC|MB, ONE|B, 304 /*QST*/ QST, QST, OPR, QST, QST, 305 /*SPC*/ OPR, ATM, QST, SPC|M, ONE, 306 /*ONE*/ OPR, OPR, OPR, OPR, OPR, 307 }; 308 309 # define NOCHAR -1 /* signal nothing in lookahead token */ 310 311 char ** 312 prescan(addr, delim, pvpbuf, delimptr) 313 char *addr; 314 char delim; 315 char pvpbuf[]; 316 char **delimptr; 317 { 318 register char *p; 319 register char *q; 320 register int c; 321 char **avp; 322 bool bslashmode; 323 int cmntcnt; 324 int anglecnt; 325 char *tok; 326 int state; 327 int newstate; 328 static char *av[MAXATOM+1]; 329 extern int errno; 330 331 /* make sure error messages don't have garbage on them */ 332 errno = 0; 333 334 q = pvpbuf; 335 bslashmode = FALSE; 336 cmntcnt = 0; 337 anglecnt = 0; 338 avp = av; 339 state = ATM; 340 c = NOCHAR; 341 p = addr; 342 if (tTd(22, 11)) 343 { 344 printf("prescan: "); 345 xputs(p); 346 (void) putchar('\n'); 347 } 348 349 do 350 { 351 /* read a token */ 352 tok = q; 353 for (;;) 354 { 355 /* store away any old lookahead character */ 356 if (c != NOCHAR) 357 { 358 /* see if there is room */ 359 if (q >= &pvpbuf[PSBUFSIZE - 5]) 360 { 361 usrerr("553 Address too long"); 362 if (delimptr != NULL) 363 *delimptr = p; 364 return (NULL); 365 } 366 367 /* squirrel it away */ 368 *q++ = c; 369 } 370 371 /* read a new input character */ 372 c = *p++; 373 if (c == '\0') 374 { 375 /* diagnose and patch up bad syntax */ 376 if (state == QST) 377 { 378 usrerr("553 Unbalanced '\"'"); 379 c = '"'; 380 } 381 else if (cmntcnt > 0) 382 { 383 usrerr("553 Unbalanced '('"); 384 c = ')'; 385 } 386 else if (anglecnt > 0) 387 { 388 c = '>'; 389 usrerr("553 Unbalanced '<'"); 390 } 391 else 392 break; 393 394 p--; 395 } 396 else if (c == delim && anglecnt <= 0 && 397 cmntcnt <= 0 && state != QST) 398 break; 399 400 if (tTd(22, 101)) 401 printf("c=%c, s=%d; ", c, state); 402 403 /* chew up special characters */ 404 *q = '\0'; 405 if (bslashmode) 406 { 407 /* kludge \! for naive users */ 408 if (cmntcnt > 0) 409 c = NOCHAR; 410 else if (c != '!') 411 *q++ = '\\'; 412 bslashmode = FALSE; 413 continue; 414 } 415 416 if (c == '\\') 417 { 418 bslashmode = TRUE; 419 c = NOCHAR; 420 continue; 421 } 422 else if (state == QST) 423 { 424 /* do nothing, just avoid next clauses */ 425 } 426 else if (c == '(') 427 { 428 cmntcnt++; 429 c = NOCHAR; 430 } 431 else if (c == ')') 432 { 433 if (cmntcnt <= 0) 434 { 435 usrerr("553 Unbalanced ')'"); 436 if (delimptr != NULL) 437 *delimptr = p; 438 return (NULL); 439 } 440 else 441 cmntcnt--; 442 } 443 else if (cmntcnt > 0) 444 c = NOCHAR; 445 else if (c == '<') 446 anglecnt++; 447 else if (c == '>') 448 { 449 if (anglecnt <= 0) 450 { 451 usrerr("553 Unbalanced '>'"); 452 if (delimptr != NULL) 453 *delimptr = p; 454 return (NULL); 455 } 456 anglecnt--; 457 } 458 else if (delim == ' ' && isascii(c) && isspace(c)) 459 c = ' '; 460 461 if (c == NOCHAR) 462 continue; 463 464 /* see if this is end of input */ 465 if (c == delim && anglecnt <= 0 && state != QST) 466 break; 467 468 newstate = StateTab[state][toktype(c)]; 469 if (tTd(22, 101)) 470 printf("ns=%02o\n", newstate); 471 state = newstate & TYPE; 472 if (bitset(M, newstate)) 473 c = NOCHAR; 474 if (bitset(B, newstate)) 475 break; 476 } 477 478 /* new token */ 479 if (tok != q) 480 { 481 *q++ = '\0'; 482 if (tTd(22, 36)) 483 { 484 printf("tok="); 485 xputs(tok); 486 (void) putchar('\n'); 487 } 488 if (avp >= &av[MAXATOM]) 489 { 490 syserr("553 prescan: too many tokens"); 491 if (delimptr != NULL) 492 *delimptr = p; 493 return (NULL); 494 } 495 *avp++ = tok; 496 } 497 } while (c != '\0' && (c != delim || anglecnt > 0)); 498 *avp = NULL; 499 p--; 500 if (delimptr != NULL) 501 *delimptr = p; 502 if (tTd(22, 12)) 503 { 504 printf("prescan==>"); 505 printav(av); 506 } 507 return (av); 508 } 509 /* 510 ** TOKTYPE -- return token type 511 ** 512 ** Parameters: 513 ** c -- the character in question. 514 ** 515 ** Returns: 516 ** Its type. 517 ** 518 ** Side Effects: 519 ** none. 520 */ 521 522 toktype(c) 523 register int c; 524 { 525 static char buf[50]; 526 static bool firstime = TRUE; 527 528 if (firstime) 529 { 530 firstime = FALSE; 531 expand("\201o", buf, &buf[sizeof buf - 1], CurEnv); 532 (void) strcat(buf, DELIMCHARS); 533 } 534 c &= 0377; 535 if (c == MATCHCLASS || c == MATCHREPL || c == MATCHNCLASS) 536 return (ONE); 537 if (c == '"') 538 return (QST); 539 if ((c & 0340) == 0200) 540 return (OPR); 541 if (!isascii(c)) 542 return (ATM); 543 if (isspace(c) || c == ')') 544 return (SPC); 545 if (strchr(buf, c) != NULL) 546 return (OPR); 547 return (ATM); 548 } 549 /* 550 ** REWRITE -- apply rewrite rules to token vector. 551 ** 552 ** This routine is an ordered production system. Each rewrite 553 ** rule has a LHS (called the pattern) and a RHS (called the 554 ** rewrite); 'rwr' points the the current rewrite rule. 555 ** 556 ** For each rewrite rule, 'avp' points the address vector we 557 ** are trying to match against, and 'pvp' points to the pattern. 558 ** If pvp points to a special match value (MATCHZANY, MATCHANY, 559 ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp 560 ** matched is saved away in the match vector (pointed to by 'mvp'). 561 ** 562 ** When a match between avp & pvp does not match, we try to 563 ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS 564 ** we must also back out the match in mvp. If we reach a 565 ** MATCHANY or MATCHZANY we just extend the match and start 566 ** over again. 567 ** 568 ** When we finally match, we rewrite the address vector 569 ** and try over again. 570 ** 571 ** Parameters: 572 ** pvp -- pointer to token vector. 573 ** 574 ** Returns: 575 ** none. 576 ** 577 ** Side Effects: 578 ** pvp is modified. 579 */ 580 581 struct match 582 { 583 char **first; /* first token matched */ 584 char **last; /* last token matched */ 585 }; 586 587 # define MAXMATCH 9 /* max params per rewrite */ 588 589 590 rewrite(pvp, ruleset) 591 char **pvp; 592 int ruleset; 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 struct match mlist[MAXMATCH]; /* stores match on LHS */ 601 char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 602 603 if (OpMode == MD_TEST || tTd(21, 2)) 604 { 605 printf("rewrite: ruleset %2d input:", ruleset); 606 printav(pvp); 607 } 608 if (ruleset < 0 || ruleset >= MAXRWSETS) 609 { 610 syserr("554 rewrite: illegal ruleset number %d", ruleset); 611 return; 612 } 613 if (pvp == NULL) 614 return; 615 616 /* 617 ** Run through the list of rewrite rules, applying 618 ** any that match. 619 */ 620 621 for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 622 { 623 int loopcount = 0; 624 625 if (tTd(21, 12)) 626 { 627 printf("-----trying rule:"); 628 printav(rwr->r_lhs); 629 } 630 631 /* try to match on this rule */ 632 mlp = mlist; 633 rvp = rwr->r_lhs; 634 avp = pvp; 635 while ((ap = *avp) != NULL || *rvp != NULL) 636 { 637 if (++loopcount > 100) 638 { 639 syserr("554 Infinite loop in ruleset %d", ruleset); 640 printf("workspace: "); 641 printav(pvp); 642 break; 643 } 644 rp = *rvp; 645 if (tTd(21, 35)) 646 { 647 printf("rp="); 648 xputs(rp); 649 printf(", ap="); 650 xputs(ap); 651 printf("\n"); 652 } 653 if (rp == NULL) 654 { 655 /* end-of-pattern before end-of-address */ 656 goto backup; 657 } 658 if (ap == NULL && (*rp & 0377) != MATCHZANY && 659 (*rp & 0377) != CANONHOST) 660 { 661 /* end-of-input */ 662 break; 663 } 664 665 switch (*rp & 0377) 666 { 667 register STAB *s; 668 669 case MATCHCLASS: 670 case MATCHNCLASS: 671 /* match any token in (not in) a class */ 672 s = stab(ap, ST_CLASS, ST_FIND); 673 if (s == NULL || !bitnset(rp[1], s->s_class)) 674 { 675 if ((*rp & 0377) == MATCHCLASS) 676 goto backup; 677 } 678 else if ((*rp & 0377) == MATCHNCLASS) 679 goto backup; 680 681 /* explicit fall-through */ 682 683 case MATCHONE: 684 case MATCHANY: 685 /* match exactly one token */ 686 mlp->first = avp; 687 mlp->last = avp++; 688 mlp++; 689 break; 690 691 case MATCHZANY: 692 /* match zero or more tokens */ 693 mlp->first = avp; 694 mlp->last = avp - 1; 695 mlp++; 696 break; 697 698 case CANONHOST: 699 /* match zero tokens */ 700 break; 701 702 default: 703 /* must have exact match */ 704 if (strcasecmp(rp, ap)) 705 goto backup; 706 avp++; 707 break; 708 } 709 710 /* successful match on this token */ 711 rvp++; 712 continue; 713 714 backup: 715 /* match failed -- back up */ 716 while (--rvp >= rwr->r_lhs) 717 { 718 rp = *rvp; 719 if ((*rp & 0377) == MATCHANY || 720 (*rp & 0377) == MATCHZANY) 721 { 722 /* extend binding and continue */ 723 avp = ++mlp[-1].last; 724 avp++; 725 rvp++; 726 break; 727 } 728 avp--; 729 if ((*rp & 0377) == MATCHONE || 730 (*rp & 0377) == MATCHCLASS || 731 (*rp & 0377) == MATCHNCLASS) 732 { 733 /* back out binding */ 734 mlp--; 735 } 736 } 737 738 if (rvp < rwr->r_lhs) 739 { 740 /* total failure to match */ 741 break; 742 } 743 } 744 745 /* 746 ** See if we successfully matched 747 */ 748 749 if (rvp < rwr->r_lhs || *rvp != NULL) 750 { 751 if (tTd(21, 10)) 752 printf("----- rule fails\n"); 753 rwr = rwr->r_next; 754 continue; 755 } 756 757 rvp = rwr->r_rhs; 758 if (tTd(21, 12)) 759 { 760 printf("-----rule matches:"); 761 printav(rvp); 762 } 763 764 rp = *rvp; 765 if ((*rp & 0377) == CANONUSER) 766 { 767 rvp++; 768 rwr = rwr->r_next; 769 } 770 else if ((*rp & 0377) == CANONHOST) 771 { 772 rvp++; 773 rwr = NULL; 774 } 775 else if ((*rp & 0377) == CANONNET) 776 rwr = NULL; 777 778 /* substitute */ 779 for (avp = npvp; *rvp != NULL; rvp++) 780 { 781 register struct match *m; 782 register char **pp; 783 784 rp = *rvp; 785 if ((*rp & 0377) == MATCHREPL) 786 { 787 /* substitute from LHS */ 788 m = &mlist[rp[1] - '1']; 789 if (m < mlist || m >= mlp) 790 { 791 syserr("554 rewrite: ruleset %d: replacement $%c out of bounds", 792 ruleset, rp[1]); 793 return; 794 } 795 if (tTd(21, 15)) 796 { 797 printf("$%c:", rp[1]); 798 pp = m->first; 799 while (pp <= m->last) 800 { 801 printf(" %x=\"", *pp); 802 (void) fflush(stdout); 803 printf("%s\"", *pp++); 804 } 805 printf("\n"); 806 } 807 pp = m->first; 808 while (pp <= m->last) 809 { 810 if (avp >= &npvp[MAXATOM]) 811 { 812 syserr("554 rewrite: expansion too long"); 813 return; 814 } 815 *avp++ = *pp++; 816 } 817 } 818 else 819 { 820 /* vanilla replacement */ 821 if (avp >= &npvp[MAXATOM]) 822 { 823 toolong: 824 syserr("554 rewrite: expansion too long"); 825 return; 826 } 827 *avp++ = rp; 828 } 829 } 830 *avp++ = NULL; 831 832 /* 833 ** Check for any hostname/keyword lookups. 834 */ 835 836 for (rvp = npvp; *rvp != NULL; rvp++) 837 { 838 char **hbrvp; 839 char **xpvp; 840 int trsize; 841 char *olddelimchar; 842 char *replac; 843 int endtoken; 844 STAB *map; 845 char *mapname; 846 char **key_rvp; 847 char **arg_rvp; 848 char **default_rvp; 849 char buf[MAXNAME + 1]; 850 char *pvpb1[MAXATOM + 1]; 851 char *argvect[10]; 852 char pvpbuf[PSBUFSIZE]; 853 854 if ((**rvp & 0377) != HOSTBEGIN && 855 (**rvp & 0377) != LOOKUPBEGIN) 856 continue; 857 858 /* 859 ** Got a hostname/keyword lookup. 860 ** 861 ** This could be optimized fairly easily. 862 */ 863 864 hbrvp = rvp; 865 if ((**rvp & 0377) == HOSTBEGIN) 866 { 867 endtoken = HOSTEND; 868 mapname = "host"; 869 } 870 else 871 { 872 endtoken = LOOKUPEND; 873 mapname = *++rvp; 874 } 875 map = stab(mapname, ST_MAP, ST_FIND); 876 if (map == NULL) 877 syserr("554 rewrite: map %s not found", mapname); 878 879 /* extract the match part */ 880 key_rvp = ++rvp; 881 default_rvp = NULL; 882 arg_rvp = argvect; 883 xpvp = NULL; 884 replac = pvpbuf; 885 while (*rvp != NULL && (**rvp & 0377) != endtoken) 886 { 887 int nodetype = **rvp & 0377; 888 889 if (nodetype != CANONHOST && nodetype != CANONUSER) 890 { 891 rvp++; 892 continue; 893 } 894 895 *rvp++ = NULL; 896 897 if (xpvp != NULL) 898 { 899 cataddr(xpvp, replac, 900 &pvpbuf[sizeof pvpbuf] - replac, 901 '\0'); 902 *++arg_rvp = replac; 903 replac += strlen(replac) + 1; 904 xpvp = NULL; 905 } 906 switch (nodetype) 907 { 908 case CANONHOST: 909 xpvp = rvp; 910 break; 911 912 case CANONUSER: 913 default_rvp = rvp; 914 break; 915 } 916 } 917 if (*rvp != NULL) 918 *rvp++ = NULL; 919 if (xpvp != NULL) 920 { 921 cataddr(xpvp, replac, 922 &pvpbuf[sizeof pvpbuf] - replac, 923 '\0'); 924 *++arg_rvp = replac; 925 } 926 *++arg_rvp = NULL; 927 928 /* save the remainder of the input string */ 929 trsize = (int) (avp - rvp + 1) * sizeof *rvp; 930 bcopy((char *) rvp, (char *) pvpb1, trsize); 931 932 /* look it up */ 933 cataddr(key_rvp, buf, sizeof buf, '\0'); 934 argvect[0] = buf; 935 if (map != NULL && bitset(MF_VALID, map->s_map.map_flags)) 936 { 937 int bsize = sizeof buf - 1; 938 939 if (map->s_map.map_app != NULL) 940 bsize -= strlen(map->s_map.map_app); 941 replac = (*map->s_map.map_class->map_lookup)(&map->s_map, 942 buf, sizeof buf - 1, argvect); 943 if (replac != NULL && map->s_map.map_app != NULL) 944 strcat(replac, map->s_map.map_app); 945 } 946 else 947 replac = NULL; 948 949 /* if no replacement, use default */ 950 if (replac == NULL && default_rvp != NULL) 951 { 952 char buf2[sizeof buf]; 953 954 /* rewrite the default with % translations */ 955 cataddr(default_rvp, buf2, sizeof buf2, '\0'); 956 map_rewrite(buf2, sizeof buf2, buf, sizeof buf, 957 argvect); 958 replac = buf; 959 } 960 961 if (replac == NULL) 962 { 963 xpvp = key_rvp; 964 } 965 else 966 { 967 /* scan the new replacement */ 968 xpvp = prescan(replac, '\0', pvpbuf, NULL); 969 if (xpvp == NULL) 970 { 971 /* prescan already printed error */ 972 return; 973 } 974 } 975 976 /* append it to the token list */ 977 for (avp = hbrvp; *xpvp != NULL; xpvp++) 978 { 979 *avp++ = newstr(*xpvp); 980 if (avp >= &npvp[MAXATOM]) 981 goto toolong; 982 } 983 984 /* restore the old trailing information */ 985 for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) 986 if (avp >= &npvp[MAXATOM]) 987 goto toolong; 988 989 break; 990 } 991 992 /* 993 ** Check for subroutine calls. 994 */ 995 996 if (*npvp != NULL && (**npvp & 0377) == CALLSUBR) 997 { 998 bcopy((char *) &npvp[2], (char *) pvp, 999 (int) (avp - npvp - 2) * sizeof *avp); 1000 if (tTd(21, 3)) 1001 printf("-----callsubr %s\n", npvp[1]); 1002 rewrite(pvp, atoi(npvp[1])); 1003 } 1004 else 1005 { 1006 bcopy((char *) npvp, (char *) pvp, 1007 (int) (avp - npvp) * sizeof *avp); 1008 } 1009 if (tTd(21, 4)) 1010 { 1011 printf("rewritten as:"); 1012 printav(pvp); 1013 } 1014 } 1015 1016 if (OpMode == MD_TEST || tTd(21, 2)) 1017 { 1018 printf("rewrite: ruleset %2d returns:", ruleset); 1019 printav(pvp); 1020 } 1021 } 1022 /* 1023 ** BUILDADDR -- build address from token vector. 1024 ** 1025 ** Parameters: 1026 ** tv -- token vector. 1027 ** a -- pointer to address descriptor to fill. 1028 ** If NULL, one will be allocated. 1029 ** 1030 ** Returns: 1031 ** NULL if there was an error. 1032 ** 'a' otherwise. 1033 ** 1034 ** Side Effects: 1035 ** fills in 'a' 1036 */ 1037 1038 struct errcodes 1039 { 1040 char *ec_name; /* name of error code */ 1041 int ec_code; /* numeric code */ 1042 } ErrorCodes[] = 1043 { 1044 "usage", EX_USAGE, 1045 "nouser", EX_NOUSER, 1046 "nohost", EX_NOHOST, 1047 "unavailable", EX_UNAVAILABLE, 1048 "software", EX_SOFTWARE, 1049 "tempfail", EX_TEMPFAIL, 1050 "protocol", EX_PROTOCOL, 1051 #ifdef EX_CONFIG 1052 "config", EX_CONFIG, 1053 #endif 1054 NULL, EX_UNAVAILABLE, 1055 }; 1056 1057 ADDRESS * 1058 buildaddr(tv, a) 1059 register char **tv; 1060 register ADDRESS *a; 1061 { 1062 struct mailer **mp; 1063 register struct mailer *m; 1064 char *bp; 1065 int spaceleft; 1066 static char buf[MAXNAME]; 1067 1068 if (a == NULL) 1069 a = (ADDRESS *) xalloc(sizeof *a); 1070 bzero((char *) a, sizeof *a); 1071 1072 /* figure out what net/mailer to use */ 1073 if ((**tv & 0377) != CANONNET) 1074 { 1075 syserr("554 buildaddr: no net"); 1076 return (NULL); 1077 } 1078 tv++; 1079 if (!strcasecmp(*tv, "error")) 1080 { 1081 if ((**++tv & 0377) == CANONHOST) 1082 { 1083 register struct errcodes *ep; 1084 1085 if (isascii(**++tv) && isdigit(**tv)) 1086 { 1087 setstat(atoi(*tv)); 1088 } 1089 else 1090 { 1091 for (ep = ErrorCodes; ep->ec_name != NULL; ep++) 1092 if (strcasecmp(ep->ec_name, *tv) == 0) 1093 break; 1094 setstat(ep->ec_code); 1095 } 1096 tv++; 1097 } 1098 if ((**tv & 0377) != CANONUSER) 1099 syserr("554 buildaddr: error: no user"); 1100 cataddr(++tv, buf, sizeof buf, ' '); 1101 stripquotes(buf); 1102 usrerr(buf); 1103 return (NULL); 1104 } 1105 1106 for (mp = Mailer; (m = *mp++) != NULL; ) 1107 { 1108 if (!strcasecmp(m->m_name, *tv)) 1109 break; 1110 } 1111 if (m == NULL) 1112 { 1113 syserr("554 buildaddr: unknown mailer %s", *tv); 1114 return (NULL); 1115 } 1116 a->q_mailer = m; 1117 1118 /* figure out what host (if any) */ 1119 tv++; 1120 if ((**tv & 0377) == CANONHOST) 1121 { 1122 bp = buf; 1123 spaceleft = sizeof buf - 1; 1124 while (*++tv != NULL && (**tv & 0377) != CANONUSER) 1125 { 1126 int i = strlen(*tv); 1127 1128 if (i > spaceleft) 1129 { 1130 /* out of space for this address */ 1131 if (spaceleft >= 0) 1132 syserr("554 buildaddr: host too long (%.40s...)", 1133 buf); 1134 i = spaceleft; 1135 spaceleft = 0; 1136 } 1137 if (i <= 0) 1138 continue; 1139 bcopy(*tv, bp, i); 1140 bp += i; 1141 spaceleft -= i; 1142 } 1143 *bp = '\0'; 1144 a->q_host = newstr(buf); 1145 } 1146 else 1147 { 1148 if (!bitnset(M_LOCALMAILER, m->m_flags)) 1149 { 1150 syserr("554 buildaddr: no host"); 1151 return (NULL); 1152 } 1153 a->q_host = NULL; 1154 } 1155 1156 /* figure out the user */ 1157 if (*tv == NULL || (**tv & 0377) != CANONUSER) 1158 { 1159 syserr("554 buildaddr: no user"); 1160 return (NULL); 1161 } 1162 tv++; 1163 1164 /* do special mapping for local mailer */ 1165 if (m == LocalMailer && *tv != NULL) 1166 { 1167 register char *p = *tv; 1168 1169 if (*p == '"') 1170 p++; 1171 if (*p == '|') 1172 a->q_mailer = m = ProgMailer; 1173 else if (*p == '/') 1174 a->q_mailer = m = FileMailer; 1175 else if (*p == ':') 1176 { 1177 /* may be :include: */ 1178 cataddr(tv, buf, sizeof buf, '\0'); 1179 stripquotes(buf); 1180 if (strncasecmp(buf, ":include:", 9) == 0) 1181 { 1182 /* if :include:, don't need further rewriting */ 1183 a->q_mailer = m = InclMailer; 1184 a->q_user = &buf[9]; 1185 return (a); 1186 } 1187 } 1188 } 1189 1190 if (m == LocalMailer && *tv != NULL && strcmp(*tv, "@") == 0) 1191 { 1192 tv++; 1193 a->q_flags |= QNOTREMOTE; 1194 } 1195 1196 /* rewrite according recipient mailer rewriting rules */ 1197 rewrite(tv, 2); 1198 if (m->m_re_rwset > 0) 1199 rewrite(tv, m->m_re_rwset); 1200 rewrite(tv, 4); 1201 1202 /* save the result for the command line/RCPT argument */ 1203 cataddr(tv, buf, sizeof buf, '\0'); 1204 a->q_user = buf; 1205 1206 return (a); 1207 } 1208 /* 1209 ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 1210 ** 1211 ** Parameters: 1212 ** pvp -- parameter vector to rebuild. 1213 ** buf -- buffer to build the string into. 1214 ** sz -- size of buf. 1215 ** spacesub -- the space separator character; if null, 1216 ** use SpaceSub. 1217 ** 1218 ** Returns: 1219 ** none. 1220 ** 1221 ** Side Effects: 1222 ** Destroys buf. 1223 */ 1224 1225 cataddr(pvp, buf, sz, spacesub) 1226 char **pvp; 1227 char *buf; 1228 register int sz; 1229 char spacesub; 1230 { 1231 bool oatomtok = FALSE; 1232 bool natomtok = FALSE; 1233 register int i; 1234 register char *p; 1235 1236 if (spacesub == '\0') 1237 spacesub = SpaceSub; 1238 1239 if (pvp == NULL) 1240 { 1241 (void) strcpy(buf, ""); 1242 return; 1243 } 1244 p = buf; 1245 sz -= 2; 1246 while (*pvp != NULL && (i = strlen(*pvp)) < sz) 1247 { 1248 natomtok = (toktype(**pvp) == ATM); 1249 if (oatomtok && natomtok) 1250 *p++ = spacesub; 1251 (void) strcpy(p, *pvp); 1252 oatomtok = natomtok; 1253 p += i; 1254 sz -= i + 1; 1255 pvp++; 1256 } 1257 *p = '\0'; 1258 } 1259 /* 1260 ** SAMEADDR -- Determine if two addresses are the same 1261 ** 1262 ** This is not just a straight comparison -- if the mailer doesn't 1263 ** care about the host we just ignore it, etc. 1264 ** 1265 ** Parameters: 1266 ** a, b -- pointers to the internal forms to compare. 1267 ** 1268 ** Returns: 1269 ** TRUE -- they represent the same mailbox. 1270 ** FALSE -- they don't. 1271 ** 1272 ** Side Effects: 1273 ** none. 1274 */ 1275 1276 bool 1277 sameaddr(a, b) 1278 register ADDRESS *a; 1279 register ADDRESS *b; 1280 { 1281 /* if they don't have the same mailer, forget it */ 1282 if (a->q_mailer != b->q_mailer) 1283 return (FALSE); 1284 1285 /* if the user isn't the same, we can drop out */ 1286 if (strcmp(a->q_user, b->q_user) != 0) 1287 return (FALSE); 1288 1289 /* if we have good uids for both but the differ, these are different */ 1290 if (bitset(QGOODUID, a->q_flags & b->q_flags) && a->q_uid != b->q_uid) 1291 return (FALSE); 1292 1293 /* otherwise compare hosts (but be careful for NULL ptrs) */ 1294 if (a->q_host == b->q_host) 1295 { 1296 /* probably both null pointers */ 1297 return (TRUE); 1298 } 1299 if (a->q_host == NULL || b->q_host == NULL) 1300 { 1301 /* only one is a null pointer */ 1302 return (FALSE); 1303 } 1304 if (strcmp(a->q_host, b->q_host) != 0) 1305 return (FALSE); 1306 1307 return (TRUE); 1308 } 1309 /* 1310 ** PRINTADDR -- print address (for debugging) 1311 ** 1312 ** Parameters: 1313 ** a -- the address to print 1314 ** follow -- follow the q_next chain. 1315 ** 1316 ** Returns: 1317 ** none. 1318 ** 1319 ** Side Effects: 1320 ** none. 1321 */ 1322 1323 printaddr(a, follow) 1324 register ADDRESS *a; 1325 bool follow; 1326 { 1327 bool first = TRUE; 1328 register MAILER *m; 1329 MAILER pseudomailer; 1330 1331 while (a != NULL) 1332 { 1333 first = FALSE; 1334 printf("%x=", a); 1335 (void) fflush(stdout); 1336 1337 /* find the mailer -- carefully */ 1338 m = a->q_mailer; 1339 if (m == NULL) 1340 { 1341 m = &pseudomailer; 1342 m->m_mno = -1; 1343 m->m_name = "NULL"; 1344 } 1345 1346 printf("%s: mailer %d (%s), host `%s', user `%s', ruser `%s'\n", 1347 a->q_paddr, m->m_mno, m->m_name, 1348 a->q_host, a->q_user, a->q_ruser? a->q_ruser: "<null>"); 1349 printf("\tnext=%x, flags=%o, alias %x\n", a->q_next, a->q_flags, 1350 a->q_alias); 1351 printf("\thome=\"%s\", fullname=\"%s\"\n", a->q_home, 1352 a->q_fullname); 1353 1354 if (!follow) 1355 return; 1356 a = a->q_next; 1357 } 1358 if (first) 1359 printf("[NULL]\n"); 1360 } 1361 1362 /* 1363 ** REMOTENAME -- return the name relative to the current mailer 1364 ** 1365 ** Parameters: 1366 ** name -- the name to translate. 1367 ** m -- the mailer that we want to do rewriting relative 1368 ** to. 1369 ** senderaddress -- if set, uses the sender rewriting rules 1370 ** rather than the recipient rewriting rules. 1371 ** header -- set if this address is in the header, rather 1372 ** than an envelope header. 1373 ** canonical -- if set, strip out any comment information, 1374 ** etc. 1375 ** adddomain -- if set, OK to do domain extension. 1376 ** e -- the current envelope. 1377 ** 1378 ** Returns: 1379 ** the text string representing this address relative to 1380 ** the receiving mailer. 1381 ** 1382 ** Side Effects: 1383 ** none. 1384 ** 1385 ** Warnings: 1386 ** The text string returned is tucked away locally; 1387 ** copy it if you intend to save it. 1388 */ 1389 1390 char * 1391 remotename(name, m, senderaddress, header, canonical, adddomain, e) 1392 char *name; 1393 struct mailer *m; 1394 bool senderaddress; 1395 bool header; 1396 bool canonical; 1397 bool adddomain; 1398 register ENVELOPE *e; 1399 { 1400 register char **pvp; 1401 char *fancy; 1402 extern char *macvalue(); 1403 char *oldg = macvalue('g', e); 1404 int rwset; 1405 static char buf[MAXNAME]; 1406 char lbuf[MAXNAME]; 1407 char pvpbuf[PSBUFSIZE]; 1408 extern char **prescan(); 1409 extern char *crackaddr(); 1410 1411 if (tTd(12, 1)) 1412 printf("remotename(%s)\n", name); 1413 1414 /* don't do anything if we are tagging it as special */ 1415 if (senderaddress) 1416 rwset = header ? m->m_sh_rwset : m->m_se_rwset; 1417 else 1418 rwset = header ? m->m_rh_rwset : m->m_re_rwset; 1419 if (rwset < 0) 1420 return (name); 1421 1422 /* 1423 ** Do a heuristic crack of this name to extract any comment info. 1424 ** This will leave the name as a comment and a $g macro. 1425 */ 1426 1427 if (canonical || bitnset(M_NOCOMMENT, m->m_flags)) 1428 fancy = "\201g"; 1429 else 1430 fancy = crackaddr(name); 1431 1432 /* 1433 ** Turn the name into canonical form. 1434 ** Normally this will be RFC 822 style, i.e., "user@domain". 1435 ** If this only resolves to "user", and the "C" flag is 1436 ** specified in the sending mailer, then the sender's 1437 ** domain will be appended. 1438 */ 1439 1440 pvp = prescan(name, '\0', pvpbuf, NULL); 1441 if (pvp == NULL) 1442 return (name); 1443 rewrite(pvp, 3); 1444 if (adddomain && e->e_fromdomain != NULL) 1445 { 1446 /* append from domain to this address */ 1447 register char **pxp = pvp; 1448 1449 /* see if there is an "@domain" in the current name */ 1450 while (*pxp != NULL && strcmp(*pxp, "@") != 0) 1451 pxp++; 1452 if (*pxp == NULL) 1453 { 1454 /* no.... append the "@domain" from the sender */ 1455 register char **qxq = e->e_fromdomain; 1456 1457 while ((*pxp++ = *qxq++) != NULL) 1458 continue; 1459 rewrite(pvp, 3); 1460 } 1461 } 1462 1463 /* 1464 ** Do more specific rewriting. 1465 ** Rewrite using ruleset 1 or 2 depending on whether this is 1466 ** a sender address or not. 1467 ** Then run it through any receiving-mailer-specific rulesets. 1468 */ 1469 1470 if (senderaddress) 1471 rewrite(pvp, 1); 1472 else 1473 rewrite(pvp, 2); 1474 if (rwset > 0) 1475 rewrite(pvp, rwset); 1476 1477 /* 1478 ** Do any final sanitation the address may require. 1479 ** This will normally be used to turn internal forms 1480 ** (e.g., user@host.LOCAL) into external form. This 1481 ** may be used as a default to the above rules. 1482 */ 1483 1484 rewrite(pvp, 4); 1485 1486 /* 1487 ** Now restore the comment information we had at the beginning. 1488 */ 1489 1490 cataddr(pvp, lbuf, sizeof lbuf, '\0'); 1491 define('g', lbuf, e); 1492 expand(fancy, buf, &buf[sizeof buf - 1], e); 1493 define('g', oldg, e); 1494 1495 if (tTd(12, 1)) 1496 printf("remotename => `%s'\n", buf); 1497 return (buf); 1498 } 1499 /* 1500 ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 1501 ** 1502 ** Parameters: 1503 ** a -- the address to map (but just the user name part). 1504 ** sendq -- the sendq in which to install any replacement 1505 ** addresses. 1506 ** 1507 ** Returns: 1508 ** none. 1509 */ 1510 1511 maplocaluser(a, sendq, e) 1512 register ADDRESS *a; 1513 ADDRESS **sendq; 1514 ENVELOPE *e; 1515 { 1516 register char **pvp; 1517 register ADDRESS *a1 = NULL; 1518 auto char *delimptr; 1519 char pvpbuf[PSBUFSIZE]; 1520 1521 if (tTd(29, 1)) 1522 { 1523 printf("maplocaluser: "); 1524 printaddr(a, FALSE); 1525 } 1526 pvp = prescan(a->q_user, '\0', pvpbuf, &delimptr); 1527 if (pvp == NULL) 1528 return; 1529 1530 rewrite(pvp, 5); 1531 if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 1532 return; 1533 1534 /* if non-null, mailer destination specified -- has it changed? */ 1535 a1 = buildaddr(pvp, NULL); 1536 if (a1 == NULL || sameaddr(a, a1)) 1537 return; 1538 1539 /* mark old address as dead; insert new address */ 1540 a->q_flags |= QDONTSEND; 1541 if (tTd(29, 5)) 1542 { 1543 printf("maplocaluser: QDONTSEND "); 1544 printaddr(a, FALSE); 1545 } 1546 a1->q_alias = a; 1547 allocaddr(a1, 1, NULL, delimptr); 1548 (void) recipient(a1, sendq, e); 1549 } 1550