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