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