|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1983 Eric P. Allman ! 3: * Copyright (c) 1988 Regents of the University of California. ! 4: * All rights reserved. ! 5: * ! 6: * Redistribution and use in source and binary forms are permitted ! 7: * provided that the above copyright notice and this paragraph are ! 8: * duplicated in all such forms and that any documentation, ! 9: * advertising materials, and other materials related to such ! 10: * distribution and use acknowledge that the software was developed ! 11: * by the University of California, Berkeley. The name of the ! 12: * University may not be used to endorse or promote products derived ! 13: * from this software without specific prior written permission. ! 14: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 15: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 16: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 17: */ ! 18: ! 19: #ifndef lint ! 20: static char sccsid[] = "@(#)parseaddr.c 5.9 (Berkeley) 6/30/88"; ! 21: #endif /* not lint */ ! 22: ! 23: # include "sendmail.h" ! 24: ! 25: /* ! 26: ** PARSEADDR -- Parse an address ! 27: ** ! 28: ** Parses an address and breaks it up into three parts: a ! 29: ** net to transmit the message on, the host to transmit it ! 30: ** to, and a user on that host. These are loaded into an ! 31: ** ADDRESS header with the values squirreled away if necessary. ! 32: ** The "user" part may not be a real user; the process may ! 33: ** just reoccur on that machine. For example, on a machine ! 34: ** with an arpanet connection, the address ! 35: ** csvax.bill@berkeley ! 36: ** will break up to a "user" of 'csvax.bill' and a host ! 37: ** of 'berkeley' -- to be transmitted over the arpanet. ! 38: ** ! 39: ** Parameters: ! 40: ** addr -- the address to parse. ! 41: ** a -- a pointer to the address descriptor buffer. ! 42: ** If NULL, a header will be created. ! 43: ** copyf -- determines what shall be copied: ! 44: ** -1 -- don't copy anything. The printname ! 45: ** (q_paddr) is just addr, and the ! 46: ** user & host are allocated internally ! 47: ** to parse. ! 48: ** 0 -- copy out the parsed user & host, but ! 49: ** don't copy the printname. ! 50: ** +1 -- copy everything. ! 51: ** delim -- the character to terminate the address, passed ! 52: ** to prescan. ! 53: ** ! 54: ** Returns: ! 55: ** A pointer to the address descriptor header (`a' if ! 56: ** `a' is non-NULL). ! 57: ** NULL on error. ! 58: ** ! 59: ** Side Effects: ! 60: ** none ! 61: */ ! 62: ! 63: /* following delimiters are inherent to the internal algorithms */ ! 64: # define DELIMCHARS "\001()<>,;\\\"\r\n" /* word delimiters */ ! 65: ! 66: ADDRESS * ! 67: parseaddr(addr, a, copyf, delim) ! 68: char *addr; ! 69: register ADDRESS *a; ! 70: int copyf; ! 71: char delim; ! 72: { ! 73: register char **pvp; ! 74: register struct mailer *m; ! 75: char pvpbuf[PSBUFSIZE]; ! 76: extern char **prescan(); ! 77: extern ADDRESS *buildaddr(); ! 78: ! 79: /* ! 80: ** Initialize and prescan address. ! 81: */ ! 82: ! 83: CurEnv->e_to = addr; ! 84: # ifdef DEBUG ! 85: if (tTd(20, 1)) ! 86: printf("\n--parseaddr(%s)\n", addr); ! 87: # endif DEBUG ! 88: ! 89: pvp = prescan(addr, delim, pvpbuf); ! 90: if (pvp == NULL) ! 91: return (NULL); ! 92: ! 93: /* ! 94: ** Apply rewriting rules. ! 95: ** Ruleset 0 does basic parsing. It must resolve. ! 96: */ ! 97: ! 98: rewrite(pvp, 3); ! 99: rewrite(pvp, 0); ! 100: ! 101: /* ! 102: ** See if we resolved to a real mailer. ! 103: */ ! 104: ! 105: if (pvp[0][0] != CANONNET) ! 106: { ! 107: setstat(EX_USAGE); ! 108: usrerr("cannot resolve name"); ! 109: return (NULL); ! 110: } ! 111: ! 112: /* ! 113: ** Build canonical address from pvp. ! 114: */ ! 115: ! 116: a = buildaddr(pvp, a); ! 117: if (a == NULL) ! 118: return (NULL); ! 119: m = a->q_mailer; ! 120: ! 121: /* ! 122: ** Make local copies of the host & user and then ! 123: ** transport them out. ! 124: */ ! 125: ! 126: if (copyf > 0) ! 127: { ! 128: extern char *DelimChar; ! 129: char savec = *DelimChar; ! 130: ! 131: *DelimChar = '\0'; ! 132: a->q_paddr = newstr(addr); ! 133: *DelimChar = savec; ! 134: } ! 135: else ! 136: a->q_paddr = addr; ! 137: ! 138: if (a->q_user == NULL) ! 139: a->q_user = ""; ! 140: if (a->q_host == NULL) ! 141: a->q_host = ""; ! 142: ! 143: if (copyf >= 0) ! 144: { ! 145: a->q_host = newstr(a->q_host); ! 146: if (a->q_user != a->q_paddr) ! 147: a->q_user = newstr(a->q_user); ! 148: } ! 149: ! 150: /* ! 151: ** Convert host name to lower case if requested. ! 152: ** User name will be done later. ! 153: */ ! 154: ! 155: if (!bitnset(M_HST_UPPER, m->m_flags)) ! 156: makelower(a->q_host); ! 157: ! 158: /* ! 159: ** Compute return value. ! 160: */ ! 161: ! 162: # ifdef DEBUG ! 163: if (tTd(20, 1)) ! 164: { ! 165: printf("parseaddr-->"); ! 166: printaddr(a, FALSE); ! 167: } ! 168: # endif DEBUG ! 169: ! 170: return (a); ! 171: } ! 172: /* ! 173: ** LOWERADDR -- map UPPER->lower case on addresses as requested. ! 174: ** ! 175: ** Parameters: ! 176: ** a -- address to be mapped. ! 177: ** ! 178: ** Returns: ! 179: ** none. ! 180: ** ! 181: ** Side Effects: ! 182: ** none. ! 183: */ ! 184: ! 185: loweraddr(a) ! 186: register ADDRESS *a; ! 187: { ! 188: register MAILER *m = a->q_mailer; ! 189: ! 190: if (!bitnset(M_USR_UPPER, m->m_flags)) ! 191: makelower(a->q_user); ! 192: } ! 193: /* ! 194: ** PRESCAN -- Prescan name and make it canonical ! 195: ** ! 196: ** Scans a name and turns it into a set of tokens. This process ! 197: ** deletes blanks and comments (in parentheses). ! 198: ** ! 199: ** This routine knows about quoted strings and angle brackets. ! 200: ** ! 201: ** There are certain subtleties to this routine. The one that ! 202: ** comes to mind now is that backslashes on the ends of names ! 203: ** are silently stripped off; this is intentional. The problem ! 204: ** is that some versions of sndmsg (like at LBL) set the kill ! 205: ** character to something other than @ when reading addresses; ! 206: ** so people type "csvax.eric\@berkeley" -- which screws up the ! 207: ** berknet mailer. ! 208: ** ! 209: ** Parameters: ! 210: ** addr -- the name to chomp. ! 211: ** delim -- the delimiter for the address, normally ! 212: ** '\0' or ','; \0 is accepted in any case. ! 213: ** If '\t' then we are reading the .cf file. ! 214: ** pvpbuf -- place to put the saved text -- note that ! 215: ** the pointers are static. ! 216: ** ! 217: ** Returns: ! 218: ** A pointer to a vector of tokens. ! 219: ** NULL on error. ! 220: ** ! 221: ** Side Effects: ! 222: ** sets DelimChar to point to the character matching 'delim'. ! 223: */ ! 224: ! 225: /* states and character types */ ! 226: # define OPR 0 /* operator */ ! 227: # define ATM 1 /* atom */ ! 228: # define QST 2 /* in quoted string */ ! 229: # define SPC 3 /* chewing up spaces */ ! 230: # define ONE 4 /* pick up one character */ ! 231: ! 232: # define NSTATES 5 /* number of states */ ! 233: # define TYPE 017 /* mask to select state type */ ! 234: ! 235: /* meta bits for table */ ! 236: # define M 020 /* meta character; don't pass through */ ! 237: # define B 040 /* cause a break */ ! 238: # define MB M|B /* meta-break */ ! 239: ! 240: static short StateTab[NSTATES][NSTATES] = ! 241: { ! 242: /* oldst chtype> OPR ATM QST SPC ONE */ ! 243: /*OPR*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ! 244: /*ATM*/ OPR|B, ATM, QST|B, SPC|MB, ONE|B, ! 245: /*QST*/ QST, QST, OPR, QST, QST, ! 246: /*SPC*/ OPR, ATM, QST, SPC|M, ONE, ! 247: /*ONE*/ OPR, OPR, OPR, OPR, OPR, ! 248: }; ! 249: ! 250: # define NOCHAR -1 /* signal nothing in lookahead token */ ! 251: ! 252: char *DelimChar; /* set to point to the delimiter */ ! 253: ! 254: char ** ! 255: prescan(addr, delim, pvpbuf) ! 256: char *addr; ! 257: char delim; ! 258: char pvpbuf[]; ! 259: { ! 260: register char *p; ! 261: register char *q; ! 262: register int c; ! 263: char **avp; ! 264: bool bslashmode; ! 265: int cmntcnt; ! 266: int anglecnt; ! 267: char *tok; ! 268: int state; ! 269: int newstate; ! 270: static char *av[MAXATOM+1]; ! 271: extern int errno; ! 272: ! 273: /* make sure error messages don't have garbage on them */ ! 274: errno = 0; ! 275: ! 276: q = pvpbuf; ! 277: bslashmode = FALSE; ! 278: cmntcnt = 0; ! 279: anglecnt = 0; ! 280: avp = av; ! 281: state = OPR; ! 282: c = NOCHAR; ! 283: p = addr; ! 284: # ifdef DEBUG ! 285: if (tTd(22, 45)) ! 286: { ! 287: printf("prescan: "); ! 288: xputs(p); ! 289: (void) putchar('\n'); ! 290: } ! 291: # endif DEBUG ! 292: ! 293: do ! 294: { ! 295: /* read a token */ ! 296: tok = q; ! 297: for (;;) ! 298: { ! 299: /* store away any old lookahead character */ ! 300: if (c != NOCHAR) ! 301: { ! 302: /* see if there is room */ ! 303: if (q >= &pvpbuf[PSBUFSIZE - 5]) ! 304: { ! 305: usrerr("Address too long"); ! 306: DelimChar = p; ! 307: return (NULL); ! 308: } ! 309: ! 310: /* squirrel it away */ ! 311: *q++ = c; ! 312: } ! 313: ! 314: /* read a new input character */ ! 315: c = *p++; ! 316: if (c == '\0') ! 317: break; ! 318: c &= ~0200; ! 319: ! 320: # ifdef DEBUG ! 321: if (tTd(22, 101)) ! 322: printf("c=%c, s=%d; ", c, state); ! 323: # endif DEBUG ! 324: ! 325: /* chew up special characters */ ! 326: *q = '\0'; ! 327: if (bslashmode) ! 328: { ! 329: /* kludge \! for naive users */ ! 330: if (c != '!') ! 331: c |= 0200; ! 332: bslashmode = FALSE; ! 333: } ! 334: else if (c == '\\') ! 335: { ! 336: bslashmode = TRUE; ! 337: c = NOCHAR; ! 338: } ! 339: else if (state == QST) ! 340: { ! 341: /* do nothing, just avoid next clauses */ ! 342: } ! 343: else if (c == '(') ! 344: { ! 345: cmntcnt++; ! 346: c = NOCHAR; ! 347: } ! 348: else if (c == ')') ! 349: { ! 350: if (cmntcnt <= 0) ! 351: { ! 352: usrerr("Unbalanced ')'"); ! 353: DelimChar = p; ! 354: return (NULL); ! 355: } ! 356: else ! 357: cmntcnt--; ! 358: } ! 359: else if (cmntcnt > 0) ! 360: c = NOCHAR; ! 361: else if (c == '<') ! 362: anglecnt++; ! 363: else if (c == '>') ! 364: { ! 365: if (anglecnt <= 0) ! 366: { ! 367: usrerr("Unbalanced '>'"); ! 368: DelimChar = p; ! 369: return (NULL); ! 370: } ! 371: anglecnt--; ! 372: } ! 373: else if (delim == ' ' && isspace(c)) ! 374: c = ' '; ! 375: ! 376: if (c == NOCHAR) ! 377: continue; ! 378: ! 379: /* see if this is end of input */ ! 380: if (c == delim && anglecnt <= 0 && state != QST) ! 381: break; ! 382: ! 383: newstate = StateTab[state][toktype(c)]; ! 384: # ifdef DEBUG ! 385: if (tTd(22, 101)) ! 386: printf("ns=%02o\n", newstate); ! 387: # endif DEBUG ! 388: state = newstate & TYPE; ! 389: if (bitset(M, newstate)) ! 390: c = NOCHAR; ! 391: if (bitset(B, newstate)) ! 392: break; ! 393: } ! 394: ! 395: /* new token */ ! 396: if (tok != q) ! 397: { ! 398: *q++ = '\0'; ! 399: # ifdef DEBUG ! 400: if (tTd(22, 36)) ! 401: { ! 402: printf("tok="); ! 403: xputs(tok); ! 404: (void) putchar('\n'); ! 405: } ! 406: # endif DEBUG ! 407: if (avp >= &av[MAXATOM]) ! 408: { ! 409: syserr("prescan: too many tokens"); ! 410: DelimChar = p; ! 411: return (NULL); ! 412: } ! 413: *avp++ = tok; ! 414: } ! 415: } while (c != '\0' && (c != delim || anglecnt > 0)); ! 416: *avp = NULL; ! 417: DelimChar = --p; ! 418: if (cmntcnt > 0) ! 419: usrerr("Unbalanced '('"); ! 420: else if (anglecnt > 0) ! 421: usrerr("Unbalanced '<'"); ! 422: else if (state == QST) ! 423: usrerr("Unbalanced '\"'"); ! 424: else if (av[0] != NULL) ! 425: return (av); ! 426: return (NULL); ! 427: } ! 428: /* ! 429: ** TOKTYPE -- return token type ! 430: ** ! 431: ** Parameters: ! 432: ** c -- the character in question. ! 433: ** ! 434: ** Returns: ! 435: ** Its type. ! 436: ** ! 437: ** Side Effects: ! 438: ** none. ! 439: */ ! 440: ! 441: toktype(c) ! 442: register char c; ! 443: { ! 444: static char buf[50]; ! 445: static bool firstime = TRUE; ! 446: ! 447: if (firstime) ! 448: { ! 449: firstime = FALSE; ! 450: expand("\001o", buf, &buf[sizeof buf - 1], CurEnv); ! 451: (void) strcat(buf, DELIMCHARS); ! 452: } ! 453: if (c == MATCHCLASS || c == MATCHREPL || c == MATCHNCLASS) ! 454: return (ONE); ! 455: if (c == '"') ! 456: return (QST); ! 457: if (!isascii(c)) ! 458: return (ATM); ! 459: if (isspace(c) || c == ')') ! 460: return (SPC); ! 461: if (iscntrl(c) || index(buf, c) != NULL) ! 462: return (OPR); ! 463: return (ATM); ! 464: } ! 465: /* ! 466: ** REWRITE -- apply rewrite rules to token vector. ! 467: ** ! 468: ** This routine is an ordered production system. Each rewrite ! 469: ** rule has a LHS (called the pattern) and a RHS (called the ! 470: ** rewrite); 'rwr' points the the current rewrite rule. ! 471: ** ! 472: ** For each rewrite rule, 'avp' points the address vector we ! 473: ** are trying to match against, and 'pvp' points to the pattern. ! 474: ** If pvp points to a special match value (MATCHZANY, MATCHANY, ! 475: ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp ! 476: ** matched is saved away in the match vector (pointed to by 'mvp'). ! 477: ** ! 478: ** When a match between avp & pvp does not match, we try to ! 479: ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS ! 480: ** we must also back out the match in mvp. If we reach a ! 481: ** MATCHANY or MATCHZANY we just extend the match and start ! 482: ** over again. ! 483: ** ! 484: ** When we finally match, we rewrite the address vector ! 485: ** and try over again. ! 486: ** ! 487: ** Parameters: ! 488: ** pvp -- pointer to token vector. ! 489: ** ! 490: ** Returns: ! 491: ** none. ! 492: ** ! 493: ** Side Effects: ! 494: ** pvp is modified. ! 495: */ ! 496: ! 497: struct match ! 498: { ! 499: char **first; /* first token matched */ ! 500: char **last; /* last token matched */ ! 501: }; ! 502: ! 503: # define MAXMATCH 9 /* max params per rewrite */ ! 504: ! 505: ! 506: rewrite(pvp, ruleset) ! 507: char **pvp; ! 508: int ruleset; ! 509: { ! 510: register char *ap; /* address pointer */ ! 511: register char *rp; /* rewrite pointer */ ! 512: register char **avp; /* address vector pointer */ ! 513: register char **rvp; /* rewrite vector pointer */ ! 514: register struct match *mlp; /* cur ptr into mlist */ ! 515: register struct rewrite *rwr; /* pointer to current rewrite rule */ ! 516: struct match mlist[MAXMATCH]; /* stores match on LHS */ ! 517: char *npvp[MAXATOM+1]; /* temporary space for rebuild */ ! 518: ! 519: if (OpMode == MD_TEST || tTd(21, 2)) ! 520: { ! 521: printf("rewrite: ruleset %2d input:", ruleset); ! 522: printav(pvp); ! 523: } ! 524: if (pvp == NULL) ! 525: return; ! 526: ! 527: /* ! 528: ** Run through the list of rewrite rules, applying ! 529: ** any that match. ! 530: */ ! 531: ! 532: for (rwr = RewriteRules[ruleset]; rwr != NULL; ) ! 533: { ! 534: # ifdef DEBUG ! 535: if (tTd(21, 12)) ! 536: { ! 537: printf("-----trying rule:"); ! 538: printav(rwr->r_lhs); ! 539: } ! 540: # endif DEBUG ! 541: ! 542: /* try to match on this rule */ ! 543: mlp = mlist; ! 544: rvp = rwr->r_lhs; ! 545: avp = pvp; ! 546: while ((ap = *avp) != NULL || *rvp != NULL) ! 547: { ! 548: rp = *rvp; ! 549: # ifdef DEBUG ! 550: if (tTd(21, 35)) ! 551: { ! 552: printf("ap="); ! 553: xputs(ap); ! 554: printf(", rp="); ! 555: xputs(rp); ! 556: printf("\n"); ! 557: } ! 558: # endif DEBUG ! 559: if (rp == NULL) ! 560: { ! 561: /* end-of-pattern before end-of-address */ ! 562: goto backup; ! 563: } ! 564: if (ap == NULL && *rp != MATCHZANY) ! 565: { ! 566: /* end-of-input */ ! 567: break; ! 568: } ! 569: ! 570: switch (*rp) ! 571: { ! 572: register STAB *s; ! 573: ! 574: case MATCHCLASS: ! 575: case MATCHNCLASS: ! 576: /* match any token in (not in) a class */ ! 577: s = stab(ap, ST_CLASS, ST_FIND); ! 578: if (s == NULL || !bitnset(rp[1], s->s_class)) ! 579: { ! 580: if (*rp == MATCHCLASS) ! 581: goto backup; ! 582: } ! 583: else if (*rp == MATCHNCLASS) ! 584: goto backup; ! 585: ! 586: /* explicit fall-through */ ! 587: ! 588: case MATCHONE: ! 589: case MATCHANY: ! 590: /* match exactly one token */ ! 591: mlp->first = avp; ! 592: mlp->last = avp++; ! 593: mlp++; ! 594: break; ! 595: ! 596: case MATCHZANY: ! 597: /* match zero or more tokens */ ! 598: mlp->first = avp; ! 599: mlp->last = avp - 1; ! 600: mlp++; ! 601: break; ! 602: ! 603: default: ! 604: /* must have exact match */ ! 605: if (strcasecmp(rp, ap)) ! 606: goto backup; ! 607: avp++; ! 608: break; ! 609: } ! 610: ! 611: /* successful match on this token */ ! 612: rvp++; ! 613: continue; ! 614: ! 615: backup: ! 616: /* match failed -- back up */ ! 617: while (--rvp >= rwr->r_lhs) ! 618: { ! 619: rp = *rvp; ! 620: if (*rp == MATCHANY || *rp == MATCHZANY) ! 621: { ! 622: /* extend binding and continue */ ! 623: avp = ++mlp[-1].last; ! 624: avp++; ! 625: rvp++; ! 626: break; ! 627: } ! 628: avp--; ! 629: if (*rp == MATCHONE || *rp == MATCHCLASS || ! 630: *rp == MATCHNCLASS) ! 631: { ! 632: /* back out binding */ ! 633: mlp--; ! 634: } ! 635: } ! 636: ! 637: if (rvp < rwr->r_lhs) ! 638: { ! 639: /* total failure to match */ ! 640: break; ! 641: } ! 642: } ! 643: ! 644: /* ! 645: ** See if we successfully matched ! 646: */ ! 647: ! 648: if (rvp < rwr->r_lhs || *rvp != NULL) ! 649: { ! 650: # ifdef DEBUG ! 651: if (tTd(21, 10)) ! 652: printf("----- rule fails\n"); ! 653: # endif DEBUG ! 654: rwr = rwr->r_next; ! 655: continue; ! 656: } ! 657: ! 658: rvp = rwr->r_rhs; ! 659: # ifdef DEBUG ! 660: if (tTd(21, 12)) ! 661: { ! 662: printf("-----rule matches:"); ! 663: printav(rvp); ! 664: } ! 665: # endif DEBUG ! 666: ! 667: rp = *rvp; ! 668: if (*rp == CANONUSER) ! 669: { ! 670: rvp++; ! 671: rwr = rwr->r_next; ! 672: } ! 673: else if (*rp == CANONHOST) ! 674: { ! 675: rvp++; ! 676: rwr = NULL; ! 677: } ! 678: else if (*rp == CANONNET) ! 679: rwr = NULL; ! 680: ! 681: /* substitute */ ! 682: for (avp = npvp; *rvp != NULL; rvp++) ! 683: { ! 684: register struct match *m; ! 685: register char **pp; ! 686: ! 687: rp = *rvp; ! 688: if (*rp == MATCHREPL) ! 689: { ! 690: /* substitute from LHS */ ! 691: m = &mlist[rp[1] - '1']; ! 692: if (m >= mlp) ! 693: { ! 694: syserr("rewrite: ruleset %d: replacement out of bounds", ruleset); ! 695: return; ! 696: } ! 697: # ifdef DEBUG ! 698: if (tTd(21, 15)) ! 699: { ! 700: printf("$%c:", rp[1]); ! 701: pp = m->first; ! 702: while (pp <= m->last) ! 703: { ! 704: printf(" %x=\"", *pp); ! 705: (void) fflush(stdout); ! 706: printf("%s\"", *pp++); ! 707: } ! 708: printf("\n"); ! 709: } ! 710: # endif DEBUG ! 711: pp = m->first; ! 712: while (pp <= m->last) ! 713: { ! 714: if (avp >= &npvp[MAXATOM]) ! 715: { ! 716: syserr("rewrite: expansion too long"); ! 717: return; ! 718: } ! 719: *avp++ = *pp++; ! 720: } ! 721: } ! 722: else ! 723: { ! 724: /* vanilla replacement */ ! 725: if (avp >= &npvp[MAXATOM]) ! 726: { ! 727: toolong: ! 728: syserr("rewrite: expansion too long"); ! 729: return; ! 730: } ! 731: *avp++ = rp; ! 732: } ! 733: } ! 734: *avp++ = NULL; ! 735: ! 736: /* ! 737: ** Check for any hostname lookups. ! 738: */ ! 739: ! 740: for (rvp = npvp; *rvp != NULL; rvp++) ! 741: { ! 742: char **hbrvp; ! 743: char **xpvp; ! 744: int trsize; ! 745: char *olddelimchar; ! 746: char buf[MAXNAME + 1]; ! 747: char *pvpb1[MAXATOM + 1]; ! 748: char pvpbuf[PSBUFSIZE]; ! 749: extern char *DelimChar; ! 750: ! 751: if (**rvp != HOSTBEGIN) ! 752: continue; ! 753: ! 754: /* ! 755: ** Got a hostname lookup. ! 756: ** ! 757: ** This could be optimized fairly easily. ! 758: */ ! 759: ! 760: hbrvp = rvp; ! 761: ! 762: /* extract the match part */ ! 763: while (*++rvp != NULL && **rvp != HOSTEND) ! 764: continue; ! 765: if (*rvp != NULL) ! 766: *rvp++ = NULL; ! 767: ! 768: /* save the remainder of the input string */ ! 769: trsize = (int) (avp - rvp + 1) * sizeof *rvp; ! 770: bcopy((char *) rvp, (char *) pvpb1, trsize); ! 771: ! 772: /* look it up */ ! 773: cataddr(++hbrvp, buf, sizeof buf); ! 774: maphostname(buf, sizeof buf); ! 775: ! 776: /* scan the new host name */ ! 777: olddelimchar = DelimChar; ! 778: xpvp = prescan(buf, '\0', pvpbuf); ! 779: DelimChar = olddelimchar; ! 780: if (xpvp == NULL) ! 781: { ! 782: syserr("rewrite: cannot prescan canonical hostname: %s", buf); ! 783: return; ! 784: } ! 785: ! 786: /* append it to the token list */ ! 787: for (avp = --hbrvp; *xpvp != NULL; xpvp++) ! 788: { ! 789: *avp++ = newstr(*xpvp); ! 790: if (avp >= &npvp[MAXATOM]) ! 791: goto toolong; ! 792: } ! 793: ! 794: /* restore the old trailing information */ ! 795: for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) ! 796: if (avp >= &npvp[MAXATOM]) ! 797: goto toolong; ! 798: ! 799: break; ! 800: } ! 801: ! 802: /* ! 803: ** Check for subroutine calls. ! 804: */ ! 805: ! 806: if (*npvp != NULL && **npvp == CALLSUBR) ! 807: { ! 808: bcopy((char *) &npvp[2], (char *) pvp, ! 809: (int) (avp - npvp - 2) * sizeof *avp); ! 810: # ifdef DEBUG ! 811: if (tTd(21, 3)) ! 812: printf("-----callsubr %s\n", npvp[1]); ! 813: # endif DEBUG ! 814: rewrite(pvp, atoi(npvp[1])); ! 815: } ! 816: else ! 817: { ! 818: bcopy((char *) npvp, (char *) pvp, ! 819: (int) (avp - npvp) * sizeof *avp); ! 820: } ! 821: # ifdef DEBUG ! 822: if (tTd(21, 4)) ! 823: { ! 824: printf("rewritten as:"); ! 825: printav(pvp); ! 826: } ! 827: # endif DEBUG ! 828: } ! 829: ! 830: if (OpMode == MD_TEST || tTd(21, 2)) ! 831: { ! 832: printf("rewrite: ruleset %2d returns:", ruleset); ! 833: printav(pvp); ! 834: } ! 835: } ! 836: /* ! 837: ** BUILDADDR -- build address from token vector. ! 838: ** ! 839: ** Parameters: ! 840: ** tv -- token vector. ! 841: ** a -- pointer to address descriptor to fill. ! 842: ** If NULL, one will be allocated. ! 843: ** ! 844: ** Returns: ! 845: ** NULL if there was an error. ! 846: ** 'a' otherwise. ! 847: ** ! 848: ** Side Effects: ! 849: ** fills in 'a' ! 850: */ ! 851: ! 852: ADDRESS * ! 853: buildaddr(tv, a) ! 854: register char **tv; ! 855: register ADDRESS *a; ! 856: { ! 857: static char buf[MAXNAME]; ! 858: struct mailer **mp; ! 859: register struct mailer *m; ! 860: ! 861: if (a == NULL) ! 862: a = (ADDRESS *) xalloc(sizeof *a); ! 863: bzero((char *) a, sizeof *a); ! 864: ! 865: /* figure out what net/mailer to use */ ! 866: if (**tv != CANONNET) ! 867: { ! 868: syserr("buildaddr: no net"); ! 869: return (NULL); ! 870: } ! 871: tv++; ! 872: if (!strcasecmp(*tv, "error")) ! 873: { ! 874: if (**++tv == CANONHOST) ! 875: { ! 876: setstat(atoi(*++tv)); ! 877: tv++; ! 878: } ! 879: if (**tv != CANONUSER) ! 880: syserr("buildaddr: error: no user"); ! 881: buf[0] = '\0'; ! 882: while (*++tv != NULL) ! 883: { ! 884: if (buf[0] != '\0') ! 885: (void) strcat(buf, " "); ! 886: (void) strcat(buf, *tv); ! 887: } ! 888: usrerr(buf); ! 889: return (NULL); ! 890: } ! 891: for (mp = Mailer; (m = *mp++) != NULL; ) ! 892: { ! 893: if (!strcasecmp(m->m_name, *tv)) ! 894: break; ! 895: } ! 896: if (m == NULL) ! 897: { ! 898: syserr("buildaddr: unknown mailer %s", *tv); ! 899: return (NULL); ! 900: } ! 901: a->q_mailer = m; ! 902: ! 903: /* figure out what host (if any) */ ! 904: tv++; ! 905: if (!bitnset(M_LOCAL, m->m_flags)) ! 906: { ! 907: if (**tv++ != CANONHOST) ! 908: { ! 909: syserr("buildaddr: no host"); ! 910: return (NULL); ! 911: } ! 912: buf[0] = '\0'; ! 913: while (*tv != NULL && **tv != CANONUSER) ! 914: (void) strcat(buf, *tv++); ! 915: a->q_host = newstr(buf); ! 916: } ! 917: else ! 918: a->q_host = NULL; ! 919: ! 920: /* figure out the user */ ! 921: if (**tv != CANONUSER) ! 922: { ! 923: syserr("buildaddr: no user"); ! 924: return (NULL); ! 925: } ! 926: ! 927: /* rewrite according recipient mailer rewriting rules */ ! 928: rewrite(++tv, 2); ! 929: if (m->m_r_rwset > 0) ! 930: rewrite(tv, m->m_r_rwset); ! 931: rewrite(tv, 4); ! 932: ! 933: /* save the result for the command line/RCPT argument */ ! 934: cataddr(tv, buf, sizeof buf); ! 935: a->q_user = buf; ! 936: ! 937: return (a); ! 938: } ! 939: /* ! 940: ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) ! 941: ** ! 942: ** Parameters: ! 943: ** pvp -- parameter vector to rebuild. ! 944: ** buf -- buffer to build the string into. ! 945: ** sz -- size of buf. ! 946: ** ! 947: ** Returns: ! 948: ** none. ! 949: ** ! 950: ** Side Effects: ! 951: ** Destroys buf. ! 952: */ ! 953: ! 954: cataddr(pvp, buf, sz) ! 955: char **pvp; ! 956: char *buf; ! 957: register int sz; ! 958: { ! 959: bool oatomtok = FALSE; ! 960: bool natomtok = FALSE; ! 961: register int i; ! 962: register char *p; ! 963: ! 964: if (pvp == NULL) ! 965: { ! 966: (void) strcpy(buf, ""); ! 967: return; ! 968: } ! 969: p = buf; ! 970: sz -= 2; ! 971: while (*pvp != NULL && (i = strlen(*pvp)) < sz) ! 972: { ! 973: natomtok = (toktype(**pvp) == ATM); ! 974: if (oatomtok && natomtok) ! 975: *p++ = SpaceSub; ! 976: (void) strcpy(p, *pvp); ! 977: oatomtok = natomtok; ! 978: p += i; ! 979: sz -= i + 1; ! 980: pvp++; ! 981: } ! 982: *p = '\0'; ! 983: } ! 984: /* ! 985: ** SAMEADDR -- Determine if two addresses are the same ! 986: ** ! 987: ** This is not just a straight comparison -- if the mailer doesn't ! 988: ** care about the host we just ignore it, etc. ! 989: ** ! 990: ** Parameters: ! 991: ** a, b -- pointers to the internal forms to compare. ! 992: ** ! 993: ** Returns: ! 994: ** TRUE -- they represent the same mailbox. ! 995: ** FALSE -- they don't. ! 996: ** ! 997: ** Side Effects: ! 998: ** none. ! 999: */ ! 1000: ! 1001: bool ! 1002: sameaddr(a, b) ! 1003: register ADDRESS *a; ! 1004: register ADDRESS *b; ! 1005: { ! 1006: /* if they don't have the same mailer, forget it */ ! 1007: if (a->q_mailer != b->q_mailer) ! 1008: return (FALSE); ! 1009: ! 1010: /* if the user isn't the same, we can drop out */ ! 1011: if (strcmp(a->q_user, b->q_user) != 0) ! 1012: return (FALSE); ! 1013: ! 1014: /* if the mailer ignores hosts, we have succeeded! */ ! 1015: if (bitnset(M_LOCAL, a->q_mailer->m_flags)) ! 1016: return (TRUE); ! 1017: ! 1018: /* otherwise compare hosts (but be careful for NULL ptrs) */ ! 1019: if (a->q_host == NULL || b->q_host == NULL) ! 1020: return (FALSE); ! 1021: if (strcmp(a->q_host, b->q_host) != 0) ! 1022: return (FALSE); ! 1023: ! 1024: return (TRUE); ! 1025: } ! 1026: /* ! 1027: ** PRINTADDR -- print address (for debugging) ! 1028: ** ! 1029: ** Parameters: ! 1030: ** a -- the address to print ! 1031: ** follow -- follow the q_next chain. ! 1032: ** ! 1033: ** Returns: ! 1034: ** none. ! 1035: ** ! 1036: ** Side Effects: ! 1037: ** none. ! 1038: */ ! 1039: ! 1040: # ifdef DEBUG ! 1041: ! 1042: printaddr(a, follow) ! 1043: register ADDRESS *a; ! 1044: bool follow; ! 1045: { ! 1046: bool first = TRUE; ! 1047: ! 1048: while (a != NULL) ! 1049: { ! 1050: first = FALSE; ! 1051: printf("%x=", a); ! 1052: (void) fflush(stdout); ! 1053: printf("%s: mailer %d (%s), host `%s', user `%s'\n", a->q_paddr, ! 1054: a->q_mailer->m_mno, a->q_mailer->m_name, a->q_host, ! 1055: a->q_user); ! 1056: printf("\tnext=%x, flags=%o, alias %x\n", a->q_next, a->q_flags, ! 1057: a->q_alias); ! 1058: printf("\thome=\"%s\", fullname=\"%s\"\n", a->q_home, ! 1059: a->q_fullname); ! 1060: ! 1061: if (!follow) ! 1062: return; ! 1063: a = a->q_next; ! 1064: } ! 1065: if (first) ! 1066: printf("[NULL]\n"); ! 1067: } ! 1068: ! 1069: # endif DEBUG ! 1070: /* ! 1071: ** REMOTENAME -- return the name relative to the current mailer ! 1072: ** ! 1073: ** Parameters: ! 1074: ** name -- the name to translate. ! 1075: ** m -- the mailer that we want to do rewriting relative ! 1076: ** to. ! 1077: ** senderaddress -- if set, uses the sender rewriting rules ! 1078: ** rather than the recipient rewriting rules. ! 1079: ** canonical -- if set, strip out any comment information, ! 1080: ** etc. ! 1081: ** ! 1082: ** Returns: ! 1083: ** the text string representing this address relative to ! 1084: ** the receiving mailer. ! 1085: ** ! 1086: ** Side Effects: ! 1087: ** none. ! 1088: ** ! 1089: ** Warnings: ! 1090: ** The text string returned is tucked away locally; ! 1091: ** copy it if you intend to save it. ! 1092: */ ! 1093: ! 1094: char * ! 1095: remotename(name, m, senderaddress, canonical) ! 1096: char *name; ! 1097: struct mailer *m; ! 1098: bool senderaddress; ! 1099: bool canonical; ! 1100: { ! 1101: register char **pvp; ! 1102: char *fancy; ! 1103: extern char *macvalue(); ! 1104: char *oldg = macvalue('g', CurEnv); ! 1105: static char buf[MAXNAME]; ! 1106: char lbuf[MAXNAME]; ! 1107: char pvpbuf[PSBUFSIZE]; ! 1108: extern char **prescan(); ! 1109: extern char *crackaddr(); ! 1110: ! 1111: # ifdef DEBUG ! 1112: if (tTd(12, 1)) ! 1113: printf("remotename(%s)\n", name); ! 1114: # endif DEBUG ! 1115: ! 1116: /* don't do anything if we are tagging it as special */ ! 1117: if ((senderaddress ? m->m_s_rwset : m->m_r_rwset) < 0) ! 1118: return (name); ! 1119: ! 1120: /* ! 1121: ** Do a heuristic crack of this name to extract any comment info. ! 1122: ** This will leave the name as a comment and a $g macro. ! 1123: */ ! 1124: ! 1125: if (canonical) ! 1126: fancy = "\001g"; ! 1127: else ! 1128: fancy = crackaddr(name); ! 1129: ! 1130: /* ! 1131: ** Turn the name into canonical form. ! 1132: ** Normally this will be RFC 822 style, i.e., "user@domain". ! 1133: ** If this only resolves to "user", and the "C" flag is ! 1134: ** specified in the sending mailer, then the sender's ! 1135: ** domain will be appended. ! 1136: */ ! 1137: ! 1138: pvp = prescan(name, '\0', pvpbuf); ! 1139: if (pvp == NULL) ! 1140: return (name); ! 1141: rewrite(pvp, 3); ! 1142: if (CurEnv->e_fromdomain != NULL) ! 1143: { ! 1144: /* append from domain to this address */ ! 1145: register char **pxp = pvp; ! 1146: ! 1147: /* see if there is an "@domain" in the current name */ ! 1148: while (*pxp != NULL && strcmp(*pxp, "@") != 0) ! 1149: pxp++; ! 1150: if (*pxp == NULL) ! 1151: { ! 1152: /* no.... append the "@domain" from the sender */ ! 1153: register char **qxq = CurEnv->e_fromdomain; ! 1154: ! 1155: while ((*pxp++ = *qxq++) != NULL) ! 1156: continue; ! 1157: rewrite(pvp, 3); ! 1158: } ! 1159: } ! 1160: ! 1161: /* ! 1162: ** Do more specific rewriting. ! 1163: ** Rewrite using ruleset 1 or 2 depending on whether this is ! 1164: ** a sender address or not. ! 1165: ** Then run it through any receiving-mailer-specific rulesets. ! 1166: */ ! 1167: ! 1168: if (senderaddress) ! 1169: { ! 1170: rewrite(pvp, 1); ! 1171: if (m->m_s_rwset > 0) ! 1172: rewrite(pvp, m->m_s_rwset); ! 1173: } ! 1174: else ! 1175: { ! 1176: rewrite(pvp, 2); ! 1177: if (m->m_r_rwset > 0) ! 1178: rewrite(pvp, m->m_r_rwset); ! 1179: } ! 1180: ! 1181: /* ! 1182: ** Do any final sanitation the address may require. ! 1183: ** This will normally be used to turn internal forms ! 1184: ** (e.g., [email protected]) into external form. This ! 1185: ** may be used as a default to the above rules. ! 1186: */ ! 1187: ! 1188: rewrite(pvp, 4); ! 1189: ! 1190: /* ! 1191: ** Now restore the comment information we had at the beginning. ! 1192: */ ! 1193: ! 1194: cataddr(pvp, lbuf, sizeof lbuf); ! 1195: define('g', lbuf, CurEnv); ! 1196: expand(fancy, buf, &buf[sizeof buf - 1], CurEnv); ! 1197: define('g', oldg, CurEnv); ! 1198: ! 1199: # ifdef DEBUG ! 1200: if (tTd(12, 1)) ! 1201: printf("remotename => `%s'\n", buf); ! 1202: # endif DEBUG ! 1203: return (buf); ! 1204: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.