parseaddr.c revision 147078
138032Speter/* 2147078Sgshapiro * Copyright (c) 1998-2005 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 16147078SgshapiroSM_RCSID("@(#)$Id: parseaddr.c,v 8.381 2005/02/04 22:01:45 ca 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 93132943Sgshapiro pvp = prescan(addr, delim, pvpbuf, sizeof pvpbuf, delimptr, NULL, false); 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-->"); 231132943Sgshapiro printaddr(sm_debug_file(), 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. 463132943Sgshapiro** ignore -- if true, ignore unbalanced addresses 46438032Speter** 46538032Speter** Returns: 46638032Speter** A pointer to a vector of tokens. 46738032Speter** NULL on error. 46838032Speter*/ 46938032Speter 47038032Speter/* states and character types */ 47164562Sgshapiro#define OPR 0 /* operator */ 47264562Sgshapiro#define ATM 1 /* atom */ 47364562Sgshapiro#define QST 2 /* in quoted string */ 47464562Sgshapiro#define SPC 3 /* chewing up spaces */ 47564562Sgshapiro#define ONE 4 /* pick up one character */ 47664562Sgshapiro#define ILL 5 /* illegal character */ 47738032Speter 47864562Sgshapiro#define NSTATES 6 /* number of states */ 47964562Sgshapiro#define TYPE 017 /* mask to select state type */ 48038032Speter 48138032Speter/* meta bits for table */ 48264562Sgshapiro#define M 020 /* meta character; don't pass through */ 48364562Sgshapiro#define B 040 /* cause a break */ 48464562Sgshapiro#define MB M|B /* meta-break */ 48538032Speter 48638032Speterstatic short StateTab[NSTATES][NSTATES] = 48738032Speter{ 48838032Speter /* oldst chtype> OPR ATM QST SPC ONE ILL */ 48938032Speter /*OPR*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|MB }, 49038032Speter /*ATM*/ { OPR|B, ATM, QST|B, SPC|MB, ONE|B, ILL|MB }, 49138032Speter /*QST*/ { QST, QST, OPR, QST, QST, QST }, 49238032Speter /*SPC*/ { OPR, ATM, QST, SPC|M, ONE, ILL|MB }, 49338032Speter /*ONE*/ { OPR, OPR, OPR, OPR, OPR, ILL|MB }, 49438032Speter /*ILL*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|M }, 49538032Speter}; 49638032Speter 49738032Speter/* token type table -- it gets modified with $o characters */ 49890792Sgshapirostatic unsigned char TokTypeTab[256] = 49938032Speter{ 50038032Speter /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 50138032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM, 50238032Speter /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 50338032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 50438032Speter /* sp ! " # $ % & ' ( ) * + , - . / */ 50564562Sgshapiro SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, SPC,SPC,ATM,ATM,ATM,ATM,ATM,ATM, 50638032Speter /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 50738032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 50838032Speter /* @ A B C D E F G H I J K L M N O */ 50938032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 51038032Speter /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 51138032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 51238032Speter /* ` a b c d e f g h i j k l m n o */ 51338032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 51438032Speter /* p q r s t u v w x y z { | } ~ del */ 51538032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 51638032Speter 51738032Speter /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 51838032Speter OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 51938032Speter /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 52038032Speter OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 52138032Speter /* sp ! " # $ % & ' ( ) * + , - . / */ 52238032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 52338032Speter /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 52438032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 52538032Speter /* @ A B C D E F G H I J K L M N O */ 52638032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 52738032Speter /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 52838032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 52938032Speter /* ` a b c d e f g h i j k l m n o */ 53038032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 53138032Speter /* p q r s t u v w x y z { | } ~ del */ 53238032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 53338032Speter}; 53438032Speter 53538032Speter/* token type table for MIME parsing */ 53690792Sgshapirounsigned char MimeTokenTab[256] = 53738032Speter{ 53838032Speter /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 53938032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,SPC,SPC,SPC,SPC,SPC,ILL,ILL, 54038032Speter /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 54138032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 54238032Speter /* sp ! " # $ % & ' ( ) * + , - . / */ 54364562Sgshapiro SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, SPC,SPC,ATM,ATM,OPR,ATM,ATM,OPR, 54438032Speter /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 54538032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,OPR,OPR,OPR,OPR,OPR,OPR, 54638032Speter /* @ A B C D E F G H I J K L M N O */ 54738032Speter OPR,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 54838032Speter /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 54938032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,OPR,OPR,OPR,ATM,ATM, 55038032Speter /* ` a b c d e f g h i j k l m n o */ 55138032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 55238032Speter /* p q r s t u v w x y z { | } ~ del */ 55338032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 55438032Speter 55538032Speter /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 55638032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 55738032Speter /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 55838032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 55938032Speter /* sp ! " # $ % & ' ( ) * + , - . / */ 56038032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 56138032Speter /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 56238032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 56338032Speter /* @ A B C D E F G H I J K L M N O */ 56438032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 56538032Speter /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 56638032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 56738032Speter /* ` a b c d e f g h i j k l m n o */ 56838032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 56938032Speter /* p q r s t u v w x y z { | } ~ del */ 57038032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 57138032Speter}; 57238032Speter 57364562Sgshapiro/* token type table: don't strip comments */ 57490792Sgshapirounsigned char TokTypeNoC[256] = 57564562Sgshapiro{ 57664562Sgshapiro /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 57764562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM, 57864562Sgshapiro /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 57964562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 58064562Sgshapiro /* sp ! " # $ % & ' ( ) * + , - . / */ 58164562Sgshapiro SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, OPR,OPR,ATM,ATM,ATM,ATM,ATM,ATM, 58264562Sgshapiro /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 58364562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 58464562Sgshapiro /* @ A B C D E F G H I J K L M N O */ 58564562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 58664562Sgshapiro /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 58764562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 58864562Sgshapiro /* ` a b c d e f g h i j k l m n o */ 58964562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 59064562Sgshapiro /* p q r s t u v w x y z { | } ~ del */ 59164562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 59238032Speter 59364562Sgshapiro /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 59464562Sgshapiro OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 59564562Sgshapiro /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 59664562Sgshapiro OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 59764562Sgshapiro /* sp ! " # $ % & ' ( ) * + , - . / */ 59864562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 59964562Sgshapiro /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 60064562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 60164562Sgshapiro /* @ A B C D E F G H I J K L M N O */ 60264562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 60364562Sgshapiro /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 60464562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 60564562Sgshapiro /* ` a b c d e f g h i j k l m n o */ 60664562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 60764562Sgshapiro /* p q r s t u v w x y z { | } ~ del */ 60864562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 60964562Sgshapiro}; 61038032Speter 61164562Sgshapiro 612112810Sgshapiro#define NOCHAR (-1) /* signal nothing in lookahead token */ 61364562Sgshapiro 61438032Speterchar ** 615132943Sgshapiroprescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab, ignore) 61638032Speter char *addr; 61738032Speter int delim; 61838032Speter char pvpbuf[]; 61938032Speter int pvpbsize; 62038032Speter char **delimptr; 62190792Sgshapiro unsigned char *toktab; 622132943Sgshapiro bool ignore; 62338032Speter{ 62438032Speter register char *p; 62538032Speter register char *q; 62638032Speter register int c; 62738032Speter char **avp; 62838032Speter bool bslashmode; 62938032Speter bool route_syntax; 63038032Speter int cmntcnt; 63138032Speter int anglecnt; 63238032Speter char *tok; 63338032Speter int state; 63438032Speter int newstate; 63538032Speter char *saveto = CurEnv->e_to; 63664562Sgshapiro static char *av[MAXATOM + 1]; 63790792Sgshapiro static bool firsttime = true; 63838032Speter 63938032Speter if (firsttime) 64038032Speter { 64138032Speter /* initialize the token type table */ 64238032Speter char obuf[50]; 64338032Speter 64490792Sgshapiro firsttime = false; 64538032Speter if (OperatorChars == NULL) 64638032Speter { 64738032Speter if (ConfigLevel < 7) 64838032Speter OperatorChars = macvalue('o', CurEnv); 64938032Speter if (OperatorChars == NULL) 65038032Speter OperatorChars = ".:@[]"; 65138032Speter } 65264562Sgshapiro expand(OperatorChars, obuf, sizeof obuf - sizeof DELIMCHARS, 65364562Sgshapiro CurEnv); 65490792Sgshapiro (void) sm_strlcat(obuf, DELIMCHARS, sizeof obuf); 65538032Speter for (p = obuf; *p != '\0'; p++) 65638032Speter { 65738032Speter if (TokTypeTab[*p & 0xff] == ATM) 65838032Speter TokTypeTab[*p & 0xff] = OPR; 65964562Sgshapiro if (TokTypeNoC[*p & 0xff] == ATM) 66064562Sgshapiro TokTypeNoC[*p & 0xff] = OPR; 66138032Speter } 66238032Speter } 66338032Speter if (toktab == NULL) 66438032Speter toktab = TokTypeTab; 66538032Speter 66638032Speter /* make sure error messages don't have garbage on them */ 66738032Speter errno = 0; 66838032Speter 66938032Speter q = pvpbuf; 67090792Sgshapiro bslashmode = false; 67190792Sgshapiro route_syntax = false; 67238032Speter cmntcnt = 0; 67338032Speter anglecnt = 0; 67438032Speter avp = av; 67538032Speter state = ATM; 67638032Speter c = NOCHAR; 67738032Speter p = addr; 67838032Speter CurEnv->e_to = p; 67938032Speter if (tTd(22, 11)) 68038032Speter { 68190792Sgshapiro sm_dprintf("prescan: "); 682132943Sgshapiro xputs(sm_debug_file(), p); 68390792Sgshapiro sm_dprintf("\n"); 68438032Speter } 68538032Speter 68638032Speter do 68738032Speter { 68838032Speter /* read a token */ 68938032Speter tok = q; 69038032Speter for (;;) 69138032Speter { 69238032Speter /* store away any old lookahead character */ 69338032Speter if (c != NOCHAR && !bslashmode) 69438032Speter { 69538032Speter /* see if there is room */ 69638032Speter if (q >= &pvpbuf[pvpbsize - 5]) 69738032Speter { 698112810Sgshapiro addrtoolong: 69964562Sgshapiro usrerr("553 5.1.1 Address too long"); 70090792Sgshapiro if (strlen(addr) > MAXNAME) 70138032Speter addr[MAXNAME] = '\0'; 70238032Speter returnnull: 70338032Speter if (delimptr != NULL) 704120169Snectar { 705120169Snectar if (p > addr) 706120256Sgshapiro --p; 70738032Speter *delimptr = p; 708120169Snectar } 70938032Speter CurEnv->e_to = saveto; 71064562Sgshapiro return NULL; 71138032Speter } 71238032Speter 71338032Speter /* squirrel it away */ 714112810Sgshapiro#if !ALLOW_255 715112810Sgshapiro if ((char) c == (char) -1 && !tTd(82, 101)) 716112810Sgshapiro c &= 0x7f; 717112810Sgshapiro#endif /* !ALLOW_255 */ 71838032Speter *q++ = c; 71938032Speter } 72038032Speter 72138032Speter /* read a new input character */ 722112810Sgshapiro c = (*p++) & 0x00ff; 72338032Speter if (c == '\0') 72438032Speter { 72538032Speter /* diagnose and patch up bad syntax */ 726132943Sgshapiro if (ignore) 727132943Sgshapiro break; 728132943Sgshapiro else if (state == QST) 72938032Speter { 73090792Sgshapiro usrerr("553 Unbalanced '\"'"); 73138032Speter c = '"'; 73238032Speter } 73338032Speter else if (cmntcnt > 0) 73438032Speter { 73590792Sgshapiro usrerr("553 Unbalanced '('"); 73638032Speter c = ')'; 73738032Speter } 73838032Speter else if (anglecnt > 0) 73938032Speter { 74038032Speter c = '>'; 74190792Sgshapiro usrerr("553 Unbalanced '<'"); 74238032Speter } 74338032Speter else 74438032Speter break; 74538032Speter 74638032Speter p--; 74738032Speter } 74838032Speter else if (c == delim && cmntcnt <= 0 && state != QST) 74938032Speter { 75038032Speter if (anglecnt <= 0) 75138032Speter break; 75238032Speter 75338032Speter /* special case for better error management */ 754132943Sgshapiro if (delim == ',' && !route_syntax && !ignore) 75538032Speter { 75690792Sgshapiro usrerr("553 Unbalanced '<'"); 75738032Speter c = '>'; 75838032Speter p--; 75938032Speter } 76038032Speter } 76138032Speter 76238032Speter if (tTd(22, 101)) 76390792Sgshapiro sm_dprintf("c=%c, s=%d; ", c, state); 76438032Speter 76538032Speter /* chew up special characters */ 76638032Speter *q = '\0'; 76738032Speter if (bslashmode) 76838032Speter { 76990792Sgshapiro bslashmode = false; 77038032Speter 77138032Speter /* kludge \! for naive users */ 77238032Speter if (cmntcnt > 0) 77338032Speter { 77438032Speter c = NOCHAR; 77538032Speter continue; 77638032Speter } 77738032Speter else if (c != '!' || state == QST) 77838032Speter { 779112810Sgshapiro /* see if there is room */ 780112810Sgshapiro if (q >= &pvpbuf[pvpbsize - 5]) 781112810Sgshapiro goto addrtoolong; 78238032Speter *q++ = '\\'; 78338032Speter continue; 78438032Speter } 78538032Speter } 78638032Speter 78738032Speter if (c == '\\') 78838032Speter { 78990792Sgshapiro bslashmode = true; 79038032Speter } 79138032Speter else if (state == QST) 79238032Speter { 79364562Sgshapiro /* EMPTY */ 79438032Speter /* do nothing, just avoid next clauses */ 79538032Speter } 79664562Sgshapiro else if (c == '(' && toktab['('] == SPC) 79738032Speter { 79838032Speter cmntcnt++; 79938032Speter c = NOCHAR; 80038032Speter } 80164562Sgshapiro else if (c == ')' && toktab['('] == SPC) 80238032Speter { 80338032Speter if (cmntcnt <= 0) 80438032Speter { 805132943Sgshapiro if (!ignore) 806132943Sgshapiro { 807132943Sgshapiro usrerr("553 Unbalanced ')'"); 808132943Sgshapiro c = NOCHAR; 809132943Sgshapiro } 81038032Speter } 81138032Speter else 81238032Speter cmntcnt--; 81338032Speter } 81438032Speter else if (cmntcnt > 0) 81564562Sgshapiro { 81638032Speter c = NOCHAR; 81764562Sgshapiro } 81838032Speter else if (c == '<') 81938032Speter { 82064562Sgshapiro char *ptr = p; 82138032Speter 82238032Speter anglecnt++; 82364562Sgshapiro while (isascii(*ptr) && isspace(*ptr)) 82464562Sgshapiro ptr++; 82564562Sgshapiro if (*ptr == '@') 82690792Sgshapiro route_syntax = true; 82738032Speter } 82838032Speter else if (c == '>') 82938032Speter { 83038032Speter if (anglecnt <= 0) 83138032Speter { 832132943Sgshapiro if (!ignore) 833132943Sgshapiro { 834132943Sgshapiro usrerr("553 Unbalanced '>'"); 835132943Sgshapiro c = NOCHAR; 836132943Sgshapiro } 83738032Speter } 83838032Speter else 83938032Speter anglecnt--; 84090792Sgshapiro route_syntax = false; 84138032Speter } 84238032Speter else if (delim == ' ' && isascii(c) && isspace(c)) 84338032Speter c = ' '; 84438032Speter 84538032Speter if (c == NOCHAR) 84638032Speter continue; 84738032Speter 84838032Speter /* see if this is end of input */ 84938032Speter if (c == delim && anglecnt <= 0 && state != QST) 85038032Speter break; 85138032Speter 85238032Speter newstate = StateTab[state][toktab[c & 0xff]]; 85338032Speter if (tTd(22, 101)) 85490792Sgshapiro sm_dprintf("ns=%02o\n", newstate); 85538032Speter state = newstate & TYPE; 85638032Speter if (state == ILL) 85738032Speter { 85838032Speter if (isascii(c) && isprint(c)) 85990792Sgshapiro usrerr("553 Illegal character %c", c); 86038032Speter else 86190792Sgshapiro usrerr("553 Illegal character 0x%02x", 86290792Sgshapiro c & 0x0ff); 86338032Speter } 86438032Speter if (bitset(M, newstate)) 86538032Speter c = NOCHAR; 86638032Speter if (bitset(B, newstate)) 86738032Speter break; 86838032Speter } 86938032Speter 87038032Speter /* new token */ 87138032Speter if (tok != q) 87238032Speter { 873112810Sgshapiro /* see if there is room */ 874112810Sgshapiro if (q >= &pvpbuf[pvpbsize - 5]) 875112810Sgshapiro goto addrtoolong; 87638032Speter *q++ = '\0'; 87738032Speter if (tTd(22, 36)) 87838032Speter { 87990792Sgshapiro sm_dprintf("tok="); 880132943Sgshapiro xputs(sm_debug_file(), tok); 88190792Sgshapiro sm_dprintf("\n"); 88238032Speter } 88338032Speter if (avp >= &av[MAXATOM]) 88438032Speter { 88564562Sgshapiro usrerr("553 5.1.0 prescan: too many tokens"); 88638032Speter goto returnnull; 88738032Speter } 88838032Speter if (q - tok > MAXNAME) 88938032Speter { 89064562Sgshapiro usrerr("553 5.1.0 prescan: token too long"); 89138032Speter goto returnnull; 89238032Speter } 89338032Speter *avp++ = tok; 89438032Speter } 89538032Speter } while (c != '\0' && (c != delim || anglecnt > 0)); 89638032Speter *avp = NULL; 89738032Speter if (delimptr != NULL) 898120256Sgshapiro { 899120256Sgshapiro if (p > addr) 900120256Sgshapiro p--; 90138032Speter *delimptr = p; 902120256Sgshapiro } 90338032Speter if (tTd(22, 12)) 90438032Speter { 90590792Sgshapiro sm_dprintf("prescan==>"); 906132943Sgshapiro printav(sm_debug_file(), av); 90738032Speter } 90838032Speter CurEnv->e_to = saveto; 90938032Speter if (av[0] == NULL) 91038032Speter { 91138032Speter if (tTd(22, 1)) 91290792Sgshapiro sm_dprintf("prescan: null leading token\n"); 91364562Sgshapiro return NULL; 91438032Speter } 91564562Sgshapiro return av; 91638032Speter} 91790792Sgshapiro/* 91838032Speter** REWRITE -- apply rewrite rules to token vector. 91938032Speter** 92038032Speter** This routine is an ordered production system. Each rewrite 92138032Speter** rule has a LHS (called the pattern) and a RHS (called the 92238032Speter** rewrite); 'rwr' points the the current rewrite rule. 92338032Speter** 92438032Speter** For each rewrite rule, 'avp' points the address vector we 92538032Speter** are trying to match against, and 'pvp' points to the pattern. 92638032Speter** If pvp points to a special match value (MATCHZANY, MATCHANY, 92738032Speter** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp 92838032Speter** matched is saved away in the match vector (pointed to by 'mvp'). 92938032Speter** 93038032Speter** When a match between avp & pvp does not match, we try to 93138032Speter** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS 93238032Speter** we must also back out the match in mvp. If we reach a 93338032Speter** MATCHANY or MATCHZANY we just extend the match and start 93438032Speter** over again. 93538032Speter** 93638032Speter** When we finally match, we rewrite the address vector 93738032Speter** and try over again. 93838032Speter** 93938032Speter** Parameters: 94038032Speter** pvp -- pointer to token vector. 94138032Speter** ruleset -- the ruleset to use for rewriting. 94238032Speter** reclevel -- recursion level (to catch loops). 94338032Speter** e -- the current envelope. 94490792Sgshapiro** maxatom -- maximum length of buffer (usually MAXATOM) 94538032Speter** 94638032Speter** Returns: 94738032Speter** A status code. If EX_TEMPFAIL, higher level code should 94838032Speter** attempt recovery. 94938032Speter** 95038032Speter** Side Effects: 95138032Speter** pvp is modified. 95238032Speter*/ 95338032Speter 95438032Speterstruct match 95538032Speter{ 95664562Sgshapiro char **match_first; /* first token matched */ 95764562Sgshapiro char **match_last; /* last token matched */ 95864562Sgshapiro char **match_pattern; /* pointer to pattern */ 95938032Speter}; 96038032Speter 96138032Speterint 96290792Sgshapirorewrite(pvp, ruleset, reclevel, e, maxatom) 96338032Speter char **pvp; 96438032Speter int ruleset; 96538032Speter int reclevel; 96638032Speter register ENVELOPE *e; 96790792Sgshapiro int maxatom; 96838032Speter{ 96938032Speter register char *ap; /* address pointer */ 97038032Speter register char *rp; /* rewrite pointer */ 97164562Sgshapiro register char *rulename; /* ruleset name */ 97264562Sgshapiro register char *prefix; 97338032Speter register char **avp; /* address vector pointer */ 97438032Speter register char **rvp; /* rewrite vector pointer */ 97538032Speter register struct match *mlp; /* cur ptr into mlist */ 97638032Speter register struct rewrite *rwr; /* pointer to current rewrite rule */ 97738032Speter int ruleno; /* current rule number */ 97838032Speter int rstat = EX_OK; /* return status */ 97938032Speter int loopcount; 98038032Speter struct match mlist[MAXMATCH]; /* stores match on LHS */ 98164562Sgshapiro char *npvp[MAXATOM + 1]; /* temporary space for rebuild */ 98238032Speter char buf[MAXLINE]; 98364562Sgshapiro char name[6]; 98438032Speter 985120256Sgshapiro /* 986120256Sgshapiro ** mlp will not exceed mlist[] because readcf enforces 987120256Sgshapiro ** the upper limit of entries when reading rulesets. 988120256Sgshapiro */ 989120256Sgshapiro 99064562Sgshapiro if (ruleset < 0 || ruleset >= MAXRWSETS) 99138032Speter { 99264562Sgshapiro syserr("554 5.3.5 rewrite: illegal ruleset number %d", ruleset); 99364562Sgshapiro return EX_CONFIG; 99464562Sgshapiro } 99564562Sgshapiro rulename = RuleSetNames[ruleset]; 99664562Sgshapiro if (rulename == NULL) 99764562Sgshapiro { 99890792Sgshapiro (void) sm_snprintf(name, sizeof name, "%d", ruleset); 99964562Sgshapiro rulename = name; 100064562Sgshapiro } 100164562Sgshapiro if (OpMode == MD_TEST) 100264562Sgshapiro prefix = ""; 100364562Sgshapiro else 100464562Sgshapiro prefix = "rewrite: ruleset "; 100564562Sgshapiro if (OpMode == MD_TEST) 100664562Sgshapiro { 100790792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 100890792Sgshapiro "%s%-16.16s input:", prefix, rulename); 1009132943Sgshapiro printav(smioout, pvp); 101038032Speter } 101164562Sgshapiro else if (tTd(21, 1)) 101238032Speter { 101390792Sgshapiro sm_dprintf("%s%-16.16s input:", prefix, rulename); 1014132943Sgshapiro printav(sm_debug_file(), pvp); 101538032Speter } 101638032Speter if (reclevel++ > MaxRuleRecursion) 101738032Speter { 101864562Sgshapiro syserr("rewrite: excessive recursion (max %d), ruleset %s", 101964562Sgshapiro MaxRuleRecursion, rulename); 102038032Speter return EX_CONFIG; 102138032Speter } 102238032Speter if (pvp == NULL) 102338032Speter return EX_USAGE; 1024120256Sgshapiro if (maxatom <= 0) 1025120256Sgshapiro return EX_USAGE; 102638032Speter 102738032Speter /* 102838032Speter ** Run through the list of rewrite rules, applying 102938032Speter ** any that match. 103038032Speter */ 103138032Speter 103238032Speter ruleno = 1; 103338032Speter loopcount = 0; 103438032Speter for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 103538032Speter { 103664562Sgshapiro int status; 103738032Speter 103838032Speter /* if already canonical, quit now */ 103938032Speter if (pvp[0] != NULL && (pvp[0][0] & 0377) == CANONNET) 104038032Speter break; 104138032Speter 104238032Speter if (tTd(21, 12)) 104338032Speter { 104464562Sgshapiro if (tTd(21, 15)) 104590792Sgshapiro sm_dprintf("-----trying rule (line %d):", 104664562Sgshapiro rwr->r_line); 104764562Sgshapiro else 104890792Sgshapiro sm_dprintf("-----trying rule:"); 1049132943Sgshapiro printav(sm_debug_file(), rwr->r_lhs); 105038032Speter } 105138032Speter 105238032Speter /* try to match on this rule */ 105338032Speter mlp = mlist; 105438032Speter rvp = rwr->r_lhs; 105538032Speter avp = pvp; 105638032Speter if (++loopcount > 100) 105738032Speter { 105864562Sgshapiro syserr("554 5.3.5 Infinite loop in ruleset %s, rule %d", 105964562Sgshapiro rulename, ruleno); 106038032Speter if (tTd(21, 1)) 106138032Speter { 106290792Sgshapiro sm_dprintf("workspace: "); 1063132943Sgshapiro printav(sm_debug_file(), pvp); 106438032Speter } 106538032Speter break; 106638032Speter } 106738032Speter 106838032Speter while ((ap = *avp) != NULL || *rvp != NULL) 106938032Speter { 107038032Speter rp = *rvp; 107138032Speter if (tTd(21, 35)) 107238032Speter { 107390792Sgshapiro sm_dprintf("ADVANCE rp="); 1074132943Sgshapiro xputs(sm_debug_file(), rp); 107590792Sgshapiro sm_dprintf(", ap="); 1076132943Sgshapiro xputs(sm_debug_file(), ap); 107790792Sgshapiro sm_dprintf("\n"); 107838032Speter } 107938032Speter if (rp == NULL) 108038032Speter { 108138032Speter /* end-of-pattern before end-of-address */ 108238032Speter goto backup; 108338032Speter } 108438032Speter if (ap == NULL && (*rp & 0377) != MATCHZANY && 108538032Speter (*rp & 0377) != MATCHZERO) 108638032Speter { 108738032Speter /* end-of-input with patterns left */ 108838032Speter goto backup; 108938032Speter } 109038032Speter 109138032Speter switch (*rp & 0377) 109238032Speter { 109338032Speter case MATCHCLASS: 109438032Speter /* match any phrase in a class */ 109564562Sgshapiro mlp->match_pattern = rvp; 109664562Sgshapiro mlp->match_first = avp; 109738032Speter extendclass: 109838032Speter ap = *avp; 109938032Speter if (ap == NULL) 110038032Speter goto backup; 110164562Sgshapiro mlp->match_last = avp++; 110264562Sgshapiro cataddr(mlp->match_first, mlp->match_last, 110364562Sgshapiro buf, sizeof buf, '\0'); 110438032Speter if (!wordinclass(buf, rp[1])) 110538032Speter { 110638032Speter if (tTd(21, 36)) 110738032Speter { 110890792Sgshapiro sm_dprintf("EXTEND rp="); 1109132943Sgshapiro xputs(sm_debug_file(), rp); 111090792Sgshapiro sm_dprintf(", ap="); 1111132943Sgshapiro xputs(sm_debug_file(), ap); 111290792Sgshapiro sm_dprintf("\n"); 111338032Speter } 111438032Speter goto extendclass; 111538032Speter } 111638032Speter if (tTd(21, 36)) 111790792Sgshapiro sm_dprintf("CLMATCH\n"); 111838032Speter mlp++; 111938032Speter break; 112038032Speter 112138032Speter case MATCHNCLASS: 112238032Speter /* match any token not in a class */ 112338032Speter if (wordinclass(ap, rp[1])) 112438032Speter goto backup; 112538032Speter 112664562Sgshapiro /* FALLTHROUGH */ 112738032Speter 112838032Speter case MATCHONE: 112938032Speter case MATCHANY: 113038032Speter /* match exactly one token */ 113164562Sgshapiro mlp->match_pattern = rvp; 113264562Sgshapiro mlp->match_first = avp; 113364562Sgshapiro mlp->match_last = avp++; 113438032Speter mlp++; 113538032Speter break; 113638032Speter 113738032Speter case MATCHZANY: 113838032Speter /* match zero or more tokens */ 113964562Sgshapiro mlp->match_pattern = rvp; 114064562Sgshapiro mlp->match_first = avp; 114164562Sgshapiro mlp->match_last = avp - 1; 114238032Speter mlp++; 114338032Speter break; 114438032Speter 114538032Speter case MATCHZERO: 114638032Speter /* match zero tokens */ 114738032Speter break; 114838032Speter 114938032Speter case MACRODEXPAND: 115038032Speter /* 115138032Speter ** Match against run-time macro. 115238032Speter ** This algorithm is broken for the 115338032Speter ** general case (no recursive macros, 115438032Speter ** improper tokenization) but should 115538032Speter ** work for the usual cases. 115638032Speter */ 115738032Speter 115838032Speter ap = macvalue(rp[1], e); 115964562Sgshapiro mlp->match_first = avp; 116038032Speter if (tTd(21, 2)) 116198841Sgshapiro sm_dprintf("rewrite: LHS $&{%s} => \"%s\"\n", 116238032Speter macname(rp[1]), 116338032Speter ap == NULL ? "(NULL)" : ap); 116438032Speter 116538032Speter if (ap == NULL) 116638032Speter break; 116738032Speter while (*ap != '\0') 116838032Speter { 116938032Speter if (*avp == NULL || 117090792Sgshapiro sm_strncasecmp(ap, *avp, 117190792Sgshapiro strlen(*avp)) != 0) 117238032Speter { 117338032Speter /* no match */ 117464562Sgshapiro avp = mlp->match_first; 117538032Speter goto backup; 117638032Speter } 117738032Speter ap += strlen(*avp++); 117838032Speter } 117938032Speter 118038032Speter /* match */ 118138032Speter break; 118238032Speter 118338032Speter default: 118438032Speter /* must have exact match */ 118538032Speter if (sm_strcasecmp(rp, ap)) 118638032Speter goto backup; 118738032Speter avp++; 118838032Speter break; 118938032Speter } 119038032Speter 119138032Speter /* successful match on this token */ 119238032Speter rvp++; 119338032Speter continue; 119438032Speter 119538032Speter backup: 119638032Speter /* match failed -- back up */ 119738032Speter while (--mlp >= mlist) 119838032Speter { 119964562Sgshapiro rvp = mlp->match_pattern; 120038032Speter rp = *rvp; 120164562Sgshapiro avp = mlp->match_last + 1; 120238032Speter ap = *avp; 120338032Speter 120438032Speter if (tTd(21, 36)) 120538032Speter { 120690792Sgshapiro sm_dprintf("BACKUP rp="); 1207132943Sgshapiro xputs(sm_debug_file(), rp); 120890792Sgshapiro sm_dprintf(", ap="); 1209132943Sgshapiro xputs(sm_debug_file(), ap); 121090792Sgshapiro sm_dprintf("\n"); 121138032Speter } 121238032Speter 121338032Speter if (ap == NULL) 121438032Speter { 121538032Speter /* run off the end -- back up again */ 121638032Speter continue; 121738032Speter } 121838032Speter if ((*rp & 0377) == MATCHANY || 121938032Speter (*rp & 0377) == MATCHZANY) 122038032Speter { 122138032Speter /* extend binding and continue */ 122264562Sgshapiro mlp->match_last = avp++; 122338032Speter rvp++; 122438032Speter mlp++; 122538032Speter break; 122638032Speter } 122738032Speter if ((*rp & 0377) == MATCHCLASS) 122838032Speter { 122938032Speter /* extend binding and try again */ 123064562Sgshapiro mlp->match_last = avp; 123138032Speter goto extendclass; 123238032Speter } 123338032Speter } 123438032Speter 123538032Speter if (mlp < mlist) 123638032Speter { 123738032Speter /* total failure to match */ 123838032Speter break; 123938032Speter } 124038032Speter } 124138032Speter 124238032Speter /* 124338032Speter ** See if we successfully matched 124438032Speter */ 124538032Speter 124638032Speter if (mlp < mlist || *rvp != NULL) 124738032Speter { 124838032Speter if (tTd(21, 10)) 124990792Sgshapiro sm_dprintf("----- rule fails\n"); 125038032Speter rwr = rwr->r_next; 125138032Speter ruleno++; 125238032Speter loopcount = 0; 125338032Speter continue; 125438032Speter } 125538032Speter 125638032Speter rvp = rwr->r_rhs; 125738032Speter if (tTd(21, 12)) 125838032Speter { 125990792Sgshapiro sm_dprintf("-----rule matches:"); 1260132943Sgshapiro printav(sm_debug_file(), rvp); 126138032Speter } 126238032Speter 126338032Speter rp = *rvp; 126464562Sgshapiro if (rp != NULL) 126538032Speter { 126664562Sgshapiro if ((*rp & 0377) == CANONUSER) 126764562Sgshapiro { 126864562Sgshapiro rvp++; 126964562Sgshapiro rwr = rwr->r_next; 127064562Sgshapiro ruleno++; 127164562Sgshapiro loopcount = 0; 127264562Sgshapiro } 127364562Sgshapiro else if ((*rp & 0377) == CANONHOST) 127464562Sgshapiro { 127564562Sgshapiro rvp++; 127664562Sgshapiro rwr = NULL; 127764562Sgshapiro } 127838032Speter } 127938032Speter 128038032Speter /* substitute */ 128138032Speter for (avp = npvp; *rvp != NULL; rvp++) 128238032Speter { 128338032Speter register struct match *m; 128438032Speter register char **pp; 128538032Speter 128638032Speter rp = *rvp; 128738032Speter if ((*rp & 0377) == MATCHREPL) 128838032Speter { 128938032Speter /* substitute from LHS */ 129038032Speter m = &mlist[rp[1] - '1']; 129138032Speter if (m < mlist || m >= mlp) 129238032Speter { 129364562Sgshapiro syserr("554 5.3.5 rewrite: ruleset %s: replacement $%c out of bounds", 129464562Sgshapiro rulename, rp[1]); 129538032Speter return EX_CONFIG; 129638032Speter } 129738032Speter if (tTd(21, 15)) 129838032Speter { 129990792Sgshapiro sm_dprintf("$%c:", rp[1]); 130064562Sgshapiro pp = m->match_first; 130164562Sgshapiro while (pp <= m->match_last) 130238032Speter { 130390792Sgshapiro sm_dprintf(" %p=\"", *pp); 130490792Sgshapiro sm_dflush(); 130590792Sgshapiro sm_dprintf("%s\"", *pp++); 130638032Speter } 130790792Sgshapiro sm_dprintf("\n"); 130838032Speter } 130964562Sgshapiro pp = m->match_first; 131064562Sgshapiro while (pp <= m->match_last) 131138032Speter { 131290792Sgshapiro if (avp >= &npvp[maxatom]) 1313120256Sgshapiro goto toolong; 131438032Speter *avp++ = *pp++; 131538032Speter } 131638032Speter } 131738032Speter else 131838032Speter { 131938032Speter /* some sort of replacement */ 132090792Sgshapiro if (avp >= &npvp[maxatom]) 132138032Speter { 132238032Speter toolong: 132364562Sgshapiro syserr("554 5.3.0 rewrite: expansion too long"); 132490792Sgshapiro if (LogLevel > 9) 132590792Sgshapiro sm_syslog(LOG_ERR, e->e_id, 132690792Sgshapiro "rewrite: expansion too long, ruleset=%s, ruleno=%d", 132790792Sgshapiro rulename, ruleno); 132838032Speter return EX_DATAERR; 132938032Speter } 133038032Speter if ((*rp & 0377) != MACRODEXPAND) 133138032Speter { 133238032Speter /* vanilla replacement */ 133338032Speter *avp++ = rp; 133438032Speter } 133538032Speter else 133638032Speter { 133798841Sgshapiro /* $&{x} replacement */ 133838032Speter char *mval = macvalue(rp[1], e); 133938032Speter char **xpvp; 134038032Speter int trsize = 0; 134138032Speter static size_t pvpb1_size = 0; 134238032Speter static char **pvpb1 = NULL; 134338032Speter char pvpbuf[PSBUFSIZE]; 134438032Speter 134538032Speter if (tTd(21, 2)) 134698841Sgshapiro sm_dprintf("rewrite: RHS $&{%s} => \"%s\"\n", 134738032Speter macname(rp[1]), 134838032Speter mval == NULL ? "(NULL)" : mval); 134938032Speter if (mval == NULL || *mval == '\0') 135038032Speter continue; 135138032Speter 135238032Speter /* save the remainder of the input */ 135338032Speter for (xpvp = pvp; *xpvp != NULL; xpvp++) 135438032Speter trsize += sizeof *xpvp; 135564562Sgshapiro if ((size_t) trsize > pvpb1_size) 135638032Speter { 135738032Speter if (pvpb1 != NULL) 135877349Sgshapiro sm_free(pvpb1); 135990792Sgshapiro pvpb1 = (char **) 136090792Sgshapiro sm_pmalloc_x(trsize); 136138032Speter pvpb1_size = trsize; 136238032Speter } 136338032Speter 136464562Sgshapiro memmove((char *) pvpb1, 136564562Sgshapiro (char *) pvp, 136664562Sgshapiro trsize); 136738032Speter 136838032Speter /* scan the new replacement */ 136938032Speter xpvp = prescan(mval, '\0', pvpbuf, 137064562Sgshapiro sizeof pvpbuf, NULL, 1371132943Sgshapiro NULL, false); 137238032Speter if (xpvp == NULL) 137338032Speter { 137438032Speter /* prescan pre-printed error */ 137538032Speter return EX_DATAERR; 137638032Speter } 137738032Speter 137838032Speter /* insert it into the output stream */ 137938032Speter while (*xpvp != NULL) 138038032Speter { 138138032Speter if (tTd(21, 19)) 138290792Sgshapiro sm_dprintf(" ... %s\n", 138364562Sgshapiro *xpvp); 138490792Sgshapiro *avp++ = sm_rpool_strdup_x( 138590792Sgshapiro e->e_rpool, *xpvp); 138690792Sgshapiro if (avp >= &npvp[maxatom]) 138738032Speter goto toolong; 138838032Speter xpvp++; 138938032Speter } 139038032Speter if (tTd(21, 19)) 139190792Sgshapiro sm_dprintf(" ... DONE\n"); 139238032Speter 139338032Speter /* restore the old trailing input */ 139464562Sgshapiro memmove((char *) pvp, 139564562Sgshapiro (char *) pvpb1, 139664562Sgshapiro trsize); 139738032Speter } 139838032Speter } 139938032Speter } 140038032Speter *avp++ = NULL; 140138032Speter 140238032Speter /* 140338032Speter ** Check for any hostname/keyword lookups. 140438032Speter */ 140538032Speter 140638032Speter for (rvp = npvp; *rvp != NULL; rvp++) 140738032Speter { 140838032Speter char **hbrvp; 140938032Speter char **xpvp; 141038032Speter int trsize; 141138032Speter char *replac; 141238032Speter int endtoken; 141338032Speter STAB *map; 141438032Speter char *mapname; 141538032Speter char **key_rvp; 141638032Speter char **arg_rvp; 141738032Speter char **default_rvp; 141864562Sgshapiro char cbuf[MAXNAME + 1]; 141938032Speter char *pvpb1[MAXATOM + 1]; 1420120256Sgshapiro char *argvect[MAX_MAP_ARGS]; 142138032Speter char pvpbuf[PSBUFSIZE]; 142238032Speter char *nullpvp[1]; 142338032Speter 142438032Speter if ((**rvp & 0377) != HOSTBEGIN && 142538032Speter (**rvp & 0377) != LOOKUPBEGIN) 142638032Speter continue; 142738032Speter 142838032Speter /* 142938032Speter ** Got a hostname/keyword lookup. 143038032Speter ** 143138032Speter ** This could be optimized fairly easily. 143238032Speter */ 143338032Speter 143438032Speter hbrvp = rvp; 143538032Speter if ((**rvp & 0377) == HOSTBEGIN) 143638032Speter { 143738032Speter endtoken = HOSTEND; 143838032Speter mapname = "host"; 143938032Speter } 144038032Speter else 144138032Speter { 144238032Speter endtoken = LOOKUPEND; 144338032Speter mapname = *++rvp; 1444120256Sgshapiro if (mapname == NULL) 1445120256Sgshapiro syserr("554 5.3.0 rewrite: missing mapname"); 144638032Speter } 144738032Speter map = stab(mapname, ST_MAP, ST_FIND); 144838032Speter if (map == NULL) 1449120256Sgshapiro syserr("554 5.3.0 rewrite: map %s not found", 1450120256Sgshapiro mapname); 145138032Speter 145238032Speter /* extract the match part */ 145338032Speter key_rvp = ++rvp; 1454120256Sgshapiro if (key_rvp == NULL) 1455120256Sgshapiro syserr("554 5.3.0 rewrite: missing key for map %s", 1456120256Sgshapiro mapname); 145738032Speter default_rvp = NULL; 145838032Speter arg_rvp = argvect; 145938032Speter xpvp = NULL; 146038032Speter replac = pvpbuf; 146138032Speter while (*rvp != NULL && (**rvp & 0377) != endtoken) 146238032Speter { 146338032Speter int nodetype = **rvp & 0377; 146438032Speter 1465120256Sgshapiro if (nodetype != CANONHOST && 1466120256Sgshapiro nodetype != CANONUSER) 146738032Speter { 146838032Speter rvp++; 146938032Speter continue; 147038032Speter } 147138032Speter 147238032Speter *rvp++ = NULL; 147338032Speter 147438032Speter if (xpvp != NULL) 147538032Speter { 147638032Speter cataddr(xpvp, NULL, replac, 147738032Speter &pvpbuf[sizeof pvpbuf] - replac, 147838032Speter '\0'); 1479120256Sgshapiro if (arg_rvp < 1480120256Sgshapiro &argvect[MAX_MAP_ARGS - 1]) 1481120256Sgshapiro *++arg_rvp = replac; 148238032Speter replac += strlen(replac) + 1; 148338032Speter xpvp = NULL; 148438032Speter } 148538032Speter switch (nodetype) 148638032Speter { 148738032Speter case CANONHOST: 148838032Speter xpvp = rvp; 148938032Speter break; 149038032Speter 149138032Speter case CANONUSER: 149238032Speter default_rvp = rvp; 149338032Speter break; 149438032Speter } 149538032Speter } 149638032Speter if (*rvp != NULL) 149738032Speter *rvp++ = NULL; 149838032Speter if (xpvp != NULL) 149938032Speter { 150038032Speter cataddr(xpvp, NULL, replac, 150138032Speter &pvpbuf[sizeof pvpbuf] - replac, 150238032Speter '\0'); 1503120256Sgshapiro if (arg_rvp < &argvect[MAX_MAP_ARGS - 1]) 1504120256Sgshapiro *++arg_rvp = replac; 150538032Speter } 1506120256Sgshapiro if (arg_rvp >= &argvect[MAX_MAP_ARGS - 1]) 1507120256Sgshapiro argvect[MAX_MAP_ARGS - 1] = NULL; 1508120256Sgshapiro else 1509120256Sgshapiro *++arg_rvp = NULL; 151038032Speter 151138032Speter /* save the remainder of the input string */ 151238032Speter trsize = (int) (avp - rvp + 1) * sizeof *rvp; 151364562Sgshapiro memmove((char *) pvpb1, (char *) rvp, trsize); 151438032Speter 151538032Speter /* look it up */ 151664562Sgshapiro cataddr(key_rvp, NULL, cbuf, sizeof cbuf, 151764562Sgshapiro map == NULL ? '\0' : map->s_map.map_spacesub); 151864562Sgshapiro argvect[0] = cbuf; 151964562Sgshapiro replac = map_lookup(map, cbuf, argvect, &rstat, e); 152038032Speter 152138032Speter /* if no replacement, use default */ 152238032Speter if (replac == NULL && default_rvp != NULL) 152338032Speter { 152438032Speter /* create the default */ 152564562Sgshapiro cataddr(default_rvp, NULL, cbuf, sizeof cbuf, '\0'); 152664562Sgshapiro replac = cbuf; 152738032Speter } 152838032Speter 152938032Speter if (replac == NULL) 153038032Speter { 153138032Speter xpvp = key_rvp; 153238032Speter } 153338032Speter else if (*replac == '\0') 153438032Speter { 153538032Speter /* null replacement */ 153638032Speter nullpvp[0] = NULL; 153738032Speter xpvp = nullpvp; 153838032Speter } 153938032Speter else 154038032Speter { 154138032Speter /* scan the new replacement */ 154238032Speter xpvp = prescan(replac, '\0', pvpbuf, 1543132943Sgshapiro sizeof pvpbuf, NULL, NULL, false); 154438032Speter if (xpvp == NULL) 154538032Speter { 154638032Speter /* prescan already printed error */ 154738032Speter return EX_DATAERR; 154838032Speter } 154938032Speter } 155038032Speter 155138032Speter /* append it to the token list */ 155238032Speter for (avp = hbrvp; *xpvp != NULL; xpvp++) 155338032Speter { 155490792Sgshapiro *avp++ = sm_rpool_strdup_x(e->e_rpool, *xpvp); 155590792Sgshapiro if (avp >= &npvp[maxatom]) 155638032Speter goto toolong; 155738032Speter } 155838032Speter 155938032Speter /* restore the old trailing information */ 156038032Speter rvp = avp - 1; 156138032Speter for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) 156290792Sgshapiro if (avp >= &npvp[maxatom]) 156338032Speter goto toolong; 156438032Speter } 156538032Speter 156638032Speter /* 156738032Speter ** Check for subroutine calls. 156838032Speter */ 156938032Speter 157064562Sgshapiro status = callsubr(npvp, reclevel, e); 157164562Sgshapiro if (rstat == EX_OK || status == EX_TEMPFAIL) 157264562Sgshapiro rstat = status; 157338032Speter 157438032Speter /* copy vector back into original space. */ 157538032Speter for (avp = npvp; *avp++ != NULL;) 157638032Speter continue; 157764562Sgshapiro memmove((char *) pvp, (char *) npvp, 157838032Speter (int) (avp - npvp) * sizeof *avp); 157964562Sgshapiro 158038032Speter if (tTd(21, 4)) 158138032Speter { 158290792Sgshapiro sm_dprintf("rewritten as:"); 1583132943Sgshapiro printav(sm_debug_file(), pvp); 158438032Speter } 158538032Speter } 158638032Speter 158764562Sgshapiro if (OpMode == MD_TEST) 158838032Speter { 158990792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 159090792Sgshapiro "%s%-16.16s returns:", prefix, rulename); 1591132943Sgshapiro printav(smioout, pvp); 159238032Speter } 159364562Sgshapiro else if (tTd(21, 1)) 159464562Sgshapiro { 159590792Sgshapiro sm_dprintf("%s%-16.16s returns:", prefix, rulename); 1596132943Sgshapiro printav(sm_debug_file(), pvp); 159764562Sgshapiro } 159838032Speter return rstat; 159938032Speter} 160090792Sgshapiro/* 160138032Speter** CALLSUBR -- call subroutines in rewrite vector 160238032Speter** 160338032Speter** Parameters: 160438032Speter** pvp -- pointer to token vector. 160538032Speter** reclevel -- the current recursion level. 160638032Speter** e -- the current envelope. 160738032Speter** 160838032Speter** Returns: 160938032Speter** The status from the subroutine call. 161038032Speter** 161138032Speter** Side Effects: 161238032Speter** pvp is modified. 161338032Speter*/ 161438032Speter 161564562Sgshapirostatic int 161638032Spetercallsubr(pvp, reclevel, e) 161738032Speter char **pvp; 161838032Speter int reclevel; 161938032Speter ENVELOPE *e; 162038032Speter{ 162164562Sgshapiro char **avp; 162238032Speter register int i; 162390792Sgshapiro int subr, j; 162490792Sgshapiro int nsubr; 162564562Sgshapiro int status; 162638032Speter int rstat = EX_OK; 162790792Sgshapiro#define MAX_SUBR 16 162890792Sgshapiro int subrnumber[MAX_SUBR]; 162990792Sgshapiro int subrindex[MAX_SUBR]; 163038032Speter 163190792Sgshapiro nsubr = 0; 163290792Sgshapiro 163390792Sgshapiro /* 163490792Sgshapiro ** Look for subroutine calls in pvp, collect them into subr*[] 163590792Sgshapiro ** We will perform the calls in the next loop, because we will 163690792Sgshapiro ** call the "last" subroutine first to avoid recursive calls 163790792Sgshapiro ** and too much copying. 163890792Sgshapiro */ 163990792Sgshapiro 164090792Sgshapiro for (avp = pvp, j = 0; *avp != NULL; avp++, j++) 164138032Speter { 164238032Speter if ((**avp & 0377) == CALLSUBR && avp[1] != NULL) 164338032Speter { 164438032Speter stripquotes(avp[1]); 164538032Speter subr = strtorwset(avp[1], NULL, ST_FIND); 164638032Speter if (subr < 0) 164738032Speter { 164890792Sgshapiro syserr("554 5.3.5 Unknown ruleset %s", avp[1]); 164938032Speter return EX_CONFIG; 165038032Speter } 165138032Speter 165238032Speter /* 165390792Sgshapiro ** XXX instead of doing this we could optimize 165490792Sgshapiro ** the rules after reading them: just remove 165590792Sgshapiro ** calls to empty rulesets 165638032Speter */ 165738032Speter 165890792Sgshapiro /* subroutine is an empty ruleset? don't call it */ 165990792Sgshapiro if (RewriteRules[subr] == NULL) 166090792Sgshapiro { 166190792Sgshapiro if (tTd(21, 3)) 166290792Sgshapiro sm_dprintf("-----skip subr %s (%d)\n", 166390792Sgshapiro avp[1], subr); 166490792Sgshapiro for (i = 2; avp[i] != NULL; i++) 166590792Sgshapiro avp[i - 2] = avp[i]; 166690792Sgshapiro avp[i - 2] = NULL; 166738032Speter continue; 166890792Sgshapiro } 166990792Sgshapiro if (++nsubr >= MAX_SUBR) 167038032Speter { 167190792Sgshapiro syserr("554 5.3.0 Too many subroutine calls (%d max)", 167290792Sgshapiro MAX_SUBR); 167390792Sgshapiro return EX_CONFIG; 167438032Speter } 167590792Sgshapiro subrnumber[nsubr] = subr; 167690792Sgshapiro subrindex[nsubr] = j; 167790792Sgshapiro } 167890792Sgshapiro } 167938032Speter 168090792Sgshapiro /* 168190792Sgshapiro ** Perform the actual subroutines calls, "last" one first, i.e., 168290792Sgshapiro ** go from the right to the left through all calls, 168390792Sgshapiro ** do the rewriting in place. 168490792Sgshapiro */ 168538032Speter 168690792Sgshapiro for (; nsubr > 0; nsubr--) 168790792Sgshapiro { 168890792Sgshapiro subr = subrnumber[nsubr]; 168990792Sgshapiro avp = pvp + subrindex[nsubr]; 169038032Speter 169190792Sgshapiro /* remove the subroutine call and name */ 169290792Sgshapiro for (i = 2; avp[i] != NULL; i++) 169390792Sgshapiro avp[i - 2] = avp[i]; 169490792Sgshapiro avp[i - 2] = NULL; 169538032Speter 169690792Sgshapiro /* 169790792Sgshapiro ** Now we need to call the ruleset specified for 1698120256Sgshapiro ** the subroutine. We can do this in place since 169990792Sgshapiro ** we call the "last" subroutine first. 170090792Sgshapiro */ 170190792Sgshapiro 170290792Sgshapiro status = rewrite(avp, subr, reclevel, e, 170390792Sgshapiro MAXATOM - subrindex[nsubr]); 170490792Sgshapiro if (status != EX_OK && status != EX_TEMPFAIL) 170590792Sgshapiro return status; 170690792Sgshapiro if (rstat == EX_OK || status == EX_TEMPFAIL) 170790792Sgshapiro rstat = status; 170838032Speter } 170938032Speter return rstat; 171038032Speter} 171190792Sgshapiro/* 171238032Speter** MAP_LOOKUP -- do lookup in map 171338032Speter** 171438032Speter** Parameters: 171590792Sgshapiro** smap -- the map to use for the lookup. 171638032Speter** key -- the key to look up. 171738032Speter** argvect -- arguments to pass to the map lookup. 171838032Speter** pstat -- a pointer to an integer in which to store the 171938032Speter** status from the lookup. 172038032Speter** e -- the current envelope. 172138032Speter** 172238032Speter** Returns: 172338032Speter** The result of the lookup. 172438032Speter** NULL -- if there was no data for the given key. 172538032Speter*/ 172638032Speter 172764562Sgshapirostatic char * 172864562Sgshapiromap_lookup(smap, key, argvect, pstat, e) 172964562Sgshapiro STAB *smap; 173038032Speter char key[]; 173138032Speter char **argvect; 173238032Speter int *pstat; 173338032Speter ENVELOPE *e; 173438032Speter{ 173564562Sgshapiro auto int status = EX_OK; 173664562Sgshapiro MAP *map; 173738032Speter char *replac; 173838032Speter 173964562Sgshapiro if (smap == NULL) 174064562Sgshapiro return NULL; 174164562Sgshapiro 174264562Sgshapiro map = &smap->s_map; 174364562Sgshapiro DYNOPENMAP(map); 174464562Sgshapiro 174564562Sgshapiro if (e->e_sendmode == SM_DEFER && 174664562Sgshapiro bitset(MF_DEFER, map->map_mflags)) 174738032Speter { 174838032Speter /* don't do any map lookups */ 174938032Speter if (tTd(60, 1)) 175090792Sgshapiro sm_dprintf("map_lookup(%s, %s) => DEFERRED\n", 175164562Sgshapiro smap->s_name, key); 175238032Speter *pstat = EX_TEMPFAIL; 175338032Speter return NULL; 175438032Speter } 175538032Speter 175664562Sgshapiro if (!bitset(MF_KEEPQUOTES, map->map_mflags)) 175738032Speter stripquotes(key); 175838032Speter 175938032Speter if (tTd(60, 1)) 176042575Speter { 176190792Sgshapiro sm_dprintf("map_lookup(%s, %s", smap->s_name, key); 176242575Speter if (tTd(60, 5)) 176342575Speter { 176442575Speter int i; 176542575Speter 176642575Speter for (i = 0; argvect[i] != NULL; i++) 176790792Sgshapiro sm_dprintf(", %%%d=%s", i, argvect[i]); 176842575Speter } 176990792Sgshapiro sm_dprintf(") => "); 177042575Speter } 177164562Sgshapiro replac = (*map->map_class->map_lookup)(map, key, argvect, &status); 177238032Speter if (tTd(60, 1)) 177390792Sgshapiro sm_dprintf("%s (%d)\n", 177438032Speter replac != NULL ? replac : "NOT FOUND", 177564562Sgshapiro status); 177638032Speter 177764562Sgshapiro /* should recover if status == EX_TEMPFAIL */ 177864562Sgshapiro if (status == EX_TEMPFAIL && !bitset(MF_NODEFER, map->map_mflags)) 177938032Speter { 178038032Speter *pstat = EX_TEMPFAIL; 178138032Speter if (tTd(60, 1)) 178290792Sgshapiro sm_dprintf("map_lookup(%s, %s) tempfail: errno=%d\n", 178364562Sgshapiro smap->s_name, key, errno); 178438032Speter if (e->e_message == NULL) 178538032Speter { 178638032Speter char mbuf[320]; 178738032Speter 178890792Sgshapiro (void) sm_snprintf(mbuf, sizeof mbuf, 178938032Speter "%.80s map: lookup (%s): deferred", 179064562Sgshapiro smap->s_name, 179138032Speter shortenstring(key, MAXSHORTSTR)); 179290792Sgshapiro e->e_message = sm_rpool_strdup_x(e->e_rpool, mbuf); 179338032Speter } 179438032Speter } 179564562Sgshapiro if (status == EX_TEMPFAIL && map->map_tapp != NULL) 179638032Speter { 179764562Sgshapiro size_t i = strlen(key) + strlen(map->map_tapp) + 1; 179838032Speter static char *rwbuf = NULL; 179938032Speter static size_t rwbuflen = 0; 180038032Speter 180138032Speter if (i > rwbuflen) 180238032Speter { 180338032Speter if (rwbuf != NULL) 180477349Sgshapiro sm_free(rwbuf); 180538032Speter rwbuflen = i; 180690792Sgshapiro rwbuf = (char *) sm_pmalloc_x(rwbuflen); 180738032Speter } 180890792Sgshapiro (void) sm_strlcpyn(rwbuf, rwbuflen, 2, key, map->map_tapp); 180938032Speter if (tTd(60, 4)) 181090792Sgshapiro sm_dprintf("map_lookup tempfail: returning \"%s\"\n", 181138032Speter rwbuf); 181238032Speter return rwbuf; 181338032Speter } 181438032Speter return replac; 181538032Speter} 181690792Sgshapiro/* 181764562Sgshapiro** INITERRMAILERS -- initialize error and discard mailers 181864562Sgshapiro** 181964562Sgshapiro** Parameters: 182064562Sgshapiro** none. 182164562Sgshapiro** 182264562Sgshapiro** Returns: 182364562Sgshapiro** none. 182464562Sgshapiro** 182564562Sgshapiro** Side Effects: 182664562Sgshapiro** initializes error and discard mailers. 182764562Sgshapiro*/ 182864562Sgshapiro 182964562Sgshapirostatic MAILER discardmailer; 183064562Sgshapirostatic MAILER errormailer; 183164562Sgshapirostatic char *discardargv[] = { "DISCARD", NULL }; 183264562Sgshapirostatic char *errorargv[] = { "ERROR", NULL }; 183364562Sgshapiro 183464562Sgshapirovoid 183564562Sgshapiroiniterrmailers() 183664562Sgshapiro{ 183764562Sgshapiro if (discardmailer.m_name == NULL) 183864562Sgshapiro { 183964562Sgshapiro /* initialize the discard mailer */ 184064562Sgshapiro discardmailer.m_name = "*discard*"; 184164562Sgshapiro discardmailer.m_mailer = "DISCARD"; 184264562Sgshapiro discardmailer.m_argv = discardargv; 184364562Sgshapiro } 184464562Sgshapiro if (errormailer.m_name == NULL) 184564562Sgshapiro { 184664562Sgshapiro /* initialize the bogus mailer */ 184764562Sgshapiro errormailer.m_name = "*error*"; 184864562Sgshapiro errormailer.m_mailer = "ERROR"; 184964562Sgshapiro errormailer.m_argv = errorargv; 185064562Sgshapiro } 185164562Sgshapiro} 185290792Sgshapiro/* 185338032Speter** BUILDADDR -- build address from token vector. 185438032Speter** 185538032Speter** Parameters: 185638032Speter** tv -- token vector. 185738032Speter** a -- pointer to address descriptor to fill. 185838032Speter** If NULL, one will be allocated. 185938032Speter** flags -- info regarding whether this is a sender or 186038032Speter** a recipient. 186138032Speter** e -- the current envelope. 186238032Speter** 186338032Speter** Returns: 186438032Speter** NULL if there was an error. 186538032Speter** 'a' otherwise. 186638032Speter** 186738032Speter** Side Effects: 186838032Speter** fills in 'a' 186938032Speter*/ 187038032Speter 187164562Sgshapirostatic struct errcodes 187238032Speter{ 187338032Speter char *ec_name; /* name of error code */ 187438032Speter int ec_code; /* numeric code */ 187538032Speter} ErrorCodes[] = 187638032Speter{ 187738032Speter { "usage", EX_USAGE }, 187838032Speter { "nouser", EX_NOUSER }, 187938032Speter { "nohost", EX_NOHOST }, 188038032Speter { "unavailable", EX_UNAVAILABLE }, 188138032Speter { "software", EX_SOFTWARE }, 188238032Speter { "tempfail", EX_TEMPFAIL }, 188338032Speter { "protocol", EX_PROTOCOL }, 188438032Speter { "config", EX_CONFIG }, 188538032Speter { NULL, EX_UNAVAILABLE } 188638032Speter}; 188738032Speter 188864562Sgshapirostatic ADDRESS * 188938032Speterbuildaddr(tv, a, flags, e) 189038032Speter register char **tv; 189138032Speter register ADDRESS *a; 189238032Speter int flags; 189338032Speter register ENVELOPE *e; 189438032Speter{ 189594334Sgshapiro bool tempfail = false; 1896120256Sgshapiro int maxatom; 189738032Speter struct mailer **mp; 189838032Speter register struct mailer *m; 189938032Speter register char *p; 190038032Speter char *mname; 190138032Speter char **hostp; 190238032Speter char hbuf[MAXNAME + 1]; 190342575Speter static char ubuf[MAXNAME + 2]; 190438032Speter 190538032Speter if (tTd(24, 5)) 190638032Speter { 190790792Sgshapiro sm_dprintf("buildaddr, flags=%x, tv=", flags); 1908132943Sgshapiro printav(sm_debug_file(), tv); 190938032Speter } 191038032Speter 1911120256Sgshapiro maxatom = MAXATOM; 191238032Speter if (a == NULL) 191390792Sgshapiro a = (ADDRESS *) sm_rpool_malloc_x(e->e_rpool, sizeof *a); 191464562Sgshapiro memset((char *) a, '\0', sizeof *a); 191564562Sgshapiro hbuf[0] = '\0'; 191638032Speter 191738032Speter /* set up default error return flags */ 191838032Speter a->q_flags |= DefaultNotify; 191938032Speter 192038032Speter /* figure out what net/mailer to use */ 192138032Speter if (*tv == NULL || (**tv & 0377) != CANONNET) 192238032Speter { 192364562Sgshapiro syserr("554 5.3.5 buildaddr: no mailer in parsed address"); 192438032Speterbadaddr: 192594334Sgshapiro /* 192694334Sgshapiro ** ExitStat may have been set by an earlier map open 192794334Sgshapiro ** failure (to a permanent error (EX_OSERR) in syserr()) 192894334Sgshapiro ** so we also need to check if this particular $#error 192994334Sgshapiro ** return wanted a 4XX failure. 193094334Sgshapiro ** 193194334Sgshapiro ** XXX the real fix is probably to set ExitStat correctly, 193294334Sgshapiro ** i.e., to EX_TEMPFAIL if the map open is just a temporary 193394334Sgshapiro ** error. 193494334Sgshapiro */ 193594334Sgshapiro 193694334Sgshapiro if (ExitStat == EX_TEMPFAIL || tempfail) 193764562Sgshapiro a->q_state = QS_QUEUEUP; 193864562Sgshapiro else 193938032Speter { 194064562Sgshapiro a->q_state = QS_BADADDR; 194164562Sgshapiro a->q_mailer = &errormailer; 194238032Speter } 194338032Speter return a; 194438032Speter } 194538032Speter mname = *++tv; 1946120256Sgshapiro --maxatom; 194738032Speter 194838032Speter /* extract host and user portions */ 194938032Speter if (*++tv != NULL && (**tv & 0377) == CANONHOST) 1950120256Sgshapiro { 195138032Speter hostp = ++tv; 1952120256Sgshapiro --maxatom; 1953120256Sgshapiro } 195438032Speter else 195538032Speter hostp = NULL; 1956120256Sgshapiro --maxatom; 195738032Speter while (*tv != NULL && (**tv & 0377) != CANONUSER) 1958120256Sgshapiro { 195938032Speter tv++; 1960120256Sgshapiro --maxatom; 1961120256Sgshapiro } 196238032Speter if (*tv == NULL) 196338032Speter { 196464562Sgshapiro syserr("554 5.3.5 buildaddr: no user"); 196538032Speter goto badaddr; 196638032Speter } 196738032Speter if (tv == hostp) 196838032Speter hostp = NULL; 196938032Speter else if (hostp != NULL) 197038032Speter cataddr(hostp, tv - 1, hbuf, sizeof hbuf, '\0'); 197138032Speter cataddr(++tv, NULL, ubuf, sizeof ubuf, ' '); 1972120256Sgshapiro --maxatom; 197338032Speter 197438032Speter /* save away the host name */ 197590792Sgshapiro if (sm_strcasecmp(mname, "error") == 0) 197638032Speter { 197764562Sgshapiro /* Set up triplet for use by -bv */ 197864562Sgshapiro a->q_mailer = &errormailer; 197990792Sgshapiro a->q_user = sm_rpool_strdup_x(e->e_rpool, ubuf); 198090792Sgshapiro /* XXX wrong place? */ 198164562Sgshapiro 198238032Speter if (hostp != NULL) 198338032Speter { 198438032Speter register struct errcodes *ep; 198538032Speter 198690792Sgshapiro a->q_host = sm_rpool_strdup_x(e->e_rpool, hbuf); 198738032Speter if (strchr(hbuf, '.') != NULL) 198838032Speter { 198990792Sgshapiro a->q_status = sm_rpool_strdup_x(e->e_rpool, 199090792Sgshapiro hbuf); 199138032Speter setstat(dsntoexitstat(hbuf)); 199238032Speter } 199338032Speter else if (isascii(hbuf[0]) && isdigit(hbuf[0])) 199438032Speter { 199538032Speter setstat(atoi(hbuf)); 199638032Speter } 199738032Speter else 199838032Speter { 199938032Speter for (ep = ErrorCodes; ep->ec_name != NULL; ep++) 200090792Sgshapiro if (sm_strcasecmp(ep->ec_name, hbuf) == 0) 200138032Speter break; 200238032Speter setstat(ep->ec_code); 200338032Speter } 200438032Speter } 200538032Speter else 200664562Sgshapiro { 200764562Sgshapiro a->q_host = NULL; 200838032Speter setstat(EX_UNAVAILABLE); 200964562Sgshapiro } 201038032Speter stripquotes(ubuf); 201164562Sgshapiro if (ISSMTPCODE(ubuf) && ubuf[3] == ' ') 201238032Speter { 201364562Sgshapiro char fmt[16]; 201464562Sgshapiro int off; 201538032Speter 201664562Sgshapiro if ((off = isenhsc(ubuf + 4, ' ')) > 0) 201738032Speter { 201864562Sgshapiro ubuf[off + 4] = '\0'; 201964562Sgshapiro off += 5; 202038032Speter } 202164562Sgshapiro else 202264562Sgshapiro { 202364562Sgshapiro off = 4; 202464562Sgshapiro ubuf[3] = '\0'; 202564562Sgshapiro } 202690792Sgshapiro (void) sm_strlcpyn(fmt, sizeof fmt, 2, ubuf, " %s"); 202764562Sgshapiro if (off > 4) 202864562Sgshapiro usrerr(fmt, ubuf + off); 202964562Sgshapiro else if (isenhsc(hbuf, '\0') > 0) 203064562Sgshapiro usrerrenh(hbuf, fmt, ubuf + off); 203164562Sgshapiro else 203264562Sgshapiro usrerr(fmt, ubuf + off); 203364562Sgshapiro /* XXX ubuf[off - 1] = ' '; */ 203494334Sgshapiro if (ubuf[0] == '4') 203594334Sgshapiro tempfail = true; 203638032Speter } 203738032Speter else 203838032Speter { 203964562Sgshapiro usrerr("553 5.3.0 %s", ubuf); 204038032Speter } 204138032Speter goto badaddr; 204238032Speter } 204338032Speter 204438032Speter for (mp = Mailer; (m = *mp++) != NULL; ) 204538032Speter { 204690792Sgshapiro if (sm_strcasecmp(m->m_name, mname) == 0) 204738032Speter break; 204838032Speter } 204938032Speter if (m == NULL) 205038032Speter { 205164562Sgshapiro syserr("554 5.3.5 buildaddr: unknown mailer %s", mname); 205238032Speter goto badaddr; 205338032Speter } 205438032Speter a->q_mailer = m; 205538032Speter 205638032Speter /* figure out what host (if any) */ 205738032Speter if (hostp == NULL) 205838032Speter { 205938032Speter if (!bitnset(M_LOCALMAILER, m->m_flags)) 206038032Speter { 206164562Sgshapiro syserr("554 5.3.5 buildaddr: no host"); 206238032Speter goto badaddr; 206338032Speter } 206438032Speter a->q_host = NULL; 206538032Speter } 206638032Speter else 206790792Sgshapiro a->q_host = sm_rpool_strdup_x(e->e_rpool, hbuf); 206838032Speter 206938032Speter /* figure out the user */ 207038032Speter p = ubuf; 207138032Speter if (bitnset(M_CHECKUDB, m->m_flags) && *p == '@') 207238032Speter { 207338032Speter p++; 207438032Speter tv++; 2075120256Sgshapiro --maxatom; 207638032Speter a->q_flags |= QNOTREMOTE; 207738032Speter } 207838032Speter 207938032Speter /* do special mapping for local mailer */ 208038032Speter if (*p == '"') 208138032Speter p++; 208238032Speter if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags)) 208338032Speter a->q_mailer = m = ProgMailer; 208438032Speter else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags)) 208538032Speter a->q_mailer = m = FileMailer; 208638032Speter else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags)) 208738032Speter { 208838032Speter /* may be :include: */ 208938032Speter stripquotes(ubuf); 209090792Sgshapiro if (sm_strncasecmp(ubuf, ":include:", 9) == 0) 209138032Speter { 209238032Speter /* if :include:, don't need further rewriting */ 209338032Speter a->q_mailer = m = InclMailer; 209490792Sgshapiro a->q_user = sm_rpool_strdup_x(e->e_rpool, &ubuf[9]); 209538032Speter return a; 209638032Speter } 209738032Speter } 209838032Speter 209938032Speter /* rewrite according recipient mailer rewriting rules */ 210090792Sgshapiro macdefine(&e->e_macro, A_PERM, 'h', a->q_host); 210164562Sgshapiro 210290792Sgshapiro if (ConfigLevel >= 10 || 210364562Sgshapiro !bitset(RF_SENDERADDR|RF_HEADERADDR, flags)) 210438032Speter { 210538032Speter /* sender addresses done later */ 2106120256Sgshapiro (void) rewrite(tv, 2, 0, e, maxatom); 210738032Speter if (m->m_re_rwset > 0) 2108120256Sgshapiro (void) rewrite(tv, m->m_re_rwset, 0, e, maxatom); 210938032Speter } 2110120256Sgshapiro (void) rewrite(tv, 4, 0, e, maxatom); 211138032Speter 211238032Speter /* save the result for the command line/RCPT argument */ 211338032Speter cataddr(tv, NULL, ubuf, sizeof ubuf, '\0'); 211490792Sgshapiro a->q_user = sm_rpool_strdup_x(e->e_rpool, ubuf); 211538032Speter 211638032Speter /* 211738032Speter ** Do mapping to lower case as requested by mailer 211838032Speter */ 211938032Speter 212038032Speter if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags)) 212138032Speter makelower(a->q_host); 212238032Speter if (!bitnset(M_USR_UPPER, m->m_flags)) 212338032Speter makelower(a->q_user); 212438032Speter 212538032Speter if (tTd(24, 6)) 212638032Speter { 212790792Sgshapiro sm_dprintf("buildaddr => "); 2128132943Sgshapiro printaddr(sm_debug_file(), a, false); 212938032Speter } 213038032Speter return a; 213138032Speter} 2132110560Sgshapiro 213390792Sgshapiro/* 213438032Speter** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 213538032Speter** 213638032Speter** Parameters: 213738032Speter** pvp -- parameter vector to rebuild. 213838032Speter** evp -- last parameter to include. Can be NULL to 213938032Speter** use entire pvp. 214038032Speter** buf -- buffer to build the string into. 214138032Speter** sz -- size of buf. 214290792Sgshapiro** spacesub -- the space separator character; if '\0', 214338032Speter** use SpaceSub. 214438032Speter** 214538032Speter** Returns: 214638032Speter** none. 214738032Speter** 214838032Speter** Side Effects: 214938032Speter** Destroys buf. 215038032Speter*/ 215138032Speter 215238032Spetervoid 215338032Spetercataddr(pvp, evp, buf, sz, spacesub) 215438032Speter char **pvp; 215538032Speter char **evp; 215638032Speter char *buf; 215738032Speter register int sz; 215838032Speter int spacesub; 215938032Speter{ 216090792Sgshapiro bool oatomtok = false; 216190792Sgshapiro bool natomtok = false; 216238032Speter register int i; 216338032Speter register char *p; 216438032Speter 216564562Sgshapiro if (sz <= 0) 216664562Sgshapiro return; 216764562Sgshapiro 216838032Speter if (spacesub == '\0') 216938032Speter spacesub = SpaceSub; 217038032Speter 217138032Speter if (pvp == NULL) 217238032Speter { 217364562Sgshapiro *buf = '\0'; 217438032Speter return; 217538032Speter } 217638032Speter p = buf; 217738032Speter sz -= 2; 217890792Sgshapiro while (*pvp != NULL && sz > 0) 217938032Speter { 218038032Speter natomtok = (TokTypeTab[**pvp & 0xff] == ATM); 218138032Speter if (oatomtok && natomtok) 218264562Sgshapiro { 218338032Speter *p++ = spacesub; 218490792Sgshapiro if (--sz <= 0) 218590792Sgshapiro break; 218664562Sgshapiro } 2187132943Sgshapiro i = sm_strlcpy(p, *pvp, sz); 2188132943Sgshapiro sz -= i; 2189132943Sgshapiro if (sz <= 0) 219090792Sgshapiro break; 219138032Speter oatomtok = natomtok; 219238032Speter p += i; 219338032Speter if (pvp++ == evp) 219438032Speter break; 219538032Speter } 2196132943Sgshapiro 2197147078Sgshapiro#if 0 2198147078Sgshapiro /* 2199147078Sgshapiro ** Silently truncate long strings: even though this doesn't 2200147078Sgshapiro ** seem like a good idea it is necessary because header checks 2201147078Sgshapiro ** send the whole header value to rscheck() and hence rewrite(). 2202147078Sgshapiro ** The latter however sometimes uses a "short" buffer (e.g., 2203147078Sgshapiro ** cbuf[MAXNAME + 1]) to call cataddr() which then triggers this 2204147078Sgshapiro ** error function. One possible fix to the problem is to pass 2205147078Sgshapiro ** flags to rscheck() and rewrite() to distinguish the various 2206147078Sgshapiro ** calls and only trigger the error if necessary. For now just 2207147078Sgshapiro ** undo the change from 8.13.0. 2208147078Sgshapiro */ 2209147078Sgshapiro 2210132943Sgshapiro if (sz <= 0) 2211141858Sgshapiro usrerr("cataddr: string too long"); 2212147078Sgshapiro#endif 221338032Speter *p = '\0'; 221438032Speter} 221590792Sgshapiro/* 221638032Speter** SAMEADDR -- Determine if two addresses are the same 221738032Speter** 221838032Speter** This is not just a straight comparison -- if the mailer doesn't 221938032Speter** care about the host we just ignore it, etc. 222038032Speter** 222138032Speter** Parameters: 222238032Speter** a, b -- pointers to the internal forms to compare. 222338032Speter** 222438032Speter** Returns: 222590792Sgshapiro** true -- they represent the same mailbox. 222690792Sgshapiro** false -- they don't. 222738032Speter** 222838032Speter** Side Effects: 222938032Speter** none. 223038032Speter*/ 223138032Speter 223238032Speterbool 223338032Spetersameaddr(a, b) 223438032Speter register ADDRESS *a; 223538032Speter register ADDRESS *b; 223638032Speter{ 223738032Speter register ADDRESS *ca, *cb; 223838032Speter 223938032Speter /* if they don't have the same mailer, forget it */ 224038032Speter if (a->q_mailer != b->q_mailer) 224190792Sgshapiro return false; 224238032Speter 224338032Speter /* if the user isn't the same, we can drop out */ 224438032Speter if (strcmp(a->q_user, b->q_user) != 0) 224590792Sgshapiro return false; 224638032Speter 224738032Speter /* if we have good uids for both but they differ, these are different */ 224838032Speter if (a->q_mailer == ProgMailer) 224938032Speter { 225038032Speter ca = getctladdr(a); 225138032Speter cb = getctladdr(b); 225238032Speter if (ca != NULL && cb != NULL && 225338032Speter bitset(QGOODUID, ca->q_flags & cb->q_flags) && 225438032Speter ca->q_uid != cb->q_uid) 225590792Sgshapiro return false; 225638032Speter } 225738032Speter 225838032Speter /* otherwise compare hosts (but be careful for NULL ptrs) */ 225938032Speter if (a->q_host == b->q_host) 226038032Speter { 226138032Speter /* probably both null pointers */ 226290792Sgshapiro return true; 226338032Speter } 226438032Speter if (a->q_host == NULL || b->q_host == NULL) 226538032Speter { 226638032Speter /* only one is a null pointer */ 226790792Sgshapiro return false; 226838032Speter } 226938032Speter if (strcmp(a->q_host, b->q_host) != 0) 227090792Sgshapiro return false; 227138032Speter 227290792Sgshapiro return true; 227338032Speter} 227490792Sgshapiro/* 227538032Speter** PRINTADDR -- print address (for debugging) 227638032Speter** 227738032Speter** Parameters: 227838032Speter** a -- the address to print 227938032Speter** follow -- follow the q_next chain. 228038032Speter** 228138032Speter** Returns: 228238032Speter** none. 228338032Speter** 228438032Speter** Side Effects: 228538032Speter** none. 228638032Speter*/ 228738032Speter 228838032Speterstruct qflags 228938032Speter{ 229090792Sgshapiro char *qf_name; 229190792Sgshapiro unsigned long qf_bit; 229238032Speter}; 229338032Speter 229464562Sgshapirostatic struct qflags AddressFlags[] = 229538032Speter{ 229638032Speter { "QGOODUID", QGOODUID }, 229738032Speter { "QPRIMARY", QPRIMARY }, 229838032Speter { "QNOTREMOTE", QNOTREMOTE }, 229938032Speter { "QSELFREF", QSELFREF }, 230038032Speter { "QBOGUSSHELL", QBOGUSSHELL }, 230138032Speter { "QUNSAFEADDR", QUNSAFEADDR }, 230238032Speter { "QPINGONSUCCESS", QPINGONSUCCESS }, 230338032Speter { "QPINGONFAILURE", QPINGONFAILURE }, 230438032Speter { "QPINGONDELAY", QPINGONDELAY }, 230538032Speter { "QHASNOTIFY", QHASNOTIFY }, 230638032Speter { "QRELAYED", QRELAYED }, 230738032Speter { "QEXPANDED", QEXPANDED }, 230838032Speter { "QDELIVERED", QDELIVERED }, 230938032Speter { "QDELAYED", QDELAYED }, 231038032Speter { "QTHISPASS", QTHISPASS }, 231138032Speter { "QRCPTOK", QRCPTOK }, 231271345Sgshapiro { NULL, 0 } 231338032Speter}; 231438032Speter 231538032Spetervoid 2316132943Sgshapiroprintaddr(fp, a, follow) 2317132943Sgshapiro SM_FILE_T *fp; 231838032Speter register ADDRESS *a; 231938032Speter bool follow; 232038032Speter{ 232138032Speter register MAILER *m; 232238032Speter MAILER pseudomailer; 232338032Speter register struct qflags *qfp; 232438032Speter bool firstone; 232538032Speter 232638032Speter if (a == NULL) 232738032Speter { 2328132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "[NULL]\n"); 232938032Speter return; 233038032Speter } 233138032Speter 233238032Speter while (a != NULL) 233338032Speter { 2334132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%p=", a); 2335132943Sgshapiro (void) sm_io_flush(fp, SM_TIME_DEFAULT); 233638032Speter 233738032Speter /* find the mailer -- carefully */ 233838032Speter m = a->q_mailer; 233938032Speter if (m == NULL) 234038032Speter { 234138032Speter m = &pseudomailer; 234238032Speter m->m_mno = -1; 234338032Speter m->m_name = "NULL"; 234438032Speter } 234538032Speter 2346132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 234790792Sgshapiro "%s:\n\tmailer %d (%s), host `%s'\n", 234890792Sgshapiro a->q_paddr == NULL ? "<null>" : a->q_paddr, 234990792Sgshapiro m->m_mno, m->m_name, 235090792Sgshapiro a->q_host == NULL ? "<null>" : a->q_host); 2351132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 235290792Sgshapiro "\tuser `%s', ruser `%s'\n", 235390792Sgshapiro a->q_user, 235490792Sgshapiro a->q_ruser == NULL ? "<null>" : a->q_ruser); 2355132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\tstate="); 235664562Sgshapiro switch (a->q_state) 235764562Sgshapiro { 235864562Sgshapiro case QS_OK: 2359132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "OK"); 236064562Sgshapiro break; 236164562Sgshapiro 236264562Sgshapiro case QS_DONTSEND: 2363132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 236490792Sgshapiro "DONTSEND"); 236564562Sgshapiro break; 236664562Sgshapiro 236764562Sgshapiro case QS_BADADDR: 2368132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 236990792Sgshapiro "BADADDR"); 237064562Sgshapiro break; 237164562Sgshapiro 237264562Sgshapiro case QS_QUEUEUP: 2373132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 237490792Sgshapiro "QUEUEUP"); 237564562Sgshapiro break; 237664562Sgshapiro 237790792Sgshapiro case QS_RETRY: 2378132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "RETRY"); 237990792Sgshapiro break; 238090792Sgshapiro 238164562Sgshapiro case QS_SENT: 2382132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "SENT"); 238364562Sgshapiro break; 238464562Sgshapiro 238564562Sgshapiro case QS_VERIFIED: 2386132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 238790792Sgshapiro "VERIFIED"); 238864562Sgshapiro break; 238964562Sgshapiro 239064562Sgshapiro case QS_EXPANDED: 2391132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 239290792Sgshapiro "EXPANDED"); 239364562Sgshapiro break; 239464562Sgshapiro 239564562Sgshapiro case QS_SENDER: 2396132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 239790792Sgshapiro "SENDER"); 239864562Sgshapiro break; 239964562Sgshapiro 240064562Sgshapiro case QS_CLONED: 2401132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 240290792Sgshapiro "CLONED"); 240364562Sgshapiro break; 240464562Sgshapiro 240564562Sgshapiro case QS_DISCARDED: 2406132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 240790792Sgshapiro "DISCARDED"); 240864562Sgshapiro break; 240964562Sgshapiro 241064562Sgshapiro case QS_REPLACED: 2411132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 241290792Sgshapiro "REPLACED"); 241364562Sgshapiro break; 241464562Sgshapiro 241564562Sgshapiro case QS_REMOVED: 2416132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 241790792Sgshapiro "REMOVED"); 241864562Sgshapiro break; 241964562Sgshapiro 242064562Sgshapiro case QS_DUPLICATE: 2421132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 242290792Sgshapiro "DUPLICATE"); 242364562Sgshapiro break; 242464562Sgshapiro 242564562Sgshapiro case QS_INCLUDED: 2426132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 242790792Sgshapiro "INCLUDED"); 242864562Sgshapiro break; 242964562Sgshapiro 243064562Sgshapiro default: 2431132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 243290792Sgshapiro "%d", a->q_state); 243364562Sgshapiro break; 243464562Sgshapiro } 2435132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 243690792Sgshapiro ", next=%p, alias %p, uid %d, gid %d\n", 243790792Sgshapiro a->q_next, a->q_alias, 243890792Sgshapiro (int) a->q_uid, (int) a->q_gid); 2439132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\tflags=%lx<", 244090792Sgshapiro a->q_flags); 244190792Sgshapiro firstone = true; 244238032Speter for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++) 244338032Speter { 244438032Speter if (!bitset(qfp->qf_bit, a->q_flags)) 244538032Speter continue; 244638032Speter if (!firstone) 2447132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 244890792Sgshapiro ","); 244990792Sgshapiro firstone = false; 2450132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s", 245190792Sgshapiro qfp->qf_name); 245238032Speter } 2453132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, ">\n"); 2454132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 245590792Sgshapiro "\towner=%s, home=\"%s\", fullname=\"%s\"\n", 245690792Sgshapiro a->q_owner == NULL ? "(none)" : a->q_owner, 245790792Sgshapiro a->q_home == NULL ? "(none)" : a->q_home, 245890792Sgshapiro a->q_fullname == NULL ? "(none)" : a->q_fullname); 2459132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 246090792Sgshapiro "\torcpt=\"%s\", statmta=%s, status=%s\n", 246190792Sgshapiro a->q_orcpt == NULL ? "(none)" : a->q_orcpt, 246290792Sgshapiro a->q_statmta == NULL ? "(none)" : a->q_statmta, 246390792Sgshapiro a->q_status == NULL ? "(none)" : a->q_status); 2464132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 246590792Sgshapiro "\tfinalrcpt=\"%s\"\n", 246690792Sgshapiro a->q_finalrcpt == NULL ? "(none)" : a->q_finalrcpt); 2467132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 246890792Sgshapiro "\trstatus=\"%s\"\n", 246990792Sgshapiro a->q_rstatus == NULL ? "(none)" : a->q_rstatus); 2470132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 247190792Sgshapiro "\tstatdate=%s\n", 247290792Sgshapiro a->q_statdate == 0 ? "(none)" : ctime(&a->q_statdate)); 247338032Speter 247438032Speter if (!follow) 247538032Speter return; 247638032Speter a = a->q_next; 247738032Speter } 247838032Speter} 247990792Sgshapiro/* 248090792Sgshapiro** EMPTYADDR -- return true if this address is empty (``<>'') 248138032Speter** 248238032Speter** Parameters: 248338032Speter** a -- pointer to the address 248438032Speter** 248538032Speter** Returns: 248690792Sgshapiro** true -- if this address is "empty" (i.e., no one should 248738032Speter** ever generate replies to it. 248890792Sgshapiro** false -- if it is a "regular" (read: replyable) address. 248938032Speter*/ 249038032Speter 249138032Speterbool 249238032Speteremptyaddr(a) 249338032Speter register ADDRESS *a; 249438032Speter{ 249538032Speter return a->q_paddr == NULL || strcmp(a->q_paddr, "<>") == 0 || 249638032Speter a->q_user == NULL || strcmp(a->q_user, "<>") == 0; 249738032Speter} 249890792Sgshapiro/* 249938032Speter** REMOTENAME -- return the name relative to the current mailer 250038032Speter** 250138032Speter** Parameters: 250238032Speter** name -- the name to translate. 2503120256Sgshapiro** m -- the mailer that we want to do rewriting relative to. 250438032Speter** flags -- fine tune operations. 250538032Speter** pstat -- pointer to status word. 250638032Speter** e -- the current envelope. 250738032Speter** 250838032Speter** Returns: 250938032Speter** the text string representing this address relative to 251038032Speter** the receiving mailer. 251138032Speter** 251238032Speter** Side Effects: 251338032Speter** none. 251438032Speter** 251538032Speter** Warnings: 251638032Speter** The text string returned is tucked away locally; 251738032Speter** copy it if you intend to save it. 251838032Speter*/ 251938032Speter 252038032Speterchar * 252138032Speterremotename(name, m, flags, pstat, e) 252238032Speter char *name; 252338032Speter struct mailer *m; 252438032Speter int flags; 252538032Speter int *pstat; 252638032Speter register ENVELOPE *e; 252738032Speter{ 252838032Speter register char **pvp; 252990792Sgshapiro char *SM_NONVOLATILE fancy; 253090792Sgshapiro char *oldg; 253138032Speter int rwset; 253238032Speter static char buf[MAXNAME + 1]; 253338032Speter char lbuf[MAXNAME + 1]; 253438032Speter char pvpbuf[PSBUFSIZE]; 253564562Sgshapiro char addrtype[4]; 253638032Speter 253738032Speter if (tTd(12, 1)) 253890792Sgshapiro sm_dprintf("remotename(%s)\n", name); 253938032Speter 254038032Speter /* don't do anything if we are tagging it as special */ 254138032Speter if (bitset(RF_SENDERADDR, flags)) 254264562Sgshapiro { 254338032Speter rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset 254438032Speter : m->m_se_rwset; 254564562Sgshapiro addrtype[2] = 's'; 254664562Sgshapiro } 254738032Speter else 254864562Sgshapiro { 254938032Speter rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset 255038032Speter : m->m_re_rwset; 255164562Sgshapiro addrtype[2] = 'r'; 255264562Sgshapiro } 255338032Speter if (rwset < 0) 255464562Sgshapiro return name; 255564562Sgshapiro addrtype[1] = ' '; 255664562Sgshapiro addrtype[3] = '\0'; 255764562Sgshapiro addrtype[0] = bitset(RF_HEADERADDR, flags) ? 'h' : 'e'; 255890792Sgshapiro macdefine(&e->e_macro, A_TEMP, macid("{addr_type}"), addrtype); 255938032Speter 256038032Speter /* 256138032Speter ** Do a heuristic crack of this name to extract any comment info. 256238032Speter ** This will leave the name as a comment and a $g macro. 256338032Speter */ 256438032Speter 256538032Speter if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) 256638032Speter fancy = "\201g"; 256738032Speter else 2568111823Sgshapiro fancy = crackaddr(name, e); 256938032Speter 257038032Speter /* 257138032Speter ** Turn the name into canonical form. 257238032Speter ** Normally this will be RFC 822 style, i.e., "user@domain". 257338032Speter ** If this only resolves to "user", and the "C" flag is 257438032Speter ** specified in the sending mailer, then the sender's 257538032Speter ** domain will be appended. 257638032Speter */ 257738032Speter 2578132943Sgshapiro pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL, false); 257938032Speter if (pvp == NULL) 258064562Sgshapiro return name; 258190792Sgshapiro if (REWRITE(pvp, 3, e) == EX_TEMPFAIL) 258238032Speter *pstat = EX_TEMPFAIL; 258338032Speter if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) 258438032Speter { 258538032Speter /* append from domain to this address */ 258638032Speter register char **pxp = pvp; 258764562Sgshapiro int l = MAXATOM; /* size of buffer for pvp */ 258838032Speter 258938032Speter /* see if there is an "@domain" in the current name */ 259038032Speter while (*pxp != NULL && strcmp(*pxp, "@") != 0) 259164562Sgshapiro { 259238032Speter pxp++; 259364562Sgshapiro --l; 259464562Sgshapiro } 259538032Speter if (*pxp == NULL) 259638032Speter { 259738032Speter /* no.... append the "@domain" from the sender */ 259838032Speter register char **qxq = e->e_fromdomain; 259938032Speter 260038032Speter while ((*pxp++ = *qxq++) != NULL) 260164562Sgshapiro { 260264562Sgshapiro if (--l <= 0) 260364562Sgshapiro { 260464562Sgshapiro *--pxp = NULL; 260564562Sgshapiro usrerr("553 5.1.0 remotename: too many tokens"); 260664562Sgshapiro *pstat = EX_UNAVAILABLE; 260764562Sgshapiro break; 260864562Sgshapiro } 260964562Sgshapiro } 261090792Sgshapiro if (REWRITE(pvp, 3, e) == EX_TEMPFAIL) 261138032Speter *pstat = EX_TEMPFAIL; 261238032Speter } 261338032Speter } 261438032Speter 261538032Speter /* 261638032Speter ** Do more specific rewriting. 261738032Speter ** Rewrite using ruleset 1 or 2 depending on whether this is 261838032Speter ** a sender address or not. 261938032Speter ** Then run it through any receiving-mailer-specific rulesets. 262038032Speter */ 262138032Speter 262238032Speter if (bitset(RF_SENDERADDR, flags)) 262338032Speter { 262490792Sgshapiro if (REWRITE(pvp, 1, e) == EX_TEMPFAIL) 262538032Speter *pstat = EX_TEMPFAIL; 262638032Speter } 262738032Speter else 262838032Speter { 262990792Sgshapiro if (REWRITE(pvp, 2, e) == EX_TEMPFAIL) 263038032Speter *pstat = EX_TEMPFAIL; 263138032Speter } 263238032Speter if (rwset > 0) 263338032Speter { 263490792Sgshapiro if (REWRITE(pvp, rwset, e) == EX_TEMPFAIL) 263538032Speter *pstat = EX_TEMPFAIL; 263638032Speter } 263738032Speter 263838032Speter /* 263938032Speter ** Do any final sanitation the address may require. 264038032Speter ** This will normally be used to turn internal forms 264138032Speter ** (e.g., user@host.LOCAL) into external form. This 264238032Speter ** may be used as a default to the above rules. 264338032Speter */ 264438032Speter 264590792Sgshapiro if (REWRITE(pvp, 4, e) == EX_TEMPFAIL) 264638032Speter *pstat = EX_TEMPFAIL; 264738032Speter 264838032Speter /* 264938032Speter ** Now restore the comment information we had at the beginning. 265038032Speter */ 265138032Speter 265238032Speter cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0'); 265390792Sgshapiro oldg = macget(&e->e_macro, 'g'); 265490792Sgshapiro macset(&e->e_macro, 'g', lbuf); 265538032Speter 265690792Sgshapiro SM_TRY 265790792Sgshapiro /* need to make sure route-addrs have <angle brackets> */ 265890792Sgshapiro if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@') 265990792Sgshapiro expand("<\201g>", buf, sizeof buf, e); 266090792Sgshapiro else 266190792Sgshapiro expand(fancy, buf, sizeof buf, e); 266290792Sgshapiro SM_FINALLY 266390792Sgshapiro macset(&e->e_macro, 'g', oldg); 266490792Sgshapiro SM_END_TRY 266538032Speter 266638032Speter if (tTd(12, 1)) 266790792Sgshapiro sm_dprintf("remotename => `%s'\n", buf); 266864562Sgshapiro return buf; 266938032Speter} 267090792Sgshapiro/* 267138032Speter** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 267238032Speter** 267338032Speter** Parameters: 267438032Speter** a -- the address to map (but just the user name part). 267538032Speter** sendq -- the sendq in which to install any replacement 267638032Speter** addresses. 267738032Speter** aliaslevel -- the alias nesting depth. 267838032Speter** e -- the envelope. 267938032Speter** 268038032Speter** Returns: 268138032Speter** none. 268238032Speter*/ 268338032Speter 268438032Speter#define Q_COPYFLAGS (QPRIMARY|QBOGUSSHELL|QUNSAFEADDR|\ 268538032Speter Q_PINGFLAGS|QHASNOTIFY|\ 268690792Sgshapiro QRELAYED|QEXPANDED|QDELIVERED|QDELAYED|\ 268790792Sgshapiro QBYTRACE|QBYNDELAY|QBYNRELAY) 268838032Speter 268938032Spetervoid 269038032Spetermaplocaluser(a, sendq, aliaslevel, e) 269138032Speter register ADDRESS *a; 269238032Speter ADDRESS **sendq; 269338032Speter int aliaslevel; 269438032Speter ENVELOPE *e; 269538032Speter{ 269638032Speter register char **pvp; 269790792Sgshapiro register ADDRESS *SM_NONVOLATILE a1 = NULL; 269838032Speter char pvpbuf[PSBUFSIZE]; 269938032Speter 270038032Speter if (tTd(29, 1)) 270138032Speter { 270290792Sgshapiro sm_dprintf("maplocaluser: "); 2703132943Sgshapiro printaddr(sm_debug_file(), a, false); 270438032Speter } 2705132943Sgshapiro pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL, false); 270638032Speter if (pvp == NULL) 270738032Speter { 270838032Speter if (tTd(29, 9)) 270990792Sgshapiro sm_dprintf("maplocaluser: cannot prescan %s\n", 271064562Sgshapiro a->q_user); 271138032Speter return; 271238032Speter } 271338032Speter 271490792Sgshapiro macdefine(&e->e_macro, A_PERM, 'h', a->q_host); 271590792Sgshapiro macdefine(&e->e_macro, A_PERM, 'u', a->q_user); 271690792Sgshapiro macdefine(&e->e_macro, A_PERM, 'z', a->q_home); 271764562Sgshapiro 271890792Sgshapiro macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e r"); 271990792Sgshapiro if (REWRITE(pvp, 5, e) == EX_TEMPFAIL) 272038032Speter { 272138032Speter if (tTd(29, 9)) 272290792Sgshapiro sm_dprintf("maplocaluser: rewrite tempfail\n"); 272364562Sgshapiro a->q_state = QS_QUEUEUP; 272438032Speter a->q_status = "4.4.3"; 272538032Speter return; 272638032Speter } 272738032Speter if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 272838032Speter { 272938032Speter if (tTd(29, 9)) 273090792Sgshapiro sm_dprintf("maplocaluser: doesn't resolve\n"); 273138032Speter return; 273238032Speter } 273338032Speter 273490792Sgshapiro SM_TRY 273590792Sgshapiro a1 = buildaddr(pvp, NULL, 0, e); 273690792Sgshapiro SM_EXCEPT(exc, "E:mta.quickabort") 273790792Sgshapiro 273890792Sgshapiro /* 273990792Sgshapiro ** mark address as bad, S5 returned an error 274090792Sgshapiro ** and we gave that back to the SMTP client. 274190792Sgshapiro */ 274290792Sgshapiro 274390792Sgshapiro a->q_state = QS_DONTSEND; 274490792Sgshapiro sm_exc_raisenew_x(&EtypeQuickAbort, 2); 274590792Sgshapiro SM_END_TRY 274690792Sgshapiro 274738032Speter /* if non-null, mailer destination specified -- has it changed? */ 274838032Speter if (a1 == NULL || sameaddr(a, a1)) 274938032Speter { 275038032Speter if (tTd(29, 9)) 275190792Sgshapiro sm_dprintf("maplocaluser: address unchanged\n"); 275238032Speter return; 275338032Speter } 275438032Speter 275538032Speter /* make new address take on flags and print attributes of old */ 275638032Speter a1->q_flags &= ~Q_COPYFLAGS; 275738032Speter a1->q_flags |= a->q_flags & Q_COPYFLAGS; 275890792Sgshapiro a1->q_paddr = sm_rpool_strdup_x(e->e_rpool, a->q_paddr); 275990792Sgshapiro a1->q_finalrcpt = a->q_finalrcpt; 276064562Sgshapiro a1->q_orcpt = a->q_orcpt; 276138032Speter 276238032Speter /* mark old address as dead; insert new address */ 276364562Sgshapiro a->q_state = QS_REPLACED; 276438032Speter if (tTd(29, 5)) 276538032Speter { 276690792Sgshapiro sm_dprintf("maplocaluser: QS_REPLACED "); 2767132943Sgshapiro printaddr(sm_debug_file(), a, false); 276838032Speter } 276938032Speter a1->q_alias = a; 277090792Sgshapiro allocaddr(a1, RF_COPYALL, sm_rpool_strdup_x(e->e_rpool, a->q_paddr), e); 277138032Speter (void) recipient(a1, sendq, aliaslevel, e); 277238032Speter} 277390792Sgshapiro/* 277438032Speter** DEQUOTE_INIT -- initialize dequote map 277538032Speter** 277638032Speter** Parameters: 277738032Speter** map -- the internal map structure. 277838032Speter** args -- arguments. 277938032Speter** 278038032Speter** Returns: 278190792Sgshapiro** true. 278238032Speter*/ 278338032Speter 278438032Speterbool 278538032Speterdequote_init(map, args) 278638032Speter MAP *map; 278738032Speter char *args; 278838032Speter{ 278938032Speter register char *p = args; 279038032Speter 279164562Sgshapiro /* there is no check whether there is really an argument */ 279238032Speter map->map_mflags |= MF_KEEPQUOTES; 279338032Speter for (;;) 279438032Speter { 279538032Speter while (isascii(*p) && isspace(*p)) 279638032Speter p++; 279738032Speter if (*p != '-') 279838032Speter break; 279938032Speter switch (*++p) 280038032Speter { 280138032Speter case 'a': 280238032Speter map->map_app = ++p; 280338032Speter break; 280438032Speter 280564562Sgshapiro case 'D': 280664562Sgshapiro map->map_mflags |= MF_DEFER; 280764562Sgshapiro break; 280864562Sgshapiro 280964562Sgshapiro case 'S': 281038032Speter case 's': 281164562Sgshapiro map->map_spacesub = *++p; 281238032Speter break; 281338032Speter } 281438032Speter while (*p != '\0' && !(isascii(*p) && isspace(*p))) 281538032Speter p++; 281638032Speter if (*p != '\0') 281738032Speter *p = '\0'; 281838032Speter } 281938032Speter if (map->map_app != NULL) 282038032Speter map->map_app = newstr(map->map_app); 282138032Speter 282290792Sgshapiro return true; 282338032Speter} 282490792Sgshapiro/* 282538032Speter** DEQUOTE_MAP -- unquote an address 282638032Speter** 282738032Speter** Parameters: 282838032Speter** map -- the internal map structure (ignored). 282938032Speter** name -- the name to dequote. 283038032Speter** av -- arguments (ignored). 283138032Speter** statp -- pointer to status out-parameter. 283238032Speter** 283338032Speter** Returns: 283438032Speter** NULL -- if there were no quotes, or if the resulting 283538032Speter** unquoted buffer would not be acceptable to prescan. 283638032Speter** else -- The dequoted buffer. 283738032Speter*/ 283838032Speter 283938032Speter/* ARGSUSED2 */ 284038032Speterchar * 284138032Speterdequote_map(map, name, av, statp) 284238032Speter MAP *map; 284338032Speter char *name; 284438032Speter char **av; 284538032Speter int *statp; 284638032Speter{ 284738032Speter register char *p; 284838032Speter register char *q; 284938032Speter register char c; 285038032Speter int anglecnt = 0; 285138032Speter int cmntcnt = 0; 285238032Speter int quotecnt = 0; 285338032Speter int spacecnt = 0; 285490792Sgshapiro bool quotemode = false; 285590792Sgshapiro bool bslashmode = false; 285664562Sgshapiro char spacesub = map->map_spacesub; 285738032Speter 285838032Speter for (p = q = name; (c = *p++) != '\0'; ) 285938032Speter { 286038032Speter if (bslashmode) 286138032Speter { 286290792Sgshapiro bslashmode = false; 286338032Speter *q++ = c; 286438032Speter continue; 286538032Speter } 286638032Speter 286738032Speter if (c == ' ' && spacesub != '\0') 286838032Speter c = spacesub; 286938032Speter 287038032Speter switch (c) 287138032Speter { 287238032Speter case '\\': 287390792Sgshapiro bslashmode = true; 287438032Speter break; 287538032Speter 287638032Speter case '(': 287738032Speter cmntcnt++; 287838032Speter break; 287938032Speter 288038032Speter case ')': 288138032Speter if (cmntcnt-- <= 0) 288238032Speter return NULL; 288338032Speter break; 288438032Speter 288538032Speter case ' ': 288664562Sgshapiro case '\t': 288738032Speter spacecnt++; 288838032Speter break; 288938032Speter } 289038032Speter 289138032Speter if (cmntcnt > 0) 289238032Speter { 289338032Speter *q++ = c; 289438032Speter continue; 289538032Speter } 289638032Speter 289738032Speter switch (c) 289838032Speter { 289938032Speter case '"': 290038032Speter quotemode = !quotemode; 290138032Speter quotecnt++; 290238032Speter continue; 290338032Speter 290438032Speter case '<': 290538032Speter anglecnt++; 290638032Speter break; 290738032Speter 290838032Speter case '>': 290938032Speter if (anglecnt-- <= 0) 291038032Speter return NULL; 291138032Speter break; 291238032Speter } 291338032Speter *q++ = c; 291438032Speter } 291538032Speter 291638032Speter if (anglecnt != 0 || cmntcnt != 0 || bslashmode || 291738032Speter quotemode || quotecnt <= 0 || spacecnt != 0) 291838032Speter return NULL; 291938032Speter *q++ = '\0'; 292038032Speter return map_rewrite(map, name, strlen(name), NULL); 292138032Speter} 292290792Sgshapiro/* 292338032Speter** RSCHECK -- check string(s) for validity using rewriting sets 292438032Speter** 292538032Speter** Parameters: 292638032Speter** rwset -- the rewriting set to use. 292738032Speter** p1 -- the first string to check. 292838032Speter** p2 -- the second string to check -- may be null. 292938032Speter** e -- the current envelope. 2930102528Sgshapiro** flags -- control some behavior, see RSF_ in sendmail.h 293190792Sgshapiro** logl -- logging level. 293271345Sgshapiro** host -- NULL or relay host. 293390792Sgshapiro** logid -- id for sm_syslog. 293438032Speter** 293538032Speter** Returns: 293638032Speter** EX_OK -- if the rwset doesn't resolve to $#error 293738032Speter** else -- the failure status (message printed) 293838032Speter*/ 293938032Speter 294038032Speterint 2941102528Sgshapirorscheck(rwset, p1, p2, e, flags, logl, host, logid) 294238032Speter char *rwset; 294338032Speter char *p1; 294438032Speter char *p2; 294538032Speter ENVELOPE *e; 2946102528Sgshapiro int flags; 294764562Sgshapiro int logl; 294871345Sgshapiro char *host; 294990792Sgshapiro char *logid; 295038032Speter{ 295190792Sgshapiro char *volatile buf; 295238032Speter int bufsize; 295338032Speter int saveexitstat; 295490792Sgshapiro int volatile rstat = EX_OK; 295538032Speter char **pvp; 295638032Speter int rsno; 295790792Sgshapiro bool volatile discard = false; 295838032Speter auto ADDRESS a1; 295938032Speter bool saveQuickAbort = QuickAbort; 296038032Speter bool saveSuprErrs = SuprErrs; 296190792Sgshapiro bool quarantine = false; 296290792Sgshapiro char ubuf[BUFSIZ * 2]; 296338032Speter char buf0[MAXLINE]; 296438032Speter char pvpbuf[PSBUFSIZE]; 296538032Speter extern char MsgBuf[]; 296638032Speter 296738032Speter if (tTd(48, 2)) 296890792Sgshapiro sm_dprintf("rscheck(%s, %s, %s)\n", rwset, p1, 296938032Speter p2 == NULL ? "(NULL)" : p2); 297038032Speter 297138032Speter rsno = strtorwset(rwset, NULL, ST_FIND); 297238032Speter if (rsno < 0) 297338032Speter return EX_OK; 297438032Speter 297538032Speter if (p2 != NULL) 297638032Speter { 297738032Speter bufsize = strlen(p1) + strlen(p2) + 2; 297838032Speter if (bufsize > sizeof buf0) 297990792Sgshapiro buf = sm_malloc_x(bufsize); 298038032Speter else 298138032Speter { 298238032Speter buf = buf0; 298338032Speter bufsize = sizeof buf0; 298438032Speter } 298590792Sgshapiro (void) sm_snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2); 298638032Speter } 298738032Speter else 298838032Speter { 298938032Speter bufsize = strlen(p1) + 1; 299038032Speter if (bufsize > sizeof buf0) 299190792Sgshapiro buf = sm_malloc_x(bufsize); 299238032Speter else 299338032Speter { 299438032Speter buf = buf0; 299538032Speter bufsize = sizeof buf0; 299638032Speter } 299790792Sgshapiro (void) sm_strlcpy(buf, p1, bufsize); 299838032Speter } 299990792Sgshapiro SM_TRY 300038032Speter { 300190792Sgshapiro SuprErrs = true; 300290792Sgshapiro QuickAbort = false; 300390792Sgshapiro pvp = prescan(buf, '\0', pvpbuf, sizeof pvpbuf, NULL, 3004132943Sgshapiro bitset(RSF_RMCOMM, flags) ? NULL : TokTypeNoC, 3005132943Sgshapiro bitset(RSF_RMCOMM, flags) ? false : true); 300690792Sgshapiro SuprErrs = saveSuprErrs; 300790792Sgshapiro if (pvp == NULL) 300890792Sgshapiro { 300990792Sgshapiro if (tTd(48, 2)) 301090792Sgshapiro sm_dprintf("rscheck: cannot prescan input\n"); 301190792Sgshapiro /* 301290792Sgshapiro syserr("rscheck: cannot prescan input: \"%s\"", 301390792Sgshapiro shortenstring(buf, MAXSHORTSTR)); 301490792Sgshapiro rstat = EX_DATAERR; 301590792Sgshapiro */ 301690792Sgshapiro goto finis; 301790792Sgshapiro } 3018102528Sgshapiro if (bitset(RSF_UNSTRUCTURED, flags)) 3019102528Sgshapiro SuprErrs = true; 302090792Sgshapiro (void) REWRITE(pvp, rsno, e); 3021102528Sgshapiro if (bitset(RSF_UNSTRUCTURED, flags)) 3022102528Sgshapiro SuprErrs = saveSuprErrs; 302390792Sgshapiro if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET || 302490792Sgshapiro pvp[1] == NULL || (strcmp(pvp[1], "error") != 0 && 302590792Sgshapiro strcmp(pvp[1], "discard") != 0)) 302690792Sgshapiro { 302790792Sgshapiro goto finis; 302890792Sgshapiro } 302966494Sgshapiro 303090792Sgshapiro if (strcmp(pvp[1], "discard") == 0) 303190792Sgshapiro { 303290792Sgshapiro if (tTd(48, 2)) 303390792Sgshapiro sm_dprintf("rscheck: discard mailer selected\n"); 303490792Sgshapiro e->e_flags |= EF_DISCARD; 303590792Sgshapiro discard = true; 303690792Sgshapiro } 303790792Sgshapiro else if (strcmp(pvp[1], "error") == 0 && 303890792Sgshapiro pvp[2] != NULL && (pvp[2][0] & 0377) == CANONHOST && 303990792Sgshapiro pvp[3] != NULL && strcmp(pvp[3], "quarantine") == 0) 304090792Sgshapiro { 304190792Sgshapiro if (pvp[4] == NULL || 304290792Sgshapiro (pvp[4][0] & 0377) != CANONUSER || 304390792Sgshapiro pvp[5] == NULL) 304490792Sgshapiro e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, 304590792Sgshapiro rwset); 304690792Sgshapiro else 304790792Sgshapiro { 304890792Sgshapiro cataddr(&(pvp[5]), NULL, ubuf, 304990792Sgshapiro sizeof ubuf, ' '); 305090792Sgshapiro e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, 305190792Sgshapiro ubuf); 305290792Sgshapiro } 305390792Sgshapiro macdefine(&e->e_macro, A_PERM, 305490792Sgshapiro macid("{quarantine}"), e->e_quarmsg); 305590792Sgshapiro quarantine = true; 305690792Sgshapiro } 305790792Sgshapiro else 305890792Sgshapiro { 305990792Sgshapiro int savelogusrerrs = LogUsrErrs; 306090792Sgshapiro static bool logged = false; 306190792Sgshapiro 306290792Sgshapiro /* got an error -- process it */ 306390792Sgshapiro saveexitstat = ExitStat; 306490792Sgshapiro LogUsrErrs = false; 306590792Sgshapiro (void) buildaddr(pvp, &a1, 0, e); 306690792Sgshapiro LogUsrErrs = savelogusrerrs; 306790792Sgshapiro rstat = ExitStat; 306890792Sgshapiro ExitStat = saveexitstat; 306990792Sgshapiro if (!logged) 307090792Sgshapiro { 3071102528Sgshapiro if (bitset(RSF_COUNT, flags)) 307290792Sgshapiro markstats(e, &a1, STATS_REJECT); 307390792Sgshapiro logged = true; 307490792Sgshapiro } 307590792Sgshapiro } 307690792Sgshapiro 307790792Sgshapiro if (LogLevel > logl) 307890792Sgshapiro { 307990792Sgshapiro char *relay; 308090792Sgshapiro char *p; 308190792Sgshapiro char lbuf[MAXLINE]; 308290792Sgshapiro 308390792Sgshapiro p = lbuf; 308490792Sgshapiro if (p2 != NULL) 308590792Sgshapiro { 308690792Sgshapiro (void) sm_snprintf(p, SPACELEFT(lbuf, p), 308790792Sgshapiro ", arg2=%s", 308890792Sgshapiro p2); 308990792Sgshapiro p += strlen(p); 309090792Sgshapiro } 309190792Sgshapiro 309290792Sgshapiro if (host != NULL) 309390792Sgshapiro relay = host; 309490792Sgshapiro else 309590792Sgshapiro relay = macvalue('_', e); 309690792Sgshapiro if (relay != NULL) 309790792Sgshapiro { 309890792Sgshapiro (void) sm_snprintf(p, SPACELEFT(lbuf, p), 309990792Sgshapiro ", relay=%s", relay); 310090792Sgshapiro p += strlen(p); 310190792Sgshapiro } 310290792Sgshapiro *p = '\0'; 310390792Sgshapiro if (discard) 310490792Sgshapiro sm_syslog(LOG_NOTICE, logid, 310590792Sgshapiro "ruleset=%s, arg1=%s%s, discard", 310690792Sgshapiro rwset, p1, lbuf); 310790792Sgshapiro else if (quarantine) 310890792Sgshapiro sm_syslog(LOG_NOTICE, logid, 310990792Sgshapiro "ruleset=%s, arg1=%s%s, quarantine=%s", 311090792Sgshapiro rwset, p1, lbuf, ubuf); 311190792Sgshapiro else 311290792Sgshapiro sm_syslog(LOG_NOTICE, logid, 311390792Sgshapiro "ruleset=%s, arg1=%s%s, reject=%s", 311490792Sgshapiro rwset, p1, lbuf, MsgBuf); 311590792Sgshapiro } 311690792Sgshapiro 311790792Sgshapiro finis: ; 311873188Sgshapiro } 311990792Sgshapiro SM_FINALLY 312038032Speter { 312190792Sgshapiro /* clean up */ 312290792Sgshapiro if (buf != buf0) 312390792Sgshapiro sm_free(buf); 312490792Sgshapiro QuickAbort = saveQuickAbort; 312538032Speter } 312690792Sgshapiro SM_END_TRY 312738032Speter 312890792Sgshapiro setstat(rstat); 312990792Sgshapiro 313090792Sgshapiro /* rulesets don't set errno */ 313190792Sgshapiro errno = 0; 313290792Sgshapiro if (rstat != EX_OK && QuickAbort) 313390792Sgshapiro sm_exc_raisenew_x(&EtypeQuickAbort, 2); 313490792Sgshapiro return rstat; 313590792Sgshapiro} 313690792Sgshapiro/* 313790792Sgshapiro** RSCAP -- call rewriting set to return capabilities 313890792Sgshapiro** 313990792Sgshapiro** Parameters: 314090792Sgshapiro** rwset -- the rewriting set to use. 314190792Sgshapiro** p1 -- the first string to check. 314290792Sgshapiro** p2 -- the second string to check -- may be null. 314390792Sgshapiro** e -- the current envelope. 314490792Sgshapiro** pvp -- pointer to token vector. 314590792Sgshapiro** pvpbuf -- buffer space. 3146120256Sgshapiro** size -- size of buffer space. 314790792Sgshapiro** 314890792Sgshapiro** Returns: 314990792Sgshapiro** EX_UNAVAILABLE -- ruleset doesn't exist. 315090792Sgshapiro** EX_DATAERR -- prescan() failed. 315190792Sgshapiro** EX_OK -- rewrite() was successful. 315290792Sgshapiro** else -- return status from rewrite(). 315390792Sgshapiro*/ 315490792Sgshapiro 315590792Sgshapiroint 315690792Sgshapirorscap(rwset, p1, p2, e, pvp, pvpbuf, size) 315790792Sgshapiro char *rwset; 315890792Sgshapiro char *p1; 315990792Sgshapiro char *p2; 316090792Sgshapiro ENVELOPE *e; 316190792Sgshapiro char ***pvp; 316290792Sgshapiro char *pvpbuf; 316390792Sgshapiro int size; 316490792Sgshapiro{ 316590792Sgshapiro char *volatile buf; 316690792Sgshapiro int bufsize; 316790792Sgshapiro int volatile rstat = EX_OK; 316890792Sgshapiro int rsno; 316990792Sgshapiro bool saveQuickAbort = QuickAbort; 317090792Sgshapiro bool saveSuprErrs = SuprErrs; 317190792Sgshapiro char buf0[MAXLINE]; 317290792Sgshapiro extern char MsgBuf[]; 317390792Sgshapiro 317490792Sgshapiro if (tTd(48, 2)) 317590792Sgshapiro sm_dprintf("rscap(%s, %s, %s)\n", rwset, p1, 317690792Sgshapiro p2 == NULL ? "(NULL)" : p2); 317790792Sgshapiro 317890792Sgshapiro if (pvp != NULL) 317990792Sgshapiro *pvp = NULL; 318090792Sgshapiro rsno = strtorwset(rwset, NULL, ST_FIND); 318190792Sgshapiro if (rsno < 0) 318290792Sgshapiro return EX_UNAVAILABLE; 318390792Sgshapiro 318490792Sgshapiro if (p2 != NULL) 318538032Speter { 318690792Sgshapiro bufsize = strlen(p1) + strlen(p2) + 2; 318790792Sgshapiro if (bufsize > sizeof buf0) 318890792Sgshapiro buf = sm_malloc_x(bufsize); 318990792Sgshapiro else 319090792Sgshapiro { 319190792Sgshapiro buf = buf0; 319290792Sgshapiro bufsize = sizeof buf0; 319390792Sgshapiro } 319490792Sgshapiro (void) sm_snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2); 319538032Speter } 319664562Sgshapiro else 319738032Speter { 319890792Sgshapiro bufsize = strlen(p1) + 1; 319990792Sgshapiro if (bufsize > sizeof buf0) 320090792Sgshapiro buf = sm_malloc_x(bufsize); 320190792Sgshapiro else 320238032Speter { 320390792Sgshapiro buf = buf0; 320490792Sgshapiro bufsize = sizeof buf0; 320538032Speter } 320690792Sgshapiro (void) sm_strlcpy(buf, p1, bufsize); 320738032Speter } 320890792Sgshapiro SM_TRY 320938032Speter { 321090792Sgshapiro SuprErrs = true; 321190792Sgshapiro QuickAbort = false; 3212132943Sgshapiro *pvp = prescan(buf, '\0', pvpbuf, size, NULL, NULL, false); 321390792Sgshapiro if (*pvp != NULL) 3214120256Sgshapiro rstat = rewrite(*pvp, rsno, 0, e, size); 321571345Sgshapiro else 321638032Speter { 321790792Sgshapiro if (tTd(48, 2)) 321890792Sgshapiro sm_dprintf("rscap: cannot prescan input\n"); 321990792Sgshapiro rstat = EX_DATAERR; 322038032Speter } 322138032Speter } 322290792Sgshapiro SM_FINALLY 322390792Sgshapiro { 322490792Sgshapiro /* clean up */ 322590792Sgshapiro if (buf != buf0) 322690792Sgshapiro sm_free(buf); 322790792Sgshapiro SuprErrs = saveSuprErrs; 322890792Sgshapiro QuickAbort = saveQuickAbort; 322938032Speter 323090792Sgshapiro /* prevent information leak, this may contain rewrite error */ 323190792Sgshapiro MsgBuf[0] = '\0'; 323290792Sgshapiro } 323390792Sgshapiro SM_END_TRY 323438032Speter return rstat; 323538032Speter} 3236