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: #if !defined(lint) && !defined(NOSCCS) 12: static char SccsId[] = "@(#)parseaddr.c 5.6 (Berkeley) 4/2/86"; 13: #endif 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., user@host.LOCAL) 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: }