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