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