1c2aa98e2SPeter Wemm /* 213d88268SGregory Neil Shapiro * Copyright (c) 1998-2005 Sendmail, Inc. and its suppliers. 306f25ae9SGregory Neil Shapiro * All rights reserved. 4c2aa98e2SPeter Wemm * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 5c2aa98e2SPeter Wemm * Copyright (c) 1988, 1993 6c2aa98e2SPeter Wemm * The Regents of the University of California. All rights reserved. 7c2aa98e2SPeter Wemm * 8c2aa98e2SPeter Wemm * By using this file, you agree to the terms and conditions set 9c2aa98e2SPeter Wemm * forth in the LICENSE file which can be found at the top level of 10c2aa98e2SPeter Wemm * the sendmail distribution. 11c2aa98e2SPeter Wemm * 12c2aa98e2SPeter Wemm */ 13c2aa98e2SPeter Wemm 1406f25ae9SGregory Neil Shapiro #include <sendmail.h> 1506f25ae9SGregory Neil Shapiro 16af9557fdSGregory Neil Shapiro SM_RCSID("@(#)$Id: parseaddr.c,v 8.384 2006/04/18 01:28:47 ca Exp $") 1740266059SGregory Neil Shapiro 1840266059SGregory Neil Shapiro static void allocaddr __P((ADDRESS *, int, char *, ENVELOPE *)); 1906f25ae9SGregory Neil Shapiro static int callsubr __P((char**, int, ENVELOPE *)); 2006f25ae9SGregory Neil Shapiro static char *map_lookup __P((STAB *, char *, char **, int *, ENVELOPE *)); 2106f25ae9SGregory Neil Shapiro static ADDRESS *buildaddr __P((char **, ADDRESS *, int, ENVELOPE *)); 22605302a5SGregory Neil Shapiro static bool hasctrlchar __P((register char *, bool, bool)); 23605302a5SGregory Neil Shapiro 24605302a5SGregory Neil Shapiro /* replacement for illegal characters in addresses */ 25605302a5SGregory Neil Shapiro #define BAD_CHAR_REPLACEMENT '?' 26c2aa98e2SPeter Wemm 27c2aa98e2SPeter Wemm /* 28c2aa98e2SPeter Wemm ** PARSEADDR -- Parse an address 29c2aa98e2SPeter Wemm ** 30c2aa98e2SPeter Wemm ** Parses an address and breaks it up into three parts: a 31c2aa98e2SPeter Wemm ** net to transmit the message on, the host to transmit it 32c2aa98e2SPeter Wemm ** to, and a user on that host. These are loaded into an 33c2aa98e2SPeter Wemm ** ADDRESS header with the values squirreled away if necessary. 34c2aa98e2SPeter Wemm ** The "user" part may not be a real user; the process may 35c2aa98e2SPeter Wemm ** just reoccur on that machine. For example, on a machine 36c2aa98e2SPeter Wemm ** with an arpanet connection, the address 37c2aa98e2SPeter Wemm ** csvax.bill@berkeley 38c2aa98e2SPeter Wemm ** will break up to a "user" of 'csvax.bill' and a host 39c2aa98e2SPeter Wemm ** of 'berkeley' -- to be transmitted over the arpanet. 40c2aa98e2SPeter Wemm ** 41c2aa98e2SPeter Wemm ** Parameters: 42c2aa98e2SPeter Wemm ** addr -- the address to parse. 43c2aa98e2SPeter Wemm ** a -- a pointer to the address descriptor buffer. 4440266059SGregory Neil Shapiro ** If NULL, an address will be created. 45c2aa98e2SPeter Wemm ** flags -- describe detail for parsing. See RF_ definitions 46c2aa98e2SPeter Wemm ** in sendmail.h. 47c2aa98e2SPeter Wemm ** delim -- the character to terminate the address, passed 48c2aa98e2SPeter Wemm ** to prescan. 49c2aa98e2SPeter Wemm ** delimptr -- if non-NULL, set to the location of the 50c2aa98e2SPeter Wemm ** delim character that was found. 51c2aa98e2SPeter Wemm ** e -- the envelope that will contain this address. 5240266059SGregory Neil Shapiro ** isrcpt -- true if the address denotes a recipient; false 5340266059SGregory Neil Shapiro ** indicates a sender. 54c2aa98e2SPeter Wemm ** 55c2aa98e2SPeter Wemm ** Returns: 56c2aa98e2SPeter Wemm ** A pointer to the address descriptor header (`a' if 57c2aa98e2SPeter Wemm ** `a' is non-NULL). 58c2aa98e2SPeter Wemm ** NULL on error. 59c2aa98e2SPeter Wemm ** 60c2aa98e2SPeter Wemm ** Side Effects: 6140266059SGregory Neil Shapiro ** e->e_to = addr 62c2aa98e2SPeter Wemm */ 63c2aa98e2SPeter Wemm 64c2aa98e2SPeter Wemm /* following delimiters are inherent to the internal algorithms */ 65c2aa98e2SPeter Wemm #define DELIMCHARS "()<>,;\r\n" /* default word delimiters */ 66c2aa98e2SPeter Wemm 67c2aa98e2SPeter Wemm ADDRESS * 6840266059SGregory Neil Shapiro parseaddr(addr, a, flags, delim, delimptr, e, isrcpt) 69c2aa98e2SPeter Wemm char *addr; 70c2aa98e2SPeter Wemm register ADDRESS *a; 71c2aa98e2SPeter Wemm int flags; 72c2aa98e2SPeter Wemm int delim; 73c2aa98e2SPeter Wemm char **delimptr; 74c2aa98e2SPeter Wemm register ENVELOPE *e; 7540266059SGregory Neil Shapiro bool isrcpt; 76c2aa98e2SPeter Wemm { 7740266059SGregory Neil Shapiro char **pvp; 78c2aa98e2SPeter Wemm auto char *delimptrbuf; 7906f25ae9SGregory Neil Shapiro bool qup; 80c2aa98e2SPeter Wemm char pvpbuf[PSBUFSIZE]; 81c2aa98e2SPeter Wemm 82c2aa98e2SPeter Wemm /* 83c2aa98e2SPeter Wemm ** Initialize and prescan address. 84c2aa98e2SPeter Wemm */ 85c2aa98e2SPeter Wemm 86c2aa98e2SPeter Wemm e->e_to = addr; 87c2aa98e2SPeter Wemm if (tTd(20, 1)) 8840266059SGregory Neil Shapiro sm_dprintf("\n--parseaddr(%s)\n", addr); 89c2aa98e2SPeter Wemm 90c2aa98e2SPeter Wemm if (delimptr == NULL) 91c2aa98e2SPeter Wemm delimptr = &delimptrbuf; 92c2aa98e2SPeter Wemm 93e92d3f3fSGregory Neil Shapiro pvp = prescan(addr, delim, pvpbuf, sizeof pvpbuf, delimptr, NULL, false); 94c2aa98e2SPeter Wemm if (pvp == NULL) 95c2aa98e2SPeter Wemm { 96c2aa98e2SPeter Wemm if (tTd(20, 1)) 9740266059SGregory Neil Shapiro sm_dprintf("parseaddr-->NULL\n"); 9806f25ae9SGregory Neil Shapiro return NULL; 99c2aa98e2SPeter Wemm } 100c2aa98e2SPeter Wemm 10140266059SGregory Neil Shapiro if (invalidaddr(addr, delim == '\0' ? NULL : *delimptr, isrcpt)) 102c2aa98e2SPeter Wemm { 103c2aa98e2SPeter Wemm if (tTd(20, 1)) 10440266059SGregory Neil Shapiro sm_dprintf("parseaddr-->bad address\n"); 105c2aa98e2SPeter Wemm return NULL; 106c2aa98e2SPeter Wemm } 107c2aa98e2SPeter Wemm 108c2aa98e2SPeter Wemm /* 109c2aa98e2SPeter Wemm ** Save addr if we are going to have to. 110c2aa98e2SPeter Wemm ** 111c2aa98e2SPeter Wemm ** We have to do this early because there is a chance that 112c2aa98e2SPeter Wemm ** the map lookups in the rewriting rules could clobber 113c2aa98e2SPeter Wemm ** static memory somewhere. 114c2aa98e2SPeter Wemm */ 115c2aa98e2SPeter Wemm 116c2aa98e2SPeter Wemm if (bitset(RF_COPYPADDR, flags) && addr != NULL) 117c2aa98e2SPeter Wemm { 118c2aa98e2SPeter Wemm char savec = **delimptr; 119c2aa98e2SPeter Wemm 120c2aa98e2SPeter Wemm if (savec != '\0') 121c2aa98e2SPeter Wemm **delimptr = '\0'; 12240266059SGregory Neil Shapiro e->e_to = addr = sm_rpool_strdup_x(e->e_rpool, addr); 123c2aa98e2SPeter Wemm if (savec != '\0') 124c2aa98e2SPeter Wemm **delimptr = savec; 125c2aa98e2SPeter Wemm } 126c2aa98e2SPeter Wemm 127c2aa98e2SPeter Wemm /* 128c2aa98e2SPeter Wemm ** Apply rewriting rules. 129c2aa98e2SPeter Wemm ** Ruleset 0 does basic parsing. It must resolve. 130c2aa98e2SPeter Wemm */ 131c2aa98e2SPeter Wemm 13240266059SGregory Neil Shapiro qup = false; 13340266059SGregory Neil Shapiro if (REWRITE(pvp, 3, e) == EX_TEMPFAIL) 13440266059SGregory Neil Shapiro qup = true; 13540266059SGregory Neil Shapiro if (REWRITE(pvp, 0, e) == EX_TEMPFAIL) 13640266059SGregory Neil Shapiro qup = true; 137c2aa98e2SPeter Wemm 138c2aa98e2SPeter Wemm /* 139c2aa98e2SPeter Wemm ** Build canonical address from pvp. 140c2aa98e2SPeter Wemm */ 141c2aa98e2SPeter Wemm 142c2aa98e2SPeter Wemm a = buildaddr(pvp, a, flags, e); 143c2aa98e2SPeter Wemm 144605302a5SGregory Neil Shapiro if (hasctrlchar(a->q_user, isrcpt, true)) 14540266059SGregory Neil Shapiro { 14640266059SGregory Neil Shapiro if (tTd(20, 1)) 14740266059SGregory Neil Shapiro sm_dprintf("parseaddr-->bad q_user\n"); 148605302a5SGregory Neil Shapiro 149605302a5SGregory Neil Shapiro /* 150605302a5SGregory Neil Shapiro ** Just mark the address as bad so DSNs work. 151605302a5SGregory Neil Shapiro ** hasctrlchar() has to make sure that the address 152605302a5SGregory Neil Shapiro ** has been sanitized, e.g., shortened. 153605302a5SGregory Neil Shapiro */ 154605302a5SGregory Neil Shapiro 155605302a5SGregory Neil Shapiro a->q_state = QS_BADADDR; 15640266059SGregory Neil Shapiro } 15740266059SGregory Neil Shapiro 158c2aa98e2SPeter Wemm /* 159c2aa98e2SPeter Wemm ** Make local copies of the host & user and then 160c2aa98e2SPeter Wemm ** transport them out. 161c2aa98e2SPeter Wemm */ 162c2aa98e2SPeter Wemm 16340266059SGregory Neil Shapiro allocaddr(a, flags, addr, e); 16406f25ae9SGregory Neil Shapiro if (QS_IS_BADADDR(a->q_state)) 165605302a5SGregory Neil Shapiro { 166605302a5SGregory Neil Shapiro /* weed out bad characters in the printable address too */ 167605302a5SGregory Neil Shapiro (void) hasctrlchar(a->q_paddr, isrcpt, false); 168c2aa98e2SPeter Wemm return a; 169605302a5SGregory Neil Shapiro } 170c2aa98e2SPeter Wemm 171c2aa98e2SPeter Wemm /* 17240266059SGregory Neil Shapiro ** Select a queue directory for recipient addresses. 17340266059SGregory Neil Shapiro ** This is done here and in split_across_queue_groups(), 17440266059SGregory Neil Shapiro ** but the latter applies to addresses after aliasing, 17540266059SGregory Neil Shapiro ** and only if splitting is done. 17640266059SGregory Neil Shapiro */ 17740266059SGregory Neil Shapiro 17840266059SGregory Neil Shapiro if ((a->q_qgrp == NOAQGRP || a->q_qgrp == ENVQGRP) && 17940266059SGregory Neil Shapiro !bitset(RF_SENDERADDR|RF_HEADERADDR, flags) && 18040266059SGregory Neil Shapiro OpMode != MD_INITALIAS) 18140266059SGregory Neil Shapiro { 18240266059SGregory Neil Shapiro int r; 18340266059SGregory Neil Shapiro 18440266059SGregory Neil Shapiro /* call ruleset which should return a queue group name */ 18540266059SGregory Neil Shapiro r = rscap(RS_QUEUEGROUP, a->q_user, NULL, e, &pvp, pvpbuf, 18640266059SGregory Neil Shapiro sizeof(pvpbuf)); 18740266059SGregory Neil Shapiro if (r == EX_OK && 18840266059SGregory Neil Shapiro pvp != NULL && pvp[0] != NULL && 18940266059SGregory Neil Shapiro (pvp[0][0] & 0377) == CANONNET && 19040266059SGregory Neil Shapiro pvp[1] != NULL && pvp[1][0] != '\0') 19140266059SGregory Neil Shapiro { 19240266059SGregory Neil Shapiro r = name2qid(pvp[1]); 19340266059SGregory Neil Shapiro if (r == NOQGRP && LogLevel > 10) 19440266059SGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID, 19540266059SGregory Neil Shapiro "can't find queue group name %s, selection ignored", 19640266059SGregory Neil Shapiro pvp[1]); 19740266059SGregory Neil Shapiro if (tTd(20, 4) && r != NOQGRP) 19840266059SGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID, 19940266059SGregory Neil Shapiro "queue group name %s -> %d", 20040266059SGregory Neil Shapiro pvp[1], r); 20140266059SGregory Neil Shapiro a->q_qgrp = r == NOQGRP ? ENVQGRP : r; 20240266059SGregory Neil Shapiro } 20340266059SGregory Neil Shapiro } 20440266059SGregory Neil Shapiro 20540266059SGregory Neil Shapiro /* 206c2aa98e2SPeter Wemm ** If there was a parsing failure, mark it for queueing. 207c2aa98e2SPeter Wemm */ 208c2aa98e2SPeter Wemm 20906f25ae9SGregory Neil Shapiro if (qup && OpMode != MD_INITALIAS) 210c2aa98e2SPeter Wemm { 211c2aa98e2SPeter Wemm char *msg = "Transient parse error -- message queued for future delivery"; 212c2aa98e2SPeter Wemm 213c2aa98e2SPeter Wemm if (e->e_sendmode == SM_DEFER) 214c2aa98e2SPeter Wemm msg = "Deferring message until queue run"; 215c2aa98e2SPeter Wemm if (tTd(20, 1)) 21640266059SGregory Neil Shapiro sm_dprintf("parseaddr: queuing message\n"); 217c2aa98e2SPeter Wemm message(msg); 218c2aa98e2SPeter Wemm if (e->e_message == NULL && e->e_sendmode != SM_DEFER) 21940266059SGregory Neil Shapiro e->e_message = sm_rpool_strdup_x(e->e_rpool, msg); 22006f25ae9SGregory Neil Shapiro a->q_state = QS_QUEUEUP; 221c2aa98e2SPeter Wemm a->q_status = "4.4.3"; 222c2aa98e2SPeter Wemm } 223c2aa98e2SPeter Wemm 224c2aa98e2SPeter Wemm /* 225c2aa98e2SPeter Wemm ** Compute return value. 226c2aa98e2SPeter Wemm */ 227c2aa98e2SPeter Wemm 228c2aa98e2SPeter Wemm if (tTd(20, 1)) 229c2aa98e2SPeter Wemm { 23040266059SGregory Neil Shapiro sm_dprintf("parseaddr-->"); 231e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), a, false); 232c2aa98e2SPeter Wemm } 233c2aa98e2SPeter Wemm 23406f25ae9SGregory Neil Shapiro return a; 235c2aa98e2SPeter Wemm } 23640266059SGregory Neil Shapiro /* 23740266059SGregory Neil Shapiro ** INVALIDADDR -- check for address containing characters used for macros 238c2aa98e2SPeter Wemm ** 239c2aa98e2SPeter Wemm ** Parameters: 240c2aa98e2SPeter Wemm ** addr -- the address to check. 24140266059SGregory Neil Shapiro ** delimptr -- if non-NULL: end of address to check, i.e., 24240266059SGregory Neil Shapiro ** a pointer in the address string. 24340266059SGregory Neil Shapiro ** isrcpt -- true iff the address is for a recipient. 244c2aa98e2SPeter Wemm ** 245c2aa98e2SPeter Wemm ** Returns: 24640266059SGregory Neil Shapiro ** true -- if the address has characters that are reservered 24740266059SGregory Neil Shapiro ** for macros or is too long. 24840266059SGregory Neil Shapiro ** false -- otherwise. 249c2aa98e2SPeter Wemm */ 250c2aa98e2SPeter Wemm 251c2aa98e2SPeter Wemm bool 25240266059SGregory Neil Shapiro invalidaddr(addr, delimptr, isrcpt) 253c2aa98e2SPeter Wemm register char *addr; 254c2aa98e2SPeter Wemm char *delimptr; 25540266059SGregory Neil Shapiro bool isrcpt; 256c2aa98e2SPeter Wemm { 25740266059SGregory Neil Shapiro bool result = false; 258c2aa98e2SPeter Wemm char savedelim = '\0'; 259605302a5SGregory Neil Shapiro char *b = addr; 26040266059SGregory Neil Shapiro int len = 0; 261c2aa98e2SPeter Wemm 262c2aa98e2SPeter Wemm if (delimptr != NULL) 263c2aa98e2SPeter Wemm { 26440266059SGregory Neil Shapiro /* delimptr points to the end of the address to test */ 265c2aa98e2SPeter Wemm savedelim = *delimptr; 26640266059SGregory Neil Shapiro if (savedelim != '\0') /* if that isn't '\0' already: */ 26740266059SGregory Neil Shapiro *delimptr = '\0'; /* set it */ 268c2aa98e2SPeter Wemm } 269c2aa98e2SPeter Wemm for (; *addr != '\0'; addr++) 270c2aa98e2SPeter Wemm { 271c2aa98e2SPeter Wemm if ((*addr & 0340) == 0200) 27240266059SGregory Neil Shapiro { 27340266059SGregory Neil Shapiro setstat(EX_USAGE); 27440266059SGregory Neil Shapiro result = true; 275605302a5SGregory Neil Shapiro *addr = BAD_CHAR_REPLACEMENT; 276c2aa98e2SPeter Wemm } 27740266059SGregory Neil Shapiro if (++len > MAXNAME - 1) 278c2aa98e2SPeter Wemm { 279605302a5SGregory Neil Shapiro char saved = *addr; 280605302a5SGregory Neil Shapiro 281605302a5SGregory Neil Shapiro *addr = '\0'; 282605302a5SGregory Neil Shapiro usrerr("553 5.1.0 Address \"%s\" too long (%d bytes max)", 283605302a5SGregory Neil Shapiro b, MAXNAME - 1); 284605302a5SGregory Neil Shapiro *addr = saved; 28540266059SGregory Neil Shapiro result = true; 28640266059SGregory Neil Shapiro goto delim; 287c2aa98e2SPeter Wemm } 28840266059SGregory Neil Shapiro } 28940266059SGregory Neil Shapiro if (result) 29040266059SGregory Neil Shapiro { 29140266059SGregory Neil Shapiro if (isrcpt) 292605302a5SGregory Neil Shapiro usrerr("501 5.1.3 8-bit character in mailbox address \"%s\"", 293605302a5SGregory Neil Shapiro b); 29440266059SGregory Neil Shapiro else 295605302a5SGregory Neil Shapiro usrerr("501 5.1.7 8-bit character in mailbox address \"%s\"", 296605302a5SGregory Neil Shapiro b); 29740266059SGregory Neil Shapiro } 29840266059SGregory Neil Shapiro delim: 29940266059SGregory Neil Shapiro if (delimptr != NULL && savedelim != '\0') 30040266059SGregory Neil Shapiro *delimptr = savedelim; /* restore old character at delimptr */ 30140266059SGregory Neil Shapiro return result; 30240266059SGregory Neil Shapiro } 30340266059SGregory Neil Shapiro /* 30440266059SGregory Neil Shapiro ** HASCTRLCHAR -- check for address containing meta-characters 30540266059SGregory Neil Shapiro ** 30640266059SGregory Neil Shapiro ** Checks that the address contains no meta-characters, and contains 30740266059SGregory Neil Shapiro ** no "non-printable" characters unless they are quoted or escaped. 30840266059SGregory Neil Shapiro ** Quoted or escaped characters are literals. 30940266059SGregory Neil Shapiro ** 31040266059SGregory Neil Shapiro ** Parameters: 31140266059SGregory Neil Shapiro ** addr -- the address to check. 31240266059SGregory Neil Shapiro ** isrcpt -- true if the address is for a recipient; false 31340266059SGregory Neil Shapiro ** indicates a from. 314605302a5SGregory Neil Shapiro ** complain -- true if an error should issued if the address 315605302a5SGregory Neil Shapiro ** is invalid and should be "repaired". 31640266059SGregory Neil Shapiro ** 31740266059SGregory Neil Shapiro ** Returns: 31840266059SGregory Neil Shapiro ** true -- if the address has any "wierd" characters or 31940266059SGregory Neil Shapiro ** non-printable characters or if a quote is unbalanced. 32040266059SGregory Neil Shapiro ** false -- otherwise. 32140266059SGregory Neil Shapiro */ 32240266059SGregory Neil Shapiro 32340266059SGregory Neil Shapiro static bool 324605302a5SGregory Neil Shapiro hasctrlchar(addr, isrcpt, complain) 32540266059SGregory Neil Shapiro register char *addr; 326605302a5SGregory Neil Shapiro bool isrcpt, complain; 32740266059SGregory Neil Shapiro { 32840266059SGregory Neil Shapiro bool quoted = false; 329605302a5SGregory Neil Shapiro int len = 0; 330605302a5SGregory Neil Shapiro char *result = NULL; 331605302a5SGregory Neil Shapiro char *b = addr; 33240266059SGregory Neil Shapiro 33340266059SGregory Neil Shapiro if (addr == NULL) 33440266059SGregory Neil Shapiro return false; 33540266059SGregory Neil Shapiro for (; *addr != '\0'; addr++) 33640266059SGregory Neil Shapiro { 337605302a5SGregory Neil Shapiro if (++len > MAXNAME - 1) 338605302a5SGregory Neil Shapiro { 339605302a5SGregory Neil Shapiro if (complain) 340605302a5SGregory Neil Shapiro { 341605302a5SGregory Neil Shapiro (void) shorten_rfc822_string(b, MAXNAME - 1); 342605302a5SGregory Neil Shapiro usrerr("553 5.1.0 Address \"%s\" too long (%d bytes max)", 343605302a5SGregory Neil Shapiro b, MAXNAME - 1); 344605302a5SGregory Neil Shapiro return true; 345605302a5SGregory Neil Shapiro } 346605302a5SGregory Neil Shapiro result = "too long"; 347605302a5SGregory Neil Shapiro } 34840266059SGregory Neil Shapiro if (!quoted && (*addr < 32 || *addr == 127)) 34940266059SGregory Neil Shapiro { 350605302a5SGregory Neil Shapiro result = "non-printable character"; 351605302a5SGregory Neil Shapiro *addr = BAD_CHAR_REPLACEMENT; 352605302a5SGregory Neil Shapiro continue; 35340266059SGregory Neil Shapiro } 35440266059SGregory Neil Shapiro if (*addr == '"') 35540266059SGregory Neil Shapiro quoted = !quoted; 35640266059SGregory Neil Shapiro else if (*addr == '\\') 35740266059SGregory Neil Shapiro { 35840266059SGregory Neil Shapiro /* XXX Generic problem: no '\0' in strings. */ 35940266059SGregory Neil Shapiro if (*++addr == '\0') 36040266059SGregory Neil Shapiro { 361605302a5SGregory Neil Shapiro result = "trailing \\ character"; 362605302a5SGregory Neil Shapiro *--addr = BAD_CHAR_REPLACEMENT; 36340266059SGregory Neil Shapiro break; 36440266059SGregory Neil Shapiro } 36540266059SGregory Neil Shapiro } 36640266059SGregory Neil Shapiro if ((*addr & 0340) == 0200) 36740266059SGregory Neil Shapiro { 368c2aa98e2SPeter Wemm setstat(EX_USAGE); 369605302a5SGregory Neil Shapiro result = "8-bit character"; 370605302a5SGregory Neil Shapiro *addr = BAD_CHAR_REPLACEMENT; 371605302a5SGregory Neil Shapiro continue; 37240266059SGregory Neil Shapiro } 37340266059SGregory Neil Shapiro } 37440266059SGregory Neil Shapiro if (quoted) 375605302a5SGregory Neil Shapiro result = "unbalanced quote"; /* unbalanced quote */ 376605302a5SGregory Neil Shapiro if (result != NULL && complain) 37740266059SGregory Neil Shapiro { 37840266059SGregory Neil Shapiro if (isrcpt) 379605302a5SGregory Neil Shapiro usrerr("501 5.1.3 Syntax error in mailbox address \"%s\" (%s)", 380605302a5SGregory Neil Shapiro b, result); 38140266059SGregory Neil Shapiro else 382605302a5SGregory Neil Shapiro usrerr("501 5.1.7 Syntax error in mailbox address \"%s\" (%s)", 383605302a5SGregory Neil Shapiro b, result); 38440266059SGregory Neil Shapiro } 385605302a5SGregory Neil Shapiro return result != NULL; 38640266059SGregory Neil Shapiro } 38740266059SGregory Neil Shapiro /* 388c2aa98e2SPeter Wemm ** ALLOCADDR -- do local allocations of address on demand. 389c2aa98e2SPeter Wemm ** 390c2aa98e2SPeter Wemm ** Also lowercases the host name if requested. 391c2aa98e2SPeter Wemm ** 392c2aa98e2SPeter Wemm ** Parameters: 393c2aa98e2SPeter Wemm ** a -- the address to reallocate. 394c2aa98e2SPeter Wemm ** flags -- the copy flag (see RF_ definitions in sendmail.h 395c2aa98e2SPeter Wemm ** for a description). 396c2aa98e2SPeter Wemm ** paddr -- the printname of the address. 39740266059SGregory Neil Shapiro ** e -- envelope 398c2aa98e2SPeter Wemm ** 399c2aa98e2SPeter Wemm ** Returns: 400c2aa98e2SPeter Wemm ** none. 401c2aa98e2SPeter Wemm ** 402c2aa98e2SPeter Wemm ** Side Effects: 403c2aa98e2SPeter Wemm ** Copies portions of a into local buffers as requested. 404c2aa98e2SPeter Wemm */ 405c2aa98e2SPeter Wemm 40606f25ae9SGregory Neil Shapiro static void 40740266059SGregory Neil Shapiro allocaddr(a, flags, paddr, e) 408c2aa98e2SPeter Wemm register ADDRESS *a; 409c2aa98e2SPeter Wemm int flags; 410c2aa98e2SPeter Wemm char *paddr; 41140266059SGregory Neil Shapiro ENVELOPE *e; 412c2aa98e2SPeter Wemm { 413c2aa98e2SPeter Wemm if (tTd(24, 4)) 41440266059SGregory Neil Shapiro sm_dprintf("allocaddr(flags=%x, paddr=%s)\n", flags, paddr); 415c2aa98e2SPeter Wemm 416c2aa98e2SPeter Wemm a->q_paddr = paddr; 417c2aa98e2SPeter Wemm 418c2aa98e2SPeter Wemm if (a->q_user == NULL) 41940266059SGregory Neil Shapiro a->q_user = ""; 420c2aa98e2SPeter Wemm if (a->q_host == NULL) 42140266059SGregory Neil Shapiro a->q_host = ""; 422c2aa98e2SPeter Wemm 423c2aa98e2SPeter Wemm if (bitset(RF_COPYPARSE, flags)) 424c2aa98e2SPeter Wemm { 42540266059SGregory Neil Shapiro a->q_host = sm_rpool_strdup_x(e->e_rpool, a->q_host); 426c2aa98e2SPeter Wemm if (a->q_user != a->q_paddr) 42740266059SGregory Neil Shapiro a->q_user = sm_rpool_strdup_x(e->e_rpool, a->q_user); 428c2aa98e2SPeter Wemm } 429c2aa98e2SPeter Wemm 430c2aa98e2SPeter Wemm if (a->q_paddr == NULL) 43140266059SGregory Neil Shapiro a->q_paddr = sm_rpool_strdup_x(e->e_rpool, a->q_user); 43240266059SGregory Neil Shapiro a->q_qgrp = NOAQGRP; 433c2aa98e2SPeter Wemm } 43440266059SGregory Neil Shapiro /* 435c2aa98e2SPeter Wemm ** PRESCAN -- Prescan name and make it canonical 436c2aa98e2SPeter Wemm ** 437c2aa98e2SPeter Wemm ** Scans a name and turns it into a set of tokens. This process 43806f25ae9SGregory Neil Shapiro ** deletes blanks and comments (in parentheses) (if the token type 43906f25ae9SGregory Neil Shapiro ** for left paren is SPC). 440c2aa98e2SPeter Wemm ** 441c2aa98e2SPeter Wemm ** This routine knows about quoted strings and angle brackets. 442c2aa98e2SPeter Wemm ** 443c2aa98e2SPeter Wemm ** There are certain subtleties to this routine. The one that 444c2aa98e2SPeter Wemm ** comes to mind now is that backslashes on the ends of names 445c2aa98e2SPeter Wemm ** are silently stripped off; this is intentional. The problem 446c2aa98e2SPeter Wemm ** is that some versions of sndmsg (like at LBL) set the kill 447c2aa98e2SPeter Wemm ** character to something other than @ when reading addresses; 448c2aa98e2SPeter Wemm ** so people type "csvax.eric\@berkeley" -- which screws up the 449c2aa98e2SPeter Wemm ** berknet mailer. 450c2aa98e2SPeter Wemm ** 451c2aa98e2SPeter Wemm ** Parameters: 452c2aa98e2SPeter Wemm ** addr -- the name to chomp. 453c2aa98e2SPeter Wemm ** delim -- the delimiter for the address, normally 454c2aa98e2SPeter Wemm ** '\0' or ','; \0 is accepted in any case. 455c2aa98e2SPeter Wemm ** If '\t' then we are reading the .cf file. 456c2aa98e2SPeter Wemm ** pvpbuf -- place to put the saved text -- note that 457c2aa98e2SPeter Wemm ** the pointers are static. 458c2aa98e2SPeter Wemm ** pvpbsize -- size of pvpbuf. 459c2aa98e2SPeter Wemm ** delimptr -- if non-NULL, set to the location of the 460c2aa98e2SPeter Wemm ** terminating delimiter. 461c2aa98e2SPeter Wemm ** toktab -- if set, a token table to use for parsing. 462c2aa98e2SPeter Wemm ** If NULL, use the default table. 463e92d3f3fSGregory Neil Shapiro ** ignore -- if true, ignore unbalanced addresses 464c2aa98e2SPeter Wemm ** 465c2aa98e2SPeter Wemm ** Returns: 466c2aa98e2SPeter Wemm ** A pointer to a vector of tokens. 467c2aa98e2SPeter Wemm ** NULL on error. 468c2aa98e2SPeter Wemm */ 469c2aa98e2SPeter Wemm 470c2aa98e2SPeter Wemm /* states and character types */ 471c2aa98e2SPeter Wemm #define OPR 0 /* operator */ 472c2aa98e2SPeter Wemm #define ATM 1 /* atom */ 473c2aa98e2SPeter Wemm #define QST 2 /* in quoted string */ 474c2aa98e2SPeter Wemm #define SPC 3 /* chewing up spaces */ 475c2aa98e2SPeter Wemm #define ONE 4 /* pick up one character */ 476c2aa98e2SPeter Wemm #define ILL 5 /* illegal character */ 477c2aa98e2SPeter Wemm 478c2aa98e2SPeter Wemm #define NSTATES 6 /* number of states */ 479c2aa98e2SPeter Wemm #define TYPE 017 /* mask to select state type */ 480c2aa98e2SPeter Wemm 481c2aa98e2SPeter Wemm /* meta bits for table */ 482c2aa98e2SPeter Wemm #define M 020 /* meta character; don't pass through */ 483c2aa98e2SPeter Wemm #define B 040 /* cause a break */ 484c2aa98e2SPeter Wemm #define MB M|B /* meta-break */ 485c2aa98e2SPeter Wemm 486c2aa98e2SPeter Wemm static short StateTab[NSTATES][NSTATES] = 487c2aa98e2SPeter Wemm { 488c2aa98e2SPeter Wemm /* oldst chtype> OPR ATM QST SPC ONE ILL */ 489c2aa98e2SPeter Wemm /*OPR*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|MB }, 490c2aa98e2SPeter Wemm /*ATM*/ { OPR|B, ATM, QST|B, SPC|MB, ONE|B, ILL|MB }, 491c2aa98e2SPeter Wemm /*QST*/ { QST, QST, OPR, QST, QST, QST }, 492c2aa98e2SPeter Wemm /*SPC*/ { OPR, ATM, QST, SPC|M, ONE, ILL|MB }, 493c2aa98e2SPeter Wemm /*ONE*/ { OPR, OPR, OPR, OPR, OPR, ILL|MB }, 494c2aa98e2SPeter Wemm /*ILL*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|M }, 495c2aa98e2SPeter Wemm }; 496c2aa98e2SPeter Wemm 497c2aa98e2SPeter Wemm /* token type table -- it gets modified with $o characters */ 49840266059SGregory Neil Shapiro static unsigned char TokTypeTab[256] = 499c2aa98e2SPeter Wemm { 500c2aa98e2SPeter Wemm /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 501c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM, 502c2aa98e2SPeter Wemm /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 503c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 504c2aa98e2SPeter Wemm /* sp ! " # $ % & ' ( ) * + , - . / */ 50506f25ae9SGregory Neil Shapiro SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, SPC,SPC,ATM,ATM,ATM,ATM,ATM,ATM, 506c2aa98e2SPeter Wemm /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 507c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 508c2aa98e2SPeter Wemm /* @ A B C D E F G H I J K L M N O */ 509c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 510c2aa98e2SPeter Wemm /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 511c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 512c2aa98e2SPeter Wemm /* ` a b c d e f g h i j k l m n o */ 513c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 514c2aa98e2SPeter Wemm /* p q r s t u v w x y z { | } ~ del */ 515c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 516c2aa98e2SPeter Wemm 517c2aa98e2SPeter Wemm /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 518c2aa98e2SPeter Wemm OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 519c2aa98e2SPeter Wemm /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 520c2aa98e2SPeter Wemm OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 521c2aa98e2SPeter Wemm /* sp ! " # $ % & ' ( ) * + , - . / */ 522c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 523c2aa98e2SPeter Wemm /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 524c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 525c2aa98e2SPeter Wemm /* @ A B C D E F G H I J K L M N O */ 526c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 527c2aa98e2SPeter Wemm /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 528c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 529c2aa98e2SPeter Wemm /* ` a b c d e f g h i j k l m n o */ 530c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 531c2aa98e2SPeter Wemm /* p q r s t u v w x y z { | } ~ del */ 532c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 533c2aa98e2SPeter Wemm }; 534c2aa98e2SPeter Wemm 535c2aa98e2SPeter Wemm /* token type table for MIME parsing */ 53640266059SGregory Neil Shapiro unsigned char MimeTokenTab[256] = 537c2aa98e2SPeter Wemm { 538c2aa98e2SPeter Wemm /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 539c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,SPC,SPC,SPC,SPC,SPC,ILL,ILL, 540c2aa98e2SPeter Wemm /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 541c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 542c2aa98e2SPeter Wemm /* sp ! " # $ % & ' ( ) * + , - . / */ 54306f25ae9SGregory Neil Shapiro SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, SPC,SPC,ATM,ATM,OPR,ATM,ATM,OPR, 544c2aa98e2SPeter Wemm /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 545c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,OPR,OPR,OPR,OPR,OPR,OPR, 546c2aa98e2SPeter Wemm /* @ A B C D E F G H I J K L M N O */ 547c2aa98e2SPeter Wemm OPR,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 548c2aa98e2SPeter Wemm /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 549c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,OPR,OPR,OPR,ATM,ATM, 550c2aa98e2SPeter Wemm /* ` a b c d e f g h i j k l m n o */ 551c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 552c2aa98e2SPeter Wemm /* p q r s t u v w x y z { | } ~ del */ 553c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 554c2aa98e2SPeter Wemm 555c2aa98e2SPeter Wemm /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 556c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 557c2aa98e2SPeter Wemm /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 558c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 559c2aa98e2SPeter Wemm /* sp ! " # $ % & ' ( ) * + , - . / */ 560c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 561c2aa98e2SPeter Wemm /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 562c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 563c2aa98e2SPeter Wemm /* @ A B C D E F G H I J K L M N O */ 564c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 565c2aa98e2SPeter Wemm /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 566c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 567c2aa98e2SPeter Wemm /* ` a b c d e f g h i j k l m n o */ 568c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 569c2aa98e2SPeter Wemm /* p q r s t u v w x y z { | } ~ del */ 570c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 571c2aa98e2SPeter Wemm }; 572c2aa98e2SPeter Wemm 57306f25ae9SGregory Neil Shapiro /* token type table: don't strip comments */ 57440266059SGregory Neil Shapiro unsigned char TokTypeNoC[256] = 57506f25ae9SGregory Neil Shapiro { 57606f25ae9SGregory Neil Shapiro /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 57706f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM, 57806f25ae9SGregory Neil Shapiro /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 57906f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 58006f25ae9SGregory Neil Shapiro /* sp ! " # $ % & ' ( ) * + , - . / */ 58106f25ae9SGregory Neil Shapiro SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, OPR,OPR,ATM,ATM,ATM,ATM,ATM,ATM, 58206f25ae9SGregory Neil Shapiro /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 58306f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 58406f25ae9SGregory Neil Shapiro /* @ A B C D E F G H I J K L M N O */ 58506f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 58606f25ae9SGregory Neil Shapiro /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 58706f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 58806f25ae9SGregory Neil Shapiro /* ` a b c d e f g h i j k l m n o */ 58906f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 59006f25ae9SGregory Neil Shapiro /* p q r s t u v w x y z { | } ~ del */ 59106f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 59206f25ae9SGregory Neil Shapiro 59306f25ae9SGregory Neil Shapiro /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 59406f25ae9SGregory Neil Shapiro OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 59506f25ae9SGregory Neil Shapiro /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 59606f25ae9SGregory Neil Shapiro OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 59706f25ae9SGregory Neil Shapiro /* sp ! " # $ % & ' ( ) * + , - . / */ 59806f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 59906f25ae9SGregory Neil Shapiro /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 60006f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 60106f25ae9SGregory Neil Shapiro /* @ A B C D E F G H I J K L M N O */ 60206f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 60306f25ae9SGregory Neil Shapiro /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 60406f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 60506f25ae9SGregory Neil Shapiro /* ` a b c d e f g h i j k l m n o */ 60606f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 60706f25ae9SGregory Neil Shapiro /* p q r s t u v w x y z { | } ~ del */ 60806f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 60906f25ae9SGregory Neil Shapiro }; 61006f25ae9SGregory Neil Shapiro 611c2aa98e2SPeter Wemm 6125ef517c0SGregory Neil Shapiro #define NOCHAR (-1) /* signal nothing in lookahead token */ 613c2aa98e2SPeter Wemm 614c2aa98e2SPeter Wemm char ** 615e92d3f3fSGregory Neil Shapiro prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab, ignore) 616c2aa98e2SPeter Wemm char *addr; 617c2aa98e2SPeter Wemm int delim; 618c2aa98e2SPeter Wemm char pvpbuf[]; 619c2aa98e2SPeter Wemm int pvpbsize; 620c2aa98e2SPeter Wemm char **delimptr; 62140266059SGregory Neil Shapiro unsigned char *toktab; 622e92d3f3fSGregory Neil Shapiro bool ignore; 623c2aa98e2SPeter Wemm { 624c2aa98e2SPeter Wemm register char *p; 625c2aa98e2SPeter Wemm register char *q; 626c2aa98e2SPeter Wemm register int c; 627c2aa98e2SPeter Wemm char **avp; 628c2aa98e2SPeter Wemm bool bslashmode; 629c2aa98e2SPeter Wemm bool route_syntax; 630c2aa98e2SPeter Wemm int cmntcnt; 631c2aa98e2SPeter Wemm int anglecnt; 632c2aa98e2SPeter Wemm char *tok; 633c2aa98e2SPeter Wemm int state; 634c2aa98e2SPeter Wemm int newstate; 635c2aa98e2SPeter Wemm char *saveto = CurEnv->e_to; 636c2aa98e2SPeter Wemm static char *av[MAXATOM + 1]; 63740266059SGregory Neil Shapiro static bool firsttime = true; 638c2aa98e2SPeter Wemm 639c2aa98e2SPeter Wemm if (firsttime) 640c2aa98e2SPeter Wemm { 641c2aa98e2SPeter Wemm /* initialize the token type table */ 642c2aa98e2SPeter Wemm char obuf[50]; 643c2aa98e2SPeter Wemm 64440266059SGregory Neil Shapiro firsttime = false; 645c2aa98e2SPeter Wemm if (OperatorChars == NULL) 646c2aa98e2SPeter Wemm { 647c2aa98e2SPeter Wemm if (ConfigLevel < 7) 648c2aa98e2SPeter Wemm OperatorChars = macvalue('o', CurEnv); 649c2aa98e2SPeter Wemm if (OperatorChars == NULL) 650c2aa98e2SPeter Wemm OperatorChars = ".:@[]"; 651c2aa98e2SPeter Wemm } 65206f25ae9SGregory Neil Shapiro expand(OperatorChars, obuf, sizeof obuf - sizeof DELIMCHARS, 65306f25ae9SGregory Neil Shapiro CurEnv); 65440266059SGregory Neil Shapiro (void) sm_strlcat(obuf, DELIMCHARS, sizeof obuf); 655c2aa98e2SPeter Wemm for (p = obuf; *p != '\0'; p++) 656c2aa98e2SPeter Wemm { 657c2aa98e2SPeter Wemm if (TokTypeTab[*p & 0xff] == ATM) 658c2aa98e2SPeter Wemm TokTypeTab[*p & 0xff] = OPR; 65906f25ae9SGregory Neil Shapiro if (TokTypeNoC[*p & 0xff] == ATM) 66006f25ae9SGregory Neil Shapiro TokTypeNoC[*p & 0xff] = OPR; 661c2aa98e2SPeter Wemm } 662c2aa98e2SPeter Wemm } 663c2aa98e2SPeter Wemm if (toktab == NULL) 664c2aa98e2SPeter Wemm toktab = TokTypeTab; 665c2aa98e2SPeter Wemm 666c2aa98e2SPeter Wemm /* make sure error messages don't have garbage on them */ 667c2aa98e2SPeter Wemm errno = 0; 668c2aa98e2SPeter Wemm 669c2aa98e2SPeter Wemm q = pvpbuf; 67040266059SGregory Neil Shapiro bslashmode = false; 67140266059SGregory Neil Shapiro route_syntax = false; 672c2aa98e2SPeter Wemm cmntcnt = 0; 673c2aa98e2SPeter Wemm anglecnt = 0; 674c2aa98e2SPeter Wemm avp = av; 675c2aa98e2SPeter Wemm state = ATM; 676c2aa98e2SPeter Wemm c = NOCHAR; 677c2aa98e2SPeter Wemm p = addr; 678c2aa98e2SPeter Wemm CurEnv->e_to = p; 679c2aa98e2SPeter Wemm if (tTd(22, 11)) 680c2aa98e2SPeter Wemm { 68140266059SGregory Neil Shapiro sm_dprintf("prescan: "); 682e92d3f3fSGregory Neil Shapiro xputs(sm_debug_file(), p); 68340266059SGregory Neil Shapiro sm_dprintf("\n"); 684c2aa98e2SPeter Wemm } 685c2aa98e2SPeter Wemm 686c2aa98e2SPeter Wemm do 687c2aa98e2SPeter Wemm { 688c2aa98e2SPeter Wemm /* read a token */ 689c2aa98e2SPeter Wemm tok = q; 690c2aa98e2SPeter Wemm for (;;) 691c2aa98e2SPeter Wemm { 692c2aa98e2SPeter Wemm /* store away any old lookahead character */ 693c2aa98e2SPeter Wemm if (c != NOCHAR && !bslashmode) 694c2aa98e2SPeter Wemm { 695c2aa98e2SPeter Wemm /* see if there is room */ 696c2aa98e2SPeter Wemm if (q >= &pvpbuf[pvpbsize - 5]) 697c2aa98e2SPeter Wemm { 6985ef517c0SGregory Neil Shapiro addrtoolong: 69906f25ae9SGregory Neil Shapiro usrerr("553 5.1.1 Address too long"); 70040266059SGregory Neil Shapiro if (strlen(addr) > MAXNAME) 701c2aa98e2SPeter Wemm addr[MAXNAME] = '\0'; 702c2aa98e2SPeter Wemm returnnull: 703c2aa98e2SPeter Wemm if (delimptr != NULL) 70458fec675SJacques Vidrine { 70558fec675SJacques Vidrine if (p > addr) 706a7ec597cSGregory Neil Shapiro --p; 707c2aa98e2SPeter Wemm *delimptr = p; 70858fec675SJacques Vidrine } 709c2aa98e2SPeter Wemm CurEnv->e_to = saveto; 71006f25ae9SGregory Neil Shapiro return NULL; 711c2aa98e2SPeter Wemm } 712c2aa98e2SPeter Wemm 713c2aa98e2SPeter Wemm /* squirrel it away */ 7145ef517c0SGregory Neil Shapiro #if !ALLOW_255 7155ef517c0SGregory Neil Shapiro if ((char) c == (char) -1 && !tTd(82, 101)) 7165ef517c0SGregory Neil Shapiro c &= 0x7f; 7175ef517c0SGregory Neil Shapiro #endif /* !ALLOW_255 */ 718c2aa98e2SPeter Wemm *q++ = c; 719c2aa98e2SPeter Wemm } 720c2aa98e2SPeter Wemm 721c2aa98e2SPeter Wemm /* read a new input character */ 7225ef517c0SGregory Neil Shapiro c = (*p++) & 0x00ff; 723c2aa98e2SPeter Wemm if (c == '\0') 724c2aa98e2SPeter Wemm { 725c2aa98e2SPeter Wemm /* diagnose and patch up bad syntax */ 726e92d3f3fSGregory Neil Shapiro if (ignore) 727e92d3f3fSGregory Neil Shapiro break; 728e92d3f3fSGregory Neil Shapiro else if (state == QST) 729c2aa98e2SPeter Wemm { 73040266059SGregory Neil Shapiro usrerr("553 Unbalanced '\"'"); 731c2aa98e2SPeter Wemm c = '"'; 732c2aa98e2SPeter Wemm } 733c2aa98e2SPeter Wemm else if (cmntcnt > 0) 734c2aa98e2SPeter Wemm { 73540266059SGregory Neil Shapiro usrerr("553 Unbalanced '('"); 736c2aa98e2SPeter Wemm c = ')'; 737c2aa98e2SPeter Wemm } 738c2aa98e2SPeter Wemm else if (anglecnt > 0) 739c2aa98e2SPeter Wemm { 740c2aa98e2SPeter Wemm c = '>'; 74140266059SGregory Neil Shapiro usrerr("553 Unbalanced '<'"); 742c2aa98e2SPeter Wemm } 743c2aa98e2SPeter Wemm else 744c2aa98e2SPeter Wemm break; 745c2aa98e2SPeter Wemm 746c2aa98e2SPeter Wemm p--; 747c2aa98e2SPeter Wemm } 748c2aa98e2SPeter Wemm else if (c == delim && cmntcnt <= 0 && state != QST) 749c2aa98e2SPeter Wemm { 750c2aa98e2SPeter Wemm if (anglecnt <= 0) 751c2aa98e2SPeter Wemm break; 752c2aa98e2SPeter Wemm 753c2aa98e2SPeter Wemm /* special case for better error management */ 754e92d3f3fSGregory Neil Shapiro if (delim == ',' && !route_syntax && !ignore) 755c2aa98e2SPeter Wemm { 75640266059SGregory Neil Shapiro usrerr("553 Unbalanced '<'"); 757c2aa98e2SPeter Wemm c = '>'; 758c2aa98e2SPeter Wemm p--; 759c2aa98e2SPeter Wemm } 760c2aa98e2SPeter Wemm } 761c2aa98e2SPeter Wemm 762c2aa98e2SPeter Wemm if (tTd(22, 101)) 76340266059SGregory Neil Shapiro sm_dprintf("c=%c, s=%d; ", c, state); 764c2aa98e2SPeter Wemm 765c2aa98e2SPeter Wemm /* chew up special characters */ 766c2aa98e2SPeter Wemm *q = '\0'; 767c2aa98e2SPeter Wemm if (bslashmode) 768c2aa98e2SPeter Wemm { 76940266059SGregory Neil Shapiro bslashmode = false; 770c2aa98e2SPeter Wemm 771c2aa98e2SPeter Wemm /* kludge \! for naive users */ 772c2aa98e2SPeter Wemm if (cmntcnt > 0) 773c2aa98e2SPeter Wemm { 774c2aa98e2SPeter Wemm c = NOCHAR; 775c2aa98e2SPeter Wemm continue; 776c2aa98e2SPeter Wemm } 777c2aa98e2SPeter Wemm else if (c != '!' || state == QST) 778c2aa98e2SPeter Wemm { 7795ef517c0SGregory Neil Shapiro /* see if there is room */ 7805ef517c0SGregory Neil Shapiro if (q >= &pvpbuf[pvpbsize - 5]) 7815ef517c0SGregory Neil Shapiro goto addrtoolong; 782c2aa98e2SPeter Wemm *q++ = '\\'; 783c2aa98e2SPeter Wemm continue; 784c2aa98e2SPeter Wemm } 785c2aa98e2SPeter Wemm } 786c2aa98e2SPeter Wemm 787c2aa98e2SPeter Wemm if (c == '\\') 788c2aa98e2SPeter Wemm { 78940266059SGregory Neil Shapiro bslashmode = true; 790c2aa98e2SPeter Wemm } 791c2aa98e2SPeter Wemm else if (state == QST) 792c2aa98e2SPeter Wemm { 79306f25ae9SGregory Neil Shapiro /* EMPTY */ 794c2aa98e2SPeter Wemm /* do nothing, just avoid next clauses */ 795c2aa98e2SPeter Wemm } 79606f25ae9SGregory Neil Shapiro else if (c == '(' && toktab['('] == SPC) 797c2aa98e2SPeter Wemm { 798c2aa98e2SPeter Wemm cmntcnt++; 799c2aa98e2SPeter Wemm c = NOCHAR; 800c2aa98e2SPeter Wemm } 80106f25ae9SGregory Neil Shapiro else if (c == ')' && toktab['('] == SPC) 802c2aa98e2SPeter Wemm { 803c2aa98e2SPeter Wemm if (cmntcnt <= 0) 804c2aa98e2SPeter Wemm { 805e92d3f3fSGregory Neil Shapiro if (!ignore) 806e92d3f3fSGregory Neil Shapiro { 80740266059SGregory Neil Shapiro usrerr("553 Unbalanced ')'"); 808c2aa98e2SPeter Wemm c = NOCHAR; 809c2aa98e2SPeter Wemm } 810e92d3f3fSGregory Neil Shapiro } 811c2aa98e2SPeter Wemm else 812c2aa98e2SPeter Wemm cmntcnt--; 813c2aa98e2SPeter Wemm } 814c2aa98e2SPeter Wemm else if (cmntcnt > 0) 81506f25ae9SGregory Neil Shapiro { 816c2aa98e2SPeter Wemm c = NOCHAR; 81706f25ae9SGregory Neil Shapiro } 818c2aa98e2SPeter Wemm else if (c == '<') 819c2aa98e2SPeter Wemm { 82006f25ae9SGregory Neil Shapiro char *ptr = p; 821c2aa98e2SPeter Wemm 822c2aa98e2SPeter Wemm anglecnt++; 82306f25ae9SGregory Neil Shapiro while (isascii(*ptr) && isspace(*ptr)) 82406f25ae9SGregory Neil Shapiro ptr++; 82506f25ae9SGregory Neil Shapiro if (*ptr == '@') 82640266059SGregory Neil Shapiro route_syntax = true; 827c2aa98e2SPeter Wemm } 828c2aa98e2SPeter Wemm else if (c == '>') 829c2aa98e2SPeter Wemm { 830c2aa98e2SPeter Wemm if (anglecnt <= 0) 831c2aa98e2SPeter Wemm { 832e92d3f3fSGregory Neil Shapiro if (!ignore) 833e92d3f3fSGregory Neil Shapiro { 83440266059SGregory Neil Shapiro usrerr("553 Unbalanced '>'"); 835c2aa98e2SPeter Wemm c = NOCHAR; 836c2aa98e2SPeter Wemm } 837e92d3f3fSGregory Neil Shapiro } 838c2aa98e2SPeter Wemm else 839c2aa98e2SPeter Wemm anglecnt--; 84040266059SGregory Neil Shapiro route_syntax = false; 841c2aa98e2SPeter Wemm } 842c2aa98e2SPeter Wemm else if (delim == ' ' && isascii(c) && isspace(c)) 843c2aa98e2SPeter Wemm c = ' '; 844c2aa98e2SPeter Wemm 845c2aa98e2SPeter Wemm if (c == NOCHAR) 846c2aa98e2SPeter Wemm continue; 847c2aa98e2SPeter Wemm 848c2aa98e2SPeter Wemm /* see if this is end of input */ 849c2aa98e2SPeter Wemm if (c == delim && anglecnt <= 0 && state != QST) 850c2aa98e2SPeter Wemm break; 851c2aa98e2SPeter Wemm 852c2aa98e2SPeter Wemm newstate = StateTab[state][toktab[c & 0xff]]; 853c2aa98e2SPeter Wemm if (tTd(22, 101)) 85440266059SGregory Neil Shapiro sm_dprintf("ns=%02o\n", newstate); 855c2aa98e2SPeter Wemm state = newstate & TYPE; 856c2aa98e2SPeter Wemm if (state == ILL) 857c2aa98e2SPeter Wemm { 858c2aa98e2SPeter Wemm if (isascii(c) && isprint(c)) 85940266059SGregory Neil Shapiro usrerr("553 Illegal character %c", c); 860c2aa98e2SPeter Wemm else 86140266059SGregory Neil Shapiro usrerr("553 Illegal character 0x%02x", 86240266059SGregory Neil Shapiro c & 0x0ff); 863c2aa98e2SPeter Wemm } 864c2aa98e2SPeter Wemm if (bitset(M, newstate)) 865c2aa98e2SPeter Wemm c = NOCHAR; 866c2aa98e2SPeter Wemm if (bitset(B, newstate)) 867c2aa98e2SPeter Wemm break; 868c2aa98e2SPeter Wemm } 869c2aa98e2SPeter Wemm 870c2aa98e2SPeter Wemm /* new token */ 871c2aa98e2SPeter Wemm if (tok != q) 872c2aa98e2SPeter Wemm { 8735ef517c0SGregory Neil Shapiro /* see if there is room */ 8745ef517c0SGregory Neil Shapiro if (q >= &pvpbuf[pvpbsize - 5]) 8755ef517c0SGregory Neil Shapiro goto addrtoolong; 876c2aa98e2SPeter Wemm *q++ = '\0'; 877c2aa98e2SPeter Wemm if (tTd(22, 36)) 878c2aa98e2SPeter Wemm { 87940266059SGregory Neil Shapiro sm_dprintf("tok="); 880e92d3f3fSGregory Neil Shapiro xputs(sm_debug_file(), tok); 88140266059SGregory Neil Shapiro sm_dprintf("\n"); 882c2aa98e2SPeter Wemm } 883c2aa98e2SPeter Wemm if (avp >= &av[MAXATOM]) 884c2aa98e2SPeter Wemm { 88506f25ae9SGregory Neil Shapiro usrerr("553 5.1.0 prescan: too many tokens"); 886c2aa98e2SPeter Wemm goto returnnull; 887c2aa98e2SPeter Wemm } 888c2aa98e2SPeter Wemm if (q - tok > MAXNAME) 889c2aa98e2SPeter Wemm { 89006f25ae9SGregory Neil Shapiro usrerr("553 5.1.0 prescan: token too long"); 891c2aa98e2SPeter Wemm goto returnnull; 892c2aa98e2SPeter Wemm } 893c2aa98e2SPeter Wemm *avp++ = tok; 894c2aa98e2SPeter Wemm } 895c2aa98e2SPeter Wemm } while (c != '\0' && (c != delim || anglecnt > 0)); 896c2aa98e2SPeter Wemm *avp = NULL; 897c2aa98e2SPeter Wemm if (delimptr != NULL) 898a7ec597cSGregory Neil Shapiro { 899a7ec597cSGregory Neil Shapiro if (p > addr) 900a7ec597cSGregory Neil Shapiro p--; 901c2aa98e2SPeter Wemm *delimptr = p; 902a7ec597cSGregory Neil Shapiro } 903c2aa98e2SPeter Wemm if (tTd(22, 12)) 904c2aa98e2SPeter Wemm { 90540266059SGregory Neil Shapiro sm_dprintf("prescan==>"); 906e92d3f3fSGregory Neil Shapiro printav(sm_debug_file(), av); 907c2aa98e2SPeter Wemm } 908c2aa98e2SPeter Wemm CurEnv->e_to = saveto; 909c2aa98e2SPeter Wemm if (av[0] == NULL) 910c2aa98e2SPeter Wemm { 911c2aa98e2SPeter Wemm if (tTd(22, 1)) 91240266059SGregory Neil Shapiro sm_dprintf("prescan: null leading token\n"); 91306f25ae9SGregory Neil Shapiro return NULL; 914c2aa98e2SPeter Wemm } 91506f25ae9SGregory Neil Shapiro return av; 916c2aa98e2SPeter Wemm } 91740266059SGregory Neil Shapiro /* 918c2aa98e2SPeter Wemm ** REWRITE -- apply rewrite rules to token vector. 919c2aa98e2SPeter Wemm ** 920c2aa98e2SPeter Wemm ** This routine is an ordered production system. Each rewrite 921c2aa98e2SPeter Wemm ** rule has a LHS (called the pattern) and a RHS (called the 922c2aa98e2SPeter Wemm ** rewrite); 'rwr' points the the current rewrite rule. 923c2aa98e2SPeter Wemm ** 924c2aa98e2SPeter Wemm ** For each rewrite rule, 'avp' points the address vector we 925c2aa98e2SPeter Wemm ** are trying to match against, and 'pvp' points to the pattern. 926c2aa98e2SPeter Wemm ** If pvp points to a special match value (MATCHZANY, MATCHANY, 927c2aa98e2SPeter Wemm ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp 928c2aa98e2SPeter Wemm ** matched is saved away in the match vector (pointed to by 'mvp'). 929c2aa98e2SPeter Wemm ** 930c2aa98e2SPeter Wemm ** When a match between avp & pvp does not match, we try to 931c2aa98e2SPeter Wemm ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS 932c2aa98e2SPeter Wemm ** we must also back out the match in mvp. If we reach a 933c2aa98e2SPeter Wemm ** MATCHANY or MATCHZANY we just extend the match and start 934c2aa98e2SPeter Wemm ** over again. 935c2aa98e2SPeter Wemm ** 936c2aa98e2SPeter Wemm ** When we finally match, we rewrite the address vector 937c2aa98e2SPeter Wemm ** and try over again. 938c2aa98e2SPeter Wemm ** 939c2aa98e2SPeter Wemm ** Parameters: 940c2aa98e2SPeter Wemm ** pvp -- pointer to token vector. 941c2aa98e2SPeter Wemm ** ruleset -- the ruleset to use for rewriting. 942c2aa98e2SPeter Wemm ** reclevel -- recursion level (to catch loops). 943c2aa98e2SPeter Wemm ** e -- the current envelope. 94440266059SGregory Neil Shapiro ** maxatom -- maximum length of buffer (usually MAXATOM) 945c2aa98e2SPeter Wemm ** 946c2aa98e2SPeter Wemm ** Returns: 947c2aa98e2SPeter Wemm ** A status code. If EX_TEMPFAIL, higher level code should 948c2aa98e2SPeter Wemm ** attempt recovery. 949c2aa98e2SPeter Wemm ** 950c2aa98e2SPeter Wemm ** Side Effects: 951c2aa98e2SPeter Wemm ** pvp is modified. 952c2aa98e2SPeter Wemm */ 953c2aa98e2SPeter Wemm 954c2aa98e2SPeter Wemm struct match 955c2aa98e2SPeter Wemm { 95606f25ae9SGregory Neil Shapiro char **match_first; /* first token matched */ 95706f25ae9SGregory Neil Shapiro char **match_last; /* last token matched */ 95806f25ae9SGregory Neil Shapiro char **match_pattern; /* pointer to pattern */ 959c2aa98e2SPeter Wemm }; 960c2aa98e2SPeter Wemm 961c2aa98e2SPeter Wemm int 96240266059SGregory Neil Shapiro rewrite(pvp, ruleset, reclevel, e, maxatom) 963c2aa98e2SPeter Wemm char **pvp; 964c2aa98e2SPeter Wemm int ruleset; 965c2aa98e2SPeter Wemm int reclevel; 966c2aa98e2SPeter Wemm register ENVELOPE *e; 96740266059SGregory Neil Shapiro int maxatom; 968c2aa98e2SPeter Wemm { 969c2aa98e2SPeter Wemm register char *ap; /* address pointer */ 970c2aa98e2SPeter Wemm register char *rp; /* rewrite pointer */ 97106f25ae9SGregory Neil Shapiro register char *rulename; /* ruleset name */ 97206f25ae9SGregory Neil Shapiro register char *prefix; 973c2aa98e2SPeter Wemm register char **avp; /* address vector pointer */ 974c2aa98e2SPeter Wemm register char **rvp; /* rewrite vector pointer */ 975c2aa98e2SPeter Wemm register struct match *mlp; /* cur ptr into mlist */ 976c2aa98e2SPeter Wemm register struct rewrite *rwr; /* pointer to current rewrite rule */ 977c2aa98e2SPeter Wemm int ruleno; /* current rule number */ 978c2aa98e2SPeter Wemm int rstat = EX_OK; /* return status */ 979c2aa98e2SPeter Wemm int loopcount; 980c2aa98e2SPeter Wemm struct match mlist[MAXMATCH]; /* stores match on LHS */ 981c2aa98e2SPeter Wemm char *npvp[MAXATOM + 1]; /* temporary space for rebuild */ 982c2aa98e2SPeter Wemm char buf[MAXLINE]; 98306f25ae9SGregory Neil Shapiro char name[6]; 984c2aa98e2SPeter Wemm 985a7ec597cSGregory Neil Shapiro /* 986a7ec597cSGregory Neil Shapiro ** mlp will not exceed mlist[] because readcf enforces 987a7ec597cSGregory Neil Shapiro ** the upper limit of entries when reading rulesets. 988a7ec597cSGregory Neil Shapiro */ 989a7ec597cSGregory Neil Shapiro 990c2aa98e2SPeter Wemm if (ruleset < 0 || ruleset >= MAXRWSETS) 991c2aa98e2SPeter Wemm { 99206f25ae9SGregory Neil Shapiro syserr("554 5.3.5 rewrite: illegal ruleset number %d", ruleset); 993c2aa98e2SPeter Wemm return EX_CONFIG; 994c2aa98e2SPeter Wemm } 99506f25ae9SGregory Neil Shapiro rulename = RuleSetNames[ruleset]; 99606f25ae9SGregory Neil Shapiro if (rulename == NULL) 99706f25ae9SGregory Neil Shapiro { 99840266059SGregory Neil Shapiro (void) sm_snprintf(name, sizeof name, "%d", ruleset); 99906f25ae9SGregory Neil Shapiro rulename = name; 100006f25ae9SGregory Neil Shapiro } 100106f25ae9SGregory Neil Shapiro if (OpMode == MD_TEST) 100206f25ae9SGregory Neil Shapiro prefix = ""; 100306f25ae9SGregory Neil Shapiro else 100406f25ae9SGregory Neil Shapiro prefix = "rewrite: ruleset "; 100506f25ae9SGregory Neil Shapiro if (OpMode == MD_TEST) 100606f25ae9SGregory Neil Shapiro { 100740266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 100840266059SGregory Neil Shapiro "%s%-16.16s input:", prefix, rulename); 1009e92d3f3fSGregory Neil Shapiro printav(smioout, pvp); 101006f25ae9SGregory Neil Shapiro } 101106f25ae9SGregory Neil Shapiro else if (tTd(21, 1)) 101206f25ae9SGregory Neil Shapiro { 101340266059SGregory Neil Shapiro sm_dprintf("%s%-16.16s input:", prefix, rulename); 1014e92d3f3fSGregory Neil Shapiro printav(sm_debug_file(), pvp); 101506f25ae9SGregory Neil Shapiro } 1016c2aa98e2SPeter Wemm if (reclevel++ > MaxRuleRecursion) 1017c2aa98e2SPeter Wemm { 101806f25ae9SGregory Neil Shapiro syserr("rewrite: excessive recursion (max %d), ruleset %s", 101906f25ae9SGregory Neil Shapiro MaxRuleRecursion, rulename); 1020c2aa98e2SPeter Wemm return EX_CONFIG; 1021c2aa98e2SPeter Wemm } 1022c2aa98e2SPeter Wemm if (pvp == NULL) 1023c2aa98e2SPeter Wemm return EX_USAGE; 1024a7ec597cSGregory Neil Shapiro if (maxatom <= 0) 1025a7ec597cSGregory Neil Shapiro return EX_USAGE; 1026c2aa98e2SPeter Wemm 1027c2aa98e2SPeter Wemm /* 1028c2aa98e2SPeter Wemm ** Run through the list of rewrite rules, applying 1029c2aa98e2SPeter Wemm ** any that match. 1030c2aa98e2SPeter Wemm */ 1031c2aa98e2SPeter Wemm 1032c2aa98e2SPeter Wemm ruleno = 1; 1033c2aa98e2SPeter Wemm loopcount = 0; 1034c2aa98e2SPeter Wemm for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 1035c2aa98e2SPeter Wemm { 103606f25ae9SGregory Neil Shapiro int status; 1037c2aa98e2SPeter Wemm 1038c2aa98e2SPeter Wemm /* if already canonical, quit now */ 1039c2aa98e2SPeter Wemm if (pvp[0] != NULL && (pvp[0][0] & 0377) == CANONNET) 1040c2aa98e2SPeter Wemm break; 1041c2aa98e2SPeter Wemm 1042c2aa98e2SPeter Wemm if (tTd(21, 12)) 1043c2aa98e2SPeter Wemm { 104406f25ae9SGregory Neil Shapiro if (tTd(21, 15)) 104540266059SGregory Neil Shapiro sm_dprintf("-----trying rule (line %d):", 104606f25ae9SGregory Neil Shapiro rwr->r_line); 104706f25ae9SGregory Neil Shapiro else 104840266059SGregory Neil Shapiro sm_dprintf("-----trying rule:"); 1049e92d3f3fSGregory Neil Shapiro printav(sm_debug_file(), rwr->r_lhs); 1050c2aa98e2SPeter Wemm } 1051c2aa98e2SPeter Wemm 1052c2aa98e2SPeter Wemm /* try to match on this rule */ 1053c2aa98e2SPeter Wemm mlp = mlist; 1054c2aa98e2SPeter Wemm rvp = rwr->r_lhs; 1055c2aa98e2SPeter Wemm avp = pvp; 1056c2aa98e2SPeter Wemm if (++loopcount > 100) 1057c2aa98e2SPeter Wemm { 105806f25ae9SGregory Neil Shapiro syserr("554 5.3.5 Infinite loop in ruleset %s, rule %d", 105906f25ae9SGregory Neil Shapiro rulename, ruleno); 1060c2aa98e2SPeter Wemm if (tTd(21, 1)) 1061c2aa98e2SPeter Wemm { 106240266059SGregory Neil Shapiro sm_dprintf("workspace: "); 1063e92d3f3fSGregory Neil Shapiro printav(sm_debug_file(), pvp); 1064c2aa98e2SPeter Wemm } 1065c2aa98e2SPeter Wemm break; 1066c2aa98e2SPeter Wemm } 1067c2aa98e2SPeter Wemm 1068c2aa98e2SPeter Wemm while ((ap = *avp) != NULL || *rvp != NULL) 1069c2aa98e2SPeter Wemm { 1070c2aa98e2SPeter Wemm rp = *rvp; 1071c2aa98e2SPeter Wemm if (tTd(21, 35)) 1072c2aa98e2SPeter Wemm { 107340266059SGregory Neil Shapiro sm_dprintf("ADVANCE rp="); 1074e92d3f3fSGregory Neil Shapiro xputs(sm_debug_file(), rp); 107540266059SGregory Neil Shapiro sm_dprintf(", ap="); 1076e92d3f3fSGregory Neil Shapiro xputs(sm_debug_file(), ap); 107740266059SGregory Neil Shapiro sm_dprintf("\n"); 1078c2aa98e2SPeter Wemm } 1079c2aa98e2SPeter Wemm if (rp == NULL) 1080c2aa98e2SPeter Wemm { 1081c2aa98e2SPeter Wemm /* end-of-pattern before end-of-address */ 1082c2aa98e2SPeter Wemm goto backup; 1083c2aa98e2SPeter Wemm } 1084c2aa98e2SPeter Wemm if (ap == NULL && (*rp & 0377) != MATCHZANY && 1085c2aa98e2SPeter Wemm (*rp & 0377) != MATCHZERO) 1086c2aa98e2SPeter Wemm { 1087c2aa98e2SPeter Wemm /* end-of-input with patterns left */ 1088c2aa98e2SPeter Wemm goto backup; 1089c2aa98e2SPeter Wemm } 1090c2aa98e2SPeter Wemm 1091c2aa98e2SPeter Wemm switch (*rp & 0377) 1092c2aa98e2SPeter Wemm { 1093c2aa98e2SPeter Wemm case MATCHCLASS: 1094c2aa98e2SPeter Wemm /* match any phrase in a class */ 109506f25ae9SGregory Neil Shapiro mlp->match_pattern = rvp; 109606f25ae9SGregory Neil Shapiro mlp->match_first = avp; 1097c2aa98e2SPeter Wemm extendclass: 1098c2aa98e2SPeter Wemm ap = *avp; 1099c2aa98e2SPeter Wemm if (ap == NULL) 1100c2aa98e2SPeter Wemm goto backup; 110106f25ae9SGregory Neil Shapiro mlp->match_last = avp++; 110206f25ae9SGregory Neil Shapiro cataddr(mlp->match_first, mlp->match_last, 110306f25ae9SGregory Neil Shapiro buf, sizeof buf, '\0'); 1104c2aa98e2SPeter Wemm if (!wordinclass(buf, rp[1])) 1105c2aa98e2SPeter Wemm { 1106c2aa98e2SPeter Wemm if (tTd(21, 36)) 1107c2aa98e2SPeter Wemm { 110840266059SGregory Neil Shapiro sm_dprintf("EXTEND rp="); 1109e92d3f3fSGregory Neil Shapiro xputs(sm_debug_file(), rp); 111040266059SGregory Neil Shapiro sm_dprintf(", ap="); 1111e92d3f3fSGregory Neil Shapiro xputs(sm_debug_file(), ap); 111240266059SGregory Neil Shapiro sm_dprintf("\n"); 1113c2aa98e2SPeter Wemm } 1114c2aa98e2SPeter Wemm goto extendclass; 1115c2aa98e2SPeter Wemm } 1116c2aa98e2SPeter Wemm if (tTd(21, 36)) 111740266059SGregory Neil Shapiro sm_dprintf("CLMATCH\n"); 1118c2aa98e2SPeter Wemm mlp++; 1119c2aa98e2SPeter Wemm break; 1120c2aa98e2SPeter Wemm 1121c2aa98e2SPeter Wemm case MATCHNCLASS: 1122c2aa98e2SPeter Wemm /* match any token not in a class */ 1123c2aa98e2SPeter Wemm if (wordinclass(ap, rp[1])) 1124c2aa98e2SPeter Wemm goto backup; 1125c2aa98e2SPeter Wemm 112606f25ae9SGregory Neil Shapiro /* FALLTHROUGH */ 1127c2aa98e2SPeter Wemm 1128c2aa98e2SPeter Wemm case MATCHONE: 1129c2aa98e2SPeter Wemm case MATCHANY: 1130c2aa98e2SPeter Wemm /* match exactly one token */ 113106f25ae9SGregory Neil Shapiro mlp->match_pattern = rvp; 113206f25ae9SGregory Neil Shapiro mlp->match_first = avp; 113306f25ae9SGregory Neil Shapiro mlp->match_last = avp++; 1134c2aa98e2SPeter Wemm mlp++; 1135c2aa98e2SPeter Wemm break; 1136c2aa98e2SPeter Wemm 1137c2aa98e2SPeter Wemm case MATCHZANY: 1138c2aa98e2SPeter Wemm /* match zero or more tokens */ 113906f25ae9SGregory Neil Shapiro mlp->match_pattern = rvp; 114006f25ae9SGregory Neil Shapiro mlp->match_first = avp; 114106f25ae9SGregory Neil Shapiro mlp->match_last = avp - 1; 1142c2aa98e2SPeter Wemm mlp++; 1143c2aa98e2SPeter Wemm break; 1144c2aa98e2SPeter Wemm 1145c2aa98e2SPeter Wemm case MATCHZERO: 1146c2aa98e2SPeter Wemm /* match zero tokens */ 1147c2aa98e2SPeter Wemm break; 1148c2aa98e2SPeter Wemm 1149c2aa98e2SPeter Wemm case MACRODEXPAND: 1150c2aa98e2SPeter Wemm /* 1151c2aa98e2SPeter Wemm ** Match against run-time macro. 1152c2aa98e2SPeter Wemm ** This algorithm is broken for the 1153c2aa98e2SPeter Wemm ** general case (no recursive macros, 1154c2aa98e2SPeter Wemm ** improper tokenization) but should 1155c2aa98e2SPeter Wemm ** work for the usual cases. 1156c2aa98e2SPeter Wemm */ 1157c2aa98e2SPeter Wemm 1158c2aa98e2SPeter Wemm ap = macvalue(rp[1], e); 115906f25ae9SGregory Neil Shapiro mlp->match_first = avp; 1160c2aa98e2SPeter Wemm if (tTd(21, 2)) 1161739ac4d4SGregory Neil Shapiro sm_dprintf("rewrite: LHS $&{%s} => \"%s\"\n", 1162c2aa98e2SPeter Wemm macname(rp[1]), 1163c2aa98e2SPeter Wemm ap == NULL ? "(NULL)" : ap); 1164c2aa98e2SPeter Wemm 1165c2aa98e2SPeter Wemm if (ap == NULL) 1166c2aa98e2SPeter Wemm break; 1167c2aa98e2SPeter Wemm while (*ap != '\0') 1168c2aa98e2SPeter Wemm { 1169c2aa98e2SPeter Wemm if (*avp == NULL || 117040266059SGregory Neil Shapiro sm_strncasecmp(ap, *avp, 117140266059SGregory Neil Shapiro strlen(*avp)) != 0) 1172c2aa98e2SPeter Wemm { 1173c2aa98e2SPeter Wemm /* no match */ 117406f25ae9SGregory Neil Shapiro avp = mlp->match_first; 1175c2aa98e2SPeter Wemm goto backup; 1176c2aa98e2SPeter Wemm } 1177c2aa98e2SPeter Wemm ap += strlen(*avp++); 1178c2aa98e2SPeter Wemm } 1179c2aa98e2SPeter Wemm 1180c2aa98e2SPeter Wemm /* match */ 1181c2aa98e2SPeter Wemm break; 1182c2aa98e2SPeter Wemm 1183c2aa98e2SPeter Wemm default: 1184c2aa98e2SPeter Wemm /* must have exact match */ 1185c2aa98e2SPeter Wemm if (sm_strcasecmp(rp, ap)) 1186c2aa98e2SPeter Wemm goto backup; 1187c2aa98e2SPeter Wemm avp++; 1188c2aa98e2SPeter Wemm break; 1189c2aa98e2SPeter Wemm } 1190c2aa98e2SPeter Wemm 1191c2aa98e2SPeter Wemm /* successful match on this token */ 1192c2aa98e2SPeter Wemm rvp++; 1193c2aa98e2SPeter Wemm continue; 1194c2aa98e2SPeter Wemm 1195c2aa98e2SPeter Wemm backup: 1196c2aa98e2SPeter Wemm /* match failed -- back up */ 1197c2aa98e2SPeter Wemm while (--mlp >= mlist) 1198c2aa98e2SPeter Wemm { 119906f25ae9SGregory Neil Shapiro rvp = mlp->match_pattern; 1200c2aa98e2SPeter Wemm rp = *rvp; 120106f25ae9SGregory Neil Shapiro avp = mlp->match_last + 1; 1202c2aa98e2SPeter Wemm ap = *avp; 1203c2aa98e2SPeter Wemm 1204c2aa98e2SPeter Wemm if (tTd(21, 36)) 1205c2aa98e2SPeter Wemm { 120640266059SGregory Neil Shapiro sm_dprintf("BACKUP rp="); 1207e92d3f3fSGregory Neil Shapiro xputs(sm_debug_file(), rp); 120840266059SGregory Neil Shapiro sm_dprintf(", ap="); 1209e92d3f3fSGregory Neil Shapiro xputs(sm_debug_file(), ap); 121040266059SGregory Neil Shapiro sm_dprintf("\n"); 1211c2aa98e2SPeter Wemm } 1212c2aa98e2SPeter Wemm 1213c2aa98e2SPeter Wemm if (ap == NULL) 1214c2aa98e2SPeter Wemm { 1215c2aa98e2SPeter Wemm /* run off the end -- back up again */ 1216c2aa98e2SPeter Wemm continue; 1217c2aa98e2SPeter Wemm } 1218c2aa98e2SPeter Wemm if ((*rp & 0377) == MATCHANY || 1219c2aa98e2SPeter Wemm (*rp & 0377) == MATCHZANY) 1220c2aa98e2SPeter Wemm { 1221c2aa98e2SPeter Wemm /* extend binding and continue */ 122206f25ae9SGregory Neil Shapiro mlp->match_last = avp++; 1223c2aa98e2SPeter Wemm rvp++; 1224c2aa98e2SPeter Wemm mlp++; 1225c2aa98e2SPeter Wemm break; 1226c2aa98e2SPeter Wemm } 1227c2aa98e2SPeter Wemm if ((*rp & 0377) == MATCHCLASS) 1228c2aa98e2SPeter Wemm { 1229c2aa98e2SPeter Wemm /* extend binding and try again */ 123006f25ae9SGregory Neil Shapiro mlp->match_last = avp; 1231c2aa98e2SPeter Wemm goto extendclass; 1232c2aa98e2SPeter Wemm } 1233c2aa98e2SPeter Wemm } 1234c2aa98e2SPeter Wemm 1235c2aa98e2SPeter Wemm if (mlp < mlist) 1236c2aa98e2SPeter Wemm { 1237c2aa98e2SPeter Wemm /* total failure to match */ 1238c2aa98e2SPeter Wemm break; 1239c2aa98e2SPeter Wemm } 1240c2aa98e2SPeter Wemm } 1241c2aa98e2SPeter Wemm 1242c2aa98e2SPeter Wemm /* 1243c2aa98e2SPeter Wemm ** See if we successfully matched 1244c2aa98e2SPeter Wemm */ 1245c2aa98e2SPeter Wemm 1246c2aa98e2SPeter Wemm if (mlp < mlist || *rvp != NULL) 1247c2aa98e2SPeter Wemm { 1248c2aa98e2SPeter Wemm if (tTd(21, 10)) 124940266059SGregory Neil Shapiro sm_dprintf("----- rule fails\n"); 1250c2aa98e2SPeter Wemm rwr = rwr->r_next; 1251c2aa98e2SPeter Wemm ruleno++; 1252c2aa98e2SPeter Wemm loopcount = 0; 1253c2aa98e2SPeter Wemm continue; 1254c2aa98e2SPeter Wemm } 1255c2aa98e2SPeter Wemm 1256c2aa98e2SPeter Wemm rvp = rwr->r_rhs; 1257c2aa98e2SPeter Wemm if (tTd(21, 12)) 1258c2aa98e2SPeter Wemm { 125940266059SGregory Neil Shapiro sm_dprintf("-----rule matches:"); 1260e92d3f3fSGregory Neil Shapiro printav(sm_debug_file(), rvp); 1261c2aa98e2SPeter Wemm } 1262c2aa98e2SPeter Wemm 1263c2aa98e2SPeter Wemm rp = *rvp; 126406f25ae9SGregory Neil Shapiro if (rp != NULL) 126506f25ae9SGregory Neil Shapiro { 1266c2aa98e2SPeter Wemm if ((*rp & 0377) == CANONUSER) 1267c2aa98e2SPeter Wemm { 1268c2aa98e2SPeter Wemm rvp++; 1269c2aa98e2SPeter Wemm rwr = rwr->r_next; 1270c2aa98e2SPeter Wemm ruleno++; 1271c2aa98e2SPeter Wemm loopcount = 0; 1272c2aa98e2SPeter Wemm } 1273c2aa98e2SPeter Wemm else if ((*rp & 0377) == CANONHOST) 1274c2aa98e2SPeter Wemm { 1275c2aa98e2SPeter Wemm rvp++; 1276c2aa98e2SPeter Wemm rwr = NULL; 1277c2aa98e2SPeter Wemm } 127806f25ae9SGregory Neil Shapiro } 1279c2aa98e2SPeter Wemm 1280c2aa98e2SPeter Wemm /* substitute */ 1281c2aa98e2SPeter Wemm for (avp = npvp; *rvp != NULL; rvp++) 1282c2aa98e2SPeter Wemm { 1283c2aa98e2SPeter Wemm register struct match *m; 1284c2aa98e2SPeter Wemm register char **pp; 1285c2aa98e2SPeter Wemm 1286c2aa98e2SPeter Wemm rp = *rvp; 1287c2aa98e2SPeter Wemm if ((*rp & 0377) == MATCHREPL) 1288c2aa98e2SPeter Wemm { 1289c2aa98e2SPeter Wemm /* substitute from LHS */ 1290c2aa98e2SPeter Wemm m = &mlist[rp[1] - '1']; 1291c2aa98e2SPeter Wemm if (m < mlist || m >= mlp) 1292c2aa98e2SPeter Wemm { 129306f25ae9SGregory Neil Shapiro syserr("554 5.3.5 rewrite: ruleset %s: replacement $%c out of bounds", 129406f25ae9SGregory Neil Shapiro rulename, rp[1]); 1295c2aa98e2SPeter Wemm return EX_CONFIG; 1296c2aa98e2SPeter Wemm } 1297c2aa98e2SPeter Wemm if (tTd(21, 15)) 1298c2aa98e2SPeter Wemm { 129940266059SGregory Neil Shapiro sm_dprintf("$%c:", rp[1]); 130006f25ae9SGregory Neil Shapiro pp = m->match_first; 130106f25ae9SGregory Neil Shapiro while (pp <= m->match_last) 1302c2aa98e2SPeter Wemm { 130340266059SGregory Neil Shapiro sm_dprintf(" %p=\"", *pp); 130440266059SGregory Neil Shapiro sm_dflush(); 130540266059SGregory Neil Shapiro sm_dprintf("%s\"", *pp++); 1306c2aa98e2SPeter Wemm } 130740266059SGregory Neil Shapiro sm_dprintf("\n"); 1308c2aa98e2SPeter Wemm } 130906f25ae9SGregory Neil Shapiro pp = m->match_first; 131006f25ae9SGregory Neil Shapiro while (pp <= m->match_last) 1311c2aa98e2SPeter Wemm { 131240266059SGregory Neil Shapiro if (avp >= &npvp[maxatom]) 1313a7ec597cSGregory Neil Shapiro goto toolong; 1314c2aa98e2SPeter Wemm *avp++ = *pp++; 1315c2aa98e2SPeter Wemm } 1316c2aa98e2SPeter Wemm } 1317c2aa98e2SPeter Wemm else 1318c2aa98e2SPeter Wemm { 1319c2aa98e2SPeter Wemm /* some sort of replacement */ 132040266059SGregory Neil Shapiro if (avp >= &npvp[maxatom]) 1321c2aa98e2SPeter Wemm { 1322c2aa98e2SPeter Wemm toolong: 132306f25ae9SGregory Neil Shapiro syserr("554 5.3.0 rewrite: expansion too long"); 132440266059SGregory Neil Shapiro if (LogLevel > 9) 132540266059SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 132640266059SGregory Neil Shapiro "rewrite: expansion too long, ruleset=%s, ruleno=%d", 132740266059SGregory Neil Shapiro rulename, ruleno); 1328c2aa98e2SPeter Wemm return EX_DATAERR; 1329c2aa98e2SPeter Wemm } 1330c2aa98e2SPeter Wemm if ((*rp & 0377) != MACRODEXPAND) 1331c2aa98e2SPeter Wemm { 1332c2aa98e2SPeter Wemm /* vanilla replacement */ 1333c2aa98e2SPeter Wemm *avp++ = rp; 1334c2aa98e2SPeter Wemm } 1335c2aa98e2SPeter Wemm else 1336c2aa98e2SPeter Wemm { 1337739ac4d4SGregory Neil Shapiro /* $&{x} replacement */ 1338c2aa98e2SPeter Wemm char *mval = macvalue(rp[1], e); 1339c2aa98e2SPeter Wemm char **xpvp; 13404e4196cbSGregory Neil Shapiro size_t trsize = 0; 1341c2aa98e2SPeter Wemm static size_t pvpb1_size = 0; 1342c2aa98e2SPeter Wemm static char **pvpb1 = NULL; 1343c2aa98e2SPeter Wemm char pvpbuf[PSBUFSIZE]; 1344c2aa98e2SPeter Wemm 1345c2aa98e2SPeter Wemm if (tTd(21, 2)) 1346739ac4d4SGregory Neil Shapiro sm_dprintf("rewrite: RHS $&{%s} => \"%s\"\n", 1347c2aa98e2SPeter Wemm macname(rp[1]), 1348c2aa98e2SPeter Wemm mval == NULL ? "(NULL)" : mval); 1349c2aa98e2SPeter Wemm if (mval == NULL || *mval == '\0') 1350c2aa98e2SPeter Wemm continue; 1351c2aa98e2SPeter Wemm 1352c2aa98e2SPeter Wemm /* save the remainder of the input */ 1353c2aa98e2SPeter Wemm for (xpvp = pvp; *xpvp != NULL; xpvp++) 1354c2aa98e2SPeter Wemm trsize += sizeof *xpvp; 13554e4196cbSGregory Neil Shapiro if (trsize > pvpb1_size) 1356c2aa98e2SPeter Wemm { 1357c2aa98e2SPeter Wemm if (pvpb1 != NULL) 13588774250cSGregory Neil Shapiro sm_free(pvpb1); 135940266059SGregory Neil Shapiro pvpb1 = (char **) 136040266059SGregory Neil Shapiro sm_pmalloc_x(trsize); 1361c2aa98e2SPeter Wemm pvpb1_size = trsize; 1362c2aa98e2SPeter Wemm } 1363c2aa98e2SPeter Wemm 136406f25ae9SGregory Neil Shapiro memmove((char *) pvpb1, 136506f25ae9SGregory Neil Shapiro (char *) pvp, 136606f25ae9SGregory Neil Shapiro trsize); 1367c2aa98e2SPeter Wemm 1368c2aa98e2SPeter Wemm /* scan the new replacement */ 1369c2aa98e2SPeter Wemm xpvp = prescan(mval, '\0', pvpbuf, 137006f25ae9SGregory Neil Shapiro sizeof pvpbuf, NULL, 1371e92d3f3fSGregory Neil Shapiro NULL, false); 1372c2aa98e2SPeter Wemm if (xpvp == NULL) 1373c2aa98e2SPeter Wemm { 1374c2aa98e2SPeter Wemm /* prescan pre-printed error */ 1375c2aa98e2SPeter Wemm return EX_DATAERR; 1376c2aa98e2SPeter Wemm } 1377c2aa98e2SPeter Wemm 1378c2aa98e2SPeter Wemm /* insert it into the output stream */ 1379c2aa98e2SPeter Wemm while (*xpvp != NULL) 1380c2aa98e2SPeter Wemm { 1381c2aa98e2SPeter Wemm if (tTd(21, 19)) 138240266059SGregory Neil Shapiro sm_dprintf(" ... %s\n", 138306f25ae9SGregory Neil Shapiro *xpvp); 138440266059SGregory Neil Shapiro *avp++ = sm_rpool_strdup_x( 138540266059SGregory Neil Shapiro e->e_rpool, *xpvp); 138640266059SGregory Neil Shapiro if (avp >= &npvp[maxatom]) 1387c2aa98e2SPeter Wemm goto toolong; 1388c2aa98e2SPeter Wemm xpvp++; 1389c2aa98e2SPeter Wemm } 1390c2aa98e2SPeter Wemm if (tTd(21, 19)) 139140266059SGregory Neil Shapiro sm_dprintf(" ... DONE\n"); 1392c2aa98e2SPeter Wemm 1393c2aa98e2SPeter Wemm /* restore the old trailing input */ 139406f25ae9SGregory Neil Shapiro memmove((char *) pvp, 139506f25ae9SGregory Neil Shapiro (char *) pvpb1, 139606f25ae9SGregory Neil Shapiro trsize); 1397c2aa98e2SPeter Wemm } 1398c2aa98e2SPeter Wemm } 1399c2aa98e2SPeter Wemm } 1400c2aa98e2SPeter Wemm *avp++ = NULL; 1401c2aa98e2SPeter Wemm 1402c2aa98e2SPeter Wemm /* 1403c2aa98e2SPeter Wemm ** Check for any hostname/keyword lookups. 1404c2aa98e2SPeter Wemm */ 1405c2aa98e2SPeter Wemm 1406c2aa98e2SPeter Wemm for (rvp = npvp; *rvp != NULL; rvp++) 1407c2aa98e2SPeter Wemm { 1408c2aa98e2SPeter Wemm char **hbrvp; 1409c2aa98e2SPeter Wemm char **xpvp; 14104e4196cbSGregory Neil Shapiro size_t trsize; 1411c2aa98e2SPeter Wemm char *replac; 1412c2aa98e2SPeter Wemm int endtoken; 1413c2aa98e2SPeter Wemm STAB *map; 1414c2aa98e2SPeter Wemm char *mapname; 1415c2aa98e2SPeter Wemm char **key_rvp; 1416c2aa98e2SPeter Wemm char **arg_rvp; 1417c2aa98e2SPeter Wemm char **default_rvp; 14184e4196cbSGregory Neil Shapiro char cbuf[MAXKEY]; 1419c2aa98e2SPeter Wemm char *pvpb1[MAXATOM + 1]; 1420a7ec597cSGregory Neil Shapiro char *argvect[MAX_MAP_ARGS]; 1421c2aa98e2SPeter Wemm char pvpbuf[PSBUFSIZE]; 1422c2aa98e2SPeter Wemm char *nullpvp[1]; 1423c2aa98e2SPeter Wemm 1424c2aa98e2SPeter Wemm if ((**rvp & 0377) != HOSTBEGIN && 1425c2aa98e2SPeter Wemm (**rvp & 0377) != LOOKUPBEGIN) 1426c2aa98e2SPeter Wemm continue; 1427c2aa98e2SPeter Wemm 1428c2aa98e2SPeter Wemm /* 1429c2aa98e2SPeter Wemm ** Got a hostname/keyword lookup. 1430c2aa98e2SPeter Wemm ** 1431c2aa98e2SPeter Wemm ** This could be optimized fairly easily. 1432c2aa98e2SPeter Wemm */ 1433c2aa98e2SPeter Wemm 1434c2aa98e2SPeter Wemm hbrvp = rvp; 1435c2aa98e2SPeter Wemm if ((**rvp & 0377) == HOSTBEGIN) 1436c2aa98e2SPeter Wemm { 1437c2aa98e2SPeter Wemm endtoken = HOSTEND; 1438c2aa98e2SPeter Wemm mapname = "host"; 1439c2aa98e2SPeter Wemm } 1440c2aa98e2SPeter Wemm else 1441c2aa98e2SPeter Wemm { 1442c2aa98e2SPeter Wemm endtoken = LOOKUPEND; 1443c2aa98e2SPeter Wemm mapname = *++rvp; 1444a7ec597cSGregory Neil Shapiro if (mapname == NULL) 1445af9557fdSGregory Neil Shapiro { 1446a7ec597cSGregory Neil Shapiro syserr("554 5.3.0 rewrite: missing mapname"); 1447af9557fdSGregory Neil Shapiro /* NOTREACHED */ 1448af9557fdSGregory Neil Shapiro SM_ASSERT(0); 1449af9557fdSGregory Neil Shapiro } 1450c2aa98e2SPeter Wemm } 1451c2aa98e2SPeter Wemm map = stab(mapname, ST_MAP, ST_FIND); 1452c2aa98e2SPeter Wemm if (map == NULL) 1453a7ec597cSGregory Neil Shapiro syserr("554 5.3.0 rewrite: map %s not found", 1454a7ec597cSGregory Neil Shapiro mapname); 1455c2aa98e2SPeter Wemm 1456c2aa98e2SPeter Wemm /* extract the match part */ 1457c2aa98e2SPeter Wemm key_rvp = ++rvp; 1458a7ec597cSGregory Neil Shapiro if (key_rvp == NULL) 1459af9557fdSGregory Neil Shapiro { 1460a7ec597cSGregory Neil Shapiro syserr("554 5.3.0 rewrite: missing key for map %s", 1461a7ec597cSGregory Neil Shapiro mapname); 1462af9557fdSGregory Neil Shapiro /* NOTREACHED */ 1463af9557fdSGregory Neil Shapiro SM_ASSERT(0); 1464af9557fdSGregory Neil Shapiro } 1465c2aa98e2SPeter Wemm default_rvp = NULL; 1466c2aa98e2SPeter Wemm arg_rvp = argvect; 1467c2aa98e2SPeter Wemm xpvp = NULL; 1468c2aa98e2SPeter Wemm replac = pvpbuf; 1469c2aa98e2SPeter Wemm while (*rvp != NULL && (**rvp & 0377) != endtoken) 1470c2aa98e2SPeter Wemm { 1471c2aa98e2SPeter Wemm int nodetype = **rvp & 0377; 1472c2aa98e2SPeter Wemm 1473a7ec597cSGregory Neil Shapiro if (nodetype != CANONHOST && 1474a7ec597cSGregory Neil Shapiro nodetype != CANONUSER) 1475c2aa98e2SPeter Wemm { 1476c2aa98e2SPeter Wemm rvp++; 1477c2aa98e2SPeter Wemm continue; 1478c2aa98e2SPeter Wemm } 1479c2aa98e2SPeter Wemm 1480c2aa98e2SPeter Wemm *rvp++ = NULL; 1481c2aa98e2SPeter Wemm 1482c2aa98e2SPeter Wemm if (xpvp != NULL) 1483c2aa98e2SPeter Wemm { 1484c2aa98e2SPeter Wemm cataddr(xpvp, NULL, replac, 1485c2aa98e2SPeter Wemm &pvpbuf[sizeof pvpbuf] - replac, 1486c2aa98e2SPeter Wemm '\0'); 1487a7ec597cSGregory Neil Shapiro if (arg_rvp < 1488a7ec597cSGregory Neil Shapiro &argvect[MAX_MAP_ARGS - 1]) 1489c2aa98e2SPeter Wemm *++arg_rvp = replac; 1490c2aa98e2SPeter Wemm replac += strlen(replac) + 1; 1491c2aa98e2SPeter Wemm xpvp = NULL; 1492c2aa98e2SPeter Wemm } 1493c2aa98e2SPeter Wemm switch (nodetype) 1494c2aa98e2SPeter Wemm { 1495c2aa98e2SPeter Wemm case CANONHOST: 1496c2aa98e2SPeter Wemm xpvp = rvp; 1497c2aa98e2SPeter Wemm break; 1498c2aa98e2SPeter Wemm 1499c2aa98e2SPeter Wemm case CANONUSER: 1500c2aa98e2SPeter Wemm default_rvp = rvp; 1501c2aa98e2SPeter Wemm break; 1502c2aa98e2SPeter Wemm } 1503c2aa98e2SPeter Wemm } 1504c2aa98e2SPeter Wemm if (*rvp != NULL) 1505c2aa98e2SPeter Wemm *rvp++ = NULL; 1506c2aa98e2SPeter Wemm if (xpvp != NULL) 1507c2aa98e2SPeter Wemm { 1508c2aa98e2SPeter Wemm cataddr(xpvp, NULL, replac, 1509c2aa98e2SPeter Wemm &pvpbuf[sizeof pvpbuf] - replac, 1510c2aa98e2SPeter Wemm '\0'); 1511a7ec597cSGregory Neil Shapiro if (arg_rvp < &argvect[MAX_MAP_ARGS - 1]) 1512c2aa98e2SPeter Wemm *++arg_rvp = replac; 1513c2aa98e2SPeter Wemm } 1514a7ec597cSGregory Neil Shapiro if (arg_rvp >= &argvect[MAX_MAP_ARGS - 1]) 1515a7ec597cSGregory Neil Shapiro argvect[MAX_MAP_ARGS - 1] = NULL; 1516a7ec597cSGregory Neil Shapiro else 1517c2aa98e2SPeter Wemm *++arg_rvp = NULL; 1518c2aa98e2SPeter Wemm 1519c2aa98e2SPeter Wemm /* save the remainder of the input string */ 15204e4196cbSGregory Neil Shapiro trsize = (avp - rvp + 1) * sizeof *rvp; 152106f25ae9SGregory Neil Shapiro memmove((char *) pvpb1, (char *) rvp, trsize); 1522c2aa98e2SPeter Wemm 1523c2aa98e2SPeter Wemm /* look it up */ 152406f25ae9SGregory Neil Shapiro cataddr(key_rvp, NULL, cbuf, sizeof cbuf, 152506f25ae9SGregory Neil Shapiro map == NULL ? '\0' : map->s_map.map_spacesub); 152606f25ae9SGregory Neil Shapiro argvect[0] = cbuf; 152706f25ae9SGregory Neil Shapiro replac = map_lookup(map, cbuf, argvect, &rstat, e); 1528c2aa98e2SPeter Wemm 1529c2aa98e2SPeter Wemm /* if no replacement, use default */ 1530c2aa98e2SPeter Wemm if (replac == NULL && default_rvp != NULL) 1531c2aa98e2SPeter Wemm { 1532c2aa98e2SPeter Wemm /* create the default */ 1533af9557fdSGregory Neil Shapiro cataddr(default_rvp, NULL, cbuf, sizeof cbuf, 1534af9557fdSGregory Neil Shapiro '\0'); 153506f25ae9SGregory Neil Shapiro replac = cbuf; 1536c2aa98e2SPeter Wemm } 1537c2aa98e2SPeter Wemm 1538c2aa98e2SPeter Wemm if (replac == NULL) 1539c2aa98e2SPeter Wemm { 1540c2aa98e2SPeter Wemm xpvp = key_rvp; 1541c2aa98e2SPeter Wemm } 1542c2aa98e2SPeter Wemm else if (*replac == '\0') 1543c2aa98e2SPeter Wemm { 1544c2aa98e2SPeter Wemm /* null replacement */ 1545c2aa98e2SPeter Wemm nullpvp[0] = NULL; 1546c2aa98e2SPeter Wemm xpvp = nullpvp; 1547c2aa98e2SPeter Wemm } 1548c2aa98e2SPeter Wemm else 1549c2aa98e2SPeter Wemm { 1550c2aa98e2SPeter Wemm /* scan the new replacement */ 1551c2aa98e2SPeter Wemm xpvp = prescan(replac, '\0', pvpbuf, 1552e92d3f3fSGregory Neil Shapiro sizeof pvpbuf, NULL, NULL, false); 1553c2aa98e2SPeter Wemm if (xpvp == NULL) 1554c2aa98e2SPeter Wemm { 1555c2aa98e2SPeter Wemm /* prescan already printed error */ 1556c2aa98e2SPeter Wemm return EX_DATAERR; 1557c2aa98e2SPeter Wemm } 1558c2aa98e2SPeter Wemm } 1559c2aa98e2SPeter Wemm 1560c2aa98e2SPeter Wemm /* append it to the token list */ 1561c2aa98e2SPeter Wemm for (avp = hbrvp; *xpvp != NULL; xpvp++) 1562c2aa98e2SPeter Wemm { 156340266059SGregory Neil Shapiro *avp++ = sm_rpool_strdup_x(e->e_rpool, *xpvp); 156440266059SGregory Neil Shapiro if (avp >= &npvp[maxatom]) 1565c2aa98e2SPeter Wemm goto toolong; 1566c2aa98e2SPeter Wemm } 1567c2aa98e2SPeter Wemm 1568c2aa98e2SPeter Wemm /* restore the old trailing information */ 1569c2aa98e2SPeter Wemm rvp = avp - 1; 1570c2aa98e2SPeter Wemm for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) 157140266059SGregory Neil Shapiro if (avp >= &npvp[maxatom]) 1572c2aa98e2SPeter Wemm goto toolong; 1573c2aa98e2SPeter Wemm } 1574c2aa98e2SPeter Wemm 1575c2aa98e2SPeter Wemm /* 1576c2aa98e2SPeter Wemm ** Check for subroutine calls. 1577c2aa98e2SPeter Wemm */ 1578c2aa98e2SPeter Wemm 157906f25ae9SGregory Neil Shapiro status = callsubr(npvp, reclevel, e); 158006f25ae9SGregory Neil Shapiro if (rstat == EX_OK || status == EX_TEMPFAIL) 158106f25ae9SGregory Neil Shapiro rstat = status; 1582c2aa98e2SPeter Wemm 1583c2aa98e2SPeter Wemm /* copy vector back into original space. */ 1584c2aa98e2SPeter Wemm for (avp = npvp; *avp++ != NULL;) 1585c2aa98e2SPeter Wemm continue; 158606f25ae9SGregory Neil Shapiro memmove((char *) pvp, (char *) npvp, 1587c2aa98e2SPeter Wemm (int) (avp - npvp) * sizeof *avp); 1588c2aa98e2SPeter Wemm 1589c2aa98e2SPeter Wemm if (tTd(21, 4)) 1590c2aa98e2SPeter Wemm { 159140266059SGregory Neil Shapiro sm_dprintf("rewritten as:"); 1592e92d3f3fSGregory Neil Shapiro printav(sm_debug_file(), pvp); 1593c2aa98e2SPeter Wemm } 1594c2aa98e2SPeter Wemm } 1595c2aa98e2SPeter Wemm 159606f25ae9SGregory Neil Shapiro if (OpMode == MD_TEST) 1597c2aa98e2SPeter Wemm { 159840266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 159940266059SGregory Neil Shapiro "%s%-16.16s returns:", prefix, rulename); 1600e92d3f3fSGregory Neil Shapiro printav(smioout, pvp); 1601c2aa98e2SPeter Wemm } 160206f25ae9SGregory Neil Shapiro else if (tTd(21, 1)) 160306f25ae9SGregory Neil Shapiro { 160440266059SGregory Neil Shapiro sm_dprintf("%s%-16.16s returns:", prefix, rulename); 1605e92d3f3fSGregory Neil Shapiro printav(sm_debug_file(), pvp); 160606f25ae9SGregory Neil Shapiro } 1607c2aa98e2SPeter Wemm return rstat; 1608c2aa98e2SPeter Wemm } 160940266059SGregory Neil Shapiro /* 1610c2aa98e2SPeter Wemm ** CALLSUBR -- call subroutines in rewrite vector 1611c2aa98e2SPeter Wemm ** 1612c2aa98e2SPeter Wemm ** Parameters: 1613c2aa98e2SPeter Wemm ** pvp -- pointer to token vector. 1614c2aa98e2SPeter Wemm ** reclevel -- the current recursion level. 1615c2aa98e2SPeter Wemm ** e -- the current envelope. 1616c2aa98e2SPeter Wemm ** 1617c2aa98e2SPeter Wemm ** Returns: 1618c2aa98e2SPeter Wemm ** The status from the subroutine call. 1619c2aa98e2SPeter Wemm ** 1620c2aa98e2SPeter Wemm ** Side Effects: 1621c2aa98e2SPeter Wemm ** pvp is modified. 1622c2aa98e2SPeter Wemm */ 1623c2aa98e2SPeter Wemm 162406f25ae9SGregory Neil Shapiro static int 1625c2aa98e2SPeter Wemm callsubr(pvp, reclevel, e) 1626c2aa98e2SPeter Wemm char **pvp; 1627c2aa98e2SPeter Wemm int reclevel; 1628c2aa98e2SPeter Wemm ENVELOPE *e; 1629c2aa98e2SPeter Wemm { 1630c2aa98e2SPeter Wemm char **avp; 1631c2aa98e2SPeter Wemm register int i; 163240266059SGregory Neil Shapiro int subr, j; 163340266059SGregory Neil Shapiro int nsubr; 163406f25ae9SGregory Neil Shapiro int status; 1635c2aa98e2SPeter Wemm int rstat = EX_OK; 163640266059SGregory Neil Shapiro #define MAX_SUBR 16 163740266059SGregory Neil Shapiro int subrnumber[MAX_SUBR]; 163840266059SGregory Neil Shapiro int subrindex[MAX_SUBR]; 1639c2aa98e2SPeter Wemm 164040266059SGregory Neil Shapiro nsubr = 0; 164140266059SGregory Neil Shapiro 164240266059SGregory Neil Shapiro /* 164340266059SGregory Neil Shapiro ** Look for subroutine calls in pvp, collect them into subr*[] 164440266059SGregory Neil Shapiro ** We will perform the calls in the next loop, because we will 164540266059SGregory Neil Shapiro ** call the "last" subroutine first to avoid recursive calls 164640266059SGregory Neil Shapiro ** and too much copying. 164740266059SGregory Neil Shapiro */ 164840266059SGregory Neil Shapiro 164940266059SGregory Neil Shapiro for (avp = pvp, j = 0; *avp != NULL; avp++, j++) 1650c2aa98e2SPeter Wemm { 1651c2aa98e2SPeter Wemm if ((**avp & 0377) == CALLSUBR && avp[1] != NULL) 1652c2aa98e2SPeter Wemm { 1653c2aa98e2SPeter Wemm stripquotes(avp[1]); 1654c2aa98e2SPeter Wemm subr = strtorwset(avp[1], NULL, ST_FIND); 1655c2aa98e2SPeter Wemm if (subr < 0) 1656c2aa98e2SPeter Wemm { 165740266059SGregory Neil Shapiro syserr("554 5.3.5 Unknown ruleset %s", avp[1]); 1658c2aa98e2SPeter Wemm return EX_CONFIG; 1659c2aa98e2SPeter Wemm } 1660c2aa98e2SPeter Wemm 1661c2aa98e2SPeter Wemm /* 166240266059SGregory Neil Shapiro ** XXX instead of doing this we could optimize 166340266059SGregory Neil Shapiro ** the rules after reading them: just remove 166440266059SGregory Neil Shapiro ** calls to empty rulesets 1665c2aa98e2SPeter Wemm */ 1666c2aa98e2SPeter Wemm 166740266059SGregory Neil Shapiro /* subroutine is an empty ruleset? don't call it */ 166840266059SGregory Neil Shapiro if (RewriteRules[subr] == NULL) 166940266059SGregory Neil Shapiro { 167040266059SGregory Neil Shapiro if (tTd(21, 3)) 167140266059SGregory Neil Shapiro sm_dprintf("-----skip subr %s (%d)\n", 167240266059SGregory Neil Shapiro avp[1], subr); 1673c2aa98e2SPeter Wemm for (i = 2; avp[i] != NULL; i++) 167440266059SGregory Neil Shapiro avp[i - 2] = avp[i]; 167540266059SGregory Neil Shapiro avp[i - 2] = NULL; 167640266059SGregory Neil Shapiro continue; 167740266059SGregory Neil Shapiro } 167840266059SGregory Neil Shapiro if (++nsubr >= MAX_SUBR) 167940266059SGregory Neil Shapiro { 168040266059SGregory Neil Shapiro syserr("554 5.3.0 Too many subroutine calls (%d max)", 168140266059SGregory Neil Shapiro MAX_SUBR); 168240266059SGregory Neil Shapiro return EX_CONFIG; 168340266059SGregory Neil Shapiro } 168440266059SGregory Neil Shapiro subrnumber[nsubr] = subr; 168540266059SGregory Neil Shapiro subrindex[nsubr] = j; 168640266059SGregory Neil Shapiro } 168740266059SGregory Neil Shapiro } 1688c2aa98e2SPeter Wemm 168940266059SGregory Neil Shapiro /* 169040266059SGregory Neil Shapiro ** Perform the actual subroutines calls, "last" one first, i.e., 169140266059SGregory Neil Shapiro ** go from the right to the left through all calls, 169240266059SGregory Neil Shapiro ** do the rewriting in place. 169340266059SGregory Neil Shapiro */ 169440266059SGregory Neil Shapiro 169540266059SGregory Neil Shapiro for (; nsubr > 0; nsubr--) 169640266059SGregory Neil Shapiro { 169740266059SGregory Neil Shapiro subr = subrnumber[nsubr]; 169840266059SGregory Neil Shapiro avp = pvp + subrindex[nsubr]; 169940266059SGregory Neil Shapiro 170040266059SGregory Neil Shapiro /* remove the subroutine call and name */ 170140266059SGregory Neil Shapiro for (i = 2; avp[i] != NULL; i++) 170240266059SGregory Neil Shapiro avp[i - 2] = avp[i]; 170340266059SGregory Neil Shapiro avp[i - 2] = NULL; 1704c2aa98e2SPeter Wemm 1705c2aa98e2SPeter Wemm /* 1706c2aa98e2SPeter Wemm ** Now we need to call the ruleset specified for 1707a7ec597cSGregory Neil Shapiro ** the subroutine. We can do this in place since 170840266059SGregory Neil Shapiro ** we call the "last" subroutine first. 1709c2aa98e2SPeter Wemm */ 1710c2aa98e2SPeter Wemm 171140266059SGregory Neil Shapiro status = rewrite(avp, subr, reclevel, e, 171240266059SGregory Neil Shapiro MAXATOM - subrindex[nsubr]); 171340266059SGregory Neil Shapiro if (status != EX_OK && status != EX_TEMPFAIL) 171440266059SGregory Neil Shapiro return status; 171506f25ae9SGregory Neil Shapiro if (rstat == EX_OK || status == EX_TEMPFAIL) 171606f25ae9SGregory Neil Shapiro rstat = status; 1717c2aa98e2SPeter Wemm } 1718c2aa98e2SPeter Wemm return rstat; 1719c2aa98e2SPeter Wemm } 172040266059SGregory Neil Shapiro /* 1721c2aa98e2SPeter Wemm ** MAP_LOOKUP -- do lookup in map 1722c2aa98e2SPeter Wemm ** 1723c2aa98e2SPeter Wemm ** Parameters: 172440266059SGregory Neil Shapiro ** smap -- the map to use for the lookup. 1725c2aa98e2SPeter Wemm ** key -- the key to look up. 1726c2aa98e2SPeter Wemm ** argvect -- arguments to pass to the map lookup. 1727c2aa98e2SPeter Wemm ** pstat -- a pointer to an integer in which to store the 1728c2aa98e2SPeter Wemm ** status from the lookup. 1729c2aa98e2SPeter Wemm ** e -- the current envelope. 1730c2aa98e2SPeter Wemm ** 1731c2aa98e2SPeter Wemm ** Returns: 1732c2aa98e2SPeter Wemm ** The result of the lookup. 1733c2aa98e2SPeter Wemm ** NULL -- if there was no data for the given key. 1734c2aa98e2SPeter Wemm */ 1735c2aa98e2SPeter Wemm 173606f25ae9SGregory Neil Shapiro static char * 173706f25ae9SGregory Neil Shapiro map_lookup(smap, key, argvect, pstat, e) 173806f25ae9SGregory Neil Shapiro STAB *smap; 1739c2aa98e2SPeter Wemm char key[]; 1740c2aa98e2SPeter Wemm char **argvect; 1741c2aa98e2SPeter Wemm int *pstat; 1742c2aa98e2SPeter Wemm ENVELOPE *e; 1743c2aa98e2SPeter Wemm { 174406f25ae9SGregory Neil Shapiro auto int status = EX_OK; 174506f25ae9SGregory Neil Shapiro MAP *map; 1746c2aa98e2SPeter Wemm char *replac; 1747c2aa98e2SPeter Wemm 174806f25ae9SGregory Neil Shapiro if (smap == NULL) 174906f25ae9SGregory Neil Shapiro return NULL; 175006f25ae9SGregory Neil Shapiro 175106f25ae9SGregory Neil Shapiro map = &smap->s_map; 175206f25ae9SGregory Neil Shapiro DYNOPENMAP(map); 175306f25ae9SGregory Neil Shapiro 175406f25ae9SGregory Neil Shapiro if (e->e_sendmode == SM_DEFER && 175506f25ae9SGregory Neil Shapiro bitset(MF_DEFER, map->map_mflags)) 1756c2aa98e2SPeter Wemm { 1757c2aa98e2SPeter Wemm /* don't do any map lookups */ 1758c2aa98e2SPeter Wemm if (tTd(60, 1)) 175940266059SGregory Neil Shapiro sm_dprintf("map_lookup(%s, %s) => DEFERRED\n", 176006f25ae9SGregory Neil Shapiro smap->s_name, key); 1761c2aa98e2SPeter Wemm *pstat = EX_TEMPFAIL; 1762c2aa98e2SPeter Wemm return NULL; 1763c2aa98e2SPeter Wemm } 1764c2aa98e2SPeter Wemm 176506f25ae9SGregory Neil Shapiro if (!bitset(MF_KEEPQUOTES, map->map_mflags)) 1766c2aa98e2SPeter Wemm stripquotes(key); 1767c2aa98e2SPeter Wemm 1768c2aa98e2SPeter Wemm if (tTd(60, 1)) 1769065a643dSPeter Wemm { 177040266059SGregory Neil Shapiro sm_dprintf("map_lookup(%s, %s", smap->s_name, key); 1771065a643dSPeter Wemm if (tTd(60, 5)) 1772065a643dSPeter Wemm { 1773065a643dSPeter Wemm int i; 1774065a643dSPeter Wemm 1775065a643dSPeter Wemm for (i = 0; argvect[i] != NULL; i++) 177640266059SGregory Neil Shapiro sm_dprintf(", %%%d=%s", i, argvect[i]); 1777065a643dSPeter Wemm } 177840266059SGregory Neil Shapiro sm_dprintf(") => "); 1779065a643dSPeter Wemm } 178006f25ae9SGregory Neil Shapiro replac = (*map->map_class->map_lookup)(map, key, argvect, &status); 1781c2aa98e2SPeter Wemm if (tTd(60, 1)) 178240266059SGregory Neil Shapiro sm_dprintf("%s (%d)\n", 1783c2aa98e2SPeter Wemm replac != NULL ? replac : "NOT FOUND", 178406f25ae9SGregory Neil Shapiro status); 1785c2aa98e2SPeter Wemm 178606f25ae9SGregory Neil Shapiro /* should recover if status == EX_TEMPFAIL */ 178706f25ae9SGregory Neil Shapiro if (status == EX_TEMPFAIL && !bitset(MF_NODEFER, map->map_mflags)) 1788c2aa98e2SPeter Wemm { 1789c2aa98e2SPeter Wemm *pstat = EX_TEMPFAIL; 1790c2aa98e2SPeter Wemm if (tTd(60, 1)) 179140266059SGregory Neil Shapiro sm_dprintf("map_lookup(%s, %s) tempfail: errno=%d\n", 179206f25ae9SGregory Neil Shapiro smap->s_name, key, errno); 1793c2aa98e2SPeter Wemm if (e->e_message == NULL) 1794c2aa98e2SPeter Wemm { 1795c2aa98e2SPeter Wemm char mbuf[320]; 1796c2aa98e2SPeter Wemm 179740266059SGregory Neil Shapiro (void) sm_snprintf(mbuf, sizeof mbuf, 1798c2aa98e2SPeter Wemm "%.80s map: lookup (%s): deferred", 179906f25ae9SGregory Neil Shapiro smap->s_name, 1800c2aa98e2SPeter Wemm shortenstring(key, MAXSHORTSTR)); 180140266059SGregory Neil Shapiro e->e_message = sm_rpool_strdup_x(e->e_rpool, mbuf); 1802c2aa98e2SPeter Wemm } 1803c2aa98e2SPeter Wemm } 180406f25ae9SGregory Neil Shapiro if (status == EX_TEMPFAIL && map->map_tapp != NULL) 1805c2aa98e2SPeter Wemm { 180606f25ae9SGregory Neil Shapiro size_t i = strlen(key) + strlen(map->map_tapp) + 1; 1807c2aa98e2SPeter Wemm static char *rwbuf = NULL; 1808c2aa98e2SPeter Wemm static size_t rwbuflen = 0; 1809c2aa98e2SPeter Wemm 1810c2aa98e2SPeter Wemm if (i > rwbuflen) 1811c2aa98e2SPeter Wemm { 1812c2aa98e2SPeter Wemm if (rwbuf != NULL) 18138774250cSGregory Neil Shapiro sm_free(rwbuf); 1814c2aa98e2SPeter Wemm rwbuflen = i; 181540266059SGregory Neil Shapiro rwbuf = (char *) sm_pmalloc_x(rwbuflen); 1816c2aa98e2SPeter Wemm } 181740266059SGregory Neil Shapiro (void) sm_strlcpyn(rwbuf, rwbuflen, 2, key, map->map_tapp); 1818c2aa98e2SPeter Wemm if (tTd(60, 4)) 181940266059SGregory Neil Shapiro sm_dprintf("map_lookup tempfail: returning \"%s\"\n", 1820c2aa98e2SPeter Wemm rwbuf); 1821c2aa98e2SPeter Wemm return rwbuf; 1822c2aa98e2SPeter Wemm } 1823c2aa98e2SPeter Wemm return replac; 1824c2aa98e2SPeter Wemm } 182540266059SGregory Neil Shapiro /* 182606f25ae9SGregory Neil Shapiro ** INITERRMAILERS -- initialize error and discard mailers 182706f25ae9SGregory Neil Shapiro ** 182806f25ae9SGregory Neil Shapiro ** Parameters: 182906f25ae9SGregory Neil Shapiro ** none. 183006f25ae9SGregory Neil Shapiro ** 183106f25ae9SGregory Neil Shapiro ** Returns: 183206f25ae9SGregory Neil Shapiro ** none. 183306f25ae9SGregory Neil Shapiro ** 183406f25ae9SGregory Neil Shapiro ** Side Effects: 183506f25ae9SGregory Neil Shapiro ** initializes error and discard mailers. 183606f25ae9SGregory Neil Shapiro */ 183706f25ae9SGregory Neil Shapiro 183806f25ae9SGregory Neil Shapiro static MAILER discardmailer; 183906f25ae9SGregory Neil Shapiro static MAILER errormailer; 184006f25ae9SGregory Neil Shapiro static char *discardargv[] = { "DISCARD", NULL }; 184106f25ae9SGregory Neil Shapiro static char *errorargv[] = { "ERROR", NULL }; 184206f25ae9SGregory Neil Shapiro 184306f25ae9SGregory Neil Shapiro void 184406f25ae9SGregory Neil Shapiro initerrmailers() 184506f25ae9SGregory Neil Shapiro { 184606f25ae9SGregory Neil Shapiro if (discardmailer.m_name == NULL) 184706f25ae9SGregory Neil Shapiro { 184806f25ae9SGregory Neil Shapiro /* initialize the discard mailer */ 184906f25ae9SGregory Neil Shapiro discardmailer.m_name = "*discard*"; 185006f25ae9SGregory Neil Shapiro discardmailer.m_mailer = "DISCARD"; 185106f25ae9SGregory Neil Shapiro discardmailer.m_argv = discardargv; 185206f25ae9SGregory Neil Shapiro } 185306f25ae9SGregory Neil Shapiro if (errormailer.m_name == NULL) 185406f25ae9SGregory Neil Shapiro { 185506f25ae9SGregory Neil Shapiro /* initialize the bogus mailer */ 185606f25ae9SGregory Neil Shapiro errormailer.m_name = "*error*"; 185706f25ae9SGregory Neil Shapiro errormailer.m_mailer = "ERROR"; 185806f25ae9SGregory Neil Shapiro errormailer.m_argv = errorargv; 185906f25ae9SGregory Neil Shapiro } 186006f25ae9SGregory Neil Shapiro } 186140266059SGregory Neil Shapiro /* 1862c2aa98e2SPeter Wemm ** BUILDADDR -- build address from token vector. 1863c2aa98e2SPeter Wemm ** 1864c2aa98e2SPeter Wemm ** Parameters: 1865c2aa98e2SPeter Wemm ** tv -- token vector. 1866c2aa98e2SPeter Wemm ** a -- pointer to address descriptor to fill. 1867c2aa98e2SPeter Wemm ** If NULL, one will be allocated. 1868c2aa98e2SPeter Wemm ** flags -- info regarding whether this is a sender or 1869c2aa98e2SPeter Wemm ** a recipient. 1870c2aa98e2SPeter Wemm ** e -- the current envelope. 1871c2aa98e2SPeter Wemm ** 1872c2aa98e2SPeter Wemm ** Returns: 1873c2aa98e2SPeter Wemm ** NULL if there was an error. 1874c2aa98e2SPeter Wemm ** 'a' otherwise. 1875c2aa98e2SPeter Wemm ** 1876c2aa98e2SPeter Wemm ** Side Effects: 1877c2aa98e2SPeter Wemm ** fills in 'a' 1878c2aa98e2SPeter Wemm */ 1879c2aa98e2SPeter Wemm 188006f25ae9SGregory Neil Shapiro static struct errcodes 1881c2aa98e2SPeter Wemm { 1882c2aa98e2SPeter Wemm char *ec_name; /* name of error code */ 1883c2aa98e2SPeter Wemm int ec_code; /* numeric code */ 1884c2aa98e2SPeter Wemm } ErrorCodes[] = 1885c2aa98e2SPeter Wemm { 1886c2aa98e2SPeter Wemm { "usage", EX_USAGE }, 1887c2aa98e2SPeter Wemm { "nouser", EX_NOUSER }, 1888c2aa98e2SPeter Wemm { "nohost", EX_NOHOST }, 1889c2aa98e2SPeter Wemm { "unavailable", EX_UNAVAILABLE }, 1890c2aa98e2SPeter Wemm { "software", EX_SOFTWARE }, 1891c2aa98e2SPeter Wemm { "tempfail", EX_TEMPFAIL }, 1892c2aa98e2SPeter Wemm { "protocol", EX_PROTOCOL }, 1893c2aa98e2SPeter Wemm { "config", EX_CONFIG }, 1894c2aa98e2SPeter Wemm { NULL, EX_UNAVAILABLE } 1895c2aa98e2SPeter Wemm }; 1896c2aa98e2SPeter Wemm 189706f25ae9SGregory Neil Shapiro static ADDRESS * 1898c2aa98e2SPeter Wemm buildaddr(tv, a, flags, e) 1899c2aa98e2SPeter Wemm register char **tv; 1900c2aa98e2SPeter Wemm register ADDRESS *a; 1901c2aa98e2SPeter Wemm int flags; 1902c2aa98e2SPeter Wemm register ENVELOPE *e; 1903c2aa98e2SPeter Wemm { 1904605302a5SGregory Neil Shapiro bool tempfail = false; 1905a7ec597cSGregory Neil Shapiro int maxatom; 1906c2aa98e2SPeter Wemm struct mailer **mp; 1907c2aa98e2SPeter Wemm register struct mailer *m; 1908c2aa98e2SPeter Wemm register char *p; 1909c2aa98e2SPeter Wemm char *mname; 1910c2aa98e2SPeter Wemm char **hostp; 1911c2aa98e2SPeter Wemm char hbuf[MAXNAME + 1]; 1912065a643dSPeter Wemm static char ubuf[MAXNAME + 2]; 1913c2aa98e2SPeter Wemm 1914c2aa98e2SPeter Wemm if (tTd(24, 5)) 1915c2aa98e2SPeter Wemm { 191640266059SGregory Neil Shapiro sm_dprintf("buildaddr, flags=%x, tv=", flags); 1917e92d3f3fSGregory Neil Shapiro printav(sm_debug_file(), tv); 1918c2aa98e2SPeter Wemm } 1919c2aa98e2SPeter Wemm 1920a7ec597cSGregory Neil Shapiro maxatom = MAXATOM; 1921c2aa98e2SPeter Wemm if (a == NULL) 192240266059SGregory Neil Shapiro a = (ADDRESS *) sm_rpool_malloc_x(e->e_rpool, sizeof *a); 192306f25ae9SGregory Neil Shapiro memset((char *) a, '\0', sizeof *a); 192406f25ae9SGregory Neil Shapiro hbuf[0] = '\0'; 1925c2aa98e2SPeter Wemm 1926c2aa98e2SPeter Wemm /* set up default error return flags */ 1927c2aa98e2SPeter Wemm a->q_flags |= DefaultNotify; 1928c2aa98e2SPeter Wemm 1929c2aa98e2SPeter Wemm /* figure out what net/mailer to use */ 1930c2aa98e2SPeter Wemm if (*tv == NULL || (**tv & 0377) != CANONNET) 1931c2aa98e2SPeter Wemm { 193206f25ae9SGregory Neil Shapiro syserr("554 5.3.5 buildaddr: no mailer in parsed address"); 1933c2aa98e2SPeter Wemm badaddr: 1934605302a5SGregory Neil Shapiro /* 1935605302a5SGregory Neil Shapiro ** ExitStat may have been set by an earlier map open 1936605302a5SGregory Neil Shapiro ** failure (to a permanent error (EX_OSERR) in syserr()) 1937605302a5SGregory Neil Shapiro ** so we also need to check if this particular $#error 1938605302a5SGregory Neil Shapiro ** return wanted a 4XX failure. 1939605302a5SGregory Neil Shapiro ** 1940605302a5SGregory Neil Shapiro ** XXX the real fix is probably to set ExitStat correctly, 1941605302a5SGregory Neil Shapiro ** i.e., to EX_TEMPFAIL if the map open is just a temporary 1942605302a5SGregory Neil Shapiro ** error. 1943605302a5SGregory Neil Shapiro */ 1944605302a5SGregory Neil Shapiro 1945605302a5SGregory Neil Shapiro if (ExitStat == EX_TEMPFAIL || tempfail) 194606f25ae9SGregory Neil Shapiro a->q_state = QS_QUEUEUP; 194706f25ae9SGregory Neil Shapiro else 1948c2aa98e2SPeter Wemm { 194906f25ae9SGregory Neil Shapiro a->q_state = QS_BADADDR; 195006f25ae9SGregory Neil Shapiro a->q_mailer = &errormailer; 1951c2aa98e2SPeter Wemm } 1952c2aa98e2SPeter Wemm return a; 1953c2aa98e2SPeter Wemm } 1954c2aa98e2SPeter Wemm mname = *++tv; 1955a7ec597cSGregory Neil Shapiro --maxatom; 1956c2aa98e2SPeter Wemm 1957c2aa98e2SPeter Wemm /* extract host and user portions */ 1958c2aa98e2SPeter Wemm if (*++tv != NULL && (**tv & 0377) == CANONHOST) 1959a7ec597cSGregory Neil Shapiro { 1960c2aa98e2SPeter Wemm hostp = ++tv; 1961a7ec597cSGregory Neil Shapiro --maxatom; 1962a7ec597cSGregory Neil Shapiro } 1963c2aa98e2SPeter Wemm else 1964c2aa98e2SPeter Wemm hostp = NULL; 1965a7ec597cSGregory Neil Shapiro --maxatom; 1966c2aa98e2SPeter Wemm while (*tv != NULL && (**tv & 0377) != CANONUSER) 1967a7ec597cSGregory Neil Shapiro { 1968c2aa98e2SPeter Wemm tv++; 1969a7ec597cSGregory Neil Shapiro --maxatom; 1970a7ec597cSGregory Neil Shapiro } 1971c2aa98e2SPeter Wemm if (*tv == NULL) 1972c2aa98e2SPeter Wemm { 197306f25ae9SGregory Neil Shapiro syserr("554 5.3.5 buildaddr: no user"); 1974c2aa98e2SPeter Wemm goto badaddr; 1975c2aa98e2SPeter Wemm } 1976c2aa98e2SPeter Wemm if (tv == hostp) 1977c2aa98e2SPeter Wemm hostp = NULL; 1978c2aa98e2SPeter Wemm else if (hostp != NULL) 1979c2aa98e2SPeter Wemm cataddr(hostp, tv - 1, hbuf, sizeof hbuf, '\0'); 1980c2aa98e2SPeter Wemm cataddr(++tv, NULL, ubuf, sizeof ubuf, ' '); 1981a7ec597cSGregory Neil Shapiro --maxatom; 1982c2aa98e2SPeter Wemm 1983c2aa98e2SPeter Wemm /* save away the host name */ 198440266059SGregory Neil Shapiro if (sm_strcasecmp(mname, "error") == 0) 1985c2aa98e2SPeter Wemm { 198606f25ae9SGregory Neil Shapiro /* Set up triplet for use by -bv */ 198706f25ae9SGregory Neil Shapiro a->q_mailer = &errormailer; 198840266059SGregory Neil Shapiro a->q_user = sm_rpool_strdup_x(e->e_rpool, ubuf); 198940266059SGregory Neil Shapiro /* XXX wrong place? */ 199006f25ae9SGregory Neil Shapiro 1991c2aa98e2SPeter Wemm if (hostp != NULL) 1992c2aa98e2SPeter Wemm { 1993c2aa98e2SPeter Wemm register struct errcodes *ep; 1994c2aa98e2SPeter Wemm 199540266059SGregory Neil Shapiro a->q_host = sm_rpool_strdup_x(e->e_rpool, hbuf); 1996c2aa98e2SPeter Wemm if (strchr(hbuf, '.') != NULL) 1997c2aa98e2SPeter Wemm { 199840266059SGregory Neil Shapiro a->q_status = sm_rpool_strdup_x(e->e_rpool, 199940266059SGregory Neil Shapiro hbuf); 2000c2aa98e2SPeter Wemm setstat(dsntoexitstat(hbuf)); 2001c2aa98e2SPeter Wemm } 2002c2aa98e2SPeter Wemm else if (isascii(hbuf[0]) && isdigit(hbuf[0])) 2003c2aa98e2SPeter Wemm { 2004c2aa98e2SPeter Wemm setstat(atoi(hbuf)); 2005c2aa98e2SPeter Wemm } 2006c2aa98e2SPeter Wemm else 2007c2aa98e2SPeter Wemm { 2008c2aa98e2SPeter Wemm for (ep = ErrorCodes; ep->ec_name != NULL; ep++) 200940266059SGregory Neil Shapiro if (sm_strcasecmp(ep->ec_name, hbuf) == 0) 2010c2aa98e2SPeter Wemm break; 2011c2aa98e2SPeter Wemm setstat(ep->ec_code); 2012c2aa98e2SPeter Wemm } 2013c2aa98e2SPeter Wemm } 2014c2aa98e2SPeter Wemm else 201506f25ae9SGregory Neil Shapiro { 201606f25ae9SGregory Neil Shapiro a->q_host = NULL; 2017c2aa98e2SPeter Wemm setstat(EX_UNAVAILABLE); 2018c2aa98e2SPeter Wemm } 201906f25ae9SGregory Neil Shapiro stripquotes(ubuf); 202006f25ae9SGregory Neil Shapiro if (ISSMTPCODE(ubuf) && ubuf[3] == ' ') 202106f25ae9SGregory Neil Shapiro { 202206f25ae9SGregory Neil Shapiro char fmt[16]; 202306f25ae9SGregory Neil Shapiro int off; 202406f25ae9SGregory Neil Shapiro 202506f25ae9SGregory Neil Shapiro if ((off = isenhsc(ubuf + 4, ' ')) > 0) 202606f25ae9SGregory Neil Shapiro { 202706f25ae9SGregory Neil Shapiro ubuf[off + 4] = '\0'; 202806f25ae9SGregory Neil Shapiro off += 5; 2029c2aa98e2SPeter Wemm } 2030c2aa98e2SPeter Wemm else 2031c2aa98e2SPeter Wemm { 203206f25ae9SGregory Neil Shapiro off = 4; 203306f25ae9SGregory Neil Shapiro ubuf[3] = '\0'; 203406f25ae9SGregory Neil Shapiro } 203540266059SGregory Neil Shapiro (void) sm_strlcpyn(fmt, sizeof fmt, 2, ubuf, " %s"); 203606f25ae9SGregory Neil Shapiro if (off > 4) 203706f25ae9SGregory Neil Shapiro usrerr(fmt, ubuf + off); 203806f25ae9SGregory Neil Shapiro else if (isenhsc(hbuf, '\0') > 0) 203906f25ae9SGregory Neil Shapiro usrerrenh(hbuf, fmt, ubuf + off); 204006f25ae9SGregory Neil Shapiro else 204106f25ae9SGregory Neil Shapiro usrerr(fmt, ubuf + off); 204206f25ae9SGregory Neil Shapiro /* XXX ubuf[off - 1] = ' '; */ 2043605302a5SGregory Neil Shapiro if (ubuf[0] == '4') 2044605302a5SGregory Neil Shapiro tempfail = true; 204506f25ae9SGregory Neil Shapiro } 204606f25ae9SGregory Neil Shapiro else 204706f25ae9SGregory Neil Shapiro { 204806f25ae9SGregory Neil Shapiro usrerr("553 5.3.0 %s", ubuf); 2049c2aa98e2SPeter Wemm } 2050c2aa98e2SPeter Wemm goto badaddr; 2051c2aa98e2SPeter Wemm } 2052c2aa98e2SPeter Wemm 2053c2aa98e2SPeter Wemm for (mp = Mailer; (m = *mp++) != NULL; ) 2054c2aa98e2SPeter Wemm { 205540266059SGregory Neil Shapiro if (sm_strcasecmp(m->m_name, mname) == 0) 2056c2aa98e2SPeter Wemm break; 2057c2aa98e2SPeter Wemm } 2058c2aa98e2SPeter Wemm if (m == NULL) 2059c2aa98e2SPeter Wemm { 206006f25ae9SGregory Neil Shapiro syserr("554 5.3.5 buildaddr: unknown mailer %s", mname); 2061c2aa98e2SPeter Wemm goto badaddr; 2062c2aa98e2SPeter Wemm } 2063c2aa98e2SPeter Wemm a->q_mailer = m; 2064c2aa98e2SPeter Wemm 2065c2aa98e2SPeter Wemm /* figure out what host (if any) */ 2066c2aa98e2SPeter Wemm if (hostp == NULL) 2067c2aa98e2SPeter Wemm { 2068c2aa98e2SPeter Wemm if (!bitnset(M_LOCALMAILER, m->m_flags)) 2069c2aa98e2SPeter Wemm { 207006f25ae9SGregory Neil Shapiro syserr("554 5.3.5 buildaddr: no host"); 2071c2aa98e2SPeter Wemm goto badaddr; 2072c2aa98e2SPeter Wemm } 2073c2aa98e2SPeter Wemm a->q_host = NULL; 2074c2aa98e2SPeter Wemm } 2075c2aa98e2SPeter Wemm else 207640266059SGregory Neil Shapiro a->q_host = sm_rpool_strdup_x(e->e_rpool, hbuf); 2077c2aa98e2SPeter Wemm 2078c2aa98e2SPeter Wemm /* figure out the user */ 2079c2aa98e2SPeter Wemm p = ubuf; 2080c2aa98e2SPeter Wemm if (bitnset(M_CHECKUDB, m->m_flags) && *p == '@') 2081c2aa98e2SPeter Wemm { 2082c2aa98e2SPeter Wemm p++; 2083c2aa98e2SPeter Wemm tv++; 2084a7ec597cSGregory Neil Shapiro --maxatom; 2085c2aa98e2SPeter Wemm a->q_flags |= QNOTREMOTE; 2086c2aa98e2SPeter Wemm } 2087c2aa98e2SPeter Wemm 2088c2aa98e2SPeter Wemm /* do special mapping for local mailer */ 2089c2aa98e2SPeter Wemm if (*p == '"') 2090c2aa98e2SPeter Wemm p++; 2091c2aa98e2SPeter Wemm if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags)) 2092c2aa98e2SPeter Wemm a->q_mailer = m = ProgMailer; 2093c2aa98e2SPeter Wemm else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags)) 2094c2aa98e2SPeter Wemm a->q_mailer = m = FileMailer; 2095c2aa98e2SPeter Wemm else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags)) 2096c2aa98e2SPeter Wemm { 2097c2aa98e2SPeter Wemm /* may be :include: */ 2098c2aa98e2SPeter Wemm stripquotes(ubuf); 209940266059SGregory Neil Shapiro if (sm_strncasecmp(ubuf, ":include:", 9) == 0) 2100c2aa98e2SPeter Wemm { 2101c2aa98e2SPeter Wemm /* if :include:, don't need further rewriting */ 2102c2aa98e2SPeter Wemm a->q_mailer = m = InclMailer; 210340266059SGregory Neil Shapiro a->q_user = sm_rpool_strdup_x(e->e_rpool, &ubuf[9]); 2104c2aa98e2SPeter Wemm return a; 2105c2aa98e2SPeter Wemm } 2106c2aa98e2SPeter Wemm } 2107c2aa98e2SPeter Wemm 2108c2aa98e2SPeter Wemm /* rewrite according recipient mailer rewriting rules */ 210940266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'h', a->q_host); 211006f25ae9SGregory Neil Shapiro 211140266059SGregory Neil Shapiro if (ConfigLevel >= 10 || 211206f25ae9SGregory Neil Shapiro !bitset(RF_SENDERADDR|RF_HEADERADDR, flags)) 2113c2aa98e2SPeter Wemm { 2114c2aa98e2SPeter Wemm /* sender addresses done later */ 2115a7ec597cSGregory Neil Shapiro (void) rewrite(tv, 2, 0, e, maxatom); 2116c2aa98e2SPeter Wemm if (m->m_re_rwset > 0) 2117a7ec597cSGregory Neil Shapiro (void) rewrite(tv, m->m_re_rwset, 0, e, maxatom); 2118c2aa98e2SPeter Wemm } 2119a7ec597cSGregory Neil Shapiro (void) rewrite(tv, 4, 0, e, maxatom); 2120c2aa98e2SPeter Wemm 2121c2aa98e2SPeter Wemm /* save the result for the command line/RCPT argument */ 2122c2aa98e2SPeter Wemm cataddr(tv, NULL, ubuf, sizeof ubuf, '\0'); 212340266059SGregory Neil Shapiro a->q_user = sm_rpool_strdup_x(e->e_rpool, ubuf); 2124c2aa98e2SPeter Wemm 2125c2aa98e2SPeter Wemm /* 2126c2aa98e2SPeter Wemm ** Do mapping to lower case as requested by mailer 2127c2aa98e2SPeter Wemm */ 2128c2aa98e2SPeter Wemm 2129c2aa98e2SPeter Wemm if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags)) 2130c2aa98e2SPeter Wemm makelower(a->q_host); 2131c2aa98e2SPeter Wemm if (!bitnset(M_USR_UPPER, m->m_flags)) 2132c2aa98e2SPeter Wemm makelower(a->q_user); 2133c2aa98e2SPeter Wemm 2134c2aa98e2SPeter Wemm if (tTd(24, 6)) 2135c2aa98e2SPeter Wemm { 213640266059SGregory Neil Shapiro sm_dprintf("buildaddr => "); 2137e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), a, false); 2138c2aa98e2SPeter Wemm } 2139c2aa98e2SPeter Wemm return a; 2140c2aa98e2SPeter Wemm } 214113bd1963SGregory Neil Shapiro 214240266059SGregory Neil Shapiro /* 2143c2aa98e2SPeter Wemm ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 2144c2aa98e2SPeter Wemm ** 2145c2aa98e2SPeter Wemm ** Parameters: 2146c2aa98e2SPeter Wemm ** pvp -- parameter vector to rebuild. 2147c2aa98e2SPeter Wemm ** evp -- last parameter to include. Can be NULL to 2148c2aa98e2SPeter Wemm ** use entire pvp. 2149c2aa98e2SPeter Wemm ** buf -- buffer to build the string into. 2150c2aa98e2SPeter Wemm ** sz -- size of buf. 215140266059SGregory Neil Shapiro ** spacesub -- the space separator character; if '\0', 2152c2aa98e2SPeter Wemm ** use SpaceSub. 2153c2aa98e2SPeter Wemm ** 2154c2aa98e2SPeter Wemm ** Returns: 2155c2aa98e2SPeter Wemm ** none. 2156c2aa98e2SPeter Wemm ** 2157c2aa98e2SPeter Wemm ** Side Effects: 2158c2aa98e2SPeter Wemm ** Destroys buf. 2159c2aa98e2SPeter Wemm */ 2160c2aa98e2SPeter Wemm 2161c2aa98e2SPeter Wemm void 2162c2aa98e2SPeter Wemm cataddr(pvp, evp, buf, sz, spacesub) 2163c2aa98e2SPeter Wemm char **pvp; 2164c2aa98e2SPeter Wemm char **evp; 2165c2aa98e2SPeter Wemm char *buf; 2166c2aa98e2SPeter Wemm register int sz; 2167c2aa98e2SPeter Wemm int spacesub; 2168c2aa98e2SPeter Wemm { 216940266059SGregory Neil Shapiro bool oatomtok = false; 217040266059SGregory Neil Shapiro bool natomtok = false; 2171c2aa98e2SPeter Wemm register int i; 2172c2aa98e2SPeter Wemm register char *p; 2173c2aa98e2SPeter Wemm 217406f25ae9SGregory Neil Shapiro if (sz <= 0) 217506f25ae9SGregory Neil Shapiro return; 217606f25ae9SGregory Neil Shapiro 2177c2aa98e2SPeter Wemm if (spacesub == '\0') 2178c2aa98e2SPeter Wemm spacesub = SpaceSub; 2179c2aa98e2SPeter Wemm 2180c2aa98e2SPeter Wemm if (pvp == NULL) 2181c2aa98e2SPeter Wemm { 218206f25ae9SGregory Neil Shapiro *buf = '\0'; 2183c2aa98e2SPeter Wemm return; 2184c2aa98e2SPeter Wemm } 2185c2aa98e2SPeter Wemm p = buf; 2186c2aa98e2SPeter Wemm sz -= 2; 218740266059SGregory Neil Shapiro while (*pvp != NULL && sz > 0) 2188c2aa98e2SPeter Wemm { 2189c2aa98e2SPeter Wemm natomtok = (TokTypeTab[**pvp & 0xff] == ATM); 2190c2aa98e2SPeter Wemm if (oatomtok && natomtok) 219106f25ae9SGregory Neil Shapiro { 2192c2aa98e2SPeter Wemm *p++ = spacesub; 219340266059SGregory Neil Shapiro if (--sz <= 0) 219440266059SGregory Neil Shapiro break; 219506f25ae9SGregory Neil Shapiro } 2196e92d3f3fSGregory Neil Shapiro i = sm_strlcpy(p, *pvp, sz); 2197e92d3f3fSGregory Neil Shapiro sz -= i; 2198e92d3f3fSGregory Neil Shapiro if (sz <= 0) 219940266059SGregory Neil Shapiro break; 2200c2aa98e2SPeter Wemm oatomtok = natomtok; 2201c2aa98e2SPeter Wemm p += i; 2202c2aa98e2SPeter Wemm if (pvp++ == evp) 2203c2aa98e2SPeter Wemm break; 2204c2aa98e2SPeter Wemm } 2205e92d3f3fSGregory Neil Shapiro 220613d88268SGregory Neil Shapiro #if 0 220713d88268SGregory Neil Shapiro /* 220813d88268SGregory Neil Shapiro ** Silently truncate long strings: even though this doesn't 220913d88268SGregory Neil Shapiro ** seem like a good idea it is necessary because header checks 221013d88268SGregory Neil Shapiro ** send the whole header value to rscheck() and hence rewrite(). 221113d88268SGregory Neil Shapiro ** The latter however sometimes uses a "short" buffer (e.g., 221213d88268SGregory Neil Shapiro ** cbuf[MAXNAME + 1]) to call cataddr() which then triggers this 221313d88268SGregory Neil Shapiro ** error function. One possible fix to the problem is to pass 221413d88268SGregory Neil Shapiro ** flags to rscheck() and rewrite() to distinguish the various 221513d88268SGregory Neil Shapiro ** calls and only trigger the error if necessary. For now just 221613d88268SGregory Neil Shapiro ** undo the change from 8.13.0. 221713d88268SGregory Neil Shapiro */ 221813d88268SGregory Neil Shapiro 2219e92d3f3fSGregory Neil Shapiro if (sz <= 0) 2220b6bacd31SGregory Neil Shapiro usrerr("cataddr: string too long"); 222113d88268SGregory Neil Shapiro #endif 2222c2aa98e2SPeter Wemm *p = '\0'; 2223c2aa98e2SPeter Wemm } 222440266059SGregory Neil Shapiro /* 2225c2aa98e2SPeter Wemm ** SAMEADDR -- Determine if two addresses are the same 2226c2aa98e2SPeter Wemm ** 2227c2aa98e2SPeter Wemm ** This is not just a straight comparison -- if the mailer doesn't 2228c2aa98e2SPeter Wemm ** care about the host we just ignore it, etc. 2229c2aa98e2SPeter Wemm ** 2230c2aa98e2SPeter Wemm ** Parameters: 2231c2aa98e2SPeter Wemm ** a, b -- pointers to the internal forms to compare. 2232c2aa98e2SPeter Wemm ** 2233c2aa98e2SPeter Wemm ** Returns: 223440266059SGregory Neil Shapiro ** true -- they represent the same mailbox. 223540266059SGregory Neil Shapiro ** false -- they don't. 2236c2aa98e2SPeter Wemm ** 2237c2aa98e2SPeter Wemm ** Side Effects: 2238c2aa98e2SPeter Wemm ** none. 2239c2aa98e2SPeter Wemm */ 2240c2aa98e2SPeter Wemm 2241c2aa98e2SPeter Wemm bool 2242c2aa98e2SPeter Wemm sameaddr(a, b) 2243c2aa98e2SPeter Wemm register ADDRESS *a; 2244c2aa98e2SPeter Wemm register ADDRESS *b; 2245c2aa98e2SPeter Wemm { 2246c2aa98e2SPeter Wemm register ADDRESS *ca, *cb; 2247c2aa98e2SPeter Wemm 2248c2aa98e2SPeter Wemm /* if they don't have the same mailer, forget it */ 2249c2aa98e2SPeter Wemm if (a->q_mailer != b->q_mailer) 225040266059SGregory Neil Shapiro return false; 2251c2aa98e2SPeter Wemm 2252c2aa98e2SPeter Wemm /* if the user isn't the same, we can drop out */ 2253c2aa98e2SPeter Wemm if (strcmp(a->q_user, b->q_user) != 0) 225440266059SGregory Neil Shapiro return false; 2255c2aa98e2SPeter Wemm 2256c2aa98e2SPeter Wemm /* if we have good uids for both but they differ, these are different */ 2257c2aa98e2SPeter Wemm if (a->q_mailer == ProgMailer) 2258c2aa98e2SPeter Wemm { 2259c2aa98e2SPeter Wemm ca = getctladdr(a); 2260c2aa98e2SPeter Wemm cb = getctladdr(b); 2261c2aa98e2SPeter Wemm if (ca != NULL && cb != NULL && 2262c2aa98e2SPeter Wemm bitset(QGOODUID, ca->q_flags & cb->q_flags) && 2263c2aa98e2SPeter Wemm ca->q_uid != cb->q_uid) 226440266059SGregory Neil Shapiro return false; 2265c2aa98e2SPeter Wemm } 2266c2aa98e2SPeter Wemm 2267c2aa98e2SPeter Wemm /* otherwise compare hosts (but be careful for NULL ptrs) */ 2268c2aa98e2SPeter Wemm if (a->q_host == b->q_host) 2269c2aa98e2SPeter Wemm { 2270c2aa98e2SPeter Wemm /* probably both null pointers */ 227140266059SGregory Neil Shapiro return true; 2272c2aa98e2SPeter Wemm } 2273c2aa98e2SPeter Wemm if (a->q_host == NULL || b->q_host == NULL) 2274c2aa98e2SPeter Wemm { 2275c2aa98e2SPeter Wemm /* only one is a null pointer */ 227640266059SGregory Neil Shapiro return false; 2277c2aa98e2SPeter Wemm } 2278c2aa98e2SPeter Wemm if (strcmp(a->q_host, b->q_host) != 0) 227940266059SGregory Neil Shapiro return false; 2280c2aa98e2SPeter Wemm 228140266059SGregory Neil Shapiro return true; 2282c2aa98e2SPeter Wemm } 228340266059SGregory Neil Shapiro /* 2284c2aa98e2SPeter Wemm ** PRINTADDR -- print address (for debugging) 2285c2aa98e2SPeter Wemm ** 2286c2aa98e2SPeter Wemm ** Parameters: 2287c2aa98e2SPeter Wemm ** a -- the address to print 2288c2aa98e2SPeter Wemm ** follow -- follow the q_next chain. 2289c2aa98e2SPeter Wemm ** 2290c2aa98e2SPeter Wemm ** Returns: 2291c2aa98e2SPeter Wemm ** none. 2292c2aa98e2SPeter Wemm ** 2293c2aa98e2SPeter Wemm ** Side Effects: 2294c2aa98e2SPeter Wemm ** none. 2295c2aa98e2SPeter Wemm */ 2296c2aa98e2SPeter Wemm 2297c2aa98e2SPeter Wemm struct qflags 2298c2aa98e2SPeter Wemm { 2299c2aa98e2SPeter Wemm char *qf_name; 230040266059SGregory Neil Shapiro unsigned long qf_bit; 2301c2aa98e2SPeter Wemm }; 2302c2aa98e2SPeter Wemm 230306f25ae9SGregory Neil Shapiro static struct qflags AddressFlags[] = 2304c2aa98e2SPeter Wemm { 2305c2aa98e2SPeter Wemm { "QGOODUID", QGOODUID }, 2306c2aa98e2SPeter Wemm { "QPRIMARY", QPRIMARY }, 2307c2aa98e2SPeter Wemm { "QNOTREMOTE", QNOTREMOTE }, 2308c2aa98e2SPeter Wemm { "QSELFREF", QSELFREF }, 2309c2aa98e2SPeter Wemm { "QBOGUSSHELL", QBOGUSSHELL }, 2310c2aa98e2SPeter Wemm { "QUNSAFEADDR", QUNSAFEADDR }, 2311c2aa98e2SPeter Wemm { "QPINGONSUCCESS", QPINGONSUCCESS }, 2312c2aa98e2SPeter Wemm { "QPINGONFAILURE", QPINGONFAILURE }, 2313c2aa98e2SPeter Wemm { "QPINGONDELAY", QPINGONDELAY }, 2314c2aa98e2SPeter Wemm { "QHASNOTIFY", QHASNOTIFY }, 2315c2aa98e2SPeter Wemm { "QRELAYED", QRELAYED }, 2316c2aa98e2SPeter Wemm { "QEXPANDED", QEXPANDED }, 2317c2aa98e2SPeter Wemm { "QDELIVERED", QDELIVERED }, 2318c2aa98e2SPeter Wemm { "QDELAYED", QDELAYED }, 2319c2aa98e2SPeter Wemm { "QTHISPASS", QTHISPASS }, 2320c2aa98e2SPeter Wemm { "QRCPTOK", QRCPTOK }, 2321193538b7SGregory Neil Shapiro { NULL, 0 } 2322c2aa98e2SPeter Wemm }; 2323c2aa98e2SPeter Wemm 2324c2aa98e2SPeter Wemm void 2325e92d3f3fSGregory Neil Shapiro printaddr(fp, a, follow) 2326e92d3f3fSGregory Neil Shapiro SM_FILE_T *fp; 2327c2aa98e2SPeter Wemm register ADDRESS *a; 2328c2aa98e2SPeter Wemm bool follow; 2329c2aa98e2SPeter Wemm { 2330c2aa98e2SPeter Wemm register MAILER *m; 2331c2aa98e2SPeter Wemm MAILER pseudomailer; 2332c2aa98e2SPeter Wemm register struct qflags *qfp; 2333c2aa98e2SPeter Wemm bool firstone; 2334c2aa98e2SPeter Wemm 2335c2aa98e2SPeter Wemm if (a == NULL) 2336c2aa98e2SPeter Wemm { 2337e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "[NULL]\n"); 2338c2aa98e2SPeter Wemm return; 2339c2aa98e2SPeter Wemm } 2340c2aa98e2SPeter Wemm 2341c2aa98e2SPeter Wemm while (a != NULL) 2342c2aa98e2SPeter Wemm { 2343e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%p=", a); 2344e92d3f3fSGregory Neil Shapiro (void) sm_io_flush(fp, SM_TIME_DEFAULT); 2345c2aa98e2SPeter Wemm 2346c2aa98e2SPeter Wemm /* find the mailer -- carefully */ 2347c2aa98e2SPeter Wemm m = a->q_mailer; 2348c2aa98e2SPeter Wemm if (m == NULL) 2349c2aa98e2SPeter Wemm { 2350c2aa98e2SPeter Wemm m = &pseudomailer; 2351c2aa98e2SPeter Wemm m->m_mno = -1; 2352c2aa98e2SPeter Wemm m->m_name = "NULL"; 2353c2aa98e2SPeter Wemm } 2354c2aa98e2SPeter Wemm 2355e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 235640266059SGregory Neil Shapiro "%s:\n\tmailer %d (%s), host `%s'\n", 2357c2aa98e2SPeter Wemm a->q_paddr == NULL ? "<null>" : a->q_paddr, 2358c2aa98e2SPeter Wemm m->m_mno, m->m_name, 2359c2aa98e2SPeter Wemm a->q_host == NULL ? "<null>" : a->q_host); 2360e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 236140266059SGregory Neil Shapiro "\tuser `%s', ruser `%s'\n", 2362c2aa98e2SPeter Wemm a->q_user, 2363c2aa98e2SPeter Wemm a->q_ruser == NULL ? "<null>" : a->q_ruser); 2364e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\tstate="); 236506f25ae9SGregory Neil Shapiro switch (a->q_state) 236606f25ae9SGregory Neil Shapiro { 236706f25ae9SGregory Neil Shapiro case QS_OK: 2368e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "OK"); 236906f25ae9SGregory Neil Shapiro break; 237006f25ae9SGregory Neil Shapiro 237106f25ae9SGregory Neil Shapiro case QS_DONTSEND: 2372e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 237340266059SGregory Neil Shapiro "DONTSEND"); 237406f25ae9SGregory Neil Shapiro break; 237506f25ae9SGregory Neil Shapiro 237606f25ae9SGregory Neil Shapiro case QS_BADADDR: 2377e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 237840266059SGregory Neil Shapiro "BADADDR"); 237906f25ae9SGregory Neil Shapiro break; 238006f25ae9SGregory Neil Shapiro 238106f25ae9SGregory Neil Shapiro case QS_QUEUEUP: 2382e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 238340266059SGregory Neil Shapiro "QUEUEUP"); 238440266059SGregory Neil Shapiro break; 238540266059SGregory Neil Shapiro 238640266059SGregory Neil Shapiro case QS_RETRY: 2387e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "RETRY"); 238806f25ae9SGregory Neil Shapiro break; 238906f25ae9SGregory Neil Shapiro 239006f25ae9SGregory Neil Shapiro case QS_SENT: 2391e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "SENT"); 239206f25ae9SGregory Neil Shapiro break; 239306f25ae9SGregory Neil Shapiro 239406f25ae9SGregory Neil Shapiro case QS_VERIFIED: 2395e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 239640266059SGregory Neil Shapiro "VERIFIED"); 239706f25ae9SGregory Neil Shapiro break; 239806f25ae9SGregory Neil Shapiro 239906f25ae9SGregory Neil Shapiro case QS_EXPANDED: 2400e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 240140266059SGregory Neil Shapiro "EXPANDED"); 240206f25ae9SGregory Neil Shapiro break; 240306f25ae9SGregory Neil Shapiro 240406f25ae9SGregory Neil Shapiro case QS_SENDER: 2405e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 240640266059SGregory Neil Shapiro "SENDER"); 240706f25ae9SGregory Neil Shapiro break; 240806f25ae9SGregory Neil Shapiro 240906f25ae9SGregory Neil Shapiro case QS_CLONED: 2410e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 241140266059SGregory Neil Shapiro "CLONED"); 241206f25ae9SGregory Neil Shapiro break; 241306f25ae9SGregory Neil Shapiro 241406f25ae9SGregory Neil Shapiro case QS_DISCARDED: 2415e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 241640266059SGregory Neil Shapiro "DISCARDED"); 241706f25ae9SGregory Neil Shapiro break; 241806f25ae9SGregory Neil Shapiro 241906f25ae9SGregory Neil Shapiro case QS_REPLACED: 2420e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 242140266059SGregory Neil Shapiro "REPLACED"); 242206f25ae9SGregory Neil Shapiro break; 242306f25ae9SGregory Neil Shapiro 242406f25ae9SGregory Neil Shapiro case QS_REMOVED: 2425e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 242640266059SGregory Neil Shapiro "REMOVED"); 242706f25ae9SGregory Neil Shapiro break; 242806f25ae9SGregory Neil Shapiro 242906f25ae9SGregory Neil Shapiro case QS_DUPLICATE: 2430e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 243140266059SGregory Neil Shapiro "DUPLICATE"); 243206f25ae9SGregory Neil Shapiro break; 243306f25ae9SGregory Neil Shapiro 243406f25ae9SGregory Neil Shapiro case QS_INCLUDED: 2435e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 243640266059SGregory Neil Shapiro "INCLUDED"); 243706f25ae9SGregory Neil Shapiro break; 243806f25ae9SGregory Neil Shapiro 243906f25ae9SGregory Neil Shapiro default: 2440e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 244140266059SGregory Neil Shapiro "%d", a->q_state); 244206f25ae9SGregory Neil Shapiro break; 244306f25ae9SGregory Neil Shapiro } 2444e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 244540266059SGregory Neil Shapiro ", next=%p, alias %p, uid %d, gid %d\n", 244640266059SGregory Neil Shapiro a->q_next, a->q_alias, 2447c2aa98e2SPeter Wemm (int) a->q_uid, (int) a->q_gid); 2448e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\tflags=%lx<", 244940266059SGregory Neil Shapiro a->q_flags); 245040266059SGregory Neil Shapiro firstone = true; 2451c2aa98e2SPeter Wemm for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++) 2452c2aa98e2SPeter Wemm { 2453c2aa98e2SPeter Wemm if (!bitset(qfp->qf_bit, a->q_flags)) 2454c2aa98e2SPeter Wemm continue; 2455c2aa98e2SPeter Wemm if (!firstone) 2456e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 245740266059SGregory Neil Shapiro ","); 245840266059SGregory Neil Shapiro firstone = false; 2459e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s", 246040266059SGregory Neil Shapiro qfp->qf_name); 2461c2aa98e2SPeter Wemm } 2462e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, ">\n"); 2463e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 246440266059SGregory Neil Shapiro "\towner=%s, home=\"%s\", fullname=\"%s\"\n", 2465c2aa98e2SPeter Wemm a->q_owner == NULL ? "(none)" : a->q_owner, 2466c2aa98e2SPeter Wemm a->q_home == NULL ? "(none)" : a->q_home, 2467c2aa98e2SPeter Wemm a->q_fullname == NULL ? "(none)" : a->q_fullname); 2468e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 246940266059SGregory Neil Shapiro "\torcpt=\"%s\", statmta=%s, status=%s\n", 2470c2aa98e2SPeter Wemm a->q_orcpt == NULL ? "(none)" : a->q_orcpt, 2471c2aa98e2SPeter Wemm a->q_statmta == NULL ? "(none)" : a->q_statmta, 2472c2aa98e2SPeter Wemm a->q_status == NULL ? "(none)" : a->q_status); 2473e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 247440266059SGregory Neil Shapiro "\tfinalrcpt=\"%s\"\n", 247540266059SGregory Neil Shapiro a->q_finalrcpt == NULL ? "(none)" : a->q_finalrcpt); 2476e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 247740266059SGregory Neil Shapiro "\trstatus=\"%s\"\n", 2478c2aa98e2SPeter Wemm a->q_rstatus == NULL ? "(none)" : a->q_rstatus); 2479e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 248040266059SGregory Neil Shapiro "\tstatdate=%s\n", 248106f25ae9SGregory Neil Shapiro a->q_statdate == 0 ? "(none)" : ctime(&a->q_statdate)); 2482c2aa98e2SPeter Wemm 2483c2aa98e2SPeter Wemm if (!follow) 2484c2aa98e2SPeter Wemm return; 2485c2aa98e2SPeter Wemm a = a->q_next; 2486c2aa98e2SPeter Wemm } 2487c2aa98e2SPeter Wemm } 248840266059SGregory Neil Shapiro /* 248940266059SGregory Neil Shapiro ** EMPTYADDR -- return true if this address is empty (``<>'') 2490c2aa98e2SPeter Wemm ** 2491c2aa98e2SPeter Wemm ** Parameters: 2492c2aa98e2SPeter Wemm ** a -- pointer to the address 2493c2aa98e2SPeter Wemm ** 2494c2aa98e2SPeter Wemm ** Returns: 249540266059SGregory Neil Shapiro ** true -- if this address is "empty" (i.e., no one should 2496c2aa98e2SPeter Wemm ** ever generate replies to it. 249740266059SGregory Neil Shapiro ** false -- if it is a "regular" (read: replyable) address. 2498c2aa98e2SPeter Wemm */ 2499c2aa98e2SPeter Wemm 2500c2aa98e2SPeter Wemm bool 2501c2aa98e2SPeter Wemm emptyaddr(a) 2502c2aa98e2SPeter Wemm register ADDRESS *a; 2503c2aa98e2SPeter Wemm { 2504c2aa98e2SPeter Wemm return a->q_paddr == NULL || strcmp(a->q_paddr, "<>") == 0 || 2505c2aa98e2SPeter Wemm a->q_user == NULL || strcmp(a->q_user, "<>") == 0; 2506c2aa98e2SPeter Wemm } 250740266059SGregory Neil Shapiro /* 2508c2aa98e2SPeter Wemm ** REMOTENAME -- return the name relative to the current mailer 2509c2aa98e2SPeter Wemm ** 2510c2aa98e2SPeter Wemm ** Parameters: 2511c2aa98e2SPeter Wemm ** name -- the name to translate. 2512a7ec597cSGregory Neil Shapiro ** m -- the mailer that we want to do rewriting relative to. 2513c2aa98e2SPeter Wemm ** flags -- fine tune operations. 2514c2aa98e2SPeter Wemm ** pstat -- pointer to status word. 2515c2aa98e2SPeter Wemm ** e -- the current envelope. 2516c2aa98e2SPeter Wemm ** 2517c2aa98e2SPeter Wemm ** Returns: 2518c2aa98e2SPeter Wemm ** the text string representing this address relative to 2519c2aa98e2SPeter Wemm ** the receiving mailer. 2520c2aa98e2SPeter Wemm ** 2521c2aa98e2SPeter Wemm ** Side Effects: 2522c2aa98e2SPeter Wemm ** none. 2523c2aa98e2SPeter Wemm ** 2524c2aa98e2SPeter Wemm ** Warnings: 2525c2aa98e2SPeter Wemm ** The text string returned is tucked away locally; 2526c2aa98e2SPeter Wemm ** copy it if you intend to save it. 2527c2aa98e2SPeter Wemm */ 2528c2aa98e2SPeter Wemm 2529c2aa98e2SPeter Wemm char * 2530c2aa98e2SPeter Wemm remotename(name, m, flags, pstat, e) 2531c2aa98e2SPeter Wemm char *name; 2532c2aa98e2SPeter Wemm struct mailer *m; 2533c2aa98e2SPeter Wemm int flags; 2534c2aa98e2SPeter Wemm int *pstat; 2535c2aa98e2SPeter Wemm register ENVELOPE *e; 2536c2aa98e2SPeter Wemm { 2537c2aa98e2SPeter Wemm register char **pvp; 253840266059SGregory Neil Shapiro char *SM_NONVOLATILE fancy; 253940266059SGregory Neil Shapiro char *oldg; 2540c2aa98e2SPeter Wemm int rwset; 2541c2aa98e2SPeter Wemm static char buf[MAXNAME + 1]; 2542c2aa98e2SPeter Wemm char lbuf[MAXNAME + 1]; 2543c2aa98e2SPeter Wemm char pvpbuf[PSBUFSIZE]; 254406f25ae9SGregory Neil Shapiro char addrtype[4]; 2545c2aa98e2SPeter Wemm 2546c2aa98e2SPeter Wemm if (tTd(12, 1)) 254740266059SGregory Neil Shapiro sm_dprintf("remotename(%s)\n", name); 2548c2aa98e2SPeter Wemm 2549c2aa98e2SPeter Wemm /* don't do anything if we are tagging it as special */ 2550c2aa98e2SPeter Wemm if (bitset(RF_SENDERADDR, flags)) 255106f25ae9SGregory Neil Shapiro { 2552c2aa98e2SPeter Wemm rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset 2553c2aa98e2SPeter Wemm : m->m_se_rwset; 255406f25ae9SGregory Neil Shapiro addrtype[2] = 's'; 255506f25ae9SGregory Neil Shapiro } 2556c2aa98e2SPeter Wemm else 255706f25ae9SGregory Neil Shapiro { 2558c2aa98e2SPeter Wemm rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset 2559c2aa98e2SPeter Wemm : m->m_re_rwset; 256006f25ae9SGregory Neil Shapiro addrtype[2] = 'r'; 256106f25ae9SGregory Neil Shapiro } 2562c2aa98e2SPeter Wemm if (rwset < 0) 256306f25ae9SGregory Neil Shapiro return name; 256406f25ae9SGregory Neil Shapiro addrtype[1] = ' '; 256506f25ae9SGregory Neil Shapiro addrtype[3] = '\0'; 256606f25ae9SGregory Neil Shapiro addrtype[0] = bitset(RF_HEADERADDR, flags) ? 'h' : 'e'; 256740266059SGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, macid("{addr_type}"), addrtype); 2568c2aa98e2SPeter Wemm 2569c2aa98e2SPeter Wemm /* 2570c2aa98e2SPeter Wemm ** Do a heuristic crack of this name to extract any comment info. 2571c2aa98e2SPeter Wemm ** This will leave the name as a comment and a $g macro. 2572c2aa98e2SPeter Wemm */ 2573c2aa98e2SPeter Wemm 2574c2aa98e2SPeter Wemm if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) 2575c2aa98e2SPeter Wemm fancy = "\201g"; 2576c2aa98e2SPeter Wemm else 2577d9986b26SGregory Neil Shapiro fancy = crackaddr(name, e); 2578c2aa98e2SPeter Wemm 2579c2aa98e2SPeter Wemm /* 2580c2aa98e2SPeter Wemm ** Turn the name into canonical form. 2581c2aa98e2SPeter Wemm ** Normally this will be RFC 822 style, i.e., "user@domain". 2582c2aa98e2SPeter Wemm ** If this only resolves to "user", and the "C" flag is 2583c2aa98e2SPeter Wemm ** specified in the sending mailer, then the sender's 2584c2aa98e2SPeter Wemm ** domain will be appended. 2585c2aa98e2SPeter Wemm */ 2586c2aa98e2SPeter Wemm 2587e92d3f3fSGregory Neil Shapiro pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL, false); 2588c2aa98e2SPeter Wemm if (pvp == NULL) 258906f25ae9SGregory Neil Shapiro return name; 259040266059SGregory Neil Shapiro if (REWRITE(pvp, 3, e) == EX_TEMPFAIL) 2591c2aa98e2SPeter Wemm *pstat = EX_TEMPFAIL; 2592c2aa98e2SPeter Wemm if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) 2593c2aa98e2SPeter Wemm { 2594c2aa98e2SPeter Wemm /* append from domain to this address */ 2595c2aa98e2SPeter Wemm register char **pxp = pvp; 259606f25ae9SGregory Neil Shapiro int l = MAXATOM; /* size of buffer for pvp */ 2597c2aa98e2SPeter Wemm 2598c2aa98e2SPeter Wemm /* see if there is an "@domain" in the current name */ 2599c2aa98e2SPeter Wemm while (*pxp != NULL && strcmp(*pxp, "@") != 0) 260006f25ae9SGregory Neil Shapiro { 2601c2aa98e2SPeter Wemm pxp++; 260206f25ae9SGregory Neil Shapiro --l; 260306f25ae9SGregory Neil Shapiro } 2604c2aa98e2SPeter Wemm if (*pxp == NULL) 2605c2aa98e2SPeter Wemm { 2606c2aa98e2SPeter Wemm /* no.... append the "@domain" from the sender */ 2607c2aa98e2SPeter Wemm register char **qxq = e->e_fromdomain; 2608c2aa98e2SPeter Wemm 2609c2aa98e2SPeter Wemm while ((*pxp++ = *qxq++) != NULL) 261006f25ae9SGregory Neil Shapiro { 261106f25ae9SGregory Neil Shapiro if (--l <= 0) 261206f25ae9SGregory Neil Shapiro { 261306f25ae9SGregory Neil Shapiro *--pxp = NULL; 261406f25ae9SGregory Neil Shapiro usrerr("553 5.1.0 remotename: too many tokens"); 261506f25ae9SGregory Neil Shapiro *pstat = EX_UNAVAILABLE; 261606f25ae9SGregory Neil Shapiro break; 261706f25ae9SGregory Neil Shapiro } 261806f25ae9SGregory Neil Shapiro } 261940266059SGregory Neil Shapiro if (REWRITE(pvp, 3, e) == EX_TEMPFAIL) 2620c2aa98e2SPeter Wemm *pstat = EX_TEMPFAIL; 2621c2aa98e2SPeter Wemm } 2622c2aa98e2SPeter Wemm } 2623c2aa98e2SPeter Wemm 2624c2aa98e2SPeter Wemm /* 2625c2aa98e2SPeter Wemm ** Do more specific rewriting. 2626c2aa98e2SPeter Wemm ** Rewrite using ruleset 1 or 2 depending on whether this is 2627c2aa98e2SPeter Wemm ** a sender address or not. 2628c2aa98e2SPeter Wemm ** Then run it through any receiving-mailer-specific rulesets. 2629c2aa98e2SPeter Wemm */ 2630c2aa98e2SPeter Wemm 2631c2aa98e2SPeter Wemm if (bitset(RF_SENDERADDR, flags)) 2632c2aa98e2SPeter Wemm { 263340266059SGregory Neil Shapiro if (REWRITE(pvp, 1, e) == EX_TEMPFAIL) 2634c2aa98e2SPeter Wemm *pstat = EX_TEMPFAIL; 2635c2aa98e2SPeter Wemm } 2636c2aa98e2SPeter Wemm else 2637c2aa98e2SPeter Wemm { 263840266059SGregory Neil Shapiro if (REWRITE(pvp, 2, e) == EX_TEMPFAIL) 2639c2aa98e2SPeter Wemm *pstat = EX_TEMPFAIL; 2640c2aa98e2SPeter Wemm } 2641c2aa98e2SPeter Wemm if (rwset > 0) 2642c2aa98e2SPeter Wemm { 264340266059SGregory Neil Shapiro if (REWRITE(pvp, rwset, e) == EX_TEMPFAIL) 2644c2aa98e2SPeter Wemm *pstat = EX_TEMPFAIL; 2645c2aa98e2SPeter Wemm } 2646c2aa98e2SPeter Wemm 2647c2aa98e2SPeter Wemm /* 2648c2aa98e2SPeter Wemm ** Do any final sanitation the address may require. 2649c2aa98e2SPeter Wemm ** This will normally be used to turn internal forms 2650c2aa98e2SPeter Wemm ** (e.g., user@host.LOCAL) into external form. This 2651c2aa98e2SPeter Wemm ** may be used as a default to the above rules. 2652c2aa98e2SPeter Wemm */ 2653c2aa98e2SPeter Wemm 265440266059SGregory Neil Shapiro if (REWRITE(pvp, 4, e) == EX_TEMPFAIL) 2655c2aa98e2SPeter Wemm *pstat = EX_TEMPFAIL; 2656c2aa98e2SPeter Wemm 2657c2aa98e2SPeter Wemm /* 2658c2aa98e2SPeter Wemm ** Now restore the comment information we had at the beginning. 2659c2aa98e2SPeter Wemm */ 2660c2aa98e2SPeter Wemm 2661c2aa98e2SPeter Wemm cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0'); 266240266059SGregory Neil Shapiro oldg = macget(&e->e_macro, 'g'); 266340266059SGregory Neil Shapiro macset(&e->e_macro, 'g', lbuf); 2664c2aa98e2SPeter Wemm 266540266059SGregory Neil Shapiro SM_TRY 2666c2aa98e2SPeter Wemm /* need to make sure route-addrs have <angle brackets> */ 2667c2aa98e2SPeter Wemm if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@') 2668c2aa98e2SPeter Wemm expand("<\201g>", buf, sizeof buf, e); 2669c2aa98e2SPeter Wemm else 2670c2aa98e2SPeter Wemm expand(fancy, buf, sizeof buf, e); 267140266059SGregory Neil Shapiro SM_FINALLY 267240266059SGregory Neil Shapiro macset(&e->e_macro, 'g', oldg); 267340266059SGregory Neil Shapiro SM_END_TRY 2674c2aa98e2SPeter Wemm 2675c2aa98e2SPeter Wemm if (tTd(12, 1)) 267640266059SGregory Neil Shapiro sm_dprintf("remotename => `%s'\n", buf); 267706f25ae9SGregory Neil Shapiro return buf; 2678c2aa98e2SPeter Wemm } 267940266059SGregory Neil Shapiro /* 2680c2aa98e2SPeter Wemm ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 2681c2aa98e2SPeter Wemm ** 2682c2aa98e2SPeter Wemm ** Parameters: 2683c2aa98e2SPeter Wemm ** a -- the address to map (but just the user name part). 2684c2aa98e2SPeter Wemm ** sendq -- the sendq in which to install any replacement 2685c2aa98e2SPeter Wemm ** addresses. 2686c2aa98e2SPeter Wemm ** aliaslevel -- the alias nesting depth. 2687c2aa98e2SPeter Wemm ** e -- the envelope. 2688c2aa98e2SPeter Wemm ** 2689c2aa98e2SPeter Wemm ** Returns: 2690c2aa98e2SPeter Wemm ** none. 2691c2aa98e2SPeter Wemm */ 2692c2aa98e2SPeter Wemm 2693c2aa98e2SPeter Wemm #define Q_COPYFLAGS (QPRIMARY|QBOGUSSHELL|QUNSAFEADDR|\ 2694c2aa98e2SPeter Wemm Q_PINGFLAGS|QHASNOTIFY|\ 269540266059SGregory Neil Shapiro QRELAYED|QEXPANDED|QDELIVERED|QDELAYED|\ 269640266059SGregory Neil Shapiro QBYTRACE|QBYNDELAY|QBYNRELAY) 2697c2aa98e2SPeter Wemm 2698c2aa98e2SPeter Wemm void 2699c2aa98e2SPeter Wemm maplocaluser(a, sendq, aliaslevel, e) 2700c2aa98e2SPeter Wemm register ADDRESS *a; 2701c2aa98e2SPeter Wemm ADDRESS **sendq; 2702c2aa98e2SPeter Wemm int aliaslevel; 2703c2aa98e2SPeter Wemm ENVELOPE *e; 2704c2aa98e2SPeter Wemm { 2705c2aa98e2SPeter Wemm register char **pvp; 270640266059SGregory Neil Shapiro register ADDRESS *SM_NONVOLATILE a1 = NULL; 2707c2aa98e2SPeter Wemm char pvpbuf[PSBUFSIZE]; 2708c2aa98e2SPeter Wemm 2709c2aa98e2SPeter Wemm if (tTd(29, 1)) 2710c2aa98e2SPeter Wemm { 271140266059SGregory Neil Shapiro sm_dprintf("maplocaluser: "); 2712e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), a, false); 2713c2aa98e2SPeter Wemm } 2714e92d3f3fSGregory Neil Shapiro pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL, false); 2715c2aa98e2SPeter Wemm if (pvp == NULL) 2716c2aa98e2SPeter Wemm { 2717c2aa98e2SPeter Wemm if (tTd(29, 9)) 271840266059SGregory Neil Shapiro sm_dprintf("maplocaluser: cannot prescan %s\n", 271906f25ae9SGregory Neil Shapiro a->q_user); 2720c2aa98e2SPeter Wemm return; 2721c2aa98e2SPeter Wemm } 2722c2aa98e2SPeter Wemm 272340266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'h', a->q_host); 272440266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'u', a->q_user); 272540266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'z', a->q_home); 2726c2aa98e2SPeter Wemm 272740266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e r"); 272840266059SGregory Neil Shapiro if (REWRITE(pvp, 5, e) == EX_TEMPFAIL) 2729c2aa98e2SPeter Wemm { 2730c2aa98e2SPeter Wemm if (tTd(29, 9)) 273140266059SGregory Neil Shapiro sm_dprintf("maplocaluser: rewrite tempfail\n"); 273206f25ae9SGregory Neil Shapiro a->q_state = QS_QUEUEUP; 2733c2aa98e2SPeter Wemm a->q_status = "4.4.3"; 2734c2aa98e2SPeter Wemm return; 2735c2aa98e2SPeter Wemm } 2736c2aa98e2SPeter Wemm if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 2737c2aa98e2SPeter Wemm { 2738c2aa98e2SPeter Wemm if (tTd(29, 9)) 273940266059SGregory Neil Shapiro sm_dprintf("maplocaluser: doesn't resolve\n"); 2740c2aa98e2SPeter Wemm return; 2741c2aa98e2SPeter Wemm } 2742c2aa98e2SPeter Wemm 274340266059SGregory Neil Shapiro SM_TRY 2744c2aa98e2SPeter Wemm a1 = buildaddr(pvp, NULL, 0, e); 274540266059SGregory Neil Shapiro SM_EXCEPT(exc, "E:mta.quickabort") 274640266059SGregory Neil Shapiro 274740266059SGregory Neil Shapiro /* 274840266059SGregory Neil Shapiro ** mark address as bad, S5 returned an error 274940266059SGregory Neil Shapiro ** and we gave that back to the SMTP client. 275040266059SGregory Neil Shapiro */ 275140266059SGregory Neil Shapiro 275240266059SGregory Neil Shapiro a->q_state = QS_DONTSEND; 275340266059SGregory Neil Shapiro sm_exc_raisenew_x(&EtypeQuickAbort, 2); 275440266059SGregory Neil Shapiro SM_END_TRY 275540266059SGregory Neil Shapiro 275640266059SGregory Neil Shapiro /* if non-null, mailer destination specified -- has it changed? */ 2757c2aa98e2SPeter Wemm if (a1 == NULL || sameaddr(a, a1)) 2758c2aa98e2SPeter Wemm { 2759c2aa98e2SPeter Wemm if (tTd(29, 9)) 276040266059SGregory Neil Shapiro sm_dprintf("maplocaluser: address unchanged\n"); 2761c2aa98e2SPeter Wemm return; 2762c2aa98e2SPeter Wemm } 2763c2aa98e2SPeter Wemm 2764c2aa98e2SPeter Wemm /* make new address take on flags and print attributes of old */ 2765c2aa98e2SPeter Wemm a1->q_flags &= ~Q_COPYFLAGS; 2766c2aa98e2SPeter Wemm a1->q_flags |= a->q_flags & Q_COPYFLAGS; 276740266059SGregory Neil Shapiro a1->q_paddr = sm_rpool_strdup_x(e->e_rpool, a->q_paddr); 276840266059SGregory Neil Shapiro a1->q_finalrcpt = a->q_finalrcpt; 276906f25ae9SGregory Neil Shapiro a1->q_orcpt = a->q_orcpt; 2770c2aa98e2SPeter Wemm 2771c2aa98e2SPeter Wemm /* mark old address as dead; insert new address */ 277206f25ae9SGregory Neil Shapiro a->q_state = QS_REPLACED; 2773c2aa98e2SPeter Wemm if (tTd(29, 5)) 2774c2aa98e2SPeter Wemm { 277540266059SGregory Neil Shapiro sm_dprintf("maplocaluser: QS_REPLACED "); 2776e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), a, false); 2777c2aa98e2SPeter Wemm } 2778c2aa98e2SPeter Wemm a1->q_alias = a; 277940266059SGregory Neil Shapiro allocaddr(a1, RF_COPYALL, sm_rpool_strdup_x(e->e_rpool, a->q_paddr), e); 2780c2aa98e2SPeter Wemm (void) recipient(a1, sendq, aliaslevel, e); 2781c2aa98e2SPeter Wemm } 278240266059SGregory Neil Shapiro /* 2783c2aa98e2SPeter Wemm ** DEQUOTE_INIT -- initialize dequote map 2784c2aa98e2SPeter Wemm ** 2785c2aa98e2SPeter Wemm ** Parameters: 2786c2aa98e2SPeter Wemm ** map -- the internal map structure. 2787c2aa98e2SPeter Wemm ** args -- arguments. 2788c2aa98e2SPeter Wemm ** 2789c2aa98e2SPeter Wemm ** Returns: 279040266059SGregory Neil Shapiro ** true. 2791c2aa98e2SPeter Wemm */ 2792c2aa98e2SPeter Wemm 2793c2aa98e2SPeter Wemm bool 2794c2aa98e2SPeter Wemm dequote_init(map, args) 2795c2aa98e2SPeter Wemm MAP *map; 2796c2aa98e2SPeter Wemm char *args; 2797c2aa98e2SPeter Wemm { 2798c2aa98e2SPeter Wemm register char *p = args; 2799c2aa98e2SPeter Wemm 280006f25ae9SGregory Neil Shapiro /* there is no check whether there is really an argument */ 2801c2aa98e2SPeter Wemm map->map_mflags |= MF_KEEPQUOTES; 2802c2aa98e2SPeter Wemm for (;;) 2803c2aa98e2SPeter Wemm { 2804c2aa98e2SPeter Wemm while (isascii(*p) && isspace(*p)) 2805c2aa98e2SPeter Wemm p++; 2806c2aa98e2SPeter Wemm if (*p != '-') 2807c2aa98e2SPeter Wemm break; 2808c2aa98e2SPeter Wemm switch (*++p) 2809c2aa98e2SPeter Wemm { 2810c2aa98e2SPeter Wemm case 'a': 2811c2aa98e2SPeter Wemm map->map_app = ++p; 2812c2aa98e2SPeter Wemm break; 2813c2aa98e2SPeter Wemm 281406f25ae9SGregory Neil Shapiro case 'D': 281506f25ae9SGregory Neil Shapiro map->map_mflags |= MF_DEFER; 281606f25ae9SGregory Neil Shapiro break; 281706f25ae9SGregory Neil Shapiro 281806f25ae9SGregory Neil Shapiro case 'S': 2819c2aa98e2SPeter Wemm case 's': 282006f25ae9SGregory Neil Shapiro map->map_spacesub = *++p; 2821c2aa98e2SPeter Wemm break; 2822c2aa98e2SPeter Wemm } 2823c2aa98e2SPeter Wemm while (*p != '\0' && !(isascii(*p) && isspace(*p))) 2824c2aa98e2SPeter Wemm p++; 2825c2aa98e2SPeter Wemm if (*p != '\0') 2826c2aa98e2SPeter Wemm *p = '\0'; 2827c2aa98e2SPeter Wemm } 2828c2aa98e2SPeter Wemm if (map->map_app != NULL) 2829c2aa98e2SPeter Wemm map->map_app = newstr(map->map_app); 2830c2aa98e2SPeter Wemm 283140266059SGregory Neil Shapiro return true; 2832c2aa98e2SPeter Wemm } 283340266059SGregory Neil Shapiro /* 2834c2aa98e2SPeter Wemm ** DEQUOTE_MAP -- unquote an address 2835c2aa98e2SPeter Wemm ** 2836c2aa98e2SPeter Wemm ** Parameters: 2837c2aa98e2SPeter Wemm ** map -- the internal map structure (ignored). 2838c2aa98e2SPeter Wemm ** name -- the name to dequote. 2839c2aa98e2SPeter Wemm ** av -- arguments (ignored). 2840c2aa98e2SPeter Wemm ** statp -- pointer to status out-parameter. 2841c2aa98e2SPeter Wemm ** 2842c2aa98e2SPeter Wemm ** Returns: 2843c2aa98e2SPeter Wemm ** NULL -- if there were no quotes, or if the resulting 2844c2aa98e2SPeter Wemm ** unquoted buffer would not be acceptable to prescan. 2845c2aa98e2SPeter Wemm ** else -- The dequoted buffer. 2846c2aa98e2SPeter Wemm */ 2847c2aa98e2SPeter Wemm 2848c2aa98e2SPeter Wemm /* ARGSUSED2 */ 2849c2aa98e2SPeter Wemm char * 2850c2aa98e2SPeter Wemm dequote_map(map, name, av, statp) 2851c2aa98e2SPeter Wemm MAP *map; 2852c2aa98e2SPeter Wemm char *name; 2853c2aa98e2SPeter Wemm char **av; 2854c2aa98e2SPeter Wemm int *statp; 2855c2aa98e2SPeter Wemm { 2856c2aa98e2SPeter Wemm register char *p; 2857c2aa98e2SPeter Wemm register char *q; 2858c2aa98e2SPeter Wemm register char c; 2859c2aa98e2SPeter Wemm int anglecnt = 0; 2860c2aa98e2SPeter Wemm int cmntcnt = 0; 2861c2aa98e2SPeter Wemm int quotecnt = 0; 2862c2aa98e2SPeter Wemm int spacecnt = 0; 286340266059SGregory Neil Shapiro bool quotemode = false; 286440266059SGregory Neil Shapiro bool bslashmode = false; 286506f25ae9SGregory Neil Shapiro char spacesub = map->map_spacesub; 2866c2aa98e2SPeter Wemm 2867c2aa98e2SPeter Wemm for (p = q = name; (c = *p++) != '\0'; ) 2868c2aa98e2SPeter Wemm { 2869c2aa98e2SPeter Wemm if (bslashmode) 2870c2aa98e2SPeter Wemm { 287140266059SGregory Neil Shapiro bslashmode = false; 2872c2aa98e2SPeter Wemm *q++ = c; 2873c2aa98e2SPeter Wemm continue; 2874c2aa98e2SPeter Wemm } 2875c2aa98e2SPeter Wemm 2876c2aa98e2SPeter Wemm if (c == ' ' && spacesub != '\0') 2877c2aa98e2SPeter Wemm c = spacesub; 2878c2aa98e2SPeter Wemm 2879c2aa98e2SPeter Wemm switch (c) 2880c2aa98e2SPeter Wemm { 2881c2aa98e2SPeter Wemm case '\\': 288240266059SGregory Neil Shapiro bslashmode = true; 2883c2aa98e2SPeter Wemm break; 2884c2aa98e2SPeter Wemm 2885c2aa98e2SPeter Wemm case '(': 2886c2aa98e2SPeter Wemm cmntcnt++; 2887c2aa98e2SPeter Wemm break; 2888c2aa98e2SPeter Wemm 2889c2aa98e2SPeter Wemm case ')': 2890c2aa98e2SPeter Wemm if (cmntcnt-- <= 0) 2891c2aa98e2SPeter Wemm return NULL; 2892c2aa98e2SPeter Wemm break; 2893c2aa98e2SPeter Wemm 2894c2aa98e2SPeter Wemm case ' ': 289506f25ae9SGregory Neil Shapiro case '\t': 2896c2aa98e2SPeter Wemm spacecnt++; 2897c2aa98e2SPeter Wemm break; 2898c2aa98e2SPeter Wemm } 2899c2aa98e2SPeter Wemm 2900c2aa98e2SPeter Wemm if (cmntcnt > 0) 2901c2aa98e2SPeter Wemm { 2902c2aa98e2SPeter Wemm *q++ = c; 2903c2aa98e2SPeter Wemm continue; 2904c2aa98e2SPeter Wemm } 2905c2aa98e2SPeter Wemm 2906c2aa98e2SPeter Wemm switch (c) 2907c2aa98e2SPeter Wemm { 2908c2aa98e2SPeter Wemm case '"': 2909c2aa98e2SPeter Wemm quotemode = !quotemode; 2910c2aa98e2SPeter Wemm quotecnt++; 2911c2aa98e2SPeter Wemm continue; 2912c2aa98e2SPeter Wemm 2913c2aa98e2SPeter Wemm case '<': 2914c2aa98e2SPeter Wemm anglecnt++; 2915c2aa98e2SPeter Wemm break; 2916c2aa98e2SPeter Wemm 2917c2aa98e2SPeter Wemm case '>': 2918c2aa98e2SPeter Wemm if (anglecnt-- <= 0) 2919c2aa98e2SPeter Wemm return NULL; 2920c2aa98e2SPeter Wemm break; 2921c2aa98e2SPeter Wemm } 2922c2aa98e2SPeter Wemm *q++ = c; 2923c2aa98e2SPeter Wemm } 2924c2aa98e2SPeter Wemm 2925c2aa98e2SPeter Wemm if (anglecnt != 0 || cmntcnt != 0 || bslashmode || 2926c2aa98e2SPeter Wemm quotemode || quotecnt <= 0 || spacecnt != 0) 2927c2aa98e2SPeter Wemm return NULL; 2928c2aa98e2SPeter Wemm *q++ = '\0'; 2929c2aa98e2SPeter Wemm return map_rewrite(map, name, strlen(name), NULL); 2930c2aa98e2SPeter Wemm } 293140266059SGregory Neil Shapiro /* 2932c2aa98e2SPeter Wemm ** RSCHECK -- check string(s) for validity using rewriting sets 2933c2aa98e2SPeter Wemm ** 2934c2aa98e2SPeter Wemm ** Parameters: 2935c2aa98e2SPeter Wemm ** rwset -- the rewriting set to use. 2936c2aa98e2SPeter Wemm ** p1 -- the first string to check. 2937c2aa98e2SPeter Wemm ** p2 -- the second string to check -- may be null. 2938c2aa98e2SPeter Wemm ** e -- the current envelope. 2939959366dcSGregory Neil Shapiro ** flags -- control some behavior, see RSF_ in sendmail.h 294040266059SGregory Neil Shapiro ** logl -- logging level. 2941193538b7SGregory Neil Shapiro ** host -- NULL or relay host. 294240266059SGregory Neil Shapiro ** logid -- id for sm_syslog. 2943c2aa98e2SPeter Wemm ** 2944c2aa98e2SPeter Wemm ** Returns: 2945c2aa98e2SPeter Wemm ** EX_OK -- if the rwset doesn't resolve to $#error 2946c2aa98e2SPeter Wemm ** else -- the failure status (message printed) 2947c2aa98e2SPeter Wemm */ 2948c2aa98e2SPeter Wemm 2949c2aa98e2SPeter Wemm int 2950959366dcSGregory Neil Shapiro rscheck(rwset, p1, p2, e, flags, logl, host, logid) 2951c2aa98e2SPeter Wemm char *rwset; 2952c2aa98e2SPeter Wemm char *p1; 2953c2aa98e2SPeter Wemm char *p2; 2954c2aa98e2SPeter Wemm ENVELOPE *e; 2955959366dcSGregory Neil Shapiro int flags; 295606f25ae9SGregory Neil Shapiro int logl; 2957193538b7SGregory Neil Shapiro char *host; 295840266059SGregory Neil Shapiro char *logid; 2959c2aa98e2SPeter Wemm { 296040266059SGregory Neil Shapiro char *volatile buf; 29614e4196cbSGregory Neil Shapiro size_t bufsize; 2962c2aa98e2SPeter Wemm int saveexitstat; 296340266059SGregory Neil Shapiro int volatile rstat = EX_OK; 2964c2aa98e2SPeter Wemm char **pvp; 2965c2aa98e2SPeter Wemm int rsno; 296640266059SGregory Neil Shapiro bool volatile discard = false; 2967c2aa98e2SPeter Wemm auto ADDRESS a1; 2968c2aa98e2SPeter Wemm bool saveQuickAbort = QuickAbort; 2969c2aa98e2SPeter Wemm bool saveSuprErrs = SuprErrs; 297040266059SGregory Neil Shapiro bool quarantine = false; 297140266059SGregory Neil Shapiro char ubuf[BUFSIZ * 2]; 2972c2aa98e2SPeter Wemm char buf0[MAXLINE]; 2973c2aa98e2SPeter Wemm char pvpbuf[PSBUFSIZE]; 2974c2aa98e2SPeter Wemm extern char MsgBuf[]; 2975c2aa98e2SPeter Wemm 2976c2aa98e2SPeter Wemm if (tTd(48, 2)) 297740266059SGregory Neil Shapiro sm_dprintf("rscheck(%s, %s, %s)\n", rwset, p1, 2978c2aa98e2SPeter Wemm p2 == NULL ? "(NULL)" : p2); 2979c2aa98e2SPeter Wemm 2980c2aa98e2SPeter Wemm rsno = strtorwset(rwset, NULL, ST_FIND); 2981c2aa98e2SPeter Wemm if (rsno < 0) 2982c2aa98e2SPeter Wemm return EX_OK; 2983c2aa98e2SPeter Wemm 2984c2aa98e2SPeter Wemm if (p2 != NULL) 2985c2aa98e2SPeter Wemm { 2986c2aa98e2SPeter Wemm bufsize = strlen(p1) + strlen(p2) + 2; 2987c2aa98e2SPeter Wemm if (bufsize > sizeof buf0) 298840266059SGregory Neil Shapiro buf = sm_malloc_x(bufsize); 2989c2aa98e2SPeter Wemm else 2990c2aa98e2SPeter Wemm { 2991c2aa98e2SPeter Wemm buf = buf0; 2992c2aa98e2SPeter Wemm bufsize = sizeof buf0; 2993c2aa98e2SPeter Wemm } 299440266059SGregory Neil Shapiro (void) sm_snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2); 2995c2aa98e2SPeter Wemm } 2996c2aa98e2SPeter Wemm else 2997c2aa98e2SPeter Wemm { 2998c2aa98e2SPeter Wemm bufsize = strlen(p1) + 1; 2999c2aa98e2SPeter Wemm if (bufsize > sizeof buf0) 300040266059SGregory Neil Shapiro buf = sm_malloc_x(bufsize); 3001c2aa98e2SPeter Wemm else 3002c2aa98e2SPeter Wemm { 3003c2aa98e2SPeter Wemm buf = buf0; 3004c2aa98e2SPeter Wemm bufsize = sizeof buf0; 3005c2aa98e2SPeter Wemm } 300640266059SGregory Neil Shapiro (void) sm_strlcpy(buf, p1, bufsize); 3007c2aa98e2SPeter Wemm } 300840266059SGregory Neil Shapiro SM_TRY 300940266059SGregory Neil Shapiro { 301040266059SGregory Neil Shapiro SuprErrs = true; 301140266059SGregory Neil Shapiro QuickAbort = false; 301206f25ae9SGregory Neil Shapiro pvp = prescan(buf, '\0', pvpbuf, sizeof pvpbuf, NULL, 3013e92d3f3fSGregory Neil Shapiro bitset(RSF_RMCOMM, flags) ? NULL : TokTypeNoC, 3014e92d3f3fSGregory Neil Shapiro bitset(RSF_RMCOMM, flags) ? false : true); 3015c2aa98e2SPeter Wemm SuprErrs = saveSuprErrs; 3016c2aa98e2SPeter Wemm if (pvp == NULL) 3017c2aa98e2SPeter Wemm { 3018c2aa98e2SPeter Wemm if (tTd(48, 2)) 301940266059SGregory Neil Shapiro sm_dprintf("rscheck: cannot prescan input\n"); 3020c2aa98e2SPeter Wemm /* 3021c2aa98e2SPeter Wemm syserr("rscheck: cannot prescan input: \"%s\"", 3022c2aa98e2SPeter Wemm shortenstring(buf, MAXSHORTSTR)); 3023c2aa98e2SPeter Wemm rstat = EX_DATAERR; 3024c2aa98e2SPeter Wemm */ 3025c2aa98e2SPeter Wemm goto finis; 3026c2aa98e2SPeter Wemm } 3027959366dcSGregory Neil Shapiro if (bitset(RSF_UNSTRUCTURED, flags)) 3028959366dcSGregory Neil Shapiro SuprErrs = true; 302940266059SGregory Neil Shapiro (void) REWRITE(pvp, rsno, e); 3030959366dcSGregory Neil Shapiro if (bitset(RSF_UNSTRUCTURED, flags)) 3031959366dcSGregory Neil Shapiro SuprErrs = saveSuprErrs; 3032c2aa98e2SPeter Wemm if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET || 3033c2aa98e2SPeter Wemm pvp[1] == NULL || (strcmp(pvp[1], "error") != 0 && 3034c2aa98e2SPeter Wemm strcmp(pvp[1], "discard") != 0)) 3035c2aa98e2SPeter Wemm { 3036c2aa98e2SPeter Wemm goto finis; 3037c2aa98e2SPeter Wemm } 3038c2aa98e2SPeter Wemm 3039c2aa98e2SPeter Wemm if (strcmp(pvp[1], "discard") == 0) 3040c2aa98e2SPeter Wemm { 3041c2aa98e2SPeter Wemm if (tTd(48, 2)) 304240266059SGregory Neil Shapiro sm_dprintf("rscheck: discard mailer selected\n"); 3043c2aa98e2SPeter Wemm e->e_flags |= EF_DISCARD; 304440266059SGregory Neil Shapiro discard = true; 3045c2aa98e2SPeter Wemm } 304640266059SGregory Neil Shapiro else if (strcmp(pvp[1], "error") == 0 && 304740266059SGregory Neil Shapiro pvp[2] != NULL && (pvp[2][0] & 0377) == CANONHOST && 304840266059SGregory Neil Shapiro pvp[3] != NULL && strcmp(pvp[3], "quarantine") == 0) 304940266059SGregory Neil Shapiro { 305040266059SGregory Neil Shapiro if (pvp[4] == NULL || 305140266059SGregory Neil Shapiro (pvp[4][0] & 0377) != CANONUSER || 305240266059SGregory Neil Shapiro pvp[5] == NULL) 305340266059SGregory Neil Shapiro e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, 305440266059SGregory Neil Shapiro rwset); 305540266059SGregory Neil Shapiro else 305640266059SGregory Neil Shapiro { 305740266059SGregory Neil Shapiro cataddr(&(pvp[5]), NULL, ubuf, 305840266059SGregory Neil Shapiro sizeof ubuf, ' '); 305940266059SGregory Neil Shapiro e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, 306040266059SGregory Neil Shapiro ubuf); 306140266059SGregory Neil Shapiro } 306240266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 306340266059SGregory Neil Shapiro macid("{quarantine}"), e->e_quarmsg); 306440266059SGregory Neil Shapiro quarantine = true; 306540266059SGregory Neil Shapiro } 3066c2aa98e2SPeter Wemm else 3067c2aa98e2SPeter Wemm { 3068c2aa98e2SPeter Wemm int savelogusrerrs = LogUsrErrs; 306940266059SGregory Neil Shapiro static bool logged = false; 3070c2aa98e2SPeter Wemm 3071c2aa98e2SPeter Wemm /* got an error -- process it */ 3072c2aa98e2SPeter Wemm saveexitstat = ExitStat; 307340266059SGregory Neil Shapiro LogUsrErrs = false; 3074c2aa98e2SPeter Wemm (void) buildaddr(pvp, &a1, 0, e); 3075c2aa98e2SPeter Wemm LogUsrErrs = savelogusrerrs; 3076c2aa98e2SPeter Wemm rstat = ExitStat; 3077c2aa98e2SPeter Wemm ExitStat = saveexitstat; 3078c2aa98e2SPeter Wemm if (!logged) 3079c2aa98e2SPeter Wemm { 3080959366dcSGregory Neil Shapiro if (bitset(RSF_COUNT, flags)) 308140266059SGregory Neil Shapiro markstats(e, &a1, STATS_REJECT); 308240266059SGregory Neil Shapiro logged = true; 3083c2aa98e2SPeter Wemm } 3084c2aa98e2SPeter Wemm } 3085c2aa98e2SPeter Wemm 308640266059SGregory Neil Shapiro if (LogLevel > logl) 3087c2aa98e2SPeter Wemm { 3088c2aa98e2SPeter Wemm char *relay; 3089c2aa98e2SPeter Wemm char *p; 3090c2aa98e2SPeter Wemm char lbuf[MAXLINE]; 3091c2aa98e2SPeter Wemm 3092c2aa98e2SPeter Wemm p = lbuf; 3093c2aa98e2SPeter Wemm if (p2 != NULL) 3094c2aa98e2SPeter Wemm { 309540266059SGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(lbuf, p), 3096c2aa98e2SPeter Wemm ", arg2=%s", 3097c2aa98e2SPeter Wemm p2); 3098c2aa98e2SPeter Wemm p += strlen(p); 3099c2aa98e2SPeter Wemm } 3100193538b7SGregory Neil Shapiro 3101193538b7SGregory Neil Shapiro if (host != NULL) 3102193538b7SGregory Neil Shapiro relay = host; 3103193538b7SGregory Neil Shapiro else 3104193538b7SGregory Neil Shapiro relay = macvalue('_', e); 3105193538b7SGregory Neil Shapiro if (relay != NULL) 3106c2aa98e2SPeter Wemm { 310740266059SGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(lbuf, p), 3108c2aa98e2SPeter Wemm ", relay=%s", relay); 3109c2aa98e2SPeter Wemm p += strlen(p); 3110c2aa98e2SPeter Wemm } 3111c2aa98e2SPeter Wemm *p = '\0'; 3112c2aa98e2SPeter Wemm if (discard) 311340266059SGregory Neil Shapiro sm_syslog(LOG_NOTICE, logid, 3114c2aa98e2SPeter Wemm "ruleset=%s, arg1=%s%s, discard", 3115c2aa98e2SPeter Wemm rwset, p1, lbuf); 311640266059SGregory Neil Shapiro else if (quarantine) 311740266059SGregory Neil Shapiro sm_syslog(LOG_NOTICE, logid, 311840266059SGregory Neil Shapiro "ruleset=%s, arg1=%s%s, quarantine=%s", 311940266059SGregory Neil Shapiro rwset, p1, lbuf, ubuf); 3120c2aa98e2SPeter Wemm else 312140266059SGregory Neil Shapiro sm_syslog(LOG_NOTICE, logid, 3122c2aa98e2SPeter Wemm "ruleset=%s, arg1=%s%s, reject=%s", 3123c2aa98e2SPeter Wemm rwset, p1, lbuf, MsgBuf); 3124c2aa98e2SPeter Wemm } 3125c2aa98e2SPeter Wemm 312640266059SGregory Neil Shapiro finis: ; 312740266059SGregory Neil Shapiro } 312840266059SGregory Neil Shapiro SM_FINALLY 312940266059SGregory Neil Shapiro { 3130c2aa98e2SPeter Wemm /* clean up */ 3131c2aa98e2SPeter Wemm if (buf != buf0) 31328774250cSGregory Neil Shapiro sm_free(buf); 313340266059SGregory Neil Shapiro QuickAbort = saveQuickAbort; 313440266059SGregory Neil Shapiro } 313540266059SGregory Neil Shapiro SM_END_TRY 3136c2aa98e2SPeter Wemm 313740266059SGregory Neil Shapiro setstat(rstat); 313840266059SGregory Neil Shapiro 313940266059SGregory Neil Shapiro /* rulesets don't set errno */ 314040266059SGregory Neil Shapiro errno = 0; 3141c2aa98e2SPeter Wemm if (rstat != EX_OK && QuickAbort) 314240266059SGregory Neil Shapiro sm_exc_raisenew_x(&EtypeQuickAbort, 2); 314340266059SGregory Neil Shapiro return rstat; 314440266059SGregory Neil Shapiro } 314540266059SGregory Neil Shapiro /* 314640266059SGregory Neil Shapiro ** RSCAP -- call rewriting set to return capabilities 314740266059SGregory Neil Shapiro ** 314840266059SGregory Neil Shapiro ** Parameters: 314940266059SGregory Neil Shapiro ** rwset -- the rewriting set to use. 315040266059SGregory Neil Shapiro ** p1 -- the first string to check. 315140266059SGregory Neil Shapiro ** p2 -- the second string to check -- may be null. 315240266059SGregory Neil Shapiro ** e -- the current envelope. 315340266059SGregory Neil Shapiro ** pvp -- pointer to token vector. 315440266059SGregory Neil Shapiro ** pvpbuf -- buffer space. 3155a7ec597cSGregory Neil Shapiro ** size -- size of buffer space. 315640266059SGregory Neil Shapiro ** 315740266059SGregory Neil Shapiro ** Returns: 315840266059SGregory Neil Shapiro ** EX_UNAVAILABLE -- ruleset doesn't exist. 315940266059SGregory Neil Shapiro ** EX_DATAERR -- prescan() failed. 316040266059SGregory Neil Shapiro ** EX_OK -- rewrite() was successful. 316140266059SGregory Neil Shapiro ** else -- return status from rewrite(). 316240266059SGregory Neil Shapiro */ 316340266059SGregory Neil Shapiro 316440266059SGregory Neil Shapiro int 316540266059SGregory Neil Shapiro rscap(rwset, p1, p2, e, pvp, pvpbuf, size) 316640266059SGregory Neil Shapiro char *rwset; 316740266059SGregory Neil Shapiro char *p1; 316840266059SGregory Neil Shapiro char *p2; 316940266059SGregory Neil Shapiro ENVELOPE *e; 317040266059SGregory Neil Shapiro char ***pvp; 317140266059SGregory Neil Shapiro char *pvpbuf; 317240266059SGregory Neil Shapiro int size; 317340266059SGregory Neil Shapiro { 317440266059SGregory Neil Shapiro char *volatile buf; 31754e4196cbSGregory Neil Shapiro size_t bufsize; 317640266059SGregory Neil Shapiro int volatile rstat = EX_OK; 317740266059SGregory Neil Shapiro int rsno; 317840266059SGregory Neil Shapiro bool saveQuickAbort = QuickAbort; 317940266059SGregory Neil Shapiro bool saveSuprErrs = SuprErrs; 318040266059SGregory Neil Shapiro char buf0[MAXLINE]; 318140266059SGregory Neil Shapiro extern char MsgBuf[]; 318240266059SGregory Neil Shapiro 318340266059SGregory Neil Shapiro if (tTd(48, 2)) 318440266059SGregory Neil Shapiro sm_dprintf("rscap(%s, %s, %s)\n", rwset, p1, 318540266059SGregory Neil Shapiro p2 == NULL ? "(NULL)" : p2); 318640266059SGregory Neil Shapiro 3187af9557fdSGregory Neil Shapiro SM_REQUIRE(pvp != NULL); 318840266059SGregory Neil Shapiro rsno = strtorwset(rwset, NULL, ST_FIND); 318940266059SGregory Neil Shapiro if (rsno < 0) 319040266059SGregory Neil Shapiro return EX_UNAVAILABLE; 319140266059SGregory Neil Shapiro 319240266059SGregory Neil Shapiro if (p2 != NULL) 319340266059SGregory Neil Shapiro { 319440266059SGregory Neil Shapiro bufsize = strlen(p1) + strlen(p2) + 2; 319540266059SGregory Neil Shapiro if (bufsize > sizeof buf0) 319640266059SGregory Neil Shapiro buf = sm_malloc_x(bufsize); 319740266059SGregory Neil Shapiro else 319840266059SGregory Neil Shapiro { 319940266059SGregory Neil Shapiro buf = buf0; 320040266059SGregory Neil Shapiro bufsize = sizeof buf0; 320140266059SGregory Neil Shapiro } 320240266059SGregory Neil Shapiro (void) sm_snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2); 320340266059SGregory Neil Shapiro } 320440266059SGregory Neil Shapiro else 320540266059SGregory Neil Shapiro { 320640266059SGregory Neil Shapiro bufsize = strlen(p1) + 1; 320740266059SGregory Neil Shapiro if (bufsize > sizeof buf0) 320840266059SGregory Neil Shapiro buf = sm_malloc_x(bufsize); 320940266059SGregory Neil Shapiro else 321040266059SGregory Neil Shapiro { 321140266059SGregory Neil Shapiro buf = buf0; 321240266059SGregory Neil Shapiro bufsize = sizeof buf0; 321340266059SGregory Neil Shapiro } 321440266059SGregory Neil Shapiro (void) sm_strlcpy(buf, p1, bufsize); 321540266059SGregory Neil Shapiro } 321640266059SGregory Neil Shapiro SM_TRY 321740266059SGregory Neil Shapiro { 321840266059SGregory Neil Shapiro SuprErrs = true; 321940266059SGregory Neil Shapiro QuickAbort = false; 3220e92d3f3fSGregory Neil Shapiro *pvp = prescan(buf, '\0', pvpbuf, size, NULL, NULL, false); 322140266059SGregory Neil Shapiro if (*pvp != NULL) 3222a7ec597cSGregory Neil Shapiro rstat = rewrite(*pvp, rsno, 0, e, size); 322340266059SGregory Neil Shapiro else 322440266059SGregory Neil Shapiro { 322540266059SGregory Neil Shapiro if (tTd(48, 2)) 322640266059SGregory Neil Shapiro sm_dprintf("rscap: cannot prescan input\n"); 322740266059SGregory Neil Shapiro rstat = EX_DATAERR; 322840266059SGregory Neil Shapiro } 322940266059SGregory Neil Shapiro } 323040266059SGregory Neil Shapiro SM_FINALLY 323140266059SGregory Neil Shapiro { 323240266059SGregory Neil Shapiro /* clean up */ 323340266059SGregory Neil Shapiro if (buf != buf0) 323440266059SGregory Neil Shapiro sm_free(buf); 323540266059SGregory Neil Shapiro SuprErrs = saveSuprErrs; 323640266059SGregory Neil Shapiro QuickAbort = saveQuickAbort; 323740266059SGregory Neil Shapiro 323840266059SGregory Neil Shapiro /* prevent information leak, this may contain rewrite error */ 323940266059SGregory Neil Shapiro MsgBuf[0] = '\0'; 324040266059SGregory Neil Shapiro } 324140266059SGregory Neil Shapiro SM_END_TRY 3242c2aa98e2SPeter Wemm return rstat; 3243c2aa98e2SPeter Wemm } 3244