parseaddr.c revision 285229
138032Speter/* 2261194Sgshapiro * Copyright (c) 1998-2006 Proofpoint, 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 16266527SgshapiroSM_RCSID("@(#)$Id: parseaddr.c,v 8.407 2013-11-22 20:51:56 ca Exp $") 1790792Sgshapiro 18168515Sgshapiro#include <sm/sendmail.h> 19168515Sgshapiro#include "map.h" 20168515Sgshapiro 2190792Sgshapirostatic void allocaddr __P((ADDRESS *, int, char *, ENVELOPE *)); 2264562Sgshapirostatic int callsubr __P((char**, int, ENVELOPE *)); 2364562Sgshapirostatic char *map_lookup __P((STAB *, char *, char **, int *, ENVELOPE *)); 2464562Sgshapirostatic ADDRESS *buildaddr __P((char **, ADDRESS *, int, ENVELOPE *)); 2594334Sgshapirostatic bool hasctrlchar __P((register char *, bool, bool)); 2664562Sgshapiro 2794334Sgshapiro/* replacement for illegal characters in addresses */ 2894334Sgshapiro#define BAD_CHAR_REPLACEMENT '?' 2994334Sgshapiro 3038032Speter/* 3138032Speter** PARSEADDR -- Parse an address 3238032Speter** 3338032Speter** Parses an address and breaks it up into three parts: a 3438032Speter** net to transmit the message on, the host to transmit it 3538032Speter** to, and a user on that host. These are loaded into an 3638032Speter** ADDRESS header with the values squirreled away if necessary. 3738032Speter** The "user" part may not be a real user; the process may 3838032Speter** just reoccur on that machine. For example, on a machine 3938032Speter** with an arpanet connection, the address 4038032Speter** csvax.bill@berkeley 4138032Speter** will break up to a "user" of 'csvax.bill' and a host 4238032Speter** of 'berkeley' -- to be transmitted over the arpanet. 4338032Speter** 4438032Speter** Parameters: 4538032Speter** addr -- the address to parse. 4638032Speter** a -- a pointer to the address descriptor buffer. 4790792Sgshapiro** If NULL, an address will be created. 4838032Speter** flags -- describe detail for parsing. See RF_ definitions 4938032Speter** in sendmail.h. 5038032Speter** delim -- the character to terminate the address, passed 5138032Speter** to prescan. 5238032Speter** delimptr -- if non-NULL, set to the location of the 5338032Speter** delim character that was found. 5438032Speter** e -- the envelope that will contain this address. 5590792Sgshapiro** isrcpt -- true if the address denotes a recipient; false 5690792Sgshapiro** indicates a sender. 5738032Speter** 5838032Speter** Returns: 5938032Speter** A pointer to the address descriptor header (`a' if 6038032Speter** `a' is non-NULL). 6138032Speter** NULL on error. 6238032Speter** 6338032Speter** Side Effects: 6490792Sgshapiro** e->e_to = addr 6538032Speter*/ 6638032Speter 6738032Speter/* following delimiters are inherent to the internal algorithms */ 6864562Sgshapiro#define DELIMCHARS "()<>,;\r\n" /* default word delimiters */ 6938032Speter 7038032SpeterADDRESS * 7190792Sgshapiroparseaddr(addr, a, flags, delim, delimptr, e, isrcpt) 7238032Speter char *addr; 7338032Speter register ADDRESS *a; 7438032Speter int flags; 7538032Speter int delim; 7638032Speter char **delimptr; 7738032Speter register ENVELOPE *e; 7890792Sgshapiro bool isrcpt; 7938032Speter{ 8090792Sgshapiro char **pvp; 8138032Speter auto char *delimptrbuf; 8264562Sgshapiro bool qup; 8338032Speter char pvpbuf[PSBUFSIZE]; 8438032Speter 8538032Speter /* 8638032Speter ** Initialize and prescan address. 8738032Speter */ 8838032Speter 8938032Speter e->e_to = addr; 9038032Speter if (tTd(20, 1)) 9190792Sgshapiro sm_dprintf("\n--parseaddr(%s)\n", addr); 9238032Speter 9338032Speter if (delimptr == NULL) 9438032Speter delimptr = &delimptrbuf; 9538032Speter 96168515Sgshapiro pvp = prescan(addr, delim, pvpbuf, sizeof(pvpbuf), delimptr, 97168515Sgshapiro ExtTokenTab, false); 9838032Speter if (pvp == NULL) 9938032Speter { 10038032Speter if (tTd(20, 1)) 10190792Sgshapiro sm_dprintf("parseaddr-->NULL\n"); 10264562Sgshapiro return NULL; 10338032Speter } 10438032Speter 10590792Sgshapiro if (invalidaddr(addr, delim == '\0' ? NULL : *delimptr, isrcpt)) 10638032Speter { 10738032Speter if (tTd(20, 1)) 10890792Sgshapiro sm_dprintf("parseaddr-->bad address\n"); 10938032Speter return NULL; 11038032Speter } 11138032Speter 11238032Speter /* 11338032Speter ** Save addr if we are going to have to. 11438032Speter ** 11538032Speter ** We have to do this early because there is a chance that 11638032Speter ** the map lookups in the rewriting rules could clobber 11738032Speter ** static memory somewhere. 11838032Speter */ 11938032Speter 12038032Speter if (bitset(RF_COPYPADDR, flags) && addr != NULL) 12138032Speter { 12238032Speter char savec = **delimptr; 12338032Speter 12438032Speter if (savec != '\0') 12538032Speter **delimptr = '\0'; 12690792Sgshapiro e->e_to = addr = sm_rpool_strdup_x(e->e_rpool, addr); 12738032Speter if (savec != '\0') 12838032Speter **delimptr = savec; 12938032Speter } 13038032Speter 13138032Speter /* 13238032Speter ** Apply rewriting rules. 13338032Speter ** Ruleset 0 does basic parsing. It must resolve. 13438032Speter */ 13538032Speter 13690792Sgshapiro qup = false; 13790792Sgshapiro if (REWRITE(pvp, 3, e) == EX_TEMPFAIL) 13890792Sgshapiro qup = true; 13990792Sgshapiro if (REWRITE(pvp, 0, e) == EX_TEMPFAIL) 14090792Sgshapiro qup = true; 14138032Speter 14238032Speter /* 14338032Speter ** Build canonical address from pvp. 14438032Speter */ 14538032Speter 14638032Speter a = buildaddr(pvp, a, flags, e); 14738032Speter 14894334Sgshapiro if (hasctrlchar(a->q_user, isrcpt, true)) 14990792Sgshapiro { 15090792Sgshapiro if (tTd(20, 1)) 15190792Sgshapiro sm_dprintf("parseaddr-->bad q_user\n"); 15294334Sgshapiro 15394334Sgshapiro /* 15494334Sgshapiro ** Just mark the address as bad so DSNs work. 15594334Sgshapiro ** hasctrlchar() has to make sure that the address 15694334Sgshapiro ** has been sanitized, e.g., shortened. 15794334Sgshapiro */ 15894334Sgshapiro 15994334Sgshapiro a->q_state = QS_BADADDR; 16090792Sgshapiro } 16190792Sgshapiro 16238032Speter /* 16338032Speter ** Make local copies of the host & user and then 16438032Speter ** transport them out. 16538032Speter */ 16638032Speter 16790792Sgshapiro allocaddr(a, flags, addr, e); 16864562Sgshapiro if (QS_IS_BADADDR(a->q_state)) 16994334Sgshapiro { 17094334Sgshapiro /* weed out bad characters in the printable address too */ 17194334Sgshapiro (void) hasctrlchar(a->q_paddr, isrcpt, false); 17238032Speter return a; 17394334Sgshapiro } 17438032Speter 17538032Speter /* 17690792Sgshapiro ** Select a queue directory for recipient addresses. 17790792Sgshapiro ** This is done here and in split_across_queue_groups(), 17890792Sgshapiro ** but the latter applies to addresses after aliasing, 17990792Sgshapiro ** and only if splitting is done. 18090792Sgshapiro */ 18190792Sgshapiro 18290792Sgshapiro if ((a->q_qgrp == NOAQGRP || a->q_qgrp == ENVQGRP) && 183168515Sgshapiro !bitset(RF_SENDERADDR|RF_HEADERADDR|RF_RM_ADDR, flags) && 18490792Sgshapiro OpMode != MD_INITALIAS) 18590792Sgshapiro { 18690792Sgshapiro int r; 18790792Sgshapiro 18890792Sgshapiro /* call ruleset which should return a queue group name */ 18990792Sgshapiro r = rscap(RS_QUEUEGROUP, a->q_user, NULL, e, &pvp, pvpbuf, 19090792Sgshapiro sizeof(pvpbuf)); 19190792Sgshapiro if (r == EX_OK && 19290792Sgshapiro pvp != NULL && pvp[0] != NULL && 19390792Sgshapiro (pvp[0][0] & 0377) == CANONNET && 19490792Sgshapiro pvp[1] != NULL && pvp[1][0] != '\0') 19590792Sgshapiro { 19690792Sgshapiro r = name2qid(pvp[1]); 19790792Sgshapiro if (r == NOQGRP && LogLevel > 10) 19890792Sgshapiro sm_syslog(LOG_INFO, NOQID, 19990792Sgshapiro "can't find queue group name %s, selection ignored", 20090792Sgshapiro pvp[1]); 20190792Sgshapiro if (tTd(20, 4) && r != NOQGRP) 20290792Sgshapiro sm_syslog(LOG_INFO, NOQID, 20390792Sgshapiro "queue group name %s -> %d", 20490792Sgshapiro pvp[1], r); 20590792Sgshapiro a->q_qgrp = r == NOQGRP ? ENVQGRP : r; 20690792Sgshapiro } 20790792Sgshapiro } 20890792Sgshapiro 20990792Sgshapiro /* 21038032Speter ** If there was a parsing failure, mark it for queueing. 21138032Speter */ 21238032Speter 21364562Sgshapiro if (qup && OpMode != MD_INITALIAS) 21438032Speter { 21538032Speter char *msg = "Transient parse error -- message queued for future delivery"; 21638032Speter 21738032Speter if (e->e_sendmode == SM_DEFER) 21838032Speter msg = "Deferring message until queue run"; 21938032Speter if (tTd(20, 1)) 220173340Sgshapiro sm_dprintf("parseaddr: queueing message\n"); 22138032Speter message(msg); 22238032Speter if (e->e_message == NULL && e->e_sendmode != SM_DEFER) 22390792Sgshapiro e->e_message = sm_rpool_strdup_x(e->e_rpool, msg); 22464562Sgshapiro a->q_state = QS_QUEUEUP; 22538032Speter a->q_status = "4.4.3"; 22638032Speter } 22738032Speter 22838032Speter /* 22938032Speter ** Compute return value. 23038032Speter */ 23138032Speter 23238032Speter if (tTd(20, 1)) 23338032Speter { 23490792Sgshapiro sm_dprintf("parseaddr-->"); 235132943Sgshapiro printaddr(sm_debug_file(), a, false); 23638032Speter } 23738032Speter 23864562Sgshapiro return a; 23938032Speter} 24090792Sgshapiro/* 24190792Sgshapiro** INVALIDADDR -- check for address containing characters used for macros 24238032Speter** 24338032Speter** Parameters: 24438032Speter** addr -- the address to check. 245244833Sgshapiro** note: this is the complete address (including display part) 24690792Sgshapiro** delimptr -- if non-NULL: end of address to check, i.e., 24790792Sgshapiro** a pointer in the address string. 24890792Sgshapiro** isrcpt -- true iff the address is for a recipient. 24938032Speter** 25038032Speter** Returns: 25190792Sgshapiro** true -- if the address has characters that are reservered 25290792Sgshapiro** for macros or is too long. 25390792Sgshapiro** false -- otherwise. 25438032Speter*/ 25538032Speter 25638032Speterbool 25790792Sgshapiroinvalidaddr(addr, delimptr, isrcpt) 25838032Speter register char *addr; 25938032Speter char *delimptr; 26090792Sgshapiro bool isrcpt; 26138032Speter{ 26290792Sgshapiro bool result = false; 26338032Speter char savedelim = '\0'; 26494334Sgshapiro char *b = addr; 26590792Sgshapiro int len = 0; 26638032Speter 26738032Speter if (delimptr != NULL) 26838032Speter { 26990792Sgshapiro /* delimptr points to the end of the address to test */ 27038032Speter savedelim = *delimptr; 27190792Sgshapiro if (savedelim != '\0') /* if that isn't '\0' already: */ 27290792Sgshapiro *delimptr = '\0'; /* set it */ 27338032Speter } 27490792Sgshapiro for (; *addr != '\0'; addr++) 27538032Speter { 276168515Sgshapiro if (!EightBitAddrOK && (*addr & 0340) == 0200) 27790792Sgshapiro { 27890792Sgshapiro setstat(EX_USAGE); 27990792Sgshapiro result = true; 28094334Sgshapiro *addr = BAD_CHAR_REPLACEMENT; 28190792Sgshapiro } 28290792Sgshapiro if (++len > MAXNAME - 1) 28390792Sgshapiro { 28494334Sgshapiro char saved = *addr; 28594334Sgshapiro 28694334Sgshapiro *addr = '\0'; 28794334Sgshapiro usrerr("553 5.1.0 Address \"%s\" too long (%d bytes max)", 28894334Sgshapiro b, MAXNAME - 1); 28994334Sgshapiro *addr = saved; 29090792Sgshapiro result = true; 29190792Sgshapiro goto delim; 29290792Sgshapiro } 29338032Speter } 29490792Sgshapiro if (result) 29590792Sgshapiro { 29690792Sgshapiro if (isrcpt) 29794334Sgshapiro usrerr("501 5.1.3 8-bit character in mailbox address \"%s\"", 29894334Sgshapiro b); 29990792Sgshapiro else 30094334Sgshapiro usrerr("501 5.1.7 8-bit character in mailbox address \"%s\"", 30194334Sgshapiro b); 30290792Sgshapiro } 30390792Sgshapirodelim: 30490792Sgshapiro if (delimptr != NULL && savedelim != '\0') 30590792Sgshapiro *delimptr = savedelim; /* restore old character at delimptr */ 30690792Sgshapiro return result; 30790792Sgshapiro} 30890792Sgshapiro/* 30990792Sgshapiro** HASCTRLCHAR -- check for address containing meta-characters 31090792Sgshapiro** 31190792Sgshapiro** Checks that the address contains no meta-characters, and contains 31290792Sgshapiro** no "non-printable" characters unless they are quoted or escaped. 31390792Sgshapiro** Quoted or escaped characters are literals. 31490792Sgshapiro** 31590792Sgshapiro** Parameters: 31690792Sgshapiro** addr -- the address to check. 31790792Sgshapiro** isrcpt -- true if the address is for a recipient; false 31890792Sgshapiro** indicates a from. 31994334Sgshapiro** complain -- true if an error should issued if the address 32094334Sgshapiro** is invalid and should be "repaired". 32190792Sgshapiro** 32290792Sgshapiro** Returns: 323223067Sgshapiro** true -- if the address has any "weird" characters or 32490792Sgshapiro** non-printable characters or if a quote is unbalanced. 32590792Sgshapiro** false -- otherwise. 32690792Sgshapiro*/ 32790792Sgshapiro 32890792Sgshapirostatic bool 32994334Sgshapirohasctrlchar(addr, isrcpt, complain) 33090792Sgshapiro register char *addr; 33194334Sgshapiro bool isrcpt, complain; 33290792Sgshapiro{ 33394334Sgshapiro bool quoted = false; 33490792Sgshapiro int len = 0; 33594334Sgshapiro char *result = NULL; 33694334Sgshapiro char *b = addr; 33790792Sgshapiro 33890792Sgshapiro if (addr == NULL) 33990792Sgshapiro return false; 34038032Speter for (; *addr != '\0'; addr++) 34138032Speter { 34294334Sgshapiro if (++len > MAXNAME - 1) 34394334Sgshapiro { 34494334Sgshapiro if (complain) 34594334Sgshapiro { 34694334Sgshapiro (void) shorten_rfc822_string(b, MAXNAME - 1); 34794334Sgshapiro usrerr("553 5.1.0 Address \"%s\" too long (%d bytes max)", 34894334Sgshapiro b, MAXNAME - 1); 34994334Sgshapiro return true; 35094334Sgshapiro } 35194334Sgshapiro result = "too long"; 35294334Sgshapiro } 353168515Sgshapiro if (!EightBitAddrOK && !quoted && (*addr < 32 || *addr == 127)) 35490792Sgshapiro { 35594334Sgshapiro result = "non-printable character"; 35694334Sgshapiro *addr = BAD_CHAR_REPLACEMENT; 35794334Sgshapiro continue; 35890792Sgshapiro } 35990792Sgshapiro if (*addr == '"') 36090792Sgshapiro quoted = !quoted; 36190792Sgshapiro else if (*addr == '\\') 36290792Sgshapiro { 36390792Sgshapiro /* XXX Generic problem: no '\0' in strings. */ 36490792Sgshapiro if (*++addr == '\0') 36590792Sgshapiro { 36694334Sgshapiro result = "trailing \\ character"; 36794334Sgshapiro *--addr = BAD_CHAR_REPLACEMENT; 36890792Sgshapiro break; 36990792Sgshapiro } 37090792Sgshapiro } 371168515Sgshapiro if (!EightBitAddrOK && (*addr & 0340) == 0200) 37290792Sgshapiro { 37390792Sgshapiro setstat(EX_USAGE); 37494334Sgshapiro result = "8-bit character"; 37594334Sgshapiro *addr = BAD_CHAR_REPLACEMENT; 37694334Sgshapiro continue; 37790792Sgshapiro } 37838032Speter } 37990792Sgshapiro if (quoted) 38094334Sgshapiro result = "unbalanced quote"; /* unbalanced quote */ 38194334Sgshapiro if (result != NULL && complain) 38238032Speter { 38390792Sgshapiro if (isrcpt) 38494334Sgshapiro usrerr("501 5.1.3 Syntax error in mailbox address \"%s\" (%s)", 38594334Sgshapiro b, result); 38690792Sgshapiro else 38794334Sgshapiro usrerr("501 5.1.7 Syntax error in mailbox address \"%s\" (%s)", 38894334Sgshapiro b, result); 38938032Speter } 39094334Sgshapiro return result != NULL; 39138032Speter} 39290792Sgshapiro/* 39338032Speter** ALLOCADDR -- do local allocations of address on demand. 39438032Speter** 39538032Speter** Also lowercases the host name if requested. 39638032Speter** 39738032Speter** Parameters: 39838032Speter** a -- the address to reallocate. 39938032Speter** flags -- the copy flag (see RF_ definitions in sendmail.h 40038032Speter** for a description). 40138032Speter** paddr -- the printname of the address. 40290792Sgshapiro** e -- envelope 40338032Speter** 40438032Speter** Returns: 40538032Speter** none. 40638032Speter** 40738032Speter** Side Effects: 40838032Speter** Copies portions of a into local buffers as requested. 40938032Speter*/ 41038032Speter 41164562Sgshapirostatic void 41290792Sgshapiroallocaddr(a, flags, paddr, e) 41338032Speter register ADDRESS *a; 41438032Speter int flags; 41538032Speter char *paddr; 41690792Sgshapiro ENVELOPE *e; 41738032Speter{ 41838032Speter if (tTd(24, 4)) 41990792Sgshapiro sm_dprintf("allocaddr(flags=%x, paddr=%s)\n", flags, paddr); 42038032Speter 42138032Speter a->q_paddr = paddr; 42238032Speter 42338032Speter if (a->q_user == NULL) 42490792Sgshapiro a->q_user = ""; 42538032Speter if (a->q_host == NULL) 42690792Sgshapiro a->q_host = ""; 42738032Speter 42838032Speter if (bitset(RF_COPYPARSE, flags)) 42938032Speter { 43090792Sgshapiro a->q_host = sm_rpool_strdup_x(e->e_rpool, a->q_host); 43138032Speter if (a->q_user != a->q_paddr) 43290792Sgshapiro a->q_user = sm_rpool_strdup_x(e->e_rpool, a->q_user); 43338032Speter } 43438032Speter 43538032Speter if (a->q_paddr == NULL) 43690792Sgshapiro a->q_paddr = sm_rpool_strdup_x(e->e_rpool, a->q_user); 43790792Sgshapiro a->q_qgrp = NOAQGRP; 43838032Speter} 439168515Sgshapiro 44090792Sgshapiro/* 44138032Speter** PRESCAN -- Prescan name and make it canonical 44238032Speter** 44338032Speter** Scans a name and turns it into a set of tokens. This process 44464562Sgshapiro** deletes blanks and comments (in parentheses) (if the token type 44564562Sgshapiro** for left paren is SPC). 44638032Speter** 44738032Speter** This routine knows about quoted strings and angle brackets. 44838032Speter** 44938032Speter** There are certain subtleties to this routine. The one that 45038032Speter** comes to mind now is that backslashes on the ends of names 45138032Speter** are silently stripped off; this is intentional. The problem 45238032Speter** is that some versions of sndmsg (like at LBL) set the kill 45338032Speter** character to something other than @ when reading addresses; 45438032Speter** so people type "csvax.eric\@berkeley" -- which screws up the 45538032Speter** berknet mailer. 45638032Speter** 45738032Speter** Parameters: 45838032Speter** addr -- the name to chomp. 45938032Speter** delim -- the delimiter for the address, normally 46038032Speter** '\0' or ','; \0 is accepted in any case. 46138032Speter** If '\t' then we are reading the .cf file. 46238032Speter** pvpbuf -- place to put the saved text -- note that 46338032Speter** the pointers are static. 46438032Speter** pvpbsize -- size of pvpbuf. 46538032Speter** delimptr -- if non-NULL, set to the location of the 46638032Speter** terminating delimiter. 46738032Speter** toktab -- if set, a token table to use for parsing. 46838032Speter** If NULL, use the default table. 469132943Sgshapiro** ignore -- if true, ignore unbalanced addresses 47038032Speter** 47138032Speter** Returns: 47238032Speter** A pointer to a vector of tokens. 47338032Speter** NULL on error. 47438032Speter*/ 47538032Speter 47638032Speter/* states and character types */ 47764562Sgshapiro#define OPR 0 /* operator */ 47864562Sgshapiro#define ATM 1 /* atom */ 47964562Sgshapiro#define QST 2 /* in quoted string */ 48064562Sgshapiro#define SPC 3 /* chewing up spaces */ 48164562Sgshapiro#define ONE 4 /* pick up one character */ 48264562Sgshapiro#define ILL 5 /* illegal character */ 48338032Speter 48464562Sgshapiro#define NSTATES 6 /* number of states */ 48564562Sgshapiro#define TYPE 017 /* mask to select state type */ 48638032Speter 48738032Speter/* meta bits for table */ 48864562Sgshapiro#define M 020 /* meta character; don't pass through */ 48964562Sgshapiro#define B 040 /* cause a break */ 49064562Sgshapiro#define MB M|B /* meta-break */ 49138032Speter 49238032Speterstatic short StateTab[NSTATES][NSTATES] = 49338032Speter{ 49438032Speter /* oldst chtype> OPR ATM QST SPC ONE ILL */ 49538032Speter /*OPR*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|MB }, 49638032Speter /*ATM*/ { OPR|B, ATM, QST|B, SPC|MB, ONE|B, ILL|MB }, 49738032Speter /*QST*/ { QST, QST, OPR, QST, QST, QST }, 49838032Speter /*SPC*/ { OPR, ATM, QST, SPC|M, ONE, ILL|MB }, 49938032Speter /*ONE*/ { OPR, OPR, OPR, OPR, OPR, ILL|MB }, 500168515Sgshapiro /*ILL*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|M } 50138032Speter}; 50238032Speter 503168515Sgshapiro/* these all get modified with the OperatorChars */ 504168515Sgshapiro 505168515Sgshapiro/* token type table for external strings */ 506168515Sgshapirounsigned char ExtTokenTab[256] = 50738032Speter{ 50838032Speter /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 50938032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM, 51038032Speter /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 51138032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 51238032Speter /* sp ! " # $ % & ' ( ) * + , - . / */ 51364562Sgshapiro SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, SPC,SPC,ATM,ATM,ATM,ATM,ATM,ATM, 51438032Speter /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 51538032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 51638032Speter /* @ A B C D E F G H I J K L M N O */ 51738032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 51838032Speter /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 51938032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 52038032Speter /* ` a b c d e f g h i j k l m n o */ 52138032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 52238032Speter /* p q r s t u v w x y z { | } ~ del */ 52338032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 52438032Speter 52538032Speter /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 526168515Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 527168515Sgshapiro /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 528168515Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 529168515Sgshapiro /* sp ! " # $ % & ' ( ) * + , - . / */ 530168515Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 531168515Sgshapiro /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 532168515Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 533168515Sgshapiro /* @ A B C D E F G H I J K L M N O */ 534168515Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 535168515Sgshapiro /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 536168515Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 537168515Sgshapiro /* ` a b c d e f g h i j k l m n o */ 538168515Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 539168515Sgshapiro /* p q r s t u v w x y z { | } ~ del */ 540168515Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM 541168515Sgshapiro}; 542168515Sgshapiro 543168515Sgshapiro/* token type table for internal strings */ 544168515Sgshapirounsigned char IntTokenTab[256] = 545168515Sgshapiro{ 546168515Sgshapiro /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 547168515Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM, 548168515Sgshapiro /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 549168515Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 550168515Sgshapiro /* sp ! " # $ % & ' ( ) * + , - . / */ 551168515Sgshapiro SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, SPC,SPC,ATM,ATM,ATM,ATM,ATM,ATM, 552168515Sgshapiro /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 553168515Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 554168515Sgshapiro /* @ A B C D E F G H I J K L M N O */ 555168515Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 556168515Sgshapiro /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 557168515Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 558168515Sgshapiro /* ` a b c d e f g h i j k l m n o */ 559168515Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 560168515Sgshapiro /* p q r s t u v w x y z { | } ~ del */ 561168515Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 562168515Sgshapiro 563168515Sgshapiro /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 56438032Speter OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 56538032Speter /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 56638032Speter OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 56738032Speter /* sp ! " # $ % & ' ( ) * + , - . / */ 56838032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 56938032Speter /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 57038032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 57138032Speter /* @ A B C D E F G H I J K L M N O */ 57238032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 57338032Speter /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 57438032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 57538032Speter /* ` a b c d e f g h i j k l m n o */ 57638032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 57738032Speter /* p q r s t u v w x y z { | } ~ del */ 578168515Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ONE 57938032Speter}; 58038032Speter 58138032Speter/* token type table for MIME parsing */ 58290792Sgshapirounsigned char MimeTokenTab[256] = 58338032Speter{ 58438032Speter /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 58538032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,SPC,SPC,SPC,SPC,SPC,ILL,ILL, 58638032Speter /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 58738032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 58838032Speter /* sp ! " # $ % & ' ( ) * + , - . / */ 58964562Sgshapiro SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, SPC,SPC,ATM,ATM,OPR,ATM,ATM,OPR, 59038032Speter /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 59138032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,OPR,OPR,OPR,OPR,OPR,OPR, 59238032Speter /* @ A B C D E F G H I J K L M N O */ 59338032Speter OPR,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 59438032Speter /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 59538032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,OPR,OPR,OPR,ATM,ATM, 59638032Speter /* ` a b c d e f g h i j k l m n o */ 59738032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 59838032Speter /* p q r s t u v w x y z { | } ~ del */ 59938032Speter ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 60038032Speter 60138032Speter /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 60238032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 60338032Speter /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 60438032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 60538032Speter /* sp ! " # $ % & ' ( ) * + , - . / */ 60638032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 60738032Speter /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 60838032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 60938032Speter /* @ A B C D E F G H I J K L M N O */ 61038032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 61138032Speter /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 61238032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 61338032Speter /* ` a b c d e f g h i j k l m n o */ 61438032Speter ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 61538032Speter /* p q r s t u v w x y z { | } ~ del */ 616168515Sgshapiro ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ONE 61738032Speter}; 61838032Speter 61964562Sgshapiro/* token type table: don't strip comments */ 62090792Sgshapirounsigned char TokTypeNoC[256] = 62164562Sgshapiro{ 62264562Sgshapiro /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 62364562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM, 62464562Sgshapiro /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 62564562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 62664562Sgshapiro /* sp ! " # $ % & ' ( ) * + , - . / */ 62764562Sgshapiro SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, OPR,OPR,ATM,ATM,ATM,ATM,ATM,ATM, 62864562Sgshapiro /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 62964562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 63064562Sgshapiro /* @ A B C D E F G H I J K L M N O */ 63164562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 63264562Sgshapiro /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 63364562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 63464562Sgshapiro /* ` a b c d e f g h i j k l m n o */ 63564562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 63664562Sgshapiro /* p q r s t u v w x y z { | } ~ del */ 63764562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 63838032Speter 63964562Sgshapiro /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 64064562Sgshapiro OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 64164562Sgshapiro /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 64264562Sgshapiro OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 64364562Sgshapiro /* sp ! " # $ % & ' ( ) * + , - . / */ 64464562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 64564562Sgshapiro /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 64664562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 64764562Sgshapiro /* @ A B C D E F G H I J K L M N O */ 64864562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 64964562Sgshapiro /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 65064562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 65164562Sgshapiro /* ` a b c d e f g h i j k l m n o */ 65264562Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 65364562Sgshapiro /* p q r s t u v w x y z { | } ~ del */ 654168515Sgshapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ONE 65564562Sgshapiro}; 65638032Speter 65764562Sgshapiro 658112810Sgshapiro#define NOCHAR (-1) /* signal nothing in lookahead token */ 65964562Sgshapiro 66038032Speterchar ** 661132943Sgshapiroprescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab, ignore) 66238032Speter char *addr; 66338032Speter int delim; 66438032Speter char pvpbuf[]; 66538032Speter int pvpbsize; 66638032Speter char **delimptr; 66790792Sgshapiro unsigned char *toktab; 668132943Sgshapiro bool ignore; 66938032Speter{ 67038032Speter register char *p; 67138032Speter register char *q; 67238032Speter register int c; 67338032Speter char **avp; 67438032Speter bool bslashmode; 67538032Speter bool route_syntax; 67638032Speter int cmntcnt; 67738032Speter int anglecnt; 67838032Speter char *tok; 67938032Speter int state; 68038032Speter int newstate; 68138032Speter char *saveto = CurEnv->e_to; 68264562Sgshapiro static char *av[MAXATOM + 1]; 68390792Sgshapiro static bool firsttime = true; 68438032Speter 68538032Speter if (firsttime) 68638032Speter { 68738032Speter /* initialize the token type table */ 68838032Speter char obuf[50]; 68938032Speter 69090792Sgshapiro firsttime = false; 69138032Speter if (OperatorChars == NULL) 69238032Speter { 69338032Speter if (ConfigLevel < 7) 69438032Speter OperatorChars = macvalue('o', CurEnv); 69538032Speter if (OperatorChars == NULL) 69638032Speter OperatorChars = ".:@[]"; 69738032Speter } 698168515Sgshapiro expand(OperatorChars, obuf, sizeof(obuf) - sizeof(DELIMCHARS), 69964562Sgshapiro CurEnv); 700168515Sgshapiro (void) sm_strlcat(obuf, DELIMCHARS, sizeof(obuf)); 70138032Speter for (p = obuf; *p != '\0'; p++) 70238032Speter { 703168515Sgshapiro if (IntTokenTab[*p & 0xff] == ATM) 704168515Sgshapiro IntTokenTab[*p & 0xff] = OPR; 705168515Sgshapiro if (ExtTokenTab[*p & 0xff] == ATM) 706168515Sgshapiro ExtTokenTab[*p & 0xff] = OPR; 70764562Sgshapiro if (TokTypeNoC[*p & 0xff] == ATM) 70864562Sgshapiro TokTypeNoC[*p & 0xff] = OPR; 70938032Speter } 71038032Speter } 71138032Speter if (toktab == NULL) 712168515Sgshapiro toktab = ExtTokenTab; 71338032Speter 71438032Speter /* make sure error messages don't have garbage on them */ 71538032Speter errno = 0; 71638032Speter 71738032Speter q = pvpbuf; 71890792Sgshapiro bslashmode = false; 71990792Sgshapiro route_syntax = false; 72038032Speter cmntcnt = 0; 72138032Speter anglecnt = 0; 72238032Speter avp = av; 72338032Speter state = ATM; 72438032Speter c = NOCHAR; 72538032Speter p = addr; 72638032Speter CurEnv->e_to = p; 72738032Speter if (tTd(22, 11)) 72838032Speter { 72990792Sgshapiro sm_dprintf("prescan: "); 730132943Sgshapiro xputs(sm_debug_file(), p); 73190792Sgshapiro sm_dprintf("\n"); 73238032Speter } 73338032Speter 73438032Speter do 73538032Speter { 73638032Speter /* read a token */ 73738032Speter tok = q; 73838032Speter for (;;) 73938032Speter { 74038032Speter /* store away any old lookahead character */ 74138032Speter if (c != NOCHAR && !bslashmode) 74238032Speter { 74338032Speter /* see if there is room */ 74438032Speter if (q >= &pvpbuf[pvpbsize - 5]) 74538032Speter { 746112810Sgshapiro addrtoolong: 74764562Sgshapiro usrerr("553 5.1.1 Address too long"); 74890792Sgshapiro if (strlen(addr) > MAXNAME) 74938032Speter addr[MAXNAME] = '\0'; 75038032Speter returnnull: 75138032Speter if (delimptr != NULL) 752120169Snectar { 753120169Snectar if (p > addr) 754120256Sgshapiro --p; 75538032Speter *delimptr = p; 756120169Snectar } 75738032Speter CurEnv->e_to = saveto; 75864562Sgshapiro return NULL; 75938032Speter } 76038032Speter 76138032Speter /* squirrel it away */ 762112810Sgshapiro#if !ALLOW_255 763168515Sgshapiro if ((char) c == (char) -1 && !tTd(82, 101) && 764168515Sgshapiro !EightBitAddrOK) 765112810Sgshapiro c &= 0x7f; 766112810Sgshapiro#endif /* !ALLOW_255 */ 76738032Speter *q++ = c; 76838032Speter } 76938032Speter 77038032Speter /* read a new input character */ 771112810Sgshapiro c = (*p++) & 0x00ff; 77238032Speter if (c == '\0') 77338032Speter { 77438032Speter /* diagnose and patch up bad syntax */ 775132943Sgshapiro if (ignore) 776132943Sgshapiro break; 777132943Sgshapiro else if (state == QST) 77838032Speter { 77990792Sgshapiro usrerr("553 Unbalanced '\"'"); 78038032Speter c = '"'; 78138032Speter } 78238032Speter else if (cmntcnt > 0) 78338032Speter { 78490792Sgshapiro usrerr("553 Unbalanced '('"); 78538032Speter c = ')'; 78638032Speter } 78738032Speter else if (anglecnt > 0) 78838032Speter { 78938032Speter c = '>'; 79090792Sgshapiro usrerr("553 Unbalanced '<'"); 79138032Speter } 79238032Speter else 79338032Speter break; 79438032Speter 79538032Speter p--; 79638032Speter } 79738032Speter else if (c == delim && cmntcnt <= 0 && state != QST) 79838032Speter { 79938032Speter if (anglecnt <= 0) 80038032Speter break; 80138032Speter 80238032Speter /* special case for better error management */ 803132943Sgshapiro if (delim == ',' && !route_syntax && !ignore) 80438032Speter { 80590792Sgshapiro usrerr("553 Unbalanced '<'"); 80638032Speter c = '>'; 80738032Speter p--; 80838032Speter } 80938032Speter } 81038032Speter 81138032Speter if (tTd(22, 101)) 81290792Sgshapiro sm_dprintf("c=%c, s=%d; ", c, state); 81338032Speter 81438032Speter /* chew up special characters */ 81538032Speter *q = '\0'; 81638032Speter if (bslashmode) 81738032Speter { 81890792Sgshapiro bslashmode = false; 81938032Speter 82038032Speter /* kludge \! for naive users */ 82138032Speter if (cmntcnt > 0) 82238032Speter { 82338032Speter c = NOCHAR; 82438032Speter continue; 82538032Speter } 82638032Speter else if (c != '!' || state == QST) 82738032Speter { 828112810Sgshapiro /* see if there is room */ 829112810Sgshapiro if (q >= &pvpbuf[pvpbsize - 5]) 830112810Sgshapiro goto addrtoolong; 83138032Speter *q++ = '\\'; 83238032Speter continue; 83338032Speter } 83438032Speter } 83538032Speter 83638032Speter if (c == '\\') 83738032Speter { 83890792Sgshapiro bslashmode = true; 83938032Speter } 84038032Speter else if (state == QST) 84138032Speter { 84264562Sgshapiro /* EMPTY */ 84338032Speter /* do nothing, just avoid next clauses */ 84438032Speter } 84564562Sgshapiro else if (c == '(' && toktab['('] == SPC) 84638032Speter { 84738032Speter cmntcnt++; 84838032Speter c = NOCHAR; 84938032Speter } 85064562Sgshapiro else if (c == ')' && toktab['('] == SPC) 85138032Speter { 85238032Speter if (cmntcnt <= 0) 85338032Speter { 854132943Sgshapiro if (!ignore) 855132943Sgshapiro { 856132943Sgshapiro usrerr("553 Unbalanced ')'"); 857132943Sgshapiro c = NOCHAR; 858132943Sgshapiro } 85938032Speter } 86038032Speter else 86138032Speter cmntcnt--; 86238032Speter } 86338032Speter else if (cmntcnt > 0) 86464562Sgshapiro { 86538032Speter c = NOCHAR; 86664562Sgshapiro } 86738032Speter else if (c == '<') 86838032Speter { 86964562Sgshapiro char *ptr = p; 87038032Speter 87138032Speter anglecnt++; 87264562Sgshapiro while (isascii(*ptr) && isspace(*ptr)) 87364562Sgshapiro ptr++; 87464562Sgshapiro if (*ptr == '@') 87590792Sgshapiro route_syntax = true; 87638032Speter } 87738032Speter else if (c == '>') 87838032Speter { 87938032Speter if (anglecnt <= 0) 88038032Speter { 881132943Sgshapiro if (!ignore) 882132943Sgshapiro { 883132943Sgshapiro usrerr("553 Unbalanced '>'"); 884132943Sgshapiro c = NOCHAR; 885132943Sgshapiro } 88638032Speter } 88738032Speter else 88838032Speter anglecnt--; 88990792Sgshapiro route_syntax = false; 89038032Speter } 89138032Speter else if (delim == ' ' && isascii(c) && isspace(c)) 89238032Speter c = ' '; 89338032Speter 89438032Speter if (c == NOCHAR) 89538032Speter continue; 89638032Speter 89738032Speter /* see if this is end of input */ 89838032Speter if (c == delim && anglecnt <= 0 && state != QST) 89938032Speter break; 90038032Speter 90138032Speter newstate = StateTab[state][toktab[c & 0xff]]; 90238032Speter if (tTd(22, 101)) 90390792Sgshapiro sm_dprintf("ns=%02o\n", newstate); 90438032Speter state = newstate & TYPE; 90538032Speter if (state == ILL) 90638032Speter { 90738032Speter if (isascii(c) && isprint(c)) 90890792Sgshapiro usrerr("553 Illegal character %c", c); 90938032Speter else 91090792Sgshapiro usrerr("553 Illegal character 0x%02x", 91190792Sgshapiro c & 0x0ff); 91238032Speter } 91338032Speter if (bitset(M, newstate)) 91438032Speter c = NOCHAR; 91538032Speter if (bitset(B, newstate)) 91638032Speter break; 91738032Speter } 91838032Speter 91938032Speter /* new token */ 92038032Speter if (tok != q) 92138032Speter { 922112810Sgshapiro /* see if there is room */ 923112810Sgshapiro if (q >= &pvpbuf[pvpbsize - 5]) 924112810Sgshapiro goto addrtoolong; 92538032Speter *q++ = '\0'; 92638032Speter if (tTd(22, 36)) 92738032Speter { 92890792Sgshapiro sm_dprintf("tok="); 929132943Sgshapiro xputs(sm_debug_file(), tok); 93090792Sgshapiro sm_dprintf("\n"); 93138032Speter } 93238032Speter if (avp >= &av[MAXATOM]) 93338032Speter { 93464562Sgshapiro usrerr("553 5.1.0 prescan: too many tokens"); 93538032Speter goto returnnull; 93638032Speter } 93738032Speter if (q - tok > MAXNAME) 93838032Speter { 93964562Sgshapiro usrerr("553 5.1.0 prescan: token too long"); 94038032Speter goto returnnull; 94138032Speter } 94238032Speter *avp++ = tok; 94338032Speter } 94438032Speter } while (c != '\0' && (c != delim || anglecnt > 0)); 94538032Speter *avp = NULL; 94638032Speter if (delimptr != NULL) 947120256Sgshapiro { 948120256Sgshapiro if (p > addr) 949120256Sgshapiro p--; 95038032Speter *delimptr = p; 951120256Sgshapiro } 95238032Speter if (tTd(22, 12)) 95338032Speter { 95490792Sgshapiro sm_dprintf("prescan==>"); 955132943Sgshapiro printav(sm_debug_file(), av); 95638032Speter } 95738032Speter CurEnv->e_to = saveto; 95838032Speter if (av[0] == NULL) 95938032Speter { 96038032Speter if (tTd(22, 1)) 96190792Sgshapiro sm_dprintf("prescan: null leading token\n"); 96264562Sgshapiro return NULL; 96338032Speter } 96464562Sgshapiro return av; 96538032Speter} 96690792Sgshapiro/* 96738032Speter** REWRITE -- apply rewrite rules to token vector. 96838032Speter** 96938032Speter** This routine is an ordered production system. Each rewrite 97038032Speter** rule has a LHS (called the pattern) and a RHS (called the 97138032Speter** rewrite); 'rwr' points the the current rewrite rule. 97238032Speter** 97338032Speter** For each rewrite rule, 'avp' points the address vector we 97438032Speter** are trying to match against, and 'pvp' points to the pattern. 97538032Speter** If pvp points to a special match value (MATCHZANY, MATCHANY, 97638032Speter** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp 97738032Speter** matched is saved away in the match vector (pointed to by 'mvp'). 97838032Speter** 97938032Speter** When a match between avp & pvp does not match, we try to 98038032Speter** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS 98138032Speter** we must also back out the match in mvp. If we reach a 98238032Speter** MATCHANY or MATCHZANY we just extend the match and start 98338032Speter** over again. 98438032Speter** 98538032Speter** When we finally match, we rewrite the address vector 98638032Speter** and try over again. 98738032Speter** 98838032Speter** Parameters: 98938032Speter** pvp -- pointer to token vector. 99038032Speter** ruleset -- the ruleset to use for rewriting. 99138032Speter** reclevel -- recursion level (to catch loops). 99238032Speter** e -- the current envelope. 99390792Sgshapiro** maxatom -- maximum length of buffer (usually MAXATOM) 99438032Speter** 99538032Speter** Returns: 99638032Speter** A status code. If EX_TEMPFAIL, higher level code should 99738032Speter** attempt recovery. 99838032Speter** 99938032Speter** Side Effects: 100038032Speter** pvp is modified. 100138032Speter*/ 100238032Speter 100338032Speterstruct match 100438032Speter{ 100564562Sgshapiro char **match_first; /* first token matched */ 100664562Sgshapiro char **match_last; /* last token matched */ 100764562Sgshapiro char **match_pattern; /* pointer to pattern */ 100838032Speter}; 100938032Speter 101038032Speterint 101190792Sgshapirorewrite(pvp, ruleset, reclevel, e, maxatom) 101238032Speter char **pvp; 101338032Speter int ruleset; 101438032Speter int reclevel; 101538032Speter register ENVELOPE *e; 101690792Sgshapiro int maxatom; 101738032Speter{ 101838032Speter register char *ap; /* address pointer */ 101938032Speter register char *rp; /* rewrite pointer */ 102064562Sgshapiro register char *rulename; /* ruleset name */ 102164562Sgshapiro register char *prefix; 102238032Speter register char **avp; /* address vector pointer */ 102338032Speter register char **rvp; /* rewrite vector pointer */ 102438032Speter register struct match *mlp; /* cur ptr into mlist */ 102538032Speter register struct rewrite *rwr; /* pointer to current rewrite rule */ 102638032Speter int ruleno; /* current rule number */ 102738032Speter int rstat = EX_OK; /* return status */ 102838032Speter int loopcount; 102938032Speter struct match mlist[MAXMATCH]; /* stores match on LHS */ 103064562Sgshapiro char *npvp[MAXATOM + 1]; /* temporary space for rebuild */ 103138032Speter char buf[MAXLINE]; 103264562Sgshapiro char name[6]; 103338032Speter 1034120256Sgshapiro /* 1035120256Sgshapiro ** mlp will not exceed mlist[] because readcf enforces 1036120256Sgshapiro ** the upper limit of entries when reading rulesets. 1037120256Sgshapiro */ 1038120256Sgshapiro 103964562Sgshapiro if (ruleset < 0 || ruleset >= MAXRWSETS) 104038032Speter { 104164562Sgshapiro syserr("554 5.3.5 rewrite: illegal ruleset number %d", ruleset); 104264562Sgshapiro return EX_CONFIG; 104364562Sgshapiro } 104464562Sgshapiro rulename = RuleSetNames[ruleset]; 104564562Sgshapiro if (rulename == NULL) 104664562Sgshapiro { 1047168515Sgshapiro (void) sm_snprintf(name, sizeof(name), "%d", ruleset); 104864562Sgshapiro rulename = name; 104964562Sgshapiro } 105064562Sgshapiro if (OpMode == MD_TEST) 105164562Sgshapiro prefix = ""; 105264562Sgshapiro else 105364562Sgshapiro prefix = "rewrite: ruleset "; 105464562Sgshapiro if (OpMode == MD_TEST) 105564562Sgshapiro { 105690792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 105790792Sgshapiro "%s%-16.16s input:", prefix, rulename); 1058132943Sgshapiro printav(smioout, pvp); 105938032Speter } 106064562Sgshapiro else if (tTd(21, 1)) 106138032Speter { 106290792Sgshapiro sm_dprintf("%s%-16.16s input:", prefix, rulename); 1063132943Sgshapiro printav(sm_debug_file(), pvp); 106438032Speter } 106538032Speter if (reclevel++ > MaxRuleRecursion) 106638032Speter { 106764562Sgshapiro syserr("rewrite: excessive recursion (max %d), ruleset %s", 106864562Sgshapiro MaxRuleRecursion, rulename); 106938032Speter return EX_CONFIG; 107038032Speter } 107138032Speter if (pvp == NULL) 107238032Speter return EX_USAGE; 1073120256Sgshapiro if (maxatom <= 0) 1074120256Sgshapiro return EX_USAGE; 107538032Speter 107638032Speter /* 107738032Speter ** Run through the list of rewrite rules, applying 107838032Speter ** any that match. 107938032Speter */ 108038032Speter 108138032Speter ruleno = 1; 108238032Speter loopcount = 0; 108338032Speter for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 108438032Speter { 108564562Sgshapiro int status; 108638032Speter 108738032Speter /* if already canonical, quit now */ 108838032Speter if (pvp[0] != NULL && (pvp[0][0] & 0377) == CANONNET) 108938032Speter break; 109038032Speter 109138032Speter if (tTd(21, 12)) 109238032Speter { 109364562Sgshapiro if (tTd(21, 15)) 109490792Sgshapiro sm_dprintf("-----trying rule (line %d):", 109564562Sgshapiro rwr->r_line); 109664562Sgshapiro else 109790792Sgshapiro sm_dprintf("-----trying rule:"); 1098132943Sgshapiro printav(sm_debug_file(), rwr->r_lhs); 109938032Speter } 110038032Speter 110138032Speter /* try to match on this rule */ 110238032Speter mlp = mlist; 110338032Speter rvp = rwr->r_lhs; 110438032Speter avp = pvp; 110538032Speter if (++loopcount > 100) 110638032Speter { 110764562Sgshapiro syserr("554 5.3.5 Infinite loop in ruleset %s, rule %d", 110864562Sgshapiro rulename, ruleno); 110938032Speter if (tTd(21, 1)) 111038032Speter { 111190792Sgshapiro sm_dprintf("workspace: "); 1112132943Sgshapiro printav(sm_debug_file(), pvp); 111338032Speter } 111438032Speter break; 111538032Speter } 111638032Speter 111738032Speter while ((ap = *avp) != NULL || *rvp != NULL) 111838032Speter { 111938032Speter rp = *rvp; 112038032Speter if (tTd(21, 35)) 112138032Speter { 112290792Sgshapiro sm_dprintf("ADVANCE rp="); 1123132943Sgshapiro xputs(sm_debug_file(), rp); 112490792Sgshapiro sm_dprintf(", ap="); 1125132943Sgshapiro xputs(sm_debug_file(), ap); 112690792Sgshapiro sm_dprintf("\n"); 112738032Speter } 112838032Speter if (rp == NULL) 112938032Speter { 113038032Speter /* end-of-pattern before end-of-address */ 113138032Speter goto backup; 113238032Speter } 1133168515Sgshapiro if (ap == NULL && 1134168515Sgshapiro (rp[0] & 0377) != MATCHZANY && 1135168515Sgshapiro (rp[0] & 0377) != MATCHZERO) 113638032Speter { 113738032Speter /* end-of-input with patterns left */ 113838032Speter goto backup; 113938032Speter } 114038032Speter 1141168515Sgshapiro switch (rp[0] & 0377) 114238032Speter { 114338032Speter case MATCHCLASS: 114438032Speter /* match any phrase in a class */ 114564562Sgshapiro mlp->match_pattern = rvp; 114664562Sgshapiro mlp->match_first = avp; 114738032Speter extendclass: 114838032Speter ap = *avp; 114938032Speter if (ap == NULL) 115038032Speter goto backup; 115164562Sgshapiro mlp->match_last = avp++; 115264562Sgshapiro cataddr(mlp->match_first, mlp->match_last, 1153168515Sgshapiro buf, sizeof(buf), '\0', true); 115438032Speter if (!wordinclass(buf, rp[1])) 115538032Speter { 115638032Speter if (tTd(21, 36)) 115738032Speter { 115890792Sgshapiro sm_dprintf("EXTEND rp="); 1159132943Sgshapiro xputs(sm_debug_file(), rp); 116090792Sgshapiro sm_dprintf(", ap="); 1161132943Sgshapiro xputs(sm_debug_file(), ap); 116290792Sgshapiro sm_dprintf("\n"); 116338032Speter } 116438032Speter goto extendclass; 116538032Speter } 116638032Speter if (tTd(21, 36)) 116790792Sgshapiro sm_dprintf("CLMATCH\n"); 116838032Speter mlp++; 116938032Speter break; 117038032Speter 117138032Speter case MATCHNCLASS: 117238032Speter /* match any token not in a class */ 117338032Speter if (wordinclass(ap, rp[1])) 117438032Speter goto backup; 117538032Speter 117664562Sgshapiro /* FALLTHROUGH */ 117738032Speter 117838032Speter case MATCHONE: 117938032Speter case MATCHANY: 118038032Speter /* match exactly one token */ 118164562Sgshapiro mlp->match_pattern = rvp; 118264562Sgshapiro mlp->match_first = avp; 118364562Sgshapiro mlp->match_last = avp++; 118438032Speter mlp++; 118538032Speter break; 118638032Speter 118738032Speter case MATCHZANY: 118838032Speter /* match zero or more tokens */ 118964562Sgshapiro mlp->match_pattern = rvp; 119064562Sgshapiro mlp->match_first = avp; 119164562Sgshapiro mlp->match_last = avp - 1; 119238032Speter mlp++; 119338032Speter break; 119438032Speter 119538032Speter case MATCHZERO: 119638032Speter /* match zero tokens */ 119738032Speter break; 119838032Speter 119938032Speter case MACRODEXPAND: 120038032Speter /* 120138032Speter ** Match against run-time macro. 120238032Speter ** This algorithm is broken for the 120338032Speter ** general case (no recursive macros, 120438032Speter ** improper tokenization) but should 120538032Speter ** work for the usual cases. 120638032Speter */ 120738032Speter 120838032Speter ap = macvalue(rp[1], e); 120964562Sgshapiro mlp->match_first = avp; 121038032Speter if (tTd(21, 2)) 121198841Sgshapiro sm_dprintf("rewrite: LHS $&{%s} => \"%s\"\n", 121238032Speter macname(rp[1]), 121338032Speter ap == NULL ? "(NULL)" : ap); 121438032Speter 121538032Speter if (ap == NULL) 121638032Speter break; 121738032Speter while (*ap != '\0') 121838032Speter { 121938032Speter if (*avp == NULL || 122090792Sgshapiro sm_strncasecmp(ap, *avp, 122190792Sgshapiro strlen(*avp)) != 0) 122238032Speter { 122338032Speter /* no match */ 122464562Sgshapiro avp = mlp->match_first; 122538032Speter goto backup; 122638032Speter } 122738032Speter ap += strlen(*avp++); 122838032Speter } 122938032Speter 123038032Speter /* match */ 123138032Speter break; 123238032Speter 123338032Speter default: 123438032Speter /* must have exact match */ 123538032Speter if (sm_strcasecmp(rp, ap)) 123638032Speter goto backup; 123738032Speter avp++; 123838032Speter break; 123938032Speter } 124038032Speter 124138032Speter /* successful match on this token */ 124238032Speter rvp++; 124338032Speter continue; 124438032Speter 124538032Speter backup: 124638032Speter /* match failed -- back up */ 124738032Speter while (--mlp >= mlist) 124838032Speter { 124964562Sgshapiro rvp = mlp->match_pattern; 125038032Speter rp = *rvp; 125164562Sgshapiro avp = mlp->match_last + 1; 125238032Speter ap = *avp; 125338032Speter 125438032Speter if (tTd(21, 36)) 125538032Speter { 125690792Sgshapiro sm_dprintf("BACKUP rp="); 1257132943Sgshapiro xputs(sm_debug_file(), rp); 125890792Sgshapiro sm_dprintf(", ap="); 1259132943Sgshapiro xputs(sm_debug_file(), ap); 126090792Sgshapiro sm_dprintf("\n"); 126138032Speter } 126238032Speter 126338032Speter if (ap == NULL) 126438032Speter { 126538032Speter /* run off the end -- back up again */ 126638032Speter continue; 126738032Speter } 1268168515Sgshapiro 1269168515Sgshapiro if ((rp[0] & 0377) == MATCHANY || 1270168515Sgshapiro (rp[0] & 0377) == MATCHZANY) 127138032Speter { 127238032Speter /* extend binding and continue */ 127364562Sgshapiro mlp->match_last = avp++; 127438032Speter rvp++; 127538032Speter mlp++; 127638032Speter break; 127738032Speter } 1278168515Sgshapiro if ((rp[0] & 0377) == MATCHCLASS) 127938032Speter { 128038032Speter /* extend binding and try again */ 128164562Sgshapiro mlp->match_last = avp; 128238032Speter goto extendclass; 128338032Speter } 128438032Speter } 128538032Speter 128638032Speter if (mlp < mlist) 128738032Speter { 128838032Speter /* total failure to match */ 128938032Speter break; 129038032Speter } 129138032Speter } 129238032Speter 129338032Speter /* 129438032Speter ** See if we successfully matched 129538032Speter */ 129638032Speter 129738032Speter if (mlp < mlist || *rvp != NULL) 129838032Speter { 129938032Speter if (tTd(21, 10)) 130090792Sgshapiro sm_dprintf("----- rule fails\n"); 130138032Speter rwr = rwr->r_next; 130238032Speter ruleno++; 130338032Speter loopcount = 0; 130438032Speter continue; 130538032Speter } 130638032Speter 130738032Speter rvp = rwr->r_rhs; 130838032Speter if (tTd(21, 12)) 130938032Speter { 131090792Sgshapiro sm_dprintf("-----rule matches:"); 1311132943Sgshapiro printav(sm_debug_file(), rvp); 131238032Speter } 131338032Speter 131438032Speter rp = *rvp; 131564562Sgshapiro if (rp != NULL) 131638032Speter { 1317168515Sgshapiro if ((rp[0] & 0377) == CANONUSER) 131864562Sgshapiro { 131964562Sgshapiro rvp++; 132064562Sgshapiro rwr = rwr->r_next; 132164562Sgshapiro ruleno++; 132264562Sgshapiro loopcount = 0; 132364562Sgshapiro } 1324168515Sgshapiro else if ((rp[0] & 0377) == CANONHOST) 132564562Sgshapiro { 132664562Sgshapiro rvp++; 132764562Sgshapiro rwr = NULL; 132864562Sgshapiro } 132938032Speter } 133038032Speter 133138032Speter /* substitute */ 133238032Speter for (avp = npvp; *rvp != NULL; rvp++) 133338032Speter { 133438032Speter register struct match *m; 133538032Speter register char **pp; 133638032Speter 133738032Speter rp = *rvp; 1338168515Sgshapiro if ((rp[0] & 0377) == MATCHREPL) 133938032Speter { 134038032Speter /* substitute from LHS */ 134138032Speter m = &mlist[rp[1] - '1']; 134238032Speter if (m < mlist || m >= mlp) 134338032Speter { 134464562Sgshapiro syserr("554 5.3.5 rewrite: ruleset %s: replacement $%c out of bounds", 134564562Sgshapiro rulename, rp[1]); 134638032Speter return EX_CONFIG; 134738032Speter } 134838032Speter if (tTd(21, 15)) 134938032Speter { 135090792Sgshapiro sm_dprintf("$%c:", rp[1]); 135164562Sgshapiro pp = m->match_first; 135264562Sgshapiro while (pp <= m->match_last) 135338032Speter { 135490792Sgshapiro sm_dprintf(" %p=\"", *pp); 135590792Sgshapiro sm_dflush(); 135690792Sgshapiro sm_dprintf("%s\"", *pp++); 135738032Speter } 135890792Sgshapiro sm_dprintf("\n"); 135938032Speter } 136064562Sgshapiro pp = m->match_first; 136164562Sgshapiro while (pp <= m->match_last) 136238032Speter { 136390792Sgshapiro if (avp >= &npvp[maxatom]) 1364120256Sgshapiro goto toolong; 136538032Speter *avp++ = *pp++; 136638032Speter } 136738032Speter } 136838032Speter else 136938032Speter { 137038032Speter /* some sort of replacement */ 137190792Sgshapiro if (avp >= &npvp[maxatom]) 137238032Speter { 137338032Speter toolong: 137464562Sgshapiro syserr("554 5.3.0 rewrite: expansion too long"); 137590792Sgshapiro if (LogLevel > 9) 137690792Sgshapiro sm_syslog(LOG_ERR, e->e_id, 137790792Sgshapiro "rewrite: expansion too long, ruleset=%s, ruleno=%d", 137890792Sgshapiro rulename, ruleno); 137938032Speter return EX_DATAERR; 138038032Speter } 1381168515Sgshapiro if ((rp[0] & 0377) != MACRODEXPAND) 138238032Speter { 1383168515Sgshapiro /* vanilla replacement from RHS */ 138438032Speter *avp++ = rp; 138538032Speter } 138638032Speter else 138738032Speter { 138898841Sgshapiro /* $&{x} replacement */ 138938032Speter char *mval = macvalue(rp[1], e); 139038032Speter char **xpvp; 1391157001Sgshapiro size_t trsize = 0; 139238032Speter static size_t pvpb1_size = 0; 139338032Speter static char **pvpb1 = NULL; 139438032Speter char pvpbuf[PSBUFSIZE]; 139538032Speter 139638032Speter if (tTd(21, 2)) 139798841Sgshapiro sm_dprintf("rewrite: RHS $&{%s} => \"%s\"\n", 139838032Speter macname(rp[1]), 139938032Speter mval == NULL ? "(NULL)" : mval); 140038032Speter if (mval == NULL || *mval == '\0') 140138032Speter continue; 140238032Speter 140338032Speter /* save the remainder of the input */ 140438032Speter for (xpvp = pvp; *xpvp != NULL; xpvp++) 1405168515Sgshapiro trsize += sizeof(*xpvp); 1406157001Sgshapiro if (trsize > pvpb1_size) 140738032Speter { 140838032Speter if (pvpb1 != NULL) 140977349Sgshapiro sm_free(pvpb1); 141090792Sgshapiro pvpb1 = (char **) 141190792Sgshapiro sm_pmalloc_x(trsize); 141238032Speter pvpb1_size = trsize; 141338032Speter } 141438032Speter 141564562Sgshapiro memmove((char *) pvpb1, 141664562Sgshapiro (char *) pvp, 141764562Sgshapiro trsize); 141838032Speter 141938032Speter /* scan the new replacement */ 142038032Speter xpvp = prescan(mval, '\0', pvpbuf, 1421168515Sgshapiro sizeof(pvpbuf), NULL, 1422132943Sgshapiro NULL, false); 142338032Speter if (xpvp == NULL) 142438032Speter { 142538032Speter /* prescan pre-printed error */ 142638032Speter return EX_DATAERR; 142738032Speter } 142838032Speter 142938032Speter /* insert it into the output stream */ 143038032Speter while (*xpvp != NULL) 143138032Speter { 143238032Speter if (tTd(21, 19)) 143390792Sgshapiro sm_dprintf(" ... %s\n", 143464562Sgshapiro *xpvp); 143590792Sgshapiro *avp++ = sm_rpool_strdup_x( 143690792Sgshapiro e->e_rpool, *xpvp); 143790792Sgshapiro if (avp >= &npvp[maxatom]) 143838032Speter goto toolong; 143938032Speter xpvp++; 144038032Speter } 144138032Speter if (tTd(21, 19)) 144290792Sgshapiro sm_dprintf(" ... DONE\n"); 144338032Speter 144438032Speter /* restore the old trailing input */ 144564562Sgshapiro memmove((char *) pvp, 144664562Sgshapiro (char *) pvpb1, 144764562Sgshapiro trsize); 144838032Speter } 144938032Speter } 145038032Speter } 145138032Speter *avp++ = NULL; 145238032Speter 145338032Speter /* 145438032Speter ** Check for any hostname/keyword lookups. 145538032Speter */ 145638032Speter 145738032Speter for (rvp = npvp; *rvp != NULL; rvp++) 145838032Speter { 145938032Speter char **hbrvp; 146038032Speter char **xpvp; 1461157001Sgshapiro size_t trsize; 146238032Speter char *replac; 146338032Speter int endtoken; 1464182352Sgshapiro bool external; 146538032Speter STAB *map; 146638032Speter char *mapname; 146738032Speter char **key_rvp; 146838032Speter char **arg_rvp; 146938032Speter char **default_rvp; 1470157001Sgshapiro char cbuf[MAXKEY]; 147138032Speter char *pvpb1[MAXATOM + 1]; 1472120256Sgshapiro char *argvect[MAX_MAP_ARGS]; 147338032Speter char pvpbuf[PSBUFSIZE]; 147438032Speter char *nullpvp[1]; 147538032Speter 147638032Speter hbrvp = rvp; 1477168515Sgshapiro if ((rvp[0][0] & 0377) == HOSTBEGIN) 147838032Speter { 147938032Speter endtoken = HOSTEND; 148038032Speter mapname = "host"; 148138032Speter } 1482168515Sgshapiro else if ((rvp[0][0] & 0377) == LOOKUPBEGIN) 148338032Speter { 148438032Speter endtoken = LOOKUPEND; 148538032Speter mapname = *++rvp; 1486120256Sgshapiro if (mapname == NULL) 1487159609Sgshapiro { 1488120256Sgshapiro syserr("554 5.3.0 rewrite: missing mapname"); 1489159609Sgshapiro /* NOTREACHED */ 1490159609Sgshapiro SM_ASSERT(0); 1491159609Sgshapiro } 149238032Speter } 1493168515Sgshapiro else 1494168515Sgshapiro continue; 1495168515Sgshapiro 1496168515Sgshapiro /* 1497168515Sgshapiro ** Got a hostname/keyword lookup. 1498168515Sgshapiro ** 1499168515Sgshapiro ** This could be optimized fairly easily. 1500168515Sgshapiro */ 1501168515Sgshapiro 150238032Speter map = stab(mapname, ST_MAP, ST_FIND); 150338032Speter if (map == NULL) 1504120256Sgshapiro syserr("554 5.3.0 rewrite: map %s not found", 1505120256Sgshapiro mapname); 150638032Speter 150738032Speter /* extract the match part */ 150838032Speter key_rvp = ++rvp; 1509120256Sgshapiro if (key_rvp == NULL) 1510159609Sgshapiro { 1511120256Sgshapiro syserr("554 5.3.0 rewrite: missing key for map %s", 1512120256Sgshapiro mapname); 1513159609Sgshapiro /* NOTREACHED */ 1514159609Sgshapiro SM_ASSERT(0); 1515159609Sgshapiro } 151638032Speter default_rvp = NULL; 151738032Speter arg_rvp = argvect; 151838032Speter xpvp = NULL; 151938032Speter replac = pvpbuf; 1520168515Sgshapiro while (*rvp != NULL && ((rvp[0][0] & 0377) != endtoken)) 152138032Speter { 1522168515Sgshapiro int nodetype = rvp[0][0] & 0377; 152338032Speter 1524120256Sgshapiro if (nodetype != CANONHOST && 1525120256Sgshapiro nodetype != CANONUSER) 152638032Speter { 152738032Speter rvp++; 152838032Speter continue; 152938032Speter } 153038032Speter 153138032Speter *rvp++ = NULL; 153238032Speter 153338032Speter if (xpvp != NULL) 153438032Speter { 153538032Speter cataddr(xpvp, NULL, replac, 1536168515Sgshapiro &pvpbuf[sizeof(pvpbuf)] - replac, 1537168515Sgshapiro '\0', false); 1538120256Sgshapiro if (arg_rvp < 1539120256Sgshapiro &argvect[MAX_MAP_ARGS - 1]) 1540120256Sgshapiro *++arg_rvp = replac; 154138032Speter replac += strlen(replac) + 1; 154238032Speter xpvp = NULL; 154338032Speter } 154438032Speter switch (nodetype) 154538032Speter { 154638032Speter case CANONHOST: 154738032Speter xpvp = rvp; 154838032Speter break; 154938032Speter 155038032Speter case CANONUSER: 155138032Speter default_rvp = rvp; 155238032Speter break; 155338032Speter } 155438032Speter } 155538032Speter if (*rvp != NULL) 155638032Speter *rvp++ = NULL; 155738032Speter if (xpvp != NULL) 155838032Speter { 155938032Speter cataddr(xpvp, NULL, replac, 1560168515Sgshapiro &pvpbuf[sizeof(pvpbuf)] - replac, 1561168515Sgshapiro '\0', false); 1562120256Sgshapiro if (arg_rvp < &argvect[MAX_MAP_ARGS - 1]) 1563120256Sgshapiro *++arg_rvp = replac; 156438032Speter } 1565120256Sgshapiro if (arg_rvp >= &argvect[MAX_MAP_ARGS - 1]) 1566120256Sgshapiro argvect[MAX_MAP_ARGS - 1] = NULL; 1567120256Sgshapiro else 1568120256Sgshapiro *++arg_rvp = NULL; 156938032Speter 157038032Speter /* save the remainder of the input string */ 1571168515Sgshapiro trsize = (avp - rvp + 1) * sizeof(*rvp); 157264562Sgshapiro memmove((char *) pvpb1, (char *) rvp, trsize); 157338032Speter 157438032Speter /* look it up */ 1575168515Sgshapiro cataddr(key_rvp, NULL, cbuf, sizeof(cbuf), 1576168515Sgshapiro map == NULL ? '\0' : map->s_map.map_spacesub, 1577168515Sgshapiro true); 157864562Sgshapiro argvect[0] = cbuf; 157964562Sgshapiro replac = map_lookup(map, cbuf, argvect, &rstat, e); 1580182352Sgshapiro external = replac != NULL; 158138032Speter 158238032Speter /* if no replacement, use default */ 158338032Speter if (replac == NULL && default_rvp != NULL) 158438032Speter { 158538032Speter /* create the default */ 1586168515Sgshapiro cataddr(default_rvp, NULL, cbuf, sizeof(cbuf), 1587168515Sgshapiro '\0', false); 158864562Sgshapiro replac = cbuf; 158938032Speter } 159038032Speter 159138032Speter if (replac == NULL) 159238032Speter { 159338032Speter xpvp = key_rvp; 159438032Speter } 159538032Speter else if (*replac == '\0') 159638032Speter { 159738032Speter /* null replacement */ 159838032Speter nullpvp[0] = NULL; 159938032Speter xpvp = nullpvp; 160038032Speter } 160138032Speter else 160238032Speter { 160338032Speter /* scan the new replacement */ 160438032Speter xpvp = prescan(replac, '\0', pvpbuf, 1605182352Sgshapiro sizeof(pvpbuf), NULL, 1606182352Sgshapiro external ? NULL : IntTokenTab, 1607168515Sgshapiro false); 160838032Speter if (xpvp == NULL) 160938032Speter { 161038032Speter /* prescan already printed error */ 161138032Speter return EX_DATAERR; 161238032Speter } 161338032Speter } 161438032Speter 161538032Speter /* append it to the token list */ 161638032Speter for (avp = hbrvp; *xpvp != NULL; xpvp++) 161738032Speter { 161890792Sgshapiro *avp++ = sm_rpool_strdup_x(e->e_rpool, *xpvp); 161990792Sgshapiro if (avp >= &npvp[maxatom]) 162038032Speter goto toolong; 162138032Speter } 162238032Speter 162338032Speter /* restore the old trailing information */ 162438032Speter rvp = avp - 1; 162538032Speter for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) 162690792Sgshapiro if (avp >= &npvp[maxatom]) 162738032Speter goto toolong; 162838032Speter } 162938032Speter 163038032Speter /* 163138032Speter ** Check for subroutine calls. 163238032Speter */ 163338032Speter 163464562Sgshapiro status = callsubr(npvp, reclevel, e); 163564562Sgshapiro if (rstat == EX_OK || status == EX_TEMPFAIL) 163664562Sgshapiro rstat = status; 163738032Speter 163838032Speter /* copy vector back into original space. */ 163938032Speter for (avp = npvp; *avp++ != NULL;) 164038032Speter continue; 164164562Sgshapiro memmove((char *) pvp, (char *) npvp, 1642168515Sgshapiro (int) (avp - npvp) * sizeof(*avp)); 164364562Sgshapiro 164438032Speter if (tTd(21, 4)) 164538032Speter { 164690792Sgshapiro sm_dprintf("rewritten as:"); 1647132943Sgshapiro printav(sm_debug_file(), pvp); 164838032Speter } 164938032Speter } 165038032Speter 165164562Sgshapiro if (OpMode == MD_TEST) 165238032Speter { 165390792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 165490792Sgshapiro "%s%-16.16s returns:", prefix, rulename); 1655132943Sgshapiro printav(smioout, pvp); 165638032Speter } 165764562Sgshapiro else if (tTd(21, 1)) 165864562Sgshapiro { 165990792Sgshapiro sm_dprintf("%s%-16.16s returns:", prefix, rulename); 1660132943Sgshapiro printav(sm_debug_file(), pvp); 166164562Sgshapiro } 166238032Speter return rstat; 166338032Speter} 166490792Sgshapiro/* 166538032Speter** CALLSUBR -- call subroutines in rewrite vector 166638032Speter** 166738032Speter** Parameters: 166838032Speter** pvp -- pointer to token vector. 166938032Speter** reclevel -- the current recursion level. 167038032Speter** e -- the current envelope. 167138032Speter** 167238032Speter** Returns: 167338032Speter** The status from the subroutine call. 167438032Speter** 167538032Speter** Side Effects: 167638032Speter** pvp is modified. 167738032Speter*/ 167838032Speter 167964562Sgshapirostatic int 168038032Spetercallsubr(pvp, reclevel, e) 168138032Speter char **pvp; 168238032Speter int reclevel; 168338032Speter ENVELOPE *e; 168438032Speter{ 168564562Sgshapiro char **avp; 168638032Speter register int i; 168790792Sgshapiro int subr, j; 168890792Sgshapiro int nsubr; 168964562Sgshapiro int status; 169038032Speter int rstat = EX_OK; 169190792Sgshapiro#define MAX_SUBR 16 169290792Sgshapiro int subrnumber[MAX_SUBR]; 169390792Sgshapiro int subrindex[MAX_SUBR]; 169438032Speter 169590792Sgshapiro nsubr = 0; 169690792Sgshapiro 169790792Sgshapiro /* 169890792Sgshapiro ** Look for subroutine calls in pvp, collect them into subr*[] 169990792Sgshapiro ** We will perform the calls in the next loop, because we will 170090792Sgshapiro ** call the "last" subroutine first to avoid recursive calls 170190792Sgshapiro ** and too much copying. 170290792Sgshapiro */ 170390792Sgshapiro 170490792Sgshapiro for (avp = pvp, j = 0; *avp != NULL; avp++, j++) 170538032Speter { 1706168515Sgshapiro if ((avp[0][0] & 0377) == CALLSUBR && avp[1] != NULL) 170738032Speter { 170838032Speter stripquotes(avp[1]); 170938032Speter subr = strtorwset(avp[1], NULL, ST_FIND); 171038032Speter if (subr < 0) 171138032Speter { 171290792Sgshapiro syserr("554 5.3.5 Unknown ruleset %s", avp[1]); 171338032Speter return EX_CONFIG; 171438032Speter } 171538032Speter 171638032Speter /* 171790792Sgshapiro ** XXX instead of doing this we could optimize 171890792Sgshapiro ** the rules after reading them: just remove 171990792Sgshapiro ** calls to empty rulesets 172038032Speter */ 172138032Speter 172290792Sgshapiro /* subroutine is an empty ruleset? don't call it */ 172390792Sgshapiro if (RewriteRules[subr] == NULL) 172490792Sgshapiro { 172590792Sgshapiro if (tTd(21, 3)) 172690792Sgshapiro sm_dprintf("-----skip subr %s (%d)\n", 172790792Sgshapiro avp[1], subr); 172890792Sgshapiro for (i = 2; avp[i] != NULL; i++) 172990792Sgshapiro avp[i - 2] = avp[i]; 173090792Sgshapiro avp[i - 2] = NULL; 173138032Speter continue; 173290792Sgshapiro } 173390792Sgshapiro if (++nsubr >= MAX_SUBR) 173438032Speter { 173590792Sgshapiro syserr("554 5.3.0 Too many subroutine calls (%d max)", 173690792Sgshapiro MAX_SUBR); 173790792Sgshapiro return EX_CONFIG; 173838032Speter } 173990792Sgshapiro subrnumber[nsubr] = subr; 174090792Sgshapiro subrindex[nsubr] = j; 174190792Sgshapiro } 174290792Sgshapiro } 174338032Speter 174490792Sgshapiro /* 174590792Sgshapiro ** Perform the actual subroutines calls, "last" one first, i.e., 174690792Sgshapiro ** go from the right to the left through all calls, 174790792Sgshapiro ** do the rewriting in place. 174890792Sgshapiro */ 174938032Speter 175090792Sgshapiro for (; nsubr > 0; nsubr--) 175190792Sgshapiro { 175290792Sgshapiro subr = subrnumber[nsubr]; 175390792Sgshapiro avp = pvp + subrindex[nsubr]; 175438032Speter 175590792Sgshapiro /* remove the subroutine call and name */ 175690792Sgshapiro for (i = 2; avp[i] != NULL; i++) 175790792Sgshapiro avp[i - 2] = avp[i]; 175890792Sgshapiro avp[i - 2] = NULL; 175938032Speter 176090792Sgshapiro /* 176190792Sgshapiro ** Now we need to call the ruleset specified for 1762120256Sgshapiro ** the subroutine. We can do this in place since 176390792Sgshapiro ** we call the "last" subroutine first. 176490792Sgshapiro */ 176590792Sgshapiro 176690792Sgshapiro status = rewrite(avp, subr, reclevel, e, 176790792Sgshapiro MAXATOM - subrindex[nsubr]); 176890792Sgshapiro if (status != EX_OK && status != EX_TEMPFAIL) 176990792Sgshapiro return status; 177090792Sgshapiro if (rstat == EX_OK || status == EX_TEMPFAIL) 177190792Sgshapiro rstat = status; 177238032Speter } 177338032Speter return rstat; 177438032Speter} 177590792Sgshapiro/* 177638032Speter** MAP_LOOKUP -- do lookup in map 177738032Speter** 177838032Speter** Parameters: 177990792Sgshapiro** smap -- the map to use for the lookup. 178038032Speter** key -- the key to look up. 178138032Speter** argvect -- arguments to pass to the map lookup. 178238032Speter** pstat -- a pointer to an integer in which to store the 178338032Speter** status from the lookup. 178438032Speter** e -- the current envelope. 178538032Speter** 178638032Speter** Returns: 178738032Speter** The result of the lookup. 178838032Speter** NULL -- if there was no data for the given key. 178938032Speter*/ 179038032Speter 179164562Sgshapirostatic char * 179264562Sgshapiromap_lookup(smap, key, argvect, pstat, e) 179364562Sgshapiro STAB *smap; 179438032Speter char key[]; 179538032Speter char **argvect; 179638032Speter int *pstat; 179738032Speter ENVELOPE *e; 179838032Speter{ 179964562Sgshapiro auto int status = EX_OK; 180064562Sgshapiro MAP *map; 180138032Speter char *replac; 180238032Speter 180364562Sgshapiro if (smap == NULL) 180464562Sgshapiro return NULL; 180564562Sgshapiro 180664562Sgshapiro map = &smap->s_map; 180764562Sgshapiro DYNOPENMAP(map); 180864562Sgshapiro 180964562Sgshapiro if (e->e_sendmode == SM_DEFER && 181064562Sgshapiro bitset(MF_DEFER, map->map_mflags)) 181138032Speter { 181238032Speter /* don't do any map lookups */ 181338032Speter if (tTd(60, 1)) 181490792Sgshapiro sm_dprintf("map_lookup(%s, %s) => DEFERRED\n", 181564562Sgshapiro smap->s_name, key); 181638032Speter *pstat = EX_TEMPFAIL; 181738032Speter return NULL; 181838032Speter } 181938032Speter 182064562Sgshapiro if (!bitset(MF_KEEPQUOTES, map->map_mflags)) 182138032Speter stripquotes(key); 182238032Speter 182338032Speter if (tTd(60, 1)) 182442575Speter { 1825168515Sgshapiro sm_dprintf("map_lookup(%s, ", smap->s_name); 1826168515Sgshapiro xputs(sm_debug_file(), key); 182742575Speter if (tTd(60, 5)) 182842575Speter { 182942575Speter int i; 183042575Speter 183142575Speter for (i = 0; argvect[i] != NULL; i++) 183290792Sgshapiro sm_dprintf(", %%%d=%s", i, argvect[i]); 183342575Speter } 183490792Sgshapiro sm_dprintf(") => "); 183542575Speter } 183664562Sgshapiro replac = (*map->map_class->map_lookup)(map, key, argvect, &status); 183738032Speter if (tTd(60, 1)) 183890792Sgshapiro sm_dprintf("%s (%d)\n", 183938032Speter replac != NULL ? replac : "NOT FOUND", 184064562Sgshapiro status); 184138032Speter 184264562Sgshapiro /* should recover if status == EX_TEMPFAIL */ 184364562Sgshapiro if (status == EX_TEMPFAIL && !bitset(MF_NODEFER, map->map_mflags)) 184438032Speter { 184538032Speter *pstat = EX_TEMPFAIL; 184638032Speter if (tTd(60, 1)) 184790792Sgshapiro sm_dprintf("map_lookup(%s, %s) tempfail: errno=%d\n", 184864562Sgshapiro smap->s_name, key, errno); 184938032Speter if (e->e_message == NULL) 185038032Speter { 185138032Speter char mbuf[320]; 185238032Speter 1853168515Sgshapiro (void) sm_snprintf(mbuf, sizeof(mbuf), 185438032Speter "%.80s map: lookup (%s): deferred", 185564562Sgshapiro smap->s_name, 185638032Speter shortenstring(key, MAXSHORTSTR)); 185790792Sgshapiro e->e_message = sm_rpool_strdup_x(e->e_rpool, mbuf); 185838032Speter } 185938032Speter } 186064562Sgshapiro if (status == EX_TEMPFAIL && map->map_tapp != NULL) 186138032Speter { 186264562Sgshapiro size_t i = strlen(key) + strlen(map->map_tapp) + 1; 186338032Speter static char *rwbuf = NULL; 186438032Speter static size_t rwbuflen = 0; 186538032Speter 186638032Speter if (i > rwbuflen) 186738032Speter { 186838032Speter if (rwbuf != NULL) 186977349Sgshapiro sm_free(rwbuf); 187038032Speter rwbuflen = i; 187190792Sgshapiro rwbuf = (char *) sm_pmalloc_x(rwbuflen); 187238032Speter } 187390792Sgshapiro (void) sm_strlcpyn(rwbuf, rwbuflen, 2, key, map->map_tapp); 187438032Speter if (tTd(60, 4)) 187590792Sgshapiro sm_dprintf("map_lookup tempfail: returning \"%s\"\n", 187638032Speter rwbuf); 187738032Speter return rwbuf; 187838032Speter } 187938032Speter return replac; 188038032Speter} 188190792Sgshapiro/* 188264562Sgshapiro** INITERRMAILERS -- initialize error and discard mailers 188364562Sgshapiro** 188464562Sgshapiro** Parameters: 188564562Sgshapiro** none. 188664562Sgshapiro** 188764562Sgshapiro** Returns: 188864562Sgshapiro** none. 188964562Sgshapiro** 189064562Sgshapiro** Side Effects: 189164562Sgshapiro** initializes error and discard mailers. 189264562Sgshapiro*/ 189364562Sgshapiro 189464562Sgshapirostatic MAILER discardmailer; 189564562Sgshapirostatic MAILER errormailer; 189664562Sgshapirostatic char *discardargv[] = { "DISCARD", NULL }; 189764562Sgshapirostatic char *errorargv[] = { "ERROR", NULL }; 189864562Sgshapiro 189964562Sgshapirovoid 190064562Sgshapiroiniterrmailers() 190164562Sgshapiro{ 190264562Sgshapiro if (discardmailer.m_name == NULL) 190364562Sgshapiro { 190464562Sgshapiro /* initialize the discard mailer */ 190564562Sgshapiro discardmailer.m_name = "*discard*"; 190664562Sgshapiro discardmailer.m_mailer = "DISCARD"; 190764562Sgshapiro discardmailer.m_argv = discardargv; 190864562Sgshapiro } 190964562Sgshapiro if (errormailer.m_name == NULL) 191064562Sgshapiro { 191164562Sgshapiro /* initialize the bogus mailer */ 191264562Sgshapiro errormailer.m_name = "*error*"; 191364562Sgshapiro errormailer.m_mailer = "ERROR"; 191464562Sgshapiro errormailer.m_argv = errorargv; 191564562Sgshapiro } 191664562Sgshapiro} 191790792Sgshapiro/* 191838032Speter** BUILDADDR -- build address from token vector. 191938032Speter** 192038032Speter** Parameters: 192138032Speter** tv -- token vector. 192238032Speter** a -- pointer to address descriptor to fill. 192338032Speter** If NULL, one will be allocated. 192438032Speter** flags -- info regarding whether this is a sender or 192538032Speter** a recipient. 192638032Speter** e -- the current envelope. 192738032Speter** 192838032Speter** Returns: 192938032Speter** NULL if there was an error. 193038032Speter** 'a' otherwise. 193138032Speter** 193238032Speter** Side Effects: 193338032Speter** fills in 'a' 193438032Speter*/ 193538032Speter 193664562Sgshapirostatic struct errcodes 193738032Speter{ 193838032Speter char *ec_name; /* name of error code */ 193938032Speter int ec_code; /* numeric code */ 194038032Speter} ErrorCodes[] = 194138032Speter{ 194238032Speter { "usage", EX_USAGE }, 194338032Speter { "nouser", EX_NOUSER }, 194438032Speter { "nohost", EX_NOHOST }, 194538032Speter { "unavailable", EX_UNAVAILABLE }, 194638032Speter { "software", EX_SOFTWARE }, 194738032Speter { "tempfail", EX_TEMPFAIL }, 194838032Speter { "protocol", EX_PROTOCOL }, 194938032Speter { "config", EX_CONFIG }, 195038032Speter { NULL, EX_UNAVAILABLE } 195138032Speter}; 195238032Speter 195364562Sgshapirostatic ADDRESS * 195438032Speterbuildaddr(tv, a, flags, e) 195538032Speter register char **tv; 195638032Speter register ADDRESS *a; 195738032Speter int flags; 195838032Speter register ENVELOPE *e; 195938032Speter{ 196094334Sgshapiro bool tempfail = false; 1961120256Sgshapiro int maxatom; 196238032Speter struct mailer **mp; 196338032Speter register struct mailer *m; 196438032Speter register char *p; 196538032Speter char *mname; 196638032Speter char **hostp; 196738032Speter char hbuf[MAXNAME + 1]; 196842575Speter static char ubuf[MAXNAME + 2]; 196938032Speter 197038032Speter if (tTd(24, 5)) 197138032Speter { 197290792Sgshapiro sm_dprintf("buildaddr, flags=%x, tv=", flags); 1973132943Sgshapiro printav(sm_debug_file(), tv); 197438032Speter } 197538032Speter 1976120256Sgshapiro maxatom = MAXATOM; 197738032Speter if (a == NULL) 1978168515Sgshapiro a = (ADDRESS *) sm_rpool_malloc_x(e->e_rpool, sizeof(*a)); 1979168515Sgshapiro memset((char *) a, '\0', sizeof(*a)); 198064562Sgshapiro hbuf[0] = '\0'; 198138032Speter 198238032Speter /* set up default error return flags */ 198338032Speter a->q_flags |= DefaultNotify; 198438032Speter 198538032Speter /* figure out what net/mailer to use */ 198638032Speter if (*tv == NULL || (**tv & 0377) != CANONNET) 198738032Speter { 198864562Sgshapiro syserr("554 5.3.5 buildaddr: no mailer in parsed address"); 198938032Speterbadaddr: 199094334Sgshapiro /* 199194334Sgshapiro ** ExitStat may have been set by an earlier map open 199294334Sgshapiro ** failure (to a permanent error (EX_OSERR) in syserr()) 199394334Sgshapiro ** so we also need to check if this particular $#error 199494334Sgshapiro ** return wanted a 4XX failure. 199594334Sgshapiro ** 199694334Sgshapiro ** XXX the real fix is probably to set ExitStat correctly, 199794334Sgshapiro ** i.e., to EX_TEMPFAIL if the map open is just a temporary 199894334Sgshapiro ** error. 199994334Sgshapiro */ 200094334Sgshapiro 200194334Sgshapiro if (ExitStat == EX_TEMPFAIL || tempfail) 200264562Sgshapiro a->q_state = QS_QUEUEUP; 200364562Sgshapiro else 200438032Speter { 200564562Sgshapiro a->q_state = QS_BADADDR; 200664562Sgshapiro a->q_mailer = &errormailer; 200738032Speter } 200838032Speter return a; 200938032Speter } 201038032Speter mname = *++tv; 2011120256Sgshapiro --maxatom; 201238032Speter 201338032Speter /* extract host and user portions */ 201438032Speter if (*++tv != NULL && (**tv & 0377) == CANONHOST) 2015120256Sgshapiro { 201638032Speter hostp = ++tv; 2017120256Sgshapiro --maxatom; 2018120256Sgshapiro } 201938032Speter else 202038032Speter hostp = NULL; 2021120256Sgshapiro --maxatom; 202238032Speter while (*tv != NULL && (**tv & 0377) != CANONUSER) 2023120256Sgshapiro { 202438032Speter tv++; 2025120256Sgshapiro --maxatom; 2026120256Sgshapiro } 202738032Speter if (*tv == NULL) 202838032Speter { 202964562Sgshapiro syserr("554 5.3.5 buildaddr: no user"); 203038032Speter goto badaddr; 203138032Speter } 203238032Speter if (tv == hostp) 203338032Speter hostp = NULL; 203438032Speter else if (hostp != NULL) 2035168515Sgshapiro cataddr(hostp, tv - 1, hbuf, sizeof(hbuf), '\0', false); 2036168515Sgshapiro cataddr(++tv, NULL, ubuf, sizeof(ubuf), ' ', false); 2037120256Sgshapiro --maxatom; 203838032Speter 203938032Speter /* save away the host name */ 204090792Sgshapiro if (sm_strcasecmp(mname, "error") == 0) 204138032Speter { 204264562Sgshapiro /* Set up triplet for use by -bv */ 204364562Sgshapiro a->q_mailer = &errormailer; 204490792Sgshapiro a->q_user = sm_rpool_strdup_x(e->e_rpool, ubuf); 204590792Sgshapiro /* XXX wrong place? */ 204664562Sgshapiro 204738032Speter if (hostp != NULL) 204838032Speter { 204938032Speter register struct errcodes *ep; 205038032Speter 205190792Sgshapiro a->q_host = sm_rpool_strdup_x(e->e_rpool, hbuf); 205238032Speter if (strchr(hbuf, '.') != NULL) 205338032Speter { 205490792Sgshapiro a->q_status = sm_rpool_strdup_x(e->e_rpool, 205590792Sgshapiro hbuf); 205638032Speter setstat(dsntoexitstat(hbuf)); 205738032Speter } 205838032Speter else if (isascii(hbuf[0]) && isdigit(hbuf[0])) 205938032Speter { 206038032Speter setstat(atoi(hbuf)); 206138032Speter } 206238032Speter else 206338032Speter { 206438032Speter for (ep = ErrorCodes; ep->ec_name != NULL; ep++) 206590792Sgshapiro if (sm_strcasecmp(ep->ec_name, hbuf) == 0) 206638032Speter break; 206738032Speter setstat(ep->ec_code); 206838032Speter } 206938032Speter } 207038032Speter else 207164562Sgshapiro { 207264562Sgshapiro a->q_host = NULL; 207338032Speter setstat(EX_UNAVAILABLE); 207464562Sgshapiro } 207538032Speter stripquotes(ubuf); 207664562Sgshapiro if (ISSMTPCODE(ubuf) && ubuf[3] == ' ') 207738032Speter { 207864562Sgshapiro char fmt[16]; 207964562Sgshapiro int off; 208038032Speter 208164562Sgshapiro if ((off = isenhsc(ubuf + 4, ' ')) > 0) 208238032Speter { 208364562Sgshapiro ubuf[off + 4] = '\0'; 208464562Sgshapiro off += 5; 208538032Speter } 208664562Sgshapiro else 208764562Sgshapiro { 208864562Sgshapiro off = 4; 208964562Sgshapiro ubuf[3] = '\0'; 209064562Sgshapiro } 2091168515Sgshapiro (void) sm_strlcpyn(fmt, sizeof(fmt), 2, ubuf, " %s"); 209264562Sgshapiro if (off > 4) 209364562Sgshapiro usrerr(fmt, ubuf + off); 209464562Sgshapiro else if (isenhsc(hbuf, '\0') > 0) 209564562Sgshapiro usrerrenh(hbuf, fmt, ubuf + off); 209664562Sgshapiro else 209764562Sgshapiro usrerr(fmt, ubuf + off); 209864562Sgshapiro /* XXX ubuf[off - 1] = ' '; */ 209994334Sgshapiro if (ubuf[0] == '4') 210094334Sgshapiro tempfail = true; 210138032Speter } 210238032Speter else 210338032Speter { 210464562Sgshapiro usrerr("553 5.3.0 %s", ubuf); 210538032Speter } 210638032Speter goto badaddr; 210738032Speter } 210838032Speter 210938032Speter for (mp = Mailer; (m = *mp++) != NULL; ) 211038032Speter { 211190792Sgshapiro if (sm_strcasecmp(m->m_name, mname) == 0) 211238032Speter break; 211338032Speter } 211438032Speter if (m == NULL) 211538032Speter { 211664562Sgshapiro syserr("554 5.3.5 buildaddr: unknown mailer %s", mname); 211738032Speter goto badaddr; 211838032Speter } 211938032Speter a->q_mailer = m; 212038032Speter 212138032Speter /* figure out what host (if any) */ 212238032Speter if (hostp == NULL) 212338032Speter { 212438032Speter if (!bitnset(M_LOCALMAILER, m->m_flags)) 212538032Speter { 212664562Sgshapiro syserr("554 5.3.5 buildaddr: no host"); 212738032Speter goto badaddr; 212838032Speter } 212938032Speter a->q_host = NULL; 213038032Speter } 213138032Speter else 213290792Sgshapiro a->q_host = sm_rpool_strdup_x(e->e_rpool, hbuf); 213338032Speter 213438032Speter /* figure out the user */ 213538032Speter p = ubuf; 213638032Speter if (bitnset(M_CHECKUDB, m->m_flags) && *p == '@') 213738032Speter { 213838032Speter p++; 213938032Speter tv++; 2140120256Sgshapiro --maxatom; 214138032Speter a->q_flags |= QNOTREMOTE; 214238032Speter } 214338032Speter 214438032Speter /* do special mapping for local mailer */ 214538032Speter if (*p == '"') 214638032Speter p++; 214738032Speter if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags)) 214838032Speter a->q_mailer = m = ProgMailer; 214938032Speter else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags)) 215038032Speter a->q_mailer = m = FileMailer; 215138032Speter else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags)) 215238032Speter { 215338032Speter /* may be :include: */ 215438032Speter stripquotes(ubuf); 215590792Sgshapiro if (sm_strncasecmp(ubuf, ":include:", 9) == 0) 215638032Speter { 215738032Speter /* if :include:, don't need further rewriting */ 215838032Speter a->q_mailer = m = InclMailer; 215990792Sgshapiro a->q_user = sm_rpool_strdup_x(e->e_rpool, &ubuf[9]); 216038032Speter return a; 216138032Speter } 216238032Speter } 216338032Speter 216438032Speter /* rewrite according recipient mailer rewriting rules */ 216590792Sgshapiro macdefine(&e->e_macro, A_PERM, 'h', a->q_host); 216664562Sgshapiro 216790792Sgshapiro if (ConfigLevel >= 10 || 216864562Sgshapiro !bitset(RF_SENDERADDR|RF_HEADERADDR, flags)) 216938032Speter { 217038032Speter /* sender addresses done later */ 2171120256Sgshapiro (void) rewrite(tv, 2, 0, e, maxatom); 217238032Speter if (m->m_re_rwset > 0) 2173120256Sgshapiro (void) rewrite(tv, m->m_re_rwset, 0, e, maxatom); 217438032Speter } 2175120256Sgshapiro (void) rewrite(tv, 4, 0, e, maxatom); 217638032Speter 217738032Speter /* save the result for the command line/RCPT argument */ 2178168515Sgshapiro cataddr(tv, NULL, ubuf, sizeof(ubuf), '\0', true); 217990792Sgshapiro a->q_user = sm_rpool_strdup_x(e->e_rpool, ubuf); 218038032Speter 218138032Speter /* 218238032Speter ** Do mapping to lower case as requested by mailer 218338032Speter */ 218438032Speter 218538032Speter if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags)) 218638032Speter makelower(a->q_host); 218738032Speter if (!bitnset(M_USR_UPPER, m->m_flags)) 218838032Speter makelower(a->q_user); 218938032Speter 219038032Speter if (tTd(24, 6)) 219138032Speter { 219290792Sgshapiro sm_dprintf("buildaddr => "); 2193132943Sgshapiro printaddr(sm_debug_file(), a, false); 219438032Speter } 219538032Speter return a; 219638032Speter} 2197110560Sgshapiro 219890792Sgshapiro/* 219938032Speter** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 220038032Speter** 220138032Speter** Parameters: 220238032Speter** pvp -- parameter vector to rebuild. 220338032Speter** evp -- last parameter to include. Can be NULL to 220438032Speter** use entire pvp. 220538032Speter** buf -- buffer to build the string into. 220638032Speter** sz -- size of buf. 2207285229Sgshapiro** spacesub -- the space separator character; 2208285229Sgshapiro** '\0': SpaceSub. 2209285229Sgshapiro** NOSPACESEP: no separator 2210168515Sgshapiro** external -- convert to external form? 2211168515Sgshapiro** (no metacharacters; METAQUOTEs removed, see below) 221238032Speter** 221338032Speter** Returns: 221438032Speter** none. 221538032Speter** 221638032Speter** Side Effects: 221738032Speter** Destroys buf. 2218168515Sgshapiro** 2219168515Sgshapiro** Notes: 2220168515Sgshapiro** There are two formats for strings: internal and external. 2221168515Sgshapiro** The external format is just an eight-bit clean string (no 2222168515Sgshapiro** null bytes, everything else OK). The internal format can 2223168515Sgshapiro** include sendmail metacharacters. The special character 2224168515Sgshapiro** METAQUOTE essentially quotes the character following, stripping 2225168515Sgshapiro** it of all special semantics. 2226168515Sgshapiro** 2227168515Sgshapiro** The cataddr routine needs to be aware of whether it is producing 2228168515Sgshapiro** an internal or external form as output (it only takes internal 2229168515Sgshapiro** form as input). 2230168515Sgshapiro** 2231168515Sgshapiro** The parseaddr routine has a similar issue on input, but that 2232168515Sgshapiro** is flagged on the basis of which token table is passed in. 223338032Speter*/ 223438032Speter 223538032Spetervoid 2236168515Sgshapirocataddr(pvp, evp, buf, sz, spacesub, external) 223738032Speter char **pvp; 223838032Speter char **evp; 223938032Speter char *buf; 224038032Speter register int sz; 224138032Speter int spacesub; 2242168515Sgshapiro bool external; 224338032Speter{ 2244168515Sgshapiro bool oatomtok, natomtok; 2245168515Sgshapiro char *p; 224638032Speter 2247168515Sgshapiro oatomtok = natomtok = false; 2248168515Sgshapiro if (tTd(59, 14)) 2249168515Sgshapiro { 2250168515Sgshapiro sm_dprintf("cataddr(%d) <==", external); 2251168515Sgshapiro printav(sm_debug_file(), pvp); 2252168515Sgshapiro } 2253168515Sgshapiro 225464562Sgshapiro if (sz <= 0) 225564562Sgshapiro return; 225664562Sgshapiro 225738032Speter if (spacesub == '\0') 225838032Speter spacesub = SpaceSub; 225938032Speter 226038032Speter if (pvp == NULL) 226138032Speter { 226264562Sgshapiro *buf = '\0'; 226338032Speter return; 226438032Speter } 226538032Speter p = buf; 226638032Speter sz -= 2; 226790792Sgshapiro while (*pvp != NULL && sz > 0) 226838032Speter { 2269168515Sgshapiro char *q; 2270168515Sgshapiro 2271182352Sgshapiro natomtok = (IntTokenTab[**pvp & 0xff] == ATM); 2272285229Sgshapiro if (oatomtok && natomtok && spacesub != NOSPACESEP) 227364562Sgshapiro { 227438032Speter *p++ = spacesub; 227590792Sgshapiro if (--sz <= 0) 227690792Sgshapiro break; 227764562Sgshapiro } 2278168515Sgshapiro for (q = *pvp; *q != '\0'; ) 2279168515Sgshapiro { 2280168515Sgshapiro int c; 2281168515Sgshapiro 2282168515Sgshapiro if (--sz <= 0) 2283168515Sgshapiro break; 2284168515Sgshapiro *p++ = c = *q++; 2285168515Sgshapiro 2286168515Sgshapiro /* 2287168515Sgshapiro ** If the current character (c) is METAQUOTE and we 2288168515Sgshapiro ** want the "external" form and the next character 2289168515Sgshapiro ** is not NUL, then overwrite METAQUOTE with that 2290168515Sgshapiro ** character (i.e., METAQUOTE ch is changed to 2291168515Sgshapiro ** ch). p[-1] is used because p is advanced (above). 2292168515Sgshapiro */ 2293168515Sgshapiro 2294168515Sgshapiro if ((c & 0377) == METAQUOTE && external && *q != '\0') 2295168515Sgshapiro p[-1] = *q++; 2296168515Sgshapiro } 2297132943Sgshapiro if (sz <= 0) 229890792Sgshapiro break; 229938032Speter oatomtok = natomtok; 230038032Speter if (pvp++ == evp) 230138032Speter break; 230238032Speter } 2303132943Sgshapiro 2304147078Sgshapiro#if 0 2305147078Sgshapiro /* 2306147078Sgshapiro ** Silently truncate long strings: even though this doesn't 2307147078Sgshapiro ** seem like a good idea it is necessary because header checks 2308147078Sgshapiro ** send the whole header value to rscheck() and hence rewrite(). 2309147078Sgshapiro ** The latter however sometimes uses a "short" buffer (e.g., 2310147078Sgshapiro ** cbuf[MAXNAME + 1]) to call cataddr() which then triggers this 2311147078Sgshapiro ** error function. One possible fix to the problem is to pass 2312147078Sgshapiro ** flags to rscheck() and rewrite() to distinguish the various 2313147078Sgshapiro ** calls and only trigger the error if necessary. For now just 2314147078Sgshapiro ** undo the change from 8.13.0. 2315147078Sgshapiro */ 2316147078Sgshapiro 2317132943Sgshapiro if (sz <= 0) 2318141858Sgshapiro usrerr("cataddr: string too long"); 2319147078Sgshapiro#endif 232038032Speter *p = '\0'; 2321168515Sgshapiro 2322168515Sgshapiro if (tTd(59, 14)) 2323168515Sgshapiro sm_dprintf(" cataddr => %s\n", str2prt(buf)); 232438032Speter} 2325168515Sgshapiro 232690792Sgshapiro/* 232738032Speter** SAMEADDR -- Determine if two addresses are the same 232838032Speter** 232938032Speter** This is not just a straight comparison -- if the mailer doesn't 233038032Speter** care about the host we just ignore it, etc. 233138032Speter** 233238032Speter** Parameters: 233338032Speter** a, b -- pointers to the internal forms to compare. 233438032Speter** 233538032Speter** Returns: 233690792Sgshapiro** true -- they represent the same mailbox. 233790792Sgshapiro** false -- they don't. 233838032Speter** 233938032Speter** Side Effects: 234038032Speter** none. 234138032Speter*/ 234238032Speter 234338032Speterbool 234438032Spetersameaddr(a, b) 234538032Speter register ADDRESS *a; 234638032Speter register ADDRESS *b; 234738032Speter{ 234838032Speter register ADDRESS *ca, *cb; 234938032Speter 235038032Speter /* if they don't have the same mailer, forget it */ 235138032Speter if (a->q_mailer != b->q_mailer) 235290792Sgshapiro return false; 235338032Speter 2354249729Sgshapiro /* 2355249729Sgshapiro ** Addresses resolving to error mailer 2356249729Sgshapiro ** should not be considered identical 2357249729Sgshapiro */ 2358249729Sgshapiro 2359249729Sgshapiro if (a->q_mailer == &errormailer) 2360249729Sgshapiro return false; 2361249729Sgshapiro 236238032Speter /* if the user isn't the same, we can drop out */ 236338032Speter if (strcmp(a->q_user, b->q_user) != 0) 236490792Sgshapiro return false; 236538032Speter 2366285229Sgshapiro /* do the required flags match? */ 2367285229Sgshapiro if (!ADDR_FLAGS_MATCH(a, b)) 2368285229Sgshapiro return false; 2369285229Sgshapiro 237038032Speter /* if we have good uids for both but they differ, these are different */ 237138032Speter if (a->q_mailer == ProgMailer) 237238032Speter { 237338032Speter ca = getctladdr(a); 237438032Speter cb = getctladdr(b); 237538032Speter if (ca != NULL && cb != NULL && 237638032Speter bitset(QGOODUID, ca->q_flags & cb->q_flags) && 237738032Speter ca->q_uid != cb->q_uid) 237890792Sgshapiro return false; 237938032Speter } 238038032Speter 238138032Speter /* otherwise compare hosts (but be careful for NULL ptrs) */ 238238032Speter if (a->q_host == b->q_host) 238338032Speter { 238438032Speter /* probably both null pointers */ 238590792Sgshapiro return true; 238638032Speter } 238738032Speter if (a->q_host == NULL || b->q_host == NULL) 238838032Speter { 238938032Speter /* only one is a null pointer */ 239090792Sgshapiro return false; 239138032Speter } 239238032Speter if (strcmp(a->q_host, b->q_host) != 0) 239390792Sgshapiro return false; 239438032Speter 239590792Sgshapiro return true; 239638032Speter} 239790792Sgshapiro/* 239838032Speter** PRINTADDR -- print address (for debugging) 239938032Speter** 240038032Speter** Parameters: 240138032Speter** a -- the address to print 240238032Speter** follow -- follow the q_next chain. 240338032Speter** 240438032Speter** Returns: 240538032Speter** none. 240638032Speter** 240738032Speter** Side Effects: 240838032Speter** none. 240938032Speter*/ 241038032Speter 241138032Speterstruct qflags 241238032Speter{ 241390792Sgshapiro char *qf_name; 241490792Sgshapiro unsigned long qf_bit; 241538032Speter}; 241638032Speter 2417285229Sgshapiro/* :'a,.s;^#define \(Q[A-Z]*\) .*; { "\1", \1 },; */ 241864562Sgshapirostatic struct qflags AddressFlags[] = 241938032Speter{ 242038032Speter { "QGOODUID", QGOODUID }, 242138032Speter { "QPRIMARY", QPRIMARY }, 242238032Speter { "QNOTREMOTE", QNOTREMOTE }, 242338032Speter { "QSELFREF", QSELFREF }, 242438032Speter { "QBOGUSSHELL", QBOGUSSHELL }, 242538032Speter { "QUNSAFEADDR", QUNSAFEADDR }, 242638032Speter { "QPINGONSUCCESS", QPINGONSUCCESS }, 242738032Speter { "QPINGONFAILURE", QPINGONFAILURE }, 242838032Speter { "QPINGONDELAY", QPINGONDELAY }, 242938032Speter { "QHASNOTIFY", QHASNOTIFY }, 243038032Speter { "QRELAYED", QRELAYED }, 243138032Speter { "QEXPANDED", QEXPANDED }, 243238032Speter { "QDELIVERED", QDELIVERED }, 243338032Speter { "QDELAYED", QDELAYED }, 243438032Speter { "QTHISPASS", QTHISPASS }, 2435285229Sgshapiro { "QALIAS", QALIAS }, 2436285229Sgshapiro { "QBYTRACE", QBYTRACE }, 2437285229Sgshapiro { "QBYNDELAY", QBYNDELAY }, 2438285229Sgshapiro { "QBYNRELAY", QBYNRELAY }, 2439285229Sgshapiro { "QINTBCC", QINTBCC }, 2440285229Sgshapiro { "QDYNMAILER", QDYNMAILER }, 244138032Speter { "QRCPTOK", QRCPTOK }, 244271345Sgshapiro { NULL, 0 } 244338032Speter}; 244438032Speter 244538032Spetervoid 2446132943Sgshapiroprintaddr(fp, a, follow) 2447132943Sgshapiro SM_FILE_T *fp; 244838032Speter register ADDRESS *a; 244938032Speter bool follow; 245038032Speter{ 245138032Speter register MAILER *m; 245238032Speter MAILER pseudomailer; 245338032Speter register struct qflags *qfp; 245438032Speter bool firstone; 245538032Speter 245638032Speter if (a == NULL) 245738032Speter { 2458132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "[NULL]\n"); 245938032Speter return; 246038032Speter } 246138032Speter 246238032Speter while (a != NULL) 246338032Speter { 2464132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%p=", a); 2465132943Sgshapiro (void) sm_io_flush(fp, SM_TIME_DEFAULT); 246638032Speter 246738032Speter /* find the mailer -- carefully */ 246838032Speter m = a->q_mailer; 246938032Speter if (m == NULL) 247038032Speter { 247138032Speter m = &pseudomailer; 247238032Speter m->m_mno = -1; 247338032Speter m->m_name = "NULL"; 247438032Speter } 247538032Speter 2476132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 247790792Sgshapiro "%s:\n\tmailer %d (%s), host `%s'\n", 247890792Sgshapiro a->q_paddr == NULL ? "<null>" : a->q_paddr, 247990792Sgshapiro m->m_mno, m->m_name, 248090792Sgshapiro a->q_host == NULL ? "<null>" : a->q_host); 2481132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 248290792Sgshapiro "\tuser `%s', ruser `%s'\n", 248390792Sgshapiro a->q_user, 248490792Sgshapiro a->q_ruser == NULL ? "<null>" : a->q_ruser); 2485132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\tstate="); 248664562Sgshapiro switch (a->q_state) 248764562Sgshapiro { 248864562Sgshapiro case QS_OK: 2489132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "OK"); 249064562Sgshapiro break; 249164562Sgshapiro 249264562Sgshapiro case QS_DONTSEND: 2493132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 249490792Sgshapiro "DONTSEND"); 249564562Sgshapiro break; 249664562Sgshapiro 249764562Sgshapiro case QS_BADADDR: 2498132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 249990792Sgshapiro "BADADDR"); 250064562Sgshapiro break; 250164562Sgshapiro 250264562Sgshapiro case QS_QUEUEUP: 2503132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 250490792Sgshapiro "QUEUEUP"); 250564562Sgshapiro break; 250664562Sgshapiro 250790792Sgshapiro case QS_RETRY: 2508132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "RETRY"); 250990792Sgshapiro break; 251090792Sgshapiro 251164562Sgshapiro case QS_SENT: 2512132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "SENT"); 251364562Sgshapiro break; 251464562Sgshapiro 251564562Sgshapiro case QS_VERIFIED: 2516132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 251790792Sgshapiro "VERIFIED"); 251864562Sgshapiro break; 251964562Sgshapiro 252064562Sgshapiro case QS_EXPANDED: 2521132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 252290792Sgshapiro "EXPANDED"); 252364562Sgshapiro break; 252464562Sgshapiro 252564562Sgshapiro case QS_SENDER: 2526132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 252790792Sgshapiro "SENDER"); 252864562Sgshapiro break; 252964562Sgshapiro 253064562Sgshapiro case QS_CLONED: 2531132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 253290792Sgshapiro "CLONED"); 253364562Sgshapiro break; 253464562Sgshapiro 253564562Sgshapiro case QS_DISCARDED: 2536132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 253790792Sgshapiro "DISCARDED"); 253864562Sgshapiro break; 253964562Sgshapiro 254064562Sgshapiro case QS_REPLACED: 2541132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 254290792Sgshapiro "REPLACED"); 254364562Sgshapiro break; 254464562Sgshapiro 254564562Sgshapiro case QS_REMOVED: 2546132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 254790792Sgshapiro "REMOVED"); 254864562Sgshapiro break; 254964562Sgshapiro 255064562Sgshapiro case QS_DUPLICATE: 2551132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 255290792Sgshapiro "DUPLICATE"); 255364562Sgshapiro break; 255464562Sgshapiro 255564562Sgshapiro case QS_INCLUDED: 2556132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 255790792Sgshapiro "INCLUDED"); 255864562Sgshapiro break; 255964562Sgshapiro 256064562Sgshapiro default: 2561132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 256290792Sgshapiro "%d", a->q_state); 256364562Sgshapiro break; 256464562Sgshapiro } 2565132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 256690792Sgshapiro ", next=%p, alias %p, uid %d, gid %d\n", 256790792Sgshapiro a->q_next, a->q_alias, 256890792Sgshapiro (int) a->q_uid, (int) a->q_gid); 2569132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\tflags=%lx<", 257090792Sgshapiro a->q_flags); 257190792Sgshapiro firstone = true; 257238032Speter for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++) 257338032Speter { 257438032Speter if (!bitset(qfp->qf_bit, a->q_flags)) 257538032Speter continue; 257638032Speter if (!firstone) 2577132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 257890792Sgshapiro ","); 257990792Sgshapiro firstone = false; 2580132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s", 258190792Sgshapiro qfp->qf_name); 258238032Speter } 2583132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, ">\n"); 2584132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 258590792Sgshapiro "\towner=%s, home=\"%s\", fullname=\"%s\"\n", 258690792Sgshapiro a->q_owner == NULL ? "(none)" : a->q_owner, 258790792Sgshapiro a->q_home == NULL ? "(none)" : a->q_home, 258890792Sgshapiro a->q_fullname == NULL ? "(none)" : a->q_fullname); 2589132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 259090792Sgshapiro "\torcpt=\"%s\", statmta=%s, status=%s\n", 259190792Sgshapiro a->q_orcpt == NULL ? "(none)" : a->q_orcpt, 259290792Sgshapiro a->q_statmta == NULL ? "(none)" : a->q_statmta, 259390792Sgshapiro a->q_status == NULL ? "(none)" : a->q_status); 2594132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 259590792Sgshapiro "\tfinalrcpt=\"%s\"\n", 259690792Sgshapiro a->q_finalrcpt == NULL ? "(none)" : a->q_finalrcpt); 2597132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 259890792Sgshapiro "\trstatus=\"%s\"\n", 259990792Sgshapiro a->q_rstatus == NULL ? "(none)" : a->q_rstatus); 2600132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 260190792Sgshapiro "\tstatdate=%s\n", 260290792Sgshapiro a->q_statdate == 0 ? "(none)" : ctime(&a->q_statdate)); 260338032Speter 260438032Speter if (!follow) 260538032Speter return; 260638032Speter a = a->q_next; 260738032Speter } 260838032Speter} 260990792Sgshapiro/* 261090792Sgshapiro** EMPTYADDR -- return true if this address is empty (``<>'') 261138032Speter** 261238032Speter** Parameters: 261338032Speter** a -- pointer to the address 261438032Speter** 261538032Speter** Returns: 261690792Sgshapiro** true -- if this address is "empty" (i.e., no one should 261738032Speter** ever generate replies to it. 261890792Sgshapiro** false -- if it is a "regular" (read: replyable) address. 261938032Speter*/ 262038032Speter 262138032Speterbool 262238032Speteremptyaddr(a) 262338032Speter register ADDRESS *a; 262438032Speter{ 262538032Speter return a->q_paddr == NULL || strcmp(a->q_paddr, "<>") == 0 || 262638032Speter a->q_user == NULL || strcmp(a->q_user, "<>") == 0; 262738032Speter} 262890792Sgshapiro/* 262938032Speter** REMOTENAME -- return the name relative to the current mailer 263038032Speter** 263138032Speter** Parameters: 263238032Speter** name -- the name to translate. 2633120256Sgshapiro** m -- the mailer that we want to do rewriting relative to. 263438032Speter** flags -- fine tune operations. 263538032Speter** pstat -- pointer to status word. 263638032Speter** e -- the current envelope. 263738032Speter** 263838032Speter** Returns: 263938032Speter** the text string representing this address relative to 264038032Speter** the receiving mailer. 264138032Speter** 264238032Speter** Side Effects: 264338032Speter** none. 264438032Speter** 264538032Speter** Warnings: 264638032Speter** The text string returned is tucked away locally; 264738032Speter** copy it if you intend to save it. 264838032Speter*/ 264938032Speter 265038032Speterchar * 265138032Speterremotename(name, m, flags, pstat, e) 265238032Speter char *name; 265338032Speter struct mailer *m; 265438032Speter int flags; 265538032Speter int *pstat; 265638032Speter register ENVELOPE *e; 265738032Speter{ 265838032Speter register char **pvp; 265990792Sgshapiro char *SM_NONVOLATILE fancy; 266090792Sgshapiro char *oldg; 266138032Speter int rwset; 266238032Speter static char buf[MAXNAME + 1]; 266338032Speter char lbuf[MAXNAME + 1]; 266438032Speter char pvpbuf[PSBUFSIZE]; 266564562Sgshapiro char addrtype[4]; 266638032Speter 266738032Speter if (tTd(12, 1)) 2668168515Sgshapiro { 2669168515Sgshapiro sm_dprintf("remotename("); 2670168515Sgshapiro xputs(sm_debug_file(), name); 2671168515Sgshapiro sm_dprintf(")\n"); 2672168515Sgshapiro } 267338032Speter 267438032Speter /* don't do anything if we are tagging it as special */ 267538032Speter if (bitset(RF_SENDERADDR, flags)) 267664562Sgshapiro { 267738032Speter rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset 267838032Speter : m->m_se_rwset; 267964562Sgshapiro addrtype[2] = 's'; 268064562Sgshapiro } 268138032Speter else 268264562Sgshapiro { 268338032Speter rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset 268438032Speter : m->m_re_rwset; 268564562Sgshapiro addrtype[2] = 'r'; 268664562Sgshapiro } 268738032Speter if (rwset < 0) 268864562Sgshapiro return name; 268964562Sgshapiro addrtype[1] = ' '; 269064562Sgshapiro addrtype[3] = '\0'; 269164562Sgshapiro addrtype[0] = bitset(RF_HEADERADDR, flags) ? 'h' : 'e'; 269290792Sgshapiro macdefine(&e->e_macro, A_TEMP, macid("{addr_type}"), addrtype); 269338032Speter 269438032Speter /* 269538032Speter ** Do a heuristic crack of this name to extract any comment info. 269638032Speter ** This will leave the name as a comment and a $g macro. 269738032Speter */ 269838032Speter 269938032Speter if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) 270038032Speter fancy = "\201g"; 270138032Speter else 2702111823Sgshapiro fancy = crackaddr(name, e); 270338032Speter 270438032Speter /* 270538032Speter ** Turn the name into canonical form. 270638032Speter ** Normally this will be RFC 822 style, i.e., "user@domain". 270738032Speter ** If this only resolves to "user", and the "C" flag is 270838032Speter ** specified in the sending mailer, then the sender's 270938032Speter ** domain will be appended. 271038032Speter */ 271138032Speter 2712168515Sgshapiro pvp = prescan(name, '\0', pvpbuf, sizeof(pvpbuf), NULL, NULL, false); 271338032Speter if (pvp == NULL) 271464562Sgshapiro return name; 271590792Sgshapiro if (REWRITE(pvp, 3, e) == EX_TEMPFAIL) 271638032Speter *pstat = EX_TEMPFAIL; 271738032Speter if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) 271838032Speter { 271938032Speter /* append from domain to this address */ 272038032Speter register char **pxp = pvp; 272164562Sgshapiro int l = MAXATOM; /* size of buffer for pvp */ 272238032Speter 272338032Speter /* see if there is an "@domain" in the current name */ 272438032Speter while (*pxp != NULL && strcmp(*pxp, "@") != 0) 272564562Sgshapiro { 272638032Speter pxp++; 272764562Sgshapiro --l; 272864562Sgshapiro } 272938032Speter if (*pxp == NULL) 273038032Speter { 273138032Speter /* no.... append the "@domain" from the sender */ 273238032Speter register char **qxq = e->e_fromdomain; 273338032Speter 273438032Speter while ((*pxp++ = *qxq++) != NULL) 273564562Sgshapiro { 273664562Sgshapiro if (--l <= 0) 273764562Sgshapiro { 273864562Sgshapiro *--pxp = NULL; 273964562Sgshapiro usrerr("553 5.1.0 remotename: too many tokens"); 274064562Sgshapiro *pstat = EX_UNAVAILABLE; 274164562Sgshapiro break; 274264562Sgshapiro } 274364562Sgshapiro } 274490792Sgshapiro if (REWRITE(pvp, 3, e) == EX_TEMPFAIL) 274538032Speter *pstat = EX_TEMPFAIL; 274638032Speter } 274738032Speter } 274838032Speter 274938032Speter /* 275038032Speter ** Do more specific rewriting. 275138032Speter ** Rewrite using ruleset 1 or 2 depending on whether this is 275238032Speter ** a sender address or not. 275338032Speter ** Then run it through any receiving-mailer-specific rulesets. 275438032Speter */ 275538032Speter 275638032Speter if (bitset(RF_SENDERADDR, flags)) 275738032Speter { 275890792Sgshapiro if (REWRITE(pvp, 1, e) == EX_TEMPFAIL) 275938032Speter *pstat = EX_TEMPFAIL; 276038032Speter } 276138032Speter else 276238032Speter { 276390792Sgshapiro if (REWRITE(pvp, 2, e) == EX_TEMPFAIL) 276438032Speter *pstat = EX_TEMPFAIL; 276538032Speter } 276638032Speter if (rwset > 0) 276738032Speter { 276890792Sgshapiro if (REWRITE(pvp, rwset, e) == EX_TEMPFAIL) 276938032Speter *pstat = EX_TEMPFAIL; 277038032Speter } 277138032Speter 277238032Speter /* 277338032Speter ** Do any final sanitation the address may require. 277438032Speter ** This will normally be used to turn internal forms 277538032Speter ** (e.g., user@host.LOCAL) into external form. This 277638032Speter ** may be used as a default to the above rules. 277738032Speter */ 277838032Speter 277990792Sgshapiro if (REWRITE(pvp, 4, e) == EX_TEMPFAIL) 278038032Speter *pstat = EX_TEMPFAIL; 278138032Speter 278238032Speter /* 278338032Speter ** Now restore the comment information we had at the beginning. 278438032Speter */ 278538032Speter 2786168515Sgshapiro cataddr(pvp, NULL, lbuf, sizeof(lbuf), '\0', false); 278790792Sgshapiro oldg = macget(&e->e_macro, 'g'); 278890792Sgshapiro macset(&e->e_macro, 'g', lbuf); 278938032Speter 279090792Sgshapiro SM_TRY 279190792Sgshapiro /* need to make sure route-addrs have <angle brackets> */ 279290792Sgshapiro if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@') 2793168515Sgshapiro expand("<\201g>", buf, sizeof(buf), e); 279490792Sgshapiro else 2795168515Sgshapiro expand(fancy, buf, sizeof(buf), e); 279690792Sgshapiro SM_FINALLY 279790792Sgshapiro macset(&e->e_macro, 'g', oldg); 279890792Sgshapiro SM_END_TRY 279938032Speter 280038032Speter if (tTd(12, 1)) 2801168515Sgshapiro { 2802168515Sgshapiro sm_dprintf("remotename => `"); 2803168515Sgshapiro xputs(sm_debug_file(), buf); 2804285229Sgshapiro sm_dprintf("', stat=%d\n", *pstat); 2805168515Sgshapiro } 280664562Sgshapiro return buf; 280738032Speter} 280890792Sgshapiro/* 280938032Speter** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 281038032Speter** 281138032Speter** Parameters: 281238032Speter** a -- the address to map (but just the user name part). 281338032Speter** sendq -- the sendq in which to install any replacement 281438032Speter** addresses. 281538032Speter** aliaslevel -- the alias nesting depth. 281638032Speter** e -- the envelope. 281738032Speter** 281838032Speter** Returns: 281938032Speter** none. 282038032Speter*/ 282138032Speter 282238032Speter#define Q_COPYFLAGS (QPRIMARY|QBOGUSSHELL|QUNSAFEADDR|\ 282338032Speter Q_PINGFLAGS|QHASNOTIFY|\ 282490792Sgshapiro QRELAYED|QEXPANDED|QDELIVERED|QDELAYED|\ 282590792Sgshapiro QBYTRACE|QBYNDELAY|QBYNRELAY) 282638032Speter 282738032Spetervoid 282838032Spetermaplocaluser(a, sendq, aliaslevel, e) 282938032Speter register ADDRESS *a; 283038032Speter ADDRESS **sendq; 283138032Speter int aliaslevel; 283238032Speter ENVELOPE *e; 283338032Speter{ 283438032Speter register char **pvp; 283590792Sgshapiro register ADDRESS *SM_NONVOLATILE a1 = NULL; 283638032Speter char pvpbuf[PSBUFSIZE]; 283738032Speter 283838032Speter if (tTd(29, 1)) 283938032Speter { 284090792Sgshapiro sm_dprintf("maplocaluser: "); 2841132943Sgshapiro printaddr(sm_debug_file(), a, false); 284238032Speter } 2843168515Sgshapiro pvp = prescan(a->q_user, '\0', pvpbuf, sizeof(pvpbuf), NULL, NULL, 2844168515Sgshapiro false); 284538032Speter if (pvp == NULL) 284638032Speter { 284738032Speter if (tTd(29, 9)) 284890792Sgshapiro sm_dprintf("maplocaluser: cannot prescan %s\n", 284964562Sgshapiro a->q_user); 285038032Speter return; 285138032Speter } 285238032Speter 285390792Sgshapiro macdefine(&e->e_macro, A_PERM, 'h', a->q_host); 285490792Sgshapiro macdefine(&e->e_macro, A_PERM, 'u', a->q_user); 285590792Sgshapiro macdefine(&e->e_macro, A_PERM, 'z', a->q_home); 285664562Sgshapiro 285790792Sgshapiro macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e r"); 285890792Sgshapiro if (REWRITE(pvp, 5, e) == EX_TEMPFAIL) 285938032Speter { 286038032Speter if (tTd(29, 9)) 286190792Sgshapiro sm_dprintf("maplocaluser: rewrite tempfail\n"); 286264562Sgshapiro a->q_state = QS_QUEUEUP; 286338032Speter a->q_status = "4.4.3"; 286438032Speter return; 286538032Speter } 286638032Speter if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 286738032Speter { 286838032Speter if (tTd(29, 9)) 286990792Sgshapiro sm_dprintf("maplocaluser: doesn't resolve\n"); 287038032Speter return; 287138032Speter } 287238032Speter 287390792Sgshapiro SM_TRY 287490792Sgshapiro a1 = buildaddr(pvp, NULL, 0, e); 287590792Sgshapiro SM_EXCEPT(exc, "E:mta.quickabort") 287690792Sgshapiro 287790792Sgshapiro /* 287890792Sgshapiro ** mark address as bad, S5 returned an error 287990792Sgshapiro ** and we gave that back to the SMTP client. 288090792Sgshapiro */ 288190792Sgshapiro 288290792Sgshapiro a->q_state = QS_DONTSEND; 288390792Sgshapiro sm_exc_raisenew_x(&EtypeQuickAbort, 2); 288490792Sgshapiro SM_END_TRY 288590792Sgshapiro 288638032Speter /* if non-null, mailer destination specified -- has it changed? */ 288738032Speter if (a1 == NULL || sameaddr(a, a1)) 288838032Speter { 288938032Speter if (tTd(29, 9)) 289090792Sgshapiro sm_dprintf("maplocaluser: address unchanged\n"); 289138032Speter return; 289238032Speter } 289338032Speter 289438032Speter /* make new address take on flags and print attributes of old */ 289538032Speter a1->q_flags &= ~Q_COPYFLAGS; 289638032Speter a1->q_flags |= a->q_flags & Q_COPYFLAGS; 289790792Sgshapiro a1->q_paddr = sm_rpool_strdup_x(e->e_rpool, a->q_paddr); 289890792Sgshapiro a1->q_finalrcpt = a->q_finalrcpt; 289964562Sgshapiro a1->q_orcpt = a->q_orcpt; 290038032Speter 290138032Speter /* mark old address as dead; insert new address */ 290264562Sgshapiro a->q_state = QS_REPLACED; 290338032Speter if (tTd(29, 5)) 290438032Speter { 290590792Sgshapiro sm_dprintf("maplocaluser: QS_REPLACED "); 2906132943Sgshapiro printaddr(sm_debug_file(), a, false); 290738032Speter } 290838032Speter a1->q_alias = a; 290990792Sgshapiro allocaddr(a1, RF_COPYALL, sm_rpool_strdup_x(e->e_rpool, a->q_paddr), e); 291038032Speter (void) recipient(a1, sendq, aliaslevel, e); 291138032Speter} 291290792Sgshapiro/* 291338032Speter** DEQUOTE_INIT -- initialize dequote map 291438032Speter** 291538032Speter** Parameters: 291638032Speter** map -- the internal map structure. 291738032Speter** args -- arguments. 291838032Speter** 291938032Speter** Returns: 292090792Sgshapiro** true. 292138032Speter*/ 292238032Speter 292338032Speterbool 292438032Speterdequote_init(map, args) 292538032Speter MAP *map; 292638032Speter char *args; 292738032Speter{ 292838032Speter register char *p = args; 292938032Speter 293064562Sgshapiro /* there is no check whether there is really an argument */ 293138032Speter map->map_mflags |= MF_KEEPQUOTES; 293238032Speter for (;;) 293338032Speter { 293438032Speter while (isascii(*p) && isspace(*p)) 293538032Speter p++; 293638032Speter if (*p != '-') 293738032Speter break; 293838032Speter switch (*++p) 293938032Speter { 294038032Speter case 'a': 294138032Speter map->map_app = ++p; 294238032Speter break; 294338032Speter 294464562Sgshapiro case 'D': 294564562Sgshapiro map->map_mflags |= MF_DEFER; 294664562Sgshapiro break; 294764562Sgshapiro 294864562Sgshapiro case 'S': 294938032Speter case 's': 295064562Sgshapiro map->map_spacesub = *++p; 295138032Speter break; 295238032Speter } 295338032Speter while (*p != '\0' && !(isascii(*p) && isspace(*p))) 295438032Speter p++; 295538032Speter if (*p != '\0') 295638032Speter *p = '\0'; 295738032Speter } 295838032Speter if (map->map_app != NULL) 295938032Speter map->map_app = newstr(map->map_app); 296038032Speter 296190792Sgshapiro return true; 296238032Speter} 296390792Sgshapiro/* 296438032Speter** DEQUOTE_MAP -- unquote an address 296538032Speter** 296638032Speter** Parameters: 296738032Speter** map -- the internal map structure (ignored). 296838032Speter** name -- the name to dequote. 296938032Speter** av -- arguments (ignored). 297038032Speter** statp -- pointer to status out-parameter. 297138032Speter** 297238032Speter** Returns: 297338032Speter** NULL -- if there were no quotes, or if the resulting 297438032Speter** unquoted buffer would not be acceptable to prescan. 297538032Speter** else -- The dequoted buffer. 297638032Speter*/ 297738032Speter 297838032Speter/* ARGSUSED2 */ 297938032Speterchar * 298038032Speterdequote_map(map, name, av, statp) 298138032Speter MAP *map; 298238032Speter char *name; 298338032Speter char **av; 298438032Speter int *statp; 298538032Speter{ 298638032Speter register char *p; 298738032Speter register char *q; 298838032Speter register char c; 298938032Speter int anglecnt = 0; 299038032Speter int cmntcnt = 0; 299138032Speter int quotecnt = 0; 299238032Speter int spacecnt = 0; 299390792Sgshapiro bool quotemode = false; 299490792Sgshapiro bool bslashmode = false; 299564562Sgshapiro char spacesub = map->map_spacesub; 299638032Speter 299738032Speter for (p = q = name; (c = *p++) != '\0'; ) 299838032Speter { 299938032Speter if (bslashmode) 300038032Speter { 300190792Sgshapiro bslashmode = false; 300238032Speter *q++ = c; 300338032Speter continue; 300438032Speter } 300538032Speter 300638032Speter if (c == ' ' && spacesub != '\0') 300738032Speter c = spacesub; 300838032Speter 300938032Speter switch (c) 301038032Speter { 301138032Speter case '\\': 301290792Sgshapiro bslashmode = true; 301338032Speter break; 301438032Speter 301538032Speter case '(': 301638032Speter cmntcnt++; 301738032Speter break; 301838032Speter 301938032Speter case ')': 302038032Speter if (cmntcnt-- <= 0) 302138032Speter return NULL; 302238032Speter break; 302338032Speter 302438032Speter case ' ': 302564562Sgshapiro case '\t': 302638032Speter spacecnt++; 302738032Speter break; 302838032Speter } 302938032Speter 303038032Speter if (cmntcnt > 0) 303138032Speter { 303238032Speter *q++ = c; 303338032Speter continue; 303438032Speter } 303538032Speter 303638032Speter switch (c) 303738032Speter { 303838032Speter case '"': 303938032Speter quotemode = !quotemode; 304038032Speter quotecnt++; 304138032Speter continue; 304238032Speter 304338032Speter case '<': 304438032Speter anglecnt++; 304538032Speter break; 304638032Speter 304738032Speter case '>': 304838032Speter if (anglecnt-- <= 0) 304938032Speter return NULL; 305038032Speter break; 305138032Speter } 305238032Speter *q++ = c; 305338032Speter } 305438032Speter 305538032Speter if (anglecnt != 0 || cmntcnt != 0 || bslashmode || 305638032Speter quotemode || quotecnt <= 0 || spacecnt != 0) 305738032Speter return NULL; 305838032Speter *q++ = '\0'; 305938032Speter return map_rewrite(map, name, strlen(name), NULL); 306038032Speter} 306190792Sgshapiro/* 306238032Speter** RSCHECK -- check string(s) for validity using rewriting sets 306338032Speter** 306438032Speter** Parameters: 306538032Speter** rwset -- the rewriting set to use. 306638032Speter** p1 -- the first string to check. 306738032Speter** p2 -- the second string to check -- may be null. 306838032Speter** e -- the current envelope. 3069102528Sgshapiro** flags -- control some behavior, see RSF_ in sendmail.h 307090792Sgshapiro** logl -- logging level. 307171345Sgshapiro** host -- NULL or relay host. 307290792Sgshapiro** logid -- id for sm_syslog. 3073168515Sgshapiro** addr -- if not NULL and ruleset returns $#error: 3074168515Sgshapiro** store mailer triple here. 3075285229Sgshapiro** addrstr -- if not NULL and ruleset does not return $#: 3076285229Sgshapiro** address string 307738032Speter** 307838032Speter** Returns: 307938032Speter** EX_OK -- if the rwset doesn't resolve to $#error 308038032Speter** else -- the failure status (message printed) 308138032Speter*/ 308238032Speter 308338032Speterint 3084285229Sgshapirorscheck(rwset, p1, p2, e, flags, logl, host, logid, addr, addrstr) 308538032Speter char *rwset; 308638032Speter char *p1; 308738032Speter char *p2; 308838032Speter ENVELOPE *e; 3089102528Sgshapiro int flags; 309064562Sgshapiro int logl; 309171345Sgshapiro char *host; 309290792Sgshapiro char *logid; 3093168515Sgshapiro ADDRESS *addr; 3094285229Sgshapiro char **addrstr; 309538032Speter{ 309690792Sgshapiro char *volatile buf; 3097157001Sgshapiro size_t bufsize; 309838032Speter int saveexitstat; 309990792Sgshapiro int volatile rstat = EX_OK; 310038032Speter char **pvp; 310138032Speter int rsno; 310290792Sgshapiro bool volatile discard = false; 310338032Speter bool saveQuickAbort = QuickAbort; 310438032Speter bool saveSuprErrs = SuprErrs; 310590792Sgshapiro bool quarantine = false; 310690792Sgshapiro char ubuf[BUFSIZ * 2]; 310738032Speter char buf0[MAXLINE]; 310838032Speter char pvpbuf[PSBUFSIZE]; 310938032Speter extern char MsgBuf[]; 311038032Speter 311138032Speter if (tTd(48, 2)) 311290792Sgshapiro sm_dprintf("rscheck(%s, %s, %s)\n", rwset, p1, 311338032Speter p2 == NULL ? "(NULL)" : p2); 311438032Speter 311538032Speter rsno = strtorwset(rwset, NULL, ST_FIND); 311638032Speter if (rsno < 0) 311738032Speter return EX_OK; 311838032Speter 311938032Speter if (p2 != NULL) 312038032Speter { 312138032Speter bufsize = strlen(p1) + strlen(p2) + 2; 3122168515Sgshapiro if (bufsize > sizeof(buf0)) 312390792Sgshapiro buf = sm_malloc_x(bufsize); 312438032Speter else 312538032Speter { 312638032Speter buf = buf0; 3127168515Sgshapiro bufsize = sizeof(buf0); 312838032Speter } 312990792Sgshapiro (void) sm_snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2); 313038032Speter } 313138032Speter else 313238032Speter { 313338032Speter bufsize = strlen(p1) + 1; 3134168515Sgshapiro if (bufsize > sizeof(buf0)) 313590792Sgshapiro buf = sm_malloc_x(bufsize); 313638032Speter else 313738032Speter { 313838032Speter buf = buf0; 3139168515Sgshapiro bufsize = sizeof(buf0); 314038032Speter } 314190792Sgshapiro (void) sm_strlcpy(buf, p1, bufsize); 314238032Speter } 314390792Sgshapiro SM_TRY 314438032Speter { 314590792Sgshapiro SuprErrs = true; 314690792Sgshapiro QuickAbort = false; 3147168515Sgshapiro pvp = prescan(buf, '\0', pvpbuf, sizeof(pvpbuf), NULL, 3148168515Sgshapiro bitset(RSF_RMCOMM, flags) ? 3149168515Sgshapiro IntTokenTab : TokTypeNoC, 3150132943Sgshapiro bitset(RSF_RMCOMM, flags) ? false : true); 315190792Sgshapiro SuprErrs = saveSuprErrs; 315290792Sgshapiro if (pvp == NULL) 315390792Sgshapiro { 315490792Sgshapiro if (tTd(48, 2)) 315590792Sgshapiro sm_dprintf("rscheck: cannot prescan input\n"); 315690792Sgshapiro /* 315790792Sgshapiro syserr("rscheck: cannot prescan input: \"%s\"", 315890792Sgshapiro shortenstring(buf, MAXSHORTSTR)); 315990792Sgshapiro rstat = EX_DATAERR; 316090792Sgshapiro */ 316190792Sgshapiro goto finis; 316290792Sgshapiro } 3163102528Sgshapiro if (bitset(RSF_UNSTRUCTURED, flags)) 3164102528Sgshapiro SuprErrs = true; 316590792Sgshapiro (void) REWRITE(pvp, rsno, e); 3166102528Sgshapiro if (bitset(RSF_UNSTRUCTURED, flags)) 3167102528Sgshapiro SuprErrs = saveSuprErrs; 3168285229Sgshapiro 3169285229Sgshapiro if (pvp[0] != NULL && (pvp[0][0] & 0377) != CANONNET && 3170285229Sgshapiro bitset(RSF_ADDR, flags) && addrstr != NULL) 3171285229Sgshapiro { 3172285229Sgshapiro cataddr(&(pvp[0]), NULL, ubuf, sizeof(ubuf), 3173285229Sgshapiro bitset(RSF_STRING, flags) ? NOSPACESEP : ' ', 3174285229Sgshapiro true); 3175285229Sgshapiro *addrstr = sm_rpool_strdup_x(e->e_rpool, ubuf); 3176285229Sgshapiro goto finis; 3177285229Sgshapiro } 3178285229Sgshapiro 317990792Sgshapiro if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET || 318090792Sgshapiro pvp[1] == NULL || (strcmp(pvp[1], "error") != 0 && 318190792Sgshapiro strcmp(pvp[1], "discard") != 0)) 318290792Sgshapiro { 318390792Sgshapiro goto finis; 318490792Sgshapiro } 318566494Sgshapiro 318690792Sgshapiro if (strcmp(pvp[1], "discard") == 0) 318790792Sgshapiro { 318890792Sgshapiro if (tTd(48, 2)) 318990792Sgshapiro sm_dprintf("rscheck: discard mailer selected\n"); 319090792Sgshapiro e->e_flags |= EF_DISCARD; 319190792Sgshapiro discard = true; 319290792Sgshapiro } 319390792Sgshapiro else if (strcmp(pvp[1], "error") == 0 && 319490792Sgshapiro pvp[2] != NULL && (pvp[2][0] & 0377) == CANONHOST && 319590792Sgshapiro pvp[3] != NULL && strcmp(pvp[3], "quarantine") == 0) 319690792Sgshapiro { 319790792Sgshapiro if (pvp[4] == NULL || 319890792Sgshapiro (pvp[4][0] & 0377) != CANONUSER || 319990792Sgshapiro pvp[5] == NULL) 320090792Sgshapiro e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, 320190792Sgshapiro rwset); 320290792Sgshapiro else 320390792Sgshapiro { 320490792Sgshapiro cataddr(&(pvp[5]), NULL, ubuf, 3205168515Sgshapiro sizeof(ubuf), ' ', true); 320690792Sgshapiro e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, 320790792Sgshapiro ubuf); 320890792Sgshapiro } 320990792Sgshapiro macdefine(&e->e_macro, A_PERM, 321090792Sgshapiro macid("{quarantine}"), e->e_quarmsg); 321190792Sgshapiro quarantine = true; 321290792Sgshapiro } 321390792Sgshapiro else 321490792Sgshapiro { 3215168515Sgshapiro auto ADDRESS a1; 321690792Sgshapiro int savelogusrerrs = LogUsrErrs; 321790792Sgshapiro static bool logged = false; 321890792Sgshapiro 321990792Sgshapiro /* got an error -- process it */ 322090792Sgshapiro saveexitstat = ExitStat; 322190792Sgshapiro LogUsrErrs = false; 322290792Sgshapiro (void) buildaddr(pvp, &a1, 0, e); 3223168515Sgshapiro if (addr != NULL) 3224168515Sgshapiro { 3225168515Sgshapiro addr->q_mailer = a1.q_mailer; 3226168515Sgshapiro addr->q_user = a1.q_user; 3227168515Sgshapiro addr->q_host = a1.q_host; 3228168515Sgshapiro } 322990792Sgshapiro LogUsrErrs = savelogusrerrs; 323090792Sgshapiro rstat = ExitStat; 323190792Sgshapiro ExitStat = saveexitstat; 323290792Sgshapiro if (!logged) 323390792Sgshapiro { 3234102528Sgshapiro if (bitset(RSF_COUNT, flags)) 323590792Sgshapiro markstats(e, &a1, STATS_REJECT); 323690792Sgshapiro logged = true; 323790792Sgshapiro } 323890792Sgshapiro } 323990792Sgshapiro 324090792Sgshapiro if (LogLevel > logl) 324190792Sgshapiro { 324290792Sgshapiro char *relay; 324390792Sgshapiro char *p; 324490792Sgshapiro char lbuf[MAXLINE]; 324590792Sgshapiro 324690792Sgshapiro p = lbuf; 324790792Sgshapiro if (p2 != NULL) 324890792Sgshapiro { 324990792Sgshapiro (void) sm_snprintf(p, SPACELEFT(lbuf, p), 325090792Sgshapiro ", arg2=%s", 325190792Sgshapiro p2); 325290792Sgshapiro p += strlen(p); 325390792Sgshapiro } 325490792Sgshapiro 325590792Sgshapiro if (host != NULL) 325690792Sgshapiro relay = host; 325790792Sgshapiro else 325890792Sgshapiro relay = macvalue('_', e); 325990792Sgshapiro if (relay != NULL) 326090792Sgshapiro { 326190792Sgshapiro (void) sm_snprintf(p, SPACELEFT(lbuf, p), 326290792Sgshapiro ", relay=%s", relay); 326390792Sgshapiro p += strlen(p); 326490792Sgshapiro } 326590792Sgshapiro *p = '\0'; 326690792Sgshapiro if (discard) 326790792Sgshapiro sm_syslog(LOG_NOTICE, logid, 326890792Sgshapiro "ruleset=%s, arg1=%s%s, discard", 326990792Sgshapiro rwset, p1, lbuf); 327090792Sgshapiro else if (quarantine) 327190792Sgshapiro sm_syslog(LOG_NOTICE, logid, 327290792Sgshapiro "ruleset=%s, arg1=%s%s, quarantine=%s", 327390792Sgshapiro rwset, p1, lbuf, ubuf); 327490792Sgshapiro else 327590792Sgshapiro sm_syslog(LOG_NOTICE, logid, 327690792Sgshapiro "ruleset=%s, arg1=%s%s, reject=%s", 327790792Sgshapiro rwset, p1, lbuf, MsgBuf); 327890792Sgshapiro } 327990792Sgshapiro 328090792Sgshapiro finis: ; 328173188Sgshapiro } 328290792Sgshapiro SM_FINALLY 328338032Speter { 328490792Sgshapiro /* clean up */ 328590792Sgshapiro if (buf != buf0) 328690792Sgshapiro sm_free(buf); 328790792Sgshapiro QuickAbort = saveQuickAbort; 328838032Speter } 328990792Sgshapiro SM_END_TRY 329038032Speter 329190792Sgshapiro setstat(rstat); 329290792Sgshapiro 329390792Sgshapiro /* rulesets don't set errno */ 329490792Sgshapiro errno = 0; 329590792Sgshapiro if (rstat != EX_OK && QuickAbort) 329690792Sgshapiro sm_exc_raisenew_x(&EtypeQuickAbort, 2); 329790792Sgshapiro return rstat; 329890792Sgshapiro} 329990792Sgshapiro/* 330090792Sgshapiro** RSCAP -- call rewriting set to return capabilities 330190792Sgshapiro** 330290792Sgshapiro** Parameters: 330390792Sgshapiro** rwset -- the rewriting set to use. 330490792Sgshapiro** p1 -- the first string to check. 330590792Sgshapiro** p2 -- the second string to check -- may be null. 330690792Sgshapiro** e -- the current envelope. 330790792Sgshapiro** pvp -- pointer to token vector. 330890792Sgshapiro** pvpbuf -- buffer space. 3309120256Sgshapiro** size -- size of buffer space. 331090792Sgshapiro** 331190792Sgshapiro** Returns: 331290792Sgshapiro** EX_UNAVAILABLE -- ruleset doesn't exist. 331390792Sgshapiro** EX_DATAERR -- prescan() failed. 331490792Sgshapiro** EX_OK -- rewrite() was successful. 331590792Sgshapiro** else -- return status from rewrite(). 331690792Sgshapiro*/ 331790792Sgshapiro 331890792Sgshapiroint 331990792Sgshapirorscap(rwset, p1, p2, e, pvp, pvpbuf, size) 332090792Sgshapiro char *rwset; 332190792Sgshapiro char *p1; 332290792Sgshapiro char *p2; 332390792Sgshapiro ENVELOPE *e; 332490792Sgshapiro char ***pvp; 332590792Sgshapiro char *pvpbuf; 332690792Sgshapiro int size; 332790792Sgshapiro{ 332890792Sgshapiro char *volatile buf; 3329157001Sgshapiro size_t bufsize; 333090792Sgshapiro int volatile rstat = EX_OK; 333190792Sgshapiro int rsno; 333290792Sgshapiro bool saveQuickAbort = QuickAbort; 333390792Sgshapiro bool saveSuprErrs = SuprErrs; 333490792Sgshapiro char buf0[MAXLINE]; 333590792Sgshapiro extern char MsgBuf[]; 333690792Sgshapiro 333790792Sgshapiro if (tTd(48, 2)) 333890792Sgshapiro sm_dprintf("rscap(%s, %s, %s)\n", rwset, p1, 333990792Sgshapiro p2 == NULL ? "(NULL)" : p2); 334090792Sgshapiro 3341159609Sgshapiro SM_REQUIRE(pvp != NULL); 334290792Sgshapiro rsno = strtorwset(rwset, NULL, ST_FIND); 334390792Sgshapiro if (rsno < 0) 334490792Sgshapiro return EX_UNAVAILABLE; 334590792Sgshapiro 334690792Sgshapiro if (p2 != NULL) 334738032Speter { 334890792Sgshapiro bufsize = strlen(p1) + strlen(p2) + 2; 3349168515Sgshapiro if (bufsize > sizeof(buf0)) 335090792Sgshapiro buf = sm_malloc_x(bufsize); 335190792Sgshapiro else 335290792Sgshapiro { 335390792Sgshapiro buf = buf0; 3354168515Sgshapiro bufsize = sizeof(buf0); 335590792Sgshapiro } 335690792Sgshapiro (void) sm_snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2); 335738032Speter } 335864562Sgshapiro else 335938032Speter { 336090792Sgshapiro bufsize = strlen(p1) + 1; 3361168515Sgshapiro if (bufsize > sizeof(buf0)) 336290792Sgshapiro buf = sm_malloc_x(bufsize); 336390792Sgshapiro else 336438032Speter { 336590792Sgshapiro buf = buf0; 3366168515Sgshapiro bufsize = sizeof(buf0); 336738032Speter } 336890792Sgshapiro (void) sm_strlcpy(buf, p1, bufsize); 336938032Speter } 337090792Sgshapiro SM_TRY 337138032Speter { 337290792Sgshapiro SuprErrs = true; 337390792Sgshapiro QuickAbort = false; 3374168515Sgshapiro *pvp = prescan(buf, '\0', pvpbuf, size, NULL, IntTokenTab, 3375168515Sgshapiro false); 337690792Sgshapiro if (*pvp != NULL) 3377120256Sgshapiro rstat = rewrite(*pvp, rsno, 0, e, size); 337871345Sgshapiro else 337938032Speter { 338090792Sgshapiro if (tTd(48, 2)) 338190792Sgshapiro sm_dprintf("rscap: cannot prescan input\n"); 338290792Sgshapiro rstat = EX_DATAERR; 338338032Speter } 338438032Speter } 338590792Sgshapiro SM_FINALLY 338690792Sgshapiro { 338790792Sgshapiro /* clean up */ 338890792Sgshapiro if (buf != buf0) 338990792Sgshapiro sm_free(buf); 339090792Sgshapiro SuprErrs = saveSuprErrs; 339190792Sgshapiro QuickAbort = saveQuickAbort; 339238032Speter 339390792Sgshapiro /* prevent information leak, this may contain rewrite error */ 339490792Sgshapiro MsgBuf[0] = '\0'; 339590792Sgshapiro } 339690792Sgshapiro SM_END_TRY 339738032Speter return rstat; 339838032Speter} 3399