122976Smiriam /* 222976Smiriam ** Sendmail 322976Smiriam ** Copyright (c) 1983 Eric P. Allman 422976Smiriam ** Berkeley, California 522976Smiriam ** 622976Smiriam ** Copyright (c) 1983 Regents of the University of California. 722976Smiriam ** All rights reserved. The Berkeley software License Agreement 822976Smiriam ** specifies the terms and conditions for redistribution. 922976Smiriam */ 1022976Smiriam 1122976Smiriam #ifndef lint 12*33725Sbostic static char SccsId[] = "@(#)parseaddr.c 5.7 (Berkeley) 03/13/88"; 1322976Smiriam #endif not lint 1422976Smiriam 153312Seric # include "sendmail.h" 16297Seric 17297Seric /* 189888Seric ** PARSEADDR -- Parse an address 19297Seric ** 20297Seric ** Parses an address and breaks it up into three parts: a 21297Seric ** net to transmit the message on, the host to transmit it 22297Seric ** to, and a user on that host. These are loaded into an 232973Seric ** ADDRESS header with the values squirreled away if necessary. 24297Seric ** The "user" part may not be a real user; the process may 25297Seric ** just reoccur on that machine. For example, on a machine 26297Seric ** with an arpanet connection, the address 27297Seric ** csvax.bill@berkeley 28297Seric ** will break up to a "user" of 'csvax.bill' and a host 29297Seric ** of 'berkeley' -- to be transmitted over the arpanet. 30297Seric ** 31297Seric ** Parameters: 32297Seric ** addr -- the address to parse. 33297Seric ** a -- a pointer to the address descriptor buffer. 34297Seric ** If NULL, a header will be created. 35297Seric ** copyf -- determines what shall be copied: 36297Seric ** -1 -- don't copy anything. The printname 37297Seric ** (q_paddr) is just addr, and the 38297Seric ** user & host are allocated internally 39297Seric ** to parse. 40297Seric ** 0 -- copy out the parsed user & host, but 41297Seric ** don't copy the printname. 42297Seric ** +1 -- copy everything. 4311445Seric ** delim -- the character to terminate the address, passed 4411445Seric ** to prescan. 45297Seric ** 46297Seric ** Returns: 47297Seric ** A pointer to the address descriptor header (`a' if 48297Seric ** `a' is non-NULL). 49297Seric ** NULL on error. 50297Seric ** 51297Seric ** Side Effects: 52297Seric ** none 53297Seric */ 54297Seric 559374Seric /* following delimiters are inherent to the internal algorithms */ 5616155Seric # define DELIMCHARS "\001()<>,;\\\"\r\n" /* word delimiters */ 572091Seric 582973Seric ADDRESS * 5911445Seric parseaddr(addr, a, copyf, delim) 60297Seric char *addr; 612973Seric register ADDRESS *a; 62297Seric int copyf; 6311445Seric char delim; 64297Seric { 653149Seric register char **pvp; 663149Seric register struct mailer *m; 6716914Seric char pvpbuf[PSBUFSIZE]; 683149Seric extern char **prescan(); 693149Seric extern ADDRESS *buildaddr(); 70297Seric 71297Seric /* 72297Seric ** Initialize and prescan address. 73297Seric */ 74297Seric 756903Seric CurEnv->e_to = addr; 763188Seric # ifdef DEBUG 777675Seric if (tTd(20, 1)) 789888Seric printf("\n--parseaddr(%s)\n", addr); 793188Seric # endif DEBUG 803188Seric 8116914Seric pvp = prescan(addr, delim, pvpbuf); 823149Seric if (pvp == NULL) 83297Seric return (NULL); 84297Seric 85297Seric /* 863149Seric ** Apply rewriting rules. 877889Seric ** Ruleset 0 does basic parsing. It must resolve. 88297Seric */ 89297Seric 908181Seric rewrite(pvp, 3); 914070Seric rewrite(pvp, 0); 92297Seric 933149Seric /* 943149Seric ** See if we resolved to a real mailer. 953149Seric */ 96297Seric 973149Seric if (pvp[0][0] != CANONNET) 983149Seric { 993149Seric setstat(EX_USAGE); 1003149Seric usrerr("cannot resolve name"); 1013149Seric return (NULL); 102297Seric } 103297Seric 104297Seric /* 1053149Seric ** Build canonical address from pvp. 106297Seric */ 107297Seric 1083149Seric a = buildaddr(pvp, a); 1094279Seric if (a == NULL) 1104279Seric return (NULL); 1114598Seric m = a->q_mailer; 112297Seric 113297Seric /* 1143149Seric ** Make local copies of the host & user and then 1153149Seric ** transport them out. 116297Seric */ 117297Seric 118297Seric if (copyf > 0) 1198078Seric { 1208078Seric extern char *DelimChar; 1218078Seric char savec = *DelimChar; 1228078Seric 1238078Seric *DelimChar = '\0'; 1242973Seric a->q_paddr = newstr(addr); 1258078Seric *DelimChar = savec; 1268078Seric } 127297Seric else 128297Seric a->q_paddr = addr; 12924944Seric 13024944Seric if (a->q_user == NULL) 13124944Seric a->q_user = ""; 13224944Seric if (a->q_host == NULL) 13324944Seric a->q_host = ""; 13424944Seric 1353149Seric if (copyf >= 0) 136297Seric { 13724944Seric a->q_host = newstr(a->q_host); 1383149Seric if (a->q_user != a->q_paddr) 1393149Seric a->q_user = newstr(a->q_user); 140297Seric } 141297Seric 142297Seric /* 14316202Seric ** Convert host name to lower case if requested. 14416202Seric ** User name will be done later. 14516202Seric */ 14616202Seric 14716202Seric if (!bitnset(M_HST_UPPER, m->m_flags)) 14816202Seric makelower(a->q_host); 14916202Seric 15016202Seric /* 151297Seric ** Compute return value. 152297Seric */ 153297Seric 154297Seric # ifdef DEBUG 1557675Seric if (tTd(20, 1)) 1564443Seric { 1579888Seric printf("parseaddr-->"); 1584443Seric printaddr(a, FALSE); 1594443Seric } 160297Seric # endif DEBUG 161297Seric 162297Seric return (a); 163297Seric } 164297Seric /* 16516162Seric ** LOWERADDR -- map UPPER->lower case on addresses as requested. 16616162Seric ** 16716162Seric ** Parameters: 16816162Seric ** a -- address to be mapped. 16916162Seric ** 17016162Seric ** Returns: 17116162Seric ** none. 17216162Seric ** 17316162Seric ** Side Effects: 17416162Seric ** none. 17516162Seric */ 17616162Seric 17716162Seric loweraddr(a) 17816162Seric register ADDRESS *a; 17916162Seric { 18016162Seric register MAILER *m = a->q_mailer; 18116162Seric 18216162Seric if (!bitnset(M_USR_UPPER, m->m_flags)) 18316162Seric makelower(a->q_user); 18416162Seric } 18516162Seric /* 186297Seric ** PRESCAN -- Prescan name and make it canonical 187297Seric ** 1889374Seric ** Scans a name and turns it into a set of tokens. This process 1899374Seric ** deletes blanks and comments (in parentheses). 190297Seric ** 191297Seric ** This routine knows about quoted strings and angle brackets. 192297Seric ** 193297Seric ** There are certain subtleties to this routine. The one that 194297Seric ** comes to mind now is that backslashes on the ends of names 195297Seric ** are silently stripped off; this is intentional. The problem 196297Seric ** is that some versions of sndmsg (like at LBL) set the kill 197297Seric ** character to something other than @ when reading addresses; 198297Seric ** so people type "csvax.eric\@berkeley" -- which screws up the 199297Seric ** berknet mailer. 200297Seric ** 201297Seric ** Parameters: 202297Seric ** addr -- the name to chomp. 203297Seric ** delim -- the delimiter for the address, normally 204297Seric ** '\0' or ','; \0 is accepted in any case. 20515284Seric ** If '\t' then we are reading the .cf file. 20616914Seric ** pvpbuf -- place to put the saved text -- note that 20716914Seric ** the pointers are static. 208297Seric ** 209297Seric ** Returns: 2103149Seric ** A pointer to a vector of tokens. 211297Seric ** NULL on error. 212297Seric ** 213297Seric ** Side Effects: 21425279Seric ** sets DelimChar to point to the character matching 'delim'. 215297Seric */ 216297Seric 2178078Seric /* states and character types */ 2188078Seric # define OPR 0 /* operator */ 2198078Seric # define ATM 1 /* atom */ 2208078Seric # define QST 2 /* in quoted string */ 2218078Seric # define SPC 3 /* chewing up spaces */ 2228078Seric # define ONE 4 /* pick up one character */ 2233149Seric 2248078Seric # define NSTATES 5 /* number of states */ 2258078Seric # define TYPE 017 /* mask to select state type */ 2268078Seric 2278078Seric /* meta bits for table */ 2288078Seric # define M 020 /* meta character; don't pass through */ 2298078Seric # define B 040 /* cause a break */ 2308078Seric # define MB M|B /* meta-break */ 2318078Seric 2328078Seric static short StateTab[NSTATES][NSTATES] = 2338078Seric { 2348087Seric /* oldst chtype> OPR ATM QST SPC ONE */ 2359051Seric /*OPR*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, 2369051Seric /*ATM*/ OPR|B, ATM, QST|B, SPC|MB, ONE|B, 2379051Seric /*QST*/ QST, QST, OPR, QST, QST, 2388078Seric /*SPC*/ OPR, ATM, QST, SPC|M, ONE, 2398078Seric /*ONE*/ OPR, OPR, OPR, OPR, OPR, 2408078Seric }; 2418078Seric 2428078Seric # define NOCHAR -1 /* signal nothing in lookahead token */ 2438078Seric 2448078Seric char *DelimChar; /* set to point to the delimiter */ 2458078Seric 2463149Seric char ** 24716914Seric prescan(addr, delim, pvpbuf) 248297Seric char *addr; 249297Seric char delim; 25016914Seric char pvpbuf[]; 251297Seric { 252297Seric register char *p; 2538078Seric register char *q; 2549346Seric register int c; 2553149Seric char **avp; 256297Seric bool bslashmode; 257297Seric int cmntcnt; 2588423Seric int anglecnt; 2593149Seric char *tok; 2608078Seric int state; 2618078Seric int newstate; 2628078Seric static char *av[MAXATOM+1]; 26315253Seric extern int errno; 264297Seric 26515253Seric /* make sure error messages don't have garbage on them */ 26615253Seric errno = 0; 26715253Seric 26816914Seric q = pvpbuf; 2693149Seric bslashmode = FALSE; 2707800Seric cmntcnt = 0; 2718423Seric anglecnt = 0; 2723149Seric avp = av; 2738078Seric state = OPR; 2748078Seric c = NOCHAR; 2758078Seric p = addr; 2768078Seric # ifdef DEBUG 2778078Seric if (tTd(22, 45)) 278297Seric { 2798078Seric printf("prescan: "); 2808078Seric xputs(p); 28123109Seric (void) putchar('\n'); 2828078Seric } 2838078Seric # endif DEBUG 2848078Seric 2858078Seric do 2868078Seric { 2873149Seric /* read a token */ 2883149Seric tok = q; 2898078Seric for (;;) 290297Seric { 2918078Seric /* store away any old lookahead character */ 2928078Seric if (c != NOCHAR) 2938078Seric { 29415284Seric /* see if there is room */ 29516914Seric if (q >= &pvpbuf[PSBUFSIZE - 5]) 2968078Seric { 2978078Seric usrerr("Address too long"); 2988078Seric DelimChar = p; 2998078Seric return (NULL); 3008078Seric } 30115284Seric 30215284Seric /* squirrel it away */ 3038078Seric *q++ = c; 3048078Seric } 3058078Seric 3068078Seric /* read a new input character */ 3078078Seric c = *p++; 3088078Seric if (c == '\0') 3098078Seric break; 31015284Seric c &= ~0200; 31115284Seric 3128078Seric # ifdef DEBUG 3138078Seric if (tTd(22, 101)) 3148078Seric printf("c=%c, s=%d; ", c, state); 3158078Seric # endif DEBUG 3168078Seric 3173149Seric /* chew up special characters */ 3183149Seric *q = '\0'; 3193149Seric if (bslashmode) 3203149Seric { 32124944Seric /* kludge \! for naive users */ 32224944Seric if (c != '!') 32324944Seric c |= 0200; 3243149Seric bslashmode = FALSE; 3253149Seric } 3263149Seric else if (c == '\\') 3273149Seric { 3283149Seric bslashmode = TRUE; 3298078Seric c = NOCHAR; 3303149Seric } 3318514Seric else if (state == QST) 3328514Seric { 3338514Seric /* do nothing, just avoid next clauses */ 3348514Seric } 3358078Seric else if (c == '(') 3364100Seric { 3378078Seric cmntcnt++; 3388078Seric c = NOCHAR; 3394100Seric } 3408078Seric else if (c == ')') 3413149Seric { 3428078Seric if (cmntcnt <= 0) 3433149Seric { 3448078Seric usrerr("Unbalanced ')'"); 3458078Seric DelimChar = p; 3468078Seric return (NULL); 3473149Seric } 3488078Seric else 3498078Seric cmntcnt--; 3508078Seric } 3518078Seric else if (cmntcnt > 0) 3528078Seric c = NOCHAR; 3538423Seric else if (c == '<') 3548423Seric anglecnt++; 3558423Seric else if (c == '>') 3568423Seric { 3578423Seric if (anglecnt <= 0) 3588423Seric { 3598423Seric usrerr("Unbalanced '>'"); 3608423Seric DelimChar = p; 3618423Seric return (NULL); 3628423Seric } 3638423Seric anglecnt--; 3648423Seric } 36511423Seric else if (delim == ' ' && isspace(c)) 36611423Seric c = ' '; 3673149Seric 3688078Seric if (c == NOCHAR) 3698078Seric continue; 3703149Seric 3718078Seric /* see if this is end of input */ 37211405Seric if (c == delim && anglecnt <= 0 && state != QST) 3733149Seric break; 3743149Seric 3758078Seric newstate = StateTab[state][toktype(c)]; 3768078Seric # ifdef DEBUG 3778078Seric if (tTd(22, 101)) 3788078Seric printf("ns=%02o\n", newstate); 3798078Seric # endif DEBUG 3808078Seric state = newstate & TYPE; 3818078Seric if (bitset(M, newstate)) 3828078Seric c = NOCHAR; 3838078Seric if (bitset(B, newstate)) 3844228Seric break; 385297Seric } 3863149Seric 3873149Seric /* new token */ 3888078Seric if (tok != q) 3891378Seric { 3908078Seric *q++ = '\0'; 3918078Seric # ifdef DEBUG 3928078Seric if (tTd(22, 36)) 393297Seric { 3948078Seric printf("tok="); 3958078Seric xputs(tok); 39623109Seric (void) putchar('\n'); 397297Seric } 3988078Seric # endif DEBUG 3998078Seric if (avp >= &av[MAXATOM]) 400297Seric { 4018078Seric syserr("prescan: too many tokens"); 4028078Seric DelimChar = p; 4038078Seric return (NULL); 404297Seric } 4058078Seric *avp++ = tok; 406297Seric } 4078423Seric } while (c != '\0' && (c != delim || anglecnt > 0)); 4083149Seric *avp = NULL; 4098078Seric DelimChar = --p; 4103149Seric if (cmntcnt > 0) 4113149Seric usrerr("Unbalanced '('"); 4128423Seric else if (anglecnt > 0) 4138423Seric usrerr("Unbalanced '<'"); 4148078Seric else if (state == QST) 4153149Seric usrerr("Unbalanced '\"'"); 4163149Seric else if (av[0] != NULL) 4173149Seric return (av); 4183149Seric return (NULL); 4193149Seric } 4203149Seric /* 4213149Seric ** TOKTYPE -- return token type 4223149Seric ** 4233149Seric ** Parameters: 4243149Seric ** c -- the character in question. 4253149Seric ** 4263149Seric ** Returns: 4273149Seric ** Its type. 4283149Seric ** 4293149Seric ** Side Effects: 4303149Seric ** none. 4313149Seric */ 432297Seric 4333149Seric toktype(c) 4343149Seric register char c; 4353149Seric { 4363380Seric static char buf[50]; 4373382Seric static bool firstime = TRUE; 4383380Seric 4393382Seric if (firstime) 4403380Seric { 4413382Seric firstime = FALSE; 44216155Seric expand("\001o", buf, &buf[sizeof buf - 1], CurEnv); 4437005Seric (void) strcat(buf, DELIMCHARS); 4443380Seric } 4459585Seric if (c == MATCHCLASS || c == MATCHREPL || c == MATCHNCLASS) 4468078Seric return (ONE); 4478078Seric if (c == '"') 4488078Seric return (QST); 4494100Seric if (!isascii(c)) 4508078Seric return (ATM); 4518078Seric if (isspace(c) || c == ')') 4528078Seric return (SPC); 4533380Seric if (iscntrl(c) || index(buf, c) != NULL) 4548078Seric return (OPR); 4558078Seric return (ATM); 4563149Seric } 4573149Seric /* 4583149Seric ** REWRITE -- apply rewrite rules to token vector. 4593149Seric ** 4604476Seric ** This routine is an ordered production system. Each rewrite 4614476Seric ** rule has a LHS (called the pattern) and a RHS (called the 4624476Seric ** rewrite); 'rwr' points the the current rewrite rule. 4634476Seric ** 4644476Seric ** For each rewrite rule, 'avp' points the address vector we 4654476Seric ** are trying to match against, and 'pvp' points to the pattern. 4668058Seric ** If pvp points to a special match value (MATCHZANY, MATCHANY, 4679585Seric ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp 4689585Seric ** matched is saved away in the match vector (pointed to by 'mvp'). 4694476Seric ** 4704476Seric ** When a match between avp & pvp does not match, we try to 4719585Seric ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS 4724476Seric ** we must also back out the match in mvp. If we reach a 4738058Seric ** MATCHANY or MATCHZANY we just extend the match and start 4748058Seric ** over again. 4754476Seric ** 4764476Seric ** When we finally match, we rewrite the address vector 4774476Seric ** and try over again. 4784476Seric ** 4793149Seric ** Parameters: 4803149Seric ** pvp -- pointer to token vector. 4813149Seric ** 4823149Seric ** Returns: 4833149Seric ** none. 4843149Seric ** 4853149Seric ** Side Effects: 4863149Seric ** pvp is modified. 4873149Seric */ 4882091Seric 4893149Seric struct match 4903149Seric { 4914468Seric char **first; /* first token matched */ 4924468Seric char **last; /* last token matched */ 4933149Seric }; 4943149Seric 4954468Seric # define MAXMATCH 9 /* max params per rewrite */ 4963149Seric 4973149Seric 4984070Seric rewrite(pvp, ruleset) 4993149Seric char **pvp; 5004070Seric int ruleset; 5013149Seric { 5023149Seric register char *ap; /* address pointer */ 5033149Seric register char *rp; /* rewrite pointer */ 5043149Seric register char **avp; /* address vector pointer */ 5053149Seric register char **rvp; /* rewrite vector pointer */ 5068058Seric register struct match *mlp; /* cur ptr into mlist */ 5078058Seric register struct rewrite *rwr; /* pointer to current rewrite rule */ 5084468Seric struct match mlist[MAXMATCH]; /* stores match on LHS */ 5093149Seric char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 5103149Seric 5119279Seric if (OpMode == MD_TEST || tTd(21, 2)) 5123149Seric { 5138959Seric printf("rewrite: ruleset %2d input:", ruleset); 5143149Seric printav(pvp); 5153149Seric } 5168423Seric if (pvp == NULL) 5178423Seric return; 5183149Seric 5193149Seric /* 5203149Seric ** Run through the list of rewrite rules, applying 5213149Seric ** any that match. 5223149Seric */ 5233149Seric 5244070Seric for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 5253149Seric { 5264100Seric # ifdef DEBUG 5277675Seric if (tTd(21, 12)) 528297Seric { 5298069Seric printf("-----trying rule:"); 5303149Seric printav(rwr->r_lhs); 5313149Seric } 5324100Seric # endif DEBUG 5333149Seric 5343149Seric /* try to match on this rule */ 5354468Seric mlp = mlist; 5368058Seric rvp = rwr->r_lhs; 5378058Seric avp = pvp; 5388058Seric while ((ap = *avp) != NULL || *rvp != NULL) 5393149Seric { 5403149Seric rp = *rvp; 5418058Seric # ifdef DEBUG 5428058Seric if (tTd(21, 35)) 5438058Seric { 5448069Seric printf("ap="); 5458058Seric xputs(ap); 5468069Seric printf(", rp="); 5478058Seric xputs(rp); 5488069Seric printf("\n"); 5498058Seric } 5508058Seric # endif DEBUG 5513149Seric if (rp == NULL) 552297Seric { 5533149Seric /* end-of-pattern before end-of-address */ 5548058Seric goto backup; 555297Seric } 5568058Seric if (ap == NULL && *rp != MATCHZANY) 5578058Seric { 5588058Seric /* end-of-input */ 5598058Seric break; 5608058Seric } 5613149Seric 5623149Seric switch (*rp) 5633149Seric { 5644060Seric register STAB *s; 5654060Seric 5664060Seric case MATCHCLASS: 5679585Seric case MATCHNCLASS: 5689585Seric /* match any token in (not in) a class */ 5694100Seric s = stab(ap, ST_CLASS, ST_FIND); 57010690Seric if (s == NULL || !bitnset(rp[1], s->s_class)) 5719585Seric { 5729585Seric if (*rp == MATCHCLASS) 5739585Seric goto backup; 5749585Seric } 5759585Seric else if (*rp == MATCHNCLASS) 5768058Seric goto backup; 5774468Seric 5784476Seric /* explicit fall-through */ 5794476Seric 5804476Seric case MATCHONE: 5814476Seric case MATCHANY: 5824476Seric /* match exactly one token */ 5838058Seric mlp->first = avp; 5848058Seric mlp->last = avp++; 5854468Seric mlp++; 5864060Seric break; 5874060Seric 5888058Seric case MATCHZANY: 5898058Seric /* match zero or more tokens */ 5908058Seric mlp->first = avp; 5918058Seric mlp->last = avp - 1; 5928058Seric mlp++; 5938058Seric break; 5948058Seric 5953149Seric default: 5963149Seric /* must have exact match */ 597*33725Sbostic if (strcasecmp(rp, ap)) 5988058Seric goto backup; 5994468Seric avp++; 6003149Seric break; 6013149Seric } 6023149Seric 6033149Seric /* successful match on this token */ 6043149Seric rvp++; 6053149Seric continue; 6063149Seric 6078058Seric backup: 6083149Seric /* match failed -- back up */ 6093149Seric while (--rvp >= rwr->r_lhs) 6103149Seric { 6113149Seric rp = *rvp; 6128058Seric if (*rp == MATCHANY || *rp == MATCHZANY) 6134468Seric { 6144476Seric /* extend binding and continue */ 6158058Seric avp = ++mlp[-1].last; 6168058Seric avp++; 6174476Seric rvp++; 6183149Seric break; 6194468Seric } 6204476Seric avp--; 6219585Seric if (*rp == MATCHONE || *rp == MATCHCLASS || 6229585Seric *rp == MATCHNCLASS) 6233149Seric { 6244468Seric /* back out binding */ 6254468Seric mlp--; 6263149Seric } 6273149Seric } 6283149Seric 6293149Seric if (rvp < rwr->r_lhs) 6303149Seric { 6313149Seric /* total failure to match */ 6323149Seric break; 6333149Seric } 634297Seric } 6353149Seric 6363149Seric /* 6373149Seric ** See if we successfully matched 6383149Seric */ 6393149Seric 6409374Seric if (rvp < rwr->r_lhs || *rvp != NULL) 6413149Seric { 6424100Seric # ifdef DEBUG 6439374Seric if (tTd(21, 10)) 6449374Seric printf("----- rule fails\n"); 6454100Seric # endif DEBUG 6469374Seric rwr = rwr->r_next; 6479374Seric continue; 6489374Seric } 6493149Seric 6509374Seric rvp = rwr->r_rhs; 6519374Seric # ifdef DEBUG 6529374Seric if (tTd(21, 12)) 6539374Seric { 6549374Seric printf("-----rule matches:"); 6559374Seric printav(rvp); 6569374Seric } 6579374Seric # endif DEBUG 6589374Seric 6599374Seric rp = *rvp; 6609374Seric if (*rp == CANONUSER) 6619374Seric { 6629374Seric rvp++; 6639374Seric rwr = rwr->r_next; 6649374Seric } 6659374Seric else if (*rp == CANONHOST) 6669374Seric { 6679374Seric rvp++; 6689374Seric rwr = NULL; 6699374Seric } 6709374Seric else if (*rp == CANONNET) 6719374Seric rwr = NULL; 6729374Seric 6739374Seric /* substitute */ 6749374Seric for (avp = npvp; *rvp != NULL; rvp++) 6759374Seric { 6769374Seric register struct match *m; 6779374Seric register char **pp; 6789374Seric 6798058Seric rp = *rvp; 68016914Seric if (*rp == MATCHREPL) 6818058Seric { 68216914Seric /* substitute from LHS */ 68316914Seric m = &mlist[rp[1] - '1']; 68416914Seric if (m >= mlp) 6859374Seric { 68616914Seric syserr("rewrite: ruleset %d: replacement out of bounds", ruleset); 6879374Seric return; 6889374Seric } 6899374Seric # ifdef DEBUG 69016914Seric if (tTd(21, 15)) 69116914Seric { 69216914Seric printf("$%c:", rp[1]); 69316914Seric pp = m->first; 69416914Seric while (pp <= m->last) 69516914Seric { 69616914Seric printf(" %x=\"", *pp); 69716914Seric (void) fflush(stdout); 69816914Seric printf("%s\"", *pp++); 69916914Seric } 70016914Seric printf("\n"); 70116914Seric } 70216914Seric # endif DEBUG 7039374Seric pp = m->first; 7049374Seric while (pp <= m->last) 7053149Seric { 70616914Seric if (avp >= &npvp[MAXATOM]) 70716914Seric { 70816914Seric syserr("rewrite: expansion too long"); 70916914Seric return; 71016914Seric } 71116914Seric *avp++ = *pp++; 7123149Seric } 7133149Seric } 71416914Seric else 7158226Seric { 71616914Seric /* vanilla replacement */ 7179374Seric if (avp >= &npvp[MAXATOM]) 71816889Seric { 71916914Seric toolong: 72016889Seric syserr("rewrite: expansion too long"); 72116889Seric return; 72216889Seric } 72316914Seric *avp++ = rp; 7248226Seric } 7259374Seric } 7269374Seric *avp++ = NULL; 72716914Seric 72816914Seric /* 72916914Seric ** Check for any hostname lookups. 73016914Seric */ 73116914Seric 73216914Seric for (rvp = npvp; *rvp != NULL; rvp++) 73316914Seric { 73416914Seric char **hbrvp; 73516914Seric char **xpvp; 73616914Seric int trsize; 73717473Seric char *olddelimchar; 73816920Seric char buf[MAXNAME + 1]; 73916914Seric char *pvpb1[MAXATOM + 1]; 74017174Seric char pvpbuf[PSBUFSIZE]; 74117473Seric extern char *DelimChar; 74216914Seric 74316914Seric if (**rvp != HOSTBEGIN) 74416914Seric continue; 74516914Seric 74616914Seric /* 74716914Seric ** Got a hostname lookup. 74816914Seric ** 74916914Seric ** This could be optimized fairly easily. 75016914Seric */ 75116914Seric 75216914Seric hbrvp = rvp; 75316914Seric 75416914Seric /* extract the match part */ 75516914Seric while (*++rvp != NULL && **rvp != HOSTEND) 75616914Seric continue; 75716914Seric if (*rvp != NULL) 75816914Seric *rvp++ = NULL; 75916914Seric 76016914Seric /* save the remainder of the input string */ 76116914Seric trsize = (int) (avp - rvp + 1) * sizeof *rvp; 76216914Seric bcopy((char *) rvp, (char *) pvpb1, trsize); 76316914Seric 76416914Seric /* look it up */ 76516914Seric cataddr(++hbrvp, buf, sizeof buf); 76616914Seric maphostname(buf, sizeof buf); 76716914Seric 76816914Seric /* scan the new host name */ 76917473Seric olddelimchar = DelimChar; 77016914Seric xpvp = prescan(buf, '\0', pvpbuf); 77117473Seric DelimChar = olddelimchar; 77216914Seric if (xpvp == NULL) 77316914Seric { 77416914Seric syserr("rewrite: cannot prescan canonical hostname: %s", buf); 77522976Smiriam return; 77616914Seric } 77716914Seric 77816914Seric /* append it to the token list */ 77917174Seric for (avp = --hbrvp; *xpvp != NULL; xpvp++) 78017174Seric { 78117174Seric *avp++ = newstr(*xpvp); 78216920Seric if (avp >= &npvp[MAXATOM]) 78316914Seric goto toolong; 78417174Seric } 78516914Seric 78616914Seric /* restore the old trailing information */ 78717177Seric for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) 78816920Seric if (avp >= &npvp[MAXATOM]) 78916914Seric goto toolong; 79017174Seric 79117174Seric break; 79216914Seric } 79316914Seric 79416914Seric /* 79516914Seric ** Check for subroutine calls. 79616914Seric */ 79716914Seric 79824944Seric if (*npvp != NULL && **npvp == CALLSUBR) 7999374Seric { 80016889Seric bcopy((char *) &npvp[2], (char *) pvp, 80116900Seric (int) (avp - npvp - 2) * sizeof *avp); 80216889Seric # ifdef DEBUG 80316889Seric if (tTd(21, 3)) 80416889Seric printf("-----callsubr %s\n", npvp[1]); 80516889Seric # endif DEBUG 80616889Seric rewrite(pvp, atoi(npvp[1])); 8073149Seric } 8083149Seric else 8093149Seric { 81017348Seric bcopy((char *) npvp, (char *) pvp, 81116900Seric (int) (avp - npvp) * sizeof *avp); 8129374Seric } 8134100Seric # ifdef DEBUG 8149374Seric if (tTd(21, 4)) 8159374Seric { 8169374Seric printf("rewritten as:"); 8179374Seric printav(pvp); 8189374Seric } 8194100Seric # endif DEBUG 820297Seric } 8218069Seric 8229279Seric if (OpMode == MD_TEST || tTd(21, 2)) 8238069Seric { 8248959Seric printf("rewrite: ruleset %2d returns:", ruleset); 8258069Seric printav(pvp); 8268069Seric } 8273149Seric } 8283149Seric /* 8293149Seric ** BUILDADDR -- build address from token vector. 8303149Seric ** 8313149Seric ** Parameters: 8323149Seric ** tv -- token vector. 8333149Seric ** a -- pointer to address descriptor to fill. 8343149Seric ** If NULL, one will be allocated. 8353149Seric ** 8363149Seric ** Returns: 8374279Seric ** NULL if there was an error. 8384279Seric ** 'a' otherwise. 8393149Seric ** 8403149Seric ** Side Effects: 8413149Seric ** fills in 'a' 8423149Seric */ 8433149Seric 8443149Seric ADDRESS * 8453149Seric buildaddr(tv, a) 8463149Seric register char **tv; 8473149Seric register ADDRESS *a; 8483149Seric { 8493149Seric static char buf[MAXNAME]; 8503149Seric struct mailer **mp; 8513149Seric register struct mailer *m; 8523149Seric 8533149Seric if (a == NULL) 8543149Seric a = (ADDRESS *) xalloc(sizeof *a); 85516889Seric bzero((char *) a, sizeof *a); 8563149Seric 8573149Seric /* figure out what net/mailer to use */ 8583149Seric if (**tv != CANONNET) 8594279Seric { 8603149Seric syserr("buildaddr: no net"); 8614279Seric return (NULL); 8624279Seric } 8633149Seric tv++; 864*33725Sbostic if (!strcasecmp(*tv, "error")) 8654279Seric { 86610183Seric if (**++tv == CANONHOST) 86710183Seric { 86810183Seric setstat(atoi(*++tv)); 86910183Seric tv++; 87010183Seric } 87110183Seric if (**tv != CANONUSER) 8724279Seric syserr("buildaddr: error: no user"); 8734279Seric buf[0] = '\0'; 8744279Seric while (*++tv != NULL) 8754279Seric { 8764279Seric if (buf[0] != '\0') 8777005Seric (void) strcat(buf, " "); 8787005Seric (void) strcat(buf, *tv); 8794279Seric } 8804279Seric usrerr(buf); 8814279Seric return (NULL); 8824279Seric } 8834598Seric for (mp = Mailer; (m = *mp++) != NULL; ) 8843149Seric { 885*33725Sbostic if (!strcasecmp(m->m_name, *tv)) 8863149Seric break; 8873149Seric } 8883149Seric if (m == NULL) 8894279Seric { 89024944Seric syserr("buildaddr: unknown mailer %s", *tv); 8914279Seric return (NULL); 8924279Seric } 8934598Seric a->q_mailer = m; 8943149Seric 8953149Seric /* figure out what host (if any) */ 8963149Seric tv++; 89710690Seric if (!bitnset(M_LOCAL, m->m_flags)) 8983149Seric { 8995704Seric if (**tv++ != CANONHOST) 9004279Seric { 9013149Seric syserr("buildaddr: no host"); 9024279Seric return (NULL); 9034279Seric } 9045704Seric buf[0] = '\0'; 9055704Seric while (*tv != NULL && **tv != CANONUSER) 9067005Seric (void) strcat(buf, *tv++); 9075704Seric a->q_host = newstr(buf); 9083149Seric } 9093149Seric else 9103149Seric a->q_host = NULL; 9113149Seric 9123149Seric /* figure out the user */ 9133149Seric if (**tv != CANONUSER) 9144279Seric { 9153149Seric syserr("buildaddr: no user"); 9164279Seric return (NULL); 9174279Seric } 91819040Seric 91919040Seric /* rewrite according recipient mailer rewriting rules */ 92019040Seric rewrite(++tv, 2); 92119040Seric if (m->m_r_rwset > 0) 92219040Seric rewrite(tv, m->m_r_rwset); 92319040Seric rewrite(tv, 4); 92419040Seric 92519040Seric /* save the result for the command line/RCPT argument */ 92611278Seric cataddr(tv, buf, sizeof buf); 9273149Seric a->q_user = buf; 9283149Seric 9293149Seric return (a); 9303149Seric } 9313188Seric /* 9324228Seric ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 9334228Seric ** 9344228Seric ** Parameters: 9354228Seric ** pvp -- parameter vector to rebuild. 9364228Seric ** buf -- buffer to build the string into. 9374228Seric ** sz -- size of buf. 9384228Seric ** 9394228Seric ** Returns: 9404228Seric ** none. 9414228Seric ** 9424228Seric ** Side Effects: 9434228Seric ** Destroys buf. 9444228Seric */ 9454228Seric 9464228Seric cataddr(pvp, buf, sz) 9474228Seric char **pvp; 9484228Seric char *buf; 9494228Seric register int sz; 9504228Seric { 9514228Seric bool oatomtok = FALSE; 9524228Seric bool natomtok = FALSE; 9534228Seric register int i; 9544228Seric register char *p; 9554228Seric 9568423Seric if (pvp == NULL) 9578423Seric { 95823109Seric (void) strcpy(buf, ""); 9598423Seric return; 9608423Seric } 9614228Seric p = buf; 96211156Seric sz -= 2; 9634228Seric while (*pvp != NULL && (i = strlen(*pvp)) < sz) 9644228Seric { 9658078Seric natomtok = (toktype(**pvp) == ATM); 9664228Seric if (oatomtok && natomtok) 9679042Seric *p++ = SpaceSub; 9684228Seric (void) strcpy(p, *pvp); 9694228Seric oatomtok = natomtok; 9704228Seric p += i; 97111156Seric sz -= i + 1; 9724228Seric pvp++; 9734228Seric } 9744228Seric *p = '\0'; 9754228Seric } 9764228Seric /* 9773188Seric ** SAMEADDR -- Determine if two addresses are the same 9783188Seric ** 9793188Seric ** This is not just a straight comparison -- if the mailer doesn't 9803188Seric ** care about the host we just ignore it, etc. 9813188Seric ** 9823188Seric ** Parameters: 9833188Seric ** a, b -- pointers to the internal forms to compare. 9843188Seric ** 9853188Seric ** Returns: 9863188Seric ** TRUE -- they represent the same mailbox. 9873188Seric ** FALSE -- they don't. 9883188Seric ** 9893188Seric ** Side Effects: 9903188Seric ** none. 9913188Seric */ 9923188Seric 9933188Seric bool 9949374Seric sameaddr(a, b) 9953188Seric register ADDRESS *a; 9963188Seric register ADDRESS *b; 9973188Seric { 9983188Seric /* if they don't have the same mailer, forget it */ 9993188Seric if (a->q_mailer != b->q_mailer) 10003188Seric return (FALSE); 10013188Seric 10023188Seric /* if the user isn't the same, we can drop out */ 10039374Seric if (strcmp(a->q_user, b->q_user) != 0) 10043188Seric return (FALSE); 10053188Seric 10063188Seric /* if the mailer ignores hosts, we have succeeded! */ 100710690Seric if (bitnset(M_LOCAL, a->q_mailer->m_flags)) 10083188Seric return (TRUE); 10093188Seric 10103188Seric /* otherwise compare hosts (but be careful for NULL ptrs) */ 10113188Seric if (a->q_host == NULL || b->q_host == NULL) 10123188Seric return (FALSE); 10133188Seric if (strcmp(a->q_host, b->q_host) != 0) 10143188Seric return (FALSE); 10153188Seric 10163188Seric return (TRUE); 10173188Seric } 10183234Seric /* 10193234Seric ** PRINTADDR -- print address (for debugging) 10203234Seric ** 10213234Seric ** Parameters: 10223234Seric ** a -- the address to print 10233234Seric ** follow -- follow the q_next chain. 10243234Seric ** 10253234Seric ** Returns: 10263234Seric ** none. 10273234Seric ** 10283234Seric ** Side Effects: 10293234Seric ** none. 10303234Seric */ 10313234Seric 10324317Seric # ifdef DEBUG 10334317Seric 10343234Seric printaddr(a, follow) 10353234Seric register ADDRESS *a; 10363234Seric bool follow; 10373234Seric { 10385001Seric bool first = TRUE; 10395001Seric 10403234Seric while (a != NULL) 10413234Seric { 10425001Seric first = FALSE; 10434443Seric printf("%x=", a); 10444085Seric (void) fflush(stdout); 10453234Seric printf("%s: mailer %d (%s), host `%s', user `%s'\n", a->q_paddr, 10468181Seric a->q_mailer->m_mno, a->q_mailer->m_name, a->q_host, 10478181Seric a->q_user); 10488181Seric printf("\tnext=%x, flags=%o, alias %x\n", a->q_next, a->q_flags, 10498181Seric a->q_alias); 10508181Seric printf("\thome=\"%s\", fullname=\"%s\"\n", a->q_home, 10518181Seric a->q_fullname); 10524996Seric 10533234Seric if (!follow) 10543234Seric return; 10554996Seric a = a->q_next; 10563234Seric } 10575001Seric if (first) 10584443Seric printf("[NULL]\n"); 10593234Seric } 10604317Seric 10614317Seric # endif DEBUG 10627682Seric /* 10637682Seric ** REMOTENAME -- return the name relative to the current mailer 10647682Seric ** 10657682Seric ** Parameters: 10667682Seric ** name -- the name to translate. 10678069Seric ** m -- the mailer that we want to do rewriting relative 10688069Seric ** to. 10698069Seric ** senderaddress -- if set, uses the sender rewriting rules 10708069Seric ** rather than the recipient rewriting rules. 107110310Seric ** canonical -- if set, strip out any comment information, 107210310Seric ** etc. 10737682Seric ** 10747682Seric ** Returns: 10757682Seric ** the text string representing this address relative to 10767682Seric ** the receiving mailer. 10777682Seric ** 10787682Seric ** Side Effects: 10797682Seric ** none. 10807682Seric ** 10817682Seric ** Warnings: 10827682Seric ** The text string returned is tucked away locally; 10837682Seric ** copy it if you intend to save it. 10847682Seric */ 10857682Seric 10867682Seric char * 108710310Seric remotename(name, m, senderaddress, canonical) 10887682Seric char *name; 10897682Seric struct mailer *m; 10908069Seric bool senderaddress; 109110310Seric bool canonical; 10927682Seric { 10938069Seric register char **pvp; 10948069Seric char *fancy; 10958069Seric extern char *macvalue(); 10968181Seric char *oldg = macvalue('g', CurEnv); 10977682Seric static char buf[MAXNAME]; 10987682Seric char lbuf[MAXNAME]; 109916914Seric char pvpbuf[PSBUFSIZE]; 11007682Seric extern char **prescan(); 11017889Seric extern char *crackaddr(); 11027682Seric 11037755Seric # ifdef DEBUG 11047755Seric if (tTd(12, 1)) 11057755Seric printf("remotename(%s)\n", name); 11067755Seric # endif DEBUG 11077755Seric 110810177Seric /* don't do anything if we are tagging it as special */ 110910177Seric if ((senderaddress ? m->m_s_rwset : m->m_r_rwset) < 0) 111010177Seric return (name); 111110177Seric 11127682Seric /* 11138181Seric ** Do a heuristic crack of this name to extract any comment info. 11148181Seric ** This will leave the name as a comment and a $g macro. 11157889Seric */ 11167889Seric 111710310Seric if (canonical) 111816155Seric fancy = "\001g"; 111910310Seric else 112010310Seric fancy = crackaddr(name); 11217889Seric 11228181Seric /* 11238181Seric ** Turn the name into canonical form. 11248181Seric ** Normally this will be RFC 822 style, i.e., "user@domain". 11258181Seric ** If this only resolves to "user", and the "C" flag is 11268181Seric ** specified in the sending mailer, then the sender's 11278181Seric ** domain will be appended. 11288181Seric */ 11298181Seric 113016914Seric pvp = prescan(name, '\0', pvpbuf); 11317889Seric if (pvp == NULL) 11327889Seric return (name); 11338181Seric rewrite(pvp, 3); 11348181Seric if (CurEnv->e_fromdomain != NULL) 11358181Seric { 11368181Seric /* append from domain to this address */ 11378181Seric register char **pxp = pvp; 11388181Seric 11399594Seric /* see if there is an "@domain" in the current name */ 11408181Seric while (*pxp != NULL && strcmp(*pxp, "@") != 0) 11418181Seric pxp++; 11428181Seric if (*pxp == NULL) 11438181Seric { 11449594Seric /* no.... append the "@domain" from the sender */ 11458181Seric register char **qxq = CurEnv->e_fromdomain; 11468181Seric 11479594Seric while ((*pxp++ = *qxq++) != NULL) 11489594Seric continue; 114911726Seric rewrite(pvp, 3); 11508181Seric } 11518181Seric } 11528181Seric 11538181Seric /* 11548959Seric ** Do more specific rewriting. 11558181Seric ** Rewrite using ruleset 1 or 2 depending on whether this is 11568181Seric ** a sender address or not. 11578181Seric ** Then run it through any receiving-mailer-specific rulesets. 11588181Seric */ 11598181Seric 11608069Seric if (senderaddress) 11617755Seric { 11627889Seric rewrite(pvp, 1); 11638069Seric if (m->m_s_rwset > 0) 11648069Seric rewrite(pvp, m->m_s_rwset); 11658069Seric } 11668069Seric else 11678069Seric { 11687889Seric rewrite(pvp, 2); 11698069Seric if (m->m_r_rwset > 0) 11708069Seric rewrite(pvp, m->m_r_rwset); 11717682Seric } 11727682Seric 11738181Seric /* 11748959Seric ** Do any final sanitation the address may require. 11758959Seric ** This will normally be used to turn internal forms 11768959Seric ** (e.g., user@host.LOCAL) into external form. This 11778959Seric ** may be used as a default to the above rules. 11788959Seric */ 11798959Seric 11808959Seric rewrite(pvp, 4); 11818959Seric 11828959Seric /* 11838181Seric ** Now restore the comment information we had at the beginning. 11848181Seric */ 11858181Seric 11867682Seric cataddr(pvp, lbuf, sizeof lbuf); 11879374Seric define('g', lbuf, CurEnv); 11887889Seric expand(fancy, buf, &buf[sizeof buf - 1], CurEnv); 11899374Seric define('g', oldg, CurEnv); 11907682Seric 11917682Seric # ifdef DEBUG 11927682Seric if (tTd(12, 1)) 11937755Seric printf("remotename => `%s'\n", buf); 11947682Seric # endif DEBUG 11957682Seric return (buf); 11967682Seric } 1197