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.42 (Berkeley) 11/22/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 } 156 157 /* 158 ** Compute return value. 159 */ 160 161 if (tTd(20, 1)) 162 { 163 printf("parseaddr-->"); 164 printaddr(a, FALSE); 165 } 166 167 return (a); 168 } 169 /* 170 ** INVALIDADDR -- check for address containing meta-characters 171 ** 172 ** Parameters: 173 ** addr -- the address to check. 174 ** 175 ** Returns: 176 ** TRUE -- if the address has any "wierd" characters 177 ** FALSE -- otherwise. 178 */ 179 180 bool 181 invalidaddr(addr, delimptr) 182 register char *addr; 183 char *delimptr; 184 { 185 char savedelim; 186 187 if (delimptr != NULL) 188 { 189 savedelim = *delimptr; 190 if (savedelim != '\0') 191 *delimptr = '\0'; 192 } 193 #if 0 194 /* for testing.... */ 195 if (strcmp(addr, "INvalidADDR") == 0) 196 { 197 usrerr("553 INvalid ADDRess"); 198 goto addrfailure; 199 } 200 #endif 201 for (; *addr != '\0'; addr++) 202 { 203 if ((*addr & 0340) == 0200) 204 break; 205 } 206 if (*addr == '\0') 207 { 208 if (savedelim != '\0' && delimptr != NULL) 209 *delimptr = savedelim; 210 return FALSE; 211 } 212 setstat(EX_USAGE); 213 usrerr("553 Address contained invalid control characters"); 214 addrfailure: 215 if (savedelim != '\0' && delimptr != NULL) 216 *delimptr = savedelim; 217 return TRUE; 218 } 219 /* 220 ** ALLOCADDR -- do local allocations of address on demand. 221 ** 222 ** Also lowercases the host name if requested. 223 ** 224 ** Parameters: 225 ** a -- the address to reallocate. 226 ** flags -- the copy flag (see RF_ definitions in sendmail.h 227 ** for a description). 228 ** paddr -- the printname of the address. 229 ** 230 ** Returns: 231 ** none. 232 ** 233 ** Side Effects: 234 ** Copies portions of a into local buffers as requested. 235 */ 236 237 allocaddr(a, flags, paddr) 238 register ADDRESS *a; 239 int flags; 240 char *paddr; 241 { 242 if (tTd(24, 4)) 243 printf("allocaddr(flags=%x, paddr=%s)\n", flags, paddr); 244 245 a->q_paddr = paddr; 246 247 if (a->q_user == NULL) 248 a->q_user = ""; 249 if (a->q_host == NULL) 250 a->q_host = ""; 251 252 if (bitset(RF_COPYPARSE, flags)) 253 { 254 a->q_host = newstr(a->q_host); 255 if (a->q_user != a->q_paddr) 256 a->q_user = newstr(a->q_user); 257 } 258 259 if (a->q_paddr == NULL) 260 a->q_paddr = a->q_user; 261 } 262 /* 263 ** PRESCAN -- Prescan name and make it canonical 264 ** 265 ** Scans a name and turns it into a set of tokens. This process 266 ** deletes blanks and comments (in parentheses). 267 ** 268 ** This routine knows about quoted strings and angle brackets. 269 ** 270 ** There are certain subtleties to this routine. The one that 271 ** comes to mind now is that backslashes on the ends of names 272 ** are silently stripped off; this is intentional. The problem 273 ** is that some versions of sndmsg (like at LBL) set the kill 274 ** character to something other than @ when reading addresses; 275 ** so people type "csvax.eric\@berkeley" -- which screws up the 276 ** berknet mailer. 277 ** 278 ** Parameters: 279 ** addr -- the name to chomp. 280 ** delim -- the delimiter for the address, normally 281 ** '\0' or ','; \0 is accepted in any case. 282 ** If '\t' then we are reading the .cf file. 283 ** pvpbuf -- place to put the saved text -- note that 284 ** the pointers are static. 285 ** pvpbsize -- size of pvpbuf. 286 ** delimptr -- if non-NULL, set to the location of the 287 ** terminating delimiter. 288 ** 289 ** Returns: 290 ** A pointer to a vector of tokens. 291 ** NULL on error. 292 */ 293 294 /* states and character types */ 295 # define OPR 0 /* operator */ 296 # define ATM 1 /* atom */ 297 # define QST 2 /* in quoted string */ 298 # define SPC 3 /* chewing up spaces */ 299 # define ONE 4 /* pick up one character */ 300 301 # define NSTATES 5 /* number of states */ 302 # define TYPE 017 /* mask to select state type */ 303 304 /* meta bits for table */ 305 # define M 020 /* meta character; don't pass through */ 306 # define B 040 /* cause a break */ 307 # define MB M|B /* meta-break */ 308 309 static short StateTab[NSTATES][NSTATES] = 310 { 311 /* oldst chtype> OPR ATM QST SPC ONE */ 312 /*OPR*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, 313 /*ATM*/ OPR|B, ATM, QST|B, SPC|MB, ONE|B, 314 /*QST*/ QST, QST, OPR, QST, QST, 315 /*SPC*/ OPR, ATM, QST, SPC|M, ONE, 316 /*ONE*/ OPR, OPR, OPR, OPR, OPR, 317 }; 318 319 /* token type table -- it gets modified with $o characters */ 320 static TokTypeTab[256] = 321 { 322 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM, 323 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 324 SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM,ATM,SPC,ATM,ATM,ATM,ATM,ATM,ATM, 325 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,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 OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 331 OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 332 ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 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 }; 339 340 #define toktype(c) ((int) TokTypeTab[(c) & 0xff]) 341 342 343 # define NOCHAR -1 /* signal nothing in lookahead token */ 344 345 char ** 346 prescan(addr, delim, pvpbuf, pvpbsize, delimptr) 347 char *addr; 348 char delim; 349 char pvpbuf[]; 350 char **delimptr; 351 { 352 register char *p; 353 register char *q; 354 register int c; 355 char **avp; 356 bool bslashmode; 357 int cmntcnt; 358 int anglecnt; 359 char *tok; 360 int state; 361 int newstate; 362 char *saveto = CurEnv->e_to; 363 static char *av[MAXATOM+1]; 364 static char firsttime = TRUE; 365 extern int errno; 366 367 if (firsttime) 368 { 369 /* initialize the token type table */ 370 char obuf[50]; 371 372 firsttime = FALSE; 373 expand("\201o", obuf, &obuf[sizeof obuf - sizeof DELIMCHARS], CurEnv); 374 strcat(obuf, DELIMCHARS); 375 for (p = obuf; *p != '\0'; p++) 376 { 377 if (TokTypeTab[*p & 0xff] == ATM) 378 TokTypeTab[*p & 0xff] = OPR; 379 } 380 } 381 382 /* make sure error messages don't have garbage on them */ 383 errno = 0; 384 385 q = pvpbuf; 386 bslashmode = FALSE; 387 cmntcnt = 0; 388 anglecnt = 0; 389 avp = av; 390 state = ATM; 391 c = NOCHAR; 392 p = addr; 393 CurEnv->e_to = p; 394 if (tTd(22, 11)) 395 { 396 printf("prescan: "); 397 xputs(p); 398 (void) putchar('\n'); 399 } 400 401 do 402 { 403 /* read a token */ 404 tok = q; 405 for (;;) 406 { 407 /* store away any old lookahead character */ 408 if (c != NOCHAR && !bslashmode) 409 { 410 /* see if there is room */ 411 if (q >= &pvpbuf[pvpbsize - 5]) 412 { 413 usrerr("553 Address too long"); 414 returnnull: 415 if (delimptr != NULL) 416 *delimptr = p; 417 CurEnv->e_to = saveto; 418 return (NULL); 419 } 420 421 /* squirrel it away */ 422 *q++ = c; 423 } 424 425 /* read a new input character */ 426 c = *p++; 427 if (c == '\0') 428 { 429 /* diagnose and patch up bad syntax */ 430 if (state == QST) 431 { 432 usrerr("653 Unbalanced '\"'"); 433 c = '"'; 434 } 435 else if (cmntcnt > 0) 436 { 437 usrerr("653 Unbalanced '('"); 438 c = ')'; 439 } 440 else if (anglecnt > 0) 441 { 442 c = '>'; 443 usrerr("653 Unbalanced '<'"); 444 } 445 else 446 break; 447 448 p--; 449 } 450 else if (c == delim && anglecnt <= 0 && 451 cmntcnt <= 0 && state != QST) 452 break; 453 454 if (tTd(22, 101)) 455 printf("c=%c, s=%d; ", c, state); 456 457 /* chew up special characters */ 458 *q = '\0'; 459 if (bslashmode) 460 { 461 bslashmode = FALSE; 462 463 /* kludge \! for naive users */ 464 if (cmntcnt > 0) 465 { 466 c = NOCHAR; 467 continue; 468 } 469 else if (c != '!' || state == QST) 470 { 471 *q++ = '\\'; 472 continue; 473 } 474 } 475 476 if (c == '\\') 477 { 478 bslashmode = TRUE; 479 } 480 else if (state == QST) 481 { 482 /* do nothing, just avoid next clauses */ 483 } 484 else if (c == '(') 485 { 486 cmntcnt++; 487 c = NOCHAR; 488 } 489 else if (c == ')') 490 { 491 if (cmntcnt <= 0) 492 { 493 usrerr("653 Unbalanced ')'"); 494 c = NOCHAR; 495 } 496 else 497 cmntcnt--; 498 } 499 else if (cmntcnt > 0) 500 c = NOCHAR; 501 else if (c == '<') 502 anglecnt++; 503 else if (c == '>') 504 { 505 if (anglecnt <= 0) 506 { 507 usrerr("653 Unbalanced '>'"); 508 c = NOCHAR; 509 } 510 else 511 anglecnt--; 512 } 513 else if (delim == ' ' && isascii(c) && isspace(c)) 514 c = ' '; 515 516 if (c == NOCHAR) 517 continue; 518 519 /* see if this is end of input */ 520 if (c == delim && anglecnt <= 0 && state != QST) 521 break; 522 523 newstate = StateTab[state][toktype(c)]; 524 if (tTd(22, 101)) 525 printf("ns=%02o\n", newstate); 526 state = newstate & TYPE; 527 if (bitset(M, newstate)) 528 c = NOCHAR; 529 if (bitset(B, newstate)) 530 break; 531 } 532 533 /* new token */ 534 if (tok != q) 535 { 536 *q++ = '\0'; 537 if (tTd(22, 36)) 538 { 539 printf("tok="); 540 xputs(tok); 541 (void) putchar('\n'); 542 } 543 if (avp >= &av[MAXATOM]) 544 { 545 syserr("553 prescan: too many tokens"); 546 goto returnnull; 547 } 548 if (q - tok > MAXNAME) 549 { 550 syserr("553 prescan: token too long"); 551 goto returnnull; 552 } 553 *avp++ = tok; 554 } 555 } while (c != '\0' && (c != delim || anglecnt > 0)); 556 *avp = NULL; 557 p--; 558 if (delimptr != NULL) 559 *delimptr = p; 560 if (tTd(22, 12)) 561 { 562 printf("prescan==>"); 563 printav(av); 564 } 565 CurEnv->e_to = saveto; 566 if (av[0] == NULL) 567 { 568 if (tTd(22, 1)) 569 printf("prescan: null leading token\n"); 570 return (NULL); 571 } 572 return (av); 573 } 574 /* 575 ** REWRITE -- apply rewrite rules to token vector. 576 ** 577 ** This routine is an ordered production system. Each rewrite 578 ** rule has a LHS (called the pattern) and a RHS (called the 579 ** rewrite); 'rwr' points the the current rewrite rule. 580 ** 581 ** For each rewrite rule, 'avp' points the address vector we 582 ** are trying to match against, and 'pvp' points to the pattern. 583 ** If pvp points to a special match value (MATCHZANY, MATCHANY, 584 ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp 585 ** matched is saved away in the match vector (pointed to by 'mvp'). 586 ** 587 ** When a match between avp & pvp does not match, we try to 588 ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS 589 ** we must also back out the match in mvp. If we reach a 590 ** MATCHANY or MATCHZANY we just extend the match and start 591 ** over again. 592 ** 593 ** When we finally match, we rewrite the address vector 594 ** and try over again. 595 ** 596 ** Parameters: 597 ** pvp -- pointer to token vector. 598 ** ruleset -- the ruleset to use for rewriting. 599 ** reclevel -- recursion level (to catch loops). 600 ** e -- the current envelope. 601 ** 602 ** Returns: 603 ** A status code. If EX_TEMPFAIL, higher level code should 604 ** attempt recovery. 605 ** 606 ** Side Effects: 607 ** pvp is modified. 608 */ 609 610 struct match 611 { 612 char **first; /* first token matched */ 613 char **last; /* last token matched */ 614 char **pattern; /* pointer to pattern */ 615 }; 616 617 # define MAXMATCH 9 /* max params per rewrite */ 618 619 # ifndef MAXRULERECURSION 620 # define MAXRULERECURSION 50 /* max recursion depth */ 621 # endif 622 623 624 int 625 rewrite(pvp, ruleset, reclevel, e) 626 char **pvp; 627 int ruleset; 628 int reclevel; 629 register ENVELOPE *e; 630 { 631 register char *ap; /* address pointer */ 632 register char *rp; /* rewrite pointer */ 633 register char **avp; /* address vector pointer */ 634 register char **rvp; /* rewrite vector pointer */ 635 register struct match *mlp; /* cur ptr into mlist */ 636 register struct rewrite *rwr; /* pointer to current rewrite rule */ 637 int ruleno; /* current rule number */ 638 int rstat = EX_OK; /* return status */ 639 int loopcount; 640 struct match mlist[MAXMATCH]; /* stores match on LHS */ 641 char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 642 643 if (OpMode == MD_TEST || tTd(21, 1)) 644 { 645 printf("rewrite: ruleset %2d input:", ruleset); 646 printav(pvp); 647 } 648 if (ruleset < 0 || ruleset >= MAXRWSETS) 649 { 650 syserr("554 rewrite: illegal ruleset number %d", ruleset); 651 return EX_CONFIG; 652 } 653 if (reclevel++ > MAXRULERECURSION) 654 { 655 syserr("rewrite: infinite recursion, ruleset %d", ruleset); 656 return EX_CONFIG; 657 } 658 if (pvp == NULL) 659 return EX_USAGE; 660 661 /* 662 ** Run through the list of rewrite rules, applying 663 ** any that match. 664 */ 665 666 ruleno = 1; 667 loopcount = 0; 668 for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 669 { 670 if (tTd(21, 12)) 671 { 672 printf("-----trying rule:"); 673 printav(rwr->r_lhs); 674 } 675 676 /* try to match on this rule */ 677 mlp = mlist; 678 rvp = rwr->r_lhs; 679 avp = pvp; 680 if (++loopcount > 100) 681 { 682 syserr("554 Infinite loop in ruleset %d, rule %d", 683 ruleset, ruleno); 684 if (tTd(21, 1)) 685 { 686 printf("workspace: "); 687 printav(pvp); 688 } 689 break; 690 } 691 692 while ((ap = *avp) != NULL || *rvp != NULL) 693 { 694 rp = *rvp; 695 if (tTd(21, 35)) 696 { 697 printf("ADVANCE rp="); 698 xputs(rp); 699 printf(", ap="); 700 xputs(ap); 701 printf("\n"); 702 } 703 if (rp == NULL) 704 { 705 /* end-of-pattern before end-of-address */ 706 goto backup; 707 } 708 if (ap == NULL && (*rp & 0377) != MATCHZANY && 709 (*rp & 0377) != MATCHZERO) 710 { 711 /* end-of-input with patterns left */ 712 goto backup; 713 } 714 715 switch (*rp & 0377) 716 { 717 register STAB *s; 718 char buf[MAXLINE]; 719 720 case MATCHCLASS: 721 /* match any phrase in a class */ 722 mlp->pattern = rvp; 723 mlp->first = avp; 724 extendclass: 725 ap = *avp; 726 if (ap == NULL) 727 goto backup; 728 mlp->last = avp++; 729 cataddr(mlp->first, mlp->last, buf, sizeof buf, '\0'); 730 s = stab(buf, ST_CLASS, ST_FIND); 731 if (s == NULL || !bitnset(rp[1], s->s_class)) 732 { 733 if (tTd(21, 36)) 734 { 735 printf("EXTEND rp="); 736 xputs(rp); 737 printf(", ap="); 738 xputs(ap); 739 printf("\n"); 740 } 741 goto extendclass; 742 } 743 if (tTd(21, 36)) 744 printf("CLMATCH\n"); 745 mlp++; 746 break; 747 748 case MATCHNCLASS: 749 /* match any token not in a class */ 750 s = stab(ap, ST_CLASS, ST_FIND); 751 if (s != NULL && bitnset(rp[1], s->s_class)) 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 bcopy((char *) &npvp[2], (char *) pvp, 1160 (int) (avp - npvp - 2) * sizeof *avp); 1161 if (tTd(21, 3)) 1162 printf("-----callsubr %s\n", npvp[1]); 1163 stat = rewrite(pvp, atoi(npvp[1]), reclevel, e); 1164 if (rstat == EX_OK || stat == EX_TEMPFAIL) 1165 rstat = stat; 1166 if (*pvp != NULL && (**pvp & 0377) == CANONNET) 1167 rwr = NULL; 1168 } 1169 } 1170 else 1171 { 1172 bcopy((char *) npvp, (char *) pvp, 1173 (int) (avp - npvp) * sizeof *avp); 1174 } 1175 if (tTd(21, 4)) 1176 { 1177 printf("rewritten as:"); 1178 printav(pvp); 1179 } 1180 } 1181 1182 if (OpMode == MD_TEST || tTd(21, 1)) 1183 { 1184 printf("rewrite: ruleset %2d returns:", ruleset); 1185 printav(pvp); 1186 } 1187 1188 return rstat; 1189 } 1190 /* 1191 ** BUILDADDR -- build address from token vector. 1192 ** 1193 ** Parameters: 1194 ** tv -- token vector. 1195 ** a -- pointer to address descriptor to fill. 1196 ** If NULL, one will be allocated. 1197 ** flags -- info regarding whether this is a sender or 1198 ** a recipient. 1199 ** e -- the current envelope. 1200 ** 1201 ** Returns: 1202 ** NULL if there was an error. 1203 ** 'a' otherwise. 1204 ** 1205 ** Side Effects: 1206 ** fills in 'a' 1207 */ 1208 1209 struct errcodes 1210 { 1211 char *ec_name; /* name of error code */ 1212 int ec_code; /* numeric code */ 1213 } ErrorCodes[] = 1214 { 1215 "usage", EX_USAGE, 1216 "nouser", EX_NOUSER, 1217 "nohost", EX_NOHOST, 1218 "unavailable", EX_UNAVAILABLE, 1219 "software", EX_SOFTWARE, 1220 "tempfail", EX_TEMPFAIL, 1221 "protocol", EX_PROTOCOL, 1222 #ifdef EX_CONFIG 1223 "config", EX_CONFIG, 1224 #endif 1225 NULL, EX_UNAVAILABLE, 1226 }; 1227 1228 ADDRESS * 1229 buildaddr(tv, a, flags, e) 1230 register char **tv; 1231 register ADDRESS *a; 1232 int flags; 1233 register ENVELOPE *e; 1234 { 1235 struct mailer **mp; 1236 register struct mailer *m; 1237 char *bp; 1238 int spaceleft; 1239 static MAILER errormailer; 1240 static char *errorargv[] = { "ERROR", NULL }; 1241 static char buf[MAXNAME]; 1242 1243 if (tTd(24, 5)) 1244 { 1245 printf("buildaddr, flags=%x, tv=", flags); 1246 printav(tv); 1247 } 1248 1249 if (a == NULL) 1250 a = (ADDRESS *) xalloc(sizeof *a); 1251 bzero((char *) a, sizeof *a); 1252 1253 /* set up default error return flags */ 1254 a->q_flags |= QPINGONFAILURE|QPINGONDELAY; 1255 1256 /* figure out what net/mailer to use */ 1257 if (*tv == NULL || (**tv & 0377) != CANONNET) 1258 { 1259 syserr("554 buildaddr: no net"); 1260 badaddr: 1261 a->q_flags |= QBADADDR; 1262 a->q_mailer = &errormailer; 1263 if (errormailer.m_name == NULL) 1264 { 1265 /* initialize the bogus mailer */ 1266 errormailer.m_name = "*error*"; 1267 errormailer.m_mailer = "ERROR"; 1268 errormailer.m_argv = errorargv; 1269 } 1270 return a; 1271 } 1272 tv++; 1273 if (strcasecmp(*tv, "error") == 0) 1274 { 1275 if ((**++tv & 0377) == CANONHOST) 1276 { 1277 register struct errcodes *ep; 1278 1279 if (isascii(**++tv) && isdigit(**tv)) 1280 { 1281 setstat(atoi(*tv)); 1282 } 1283 else 1284 { 1285 for (ep = ErrorCodes; ep->ec_name != NULL; ep++) 1286 if (strcasecmp(ep->ec_name, *tv) == 0) 1287 break; 1288 setstat(ep->ec_code); 1289 } 1290 tv++; 1291 } 1292 else 1293 setstat(EX_UNAVAILABLE); 1294 if ((**tv & 0377) != CANONUSER) 1295 syserr("554 buildaddr: error: no user"); 1296 cataddr(++tv, NULL, buf, sizeof buf, ' '); 1297 stripquotes(buf); 1298 if (isascii(buf[0]) && isdigit(buf[0]) && 1299 isascii(buf[1]) && isdigit(buf[1]) && 1300 isascii(buf[2]) && isdigit(buf[2]) && 1301 buf[3] == ' ') 1302 { 1303 char fmt[10]; 1304 1305 strncpy(fmt, buf, 3); 1306 strcpy(&fmt[3], " %s"); 1307 usrerr(fmt, buf + 4); 1308 1309 /* 1310 ** If this is a 4xx code and we aren't running 1311 ** SMTP on our input, bounce this message; 1312 ** otherwise it disappears without a trace. 1313 */ 1314 1315 if (fmt[0] == '4' && OpMode != MD_SMTP && 1316 OpMode != MD_DAEMON) 1317 { 1318 e->e_flags |= EF_FATALERRS; 1319 } 1320 } 1321 else 1322 { 1323 usrerr("553 %s", buf); 1324 } 1325 goto badaddr; 1326 } 1327 1328 for (mp = Mailer; (m = *mp++) != NULL; ) 1329 { 1330 if (strcasecmp(m->m_name, *tv) == 0) 1331 break; 1332 } 1333 if (m == NULL) 1334 { 1335 syserr("554 buildaddr: unknown mailer %s", *tv); 1336 goto badaddr; 1337 } 1338 a->q_mailer = m; 1339 1340 /* figure out what host (if any) */ 1341 tv++; 1342 if ((**tv & 0377) == CANONHOST) 1343 { 1344 bp = buf; 1345 spaceleft = sizeof buf - 1; 1346 while (*++tv != NULL && (**tv & 0377) != CANONUSER) 1347 { 1348 int i = strlen(*tv); 1349 1350 if (i > spaceleft) 1351 { 1352 /* out of space for this address */ 1353 if (spaceleft >= 0) 1354 syserr("554 buildaddr: host too long (%.40s...)", 1355 buf); 1356 i = spaceleft; 1357 spaceleft = 0; 1358 } 1359 if (i <= 0) 1360 continue; 1361 bcopy(*tv, bp, i); 1362 bp += i; 1363 spaceleft -= i; 1364 } 1365 *bp = '\0'; 1366 a->q_host = newstr(buf); 1367 } 1368 else 1369 { 1370 if (!bitnset(M_LOCALMAILER, m->m_flags)) 1371 { 1372 syserr("554 buildaddr: no host"); 1373 goto badaddr; 1374 } 1375 a->q_host = NULL; 1376 } 1377 1378 /* figure out the user */ 1379 if (*tv == NULL || (**tv & 0377) != CANONUSER) 1380 { 1381 syserr("554 buildaddr: no user"); 1382 goto badaddr; 1383 } 1384 tv++; 1385 1386 /* do special mapping for local mailer */ 1387 if (*tv != NULL) 1388 { 1389 register char *p = *tv; 1390 1391 if (*p == '"') 1392 p++; 1393 if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags)) 1394 a->q_mailer = m = ProgMailer; 1395 else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags)) 1396 a->q_mailer = m = FileMailer; 1397 else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags)) 1398 { 1399 /* may be :include: */ 1400 cataddr(tv, NULL, buf, sizeof buf, '\0'); 1401 stripquotes(buf); 1402 if (strncasecmp(buf, ":include:", 9) == 0) 1403 { 1404 /* if :include:, don't need further rewriting */ 1405 a->q_mailer = m = InclMailer; 1406 a->q_user = &buf[9]; 1407 return (a); 1408 } 1409 } 1410 } 1411 1412 if (bitnset(M_CHECKUDB, m->m_flags) && *tv != NULL && 1413 strcmp(*tv, "@") == 0) 1414 { 1415 tv++; 1416 a->q_flags |= QNOTREMOTE; 1417 } 1418 1419 /* rewrite according recipient mailer rewriting rules */ 1420 define('h', a->q_host, e); 1421 if (!bitset(RF_SENDERADDR|RF_HEADERADDR, flags)) 1422 { 1423 /* sender addresses done later */ 1424 (void) rewrite(tv, 2, 0, e); 1425 if (m->m_re_rwset > 0) 1426 (void) rewrite(tv, m->m_re_rwset, 0, e); 1427 } 1428 (void) rewrite(tv, 4, 0, e); 1429 1430 /* save the result for the command line/RCPT argument */ 1431 cataddr(tv, NULL, buf, sizeof buf, '\0'); 1432 a->q_user = buf; 1433 1434 /* 1435 ** Do mapping to lower case as requested by mailer 1436 */ 1437 1438 if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags)) 1439 makelower(a->q_host); 1440 if (!bitnset(M_USR_UPPER, m->m_flags)) 1441 makelower(a->q_user); 1442 1443 return (a); 1444 } 1445 /* 1446 ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 1447 ** 1448 ** Parameters: 1449 ** pvp -- parameter vector to rebuild. 1450 ** evp -- last parameter to include. Can be NULL to 1451 ** use entire pvp. 1452 ** buf -- buffer to build the string into. 1453 ** sz -- size of buf. 1454 ** spacesub -- the space separator character; if null, 1455 ** use SpaceSub. 1456 ** 1457 ** Returns: 1458 ** none. 1459 ** 1460 ** Side Effects: 1461 ** Destroys buf. 1462 */ 1463 1464 cataddr(pvp, evp, buf, sz, spacesub) 1465 char **pvp; 1466 char **evp; 1467 char *buf; 1468 register int sz; 1469 char spacesub; 1470 { 1471 bool oatomtok = FALSE; 1472 bool natomtok = FALSE; 1473 register int i; 1474 register char *p; 1475 1476 if (spacesub == '\0') 1477 spacesub = SpaceSub; 1478 1479 if (pvp == NULL) 1480 { 1481 (void) strcpy(buf, ""); 1482 return; 1483 } 1484 p = buf; 1485 sz -= 2; 1486 while (*pvp != NULL && (i = strlen(*pvp)) < sz) 1487 { 1488 natomtok = (toktype(**pvp) == ATM); 1489 if (oatomtok && natomtok) 1490 *p++ = spacesub; 1491 (void) strcpy(p, *pvp); 1492 oatomtok = natomtok; 1493 p += i; 1494 sz -= i + 1; 1495 if (pvp++ == evp) 1496 break; 1497 } 1498 *p = '\0'; 1499 } 1500 /* 1501 ** SAMEADDR -- Determine if two addresses are the same 1502 ** 1503 ** This is not just a straight comparison -- if the mailer doesn't 1504 ** care about the host we just ignore it, etc. 1505 ** 1506 ** Parameters: 1507 ** a, b -- pointers to the internal forms to compare. 1508 ** 1509 ** Returns: 1510 ** TRUE -- they represent the same mailbox. 1511 ** FALSE -- they don't. 1512 ** 1513 ** Side Effects: 1514 ** none. 1515 */ 1516 1517 bool 1518 sameaddr(a, b) 1519 register ADDRESS *a; 1520 register ADDRESS *b; 1521 { 1522 register ADDRESS *ca, *cb; 1523 1524 /* if they don't have the same mailer, forget it */ 1525 if (a->q_mailer != b->q_mailer) 1526 return (FALSE); 1527 1528 /* if the user isn't the same, we can drop out */ 1529 if (strcmp(a->q_user, b->q_user) != 0) 1530 return (FALSE); 1531 1532 /* if we have good uids for both but they differ, these are different */ 1533 if (a->q_mailer == ProgMailer) 1534 { 1535 ca = getctladdr(a); 1536 cb = getctladdr(b); 1537 if (ca != NULL && cb != NULL && 1538 bitset(QGOODUID, ca->q_flags & cb->q_flags) && 1539 ca->q_uid != cb->q_uid) 1540 return (FALSE); 1541 } 1542 1543 /* otherwise compare hosts (but be careful for NULL ptrs) */ 1544 if (a->q_host == b->q_host) 1545 { 1546 /* probably both null pointers */ 1547 return (TRUE); 1548 } 1549 if (a->q_host == NULL || b->q_host == NULL) 1550 { 1551 /* only one is a null pointer */ 1552 return (FALSE); 1553 } 1554 if (strcmp(a->q_host, b->q_host) != 0) 1555 return (FALSE); 1556 1557 return (TRUE); 1558 } 1559 /* 1560 ** PRINTADDR -- print address (for debugging) 1561 ** 1562 ** Parameters: 1563 ** a -- the address to print 1564 ** follow -- follow the q_next chain. 1565 ** 1566 ** Returns: 1567 ** none. 1568 ** 1569 ** Side Effects: 1570 ** none. 1571 */ 1572 1573 printaddr(a, follow) 1574 register ADDRESS *a; 1575 bool follow; 1576 { 1577 bool first = TRUE; 1578 register MAILER *m; 1579 MAILER pseudomailer; 1580 1581 while (a != NULL) 1582 { 1583 first = FALSE; 1584 printf("%x=", a); 1585 (void) fflush(stdout); 1586 1587 /* find the mailer -- carefully */ 1588 m = a->q_mailer; 1589 if (m == NULL) 1590 { 1591 m = &pseudomailer; 1592 m->m_mno = -1; 1593 m->m_name = "NULL"; 1594 } 1595 1596 printf("%s:\n\tmailer %d (%s), host `%s', user `%s', ruser `%s'\n", 1597 a->q_paddr, m->m_mno, m->m_name, 1598 a->q_host == NULL ? "<null>" : a->q_host, a->q_user, 1599 a->q_ruser == NULL ? "<null>" : a->q_ruser); 1600 printf("\tnext=%x, flags=%x, alias %x, uid %d, gid %d\n", 1601 a->q_next, a->q_flags, a->q_alias, a->q_uid, a->q_gid); 1602 printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n", 1603 a->q_owner == NULL ? "(none)" : a->q_owner, 1604 a->q_home == NULL ? "(none)" : a->q_home, 1605 a->q_fullname == NULL ? "(none)" : a->q_fullname); 1606 1607 if (!follow) 1608 return; 1609 a = a->q_next; 1610 } 1611 if (first) 1612 printf("[NULL]\n"); 1613 } 1614 /* 1615 ** EMPTYADDR -- return TRUE if this address is empty (``<>'') 1616 ** 1617 ** Parameters: 1618 ** a -- pointer to the address 1619 ** 1620 ** Returns: 1621 ** TRUE -- if this address is "empty" (i.e., no one should 1622 ** ever generate replies to it. 1623 ** FALSE -- if it is a "regular" (read: replyable) address. 1624 */ 1625 1626 bool 1627 emptyaddr(a) 1628 register ADDRESS *a; 1629 { 1630 return strcmp(a->q_paddr, "<>") == 0 || strcmp(a->q_user, "<>") == 0; 1631 } 1632 /* 1633 ** REMOTENAME -- return the name relative to the current mailer 1634 ** 1635 ** Parameters: 1636 ** name -- the name to translate. 1637 ** m -- the mailer that we want to do rewriting relative 1638 ** to. 1639 ** flags -- fine tune operations. 1640 ** pstat -- pointer to status word. 1641 ** e -- the current envelope. 1642 ** 1643 ** Returns: 1644 ** the text string representing this address relative to 1645 ** the receiving mailer. 1646 ** 1647 ** Side Effects: 1648 ** none. 1649 ** 1650 ** Warnings: 1651 ** The text string returned is tucked away locally; 1652 ** copy it if you intend to save it. 1653 */ 1654 1655 char * 1656 remotename(name, m, flags, pstat, e) 1657 char *name; 1658 struct mailer *m; 1659 int flags; 1660 int *pstat; 1661 register ENVELOPE *e; 1662 { 1663 register char **pvp; 1664 char *fancy; 1665 char *oldg = macvalue('g', e); 1666 int rwset; 1667 static char buf[MAXNAME]; 1668 char lbuf[MAXNAME]; 1669 char pvpbuf[PSBUFSIZE]; 1670 extern char *crackaddr(); 1671 1672 if (tTd(12, 1)) 1673 printf("remotename(%s)\n", name); 1674 1675 /* don't do anything if we are tagging it as special */ 1676 if (bitset(RF_SENDERADDR, flags)) 1677 rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset 1678 : m->m_se_rwset; 1679 else 1680 rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset 1681 : m->m_re_rwset; 1682 if (rwset < 0) 1683 return (name); 1684 1685 /* 1686 ** Do a heuristic crack of this name to extract any comment info. 1687 ** This will leave the name as a comment and a $g macro. 1688 */ 1689 1690 if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) 1691 fancy = "\201g"; 1692 else 1693 fancy = crackaddr(name); 1694 1695 /* 1696 ** Turn the name into canonical form. 1697 ** Normally this will be RFC 822 style, i.e., "user@domain". 1698 ** If this only resolves to "user", and the "C" flag is 1699 ** specified in the sending mailer, then the sender's 1700 ** domain will be appended. 1701 */ 1702 1703 pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL); 1704 if (pvp == NULL) 1705 return (name); 1706 if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 1707 *pstat = EX_TEMPFAIL; 1708 if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) 1709 { 1710 /* append from domain to this address */ 1711 register char **pxp = pvp; 1712 1713 /* see if there is an "@domain" in the current name */ 1714 while (*pxp != NULL && strcmp(*pxp, "@") != 0) 1715 pxp++; 1716 if (*pxp == NULL) 1717 { 1718 /* no.... append the "@domain" from the sender */ 1719 register char **qxq = e->e_fromdomain; 1720 1721 while ((*pxp++ = *qxq++) != NULL) 1722 continue; 1723 if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 1724 *pstat = EX_TEMPFAIL; 1725 } 1726 } 1727 1728 /* 1729 ** Do more specific rewriting. 1730 ** Rewrite using ruleset 1 or 2 depending on whether this is 1731 ** a sender address or not. 1732 ** Then run it through any receiving-mailer-specific rulesets. 1733 */ 1734 1735 if (bitset(RF_SENDERADDR, flags)) 1736 { 1737 if (rewrite(pvp, 1, 0, e) == EX_TEMPFAIL) 1738 *pstat = EX_TEMPFAIL; 1739 } 1740 else 1741 { 1742 if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL) 1743 *pstat = EX_TEMPFAIL; 1744 } 1745 if (rwset > 0) 1746 { 1747 if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL) 1748 *pstat = EX_TEMPFAIL; 1749 } 1750 1751 /* 1752 ** Do any final sanitation the address may require. 1753 ** This will normally be used to turn internal forms 1754 ** (e.g., user@host.LOCAL) into external form. This 1755 ** may be used as a default to the above rules. 1756 */ 1757 1758 if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL) 1759 *pstat = EX_TEMPFAIL; 1760 1761 /* 1762 ** Now restore the comment information we had at the beginning. 1763 */ 1764 1765 cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0'); 1766 define('g', lbuf, e); 1767 1768 /* need to make sure route-addrs have <angle brackets> */ 1769 if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@') 1770 expand("<\201g>", buf, &buf[sizeof buf - 1], e); 1771 else 1772 expand(fancy, buf, &buf[sizeof buf - 1], e); 1773 1774 define('g', oldg, e); 1775 1776 if (tTd(12, 1)) 1777 printf("remotename => `%s'\n", buf); 1778 return (buf); 1779 } 1780 /* 1781 ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 1782 ** 1783 ** Parameters: 1784 ** a -- the address to map (but just the user name part). 1785 ** sendq -- the sendq in which to install any replacement 1786 ** addresses. 1787 ** aliaslevel -- the alias nesting depth. 1788 ** e -- the envelope. 1789 ** 1790 ** Returns: 1791 ** none. 1792 */ 1793 1794 maplocaluser(a, sendq, aliaslevel, e) 1795 register ADDRESS *a; 1796 ADDRESS **sendq; 1797 int aliaslevel; 1798 ENVELOPE *e; 1799 { 1800 register char **pvp; 1801 register ADDRESS *a1 = NULL; 1802 auto char *delimptr; 1803 char pvpbuf[PSBUFSIZE]; 1804 1805 if (tTd(29, 1)) 1806 { 1807 printf("maplocaluser: "); 1808 printaddr(a, FALSE); 1809 } 1810 pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr); 1811 if (pvp == NULL) 1812 return; 1813 1814 (void) rewrite(pvp, 5, 0, e); 1815 if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 1816 return; 1817 1818 /* if non-null, mailer destination specified -- has it changed? */ 1819 a1 = buildaddr(pvp, NULL, 0, e); 1820 if (a1 == NULL || sameaddr(a, a1)) 1821 return; 1822 1823 /* mark old address as dead; insert new address */ 1824 a->q_flags |= QDONTSEND; 1825 if (tTd(29, 5)) 1826 { 1827 printf("maplocaluser: QDONTSEND "); 1828 printaddr(a, FALSE); 1829 } 1830 a1->q_alias = a; 1831 allocaddr(a1, RF_COPYALL, NULL); 1832 (void) recipient(a1, sendq, aliaslevel, e); 1833 } 1834 /* 1835 ** DEQUOTE_INIT -- initialize dequote map 1836 ** 1837 ** This is a no-op. 1838 ** 1839 ** Parameters: 1840 ** map -- the internal map structure. 1841 ** args -- arguments. 1842 ** 1843 ** Returns: 1844 ** TRUE. 1845 */ 1846 1847 bool 1848 dequote_init(map, args) 1849 MAP *map; 1850 char *args; 1851 { 1852 register char *p = args; 1853 1854 for (;;) 1855 { 1856 while (isascii(*p) && isspace(*p)) 1857 p++; 1858 if (*p != '-') 1859 break; 1860 switch (*++p) 1861 { 1862 case 'a': 1863 map->map_app = ++p; 1864 break; 1865 1866 case 's': 1867 map->map_coldelim = *++p; 1868 break; 1869 } 1870 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 1871 p++; 1872 if (*p != '\0') 1873 *p = '\0'; 1874 } 1875 if (map->map_app != NULL) 1876 map->map_app = newstr(map->map_app); 1877 1878 return TRUE; 1879 } 1880 /* 1881 ** DEQUOTE_MAP -- unquote an address 1882 ** 1883 ** Parameters: 1884 ** map -- the internal map structure (ignored). 1885 ** name -- the name to dequote. 1886 ** av -- arguments (ignored). 1887 ** statp -- pointer to status out-parameter. 1888 ** 1889 ** Returns: 1890 ** NULL -- if there were no quotes, or if the resulting 1891 ** unquoted buffer would not be acceptable to prescan. 1892 ** else -- The dequoted buffer. 1893 */ 1894 1895 char * 1896 dequote_map(map, name, av, statp) 1897 MAP *map; 1898 char *name; 1899 char **av; 1900 int *statp; 1901 { 1902 register char *p; 1903 register char *q; 1904 register char c; 1905 int anglecnt = 0; 1906 int cmntcnt = 0; 1907 int quotecnt = 0; 1908 int spacecnt = 0; 1909 bool quotemode = FALSE; 1910 bool bslashmode = FALSE; 1911 char spacesub = map->map_coldelim; 1912 1913 for (p = q = name; (c = *p++) != '\0'; ) 1914 { 1915 if (bslashmode) 1916 { 1917 bslashmode = FALSE; 1918 *q++ = c; 1919 continue; 1920 } 1921 1922 if (c == ' ' && spacesub != '\0') 1923 c = spacesub; 1924 1925 switch (c) 1926 { 1927 case '\\': 1928 bslashmode = TRUE; 1929 break; 1930 1931 case '(': 1932 cmntcnt++; 1933 break; 1934 1935 case ')': 1936 if (cmntcnt-- <= 0) 1937 return NULL; 1938 break; 1939 1940 case ' ': 1941 spacecnt++; 1942 break; 1943 } 1944 1945 if (cmntcnt > 0) 1946 { 1947 *q++ = c; 1948 continue; 1949 } 1950 1951 switch (c) 1952 { 1953 case '"': 1954 quotemode = !quotemode; 1955 quotecnt++; 1956 continue; 1957 1958 case '<': 1959 anglecnt++; 1960 break; 1961 1962 case '>': 1963 if (anglecnt-- <= 0) 1964 return NULL; 1965 break; 1966 } 1967 *q++ = c; 1968 } 1969 1970 if (anglecnt != 0 || cmntcnt != 0 || bslashmode || 1971 quotemode || quotecnt <= 0 || spacecnt != 0) 1972 return NULL; 1973 *q++ = '\0'; 1974 return name; 1975 } 1976