122976Smiriam /* 234921Sbostic * Copyright (c) 1983 Eric P. Allman 363589Sbostic * Copyright (c) 1988, 1993 463589Sbostic * The Regents of the University of California. All rights reserved. 533730Sbostic * 642828Sbostic * %sccs.include.redist.c% 733730Sbostic */ 822976Smiriam 922976Smiriam #ifndef lint 10*64966Seric static char sccsid[] = "@(#)parseaddr.c 8.19 (Berkeley) 11/28/93"; 1133730Sbostic #endif /* not lint */ 1222976Smiriam 1356678Seric # include "sendmail.h" 14297Seric 15297Seric /* 169888Seric ** PARSEADDR -- Parse an address 17297Seric ** 18297Seric ** Parses an address and breaks it up into three parts: a 19297Seric ** net to transmit the message on, the host to transmit it 20297Seric ** to, and a user on that host. These are loaded into an 212973Seric ** ADDRESS header with the values squirreled away if necessary. 22297Seric ** The "user" part may not be a real user; the process may 23297Seric ** just reoccur on that machine. For example, on a machine 24297Seric ** with an arpanet connection, the address 25297Seric ** csvax.bill@berkeley 26297Seric ** will break up to a "user" of 'csvax.bill' and a host 27297Seric ** of 'berkeley' -- to be transmitted over the arpanet. 28297Seric ** 29297Seric ** Parameters: 30297Seric ** addr -- the address to parse. 31297Seric ** a -- a pointer to the address descriptor buffer. 32297Seric ** If NULL, a header will be created. 3364284Seric ** flags -- describe detail for parsing. See RF_ definitions 3464284Seric ** in sendmail.h. 3511445Seric ** delim -- the character to terminate the address, passed 3611445Seric ** to prescan. 3758333Seric ** delimptr -- if non-NULL, set to the location of the 3858333Seric ** delim character that was found. 3956678Seric ** e -- the envelope that will contain this address. 40297Seric ** 41297Seric ** Returns: 42297Seric ** A pointer to the address descriptor header (`a' if 43297Seric ** `a' is non-NULL). 44297Seric ** NULL on error. 45297Seric ** 46297Seric ** Side Effects: 47297Seric ** none 48297Seric */ 49297Seric 509374Seric /* following delimiters are inherent to the internal algorithms */ 5159278Seric # define DELIMCHARS "()<>,;\r\n" /* default word delimiters */ 522091Seric 532973Seric ADDRESS * 5464284Seric parseaddr(addr, a, flags, delim, delimptr, e) 55297Seric char *addr; 562973Seric register ADDRESS *a; 5764284Seric int flags; 5859700Seric int delim; 5958333Seric char **delimptr; 6056678Seric register ENVELOPE *e; 61297Seric { 623149Seric register char **pvp; 6358333Seric auto char *delimptrbuf; 6459084Seric bool queueup; 6516914Seric char pvpbuf[PSBUFSIZE]; 6656678Seric extern ADDRESS *buildaddr(); 6757388Seric extern bool invalidaddr(); 68297Seric 69297Seric /* 70297Seric ** Initialize and prescan address. 71297Seric */ 72297Seric 7356678Seric e->e_to = addr; 747675Seric if (tTd(20, 1)) 759888Seric printf("\n--parseaddr(%s)\n", addr); 763188Seric 7758333Seric if (delimptr == NULL) 7858333Seric delimptr = &delimptrbuf; 7958333Seric 80*64966Seric if (strlen(addr) >= MAXNAME) 81*64966Seric { 82*64966Seric usrerr("Name too long, %d characters max", MAXNAME - 1); 83*64966Seric if (tTd(20, 1)) 84*64966Seric printf("parseaddr-->NULL\n"); 85*64966Seric return NULL; 86*64966Seric } 87*64966Seric 8858333Seric pvp = prescan(addr, delim, pvpbuf, delimptr); 893149Seric if (pvp == NULL) 9056729Seric { 9156729Seric if (tTd(20, 1)) 9256729Seric printf("parseaddr-->NULL\n"); 93297Seric return (NULL); 9456729Seric } 95297Seric 9664726Seric if (invalidaddr(addr, delim == '\0' ? NULL : *delimptr)) 9764726Seric { 9864726Seric if (tTd(20, 1)) 9964726Seric printf("parseaddr-->bad address\n"); 10064726Seric return NULL; 10164726Seric } 10264726Seric 103297Seric /* 10464348Seric ** Save addr if we are going to have to. 10564348Seric ** 10664348Seric ** We have to do this early because there is a chance that 10764348Seric ** the map lookups in the rewriting rules could clobber 10864348Seric ** static memory somewhere. 10964348Seric */ 11064348Seric 11164348Seric if (bitset(RF_COPYPADDR, flags) && addr != NULL) 11264348Seric { 11364348Seric char savec = **delimptr; 11464348Seric 11564348Seric if (savec != '\0') 11664348Seric **delimptr = '\0'; 11764348Seric addr = newstr(addr); 11864348Seric if (savec != '\0') 11964348Seric **delimptr = savec; 12064348Seric } 12164348Seric 12264348Seric /* 1233149Seric ** Apply rewriting rules. 1247889Seric ** Ruleset 0 does basic parsing. It must resolve. 125297Seric */ 126297Seric 12759084Seric queueup = FALSE; 12859084Seric if (rewrite(pvp, 3, e) == EX_TEMPFAIL) 12959084Seric queueup = TRUE; 13059084Seric if (rewrite(pvp, 0, e) == EX_TEMPFAIL) 13159084Seric queueup = TRUE; 132297Seric 133297Seric 134297Seric /* 1353149Seric ** Build canonical address from pvp. 136297Seric */ 137297Seric 13864284Seric a = buildaddr(pvp, a, flags, e); 139297Seric 140297Seric /* 1413149Seric ** Make local copies of the host & user and then 1423149Seric ** transport them out. 143297Seric */ 144297Seric 14564348Seric allocaddr(a, flags, addr); 14664306Seric if (bitset(QBADADDR, a->q_flags)) 14764306Seric return a; 14856678Seric 14956678Seric /* 15059084Seric ** If there was a parsing failure, mark it for queueing. 15159084Seric */ 15259084Seric 15359084Seric if (queueup) 15459595Seric { 15559734Seric char *msg = "Transient parse error -- message queued for future delivery"; 15659734Seric 15759595Seric if (tTd(20, 1)) 15859595Seric printf("parseaddr: queuing message\n"); 15959734Seric message(msg); 16059734Seric if (e->e_message == NULL) 16160009Seric e->e_message = newstr(msg); 16259084Seric a->q_flags |= QQUEUEUP; 16359595Seric } 16459084Seric 16559084Seric /* 16656678Seric ** Compute return value. 16756678Seric */ 16856678Seric 16956678Seric if (tTd(20, 1)) 1708078Seric { 17156678Seric printf("parseaddr-->"); 17256678Seric printaddr(a, FALSE); 17356678Seric } 17456678Seric 17556678Seric return (a); 17656678Seric } 17756678Seric /* 17857388Seric ** INVALIDADDR -- check for address containing meta-characters 17957388Seric ** 18057388Seric ** Parameters: 18157388Seric ** addr -- the address to check. 18257388Seric ** 18357388Seric ** Returns: 18457388Seric ** TRUE -- if the address has any "wierd" characters 18557388Seric ** FALSE -- otherwise. 18657388Seric */ 18757388Seric 18857388Seric bool 18964726Seric invalidaddr(addr, delimptr) 19057388Seric register char *addr; 19164726Seric char *delimptr; 19257388Seric { 19364726Seric char savedelim; 19464726Seric 19564726Seric if (delimptr != NULL) 19664764Seric { 19764726Seric savedelim = *delimptr; 19864764Seric if (savedelim != '\0') 19964764Seric *delimptr = '\0'; 20064764Seric } 20164726Seric #if 0 20264726Seric /* for testing.... */ 20364726Seric if (strcmp(addr, "INvalidADDR") == 0) 20457388Seric { 20564726Seric usrerr("553 INvalid ADDRess"); 20664764Seric goto addrfailure; 20757388Seric } 20864726Seric #endif 20964726Seric for (; *addr != '\0'; addr++) 21064726Seric { 21164726Seric if ((*addr & 0340) == 0200) 21264726Seric break; 21364726Seric } 21464726Seric if (*addr == '\0') 21564764Seric { 21664764Seric if (savedelim != '\0' && delimptr != NULL) 21764764Seric *delimptr = savedelim; 21864726Seric return FALSE; 21964764Seric } 22064726Seric setstat(EX_USAGE); 22164726Seric usrerr("553 Address contained invalid control characters"); 22264764Seric addrfailure: 22364764Seric if (savedelim != '\0' && delimptr != NULL) 22464764Seric *delimptr = savedelim; 22564726Seric return TRUE; 22657388Seric } 22757388Seric /* 22856678Seric ** ALLOCADDR -- do local allocations of address on demand. 22956678Seric ** 23056678Seric ** Also lowercases the host name if requested. 23156678Seric ** 23256678Seric ** Parameters: 23356678Seric ** a -- the address to reallocate. 23464284Seric ** flags -- the copy flag (see RF_ definitions in sendmail.h 23564284Seric ** for a description). 23656678Seric ** paddr -- the printname of the address. 23756678Seric ** 23856678Seric ** Returns: 23956678Seric ** none. 24056678Seric ** 24156678Seric ** Side Effects: 24256678Seric ** Copies portions of a into local buffers as requested. 24356678Seric */ 24456678Seric 24564348Seric allocaddr(a, flags, paddr) 24656678Seric register ADDRESS *a; 24764284Seric int flags; 24856678Seric char *paddr; 24956678Seric { 25058673Seric if (tTd(24, 4)) 25164284Seric printf("allocaddr(flags=%o, paddr=%s)\n", flags, paddr); 25258673Seric 25364348Seric a->q_paddr = paddr; 2548078Seric 25524944Seric if (a->q_user == NULL) 25624944Seric a->q_user = ""; 25724944Seric if (a->q_host == NULL) 25824944Seric a->q_host = ""; 25924944Seric 26064284Seric if (bitset(RF_COPYPARSE, flags)) 261297Seric { 26224944Seric a->q_host = newstr(a->q_host); 2633149Seric if (a->q_user != a->q_paddr) 2643149Seric a->q_user = newstr(a->q_user); 265297Seric } 266297Seric 26756678Seric if (a->q_paddr == NULL) 26856678Seric a->q_paddr = a->q_user; 269297Seric } 270297Seric /* 271297Seric ** PRESCAN -- Prescan name and make it canonical 272297Seric ** 2739374Seric ** Scans a name and turns it into a set of tokens. This process 2749374Seric ** deletes blanks and comments (in parentheses). 275297Seric ** 276297Seric ** This routine knows about quoted strings and angle brackets. 277297Seric ** 278297Seric ** There are certain subtleties to this routine. The one that 279297Seric ** comes to mind now is that backslashes on the ends of names 280297Seric ** are silently stripped off; this is intentional. The problem 281297Seric ** is that some versions of sndmsg (like at LBL) set the kill 282297Seric ** character to something other than @ when reading addresses; 283297Seric ** so people type "csvax.eric\@berkeley" -- which screws up the 284297Seric ** berknet mailer. 285297Seric ** 286297Seric ** Parameters: 287297Seric ** addr -- the name to chomp. 288297Seric ** delim -- the delimiter for the address, normally 289297Seric ** '\0' or ','; \0 is accepted in any case. 29015284Seric ** If '\t' then we are reading the .cf file. 29116914Seric ** pvpbuf -- place to put the saved text -- note that 29216914Seric ** the pointers are static. 29358333Seric ** delimptr -- if non-NULL, set to the location of the 29458333Seric ** terminating delimiter. 295297Seric ** 296297Seric ** Returns: 2973149Seric ** A pointer to a vector of tokens. 298297Seric ** NULL on error. 299297Seric */ 300297Seric 3018078Seric /* states and character types */ 3028078Seric # define OPR 0 /* operator */ 3038078Seric # define ATM 1 /* atom */ 3048078Seric # define QST 2 /* in quoted string */ 3058078Seric # define SPC 3 /* chewing up spaces */ 3068078Seric # define ONE 4 /* pick up one character */ 3073149Seric 3088078Seric # define NSTATES 5 /* number of states */ 3098078Seric # define TYPE 017 /* mask to select state type */ 3108078Seric 3118078Seric /* meta bits for table */ 3128078Seric # define M 020 /* meta character; don't pass through */ 3138078Seric # define B 040 /* cause a break */ 3148078Seric # define MB M|B /* meta-break */ 3158078Seric 3168078Seric static short StateTab[NSTATES][NSTATES] = 3178078Seric { 3188087Seric /* oldst chtype> OPR ATM QST SPC ONE */ 3199051Seric /*OPR*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, 3209051Seric /*ATM*/ OPR|B, ATM, QST|B, SPC|MB, ONE|B, 3219051Seric /*QST*/ QST, QST, OPR, QST, QST, 3228078Seric /*SPC*/ OPR, ATM, QST, SPC|M, ONE, 3238078Seric /*ONE*/ OPR, OPR, OPR, OPR, OPR, 3248078Seric }; 3258078Seric 3268078Seric # define NOCHAR -1 /* signal nothing in lookahead token */ 3278078Seric 3283149Seric char ** 32958333Seric prescan(addr, delim, pvpbuf, delimptr) 330297Seric char *addr; 331297Seric char delim; 33216914Seric char pvpbuf[]; 33358333Seric char **delimptr; 334297Seric { 335297Seric register char *p; 3368078Seric register char *q; 3379346Seric register int c; 3383149Seric char **avp; 339297Seric bool bslashmode; 340297Seric int cmntcnt; 3418423Seric int anglecnt; 3423149Seric char *tok; 3438078Seric int state; 3448078Seric int newstate; 34559747Seric char *saveto = CurEnv->e_to; 3468078Seric static char *av[MAXATOM+1]; 34756678Seric extern int errno; 348297Seric 34915253Seric /* make sure error messages don't have garbage on them */ 35015253Seric errno = 0; 35115253Seric 35216914Seric q = pvpbuf; 3533149Seric bslashmode = FALSE; 3547800Seric cmntcnt = 0; 3558423Seric anglecnt = 0; 3563149Seric avp = av; 35756678Seric state = ATM; 3588078Seric c = NOCHAR; 3598078Seric p = addr; 36059747Seric CurEnv->e_to = p; 36156764Seric if (tTd(22, 11)) 362297Seric { 3638078Seric printf("prescan: "); 3648078Seric xputs(p); 36523109Seric (void) putchar('\n'); 3668078Seric } 3678078Seric 3688078Seric do 3698078Seric { 3703149Seric /* read a token */ 3713149Seric tok = q; 3728078Seric for (;;) 373297Seric { 3748078Seric /* store away any old lookahead character */ 37559277Seric if (c != NOCHAR && !bslashmode) 3768078Seric { 37715284Seric /* see if there is room */ 37816914Seric if (q >= &pvpbuf[PSBUFSIZE - 5]) 3798078Seric { 38058151Seric usrerr("553 Address too long"); 38158333Seric if (delimptr != NULL) 38258333Seric *delimptr = p; 38359747Seric CurEnv->e_to = saveto; 3848078Seric return (NULL); 3858078Seric } 38615284Seric 38715284Seric /* squirrel it away */ 3888078Seric *q++ = c; 3898078Seric } 3908078Seric 3918078Seric /* read a new input character */ 3928078Seric c = *p++; 39357631Seric if (c == '\0') 39456764Seric { 39556764Seric /* diagnose and patch up bad syntax */ 39656764Seric if (state == QST) 39756764Seric { 39864767Seric usrerr("653 Unbalanced '\"'"); 39956764Seric c = '"'; 40056764Seric } 40156764Seric else if (cmntcnt > 0) 40256764Seric { 40364767Seric usrerr("653 Unbalanced '('"); 40456764Seric c = ')'; 40556764Seric } 40656764Seric else if (anglecnt > 0) 40756764Seric { 40856764Seric c = '>'; 40964767Seric usrerr("653 Unbalanced '<'"); 41056764Seric } 41156764Seric else 41256764Seric break; 41315284Seric 41456764Seric p--; 41556764Seric } 41657631Seric else if (c == delim && anglecnt <= 0 && 41757631Seric cmntcnt <= 0 && state != QST) 41857631Seric break; 41956764Seric 4208078Seric if (tTd(22, 101)) 4218078Seric printf("c=%c, s=%d; ", c, state); 4228078Seric 4233149Seric /* chew up special characters */ 4243149Seric *q = '\0'; 4253149Seric if (bslashmode) 4263149Seric { 42759105Seric bslashmode = FALSE; 42859105Seric 42924944Seric /* kludge \! for naive users */ 43058061Seric if (cmntcnt > 0) 43159105Seric { 43258061Seric c = NOCHAR; 43359105Seric continue; 43459105Seric } 43559105Seric else if (c != '!' || state == QST) 43659105Seric { 43756678Seric *q++ = '\\'; 43859105Seric continue; 43959105Seric } 4403149Seric } 44156678Seric 44256678Seric if (c == '\\') 4433149Seric { 4443149Seric bslashmode = TRUE; 4453149Seric } 44656678Seric else if (state == QST) 4478514Seric { 4488514Seric /* do nothing, just avoid next clauses */ 4498514Seric } 4508078Seric else if (c == '(') 4514100Seric { 4528078Seric cmntcnt++; 4538078Seric c = NOCHAR; 4544100Seric } 4558078Seric else if (c == ')') 4563149Seric { 4578078Seric if (cmntcnt <= 0) 4583149Seric { 45964767Seric usrerr("653 Unbalanced ')'"); 46063844Seric c = NOCHAR; 4613149Seric } 4628078Seric else 4638078Seric cmntcnt--; 4648078Seric } 4658078Seric else if (cmntcnt > 0) 4668078Seric c = NOCHAR; 4678423Seric else if (c == '<') 4688423Seric anglecnt++; 4698423Seric else if (c == '>') 4708423Seric { 4718423Seric if (anglecnt <= 0) 4728423Seric { 47364767Seric usrerr("653 Unbalanced '>'"); 47463844Seric c = NOCHAR; 4758423Seric } 47663844Seric else 47763844Seric anglecnt--; 4788423Seric } 47958050Seric else if (delim == ' ' && isascii(c) && isspace(c)) 48011423Seric c = ' '; 4813149Seric 4828078Seric if (c == NOCHAR) 4838078Seric continue; 4843149Seric 4858078Seric /* see if this is end of input */ 48611405Seric if (c == delim && anglecnt <= 0 && state != QST) 4873149Seric break; 4883149Seric 4898078Seric newstate = StateTab[state][toktype(c)]; 4908078Seric if (tTd(22, 101)) 4918078Seric printf("ns=%02o\n", newstate); 4928078Seric state = newstate & TYPE; 4938078Seric if (bitset(M, newstate)) 4948078Seric c = NOCHAR; 4958078Seric if (bitset(B, newstate)) 4964228Seric break; 497297Seric } 4983149Seric 4993149Seric /* new token */ 5008078Seric if (tok != q) 5011378Seric { 5028078Seric *q++ = '\0'; 5038078Seric if (tTd(22, 36)) 504297Seric { 5058078Seric printf("tok="); 5068078Seric xputs(tok); 50723109Seric (void) putchar('\n'); 508297Seric } 5098078Seric if (avp >= &av[MAXATOM]) 510297Seric { 51158151Seric syserr("553 prescan: too many tokens"); 51258333Seric if (delimptr != NULL) 51358333Seric *delimptr = p; 51459747Seric CurEnv->e_to = saveto; 5158078Seric return (NULL); 516297Seric } 5178078Seric *avp++ = tok; 518297Seric } 5198423Seric } while (c != '\0' && (c != delim || anglecnt > 0)); 5203149Seric *avp = NULL; 52158333Seric p--; 52258333Seric if (delimptr != NULL) 52358333Seric *delimptr = p; 52456764Seric if (tTd(22, 12)) 52556764Seric { 52656764Seric printf("prescan==>"); 52756764Seric printav(av); 52856764Seric } 52959747Seric CurEnv->e_to = saveto; 53058546Seric if (av[0] == NULL) 531*64966Seric { 532*64966Seric if (tTd(22, 1)) 533*64966Seric printf("prescan: null leading token\n"); 53458546Seric return (NULL); 535*64966Seric } 53658403Seric return (av); 5373149Seric } 5383149Seric /* 5393149Seric ** TOKTYPE -- return token type 5403149Seric ** 5413149Seric ** Parameters: 5423149Seric ** c -- the character in question. 5433149Seric ** 5443149Seric ** Returns: 5453149Seric ** Its type. 5463149Seric ** 5473149Seric ** Side Effects: 5483149Seric ** none. 5493149Seric */ 550297Seric 5513149Seric toktype(c) 55258050Seric register int c; 5533149Seric { 5543380Seric static char buf[50]; 5553382Seric static bool firstime = TRUE; 5563380Seric 5573382Seric if (firstime) 5583380Seric { 5593382Seric firstime = FALSE; 56058050Seric expand("\201o", buf, &buf[sizeof buf - 1], CurEnv); 5617005Seric (void) strcat(buf, DELIMCHARS); 5623380Seric } 56358050Seric c &= 0377; 56456327Seric if (c == MATCHCLASS || c == MATCHREPL || c == MATCHNCLASS) 5658078Seric return (ONE); 56659027Seric if (c == MACRODEXPAND) 56759027Seric return (ONE); 5688078Seric if (c == '"') 5698078Seric return (QST); 57058050Seric if ((c & 0340) == 0200) 57158050Seric return (OPR); 5724100Seric if (!isascii(c)) 5738078Seric return (ATM); 5748078Seric if (isspace(c) || c == ')') 5758078Seric return (SPC); 57658050Seric if (strchr(buf, c) != NULL) 5778078Seric return (OPR); 5788078Seric return (ATM); 5793149Seric } 5803149Seric /* 5813149Seric ** REWRITE -- apply rewrite rules to token vector. 5823149Seric ** 5834476Seric ** This routine is an ordered production system. Each rewrite 5844476Seric ** rule has a LHS (called the pattern) and a RHS (called the 5854476Seric ** rewrite); 'rwr' points the the current rewrite rule. 5864476Seric ** 5874476Seric ** For each rewrite rule, 'avp' points the address vector we 5884476Seric ** are trying to match against, and 'pvp' points to the pattern. 5898058Seric ** If pvp points to a special match value (MATCHZANY, MATCHANY, 5909585Seric ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp 5919585Seric ** matched is saved away in the match vector (pointed to by 'mvp'). 5924476Seric ** 5934476Seric ** When a match between avp & pvp does not match, we try to 5949585Seric ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS 5954476Seric ** we must also back out the match in mvp. If we reach a 5968058Seric ** MATCHANY or MATCHZANY we just extend the match and start 5978058Seric ** over again. 5984476Seric ** 5994476Seric ** When we finally match, we rewrite the address vector 6004476Seric ** and try over again. 6014476Seric ** 6023149Seric ** Parameters: 6033149Seric ** pvp -- pointer to token vector. 60459027Seric ** ruleset -- the ruleset to use for rewriting. 60559027Seric ** e -- the current envelope. 6063149Seric ** 6073149Seric ** Returns: 60859084Seric ** A status code. If EX_TEMPFAIL, higher level code should 60959084Seric ** attempt recovery. 6103149Seric ** 6113149Seric ** Side Effects: 6123149Seric ** pvp is modified. 6133149Seric */ 6142091Seric 6153149Seric struct match 6163149Seric { 6174468Seric char **first; /* first token matched */ 6184468Seric char **last; /* last token matched */ 61958825Seric char **pattern; /* pointer to pattern */ 6203149Seric }; 6213149Seric 6224468Seric # define MAXMATCH 9 /* max params per rewrite */ 6233149Seric 6243149Seric 62559084Seric int 62659027Seric rewrite(pvp, ruleset, e) 6273149Seric char **pvp; 6284070Seric int ruleset; 62959027Seric register ENVELOPE *e; 6303149Seric { 6313149Seric register char *ap; /* address pointer */ 6323149Seric register char *rp; /* rewrite pointer */ 6333149Seric register char **avp; /* address vector pointer */ 6343149Seric register char **rvp; /* rewrite vector pointer */ 6358058Seric register struct match *mlp; /* cur ptr into mlist */ 6368058Seric register struct rewrite *rwr; /* pointer to current rewrite rule */ 63758866Seric int ruleno; /* current rule number */ 63859084Seric int rstat = EX_OK; /* return status */ 63964740Seric int loopcount; 64056678Seric struct match mlist[MAXMATCH]; /* stores match on LHS */ 6413149Seric char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 6423149Seric 6439279Seric if (OpMode == MD_TEST || tTd(21, 2)) 6443149Seric { 6458959Seric printf("rewrite: ruleset %2d input:", ruleset); 64656678Seric printav(pvp); 6473149Seric } 64856678Seric if (ruleset < 0 || ruleset >= MAXRWSETS) 64956326Seric { 65058151Seric syserr("554 rewrite: illegal ruleset number %d", ruleset); 65159084Seric return EX_CONFIG; 65256326Seric } 65356678Seric if (pvp == NULL) 65459084Seric return EX_USAGE; 65556326Seric 6563149Seric /* 65756678Seric ** Run through the list of rewrite rules, applying 65856678Seric ** any that match. 6593149Seric */ 6603149Seric 66158866Seric ruleno = 1; 66264740Seric loopcount = 0; 6634070Seric for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 6643149Seric { 6657675Seric if (tTd(21, 12)) 666297Seric { 6678069Seric printf("-----trying rule:"); 66856678Seric printav(rwr->r_lhs); 6693149Seric } 6703149Seric 6713149Seric /* try to match on this rule */ 6724468Seric mlp = mlist; 6738058Seric rvp = rwr->r_lhs; 6748058Seric avp = pvp; 67558866Seric if (++loopcount > 100) 6763149Seric { 67758866Seric syserr("554 Infinite loop in ruleset %d, rule %d", 67858866Seric ruleset, ruleno); 67958866Seric if (tTd(21, 1)) 68052637Seric { 68156678Seric printf("workspace: "); 68256678Seric printav(pvp); 68352637Seric } 68458866Seric break; 68558866Seric } 68658866Seric 68758866Seric while ((ap = *avp) != NULL || *rvp != NULL) 68858866Seric { 6893149Seric rp = *rvp; 6908058Seric if (tTd(21, 35)) 6918058Seric { 69258825Seric printf("ADVANCE rp="); 69357531Seric xputs(rp); 69457532Seric printf(", ap="); 6958058Seric xputs(ap); 6968069Seric printf("\n"); 6978058Seric } 69856678Seric if (rp == NULL) 69956326Seric { 7003149Seric /* end-of-pattern before end-of-address */ 7018058Seric goto backup; 70256678Seric } 70358173Seric if (ap == NULL && (*rp & 0377) != MATCHZANY && 70458827Seric (*rp & 0377) != MATCHZERO) 70556326Seric { 70658825Seric /* end-of-input with patterns left */ 70758825Seric goto backup; 708297Seric } 70956326Seric 71058050Seric switch (*rp & 0377) 7118058Seric { 71256678Seric register STAB *s; 71358814Seric char buf[MAXLINE]; 71456326Seric 71556678Seric case MATCHCLASS: 71658825Seric /* match any phrase in a class */ 71758825Seric mlp->pattern = rvp; 71858814Seric mlp->first = avp; 71958814Seric extendclass: 72058825Seric ap = *avp; 72158825Seric if (ap == NULL) 72258814Seric goto backup; 72358814Seric mlp->last = avp++; 72458814Seric cataddr(mlp->first, mlp->last, buf, sizeof buf, '\0'); 72558814Seric s = stab(buf, ST_CLASS, ST_FIND); 72656678Seric if (s == NULL || !bitnset(rp[1], s->s_class)) 72756326Seric { 72858825Seric if (tTd(21, 36)) 72958825Seric { 73058825Seric printf("EXTEND rp="); 73158825Seric xputs(rp); 73258825Seric printf(", ap="); 73358825Seric xputs(ap); 73458825Seric printf("\n"); 73558825Seric } 73658825Seric goto extendclass; 73756326Seric } 73858825Seric if (tTd(21, 36)) 73958825Seric printf("CLMATCH\n"); 74058814Seric mlp++; 74158814Seric break; 7424060Seric 74358825Seric case MATCHNCLASS: 74458825Seric /* match any token not in a class */ 74558825Seric s = stab(ap, ST_CLASS, ST_FIND); 74658825Seric if (s != NULL && bitnset(rp[1], s->s_class)) 74758825Seric goto backup; 74858825Seric 74958825Seric /* fall through */ 75058825Seric 75156678Seric case MATCHONE: 75256678Seric case MATCHANY: 75356678Seric /* match exactly one token */ 75458825Seric mlp->pattern = rvp; 75556678Seric mlp->first = avp; 75656678Seric mlp->last = avp++; 7578058Seric mlp++; 75856678Seric break; 7598058Seric 76056678Seric case MATCHZANY: 76156678Seric /* match zero or more tokens */ 76258825Seric mlp->pattern = rvp; 76356678Seric mlp->first = avp; 76456678Seric mlp->last = avp - 1; 76556678Seric mlp++; 76656678Seric break; 76756326Seric 76858827Seric case MATCHZERO: 76958173Seric /* match zero tokens */ 77058173Seric break; 77158173Seric 77259027Seric case MACRODEXPAND: 77359027Seric /* 77459027Seric ** Match against run-time macro. 77559027Seric ** This algorithm is broken for the 77659027Seric ** general case (no recursive macros, 77759027Seric ** improper tokenization) but should 77859027Seric ** work for the usual cases. 77959027Seric */ 78059027Seric 78159027Seric ap = macvalue(rp[1], e); 78259027Seric mlp->first = avp; 78359027Seric if (tTd(21, 2)) 78459027Seric printf("rewrite: LHS $&%c => \"%s\"\n", 78559027Seric rp[1], 78659027Seric ap == NULL ? "(NULL)" : ap); 78759027Seric 78859027Seric if (ap == NULL) 78959027Seric break; 79060502Seric while (*ap != '\0') 79159027Seric { 79259027Seric if (*avp == NULL || 79359027Seric strncasecmp(ap, *avp, strlen(*avp)) != 0) 79459027Seric { 79559027Seric /* no match */ 79659027Seric avp = mlp->first; 79759027Seric goto backup; 79859027Seric } 79959027Seric ap += strlen(*avp++); 80059027Seric } 80159027Seric 80259027Seric /* match */ 80359027Seric break; 80459027Seric 80556678Seric default: 80656678Seric /* must have exact match */ 80756678Seric if (strcasecmp(rp, ap)) 8088058Seric goto backup; 8094468Seric avp++; 81056678Seric break; 8113149Seric } 8123149Seric 81356678Seric /* successful match on this token */ 8143149Seric rvp++; 8153149Seric continue; 8163149Seric 81758825Seric backup: 81856678Seric /* match failed -- back up */ 81958825Seric while (--mlp >= mlist) 8203149Seric { 82158825Seric rvp = mlp->pattern; 82256678Seric rp = *rvp; 82358825Seric avp = mlp->last + 1; 82458825Seric ap = *avp; 82558825Seric 82658825Seric if (tTd(21, 36)) 82758825Seric { 82858825Seric printf("BACKUP rp="); 82958825Seric xputs(rp); 83058825Seric printf(", ap="); 83158825Seric xputs(ap); 83258825Seric printf("\n"); 83358825Seric } 83458825Seric 83558825Seric if (ap == NULL) 83658825Seric { 83758825Seric /* run off the end -- back up again */ 83858825Seric continue; 83958825Seric } 84058050Seric if ((*rp & 0377) == MATCHANY || 84158050Seric (*rp & 0377) == MATCHZANY) 8424468Seric { 84356678Seric /* extend binding and continue */ 84458825Seric mlp->last = avp++; 84556678Seric rvp++; 84658825Seric mlp++; 84756678Seric break; 8484468Seric } 84958825Seric if ((*rp & 0377) == MATCHCLASS) 85056678Seric { 85158814Seric /* extend binding and try again */ 85263397Seric mlp->last = avp; 85358814Seric goto extendclass; 85458814Seric } 8553149Seric } 8563149Seric 85758825Seric if (mlp < mlist) 85856678Seric { 85956678Seric /* total failure to match */ 86056326Seric break; 8613149Seric } 862297Seric } 8633149Seric 8643149Seric /* 86556678Seric ** See if we successfully matched 8663149Seric */ 8673149Seric 86858827Seric if (mlp < mlist || *rvp != NULL) 8693149Seric { 8709374Seric if (tTd(21, 10)) 8719374Seric printf("----- rule fails\n"); 8729374Seric rwr = rwr->r_next; 87358866Seric ruleno++; 87464740Seric loopcount = 0; 8759374Seric continue; 8769374Seric } 8773149Seric 8789374Seric rvp = rwr->r_rhs; 8799374Seric if (tTd(21, 12)) 8809374Seric { 8819374Seric printf("-----rule matches:"); 88256678Seric printav(rvp); 8839374Seric } 8849374Seric 8859374Seric rp = *rvp; 88658050Seric if ((*rp & 0377) == CANONUSER) 8879374Seric { 8889374Seric rvp++; 8899374Seric rwr = rwr->r_next; 89058866Seric ruleno++; 89164740Seric loopcount = 0; 8929374Seric } 89358050Seric else if ((*rp & 0377) == CANONHOST) 8949374Seric { 8959374Seric rvp++; 8969374Seric rwr = NULL; 8979374Seric } 89858050Seric else if ((*rp & 0377) == CANONNET) 8999374Seric rwr = NULL; 9009374Seric 9019374Seric /* substitute */ 9029374Seric for (avp = npvp; *rvp != NULL; rvp++) 9039374Seric { 9049374Seric register struct match *m; 9059374Seric register char **pp; 9069374Seric 9078058Seric rp = *rvp; 90858050Seric if ((*rp & 0377) == MATCHREPL) 9098058Seric { 91016914Seric /* substitute from LHS */ 91116914Seric m = &mlist[rp[1] - '1']; 91256678Seric if (m < mlist || m >= mlp) 9139374Seric { 91458151Seric syserr("554 rewrite: ruleset %d: replacement $%c out of bounds", 91556326Seric ruleset, rp[1]); 91659084Seric return EX_CONFIG; 9179374Seric } 91816914Seric if (tTd(21, 15)) 91916914Seric { 92016914Seric printf("$%c:", rp[1]); 92116914Seric pp = m->first; 92256678Seric while (pp <= m->last) 92316914Seric { 92416914Seric printf(" %x=\"", *pp); 92516914Seric (void) fflush(stdout); 92616914Seric printf("%s\"", *pp++); 92716914Seric } 92816914Seric printf("\n"); 92916914Seric } 9309374Seric pp = m->first; 93156678Seric while (pp <= m->last) 9323149Seric { 93316914Seric if (avp >= &npvp[MAXATOM]) 93456678Seric { 93558151Seric syserr("554 rewrite: expansion too long"); 93659084Seric return EX_DATAERR; 93756678Seric } 93816914Seric *avp++ = *pp++; 9393149Seric } 9403149Seric } 94116914Seric else 9428226Seric { 94316914Seric /* vanilla replacement */ 9449374Seric if (avp >= &npvp[MAXATOM]) 94516889Seric { 94656678Seric toolong: 94758151Seric syserr("554 rewrite: expansion too long"); 94859084Seric return EX_DATAERR; 94916889Seric } 95059027Seric if ((*rp & 0377) != MACRODEXPAND) 95159027Seric *avp++ = rp; 95259027Seric else 95359027Seric { 95459027Seric *avp = macvalue(rp[1], e); 95559027Seric if (tTd(21, 2)) 95659027Seric printf("rewrite: RHS $&%c => \"%s\"\n", 95759027Seric rp[1], 95859027Seric *avp == NULL ? "(NULL)" : *avp); 95959027Seric if (*avp != NULL) 96059027Seric avp++; 96159027Seric } 9628226Seric } 9639374Seric } 9649374Seric *avp++ = NULL; 96516914Seric 96616914Seric /* 96756678Seric ** Check for any hostname/keyword lookups. 96816914Seric */ 96916914Seric 97016914Seric for (rvp = npvp; *rvp != NULL; rvp++) 97116914Seric { 97256678Seric char **hbrvp; 97316914Seric char **xpvp; 97416914Seric int trsize; 97556678Seric char *replac; 97656678Seric int endtoken; 97756678Seric STAB *map; 97856678Seric char *mapname; 97956678Seric char **key_rvp; 98056678Seric char **arg_rvp; 98156678Seric char **default_rvp; 98256678Seric char buf[MAXNAME + 1]; 98316914Seric char *pvpb1[MAXATOM + 1]; 98456823Seric char *argvect[10]; 98517174Seric char pvpbuf[PSBUFSIZE]; 98664404Seric char *nullpvp[1]; 98716914Seric 98858050Seric if ((**rvp & 0377) != HOSTBEGIN && 98958050Seric (**rvp & 0377) != LOOKUPBEGIN) 99016914Seric continue; 99116914Seric 99216914Seric /* 99356678Seric ** Got a hostname/keyword lookup. 99416914Seric ** 99516914Seric ** This could be optimized fairly easily. 99616914Seric */ 99716914Seric 99816914Seric hbrvp = rvp; 99958050Seric if ((**rvp & 0377) == HOSTBEGIN) 100056327Seric { 100156678Seric endtoken = HOSTEND; 100256678Seric mapname = "host"; 100356327Seric } 100456326Seric else 100556327Seric { 100656678Seric endtoken = LOOKUPEND; 100756678Seric mapname = *++rvp; 100856327Seric } 100956678Seric map = stab(mapname, ST_MAP, ST_FIND); 101056678Seric if (map == NULL) 101158151Seric syserr("554 rewrite: map %s not found", mapname); 101256678Seric 101356678Seric /* extract the match part */ 101456678Seric key_rvp = ++rvp; 101556823Seric default_rvp = NULL; 101656823Seric arg_rvp = argvect; 101756823Seric xpvp = NULL; 101856823Seric replac = pvpbuf; 101958050Seric while (*rvp != NULL && (**rvp & 0377) != endtoken) 102053654Seric { 102158050Seric int nodetype = **rvp & 0377; 102256823Seric 102356823Seric if (nodetype != CANONHOST && nodetype != CANONUSER) 102456678Seric { 102556823Seric rvp++; 102656823Seric continue; 102756823Seric } 102856823Seric 102956823Seric *rvp++ = NULL; 103056823Seric 103156823Seric if (xpvp != NULL) 103256823Seric { 103358814Seric cataddr(xpvp, NULL, replac, 103458082Seric &pvpbuf[sizeof pvpbuf] - replac, 103558082Seric '\0'); 103656823Seric *++arg_rvp = replac; 103756823Seric replac += strlen(replac) + 1; 103856823Seric xpvp = NULL; 103956823Seric } 104056823Seric switch (nodetype) 104156823Seric { 104256678Seric case CANONHOST: 104356823Seric xpvp = rvp; 104456678Seric break; 104556678Seric 104656678Seric case CANONUSER: 104756678Seric default_rvp = rvp; 104856678Seric break; 104956678Seric } 105053654Seric } 105116914Seric if (*rvp != NULL) 105216914Seric *rvp++ = NULL; 105356823Seric if (xpvp != NULL) 105456823Seric { 105558814Seric cataddr(xpvp, NULL, replac, 105658082Seric &pvpbuf[sizeof pvpbuf] - replac, 105758082Seric '\0'); 105856823Seric *++arg_rvp = replac; 105956823Seric } 106056823Seric *++arg_rvp = NULL; 106116914Seric 106216914Seric /* save the remainder of the input string */ 106316914Seric trsize = (int) (avp - rvp + 1) * sizeof *rvp; 106416914Seric bcopy((char *) rvp, (char *) pvpb1, trsize); 106516914Seric 106656678Seric /* look it up */ 106758814Seric cataddr(key_rvp, NULL, buf, sizeof buf, '\0'); 106856823Seric argvect[0] = buf; 106960538Seric if (map != NULL && bitset(MF_OPEN, map->s_map.map_mflags)) 107056836Seric { 107159084Seric auto int stat = EX_OK; 107256836Seric 107360215Seric /* XXX should try to auto-open the map here */ 107460215Seric 107558796Seric if (tTd(60, 1)) 107658796Seric printf("map_lookup(%s, %s) => ", 107758796Seric mapname, buf); 107856836Seric replac = (*map->s_map.map_class->map_lookup)(&map->s_map, 107960089Seric buf, argvect, &stat); 108058796Seric if (tTd(60, 1)) 108159084Seric printf("%s (%d)\n", 108259084Seric replac ? replac : "NOT FOUND", 108359084Seric stat); 108459084Seric 108559084Seric /* should recover if stat == EX_TEMPFAIL */ 108659084Seric if (stat == EX_TEMPFAIL) 108759084Seric rstat = stat; 108856836Seric } 108953654Seric else 109056678Seric replac = NULL; 109156678Seric 109256678Seric /* if no replacement, use default */ 109356823Seric if (replac == NULL && default_rvp != NULL) 109456823Seric { 109560089Seric /* create the default */ 109660089Seric cataddr(default_rvp, NULL, buf, sizeof buf, '\0'); 109756823Seric replac = buf; 109856823Seric } 109956823Seric 110056678Seric if (replac == NULL) 110151317Seric { 110256823Seric xpvp = key_rvp; 110353654Seric } 110464404Seric else if (*replac == '\0') 110564404Seric { 110664404Seric /* null replacement */ 110764404Seric nullpvp[0] = NULL; 110864404Seric xpvp = nullpvp; 110964404Seric } 111056678Seric else 111153654Seric { 111256678Seric /* scan the new replacement */ 111358333Seric xpvp = prescan(replac, '\0', pvpbuf, NULL); 111453654Seric if (xpvp == NULL) 111551317Seric { 111658403Seric /* prescan already printed error */ 111759084Seric return EX_DATAERR; 111856678Seric } 111951317Seric } 112051317Seric 112116914Seric /* append it to the token list */ 112256678Seric for (avp = hbrvp; *xpvp != NULL; xpvp++) 112356678Seric { 112417174Seric *avp++ = newstr(*xpvp); 112516920Seric if (avp >= &npvp[MAXATOM]) 112616914Seric goto toolong; 112717174Seric } 112816914Seric 112916914Seric /* restore the old trailing information */ 113056678Seric for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) 113116920Seric if (avp >= &npvp[MAXATOM]) 113216914Seric goto toolong; 113317174Seric 113456678Seric break; 113516914Seric } 113616914Seric 113716914Seric /* 113816914Seric ** Check for subroutine calls. 113916914Seric */ 114016914Seric 114158050Seric if (*npvp != NULL && (**npvp & 0377) == CALLSUBR) 114256678Seric { 114359084Seric int stat; 114459084Seric 114556678Seric bcopy((char *) &npvp[2], (char *) pvp, 114656678Seric (int) (avp - npvp - 2) * sizeof *avp); 114756678Seric if (tTd(21, 3)) 114856678Seric printf("-----callsubr %s\n", npvp[1]); 114959084Seric stat = rewrite(pvp, atoi(npvp[1]), e); 115059084Seric if (rstat == EX_OK || stat == EX_TEMPFAIL) 115159084Seric rstat = stat; 115263581Seric if ((**pvp & 0377) == CANONNET) 115363581Seric rwr = NULL; 115456678Seric } 115556678Seric else 115656678Seric { 115717348Seric bcopy((char *) npvp, (char *) pvp, 115816900Seric (int) (avp - npvp) * sizeof *avp); 115956678Seric } 11609374Seric if (tTd(21, 4)) 11619374Seric { 11629374Seric printf("rewritten as:"); 116356678Seric printav(pvp); 11649374Seric } 1165297Seric } 11668069Seric 11679279Seric if (OpMode == MD_TEST || tTd(21, 2)) 11688069Seric { 11698959Seric printf("rewrite: ruleset %2d returns:", ruleset); 117056678Seric printav(pvp); 11718069Seric } 117259084Seric 117359084Seric return rstat; 11743149Seric } 11753149Seric /* 11763149Seric ** BUILDADDR -- build address from token vector. 11773149Seric ** 11783149Seric ** Parameters: 11793149Seric ** tv -- token vector. 11803149Seric ** a -- pointer to address descriptor to fill. 11813149Seric ** If NULL, one will be allocated. 118264284Seric ** flags -- info regarding whether this is a sender or 118364284Seric ** a recipient. 118458966Seric ** e -- the current envelope. 11853149Seric ** 11863149Seric ** Returns: 11874279Seric ** NULL if there was an error. 11884279Seric ** 'a' otherwise. 11893149Seric ** 11903149Seric ** Side Effects: 11913149Seric ** fills in 'a' 11923149Seric */ 11933149Seric 119457249Seric struct errcodes 119557249Seric { 119657249Seric char *ec_name; /* name of error code */ 119757249Seric int ec_code; /* numeric code */ 119857249Seric } ErrorCodes[] = 119957249Seric { 120057249Seric "usage", EX_USAGE, 120157249Seric "nouser", EX_NOUSER, 120257249Seric "nohost", EX_NOHOST, 120357249Seric "unavailable", EX_UNAVAILABLE, 120457249Seric "software", EX_SOFTWARE, 120557249Seric "tempfail", EX_TEMPFAIL, 120657249Seric "protocol", EX_PROTOCOL, 120757249Seric #ifdef EX_CONFIG 120857249Seric "config", EX_CONFIG, 120957249Seric #endif 121057249Seric NULL, EX_UNAVAILABLE, 121157249Seric }; 121257249Seric 121356678Seric ADDRESS * 121464284Seric buildaddr(tv, a, flags, e) 12153149Seric register char **tv; 12163149Seric register ADDRESS *a; 121764284Seric int flags; 121858966Seric register ENVELOPE *e; 12193149Seric { 12203149Seric struct mailer **mp; 12213149Seric register struct mailer *m; 122258008Seric char *bp; 122358008Seric int spaceleft; 122464306Seric static MAILER errormailer; 122564306Seric static char *errorargv[] = { "ERROR", NULL }; 122657402Seric static char buf[MAXNAME]; 12273149Seric 122864791Seric if (tTd(24, 5)) 122964791Seric { 123064791Seric printf("buildaddr, flags=%o, tv=", flags); 123164791Seric printav(tv); 123264791Seric } 123364791Seric 12343149Seric if (a == NULL) 12353149Seric a = (ADDRESS *) xalloc(sizeof *a); 123616889Seric bzero((char *) a, sizeof *a); 12373149Seric 12383149Seric /* figure out what net/mailer to use */ 123964306Seric if (*tv == NULL || (**tv & 0377) != CANONNET) 12404279Seric { 124158151Seric syserr("554 buildaddr: no net"); 124264306Seric badaddr: 124364306Seric a->q_flags |= QBADADDR; 124464306Seric a->q_mailer = &errormailer; 124564306Seric if (errormailer.m_name == NULL) 124664306Seric { 124764306Seric /* initialize the bogus mailer */ 124864306Seric errormailer.m_name = "*error*"; 124964306Seric errormailer.m_mailer = "ERROR"; 125064306Seric errormailer.m_argv = errorargv; 125164306Seric } 125264306Seric return a; 12534279Seric } 12543149Seric tv++; 125558680Seric if (strcasecmp(*tv, "error") == 0) 12564279Seric { 125758050Seric if ((**++tv & 0377) == CANONHOST) 125810183Seric { 125957249Seric register struct errcodes *ep; 126057249Seric 126158050Seric if (isascii(**++tv) && isdigit(**tv)) 126257249Seric { 126357249Seric setstat(atoi(*tv)); 126457249Seric } 126557249Seric else 126657249Seric { 126757249Seric for (ep = ErrorCodes; ep->ec_name != NULL; ep++) 126857249Seric if (strcasecmp(ep->ec_name, *tv) == 0) 126957249Seric break; 127057249Seric setstat(ep->ec_code); 127157249Seric } 127210183Seric tv++; 127310183Seric } 127464928Seric else 127564928Seric setstat(EX_UNAVAILABLE); 127658050Seric if ((**tv & 0377) != CANONUSER) 127758151Seric syserr("554 buildaddr: error: no user"); 127858814Seric cataddr(++tv, NULL, buf, sizeof buf, ' '); 127958082Seric stripquotes(buf); 128064659Seric if (isascii(buf[0]) && isdigit(buf[0]) && 128164659Seric isascii(buf[1]) && isdigit(buf[1]) && 128264659Seric isascii(buf[2]) && isdigit(buf[2]) && 128364659Seric buf[3] == ' ') 128464659Seric { 128564659Seric char fmt[10]; 128664659Seric 128764659Seric strncpy(fmt, buf, 3); 128864659Seric strcpy(&fmt[3], " %s"); 128964659Seric usrerr(fmt, buf + 4); 129064659Seric } 129164659Seric else 129264659Seric { 129364659Seric usrerr("%s", buf); 129464659Seric } 129564306Seric goto badaddr; 12964279Seric } 129757402Seric 12984598Seric for (mp = Mailer; (m = *mp++) != NULL; ) 12993149Seric { 130058680Seric if (strcasecmp(m->m_name, *tv) == 0) 13013149Seric break; 13023149Seric } 13033149Seric if (m == NULL) 13044279Seric { 130558151Seric syserr("554 buildaddr: unknown mailer %s", *tv); 130664306Seric goto badaddr; 13074279Seric } 13084598Seric a->q_mailer = m; 13093149Seric 13103149Seric /* figure out what host (if any) */ 131156678Seric tv++; 131258509Seric if ((**tv & 0377) == CANONHOST) 13133149Seric { 131458008Seric bp = buf; 131558008Seric spaceleft = sizeof buf - 1; 131658050Seric while (*++tv != NULL && (**tv & 0377) != CANONUSER) 131758008Seric { 131858008Seric int i = strlen(*tv); 131958008Seric 132058008Seric if (i > spaceleft) 132158008Seric { 132258008Seric /* out of space for this address */ 132358008Seric if (spaceleft >= 0) 132458151Seric syserr("554 buildaddr: host too long (%.40s...)", 132558008Seric buf); 132658008Seric i = spaceleft; 132758008Seric spaceleft = 0; 132858008Seric } 132958008Seric if (i <= 0) 133058008Seric continue; 133158008Seric bcopy(*tv, bp, i); 133258008Seric bp += i; 133358008Seric spaceleft -= i; 133458008Seric } 133558010Seric *bp = '\0'; 13365704Seric a->q_host = newstr(buf); 13373149Seric } 133857249Seric else 133958509Seric { 134058509Seric if (!bitnset(M_LOCALMAILER, m->m_flags)) 134158509Seric { 134258509Seric syserr("554 buildaddr: no host"); 134364306Seric goto badaddr; 134458509Seric } 134557249Seric a->q_host = NULL; 134658509Seric } 13473149Seric 13483149Seric /* figure out the user */ 134958050Seric if (*tv == NULL || (**tv & 0377) != CANONUSER) 13504279Seric { 135158151Seric syserr("554 buildaddr: no user"); 135264306Seric goto badaddr; 13534279Seric } 135457402Seric tv++; 135551317Seric 135657402Seric /* do special mapping for local mailer */ 135757402Seric if (m == LocalMailer && *tv != NULL) 135857402Seric { 135957454Seric register char *p = *tv; 136057454Seric 136157454Seric if (*p == '"') 136257454Seric p++; 136357454Seric if (*p == '|') 136457402Seric a->q_mailer = m = ProgMailer; 136557454Seric else if (*p == '/') 136657402Seric a->q_mailer = m = FileMailer; 136757454Seric else if (*p == ':') 136857402Seric { 136957402Seric /* may be :include: */ 137058814Seric cataddr(tv, NULL, buf, sizeof buf, '\0'); 137158008Seric stripquotes(buf); 137258008Seric if (strncasecmp(buf, ":include:", 9) == 0) 137358008Seric { 137458008Seric /* if :include:, don't need further rewriting */ 137557402Seric a->q_mailer = m = InclMailer; 137658008Seric a->q_user = &buf[9]; 137758008Seric return (a); 137858008Seric } 137957402Seric } 138057402Seric } 138157402Seric 138258008Seric if (m == LocalMailer && *tv != NULL && strcmp(*tv, "@") == 0) 138358008Seric { 138458008Seric tv++; 138558008Seric a->q_flags |= QNOTREMOTE; 138658008Seric } 138758008Seric 138864284Seric /* rewrite according recipient mailer rewriting rules */ 138964284Seric define('h', a->q_host, e); 139064284Seric if (!bitset(RF_SENDERADDR|RF_HEADERADDR, flags)) 139164284Seric { 139264284Seric /* sender addresses done later */ 139364284Seric (void) rewrite(tv, 2, e); 139464284Seric if (m->m_re_rwset > 0) 139564284Seric (void) rewrite(tv, m->m_re_rwset, e); 139664284Seric } 139759084Seric (void) rewrite(tv, 4, e); 139819040Seric 139919040Seric /* save the result for the command line/RCPT argument */ 140058814Seric cataddr(tv, NULL, buf, sizeof buf, '\0'); 14013149Seric a->q_user = buf; 14023149Seric 140358670Seric /* 140458670Seric ** Do mapping to lower case as requested by mailer 140558670Seric */ 140658670Seric 140758670Seric if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags)) 140858670Seric makelower(a->q_host); 140958670Seric if (!bitnset(M_USR_UPPER, m->m_flags)) 141058670Seric makelower(a->q_user); 141158670Seric 14123149Seric return (a); 14133149Seric } 14143188Seric /* 14154228Seric ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 14164228Seric ** 14174228Seric ** Parameters: 14184228Seric ** pvp -- parameter vector to rebuild. 141958814Seric ** evp -- last parameter to include. Can be NULL to 142058814Seric ** use entire pvp. 14214228Seric ** buf -- buffer to build the string into. 14224228Seric ** sz -- size of buf. 142358082Seric ** spacesub -- the space separator character; if null, 142458082Seric ** use SpaceSub. 14254228Seric ** 14264228Seric ** Returns: 14274228Seric ** none. 14284228Seric ** 14294228Seric ** Side Effects: 14304228Seric ** Destroys buf. 14314228Seric */ 14324228Seric 143358814Seric cataddr(pvp, evp, buf, sz, spacesub) 14344228Seric char **pvp; 143558814Seric char **evp; 14364228Seric char *buf; 14374228Seric register int sz; 143858082Seric char spacesub; 14394228Seric { 14404228Seric bool oatomtok = FALSE; 144156678Seric bool natomtok = FALSE; 14424228Seric register int i; 14434228Seric register char *p; 14444228Seric 144558082Seric if (spacesub == '\0') 144658082Seric spacesub = SpaceSub; 144758082Seric 14488423Seric if (pvp == NULL) 14498423Seric { 145023109Seric (void) strcpy(buf, ""); 14518423Seric return; 14528423Seric } 14534228Seric p = buf; 145411156Seric sz -= 2; 14554228Seric while (*pvp != NULL && (i = strlen(*pvp)) < sz) 14564228Seric { 14578078Seric natomtok = (toktype(**pvp) == ATM); 14584228Seric if (oatomtok && natomtok) 145958082Seric *p++ = spacesub; 14604228Seric (void) strcpy(p, *pvp); 14614228Seric oatomtok = natomtok; 14624228Seric p += i; 146311156Seric sz -= i + 1; 146458814Seric if (pvp++ == evp) 146558814Seric break; 14664228Seric } 14674228Seric *p = '\0'; 14684228Seric } 14694228Seric /* 14703188Seric ** SAMEADDR -- Determine if two addresses are the same 14713188Seric ** 14723188Seric ** This is not just a straight comparison -- if the mailer doesn't 14733188Seric ** care about the host we just ignore it, etc. 14743188Seric ** 14753188Seric ** Parameters: 14763188Seric ** a, b -- pointers to the internal forms to compare. 14773188Seric ** 14783188Seric ** Returns: 14793188Seric ** TRUE -- they represent the same mailbox. 14803188Seric ** FALSE -- they don't. 14813188Seric ** 14823188Seric ** Side Effects: 14833188Seric ** none. 14843188Seric */ 14853188Seric 14863188Seric bool 14879374Seric sameaddr(a, b) 14883188Seric register ADDRESS *a; 14893188Seric register ADDRESS *b; 14903188Seric { 14913188Seric /* if they don't have the same mailer, forget it */ 14923188Seric if (a->q_mailer != b->q_mailer) 14933188Seric return (FALSE); 14943188Seric 14953188Seric /* if the user isn't the same, we can drop out */ 149656678Seric if (strcmp(a->q_user, b->q_user) != 0) 14973188Seric return (FALSE); 14983188Seric 149958438Seric /* if we have good uids for both but the differ, these are different */ 150058438Seric if (bitset(QGOODUID, a->q_flags & b->q_flags) && a->q_uid != b->q_uid) 150158438Seric return (FALSE); 150258438Seric 150358509Seric /* otherwise compare hosts (but be careful for NULL ptrs) */ 150458509Seric if (a->q_host == b->q_host) 150558509Seric { 150658509Seric /* probably both null pointers */ 15073188Seric return (TRUE); 150858509Seric } 15093188Seric if (a->q_host == NULL || b->q_host == NULL) 151058509Seric { 151158509Seric /* only one is a null pointer */ 15123188Seric return (FALSE); 151358509Seric } 151456678Seric if (strcmp(a->q_host, b->q_host) != 0) 15153188Seric return (FALSE); 15163188Seric 15173188Seric return (TRUE); 15183188Seric } 15193234Seric /* 15203234Seric ** PRINTADDR -- print address (for debugging) 15213234Seric ** 15223234Seric ** Parameters: 15233234Seric ** a -- the address to print 15243234Seric ** follow -- follow the q_next chain. 15253234Seric ** 15263234Seric ** Returns: 15273234Seric ** none. 15283234Seric ** 15293234Seric ** Side Effects: 15303234Seric ** none. 15313234Seric */ 15323234Seric 15333234Seric printaddr(a, follow) 15343234Seric register ADDRESS *a; 15353234Seric bool follow; 15363234Seric { 15375001Seric bool first = TRUE; 153857731Seric register MAILER *m; 153957731Seric MAILER pseudomailer; 15405001Seric 15413234Seric while (a != NULL) 15423234Seric { 15435001Seric first = FALSE; 15444443Seric printf("%x=", a); 15454085Seric (void) fflush(stdout); 154657731Seric 154757731Seric /* find the mailer -- carefully */ 154857731Seric m = a->q_mailer; 154957731Seric if (m == NULL) 155057731Seric { 155157731Seric m = &pseudomailer; 155257731Seric m->m_mno = -1; 155357731Seric m->m_name = "NULL"; 155457731Seric } 155557731Seric 155658680Seric printf("%s:\n\tmailer %d (%s), host `%s', user `%s', ruser `%s'\n", 155757731Seric a->q_paddr, m->m_mno, m->m_name, 155863756Seric a->q_host, a->q_user, 155963756Seric a->q_ruser ? a->q_ruser : "<null>"); 156059269Seric printf("\tnext=%x, flags=%o, alias %x, uid %d, gid %d\n", 156159269Seric a->q_next, a->q_flags, a->q_alias, a->q_uid, a->q_gid); 156259269Seric printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n", 156359269Seric a->q_owner == NULL ? "(none)" : a->q_owner, 156463756Seric a->q_home == NULL ? "(none)" : a->q_home, 156563756Seric a->q_fullname == NULL ? "(none)" : a->q_fullname); 15664996Seric 15673234Seric if (!follow) 15683234Seric return; 15694996Seric a = a->q_next; 15703234Seric } 15715001Seric if (first) 15724443Seric printf("[NULL]\n"); 15733234Seric } 15744317Seric 15757682Seric /* 15767682Seric ** REMOTENAME -- return the name relative to the current mailer 15777682Seric ** 15787682Seric ** Parameters: 15797682Seric ** name -- the name to translate. 15808069Seric ** m -- the mailer that we want to do rewriting relative 15818069Seric ** to. 158259163Seric ** flags -- fine tune operations. 158359163Seric ** pstat -- pointer to status word. 158458020Seric ** e -- the current envelope. 15857682Seric ** 15867682Seric ** Returns: 15877682Seric ** the text string representing this address relative to 15887682Seric ** the receiving mailer. 15897682Seric ** 15907682Seric ** Side Effects: 15917682Seric ** none. 15927682Seric ** 15937682Seric ** Warnings: 15947682Seric ** The text string returned is tucked away locally; 15957682Seric ** copy it if you intend to save it. 15967682Seric */ 15977682Seric 15987682Seric char * 159959163Seric remotename(name, m, flags, pstat, e) 16007682Seric char *name; 160156678Seric struct mailer *m; 160259163Seric int flags; 160359163Seric int *pstat; 160456678Seric register ENVELOPE *e; 16057682Seric { 16068069Seric register char **pvp; 16078069Seric char *fancy; 160856678Seric char *oldg = macvalue('g', e); 160958020Seric int rwset; 16107682Seric static char buf[MAXNAME]; 16117682Seric char lbuf[MAXNAME]; 161216914Seric char pvpbuf[PSBUFSIZE]; 161356678Seric extern char *crackaddr(); 16147682Seric 16157755Seric if (tTd(12, 1)) 16167755Seric printf("remotename(%s)\n", name); 16177755Seric 161810177Seric /* don't do anything if we are tagging it as special */ 161959163Seric if (bitset(RF_SENDERADDR, flags)) 162059163Seric rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset 162159163Seric : m->m_se_rwset; 162258020Seric else 162359163Seric rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset 162459163Seric : m->m_re_rwset; 162558020Seric if (rwset < 0) 162610177Seric return (name); 162710177Seric 16287682Seric /* 16298181Seric ** Do a heuristic crack of this name to extract any comment info. 16308181Seric ** This will leave the name as a comment and a $g macro. 16317889Seric */ 16327889Seric 163359163Seric if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) 163458050Seric fancy = "\201g"; 163510310Seric else 163610310Seric fancy = crackaddr(name); 16377889Seric 16388181Seric /* 16398181Seric ** Turn the name into canonical form. 16408181Seric ** Normally this will be RFC 822 style, i.e., "user@domain". 16418181Seric ** If this only resolves to "user", and the "C" flag is 16428181Seric ** specified in the sending mailer, then the sender's 16438181Seric ** domain will be appended. 16448181Seric */ 16458181Seric 164658333Seric pvp = prescan(name, '\0', pvpbuf, NULL); 16477889Seric if (pvp == NULL) 16487889Seric return (name); 164959163Seric if (rewrite(pvp, 3, e) == EX_TEMPFAIL) 165059163Seric *pstat = EX_TEMPFAIL; 165159163Seric if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) 16528181Seric { 16538181Seric /* append from domain to this address */ 16548181Seric register char **pxp = pvp; 16558181Seric 16569594Seric /* see if there is an "@domain" in the current name */ 16578181Seric while (*pxp != NULL && strcmp(*pxp, "@") != 0) 16588181Seric pxp++; 16598181Seric if (*pxp == NULL) 16608181Seric { 16619594Seric /* no.... append the "@domain" from the sender */ 166256678Seric register char **qxq = e->e_fromdomain; 16638181Seric 16649594Seric while ((*pxp++ = *qxq++) != NULL) 16659594Seric continue; 166659163Seric if (rewrite(pvp, 3, e) == EX_TEMPFAIL) 166759163Seric *pstat = EX_TEMPFAIL; 16688181Seric } 16698181Seric } 16708181Seric 16718181Seric /* 16728959Seric ** Do more specific rewriting. 167356678Seric ** Rewrite using ruleset 1 or 2 depending on whether this is 167456678Seric ** a sender address or not. 16758181Seric ** Then run it through any receiving-mailer-specific rulesets. 16768181Seric */ 16778181Seric 167859163Seric if (bitset(RF_SENDERADDR, flags)) 167959541Seric { 168059163Seric if (rewrite(pvp, 1, e) == EX_TEMPFAIL) 168159163Seric *pstat = EX_TEMPFAIL; 168259541Seric } 16838069Seric else 168459541Seric { 168559163Seric if (rewrite(pvp, 2, e) == EX_TEMPFAIL) 168659163Seric *pstat = EX_TEMPFAIL; 168759541Seric } 168858020Seric if (rwset > 0) 168959541Seric { 169059163Seric if (rewrite(pvp, rwset, e) == EX_TEMPFAIL) 169159163Seric *pstat = EX_TEMPFAIL; 169259541Seric } 16937682Seric 16948181Seric /* 16958959Seric ** Do any final sanitation the address may require. 16968959Seric ** This will normally be used to turn internal forms 16978959Seric ** (e.g., user@host.LOCAL) into external form. This 16988959Seric ** may be used as a default to the above rules. 16998959Seric */ 17008959Seric 170159163Seric if (rewrite(pvp, 4, e) == EX_TEMPFAIL) 170259163Seric *pstat = EX_TEMPFAIL; 17038959Seric 17048959Seric /* 17058181Seric ** Now restore the comment information we had at the beginning. 17068181Seric */ 17078181Seric 170858825Seric cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0'); 170956678Seric define('g', lbuf, e); 171056678Seric expand(fancy, buf, &buf[sizeof buf - 1], e); 171156678Seric define('g', oldg, e); 17127682Seric 17137682Seric if (tTd(12, 1)) 17147755Seric printf("remotename => `%s'\n", buf); 17157682Seric return (buf); 17167682Seric } 171751317Seric /* 171856678Seric ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 171951317Seric ** 172051317Seric ** Parameters: 172156678Seric ** a -- the address to map (but just the user name part). 172256678Seric ** sendq -- the sendq in which to install any replacement 172356678Seric ** addresses. 172451317Seric ** 172551317Seric ** Returns: 172651317Seric ** none. 172751317Seric */ 172851317Seric 172956678Seric maplocaluser(a, sendq, e) 173056678Seric register ADDRESS *a; 173156678Seric ADDRESS **sendq; 173256678Seric ENVELOPE *e; 173351317Seric { 173456678Seric register char **pvp; 173556678Seric register ADDRESS *a1 = NULL; 173658333Seric auto char *delimptr; 173756678Seric char pvpbuf[PSBUFSIZE]; 173851317Seric 173956678Seric if (tTd(29, 1)) 174056678Seric { 174156678Seric printf("maplocaluser: "); 174256678Seric printaddr(a, FALSE); 174356678Seric } 174458333Seric pvp = prescan(a->q_user, '\0', pvpbuf, &delimptr); 174556678Seric if (pvp == NULL) 174656678Seric return; 174751317Seric 174859084Seric (void) rewrite(pvp, 5, e); 174958050Seric if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 175056678Seric return; 175151317Seric 175256678Seric /* if non-null, mailer destination specified -- has it changed? */ 175364284Seric a1 = buildaddr(pvp, NULL, 0, e); 175456678Seric if (a1 == NULL || sameaddr(a, a1)) 175556678Seric return; 175651317Seric 175756678Seric /* mark old address as dead; insert new address */ 175856678Seric a->q_flags |= QDONTSEND; 175957731Seric if (tTd(29, 5)) 176057731Seric { 176157731Seric printf("maplocaluser: QDONTSEND "); 176257731Seric printaddr(a, FALSE); 176357731Seric } 176456678Seric a1->q_alias = a; 176564348Seric allocaddr(a1, RF_COPYALL, NULL); 176656678Seric (void) recipient(a1, sendq, e); 176751317Seric } 176858802Seric /* 176958802Seric ** DEQUOTE_INIT -- initialize dequote map 177058802Seric ** 177158802Seric ** This is a no-op. 177258802Seric ** 177358802Seric ** Parameters: 177458802Seric ** map -- the internal map structure. 177558802Seric ** args -- arguments. 177658802Seric ** 177758802Seric ** Returns: 177858802Seric ** TRUE. 177958802Seric */ 178058802Seric 178158802Seric bool 178260219Seric dequote_init(map, args) 178358802Seric MAP *map; 178458802Seric char *args; 178558802Seric { 178658805Seric register char *p = args; 178758805Seric 178858805Seric for (;;) 178958805Seric { 179058805Seric while (isascii(*p) && isspace(*p)) 179158805Seric p++; 179258805Seric if (*p != '-') 179358805Seric break; 179458805Seric switch (*++p) 179558805Seric { 179658805Seric case 'a': 179758805Seric map->map_app = ++p; 179858805Seric break; 179958805Seric } 180058805Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 180158805Seric p++; 180258805Seric if (*p != '\0') 180358805Seric *p = '\0'; 180458805Seric } 180558805Seric if (map->map_app != NULL) 180658805Seric map->map_app = newstr(map->map_app); 180758805Seric 180858802Seric return TRUE; 180958802Seric } 181058802Seric /* 181158802Seric ** DEQUOTE_MAP -- unquote an address 181258802Seric ** 181358802Seric ** Parameters: 181458802Seric ** map -- the internal map structure (ignored). 181560089Seric ** name -- the name to dequote. 181658802Seric ** av -- arguments (ignored). 181759084Seric ** statp -- pointer to status out-parameter. 181858802Seric ** 181958802Seric ** Returns: 182058802Seric ** NULL -- if there were no quotes, or if the resulting 182158802Seric ** unquoted buffer would not be acceptable to prescan. 182258802Seric ** else -- The dequoted buffer. 182358802Seric */ 182458802Seric 182558802Seric char * 182660089Seric dequote_map(map, name, av, statp) 182758802Seric MAP *map; 182860089Seric char *name; 182958802Seric char **av; 183059084Seric int *statp; 183158802Seric { 183258802Seric register char *p; 183358802Seric register char *q; 183458802Seric register char c; 183558802Seric int anglecnt; 183658802Seric int cmntcnt; 183758802Seric int quotecnt; 183859089Seric int spacecnt; 183958802Seric bool quotemode; 184058802Seric bool bslashmode; 184158802Seric 184258802Seric anglecnt = 0; 184358802Seric cmntcnt = 0; 184458802Seric quotecnt = 0; 184559089Seric spacecnt = 0; 184658802Seric quotemode = FALSE; 184758802Seric bslashmode = FALSE; 184858802Seric 184960089Seric for (p = q = name; (c = *p++) != '\0'; ) 185058802Seric { 185158802Seric if (bslashmode) 185258802Seric { 185358802Seric bslashmode = FALSE; 185458802Seric *q++ = c; 185558802Seric continue; 185658802Seric } 185758802Seric 185858802Seric switch (c) 185958802Seric { 186058802Seric case '\\': 186158802Seric bslashmode = TRUE; 186258802Seric break; 186358802Seric 186458802Seric case '(': 186558802Seric cmntcnt++; 186658802Seric break; 186758802Seric 186858802Seric case ')': 186958802Seric if (cmntcnt-- <= 0) 187058802Seric return NULL; 187158802Seric break; 187259089Seric 187359089Seric case ' ': 187459089Seric spacecnt++; 187559089Seric break; 187658802Seric } 187758802Seric 187858802Seric if (cmntcnt > 0) 187958802Seric { 188058802Seric *q++ = c; 188158802Seric continue; 188258802Seric } 188358802Seric 188458802Seric switch (c) 188558802Seric { 188658802Seric case '"': 188758802Seric quotemode = !quotemode; 188858802Seric quotecnt++; 188958802Seric continue; 189058802Seric 189158802Seric case '<': 189258802Seric anglecnt++; 189358802Seric break; 189458802Seric 189558802Seric case '>': 189658802Seric if (anglecnt-- <= 0) 189758802Seric return NULL; 189858802Seric break; 189958802Seric } 190058802Seric *q++ = c; 190158802Seric } 190258802Seric 190358802Seric if (anglecnt != 0 || cmntcnt != 0 || bslashmode || 190459089Seric quotemode || quotecnt <= 0 || spacecnt != 0) 190558802Seric return NULL; 190658802Seric *q++ = '\0'; 190760089Seric return name; 190858802Seric } 1909