parseaddr.c revision 98841
138032Speter/* 294334Sgshapiro * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers. 364562Sgshapiro * All rights reserved. 438032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 538032Speter * Copyright (c) 1988, 1993 638032Speter * The Regents of the University of California. All rights reserved. 738032Speter * 838032Speter * By using this file, you agree to the terms and conditions set 938032Speter * forth in the LICENSE file which can be found at the top level of 1038032Speter * the sendmail distribution. 1138032Speter * 1238032Speter */ 1338032Speter 1464562Sgshapiro#include <sendmail.h> 1538032Speter 1698841SgshapiroSM_RCSID("@(#)$Id: parseaddr.c,v 8.359.2.1 2002/06/19 18:24:26 gshapiro Exp $") 1790792Sgshapiro 1890792Sgshapirostatic void allocaddr __P((ADDRESS *, int, char *, ENVELOPE *)); 1964562Sgshapirostatic int callsubr __P((char**, int, ENVELOPE *)); 2064562Sgshapirostatic char *map_lookup __P((STAB *, char *, char **, int *, ENVELOPE *)); 2164562Sgshapirostatic ADDRESS *buildaddr __P((char **, ADDRESS *, int, ENVELOPE *)); 2294334Sgshapirostatic bool hasctrlchar __P((register char *, bool, bool)); 2364562Sgshapiro 2494334Sgshapiro/* replacement for illegal characters in addresses */ 2594334Sgshapiro#define BAD_CHAR_REPLACEMENT '?' 2694334Sgshapiro 2738032Speter/* 2838032Speter** PARSEADDR -- Parse an address 2938032Speter** 3038032Speter** Parses an address and breaks it up into three parts: a 3138032Speter** net to transmit the message on, the host to transmit it 3238032Speter** to, and a user on that host. These are loaded into an 3338032Speter** ADDRESS header with the values squirreled away if necessary. 3438032Speter** The "user" part may not be a real user; the process may 3538032Speter** just reoccur on that machine. For example, on a machine 3638032Speter** with an arpanet connection, the address 3738032Speter** csvax.bill@berkeley 3838032Speter** will break up to a "user" of 'csvax.bill' and a host 3938032Speter** of 'berkeley' -- to be transmitted over the arpanet. 4038032Speter** 4138032Speter** Parameters: 4238032Speter** addr -- the address to parse. 4338032Speter** a -- a pointer to the address descriptor buffer. 4490792Sgshapiro** If NULL, an address will be created. 4538032Speter** flags -- describe detail for parsing. See RF_ definitions 4638032Speter** in sendmail.h. 4738032Speter** delim -- the character to terminate the address, passed 4838032Speter** to prescan. 4938032Speter** delimptr -- if non-NULL, set to the location of the 5038032Speter** delim character that was found. 5138032Speter** e -- the envelope that will contain this address. 5290792Sgshapiro** isrcpt -- true if the address denotes a recipient; false 5390792Sgshapiro** indicates a sender. 5438032Speter** 5538032Speter** Returns: 5638032Speter** A pointer to the address descriptor header (`a' if 5738032Speter** `a' is non-NULL). 5838032Speter** NULL on error. 5938032Speter** 6038032Speter** Side Effects: 6190792Sgshapiro** e->e_to = addr 6238032Speter*/ 6338032Speter 6438032Speter/* following delimiters are inherent to the internal algorithms */ 6564562Sgshapiro#define DELIMCHARS "()<>,;\r\n" /* default word delimiters */ 6638032Speter 6738032SpeterADDRESS * 6890792Sgshapiroparseaddr(addr, a, flags, delim, delimptr, e, isrcpt) 6938032Speter char *addr; 7038032Speter register ADDRESS *a; 7138032Speter int flags; 7238032Speter int delim; 7338032Speter char **delimptr; 7438032Speter register ENVELOPE *e; 7590792Sgshapiro bool isrcpt; 7638032Speter{ 7790792Sgshapiro char **pvp; 7838032Speter auto char *delimptrbuf; 7964562Sgshapiro bool qup; 8038032Speter char pvpbuf[PSBUFSIZE]; 8138032Speter 8238032Speter /* 8338032Speter ** Initialize and prescan address. 8438032Speter */ 8538032Speter 8638032Speter e->e_to = addr; 8738032Speter if (tTd(20, 1)) 8890792Sgshapiro sm_dprintf("\n--parseaddr(%s)\n", addr); 8938032Speter 9038032Speter if (delimptr == NULL) 9138032Speter delimptr = &delimptrbuf; 9238032Speter 9338032Speter pvp = prescan(addr, delim, pvpbuf, sizeof pvpbuf, delimptr, NULL); 9438032Speter if (pvp == NULL) 9538032Speter { 9638032Speter if (tTd(20, 1)) 9790792Sgshapiro sm_dprintf("parseaddr-->NULL\n"); 9864562Sgshapiro return NULL; 9938032Speter } 10038032Speter 10190792Sgshapiro if (invalidaddr(addr, delim == '\0' ? NULL : *delimptr, isrcpt)) 10238032Speter { 10338032Speter if (tTd(20, 1)) 10490792Sgshapiro sm_dprintf("parseaddr-->bad address\n"); 10538032Speter return NULL; 10638032Speter } 10738032Speter 10838032Speter /* 10938032Speter ** Save addr if we are going to have to. 11038032Speter ** 11138032Speter ** We have to do this early because there is a chance that 11238032Speter ** the map lookups in the rewriting rules could clobber 11338032Speter ** static memory somewhere. 11438032Speter */ 11538032Speter 11638032Speter if (bitset(RF_COPYPADDR, flags) && addr != NULL) 11738032Speter { 11838032Speter char savec = **delimptr; 11938032Speter 12038032Speter if (savec != '\0') 12138032Speter **delimptr = '\0'; 12290792Sgshapiro e->e_to = addr = sm_rpool_strdup_x(e->e_rpool, addr); 12338032Speter if (savec != '\0') 12438032Speter **delimptr = savec; 12538032Speter } 12638032Speter 12738032Speter /* 12838032Speter ** Apply rewriting rules. 12938032Speter ** Ruleset 0 does basic parsing. It must resolve. 13038032Speter */ 13138032Speter 13290792Sgshapiro qup = false; 13390792Sgshapiro if (REWRITE(pvp, 3, e) == EX_TEMPFAIL) 13490792Sgshapiro qup = true; 13590792Sgshapiro if (REWRITE(pvp, 0, e) == EX_TEMPFAIL) 13690792Sgshapiro qup = true; 13738032Speter 13838032Speter /* 13938032Speter ** Build canonical address from pvp. 14038032Speter */ 14138032Speter 14238032Speter a = buildaddr(pvp, a, flags, e); 14338032Speter 14494334Sgshapiro if (hasctrlchar(a->q_user, isrcpt, true)) 14590792Sgshapiro { 14690792Sgshapiro if (tTd(20, 1)) 14790792Sgshapiro sm_dprintf("parseaddr-->bad q_user\n"); 14894334Sgshapiro 14994334Sgshapiro /* 15094334Sgshapiro ** Just mark the address as bad so DSNs work. 15194334Sgshapiro ** hasctrlchar() has to make sure that the address 15294334Sgshapiro ** has been sanitized, e.g., shortened. 15394334Sgshapiro */ 15494334Sgshapiro 15594334Sgshapiro a->q_state = QS_BADADDR; 15690792Sgshapiro } 15790792Sgshapiro 15838032Speter /* 15938032Speter ** Make local copies of the host & user and then 16038032Speter ** transport them out. 16138032Speter */ 16238032Speter 16390792Sgshapiro allocaddr(a, flags, addr, e); 16464562Sgshapiro if (QS_IS_BADADDR(a->q_state)) 16594334Sgshapiro { 16694334Sgshapiro /* weed out bad characters in the printable address too */ 16794334Sgshapiro (void) hasctrlchar(a->q_paddr, isrcpt, false); 16838032Speter return a; 16994334Sgshapiro } 17038032Speter 17138032Speter /* 17290792Sgshapiro ** Select a queue directory for recipient addresses. 17390792Sgshapiro ** This is done here and in split_across_queue_groups(), 17490792Sgshapiro ** but the latter applies to addresses after aliasing, 17590792Sgshapiro ** and only if splitting is done. 17690792Sgshapiro */ 17790792Sgshapiro 17890792Sgshapiro if ((a->q_qgrp == NOAQGRP || a->q_qgrp == ENVQGRP) && 17990792Sgshapiro !bitset(RF_SENDERADDR|RF_HEADERADDR, flags) && 18090792Sgshapiro OpMode != MD_INITALIAS) 18190792Sgshapiro { 18290792Sgshapiro int r; 18390792Sgshapiro 18490792Sgshapiro /* call ruleset which should return a queue group name */ 18590792Sgshapiro r = rscap(RS_QUEUEGROUP, a->q_user, NULL, e, &pvp, pvpbuf, 18690792Sgshapiro sizeof(pvpbuf)); 18790792Sgshapiro if (r == EX_OK && 18890792Sgshapiro pvp != NULL && pvp[0] != NULL && 18990792Sgshapiro (pvp[0][0] & 0377) == CANONNET && 19090792Sgshapiro pvp[1] != NULL && pvp[1][0] != '\0') 19190792Sgshapiro { 19290792Sgshapiro r = name2qid(pvp[1]); 19390792Sgshapiro if (r == NOQGRP && LogLevel > 10) 19490792Sgshapiro sm_syslog(LOG_INFO, NOQID, 19590792Sgshapiro "can't find queue group name %s, selection ignored", 19690792Sgshapiro pvp[1]); 19790792Sgshapiro if (tTd(20, 4) && r != NOQGRP) 19890792Sgshapiro sm_syslog(LOG_INFO, NOQID, 19990792Sgshapiro "queue group name %s -> %d", 20090792Sgshapiro pvp[1], r); 20190792Sgshapiro a->q_qgrp = r == NOQGRP ? ENVQGRP : r; 20290792Sgshapiro } 20390792Sgshapiro } 20490792Sgshapiro 20590792Sgshapiro /* 20638032Speter ** If there was a parsing failure, mark it for queueing. 20738032Speter */ 20838032Speter 20964562Sgshapiro if (qup && OpMode != MD_INITALIAS) 21038032Speter { 21138032Speter char *msg = "Transient parse error -- message queued for future delivery"; 21238032Speter 21338032Speter if (e->e_sendmode == SM_DEFER) 21438032Speter msg = "Deferring message until queue run"; 21538032Speter if (tTd(20, 1)) 21690792Sgshapiro sm_dprintf("parseaddr: queuing message\n"); 21738032Speter message(msg); 21838032Speter if (e->e_message == NULL && e->e_sendmode != SM_DEFER) 21990792Sgshapiro e->e_message = sm_rpool_strdup_x(e->e_rpool, msg); 22064562Sgshapiro a->q_state = QS_QUEUEUP; 22138032Speter a->q_status = "4.4.3"; 22238032Speter } 22338032Speter 22438032Speter /* 22538032Speter ** Compute return value. 22638032Speter */ 22738032Speter 22838032Speter if (tTd(20, 1)) 22938032Speter { 23090792Sgshapiro sm_dprintf("parseaddr-->"); 23190792Sgshapiro printaddr(a, false); 23238032Speter } 23338032Speter 23464562Sgshapiro return a; 23538032Speter} 23690792Sgshapiro/* 23790792Sgshapiro** INVALIDADDR -- check for address containing characters used for macros 23838032Speter** 23938032Speter** Parameters: 24038032Speter** addr -- the address to check. 24190792Sgshapiro** delimptr -- if non-NULL: end of address to check, i.e., 24290792Sgshapiro** a pointer in the address string. 24390792Sgshapiro** isrcpt -- true iff the address is for a recipient. 24438032Speter** 24538032Speter** Returns: 24690792Sgshapiro** true -- if the address has characters that are reservered 24790792Sgshapiro** for macros or is too long. 24890792Sgshapiro** false -- otherwise. 24938032Speter*/ 25038032Speter 25138032Speterbool 25290792Sgshapiroinvalidaddr(addr, delimptr, isrcpt) 25338032Speter register char *addr; 25438032Speter char *delimptr; 25590792Sgshapiro bool isrcpt; 25638032Speter{ 25790792Sgshapiro bool result = false; 25838032Speter char savedelim = '\0'; 25994334Sgshapiro char *b = addr; 26090792Sgshapiro int len = 0; 26138032Speter 26238032Speter if (delimptr != NULL) 26338032Speter { 26490792Sgshapiro /* delimptr points to the end of the address to test */ 26538032Speter savedelim = *delimptr; 26690792Sgshapiro if (savedelim != '\0') /* if that isn't '\0' already: */ 26790792Sgshapiro *delimptr = '\0'; /* set it */ 26838032Speter } 26990792Sgshapiro for (; *addr != '\0'; addr++) 27038032Speter { 27190792Sgshapiro if ((*addr & 0340) == 0200) 27290792Sgshapiro { 27390792Sgshapiro setstat(EX_USAGE); 27490792Sgshapiro result = true; 27594334Sgshapiro *addr = BAD_CHAR_REPLACEMENT; 27690792Sgshapiro } 27790792Sgshapiro if (++len > MAXNAME - 1) 27890792Sgshapiro { 27994334Sgshapiro char saved = *addr; 28094334Sgshapiro 28194334Sgshapiro *addr = '\0'; 28294334Sgshapiro usrerr("553 5.1.0 Address \"%s\" too long (%d bytes max)", 28394334Sgshapiro b, MAXNAME - 1); 28494334Sgshapiro *addr = saved; 28590792Sgshapiro result = true; 28690792Sgshapiro goto delim; 28790792Sgshapiro } 28838032Speter } 28990792Sgshapiro if (result) 29090792Sgshapiro { 29190792Sgshapiro if (isrcpt) 29294334Sgshapiro usrerr("501 5.1.3 8-bit character in mailbox address \"%s\"", 29394334Sgshapiro b); 29490792Sgshapiro else 29594334Sgshapiro usrerr("501 5.1.7 8-bit character in mailbox address \"%s\"", 29694334Sgshapiro b); 29790792Sgshapiro } 29890792Sgshapirodelim: 29990792Sgshapiro if (delimptr != NULL && savedelim != '\0') 30090792Sgshapiro *delimptr = savedelim; /* restore old character at delimptr */ 30190792Sgshapiro return result; 30290792Sgshapiro} 30390792Sgshapiro/* 30490792Sgshapiro** HASCTRLCHAR -- check for address containing meta-characters 30590792Sgshapiro** 30690792Sgshapiro** Checks that the address contains no meta-characters, and contains 30790792Sgshapiro** no "non-printable" characters unless they are quoted or escaped. 30890792Sgshapiro** Quoted or escaped characters are literals. 30990792Sgshapiro** 31090792Sgshapiro** Parameters: 31190792Sgshapiro** addr -- the address to check. 31290792Sgshapiro** isrcpt -- true if the address is for a recipient; false 31390792Sgshapiro** indicates a from. 31494334Sgshapiro** complain -- true if an error should issued if the address 31594334Sgshapiro** is invalid and should be "repaired". 31690792Sgshapiro** 31790792Sgshapiro** Returns: 31890792Sgshapiro** true -- if the address has any "wierd" characters or 31990792Sgshapiro** non-printable characters or if a quote is unbalanced. 32090792Sgshapiro** false -- otherwise. 32190792Sgshapiro*/ 32290792Sgshapiro 32390792Sgshapirostatic bool 32494334Sgshapirohasctrlchar(addr, isrcpt, complain) 32590792Sgshapiro register char *addr; 32694334Sgshapiro bool isrcpt, complain; 32790792Sgshapiro{ 32894334Sgshapiro bool quoted = false; 32990792Sgshapiro int len = 0; 33094334Sgshapiro char *result = NULL; 33194334Sgshapiro char *b = addr; 33290792Sgshapiro 33390792Sgshapiro if (addr == NULL) 33490792Sgshapiro return false; 33538032Speter for (; *addr != '\0'; addr++) 33638032Speter { 33794334Sgshapiro if (++len > MAXNAME - 1) 33894334Sgshapiro { 33994334Sgshapiro if (complain) 34094334Sgshapiro { 34194334Sgshapiro (void) shorten_rfc822_string(b, MAXNAME - 1); 34294334Sgshapiro usrerr("553 5.1.0 Address \"%s\" too long (%d bytes max)", 34394334Sgshapiro b, MAXNAME - 1); 34494334Sgshapiro return true; 34594334Sgshapiro } 34694334Sgshapiro result = "too long"; 34794334Sgshapiro } 34890792Sgshapiro if (!quoted && (*addr < 32 || *addr == 127)) 34990792Sgshapiro { 35094334Sgshapiro result = "non-printable character"; 35194334Sgshapiro *addr = BAD_CHAR_REPLACEMENT; 35294334Sgshapiro continue; 35390792Sgshapiro } 35490792Sgshapiro if (*addr == '"') 35590792Sgshapiro quoted = !quoted; 35690792Sgshapiro else if (*addr == '\\') 35790792Sgshapiro { 35890792Sgshapiro /* XXX Generic problem: no '\0' in strings. */ 35990792Sgshapiro if (*++addr == '\0') 36090792Sgshapiro { 36194334Sgshapiro result = "trailing \\ character"; 36294334Sgshapiro *--addr = BAD_CHAR_REPLACEMENT; 36390792Sgshapiro break; 36490792Sgshapiro } 36590792Sgshapiro } 36638032Speter if ((*addr & 0340) == 0200) 36790792Sgshapiro { 36890792Sgshapiro setstat(EX_USAGE); 36994334Sgshapiro result = "8-bit character"; 37094334Sgshapiro *addr = BAD_CHAR_REPLACEMENT; 37194334Sgshapiro continue; 37290792Sgshapiro } 37338032Speter } 37490792Sgshapiro if (quoted) 37594334Sgshapiro result = "unbalanced quote"; /* unbalanced quote */ 37694334Sgshapiro if (result != NULL && complain) 37738032Speter { 37890792Sgshapiro if (isrcpt) 37994334Sgshapiro usrerr("501 5.1.3 Syntax error in mailbox address \"%s\" (%s)", 38094334Sgshapiro b, result); 38190792Sgshapiro else 38294334Sgshapiro usrerr("501 5.1.7 Syntax error in mailbox address \"%s\" (%s)", 38394334Sgshapiro b, result); 38438032Speter } 38594334Sgshapiro return result != NULL; 38638032Speter} 38790792Sgshapiro/* 38838032Speter** ALLOCADDR -- do local allocations of address on demand. 38938032Speter** 39038032Speter** Also lowercases the host name if requested. 39138032Speter** 39238032Speter** Parameters: 39338032Speter** a -- the address to reallocate. 39438032Speter** flags -- the copy flag (see RF_ definitions in sendmail.h 39538032Speter** for a description). 39638032Speter** paddr -- the printname of the address. 39790792Sgshapiro** e -- envelope 39838032Speter** 39938032Speter** Returns: 40038032Speter** none. 40138032Speter** 40238032Speter** Side Effects: 40338032Speter** Copies portions of a into local buffers as requested. 40438032Speter*/ 40538032Speter 40664562Sgshapirostatic void 40790792Sgshapiroallocaddr(a, flags, paddr, e) 40838032Speter register ADDRESS *a; 40938032Speter int flags; 41038032Speter char *paddr; 41190792Sgshapiro ENVELOPE *e; 41238032Speter{ 41338032Speter if (tTd(24, 4)) 41490792Sgshapiro sm_dprintf("allocaddr(flags=%x, paddr=%s)\n", flags, paddr); 41538032Speter 41638032Speter a->q_paddr = paddr; 41738032Speter 41838032Speter if (a->q_user == NULL) 41990792Sgshapiro a->q_user = ""; 42038032Speter if (a->q_host == NULL) 42190792Sgshapiro a->q_host = ""; 42238032Speter 42338032Speter if (bitset(RF_COPYPARSE, flags)) 42438032Speter { 42590792Sgshapiro a->q_host = sm_rpool_strdup_x(e->e_rpool, a->q_host); 42638032Speter if (a->q_user != a->q_paddr) 42790792Sgshapiro a->q_user = sm_rpool_strdup_x(e->e_rpool, a->q_user); 42838032Speter } 42938032Speter 43038032Speter if (a->q_paddr == NULL) 43190792Sgshapiro a->q_paddr = sm_rpool_strdup_x(e->e_rpool, a->q_user); 43290792Sgshapiro a->q_qgrp = NOAQGRP; 43338032Speter} 43490792Sgshapiro/* 43538032Speter** PRESCAN -- Prescan name and make it canonical 43638032Speter** 43738032Speter** Scans a name and turns it into a set of tokens. This process 43864562Sgshapiro** deletes blanks and comments (in parentheses) (if the token type 43964562Sgshapiro** for left paren is SPC). 44038032Speter** 44138032Speter** This routine knows about quoted strings and angle brackets. 44238032Speter** 44338032Speter** There are certain subtleties to this routine. The one that 44438032Speter** comes to mind now is that backslashes on the ends of names 44538032Speter** are silently stripped off; this is intentional. The problem 44638032Speter** is that some versions of sndmsg (like at LBL) set the kill 44738032Speter** character to something other than @ when reading addresses; 44838032Speter** so people type "csvax.eric\@berkeley" -- which screws up the 44938032Speter** berknet mailer. 45038032Speter** 45138032Speter** Parameters: 45238032Speter** addr -- the name to chomp. 45338032Speter** delim -- the delimiter for the address, normally 45438032Speter** '\0' or ','; \0 is accepted in any case. 45538032Speter** If '\t' then we are reading the .cf file. 45638032Speter** pvpbuf -- place to put the saved text -- note that 45738032Speter** the pointers are static. 45838032Speter** pvpbsize -- size of pvpbuf. 45938032Speter** delimptr -- if non-NULL, set to the location of the 46038032Speter** terminating delimiter. 46138032Speter** toktab -- if set, a token table to use for parsing. 46238032Speter** If NULL, use the default table. 46338032Speter** 46438032Speter** Returns: 46538032Speter** A pointer to a vector of tokens. 46638032Speter** NULL on error. 46738032Speter*/ 46838032Speter 46938032Speter/* states and character types */ 47064562Sgshapiro#define OPR 0 /* operator */ 47164562Sgshapiro#define ATM 1 /* atom */ 47264562Sgshapiro#define QST 2 /* in quoted string */ 47364562Sgshapiro#define SPC 3 /* chewing up spaces */ 47464562Sgshapiro#define ONE 4 /* pick up one character */ 47564562Sgshapiro#define ILL 5 /* illegal character */ 47638032Speter 47764562Sgshapiro#define NSTATES 6 /* number of states */ 47864562Sgshapiro#define TYPE 017 /* mask to select state type */ 47938032Speter 48038032Speter/* meta bits for table */ 48164562Sgshapiro#define M 020 /* meta character; don't pass through */ 48264562Sgshapiro#define B 040 /* cause a break */ 48364562Sgshapiro#define MB M|B /* meta-break */ 48438032Speter 48538032Speterstatic short StateTab[NSTATES][NSTATES] = 48638032Speter{ 48738032Speter /* oldst chtype> OPR ATM QST SPC ONE ILL */ 48838032Speter /*OPR*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|MB }, 48938032Speter /*ATM*/ { OPR|B, ATM, QST|B, SPC|MB, ONE|B, ILL|MB }, 49038032Speter /*QST*/ { QST, QST, OPR, QST, QST, QST }, 49138032Speter /*SPC*/ { OPR, ATM, QST, SPC|M, ONE, ILL|MB }, 49238032Speter /*ONE*/ { OPR, OPR, OPR, OPR, OPR, ILL|MB }, 49338032Speter /*ILL*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|M }, 49438032Speter}; 49538032Speter 49638032Speter/* token type table -- it gets modified with $o characters */ 49790792Sgshapirostatic unsigned char TokTypeTab[256] = 49838032Speter{ 49938032Speter /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 50038032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM, 50138032Speter /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 50238032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 50338032Speter /* sp ! " # $ % & ' ( ) * + , - . / */ 50464562Sgshapiro SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, SPC,SPC,ATM,ATM,ATM,ATM,ATM,ATM, 50538032Speter /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 50638032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 50738032Speter /* @ A B C D E F G H I J K L M N O */ 50838032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 50938032Speter /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 51038032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 51138032Speter /* ` a b c d e f g h i j k l m n o */ 51238032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 51338032Speter /* p q r s t u v w x y z { | } ~ del */ 51438032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 51538032Speter 51638032Speter /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 51738032Speter OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 51838032Speter /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 51938032Speter OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 52038032Speter /* sp ! " # $ % & ' ( ) * + , - . / */ 52138032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 52238032Speter /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 52338032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 52438032Speter /* @ A B C D E F G H I J K L M N O */ 52538032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 52638032Speter /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 52738032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 52838032Speter /* ` a b c d e f g h i j k l m n o */ 52938032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 53038032Speter /* p q r s t u v w x y z { | } ~ del */ 53138032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 53238032Speter}; 53338032Speter 53438032Speter/* token type table for MIME parsing */ 53590792Sgshapirounsigned char MimeTokenTab[256] = 53638032Speter{ 53738032Speter /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 53838032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,SPC,SPC,SPC,SPC,SPC,ILL,ILL, 53938032Speter /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 54038032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 54138032Speter /* sp ! " # $ % & ' ( ) * + , - . / */ 54264562Sgshapiro SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, SPC,SPC,ATM,ATM,OPR,ATM,ATM,OPR, 54338032Speter /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 54438032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,OPR,OPR,OPR,OPR,OPR,OPR, 54538032Speter /* @ A B C D E F G H I J K L M N O */ 54638032Speter OPR,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 54738032Speter /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 54838032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,OPR,OPR,OPR,ATM,ATM, 54938032Speter /* ` a b c d e f g h i j k l m n o */ 55038032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 55138032Speter /* p q r s t u v w x y z { | } ~ del */ 55238032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 55338032Speter 55438032Speter /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 55538032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 55638032Speter /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 55738032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 55838032Speter /* sp ! " # $ % & ' ( ) * + , - . / */ 55938032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 56038032Speter /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 56138032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 56238032Speter /* @ A B C D E F G H I J K L M N O */ 56338032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 56438032Speter /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 56538032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 56638032Speter /* ` a b c d e f g h i j k l m n o */ 56738032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 56838032Speter /* p q r s t u v w x y z { | } ~ del */ 56938032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 57038032Speter}; 57138032Speter 57264562Sgshapiro/* token type table: don't strip comments */ 57390792Sgshapirounsigned char TokTypeNoC[256] = 57464562Sgshapiro{ 57564562Sgshapiro /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 57664562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM, 57764562Sgshapiro /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 57864562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 57964562Sgshapiro /* sp ! " # $ % & ' ( ) * + , - . / */ 58064562Sgshapiro SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, OPR,OPR,ATM,ATM,ATM,ATM,ATM,ATM, 58164562Sgshapiro /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 58264562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 58364562Sgshapiro /* @ A B C D E F G H I J K L M N O */ 58464562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 58564562Sgshapiro /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 58664562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 58764562Sgshapiro /* ` a b c d e f g h i j k l m n o */ 58864562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 58964562Sgshapiro /* p q r s t u v w x y z { | } ~ del */ 59064562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 59138032Speter 59264562Sgshapiro /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 59364562Sgshapiro OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 59464562Sgshapiro /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 59564562Sgshapiro OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 59664562Sgshapiro /* sp ! " # $ % & ' ( ) * + , - . / */ 59764562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 59864562Sgshapiro /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 59964562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 60064562Sgshapiro /* @ A B C D E F G H I J K L M N O */ 60164562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 60264562Sgshapiro /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 60364562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 60464562Sgshapiro /* ` a b c d e f g h i j k l m n o */ 60564562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 60664562Sgshapiro /* p q r s t u v w x y z { | } ~ del */ 60764562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 60864562Sgshapiro}; 60938032Speter 61064562Sgshapiro 61164562Sgshapiro#define NOCHAR -1 /* signal nothing in lookahead token */ 61264562Sgshapiro 61338032Speterchar ** 61438032Speterprescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab) 61538032Speter char *addr; 61638032Speter int delim; 61738032Speter char pvpbuf[]; 61838032Speter int pvpbsize; 61938032Speter char **delimptr; 62090792Sgshapiro unsigned char *toktab; 62138032Speter{ 62238032Speter register char *p; 62338032Speter register char *q; 62438032Speter register int c; 62538032Speter char **avp; 62638032Speter bool bslashmode; 62738032Speter bool route_syntax; 62838032Speter int cmntcnt; 62938032Speter int anglecnt; 63038032Speter char *tok; 63138032Speter int state; 63238032Speter int newstate; 63338032Speter char *saveto = CurEnv->e_to; 63464562Sgshapiro static char *av[MAXATOM + 1]; 63590792Sgshapiro static bool firsttime = true; 63638032Speter extern int errno; 63738032Speter 63838032Speter if (firsttime) 63938032Speter { 64038032Speter /* initialize the token type table */ 64138032Speter char obuf[50]; 64238032Speter 64390792Sgshapiro firsttime = false; 64438032Speter if (OperatorChars == NULL) 64538032Speter { 64638032Speter if (ConfigLevel < 7) 64738032Speter OperatorChars = macvalue('o', CurEnv); 64838032Speter if (OperatorChars == NULL) 64938032Speter OperatorChars = ".:@[]"; 65038032Speter } 65164562Sgshapiro expand(OperatorChars, obuf, sizeof obuf - sizeof DELIMCHARS, 65264562Sgshapiro CurEnv); 65390792Sgshapiro (void) sm_strlcat(obuf, DELIMCHARS, sizeof obuf); 65438032Speter for (p = obuf; *p != '\0'; p++) 65538032Speter { 65638032Speter if (TokTypeTab[*p & 0xff] == ATM) 65738032Speter TokTypeTab[*p & 0xff] = OPR; 65864562Sgshapiro if (TokTypeNoC[*p & 0xff] == ATM) 65964562Sgshapiro TokTypeNoC[*p & 0xff] = OPR; 66038032Speter } 66138032Speter } 66238032Speter if (toktab == NULL) 66338032Speter toktab = TokTypeTab; 66438032Speter 66538032Speter /* make sure error messages don't have garbage on them */ 66638032Speter errno = 0; 66738032Speter 66838032Speter q = pvpbuf; 66990792Sgshapiro bslashmode = false; 67090792Sgshapiro route_syntax = false; 67138032Speter cmntcnt = 0; 67238032Speter anglecnt = 0; 67338032Speter avp = av; 67438032Speter state = ATM; 67538032Speter c = NOCHAR; 67638032Speter p = addr; 67738032Speter CurEnv->e_to = p; 67838032Speter if (tTd(22, 11)) 67938032Speter { 68090792Sgshapiro sm_dprintf("prescan: "); 68138032Speter xputs(p); 68290792Sgshapiro sm_dprintf("\n"); 68338032Speter } 68438032Speter 68538032Speter do 68638032Speter { 68738032Speter /* read a token */ 68838032Speter tok = q; 68938032Speter for (;;) 69038032Speter { 69138032Speter /* store away any old lookahead character */ 69238032Speter if (c != NOCHAR && !bslashmode) 69338032Speter { 69438032Speter /* see if there is room */ 69538032Speter if (q >= &pvpbuf[pvpbsize - 5]) 69638032Speter { 69764562Sgshapiro usrerr("553 5.1.1 Address too long"); 69890792Sgshapiro if (strlen(addr) > MAXNAME) 69938032Speter addr[MAXNAME] = '\0'; 70038032Speter returnnull: 70138032Speter if (delimptr != NULL) 70238032Speter *delimptr = p; 70338032Speter CurEnv->e_to = saveto; 70464562Sgshapiro return NULL; 70538032Speter } 70638032Speter 70738032Speter /* squirrel it away */ 70838032Speter *q++ = c; 70938032Speter } 71038032Speter 71138032Speter /* read a new input character */ 71238032Speter c = *p++; 71338032Speter if (c == '\0') 71438032Speter { 71538032Speter /* diagnose and patch up bad syntax */ 71638032Speter if (state == QST) 71738032Speter { 71890792Sgshapiro usrerr("553 Unbalanced '\"'"); 71938032Speter c = '"'; 72038032Speter } 72138032Speter else if (cmntcnt > 0) 72238032Speter { 72390792Sgshapiro usrerr("553 Unbalanced '('"); 72438032Speter c = ')'; 72538032Speter } 72638032Speter else if (anglecnt > 0) 72738032Speter { 72838032Speter c = '>'; 72990792Sgshapiro usrerr("553 Unbalanced '<'"); 73038032Speter } 73138032Speter else 73238032Speter break; 73338032Speter 73438032Speter p--; 73538032Speter } 73638032Speter else if (c == delim && cmntcnt <= 0 && state != QST) 73738032Speter { 73838032Speter if (anglecnt <= 0) 73938032Speter break; 74038032Speter 74138032Speter /* special case for better error management */ 74238032Speter if (delim == ',' && !route_syntax) 74338032Speter { 74490792Sgshapiro usrerr("553 Unbalanced '<'"); 74538032Speter c = '>'; 74638032Speter p--; 74738032Speter } 74838032Speter } 74938032Speter 75038032Speter if (tTd(22, 101)) 75190792Sgshapiro sm_dprintf("c=%c, s=%d; ", c, state); 75238032Speter 75338032Speter /* chew up special characters */ 75438032Speter *q = '\0'; 75538032Speter if (bslashmode) 75638032Speter { 75790792Sgshapiro bslashmode = false; 75838032Speter 75938032Speter /* kludge \! for naive users */ 76038032Speter if (cmntcnt > 0) 76138032Speter { 76238032Speter c = NOCHAR; 76338032Speter continue; 76438032Speter } 76538032Speter else if (c != '!' || state == QST) 76638032Speter { 76738032Speter *q++ = '\\'; 76838032Speter continue; 76938032Speter } 77038032Speter } 77138032Speter 77238032Speter if (c == '\\') 77338032Speter { 77490792Sgshapiro bslashmode = true; 77538032Speter } 77638032Speter else if (state == QST) 77738032Speter { 77864562Sgshapiro /* EMPTY */ 77938032Speter /* do nothing, just avoid next clauses */ 78038032Speter } 78164562Sgshapiro else if (c == '(' && toktab['('] == SPC) 78238032Speter { 78338032Speter cmntcnt++; 78438032Speter c = NOCHAR; 78538032Speter } 78664562Sgshapiro else if (c == ')' && toktab['('] == SPC) 78738032Speter { 78838032Speter if (cmntcnt <= 0) 78938032Speter { 79090792Sgshapiro usrerr("553 Unbalanced ')'"); 79138032Speter c = NOCHAR; 79238032Speter } 79338032Speter else 79438032Speter cmntcnt--; 79538032Speter } 79638032Speter else if (cmntcnt > 0) 79764562Sgshapiro { 79838032Speter c = NOCHAR; 79964562Sgshapiro } 80038032Speter else if (c == '<') 80138032Speter { 80264562Sgshapiro char *ptr = p; 80338032Speter 80438032Speter anglecnt++; 80564562Sgshapiro while (isascii(*ptr) && isspace(*ptr)) 80664562Sgshapiro ptr++; 80764562Sgshapiro if (*ptr == '@') 80890792Sgshapiro route_syntax = true; 80938032Speter } 81038032Speter else if (c == '>') 81138032Speter { 81238032Speter if (anglecnt <= 0) 81338032Speter { 81490792Sgshapiro usrerr("553 Unbalanced '>'"); 81538032Speter c = NOCHAR; 81638032Speter } 81738032Speter else 81838032Speter anglecnt--; 81990792Sgshapiro route_syntax = false; 82038032Speter } 82138032Speter else if (delim == ' ' && isascii(c) && isspace(c)) 82238032Speter c = ' '; 82338032Speter 82438032Speter if (c == NOCHAR) 82538032Speter continue; 82638032Speter 82738032Speter /* see if this is end of input */ 82838032Speter if (c == delim && anglecnt <= 0 && state != QST) 82938032Speter break; 83038032Speter 83138032Speter newstate = StateTab[state][toktab[c & 0xff]]; 83238032Speter if (tTd(22, 101)) 83390792Sgshapiro sm_dprintf("ns=%02o\n", newstate); 83438032Speter state = newstate & TYPE; 83538032Speter if (state == ILL) 83638032Speter { 83738032Speter if (isascii(c) && isprint(c)) 83890792Sgshapiro usrerr("553 Illegal character %c", c); 83938032Speter else 84090792Sgshapiro usrerr("553 Illegal character 0x%02x", 84190792Sgshapiro c & 0x0ff); 84238032Speter } 84338032Speter if (bitset(M, newstate)) 84438032Speter c = NOCHAR; 84538032Speter if (bitset(B, newstate)) 84638032Speter break; 84738032Speter } 84838032Speter 84938032Speter /* new token */ 85038032Speter if (tok != q) 85138032Speter { 85238032Speter *q++ = '\0'; 85338032Speter if (tTd(22, 36)) 85438032Speter { 85590792Sgshapiro sm_dprintf("tok="); 85638032Speter xputs(tok); 85790792Sgshapiro sm_dprintf("\n"); 85838032Speter } 85938032Speter if (avp >= &av[MAXATOM]) 86038032Speter { 86164562Sgshapiro usrerr("553 5.1.0 prescan: too many tokens"); 86238032Speter goto returnnull; 86338032Speter } 86438032Speter if (q - tok > MAXNAME) 86538032Speter { 86664562Sgshapiro usrerr("553 5.1.0 prescan: token too long"); 86738032Speter goto returnnull; 86838032Speter } 86938032Speter *avp++ = tok; 87038032Speter } 87138032Speter } while (c != '\0' && (c != delim || anglecnt > 0)); 87238032Speter *avp = NULL; 87338032Speter p--; 87438032Speter if (delimptr != NULL) 87538032Speter *delimptr = p; 87638032Speter if (tTd(22, 12)) 87738032Speter { 87890792Sgshapiro sm_dprintf("prescan==>"); 87938032Speter printav(av); 88038032Speter } 88138032Speter CurEnv->e_to = saveto; 88238032Speter if (av[0] == NULL) 88338032Speter { 88438032Speter if (tTd(22, 1)) 88590792Sgshapiro sm_dprintf("prescan: null leading token\n"); 88664562Sgshapiro return NULL; 88738032Speter } 88864562Sgshapiro return av; 88938032Speter} 89090792Sgshapiro/* 89138032Speter** REWRITE -- apply rewrite rules to token vector. 89238032Speter** 89338032Speter** This routine is an ordered production system. Each rewrite 89438032Speter** rule has a LHS (called the pattern) and a RHS (called the 89538032Speter** rewrite); 'rwr' points the the current rewrite rule. 89638032Speter** 89738032Speter** For each rewrite rule, 'avp' points the address vector we 89838032Speter** are trying to match against, and 'pvp' points to the pattern. 89938032Speter** If pvp points to a special match value (MATCHZANY, MATCHANY, 90038032Speter** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp 90138032Speter** matched is saved away in the match vector (pointed to by 'mvp'). 90238032Speter** 90338032Speter** When a match between avp & pvp does not match, we try to 90438032Speter** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS 90538032Speter** we must also back out the match in mvp. If we reach a 90638032Speter** MATCHANY or MATCHZANY we just extend the match and start 90738032Speter** over again. 90838032Speter** 90938032Speter** When we finally match, we rewrite the address vector 91038032Speter** and try over again. 91138032Speter** 91238032Speter** Parameters: 91338032Speter** pvp -- pointer to token vector. 91438032Speter** ruleset -- the ruleset to use for rewriting. 91538032Speter** reclevel -- recursion level (to catch loops). 91638032Speter** e -- the current envelope. 91790792Sgshapiro** maxatom -- maximum length of buffer (usually MAXATOM) 91838032Speter** 91938032Speter** Returns: 92038032Speter** A status code. If EX_TEMPFAIL, higher level code should 92138032Speter** attempt recovery. 92238032Speter** 92338032Speter** Side Effects: 92438032Speter** pvp is modified. 92538032Speter*/ 92638032Speter 92738032Speterstruct match 92838032Speter{ 92964562Sgshapiro char **match_first; /* first token matched */ 93064562Sgshapiro char **match_last; /* last token matched */ 93164562Sgshapiro char **match_pattern; /* pointer to pattern */ 93238032Speter}; 93338032Speter 93438032Speterint 93590792Sgshapirorewrite(pvp, ruleset, reclevel, e, maxatom) 93638032Speter char **pvp; 93738032Speter int ruleset; 93838032Speter int reclevel; 93938032Speter register ENVELOPE *e; 94090792Sgshapiro int maxatom; 94138032Speter{ 94238032Speter register char *ap; /* address pointer */ 94338032Speter register char *rp; /* rewrite pointer */ 94464562Sgshapiro register char *rulename; /* ruleset name */ 94564562Sgshapiro register char *prefix; 94638032Speter register char **avp; /* address vector pointer */ 94738032Speter register char **rvp; /* rewrite vector pointer */ 94838032Speter register struct match *mlp; /* cur ptr into mlist */ 94938032Speter register struct rewrite *rwr; /* pointer to current rewrite rule */ 95038032Speter int ruleno; /* current rule number */ 95138032Speter int rstat = EX_OK; /* return status */ 95238032Speter int loopcount; 95338032Speter struct match mlist[MAXMATCH]; /* stores match on LHS */ 95464562Sgshapiro char *npvp[MAXATOM + 1]; /* temporary space for rebuild */ 95538032Speter char buf[MAXLINE]; 95664562Sgshapiro char name[6]; 95738032Speter 95864562Sgshapiro if (ruleset < 0 || ruleset >= MAXRWSETS) 95938032Speter { 96064562Sgshapiro syserr("554 5.3.5 rewrite: illegal ruleset number %d", ruleset); 96164562Sgshapiro return EX_CONFIG; 96264562Sgshapiro } 96364562Sgshapiro rulename = RuleSetNames[ruleset]; 96464562Sgshapiro if (rulename == NULL) 96564562Sgshapiro { 96690792Sgshapiro (void) sm_snprintf(name, sizeof name, "%d", ruleset); 96764562Sgshapiro rulename = name; 96864562Sgshapiro } 96964562Sgshapiro if (OpMode == MD_TEST) 97064562Sgshapiro prefix = ""; 97164562Sgshapiro else 97264562Sgshapiro prefix = "rewrite: ruleset "; 97364562Sgshapiro if (OpMode == MD_TEST) 97464562Sgshapiro { 97590792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 97690792Sgshapiro "%s%-16.16s input:", prefix, rulename); 97738032Speter printav(pvp); 97838032Speter } 97964562Sgshapiro else if (tTd(21, 1)) 98038032Speter { 98190792Sgshapiro sm_dprintf("%s%-16.16s input:", prefix, rulename); 98264562Sgshapiro printav(pvp); 98338032Speter } 98438032Speter if (reclevel++ > MaxRuleRecursion) 98538032Speter { 98664562Sgshapiro syserr("rewrite: excessive recursion (max %d), ruleset %s", 98764562Sgshapiro MaxRuleRecursion, rulename); 98838032Speter return EX_CONFIG; 98938032Speter } 99038032Speter if (pvp == NULL) 99138032Speter return EX_USAGE; 99238032Speter 99338032Speter /* 99438032Speter ** Run through the list of rewrite rules, applying 99538032Speter ** any that match. 99638032Speter */ 99738032Speter 99838032Speter ruleno = 1; 99938032Speter loopcount = 0; 100038032Speter for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 100138032Speter { 100264562Sgshapiro int status; 100338032Speter 100438032Speter /* if already canonical, quit now */ 100538032Speter if (pvp[0] != NULL && (pvp[0][0] & 0377) == CANONNET) 100638032Speter break; 100738032Speter 100838032Speter if (tTd(21, 12)) 100938032Speter { 101064562Sgshapiro if (tTd(21, 15)) 101190792Sgshapiro sm_dprintf("-----trying rule (line %d):", 101264562Sgshapiro rwr->r_line); 101364562Sgshapiro else 101490792Sgshapiro sm_dprintf("-----trying rule:"); 101538032Speter printav(rwr->r_lhs); 101638032Speter } 101738032Speter 101838032Speter /* try to match on this rule */ 101938032Speter mlp = mlist; 102038032Speter rvp = rwr->r_lhs; 102138032Speter avp = pvp; 102238032Speter if (++loopcount > 100) 102338032Speter { 102464562Sgshapiro syserr("554 5.3.5 Infinite loop in ruleset %s, rule %d", 102564562Sgshapiro rulename, ruleno); 102638032Speter if (tTd(21, 1)) 102738032Speter { 102890792Sgshapiro sm_dprintf("workspace: "); 102938032Speter printav(pvp); 103038032Speter } 103138032Speter break; 103238032Speter } 103338032Speter 103438032Speter while ((ap = *avp) != NULL || *rvp != NULL) 103538032Speter { 103638032Speter rp = *rvp; 103738032Speter if (tTd(21, 35)) 103838032Speter { 103990792Sgshapiro sm_dprintf("ADVANCE rp="); 104038032Speter xputs(rp); 104190792Sgshapiro sm_dprintf(", ap="); 104238032Speter xputs(ap); 104390792Sgshapiro sm_dprintf("\n"); 104438032Speter } 104538032Speter if (rp == NULL) 104638032Speter { 104738032Speter /* end-of-pattern before end-of-address */ 104838032Speter goto backup; 104938032Speter } 105038032Speter if (ap == NULL && (*rp & 0377) != MATCHZANY && 105138032Speter (*rp & 0377) != MATCHZERO) 105238032Speter { 105338032Speter /* end-of-input with patterns left */ 105438032Speter goto backup; 105538032Speter } 105638032Speter 105738032Speter switch (*rp & 0377) 105838032Speter { 105938032Speter case MATCHCLASS: 106038032Speter /* match any phrase in a class */ 106164562Sgshapiro mlp->match_pattern = rvp; 106264562Sgshapiro mlp->match_first = avp; 106338032Speter extendclass: 106438032Speter ap = *avp; 106538032Speter if (ap == NULL) 106638032Speter goto backup; 106764562Sgshapiro mlp->match_last = avp++; 106864562Sgshapiro cataddr(mlp->match_first, mlp->match_last, 106964562Sgshapiro buf, sizeof buf, '\0'); 107038032Speter if (!wordinclass(buf, rp[1])) 107138032Speter { 107238032Speter if (tTd(21, 36)) 107338032Speter { 107490792Sgshapiro sm_dprintf("EXTEND rp="); 107538032Speter xputs(rp); 107690792Sgshapiro sm_dprintf(", ap="); 107738032Speter xputs(ap); 107890792Sgshapiro sm_dprintf("\n"); 107938032Speter } 108038032Speter goto extendclass; 108138032Speter } 108238032Speter if (tTd(21, 36)) 108390792Sgshapiro sm_dprintf("CLMATCH\n"); 108438032Speter mlp++; 108538032Speter break; 108638032Speter 108738032Speter case MATCHNCLASS: 108838032Speter /* match any token not in a class */ 108938032Speter if (wordinclass(ap, rp[1])) 109038032Speter goto backup; 109138032Speter 109264562Sgshapiro /* FALLTHROUGH */ 109338032Speter 109438032Speter case MATCHONE: 109538032Speter case MATCHANY: 109638032Speter /* match exactly one token */ 109764562Sgshapiro mlp->match_pattern = rvp; 109864562Sgshapiro mlp->match_first = avp; 109964562Sgshapiro mlp->match_last = avp++; 110038032Speter mlp++; 110138032Speter break; 110238032Speter 110338032Speter case MATCHZANY: 110438032Speter /* match zero or more tokens */ 110564562Sgshapiro mlp->match_pattern = rvp; 110664562Sgshapiro mlp->match_first = avp; 110764562Sgshapiro mlp->match_last = avp - 1; 110838032Speter mlp++; 110938032Speter break; 111038032Speter 111138032Speter case MATCHZERO: 111238032Speter /* match zero tokens */ 111338032Speter break; 111438032Speter 111538032Speter case MACRODEXPAND: 111638032Speter /* 111738032Speter ** Match against run-time macro. 111838032Speter ** This algorithm is broken for the 111938032Speter ** general case (no recursive macros, 112038032Speter ** improper tokenization) but should 112138032Speter ** work for the usual cases. 112238032Speter */ 112338032Speter 112438032Speter ap = macvalue(rp[1], e); 112564562Sgshapiro mlp->match_first = avp; 112638032Speter if (tTd(21, 2)) 112798841Sgshapiro sm_dprintf("rewrite: LHS $&{%s} => \"%s\"\n", 112838032Speter macname(rp[1]), 112938032Speter ap == NULL ? "(NULL)" : ap); 113038032Speter 113138032Speter if (ap == NULL) 113238032Speter break; 113338032Speter while (*ap != '\0') 113438032Speter { 113538032Speter if (*avp == NULL || 113690792Sgshapiro sm_strncasecmp(ap, *avp, 113790792Sgshapiro strlen(*avp)) != 0) 113838032Speter { 113938032Speter /* no match */ 114064562Sgshapiro avp = mlp->match_first; 114138032Speter goto backup; 114238032Speter } 114338032Speter ap += strlen(*avp++); 114438032Speter } 114538032Speter 114638032Speter /* match */ 114738032Speter break; 114838032Speter 114938032Speter default: 115038032Speter /* must have exact match */ 115138032Speter if (sm_strcasecmp(rp, ap)) 115238032Speter goto backup; 115338032Speter avp++; 115438032Speter break; 115538032Speter } 115638032Speter 115738032Speter /* successful match on this token */ 115838032Speter rvp++; 115938032Speter continue; 116038032Speter 116138032Speter backup: 116238032Speter /* match failed -- back up */ 116338032Speter while (--mlp >= mlist) 116438032Speter { 116564562Sgshapiro rvp = mlp->match_pattern; 116638032Speter rp = *rvp; 116764562Sgshapiro avp = mlp->match_last + 1; 116838032Speter ap = *avp; 116938032Speter 117038032Speter if (tTd(21, 36)) 117138032Speter { 117290792Sgshapiro sm_dprintf("BACKUP rp="); 117338032Speter xputs(rp); 117490792Sgshapiro sm_dprintf(", ap="); 117538032Speter xputs(ap); 117690792Sgshapiro sm_dprintf("\n"); 117738032Speter } 117838032Speter 117938032Speter if (ap == NULL) 118038032Speter { 118138032Speter /* run off the end -- back up again */ 118238032Speter continue; 118338032Speter } 118438032Speter if ((*rp & 0377) == MATCHANY || 118538032Speter (*rp & 0377) == MATCHZANY) 118638032Speter { 118738032Speter /* extend binding and continue */ 118864562Sgshapiro mlp->match_last = avp++; 118938032Speter rvp++; 119038032Speter mlp++; 119138032Speter break; 119238032Speter } 119338032Speter if ((*rp & 0377) == MATCHCLASS) 119438032Speter { 119538032Speter /* extend binding and try again */ 119664562Sgshapiro mlp->match_last = avp; 119738032Speter goto extendclass; 119838032Speter } 119938032Speter } 120038032Speter 120138032Speter if (mlp < mlist) 120238032Speter { 120338032Speter /* total failure to match */ 120438032Speter break; 120538032Speter } 120638032Speter } 120738032Speter 120838032Speter /* 120938032Speter ** See if we successfully matched 121038032Speter */ 121138032Speter 121238032Speter if (mlp < mlist || *rvp != NULL) 121338032Speter { 121438032Speter if (tTd(21, 10)) 121590792Sgshapiro sm_dprintf("----- rule fails\n"); 121638032Speter rwr = rwr->r_next; 121738032Speter ruleno++; 121838032Speter loopcount = 0; 121938032Speter continue; 122038032Speter } 122138032Speter 122238032Speter rvp = rwr->r_rhs; 122338032Speter if (tTd(21, 12)) 122438032Speter { 122590792Sgshapiro sm_dprintf("-----rule matches:"); 122638032Speter printav(rvp); 122738032Speter } 122838032Speter 122938032Speter rp = *rvp; 123064562Sgshapiro if (rp != NULL) 123138032Speter { 123264562Sgshapiro if ((*rp & 0377) == CANONUSER) 123364562Sgshapiro { 123464562Sgshapiro rvp++; 123564562Sgshapiro rwr = rwr->r_next; 123664562Sgshapiro ruleno++; 123764562Sgshapiro loopcount = 0; 123864562Sgshapiro } 123964562Sgshapiro else if ((*rp & 0377) == CANONHOST) 124064562Sgshapiro { 124164562Sgshapiro rvp++; 124264562Sgshapiro rwr = NULL; 124364562Sgshapiro } 124438032Speter } 124538032Speter 124638032Speter /* substitute */ 124738032Speter for (avp = npvp; *rvp != NULL; rvp++) 124838032Speter { 124938032Speter register struct match *m; 125038032Speter register char **pp; 125138032Speter 125238032Speter rp = *rvp; 125338032Speter if ((*rp & 0377) == MATCHREPL) 125438032Speter { 125538032Speter /* substitute from LHS */ 125638032Speter m = &mlist[rp[1] - '1']; 125738032Speter if (m < mlist || m >= mlp) 125838032Speter { 125964562Sgshapiro syserr("554 5.3.5 rewrite: ruleset %s: replacement $%c out of bounds", 126064562Sgshapiro rulename, rp[1]); 126138032Speter return EX_CONFIG; 126238032Speter } 126338032Speter if (tTd(21, 15)) 126438032Speter { 126590792Sgshapiro sm_dprintf("$%c:", rp[1]); 126664562Sgshapiro pp = m->match_first; 126764562Sgshapiro while (pp <= m->match_last) 126838032Speter { 126990792Sgshapiro sm_dprintf(" %p=\"", *pp); 127090792Sgshapiro sm_dflush(); 127190792Sgshapiro sm_dprintf("%s\"", *pp++); 127238032Speter } 127390792Sgshapiro sm_dprintf("\n"); 127438032Speter } 127564562Sgshapiro pp = m->match_first; 127664562Sgshapiro while (pp <= m->match_last) 127738032Speter { 127890792Sgshapiro if (avp >= &npvp[maxatom]) 127938032Speter { 128064562Sgshapiro syserr("554 5.3.0 rewrite: expansion too long"); 128190792Sgshapiro if (LogLevel > 9) 128290792Sgshapiro sm_syslog(LOG_ERR, 128390792Sgshapiro e->e_id, 128490792Sgshapiro "rewrite: expansion too long, ruleset=%s, ruleno=%d", 128590792Sgshapiro rulename, 128690792Sgshapiro ruleno); 128738032Speter return EX_DATAERR; 128838032Speter } 128938032Speter *avp++ = *pp++; 129038032Speter } 129138032Speter } 129238032Speter else 129338032Speter { 129438032Speter /* some sort of replacement */ 129590792Sgshapiro if (avp >= &npvp[maxatom]) 129638032Speter { 129738032Speter toolong: 129864562Sgshapiro syserr("554 5.3.0 rewrite: expansion too long"); 129990792Sgshapiro if (LogLevel > 9) 130090792Sgshapiro sm_syslog(LOG_ERR, e->e_id, 130190792Sgshapiro "rewrite: expansion too long, ruleset=%s, ruleno=%d", 130290792Sgshapiro rulename, ruleno); 130338032Speter return EX_DATAERR; 130438032Speter } 130538032Speter if ((*rp & 0377) != MACRODEXPAND) 130638032Speter { 130738032Speter /* vanilla replacement */ 130838032Speter *avp++ = rp; 130938032Speter } 131038032Speter else 131138032Speter { 131298841Sgshapiro /* $&{x} replacement */ 131338032Speter char *mval = macvalue(rp[1], e); 131438032Speter char **xpvp; 131538032Speter int trsize = 0; 131638032Speter static size_t pvpb1_size = 0; 131738032Speter static char **pvpb1 = NULL; 131838032Speter char pvpbuf[PSBUFSIZE]; 131938032Speter 132038032Speter if (tTd(21, 2)) 132198841Sgshapiro sm_dprintf("rewrite: RHS $&{%s} => \"%s\"\n", 132238032Speter macname(rp[1]), 132338032Speter mval == NULL ? "(NULL)" : mval); 132438032Speter if (mval == NULL || *mval == '\0') 132538032Speter continue; 132638032Speter 132738032Speter /* save the remainder of the input */ 132838032Speter for (xpvp = pvp; *xpvp != NULL; xpvp++) 132938032Speter trsize += sizeof *xpvp; 133064562Sgshapiro if ((size_t) trsize > pvpb1_size) 133138032Speter { 133238032Speter if (pvpb1 != NULL) 133377349Sgshapiro sm_free(pvpb1); 133490792Sgshapiro pvpb1 = (char **) 133590792Sgshapiro sm_pmalloc_x(trsize); 133638032Speter pvpb1_size = trsize; 133738032Speter } 133838032Speter 133964562Sgshapiro memmove((char *) pvpb1, 134064562Sgshapiro (char *) pvp, 134164562Sgshapiro trsize); 134238032Speter 134338032Speter /* scan the new replacement */ 134438032Speter xpvp = prescan(mval, '\0', pvpbuf, 134564562Sgshapiro sizeof pvpbuf, NULL, 134664562Sgshapiro NULL); 134738032Speter if (xpvp == NULL) 134838032Speter { 134938032Speter /* prescan pre-printed error */ 135038032Speter return EX_DATAERR; 135138032Speter } 135238032Speter 135338032Speter /* insert it into the output stream */ 135438032Speter while (*xpvp != NULL) 135538032Speter { 135638032Speter if (tTd(21, 19)) 135790792Sgshapiro sm_dprintf(" ... %s\n", 135864562Sgshapiro *xpvp); 135990792Sgshapiro *avp++ = sm_rpool_strdup_x( 136090792Sgshapiro e->e_rpool, *xpvp); 136190792Sgshapiro if (avp >= &npvp[maxatom]) 136238032Speter goto toolong; 136338032Speter xpvp++; 136438032Speter } 136538032Speter if (tTd(21, 19)) 136690792Sgshapiro sm_dprintf(" ... DONE\n"); 136738032Speter 136838032Speter /* restore the old trailing input */ 136964562Sgshapiro memmove((char *) pvp, 137064562Sgshapiro (char *) pvpb1, 137164562Sgshapiro trsize); 137238032Speter } 137338032Speter } 137438032Speter } 137538032Speter *avp++ = NULL; 137638032Speter 137738032Speter /* 137838032Speter ** Check for any hostname/keyword lookups. 137938032Speter */ 138038032Speter 138138032Speter for (rvp = npvp; *rvp != NULL; rvp++) 138238032Speter { 138338032Speter char **hbrvp; 138438032Speter char **xpvp; 138538032Speter int trsize; 138638032Speter char *replac; 138738032Speter int endtoken; 138838032Speter STAB *map; 138938032Speter char *mapname; 139038032Speter char **key_rvp; 139138032Speter char **arg_rvp; 139238032Speter char **default_rvp; 139364562Sgshapiro char cbuf[MAXNAME + 1]; 139438032Speter char *pvpb1[MAXATOM + 1]; 139538032Speter char *argvect[10]; 139638032Speter char pvpbuf[PSBUFSIZE]; 139738032Speter char *nullpvp[1]; 139838032Speter 139938032Speter if ((**rvp & 0377) != HOSTBEGIN && 140038032Speter (**rvp & 0377) != LOOKUPBEGIN) 140138032Speter continue; 140238032Speter 140338032Speter /* 140438032Speter ** Got a hostname/keyword lookup. 140538032Speter ** 140638032Speter ** This could be optimized fairly easily. 140738032Speter */ 140838032Speter 140938032Speter hbrvp = rvp; 141038032Speter if ((**rvp & 0377) == HOSTBEGIN) 141138032Speter { 141238032Speter endtoken = HOSTEND; 141338032Speter mapname = "host"; 141438032Speter } 141538032Speter else 141638032Speter { 141738032Speter endtoken = LOOKUPEND; 141838032Speter mapname = *++rvp; 141938032Speter } 142038032Speter map = stab(mapname, ST_MAP, ST_FIND); 142138032Speter if (map == NULL) 142264562Sgshapiro syserr("554 5.3.0 rewrite: map %s not found", mapname); 142338032Speter 142438032Speter /* extract the match part */ 142538032Speter key_rvp = ++rvp; 142638032Speter default_rvp = NULL; 142738032Speter arg_rvp = argvect; 142838032Speter xpvp = NULL; 142938032Speter replac = pvpbuf; 143038032Speter while (*rvp != NULL && (**rvp & 0377) != endtoken) 143138032Speter { 143238032Speter int nodetype = **rvp & 0377; 143338032Speter 143438032Speter if (nodetype != CANONHOST && nodetype != CANONUSER) 143538032Speter { 143638032Speter rvp++; 143738032Speter continue; 143838032Speter } 143938032Speter 144038032Speter *rvp++ = NULL; 144138032Speter 144238032Speter if (xpvp != NULL) 144338032Speter { 144438032Speter cataddr(xpvp, NULL, replac, 144538032Speter &pvpbuf[sizeof pvpbuf] - replac, 144638032Speter '\0'); 144738032Speter *++arg_rvp = replac; 144838032Speter replac += strlen(replac) + 1; 144938032Speter xpvp = NULL; 145038032Speter } 145138032Speter switch (nodetype) 145238032Speter { 145338032Speter case CANONHOST: 145438032Speter xpvp = rvp; 145538032Speter break; 145638032Speter 145738032Speter case CANONUSER: 145838032Speter default_rvp = rvp; 145938032Speter break; 146038032Speter } 146138032Speter } 146238032Speter if (*rvp != NULL) 146338032Speter *rvp++ = NULL; 146438032Speter if (xpvp != NULL) 146538032Speter { 146638032Speter cataddr(xpvp, NULL, replac, 146738032Speter &pvpbuf[sizeof pvpbuf] - replac, 146838032Speter '\0'); 146938032Speter *++arg_rvp = replac; 147038032Speter } 147138032Speter *++arg_rvp = NULL; 147238032Speter 147338032Speter /* save the remainder of the input string */ 147438032Speter trsize = (int) (avp - rvp + 1) * sizeof *rvp; 147564562Sgshapiro memmove((char *) pvpb1, (char *) rvp, trsize); 147638032Speter 147738032Speter /* look it up */ 147864562Sgshapiro cataddr(key_rvp, NULL, cbuf, sizeof cbuf, 147964562Sgshapiro map == NULL ? '\0' : map->s_map.map_spacesub); 148064562Sgshapiro argvect[0] = cbuf; 148164562Sgshapiro replac = map_lookup(map, cbuf, argvect, &rstat, e); 148238032Speter 148338032Speter /* if no replacement, use default */ 148438032Speter if (replac == NULL && default_rvp != NULL) 148538032Speter { 148638032Speter /* create the default */ 148764562Sgshapiro cataddr(default_rvp, NULL, cbuf, sizeof cbuf, '\0'); 148864562Sgshapiro replac = cbuf; 148938032Speter } 149038032Speter 149138032Speter if (replac == NULL) 149238032Speter { 149338032Speter xpvp = key_rvp; 149438032Speter } 149538032Speter else if (*replac == '\0') 149638032Speter { 149738032Speter /* null replacement */ 149838032Speter nullpvp[0] = NULL; 149938032Speter xpvp = nullpvp; 150038032Speter } 150138032Speter else 150238032Speter { 150338032Speter /* scan the new replacement */ 150438032Speter xpvp = prescan(replac, '\0', pvpbuf, 150538032Speter sizeof pvpbuf, NULL, NULL); 150638032Speter if (xpvp == NULL) 150738032Speter { 150838032Speter /* prescan already printed error */ 150938032Speter return EX_DATAERR; 151038032Speter } 151138032Speter } 151238032Speter 151338032Speter /* append it to the token list */ 151438032Speter for (avp = hbrvp; *xpvp != NULL; xpvp++) 151538032Speter { 151690792Sgshapiro *avp++ = sm_rpool_strdup_x(e->e_rpool, *xpvp); 151790792Sgshapiro if (avp >= &npvp[maxatom]) 151838032Speter goto toolong; 151938032Speter } 152038032Speter 152138032Speter /* restore the old trailing information */ 152238032Speter rvp = avp - 1; 152338032Speter for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) 152490792Sgshapiro if (avp >= &npvp[maxatom]) 152538032Speter goto toolong; 152638032Speter } 152738032Speter 152838032Speter /* 152938032Speter ** Check for subroutine calls. 153038032Speter */ 153138032Speter 153264562Sgshapiro status = callsubr(npvp, reclevel, e); 153364562Sgshapiro if (rstat == EX_OK || status == EX_TEMPFAIL) 153464562Sgshapiro rstat = status; 153538032Speter 153638032Speter /* copy vector back into original space. */ 153738032Speter for (avp = npvp; *avp++ != NULL;) 153838032Speter continue; 153964562Sgshapiro memmove((char *) pvp, (char *) npvp, 154038032Speter (int) (avp - npvp) * sizeof *avp); 154164562Sgshapiro 154238032Speter if (tTd(21, 4)) 154338032Speter { 154490792Sgshapiro sm_dprintf("rewritten as:"); 154538032Speter printav(pvp); 154638032Speter } 154738032Speter } 154838032Speter 154964562Sgshapiro if (OpMode == MD_TEST) 155038032Speter { 155190792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 155290792Sgshapiro "%s%-16.16s returns:", prefix, rulename); 155338032Speter printav(pvp); 155438032Speter } 155564562Sgshapiro else if (tTd(21, 1)) 155664562Sgshapiro { 155790792Sgshapiro sm_dprintf("%s%-16.16s returns:", prefix, rulename); 155864562Sgshapiro printav(pvp); 155964562Sgshapiro } 156038032Speter return rstat; 156138032Speter} 156290792Sgshapiro/* 156338032Speter** CALLSUBR -- call subroutines in rewrite vector 156438032Speter** 156538032Speter** Parameters: 156638032Speter** pvp -- pointer to token vector. 156738032Speter** reclevel -- the current recursion level. 156838032Speter** e -- the current envelope. 156938032Speter** 157038032Speter** Returns: 157138032Speter** The status from the subroutine call. 157238032Speter** 157338032Speter** Side Effects: 157438032Speter** pvp is modified. 157538032Speter*/ 157638032Speter 157764562Sgshapirostatic int 157838032Spetercallsubr(pvp, reclevel, e) 157938032Speter char **pvp; 158038032Speter int reclevel; 158138032Speter ENVELOPE *e; 158238032Speter{ 158364562Sgshapiro char **avp; 158438032Speter register int i; 158590792Sgshapiro int subr, j; 158690792Sgshapiro int nsubr; 158764562Sgshapiro int status; 158838032Speter int rstat = EX_OK; 158990792Sgshapiro#define MAX_SUBR 16 159090792Sgshapiro int subrnumber[MAX_SUBR]; 159190792Sgshapiro int subrindex[MAX_SUBR]; 159238032Speter 159390792Sgshapiro nsubr = 0; 159490792Sgshapiro 159590792Sgshapiro /* 159690792Sgshapiro ** Look for subroutine calls in pvp, collect them into subr*[] 159790792Sgshapiro ** We will perform the calls in the next loop, because we will 159890792Sgshapiro ** call the "last" subroutine first to avoid recursive calls 159990792Sgshapiro ** and too much copying. 160090792Sgshapiro */ 160190792Sgshapiro 160290792Sgshapiro for (avp = pvp, j = 0; *avp != NULL; avp++, j++) 160338032Speter { 160438032Speter if ((**avp & 0377) == CALLSUBR && avp[1] != NULL) 160538032Speter { 160638032Speter stripquotes(avp[1]); 160738032Speter subr = strtorwset(avp[1], NULL, ST_FIND); 160838032Speter if (subr < 0) 160938032Speter { 161090792Sgshapiro syserr("554 5.3.5 Unknown ruleset %s", avp[1]); 161138032Speter return EX_CONFIG; 161238032Speter } 161338032Speter 161438032Speter /* 161590792Sgshapiro ** XXX instead of doing this we could optimize 161690792Sgshapiro ** the rules after reading them: just remove 161790792Sgshapiro ** calls to empty rulesets 161838032Speter */ 161938032Speter 162090792Sgshapiro /* subroutine is an empty ruleset? don't call it */ 162190792Sgshapiro if (RewriteRules[subr] == NULL) 162290792Sgshapiro { 162390792Sgshapiro if (tTd(21, 3)) 162490792Sgshapiro sm_dprintf("-----skip subr %s (%d)\n", 162590792Sgshapiro avp[1], subr); 162690792Sgshapiro for (i = 2; avp[i] != NULL; i++) 162790792Sgshapiro avp[i - 2] = avp[i]; 162890792Sgshapiro avp[i - 2] = NULL; 162938032Speter continue; 163090792Sgshapiro } 163190792Sgshapiro if (++nsubr >= MAX_SUBR) 163238032Speter { 163390792Sgshapiro syserr("554 5.3.0 Too many subroutine calls (%d max)", 163490792Sgshapiro MAX_SUBR); 163590792Sgshapiro return EX_CONFIG; 163638032Speter } 163790792Sgshapiro subrnumber[nsubr] = subr; 163890792Sgshapiro subrindex[nsubr] = j; 163990792Sgshapiro } 164090792Sgshapiro } 164138032Speter 164290792Sgshapiro /* 164390792Sgshapiro ** Perform the actual subroutines calls, "last" one first, i.e., 164490792Sgshapiro ** go from the right to the left through all calls, 164590792Sgshapiro ** do the rewriting in place. 164690792Sgshapiro */ 164738032Speter 164890792Sgshapiro for (; nsubr > 0; nsubr--) 164990792Sgshapiro { 165090792Sgshapiro subr = subrnumber[nsubr]; 165190792Sgshapiro avp = pvp + subrindex[nsubr]; 165238032Speter 165390792Sgshapiro /* remove the subroutine call and name */ 165490792Sgshapiro for (i = 2; avp[i] != NULL; i++) 165590792Sgshapiro avp[i - 2] = avp[i]; 165690792Sgshapiro avp[i - 2] = NULL; 165738032Speter 165890792Sgshapiro /* 165990792Sgshapiro ** Now we need to call the ruleset specified for 166090792Sgshapiro ** the subroutine. we can do this inplace since 166190792Sgshapiro ** we call the "last" subroutine first. 166290792Sgshapiro */ 166390792Sgshapiro 166490792Sgshapiro status = rewrite(avp, subr, reclevel, e, 166590792Sgshapiro MAXATOM - subrindex[nsubr]); 166690792Sgshapiro if (status != EX_OK && status != EX_TEMPFAIL) 166790792Sgshapiro return status; 166890792Sgshapiro if (rstat == EX_OK || status == EX_TEMPFAIL) 166990792Sgshapiro rstat = status; 167038032Speter } 167138032Speter return rstat; 167238032Speter} 167390792Sgshapiro/* 167438032Speter** MAP_LOOKUP -- do lookup in map 167538032Speter** 167638032Speter** Parameters: 167790792Sgshapiro** smap -- the map to use for the lookup. 167838032Speter** key -- the key to look up. 167938032Speter** argvect -- arguments to pass to the map lookup. 168038032Speter** pstat -- a pointer to an integer in which to store the 168138032Speter** status from the lookup. 168238032Speter** e -- the current envelope. 168338032Speter** 168438032Speter** Returns: 168538032Speter** The result of the lookup. 168638032Speter** NULL -- if there was no data for the given key. 168738032Speter*/ 168838032Speter 168964562Sgshapirostatic char * 169064562Sgshapiromap_lookup(smap, key, argvect, pstat, e) 169164562Sgshapiro STAB *smap; 169238032Speter char key[]; 169338032Speter char **argvect; 169438032Speter int *pstat; 169538032Speter ENVELOPE *e; 169638032Speter{ 169764562Sgshapiro auto int status = EX_OK; 169864562Sgshapiro MAP *map; 169938032Speter char *replac; 170038032Speter 170164562Sgshapiro if (smap == NULL) 170264562Sgshapiro return NULL; 170364562Sgshapiro 170464562Sgshapiro map = &smap->s_map; 170564562Sgshapiro DYNOPENMAP(map); 170664562Sgshapiro 170764562Sgshapiro if (e->e_sendmode == SM_DEFER && 170864562Sgshapiro bitset(MF_DEFER, map->map_mflags)) 170938032Speter { 171038032Speter /* don't do any map lookups */ 171138032Speter if (tTd(60, 1)) 171290792Sgshapiro sm_dprintf("map_lookup(%s, %s) => DEFERRED\n", 171364562Sgshapiro smap->s_name, key); 171438032Speter *pstat = EX_TEMPFAIL; 171538032Speter return NULL; 171638032Speter } 171738032Speter 171864562Sgshapiro if (!bitset(MF_KEEPQUOTES, map->map_mflags)) 171938032Speter stripquotes(key); 172038032Speter 172138032Speter if (tTd(60, 1)) 172242575Speter { 172390792Sgshapiro sm_dprintf("map_lookup(%s, %s", smap->s_name, key); 172442575Speter if (tTd(60, 5)) 172542575Speter { 172642575Speter int i; 172742575Speter 172842575Speter for (i = 0; argvect[i] != NULL; i++) 172990792Sgshapiro sm_dprintf(", %%%d=%s", i, argvect[i]); 173042575Speter } 173190792Sgshapiro sm_dprintf(") => "); 173242575Speter } 173364562Sgshapiro replac = (*map->map_class->map_lookup)(map, key, argvect, &status); 173438032Speter if (tTd(60, 1)) 173590792Sgshapiro sm_dprintf("%s (%d)\n", 173638032Speter replac != NULL ? replac : "NOT FOUND", 173764562Sgshapiro status); 173838032Speter 173964562Sgshapiro /* should recover if status == EX_TEMPFAIL */ 174064562Sgshapiro if (status == EX_TEMPFAIL && !bitset(MF_NODEFER, map->map_mflags)) 174138032Speter { 174238032Speter *pstat = EX_TEMPFAIL; 174338032Speter if (tTd(60, 1)) 174490792Sgshapiro sm_dprintf("map_lookup(%s, %s) tempfail: errno=%d\n", 174564562Sgshapiro smap->s_name, key, errno); 174638032Speter if (e->e_message == NULL) 174738032Speter { 174838032Speter char mbuf[320]; 174938032Speter 175090792Sgshapiro (void) sm_snprintf(mbuf, sizeof mbuf, 175138032Speter "%.80s map: lookup (%s): deferred", 175264562Sgshapiro smap->s_name, 175338032Speter shortenstring(key, MAXSHORTSTR)); 175490792Sgshapiro e->e_message = sm_rpool_strdup_x(e->e_rpool, mbuf); 175538032Speter } 175638032Speter } 175764562Sgshapiro if (status == EX_TEMPFAIL && map->map_tapp != NULL) 175838032Speter { 175964562Sgshapiro size_t i = strlen(key) + strlen(map->map_tapp) + 1; 176038032Speter static char *rwbuf = NULL; 176138032Speter static size_t rwbuflen = 0; 176238032Speter 176338032Speter if (i > rwbuflen) 176438032Speter { 176538032Speter if (rwbuf != NULL) 176677349Sgshapiro sm_free(rwbuf); 176738032Speter rwbuflen = i; 176890792Sgshapiro rwbuf = (char *) sm_pmalloc_x(rwbuflen); 176938032Speter } 177090792Sgshapiro (void) sm_strlcpyn(rwbuf, rwbuflen, 2, key, map->map_tapp); 177138032Speter if (tTd(60, 4)) 177290792Sgshapiro sm_dprintf("map_lookup tempfail: returning \"%s\"\n", 177338032Speter rwbuf); 177438032Speter return rwbuf; 177538032Speter } 177638032Speter return replac; 177738032Speter} 177890792Sgshapiro/* 177964562Sgshapiro** INITERRMAILERS -- initialize error and discard mailers 178064562Sgshapiro** 178164562Sgshapiro** Parameters: 178264562Sgshapiro** none. 178364562Sgshapiro** 178464562Sgshapiro** Returns: 178564562Sgshapiro** none. 178664562Sgshapiro** 178764562Sgshapiro** Side Effects: 178864562Sgshapiro** initializes error and discard mailers. 178964562Sgshapiro*/ 179064562Sgshapiro 179164562Sgshapirostatic MAILER discardmailer; 179264562Sgshapirostatic MAILER errormailer; 179364562Sgshapirostatic char *discardargv[] = { "DISCARD", NULL }; 179464562Sgshapirostatic char *errorargv[] = { "ERROR", NULL }; 179564562Sgshapiro 179664562Sgshapirovoid 179764562Sgshapiroiniterrmailers() 179864562Sgshapiro{ 179964562Sgshapiro if (discardmailer.m_name == NULL) 180064562Sgshapiro { 180164562Sgshapiro /* initialize the discard mailer */ 180264562Sgshapiro discardmailer.m_name = "*discard*"; 180364562Sgshapiro discardmailer.m_mailer = "DISCARD"; 180464562Sgshapiro discardmailer.m_argv = discardargv; 180564562Sgshapiro } 180664562Sgshapiro if (errormailer.m_name == NULL) 180764562Sgshapiro { 180864562Sgshapiro /* initialize the bogus mailer */ 180964562Sgshapiro errormailer.m_name = "*error*"; 181064562Sgshapiro errormailer.m_mailer = "ERROR"; 181164562Sgshapiro errormailer.m_argv = errorargv; 181264562Sgshapiro } 181364562Sgshapiro} 181490792Sgshapiro/* 181538032Speter** BUILDADDR -- build address from token vector. 181638032Speter** 181738032Speter** Parameters: 181838032Speter** tv -- token vector. 181938032Speter** a -- pointer to address descriptor to fill. 182038032Speter** If NULL, one will be allocated. 182138032Speter** flags -- info regarding whether this is a sender or 182238032Speter** a recipient. 182338032Speter** e -- the current envelope. 182438032Speter** 182538032Speter** Returns: 182638032Speter** NULL if there was an error. 182738032Speter** 'a' otherwise. 182838032Speter** 182938032Speter** Side Effects: 183038032Speter** fills in 'a' 183138032Speter*/ 183238032Speter 183364562Sgshapirostatic struct errcodes 183438032Speter{ 183538032Speter char *ec_name; /* name of error code */ 183638032Speter int ec_code; /* numeric code */ 183738032Speter} ErrorCodes[] = 183838032Speter{ 183938032Speter { "usage", EX_USAGE }, 184038032Speter { "nouser", EX_NOUSER }, 184138032Speter { "nohost", EX_NOHOST }, 184238032Speter { "unavailable", EX_UNAVAILABLE }, 184338032Speter { "software", EX_SOFTWARE }, 184438032Speter { "tempfail", EX_TEMPFAIL }, 184538032Speter { "protocol", EX_PROTOCOL }, 184638032Speter { "config", EX_CONFIG }, 184738032Speter { NULL, EX_UNAVAILABLE } 184838032Speter}; 184938032Speter 185064562Sgshapirostatic ADDRESS * 185138032Speterbuildaddr(tv, a, flags, e) 185238032Speter register char **tv; 185338032Speter register ADDRESS *a; 185438032Speter int flags; 185538032Speter register ENVELOPE *e; 185638032Speter{ 185794334Sgshapiro bool tempfail = false; 185838032Speter struct mailer **mp; 185938032Speter register struct mailer *m; 186038032Speter register char *p; 186138032Speter char *mname; 186238032Speter char **hostp; 186338032Speter char hbuf[MAXNAME + 1]; 186442575Speter static char ubuf[MAXNAME + 2]; 186538032Speter 186638032Speter if (tTd(24, 5)) 186738032Speter { 186890792Sgshapiro sm_dprintf("buildaddr, flags=%x, tv=", flags); 186938032Speter printav(tv); 187038032Speter } 187138032Speter 187238032Speter if (a == NULL) 187390792Sgshapiro a = (ADDRESS *) sm_rpool_malloc_x(e->e_rpool, sizeof *a); 187464562Sgshapiro memset((char *) a, '\0', sizeof *a); 187564562Sgshapiro hbuf[0] = '\0'; 187638032Speter 187738032Speter /* set up default error return flags */ 187838032Speter a->q_flags |= DefaultNotify; 187938032Speter 188038032Speter /* figure out what net/mailer to use */ 188138032Speter if (*tv == NULL || (**tv & 0377) != CANONNET) 188238032Speter { 188364562Sgshapiro syserr("554 5.3.5 buildaddr: no mailer in parsed address"); 188438032Speterbadaddr: 188594334Sgshapiro#if _FFR_ALLOW_S0_ERROR_4XX 188694334Sgshapiro /* 188794334Sgshapiro ** ExitStat may have been set by an earlier map open 188894334Sgshapiro ** failure (to a permanent error (EX_OSERR) in syserr()) 188994334Sgshapiro ** so we also need to check if this particular $#error 189094334Sgshapiro ** return wanted a 4XX failure. 189194334Sgshapiro ** 189294334Sgshapiro ** XXX the real fix is probably to set ExitStat correctly, 189394334Sgshapiro ** i.e., to EX_TEMPFAIL if the map open is just a temporary 189494334Sgshapiro ** error. 189594334Sgshapiro ** 189694334Sgshapiro ** tempfail is tested here even if _FFR_ALLOW_S0_ERROR_4XX 189794334Sgshapiro ** is not set; that's ok because it is initialized to false. 189894334Sgshapiro */ 189994334Sgshapiro#endif /* _FFR_ALLOW_S0_ERROR_4XX */ 190094334Sgshapiro 190194334Sgshapiro if (ExitStat == EX_TEMPFAIL || tempfail) 190264562Sgshapiro a->q_state = QS_QUEUEUP; 190364562Sgshapiro else 190438032Speter { 190564562Sgshapiro a->q_state = QS_BADADDR; 190664562Sgshapiro a->q_mailer = &errormailer; 190738032Speter } 190838032Speter return a; 190938032Speter } 191038032Speter mname = *++tv; 191138032Speter 191238032Speter /* extract host and user portions */ 191338032Speter if (*++tv != NULL && (**tv & 0377) == CANONHOST) 191438032Speter hostp = ++tv; 191538032Speter else 191638032Speter hostp = NULL; 191738032Speter while (*tv != NULL && (**tv & 0377) != CANONUSER) 191838032Speter tv++; 191938032Speter if (*tv == NULL) 192038032Speter { 192164562Sgshapiro syserr("554 5.3.5 buildaddr: no user"); 192238032Speter goto badaddr; 192338032Speter } 192438032Speter if (tv == hostp) 192538032Speter hostp = NULL; 192638032Speter else if (hostp != NULL) 192738032Speter cataddr(hostp, tv - 1, hbuf, sizeof hbuf, '\0'); 192838032Speter cataddr(++tv, NULL, ubuf, sizeof ubuf, ' '); 192938032Speter 193038032Speter /* save away the host name */ 193190792Sgshapiro if (sm_strcasecmp(mname, "error") == 0) 193238032Speter { 193364562Sgshapiro /* Set up triplet for use by -bv */ 193464562Sgshapiro a->q_mailer = &errormailer; 193590792Sgshapiro a->q_user = sm_rpool_strdup_x(e->e_rpool, ubuf); 193690792Sgshapiro /* XXX wrong place? */ 193764562Sgshapiro 193838032Speter if (hostp != NULL) 193938032Speter { 194038032Speter register struct errcodes *ep; 194138032Speter 194290792Sgshapiro a->q_host = sm_rpool_strdup_x(e->e_rpool, hbuf); 194338032Speter if (strchr(hbuf, '.') != NULL) 194438032Speter { 194590792Sgshapiro a->q_status = sm_rpool_strdup_x(e->e_rpool, 194690792Sgshapiro hbuf); 194738032Speter setstat(dsntoexitstat(hbuf)); 194838032Speter } 194938032Speter else if (isascii(hbuf[0]) && isdigit(hbuf[0])) 195038032Speter { 195138032Speter setstat(atoi(hbuf)); 195238032Speter } 195338032Speter else 195438032Speter { 195538032Speter for (ep = ErrorCodes; ep->ec_name != NULL; ep++) 195690792Sgshapiro if (sm_strcasecmp(ep->ec_name, hbuf) == 0) 195738032Speter break; 195838032Speter setstat(ep->ec_code); 195938032Speter } 196038032Speter } 196138032Speter else 196264562Sgshapiro { 196364562Sgshapiro a->q_host = NULL; 196438032Speter setstat(EX_UNAVAILABLE); 196564562Sgshapiro } 196638032Speter stripquotes(ubuf); 196764562Sgshapiro if (ISSMTPCODE(ubuf) && ubuf[3] == ' ') 196838032Speter { 196964562Sgshapiro char fmt[16]; 197064562Sgshapiro int off; 197138032Speter 197264562Sgshapiro if ((off = isenhsc(ubuf + 4, ' ')) > 0) 197338032Speter { 197464562Sgshapiro ubuf[off + 4] = '\0'; 197564562Sgshapiro off += 5; 197638032Speter } 197764562Sgshapiro else 197864562Sgshapiro { 197964562Sgshapiro off = 4; 198064562Sgshapiro ubuf[3] = '\0'; 198164562Sgshapiro } 198290792Sgshapiro (void) sm_strlcpyn(fmt, sizeof fmt, 2, ubuf, " %s"); 198364562Sgshapiro if (off > 4) 198464562Sgshapiro usrerr(fmt, ubuf + off); 198564562Sgshapiro else if (isenhsc(hbuf, '\0') > 0) 198664562Sgshapiro usrerrenh(hbuf, fmt, ubuf + off); 198764562Sgshapiro else 198864562Sgshapiro usrerr(fmt, ubuf + off); 198964562Sgshapiro /* XXX ubuf[off - 1] = ' '; */ 199094334Sgshapiro#if _FFR_ALLOW_S0_ERROR_4XX 199194334Sgshapiro if (ubuf[0] == '4') 199294334Sgshapiro tempfail = true; 199394334Sgshapiro#endif /* _FFR_ALLOW_S0_ERROR_4XX */ 199438032Speter } 199538032Speter else 199638032Speter { 199764562Sgshapiro usrerr("553 5.3.0 %s", ubuf); 199838032Speter } 199938032Speter goto badaddr; 200038032Speter } 200138032Speter 200238032Speter for (mp = Mailer; (m = *mp++) != NULL; ) 200338032Speter { 200490792Sgshapiro if (sm_strcasecmp(m->m_name, mname) == 0) 200538032Speter break; 200638032Speter } 200738032Speter if (m == NULL) 200838032Speter { 200964562Sgshapiro syserr("554 5.3.5 buildaddr: unknown mailer %s", mname); 201038032Speter goto badaddr; 201138032Speter } 201238032Speter a->q_mailer = m; 201338032Speter 201438032Speter /* figure out what host (if any) */ 201538032Speter if (hostp == NULL) 201638032Speter { 201738032Speter if (!bitnset(M_LOCALMAILER, m->m_flags)) 201838032Speter { 201964562Sgshapiro syserr("554 5.3.5 buildaddr: no host"); 202038032Speter goto badaddr; 202138032Speter } 202238032Speter a->q_host = NULL; 202338032Speter } 202438032Speter else 202590792Sgshapiro a->q_host = sm_rpool_strdup_x(e->e_rpool, hbuf); 202638032Speter 202738032Speter /* figure out the user */ 202838032Speter p = ubuf; 202938032Speter if (bitnset(M_CHECKUDB, m->m_flags) && *p == '@') 203038032Speter { 203138032Speter p++; 203238032Speter tv++; 203338032Speter a->q_flags |= QNOTREMOTE; 203438032Speter } 203538032Speter 203638032Speter /* do special mapping for local mailer */ 203738032Speter if (*p == '"') 203838032Speter p++; 203938032Speter if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags)) 204038032Speter a->q_mailer = m = ProgMailer; 204138032Speter else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags)) 204238032Speter a->q_mailer = m = FileMailer; 204338032Speter else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags)) 204438032Speter { 204538032Speter /* may be :include: */ 204638032Speter stripquotes(ubuf); 204790792Sgshapiro if (sm_strncasecmp(ubuf, ":include:", 9) == 0) 204838032Speter { 204938032Speter /* if :include:, don't need further rewriting */ 205038032Speter a->q_mailer = m = InclMailer; 205190792Sgshapiro a->q_user = sm_rpool_strdup_x(e->e_rpool, &ubuf[9]); 205238032Speter return a; 205338032Speter } 205438032Speter } 205538032Speter 205638032Speter /* rewrite according recipient mailer rewriting rules */ 205790792Sgshapiro macdefine(&e->e_macro, A_PERM, 'h', a->q_host); 205864562Sgshapiro 205990792Sgshapiro if (ConfigLevel >= 10 || 206064562Sgshapiro !bitset(RF_SENDERADDR|RF_HEADERADDR, flags)) 206138032Speter { 206238032Speter /* sender addresses done later */ 206390792Sgshapiro (void) REWRITE(tv, 2, e); 206438032Speter if (m->m_re_rwset > 0) 206590792Sgshapiro (void) REWRITE(tv, m->m_re_rwset, e); 206638032Speter } 206790792Sgshapiro (void) REWRITE(tv, 4, e); 206838032Speter 206938032Speter /* save the result for the command line/RCPT argument */ 207038032Speter cataddr(tv, NULL, ubuf, sizeof ubuf, '\0'); 207190792Sgshapiro a->q_user = sm_rpool_strdup_x(e->e_rpool, ubuf); 207238032Speter 207338032Speter /* 207438032Speter ** Do mapping to lower case as requested by mailer 207538032Speter */ 207638032Speter 207738032Speter if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags)) 207838032Speter makelower(a->q_host); 207938032Speter if (!bitnset(M_USR_UPPER, m->m_flags)) 208038032Speter makelower(a->q_user); 208138032Speter 208238032Speter if (tTd(24, 6)) 208338032Speter { 208490792Sgshapiro sm_dprintf("buildaddr => "); 208590792Sgshapiro printaddr(a, false); 208638032Speter } 208738032Speter return a; 208838032Speter} 208990792Sgshapiro/* 209038032Speter** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 209138032Speter** 209238032Speter** Parameters: 209338032Speter** pvp -- parameter vector to rebuild. 209438032Speter** evp -- last parameter to include. Can be NULL to 209538032Speter** use entire pvp. 209638032Speter** buf -- buffer to build the string into. 209738032Speter** sz -- size of buf. 209890792Sgshapiro** spacesub -- the space separator character; if '\0', 209938032Speter** use SpaceSub. 210038032Speter** 210138032Speter** Returns: 210238032Speter** none. 210338032Speter** 210438032Speter** Side Effects: 210538032Speter** Destroys buf. 210638032Speter*/ 210738032Speter 210838032Spetervoid 210938032Spetercataddr(pvp, evp, buf, sz, spacesub) 211038032Speter char **pvp; 211138032Speter char **evp; 211238032Speter char *buf; 211338032Speter register int sz; 211438032Speter int spacesub; 211538032Speter{ 211690792Sgshapiro bool oatomtok = false; 211790792Sgshapiro bool natomtok = false; 211838032Speter register int i; 211938032Speter register char *p; 212038032Speter 212164562Sgshapiro if (sz <= 0) 212264562Sgshapiro return; 212364562Sgshapiro 212438032Speter if (spacesub == '\0') 212538032Speter spacesub = SpaceSub; 212638032Speter 212738032Speter if (pvp == NULL) 212838032Speter { 212964562Sgshapiro *buf = '\0'; 213038032Speter return; 213138032Speter } 213238032Speter p = buf; 213338032Speter sz -= 2; 213490792Sgshapiro while (*pvp != NULL && sz > 0) 213538032Speter { 213638032Speter natomtok = (TokTypeTab[**pvp & 0xff] == ATM); 213738032Speter if (oatomtok && natomtok) 213864562Sgshapiro { 213938032Speter *p++ = spacesub; 214090792Sgshapiro if (--sz <= 0) 214190792Sgshapiro break; 214264562Sgshapiro } 214390792Sgshapiro if ((i = sm_strlcpy(p, *pvp, sz)) >= sz) 214490792Sgshapiro break; 214538032Speter oatomtok = natomtok; 214638032Speter p += i; 214764562Sgshapiro sz -= i; 214838032Speter if (pvp++ == evp) 214938032Speter break; 215038032Speter } 215194334Sgshapiro#if _FFR_CATCH_LONG_STRINGS 215294334Sgshapiro /* Don't silently truncate long strings */ 215394334Sgshapiro if (*pvp != NULL) 215494334Sgshapiro syserr("cataddr: string too long"); 215594334Sgshapiro#endif /* _FFR_CATCH_LONG_STRINGS */ 215638032Speter *p = '\0'; 215738032Speter} 215890792Sgshapiro/* 215938032Speter** SAMEADDR -- Determine if two addresses are the same 216038032Speter** 216138032Speter** This is not just a straight comparison -- if the mailer doesn't 216238032Speter** care about the host we just ignore it, etc. 216338032Speter** 216438032Speter** Parameters: 216538032Speter** a, b -- pointers to the internal forms to compare. 216638032Speter** 216738032Speter** Returns: 216890792Sgshapiro** true -- they represent the same mailbox. 216990792Sgshapiro** false -- they don't. 217038032Speter** 217138032Speter** Side Effects: 217238032Speter** none. 217338032Speter*/ 217438032Speter 217538032Speterbool 217638032Spetersameaddr(a, b) 217738032Speter register ADDRESS *a; 217838032Speter register ADDRESS *b; 217938032Speter{ 218038032Speter register ADDRESS *ca, *cb; 218138032Speter 218238032Speter /* if they don't have the same mailer, forget it */ 218338032Speter if (a->q_mailer != b->q_mailer) 218490792Sgshapiro return false; 218538032Speter 218638032Speter /* if the user isn't the same, we can drop out */ 218738032Speter if (strcmp(a->q_user, b->q_user) != 0) 218890792Sgshapiro return false; 218938032Speter 219038032Speter /* if we have good uids for both but they differ, these are different */ 219138032Speter if (a->q_mailer == ProgMailer) 219238032Speter { 219338032Speter ca = getctladdr(a); 219438032Speter cb = getctladdr(b); 219538032Speter if (ca != NULL && cb != NULL && 219638032Speter bitset(QGOODUID, ca->q_flags & cb->q_flags) && 219738032Speter ca->q_uid != cb->q_uid) 219890792Sgshapiro return false; 219938032Speter } 220038032Speter 220138032Speter /* otherwise compare hosts (but be careful for NULL ptrs) */ 220238032Speter if (a->q_host == b->q_host) 220338032Speter { 220438032Speter /* probably both null pointers */ 220590792Sgshapiro return true; 220638032Speter } 220738032Speter if (a->q_host == NULL || b->q_host == NULL) 220838032Speter { 220938032Speter /* only one is a null pointer */ 221090792Sgshapiro return false; 221138032Speter } 221238032Speter if (strcmp(a->q_host, b->q_host) != 0) 221390792Sgshapiro return false; 221438032Speter 221590792Sgshapiro return true; 221638032Speter} 221790792Sgshapiro/* 221838032Speter** PRINTADDR -- print address (for debugging) 221938032Speter** 222038032Speter** Parameters: 222138032Speter** a -- the address to print 222238032Speter** follow -- follow the q_next chain. 222338032Speter** 222438032Speter** Returns: 222538032Speter** none. 222638032Speter** 222738032Speter** Side Effects: 222838032Speter** none. 222938032Speter*/ 223038032Speter 223138032Speterstruct qflags 223238032Speter{ 223390792Sgshapiro char *qf_name; 223490792Sgshapiro unsigned long qf_bit; 223538032Speter}; 223638032Speter 223764562Sgshapirostatic struct qflags AddressFlags[] = 223838032Speter{ 223938032Speter { "QGOODUID", QGOODUID }, 224038032Speter { "QPRIMARY", QPRIMARY }, 224138032Speter { "QNOTREMOTE", QNOTREMOTE }, 224238032Speter { "QSELFREF", QSELFREF }, 224338032Speter { "QBOGUSSHELL", QBOGUSSHELL }, 224438032Speter { "QUNSAFEADDR", QUNSAFEADDR }, 224538032Speter { "QPINGONSUCCESS", QPINGONSUCCESS }, 224638032Speter { "QPINGONFAILURE", QPINGONFAILURE }, 224738032Speter { "QPINGONDELAY", QPINGONDELAY }, 224838032Speter { "QHASNOTIFY", QHASNOTIFY }, 224938032Speter { "QRELAYED", QRELAYED }, 225038032Speter { "QEXPANDED", QEXPANDED }, 225138032Speter { "QDELIVERED", QDELIVERED }, 225238032Speter { "QDELAYED", QDELAYED }, 225338032Speter { "QTHISPASS", QTHISPASS }, 225438032Speter { "QRCPTOK", QRCPTOK }, 225571345Sgshapiro { NULL, 0 } 225638032Speter}; 225738032Speter 225838032Spetervoid 225938032Speterprintaddr(a, follow) 226038032Speter register ADDRESS *a; 226138032Speter bool follow; 226238032Speter{ 226338032Speter register MAILER *m; 226438032Speter MAILER pseudomailer; 226538032Speter register struct qflags *qfp; 226638032Speter bool firstone; 226738032Speter 226838032Speter if (a == NULL) 226938032Speter { 227090792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "[NULL]\n"); 227138032Speter return; 227238032Speter } 227338032Speter 227438032Speter while (a != NULL) 227538032Speter { 227690792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%p=", a); 227790792Sgshapiro (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 227838032Speter 227938032Speter /* find the mailer -- carefully */ 228038032Speter m = a->q_mailer; 228138032Speter if (m == NULL) 228238032Speter { 228338032Speter m = &pseudomailer; 228438032Speter m->m_mno = -1; 228538032Speter m->m_name = "NULL"; 228638032Speter } 228738032Speter 228890792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 228990792Sgshapiro "%s:\n\tmailer %d (%s), host `%s'\n", 229090792Sgshapiro a->q_paddr == NULL ? "<null>" : a->q_paddr, 229190792Sgshapiro m->m_mno, m->m_name, 229290792Sgshapiro a->q_host == NULL ? "<null>" : a->q_host); 229390792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 229490792Sgshapiro "\tuser `%s', ruser `%s'\n", 229590792Sgshapiro a->q_user, 229690792Sgshapiro a->q_ruser == NULL ? "<null>" : a->q_ruser); 229790792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\tstate="); 229864562Sgshapiro switch (a->q_state) 229964562Sgshapiro { 230064562Sgshapiro case QS_OK: 230190792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "OK"); 230264562Sgshapiro break; 230364562Sgshapiro 230464562Sgshapiro case QS_DONTSEND: 230590792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 230690792Sgshapiro "DONTSEND"); 230764562Sgshapiro break; 230864562Sgshapiro 230964562Sgshapiro case QS_BADADDR: 231090792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 231190792Sgshapiro "BADADDR"); 231264562Sgshapiro break; 231364562Sgshapiro 231464562Sgshapiro case QS_QUEUEUP: 231590792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 231690792Sgshapiro "QUEUEUP"); 231764562Sgshapiro break; 231864562Sgshapiro 231990792Sgshapiro case QS_RETRY: 232090792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "RETRY"); 232190792Sgshapiro break; 232290792Sgshapiro 232364562Sgshapiro case QS_SENT: 232490792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "SENT"); 232564562Sgshapiro break; 232664562Sgshapiro 232764562Sgshapiro case QS_VERIFIED: 232890792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 232990792Sgshapiro "VERIFIED"); 233064562Sgshapiro break; 233164562Sgshapiro 233264562Sgshapiro case QS_EXPANDED: 233390792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 233490792Sgshapiro "EXPANDED"); 233564562Sgshapiro break; 233664562Sgshapiro 233764562Sgshapiro case QS_SENDER: 233890792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 233990792Sgshapiro "SENDER"); 234064562Sgshapiro break; 234164562Sgshapiro 234264562Sgshapiro case QS_CLONED: 234390792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 234490792Sgshapiro "CLONED"); 234564562Sgshapiro break; 234664562Sgshapiro 234764562Sgshapiro case QS_DISCARDED: 234890792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 234990792Sgshapiro "DISCARDED"); 235064562Sgshapiro break; 235164562Sgshapiro 235264562Sgshapiro case QS_REPLACED: 235390792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 235490792Sgshapiro "REPLACED"); 235564562Sgshapiro break; 235664562Sgshapiro 235764562Sgshapiro case QS_REMOVED: 235890792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 235990792Sgshapiro "REMOVED"); 236064562Sgshapiro break; 236164562Sgshapiro 236264562Sgshapiro case QS_DUPLICATE: 236390792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 236490792Sgshapiro "DUPLICATE"); 236564562Sgshapiro break; 236664562Sgshapiro 236764562Sgshapiro case QS_INCLUDED: 236890792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 236990792Sgshapiro "INCLUDED"); 237064562Sgshapiro break; 237164562Sgshapiro 237264562Sgshapiro default: 237390792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 237490792Sgshapiro "%d", a->q_state); 237564562Sgshapiro break; 237664562Sgshapiro } 237790792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 237890792Sgshapiro ", next=%p, alias %p, uid %d, gid %d\n", 237990792Sgshapiro a->q_next, a->q_alias, 238090792Sgshapiro (int) a->q_uid, (int) a->q_gid); 238190792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\tflags=%lx<", 238290792Sgshapiro a->q_flags); 238390792Sgshapiro firstone = true; 238438032Speter for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++) 238538032Speter { 238638032Speter if (!bitset(qfp->qf_bit, a->q_flags)) 238738032Speter continue; 238838032Speter if (!firstone) 238990792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 239090792Sgshapiro ","); 239190792Sgshapiro firstone = false; 239290792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s", 239390792Sgshapiro qfp->qf_name); 239438032Speter } 239590792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, ">\n"); 239690792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 239790792Sgshapiro "\towner=%s, home=\"%s\", fullname=\"%s\"\n", 239890792Sgshapiro a->q_owner == NULL ? "(none)" : a->q_owner, 239990792Sgshapiro a->q_home == NULL ? "(none)" : a->q_home, 240090792Sgshapiro a->q_fullname == NULL ? "(none)" : a->q_fullname); 240190792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 240290792Sgshapiro "\torcpt=\"%s\", statmta=%s, status=%s\n", 240390792Sgshapiro a->q_orcpt == NULL ? "(none)" : a->q_orcpt, 240490792Sgshapiro a->q_statmta == NULL ? "(none)" : a->q_statmta, 240590792Sgshapiro a->q_status == NULL ? "(none)" : a->q_status); 240690792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 240790792Sgshapiro "\tfinalrcpt=\"%s\"\n", 240890792Sgshapiro a->q_finalrcpt == NULL ? "(none)" : a->q_finalrcpt); 240990792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 241090792Sgshapiro "\trstatus=\"%s\"\n", 241190792Sgshapiro a->q_rstatus == NULL ? "(none)" : a->q_rstatus); 241290792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 241390792Sgshapiro "\tstatdate=%s\n", 241490792Sgshapiro a->q_statdate == 0 ? "(none)" : ctime(&a->q_statdate)); 241538032Speter 241638032Speter if (!follow) 241738032Speter return; 241838032Speter a = a->q_next; 241938032Speter } 242038032Speter} 242190792Sgshapiro/* 242290792Sgshapiro** EMPTYADDR -- return true if this address is empty (``<>'') 242338032Speter** 242438032Speter** Parameters: 242538032Speter** a -- pointer to the address 242638032Speter** 242738032Speter** Returns: 242890792Sgshapiro** true -- if this address is "empty" (i.e., no one should 242938032Speter** ever generate replies to it. 243090792Sgshapiro** false -- if it is a "regular" (read: replyable) address. 243138032Speter*/ 243238032Speter 243338032Speterbool 243438032Speteremptyaddr(a) 243538032Speter register ADDRESS *a; 243638032Speter{ 243738032Speter return a->q_paddr == NULL || strcmp(a->q_paddr, "<>") == 0 || 243838032Speter a->q_user == NULL || strcmp(a->q_user, "<>") == 0; 243938032Speter} 244090792Sgshapiro/* 244138032Speter** REMOTENAME -- return the name relative to the current mailer 244238032Speter** 244338032Speter** Parameters: 244438032Speter** name -- the name to translate. 244538032Speter** m -- the mailer that we want to do rewriting relative 244638032Speter** to. 244738032Speter** flags -- fine tune operations. 244838032Speter** pstat -- pointer to status word. 244938032Speter** e -- the current envelope. 245038032Speter** 245138032Speter** Returns: 245238032Speter** the text string representing this address relative to 245338032Speter** the receiving mailer. 245438032Speter** 245538032Speter** Side Effects: 245638032Speter** none. 245738032Speter** 245838032Speter** Warnings: 245938032Speter** The text string returned is tucked away locally; 246038032Speter** copy it if you intend to save it. 246138032Speter*/ 246238032Speter 246338032Speterchar * 246438032Speterremotename(name, m, flags, pstat, e) 246538032Speter char *name; 246638032Speter struct mailer *m; 246738032Speter int flags; 246838032Speter int *pstat; 246938032Speter register ENVELOPE *e; 247038032Speter{ 247138032Speter register char **pvp; 247290792Sgshapiro char *SM_NONVOLATILE fancy; 247390792Sgshapiro char *oldg; 247438032Speter int rwset; 247538032Speter static char buf[MAXNAME + 1]; 247638032Speter char lbuf[MAXNAME + 1]; 247738032Speter char pvpbuf[PSBUFSIZE]; 247864562Sgshapiro char addrtype[4]; 247938032Speter 248038032Speter if (tTd(12, 1)) 248190792Sgshapiro sm_dprintf("remotename(%s)\n", name); 248238032Speter 248338032Speter /* don't do anything if we are tagging it as special */ 248438032Speter if (bitset(RF_SENDERADDR, flags)) 248564562Sgshapiro { 248638032Speter rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset 248738032Speter : m->m_se_rwset; 248864562Sgshapiro addrtype[2] = 's'; 248964562Sgshapiro } 249038032Speter else 249164562Sgshapiro { 249238032Speter rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset 249338032Speter : m->m_re_rwset; 249464562Sgshapiro addrtype[2] = 'r'; 249564562Sgshapiro } 249638032Speter if (rwset < 0) 249764562Sgshapiro return name; 249864562Sgshapiro addrtype[1] = ' '; 249964562Sgshapiro addrtype[3] = '\0'; 250064562Sgshapiro addrtype[0] = bitset(RF_HEADERADDR, flags) ? 'h' : 'e'; 250190792Sgshapiro macdefine(&e->e_macro, A_TEMP, macid("{addr_type}"), addrtype); 250238032Speter 250338032Speter /* 250438032Speter ** Do a heuristic crack of this name to extract any comment info. 250538032Speter ** This will leave the name as a comment and a $g macro. 250638032Speter */ 250738032Speter 250838032Speter if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) 250938032Speter fancy = "\201g"; 251038032Speter else 251138032Speter fancy = crackaddr(name); 251238032Speter 251338032Speter /* 251438032Speter ** Turn the name into canonical form. 251538032Speter ** Normally this will be RFC 822 style, i.e., "user@domain". 251638032Speter ** If this only resolves to "user", and the "C" flag is 251738032Speter ** specified in the sending mailer, then the sender's 251838032Speter ** domain will be appended. 251938032Speter */ 252038032Speter 252138032Speter pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL); 252238032Speter if (pvp == NULL) 252364562Sgshapiro return name; 252490792Sgshapiro if (REWRITE(pvp, 3, e) == EX_TEMPFAIL) 252538032Speter *pstat = EX_TEMPFAIL; 252638032Speter if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) 252738032Speter { 252838032Speter /* append from domain to this address */ 252938032Speter register char **pxp = pvp; 253064562Sgshapiro int l = MAXATOM; /* size of buffer for pvp */ 253138032Speter 253238032Speter /* see if there is an "@domain" in the current name */ 253338032Speter while (*pxp != NULL && strcmp(*pxp, "@") != 0) 253464562Sgshapiro { 253538032Speter pxp++; 253664562Sgshapiro --l; 253764562Sgshapiro } 253838032Speter if (*pxp == NULL) 253938032Speter { 254038032Speter /* no.... append the "@domain" from the sender */ 254138032Speter register char **qxq = e->e_fromdomain; 254238032Speter 254338032Speter while ((*pxp++ = *qxq++) != NULL) 254464562Sgshapiro { 254564562Sgshapiro if (--l <= 0) 254664562Sgshapiro { 254764562Sgshapiro *--pxp = NULL; 254864562Sgshapiro usrerr("553 5.1.0 remotename: too many tokens"); 254964562Sgshapiro *pstat = EX_UNAVAILABLE; 255064562Sgshapiro break; 255164562Sgshapiro } 255264562Sgshapiro } 255390792Sgshapiro if (REWRITE(pvp, 3, e) == EX_TEMPFAIL) 255438032Speter *pstat = EX_TEMPFAIL; 255538032Speter } 255638032Speter } 255738032Speter 255838032Speter /* 255938032Speter ** Do more specific rewriting. 256038032Speter ** Rewrite using ruleset 1 or 2 depending on whether this is 256138032Speter ** a sender address or not. 256238032Speter ** Then run it through any receiving-mailer-specific rulesets. 256338032Speter */ 256438032Speter 256538032Speter if (bitset(RF_SENDERADDR, flags)) 256638032Speter { 256790792Sgshapiro if (REWRITE(pvp, 1, e) == EX_TEMPFAIL) 256838032Speter *pstat = EX_TEMPFAIL; 256938032Speter } 257038032Speter else 257138032Speter { 257290792Sgshapiro if (REWRITE(pvp, 2, e) == EX_TEMPFAIL) 257338032Speter *pstat = EX_TEMPFAIL; 257438032Speter } 257538032Speter if (rwset > 0) 257638032Speter { 257790792Sgshapiro if (REWRITE(pvp, rwset, e) == EX_TEMPFAIL) 257838032Speter *pstat = EX_TEMPFAIL; 257938032Speter } 258038032Speter 258138032Speter /* 258238032Speter ** Do any final sanitation the address may require. 258338032Speter ** This will normally be used to turn internal forms 258438032Speter ** (e.g., user@host.LOCAL) into external form. This 258538032Speter ** may be used as a default to the above rules. 258638032Speter */ 258738032Speter 258890792Sgshapiro if (REWRITE(pvp, 4, e) == EX_TEMPFAIL) 258938032Speter *pstat = EX_TEMPFAIL; 259038032Speter 259138032Speter /* 259238032Speter ** Now restore the comment information we had at the beginning. 259338032Speter */ 259438032Speter 259538032Speter cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0'); 259690792Sgshapiro oldg = macget(&e->e_macro, 'g'); 259790792Sgshapiro macset(&e->e_macro, 'g', lbuf); 259838032Speter 259990792Sgshapiro SM_TRY 260090792Sgshapiro /* need to make sure route-addrs have <angle brackets> */ 260190792Sgshapiro if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@') 260290792Sgshapiro expand("<\201g>", buf, sizeof buf, e); 260390792Sgshapiro else 260490792Sgshapiro expand(fancy, buf, sizeof buf, e); 260590792Sgshapiro SM_FINALLY 260690792Sgshapiro macset(&e->e_macro, 'g', oldg); 260790792Sgshapiro SM_END_TRY 260838032Speter 260938032Speter if (tTd(12, 1)) 261090792Sgshapiro sm_dprintf("remotename => `%s'\n", buf); 261164562Sgshapiro return buf; 261238032Speter} 261390792Sgshapiro/* 261438032Speter** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 261538032Speter** 261638032Speter** Parameters: 261738032Speter** a -- the address to map (but just the user name part). 261838032Speter** sendq -- the sendq in which to install any replacement 261938032Speter** addresses. 262038032Speter** aliaslevel -- the alias nesting depth. 262138032Speter** e -- the envelope. 262238032Speter** 262338032Speter** Returns: 262438032Speter** none. 262538032Speter*/ 262638032Speter 262738032Speter#define Q_COPYFLAGS (QPRIMARY|QBOGUSSHELL|QUNSAFEADDR|\ 262838032Speter Q_PINGFLAGS|QHASNOTIFY|\ 262990792Sgshapiro QRELAYED|QEXPANDED|QDELIVERED|QDELAYED|\ 263090792Sgshapiro QBYTRACE|QBYNDELAY|QBYNRELAY) 263138032Speter 263238032Spetervoid 263338032Spetermaplocaluser(a, sendq, aliaslevel, e) 263438032Speter register ADDRESS *a; 263538032Speter ADDRESS **sendq; 263638032Speter int aliaslevel; 263738032Speter ENVELOPE *e; 263838032Speter{ 263938032Speter register char **pvp; 264090792Sgshapiro register ADDRESS *SM_NONVOLATILE a1 = NULL; 264138032Speter auto char *delimptr; 264238032Speter char pvpbuf[PSBUFSIZE]; 264338032Speter 264438032Speter if (tTd(29, 1)) 264538032Speter { 264690792Sgshapiro sm_dprintf("maplocaluser: "); 264790792Sgshapiro printaddr(a, false); 264838032Speter } 264938032Speter pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr, NULL); 265038032Speter if (pvp == NULL) 265138032Speter { 265238032Speter if (tTd(29, 9)) 265390792Sgshapiro sm_dprintf("maplocaluser: cannot prescan %s\n", 265464562Sgshapiro a->q_user); 265538032Speter return; 265638032Speter } 265738032Speter 265890792Sgshapiro macdefine(&e->e_macro, A_PERM, 'h', a->q_host); 265990792Sgshapiro macdefine(&e->e_macro, A_PERM, 'u', a->q_user); 266090792Sgshapiro macdefine(&e->e_macro, A_PERM, 'z', a->q_home); 266164562Sgshapiro 266290792Sgshapiro macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e r"); 266390792Sgshapiro if (REWRITE(pvp, 5, e) == EX_TEMPFAIL) 266438032Speter { 266538032Speter if (tTd(29, 9)) 266690792Sgshapiro sm_dprintf("maplocaluser: rewrite tempfail\n"); 266764562Sgshapiro a->q_state = QS_QUEUEUP; 266838032Speter a->q_status = "4.4.3"; 266938032Speter return; 267038032Speter } 267138032Speter if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 267238032Speter { 267338032Speter if (tTd(29, 9)) 267490792Sgshapiro sm_dprintf("maplocaluser: doesn't resolve\n"); 267538032Speter return; 267638032Speter } 267738032Speter 267890792Sgshapiro SM_TRY 267990792Sgshapiro a1 = buildaddr(pvp, NULL, 0, e); 268090792Sgshapiro SM_EXCEPT(exc, "E:mta.quickabort") 268190792Sgshapiro 268290792Sgshapiro /* 268390792Sgshapiro ** mark address as bad, S5 returned an error 268490792Sgshapiro ** and we gave that back to the SMTP client. 268590792Sgshapiro */ 268690792Sgshapiro 268790792Sgshapiro a->q_state = QS_DONTSEND; 268890792Sgshapiro sm_exc_raisenew_x(&EtypeQuickAbort, 2); 268990792Sgshapiro SM_END_TRY 269090792Sgshapiro 269138032Speter /* if non-null, mailer destination specified -- has it changed? */ 269238032Speter if (a1 == NULL || sameaddr(a, a1)) 269338032Speter { 269438032Speter if (tTd(29, 9)) 269590792Sgshapiro sm_dprintf("maplocaluser: address unchanged\n"); 269638032Speter return; 269738032Speter } 269838032Speter 269938032Speter /* make new address take on flags and print attributes of old */ 270038032Speter a1->q_flags &= ~Q_COPYFLAGS; 270138032Speter a1->q_flags |= a->q_flags & Q_COPYFLAGS; 270290792Sgshapiro a1->q_paddr = sm_rpool_strdup_x(e->e_rpool, a->q_paddr); 270390792Sgshapiro a1->q_finalrcpt = a->q_finalrcpt; 270464562Sgshapiro a1->q_orcpt = a->q_orcpt; 270538032Speter 270638032Speter /* mark old address as dead; insert new address */ 270764562Sgshapiro a->q_state = QS_REPLACED; 270838032Speter if (tTd(29, 5)) 270938032Speter { 271090792Sgshapiro sm_dprintf("maplocaluser: QS_REPLACED "); 271190792Sgshapiro printaddr(a, false); 271238032Speter } 271338032Speter a1->q_alias = a; 271490792Sgshapiro allocaddr(a1, RF_COPYALL, sm_rpool_strdup_x(e->e_rpool, a->q_paddr), e); 271538032Speter (void) recipient(a1, sendq, aliaslevel, e); 271638032Speter} 271790792Sgshapiro/* 271838032Speter** DEQUOTE_INIT -- initialize dequote map 271938032Speter** 272038032Speter** Parameters: 272138032Speter** map -- the internal map structure. 272238032Speter** args -- arguments. 272338032Speter** 272438032Speter** Returns: 272590792Sgshapiro** true. 272638032Speter*/ 272738032Speter 272838032Speterbool 272938032Speterdequote_init(map, args) 273038032Speter MAP *map; 273138032Speter char *args; 273238032Speter{ 273338032Speter register char *p = args; 273438032Speter 273564562Sgshapiro /* there is no check whether there is really an argument */ 273638032Speter map->map_mflags |= MF_KEEPQUOTES; 273738032Speter for (;;) 273838032Speter { 273938032Speter while (isascii(*p) && isspace(*p)) 274038032Speter p++; 274138032Speter if (*p != '-') 274238032Speter break; 274338032Speter switch (*++p) 274438032Speter { 274538032Speter case 'a': 274638032Speter map->map_app = ++p; 274738032Speter break; 274838032Speter 274964562Sgshapiro case 'D': 275064562Sgshapiro map->map_mflags |= MF_DEFER; 275164562Sgshapiro break; 275264562Sgshapiro 275364562Sgshapiro case 'S': 275438032Speter case 's': 275564562Sgshapiro map->map_spacesub = *++p; 275638032Speter break; 275738032Speter } 275838032Speter while (*p != '\0' && !(isascii(*p) && isspace(*p))) 275938032Speter p++; 276038032Speter if (*p != '\0') 276138032Speter *p = '\0'; 276238032Speter } 276338032Speter if (map->map_app != NULL) 276438032Speter map->map_app = newstr(map->map_app); 276538032Speter 276690792Sgshapiro return true; 276738032Speter} 276890792Sgshapiro/* 276938032Speter** DEQUOTE_MAP -- unquote an address 277038032Speter** 277138032Speter** Parameters: 277238032Speter** map -- the internal map structure (ignored). 277338032Speter** name -- the name to dequote. 277438032Speter** av -- arguments (ignored). 277538032Speter** statp -- pointer to status out-parameter. 277638032Speter** 277738032Speter** Returns: 277838032Speter** NULL -- if there were no quotes, or if the resulting 277938032Speter** unquoted buffer would not be acceptable to prescan. 278038032Speter** else -- The dequoted buffer. 278138032Speter*/ 278238032Speter 278338032Speter/* ARGSUSED2 */ 278438032Speterchar * 278538032Speterdequote_map(map, name, av, statp) 278638032Speter MAP *map; 278738032Speter char *name; 278838032Speter char **av; 278938032Speter int *statp; 279038032Speter{ 279138032Speter register char *p; 279238032Speter register char *q; 279338032Speter register char c; 279438032Speter int anglecnt = 0; 279538032Speter int cmntcnt = 0; 279638032Speter int quotecnt = 0; 279738032Speter int spacecnt = 0; 279890792Sgshapiro bool quotemode = false; 279990792Sgshapiro bool bslashmode = false; 280064562Sgshapiro char spacesub = map->map_spacesub; 280138032Speter 280238032Speter for (p = q = name; (c = *p++) != '\0'; ) 280338032Speter { 280438032Speter if (bslashmode) 280538032Speter { 280690792Sgshapiro bslashmode = false; 280738032Speter *q++ = c; 280838032Speter continue; 280938032Speter } 281038032Speter 281138032Speter if (c == ' ' && spacesub != '\0') 281238032Speter c = spacesub; 281338032Speter 281438032Speter switch (c) 281538032Speter { 281638032Speter case '\\': 281790792Sgshapiro bslashmode = true; 281838032Speter break; 281938032Speter 282038032Speter case '(': 282138032Speter cmntcnt++; 282238032Speter break; 282338032Speter 282438032Speter case ')': 282538032Speter if (cmntcnt-- <= 0) 282638032Speter return NULL; 282738032Speter break; 282838032Speter 282938032Speter case ' ': 283064562Sgshapiro case '\t': 283138032Speter spacecnt++; 283238032Speter break; 283338032Speter } 283438032Speter 283538032Speter if (cmntcnt > 0) 283638032Speter { 283738032Speter *q++ = c; 283838032Speter continue; 283938032Speter } 284038032Speter 284138032Speter switch (c) 284238032Speter { 284338032Speter case '"': 284438032Speter quotemode = !quotemode; 284538032Speter quotecnt++; 284638032Speter continue; 284738032Speter 284838032Speter case '<': 284938032Speter anglecnt++; 285038032Speter break; 285138032Speter 285238032Speter case '>': 285338032Speter if (anglecnt-- <= 0) 285438032Speter return NULL; 285538032Speter break; 285638032Speter } 285738032Speter *q++ = c; 285838032Speter } 285938032Speter 286038032Speter if (anglecnt != 0 || cmntcnt != 0 || bslashmode || 286138032Speter quotemode || quotecnt <= 0 || spacecnt != 0) 286238032Speter return NULL; 286338032Speter *q++ = '\0'; 286438032Speter return map_rewrite(map, name, strlen(name), NULL); 286538032Speter} 286690792Sgshapiro/* 286738032Speter** RSCHECK -- check string(s) for validity using rewriting sets 286838032Speter** 286938032Speter** Parameters: 287038032Speter** rwset -- the rewriting set to use. 287138032Speter** p1 -- the first string to check. 287238032Speter** p2 -- the second string to check -- may be null. 287338032Speter** e -- the current envelope. 287464562Sgshapiro** rmcomm -- remove comments? 287564562Sgshapiro** cnt -- count rejections (statistics)? 287690792Sgshapiro** logl -- logging level. 287771345Sgshapiro** host -- NULL or relay host. 287890792Sgshapiro** logid -- id for sm_syslog. 287938032Speter** 288038032Speter** Returns: 288138032Speter** EX_OK -- if the rwset doesn't resolve to $#error 288238032Speter** else -- the failure status (message printed) 288338032Speter*/ 288438032Speter 288538032Speterint 288690792Sgshapirorscheck(rwset, p1, p2, e, rmcomm, cnt, logl, host, logid) 288738032Speter char *rwset; 288838032Speter char *p1; 288938032Speter char *p2; 289038032Speter ENVELOPE *e; 289164562Sgshapiro bool rmcomm, cnt; 289264562Sgshapiro int logl; 289371345Sgshapiro char *host; 289490792Sgshapiro char *logid; 289538032Speter{ 289690792Sgshapiro char *volatile buf; 289738032Speter int bufsize; 289838032Speter int saveexitstat; 289990792Sgshapiro int volatile rstat = EX_OK; 290038032Speter char **pvp; 290138032Speter int rsno; 290290792Sgshapiro bool volatile discard = false; 290338032Speter auto ADDRESS a1; 290438032Speter bool saveQuickAbort = QuickAbort; 290538032Speter bool saveSuprErrs = SuprErrs; 290690792Sgshapiro#if _FFR_QUARANTINE 290790792Sgshapiro bool quarantine = false; 290890792Sgshapiro char ubuf[BUFSIZ * 2]; 290990792Sgshapiro#endif /* _FFR_QUARANTINE */ 291038032Speter char buf0[MAXLINE]; 291138032Speter char pvpbuf[PSBUFSIZE]; 291238032Speter extern char MsgBuf[]; 291338032Speter 291438032Speter if (tTd(48, 2)) 291590792Sgshapiro sm_dprintf("rscheck(%s, %s, %s)\n", rwset, p1, 291638032Speter p2 == NULL ? "(NULL)" : p2); 291738032Speter 291838032Speter rsno = strtorwset(rwset, NULL, ST_FIND); 291938032Speter if (rsno < 0) 292038032Speter return EX_OK; 292138032Speter 292238032Speter if (p2 != NULL) 292338032Speter { 292438032Speter bufsize = strlen(p1) + strlen(p2) + 2; 292538032Speter if (bufsize > sizeof buf0) 292690792Sgshapiro buf = sm_malloc_x(bufsize); 292738032Speter else 292838032Speter { 292938032Speter buf = buf0; 293038032Speter bufsize = sizeof buf0; 293138032Speter } 293290792Sgshapiro (void) sm_snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2); 293338032Speter } 293438032Speter else 293538032Speter { 293638032Speter bufsize = strlen(p1) + 1; 293738032Speter if (bufsize > sizeof buf0) 293890792Sgshapiro buf = sm_malloc_x(bufsize); 293938032Speter else 294038032Speter { 294138032Speter buf = buf0; 294238032Speter bufsize = sizeof buf0; 294338032Speter } 294490792Sgshapiro (void) sm_strlcpy(buf, p1, bufsize); 294538032Speter } 294690792Sgshapiro SM_TRY 294738032Speter { 294890792Sgshapiro SuprErrs = true; 294990792Sgshapiro QuickAbort = false; 295090792Sgshapiro pvp = prescan(buf, '\0', pvpbuf, sizeof pvpbuf, NULL, 295190792Sgshapiro rmcomm ? NULL : TokTypeNoC); 295290792Sgshapiro SuprErrs = saveSuprErrs; 295390792Sgshapiro if (pvp == NULL) 295490792Sgshapiro { 295590792Sgshapiro if (tTd(48, 2)) 295690792Sgshapiro sm_dprintf("rscheck: cannot prescan input\n"); 295790792Sgshapiro /* 295890792Sgshapiro syserr("rscheck: cannot prescan input: \"%s\"", 295990792Sgshapiro shortenstring(buf, MAXSHORTSTR)); 296090792Sgshapiro rstat = EX_DATAERR; 296190792Sgshapiro */ 296290792Sgshapiro goto finis; 296390792Sgshapiro } 296490792Sgshapiro (void) REWRITE(pvp, rsno, e); 296590792Sgshapiro if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET || 296690792Sgshapiro pvp[1] == NULL || (strcmp(pvp[1], "error") != 0 && 296790792Sgshapiro strcmp(pvp[1], "discard") != 0)) 296890792Sgshapiro { 296990792Sgshapiro goto finis; 297090792Sgshapiro } 297166494Sgshapiro 297290792Sgshapiro if (strcmp(pvp[1], "discard") == 0) 297390792Sgshapiro { 297490792Sgshapiro if (tTd(48, 2)) 297590792Sgshapiro sm_dprintf("rscheck: discard mailer selected\n"); 297690792Sgshapiro e->e_flags |= EF_DISCARD; 297790792Sgshapiro discard = true; 297890792Sgshapiro } 297990792Sgshapiro#if _FFR_QUARANTINE 298090792Sgshapiro else if (strcmp(pvp[1], "error") == 0 && 298190792Sgshapiro pvp[2] != NULL && (pvp[2][0] & 0377) == CANONHOST && 298290792Sgshapiro pvp[3] != NULL && strcmp(pvp[3], "quarantine") == 0) 298390792Sgshapiro { 298490792Sgshapiro if (pvp[4] == NULL || 298590792Sgshapiro (pvp[4][0] & 0377) != CANONUSER || 298690792Sgshapiro pvp[5] == NULL) 298790792Sgshapiro e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, 298890792Sgshapiro rwset); 298990792Sgshapiro else 299090792Sgshapiro { 299190792Sgshapiro cataddr(&(pvp[5]), NULL, ubuf, 299290792Sgshapiro sizeof ubuf, ' '); 299390792Sgshapiro e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, 299490792Sgshapiro ubuf); 299590792Sgshapiro } 299690792Sgshapiro macdefine(&e->e_macro, A_PERM, 299790792Sgshapiro macid("{quarantine}"), e->e_quarmsg); 299890792Sgshapiro quarantine = true; 299990792Sgshapiro } 300090792Sgshapiro#endif /* _FFR_QUARANTINE */ 300190792Sgshapiro else 300290792Sgshapiro { 300390792Sgshapiro int savelogusrerrs = LogUsrErrs; 300490792Sgshapiro static bool logged = false; 300590792Sgshapiro 300690792Sgshapiro /* got an error -- process it */ 300790792Sgshapiro saveexitstat = ExitStat; 300890792Sgshapiro LogUsrErrs = false; 300990792Sgshapiro (void) buildaddr(pvp, &a1, 0, e); 301090792Sgshapiro LogUsrErrs = savelogusrerrs; 301190792Sgshapiro rstat = ExitStat; 301290792Sgshapiro ExitStat = saveexitstat; 301390792Sgshapiro if (!logged) 301490792Sgshapiro { 301590792Sgshapiro if (cnt) 301690792Sgshapiro markstats(e, &a1, STATS_REJECT); 301790792Sgshapiro logged = true; 301890792Sgshapiro } 301990792Sgshapiro } 302090792Sgshapiro 302190792Sgshapiro if (LogLevel > logl) 302290792Sgshapiro { 302390792Sgshapiro char *relay; 302490792Sgshapiro char *p; 302590792Sgshapiro char lbuf[MAXLINE]; 302690792Sgshapiro 302790792Sgshapiro p = lbuf; 302890792Sgshapiro if (p2 != NULL) 302990792Sgshapiro { 303090792Sgshapiro (void) sm_snprintf(p, SPACELEFT(lbuf, p), 303190792Sgshapiro ", arg2=%s", 303290792Sgshapiro p2); 303390792Sgshapiro p += strlen(p); 303490792Sgshapiro } 303590792Sgshapiro 303690792Sgshapiro if (host != NULL) 303790792Sgshapiro relay = host; 303890792Sgshapiro else 303990792Sgshapiro relay = macvalue('_', e); 304090792Sgshapiro if (relay != NULL) 304190792Sgshapiro { 304290792Sgshapiro (void) sm_snprintf(p, SPACELEFT(lbuf, p), 304390792Sgshapiro ", relay=%s", relay); 304490792Sgshapiro p += strlen(p); 304590792Sgshapiro } 304690792Sgshapiro *p = '\0'; 304790792Sgshapiro if (discard) 304890792Sgshapiro sm_syslog(LOG_NOTICE, logid, 304990792Sgshapiro "ruleset=%s, arg1=%s%s, discard", 305090792Sgshapiro rwset, p1, lbuf); 305190792Sgshapiro#if _FFR_QUARANTINE 305290792Sgshapiro else if (quarantine) 305390792Sgshapiro sm_syslog(LOG_NOTICE, logid, 305490792Sgshapiro "ruleset=%s, arg1=%s%s, quarantine=%s", 305590792Sgshapiro rwset, p1, lbuf, ubuf); 305690792Sgshapiro#endif /* _FFR_QUARANTINE */ 305790792Sgshapiro else 305890792Sgshapiro sm_syslog(LOG_NOTICE, logid, 305990792Sgshapiro "ruleset=%s, arg1=%s%s, reject=%s", 306090792Sgshapiro rwset, p1, lbuf, MsgBuf); 306190792Sgshapiro } 306290792Sgshapiro 306390792Sgshapiro finis: ; 306473188Sgshapiro } 306590792Sgshapiro SM_FINALLY 306638032Speter { 306790792Sgshapiro /* clean up */ 306890792Sgshapiro if (buf != buf0) 306990792Sgshapiro sm_free(buf); 307090792Sgshapiro QuickAbort = saveQuickAbort; 307138032Speter } 307290792Sgshapiro SM_END_TRY 307338032Speter 307490792Sgshapiro setstat(rstat); 307590792Sgshapiro 307690792Sgshapiro /* rulesets don't set errno */ 307790792Sgshapiro errno = 0; 307890792Sgshapiro if (rstat != EX_OK && QuickAbort) 307990792Sgshapiro sm_exc_raisenew_x(&EtypeQuickAbort, 2); 308090792Sgshapiro return rstat; 308190792Sgshapiro} 308290792Sgshapiro/* 308390792Sgshapiro** RSCAP -- call rewriting set to return capabilities 308490792Sgshapiro** 308590792Sgshapiro** Parameters: 308690792Sgshapiro** rwset -- the rewriting set to use. 308790792Sgshapiro** p1 -- the first string to check. 308890792Sgshapiro** p2 -- the second string to check -- may be null. 308990792Sgshapiro** e -- the current envelope. 309090792Sgshapiro** pvp -- pointer to token vector. 309190792Sgshapiro** pvpbuf -- buffer space. 309290792Sgshapiro** 309390792Sgshapiro** Returns: 309490792Sgshapiro** EX_UNAVAILABLE -- ruleset doesn't exist. 309590792Sgshapiro** EX_DATAERR -- prescan() failed. 309690792Sgshapiro** EX_OK -- rewrite() was successful. 309790792Sgshapiro** else -- return status from rewrite(). 309890792Sgshapiro*/ 309990792Sgshapiro 310090792Sgshapiroint 310190792Sgshapirorscap(rwset, p1, p2, e, pvp, pvpbuf, size) 310290792Sgshapiro char *rwset; 310390792Sgshapiro char *p1; 310490792Sgshapiro char *p2; 310590792Sgshapiro ENVELOPE *e; 310690792Sgshapiro char ***pvp; 310790792Sgshapiro char *pvpbuf; 310890792Sgshapiro int size; 310990792Sgshapiro{ 311090792Sgshapiro char *volatile buf; 311190792Sgshapiro int bufsize; 311290792Sgshapiro int volatile rstat = EX_OK; 311390792Sgshapiro int rsno; 311490792Sgshapiro bool saveQuickAbort = QuickAbort; 311590792Sgshapiro bool saveSuprErrs = SuprErrs; 311690792Sgshapiro char buf0[MAXLINE]; 311790792Sgshapiro extern char MsgBuf[]; 311890792Sgshapiro 311990792Sgshapiro if (tTd(48, 2)) 312090792Sgshapiro sm_dprintf("rscap(%s, %s, %s)\n", rwset, p1, 312190792Sgshapiro p2 == NULL ? "(NULL)" : p2); 312290792Sgshapiro 312390792Sgshapiro if (pvp != NULL) 312490792Sgshapiro *pvp = NULL; 312590792Sgshapiro rsno = strtorwset(rwset, NULL, ST_FIND); 312690792Sgshapiro if (rsno < 0) 312790792Sgshapiro return EX_UNAVAILABLE; 312890792Sgshapiro 312990792Sgshapiro if (p2 != NULL) 313038032Speter { 313190792Sgshapiro bufsize = strlen(p1) + strlen(p2) + 2; 313290792Sgshapiro if (bufsize > sizeof buf0) 313390792Sgshapiro buf = sm_malloc_x(bufsize); 313490792Sgshapiro else 313590792Sgshapiro { 313690792Sgshapiro buf = buf0; 313790792Sgshapiro bufsize = sizeof buf0; 313890792Sgshapiro } 313990792Sgshapiro (void) sm_snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2); 314038032Speter } 314164562Sgshapiro else 314238032Speter { 314390792Sgshapiro bufsize = strlen(p1) + 1; 314490792Sgshapiro if (bufsize > sizeof buf0) 314590792Sgshapiro buf = sm_malloc_x(bufsize); 314690792Sgshapiro else 314738032Speter { 314890792Sgshapiro buf = buf0; 314990792Sgshapiro bufsize = sizeof buf0; 315038032Speter } 315190792Sgshapiro (void) sm_strlcpy(buf, p1, bufsize); 315238032Speter } 315390792Sgshapiro SM_TRY 315438032Speter { 315590792Sgshapiro SuprErrs = true; 315690792Sgshapiro QuickAbort = false; 315790792Sgshapiro *pvp = prescan(buf, '\0', pvpbuf, size, NULL, NULL); 315890792Sgshapiro if (*pvp != NULL) 315990792Sgshapiro rstat = REWRITE(*pvp, rsno, e); 316071345Sgshapiro else 316138032Speter { 316290792Sgshapiro if (tTd(48, 2)) 316390792Sgshapiro sm_dprintf("rscap: cannot prescan input\n"); 316490792Sgshapiro rstat = EX_DATAERR; 316538032Speter } 316638032Speter } 316790792Sgshapiro SM_FINALLY 316890792Sgshapiro { 316990792Sgshapiro /* clean up */ 317090792Sgshapiro if (buf != buf0) 317190792Sgshapiro sm_free(buf); 317290792Sgshapiro SuprErrs = saveSuprErrs; 317390792Sgshapiro QuickAbort = saveQuickAbort; 317438032Speter 317590792Sgshapiro /* prevent information leak, this may contain rewrite error */ 317690792Sgshapiro MsgBuf[0] = '\0'; 317790792Sgshapiro } 317890792Sgshapiro SM_END_TRY 317938032Speter return rstat; 318038032Speter} 3181