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