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