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.49 (Berkeley) 02/05/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 = "466"; 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 char 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 bcopy((char *) &npvp[2], (char *) pvp, 1158 (int) (avp - npvp - 2) * sizeof *avp); 1159 if (tTd(21, 3)) 1160 printf("-----callsubr %s\n", npvp[1]); 1161 stat = rewrite(pvp, atoi(npvp[1]), reclevel, e); 1162 if (rstat == EX_OK || stat == EX_TEMPFAIL) 1163 rstat = stat; 1164 if (*pvp != NULL && (**pvp & 0377) == CANONNET) 1165 rwr = NULL; 1166 } 1167 } 1168 else 1169 { 1170 bcopy((char *) npvp, (char *) pvp, 1171 (int) (avp - npvp) * sizeof *avp); 1172 } 1173 if (tTd(21, 4)) 1174 { 1175 printf("rewritten as:"); 1176 printav(pvp); 1177 } 1178 } 1179 1180 if (OpMode == MD_TEST || tTd(21, 1)) 1181 { 1182 printf("rewrite: ruleset %2d returns:", ruleset); 1183 printav(pvp); 1184 } 1185 1186 return rstat; 1187 } 1188 /* 1189 ** BUILDADDR -- build address from token vector. 1190 ** 1191 ** Parameters: 1192 ** tv -- token vector. 1193 ** a -- pointer to address descriptor to fill. 1194 ** If NULL, one will be allocated. 1195 ** flags -- info regarding whether this is a sender or 1196 ** a recipient. 1197 ** e -- the current envelope. 1198 ** 1199 ** Returns: 1200 ** NULL if there was an error. 1201 ** 'a' otherwise. 1202 ** 1203 ** Side Effects: 1204 ** fills in 'a' 1205 */ 1206 1207 struct errcodes 1208 { 1209 char *ec_name; /* name of error code */ 1210 int ec_code; /* numeric code */ 1211 } ErrorCodes[] = 1212 { 1213 "usage", EX_USAGE, 1214 "nouser", EX_NOUSER, 1215 "nohost", EX_NOHOST, 1216 "unavailable", EX_UNAVAILABLE, 1217 "software", EX_SOFTWARE, 1218 "tempfail", EX_TEMPFAIL, 1219 "protocol", EX_PROTOCOL, 1220 #ifdef EX_CONFIG 1221 "config", EX_CONFIG, 1222 #endif 1223 NULL, EX_UNAVAILABLE, 1224 }; 1225 1226 ADDRESS * 1227 buildaddr(tv, a, flags, e) 1228 register char **tv; 1229 register ADDRESS *a; 1230 int flags; 1231 register ENVELOPE *e; 1232 { 1233 struct mailer **mp; 1234 register struct mailer *m; 1235 char *bp; 1236 int spaceleft; 1237 static MAILER errormailer; 1238 static char *errorargv[] = { "ERROR", NULL }; 1239 static char buf[MAXNAME]; 1240 1241 if (tTd(24, 5)) 1242 { 1243 printf("buildaddr, flags=%x, tv=", flags); 1244 printav(tv); 1245 } 1246 1247 if (a == NULL) 1248 a = (ADDRESS *) xalloc(sizeof *a); 1249 bzero((char *) a, sizeof *a); 1250 1251 /* set up default error return flags */ 1252 a->q_flags |= QPINGONFAILURE|QPINGONDELAY; 1253 1254 /* figure out what net/mailer to use */ 1255 if (*tv == NULL || (**tv & 0377) != CANONNET) 1256 { 1257 syserr("554 buildaddr: no net"); 1258 badaddr: 1259 a->q_flags |= QBADADDR; 1260 a->q_mailer = &errormailer; 1261 if (errormailer.m_name == NULL) 1262 { 1263 /* initialize the bogus mailer */ 1264 errormailer.m_name = "*error*"; 1265 errormailer.m_mailer = "ERROR"; 1266 errormailer.m_argv = errorargv; 1267 } 1268 return a; 1269 } 1270 tv++; 1271 if (strcasecmp(*tv, "error") == 0) 1272 { 1273 if ((**++tv & 0377) == CANONHOST) 1274 { 1275 register struct errcodes *ep; 1276 1277 if (isascii(**++tv) && isdigit(**tv)) 1278 { 1279 setstat(atoi(*tv)); 1280 } 1281 else 1282 { 1283 for (ep = ErrorCodes; ep->ec_name != NULL; ep++) 1284 if (strcasecmp(ep->ec_name, *tv) == 0) 1285 break; 1286 setstat(ep->ec_code); 1287 } 1288 tv++; 1289 } 1290 else 1291 setstat(EX_UNAVAILABLE); 1292 if ((**tv & 0377) != CANONUSER) 1293 syserr("554 buildaddr: error: no user"); 1294 cataddr(++tv, NULL, buf, sizeof buf, ' '); 1295 stripquotes(buf); 1296 if (isascii(buf[0]) && isdigit(buf[0]) && 1297 isascii(buf[1]) && isdigit(buf[1]) && 1298 isascii(buf[2]) && isdigit(buf[2]) && 1299 buf[3] == ' ') 1300 { 1301 char fmt[10]; 1302 1303 strncpy(fmt, buf, 3); 1304 strcpy(&fmt[3], " %s"); 1305 usrerr(fmt, buf + 4); 1306 1307 /* 1308 ** If this is a 4xx code and we aren't running 1309 ** SMTP on our input, bounce this message; 1310 ** otherwise it disappears without a trace. 1311 */ 1312 1313 if (fmt[0] == '4' && OpMode != MD_SMTP && 1314 OpMode != MD_DAEMON) 1315 { 1316 e->e_flags |= EF_FATALERRS; 1317 } 1318 } 1319 else 1320 { 1321 usrerr("553 %s", buf); 1322 } 1323 goto badaddr; 1324 } 1325 1326 for (mp = Mailer; (m = *mp++) != NULL; ) 1327 { 1328 if (strcasecmp(m->m_name, *tv) == 0) 1329 break; 1330 } 1331 if (m == NULL) 1332 { 1333 syserr("554 buildaddr: unknown mailer %s", *tv); 1334 goto badaddr; 1335 } 1336 a->q_mailer = m; 1337 1338 /* figure out what host (if any) */ 1339 tv++; 1340 if ((**tv & 0377) == CANONHOST) 1341 { 1342 bp = buf; 1343 spaceleft = sizeof buf - 1; 1344 while (*++tv != NULL && (**tv & 0377) != CANONUSER) 1345 { 1346 int i = strlen(*tv); 1347 1348 if (i > spaceleft) 1349 { 1350 /* out of space for this address */ 1351 if (spaceleft >= 0) 1352 syserr("554 buildaddr: host too long (%.40s...)", 1353 buf); 1354 i = spaceleft; 1355 spaceleft = 0; 1356 } 1357 if (i <= 0) 1358 continue; 1359 bcopy(*tv, bp, i); 1360 bp += i; 1361 spaceleft -= i; 1362 } 1363 *bp = '\0'; 1364 a->q_host = newstr(buf); 1365 } 1366 else 1367 { 1368 if (!bitnset(M_LOCALMAILER, m->m_flags)) 1369 { 1370 syserr("554 buildaddr: no host"); 1371 goto badaddr; 1372 } 1373 a->q_host = NULL; 1374 } 1375 1376 /* figure out the user */ 1377 if (*tv == NULL || (**tv & 0377) != CANONUSER) 1378 { 1379 syserr("554 buildaddr: no user"); 1380 goto badaddr; 1381 } 1382 tv++; 1383 1384 if (bitnset(M_CHECKUDB, m->m_flags) && *tv != NULL && 1385 strcmp(*tv, "@") == 0) 1386 { 1387 tv++; 1388 a->q_flags |= QNOTREMOTE; 1389 } 1390 1391 /* do special mapping for local mailer */ 1392 if (*tv != NULL) 1393 { 1394 register char *p = *tv; 1395 1396 if (*p == '"') 1397 p++; 1398 if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags)) 1399 a->q_mailer = m = ProgMailer; 1400 else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags)) 1401 a->q_mailer = m = FileMailer; 1402 else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags)) 1403 { 1404 /* may be :include: */ 1405 cataddr(tv, NULL, buf, sizeof buf, '\0'); 1406 stripquotes(buf); 1407 if (strncasecmp(buf, ":include:", 9) == 0) 1408 { 1409 /* if :include:, don't need further rewriting */ 1410 a->q_mailer = m = InclMailer; 1411 a->q_user = &buf[9]; 1412 return (a); 1413 } 1414 } 1415 } 1416 1417 /* rewrite according recipient mailer rewriting rules */ 1418 define('h', a->q_host, e); 1419 if (!bitset(RF_SENDERADDR|RF_HEADERADDR, flags)) 1420 { 1421 /* sender addresses done later */ 1422 (void) rewrite(tv, 2, 0, e); 1423 if (m->m_re_rwset > 0) 1424 (void) rewrite(tv, m->m_re_rwset, 0, e); 1425 } 1426 (void) rewrite(tv, 4, 0, e); 1427 1428 /* save the result for the command line/RCPT argument */ 1429 cataddr(tv, NULL, buf, sizeof buf, '\0'); 1430 a->q_user = buf; 1431 1432 /* 1433 ** Do mapping to lower case as requested by mailer 1434 */ 1435 1436 if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags)) 1437 makelower(a->q_host); 1438 if (!bitnset(M_USR_UPPER, m->m_flags)) 1439 makelower(a->q_user); 1440 1441 return (a); 1442 } 1443 /* 1444 ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 1445 ** 1446 ** Parameters: 1447 ** pvp -- parameter vector to rebuild. 1448 ** evp -- last parameter to include. Can be NULL to 1449 ** use entire pvp. 1450 ** buf -- buffer to build the string into. 1451 ** sz -- size of buf. 1452 ** spacesub -- the space separator character; if null, 1453 ** use SpaceSub. 1454 ** 1455 ** Returns: 1456 ** none. 1457 ** 1458 ** Side Effects: 1459 ** Destroys buf. 1460 */ 1461 1462 cataddr(pvp, evp, buf, sz, spacesub) 1463 char **pvp; 1464 char **evp; 1465 char *buf; 1466 register int sz; 1467 char spacesub; 1468 { 1469 bool oatomtok = FALSE; 1470 bool natomtok = FALSE; 1471 register int i; 1472 register char *p; 1473 1474 if (spacesub == '\0') 1475 spacesub = SpaceSub; 1476 1477 if (pvp == NULL) 1478 { 1479 (void) strcpy(buf, ""); 1480 return; 1481 } 1482 p = buf; 1483 sz -= 2; 1484 while (*pvp != NULL && (i = strlen(*pvp)) < sz) 1485 { 1486 natomtok = (toktype(**pvp) == ATM); 1487 if (oatomtok && natomtok) 1488 *p++ = spacesub; 1489 (void) strcpy(p, *pvp); 1490 oatomtok = natomtok; 1491 p += i; 1492 sz -= i + 1; 1493 if (pvp++ == evp) 1494 break; 1495 } 1496 *p = '\0'; 1497 } 1498 /* 1499 ** SAMEADDR -- Determine if two addresses are the same 1500 ** 1501 ** This is not just a straight comparison -- if the mailer doesn't 1502 ** care about the host we just ignore it, etc. 1503 ** 1504 ** Parameters: 1505 ** a, b -- pointers to the internal forms to compare. 1506 ** 1507 ** Returns: 1508 ** TRUE -- they represent the same mailbox. 1509 ** FALSE -- they don't. 1510 ** 1511 ** Side Effects: 1512 ** none. 1513 */ 1514 1515 bool 1516 sameaddr(a, b) 1517 register ADDRESS *a; 1518 register ADDRESS *b; 1519 { 1520 register ADDRESS *ca, *cb; 1521 1522 /* if they don't have the same mailer, forget it */ 1523 if (a->q_mailer != b->q_mailer) 1524 return (FALSE); 1525 1526 /* if the user isn't the same, we can drop out */ 1527 if (strcmp(a->q_user, b->q_user) != 0) 1528 return (FALSE); 1529 1530 /* if we have good uids for both but they differ, these are different */ 1531 if (a->q_mailer == ProgMailer) 1532 { 1533 ca = getctladdr(a); 1534 cb = getctladdr(b); 1535 if (ca != NULL && cb != NULL && 1536 bitset(QGOODUID, ca->q_flags & cb->q_flags) && 1537 ca->q_uid != cb->q_uid) 1538 return (FALSE); 1539 } 1540 1541 /* otherwise compare hosts (but be careful for NULL ptrs) */ 1542 if (a->q_host == b->q_host) 1543 { 1544 /* probably both null pointers */ 1545 return (TRUE); 1546 } 1547 if (a->q_host == NULL || b->q_host == NULL) 1548 { 1549 /* only one is a null pointer */ 1550 return (FALSE); 1551 } 1552 if (strcmp(a->q_host, b->q_host) != 0) 1553 return (FALSE); 1554 1555 return (TRUE); 1556 } 1557 /* 1558 ** PRINTADDR -- print address (for debugging) 1559 ** 1560 ** Parameters: 1561 ** a -- the address to print 1562 ** follow -- follow the q_next chain. 1563 ** 1564 ** Returns: 1565 ** none. 1566 ** 1567 ** Side Effects: 1568 ** none. 1569 */ 1570 1571 struct qflags 1572 { 1573 char *qf_name; 1574 u_long qf_bit; 1575 }; 1576 1577 struct qflags AddressFlags[] = 1578 { 1579 "QDONTSEND", QDONTSEND, 1580 "QBADADDR", QBADADDR, 1581 "QGOODUID", QGOODUID, 1582 "QPRIMARY", QPRIMARY, 1583 "QQUEUEUP", QQUEUEUP, 1584 "QSENT", QSENT, 1585 "QNOTREMOTE", QNOTREMOTE, 1586 "QSELFREF", QSELFREF, 1587 "QVERIFIED", QVERIFIED, 1588 "QREPORT", QREPORT, 1589 "QBOGUSSHELL", QBOGUSSHELL, 1590 "QUNSAFEADDR", QUNSAFEADDR, 1591 "QPINGONSUCCESS", QPINGONSUCCESS, 1592 "QPINGONFAILURE", QPINGONFAILURE, 1593 "QPINGONDELAY", QPINGONDELAY, 1594 "QHAS_RET_PARAM", QHAS_RET_PARAM, 1595 "QRET_HDRS", QRET_HDRS, 1596 "QRELAYED", QRELAYED, 1597 NULL 1598 }; 1599 1600 printaddr(a, follow) 1601 register ADDRESS *a; 1602 bool follow; 1603 { 1604 register MAILER *m; 1605 MAILER pseudomailer; 1606 register struct qflags *qfp; 1607 bool firstone; 1608 1609 if (a == NULL) 1610 { 1611 printf("[NULL]\n"); 1612 return; 1613 } 1614 1615 while (a != NULL) 1616 { 1617 printf("%x=", a); 1618 (void) fflush(stdout); 1619 1620 /* find the mailer -- carefully */ 1621 m = a->q_mailer; 1622 if (m == NULL) 1623 { 1624 m = &pseudomailer; 1625 m->m_mno = -1; 1626 m->m_name = "NULL"; 1627 } 1628 1629 printf("%s:\n\tmailer %d (%s), host `%s', user `%s', ruser `%s'\n", 1630 a->q_paddr, m->m_mno, m->m_name, 1631 a->q_host == NULL ? "<null>" : a->q_host, a->q_user, 1632 a->q_ruser == NULL ? "<null>" : a->q_ruser); 1633 printf("\tnext=%x, alias %x, uid %d, gid %d\n", 1634 a->q_next, a->q_alias, a->q_uid, a->q_gid); 1635 printf("\tflags=%lx<", a->q_flags); 1636 firstone = TRUE; 1637 for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++) 1638 { 1639 if (!bitset(qfp->qf_bit, a->q_flags)) 1640 continue; 1641 if (!firstone) 1642 printf(","); 1643 firstone = FALSE; 1644 printf("%s", qfp->qf_name); 1645 } 1646 printf(">\n"); 1647 printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n", 1648 a->q_owner == NULL ? "(none)" : a->q_owner, 1649 a->q_home == NULL ? "(none)" : a->q_home, 1650 a->q_fullname == NULL ? "(none)" : a->q_fullname); 1651 printf("\torcpt=\"%s\", statmta=%s, rstatus=%s\n", 1652 a->q_orcpt == NULL ? "(none)" : a->q_orcpt, 1653 a->q_statmta == NULL ? "(none)" : a->q_statmta, 1654 a->q_rstatus == NULL ? "(none)" : a->q_rstatus); 1655 1656 if (!follow) 1657 return; 1658 a = a->q_next; 1659 } 1660 } 1661 /* 1662 ** EMPTYADDR -- return TRUE if this address is empty (``<>'') 1663 ** 1664 ** Parameters: 1665 ** a -- pointer to the address 1666 ** 1667 ** Returns: 1668 ** TRUE -- if this address is "empty" (i.e., no one should 1669 ** ever generate replies to it. 1670 ** FALSE -- if it is a "regular" (read: replyable) address. 1671 */ 1672 1673 bool 1674 emptyaddr(a) 1675 register ADDRESS *a; 1676 { 1677 return strcmp(a->q_paddr, "<>") == 0 || strcmp(a->q_user, "<>") == 0; 1678 } 1679 /* 1680 ** REMOTENAME -- return the name relative to the current mailer 1681 ** 1682 ** Parameters: 1683 ** name -- the name to translate. 1684 ** m -- the mailer that we want to do rewriting relative 1685 ** to. 1686 ** flags -- fine tune operations. 1687 ** pstat -- pointer to status word. 1688 ** e -- the current envelope. 1689 ** 1690 ** Returns: 1691 ** the text string representing this address relative to 1692 ** the receiving mailer. 1693 ** 1694 ** Side Effects: 1695 ** none. 1696 ** 1697 ** Warnings: 1698 ** The text string returned is tucked away locally; 1699 ** copy it if you intend to save it. 1700 */ 1701 1702 char * 1703 remotename(name, m, flags, pstat, e) 1704 char *name; 1705 struct mailer *m; 1706 int flags; 1707 int *pstat; 1708 register ENVELOPE *e; 1709 { 1710 register char **pvp; 1711 char *fancy; 1712 char *oldg = macvalue('g', e); 1713 int rwset; 1714 static char buf[MAXNAME]; 1715 char lbuf[MAXNAME]; 1716 char pvpbuf[PSBUFSIZE]; 1717 extern char *crackaddr(); 1718 1719 if (tTd(12, 1)) 1720 printf("remotename(%s)\n", name); 1721 1722 /* don't do anything if we are tagging it as special */ 1723 if (bitset(RF_SENDERADDR, flags)) 1724 rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset 1725 : m->m_se_rwset; 1726 else 1727 rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset 1728 : m->m_re_rwset; 1729 if (rwset < 0) 1730 return (name); 1731 1732 /* 1733 ** Do a heuristic crack of this name to extract any comment info. 1734 ** This will leave the name as a comment and a $g macro. 1735 */ 1736 1737 if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) 1738 fancy = "\201g"; 1739 else 1740 fancy = crackaddr(name); 1741 1742 /* 1743 ** Turn the name into canonical form. 1744 ** Normally this will be RFC 822 style, i.e., "user@domain". 1745 ** If this only resolves to "user", and the "C" flag is 1746 ** specified in the sending mailer, then the sender's 1747 ** domain will be appended. 1748 */ 1749 1750 pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL); 1751 if (pvp == NULL) 1752 return (name); 1753 if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 1754 *pstat = EX_TEMPFAIL; 1755 if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) 1756 { 1757 /* append from domain to this address */ 1758 register char **pxp = pvp; 1759 1760 /* see if there is an "@domain" in the current name */ 1761 while (*pxp != NULL && strcmp(*pxp, "@") != 0) 1762 pxp++; 1763 if (*pxp == NULL) 1764 { 1765 /* no.... append the "@domain" from the sender */ 1766 register char **qxq = e->e_fromdomain; 1767 1768 while ((*pxp++ = *qxq++) != NULL) 1769 continue; 1770 if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 1771 *pstat = EX_TEMPFAIL; 1772 } 1773 } 1774 1775 /* 1776 ** Do more specific rewriting. 1777 ** Rewrite using ruleset 1 or 2 depending on whether this is 1778 ** a sender address or not. 1779 ** Then run it through any receiving-mailer-specific rulesets. 1780 */ 1781 1782 if (bitset(RF_SENDERADDR, flags)) 1783 { 1784 if (rewrite(pvp, 1, 0, e) == EX_TEMPFAIL) 1785 *pstat = EX_TEMPFAIL; 1786 } 1787 else 1788 { 1789 if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL) 1790 *pstat = EX_TEMPFAIL; 1791 } 1792 if (rwset > 0) 1793 { 1794 if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL) 1795 *pstat = EX_TEMPFAIL; 1796 } 1797 1798 /* 1799 ** Do any final sanitation the address may require. 1800 ** This will normally be used to turn internal forms 1801 ** (e.g., user@host.LOCAL) into external form. This 1802 ** may be used as a default to the above rules. 1803 */ 1804 1805 if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL) 1806 *pstat = EX_TEMPFAIL; 1807 1808 /* 1809 ** Now restore the comment information we had at the beginning. 1810 */ 1811 1812 cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0'); 1813 define('g', lbuf, e); 1814 1815 /* need to make sure route-addrs have <angle brackets> */ 1816 if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@') 1817 expand("<\201g>", buf, &buf[sizeof buf - 1], e); 1818 else 1819 expand(fancy, buf, &buf[sizeof buf - 1], e); 1820 1821 define('g', oldg, e); 1822 1823 if (tTd(12, 1)) 1824 printf("remotename => `%s'\n", buf); 1825 return (buf); 1826 } 1827 /* 1828 ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 1829 ** 1830 ** Parameters: 1831 ** a -- the address to map (but just the user name part). 1832 ** sendq -- the sendq in which to install any replacement 1833 ** addresses. 1834 ** aliaslevel -- the alias nesting depth. 1835 ** e -- the envelope. 1836 ** 1837 ** Returns: 1838 ** none. 1839 */ 1840 1841 maplocaluser(a, sendq, aliaslevel, e) 1842 register ADDRESS *a; 1843 ADDRESS **sendq; 1844 int aliaslevel; 1845 ENVELOPE *e; 1846 { 1847 register char **pvp; 1848 register ADDRESS *a1 = NULL; 1849 auto char *delimptr; 1850 char pvpbuf[PSBUFSIZE]; 1851 1852 if (tTd(29, 1)) 1853 { 1854 printf("maplocaluser: "); 1855 printaddr(a, FALSE); 1856 } 1857 pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr); 1858 if (pvp == NULL) 1859 return; 1860 1861 (void) rewrite(pvp, 5, 0, e); 1862 if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 1863 return; 1864 1865 /* if non-null, mailer destination specified -- has it changed? */ 1866 a1 = buildaddr(pvp, NULL, 0, e); 1867 if (a1 == NULL || sameaddr(a, a1)) 1868 return; 1869 1870 /* mark old address as dead; insert new address */ 1871 a->q_flags |= QDONTSEND; 1872 if (tTd(29, 5)) 1873 { 1874 printf("maplocaluser: QDONTSEND "); 1875 printaddr(a, FALSE); 1876 } 1877 a1->q_alias = a; 1878 allocaddr(a1, RF_COPYALL, NULL); 1879 (void) recipient(a1, sendq, aliaslevel, e); 1880 } 1881 /* 1882 ** DEQUOTE_INIT -- initialize dequote map 1883 ** 1884 ** This is a no-op. 1885 ** 1886 ** Parameters: 1887 ** map -- the internal map structure. 1888 ** args -- arguments. 1889 ** 1890 ** Returns: 1891 ** TRUE. 1892 */ 1893 1894 bool 1895 dequote_init(map, args) 1896 MAP *map; 1897 char *args; 1898 { 1899 register char *p = args; 1900 1901 for (;;) 1902 { 1903 while (isascii(*p) && isspace(*p)) 1904 p++; 1905 if (*p != '-') 1906 break; 1907 switch (*++p) 1908 { 1909 case 'a': 1910 map->map_app = ++p; 1911 break; 1912 1913 case 's': 1914 map->map_coldelim = *++p; 1915 break; 1916 } 1917 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 1918 p++; 1919 if (*p != '\0') 1920 *p = '\0'; 1921 } 1922 if (map->map_app != NULL) 1923 map->map_app = newstr(map->map_app); 1924 1925 return TRUE; 1926 } 1927 /* 1928 ** DEQUOTE_MAP -- unquote an address 1929 ** 1930 ** Parameters: 1931 ** map -- the internal map structure (ignored). 1932 ** name -- the name to dequote. 1933 ** av -- arguments (ignored). 1934 ** statp -- pointer to status out-parameter. 1935 ** 1936 ** Returns: 1937 ** NULL -- if there were no quotes, or if the resulting 1938 ** unquoted buffer would not be acceptable to prescan. 1939 ** else -- The dequoted buffer. 1940 */ 1941 1942 char * 1943 dequote_map(map, name, av, statp) 1944 MAP *map; 1945 char *name; 1946 char **av; 1947 int *statp; 1948 { 1949 register char *p; 1950 register char *q; 1951 register char c; 1952 int anglecnt = 0; 1953 int cmntcnt = 0; 1954 int quotecnt = 0; 1955 int spacecnt = 0; 1956 bool quotemode = FALSE; 1957 bool bslashmode = FALSE; 1958 char spacesub = map->map_coldelim; 1959 1960 for (p = q = name; (c = *p++) != '\0'; ) 1961 { 1962 if (bslashmode) 1963 { 1964 bslashmode = FALSE; 1965 *q++ = c; 1966 continue; 1967 } 1968 1969 if (c == ' ' && spacesub != '\0') 1970 c = spacesub; 1971 1972 switch (c) 1973 { 1974 case '\\': 1975 bslashmode = TRUE; 1976 break; 1977 1978 case '(': 1979 cmntcnt++; 1980 break; 1981 1982 case ')': 1983 if (cmntcnt-- <= 0) 1984 return NULL; 1985 break; 1986 1987 case ' ': 1988 spacecnt++; 1989 break; 1990 } 1991 1992 if (cmntcnt > 0) 1993 { 1994 *q++ = c; 1995 continue; 1996 } 1997 1998 switch (c) 1999 { 2000 case '"': 2001 quotemode = !quotemode; 2002 quotecnt++; 2003 continue; 2004 2005 case '<': 2006 anglecnt++; 2007 break; 2008 2009 case '>': 2010 if (anglecnt-- <= 0) 2011 return NULL; 2012 break; 2013 } 2014 *q++ = c; 2015 } 2016 2017 if (anglecnt != 0 || cmntcnt != 0 || bslashmode || 2018 quotemode || quotecnt <= 0 || spacecnt != 0) 2019 return NULL; 2020 *q++ = '\0'; 2021 return name; 2022 } 2023