122976Smiriam /* 2*33730Sbostic * Copyright (c) 1988 Regents of the University of California. 3*33730Sbostic * All rights reserved. 4*33730Sbostic * 5*33730Sbostic * Redistribution and use in source and binary forms are permitted 6*33730Sbostic * provided that this notice is preserved and that due credit is given 7*33730Sbostic * to the University of California at Berkeley. The name of the University 8*33730Sbostic * may not be used to endorse or promote products derived from this 9*33730Sbostic * software without specific prior written permission. This software 10*33730Sbostic * is provided ``as is'' without express or implied warranty. 11*33730Sbostic * 12*33730Sbostic * Sendmail 13*33730Sbostic * Copyright (c) 1983 Eric P. Allman 14*33730Sbostic * Berkeley, California 15*33730Sbostic */ 1622976Smiriam 1722976Smiriam #ifndef lint 18*33730Sbostic static char sccsid[] = "@(#)parseaddr.c 5.8 (Berkeley) 03/13/88"; 19*33730Sbostic #endif /* not lint */ 2022976Smiriam 213312Seric # include "sendmail.h" 22297Seric 23297Seric /* 249888Seric ** PARSEADDR -- Parse an address 25297Seric ** 26297Seric ** Parses an address and breaks it up into three parts: a 27297Seric ** net to transmit the message on, the host to transmit it 28297Seric ** to, and a user on that host. These are loaded into an 292973Seric ** ADDRESS header with the values squirreled away if necessary. 30297Seric ** The "user" part may not be a real user; the process may 31297Seric ** just reoccur on that machine. For example, on a machine 32297Seric ** with an arpanet connection, the address 33297Seric ** csvax.bill@berkeley 34297Seric ** will break up to a "user" of 'csvax.bill' and a host 35297Seric ** of 'berkeley' -- to be transmitted over the arpanet. 36297Seric ** 37297Seric ** Parameters: 38297Seric ** addr -- the address to parse. 39297Seric ** a -- a pointer to the address descriptor buffer. 40297Seric ** If NULL, a header will be created. 41297Seric ** copyf -- determines what shall be copied: 42297Seric ** -1 -- don't copy anything. The printname 43297Seric ** (q_paddr) is just addr, and the 44297Seric ** user & host are allocated internally 45297Seric ** to parse. 46297Seric ** 0 -- copy out the parsed user & host, but 47297Seric ** don't copy the printname. 48297Seric ** +1 -- copy everything. 4911445Seric ** delim -- the character to terminate the address, passed 5011445Seric ** to prescan. 51297Seric ** 52297Seric ** Returns: 53297Seric ** A pointer to the address descriptor header (`a' if 54297Seric ** `a' is non-NULL). 55297Seric ** NULL on error. 56297Seric ** 57297Seric ** Side Effects: 58297Seric ** none 59297Seric */ 60297Seric 619374Seric /* following delimiters are inherent to the internal algorithms */ 6216155Seric # define DELIMCHARS "\001()<>,;\\\"\r\n" /* word delimiters */ 632091Seric 642973Seric ADDRESS * 6511445Seric parseaddr(addr, a, copyf, delim) 66297Seric char *addr; 672973Seric register ADDRESS *a; 68297Seric int copyf; 6911445Seric char delim; 70297Seric { 713149Seric register char **pvp; 723149Seric register struct mailer *m; 7316914Seric char pvpbuf[PSBUFSIZE]; 743149Seric extern char **prescan(); 753149Seric extern ADDRESS *buildaddr(); 76297Seric 77297Seric /* 78297Seric ** Initialize and prescan address. 79297Seric */ 80297Seric 816903Seric CurEnv->e_to = addr; 823188Seric # ifdef DEBUG 837675Seric if (tTd(20, 1)) 849888Seric printf("\n--parseaddr(%s)\n", addr); 853188Seric # endif DEBUG 863188Seric 8716914Seric pvp = prescan(addr, delim, pvpbuf); 883149Seric if (pvp == NULL) 89297Seric return (NULL); 90297Seric 91297Seric /* 923149Seric ** Apply rewriting rules. 937889Seric ** Ruleset 0 does basic parsing. It must resolve. 94297Seric */ 95297Seric 968181Seric rewrite(pvp, 3); 974070Seric rewrite(pvp, 0); 98297Seric 993149Seric /* 1003149Seric ** See if we resolved to a real mailer. 1013149Seric */ 102297Seric 1033149Seric if (pvp[0][0] != CANONNET) 1043149Seric { 1053149Seric setstat(EX_USAGE); 1063149Seric usrerr("cannot resolve name"); 1073149Seric return (NULL); 108297Seric } 109297Seric 110297Seric /* 1113149Seric ** Build canonical address from pvp. 112297Seric */ 113297Seric 1143149Seric a = buildaddr(pvp, a); 1154279Seric if (a == NULL) 1164279Seric return (NULL); 1174598Seric m = a->q_mailer; 118297Seric 119297Seric /* 1203149Seric ** Make local copies of the host & user and then 1213149Seric ** transport them out. 122297Seric */ 123297Seric 124297Seric if (copyf > 0) 1258078Seric { 1268078Seric extern char *DelimChar; 1278078Seric char savec = *DelimChar; 1288078Seric 1298078Seric *DelimChar = '\0'; 1302973Seric a->q_paddr = newstr(addr); 1318078Seric *DelimChar = savec; 1328078Seric } 133297Seric else 134297Seric a->q_paddr = addr; 13524944Seric 13624944Seric if (a->q_user == NULL) 13724944Seric a->q_user = ""; 13824944Seric if (a->q_host == NULL) 13924944Seric a->q_host = ""; 14024944Seric 1413149Seric if (copyf >= 0) 142297Seric { 14324944Seric a->q_host = newstr(a->q_host); 1443149Seric if (a->q_user != a->q_paddr) 1453149Seric a->q_user = newstr(a->q_user); 146297Seric } 147297Seric 148297Seric /* 14916202Seric ** Convert host name to lower case if requested. 15016202Seric ** User name will be done later. 15116202Seric */ 15216202Seric 15316202Seric if (!bitnset(M_HST_UPPER, m->m_flags)) 15416202Seric makelower(a->q_host); 15516202Seric 15616202Seric /* 157297Seric ** Compute return value. 158297Seric */ 159297Seric 160297Seric # ifdef DEBUG 1617675Seric if (tTd(20, 1)) 1624443Seric { 1639888Seric printf("parseaddr-->"); 1644443Seric printaddr(a, FALSE); 1654443Seric } 166297Seric # endif DEBUG 167297Seric 168297Seric return (a); 169297Seric } 170297Seric /* 17116162Seric ** LOWERADDR -- map UPPER->lower case on addresses as requested. 17216162Seric ** 17316162Seric ** Parameters: 17416162Seric ** a -- address to be mapped. 17516162Seric ** 17616162Seric ** Returns: 17716162Seric ** none. 17816162Seric ** 17916162Seric ** Side Effects: 18016162Seric ** none. 18116162Seric */ 18216162Seric 18316162Seric loweraddr(a) 18416162Seric register ADDRESS *a; 18516162Seric { 18616162Seric register MAILER *m = a->q_mailer; 18716162Seric 18816162Seric if (!bitnset(M_USR_UPPER, m->m_flags)) 18916162Seric makelower(a->q_user); 19016162Seric } 19116162Seric /* 192297Seric ** PRESCAN -- Prescan name and make it canonical 193297Seric ** 1949374Seric ** Scans a name and turns it into a set of tokens. This process 1959374Seric ** deletes blanks and comments (in parentheses). 196297Seric ** 197297Seric ** This routine knows about quoted strings and angle brackets. 198297Seric ** 199297Seric ** There are certain subtleties to this routine. The one that 200297Seric ** comes to mind now is that backslashes on the ends of names 201297Seric ** are silently stripped off; this is intentional. The problem 202297Seric ** is that some versions of sndmsg (like at LBL) set the kill 203297Seric ** character to something other than @ when reading addresses; 204297Seric ** so people type "csvax.eric\@berkeley" -- which screws up the 205297Seric ** berknet mailer. 206297Seric ** 207297Seric ** Parameters: 208297Seric ** addr -- the name to chomp. 209297Seric ** delim -- the delimiter for the address, normally 210297Seric ** '\0' or ','; \0 is accepted in any case. 21115284Seric ** If '\t' then we are reading the .cf file. 21216914Seric ** pvpbuf -- place to put the saved text -- note that 21316914Seric ** the pointers are static. 214297Seric ** 215297Seric ** Returns: 2163149Seric ** A pointer to a vector of tokens. 217297Seric ** NULL on error. 218297Seric ** 219297Seric ** Side Effects: 22025279Seric ** sets DelimChar to point to the character matching 'delim'. 221297Seric */ 222297Seric 2238078Seric /* states and character types */ 2248078Seric # define OPR 0 /* operator */ 2258078Seric # define ATM 1 /* atom */ 2268078Seric # define QST 2 /* in quoted string */ 2278078Seric # define SPC 3 /* chewing up spaces */ 2288078Seric # define ONE 4 /* pick up one character */ 2293149Seric 2308078Seric # define NSTATES 5 /* number of states */ 2318078Seric # define TYPE 017 /* mask to select state type */ 2328078Seric 2338078Seric /* meta bits for table */ 2348078Seric # define M 020 /* meta character; don't pass through */ 2358078Seric # define B 040 /* cause a break */ 2368078Seric # define MB M|B /* meta-break */ 2378078Seric 2388078Seric static short StateTab[NSTATES][NSTATES] = 2398078Seric { 2408087Seric /* oldst chtype> OPR ATM QST SPC ONE */ 2419051Seric /*OPR*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, 2429051Seric /*ATM*/ OPR|B, ATM, QST|B, SPC|MB, ONE|B, 2439051Seric /*QST*/ QST, QST, OPR, QST, QST, 2448078Seric /*SPC*/ OPR, ATM, QST, SPC|M, ONE, 2458078Seric /*ONE*/ OPR, OPR, OPR, OPR, OPR, 2468078Seric }; 2478078Seric 2488078Seric # define NOCHAR -1 /* signal nothing in lookahead token */ 2498078Seric 2508078Seric char *DelimChar; /* set to point to the delimiter */ 2518078Seric 2523149Seric char ** 25316914Seric prescan(addr, delim, pvpbuf) 254297Seric char *addr; 255297Seric char delim; 25616914Seric char pvpbuf[]; 257297Seric { 258297Seric register char *p; 2598078Seric register char *q; 2609346Seric register int c; 2613149Seric char **avp; 262297Seric bool bslashmode; 263297Seric int cmntcnt; 2648423Seric int anglecnt; 2653149Seric char *tok; 2668078Seric int state; 2678078Seric int newstate; 2688078Seric static char *av[MAXATOM+1]; 26915253Seric extern int errno; 270297Seric 27115253Seric /* make sure error messages don't have garbage on them */ 27215253Seric errno = 0; 27315253Seric 27416914Seric q = pvpbuf; 2753149Seric bslashmode = FALSE; 2767800Seric cmntcnt = 0; 2778423Seric anglecnt = 0; 2783149Seric avp = av; 2798078Seric state = OPR; 2808078Seric c = NOCHAR; 2818078Seric p = addr; 2828078Seric # ifdef DEBUG 2838078Seric if (tTd(22, 45)) 284297Seric { 2858078Seric printf("prescan: "); 2868078Seric xputs(p); 28723109Seric (void) putchar('\n'); 2888078Seric } 2898078Seric # endif DEBUG 2908078Seric 2918078Seric do 2928078Seric { 2933149Seric /* read a token */ 2943149Seric tok = q; 2958078Seric for (;;) 296297Seric { 2978078Seric /* store away any old lookahead character */ 2988078Seric if (c != NOCHAR) 2998078Seric { 30015284Seric /* see if there is room */ 30116914Seric if (q >= &pvpbuf[PSBUFSIZE - 5]) 3028078Seric { 3038078Seric usrerr("Address too long"); 3048078Seric DelimChar = p; 3058078Seric return (NULL); 3068078Seric } 30715284Seric 30815284Seric /* squirrel it away */ 3098078Seric *q++ = c; 3108078Seric } 3118078Seric 3128078Seric /* read a new input character */ 3138078Seric c = *p++; 3148078Seric if (c == '\0') 3158078Seric break; 31615284Seric c &= ~0200; 31715284Seric 3188078Seric # ifdef DEBUG 3198078Seric if (tTd(22, 101)) 3208078Seric printf("c=%c, s=%d; ", c, state); 3218078Seric # endif DEBUG 3228078Seric 3233149Seric /* chew up special characters */ 3243149Seric *q = '\0'; 3253149Seric if (bslashmode) 3263149Seric { 32724944Seric /* kludge \! for naive users */ 32824944Seric if (c != '!') 32924944Seric c |= 0200; 3303149Seric bslashmode = FALSE; 3313149Seric } 3323149Seric else if (c == '\\') 3333149Seric { 3343149Seric bslashmode = TRUE; 3358078Seric c = NOCHAR; 3363149Seric } 3378514Seric else if (state == QST) 3388514Seric { 3398514Seric /* do nothing, just avoid next clauses */ 3408514Seric } 3418078Seric else if (c == '(') 3424100Seric { 3438078Seric cmntcnt++; 3448078Seric c = NOCHAR; 3454100Seric } 3468078Seric else if (c == ')') 3473149Seric { 3488078Seric if (cmntcnt <= 0) 3493149Seric { 3508078Seric usrerr("Unbalanced ')'"); 3518078Seric DelimChar = p; 3528078Seric return (NULL); 3533149Seric } 3548078Seric else 3558078Seric cmntcnt--; 3568078Seric } 3578078Seric else if (cmntcnt > 0) 3588078Seric c = NOCHAR; 3598423Seric else if (c == '<') 3608423Seric anglecnt++; 3618423Seric else if (c == '>') 3628423Seric { 3638423Seric if (anglecnt <= 0) 3648423Seric { 3658423Seric usrerr("Unbalanced '>'"); 3668423Seric DelimChar = p; 3678423Seric return (NULL); 3688423Seric } 3698423Seric anglecnt--; 3708423Seric } 37111423Seric else if (delim == ' ' && isspace(c)) 37211423Seric c = ' '; 3733149Seric 3748078Seric if (c == NOCHAR) 3758078Seric continue; 3763149Seric 3778078Seric /* see if this is end of input */ 37811405Seric if (c == delim && anglecnt <= 0 && state != QST) 3793149Seric break; 3803149Seric 3818078Seric newstate = StateTab[state][toktype(c)]; 3828078Seric # ifdef DEBUG 3838078Seric if (tTd(22, 101)) 3848078Seric printf("ns=%02o\n", newstate); 3858078Seric # endif DEBUG 3868078Seric state = newstate & TYPE; 3878078Seric if (bitset(M, newstate)) 3888078Seric c = NOCHAR; 3898078Seric if (bitset(B, newstate)) 3904228Seric break; 391297Seric } 3923149Seric 3933149Seric /* new token */ 3948078Seric if (tok != q) 3951378Seric { 3968078Seric *q++ = '\0'; 3978078Seric # ifdef DEBUG 3988078Seric if (tTd(22, 36)) 399297Seric { 4008078Seric printf("tok="); 4018078Seric xputs(tok); 40223109Seric (void) putchar('\n'); 403297Seric } 4048078Seric # endif DEBUG 4058078Seric if (avp >= &av[MAXATOM]) 406297Seric { 4078078Seric syserr("prescan: too many tokens"); 4088078Seric DelimChar = p; 4098078Seric return (NULL); 410297Seric } 4118078Seric *avp++ = tok; 412297Seric } 4138423Seric } while (c != '\0' && (c != delim || anglecnt > 0)); 4143149Seric *avp = NULL; 4158078Seric DelimChar = --p; 4163149Seric if (cmntcnt > 0) 4173149Seric usrerr("Unbalanced '('"); 4188423Seric else if (anglecnt > 0) 4198423Seric usrerr("Unbalanced '<'"); 4208078Seric else if (state == QST) 4213149Seric usrerr("Unbalanced '\"'"); 4223149Seric else if (av[0] != NULL) 4233149Seric return (av); 4243149Seric return (NULL); 4253149Seric } 4263149Seric /* 4273149Seric ** TOKTYPE -- return token type 4283149Seric ** 4293149Seric ** Parameters: 4303149Seric ** c -- the character in question. 4313149Seric ** 4323149Seric ** Returns: 4333149Seric ** Its type. 4343149Seric ** 4353149Seric ** Side Effects: 4363149Seric ** none. 4373149Seric */ 438297Seric 4393149Seric toktype(c) 4403149Seric register char c; 4413149Seric { 4423380Seric static char buf[50]; 4433382Seric static bool firstime = TRUE; 4443380Seric 4453382Seric if (firstime) 4463380Seric { 4473382Seric firstime = FALSE; 44816155Seric expand("\001o", buf, &buf[sizeof buf - 1], CurEnv); 4497005Seric (void) strcat(buf, DELIMCHARS); 4503380Seric } 4519585Seric if (c == MATCHCLASS || c == MATCHREPL || c == MATCHNCLASS) 4528078Seric return (ONE); 4538078Seric if (c == '"') 4548078Seric return (QST); 4554100Seric if (!isascii(c)) 4568078Seric return (ATM); 4578078Seric if (isspace(c) || c == ')') 4588078Seric return (SPC); 4593380Seric if (iscntrl(c) || index(buf, c) != NULL) 4608078Seric return (OPR); 4618078Seric return (ATM); 4623149Seric } 4633149Seric /* 4643149Seric ** REWRITE -- apply rewrite rules to token vector. 4653149Seric ** 4664476Seric ** This routine is an ordered production system. Each rewrite 4674476Seric ** rule has a LHS (called the pattern) and a RHS (called the 4684476Seric ** rewrite); 'rwr' points the the current rewrite rule. 4694476Seric ** 4704476Seric ** For each rewrite rule, 'avp' points the address vector we 4714476Seric ** are trying to match against, and 'pvp' points to the pattern. 4728058Seric ** If pvp points to a special match value (MATCHZANY, MATCHANY, 4739585Seric ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp 4749585Seric ** matched is saved away in the match vector (pointed to by 'mvp'). 4754476Seric ** 4764476Seric ** When a match between avp & pvp does not match, we try to 4779585Seric ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS 4784476Seric ** we must also back out the match in mvp. If we reach a 4798058Seric ** MATCHANY or MATCHZANY we just extend the match and start 4808058Seric ** over again. 4814476Seric ** 4824476Seric ** When we finally match, we rewrite the address vector 4834476Seric ** and try over again. 4844476Seric ** 4853149Seric ** Parameters: 4863149Seric ** pvp -- pointer to token vector. 4873149Seric ** 4883149Seric ** Returns: 4893149Seric ** none. 4903149Seric ** 4913149Seric ** Side Effects: 4923149Seric ** pvp is modified. 4933149Seric */ 4942091Seric 4953149Seric struct match 4963149Seric { 4974468Seric char **first; /* first token matched */ 4984468Seric char **last; /* last token matched */ 4993149Seric }; 5003149Seric 5014468Seric # define MAXMATCH 9 /* max params per rewrite */ 5023149Seric 5033149Seric 5044070Seric rewrite(pvp, ruleset) 5053149Seric char **pvp; 5064070Seric int ruleset; 5073149Seric { 5083149Seric register char *ap; /* address pointer */ 5093149Seric register char *rp; /* rewrite pointer */ 5103149Seric register char **avp; /* address vector pointer */ 5113149Seric register char **rvp; /* rewrite vector pointer */ 5128058Seric register struct match *mlp; /* cur ptr into mlist */ 5138058Seric register struct rewrite *rwr; /* pointer to current rewrite rule */ 5144468Seric struct match mlist[MAXMATCH]; /* stores match on LHS */ 5153149Seric char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 5163149Seric 5179279Seric if (OpMode == MD_TEST || tTd(21, 2)) 5183149Seric { 5198959Seric printf("rewrite: ruleset %2d input:", ruleset); 5203149Seric printav(pvp); 5213149Seric } 5228423Seric if (pvp == NULL) 5238423Seric return; 5243149Seric 5253149Seric /* 5263149Seric ** Run through the list of rewrite rules, applying 5273149Seric ** any that match. 5283149Seric */ 5293149Seric 5304070Seric for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 5313149Seric { 5324100Seric # ifdef DEBUG 5337675Seric if (tTd(21, 12)) 534297Seric { 5358069Seric printf("-----trying rule:"); 5363149Seric printav(rwr->r_lhs); 5373149Seric } 5384100Seric # endif DEBUG 5393149Seric 5403149Seric /* try to match on this rule */ 5414468Seric mlp = mlist; 5428058Seric rvp = rwr->r_lhs; 5438058Seric avp = pvp; 5448058Seric while ((ap = *avp) != NULL || *rvp != NULL) 5453149Seric { 5463149Seric rp = *rvp; 5478058Seric # ifdef DEBUG 5488058Seric if (tTd(21, 35)) 5498058Seric { 5508069Seric printf("ap="); 5518058Seric xputs(ap); 5528069Seric printf(", rp="); 5538058Seric xputs(rp); 5548069Seric printf("\n"); 5558058Seric } 5568058Seric # endif DEBUG 5573149Seric if (rp == NULL) 558297Seric { 5593149Seric /* end-of-pattern before end-of-address */ 5608058Seric goto backup; 561297Seric } 5628058Seric if (ap == NULL && *rp != MATCHZANY) 5638058Seric { 5648058Seric /* end-of-input */ 5658058Seric break; 5668058Seric } 5673149Seric 5683149Seric switch (*rp) 5693149Seric { 5704060Seric register STAB *s; 5714060Seric 5724060Seric case MATCHCLASS: 5739585Seric case MATCHNCLASS: 5749585Seric /* match any token in (not in) a class */ 5754100Seric s = stab(ap, ST_CLASS, ST_FIND); 57610690Seric if (s == NULL || !bitnset(rp[1], s->s_class)) 5779585Seric { 5789585Seric if (*rp == MATCHCLASS) 5799585Seric goto backup; 5809585Seric } 5819585Seric else if (*rp == MATCHNCLASS) 5828058Seric goto backup; 5834468Seric 5844476Seric /* explicit fall-through */ 5854476Seric 5864476Seric case MATCHONE: 5874476Seric case MATCHANY: 5884476Seric /* match exactly one token */ 5898058Seric mlp->first = avp; 5908058Seric mlp->last = avp++; 5914468Seric mlp++; 5924060Seric break; 5934060Seric 5948058Seric case MATCHZANY: 5958058Seric /* match zero or more tokens */ 5968058Seric mlp->first = avp; 5978058Seric mlp->last = avp - 1; 5988058Seric mlp++; 5998058Seric break; 6008058Seric 6013149Seric default: 6023149Seric /* must have exact match */ 60333725Sbostic if (strcasecmp(rp, ap)) 6048058Seric goto backup; 6054468Seric avp++; 6063149Seric break; 6073149Seric } 6083149Seric 6093149Seric /* successful match on this token */ 6103149Seric rvp++; 6113149Seric continue; 6123149Seric 6138058Seric backup: 6143149Seric /* match failed -- back up */ 6153149Seric while (--rvp >= rwr->r_lhs) 6163149Seric { 6173149Seric rp = *rvp; 6188058Seric if (*rp == MATCHANY || *rp == MATCHZANY) 6194468Seric { 6204476Seric /* extend binding and continue */ 6218058Seric avp = ++mlp[-1].last; 6228058Seric avp++; 6234476Seric rvp++; 6243149Seric break; 6254468Seric } 6264476Seric avp--; 6279585Seric if (*rp == MATCHONE || *rp == MATCHCLASS || 6289585Seric *rp == MATCHNCLASS) 6293149Seric { 6304468Seric /* back out binding */ 6314468Seric mlp--; 6323149Seric } 6333149Seric } 6343149Seric 6353149Seric if (rvp < rwr->r_lhs) 6363149Seric { 6373149Seric /* total failure to match */ 6383149Seric break; 6393149Seric } 640297Seric } 6413149Seric 6423149Seric /* 6433149Seric ** See if we successfully matched 6443149Seric */ 6453149Seric 6469374Seric if (rvp < rwr->r_lhs || *rvp != NULL) 6473149Seric { 6484100Seric # ifdef DEBUG 6499374Seric if (tTd(21, 10)) 6509374Seric printf("----- rule fails\n"); 6514100Seric # endif DEBUG 6529374Seric rwr = rwr->r_next; 6539374Seric continue; 6549374Seric } 6553149Seric 6569374Seric rvp = rwr->r_rhs; 6579374Seric # ifdef DEBUG 6589374Seric if (tTd(21, 12)) 6599374Seric { 6609374Seric printf("-----rule matches:"); 6619374Seric printav(rvp); 6629374Seric } 6639374Seric # endif DEBUG 6649374Seric 6659374Seric rp = *rvp; 6669374Seric if (*rp == CANONUSER) 6679374Seric { 6689374Seric rvp++; 6699374Seric rwr = rwr->r_next; 6709374Seric } 6719374Seric else if (*rp == CANONHOST) 6729374Seric { 6739374Seric rvp++; 6749374Seric rwr = NULL; 6759374Seric } 6769374Seric else if (*rp == CANONNET) 6779374Seric rwr = NULL; 6789374Seric 6799374Seric /* substitute */ 6809374Seric for (avp = npvp; *rvp != NULL; rvp++) 6819374Seric { 6829374Seric register struct match *m; 6839374Seric register char **pp; 6849374Seric 6858058Seric rp = *rvp; 68616914Seric if (*rp == MATCHREPL) 6878058Seric { 68816914Seric /* substitute from LHS */ 68916914Seric m = &mlist[rp[1] - '1']; 69016914Seric if (m >= mlp) 6919374Seric { 69216914Seric syserr("rewrite: ruleset %d: replacement out of bounds", ruleset); 6939374Seric return; 6949374Seric } 6959374Seric # ifdef DEBUG 69616914Seric if (tTd(21, 15)) 69716914Seric { 69816914Seric printf("$%c:", rp[1]); 69916914Seric pp = m->first; 70016914Seric while (pp <= m->last) 70116914Seric { 70216914Seric printf(" %x=\"", *pp); 70316914Seric (void) fflush(stdout); 70416914Seric printf("%s\"", *pp++); 70516914Seric } 70616914Seric printf("\n"); 70716914Seric } 70816914Seric # endif DEBUG 7099374Seric pp = m->first; 7109374Seric while (pp <= m->last) 7113149Seric { 71216914Seric if (avp >= &npvp[MAXATOM]) 71316914Seric { 71416914Seric syserr("rewrite: expansion too long"); 71516914Seric return; 71616914Seric } 71716914Seric *avp++ = *pp++; 7183149Seric } 7193149Seric } 72016914Seric else 7218226Seric { 72216914Seric /* vanilla replacement */ 7239374Seric if (avp >= &npvp[MAXATOM]) 72416889Seric { 72516914Seric toolong: 72616889Seric syserr("rewrite: expansion too long"); 72716889Seric return; 72816889Seric } 72916914Seric *avp++ = rp; 7308226Seric } 7319374Seric } 7329374Seric *avp++ = NULL; 73316914Seric 73416914Seric /* 73516914Seric ** Check for any hostname lookups. 73616914Seric */ 73716914Seric 73816914Seric for (rvp = npvp; *rvp != NULL; rvp++) 73916914Seric { 74016914Seric char **hbrvp; 74116914Seric char **xpvp; 74216914Seric int trsize; 74317473Seric char *olddelimchar; 74416920Seric char buf[MAXNAME + 1]; 74516914Seric char *pvpb1[MAXATOM + 1]; 74617174Seric char pvpbuf[PSBUFSIZE]; 74717473Seric extern char *DelimChar; 74816914Seric 74916914Seric if (**rvp != HOSTBEGIN) 75016914Seric continue; 75116914Seric 75216914Seric /* 75316914Seric ** Got a hostname lookup. 75416914Seric ** 75516914Seric ** This could be optimized fairly easily. 75616914Seric */ 75716914Seric 75816914Seric hbrvp = rvp; 75916914Seric 76016914Seric /* extract the match part */ 76116914Seric while (*++rvp != NULL && **rvp != HOSTEND) 76216914Seric continue; 76316914Seric if (*rvp != NULL) 76416914Seric *rvp++ = NULL; 76516914Seric 76616914Seric /* save the remainder of the input string */ 76716914Seric trsize = (int) (avp - rvp + 1) * sizeof *rvp; 76816914Seric bcopy((char *) rvp, (char *) pvpb1, trsize); 76916914Seric 77016914Seric /* look it up */ 77116914Seric cataddr(++hbrvp, buf, sizeof buf); 77216914Seric maphostname(buf, sizeof buf); 77316914Seric 77416914Seric /* scan the new host name */ 77517473Seric olddelimchar = DelimChar; 77616914Seric xpvp = prescan(buf, '\0', pvpbuf); 77717473Seric DelimChar = olddelimchar; 77816914Seric if (xpvp == NULL) 77916914Seric { 78016914Seric syserr("rewrite: cannot prescan canonical hostname: %s", buf); 78122976Smiriam return; 78216914Seric } 78316914Seric 78416914Seric /* append it to the token list */ 78517174Seric for (avp = --hbrvp; *xpvp != NULL; xpvp++) 78617174Seric { 78717174Seric *avp++ = newstr(*xpvp); 78816920Seric if (avp >= &npvp[MAXATOM]) 78916914Seric goto toolong; 79017174Seric } 79116914Seric 79216914Seric /* restore the old trailing information */ 79317177Seric for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) 79416920Seric if (avp >= &npvp[MAXATOM]) 79516914Seric goto toolong; 79617174Seric 79717174Seric break; 79816914Seric } 79916914Seric 80016914Seric /* 80116914Seric ** Check for subroutine calls. 80216914Seric */ 80316914Seric 80424944Seric if (*npvp != NULL && **npvp == CALLSUBR) 8059374Seric { 80616889Seric bcopy((char *) &npvp[2], (char *) pvp, 80716900Seric (int) (avp - npvp - 2) * sizeof *avp); 80816889Seric # ifdef DEBUG 80916889Seric if (tTd(21, 3)) 81016889Seric printf("-----callsubr %s\n", npvp[1]); 81116889Seric # endif DEBUG 81216889Seric rewrite(pvp, atoi(npvp[1])); 8133149Seric } 8143149Seric else 8153149Seric { 81617348Seric bcopy((char *) npvp, (char *) pvp, 81716900Seric (int) (avp - npvp) * sizeof *avp); 8189374Seric } 8194100Seric # ifdef DEBUG 8209374Seric if (tTd(21, 4)) 8219374Seric { 8229374Seric printf("rewritten as:"); 8239374Seric printav(pvp); 8249374Seric } 8254100Seric # endif DEBUG 826297Seric } 8278069Seric 8289279Seric if (OpMode == MD_TEST || tTd(21, 2)) 8298069Seric { 8308959Seric printf("rewrite: ruleset %2d returns:", ruleset); 8318069Seric printav(pvp); 8328069Seric } 8333149Seric } 8343149Seric /* 8353149Seric ** BUILDADDR -- build address from token vector. 8363149Seric ** 8373149Seric ** Parameters: 8383149Seric ** tv -- token vector. 8393149Seric ** a -- pointer to address descriptor to fill. 8403149Seric ** If NULL, one will be allocated. 8413149Seric ** 8423149Seric ** Returns: 8434279Seric ** NULL if there was an error. 8444279Seric ** 'a' otherwise. 8453149Seric ** 8463149Seric ** Side Effects: 8473149Seric ** fills in 'a' 8483149Seric */ 8493149Seric 8503149Seric ADDRESS * 8513149Seric buildaddr(tv, a) 8523149Seric register char **tv; 8533149Seric register ADDRESS *a; 8543149Seric { 8553149Seric static char buf[MAXNAME]; 8563149Seric struct mailer **mp; 8573149Seric register struct mailer *m; 8583149Seric 8593149Seric if (a == NULL) 8603149Seric a = (ADDRESS *) xalloc(sizeof *a); 86116889Seric bzero((char *) a, sizeof *a); 8623149Seric 8633149Seric /* figure out what net/mailer to use */ 8643149Seric if (**tv != CANONNET) 8654279Seric { 8663149Seric syserr("buildaddr: no net"); 8674279Seric return (NULL); 8684279Seric } 8693149Seric tv++; 87033725Sbostic if (!strcasecmp(*tv, "error")) 8714279Seric { 87210183Seric if (**++tv == CANONHOST) 87310183Seric { 87410183Seric setstat(atoi(*++tv)); 87510183Seric tv++; 87610183Seric } 87710183Seric if (**tv != CANONUSER) 8784279Seric syserr("buildaddr: error: no user"); 8794279Seric buf[0] = '\0'; 8804279Seric while (*++tv != NULL) 8814279Seric { 8824279Seric if (buf[0] != '\0') 8837005Seric (void) strcat(buf, " "); 8847005Seric (void) strcat(buf, *tv); 8854279Seric } 8864279Seric usrerr(buf); 8874279Seric return (NULL); 8884279Seric } 8894598Seric for (mp = Mailer; (m = *mp++) != NULL; ) 8903149Seric { 89133725Sbostic if (!strcasecmp(m->m_name, *tv)) 8923149Seric break; 8933149Seric } 8943149Seric if (m == NULL) 8954279Seric { 89624944Seric syserr("buildaddr: unknown mailer %s", *tv); 8974279Seric return (NULL); 8984279Seric } 8994598Seric a->q_mailer = m; 9003149Seric 9013149Seric /* figure out what host (if any) */ 9023149Seric tv++; 90310690Seric if (!bitnset(M_LOCAL, m->m_flags)) 9043149Seric { 9055704Seric if (**tv++ != CANONHOST) 9064279Seric { 9073149Seric syserr("buildaddr: no host"); 9084279Seric return (NULL); 9094279Seric } 9105704Seric buf[0] = '\0'; 9115704Seric while (*tv != NULL && **tv != CANONUSER) 9127005Seric (void) strcat(buf, *tv++); 9135704Seric a->q_host = newstr(buf); 9143149Seric } 9153149Seric else 9163149Seric a->q_host = NULL; 9173149Seric 9183149Seric /* figure out the user */ 9193149Seric if (**tv != CANONUSER) 9204279Seric { 9213149Seric syserr("buildaddr: no user"); 9224279Seric return (NULL); 9234279Seric } 92419040Seric 92519040Seric /* rewrite according recipient mailer rewriting rules */ 92619040Seric rewrite(++tv, 2); 92719040Seric if (m->m_r_rwset > 0) 92819040Seric rewrite(tv, m->m_r_rwset); 92919040Seric rewrite(tv, 4); 93019040Seric 93119040Seric /* save the result for the command line/RCPT argument */ 93211278Seric cataddr(tv, buf, sizeof buf); 9333149Seric a->q_user = buf; 9343149Seric 9353149Seric return (a); 9363149Seric } 9373188Seric /* 9384228Seric ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 9394228Seric ** 9404228Seric ** Parameters: 9414228Seric ** pvp -- parameter vector to rebuild. 9424228Seric ** buf -- buffer to build the string into. 9434228Seric ** sz -- size of buf. 9444228Seric ** 9454228Seric ** Returns: 9464228Seric ** none. 9474228Seric ** 9484228Seric ** Side Effects: 9494228Seric ** Destroys buf. 9504228Seric */ 9514228Seric 9524228Seric cataddr(pvp, buf, sz) 9534228Seric char **pvp; 9544228Seric char *buf; 9554228Seric register int sz; 9564228Seric { 9574228Seric bool oatomtok = FALSE; 9584228Seric bool natomtok = FALSE; 9594228Seric register int i; 9604228Seric register char *p; 9614228Seric 9628423Seric if (pvp == NULL) 9638423Seric { 96423109Seric (void) strcpy(buf, ""); 9658423Seric return; 9668423Seric } 9674228Seric p = buf; 96811156Seric sz -= 2; 9694228Seric while (*pvp != NULL && (i = strlen(*pvp)) < sz) 9704228Seric { 9718078Seric natomtok = (toktype(**pvp) == ATM); 9724228Seric if (oatomtok && natomtok) 9739042Seric *p++ = SpaceSub; 9744228Seric (void) strcpy(p, *pvp); 9754228Seric oatomtok = natomtok; 9764228Seric p += i; 97711156Seric sz -= i + 1; 9784228Seric pvp++; 9794228Seric } 9804228Seric *p = '\0'; 9814228Seric } 9824228Seric /* 9833188Seric ** SAMEADDR -- Determine if two addresses are the same 9843188Seric ** 9853188Seric ** This is not just a straight comparison -- if the mailer doesn't 9863188Seric ** care about the host we just ignore it, etc. 9873188Seric ** 9883188Seric ** Parameters: 9893188Seric ** a, b -- pointers to the internal forms to compare. 9903188Seric ** 9913188Seric ** Returns: 9923188Seric ** TRUE -- they represent the same mailbox. 9933188Seric ** FALSE -- they don't. 9943188Seric ** 9953188Seric ** Side Effects: 9963188Seric ** none. 9973188Seric */ 9983188Seric 9993188Seric bool 10009374Seric sameaddr(a, b) 10013188Seric register ADDRESS *a; 10023188Seric register ADDRESS *b; 10033188Seric { 10043188Seric /* if they don't have the same mailer, forget it */ 10053188Seric if (a->q_mailer != b->q_mailer) 10063188Seric return (FALSE); 10073188Seric 10083188Seric /* if the user isn't the same, we can drop out */ 10099374Seric if (strcmp(a->q_user, b->q_user) != 0) 10103188Seric return (FALSE); 10113188Seric 10123188Seric /* if the mailer ignores hosts, we have succeeded! */ 101310690Seric if (bitnset(M_LOCAL, a->q_mailer->m_flags)) 10143188Seric return (TRUE); 10153188Seric 10163188Seric /* otherwise compare hosts (but be careful for NULL ptrs) */ 10173188Seric if (a->q_host == NULL || b->q_host == NULL) 10183188Seric return (FALSE); 10193188Seric if (strcmp(a->q_host, b->q_host) != 0) 10203188Seric return (FALSE); 10213188Seric 10223188Seric return (TRUE); 10233188Seric } 10243234Seric /* 10253234Seric ** PRINTADDR -- print address (for debugging) 10263234Seric ** 10273234Seric ** Parameters: 10283234Seric ** a -- the address to print 10293234Seric ** follow -- follow the q_next chain. 10303234Seric ** 10313234Seric ** Returns: 10323234Seric ** none. 10333234Seric ** 10343234Seric ** Side Effects: 10353234Seric ** none. 10363234Seric */ 10373234Seric 10384317Seric # ifdef DEBUG 10394317Seric 10403234Seric printaddr(a, follow) 10413234Seric register ADDRESS *a; 10423234Seric bool follow; 10433234Seric { 10445001Seric bool first = TRUE; 10455001Seric 10463234Seric while (a != NULL) 10473234Seric { 10485001Seric first = FALSE; 10494443Seric printf("%x=", a); 10504085Seric (void) fflush(stdout); 10513234Seric printf("%s: mailer %d (%s), host `%s', user `%s'\n", a->q_paddr, 10528181Seric a->q_mailer->m_mno, a->q_mailer->m_name, a->q_host, 10538181Seric a->q_user); 10548181Seric printf("\tnext=%x, flags=%o, alias %x\n", a->q_next, a->q_flags, 10558181Seric a->q_alias); 10568181Seric printf("\thome=\"%s\", fullname=\"%s\"\n", a->q_home, 10578181Seric a->q_fullname); 10584996Seric 10593234Seric if (!follow) 10603234Seric return; 10614996Seric a = a->q_next; 10623234Seric } 10635001Seric if (first) 10644443Seric printf("[NULL]\n"); 10653234Seric } 10664317Seric 10674317Seric # endif DEBUG 10687682Seric /* 10697682Seric ** REMOTENAME -- return the name relative to the current mailer 10707682Seric ** 10717682Seric ** Parameters: 10727682Seric ** name -- the name to translate. 10738069Seric ** m -- the mailer that we want to do rewriting relative 10748069Seric ** to. 10758069Seric ** senderaddress -- if set, uses the sender rewriting rules 10768069Seric ** rather than the recipient rewriting rules. 107710310Seric ** canonical -- if set, strip out any comment information, 107810310Seric ** etc. 10797682Seric ** 10807682Seric ** Returns: 10817682Seric ** the text string representing this address relative to 10827682Seric ** the receiving mailer. 10837682Seric ** 10847682Seric ** Side Effects: 10857682Seric ** none. 10867682Seric ** 10877682Seric ** Warnings: 10887682Seric ** The text string returned is tucked away locally; 10897682Seric ** copy it if you intend to save it. 10907682Seric */ 10917682Seric 10927682Seric char * 109310310Seric remotename(name, m, senderaddress, canonical) 10947682Seric char *name; 10957682Seric struct mailer *m; 10968069Seric bool senderaddress; 109710310Seric bool canonical; 10987682Seric { 10998069Seric register char **pvp; 11008069Seric char *fancy; 11018069Seric extern char *macvalue(); 11028181Seric char *oldg = macvalue('g', CurEnv); 11037682Seric static char buf[MAXNAME]; 11047682Seric char lbuf[MAXNAME]; 110516914Seric char pvpbuf[PSBUFSIZE]; 11067682Seric extern char **prescan(); 11077889Seric extern char *crackaddr(); 11087682Seric 11097755Seric # ifdef DEBUG 11107755Seric if (tTd(12, 1)) 11117755Seric printf("remotename(%s)\n", name); 11127755Seric # endif DEBUG 11137755Seric 111410177Seric /* don't do anything if we are tagging it as special */ 111510177Seric if ((senderaddress ? m->m_s_rwset : m->m_r_rwset) < 0) 111610177Seric return (name); 111710177Seric 11187682Seric /* 11198181Seric ** Do a heuristic crack of this name to extract any comment info. 11208181Seric ** This will leave the name as a comment and a $g macro. 11217889Seric */ 11227889Seric 112310310Seric if (canonical) 112416155Seric fancy = "\001g"; 112510310Seric else 112610310Seric fancy = crackaddr(name); 11277889Seric 11288181Seric /* 11298181Seric ** Turn the name into canonical form. 11308181Seric ** Normally this will be RFC 822 style, i.e., "user@domain". 11318181Seric ** If this only resolves to "user", and the "C" flag is 11328181Seric ** specified in the sending mailer, then the sender's 11338181Seric ** domain will be appended. 11348181Seric */ 11358181Seric 113616914Seric pvp = prescan(name, '\0', pvpbuf); 11377889Seric if (pvp == NULL) 11387889Seric return (name); 11398181Seric rewrite(pvp, 3); 11408181Seric if (CurEnv->e_fromdomain != NULL) 11418181Seric { 11428181Seric /* append from domain to this address */ 11438181Seric register char **pxp = pvp; 11448181Seric 11459594Seric /* see if there is an "@domain" in the current name */ 11468181Seric while (*pxp != NULL && strcmp(*pxp, "@") != 0) 11478181Seric pxp++; 11488181Seric if (*pxp == NULL) 11498181Seric { 11509594Seric /* no.... append the "@domain" from the sender */ 11518181Seric register char **qxq = CurEnv->e_fromdomain; 11528181Seric 11539594Seric while ((*pxp++ = *qxq++) != NULL) 11549594Seric continue; 115511726Seric rewrite(pvp, 3); 11568181Seric } 11578181Seric } 11588181Seric 11598181Seric /* 11608959Seric ** Do more specific rewriting. 11618181Seric ** Rewrite using ruleset 1 or 2 depending on whether this is 11628181Seric ** a sender address or not. 11638181Seric ** Then run it through any receiving-mailer-specific rulesets. 11648181Seric */ 11658181Seric 11668069Seric if (senderaddress) 11677755Seric { 11687889Seric rewrite(pvp, 1); 11698069Seric if (m->m_s_rwset > 0) 11708069Seric rewrite(pvp, m->m_s_rwset); 11718069Seric } 11728069Seric else 11738069Seric { 11747889Seric rewrite(pvp, 2); 11758069Seric if (m->m_r_rwset > 0) 11768069Seric rewrite(pvp, m->m_r_rwset); 11777682Seric } 11787682Seric 11798181Seric /* 11808959Seric ** Do any final sanitation the address may require. 11818959Seric ** This will normally be used to turn internal forms 11828959Seric ** (e.g., user@host.LOCAL) into external form. This 11838959Seric ** may be used as a default to the above rules. 11848959Seric */ 11858959Seric 11868959Seric rewrite(pvp, 4); 11878959Seric 11888959Seric /* 11898181Seric ** Now restore the comment information we had at the beginning. 11908181Seric */ 11918181Seric 11927682Seric cataddr(pvp, lbuf, sizeof lbuf); 11939374Seric define('g', lbuf, CurEnv); 11947889Seric expand(fancy, buf, &buf[sizeof buf - 1], CurEnv); 11959374Seric define('g', oldg, CurEnv); 11967682Seric 11977682Seric # ifdef DEBUG 11987682Seric if (tTd(12, 1)) 11997755Seric printf("remotename => `%s'\n", buf); 12007682Seric # endif DEBUG 12017682Seric return (buf); 12027682Seric } 1203