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