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.52 (Berkeley) 02/20/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; 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 (savedelim != '\0' && delimptr != NULL) 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 printaddr(a, follow) 1609 register ADDRESS *a; 1610 bool follow; 1611 { 1612 register MAILER *m; 1613 MAILER pseudomailer; 1614 register struct qflags *qfp; 1615 bool firstone; 1616 1617 if (a == NULL) 1618 { 1619 printf("[NULL]\n"); 1620 return; 1621 } 1622 1623 while (a != NULL) 1624 { 1625 printf("%x=", a); 1626 (void) fflush(stdout); 1627 1628 /* find the mailer -- carefully */ 1629 m = a->q_mailer; 1630 if (m == NULL) 1631 { 1632 m = &pseudomailer; 1633 m->m_mno = -1; 1634 m->m_name = "NULL"; 1635 } 1636 1637 printf("%s:\n\tmailer %d (%s), host `%s', user `%s', ruser `%s'\n", 1638 a->q_paddr, m->m_mno, m->m_name, 1639 a->q_host == NULL ? "<null>" : a->q_host, a->q_user, 1640 a->q_ruser == NULL ? "<null>" : a->q_ruser); 1641 printf("\tnext=%x, alias %x, uid %d, gid %d\n", 1642 a->q_next, a->q_alias, a->q_uid, a->q_gid); 1643 printf("\tflags=%lx<", a->q_flags); 1644 firstone = TRUE; 1645 for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++) 1646 { 1647 if (!bitset(qfp->qf_bit, a->q_flags)) 1648 continue; 1649 if (!firstone) 1650 printf(","); 1651 firstone = FALSE; 1652 printf("%s", qfp->qf_name); 1653 } 1654 printf(">\n"); 1655 printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n", 1656 a->q_owner == NULL ? "(none)" : a->q_owner, 1657 a->q_home == NULL ? "(none)" : a->q_home, 1658 a->q_fullname == NULL ? "(none)" : a->q_fullname); 1659 printf("\torcpt=\"%s\", statmta=%s, rstatus=%s\n", 1660 a->q_orcpt == NULL ? "(none)" : a->q_orcpt, 1661 a->q_statmta == NULL ? "(none)" : a->q_statmta, 1662 a->q_rstatus == NULL ? "(none)" : a->q_rstatus); 1663 1664 if (!follow) 1665 return; 1666 a = a->q_next; 1667 } 1668 } 1669 /* 1670 ** EMPTYADDR -- return TRUE if this address is empty (``<>'') 1671 ** 1672 ** Parameters: 1673 ** a -- pointer to the address 1674 ** 1675 ** Returns: 1676 ** TRUE -- if this address is "empty" (i.e., no one should 1677 ** ever generate replies to it. 1678 ** FALSE -- if it is a "regular" (read: replyable) address. 1679 */ 1680 1681 bool 1682 emptyaddr(a) 1683 register ADDRESS *a; 1684 { 1685 return strcmp(a->q_paddr, "<>") == 0 || strcmp(a->q_user, "<>") == 0; 1686 } 1687 /* 1688 ** REMOTENAME -- return the name relative to the current mailer 1689 ** 1690 ** Parameters: 1691 ** name -- the name to translate. 1692 ** m -- the mailer that we want to do rewriting relative 1693 ** to. 1694 ** flags -- fine tune operations. 1695 ** pstat -- pointer to status word. 1696 ** e -- the current envelope. 1697 ** 1698 ** Returns: 1699 ** the text string representing this address relative to 1700 ** the receiving mailer. 1701 ** 1702 ** Side Effects: 1703 ** none. 1704 ** 1705 ** Warnings: 1706 ** The text string returned is tucked away locally; 1707 ** copy it if you intend to save it. 1708 */ 1709 1710 char * 1711 remotename(name, m, flags, pstat, e) 1712 char *name; 1713 struct mailer *m; 1714 int flags; 1715 int *pstat; 1716 register ENVELOPE *e; 1717 { 1718 register char **pvp; 1719 char *fancy; 1720 char *oldg = macvalue('g', e); 1721 int rwset; 1722 static char buf[MAXNAME]; 1723 char lbuf[MAXNAME]; 1724 char pvpbuf[PSBUFSIZE]; 1725 extern char *crackaddr(); 1726 1727 if (tTd(12, 1)) 1728 printf("remotename(%s)\n", name); 1729 1730 /* don't do anything if we are tagging it as special */ 1731 if (bitset(RF_SENDERADDR, flags)) 1732 rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset 1733 : m->m_se_rwset; 1734 else 1735 rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset 1736 : m->m_re_rwset; 1737 if (rwset < 0) 1738 return (name); 1739 1740 /* 1741 ** Do a heuristic crack of this name to extract any comment info. 1742 ** This will leave the name as a comment and a $g macro. 1743 */ 1744 1745 if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) 1746 fancy = "\201g"; 1747 else 1748 fancy = crackaddr(name); 1749 1750 /* 1751 ** Turn the name into canonical form. 1752 ** Normally this will be RFC 822 style, i.e., "user@domain". 1753 ** If this only resolves to "user", and the "C" flag is 1754 ** specified in the sending mailer, then the sender's 1755 ** domain will be appended. 1756 */ 1757 1758 pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL); 1759 if (pvp == NULL) 1760 return (name); 1761 if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 1762 *pstat = EX_TEMPFAIL; 1763 if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) 1764 { 1765 /* append from domain to this address */ 1766 register char **pxp = pvp; 1767 1768 /* see if there is an "@domain" in the current name */ 1769 while (*pxp != NULL && strcmp(*pxp, "@") != 0) 1770 pxp++; 1771 if (*pxp == NULL) 1772 { 1773 /* no.... append the "@domain" from the sender */ 1774 register char **qxq = e->e_fromdomain; 1775 1776 while ((*pxp++ = *qxq++) != NULL) 1777 continue; 1778 if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 1779 *pstat = EX_TEMPFAIL; 1780 } 1781 } 1782 1783 /* 1784 ** Do more specific rewriting. 1785 ** Rewrite using ruleset 1 or 2 depending on whether this is 1786 ** a sender address or not. 1787 ** Then run it through any receiving-mailer-specific rulesets. 1788 */ 1789 1790 if (bitset(RF_SENDERADDR, flags)) 1791 { 1792 if (rewrite(pvp, 1, 0, e) == EX_TEMPFAIL) 1793 *pstat = EX_TEMPFAIL; 1794 } 1795 else 1796 { 1797 if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL) 1798 *pstat = EX_TEMPFAIL; 1799 } 1800 if (rwset > 0) 1801 { 1802 if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL) 1803 *pstat = EX_TEMPFAIL; 1804 } 1805 1806 /* 1807 ** Do any final sanitation the address may require. 1808 ** This will normally be used to turn internal forms 1809 ** (e.g., user@host.LOCAL) into external form. This 1810 ** may be used as a default to the above rules. 1811 */ 1812 1813 if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL) 1814 *pstat = EX_TEMPFAIL; 1815 1816 /* 1817 ** Now restore the comment information we had at the beginning. 1818 */ 1819 1820 cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0'); 1821 define('g', lbuf, e); 1822 1823 /* need to make sure route-addrs have <angle brackets> */ 1824 if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@') 1825 expand("<\201g>", buf, &buf[sizeof buf - 1], e); 1826 else 1827 expand(fancy, buf, &buf[sizeof buf - 1], e); 1828 1829 define('g', oldg, e); 1830 1831 if (tTd(12, 1)) 1832 printf("remotename => `%s'\n", buf); 1833 return (buf); 1834 } 1835 /* 1836 ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 1837 ** 1838 ** Parameters: 1839 ** a -- the address to map (but just the user name part). 1840 ** sendq -- the sendq in which to install any replacement 1841 ** addresses. 1842 ** aliaslevel -- the alias nesting depth. 1843 ** e -- the envelope. 1844 ** 1845 ** Returns: 1846 ** none. 1847 */ 1848 1849 maplocaluser(a, sendq, aliaslevel, e) 1850 register ADDRESS *a; 1851 ADDRESS **sendq; 1852 int aliaslevel; 1853 ENVELOPE *e; 1854 { 1855 register char **pvp; 1856 register ADDRESS *a1 = NULL; 1857 auto char *delimptr; 1858 char pvpbuf[PSBUFSIZE]; 1859 1860 if (tTd(29, 1)) 1861 { 1862 printf("maplocaluser: "); 1863 printaddr(a, FALSE); 1864 } 1865 pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr); 1866 if (pvp == NULL) 1867 return; 1868 1869 (void) rewrite(pvp, 5, 0, e); 1870 if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 1871 return; 1872 1873 /* if non-null, mailer destination specified -- has it changed? */ 1874 a1 = buildaddr(pvp, NULL, 0, e); 1875 if (a1 == NULL || sameaddr(a, a1)) 1876 return; 1877 1878 /* mark old address as dead; insert new address */ 1879 a->q_flags |= QDONTSEND; 1880 if (tTd(29, 5)) 1881 { 1882 printf("maplocaluser: QDONTSEND "); 1883 printaddr(a, FALSE); 1884 } 1885 a1->q_alias = a; 1886 allocaddr(a1, RF_COPYALL, NULL); 1887 (void) recipient(a1, sendq, aliaslevel, e); 1888 } 1889 /* 1890 ** DEQUOTE_INIT -- initialize dequote map 1891 ** 1892 ** This is a no-op. 1893 ** 1894 ** Parameters: 1895 ** map -- the internal map structure. 1896 ** args -- arguments. 1897 ** 1898 ** Returns: 1899 ** TRUE. 1900 */ 1901 1902 bool 1903 dequote_init(map, args) 1904 MAP *map; 1905 char *args; 1906 { 1907 register char *p = args; 1908 1909 for (;;) 1910 { 1911 while (isascii(*p) && isspace(*p)) 1912 p++; 1913 if (*p != '-') 1914 break; 1915 switch (*++p) 1916 { 1917 case 'a': 1918 map->map_app = ++p; 1919 break; 1920 1921 case 's': 1922 map->map_coldelim = *++p; 1923 break; 1924 } 1925 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 1926 p++; 1927 if (*p != '\0') 1928 *p = '\0'; 1929 } 1930 if (map->map_app != NULL) 1931 map->map_app = newstr(map->map_app); 1932 1933 return TRUE; 1934 } 1935 /* 1936 ** DEQUOTE_MAP -- unquote an address 1937 ** 1938 ** Parameters: 1939 ** map -- the internal map structure (ignored). 1940 ** name -- the name to dequote. 1941 ** av -- arguments (ignored). 1942 ** statp -- pointer to status out-parameter. 1943 ** 1944 ** Returns: 1945 ** NULL -- if there were no quotes, or if the resulting 1946 ** unquoted buffer would not be acceptable to prescan. 1947 ** else -- The dequoted buffer. 1948 */ 1949 1950 char * 1951 dequote_map(map, name, av, statp) 1952 MAP *map; 1953 char *name; 1954 char **av; 1955 int *statp; 1956 { 1957 register char *p; 1958 register char *q; 1959 register char c; 1960 int anglecnt = 0; 1961 int cmntcnt = 0; 1962 int quotecnt = 0; 1963 int spacecnt = 0; 1964 bool quotemode = FALSE; 1965 bool bslashmode = FALSE; 1966 char spacesub = map->map_coldelim; 1967 1968 for (p = q = name; (c = *p++) != '\0'; ) 1969 { 1970 if (bslashmode) 1971 { 1972 bslashmode = FALSE; 1973 *q++ = c; 1974 continue; 1975 } 1976 1977 if (c == ' ' && spacesub != '\0') 1978 c = spacesub; 1979 1980 switch (c) 1981 { 1982 case '\\': 1983 bslashmode = TRUE; 1984 break; 1985 1986 case '(': 1987 cmntcnt++; 1988 break; 1989 1990 case ')': 1991 if (cmntcnt-- <= 0) 1992 return NULL; 1993 break; 1994 1995 case ' ': 1996 spacecnt++; 1997 break; 1998 } 1999 2000 if (cmntcnt > 0) 2001 { 2002 *q++ = c; 2003 continue; 2004 } 2005 2006 switch (c) 2007 { 2008 case '"': 2009 quotemode = !quotemode; 2010 quotecnt++; 2011 continue; 2012 2013 case '<': 2014 anglecnt++; 2015 break; 2016 2017 case '>': 2018 if (anglecnt-- <= 0) 2019 return NULL; 2020 break; 2021 } 2022 *q++ = c; 2023 } 2024 2025 if (anglecnt != 0 || cmntcnt != 0 || bslashmode || 2026 quotemode || quotecnt <= 0 || spacecnt != 0) 2027 return NULL; 2028 *q++ = '\0'; 2029 return name; 2030 } 2031