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