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*68603Seric static char sccsid[] = "@(#)parseaddr.c 8.61 (Berkeley) 03/27/95"; 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 8065066Seric pvp = prescan(addr, delim, pvpbuf, sizeof pvpbuf, delimptr); 813149Seric if (pvp == NULL) 8256729Seric { 8356729Seric if (tTd(20, 1)) 8456729Seric printf("parseaddr-->NULL\n"); 85297Seric return (NULL); 8656729Seric } 87297Seric 8864726Seric if (invalidaddr(addr, delim == '\0' ? NULL : *delimptr)) 8964726Seric { 9064726Seric if (tTd(20, 1)) 9164726Seric printf("parseaddr-->bad address\n"); 9264726Seric return NULL; 9364726Seric } 9464726Seric 95297Seric /* 9664348Seric ** Save addr if we are going to have to. 9764348Seric ** 9864348Seric ** We have to do this early because there is a chance that 9964348Seric ** the map lookups in the rewriting rules could clobber 10064348Seric ** static memory somewhere. 10164348Seric */ 10264348Seric 10364348Seric if (bitset(RF_COPYPADDR, flags) && addr != NULL) 10464348Seric { 10564348Seric char savec = **delimptr; 10664348Seric 10764348Seric if (savec != '\0') 10864348Seric **delimptr = '\0'; 10966794Seric e->e_to = addr = newstr(addr); 11064348Seric if (savec != '\0') 11164348Seric **delimptr = savec; 11264348Seric } 11364348Seric 11464348Seric /* 1153149Seric ** Apply rewriting rules. 1167889Seric ** Ruleset 0 does basic parsing. It must resolve. 117297Seric */ 118297Seric 11959084Seric queueup = FALSE; 12065071Seric if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 12159084Seric queueup = TRUE; 12265071Seric if (rewrite(pvp, 0, 0, e) == EX_TEMPFAIL) 12359084Seric queueup = TRUE; 124297Seric 125297Seric 126297Seric /* 1273149Seric ** Build canonical address from pvp. 128297Seric */ 129297Seric 13064284Seric a = buildaddr(pvp, a, flags, e); 131297Seric 132297Seric /* 1333149Seric ** Make local copies of the host & user and then 1343149Seric ** transport them out. 135297Seric */ 136297Seric 13764348Seric allocaddr(a, flags, addr); 13864306Seric if (bitset(QBADADDR, a->q_flags)) 13964306Seric return a; 14056678Seric 14156678Seric /* 14259084Seric ** If there was a parsing failure, mark it for queueing. 14359084Seric */ 14459084Seric 14559084Seric if (queueup) 14659595Seric { 14759734Seric char *msg = "Transient parse error -- message queued for future delivery"; 14859734Seric 14959595Seric if (tTd(20, 1)) 15059595Seric printf("parseaddr: queuing message\n"); 15159734Seric message(msg); 15259734Seric if (e->e_message == NULL) 15360009Seric e->e_message = newstr(msg); 15459084Seric a->q_flags |= QQUEUEUP; 15568358Seric a->q_status = "4.4.3"; 15659595Seric } 15759084Seric 15859084Seric /* 15956678Seric ** Compute return value. 16056678Seric */ 16156678Seric 16256678Seric if (tTd(20, 1)) 1638078Seric { 16456678Seric printf("parseaddr-->"); 16556678Seric printaddr(a, FALSE); 16656678Seric } 16756678Seric 16856678Seric return (a); 16956678Seric } 17056678Seric /* 17157388Seric ** INVALIDADDR -- check for address containing meta-characters 17257388Seric ** 17357388Seric ** Parameters: 17457388Seric ** addr -- the address to check. 17557388Seric ** 17657388Seric ** Returns: 17757388Seric ** TRUE -- if the address has any "wierd" characters 17857388Seric ** FALSE -- otherwise. 17957388Seric */ 18057388Seric 18157388Seric bool 18264726Seric invalidaddr(addr, delimptr) 18357388Seric register char *addr; 18464726Seric char *delimptr; 18557388Seric { 18668433Seric char savedelim = '\0'; 18764726Seric 18864726Seric if (delimptr != NULL) 18964764Seric { 19064726Seric savedelim = *delimptr; 19164764Seric if (savedelim != '\0') 19264764Seric *delimptr = '\0'; 19364764Seric } 19464726Seric #if 0 19564726Seric /* for testing.... */ 19664726Seric if (strcmp(addr, "INvalidADDR") == 0) 19757388Seric { 19864726Seric usrerr("553 INvalid ADDRess"); 19964764Seric goto addrfailure; 20057388Seric } 20164726Seric #endif 20264726Seric for (; *addr != '\0'; addr++) 20364726Seric { 20464726Seric if ((*addr & 0340) == 0200) 20564726Seric break; 20664726Seric } 20764726Seric if (*addr == '\0') 20864764Seric { 20968400Seric if (delimptr != NULL && savedelim != '\0') 21064764Seric *delimptr = savedelim; 21164726Seric return FALSE; 21264764Seric } 21364726Seric setstat(EX_USAGE); 21464726Seric usrerr("553 Address contained invalid control characters"); 21564764Seric addrfailure: 21668446Seric if (delimptr != NULL && savedelim != '\0') 21764764Seric *delimptr = savedelim; 21864726Seric return TRUE; 21957388Seric } 22057388Seric /* 22156678Seric ** ALLOCADDR -- do local allocations of address on demand. 22256678Seric ** 22356678Seric ** Also lowercases the host name if requested. 22456678Seric ** 22556678Seric ** Parameters: 22656678Seric ** a -- the address to reallocate. 22764284Seric ** flags -- the copy flag (see RF_ definitions in sendmail.h 22864284Seric ** for a description). 22956678Seric ** paddr -- the printname of the address. 23056678Seric ** 23156678Seric ** Returns: 23256678Seric ** none. 23356678Seric ** 23456678Seric ** Side Effects: 23556678Seric ** Copies portions of a into local buffers as requested. 23656678Seric */ 23756678Seric 23864348Seric allocaddr(a, flags, paddr) 23956678Seric register ADDRESS *a; 24064284Seric int flags; 24156678Seric char *paddr; 24256678Seric { 24358673Seric if (tTd(24, 4)) 24467693Seric printf("allocaddr(flags=%x, paddr=%s)\n", flags, paddr); 24558673Seric 24664348Seric a->q_paddr = paddr; 2478078Seric 24824944Seric if (a->q_user == NULL) 24924944Seric a->q_user = ""; 25024944Seric if (a->q_host == NULL) 25124944Seric a->q_host = ""; 25224944Seric 25364284Seric if (bitset(RF_COPYPARSE, flags)) 254297Seric { 25524944Seric a->q_host = newstr(a->q_host); 2563149Seric if (a->q_user != a->q_paddr) 2573149Seric a->q_user = newstr(a->q_user); 258297Seric } 259297Seric 26056678Seric if (a->q_paddr == NULL) 26156678Seric a->q_paddr = a->q_user; 262297Seric } 263297Seric /* 264297Seric ** PRESCAN -- Prescan name and make it canonical 265297Seric ** 2669374Seric ** Scans a name and turns it into a set of tokens. This process 2679374Seric ** deletes blanks and comments (in parentheses). 268297Seric ** 269297Seric ** This routine knows about quoted strings and angle brackets. 270297Seric ** 271297Seric ** There are certain subtleties to this routine. The one that 272297Seric ** comes to mind now is that backslashes on the ends of names 273297Seric ** are silently stripped off; this is intentional. The problem 274297Seric ** is that some versions of sndmsg (like at LBL) set the kill 275297Seric ** character to something other than @ when reading addresses; 276297Seric ** so people type "csvax.eric\@berkeley" -- which screws up the 277297Seric ** berknet mailer. 278297Seric ** 279297Seric ** Parameters: 280297Seric ** addr -- the name to chomp. 281297Seric ** delim -- the delimiter for the address, normally 282297Seric ** '\0' or ','; \0 is accepted in any case. 28315284Seric ** If '\t' then we are reading the .cf file. 28416914Seric ** pvpbuf -- place to put the saved text -- note that 28516914Seric ** the pointers are static. 28665066Seric ** pvpbsize -- size of pvpbuf. 28758333Seric ** delimptr -- if non-NULL, set to the location of the 28858333Seric ** terminating delimiter. 289297Seric ** 290297Seric ** Returns: 2913149Seric ** A pointer to a vector of tokens. 292297Seric ** NULL on error. 293297Seric */ 294297Seric 2958078Seric /* states and character types */ 2968078Seric # define OPR 0 /* operator */ 2978078Seric # define ATM 1 /* atom */ 2988078Seric # define QST 2 /* in quoted string */ 2998078Seric # define SPC 3 /* chewing up spaces */ 3008078Seric # define ONE 4 /* pick up one character */ 3013149Seric 3028078Seric # define NSTATES 5 /* number of states */ 3038078Seric # define TYPE 017 /* mask to select state type */ 3048078Seric 3058078Seric /* meta bits for table */ 3068078Seric # define M 020 /* meta character; don't pass through */ 3078078Seric # define B 040 /* cause a break */ 3088078Seric # define MB M|B /* meta-break */ 3098078Seric 3108078Seric static short StateTab[NSTATES][NSTATES] = 3118078Seric { 3128087Seric /* oldst chtype> OPR ATM QST SPC ONE */ 3139051Seric /*OPR*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, 3149051Seric /*ATM*/ OPR|B, ATM, QST|B, SPC|MB, ONE|B, 3159051Seric /*QST*/ QST, QST, OPR, QST, QST, 3168078Seric /*SPC*/ OPR, ATM, QST, SPC|M, ONE, 3178078Seric /*ONE*/ OPR, OPR, OPR, OPR, OPR, 3188078Seric }; 3198078Seric 32065092Seric /* token type table -- it gets modified with $o characters */ 32165092Seric static TokTypeTab[256] = 32265092Seric { 32365092Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM, 32465092Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 32565092Seric SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM,ATM,SPC,ATM,ATM,ATM,ATM,ATM,ATM, 32665092Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 32765092Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 32865092Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 32965092Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 33065092Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 33165092Seric OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 33265092Seric OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 33365092Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 33465092Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 33565092Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 33665092Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 33765092Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 33865092Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 33965092Seric }; 34065092Seric 34165092Seric #define toktype(c) ((int) TokTypeTab[(c) & 0xff]) 34265092Seric 34365092Seric 3448078Seric # define NOCHAR -1 /* signal nothing in lookahead token */ 3458078Seric 3463149Seric char ** 34765066Seric prescan(addr, delim, pvpbuf, pvpbsize, delimptr) 348297Seric char *addr; 34968353Seric int delim; 35016914Seric char pvpbuf[]; 35158333Seric char **delimptr; 352297Seric { 353297Seric register char *p; 3548078Seric register char *q; 3559346Seric register int c; 3563149Seric char **avp; 357297Seric bool bslashmode; 358297Seric int cmntcnt; 3598423Seric int anglecnt; 3603149Seric char *tok; 3618078Seric int state; 3628078Seric int newstate; 36359747Seric char *saveto = CurEnv->e_to; 3648078Seric static char *av[MAXATOM+1]; 36565092Seric static char firsttime = TRUE; 36656678Seric extern int errno; 367297Seric 36865092Seric if (firsttime) 36965092Seric { 37065092Seric /* initialize the token type table */ 37165092Seric char obuf[50]; 37265092Seric 37365092Seric firsttime = FALSE; 37468529Seric expand("\201o", obuf, sizeof obuf - sizeof DELIMCHARS, CurEnv); 37565092Seric strcat(obuf, DELIMCHARS); 37665092Seric for (p = obuf; *p != '\0'; p++) 37765092Seric { 37865092Seric if (TokTypeTab[*p & 0xff] == ATM) 37965092Seric TokTypeTab[*p & 0xff] = OPR; 38065092Seric } 38165092Seric } 38265092Seric 38315253Seric /* make sure error messages don't have garbage on them */ 38415253Seric errno = 0; 38515253Seric 38616914Seric q = pvpbuf; 3873149Seric bslashmode = FALSE; 3887800Seric cmntcnt = 0; 3898423Seric anglecnt = 0; 3903149Seric avp = av; 39156678Seric state = ATM; 3928078Seric c = NOCHAR; 3938078Seric p = addr; 39459747Seric CurEnv->e_to = p; 39556764Seric if (tTd(22, 11)) 396297Seric { 3978078Seric printf("prescan: "); 3988078Seric xputs(p); 39923109Seric (void) putchar('\n'); 4008078Seric } 4018078Seric 4028078Seric do 4038078Seric { 4043149Seric /* read a token */ 4053149Seric tok = q; 4068078Seric for (;;) 407297Seric { 4088078Seric /* store away any old lookahead character */ 40959277Seric if (c != NOCHAR && !bslashmode) 4108078Seric { 41115284Seric /* see if there is room */ 41265066Seric if (q >= &pvpbuf[pvpbsize - 5]) 4138078Seric { 41458151Seric usrerr("553 Address too long"); 41568526Seric if (strlen(addr) > MAXNAME) 41668526Seric addr[MAXNAME] = '\0'; 41765015Seric returnnull: 41858333Seric if (delimptr != NULL) 41958333Seric *delimptr = p; 42059747Seric CurEnv->e_to = saveto; 4218078Seric return (NULL); 4228078Seric } 42315284Seric 42415284Seric /* squirrel it away */ 4258078Seric *q++ = c; 4268078Seric } 4278078Seric 4288078Seric /* read a new input character */ 4298078Seric c = *p++; 43057631Seric if (c == '\0') 43156764Seric { 43256764Seric /* diagnose and patch up bad syntax */ 43356764Seric if (state == QST) 43456764Seric { 43564767Seric usrerr("653 Unbalanced '\"'"); 43656764Seric c = '"'; 43756764Seric } 43856764Seric else if (cmntcnt > 0) 43956764Seric { 44064767Seric usrerr("653 Unbalanced '('"); 44156764Seric c = ')'; 44256764Seric } 44356764Seric else if (anglecnt > 0) 44456764Seric { 44556764Seric c = '>'; 44664767Seric usrerr("653 Unbalanced '<'"); 44756764Seric } 44856764Seric else 44956764Seric break; 45015284Seric 45156764Seric p--; 45256764Seric } 45357631Seric else if (c == delim && anglecnt <= 0 && 45457631Seric cmntcnt <= 0 && state != QST) 45557631Seric break; 45656764Seric 4578078Seric if (tTd(22, 101)) 4588078Seric printf("c=%c, s=%d; ", c, state); 4598078Seric 4603149Seric /* chew up special characters */ 4613149Seric *q = '\0'; 4623149Seric if (bslashmode) 4633149Seric { 46459105Seric bslashmode = FALSE; 46559105Seric 46624944Seric /* kludge \! for naive users */ 46758061Seric if (cmntcnt > 0) 46859105Seric { 46958061Seric c = NOCHAR; 47059105Seric continue; 47159105Seric } 47259105Seric else if (c != '!' || state == QST) 47359105Seric { 47456678Seric *q++ = '\\'; 47559105Seric continue; 47659105Seric } 4773149Seric } 47856678Seric 47956678Seric if (c == '\\') 4803149Seric { 4813149Seric bslashmode = TRUE; 4823149Seric } 48356678Seric else if (state == QST) 4848514Seric { 4858514Seric /* do nothing, just avoid next clauses */ 4868514Seric } 4878078Seric else if (c == '(') 4884100Seric { 4898078Seric cmntcnt++; 4908078Seric c = NOCHAR; 4914100Seric } 4928078Seric else if (c == ')') 4933149Seric { 4948078Seric if (cmntcnt <= 0) 4953149Seric { 49664767Seric usrerr("653 Unbalanced ')'"); 49763844Seric c = NOCHAR; 4983149Seric } 4998078Seric else 5008078Seric cmntcnt--; 5018078Seric } 5028078Seric else if (cmntcnt > 0) 5038078Seric c = NOCHAR; 5048423Seric else if (c == '<') 5058423Seric anglecnt++; 5068423Seric else if (c == '>') 5078423Seric { 5088423Seric if (anglecnt <= 0) 5098423Seric { 51064767Seric usrerr("653 Unbalanced '>'"); 51163844Seric c = NOCHAR; 5128423Seric } 51363844Seric else 51463844Seric anglecnt--; 5158423Seric } 51658050Seric else if (delim == ' ' && isascii(c) && isspace(c)) 51711423Seric c = ' '; 5183149Seric 5198078Seric if (c == NOCHAR) 5208078Seric continue; 5213149Seric 5228078Seric /* see if this is end of input */ 52311405Seric if (c == delim && anglecnt <= 0 && state != QST) 5243149Seric break; 5253149Seric 5268078Seric newstate = StateTab[state][toktype(c)]; 5278078Seric if (tTd(22, 101)) 5288078Seric printf("ns=%02o\n", newstate); 5298078Seric state = newstate & TYPE; 5308078Seric if (bitset(M, newstate)) 5318078Seric c = NOCHAR; 5328078Seric if (bitset(B, newstate)) 5334228Seric break; 534297Seric } 5353149Seric 5363149Seric /* new token */ 5378078Seric if (tok != q) 5381378Seric { 5398078Seric *q++ = '\0'; 5408078Seric if (tTd(22, 36)) 541297Seric { 5428078Seric printf("tok="); 5438078Seric xputs(tok); 54423109Seric (void) putchar('\n'); 545297Seric } 5468078Seric if (avp >= &av[MAXATOM]) 547297Seric { 54858151Seric syserr("553 prescan: too many tokens"); 54965015Seric goto returnnull; 550297Seric } 55165015Seric if (q - tok > MAXNAME) 55265015Seric { 55365015Seric syserr("553 prescan: token too long"); 55465015Seric goto returnnull; 55565015Seric } 5568078Seric *avp++ = tok; 557297Seric } 5588423Seric } while (c != '\0' && (c != delim || anglecnt > 0)); 5593149Seric *avp = NULL; 56058333Seric p--; 56158333Seric if (delimptr != NULL) 56258333Seric *delimptr = p; 56356764Seric if (tTd(22, 12)) 56456764Seric { 56556764Seric printf("prescan==>"); 56656764Seric printav(av); 56756764Seric } 56859747Seric CurEnv->e_to = saveto; 56958546Seric if (av[0] == NULL) 57064966Seric { 57164966Seric if (tTd(22, 1)) 57264966Seric printf("prescan: null leading token\n"); 57358546Seric return (NULL); 57464966Seric } 57558403Seric return (av); 5763149Seric } 5773149Seric /* 5783149Seric ** REWRITE -- apply rewrite rules to token vector. 5793149Seric ** 5804476Seric ** This routine is an ordered production system. Each rewrite 5814476Seric ** rule has a LHS (called the pattern) and a RHS (called the 5824476Seric ** rewrite); 'rwr' points the the current rewrite rule. 5834476Seric ** 5844476Seric ** For each rewrite rule, 'avp' points the address vector we 5854476Seric ** are trying to match against, and 'pvp' points to the pattern. 5868058Seric ** If pvp points to a special match value (MATCHZANY, MATCHANY, 5879585Seric ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp 5889585Seric ** matched is saved away in the match vector (pointed to by 'mvp'). 5894476Seric ** 5904476Seric ** When a match between avp & pvp does not match, we try to 5919585Seric ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS 5924476Seric ** we must also back out the match in mvp. If we reach a 5938058Seric ** MATCHANY or MATCHZANY we just extend the match and start 5948058Seric ** over again. 5954476Seric ** 5964476Seric ** When we finally match, we rewrite the address vector 5974476Seric ** and try over again. 5984476Seric ** 5993149Seric ** Parameters: 6003149Seric ** pvp -- pointer to token vector. 60159027Seric ** ruleset -- the ruleset to use for rewriting. 60265071Seric ** reclevel -- recursion level (to catch loops). 60359027Seric ** e -- the current envelope. 6043149Seric ** 6053149Seric ** Returns: 60659084Seric ** A status code. If EX_TEMPFAIL, higher level code should 60759084Seric ** attempt recovery. 6083149Seric ** 6093149Seric ** Side Effects: 6103149Seric ** pvp is modified. 6113149Seric */ 6122091Seric 6133149Seric struct match 6143149Seric { 6154468Seric char **first; /* first token matched */ 6164468Seric char **last; /* last token matched */ 61758825Seric char **pattern; /* pointer to pattern */ 6183149Seric }; 6193149Seric 6204468Seric # define MAXMATCH 9 /* max params per rewrite */ 6213149Seric 62265136Seric # ifndef MAXRULERECURSION 62365136Seric # define MAXRULERECURSION 50 /* max recursion depth */ 62465136Seric # endif 6253149Seric 62665136Seric 62759084Seric int 62865071Seric rewrite(pvp, ruleset, reclevel, e) 6293149Seric char **pvp; 6304070Seric int ruleset; 63165071Seric int reclevel; 63259027Seric register ENVELOPE *e; 6333149Seric { 6343149Seric register char *ap; /* address pointer */ 6353149Seric register char *rp; /* rewrite pointer */ 6363149Seric register char **avp; /* address vector pointer */ 6373149Seric register char **rvp; /* rewrite vector pointer */ 6388058Seric register struct match *mlp; /* cur ptr into mlist */ 6398058Seric register struct rewrite *rwr; /* pointer to current rewrite rule */ 64058866Seric int ruleno; /* current rule number */ 64159084Seric int rstat = EX_OK; /* return status */ 64264740Seric int loopcount; 64356678Seric struct match mlist[MAXMATCH]; /* stores match on LHS */ 6443149Seric char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 6453149Seric 64667262Seric if (OpMode == MD_TEST || tTd(21, 1)) 6473149Seric { 6488959Seric printf("rewrite: ruleset %2d input:", ruleset); 64956678Seric printav(pvp); 6503149Seric } 65156678Seric if (ruleset < 0 || ruleset >= MAXRWSETS) 65256326Seric { 65358151Seric syserr("554 rewrite: illegal ruleset number %d", ruleset); 65459084Seric return EX_CONFIG; 65556326Seric } 65665136Seric if (reclevel++ > MAXRULERECURSION) 65765071Seric { 65865071Seric syserr("rewrite: infinite recursion, ruleset %d", ruleset); 65965071Seric return EX_CONFIG; 66065071Seric } 66156678Seric if (pvp == NULL) 66259084Seric return EX_USAGE; 66356326Seric 6643149Seric /* 66556678Seric ** Run through the list of rewrite rules, applying 66656678Seric ** any that match. 6673149Seric */ 6683149Seric 66958866Seric ruleno = 1; 67064740Seric loopcount = 0; 6714070Seric for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 6723149Seric { 6737675Seric if (tTd(21, 12)) 674297Seric { 6758069Seric printf("-----trying rule:"); 67656678Seric printav(rwr->r_lhs); 6773149Seric } 6783149Seric 6793149Seric /* try to match on this rule */ 6804468Seric mlp = mlist; 6818058Seric rvp = rwr->r_lhs; 6828058Seric avp = pvp; 68358866Seric if (++loopcount > 100) 6843149Seric { 68558866Seric syserr("554 Infinite loop in ruleset %d, rule %d", 68658866Seric ruleset, ruleno); 68758866Seric if (tTd(21, 1)) 68852637Seric { 68956678Seric printf("workspace: "); 69056678Seric printav(pvp); 69152637Seric } 69258866Seric break; 69358866Seric } 69458866Seric 69558866Seric while ((ap = *avp) != NULL || *rvp != NULL) 69658866Seric { 6973149Seric rp = *rvp; 6988058Seric if (tTd(21, 35)) 6998058Seric { 70058825Seric printf("ADVANCE rp="); 70157531Seric xputs(rp); 70257532Seric printf(", ap="); 7038058Seric xputs(ap); 7048069Seric printf("\n"); 7058058Seric } 70656678Seric if (rp == NULL) 70756326Seric { 7083149Seric /* end-of-pattern before end-of-address */ 7098058Seric goto backup; 71056678Seric } 71158173Seric if (ap == NULL && (*rp & 0377) != MATCHZANY && 71258827Seric (*rp & 0377) != MATCHZERO) 71356326Seric { 71458825Seric /* end-of-input with patterns left */ 71558825Seric goto backup; 716297Seric } 71756326Seric 71858050Seric switch (*rp & 0377) 7198058Seric { 72058814Seric char buf[MAXLINE]; 72156326Seric 72256678Seric case MATCHCLASS: 72358825Seric /* match any phrase in a class */ 72458825Seric mlp->pattern = rvp; 72558814Seric mlp->first = avp; 72658814Seric extendclass: 72758825Seric ap = *avp; 72858825Seric if (ap == NULL) 72958814Seric goto backup; 73058814Seric mlp->last = avp++; 73158814Seric cataddr(mlp->first, mlp->last, buf, sizeof buf, '\0'); 73268199Seric if (!wordinclass(buf, rp[1])) 73356326Seric { 73458825Seric if (tTd(21, 36)) 73558825Seric { 73658825Seric printf("EXTEND rp="); 73758825Seric xputs(rp); 73858825Seric printf(", ap="); 73958825Seric xputs(ap); 74058825Seric printf("\n"); 74158825Seric } 74258825Seric goto extendclass; 74356326Seric } 74458825Seric if (tTd(21, 36)) 74558825Seric printf("CLMATCH\n"); 74658814Seric mlp++; 74758814Seric break; 7484060Seric 74958825Seric case MATCHNCLASS: 75058825Seric /* match any token not in a class */ 75168199Seric if (wordinclass(ap, rp[1])) 75258825Seric goto backup; 75358825Seric 75458825Seric /* fall through */ 75558825Seric 75656678Seric case MATCHONE: 75756678Seric case MATCHANY: 75856678Seric /* match exactly one token */ 75958825Seric mlp->pattern = rvp; 76056678Seric mlp->first = avp; 76156678Seric mlp->last = avp++; 7628058Seric mlp++; 76356678Seric break; 7648058Seric 76556678Seric case MATCHZANY: 76656678Seric /* match zero or more tokens */ 76758825Seric mlp->pattern = rvp; 76856678Seric mlp->first = avp; 76956678Seric mlp->last = avp - 1; 77056678Seric mlp++; 77156678Seric break; 77256326Seric 77358827Seric case MATCHZERO: 77458173Seric /* match zero tokens */ 77558173Seric break; 77658173Seric 77759027Seric case MACRODEXPAND: 77859027Seric /* 77959027Seric ** Match against run-time macro. 78059027Seric ** This algorithm is broken for the 78159027Seric ** general case (no recursive macros, 78259027Seric ** improper tokenization) but should 78359027Seric ** work for the usual cases. 78459027Seric */ 78559027Seric 78659027Seric ap = macvalue(rp[1], e); 78759027Seric mlp->first = avp; 78859027Seric if (tTd(21, 2)) 78959027Seric printf("rewrite: LHS $&%c => \"%s\"\n", 79059027Seric rp[1], 79159027Seric ap == NULL ? "(NULL)" : ap); 79259027Seric 79359027Seric if (ap == NULL) 79459027Seric break; 79560502Seric while (*ap != '\0') 79659027Seric { 79759027Seric if (*avp == NULL || 79859027Seric strncasecmp(ap, *avp, strlen(*avp)) != 0) 79959027Seric { 80059027Seric /* no match */ 80159027Seric avp = mlp->first; 80259027Seric goto backup; 80359027Seric } 80459027Seric ap += strlen(*avp++); 80559027Seric } 80659027Seric 80759027Seric /* match */ 80859027Seric break; 80959027Seric 81056678Seric default: 81156678Seric /* must have exact match */ 81256678Seric if (strcasecmp(rp, ap)) 8138058Seric goto backup; 8144468Seric avp++; 81556678Seric break; 8163149Seric } 8173149Seric 81856678Seric /* successful match on this token */ 8193149Seric rvp++; 8203149Seric continue; 8213149Seric 82258825Seric backup: 82356678Seric /* match failed -- back up */ 82458825Seric while (--mlp >= mlist) 8253149Seric { 82658825Seric rvp = mlp->pattern; 82756678Seric rp = *rvp; 82858825Seric avp = mlp->last + 1; 82958825Seric ap = *avp; 83058825Seric 83158825Seric if (tTd(21, 36)) 83258825Seric { 83358825Seric printf("BACKUP rp="); 83458825Seric xputs(rp); 83558825Seric printf(", ap="); 83658825Seric xputs(ap); 83758825Seric printf("\n"); 83858825Seric } 83958825Seric 84058825Seric if (ap == NULL) 84158825Seric { 84258825Seric /* run off the end -- back up again */ 84358825Seric continue; 84458825Seric } 84558050Seric if ((*rp & 0377) == MATCHANY || 84658050Seric (*rp & 0377) == MATCHZANY) 8474468Seric { 84856678Seric /* extend binding and continue */ 84958825Seric mlp->last = avp++; 85056678Seric rvp++; 85158825Seric mlp++; 85256678Seric break; 8534468Seric } 85458825Seric if ((*rp & 0377) == MATCHCLASS) 85556678Seric { 85658814Seric /* extend binding and try again */ 85763397Seric mlp->last = avp; 85858814Seric goto extendclass; 85958814Seric } 8603149Seric } 8613149Seric 86258825Seric if (mlp < mlist) 86356678Seric { 86456678Seric /* total failure to match */ 86556326Seric break; 8663149Seric } 867297Seric } 8683149Seric 8693149Seric /* 87056678Seric ** See if we successfully matched 8713149Seric */ 8723149Seric 87358827Seric if (mlp < mlist || *rvp != NULL) 8743149Seric { 8759374Seric if (tTd(21, 10)) 8769374Seric printf("----- rule fails\n"); 8779374Seric rwr = rwr->r_next; 87858866Seric ruleno++; 87964740Seric loopcount = 0; 8809374Seric continue; 8819374Seric } 8823149Seric 8839374Seric rvp = rwr->r_rhs; 8849374Seric if (tTd(21, 12)) 8859374Seric { 8869374Seric printf("-----rule matches:"); 88756678Seric printav(rvp); 8889374Seric } 8899374Seric 8909374Seric rp = *rvp; 89158050Seric if ((*rp & 0377) == CANONUSER) 8929374Seric { 8939374Seric rvp++; 8949374Seric rwr = rwr->r_next; 89558866Seric ruleno++; 89664740Seric loopcount = 0; 8979374Seric } 89858050Seric else if ((*rp & 0377) == CANONHOST) 8999374Seric { 9009374Seric rvp++; 9019374Seric rwr = NULL; 9029374Seric } 90358050Seric else if ((*rp & 0377) == CANONNET) 9049374Seric rwr = NULL; 9059374Seric 9069374Seric /* substitute */ 9079374Seric for (avp = npvp; *rvp != NULL; rvp++) 9089374Seric { 9099374Seric register struct match *m; 9109374Seric register char **pp; 9119374Seric 9128058Seric rp = *rvp; 91358050Seric if ((*rp & 0377) == MATCHREPL) 9148058Seric { 91516914Seric /* substitute from LHS */ 91616914Seric m = &mlist[rp[1] - '1']; 91756678Seric if (m < mlist || m >= mlp) 9189374Seric { 91958151Seric syserr("554 rewrite: ruleset %d: replacement $%c out of bounds", 92056326Seric ruleset, rp[1]); 92159084Seric return EX_CONFIG; 9229374Seric } 92316914Seric if (tTd(21, 15)) 92416914Seric { 92516914Seric printf("$%c:", rp[1]); 92616914Seric pp = m->first; 92756678Seric while (pp <= m->last) 92816914Seric { 92916914Seric printf(" %x=\"", *pp); 93016914Seric (void) fflush(stdout); 93116914Seric printf("%s\"", *pp++); 93216914Seric } 93316914Seric printf("\n"); 93416914Seric } 9359374Seric pp = m->first; 93656678Seric while (pp <= m->last) 9373149Seric { 93816914Seric if (avp >= &npvp[MAXATOM]) 93956678Seric { 94058151Seric syserr("554 rewrite: expansion too long"); 94159084Seric return EX_DATAERR; 94256678Seric } 94316914Seric *avp++ = *pp++; 9443149Seric } 9453149Seric } 94616914Seric else 9478226Seric { 94816914Seric /* vanilla replacement */ 9499374Seric if (avp >= &npvp[MAXATOM]) 95016889Seric { 95156678Seric toolong: 95258151Seric syserr("554 rewrite: expansion too long"); 95359084Seric return EX_DATAERR; 95416889Seric } 95559027Seric if ((*rp & 0377) != MACRODEXPAND) 95659027Seric *avp++ = rp; 95759027Seric else 95859027Seric { 95959027Seric *avp = macvalue(rp[1], e); 96059027Seric if (tTd(21, 2)) 96159027Seric printf("rewrite: RHS $&%c => \"%s\"\n", 96259027Seric rp[1], 96359027Seric *avp == NULL ? "(NULL)" : *avp); 96459027Seric if (*avp != NULL) 96559027Seric avp++; 96659027Seric } 9678226Seric } 9689374Seric } 9699374Seric *avp++ = NULL; 97016914Seric 97116914Seric /* 97256678Seric ** Check for any hostname/keyword lookups. 97316914Seric */ 97416914Seric 97516914Seric for (rvp = npvp; *rvp != NULL; rvp++) 97616914Seric { 97756678Seric char **hbrvp; 97816914Seric char **xpvp; 97916914Seric int trsize; 98056678Seric char *replac; 98156678Seric int endtoken; 98256678Seric STAB *map; 98356678Seric char *mapname; 98456678Seric char **key_rvp; 98556678Seric char **arg_rvp; 98656678Seric char **default_rvp; 98756678Seric char buf[MAXNAME + 1]; 98816914Seric char *pvpb1[MAXATOM + 1]; 98956823Seric char *argvect[10]; 99017174Seric char pvpbuf[PSBUFSIZE]; 99164404Seric char *nullpvp[1]; 99216914Seric 99358050Seric if ((**rvp & 0377) != HOSTBEGIN && 99458050Seric (**rvp & 0377) != LOOKUPBEGIN) 99516914Seric continue; 99616914Seric 99716914Seric /* 99856678Seric ** Got a hostname/keyword lookup. 99916914Seric ** 100016914Seric ** This could be optimized fairly easily. 100116914Seric */ 100216914Seric 100316914Seric hbrvp = rvp; 100458050Seric if ((**rvp & 0377) == HOSTBEGIN) 100556327Seric { 100656678Seric endtoken = HOSTEND; 100756678Seric mapname = "host"; 100856327Seric } 100956326Seric else 101056327Seric { 101156678Seric endtoken = LOOKUPEND; 101256678Seric mapname = *++rvp; 101356327Seric } 101456678Seric map = stab(mapname, ST_MAP, ST_FIND); 101556678Seric if (map == NULL) 101658151Seric syserr("554 rewrite: map %s not found", mapname); 101756678Seric 101856678Seric /* extract the match part */ 101956678Seric key_rvp = ++rvp; 102056823Seric default_rvp = NULL; 102156823Seric arg_rvp = argvect; 102256823Seric xpvp = NULL; 102356823Seric replac = pvpbuf; 102458050Seric while (*rvp != NULL && (**rvp & 0377) != endtoken) 102553654Seric { 102658050Seric int nodetype = **rvp & 0377; 102756823Seric 102856823Seric if (nodetype != CANONHOST && nodetype != CANONUSER) 102956678Seric { 103056823Seric rvp++; 103156823Seric continue; 103256823Seric } 103356823Seric 103456823Seric *rvp++ = NULL; 103556823Seric 103656823Seric if (xpvp != NULL) 103756823Seric { 103858814Seric cataddr(xpvp, NULL, replac, 103958082Seric &pvpbuf[sizeof pvpbuf] - replac, 104058082Seric '\0'); 104156823Seric *++arg_rvp = replac; 104256823Seric replac += strlen(replac) + 1; 104356823Seric xpvp = NULL; 104456823Seric } 104556823Seric switch (nodetype) 104656823Seric { 104756678Seric case CANONHOST: 104856823Seric xpvp = rvp; 104956678Seric break; 105056678Seric 105156678Seric case CANONUSER: 105256678Seric default_rvp = rvp; 105356678Seric break; 105456678Seric } 105553654Seric } 105616914Seric if (*rvp != NULL) 105716914Seric *rvp++ = NULL; 105856823Seric if (xpvp != NULL) 105956823Seric { 106058814Seric cataddr(xpvp, NULL, replac, 106158082Seric &pvpbuf[sizeof pvpbuf] - replac, 106258082Seric '\0'); 106356823Seric *++arg_rvp = replac; 106456823Seric } 106556823Seric *++arg_rvp = NULL; 106616914Seric 106716914Seric /* save the remainder of the input string */ 106816914Seric trsize = (int) (avp - rvp + 1) * sizeof *rvp; 106916914Seric bcopy((char *) rvp, (char *) pvpb1, trsize); 107016914Seric 107156678Seric /* look it up */ 107258814Seric cataddr(key_rvp, NULL, buf, sizeof buf, '\0'); 107356823Seric argvect[0] = buf; 107460538Seric if (map != NULL && bitset(MF_OPEN, map->s_map.map_mflags)) 107556836Seric { 107659084Seric auto int stat = EX_OK; 107756836Seric 107860215Seric /* XXX should try to auto-open the map here */ 107960215Seric 108058796Seric if (tTd(60, 1)) 108158796Seric printf("map_lookup(%s, %s) => ", 108258796Seric mapname, buf); 108356836Seric replac = (*map->s_map.map_class->map_lookup)(&map->s_map, 108460089Seric buf, argvect, &stat); 108558796Seric if (tTd(60, 1)) 108659084Seric printf("%s (%d)\n", 108759084Seric replac ? replac : "NOT FOUND", 108859084Seric stat); 108959084Seric 109059084Seric /* should recover if stat == EX_TEMPFAIL */ 109159084Seric if (stat == EX_TEMPFAIL) 109259084Seric rstat = stat; 109356836Seric } 109453654Seric else 109556678Seric replac = NULL; 109656678Seric 109756678Seric /* if no replacement, use default */ 109856823Seric if (replac == NULL && default_rvp != NULL) 109956823Seric { 110060089Seric /* create the default */ 110160089Seric cataddr(default_rvp, NULL, buf, sizeof buf, '\0'); 110256823Seric replac = buf; 110356823Seric } 110456823Seric 110556678Seric if (replac == NULL) 110651317Seric { 110756823Seric xpvp = key_rvp; 110853654Seric } 110964404Seric else if (*replac == '\0') 111064404Seric { 111164404Seric /* null replacement */ 111264404Seric nullpvp[0] = NULL; 111364404Seric xpvp = nullpvp; 111464404Seric } 111556678Seric else 111653654Seric { 111756678Seric /* scan the new replacement */ 111865066Seric xpvp = prescan(replac, '\0', pvpbuf, 111965066Seric sizeof pvpbuf, NULL); 112053654Seric if (xpvp == NULL) 112151317Seric { 112258403Seric /* prescan already printed error */ 112359084Seric return EX_DATAERR; 112456678Seric } 112551317Seric } 112651317Seric 112716914Seric /* append it to the token list */ 112856678Seric for (avp = hbrvp; *xpvp != NULL; xpvp++) 112956678Seric { 113017174Seric *avp++ = newstr(*xpvp); 113116920Seric if (avp >= &npvp[MAXATOM]) 113216914Seric goto toolong; 113317174Seric } 113416914Seric 113516914Seric /* restore the old trailing information */ 113656678Seric for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) 113716920Seric if (avp >= &npvp[MAXATOM]) 113816914Seric goto toolong; 113917174Seric 114056678Seric break; 114116914Seric } 114216914Seric 114316914Seric /* 114416914Seric ** Check for subroutine calls. 114516914Seric */ 114616914Seric 114768559Seric if (*npvp != NULL && (**npvp & 0377) == CALLSUBR) 114868559Seric { 114968559Seric int stat; 115059084Seric 115168559Seric if (npvp[1] == NULL) 115268559Seric { 115368559Seric syserr("parseaddr: NULL subroutine call in ruleset %d, rule %d", 115468559Seric ruleset, ruleno); 115568559Seric *pvp = NULL; 115668559Seric } 115768559Seric else 115868559Seric { 115968559Seric int ruleset; 116068559Seric STAB *s; 116168385Seric 116268559Seric bcopy((char *) &npvp[2], (char *) pvp, 116368559Seric (int) (avp - npvp - 2) * sizeof *avp); 116468559Seric if (tTd(21, 3)) 116568559Seric printf("-----callsubr %s\n", npvp[1]); 116668559Seric s = stab(npvp[1], ST_RULESET, ST_FIND); 116768559Seric if (s == NULL) 116868559Seric ruleset = atoi(npvp[1]); 116968559Seric else 117068559Seric ruleset = s->s_ruleset; 117168559Seric stat = rewrite(pvp, ruleset, reclevel, e); 117268559Seric if (rstat == EX_OK || stat == EX_TEMPFAIL) 117368559Seric rstat = stat; 117468559Seric if (*pvp != NULL && (**pvp & 0377) == CANONNET) 117568559Seric rwr = NULL; 117668559Seric } 117768559Seric } 117868559Seric else 117968559Seric { 118068559Seric bcopy((char *) npvp, (char *) pvp, 118168559Seric (int) (avp - npvp) * sizeof *avp); 118268559Seric } 11839374Seric if (tTd(21, 4)) 11849374Seric { 11859374Seric printf("rewritten as:"); 118656678Seric printav(pvp); 11879374Seric } 1188297Seric } 11898069Seric 119067262Seric if (OpMode == MD_TEST || tTd(21, 1)) 11918069Seric { 11928959Seric printf("rewrite: ruleset %2d returns:", ruleset); 119356678Seric printav(pvp); 11948069Seric } 119559084Seric 119659084Seric return rstat; 11973149Seric } 11983149Seric /* 11993149Seric ** BUILDADDR -- build address from token vector. 12003149Seric ** 12013149Seric ** Parameters: 12023149Seric ** tv -- token vector. 12033149Seric ** a -- pointer to address descriptor to fill. 12043149Seric ** If NULL, one will be allocated. 120564284Seric ** flags -- info regarding whether this is a sender or 120664284Seric ** a recipient. 120758966Seric ** e -- the current envelope. 12083149Seric ** 12093149Seric ** Returns: 12104279Seric ** NULL if there was an error. 12114279Seric ** 'a' otherwise. 12123149Seric ** 12133149Seric ** Side Effects: 12143149Seric ** fills in 'a' 12153149Seric */ 12163149Seric 121757249Seric struct errcodes 121857249Seric { 121957249Seric char *ec_name; /* name of error code */ 122057249Seric int ec_code; /* numeric code */ 122157249Seric } ErrorCodes[] = 122257249Seric { 122357249Seric "usage", EX_USAGE, 122457249Seric "nouser", EX_NOUSER, 122557249Seric "nohost", EX_NOHOST, 122657249Seric "unavailable", EX_UNAVAILABLE, 122757249Seric "software", EX_SOFTWARE, 122857249Seric "tempfail", EX_TEMPFAIL, 122957249Seric "protocol", EX_PROTOCOL, 123057249Seric #ifdef EX_CONFIG 123157249Seric "config", EX_CONFIG, 123257249Seric #endif 123357249Seric NULL, EX_UNAVAILABLE, 123457249Seric }; 123557249Seric 123656678Seric ADDRESS * 123764284Seric buildaddr(tv, a, flags, e) 12383149Seric register char **tv; 12393149Seric register ADDRESS *a; 124064284Seric int flags; 124158966Seric register ENVELOPE *e; 12423149Seric { 12433149Seric struct mailer **mp; 12443149Seric register struct mailer *m; 124558008Seric char *bp; 124658008Seric int spaceleft; 124764306Seric static MAILER errormailer; 124864306Seric static char *errorargv[] = { "ERROR", NULL }; 124968528Seric static char buf[MAXNAME + 1]; 12503149Seric 125164791Seric if (tTd(24, 5)) 125264791Seric { 125367693Seric printf("buildaddr, flags=%x, tv=", flags); 125464791Seric printav(tv); 125564791Seric } 125664791Seric 12573149Seric if (a == NULL) 12583149Seric a = (ADDRESS *) xalloc(sizeof *a); 125916889Seric bzero((char *) a, sizeof *a); 12603149Seric 126167880Seric /* set up default error return flags */ 126267963Seric a->q_flags |= QPINGONFAILURE|QPINGONDELAY; 126367880Seric 12643149Seric /* figure out what net/mailer to use */ 126564306Seric if (*tv == NULL || (**tv & 0377) != CANONNET) 12664279Seric { 126758151Seric syserr("554 buildaddr: no net"); 126864306Seric badaddr: 126964306Seric a->q_flags |= QBADADDR; 127064306Seric a->q_mailer = &errormailer; 127164306Seric if (errormailer.m_name == NULL) 127264306Seric { 127364306Seric /* initialize the bogus mailer */ 127464306Seric errormailer.m_name = "*error*"; 127564306Seric errormailer.m_mailer = "ERROR"; 127664306Seric errormailer.m_argv = errorargv; 127764306Seric } 127864306Seric return a; 12794279Seric } 12803149Seric tv++; 128158680Seric if (strcasecmp(*tv, "error") == 0) 12824279Seric { 128358050Seric if ((**++tv & 0377) == CANONHOST) 128410183Seric { 128557249Seric register struct errcodes *ep; 128657249Seric 128758050Seric if (isascii(**++tv) && isdigit(**tv)) 128857249Seric { 128957249Seric setstat(atoi(*tv)); 129057249Seric } 129157249Seric else 129257249Seric { 129357249Seric for (ep = ErrorCodes; ep->ec_name != NULL; ep++) 129457249Seric if (strcasecmp(ep->ec_name, *tv) == 0) 129557249Seric break; 129657249Seric setstat(ep->ec_code); 129757249Seric } 129810183Seric tv++; 129910183Seric } 130064928Seric else 130164928Seric setstat(EX_UNAVAILABLE); 130258050Seric if ((**tv & 0377) != CANONUSER) 130358151Seric syserr("554 buildaddr: error: no user"); 130458814Seric cataddr(++tv, NULL, buf, sizeof buf, ' '); 130558082Seric stripquotes(buf); 130664659Seric if (isascii(buf[0]) && isdigit(buf[0]) && 130764659Seric isascii(buf[1]) && isdigit(buf[1]) && 130864659Seric isascii(buf[2]) && isdigit(buf[2]) && 130964659Seric buf[3] == ' ') 131064659Seric { 131164659Seric char fmt[10]; 131264659Seric 131364659Seric strncpy(fmt, buf, 3); 131464659Seric strcpy(&fmt[3], " %s"); 131564659Seric usrerr(fmt, buf + 4); 131667786Seric 131767786Seric /* 131867786Seric ** If this is a 4xx code and we aren't running 131967786Seric ** SMTP on our input, bounce this message; 132067786Seric ** otherwise it disappears without a trace. 132167786Seric */ 132267786Seric 132367786Seric if (fmt[0] == '4' && OpMode != MD_SMTP && 132467786Seric OpMode != MD_DAEMON) 132567786Seric { 132667786Seric e->e_flags |= EF_FATALERRS; 132767786Seric } 132864659Seric } 132964659Seric else 133064659Seric { 133166039Seric usrerr("553 %s", buf); 133264659Seric } 133364306Seric goto badaddr; 13344279Seric } 133557402Seric 13364598Seric for (mp = Mailer; (m = *mp++) != NULL; ) 13373149Seric { 133858680Seric if (strcasecmp(m->m_name, *tv) == 0) 13393149Seric break; 13403149Seric } 13413149Seric if (m == NULL) 13424279Seric { 134358151Seric syserr("554 buildaddr: unknown mailer %s", *tv); 134464306Seric goto badaddr; 13454279Seric } 13464598Seric a->q_mailer = m; 13473149Seric 13483149Seric /* figure out what host (if any) */ 134956678Seric tv++; 135058509Seric if ((**tv & 0377) == CANONHOST) 13513149Seric { 135258008Seric bp = buf; 135358008Seric spaceleft = sizeof buf - 1; 135458050Seric while (*++tv != NULL && (**tv & 0377) != CANONUSER) 135558008Seric { 135658008Seric int i = strlen(*tv); 135758008Seric 135858008Seric if (i > spaceleft) 135958008Seric { 136058008Seric /* out of space for this address */ 136158008Seric if (spaceleft >= 0) 136258151Seric syserr("554 buildaddr: host too long (%.40s...)", 136358008Seric buf); 136458008Seric i = spaceleft; 136558008Seric spaceleft = 0; 136658008Seric } 136758008Seric if (i <= 0) 136858008Seric continue; 136958008Seric bcopy(*tv, bp, i); 137058008Seric bp += i; 137158008Seric spaceleft -= i; 137258008Seric } 137358010Seric *bp = '\0'; 13745704Seric a->q_host = newstr(buf); 13753149Seric } 137657249Seric else 137758509Seric { 137858509Seric if (!bitnset(M_LOCALMAILER, m->m_flags)) 137958509Seric { 138058509Seric syserr("554 buildaddr: no host"); 138164306Seric goto badaddr; 138258509Seric } 138357249Seric a->q_host = NULL; 138458509Seric } 13853149Seric 13863149Seric /* figure out the user */ 138758050Seric if (*tv == NULL || (**tv & 0377) != CANONUSER) 13884279Seric { 138958151Seric syserr("554 buildaddr: no user"); 139064306Seric goto badaddr; 13914279Seric } 139257402Seric tv++; 139351317Seric 139468098Seric if (bitnset(M_CHECKUDB, m->m_flags) && *tv != NULL && 139568098Seric strcmp(*tv, "@") == 0) 139668098Seric { 139768098Seric tv++; 139868098Seric a->q_flags |= QNOTREMOTE; 139968098Seric } 140068098Seric 140157402Seric /* do special mapping for local mailer */ 140267472Seric if (*tv != NULL) 140357402Seric { 140457454Seric register char *p = *tv; 140557454Seric 140657454Seric if (*p == '"') 140757454Seric p++; 140867472Seric if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags)) 140957402Seric a->q_mailer = m = ProgMailer; 141067472Seric else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags)) 141157402Seric a->q_mailer = m = FileMailer; 141267472Seric else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags)) 141357402Seric { 141457402Seric /* may be :include: */ 141558814Seric cataddr(tv, NULL, buf, sizeof buf, '\0'); 141658008Seric stripquotes(buf); 141758008Seric if (strncasecmp(buf, ":include:", 9) == 0) 141858008Seric { 141958008Seric /* if :include:, don't need further rewriting */ 142057402Seric a->q_mailer = m = InclMailer; 142158008Seric a->q_user = &buf[9]; 142258008Seric return (a); 142358008Seric } 142457402Seric } 142557402Seric } 142657402Seric 142764284Seric /* rewrite according recipient mailer rewriting rules */ 142864284Seric define('h', a->q_host, e); 142964284Seric if (!bitset(RF_SENDERADDR|RF_HEADERADDR, flags)) 143064284Seric { 143164284Seric /* sender addresses done later */ 143265071Seric (void) rewrite(tv, 2, 0, e); 143364284Seric if (m->m_re_rwset > 0) 143465071Seric (void) rewrite(tv, m->m_re_rwset, 0, e); 143564284Seric } 143665071Seric (void) rewrite(tv, 4, 0, e); 143719040Seric 143819040Seric /* save the result for the command line/RCPT argument */ 143958814Seric cataddr(tv, NULL, buf, sizeof buf, '\0'); 14403149Seric a->q_user = buf; 14413149Seric 144258670Seric /* 144358670Seric ** Do mapping to lower case as requested by mailer 144458670Seric */ 144558670Seric 144658670Seric if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags)) 144758670Seric makelower(a->q_host); 144858670Seric if (!bitnset(M_USR_UPPER, m->m_flags)) 144958670Seric makelower(a->q_user); 145058670Seric 14513149Seric return (a); 14523149Seric } 14533188Seric /* 14544228Seric ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 14554228Seric ** 14564228Seric ** Parameters: 14574228Seric ** pvp -- parameter vector to rebuild. 145858814Seric ** evp -- last parameter to include. Can be NULL to 145958814Seric ** use entire pvp. 14604228Seric ** buf -- buffer to build the string into. 14614228Seric ** sz -- size of buf. 146258082Seric ** spacesub -- the space separator character; if null, 146358082Seric ** use SpaceSub. 14644228Seric ** 14654228Seric ** Returns: 14664228Seric ** none. 14674228Seric ** 14684228Seric ** Side Effects: 14694228Seric ** Destroys buf. 14704228Seric */ 14714228Seric 147258814Seric cataddr(pvp, evp, buf, sz, spacesub) 14734228Seric char **pvp; 147458814Seric char **evp; 14754228Seric char *buf; 14764228Seric register int sz; 147758082Seric char spacesub; 14784228Seric { 14794228Seric bool oatomtok = FALSE; 148056678Seric bool natomtok = FALSE; 14814228Seric register int i; 14824228Seric register char *p; 14834228Seric 148458082Seric if (spacesub == '\0') 148558082Seric spacesub = SpaceSub; 148658082Seric 14878423Seric if (pvp == NULL) 14888423Seric { 148923109Seric (void) strcpy(buf, ""); 14908423Seric return; 14918423Seric } 14924228Seric p = buf; 149311156Seric sz -= 2; 14944228Seric while (*pvp != NULL && (i = strlen(*pvp)) < sz) 14954228Seric { 14968078Seric natomtok = (toktype(**pvp) == ATM); 14974228Seric if (oatomtok && natomtok) 149858082Seric *p++ = spacesub; 14994228Seric (void) strcpy(p, *pvp); 15004228Seric oatomtok = natomtok; 15014228Seric p += i; 150211156Seric sz -= i + 1; 150358814Seric if (pvp++ == evp) 150458814Seric break; 15054228Seric } 15064228Seric *p = '\0'; 15074228Seric } 15084228Seric /* 15093188Seric ** SAMEADDR -- Determine if two addresses are the same 15103188Seric ** 15113188Seric ** This is not just a straight comparison -- if the mailer doesn't 15123188Seric ** care about the host we just ignore it, etc. 15133188Seric ** 15143188Seric ** Parameters: 15153188Seric ** a, b -- pointers to the internal forms to compare. 15163188Seric ** 15173188Seric ** Returns: 15183188Seric ** TRUE -- they represent the same mailbox. 15193188Seric ** FALSE -- they don't. 15203188Seric ** 15213188Seric ** Side Effects: 15223188Seric ** none. 15233188Seric */ 15243188Seric 15253188Seric bool 15269374Seric sameaddr(a, b) 15273188Seric register ADDRESS *a; 15283188Seric register ADDRESS *b; 15293188Seric { 153065093Seric register ADDRESS *ca, *cb; 153165093Seric 15323188Seric /* if they don't have the same mailer, forget it */ 15333188Seric if (a->q_mailer != b->q_mailer) 15343188Seric return (FALSE); 15353188Seric 15363188Seric /* if the user isn't the same, we can drop out */ 153756678Seric if (strcmp(a->q_user, b->q_user) != 0) 15383188Seric return (FALSE); 15393188Seric 154065093Seric /* if we have good uids for both but they differ, these are different */ 154165379Seric if (a->q_mailer == ProgMailer) 154265379Seric { 154365379Seric ca = getctladdr(a); 154465379Seric cb = getctladdr(b); 154565379Seric if (ca != NULL && cb != NULL && 154665379Seric bitset(QGOODUID, ca->q_flags & cb->q_flags) && 154765379Seric ca->q_uid != cb->q_uid) 154865379Seric return (FALSE); 154965379Seric } 155058438Seric 155158509Seric /* otherwise compare hosts (but be careful for NULL ptrs) */ 155258509Seric if (a->q_host == b->q_host) 155358509Seric { 155458509Seric /* probably both null pointers */ 15553188Seric return (TRUE); 155658509Seric } 15573188Seric if (a->q_host == NULL || b->q_host == NULL) 155858509Seric { 155958509Seric /* only one is a null pointer */ 15603188Seric return (FALSE); 156158509Seric } 156256678Seric if (strcmp(a->q_host, b->q_host) != 0) 15633188Seric return (FALSE); 15643188Seric 15653188Seric return (TRUE); 15663188Seric } 15673234Seric /* 15683234Seric ** PRINTADDR -- print address (for debugging) 15693234Seric ** 15703234Seric ** Parameters: 15713234Seric ** a -- the address to print 15723234Seric ** follow -- follow the q_next chain. 15733234Seric ** 15743234Seric ** Returns: 15753234Seric ** none. 15763234Seric ** 15773234Seric ** Side Effects: 15783234Seric ** none. 15793234Seric */ 15803234Seric 158167994Seric struct qflags 158267994Seric { 158367994Seric char *qf_name; 158467994Seric u_long qf_bit; 158567994Seric }; 158667994Seric 158767994Seric struct qflags AddressFlags[] = 158867994Seric { 158967994Seric "QDONTSEND", QDONTSEND, 159067994Seric "QBADADDR", QBADADDR, 159167994Seric "QGOODUID", QGOODUID, 159267994Seric "QPRIMARY", QPRIMARY, 159367994Seric "QQUEUEUP", QQUEUEUP, 159467994Seric "QSENT", QSENT, 159567994Seric "QNOTREMOTE", QNOTREMOTE, 159667994Seric "QSELFREF", QSELFREF, 159767994Seric "QVERIFIED", QVERIFIED, 159867994Seric "QREPORT", QREPORT, 159967994Seric "QBOGUSSHELL", QBOGUSSHELL, 160067994Seric "QUNSAFEADDR", QUNSAFEADDR, 160167994Seric "QPINGONSUCCESS", QPINGONSUCCESS, 160267994Seric "QPINGONFAILURE", QPINGONFAILURE, 160367994Seric "QPINGONDELAY", QPINGONDELAY, 160468595Seric "QHASNOTIFY", QHASNOTIFY, 160567994Seric "QRELAYED", QRELAYED, 1606*68603Seric "QEXPLODED", QEXPLODED, 1607*68603Seric "QTHISPASS", QTHISPASS, 160867994Seric NULL 160967994Seric }; 161067994Seric 161168433Seric void 16123234Seric printaddr(a, follow) 16133234Seric register ADDRESS *a; 16143234Seric bool follow; 16153234Seric { 161657731Seric register MAILER *m; 161757731Seric MAILER pseudomailer; 161867994Seric register struct qflags *qfp; 161967994Seric bool firstone; 16205001Seric 162167994Seric if (a == NULL) 162267994Seric { 162367994Seric printf("[NULL]\n"); 162467994Seric return; 162567994Seric } 162667994Seric 16273234Seric while (a != NULL) 16283234Seric { 16294443Seric printf("%x=", a); 16304085Seric (void) fflush(stdout); 163157731Seric 163257731Seric /* find the mailer -- carefully */ 163357731Seric m = a->q_mailer; 163457731Seric if (m == NULL) 163557731Seric { 163657731Seric m = &pseudomailer; 163757731Seric m->m_mno = -1; 163857731Seric m->m_name = "NULL"; 163957731Seric } 164057731Seric 1641*68603Seric printf("%s:\n\tmailer %d (%s), host `%s'\n", 164257731Seric a->q_paddr, m->m_mno, m->m_name, 1643*68603Seric a->q_host == NULL ? "<null>" : a->q_host); 1644*68603Seric printf("\tuser `%s', ruser `%s'\n", 1645*68603Seric a->q_user, 164667172Seric a->q_ruser == NULL ? "<null>" : a->q_ruser); 164767994Seric printf("\tnext=%x, alias %x, uid %d, gid %d\n", 164867994Seric a->q_next, a->q_alias, a->q_uid, a->q_gid); 164967994Seric printf("\tflags=%lx<", a->q_flags); 165067994Seric firstone = TRUE; 165167994Seric for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++) 165267994Seric { 165367994Seric if (!bitset(qfp->qf_bit, a->q_flags)) 165467994Seric continue; 165567994Seric if (!firstone) 165667994Seric printf(","); 165767994Seric firstone = FALSE; 165867994Seric printf("%s", qfp->qf_name); 165967994Seric } 166067994Seric printf(">\n"); 166159269Seric printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n", 166259269Seric a->q_owner == NULL ? "(none)" : a->q_owner, 166363756Seric a->q_home == NULL ? "(none)" : a->q_home, 166463756Seric a->q_fullname == NULL ? "(none)" : a->q_fullname); 166568228Seric printf("\torcpt=\"%s\", statmta=%s, rstatus=%s\n", 166667987Seric a->q_orcpt == NULL ? "(none)" : a->q_orcpt, 166767987Seric a->q_statmta == NULL ? "(none)" : a->q_statmta, 166867990Seric a->q_rstatus == NULL ? "(none)" : a->q_rstatus); 16694996Seric 16703234Seric if (!follow) 16713234Seric return; 16724996Seric a = a->q_next; 16733234Seric } 16743234Seric } 167567939Seric /* 167667939Seric ** EMPTYADDR -- return TRUE if this address is empty (``<>'') 167767939Seric ** 167867939Seric ** Parameters: 167967939Seric ** a -- pointer to the address 168067939Seric ** 168167939Seric ** Returns: 168267939Seric ** TRUE -- if this address is "empty" (i.e., no one should 168367939Seric ** ever generate replies to it. 168467939Seric ** FALSE -- if it is a "regular" (read: replyable) address. 168567939Seric */ 16864317Seric 168767939Seric bool 168867939Seric emptyaddr(a) 168967939Seric register ADDRESS *a; 169067939Seric { 169167939Seric return strcmp(a->q_paddr, "<>") == 0 || strcmp(a->q_user, "<>") == 0; 169267939Seric } 16937682Seric /* 16947682Seric ** REMOTENAME -- return the name relative to the current mailer 16957682Seric ** 16967682Seric ** Parameters: 16977682Seric ** name -- the name to translate. 16988069Seric ** m -- the mailer that we want to do rewriting relative 16998069Seric ** to. 170059163Seric ** flags -- fine tune operations. 170159163Seric ** pstat -- pointer to status word. 170258020Seric ** e -- the current envelope. 17037682Seric ** 17047682Seric ** Returns: 17057682Seric ** the text string representing this address relative to 17067682Seric ** the receiving mailer. 17077682Seric ** 17087682Seric ** Side Effects: 17097682Seric ** none. 17107682Seric ** 17117682Seric ** Warnings: 17127682Seric ** The text string returned is tucked away locally; 17137682Seric ** copy it if you intend to save it. 17147682Seric */ 17157682Seric 17167682Seric char * 171759163Seric remotename(name, m, flags, pstat, e) 17187682Seric char *name; 171956678Seric struct mailer *m; 172059163Seric int flags; 172159163Seric int *pstat; 172256678Seric register ENVELOPE *e; 17237682Seric { 17248069Seric register char **pvp; 17258069Seric char *fancy; 172656678Seric char *oldg = macvalue('g', e); 172758020Seric int rwset; 172868528Seric static char buf[MAXNAME + 1]; 172968528Seric char lbuf[MAXNAME + 1]; 173016914Seric char pvpbuf[PSBUFSIZE]; 173156678Seric extern char *crackaddr(); 17327682Seric 17337755Seric if (tTd(12, 1)) 17347755Seric printf("remotename(%s)\n", name); 17357755Seric 173610177Seric /* don't do anything if we are tagging it as special */ 173759163Seric if (bitset(RF_SENDERADDR, flags)) 173859163Seric rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset 173959163Seric : m->m_se_rwset; 174058020Seric else 174159163Seric rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset 174259163Seric : m->m_re_rwset; 174358020Seric if (rwset < 0) 174410177Seric return (name); 174510177Seric 17467682Seric /* 17478181Seric ** Do a heuristic crack of this name to extract any comment info. 17488181Seric ** This will leave the name as a comment and a $g macro. 17497889Seric */ 17507889Seric 175159163Seric if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) 175258050Seric fancy = "\201g"; 175310310Seric else 175410310Seric fancy = crackaddr(name); 17557889Seric 17568181Seric /* 17578181Seric ** Turn the name into canonical form. 17588181Seric ** Normally this will be RFC 822 style, i.e., "user@domain". 17598181Seric ** If this only resolves to "user", and the "C" flag is 17608181Seric ** specified in the sending mailer, then the sender's 17618181Seric ** domain will be appended. 17628181Seric */ 17638181Seric 176465066Seric pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL); 17657889Seric if (pvp == NULL) 17667889Seric return (name); 176765071Seric if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 176859163Seric *pstat = EX_TEMPFAIL; 176959163Seric if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) 17708181Seric { 17718181Seric /* append from domain to this address */ 17728181Seric register char **pxp = pvp; 17738181Seric 17749594Seric /* see if there is an "@domain" in the current name */ 17758181Seric while (*pxp != NULL && strcmp(*pxp, "@") != 0) 17768181Seric pxp++; 17778181Seric if (*pxp == NULL) 17788181Seric { 17799594Seric /* no.... append the "@domain" from the sender */ 178056678Seric register char **qxq = e->e_fromdomain; 17818181Seric 17829594Seric while ((*pxp++ = *qxq++) != NULL) 17839594Seric continue; 178465071Seric if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 178559163Seric *pstat = EX_TEMPFAIL; 17868181Seric } 17878181Seric } 17888181Seric 17898181Seric /* 17908959Seric ** Do more specific rewriting. 179156678Seric ** Rewrite using ruleset 1 or 2 depending on whether this is 179256678Seric ** a sender address or not. 17938181Seric ** Then run it through any receiving-mailer-specific rulesets. 17948181Seric */ 17958181Seric 179659163Seric if (bitset(RF_SENDERADDR, flags)) 179759541Seric { 179865071Seric if (rewrite(pvp, 1, 0, e) == EX_TEMPFAIL) 179959163Seric *pstat = EX_TEMPFAIL; 180059541Seric } 18018069Seric else 180259541Seric { 180365071Seric if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL) 180459163Seric *pstat = EX_TEMPFAIL; 180559541Seric } 180658020Seric if (rwset > 0) 180759541Seric { 180865071Seric if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL) 180959163Seric *pstat = EX_TEMPFAIL; 181059541Seric } 18117682Seric 18128181Seric /* 18138959Seric ** Do any final sanitation the address may require. 18148959Seric ** This will normally be used to turn internal forms 18158959Seric ** (e.g., user@host.LOCAL) into external form. This 18168959Seric ** may be used as a default to the above rules. 18178959Seric */ 18188959Seric 181965071Seric if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL) 182059163Seric *pstat = EX_TEMPFAIL; 18218959Seric 18228959Seric /* 18238181Seric ** Now restore the comment information we had at the beginning. 18248181Seric */ 18258181Seric 182658825Seric cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0'); 182756678Seric define('g', lbuf, e); 182865494Seric 182965494Seric /* need to make sure route-addrs have <angle brackets> */ 183065494Seric if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@') 183168529Seric expand("<\201g>", buf, sizeof buf, e); 183265494Seric else 183368529Seric expand(fancy, buf, sizeof buf, e); 183465494Seric 183556678Seric define('g', oldg, e); 18367682Seric 18377682Seric if (tTd(12, 1)) 18387755Seric printf("remotename => `%s'\n", buf); 18397682Seric return (buf); 18407682Seric } 184151317Seric /* 184256678Seric ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 184351317Seric ** 184451317Seric ** Parameters: 184556678Seric ** a -- the address to map (but just the user name part). 184656678Seric ** sendq -- the sendq in which to install any replacement 184756678Seric ** addresses. 184867982Seric ** aliaslevel -- the alias nesting depth. 184967982Seric ** e -- the envelope. 185051317Seric ** 185151317Seric ** Returns: 185251317Seric ** none. 185351317Seric */ 185451317Seric 185567982Seric maplocaluser(a, sendq, aliaslevel, e) 185656678Seric register ADDRESS *a; 185756678Seric ADDRESS **sendq; 185867982Seric int aliaslevel; 185956678Seric ENVELOPE *e; 186051317Seric { 186156678Seric register char **pvp; 186256678Seric register ADDRESS *a1 = NULL; 186358333Seric auto char *delimptr; 186456678Seric char pvpbuf[PSBUFSIZE]; 186551317Seric 186656678Seric if (tTd(29, 1)) 186756678Seric { 186856678Seric printf("maplocaluser: "); 186956678Seric printaddr(a, FALSE); 187056678Seric } 187165066Seric pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr); 187256678Seric if (pvp == NULL) 187356678Seric return; 187451317Seric 187565071Seric (void) rewrite(pvp, 5, 0, e); 187658050Seric if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 187756678Seric return; 187851317Seric 187956678Seric /* if non-null, mailer destination specified -- has it changed? */ 188064284Seric a1 = buildaddr(pvp, NULL, 0, e); 188156678Seric if (a1 == NULL || sameaddr(a, a1)) 188256678Seric return; 188351317Seric 188456678Seric /* mark old address as dead; insert new address */ 188556678Seric a->q_flags |= QDONTSEND; 188657731Seric if (tTd(29, 5)) 188757731Seric { 188857731Seric printf("maplocaluser: QDONTSEND "); 188957731Seric printaddr(a, FALSE); 189057731Seric } 189156678Seric a1->q_alias = a; 189264348Seric allocaddr(a1, RF_COPYALL, NULL); 189367982Seric (void) recipient(a1, sendq, aliaslevel, e); 189451317Seric } 189558802Seric /* 189658802Seric ** DEQUOTE_INIT -- initialize dequote map 189758802Seric ** 189858802Seric ** This is a no-op. 189958802Seric ** 190058802Seric ** Parameters: 190158802Seric ** map -- the internal map structure. 190258802Seric ** args -- arguments. 190358802Seric ** 190458802Seric ** Returns: 190558802Seric ** TRUE. 190658802Seric */ 190758802Seric 190858802Seric bool 190960219Seric dequote_init(map, args) 191058802Seric MAP *map; 191158802Seric char *args; 191258802Seric { 191358805Seric register char *p = args; 191458805Seric 191558805Seric for (;;) 191658805Seric { 191758805Seric while (isascii(*p) && isspace(*p)) 191858805Seric p++; 191958805Seric if (*p != '-') 192058805Seric break; 192158805Seric switch (*++p) 192258805Seric { 192358805Seric case 'a': 192458805Seric map->map_app = ++p; 192558805Seric break; 192667824Seric 192767824Seric case 's': 192867824Seric map->map_coldelim = *++p; 192967824Seric break; 193058805Seric } 193158805Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 193258805Seric p++; 193358805Seric if (*p != '\0') 193458805Seric *p = '\0'; 193558805Seric } 193658805Seric if (map->map_app != NULL) 193758805Seric map->map_app = newstr(map->map_app); 193858805Seric 193958802Seric return TRUE; 194058802Seric } 194158802Seric /* 194258802Seric ** DEQUOTE_MAP -- unquote an address 194358802Seric ** 194458802Seric ** Parameters: 194558802Seric ** map -- the internal map structure (ignored). 194660089Seric ** name -- the name to dequote. 194758802Seric ** av -- arguments (ignored). 194859084Seric ** statp -- pointer to status out-parameter. 194958802Seric ** 195058802Seric ** Returns: 195158802Seric ** NULL -- if there were no quotes, or if the resulting 195258802Seric ** unquoted buffer would not be acceptable to prescan. 195358802Seric ** else -- The dequoted buffer. 195458802Seric */ 195558802Seric 195658802Seric char * 195760089Seric dequote_map(map, name, av, statp) 195858802Seric MAP *map; 195960089Seric char *name; 196058802Seric char **av; 196159084Seric int *statp; 196258802Seric { 196358802Seric register char *p; 196458802Seric register char *q; 196558802Seric register char c; 196667824Seric int anglecnt = 0; 196767824Seric int cmntcnt = 0; 196867824Seric int quotecnt = 0; 196967824Seric int spacecnt = 0; 197067824Seric bool quotemode = FALSE; 197167824Seric bool bslashmode = FALSE; 197267824Seric char spacesub = map->map_coldelim; 197358802Seric 197460089Seric for (p = q = name; (c = *p++) != '\0'; ) 197558802Seric { 197658802Seric if (bslashmode) 197758802Seric { 197858802Seric bslashmode = FALSE; 197958802Seric *q++ = c; 198058802Seric continue; 198158802Seric } 198258802Seric 198367824Seric if (c == ' ' && spacesub != '\0') 198467824Seric c = spacesub; 198567764Seric 198658802Seric switch (c) 198758802Seric { 198858802Seric case '\\': 198958802Seric bslashmode = TRUE; 199058802Seric break; 199158802Seric 199258802Seric case '(': 199358802Seric cmntcnt++; 199458802Seric break; 199558802Seric 199658802Seric case ')': 199758802Seric if (cmntcnt-- <= 0) 199858802Seric return NULL; 199958802Seric break; 200059089Seric 200159089Seric case ' ': 200259089Seric spacecnt++; 200359089Seric break; 200458802Seric } 200558802Seric 200658802Seric if (cmntcnt > 0) 200758802Seric { 200858802Seric *q++ = c; 200958802Seric continue; 201058802Seric } 201158802Seric 201258802Seric switch (c) 201358802Seric { 201458802Seric case '"': 201558802Seric quotemode = !quotemode; 201658802Seric quotecnt++; 201758802Seric continue; 201858802Seric 201958802Seric case '<': 202058802Seric anglecnt++; 202158802Seric break; 202258802Seric 202358802Seric case '>': 202458802Seric if (anglecnt-- <= 0) 202558802Seric return NULL; 202658802Seric break; 202758802Seric } 202858802Seric *q++ = c; 202958802Seric } 203058802Seric 203158802Seric if (anglecnt != 0 || cmntcnt != 0 || bslashmode || 203259089Seric quotemode || quotecnt <= 0 || spacecnt != 0) 203358802Seric return NULL; 203458802Seric *q++ = '\0'; 203560089Seric return name; 203658802Seric } 2037