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*68711Seric static char sccsid[] = "@(#)parseaddr.c 8.64 (Berkeley) 04/02/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 80*68711Seric pvp = prescan(addr, delim, pvpbuf, sizeof pvpbuf, delimptr, NULL); 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. 289*68711Seric ** toktab -- if set, a token table to use for parsing. 290*68711Seric ** If NULL, use the default table. 291297Seric ** 292297Seric ** Returns: 2933149Seric ** A pointer to a vector of tokens. 294297Seric ** NULL on error. 295297Seric */ 296297Seric 2978078Seric /* states and character types */ 2988078Seric # define OPR 0 /* operator */ 2998078Seric # define ATM 1 /* atom */ 3008078Seric # define QST 2 /* in quoted string */ 3018078Seric # define SPC 3 /* chewing up spaces */ 3028078Seric # define ONE 4 /* pick up one character */ 303*68711Seric # define ILL 5 /* illegal character */ 3043149Seric 305*68711Seric # define NSTATES 6 /* number of states */ 3068078Seric # define TYPE 017 /* mask to select state type */ 3078078Seric 3088078Seric /* meta bits for table */ 3098078Seric # define M 020 /* meta character; don't pass through */ 3108078Seric # define B 040 /* cause a break */ 3118078Seric # define MB M|B /* meta-break */ 3128078Seric 3138078Seric static short StateTab[NSTATES][NSTATES] = 3148078Seric { 315*68711Seric /* oldst chtype> OPR ATM QST SPC ONE ILL */ 316*68711Seric /*OPR*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|MB, 317*68711Seric /*ATM*/ OPR|B, ATM, QST|B, SPC|MB, ONE|B, ILL|MB, 318*68711Seric /*QST*/ QST, QST, OPR, QST, QST, QST, 319*68711Seric /*SPC*/ OPR, ATM, QST, SPC|M, ONE, ILL|MB, 320*68711Seric /*ONE*/ OPR, OPR, OPR, OPR, OPR, ILL|MB, 321*68711Seric /*ILL*/ OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|M, 3228078Seric }; 3238078Seric 32465092Seric /* token type table -- it gets modified with $o characters */ 325*68711Seric static char TokTypeTab[256] = 32665092Seric { 327*68711Seric /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 328*68711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM, 329*68711Seric /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 330*68711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 331*68711Seric /* sp ! " # $ % & ' ( ) * + , - . / */ 332*68711Seric SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, ATM,SPC,ATM,ATM,ATM,ATM,ATM,ATM, 333*68711Seric /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 334*68711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 335*68711Seric /* @ A B C D E F G H I J K L M N O */ 336*68711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 337*68711Seric /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 338*68711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 339*68711Seric /* ` a b c d e f g h i j k l m n o */ 340*68711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 341*68711Seric /* p q r s t u v w x y z { | } ~ del */ 342*68711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 343*68711Seric 344*68711Seric /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 345*68711Seric OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 346*68711Seric /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 347*68711Seric OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 348*68711Seric /* sp ! " # $ % & ' ( ) * + , - . / */ 349*68711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 350*68711Seric /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 351*68711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 352*68711Seric /* @ A B C D E F G H I J K L M N O */ 353*68711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 354*68711Seric /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 355*68711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 356*68711Seric /* ` a b c d e f g h i j k l m n o */ 357*68711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 358*68711Seric /* p q r s t u v w x y z { | } ~ del */ 359*68711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 36065092Seric }; 36165092Seric 362*68711Seric /* token type table for MIME parsing */ 363*68711Seric char MimeTokenTab[256] = 364*68711Seric { 365*68711Seric /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 366*68711Seric ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,SPC,SPC,SPC,SPC,SPC,ILL,ILL, 367*68711Seric /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 368*68711Seric ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 369*68711Seric /* sp ! " # $ % & ' ( ) * + , - . / */ 370*68711Seric SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, ATM,SPC,ATM,ATM,OPR,ATM,ATM,OPR, 371*68711Seric /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 372*68711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,OPR,OPR,OPR,OPR,OPR,OPR, 373*68711Seric /* @ A B C D E F G H I J K L M N O */ 374*68711Seric OPR,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 375*68711Seric /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 376*68711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,OPR,OPR,OPR,ATM,ATM, 377*68711Seric /* ` a b c d e f g h i j k l m n o */ 378*68711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 379*68711Seric /* p q r s t u v w x y z { | } ~ del */ 380*68711Seric ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 38165092Seric 382*68711Seric /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 383*68711Seric ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 384*68711Seric /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 385*68711Seric ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 386*68711Seric /* sp ! " # $ % & ' ( ) * + , - . / */ 387*68711Seric ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 388*68711Seric /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 389*68711Seric ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 390*68711Seric /* @ A B C D E F G H I J K L M N O */ 391*68711Seric ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 392*68711Seric /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 393*68711Seric ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 394*68711Seric /* ` a b c d e f g h i j k l m n o */ 395*68711Seric ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 396*68711Seric /* p q r s t u v w x y z { | } ~ del */ 397*68711Seric ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 398*68711Seric }; 39965092Seric 400*68711Seric 4018078Seric # define NOCHAR -1 /* signal nothing in lookahead token */ 4028078Seric 4033149Seric char ** 404*68711Seric prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab) 405297Seric char *addr; 40668353Seric int delim; 40716914Seric char pvpbuf[]; 40858333Seric char **delimptr; 409*68711Seric char *toktab; 410297Seric { 411297Seric register char *p; 4128078Seric register char *q; 4139346Seric register int c; 4143149Seric char **avp; 415297Seric bool bslashmode; 416297Seric int cmntcnt; 4178423Seric int anglecnt; 4183149Seric char *tok; 4198078Seric int state; 4208078Seric int newstate; 42159747Seric char *saveto = CurEnv->e_to; 4228078Seric static char *av[MAXATOM+1]; 42365092Seric static char firsttime = TRUE; 42456678Seric extern int errno; 425297Seric 42665092Seric if (firsttime) 42765092Seric { 42865092Seric /* initialize the token type table */ 42965092Seric char obuf[50]; 43065092Seric 43165092Seric firsttime = FALSE; 43268529Seric expand("\201o", obuf, sizeof obuf - sizeof DELIMCHARS, CurEnv); 43365092Seric strcat(obuf, DELIMCHARS); 43465092Seric for (p = obuf; *p != '\0'; p++) 43565092Seric { 43665092Seric if (TokTypeTab[*p & 0xff] == ATM) 43765092Seric TokTypeTab[*p & 0xff] = OPR; 43865092Seric } 43965092Seric } 440*68711Seric if (toktab == NULL) 441*68711Seric toktab = TokTypeTab; 44265092Seric 44315253Seric /* make sure error messages don't have garbage on them */ 44415253Seric errno = 0; 44515253Seric 44616914Seric q = pvpbuf; 4473149Seric bslashmode = FALSE; 4487800Seric cmntcnt = 0; 4498423Seric anglecnt = 0; 4503149Seric avp = av; 45156678Seric state = ATM; 4528078Seric c = NOCHAR; 4538078Seric p = addr; 45459747Seric CurEnv->e_to = p; 45556764Seric if (tTd(22, 11)) 456297Seric { 4578078Seric printf("prescan: "); 4588078Seric xputs(p); 45923109Seric (void) putchar('\n'); 4608078Seric } 4618078Seric 4628078Seric do 4638078Seric { 4643149Seric /* read a token */ 4653149Seric tok = q; 4668078Seric for (;;) 467297Seric { 4688078Seric /* store away any old lookahead character */ 46959277Seric if (c != NOCHAR && !bslashmode) 4708078Seric { 47115284Seric /* see if there is room */ 47265066Seric if (q >= &pvpbuf[pvpbsize - 5]) 4738078Seric { 47458151Seric usrerr("553 Address too long"); 47568526Seric if (strlen(addr) > MAXNAME) 47668526Seric addr[MAXNAME] = '\0'; 47765015Seric returnnull: 47858333Seric if (delimptr != NULL) 47958333Seric *delimptr = p; 48059747Seric CurEnv->e_to = saveto; 4818078Seric return (NULL); 4828078Seric } 48315284Seric 48415284Seric /* squirrel it away */ 4858078Seric *q++ = c; 4868078Seric } 4878078Seric 4888078Seric /* read a new input character */ 4898078Seric c = *p++; 49057631Seric if (c == '\0') 49156764Seric { 49256764Seric /* diagnose and patch up bad syntax */ 49356764Seric if (state == QST) 49456764Seric { 49564767Seric usrerr("653 Unbalanced '\"'"); 49656764Seric c = '"'; 49756764Seric } 49856764Seric else if (cmntcnt > 0) 49956764Seric { 50064767Seric usrerr("653 Unbalanced '('"); 50156764Seric c = ')'; 50256764Seric } 50356764Seric else if (anglecnt > 0) 50456764Seric { 50556764Seric c = '>'; 50664767Seric usrerr("653 Unbalanced '<'"); 50756764Seric } 50856764Seric else 50956764Seric break; 51015284Seric 51156764Seric p--; 51256764Seric } 51357631Seric else if (c == delim && anglecnt <= 0 && 51457631Seric cmntcnt <= 0 && state != QST) 51557631Seric break; 51656764Seric 5178078Seric if (tTd(22, 101)) 5188078Seric printf("c=%c, s=%d; ", c, state); 5198078Seric 5203149Seric /* chew up special characters */ 5213149Seric *q = '\0'; 5223149Seric if (bslashmode) 5233149Seric { 52459105Seric bslashmode = FALSE; 52559105Seric 52624944Seric /* kludge \! for naive users */ 52758061Seric if (cmntcnt > 0) 52859105Seric { 52958061Seric c = NOCHAR; 53059105Seric continue; 53159105Seric } 53259105Seric else if (c != '!' || state == QST) 53359105Seric { 53456678Seric *q++ = '\\'; 53559105Seric continue; 53659105Seric } 5373149Seric } 53856678Seric 53956678Seric if (c == '\\') 5403149Seric { 5413149Seric bslashmode = TRUE; 5423149Seric } 54356678Seric else if (state == QST) 5448514Seric { 5458514Seric /* do nothing, just avoid next clauses */ 5468514Seric } 5478078Seric else if (c == '(') 5484100Seric { 5498078Seric cmntcnt++; 5508078Seric c = NOCHAR; 5514100Seric } 5528078Seric else if (c == ')') 5533149Seric { 5548078Seric if (cmntcnt <= 0) 5553149Seric { 55664767Seric usrerr("653 Unbalanced ')'"); 55763844Seric c = NOCHAR; 5583149Seric } 5598078Seric else 5608078Seric cmntcnt--; 5618078Seric } 5628078Seric else if (cmntcnt > 0) 5638078Seric c = NOCHAR; 5648423Seric else if (c == '<') 5658423Seric anglecnt++; 5668423Seric else if (c == '>') 5678423Seric { 5688423Seric if (anglecnt <= 0) 5698423Seric { 57064767Seric usrerr("653 Unbalanced '>'"); 57163844Seric c = NOCHAR; 5728423Seric } 57363844Seric else 57463844Seric anglecnt--; 5758423Seric } 57658050Seric else if (delim == ' ' && isascii(c) && isspace(c)) 57711423Seric c = ' '; 5783149Seric 5798078Seric if (c == NOCHAR) 5808078Seric continue; 5813149Seric 5828078Seric /* see if this is end of input */ 58311405Seric if (c == delim && anglecnt <= 0 && state != QST) 5843149Seric break; 5853149Seric 586*68711Seric newstate = StateTab[state][toktab[c & 0xff]]; 5878078Seric if (tTd(22, 101)) 5888078Seric printf("ns=%02o\n", newstate); 5898078Seric state = newstate & TYPE; 590*68711Seric if (state == ILL) 591*68711Seric { 592*68711Seric if (isascii(c) && isprint(c)) 593*68711Seric usrerr("653 Illegal character %c", c); 594*68711Seric else 595*68711Seric usrerr("653 Illegal character 0x%02x", c); 596*68711Seric } 5978078Seric if (bitset(M, newstate)) 5988078Seric c = NOCHAR; 5998078Seric if (bitset(B, newstate)) 6004228Seric break; 601297Seric } 6023149Seric 6033149Seric /* new token */ 6048078Seric if (tok != q) 6051378Seric { 6068078Seric *q++ = '\0'; 6078078Seric if (tTd(22, 36)) 608297Seric { 6098078Seric printf("tok="); 6108078Seric xputs(tok); 61123109Seric (void) putchar('\n'); 612297Seric } 6138078Seric if (avp >= &av[MAXATOM]) 614297Seric { 61558151Seric syserr("553 prescan: too many tokens"); 61665015Seric goto returnnull; 617297Seric } 61865015Seric if (q - tok > MAXNAME) 61965015Seric { 62065015Seric syserr("553 prescan: token too long"); 62165015Seric goto returnnull; 62265015Seric } 6238078Seric *avp++ = tok; 624297Seric } 6258423Seric } while (c != '\0' && (c != delim || anglecnt > 0)); 6263149Seric *avp = NULL; 62758333Seric p--; 62858333Seric if (delimptr != NULL) 62958333Seric *delimptr = p; 63056764Seric if (tTd(22, 12)) 63156764Seric { 63256764Seric printf("prescan==>"); 63356764Seric printav(av); 63456764Seric } 63559747Seric CurEnv->e_to = saveto; 63658546Seric if (av[0] == NULL) 63764966Seric { 63864966Seric if (tTd(22, 1)) 63964966Seric printf("prescan: null leading token\n"); 64058546Seric return (NULL); 64164966Seric } 64258403Seric return (av); 6433149Seric } 6443149Seric /* 6453149Seric ** REWRITE -- apply rewrite rules to token vector. 6463149Seric ** 6474476Seric ** This routine is an ordered production system. Each rewrite 6484476Seric ** rule has a LHS (called the pattern) and a RHS (called the 6494476Seric ** rewrite); 'rwr' points the the current rewrite rule. 6504476Seric ** 6514476Seric ** For each rewrite rule, 'avp' points the address vector we 6524476Seric ** are trying to match against, and 'pvp' points to the pattern. 6538058Seric ** If pvp points to a special match value (MATCHZANY, MATCHANY, 6549585Seric ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp 6559585Seric ** matched is saved away in the match vector (pointed to by 'mvp'). 6564476Seric ** 6574476Seric ** When a match between avp & pvp does not match, we try to 6589585Seric ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS 6594476Seric ** we must also back out the match in mvp. If we reach a 6608058Seric ** MATCHANY or MATCHZANY we just extend the match and start 6618058Seric ** over again. 6624476Seric ** 6634476Seric ** When we finally match, we rewrite the address vector 6644476Seric ** and try over again. 6654476Seric ** 6663149Seric ** Parameters: 6673149Seric ** pvp -- pointer to token vector. 66859027Seric ** ruleset -- the ruleset to use for rewriting. 66965071Seric ** reclevel -- recursion level (to catch loops). 67059027Seric ** e -- the current envelope. 6713149Seric ** 6723149Seric ** Returns: 67359084Seric ** A status code. If EX_TEMPFAIL, higher level code should 67459084Seric ** attempt recovery. 6753149Seric ** 6763149Seric ** Side Effects: 6773149Seric ** pvp is modified. 6783149Seric */ 6792091Seric 6803149Seric struct match 6813149Seric { 6824468Seric char **first; /* first token matched */ 6834468Seric char **last; /* last token matched */ 68458825Seric char **pattern; /* pointer to pattern */ 6853149Seric }; 6863149Seric 6874468Seric # define MAXMATCH 9 /* max params per rewrite */ 6883149Seric 68965136Seric # ifndef MAXRULERECURSION 69065136Seric # define MAXRULERECURSION 50 /* max recursion depth */ 69165136Seric # endif 6923149Seric 69365136Seric 69459084Seric int 69565071Seric rewrite(pvp, ruleset, reclevel, e) 6963149Seric char **pvp; 6974070Seric int ruleset; 69865071Seric int reclevel; 69959027Seric register ENVELOPE *e; 7003149Seric { 7013149Seric register char *ap; /* address pointer */ 7023149Seric register char *rp; /* rewrite pointer */ 7033149Seric register char **avp; /* address vector pointer */ 7043149Seric register char **rvp; /* rewrite vector pointer */ 7058058Seric register struct match *mlp; /* cur ptr into mlist */ 7068058Seric register struct rewrite *rwr; /* pointer to current rewrite rule */ 70758866Seric int ruleno; /* current rule number */ 70859084Seric int rstat = EX_OK; /* return status */ 70964740Seric int loopcount; 71056678Seric struct match mlist[MAXMATCH]; /* stores match on LHS */ 7113149Seric char *npvp[MAXATOM+1]; /* temporary space for rebuild */ 7123149Seric 71367262Seric if (OpMode == MD_TEST || tTd(21, 1)) 7143149Seric { 7158959Seric printf("rewrite: ruleset %2d input:", ruleset); 71656678Seric printav(pvp); 7173149Seric } 71856678Seric if (ruleset < 0 || ruleset >= MAXRWSETS) 71956326Seric { 72058151Seric syserr("554 rewrite: illegal ruleset number %d", ruleset); 72159084Seric return EX_CONFIG; 72256326Seric } 72365136Seric if (reclevel++ > MAXRULERECURSION) 72465071Seric { 72565071Seric syserr("rewrite: infinite recursion, ruleset %d", ruleset); 72665071Seric return EX_CONFIG; 72765071Seric } 72856678Seric if (pvp == NULL) 72959084Seric return EX_USAGE; 73056326Seric 7313149Seric /* 73256678Seric ** Run through the list of rewrite rules, applying 73356678Seric ** any that match. 7343149Seric */ 7353149Seric 73658866Seric ruleno = 1; 73764740Seric loopcount = 0; 7384070Seric for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 7393149Seric { 7407675Seric if (tTd(21, 12)) 741297Seric { 7428069Seric printf("-----trying rule:"); 74356678Seric printav(rwr->r_lhs); 7443149Seric } 7453149Seric 7463149Seric /* try to match on this rule */ 7474468Seric mlp = mlist; 7488058Seric rvp = rwr->r_lhs; 7498058Seric avp = pvp; 75058866Seric if (++loopcount > 100) 7513149Seric { 75258866Seric syserr("554 Infinite loop in ruleset %d, rule %d", 75358866Seric ruleset, ruleno); 75458866Seric if (tTd(21, 1)) 75552637Seric { 75656678Seric printf("workspace: "); 75756678Seric printav(pvp); 75852637Seric } 75958866Seric break; 76058866Seric } 76158866Seric 76258866Seric while ((ap = *avp) != NULL || *rvp != NULL) 76358866Seric { 7643149Seric rp = *rvp; 7658058Seric if (tTd(21, 35)) 7668058Seric { 76758825Seric printf("ADVANCE rp="); 76857531Seric xputs(rp); 76957532Seric printf(", ap="); 7708058Seric xputs(ap); 7718069Seric printf("\n"); 7728058Seric } 77356678Seric if (rp == NULL) 77456326Seric { 7753149Seric /* end-of-pattern before end-of-address */ 7768058Seric goto backup; 77756678Seric } 77858173Seric if (ap == NULL && (*rp & 0377) != MATCHZANY && 77958827Seric (*rp & 0377) != MATCHZERO) 78056326Seric { 78158825Seric /* end-of-input with patterns left */ 78258825Seric goto backup; 783297Seric } 78456326Seric 78558050Seric switch (*rp & 0377) 7868058Seric { 78758814Seric char buf[MAXLINE]; 78856326Seric 78956678Seric case MATCHCLASS: 79058825Seric /* match any phrase in a class */ 79158825Seric mlp->pattern = rvp; 79258814Seric mlp->first = avp; 79358814Seric extendclass: 79458825Seric ap = *avp; 79558825Seric if (ap == NULL) 79658814Seric goto backup; 79758814Seric mlp->last = avp++; 79858814Seric cataddr(mlp->first, mlp->last, buf, sizeof buf, '\0'); 79968199Seric if (!wordinclass(buf, rp[1])) 80056326Seric { 80158825Seric if (tTd(21, 36)) 80258825Seric { 80358825Seric printf("EXTEND rp="); 80458825Seric xputs(rp); 80558825Seric printf(", ap="); 80658825Seric xputs(ap); 80758825Seric printf("\n"); 80858825Seric } 80958825Seric goto extendclass; 81056326Seric } 81158825Seric if (tTd(21, 36)) 81258825Seric printf("CLMATCH\n"); 81358814Seric mlp++; 81458814Seric break; 8154060Seric 81658825Seric case MATCHNCLASS: 81758825Seric /* match any token not in a class */ 81868199Seric if (wordinclass(ap, rp[1])) 81958825Seric goto backup; 82058825Seric 82158825Seric /* fall through */ 82258825Seric 82356678Seric case MATCHONE: 82456678Seric case MATCHANY: 82556678Seric /* match exactly one token */ 82658825Seric mlp->pattern = rvp; 82756678Seric mlp->first = avp; 82856678Seric mlp->last = avp++; 8298058Seric mlp++; 83056678Seric break; 8318058Seric 83256678Seric case MATCHZANY: 83356678Seric /* match zero or more tokens */ 83458825Seric mlp->pattern = rvp; 83556678Seric mlp->first = avp; 83656678Seric mlp->last = avp - 1; 83756678Seric mlp++; 83856678Seric break; 83956326Seric 84058827Seric case MATCHZERO: 84158173Seric /* match zero tokens */ 84258173Seric break; 84358173Seric 84459027Seric case MACRODEXPAND: 84559027Seric /* 84659027Seric ** Match against run-time macro. 84759027Seric ** This algorithm is broken for the 84859027Seric ** general case (no recursive macros, 84959027Seric ** improper tokenization) but should 85059027Seric ** work for the usual cases. 85159027Seric */ 85259027Seric 85359027Seric ap = macvalue(rp[1], e); 85459027Seric mlp->first = avp; 85559027Seric if (tTd(21, 2)) 85659027Seric printf("rewrite: LHS $&%c => \"%s\"\n", 85759027Seric rp[1], 85859027Seric ap == NULL ? "(NULL)" : ap); 85959027Seric 86059027Seric if (ap == NULL) 86159027Seric break; 86260502Seric while (*ap != '\0') 86359027Seric { 86459027Seric if (*avp == NULL || 86559027Seric strncasecmp(ap, *avp, strlen(*avp)) != 0) 86659027Seric { 86759027Seric /* no match */ 86859027Seric avp = mlp->first; 86959027Seric goto backup; 87059027Seric } 87159027Seric ap += strlen(*avp++); 87259027Seric } 87359027Seric 87459027Seric /* match */ 87559027Seric break; 87659027Seric 87756678Seric default: 87856678Seric /* must have exact match */ 87956678Seric if (strcasecmp(rp, ap)) 8808058Seric goto backup; 8814468Seric avp++; 88256678Seric break; 8833149Seric } 8843149Seric 88556678Seric /* successful match on this token */ 8863149Seric rvp++; 8873149Seric continue; 8883149Seric 88958825Seric backup: 89056678Seric /* match failed -- back up */ 89158825Seric while (--mlp >= mlist) 8923149Seric { 89358825Seric rvp = mlp->pattern; 89456678Seric rp = *rvp; 89558825Seric avp = mlp->last + 1; 89658825Seric ap = *avp; 89758825Seric 89858825Seric if (tTd(21, 36)) 89958825Seric { 90058825Seric printf("BACKUP rp="); 90158825Seric xputs(rp); 90258825Seric printf(", ap="); 90358825Seric xputs(ap); 90458825Seric printf("\n"); 90558825Seric } 90658825Seric 90758825Seric if (ap == NULL) 90858825Seric { 90958825Seric /* run off the end -- back up again */ 91058825Seric continue; 91158825Seric } 91258050Seric if ((*rp & 0377) == MATCHANY || 91358050Seric (*rp & 0377) == MATCHZANY) 9144468Seric { 91556678Seric /* extend binding and continue */ 91658825Seric mlp->last = avp++; 91756678Seric rvp++; 91858825Seric mlp++; 91956678Seric break; 9204468Seric } 92158825Seric if ((*rp & 0377) == MATCHCLASS) 92256678Seric { 92358814Seric /* extend binding and try again */ 92463397Seric mlp->last = avp; 92558814Seric goto extendclass; 92658814Seric } 9273149Seric } 9283149Seric 92958825Seric if (mlp < mlist) 93056678Seric { 93156678Seric /* total failure to match */ 93256326Seric break; 9333149Seric } 934297Seric } 9353149Seric 9363149Seric /* 93756678Seric ** See if we successfully matched 9383149Seric */ 9393149Seric 94058827Seric if (mlp < mlist || *rvp != NULL) 9413149Seric { 9429374Seric if (tTd(21, 10)) 9439374Seric printf("----- rule fails\n"); 9449374Seric rwr = rwr->r_next; 94558866Seric ruleno++; 94664740Seric loopcount = 0; 9479374Seric continue; 9489374Seric } 9493149Seric 9509374Seric rvp = rwr->r_rhs; 9519374Seric if (tTd(21, 12)) 9529374Seric { 9539374Seric printf("-----rule matches:"); 95456678Seric printav(rvp); 9559374Seric } 9569374Seric 9579374Seric rp = *rvp; 95858050Seric if ((*rp & 0377) == CANONUSER) 9599374Seric { 9609374Seric rvp++; 9619374Seric rwr = rwr->r_next; 96258866Seric ruleno++; 96364740Seric loopcount = 0; 9649374Seric } 96558050Seric else if ((*rp & 0377) == CANONHOST) 9669374Seric { 9679374Seric rvp++; 9689374Seric rwr = NULL; 9699374Seric } 97058050Seric else if ((*rp & 0377) == CANONNET) 9719374Seric rwr = NULL; 9729374Seric 9739374Seric /* substitute */ 9749374Seric for (avp = npvp; *rvp != NULL; rvp++) 9759374Seric { 9769374Seric register struct match *m; 9779374Seric register char **pp; 9789374Seric 9798058Seric rp = *rvp; 98058050Seric if ((*rp & 0377) == MATCHREPL) 9818058Seric { 98216914Seric /* substitute from LHS */ 98316914Seric m = &mlist[rp[1] - '1']; 98456678Seric if (m < mlist || m >= mlp) 9859374Seric { 98658151Seric syserr("554 rewrite: ruleset %d: replacement $%c out of bounds", 98756326Seric ruleset, rp[1]); 98859084Seric return EX_CONFIG; 9899374Seric } 99016914Seric if (tTd(21, 15)) 99116914Seric { 99216914Seric printf("$%c:", rp[1]); 99316914Seric pp = m->first; 99456678Seric while (pp <= m->last) 99516914Seric { 99616914Seric printf(" %x=\"", *pp); 99716914Seric (void) fflush(stdout); 99816914Seric printf("%s\"", *pp++); 99916914Seric } 100016914Seric printf("\n"); 100116914Seric } 10029374Seric pp = m->first; 100356678Seric while (pp <= m->last) 10043149Seric { 100516914Seric if (avp >= &npvp[MAXATOM]) 100656678Seric { 100758151Seric syserr("554 rewrite: expansion too long"); 100859084Seric return EX_DATAERR; 100956678Seric } 101016914Seric *avp++ = *pp++; 10113149Seric } 10123149Seric } 101316914Seric else 10148226Seric { 101516914Seric /* vanilla replacement */ 10169374Seric if (avp >= &npvp[MAXATOM]) 101716889Seric { 101856678Seric toolong: 101958151Seric syserr("554 rewrite: expansion too long"); 102059084Seric return EX_DATAERR; 102116889Seric } 102259027Seric if ((*rp & 0377) != MACRODEXPAND) 102359027Seric *avp++ = rp; 102459027Seric else 102559027Seric { 102659027Seric *avp = macvalue(rp[1], e); 102759027Seric if (tTd(21, 2)) 102859027Seric printf("rewrite: RHS $&%c => \"%s\"\n", 102959027Seric rp[1], 103059027Seric *avp == NULL ? "(NULL)" : *avp); 103159027Seric if (*avp != NULL) 103259027Seric avp++; 103359027Seric } 10348226Seric } 10359374Seric } 10369374Seric *avp++ = NULL; 103716914Seric 103816914Seric /* 103956678Seric ** Check for any hostname/keyword lookups. 104016914Seric */ 104116914Seric 104216914Seric for (rvp = npvp; *rvp != NULL; rvp++) 104316914Seric { 104456678Seric char **hbrvp; 104516914Seric char **xpvp; 104616914Seric int trsize; 104756678Seric char *replac; 104856678Seric int endtoken; 104956678Seric STAB *map; 105056678Seric char *mapname; 105156678Seric char **key_rvp; 105256678Seric char **arg_rvp; 105356678Seric char **default_rvp; 105456678Seric char buf[MAXNAME + 1]; 105516914Seric char *pvpb1[MAXATOM + 1]; 105656823Seric char *argvect[10]; 105717174Seric char pvpbuf[PSBUFSIZE]; 105864404Seric char *nullpvp[1]; 105916914Seric 106058050Seric if ((**rvp & 0377) != HOSTBEGIN && 106158050Seric (**rvp & 0377) != LOOKUPBEGIN) 106216914Seric continue; 106316914Seric 106416914Seric /* 106556678Seric ** Got a hostname/keyword lookup. 106616914Seric ** 106716914Seric ** This could be optimized fairly easily. 106816914Seric */ 106916914Seric 107016914Seric hbrvp = rvp; 107158050Seric if ((**rvp & 0377) == HOSTBEGIN) 107256327Seric { 107356678Seric endtoken = HOSTEND; 107456678Seric mapname = "host"; 107556327Seric } 107656326Seric else 107756327Seric { 107856678Seric endtoken = LOOKUPEND; 107956678Seric mapname = *++rvp; 108056327Seric } 108156678Seric map = stab(mapname, ST_MAP, ST_FIND); 108256678Seric if (map == NULL) 108358151Seric syserr("554 rewrite: map %s not found", mapname); 108456678Seric 108556678Seric /* extract the match part */ 108656678Seric key_rvp = ++rvp; 108756823Seric default_rvp = NULL; 108856823Seric arg_rvp = argvect; 108956823Seric xpvp = NULL; 109056823Seric replac = pvpbuf; 109158050Seric while (*rvp != NULL && (**rvp & 0377) != endtoken) 109253654Seric { 109358050Seric int nodetype = **rvp & 0377; 109456823Seric 109556823Seric if (nodetype != CANONHOST && nodetype != CANONUSER) 109656678Seric { 109756823Seric rvp++; 109856823Seric continue; 109956823Seric } 110056823Seric 110156823Seric *rvp++ = NULL; 110256823Seric 110356823Seric if (xpvp != NULL) 110456823Seric { 110558814Seric cataddr(xpvp, NULL, replac, 110658082Seric &pvpbuf[sizeof pvpbuf] - replac, 110758082Seric '\0'); 110856823Seric *++arg_rvp = replac; 110956823Seric replac += strlen(replac) + 1; 111056823Seric xpvp = NULL; 111156823Seric } 111256823Seric switch (nodetype) 111356823Seric { 111456678Seric case CANONHOST: 111556823Seric xpvp = rvp; 111656678Seric break; 111756678Seric 111856678Seric case CANONUSER: 111956678Seric default_rvp = rvp; 112056678Seric break; 112156678Seric } 112253654Seric } 112316914Seric if (*rvp != NULL) 112416914Seric *rvp++ = NULL; 112556823Seric if (xpvp != NULL) 112656823Seric { 112758814Seric cataddr(xpvp, NULL, replac, 112858082Seric &pvpbuf[sizeof pvpbuf] - replac, 112958082Seric '\0'); 113056823Seric *++arg_rvp = replac; 113156823Seric } 113256823Seric *++arg_rvp = NULL; 113316914Seric 113416914Seric /* save the remainder of the input string */ 113516914Seric trsize = (int) (avp - rvp + 1) * sizeof *rvp; 113616914Seric bcopy((char *) rvp, (char *) pvpb1, trsize); 113716914Seric 113856678Seric /* look it up */ 113958814Seric cataddr(key_rvp, NULL, buf, sizeof buf, '\0'); 114056823Seric argvect[0] = buf; 114160538Seric if (map != NULL && bitset(MF_OPEN, map->s_map.map_mflags)) 114256836Seric { 114359084Seric auto int stat = EX_OK; 114456836Seric 114560215Seric /* XXX should try to auto-open the map here */ 114660215Seric 114758796Seric if (tTd(60, 1)) 114858796Seric printf("map_lookup(%s, %s) => ", 114958796Seric mapname, buf); 115056836Seric replac = (*map->s_map.map_class->map_lookup)(&map->s_map, 115160089Seric buf, argvect, &stat); 115258796Seric if (tTd(60, 1)) 115359084Seric printf("%s (%d)\n", 115459084Seric replac ? replac : "NOT FOUND", 115559084Seric stat); 115659084Seric 115759084Seric /* should recover if stat == EX_TEMPFAIL */ 115868706Seric if (stat == EX_TEMPFAIL || stat == EX_UNAVAILABLE) 115968706Seric { 116068706Seric rstat = EX_TEMPFAIL; 116168708Seric if (tTd(50, 1)) 116268706Seric printf("map_lookup(%s, %s) failed (stat = %d)\n", 116368706Seric mapname, buf, stat); 116468706Seric if (e->e_message == NULL) 116568706Seric { 116668706Seric char mbuf[300]; 116768706Seric 116868706Seric sprintf(mbuf, "map %s: lookup (%s) failed", 116968706Seric mapname, buf); 117068706Seric e->e_message = newstr(mbuf); 117168706Seric } 117268706Seric } 117356836Seric } 117453654Seric else 117556678Seric replac = NULL; 117656678Seric 117756678Seric /* if no replacement, use default */ 117856823Seric if (replac == NULL && default_rvp != NULL) 117956823Seric { 118060089Seric /* create the default */ 118160089Seric cataddr(default_rvp, NULL, buf, sizeof buf, '\0'); 118256823Seric replac = buf; 118356823Seric } 118456823Seric 118556678Seric if (replac == NULL) 118651317Seric { 118756823Seric xpvp = key_rvp; 118853654Seric } 118964404Seric else if (*replac == '\0') 119064404Seric { 119164404Seric /* null replacement */ 119264404Seric nullpvp[0] = NULL; 119364404Seric xpvp = nullpvp; 119464404Seric } 119556678Seric else 119653654Seric { 119756678Seric /* scan the new replacement */ 119865066Seric xpvp = prescan(replac, '\0', pvpbuf, 1199*68711Seric sizeof pvpbuf, NULL, NULL); 120053654Seric if (xpvp == NULL) 120151317Seric { 120258403Seric /* prescan already printed error */ 120359084Seric return EX_DATAERR; 120456678Seric } 120551317Seric } 120651317Seric 120716914Seric /* append it to the token list */ 120856678Seric for (avp = hbrvp; *xpvp != NULL; xpvp++) 120956678Seric { 121017174Seric *avp++ = newstr(*xpvp); 121116920Seric if (avp >= &npvp[MAXATOM]) 121216914Seric goto toolong; 121317174Seric } 121416914Seric 121516914Seric /* restore the old trailing information */ 121656678Seric for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) 121716920Seric if (avp >= &npvp[MAXATOM]) 121816914Seric goto toolong; 121917174Seric 122056678Seric break; 122116914Seric } 122216914Seric 122316914Seric /* 122416914Seric ** Check for subroutine calls. 122516914Seric */ 122616914Seric 122768559Seric if (*npvp != NULL && (**npvp & 0377) == CALLSUBR) 122868559Seric { 122968559Seric int stat; 123059084Seric 123168559Seric if (npvp[1] == NULL) 123268559Seric { 123368559Seric syserr("parseaddr: NULL subroutine call in ruleset %d, rule %d", 123468559Seric ruleset, ruleno); 123568559Seric *pvp = NULL; 123668559Seric } 123768559Seric else 123868559Seric { 123968559Seric int ruleset; 124068559Seric STAB *s; 124168385Seric 124268559Seric bcopy((char *) &npvp[2], (char *) pvp, 124368559Seric (int) (avp - npvp - 2) * sizeof *avp); 124468559Seric if (tTd(21, 3)) 124568559Seric printf("-----callsubr %s\n", npvp[1]); 124668559Seric s = stab(npvp[1], ST_RULESET, ST_FIND); 124768559Seric if (s == NULL) 124868559Seric ruleset = atoi(npvp[1]); 124968559Seric else 125068559Seric ruleset = s->s_ruleset; 125168559Seric stat = rewrite(pvp, ruleset, reclevel, e); 125268559Seric if (rstat == EX_OK || stat == EX_TEMPFAIL) 125368559Seric rstat = stat; 125468559Seric if (*pvp != NULL && (**pvp & 0377) == CANONNET) 125568559Seric rwr = NULL; 125668559Seric } 125768559Seric } 125868559Seric else 125968559Seric { 126068559Seric bcopy((char *) npvp, (char *) pvp, 126168559Seric (int) (avp - npvp) * sizeof *avp); 126268559Seric } 12639374Seric if (tTd(21, 4)) 12649374Seric { 12659374Seric printf("rewritten as:"); 126656678Seric printav(pvp); 12679374Seric } 1268297Seric } 12698069Seric 127067262Seric if (OpMode == MD_TEST || tTd(21, 1)) 12718069Seric { 12728959Seric printf("rewrite: ruleset %2d returns:", ruleset); 127356678Seric printav(pvp); 12748069Seric } 127559084Seric 127659084Seric return rstat; 12773149Seric } 12783149Seric /* 12793149Seric ** BUILDADDR -- build address from token vector. 12803149Seric ** 12813149Seric ** Parameters: 12823149Seric ** tv -- token vector. 12833149Seric ** a -- pointer to address descriptor to fill. 12843149Seric ** If NULL, one will be allocated. 128564284Seric ** flags -- info regarding whether this is a sender or 128664284Seric ** a recipient. 128758966Seric ** e -- the current envelope. 12883149Seric ** 12893149Seric ** Returns: 12904279Seric ** NULL if there was an error. 12914279Seric ** 'a' otherwise. 12923149Seric ** 12933149Seric ** Side Effects: 12943149Seric ** fills in 'a' 12953149Seric */ 12963149Seric 129757249Seric struct errcodes 129857249Seric { 129957249Seric char *ec_name; /* name of error code */ 130057249Seric int ec_code; /* numeric code */ 130157249Seric } ErrorCodes[] = 130257249Seric { 130357249Seric "usage", EX_USAGE, 130457249Seric "nouser", EX_NOUSER, 130557249Seric "nohost", EX_NOHOST, 130657249Seric "unavailable", EX_UNAVAILABLE, 130757249Seric "software", EX_SOFTWARE, 130857249Seric "tempfail", EX_TEMPFAIL, 130957249Seric "protocol", EX_PROTOCOL, 131057249Seric #ifdef EX_CONFIG 131157249Seric "config", EX_CONFIG, 131257249Seric #endif 131357249Seric NULL, EX_UNAVAILABLE, 131457249Seric }; 131557249Seric 131656678Seric ADDRESS * 131764284Seric buildaddr(tv, a, flags, e) 13183149Seric register char **tv; 13193149Seric register ADDRESS *a; 132064284Seric int flags; 132158966Seric register ENVELOPE *e; 13223149Seric { 13233149Seric struct mailer **mp; 13243149Seric register struct mailer *m; 132558008Seric char *bp; 132658008Seric int spaceleft; 132764306Seric static MAILER errormailer; 132864306Seric static char *errorargv[] = { "ERROR", NULL }; 132968528Seric static char buf[MAXNAME + 1]; 13303149Seric 133164791Seric if (tTd(24, 5)) 133264791Seric { 133367693Seric printf("buildaddr, flags=%x, tv=", flags); 133464791Seric printav(tv); 133564791Seric } 133664791Seric 13373149Seric if (a == NULL) 13383149Seric a = (ADDRESS *) xalloc(sizeof *a); 133916889Seric bzero((char *) a, sizeof *a); 13403149Seric 134167880Seric /* set up default error return flags */ 134267963Seric a->q_flags |= QPINGONFAILURE|QPINGONDELAY; 134367880Seric 13443149Seric /* figure out what net/mailer to use */ 134564306Seric if (*tv == NULL || (**tv & 0377) != CANONNET) 13464279Seric { 134758151Seric syserr("554 buildaddr: no net"); 134864306Seric badaddr: 134964306Seric a->q_flags |= QBADADDR; 135064306Seric a->q_mailer = &errormailer; 135164306Seric if (errormailer.m_name == NULL) 135264306Seric { 135364306Seric /* initialize the bogus mailer */ 135464306Seric errormailer.m_name = "*error*"; 135564306Seric errormailer.m_mailer = "ERROR"; 135664306Seric errormailer.m_argv = errorargv; 135764306Seric } 135864306Seric return a; 13594279Seric } 13603149Seric tv++; 136158680Seric if (strcasecmp(*tv, "error") == 0) 13624279Seric { 136358050Seric if ((**++tv & 0377) == CANONHOST) 136410183Seric { 136557249Seric register struct errcodes *ep; 136657249Seric 136758050Seric if (isascii(**++tv) && isdigit(**tv)) 136857249Seric { 136957249Seric setstat(atoi(*tv)); 137057249Seric } 137157249Seric else 137257249Seric { 137357249Seric for (ep = ErrorCodes; ep->ec_name != NULL; ep++) 137457249Seric if (strcasecmp(ep->ec_name, *tv) == 0) 137557249Seric break; 137657249Seric setstat(ep->ec_code); 137757249Seric } 137810183Seric tv++; 137910183Seric } 138064928Seric else 138164928Seric setstat(EX_UNAVAILABLE); 138258050Seric if ((**tv & 0377) != CANONUSER) 138358151Seric syserr("554 buildaddr: error: no user"); 138458814Seric cataddr(++tv, NULL, buf, sizeof buf, ' '); 138558082Seric stripquotes(buf); 138664659Seric if (isascii(buf[0]) && isdigit(buf[0]) && 138764659Seric isascii(buf[1]) && isdigit(buf[1]) && 138864659Seric isascii(buf[2]) && isdigit(buf[2]) && 138964659Seric buf[3] == ' ') 139064659Seric { 139164659Seric char fmt[10]; 139264659Seric 139364659Seric strncpy(fmt, buf, 3); 139464659Seric strcpy(&fmt[3], " %s"); 139564659Seric usrerr(fmt, buf + 4); 139667786Seric 139767786Seric /* 139867786Seric ** If this is a 4xx code and we aren't running 139967786Seric ** SMTP on our input, bounce this message; 140067786Seric ** otherwise it disappears without a trace. 140167786Seric */ 140267786Seric 140367786Seric if (fmt[0] == '4' && OpMode != MD_SMTP && 140467786Seric OpMode != MD_DAEMON) 140567786Seric { 140667786Seric e->e_flags |= EF_FATALERRS; 140767786Seric } 140864659Seric } 140964659Seric else 141064659Seric { 141166039Seric usrerr("553 %s", buf); 141264659Seric } 141364306Seric goto badaddr; 14144279Seric } 141557402Seric 14164598Seric for (mp = Mailer; (m = *mp++) != NULL; ) 14173149Seric { 141858680Seric if (strcasecmp(m->m_name, *tv) == 0) 14193149Seric break; 14203149Seric } 14213149Seric if (m == NULL) 14224279Seric { 142358151Seric syserr("554 buildaddr: unknown mailer %s", *tv); 142464306Seric goto badaddr; 14254279Seric } 14264598Seric a->q_mailer = m; 14273149Seric 14283149Seric /* figure out what host (if any) */ 142956678Seric tv++; 143058509Seric if ((**tv & 0377) == CANONHOST) 14313149Seric { 143258008Seric bp = buf; 143358008Seric spaceleft = sizeof buf - 1; 143458050Seric while (*++tv != NULL && (**tv & 0377) != CANONUSER) 143558008Seric { 143658008Seric int i = strlen(*tv); 143758008Seric 143858008Seric if (i > spaceleft) 143958008Seric { 144058008Seric /* out of space for this address */ 144158008Seric if (spaceleft >= 0) 144258151Seric syserr("554 buildaddr: host too long (%.40s...)", 144358008Seric buf); 144458008Seric i = spaceleft; 144558008Seric spaceleft = 0; 144658008Seric } 144758008Seric if (i <= 0) 144858008Seric continue; 144958008Seric bcopy(*tv, bp, i); 145058008Seric bp += i; 145158008Seric spaceleft -= i; 145258008Seric } 145358010Seric *bp = '\0'; 14545704Seric a->q_host = newstr(buf); 14553149Seric } 145657249Seric else 145758509Seric { 145858509Seric if (!bitnset(M_LOCALMAILER, m->m_flags)) 145958509Seric { 146058509Seric syserr("554 buildaddr: no host"); 146164306Seric goto badaddr; 146258509Seric } 146357249Seric a->q_host = NULL; 146458509Seric } 14653149Seric 14663149Seric /* figure out the user */ 146758050Seric if (*tv == NULL || (**tv & 0377) != CANONUSER) 14684279Seric { 146958151Seric syserr("554 buildaddr: no user"); 147064306Seric goto badaddr; 14714279Seric } 147257402Seric tv++; 147351317Seric 147468098Seric if (bitnset(M_CHECKUDB, m->m_flags) && *tv != NULL && 147568098Seric strcmp(*tv, "@") == 0) 147668098Seric { 147768098Seric tv++; 147868098Seric a->q_flags |= QNOTREMOTE; 147968098Seric } 148068098Seric 148157402Seric /* do special mapping for local mailer */ 148267472Seric if (*tv != NULL) 148357402Seric { 148457454Seric register char *p = *tv; 148557454Seric 148657454Seric if (*p == '"') 148757454Seric p++; 148867472Seric if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags)) 148957402Seric a->q_mailer = m = ProgMailer; 149067472Seric else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags)) 149157402Seric a->q_mailer = m = FileMailer; 149267472Seric else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags)) 149357402Seric { 149457402Seric /* may be :include: */ 149558814Seric cataddr(tv, NULL, buf, sizeof buf, '\0'); 149658008Seric stripquotes(buf); 149758008Seric if (strncasecmp(buf, ":include:", 9) == 0) 149858008Seric { 149958008Seric /* if :include:, don't need further rewriting */ 150057402Seric a->q_mailer = m = InclMailer; 150158008Seric a->q_user = &buf[9]; 150258008Seric return (a); 150358008Seric } 150457402Seric } 150557402Seric } 150657402Seric 150764284Seric /* rewrite according recipient mailer rewriting rules */ 150864284Seric define('h', a->q_host, e); 150964284Seric if (!bitset(RF_SENDERADDR|RF_HEADERADDR, flags)) 151064284Seric { 151164284Seric /* sender addresses done later */ 151265071Seric (void) rewrite(tv, 2, 0, e); 151364284Seric if (m->m_re_rwset > 0) 151465071Seric (void) rewrite(tv, m->m_re_rwset, 0, e); 151564284Seric } 151665071Seric (void) rewrite(tv, 4, 0, e); 151719040Seric 151819040Seric /* save the result for the command line/RCPT argument */ 151958814Seric cataddr(tv, NULL, buf, sizeof buf, '\0'); 15203149Seric a->q_user = buf; 15213149Seric 152258670Seric /* 152358670Seric ** Do mapping to lower case as requested by mailer 152458670Seric */ 152558670Seric 152658670Seric if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags)) 152758670Seric makelower(a->q_host); 152858670Seric if (!bitnset(M_USR_UPPER, m->m_flags)) 152958670Seric makelower(a->q_user); 153058670Seric 15313149Seric return (a); 15323149Seric } 15333188Seric /* 15344228Seric ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 15354228Seric ** 15364228Seric ** Parameters: 15374228Seric ** pvp -- parameter vector to rebuild. 153858814Seric ** evp -- last parameter to include. Can be NULL to 153958814Seric ** use entire pvp. 15404228Seric ** buf -- buffer to build the string into. 15414228Seric ** sz -- size of buf. 154258082Seric ** spacesub -- the space separator character; if null, 154358082Seric ** use SpaceSub. 15444228Seric ** 15454228Seric ** Returns: 15464228Seric ** none. 15474228Seric ** 15484228Seric ** Side Effects: 15494228Seric ** Destroys buf. 15504228Seric */ 15514228Seric 155258814Seric cataddr(pvp, evp, buf, sz, spacesub) 15534228Seric char **pvp; 155458814Seric char **evp; 15554228Seric char *buf; 15564228Seric register int sz; 155758082Seric char spacesub; 15584228Seric { 15594228Seric bool oatomtok = FALSE; 156056678Seric bool natomtok = FALSE; 15614228Seric register int i; 15624228Seric register char *p; 15634228Seric 156458082Seric if (spacesub == '\0') 156558082Seric spacesub = SpaceSub; 156658082Seric 15678423Seric if (pvp == NULL) 15688423Seric { 156923109Seric (void) strcpy(buf, ""); 15708423Seric return; 15718423Seric } 15724228Seric p = buf; 157311156Seric sz -= 2; 15744228Seric while (*pvp != NULL && (i = strlen(*pvp)) < sz) 15754228Seric { 1576*68711Seric natomtok = (TokTypeTab[**pvp & 0xff] == ATM); 15774228Seric if (oatomtok && natomtok) 157858082Seric *p++ = spacesub; 15794228Seric (void) strcpy(p, *pvp); 15804228Seric oatomtok = natomtok; 15814228Seric p += i; 158211156Seric sz -= i + 1; 158358814Seric if (pvp++ == evp) 158458814Seric break; 15854228Seric } 15864228Seric *p = '\0'; 15874228Seric } 15884228Seric /* 15893188Seric ** SAMEADDR -- Determine if two addresses are the same 15903188Seric ** 15913188Seric ** This is not just a straight comparison -- if the mailer doesn't 15923188Seric ** care about the host we just ignore it, etc. 15933188Seric ** 15943188Seric ** Parameters: 15953188Seric ** a, b -- pointers to the internal forms to compare. 15963188Seric ** 15973188Seric ** Returns: 15983188Seric ** TRUE -- they represent the same mailbox. 15993188Seric ** FALSE -- they don't. 16003188Seric ** 16013188Seric ** Side Effects: 16023188Seric ** none. 16033188Seric */ 16043188Seric 16053188Seric bool 16069374Seric sameaddr(a, b) 16073188Seric register ADDRESS *a; 16083188Seric register ADDRESS *b; 16093188Seric { 161065093Seric register ADDRESS *ca, *cb; 161165093Seric 16123188Seric /* if they don't have the same mailer, forget it */ 16133188Seric if (a->q_mailer != b->q_mailer) 16143188Seric return (FALSE); 16153188Seric 16163188Seric /* if the user isn't the same, we can drop out */ 161756678Seric if (strcmp(a->q_user, b->q_user) != 0) 16183188Seric return (FALSE); 16193188Seric 162065093Seric /* if we have good uids for both but they differ, these are different */ 162165379Seric if (a->q_mailer == ProgMailer) 162265379Seric { 162365379Seric ca = getctladdr(a); 162465379Seric cb = getctladdr(b); 162565379Seric if (ca != NULL && cb != NULL && 162665379Seric bitset(QGOODUID, ca->q_flags & cb->q_flags) && 162765379Seric ca->q_uid != cb->q_uid) 162865379Seric return (FALSE); 162965379Seric } 163058438Seric 163158509Seric /* otherwise compare hosts (but be careful for NULL ptrs) */ 163258509Seric if (a->q_host == b->q_host) 163358509Seric { 163458509Seric /* probably both null pointers */ 16353188Seric return (TRUE); 163658509Seric } 16373188Seric if (a->q_host == NULL || b->q_host == NULL) 163858509Seric { 163958509Seric /* only one is a null pointer */ 16403188Seric return (FALSE); 164158509Seric } 164256678Seric if (strcmp(a->q_host, b->q_host) != 0) 16433188Seric return (FALSE); 16443188Seric 16453188Seric return (TRUE); 16463188Seric } 16473234Seric /* 16483234Seric ** PRINTADDR -- print address (for debugging) 16493234Seric ** 16503234Seric ** Parameters: 16513234Seric ** a -- the address to print 16523234Seric ** follow -- follow the q_next chain. 16533234Seric ** 16543234Seric ** Returns: 16553234Seric ** none. 16563234Seric ** 16573234Seric ** Side Effects: 16583234Seric ** none. 16593234Seric */ 16603234Seric 166167994Seric struct qflags 166267994Seric { 166367994Seric char *qf_name; 166467994Seric u_long qf_bit; 166567994Seric }; 166667994Seric 166767994Seric struct qflags AddressFlags[] = 166867994Seric { 166967994Seric "QDONTSEND", QDONTSEND, 167067994Seric "QBADADDR", QBADADDR, 167167994Seric "QGOODUID", QGOODUID, 167267994Seric "QPRIMARY", QPRIMARY, 167367994Seric "QQUEUEUP", QQUEUEUP, 167467994Seric "QSENT", QSENT, 167567994Seric "QNOTREMOTE", QNOTREMOTE, 167667994Seric "QSELFREF", QSELFREF, 167767994Seric "QVERIFIED", QVERIFIED, 167867994Seric "QREPORT", QREPORT, 167967994Seric "QBOGUSSHELL", QBOGUSSHELL, 168067994Seric "QUNSAFEADDR", QUNSAFEADDR, 168167994Seric "QPINGONSUCCESS", QPINGONSUCCESS, 168267994Seric "QPINGONFAILURE", QPINGONFAILURE, 168367994Seric "QPINGONDELAY", QPINGONDELAY, 168468595Seric "QHASNOTIFY", QHASNOTIFY, 168567994Seric "QRELAYED", QRELAYED, 168668603Seric "QEXPLODED", QEXPLODED, 168768603Seric "QTHISPASS", QTHISPASS, 168867994Seric NULL 168967994Seric }; 169067994Seric 169168433Seric void 16923234Seric printaddr(a, follow) 16933234Seric register ADDRESS *a; 16943234Seric bool follow; 16953234Seric { 169657731Seric register MAILER *m; 169757731Seric MAILER pseudomailer; 169867994Seric register struct qflags *qfp; 169967994Seric bool firstone; 17005001Seric 170167994Seric if (a == NULL) 170267994Seric { 170367994Seric printf("[NULL]\n"); 170467994Seric return; 170567994Seric } 170667994Seric 17073234Seric while (a != NULL) 17083234Seric { 17094443Seric printf("%x=", a); 17104085Seric (void) fflush(stdout); 171157731Seric 171257731Seric /* find the mailer -- carefully */ 171357731Seric m = a->q_mailer; 171457731Seric if (m == NULL) 171557731Seric { 171657731Seric m = &pseudomailer; 171757731Seric m->m_mno = -1; 171857731Seric m->m_name = "NULL"; 171957731Seric } 172057731Seric 172168603Seric printf("%s:\n\tmailer %d (%s), host `%s'\n", 172257731Seric a->q_paddr, m->m_mno, m->m_name, 172368603Seric a->q_host == NULL ? "<null>" : a->q_host); 172468603Seric printf("\tuser `%s', ruser `%s'\n", 172568603Seric a->q_user, 172667172Seric a->q_ruser == NULL ? "<null>" : a->q_ruser); 172767994Seric printf("\tnext=%x, alias %x, uid %d, gid %d\n", 172867994Seric a->q_next, a->q_alias, a->q_uid, a->q_gid); 172967994Seric printf("\tflags=%lx<", a->q_flags); 173067994Seric firstone = TRUE; 173167994Seric for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++) 173267994Seric { 173367994Seric if (!bitset(qfp->qf_bit, a->q_flags)) 173467994Seric continue; 173567994Seric if (!firstone) 173667994Seric printf(","); 173767994Seric firstone = FALSE; 173867994Seric printf("%s", qfp->qf_name); 173967994Seric } 174067994Seric printf(">\n"); 174159269Seric printf("\towner=%s, home=\"%s\", fullname=\"%s\"\n", 174259269Seric a->q_owner == NULL ? "(none)" : a->q_owner, 174363756Seric a->q_home == NULL ? "(none)" : a->q_home, 174463756Seric a->q_fullname == NULL ? "(none)" : a->q_fullname); 174568228Seric printf("\torcpt=\"%s\", statmta=%s, rstatus=%s\n", 174667987Seric a->q_orcpt == NULL ? "(none)" : a->q_orcpt, 174767987Seric a->q_statmta == NULL ? "(none)" : a->q_statmta, 174867990Seric a->q_rstatus == NULL ? "(none)" : a->q_rstatus); 17494996Seric 17503234Seric if (!follow) 17513234Seric return; 17524996Seric a = a->q_next; 17533234Seric } 17543234Seric } 175567939Seric /* 175667939Seric ** EMPTYADDR -- return TRUE if this address is empty (``<>'') 175767939Seric ** 175867939Seric ** Parameters: 175967939Seric ** a -- pointer to the address 176067939Seric ** 176167939Seric ** Returns: 176267939Seric ** TRUE -- if this address is "empty" (i.e., no one should 176367939Seric ** ever generate replies to it. 176467939Seric ** FALSE -- if it is a "regular" (read: replyable) address. 176567939Seric */ 17664317Seric 176767939Seric bool 176867939Seric emptyaddr(a) 176967939Seric register ADDRESS *a; 177067939Seric { 177167939Seric return strcmp(a->q_paddr, "<>") == 0 || strcmp(a->q_user, "<>") == 0; 177267939Seric } 17737682Seric /* 17747682Seric ** REMOTENAME -- return the name relative to the current mailer 17757682Seric ** 17767682Seric ** Parameters: 17777682Seric ** name -- the name to translate. 17788069Seric ** m -- the mailer that we want to do rewriting relative 17798069Seric ** to. 178059163Seric ** flags -- fine tune operations. 178159163Seric ** pstat -- pointer to status word. 178258020Seric ** e -- the current envelope. 17837682Seric ** 17847682Seric ** Returns: 17857682Seric ** the text string representing this address relative to 17867682Seric ** the receiving mailer. 17877682Seric ** 17887682Seric ** Side Effects: 17897682Seric ** none. 17907682Seric ** 17917682Seric ** Warnings: 17927682Seric ** The text string returned is tucked away locally; 17937682Seric ** copy it if you intend to save it. 17947682Seric */ 17957682Seric 17967682Seric char * 179759163Seric remotename(name, m, flags, pstat, e) 17987682Seric char *name; 179956678Seric struct mailer *m; 180059163Seric int flags; 180159163Seric int *pstat; 180256678Seric register ENVELOPE *e; 18037682Seric { 18048069Seric register char **pvp; 18058069Seric char *fancy; 180656678Seric char *oldg = macvalue('g', e); 180758020Seric int rwset; 180868528Seric static char buf[MAXNAME + 1]; 180968528Seric char lbuf[MAXNAME + 1]; 181016914Seric char pvpbuf[PSBUFSIZE]; 181156678Seric extern char *crackaddr(); 18127682Seric 18137755Seric if (tTd(12, 1)) 18147755Seric printf("remotename(%s)\n", name); 18157755Seric 181610177Seric /* don't do anything if we are tagging it as special */ 181759163Seric if (bitset(RF_SENDERADDR, flags)) 181859163Seric rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset 181959163Seric : m->m_se_rwset; 182058020Seric else 182159163Seric rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset 182259163Seric : m->m_re_rwset; 182358020Seric if (rwset < 0) 182410177Seric return (name); 182510177Seric 18267682Seric /* 18278181Seric ** Do a heuristic crack of this name to extract any comment info. 18288181Seric ** This will leave the name as a comment and a $g macro. 18297889Seric */ 18307889Seric 183159163Seric if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) 183258050Seric fancy = "\201g"; 183310310Seric else 183410310Seric fancy = crackaddr(name); 18357889Seric 18368181Seric /* 18378181Seric ** Turn the name into canonical form. 18388181Seric ** Normally this will be RFC 822 style, i.e., "user@domain". 18398181Seric ** If this only resolves to "user", and the "C" flag is 18408181Seric ** specified in the sending mailer, then the sender's 18418181Seric ** domain will be appended. 18428181Seric */ 18438181Seric 1844*68711Seric pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL); 18457889Seric if (pvp == NULL) 18467889Seric return (name); 184765071Seric if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 184859163Seric *pstat = EX_TEMPFAIL; 184959163Seric if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) 18508181Seric { 18518181Seric /* append from domain to this address */ 18528181Seric register char **pxp = pvp; 18538181Seric 18549594Seric /* see if there is an "@domain" in the current name */ 18558181Seric while (*pxp != NULL && strcmp(*pxp, "@") != 0) 18568181Seric pxp++; 18578181Seric if (*pxp == NULL) 18588181Seric { 18599594Seric /* no.... append the "@domain" from the sender */ 186056678Seric register char **qxq = e->e_fromdomain; 18618181Seric 18629594Seric while ((*pxp++ = *qxq++) != NULL) 18639594Seric continue; 186465071Seric if (rewrite(pvp, 3, 0, e) == EX_TEMPFAIL) 186559163Seric *pstat = EX_TEMPFAIL; 18668181Seric } 18678181Seric } 18688181Seric 18698181Seric /* 18708959Seric ** Do more specific rewriting. 187156678Seric ** Rewrite using ruleset 1 or 2 depending on whether this is 187256678Seric ** a sender address or not. 18738181Seric ** Then run it through any receiving-mailer-specific rulesets. 18748181Seric */ 18758181Seric 187659163Seric if (bitset(RF_SENDERADDR, flags)) 187759541Seric { 187865071Seric if (rewrite(pvp, 1, 0, e) == EX_TEMPFAIL) 187959163Seric *pstat = EX_TEMPFAIL; 188059541Seric } 18818069Seric else 188259541Seric { 188365071Seric if (rewrite(pvp, 2, 0, e) == EX_TEMPFAIL) 188459163Seric *pstat = EX_TEMPFAIL; 188559541Seric } 188658020Seric if (rwset > 0) 188759541Seric { 188865071Seric if (rewrite(pvp, rwset, 0, e) == EX_TEMPFAIL) 188959163Seric *pstat = EX_TEMPFAIL; 189059541Seric } 18917682Seric 18928181Seric /* 18938959Seric ** Do any final sanitation the address may require. 18948959Seric ** This will normally be used to turn internal forms 18958959Seric ** (e.g., user@host.LOCAL) into external form. This 18968959Seric ** may be used as a default to the above rules. 18978959Seric */ 18988959Seric 189965071Seric if (rewrite(pvp, 4, 0, e) == EX_TEMPFAIL) 190059163Seric *pstat = EX_TEMPFAIL; 19018959Seric 19028959Seric /* 19038181Seric ** Now restore the comment information we had at the beginning. 19048181Seric */ 19058181Seric 190658825Seric cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0'); 190756678Seric define('g', lbuf, e); 190865494Seric 190965494Seric /* need to make sure route-addrs have <angle brackets> */ 191065494Seric if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@') 191168529Seric expand("<\201g>", buf, sizeof buf, e); 191265494Seric else 191368529Seric expand(fancy, buf, sizeof buf, e); 191465494Seric 191556678Seric define('g', oldg, e); 19167682Seric 19177682Seric if (tTd(12, 1)) 19187755Seric printf("remotename => `%s'\n", buf); 19197682Seric return (buf); 19207682Seric } 192151317Seric /* 192256678Seric ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 192351317Seric ** 192451317Seric ** Parameters: 192556678Seric ** a -- the address to map (but just the user name part). 192656678Seric ** sendq -- the sendq in which to install any replacement 192756678Seric ** addresses. 192867982Seric ** aliaslevel -- the alias nesting depth. 192967982Seric ** e -- the envelope. 193051317Seric ** 193151317Seric ** Returns: 193251317Seric ** none. 193351317Seric */ 193451317Seric 193567982Seric maplocaluser(a, sendq, aliaslevel, e) 193656678Seric register ADDRESS *a; 193756678Seric ADDRESS **sendq; 193867982Seric int aliaslevel; 193956678Seric ENVELOPE *e; 194051317Seric { 194156678Seric register char **pvp; 194256678Seric register ADDRESS *a1 = NULL; 194358333Seric auto char *delimptr; 194456678Seric char pvpbuf[PSBUFSIZE]; 194551317Seric 194656678Seric if (tTd(29, 1)) 194756678Seric { 194856678Seric printf("maplocaluser: "); 194956678Seric printaddr(a, FALSE); 195056678Seric } 1951*68711Seric pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr, NULL); 195256678Seric if (pvp == NULL) 195356678Seric return; 195451317Seric 195565071Seric (void) rewrite(pvp, 5, 0, e); 195658050Seric if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 195756678Seric return; 195851317Seric 195956678Seric /* if non-null, mailer destination specified -- has it changed? */ 196064284Seric a1 = buildaddr(pvp, NULL, 0, e); 196156678Seric if (a1 == NULL || sameaddr(a, a1)) 196256678Seric return; 196351317Seric 196456678Seric /* mark old address as dead; insert new address */ 196556678Seric a->q_flags |= QDONTSEND; 196657731Seric if (tTd(29, 5)) 196757731Seric { 196857731Seric printf("maplocaluser: QDONTSEND "); 196957731Seric printaddr(a, FALSE); 197057731Seric } 197156678Seric a1->q_alias = a; 197264348Seric allocaddr(a1, RF_COPYALL, NULL); 197367982Seric (void) recipient(a1, sendq, aliaslevel, e); 197451317Seric } 197558802Seric /* 197658802Seric ** DEQUOTE_INIT -- initialize dequote map 197758802Seric ** 197858802Seric ** This is a no-op. 197958802Seric ** 198058802Seric ** Parameters: 198158802Seric ** map -- the internal map structure. 198258802Seric ** args -- arguments. 198358802Seric ** 198458802Seric ** Returns: 198558802Seric ** TRUE. 198658802Seric */ 198758802Seric 198858802Seric bool 198960219Seric dequote_init(map, args) 199058802Seric MAP *map; 199158802Seric char *args; 199258802Seric { 199358805Seric register char *p = args; 199458805Seric 199558805Seric for (;;) 199658805Seric { 199758805Seric while (isascii(*p) && isspace(*p)) 199858805Seric p++; 199958805Seric if (*p != '-') 200058805Seric break; 200158805Seric switch (*++p) 200258805Seric { 200358805Seric case 'a': 200458805Seric map->map_app = ++p; 200558805Seric break; 200667824Seric 200767824Seric case 's': 200867824Seric map->map_coldelim = *++p; 200967824Seric break; 201058805Seric } 201158805Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 201258805Seric p++; 201358805Seric if (*p != '\0') 201458805Seric *p = '\0'; 201558805Seric } 201658805Seric if (map->map_app != NULL) 201758805Seric map->map_app = newstr(map->map_app); 201858805Seric 201958802Seric return TRUE; 202058802Seric } 202158802Seric /* 202258802Seric ** DEQUOTE_MAP -- unquote an address 202358802Seric ** 202458802Seric ** Parameters: 202558802Seric ** map -- the internal map structure (ignored). 202660089Seric ** name -- the name to dequote. 202758802Seric ** av -- arguments (ignored). 202859084Seric ** statp -- pointer to status out-parameter. 202958802Seric ** 203058802Seric ** Returns: 203158802Seric ** NULL -- if there were no quotes, or if the resulting 203258802Seric ** unquoted buffer would not be acceptable to prescan. 203358802Seric ** else -- The dequoted buffer. 203458802Seric */ 203558802Seric 203658802Seric char * 203760089Seric dequote_map(map, name, av, statp) 203858802Seric MAP *map; 203960089Seric char *name; 204058802Seric char **av; 204159084Seric int *statp; 204258802Seric { 204358802Seric register char *p; 204458802Seric register char *q; 204558802Seric register char c; 204667824Seric int anglecnt = 0; 204767824Seric int cmntcnt = 0; 204867824Seric int quotecnt = 0; 204967824Seric int spacecnt = 0; 205067824Seric bool quotemode = FALSE; 205167824Seric bool bslashmode = FALSE; 205267824Seric char spacesub = map->map_coldelim; 205358802Seric 205460089Seric for (p = q = name; (c = *p++) != '\0'; ) 205558802Seric { 205658802Seric if (bslashmode) 205758802Seric { 205858802Seric bslashmode = FALSE; 205958802Seric *q++ = c; 206058802Seric continue; 206158802Seric } 206258802Seric 206367824Seric if (c == ' ' && spacesub != '\0') 206467824Seric c = spacesub; 206567764Seric 206658802Seric switch (c) 206758802Seric { 206858802Seric case '\\': 206958802Seric bslashmode = TRUE; 207058802Seric break; 207158802Seric 207258802Seric case '(': 207358802Seric cmntcnt++; 207458802Seric break; 207558802Seric 207658802Seric case ')': 207758802Seric if (cmntcnt-- <= 0) 207858802Seric return NULL; 207958802Seric break; 208059089Seric 208159089Seric case ' ': 208259089Seric spacecnt++; 208359089Seric break; 208458802Seric } 208558802Seric 208658802Seric if (cmntcnt > 0) 208758802Seric { 208858802Seric *q++ = c; 208958802Seric continue; 209058802Seric } 209158802Seric 209258802Seric switch (c) 209358802Seric { 209458802Seric case '"': 209558802Seric quotemode = !quotemode; 209658802Seric quotecnt++; 209758802Seric continue; 209858802Seric 209958802Seric case '<': 210058802Seric anglecnt++; 210158802Seric break; 210258802Seric 210358802Seric case '>': 210458802Seric if (anglecnt-- <= 0) 210558802Seric return NULL; 210658802Seric break; 210758802Seric } 210858802Seric *q++ = c; 210958802Seric } 211058802Seric 211158802Seric if (anglecnt != 0 || cmntcnt != 0 || bslashmode || 211259089Seric quotemode || quotecnt <= 0 || spacecnt != 0) 211358802Seric return NULL; 211458802Seric *q++ = '\0'; 211560089Seric return name; 211658802Seric } 2117