1c2aa98e2SPeter Wemm /* 2d9986b26SGregory Neil Shapiro * Copyright (c) 1998-2003 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 16d9986b26SGregory Neil Shapiro SM_RCSID("@(#)$Id: parseaddr.c,v 8.359.2.4 2003/01/18 00:41:48 gshapiro 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 93c2aa98e2SPeter Wemm pvp = prescan(addr, delim, pvpbuf, sizeof pvpbuf, delimptr, NULL); 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-->"); 23140266059SGregory Neil Shapiro printaddr(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. 463c2aa98e2SPeter Wemm ** 464c2aa98e2SPeter Wemm ** Returns: 465c2aa98e2SPeter Wemm ** A pointer to a vector of tokens. 466c2aa98e2SPeter Wemm ** NULL on error. 467c2aa98e2SPeter Wemm */ 468c2aa98e2SPeter Wemm 469c2aa98e2SPeter Wemm /* states and character types */ 470c2aa98e2SPeter Wemm #define OPR 0 /* operator */ 471c2aa98e2SPeter Wemm #define ATM 1 /* atom */ 472c2aa98e2SPeter Wemm #define QST 2 /* in quoted string */ 473c2aa98e2SPeter Wemm #define SPC 3 /* chewing up spaces */ 474c2aa98e2SPeter Wemm #define ONE 4 /* pick up one character */ 475c2aa98e2SPeter Wemm #define ILL 5 /* illegal character */ 476c2aa98e2SPeter Wemm 477c2aa98e2SPeter Wemm #define NSTATES 6 /* number of states */ 478c2aa98e2SPeter Wemm #define TYPE 017 /* mask to select state type */ 479c2aa98e2SPeter Wemm 480c2aa98e2SPeter Wemm /* meta bits for table */ 481c2aa98e2SPeter Wemm #define M 020 /* meta character; don't pass through */ 482c2aa98e2SPeter Wemm #define B 040 /* cause a break */ 483c2aa98e2SPeter Wemm #define MB M|B /* meta-break */ 484c2aa98e2SPeter Wemm 485c2aa98e2SPeter Wemm static short StateTab[NSTATES][NSTATES] = 486c2aa98e2SPeter Wemm { 487c2aa98e2SPeter Wemm /* oldst chtype> OPR ATM QST SPC ONE ILL */ 488c2aa98e2SPeter Wemm /*OPR*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|MB }, 489c2aa98e2SPeter Wemm /*ATM*/ { OPR|B, ATM, QST|B, SPC|MB, ONE|B, ILL|MB }, 490c2aa98e2SPeter Wemm /*QST*/ { QST, QST, OPR, QST, QST, QST }, 491c2aa98e2SPeter Wemm /*SPC*/ { OPR, ATM, QST, SPC|M, ONE, ILL|MB }, 492c2aa98e2SPeter Wemm /*ONE*/ { OPR, OPR, OPR, OPR, OPR, ILL|MB }, 493c2aa98e2SPeter Wemm /*ILL*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|M }, 494c2aa98e2SPeter Wemm }; 495c2aa98e2SPeter Wemm 496c2aa98e2SPeter Wemm /* token type table -- it gets modified with $o characters */ 49740266059SGregory Neil Shapiro static unsigned char TokTypeTab[256] = 498c2aa98e2SPeter Wemm { 499c2aa98e2SPeter Wemm /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 500c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM, 501c2aa98e2SPeter Wemm /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 502c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 503c2aa98e2SPeter Wemm /* sp ! " # $ % & ' ( ) * + , - . / */ 50406f25ae9SGregory Neil Shapiro SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, SPC,SPC,ATM,ATM,ATM,ATM,ATM,ATM, 505c2aa98e2SPeter Wemm /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 506c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 507c2aa98e2SPeter Wemm /* @ A B C D E F G H I J K L M N O */ 508c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 509c2aa98e2SPeter Wemm /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 510c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 511c2aa98e2SPeter Wemm /* ` a b c d e f g h i j k l m n o */ 512c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 513c2aa98e2SPeter Wemm /* p q r s t u v w x y z { | } ~ del */ 514c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 515c2aa98e2SPeter Wemm 516c2aa98e2SPeter Wemm /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 517c2aa98e2SPeter Wemm OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 518c2aa98e2SPeter Wemm /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 519c2aa98e2SPeter Wemm OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 520c2aa98e2SPeter Wemm /* sp ! " # $ % & ' ( ) * + , - . / */ 521c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 522c2aa98e2SPeter Wemm /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 523c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 524c2aa98e2SPeter Wemm /* @ A B C D E F G H I J K L M N O */ 525c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 526c2aa98e2SPeter Wemm /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 527c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 528c2aa98e2SPeter Wemm /* ` a b c d e f g h i j k l m n o */ 529c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 530c2aa98e2SPeter Wemm /* p q r s t u v w x y z { | } ~ del */ 531c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 532c2aa98e2SPeter Wemm }; 533c2aa98e2SPeter Wemm 534c2aa98e2SPeter Wemm /* token type table for MIME parsing */ 53540266059SGregory Neil Shapiro unsigned char MimeTokenTab[256] = 536c2aa98e2SPeter Wemm { 537c2aa98e2SPeter Wemm /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 538c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,SPC,SPC,SPC,SPC,SPC,ILL,ILL, 539c2aa98e2SPeter Wemm /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 540c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 541c2aa98e2SPeter Wemm /* sp ! " # $ % & ' ( ) * + , - . / */ 54206f25ae9SGregory Neil Shapiro SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, SPC,SPC,ATM,ATM,OPR,ATM,ATM,OPR, 543c2aa98e2SPeter Wemm /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 544c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,OPR,OPR,OPR,OPR,OPR,OPR, 545c2aa98e2SPeter Wemm /* @ A B C D E F G H I J K L M N O */ 546c2aa98e2SPeter Wemm OPR,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 547c2aa98e2SPeter Wemm /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 548c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,OPR,OPR,OPR,ATM,ATM, 549c2aa98e2SPeter Wemm /* ` a b c d e f g h i j k l m n o */ 550c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 551c2aa98e2SPeter Wemm /* p q r s t u v w x y z { | } ~ del */ 552c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 553c2aa98e2SPeter Wemm 554c2aa98e2SPeter Wemm /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 555c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 556c2aa98e2SPeter Wemm /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 557c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 558c2aa98e2SPeter Wemm /* sp ! " # $ % & ' ( ) * + , - . / */ 559c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 560c2aa98e2SPeter Wemm /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 561c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 562c2aa98e2SPeter Wemm /* @ A B C D E F G H I J K L M N O */ 563c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 564c2aa98e2SPeter Wemm /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 565c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 566c2aa98e2SPeter Wemm /* ` a b c d e f g h i j k l m n o */ 567c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 568c2aa98e2SPeter Wemm /* p q r s t u v w x y z { | } ~ del */ 569c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 570c2aa98e2SPeter Wemm }; 571c2aa98e2SPeter Wemm 57206f25ae9SGregory Neil Shapiro /* token type table: don't strip comments */ 57340266059SGregory Neil Shapiro unsigned char TokTypeNoC[256] = 57406f25ae9SGregory Neil Shapiro { 57506f25ae9SGregory Neil Shapiro /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 57606f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM, 57706f25ae9SGregory Neil Shapiro /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 57806f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 57906f25ae9SGregory Neil Shapiro /* sp ! " # $ % & ' ( ) * + , - . / */ 58006f25ae9SGregory Neil Shapiro SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, OPR,OPR,ATM,ATM,ATM,ATM,ATM,ATM, 58106f25ae9SGregory Neil Shapiro /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 58206f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 58306f25ae9SGregory Neil Shapiro /* @ A B C D E F G H I J K L M N O */ 58406f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 58506f25ae9SGregory Neil Shapiro /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 58606f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 58706f25ae9SGregory Neil Shapiro /* ` a b c d e f g h i j k l m n o */ 58806f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 58906f25ae9SGregory Neil Shapiro /* p q r s t u v w x y z { | } ~ del */ 59006f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 59106f25ae9SGregory Neil Shapiro 59206f25ae9SGregory Neil Shapiro /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 59306f25ae9SGregory Neil Shapiro OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 59406f25ae9SGregory Neil Shapiro /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 59506f25ae9SGregory Neil Shapiro OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 59606f25ae9SGregory Neil Shapiro /* sp ! " # $ % & ' ( ) * + , - . / */ 59706f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 59806f25ae9SGregory Neil Shapiro /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 59906f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 60006f25ae9SGregory Neil Shapiro /* @ A B C D E F G H I J K L M N O */ 60106f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 60206f25ae9SGregory Neil Shapiro /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 60306f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 60406f25ae9SGregory Neil Shapiro /* ` a b c d e f g h i j k l m n o */ 60506f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 60606f25ae9SGregory Neil Shapiro /* p q r s t u v w x y z { | } ~ del */ 60706f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 60806f25ae9SGregory Neil Shapiro }; 60906f25ae9SGregory Neil Shapiro 610c2aa98e2SPeter Wemm 611c2aa98e2SPeter Wemm #define NOCHAR -1 /* signal nothing in lookahead token */ 612c2aa98e2SPeter Wemm 613c2aa98e2SPeter Wemm char ** 614c2aa98e2SPeter Wemm prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab) 615c2aa98e2SPeter Wemm char *addr; 616c2aa98e2SPeter Wemm int delim; 617c2aa98e2SPeter Wemm char pvpbuf[]; 618c2aa98e2SPeter Wemm int pvpbsize; 619c2aa98e2SPeter Wemm char **delimptr; 62040266059SGregory Neil Shapiro unsigned char *toktab; 621c2aa98e2SPeter Wemm { 622c2aa98e2SPeter Wemm register char *p; 623c2aa98e2SPeter Wemm register char *q; 624c2aa98e2SPeter Wemm register int c; 625c2aa98e2SPeter Wemm char **avp; 626c2aa98e2SPeter Wemm bool bslashmode; 627c2aa98e2SPeter Wemm bool route_syntax; 628c2aa98e2SPeter Wemm int cmntcnt; 629c2aa98e2SPeter Wemm int anglecnt; 630c2aa98e2SPeter Wemm char *tok; 631c2aa98e2SPeter Wemm int state; 632c2aa98e2SPeter Wemm int newstate; 633c2aa98e2SPeter Wemm char *saveto = CurEnv->e_to; 634c2aa98e2SPeter Wemm static char *av[MAXATOM + 1]; 63540266059SGregory Neil Shapiro static bool firsttime = true; 636c2aa98e2SPeter Wemm extern int errno; 637c2aa98e2SPeter Wemm 638c2aa98e2SPeter Wemm if (firsttime) 639c2aa98e2SPeter Wemm { 640c2aa98e2SPeter Wemm /* initialize the token type table */ 641c2aa98e2SPeter Wemm char obuf[50]; 642c2aa98e2SPeter Wemm 64340266059SGregory Neil Shapiro firsttime = false; 644c2aa98e2SPeter Wemm if (OperatorChars == NULL) 645c2aa98e2SPeter Wemm { 646c2aa98e2SPeter Wemm if (ConfigLevel < 7) 647c2aa98e2SPeter Wemm OperatorChars = macvalue('o', CurEnv); 648c2aa98e2SPeter Wemm if (OperatorChars == NULL) 649c2aa98e2SPeter Wemm OperatorChars = ".:@[]"; 650c2aa98e2SPeter Wemm } 65106f25ae9SGregory Neil Shapiro expand(OperatorChars, obuf, sizeof obuf - sizeof DELIMCHARS, 65206f25ae9SGregory Neil Shapiro CurEnv); 65340266059SGregory Neil Shapiro (void) sm_strlcat(obuf, DELIMCHARS, sizeof obuf); 654c2aa98e2SPeter Wemm for (p = obuf; *p != '\0'; p++) 655c2aa98e2SPeter Wemm { 656c2aa98e2SPeter Wemm if (TokTypeTab[*p & 0xff] == ATM) 657c2aa98e2SPeter Wemm TokTypeTab[*p & 0xff] = OPR; 65806f25ae9SGregory Neil Shapiro if (TokTypeNoC[*p & 0xff] == ATM) 65906f25ae9SGregory Neil Shapiro TokTypeNoC[*p & 0xff] = OPR; 660c2aa98e2SPeter Wemm } 661c2aa98e2SPeter Wemm } 662c2aa98e2SPeter Wemm if (toktab == NULL) 663c2aa98e2SPeter Wemm toktab = TokTypeTab; 664c2aa98e2SPeter Wemm 665c2aa98e2SPeter Wemm /* make sure error messages don't have garbage on them */ 666c2aa98e2SPeter Wemm errno = 0; 667c2aa98e2SPeter Wemm 668c2aa98e2SPeter Wemm q = pvpbuf; 66940266059SGregory Neil Shapiro bslashmode = false; 67040266059SGregory Neil Shapiro route_syntax = false; 671c2aa98e2SPeter Wemm cmntcnt = 0; 672c2aa98e2SPeter Wemm anglecnt = 0; 673c2aa98e2SPeter Wemm avp = av; 674c2aa98e2SPeter Wemm state = ATM; 675c2aa98e2SPeter Wemm c = NOCHAR; 676c2aa98e2SPeter Wemm p = addr; 677c2aa98e2SPeter Wemm CurEnv->e_to = p; 678c2aa98e2SPeter Wemm if (tTd(22, 11)) 679c2aa98e2SPeter Wemm { 68040266059SGregory Neil Shapiro sm_dprintf("prescan: "); 681c2aa98e2SPeter Wemm xputs(p); 68240266059SGregory Neil Shapiro sm_dprintf("\n"); 683c2aa98e2SPeter Wemm } 684c2aa98e2SPeter Wemm 685c2aa98e2SPeter Wemm do 686c2aa98e2SPeter Wemm { 687c2aa98e2SPeter Wemm /* read a token */ 688c2aa98e2SPeter Wemm tok = q; 689c2aa98e2SPeter Wemm for (;;) 690c2aa98e2SPeter Wemm { 691c2aa98e2SPeter Wemm /* store away any old lookahead character */ 692c2aa98e2SPeter Wemm if (c != NOCHAR && !bslashmode) 693c2aa98e2SPeter Wemm { 694c2aa98e2SPeter Wemm /* see if there is room */ 695c2aa98e2SPeter Wemm if (q >= &pvpbuf[pvpbsize - 5]) 696c2aa98e2SPeter Wemm { 69706f25ae9SGregory Neil Shapiro usrerr("553 5.1.1 Address too long"); 69840266059SGregory Neil Shapiro if (strlen(addr) > MAXNAME) 699c2aa98e2SPeter Wemm addr[MAXNAME] = '\0'; 700c2aa98e2SPeter Wemm returnnull: 701c2aa98e2SPeter Wemm if (delimptr != NULL) 702c2aa98e2SPeter Wemm *delimptr = p; 703c2aa98e2SPeter Wemm CurEnv->e_to = saveto; 70406f25ae9SGregory Neil Shapiro return NULL; 705c2aa98e2SPeter Wemm } 706c2aa98e2SPeter Wemm 707c2aa98e2SPeter Wemm /* squirrel it away */ 708c2aa98e2SPeter Wemm *q++ = c; 709c2aa98e2SPeter Wemm } 710c2aa98e2SPeter Wemm 711c2aa98e2SPeter Wemm /* read a new input character */ 712c2aa98e2SPeter Wemm c = *p++; 713c2aa98e2SPeter Wemm if (c == '\0') 714c2aa98e2SPeter Wemm { 715c2aa98e2SPeter Wemm /* diagnose and patch up bad syntax */ 716c2aa98e2SPeter Wemm if (state == QST) 717c2aa98e2SPeter Wemm { 71840266059SGregory Neil Shapiro usrerr("553 Unbalanced '\"'"); 719c2aa98e2SPeter Wemm c = '"'; 720c2aa98e2SPeter Wemm } 721c2aa98e2SPeter Wemm else if (cmntcnt > 0) 722c2aa98e2SPeter Wemm { 72340266059SGregory Neil Shapiro usrerr("553 Unbalanced '('"); 724c2aa98e2SPeter Wemm c = ')'; 725c2aa98e2SPeter Wemm } 726c2aa98e2SPeter Wemm else if (anglecnt > 0) 727c2aa98e2SPeter Wemm { 728c2aa98e2SPeter Wemm c = '>'; 72940266059SGregory Neil Shapiro usrerr("553 Unbalanced '<'"); 730c2aa98e2SPeter Wemm } 731c2aa98e2SPeter Wemm else 732c2aa98e2SPeter Wemm break; 733c2aa98e2SPeter Wemm 734c2aa98e2SPeter Wemm p--; 735c2aa98e2SPeter Wemm } 736c2aa98e2SPeter Wemm else if (c == delim && cmntcnt <= 0 && state != QST) 737c2aa98e2SPeter Wemm { 738c2aa98e2SPeter Wemm if (anglecnt <= 0) 739c2aa98e2SPeter Wemm break; 740c2aa98e2SPeter Wemm 741c2aa98e2SPeter Wemm /* special case for better error management */ 742c2aa98e2SPeter Wemm if (delim == ',' && !route_syntax) 743c2aa98e2SPeter Wemm { 74440266059SGregory Neil Shapiro usrerr("553 Unbalanced '<'"); 745c2aa98e2SPeter Wemm c = '>'; 746c2aa98e2SPeter Wemm p--; 747c2aa98e2SPeter Wemm } 748c2aa98e2SPeter Wemm } 749c2aa98e2SPeter Wemm 750c2aa98e2SPeter Wemm if (tTd(22, 101)) 75140266059SGregory Neil Shapiro sm_dprintf("c=%c, s=%d; ", c, state); 752c2aa98e2SPeter Wemm 753c2aa98e2SPeter Wemm /* chew up special characters */ 754c2aa98e2SPeter Wemm *q = '\0'; 755c2aa98e2SPeter Wemm if (bslashmode) 756c2aa98e2SPeter Wemm { 75740266059SGregory Neil Shapiro bslashmode = false; 758c2aa98e2SPeter Wemm 759c2aa98e2SPeter Wemm /* kludge \! for naive users */ 760c2aa98e2SPeter Wemm if (cmntcnt > 0) 761c2aa98e2SPeter Wemm { 762c2aa98e2SPeter Wemm c = NOCHAR; 763c2aa98e2SPeter Wemm continue; 764c2aa98e2SPeter Wemm } 765c2aa98e2SPeter Wemm else if (c != '!' || state == QST) 766c2aa98e2SPeter Wemm { 767c2aa98e2SPeter Wemm *q++ = '\\'; 768c2aa98e2SPeter Wemm continue; 769c2aa98e2SPeter Wemm } 770c2aa98e2SPeter Wemm } 771c2aa98e2SPeter Wemm 772c2aa98e2SPeter Wemm if (c == '\\') 773c2aa98e2SPeter Wemm { 77440266059SGregory Neil Shapiro bslashmode = true; 775c2aa98e2SPeter Wemm } 776c2aa98e2SPeter Wemm else if (state == QST) 777c2aa98e2SPeter Wemm { 77806f25ae9SGregory Neil Shapiro /* EMPTY */ 779c2aa98e2SPeter Wemm /* do nothing, just avoid next clauses */ 780c2aa98e2SPeter Wemm } 78106f25ae9SGregory Neil Shapiro else if (c == '(' && toktab['('] == SPC) 782c2aa98e2SPeter Wemm { 783c2aa98e2SPeter Wemm cmntcnt++; 784c2aa98e2SPeter Wemm c = NOCHAR; 785c2aa98e2SPeter Wemm } 78606f25ae9SGregory Neil Shapiro else if (c == ')' && toktab['('] == SPC) 787c2aa98e2SPeter Wemm { 788c2aa98e2SPeter Wemm if (cmntcnt <= 0) 789c2aa98e2SPeter Wemm { 79040266059SGregory Neil Shapiro usrerr("553 Unbalanced ')'"); 791c2aa98e2SPeter Wemm c = NOCHAR; 792c2aa98e2SPeter Wemm } 793c2aa98e2SPeter Wemm else 794c2aa98e2SPeter Wemm cmntcnt--; 795c2aa98e2SPeter Wemm } 796c2aa98e2SPeter Wemm else if (cmntcnt > 0) 79706f25ae9SGregory Neil Shapiro { 798c2aa98e2SPeter Wemm c = NOCHAR; 79906f25ae9SGregory Neil Shapiro } 800c2aa98e2SPeter Wemm else if (c == '<') 801c2aa98e2SPeter Wemm { 80206f25ae9SGregory Neil Shapiro char *ptr = p; 803c2aa98e2SPeter Wemm 804c2aa98e2SPeter Wemm anglecnt++; 80506f25ae9SGregory Neil Shapiro while (isascii(*ptr) && isspace(*ptr)) 80606f25ae9SGregory Neil Shapiro ptr++; 80706f25ae9SGregory Neil Shapiro if (*ptr == '@') 80840266059SGregory Neil Shapiro route_syntax = true; 809c2aa98e2SPeter Wemm } 810c2aa98e2SPeter Wemm else if (c == '>') 811c2aa98e2SPeter Wemm { 812c2aa98e2SPeter Wemm if (anglecnt <= 0) 813c2aa98e2SPeter Wemm { 81440266059SGregory Neil Shapiro usrerr("553 Unbalanced '>'"); 815c2aa98e2SPeter Wemm c = NOCHAR; 816c2aa98e2SPeter Wemm } 817c2aa98e2SPeter Wemm else 818c2aa98e2SPeter Wemm anglecnt--; 81940266059SGregory Neil Shapiro route_syntax = false; 820c2aa98e2SPeter Wemm } 821c2aa98e2SPeter Wemm else if (delim == ' ' && isascii(c) && isspace(c)) 822c2aa98e2SPeter Wemm c = ' '; 823c2aa98e2SPeter Wemm 824c2aa98e2SPeter Wemm if (c == NOCHAR) 825c2aa98e2SPeter Wemm continue; 826c2aa98e2SPeter Wemm 827c2aa98e2SPeter Wemm /* see if this is end of input */ 828c2aa98e2SPeter Wemm if (c == delim && anglecnt <= 0 && state != QST) 829c2aa98e2SPeter Wemm break; 830c2aa98e2SPeter Wemm 831c2aa98e2SPeter Wemm newstate = StateTab[state][toktab[c & 0xff]]; 832c2aa98e2SPeter Wemm if (tTd(22, 101)) 83340266059SGregory Neil Shapiro sm_dprintf("ns=%02o\n", newstate); 834c2aa98e2SPeter Wemm state = newstate & TYPE; 835c2aa98e2SPeter Wemm if (state == ILL) 836c2aa98e2SPeter Wemm { 837c2aa98e2SPeter Wemm if (isascii(c) && isprint(c)) 83840266059SGregory Neil Shapiro usrerr("553 Illegal character %c", c); 839c2aa98e2SPeter Wemm else 84040266059SGregory Neil Shapiro usrerr("553 Illegal character 0x%02x", 84140266059SGregory Neil Shapiro c & 0x0ff); 842c2aa98e2SPeter Wemm } 843c2aa98e2SPeter Wemm if (bitset(M, newstate)) 844c2aa98e2SPeter Wemm c = NOCHAR; 845c2aa98e2SPeter Wemm if (bitset(B, newstate)) 846c2aa98e2SPeter Wemm break; 847c2aa98e2SPeter Wemm } 848c2aa98e2SPeter Wemm 849c2aa98e2SPeter Wemm /* new token */ 850c2aa98e2SPeter Wemm if (tok != q) 851c2aa98e2SPeter Wemm { 852c2aa98e2SPeter Wemm *q++ = '\0'; 853c2aa98e2SPeter Wemm if (tTd(22, 36)) 854c2aa98e2SPeter Wemm { 85540266059SGregory Neil Shapiro sm_dprintf("tok="); 856c2aa98e2SPeter Wemm xputs(tok); 85740266059SGregory Neil Shapiro sm_dprintf("\n"); 858c2aa98e2SPeter Wemm } 859c2aa98e2SPeter Wemm if (avp >= &av[MAXATOM]) 860c2aa98e2SPeter Wemm { 86106f25ae9SGregory Neil Shapiro usrerr("553 5.1.0 prescan: too many tokens"); 862c2aa98e2SPeter Wemm goto returnnull; 863c2aa98e2SPeter Wemm } 864c2aa98e2SPeter Wemm if (q - tok > MAXNAME) 865c2aa98e2SPeter Wemm { 86606f25ae9SGregory Neil Shapiro usrerr("553 5.1.0 prescan: token too long"); 867c2aa98e2SPeter Wemm goto returnnull; 868c2aa98e2SPeter Wemm } 869c2aa98e2SPeter Wemm *avp++ = tok; 870c2aa98e2SPeter Wemm } 871c2aa98e2SPeter Wemm } while (c != '\0' && (c != delim || anglecnt > 0)); 872c2aa98e2SPeter Wemm *avp = NULL; 873c2aa98e2SPeter Wemm p--; 874c2aa98e2SPeter Wemm if (delimptr != NULL) 875c2aa98e2SPeter Wemm *delimptr = p; 876c2aa98e2SPeter Wemm if (tTd(22, 12)) 877c2aa98e2SPeter Wemm { 87840266059SGregory Neil Shapiro sm_dprintf("prescan==>"); 879c2aa98e2SPeter Wemm printav(av); 880c2aa98e2SPeter Wemm } 881c2aa98e2SPeter Wemm CurEnv->e_to = saveto; 882c2aa98e2SPeter Wemm if (av[0] == NULL) 883c2aa98e2SPeter Wemm { 884c2aa98e2SPeter Wemm if (tTd(22, 1)) 88540266059SGregory Neil Shapiro sm_dprintf("prescan: null leading token\n"); 88606f25ae9SGregory Neil Shapiro return NULL; 887c2aa98e2SPeter Wemm } 88806f25ae9SGregory Neil Shapiro return av; 889c2aa98e2SPeter Wemm } 89040266059SGregory Neil Shapiro /* 891c2aa98e2SPeter Wemm ** REWRITE -- apply rewrite rules to token vector. 892c2aa98e2SPeter Wemm ** 893c2aa98e2SPeter Wemm ** This routine is an ordered production system. Each rewrite 894c2aa98e2SPeter Wemm ** rule has a LHS (called the pattern) and a RHS (called the 895c2aa98e2SPeter Wemm ** rewrite); 'rwr' points the the current rewrite rule. 896c2aa98e2SPeter Wemm ** 897c2aa98e2SPeter Wemm ** For each rewrite rule, 'avp' points the address vector we 898c2aa98e2SPeter Wemm ** are trying to match against, and 'pvp' points to the pattern. 899c2aa98e2SPeter Wemm ** If pvp points to a special match value (MATCHZANY, MATCHANY, 900c2aa98e2SPeter Wemm ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp 901c2aa98e2SPeter Wemm ** matched is saved away in the match vector (pointed to by 'mvp'). 902c2aa98e2SPeter Wemm ** 903c2aa98e2SPeter Wemm ** When a match between avp & pvp does not match, we try to 904c2aa98e2SPeter Wemm ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS 905c2aa98e2SPeter Wemm ** we must also back out the match in mvp. If we reach a 906c2aa98e2SPeter Wemm ** MATCHANY or MATCHZANY we just extend the match and start 907c2aa98e2SPeter Wemm ** over again. 908c2aa98e2SPeter Wemm ** 909c2aa98e2SPeter Wemm ** When we finally match, we rewrite the address vector 910c2aa98e2SPeter Wemm ** and try over again. 911c2aa98e2SPeter Wemm ** 912c2aa98e2SPeter Wemm ** Parameters: 913c2aa98e2SPeter Wemm ** pvp -- pointer to token vector. 914c2aa98e2SPeter Wemm ** ruleset -- the ruleset to use for rewriting. 915c2aa98e2SPeter Wemm ** reclevel -- recursion level (to catch loops). 916c2aa98e2SPeter Wemm ** e -- the current envelope. 91740266059SGregory Neil Shapiro ** maxatom -- maximum length of buffer (usually MAXATOM) 918c2aa98e2SPeter Wemm ** 919c2aa98e2SPeter Wemm ** Returns: 920c2aa98e2SPeter Wemm ** A status code. If EX_TEMPFAIL, higher level code should 921c2aa98e2SPeter Wemm ** attempt recovery. 922c2aa98e2SPeter Wemm ** 923c2aa98e2SPeter Wemm ** Side Effects: 924c2aa98e2SPeter Wemm ** pvp is modified. 925c2aa98e2SPeter Wemm */ 926c2aa98e2SPeter Wemm 927c2aa98e2SPeter Wemm struct match 928c2aa98e2SPeter Wemm { 92906f25ae9SGregory Neil Shapiro char **match_first; /* first token matched */ 93006f25ae9SGregory Neil Shapiro char **match_last; /* last token matched */ 93106f25ae9SGregory Neil Shapiro char **match_pattern; /* pointer to pattern */ 932c2aa98e2SPeter Wemm }; 933c2aa98e2SPeter Wemm 934c2aa98e2SPeter Wemm int 93540266059SGregory Neil Shapiro rewrite(pvp, ruleset, reclevel, e, maxatom) 936c2aa98e2SPeter Wemm char **pvp; 937c2aa98e2SPeter Wemm int ruleset; 938c2aa98e2SPeter Wemm int reclevel; 939c2aa98e2SPeter Wemm register ENVELOPE *e; 94040266059SGregory Neil Shapiro int maxatom; 941c2aa98e2SPeter Wemm { 942c2aa98e2SPeter Wemm register char *ap; /* address pointer */ 943c2aa98e2SPeter Wemm register char *rp; /* rewrite pointer */ 94406f25ae9SGregory Neil Shapiro register char *rulename; /* ruleset name */ 94506f25ae9SGregory Neil Shapiro register char *prefix; 946c2aa98e2SPeter Wemm register char **avp; /* address vector pointer */ 947c2aa98e2SPeter Wemm register char **rvp; /* rewrite vector pointer */ 948c2aa98e2SPeter Wemm register struct match *mlp; /* cur ptr into mlist */ 949c2aa98e2SPeter Wemm register struct rewrite *rwr; /* pointer to current rewrite rule */ 950c2aa98e2SPeter Wemm int ruleno; /* current rule number */ 951c2aa98e2SPeter Wemm int rstat = EX_OK; /* return status */ 952c2aa98e2SPeter Wemm int loopcount; 953c2aa98e2SPeter Wemm struct match mlist[MAXMATCH]; /* stores match on LHS */ 954c2aa98e2SPeter Wemm char *npvp[MAXATOM + 1]; /* temporary space for rebuild */ 955c2aa98e2SPeter Wemm char buf[MAXLINE]; 95606f25ae9SGregory Neil Shapiro char name[6]; 957c2aa98e2SPeter Wemm 958c2aa98e2SPeter Wemm if (ruleset < 0 || ruleset >= MAXRWSETS) 959c2aa98e2SPeter Wemm { 96006f25ae9SGregory Neil Shapiro syserr("554 5.3.5 rewrite: illegal ruleset number %d", ruleset); 961c2aa98e2SPeter Wemm return EX_CONFIG; 962c2aa98e2SPeter Wemm } 96306f25ae9SGregory Neil Shapiro rulename = RuleSetNames[ruleset]; 96406f25ae9SGregory Neil Shapiro if (rulename == NULL) 96506f25ae9SGregory Neil Shapiro { 96640266059SGregory Neil Shapiro (void) sm_snprintf(name, sizeof name, "%d", ruleset); 96706f25ae9SGregory Neil Shapiro rulename = name; 96806f25ae9SGregory Neil Shapiro } 96906f25ae9SGregory Neil Shapiro if (OpMode == MD_TEST) 97006f25ae9SGregory Neil Shapiro prefix = ""; 97106f25ae9SGregory Neil Shapiro else 97206f25ae9SGregory Neil Shapiro prefix = "rewrite: ruleset "; 97306f25ae9SGregory Neil Shapiro if (OpMode == MD_TEST) 97406f25ae9SGregory Neil Shapiro { 97540266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 97640266059SGregory Neil Shapiro "%s%-16.16s input:", prefix, rulename); 97706f25ae9SGregory Neil Shapiro printav(pvp); 97806f25ae9SGregory Neil Shapiro } 97906f25ae9SGregory Neil Shapiro else if (tTd(21, 1)) 98006f25ae9SGregory Neil Shapiro { 98140266059SGregory Neil Shapiro sm_dprintf("%s%-16.16s input:", prefix, rulename); 98206f25ae9SGregory Neil Shapiro printav(pvp); 98306f25ae9SGregory Neil Shapiro } 984c2aa98e2SPeter Wemm if (reclevel++ > MaxRuleRecursion) 985c2aa98e2SPeter Wemm { 98606f25ae9SGregory Neil Shapiro syserr("rewrite: excessive recursion (max %d), ruleset %s", 98706f25ae9SGregory Neil Shapiro MaxRuleRecursion, rulename); 988c2aa98e2SPeter Wemm return EX_CONFIG; 989c2aa98e2SPeter Wemm } 990c2aa98e2SPeter Wemm if (pvp == NULL) 991c2aa98e2SPeter Wemm return EX_USAGE; 992c2aa98e2SPeter Wemm 993c2aa98e2SPeter Wemm /* 994c2aa98e2SPeter Wemm ** Run through the list of rewrite rules, applying 995c2aa98e2SPeter Wemm ** any that match. 996c2aa98e2SPeter Wemm */ 997c2aa98e2SPeter Wemm 998c2aa98e2SPeter Wemm ruleno = 1; 999c2aa98e2SPeter Wemm loopcount = 0; 1000c2aa98e2SPeter Wemm for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 1001c2aa98e2SPeter Wemm { 100206f25ae9SGregory Neil Shapiro int status; 1003c2aa98e2SPeter Wemm 1004c2aa98e2SPeter Wemm /* if already canonical, quit now */ 1005c2aa98e2SPeter Wemm if (pvp[0] != NULL && (pvp[0][0] & 0377) == CANONNET) 1006c2aa98e2SPeter Wemm break; 1007c2aa98e2SPeter Wemm 1008c2aa98e2SPeter Wemm if (tTd(21, 12)) 1009c2aa98e2SPeter Wemm { 101006f25ae9SGregory Neil Shapiro if (tTd(21, 15)) 101140266059SGregory Neil Shapiro sm_dprintf("-----trying rule (line %d):", 101206f25ae9SGregory Neil Shapiro rwr->r_line); 101306f25ae9SGregory Neil Shapiro else 101440266059SGregory Neil Shapiro sm_dprintf("-----trying rule:"); 1015c2aa98e2SPeter Wemm printav(rwr->r_lhs); 1016c2aa98e2SPeter Wemm } 1017c2aa98e2SPeter Wemm 1018c2aa98e2SPeter Wemm /* try to match on this rule */ 1019c2aa98e2SPeter Wemm mlp = mlist; 1020c2aa98e2SPeter Wemm rvp = rwr->r_lhs; 1021c2aa98e2SPeter Wemm avp = pvp; 1022c2aa98e2SPeter Wemm if (++loopcount > 100) 1023c2aa98e2SPeter Wemm { 102406f25ae9SGregory Neil Shapiro syserr("554 5.3.5 Infinite loop in ruleset %s, rule %d", 102506f25ae9SGregory Neil Shapiro rulename, ruleno); 1026c2aa98e2SPeter Wemm if (tTd(21, 1)) 1027c2aa98e2SPeter Wemm { 102840266059SGregory Neil Shapiro sm_dprintf("workspace: "); 1029c2aa98e2SPeter Wemm printav(pvp); 1030c2aa98e2SPeter Wemm } 1031c2aa98e2SPeter Wemm break; 1032c2aa98e2SPeter Wemm } 1033c2aa98e2SPeter Wemm 1034c2aa98e2SPeter Wemm while ((ap = *avp) != NULL || *rvp != NULL) 1035c2aa98e2SPeter Wemm { 1036c2aa98e2SPeter Wemm rp = *rvp; 1037c2aa98e2SPeter Wemm if (tTd(21, 35)) 1038c2aa98e2SPeter Wemm { 103940266059SGregory Neil Shapiro sm_dprintf("ADVANCE rp="); 1040c2aa98e2SPeter Wemm xputs(rp); 104140266059SGregory Neil Shapiro sm_dprintf(", ap="); 1042c2aa98e2SPeter Wemm xputs(ap); 104340266059SGregory Neil Shapiro sm_dprintf("\n"); 1044c2aa98e2SPeter Wemm } 1045c2aa98e2SPeter Wemm if (rp == NULL) 1046c2aa98e2SPeter Wemm { 1047c2aa98e2SPeter Wemm /* end-of-pattern before end-of-address */ 1048c2aa98e2SPeter Wemm goto backup; 1049c2aa98e2SPeter Wemm } 1050c2aa98e2SPeter Wemm if (ap == NULL && (*rp & 0377) != MATCHZANY && 1051c2aa98e2SPeter Wemm (*rp & 0377) != MATCHZERO) 1052c2aa98e2SPeter Wemm { 1053c2aa98e2SPeter Wemm /* end-of-input with patterns left */ 1054c2aa98e2SPeter Wemm goto backup; 1055c2aa98e2SPeter Wemm } 1056c2aa98e2SPeter Wemm 1057c2aa98e2SPeter Wemm switch (*rp & 0377) 1058c2aa98e2SPeter Wemm { 1059c2aa98e2SPeter Wemm case MATCHCLASS: 1060c2aa98e2SPeter Wemm /* match any phrase in a class */ 106106f25ae9SGregory Neil Shapiro mlp->match_pattern = rvp; 106206f25ae9SGregory Neil Shapiro mlp->match_first = avp; 1063c2aa98e2SPeter Wemm extendclass: 1064c2aa98e2SPeter Wemm ap = *avp; 1065c2aa98e2SPeter Wemm if (ap == NULL) 1066c2aa98e2SPeter Wemm goto backup; 106706f25ae9SGregory Neil Shapiro mlp->match_last = avp++; 106806f25ae9SGregory Neil Shapiro cataddr(mlp->match_first, mlp->match_last, 106906f25ae9SGregory Neil Shapiro buf, sizeof buf, '\0'); 1070c2aa98e2SPeter Wemm if (!wordinclass(buf, rp[1])) 1071c2aa98e2SPeter Wemm { 1072c2aa98e2SPeter Wemm if (tTd(21, 36)) 1073c2aa98e2SPeter Wemm { 107440266059SGregory Neil Shapiro sm_dprintf("EXTEND rp="); 1075c2aa98e2SPeter Wemm xputs(rp); 107640266059SGregory Neil Shapiro sm_dprintf(", ap="); 1077c2aa98e2SPeter Wemm xputs(ap); 107840266059SGregory Neil Shapiro sm_dprintf("\n"); 1079c2aa98e2SPeter Wemm } 1080c2aa98e2SPeter Wemm goto extendclass; 1081c2aa98e2SPeter Wemm } 1082c2aa98e2SPeter Wemm if (tTd(21, 36)) 108340266059SGregory Neil Shapiro sm_dprintf("CLMATCH\n"); 1084c2aa98e2SPeter Wemm mlp++; 1085c2aa98e2SPeter Wemm break; 1086c2aa98e2SPeter Wemm 1087c2aa98e2SPeter Wemm case MATCHNCLASS: 1088c2aa98e2SPeter Wemm /* match any token not in a class */ 1089c2aa98e2SPeter Wemm if (wordinclass(ap, rp[1])) 1090c2aa98e2SPeter Wemm goto backup; 1091c2aa98e2SPeter Wemm 109206f25ae9SGregory Neil Shapiro /* FALLTHROUGH */ 1093c2aa98e2SPeter Wemm 1094c2aa98e2SPeter Wemm case MATCHONE: 1095c2aa98e2SPeter Wemm case MATCHANY: 1096c2aa98e2SPeter Wemm /* match exactly one token */ 109706f25ae9SGregory Neil Shapiro mlp->match_pattern = rvp; 109806f25ae9SGregory Neil Shapiro mlp->match_first = avp; 109906f25ae9SGregory Neil Shapiro mlp->match_last = avp++; 1100c2aa98e2SPeter Wemm mlp++; 1101c2aa98e2SPeter Wemm break; 1102c2aa98e2SPeter Wemm 1103c2aa98e2SPeter Wemm case MATCHZANY: 1104c2aa98e2SPeter Wemm /* match zero or more tokens */ 110506f25ae9SGregory Neil Shapiro mlp->match_pattern = rvp; 110606f25ae9SGregory Neil Shapiro mlp->match_first = avp; 110706f25ae9SGregory Neil Shapiro mlp->match_last = avp - 1; 1108c2aa98e2SPeter Wemm mlp++; 1109c2aa98e2SPeter Wemm break; 1110c2aa98e2SPeter Wemm 1111c2aa98e2SPeter Wemm case MATCHZERO: 1112c2aa98e2SPeter Wemm /* match zero tokens */ 1113c2aa98e2SPeter Wemm break; 1114c2aa98e2SPeter Wemm 1115c2aa98e2SPeter Wemm case MACRODEXPAND: 1116c2aa98e2SPeter Wemm /* 1117c2aa98e2SPeter Wemm ** Match against run-time macro. 1118c2aa98e2SPeter Wemm ** This algorithm is broken for the 1119c2aa98e2SPeter Wemm ** general case (no recursive macros, 1120c2aa98e2SPeter Wemm ** improper tokenization) but should 1121c2aa98e2SPeter Wemm ** work for the usual cases. 1122c2aa98e2SPeter Wemm */ 1123c2aa98e2SPeter Wemm 1124c2aa98e2SPeter Wemm ap = macvalue(rp[1], e); 112506f25ae9SGregory Neil Shapiro mlp->match_first = avp; 1126c2aa98e2SPeter Wemm if (tTd(21, 2)) 1127739ac4d4SGregory Neil Shapiro sm_dprintf("rewrite: LHS $&{%s} => \"%s\"\n", 1128c2aa98e2SPeter Wemm macname(rp[1]), 1129c2aa98e2SPeter Wemm ap == NULL ? "(NULL)" : ap); 1130c2aa98e2SPeter Wemm 1131c2aa98e2SPeter Wemm if (ap == NULL) 1132c2aa98e2SPeter Wemm break; 1133c2aa98e2SPeter Wemm while (*ap != '\0') 1134c2aa98e2SPeter Wemm { 1135c2aa98e2SPeter Wemm if (*avp == NULL || 113640266059SGregory Neil Shapiro sm_strncasecmp(ap, *avp, 113740266059SGregory Neil Shapiro strlen(*avp)) != 0) 1138c2aa98e2SPeter Wemm { 1139c2aa98e2SPeter Wemm /* no match */ 114006f25ae9SGregory Neil Shapiro avp = mlp->match_first; 1141c2aa98e2SPeter Wemm goto backup; 1142c2aa98e2SPeter Wemm } 1143c2aa98e2SPeter Wemm ap += strlen(*avp++); 1144c2aa98e2SPeter Wemm } 1145c2aa98e2SPeter Wemm 1146c2aa98e2SPeter Wemm /* match */ 1147c2aa98e2SPeter Wemm break; 1148c2aa98e2SPeter Wemm 1149c2aa98e2SPeter Wemm default: 1150c2aa98e2SPeter Wemm /* must have exact match */ 1151c2aa98e2SPeter Wemm if (sm_strcasecmp(rp, ap)) 1152c2aa98e2SPeter Wemm goto backup; 1153c2aa98e2SPeter Wemm avp++; 1154c2aa98e2SPeter Wemm break; 1155c2aa98e2SPeter Wemm } 1156c2aa98e2SPeter Wemm 1157c2aa98e2SPeter Wemm /* successful match on this token */ 1158c2aa98e2SPeter Wemm rvp++; 1159c2aa98e2SPeter Wemm continue; 1160c2aa98e2SPeter Wemm 1161c2aa98e2SPeter Wemm backup: 1162c2aa98e2SPeter Wemm /* match failed -- back up */ 1163c2aa98e2SPeter Wemm while (--mlp >= mlist) 1164c2aa98e2SPeter Wemm { 116506f25ae9SGregory Neil Shapiro rvp = mlp->match_pattern; 1166c2aa98e2SPeter Wemm rp = *rvp; 116706f25ae9SGregory Neil Shapiro avp = mlp->match_last + 1; 1168c2aa98e2SPeter Wemm ap = *avp; 1169c2aa98e2SPeter Wemm 1170c2aa98e2SPeter Wemm if (tTd(21, 36)) 1171c2aa98e2SPeter Wemm { 117240266059SGregory Neil Shapiro sm_dprintf("BACKUP rp="); 1173c2aa98e2SPeter Wemm xputs(rp); 117440266059SGregory Neil Shapiro sm_dprintf(", ap="); 1175c2aa98e2SPeter Wemm xputs(ap); 117640266059SGregory Neil Shapiro sm_dprintf("\n"); 1177c2aa98e2SPeter Wemm } 1178c2aa98e2SPeter Wemm 1179c2aa98e2SPeter Wemm if (ap == NULL) 1180c2aa98e2SPeter Wemm { 1181c2aa98e2SPeter Wemm /* run off the end -- back up again */ 1182c2aa98e2SPeter Wemm continue; 1183c2aa98e2SPeter Wemm } 1184c2aa98e2SPeter Wemm if ((*rp & 0377) == MATCHANY || 1185c2aa98e2SPeter Wemm (*rp & 0377) == MATCHZANY) 1186c2aa98e2SPeter Wemm { 1187c2aa98e2SPeter Wemm /* extend binding and continue */ 118806f25ae9SGregory Neil Shapiro mlp->match_last = avp++; 1189c2aa98e2SPeter Wemm rvp++; 1190c2aa98e2SPeter Wemm mlp++; 1191c2aa98e2SPeter Wemm break; 1192c2aa98e2SPeter Wemm } 1193c2aa98e2SPeter Wemm if ((*rp & 0377) == MATCHCLASS) 1194c2aa98e2SPeter Wemm { 1195c2aa98e2SPeter Wemm /* extend binding and try again */ 119606f25ae9SGregory Neil Shapiro mlp->match_last = avp; 1197c2aa98e2SPeter Wemm goto extendclass; 1198c2aa98e2SPeter Wemm } 1199c2aa98e2SPeter Wemm } 1200c2aa98e2SPeter Wemm 1201c2aa98e2SPeter Wemm if (mlp < mlist) 1202c2aa98e2SPeter Wemm { 1203c2aa98e2SPeter Wemm /* total failure to match */ 1204c2aa98e2SPeter Wemm break; 1205c2aa98e2SPeter Wemm } 1206c2aa98e2SPeter Wemm } 1207c2aa98e2SPeter Wemm 1208c2aa98e2SPeter Wemm /* 1209c2aa98e2SPeter Wemm ** See if we successfully matched 1210c2aa98e2SPeter Wemm */ 1211c2aa98e2SPeter Wemm 1212c2aa98e2SPeter Wemm if (mlp < mlist || *rvp != NULL) 1213c2aa98e2SPeter Wemm { 1214c2aa98e2SPeter Wemm if (tTd(21, 10)) 121540266059SGregory Neil Shapiro sm_dprintf("----- rule fails\n"); 1216c2aa98e2SPeter Wemm rwr = rwr->r_next; 1217c2aa98e2SPeter Wemm ruleno++; 1218c2aa98e2SPeter Wemm loopcount = 0; 1219c2aa98e2SPeter Wemm continue; 1220c2aa98e2SPeter Wemm } 1221c2aa98e2SPeter Wemm 1222c2aa98e2SPeter Wemm rvp = rwr->r_rhs; 1223c2aa98e2SPeter Wemm if (tTd(21, 12)) 1224c2aa98e2SPeter Wemm { 122540266059SGregory Neil Shapiro sm_dprintf("-----rule matches:"); 1226c2aa98e2SPeter Wemm printav(rvp); 1227c2aa98e2SPeter Wemm } 1228c2aa98e2SPeter Wemm 1229c2aa98e2SPeter Wemm rp = *rvp; 123006f25ae9SGregory Neil Shapiro if (rp != NULL) 123106f25ae9SGregory Neil Shapiro { 1232c2aa98e2SPeter Wemm if ((*rp & 0377) == CANONUSER) 1233c2aa98e2SPeter Wemm { 1234c2aa98e2SPeter Wemm rvp++; 1235c2aa98e2SPeter Wemm rwr = rwr->r_next; 1236c2aa98e2SPeter Wemm ruleno++; 1237c2aa98e2SPeter Wemm loopcount = 0; 1238c2aa98e2SPeter Wemm } 1239c2aa98e2SPeter Wemm else if ((*rp & 0377) == CANONHOST) 1240c2aa98e2SPeter Wemm { 1241c2aa98e2SPeter Wemm rvp++; 1242c2aa98e2SPeter Wemm rwr = NULL; 1243c2aa98e2SPeter Wemm } 124406f25ae9SGregory Neil Shapiro } 1245c2aa98e2SPeter Wemm 1246c2aa98e2SPeter Wemm /* substitute */ 1247c2aa98e2SPeter Wemm for (avp = npvp; *rvp != NULL; rvp++) 1248c2aa98e2SPeter Wemm { 1249c2aa98e2SPeter Wemm register struct match *m; 1250c2aa98e2SPeter Wemm register char **pp; 1251c2aa98e2SPeter Wemm 1252c2aa98e2SPeter Wemm rp = *rvp; 1253c2aa98e2SPeter Wemm if ((*rp & 0377) == MATCHREPL) 1254c2aa98e2SPeter Wemm { 1255c2aa98e2SPeter Wemm /* substitute from LHS */ 1256c2aa98e2SPeter Wemm m = &mlist[rp[1] - '1']; 1257c2aa98e2SPeter Wemm if (m < mlist || m >= mlp) 1258c2aa98e2SPeter Wemm { 125906f25ae9SGregory Neil Shapiro syserr("554 5.3.5 rewrite: ruleset %s: replacement $%c out of bounds", 126006f25ae9SGregory Neil Shapiro rulename, rp[1]); 1261c2aa98e2SPeter Wemm return EX_CONFIG; 1262c2aa98e2SPeter Wemm } 1263c2aa98e2SPeter Wemm if (tTd(21, 15)) 1264c2aa98e2SPeter Wemm { 126540266059SGregory Neil Shapiro sm_dprintf("$%c:", rp[1]); 126606f25ae9SGregory Neil Shapiro pp = m->match_first; 126706f25ae9SGregory Neil Shapiro while (pp <= m->match_last) 1268c2aa98e2SPeter Wemm { 126940266059SGregory Neil Shapiro sm_dprintf(" %p=\"", *pp); 127040266059SGregory Neil Shapiro sm_dflush(); 127140266059SGregory Neil Shapiro sm_dprintf("%s\"", *pp++); 1272c2aa98e2SPeter Wemm } 127340266059SGregory Neil Shapiro sm_dprintf("\n"); 1274c2aa98e2SPeter Wemm } 127506f25ae9SGregory Neil Shapiro pp = m->match_first; 127606f25ae9SGregory Neil Shapiro while (pp <= m->match_last) 1277c2aa98e2SPeter Wemm { 127840266059SGregory Neil Shapiro if (avp >= &npvp[maxatom]) 1279c2aa98e2SPeter Wemm { 128006f25ae9SGregory Neil Shapiro syserr("554 5.3.0 rewrite: expansion too long"); 128140266059SGregory Neil Shapiro if (LogLevel > 9) 128240266059SGregory Neil Shapiro sm_syslog(LOG_ERR, 128340266059SGregory Neil Shapiro e->e_id, 128440266059SGregory Neil Shapiro "rewrite: expansion too long, ruleset=%s, ruleno=%d", 128540266059SGregory Neil Shapiro rulename, 128640266059SGregory Neil Shapiro ruleno); 1287c2aa98e2SPeter Wemm return EX_DATAERR; 1288c2aa98e2SPeter Wemm } 1289c2aa98e2SPeter Wemm *avp++ = *pp++; 1290c2aa98e2SPeter Wemm } 1291c2aa98e2SPeter Wemm } 1292c2aa98e2SPeter Wemm else 1293c2aa98e2SPeter Wemm { 1294c2aa98e2SPeter Wemm /* some sort of replacement */ 129540266059SGregory Neil Shapiro if (avp >= &npvp[maxatom]) 1296c2aa98e2SPeter Wemm { 1297c2aa98e2SPeter Wemm toolong: 129806f25ae9SGregory Neil Shapiro syserr("554 5.3.0 rewrite: expansion too long"); 129940266059SGregory Neil Shapiro if (LogLevel > 9) 130040266059SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 130140266059SGregory Neil Shapiro "rewrite: expansion too long, ruleset=%s, ruleno=%d", 130240266059SGregory Neil Shapiro rulename, ruleno); 1303c2aa98e2SPeter Wemm return EX_DATAERR; 1304c2aa98e2SPeter Wemm } 1305c2aa98e2SPeter Wemm if ((*rp & 0377) != MACRODEXPAND) 1306c2aa98e2SPeter Wemm { 1307c2aa98e2SPeter Wemm /* vanilla replacement */ 1308c2aa98e2SPeter Wemm *avp++ = rp; 1309c2aa98e2SPeter Wemm } 1310c2aa98e2SPeter Wemm else 1311c2aa98e2SPeter Wemm { 1312739ac4d4SGregory Neil Shapiro /* $&{x} replacement */ 1313c2aa98e2SPeter Wemm char *mval = macvalue(rp[1], e); 1314c2aa98e2SPeter Wemm char **xpvp; 1315c2aa98e2SPeter Wemm int trsize = 0; 1316c2aa98e2SPeter Wemm static size_t pvpb1_size = 0; 1317c2aa98e2SPeter Wemm static char **pvpb1 = NULL; 1318c2aa98e2SPeter Wemm char pvpbuf[PSBUFSIZE]; 1319c2aa98e2SPeter Wemm 1320c2aa98e2SPeter Wemm if (tTd(21, 2)) 1321739ac4d4SGregory Neil Shapiro sm_dprintf("rewrite: RHS $&{%s} => \"%s\"\n", 1322c2aa98e2SPeter Wemm macname(rp[1]), 1323c2aa98e2SPeter Wemm mval == NULL ? "(NULL)" : mval); 1324c2aa98e2SPeter Wemm if (mval == NULL || *mval == '\0') 1325c2aa98e2SPeter Wemm continue; 1326c2aa98e2SPeter Wemm 1327c2aa98e2SPeter Wemm /* save the remainder of the input */ 1328c2aa98e2SPeter Wemm for (xpvp = pvp; *xpvp != NULL; xpvp++) 1329c2aa98e2SPeter Wemm trsize += sizeof *xpvp; 133006f25ae9SGregory Neil Shapiro if ((size_t) trsize > pvpb1_size) 1331c2aa98e2SPeter Wemm { 1332c2aa98e2SPeter Wemm if (pvpb1 != NULL) 13338774250cSGregory Neil Shapiro sm_free(pvpb1); 133440266059SGregory Neil Shapiro pvpb1 = (char **) 133540266059SGregory Neil Shapiro sm_pmalloc_x(trsize); 1336c2aa98e2SPeter Wemm pvpb1_size = trsize; 1337c2aa98e2SPeter Wemm } 1338c2aa98e2SPeter Wemm 133906f25ae9SGregory Neil Shapiro memmove((char *) pvpb1, 134006f25ae9SGregory Neil Shapiro (char *) pvp, 134106f25ae9SGregory Neil Shapiro trsize); 1342c2aa98e2SPeter Wemm 1343c2aa98e2SPeter Wemm /* scan the new replacement */ 1344c2aa98e2SPeter Wemm xpvp = prescan(mval, '\0', pvpbuf, 134506f25ae9SGregory Neil Shapiro sizeof pvpbuf, NULL, 134606f25ae9SGregory Neil Shapiro NULL); 1347c2aa98e2SPeter Wemm if (xpvp == NULL) 1348c2aa98e2SPeter Wemm { 1349c2aa98e2SPeter Wemm /* prescan pre-printed error */ 1350c2aa98e2SPeter Wemm return EX_DATAERR; 1351c2aa98e2SPeter Wemm } 1352c2aa98e2SPeter Wemm 1353c2aa98e2SPeter Wemm /* insert it into the output stream */ 1354c2aa98e2SPeter Wemm while (*xpvp != NULL) 1355c2aa98e2SPeter Wemm { 1356c2aa98e2SPeter Wemm if (tTd(21, 19)) 135740266059SGregory Neil Shapiro sm_dprintf(" ... %s\n", 135806f25ae9SGregory Neil Shapiro *xpvp); 135940266059SGregory Neil Shapiro *avp++ = sm_rpool_strdup_x( 136040266059SGregory Neil Shapiro e->e_rpool, *xpvp); 136140266059SGregory Neil Shapiro if (avp >= &npvp[maxatom]) 1362c2aa98e2SPeter Wemm goto toolong; 1363c2aa98e2SPeter Wemm xpvp++; 1364c2aa98e2SPeter Wemm } 1365c2aa98e2SPeter Wemm if (tTd(21, 19)) 136640266059SGregory Neil Shapiro sm_dprintf(" ... DONE\n"); 1367c2aa98e2SPeter Wemm 1368c2aa98e2SPeter Wemm /* restore the old trailing input */ 136906f25ae9SGregory Neil Shapiro memmove((char *) pvp, 137006f25ae9SGregory Neil Shapiro (char *) pvpb1, 137106f25ae9SGregory Neil Shapiro trsize); 1372c2aa98e2SPeter Wemm } 1373c2aa98e2SPeter Wemm } 1374c2aa98e2SPeter Wemm } 1375c2aa98e2SPeter Wemm *avp++ = NULL; 1376c2aa98e2SPeter Wemm 1377c2aa98e2SPeter Wemm /* 1378c2aa98e2SPeter Wemm ** Check for any hostname/keyword lookups. 1379c2aa98e2SPeter Wemm */ 1380c2aa98e2SPeter Wemm 1381c2aa98e2SPeter Wemm for (rvp = npvp; *rvp != NULL; rvp++) 1382c2aa98e2SPeter Wemm { 1383c2aa98e2SPeter Wemm char **hbrvp; 1384c2aa98e2SPeter Wemm char **xpvp; 1385c2aa98e2SPeter Wemm int trsize; 1386c2aa98e2SPeter Wemm char *replac; 1387c2aa98e2SPeter Wemm int endtoken; 1388c2aa98e2SPeter Wemm STAB *map; 1389c2aa98e2SPeter Wemm char *mapname; 1390c2aa98e2SPeter Wemm char **key_rvp; 1391c2aa98e2SPeter Wemm char **arg_rvp; 1392c2aa98e2SPeter Wemm char **default_rvp; 139306f25ae9SGregory Neil Shapiro char cbuf[MAXNAME + 1]; 1394c2aa98e2SPeter Wemm char *pvpb1[MAXATOM + 1]; 1395c2aa98e2SPeter Wemm char *argvect[10]; 1396c2aa98e2SPeter Wemm char pvpbuf[PSBUFSIZE]; 1397c2aa98e2SPeter Wemm char *nullpvp[1]; 1398c2aa98e2SPeter Wemm 1399c2aa98e2SPeter Wemm if ((**rvp & 0377) != HOSTBEGIN && 1400c2aa98e2SPeter Wemm (**rvp & 0377) != LOOKUPBEGIN) 1401c2aa98e2SPeter Wemm continue; 1402c2aa98e2SPeter Wemm 1403c2aa98e2SPeter Wemm /* 1404c2aa98e2SPeter Wemm ** Got a hostname/keyword lookup. 1405c2aa98e2SPeter Wemm ** 1406c2aa98e2SPeter Wemm ** This could be optimized fairly easily. 1407c2aa98e2SPeter Wemm */ 1408c2aa98e2SPeter Wemm 1409c2aa98e2SPeter Wemm hbrvp = rvp; 1410c2aa98e2SPeter Wemm if ((**rvp & 0377) == HOSTBEGIN) 1411c2aa98e2SPeter Wemm { 1412c2aa98e2SPeter Wemm endtoken = HOSTEND; 1413c2aa98e2SPeter Wemm mapname = "host"; 1414c2aa98e2SPeter Wemm } 1415c2aa98e2SPeter Wemm else 1416c2aa98e2SPeter Wemm { 1417c2aa98e2SPeter Wemm endtoken = LOOKUPEND; 1418c2aa98e2SPeter Wemm mapname = *++rvp; 1419c2aa98e2SPeter Wemm } 1420c2aa98e2SPeter Wemm map = stab(mapname, ST_MAP, ST_FIND); 1421c2aa98e2SPeter Wemm if (map == NULL) 142206f25ae9SGregory Neil Shapiro syserr("554 5.3.0 rewrite: map %s not found", mapname); 1423c2aa98e2SPeter Wemm 1424c2aa98e2SPeter Wemm /* extract the match part */ 1425c2aa98e2SPeter Wemm key_rvp = ++rvp; 1426c2aa98e2SPeter Wemm default_rvp = NULL; 1427c2aa98e2SPeter Wemm arg_rvp = argvect; 1428c2aa98e2SPeter Wemm xpvp = NULL; 1429c2aa98e2SPeter Wemm replac = pvpbuf; 1430c2aa98e2SPeter Wemm while (*rvp != NULL && (**rvp & 0377) != endtoken) 1431c2aa98e2SPeter Wemm { 1432c2aa98e2SPeter Wemm int nodetype = **rvp & 0377; 1433c2aa98e2SPeter Wemm 1434c2aa98e2SPeter Wemm if (nodetype != CANONHOST && nodetype != CANONUSER) 1435c2aa98e2SPeter Wemm { 1436c2aa98e2SPeter Wemm rvp++; 1437c2aa98e2SPeter Wemm continue; 1438c2aa98e2SPeter Wemm } 1439c2aa98e2SPeter Wemm 1440c2aa98e2SPeter Wemm *rvp++ = NULL; 1441c2aa98e2SPeter Wemm 1442c2aa98e2SPeter Wemm if (xpvp != NULL) 1443c2aa98e2SPeter Wemm { 1444c2aa98e2SPeter Wemm cataddr(xpvp, NULL, replac, 1445c2aa98e2SPeter Wemm &pvpbuf[sizeof pvpbuf] - replac, 1446c2aa98e2SPeter Wemm '\0'); 1447c2aa98e2SPeter Wemm *++arg_rvp = replac; 1448c2aa98e2SPeter Wemm replac += strlen(replac) + 1; 1449c2aa98e2SPeter Wemm xpvp = NULL; 1450c2aa98e2SPeter Wemm } 1451c2aa98e2SPeter Wemm switch (nodetype) 1452c2aa98e2SPeter Wemm { 1453c2aa98e2SPeter Wemm case CANONHOST: 1454c2aa98e2SPeter Wemm xpvp = rvp; 1455c2aa98e2SPeter Wemm break; 1456c2aa98e2SPeter Wemm 1457c2aa98e2SPeter Wemm case CANONUSER: 1458c2aa98e2SPeter Wemm default_rvp = rvp; 1459c2aa98e2SPeter Wemm break; 1460c2aa98e2SPeter Wemm } 1461c2aa98e2SPeter Wemm } 1462c2aa98e2SPeter Wemm if (*rvp != NULL) 1463c2aa98e2SPeter Wemm *rvp++ = NULL; 1464c2aa98e2SPeter Wemm if (xpvp != NULL) 1465c2aa98e2SPeter Wemm { 1466c2aa98e2SPeter Wemm cataddr(xpvp, NULL, replac, 1467c2aa98e2SPeter Wemm &pvpbuf[sizeof pvpbuf] - replac, 1468c2aa98e2SPeter Wemm '\0'); 1469c2aa98e2SPeter Wemm *++arg_rvp = replac; 1470c2aa98e2SPeter Wemm } 1471c2aa98e2SPeter Wemm *++arg_rvp = NULL; 1472c2aa98e2SPeter Wemm 1473c2aa98e2SPeter Wemm /* save the remainder of the input string */ 1474c2aa98e2SPeter Wemm trsize = (int) (avp - rvp + 1) * sizeof *rvp; 147506f25ae9SGregory Neil Shapiro memmove((char *) pvpb1, (char *) rvp, trsize); 1476c2aa98e2SPeter Wemm 1477c2aa98e2SPeter Wemm /* look it up */ 147806f25ae9SGregory Neil Shapiro cataddr(key_rvp, NULL, cbuf, sizeof cbuf, 147906f25ae9SGregory Neil Shapiro map == NULL ? '\0' : map->s_map.map_spacesub); 148006f25ae9SGregory Neil Shapiro argvect[0] = cbuf; 148106f25ae9SGregory Neil Shapiro replac = map_lookup(map, cbuf, argvect, &rstat, e); 1482c2aa98e2SPeter Wemm 1483c2aa98e2SPeter Wemm /* if no replacement, use default */ 1484c2aa98e2SPeter Wemm if (replac == NULL && default_rvp != NULL) 1485c2aa98e2SPeter Wemm { 1486c2aa98e2SPeter Wemm /* create the default */ 148706f25ae9SGregory Neil Shapiro cataddr(default_rvp, NULL, cbuf, sizeof cbuf, '\0'); 148806f25ae9SGregory Neil Shapiro replac = cbuf; 1489c2aa98e2SPeter Wemm } 1490c2aa98e2SPeter Wemm 1491c2aa98e2SPeter Wemm if (replac == NULL) 1492c2aa98e2SPeter Wemm { 1493c2aa98e2SPeter Wemm xpvp = key_rvp; 1494c2aa98e2SPeter Wemm } 1495c2aa98e2SPeter Wemm else if (*replac == '\0') 1496c2aa98e2SPeter Wemm { 1497c2aa98e2SPeter Wemm /* null replacement */ 1498c2aa98e2SPeter Wemm nullpvp[0] = NULL; 1499c2aa98e2SPeter Wemm xpvp = nullpvp; 1500c2aa98e2SPeter Wemm } 1501c2aa98e2SPeter Wemm else 1502c2aa98e2SPeter Wemm { 1503c2aa98e2SPeter Wemm /* scan the new replacement */ 1504c2aa98e2SPeter Wemm xpvp = prescan(replac, '\0', pvpbuf, 1505c2aa98e2SPeter Wemm sizeof pvpbuf, NULL, NULL); 1506c2aa98e2SPeter Wemm if (xpvp == NULL) 1507c2aa98e2SPeter Wemm { 1508c2aa98e2SPeter Wemm /* prescan already printed error */ 1509c2aa98e2SPeter Wemm return EX_DATAERR; 1510c2aa98e2SPeter Wemm } 1511c2aa98e2SPeter Wemm } 1512c2aa98e2SPeter Wemm 1513c2aa98e2SPeter Wemm /* append it to the token list */ 1514c2aa98e2SPeter Wemm for (avp = hbrvp; *xpvp != NULL; xpvp++) 1515c2aa98e2SPeter Wemm { 151640266059SGregory Neil Shapiro *avp++ = sm_rpool_strdup_x(e->e_rpool, *xpvp); 151740266059SGregory Neil Shapiro if (avp >= &npvp[maxatom]) 1518c2aa98e2SPeter Wemm goto toolong; 1519c2aa98e2SPeter Wemm } 1520c2aa98e2SPeter Wemm 1521c2aa98e2SPeter Wemm /* restore the old trailing information */ 1522c2aa98e2SPeter Wemm rvp = avp - 1; 1523c2aa98e2SPeter Wemm for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) 152440266059SGregory Neil Shapiro if (avp >= &npvp[maxatom]) 1525c2aa98e2SPeter Wemm goto toolong; 1526c2aa98e2SPeter Wemm } 1527c2aa98e2SPeter Wemm 1528c2aa98e2SPeter Wemm /* 1529c2aa98e2SPeter Wemm ** Check for subroutine calls. 1530c2aa98e2SPeter Wemm */ 1531c2aa98e2SPeter Wemm 153206f25ae9SGregory Neil Shapiro status = callsubr(npvp, reclevel, e); 153306f25ae9SGregory Neil Shapiro if (rstat == EX_OK || status == EX_TEMPFAIL) 153406f25ae9SGregory Neil Shapiro rstat = status; 1535c2aa98e2SPeter Wemm 1536c2aa98e2SPeter Wemm /* copy vector back into original space. */ 1537c2aa98e2SPeter Wemm for (avp = npvp; *avp++ != NULL;) 1538c2aa98e2SPeter Wemm continue; 153906f25ae9SGregory Neil Shapiro memmove((char *) pvp, (char *) npvp, 1540c2aa98e2SPeter Wemm (int) (avp - npvp) * sizeof *avp); 1541c2aa98e2SPeter Wemm 1542c2aa98e2SPeter Wemm if (tTd(21, 4)) 1543c2aa98e2SPeter Wemm { 154440266059SGregory Neil Shapiro sm_dprintf("rewritten as:"); 1545c2aa98e2SPeter Wemm printav(pvp); 1546c2aa98e2SPeter Wemm } 1547c2aa98e2SPeter Wemm } 1548c2aa98e2SPeter Wemm 154906f25ae9SGregory Neil Shapiro if (OpMode == MD_TEST) 1550c2aa98e2SPeter Wemm { 155140266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 155240266059SGregory Neil Shapiro "%s%-16.16s returns:", prefix, rulename); 1553c2aa98e2SPeter Wemm printav(pvp); 1554c2aa98e2SPeter Wemm } 155506f25ae9SGregory Neil Shapiro else if (tTd(21, 1)) 155606f25ae9SGregory Neil Shapiro { 155740266059SGregory Neil Shapiro sm_dprintf("%s%-16.16s returns:", prefix, rulename); 155806f25ae9SGregory Neil Shapiro printav(pvp); 155906f25ae9SGregory Neil Shapiro } 1560c2aa98e2SPeter Wemm return rstat; 1561c2aa98e2SPeter Wemm } 156240266059SGregory Neil Shapiro /* 1563c2aa98e2SPeter Wemm ** CALLSUBR -- call subroutines in rewrite vector 1564c2aa98e2SPeter Wemm ** 1565c2aa98e2SPeter Wemm ** Parameters: 1566c2aa98e2SPeter Wemm ** pvp -- pointer to token vector. 1567c2aa98e2SPeter Wemm ** reclevel -- the current recursion level. 1568c2aa98e2SPeter Wemm ** e -- the current envelope. 1569c2aa98e2SPeter Wemm ** 1570c2aa98e2SPeter Wemm ** Returns: 1571c2aa98e2SPeter Wemm ** The status from the subroutine call. 1572c2aa98e2SPeter Wemm ** 1573c2aa98e2SPeter Wemm ** Side Effects: 1574c2aa98e2SPeter Wemm ** pvp is modified. 1575c2aa98e2SPeter Wemm */ 1576c2aa98e2SPeter Wemm 157706f25ae9SGregory Neil Shapiro static int 1578c2aa98e2SPeter Wemm callsubr(pvp, reclevel, e) 1579c2aa98e2SPeter Wemm char **pvp; 1580c2aa98e2SPeter Wemm int reclevel; 1581c2aa98e2SPeter Wemm ENVELOPE *e; 1582c2aa98e2SPeter Wemm { 1583c2aa98e2SPeter Wemm char **avp; 1584c2aa98e2SPeter Wemm register int i; 158540266059SGregory Neil Shapiro int subr, j; 158640266059SGregory Neil Shapiro int nsubr; 158706f25ae9SGregory Neil Shapiro int status; 1588c2aa98e2SPeter Wemm int rstat = EX_OK; 158940266059SGregory Neil Shapiro #define MAX_SUBR 16 159040266059SGregory Neil Shapiro int subrnumber[MAX_SUBR]; 159140266059SGregory Neil Shapiro int subrindex[MAX_SUBR]; 1592c2aa98e2SPeter Wemm 159340266059SGregory Neil Shapiro nsubr = 0; 159440266059SGregory Neil Shapiro 159540266059SGregory Neil Shapiro /* 159640266059SGregory Neil Shapiro ** Look for subroutine calls in pvp, collect them into subr*[] 159740266059SGregory Neil Shapiro ** We will perform the calls in the next loop, because we will 159840266059SGregory Neil Shapiro ** call the "last" subroutine first to avoid recursive calls 159940266059SGregory Neil Shapiro ** and too much copying. 160040266059SGregory Neil Shapiro */ 160140266059SGregory Neil Shapiro 160240266059SGregory Neil Shapiro for (avp = pvp, j = 0; *avp != NULL; avp++, j++) 1603c2aa98e2SPeter Wemm { 1604c2aa98e2SPeter Wemm if ((**avp & 0377) == CALLSUBR && avp[1] != NULL) 1605c2aa98e2SPeter Wemm { 1606c2aa98e2SPeter Wemm stripquotes(avp[1]); 1607c2aa98e2SPeter Wemm subr = strtorwset(avp[1], NULL, ST_FIND); 1608c2aa98e2SPeter Wemm if (subr < 0) 1609c2aa98e2SPeter Wemm { 161040266059SGregory Neil Shapiro syserr("554 5.3.5 Unknown ruleset %s", avp[1]); 1611c2aa98e2SPeter Wemm return EX_CONFIG; 1612c2aa98e2SPeter Wemm } 1613c2aa98e2SPeter Wemm 1614c2aa98e2SPeter Wemm /* 161540266059SGregory Neil Shapiro ** XXX instead of doing this we could optimize 161640266059SGregory Neil Shapiro ** the rules after reading them: just remove 161740266059SGregory Neil Shapiro ** calls to empty rulesets 1618c2aa98e2SPeter Wemm */ 1619c2aa98e2SPeter Wemm 162040266059SGregory Neil Shapiro /* subroutine is an empty ruleset? don't call it */ 162140266059SGregory Neil Shapiro if (RewriteRules[subr] == NULL) 162240266059SGregory Neil Shapiro { 162340266059SGregory Neil Shapiro if (tTd(21, 3)) 162440266059SGregory Neil Shapiro sm_dprintf("-----skip subr %s (%d)\n", 162540266059SGregory Neil Shapiro avp[1], subr); 1626c2aa98e2SPeter Wemm for (i = 2; avp[i] != NULL; i++) 162740266059SGregory Neil Shapiro avp[i - 2] = avp[i]; 162840266059SGregory Neil Shapiro avp[i - 2] = NULL; 162940266059SGregory Neil Shapiro continue; 163040266059SGregory Neil Shapiro } 163140266059SGregory Neil Shapiro if (++nsubr >= MAX_SUBR) 163240266059SGregory Neil Shapiro { 163340266059SGregory Neil Shapiro syserr("554 5.3.0 Too many subroutine calls (%d max)", 163440266059SGregory Neil Shapiro MAX_SUBR); 163540266059SGregory Neil Shapiro return EX_CONFIG; 163640266059SGregory Neil Shapiro } 163740266059SGregory Neil Shapiro subrnumber[nsubr] = subr; 163840266059SGregory Neil Shapiro subrindex[nsubr] = j; 163940266059SGregory Neil Shapiro } 164040266059SGregory Neil Shapiro } 1641c2aa98e2SPeter Wemm 164240266059SGregory Neil Shapiro /* 164340266059SGregory Neil Shapiro ** Perform the actual subroutines calls, "last" one first, i.e., 164440266059SGregory Neil Shapiro ** go from the right to the left through all calls, 164540266059SGregory Neil Shapiro ** do the rewriting in place. 164640266059SGregory Neil Shapiro */ 164740266059SGregory Neil Shapiro 164840266059SGregory Neil Shapiro for (; nsubr > 0; nsubr--) 164940266059SGregory Neil Shapiro { 165040266059SGregory Neil Shapiro subr = subrnumber[nsubr]; 165140266059SGregory Neil Shapiro avp = pvp + subrindex[nsubr]; 165240266059SGregory Neil Shapiro 165340266059SGregory Neil Shapiro /* remove the subroutine call and name */ 165440266059SGregory Neil Shapiro for (i = 2; avp[i] != NULL; i++) 165540266059SGregory Neil Shapiro avp[i - 2] = avp[i]; 165640266059SGregory Neil Shapiro avp[i - 2] = NULL; 1657c2aa98e2SPeter Wemm 1658c2aa98e2SPeter Wemm /* 1659c2aa98e2SPeter Wemm ** Now we need to call the ruleset specified for 166040266059SGregory Neil Shapiro ** the subroutine. we can do this inplace since 166140266059SGregory Neil Shapiro ** we call the "last" subroutine first. 1662c2aa98e2SPeter Wemm */ 1663c2aa98e2SPeter Wemm 166440266059SGregory Neil Shapiro status = rewrite(avp, subr, reclevel, e, 166540266059SGregory Neil Shapiro MAXATOM - subrindex[nsubr]); 166640266059SGregory Neil Shapiro if (status != EX_OK && status != EX_TEMPFAIL) 166740266059SGregory Neil Shapiro return status; 166806f25ae9SGregory Neil Shapiro if (rstat == EX_OK || status == EX_TEMPFAIL) 166906f25ae9SGregory Neil Shapiro rstat = status; 1670c2aa98e2SPeter Wemm } 1671c2aa98e2SPeter Wemm return rstat; 1672c2aa98e2SPeter Wemm } 167340266059SGregory Neil Shapiro /* 1674c2aa98e2SPeter Wemm ** MAP_LOOKUP -- do lookup in map 1675c2aa98e2SPeter Wemm ** 1676c2aa98e2SPeter Wemm ** Parameters: 167740266059SGregory Neil Shapiro ** smap -- the map to use for the lookup. 1678c2aa98e2SPeter Wemm ** key -- the key to look up. 1679c2aa98e2SPeter Wemm ** argvect -- arguments to pass to the map lookup. 1680c2aa98e2SPeter Wemm ** pstat -- a pointer to an integer in which to store the 1681c2aa98e2SPeter Wemm ** status from the lookup. 1682c2aa98e2SPeter Wemm ** e -- the current envelope. 1683c2aa98e2SPeter Wemm ** 1684c2aa98e2SPeter Wemm ** Returns: 1685c2aa98e2SPeter Wemm ** The result of the lookup. 1686c2aa98e2SPeter Wemm ** NULL -- if there was no data for the given key. 1687c2aa98e2SPeter Wemm */ 1688c2aa98e2SPeter Wemm 168906f25ae9SGregory Neil Shapiro static char * 169006f25ae9SGregory Neil Shapiro map_lookup(smap, key, argvect, pstat, e) 169106f25ae9SGregory Neil Shapiro STAB *smap; 1692c2aa98e2SPeter Wemm char key[]; 1693c2aa98e2SPeter Wemm char **argvect; 1694c2aa98e2SPeter Wemm int *pstat; 1695c2aa98e2SPeter Wemm ENVELOPE *e; 1696c2aa98e2SPeter Wemm { 169706f25ae9SGregory Neil Shapiro auto int status = EX_OK; 169806f25ae9SGregory Neil Shapiro MAP *map; 1699c2aa98e2SPeter Wemm char *replac; 1700c2aa98e2SPeter Wemm 170106f25ae9SGregory Neil Shapiro if (smap == NULL) 170206f25ae9SGregory Neil Shapiro return NULL; 170306f25ae9SGregory Neil Shapiro 170406f25ae9SGregory Neil Shapiro map = &smap->s_map; 170506f25ae9SGregory Neil Shapiro DYNOPENMAP(map); 170606f25ae9SGregory Neil Shapiro 170706f25ae9SGregory Neil Shapiro if (e->e_sendmode == SM_DEFER && 170806f25ae9SGregory Neil Shapiro bitset(MF_DEFER, map->map_mflags)) 1709c2aa98e2SPeter Wemm { 1710c2aa98e2SPeter Wemm /* don't do any map lookups */ 1711c2aa98e2SPeter Wemm if (tTd(60, 1)) 171240266059SGregory Neil Shapiro sm_dprintf("map_lookup(%s, %s) => DEFERRED\n", 171306f25ae9SGregory Neil Shapiro smap->s_name, key); 1714c2aa98e2SPeter Wemm *pstat = EX_TEMPFAIL; 1715c2aa98e2SPeter Wemm return NULL; 1716c2aa98e2SPeter Wemm } 1717c2aa98e2SPeter Wemm 171806f25ae9SGregory Neil Shapiro if (!bitset(MF_KEEPQUOTES, map->map_mflags)) 1719c2aa98e2SPeter Wemm stripquotes(key); 1720c2aa98e2SPeter Wemm 1721c2aa98e2SPeter Wemm if (tTd(60, 1)) 1722065a643dSPeter Wemm { 172340266059SGregory Neil Shapiro sm_dprintf("map_lookup(%s, %s", smap->s_name, key); 1724065a643dSPeter Wemm if (tTd(60, 5)) 1725065a643dSPeter Wemm { 1726065a643dSPeter Wemm int i; 1727065a643dSPeter Wemm 1728065a643dSPeter Wemm for (i = 0; argvect[i] != NULL; i++) 172940266059SGregory Neil Shapiro sm_dprintf(", %%%d=%s", i, argvect[i]); 1730065a643dSPeter Wemm } 173140266059SGregory Neil Shapiro sm_dprintf(") => "); 1732065a643dSPeter Wemm } 173306f25ae9SGregory Neil Shapiro replac = (*map->map_class->map_lookup)(map, key, argvect, &status); 1734c2aa98e2SPeter Wemm if (tTd(60, 1)) 173540266059SGregory Neil Shapiro sm_dprintf("%s (%d)\n", 1736c2aa98e2SPeter Wemm replac != NULL ? replac : "NOT FOUND", 173706f25ae9SGregory Neil Shapiro status); 1738c2aa98e2SPeter Wemm 173906f25ae9SGregory Neil Shapiro /* should recover if status == EX_TEMPFAIL */ 174006f25ae9SGregory Neil Shapiro if (status == EX_TEMPFAIL && !bitset(MF_NODEFER, map->map_mflags)) 1741c2aa98e2SPeter Wemm { 1742c2aa98e2SPeter Wemm *pstat = EX_TEMPFAIL; 1743c2aa98e2SPeter Wemm if (tTd(60, 1)) 174440266059SGregory Neil Shapiro sm_dprintf("map_lookup(%s, %s) tempfail: errno=%d\n", 174506f25ae9SGregory Neil Shapiro smap->s_name, key, errno); 1746c2aa98e2SPeter Wemm if (e->e_message == NULL) 1747c2aa98e2SPeter Wemm { 1748c2aa98e2SPeter Wemm char mbuf[320]; 1749c2aa98e2SPeter Wemm 175040266059SGregory Neil Shapiro (void) sm_snprintf(mbuf, sizeof mbuf, 1751c2aa98e2SPeter Wemm "%.80s map: lookup (%s): deferred", 175206f25ae9SGregory Neil Shapiro smap->s_name, 1753c2aa98e2SPeter Wemm shortenstring(key, MAXSHORTSTR)); 175440266059SGregory Neil Shapiro e->e_message = sm_rpool_strdup_x(e->e_rpool, mbuf); 1755c2aa98e2SPeter Wemm } 1756c2aa98e2SPeter Wemm } 175706f25ae9SGregory Neil Shapiro if (status == EX_TEMPFAIL && map->map_tapp != NULL) 1758c2aa98e2SPeter Wemm { 175906f25ae9SGregory Neil Shapiro size_t i = strlen(key) + strlen(map->map_tapp) + 1; 1760c2aa98e2SPeter Wemm static char *rwbuf = NULL; 1761c2aa98e2SPeter Wemm static size_t rwbuflen = 0; 1762c2aa98e2SPeter Wemm 1763c2aa98e2SPeter Wemm if (i > rwbuflen) 1764c2aa98e2SPeter Wemm { 1765c2aa98e2SPeter Wemm if (rwbuf != NULL) 17668774250cSGregory Neil Shapiro sm_free(rwbuf); 1767c2aa98e2SPeter Wemm rwbuflen = i; 176840266059SGregory Neil Shapiro rwbuf = (char *) sm_pmalloc_x(rwbuflen); 1769c2aa98e2SPeter Wemm } 177040266059SGregory Neil Shapiro (void) sm_strlcpyn(rwbuf, rwbuflen, 2, key, map->map_tapp); 1771c2aa98e2SPeter Wemm if (tTd(60, 4)) 177240266059SGregory Neil Shapiro sm_dprintf("map_lookup tempfail: returning \"%s\"\n", 1773c2aa98e2SPeter Wemm rwbuf); 1774c2aa98e2SPeter Wemm return rwbuf; 1775c2aa98e2SPeter Wemm } 1776c2aa98e2SPeter Wemm return replac; 1777c2aa98e2SPeter Wemm } 177840266059SGregory Neil Shapiro /* 177906f25ae9SGregory Neil Shapiro ** INITERRMAILERS -- initialize error and discard mailers 178006f25ae9SGregory Neil Shapiro ** 178106f25ae9SGregory Neil Shapiro ** Parameters: 178206f25ae9SGregory Neil Shapiro ** none. 178306f25ae9SGregory Neil Shapiro ** 178406f25ae9SGregory Neil Shapiro ** Returns: 178506f25ae9SGregory Neil Shapiro ** none. 178606f25ae9SGregory Neil Shapiro ** 178706f25ae9SGregory Neil Shapiro ** Side Effects: 178806f25ae9SGregory Neil Shapiro ** initializes error and discard mailers. 178906f25ae9SGregory Neil Shapiro */ 179006f25ae9SGregory Neil Shapiro 179106f25ae9SGregory Neil Shapiro static MAILER discardmailer; 179206f25ae9SGregory Neil Shapiro static MAILER errormailer; 179306f25ae9SGregory Neil Shapiro static char *discardargv[] = { "DISCARD", NULL }; 179406f25ae9SGregory Neil Shapiro static char *errorargv[] = { "ERROR", NULL }; 179506f25ae9SGregory Neil Shapiro 179606f25ae9SGregory Neil Shapiro void 179706f25ae9SGregory Neil Shapiro initerrmailers() 179806f25ae9SGregory Neil Shapiro { 179906f25ae9SGregory Neil Shapiro if (discardmailer.m_name == NULL) 180006f25ae9SGregory Neil Shapiro { 180106f25ae9SGregory Neil Shapiro /* initialize the discard mailer */ 180206f25ae9SGregory Neil Shapiro discardmailer.m_name = "*discard*"; 180306f25ae9SGregory Neil Shapiro discardmailer.m_mailer = "DISCARD"; 180406f25ae9SGregory Neil Shapiro discardmailer.m_argv = discardargv; 180506f25ae9SGregory Neil Shapiro } 180606f25ae9SGregory Neil Shapiro if (errormailer.m_name == NULL) 180706f25ae9SGregory Neil Shapiro { 180806f25ae9SGregory Neil Shapiro /* initialize the bogus mailer */ 180906f25ae9SGregory Neil Shapiro errormailer.m_name = "*error*"; 181006f25ae9SGregory Neil Shapiro errormailer.m_mailer = "ERROR"; 181106f25ae9SGregory Neil Shapiro errormailer.m_argv = errorargv; 181206f25ae9SGregory Neil Shapiro } 181306f25ae9SGregory Neil Shapiro } 181440266059SGregory Neil Shapiro /* 1815c2aa98e2SPeter Wemm ** BUILDADDR -- build address from token vector. 1816c2aa98e2SPeter Wemm ** 1817c2aa98e2SPeter Wemm ** Parameters: 1818c2aa98e2SPeter Wemm ** tv -- token vector. 1819c2aa98e2SPeter Wemm ** a -- pointer to address descriptor to fill. 1820c2aa98e2SPeter Wemm ** If NULL, one will be allocated. 1821c2aa98e2SPeter Wemm ** flags -- info regarding whether this is a sender or 1822c2aa98e2SPeter Wemm ** a recipient. 1823c2aa98e2SPeter Wemm ** e -- the current envelope. 1824c2aa98e2SPeter Wemm ** 1825c2aa98e2SPeter Wemm ** Returns: 1826c2aa98e2SPeter Wemm ** NULL if there was an error. 1827c2aa98e2SPeter Wemm ** 'a' otherwise. 1828c2aa98e2SPeter Wemm ** 1829c2aa98e2SPeter Wemm ** Side Effects: 1830c2aa98e2SPeter Wemm ** fills in 'a' 1831c2aa98e2SPeter Wemm */ 1832c2aa98e2SPeter Wemm 183306f25ae9SGregory Neil Shapiro static struct errcodes 1834c2aa98e2SPeter Wemm { 1835c2aa98e2SPeter Wemm char *ec_name; /* name of error code */ 1836c2aa98e2SPeter Wemm int ec_code; /* numeric code */ 1837c2aa98e2SPeter Wemm } ErrorCodes[] = 1838c2aa98e2SPeter Wemm { 1839c2aa98e2SPeter Wemm { "usage", EX_USAGE }, 1840c2aa98e2SPeter Wemm { "nouser", EX_NOUSER }, 1841c2aa98e2SPeter Wemm { "nohost", EX_NOHOST }, 1842c2aa98e2SPeter Wemm { "unavailable", EX_UNAVAILABLE }, 1843c2aa98e2SPeter Wemm { "software", EX_SOFTWARE }, 1844c2aa98e2SPeter Wemm { "tempfail", EX_TEMPFAIL }, 1845c2aa98e2SPeter Wemm { "protocol", EX_PROTOCOL }, 1846c2aa98e2SPeter Wemm { "config", EX_CONFIG }, 1847c2aa98e2SPeter Wemm { NULL, EX_UNAVAILABLE } 1848c2aa98e2SPeter Wemm }; 1849c2aa98e2SPeter Wemm 185006f25ae9SGregory Neil Shapiro static ADDRESS * 1851c2aa98e2SPeter Wemm buildaddr(tv, a, flags, e) 1852c2aa98e2SPeter Wemm register char **tv; 1853c2aa98e2SPeter Wemm register ADDRESS *a; 1854c2aa98e2SPeter Wemm int flags; 1855c2aa98e2SPeter Wemm register ENVELOPE *e; 1856c2aa98e2SPeter Wemm { 1857605302a5SGregory Neil Shapiro bool tempfail = false; 1858c2aa98e2SPeter Wemm struct mailer **mp; 1859c2aa98e2SPeter Wemm register struct mailer *m; 1860c2aa98e2SPeter Wemm register char *p; 1861c2aa98e2SPeter Wemm char *mname; 1862c2aa98e2SPeter Wemm char **hostp; 1863c2aa98e2SPeter Wemm char hbuf[MAXNAME + 1]; 1864065a643dSPeter Wemm static char ubuf[MAXNAME + 2]; 1865c2aa98e2SPeter Wemm 1866c2aa98e2SPeter Wemm if (tTd(24, 5)) 1867c2aa98e2SPeter Wemm { 186840266059SGregory Neil Shapiro sm_dprintf("buildaddr, flags=%x, tv=", flags); 1869c2aa98e2SPeter Wemm printav(tv); 1870c2aa98e2SPeter Wemm } 1871c2aa98e2SPeter Wemm 1872c2aa98e2SPeter Wemm if (a == NULL) 187340266059SGregory Neil Shapiro a = (ADDRESS *) sm_rpool_malloc_x(e->e_rpool, sizeof *a); 187406f25ae9SGregory Neil Shapiro memset((char *) a, '\0', sizeof *a); 187506f25ae9SGregory Neil Shapiro hbuf[0] = '\0'; 1876c2aa98e2SPeter Wemm 1877c2aa98e2SPeter Wemm /* set up default error return flags */ 1878c2aa98e2SPeter Wemm a->q_flags |= DefaultNotify; 1879c2aa98e2SPeter Wemm 1880c2aa98e2SPeter Wemm /* figure out what net/mailer to use */ 1881c2aa98e2SPeter Wemm if (*tv == NULL || (**tv & 0377) != CANONNET) 1882c2aa98e2SPeter Wemm { 188306f25ae9SGregory Neil Shapiro syserr("554 5.3.5 buildaddr: no mailer in parsed address"); 1884c2aa98e2SPeter Wemm badaddr: 1885605302a5SGregory Neil Shapiro #if _FFR_ALLOW_S0_ERROR_4XX 1886605302a5SGregory Neil Shapiro /* 1887605302a5SGregory Neil Shapiro ** ExitStat may have been set by an earlier map open 1888605302a5SGregory Neil Shapiro ** failure (to a permanent error (EX_OSERR) in syserr()) 1889605302a5SGregory Neil Shapiro ** so we also need to check if this particular $#error 1890605302a5SGregory Neil Shapiro ** return wanted a 4XX failure. 1891605302a5SGregory Neil Shapiro ** 1892605302a5SGregory Neil Shapiro ** XXX the real fix is probably to set ExitStat correctly, 1893605302a5SGregory Neil Shapiro ** i.e., to EX_TEMPFAIL if the map open is just a temporary 1894605302a5SGregory Neil Shapiro ** error. 1895605302a5SGregory Neil Shapiro ** 1896605302a5SGregory Neil Shapiro ** tempfail is tested here even if _FFR_ALLOW_S0_ERROR_4XX 1897605302a5SGregory Neil Shapiro ** is not set; that's ok because it is initialized to false. 1898605302a5SGregory Neil Shapiro */ 1899605302a5SGregory Neil Shapiro #endif /* _FFR_ALLOW_S0_ERROR_4XX */ 1900605302a5SGregory Neil Shapiro 1901605302a5SGregory Neil Shapiro if (ExitStat == EX_TEMPFAIL || tempfail) 190206f25ae9SGregory Neil Shapiro a->q_state = QS_QUEUEUP; 190306f25ae9SGregory Neil Shapiro else 1904c2aa98e2SPeter Wemm { 190506f25ae9SGregory Neil Shapiro a->q_state = QS_BADADDR; 190606f25ae9SGregory Neil Shapiro a->q_mailer = &errormailer; 1907c2aa98e2SPeter Wemm } 1908c2aa98e2SPeter Wemm return a; 1909c2aa98e2SPeter Wemm } 1910c2aa98e2SPeter Wemm mname = *++tv; 1911c2aa98e2SPeter Wemm 1912c2aa98e2SPeter Wemm /* extract host and user portions */ 1913c2aa98e2SPeter Wemm if (*++tv != NULL && (**tv & 0377) == CANONHOST) 1914c2aa98e2SPeter Wemm hostp = ++tv; 1915c2aa98e2SPeter Wemm else 1916c2aa98e2SPeter Wemm hostp = NULL; 1917c2aa98e2SPeter Wemm while (*tv != NULL && (**tv & 0377) != CANONUSER) 1918c2aa98e2SPeter Wemm tv++; 1919c2aa98e2SPeter Wemm if (*tv == NULL) 1920c2aa98e2SPeter Wemm { 192106f25ae9SGregory Neil Shapiro syserr("554 5.3.5 buildaddr: no user"); 1922c2aa98e2SPeter Wemm goto badaddr; 1923c2aa98e2SPeter Wemm } 1924c2aa98e2SPeter Wemm if (tv == hostp) 1925c2aa98e2SPeter Wemm hostp = NULL; 1926c2aa98e2SPeter Wemm else if (hostp != NULL) 1927c2aa98e2SPeter Wemm cataddr(hostp, tv - 1, hbuf, sizeof hbuf, '\0'); 1928c2aa98e2SPeter Wemm cataddr(++tv, NULL, ubuf, sizeof ubuf, ' '); 1929c2aa98e2SPeter Wemm 1930c2aa98e2SPeter Wemm /* save away the host name */ 193140266059SGregory Neil Shapiro if (sm_strcasecmp(mname, "error") == 0) 1932c2aa98e2SPeter Wemm { 193306f25ae9SGregory Neil Shapiro /* Set up triplet for use by -bv */ 193406f25ae9SGregory Neil Shapiro a->q_mailer = &errormailer; 193540266059SGregory Neil Shapiro a->q_user = sm_rpool_strdup_x(e->e_rpool, ubuf); 193640266059SGregory Neil Shapiro /* XXX wrong place? */ 193706f25ae9SGregory Neil Shapiro 1938c2aa98e2SPeter Wemm if (hostp != NULL) 1939c2aa98e2SPeter Wemm { 1940c2aa98e2SPeter Wemm register struct errcodes *ep; 1941c2aa98e2SPeter Wemm 194240266059SGregory Neil Shapiro a->q_host = sm_rpool_strdup_x(e->e_rpool, hbuf); 1943c2aa98e2SPeter Wemm if (strchr(hbuf, '.') != NULL) 1944c2aa98e2SPeter Wemm { 194540266059SGregory Neil Shapiro a->q_status = sm_rpool_strdup_x(e->e_rpool, 194640266059SGregory Neil Shapiro hbuf); 1947c2aa98e2SPeter Wemm setstat(dsntoexitstat(hbuf)); 1948c2aa98e2SPeter Wemm } 1949c2aa98e2SPeter Wemm else if (isascii(hbuf[0]) && isdigit(hbuf[0])) 1950c2aa98e2SPeter Wemm { 1951c2aa98e2SPeter Wemm setstat(atoi(hbuf)); 1952c2aa98e2SPeter Wemm } 1953c2aa98e2SPeter Wemm else 1954c2aa98e2SPeter Wemm { 1955c2aa98e2SPeter Wemm for (ep = ErrorCodes; ep->ec_name != NULL; ep++) 195640266059SGregory Neil Shapiro if (sm_strcasecmp(ep->ec_name, hbuf) == 0) 1957c2aa98e2SPeter Wemm break; 1958c2aa98e2SPeter Wemm setstat(ep->ec_code); 1959c2aa98e2SPeter Wemm } 1960c2aa98e2SPeter Wemm } 1961c2aa98e2SPeter Wemm else 196206f25ae9SGregory Neil Shapiro { 196306f25ae9SGregory Neil Shapiro a->q_host = NULL; 1964c2aa98e2SPeter Wemm setstat(EX_UNAVAILABLE); 1965c2aa98e2SPeter Wemm } 196606f25ae9SGregory Neil Shapiro stripquotes(ubuf); 196706f25ae9SGregory Neil Shapiro if (ISSMTPCODE(ubuf) && ubuf[3] == ' ') 196806f25ae9SGregory Neil Shapiro { 196906f25ae9SGregory Neil Shapiro char fmt[16]; 197006f25ae9SGregory Neil Shapiro int off; 197106f25ae9SGregory Neil Shapiro 197206f25ae9SGregory Neil Shapiro if ((off = isenhsc(ubuf + 4, ' ')) > 0) 197306f25ae9SGregory Neil Shapiro { 197406f25ae9SGregory Neil Shapiro ubuf[off + 4] = '\0'; 197506f25ae9SGregory Neil Shapiro off += 5; 1976c2aa98e2SPeter Wemm } 1977c2aa98e2SPeter Wemm else 1978c2aa98e2SPeter Wemm { 197906f25ae9SGregory Neil Shapiro off = 4; 198006f25ae9SGregory Neil Shapiro ubuf[3] = '\0'; 198106f25ae9SGregory Neil Shapiro } 198240266059SGregory Neil Shapiro (void) sm_strlcpyn(fmt, sizeof fmt, 2, ubuf, " %s"); 198306f25ae9SGregory Neil Shapiro if (off > 4) 198406f25ae9SGregory Neil Shapiro usrerr(fmt, ubuf + off); 198506f25ae9SGregory Neil Shapiro else if (isenhsc(hbuf, '\0') > 0) 198606f25ae9SGregory Neil Shapiro usrerrenh(hbuf, fmt, ubuf + off); 198706f25ae9SGregory Neil Shapiro else 198806f25ae9SGregory Neil Shapiro usrerr(fmt, ubuf + off); 198906f25ae9SGregory Neil Shapiro /* XXX ubuf[off - 1] = ' '; */ 1990605302a5SGregory Neil Shapiro #if _FFR_ALLOW_S0_ERROR_4XX 1991605302a5SGregory Neil Shapiro if (ubuf[0] == '4') 1992605302a5SGregory Neil Shapiro tempfail = true; 1993605302a5SGregory Neil Shapiro #endif /* _FFR_ALLOW_S0_ERROR_4XX */ 199406f25ae9SGregory Neil Shapiro } 199506f25ae9SGregory Neil Shapiro else 199606f25ae9SGregory Neil Shapiro { 199706f25ae9SGregory Neil Shapiro usrerr("553 5.3.0 %s", ubuf); 1998c2aa98e2SPeter Wemm } 1999c2aa98e2SPeter Wemm goto badaddr; 2000c2aa98e2SPeter Wemm } 2001c2aa98e2SPeter Wemm 2002c2aa98e2SPeter Wemm for (mp = Mailer; (m = *mp++) != NULL; ) 2003c2aa98e2SPeter Wemm { 200440266059SGregory Neil Shapiro if (sm_strcasecmp(m->m_name, mname) == 0) 2005c2aa98e2SPeter Wemm break; 2006c2aa98e2SPeter Wemm } 2007c2aa98e2SPeter Wemm if (m == NULL) 2008c2aa98e2SPeter Wemm { 200906f25ae9SGregory Neil Shapiro syserr("554 5.3.5 buildaddr: unknown mailer %s", mname); 2010c2aa98e2SPeter Wemm goto badaddr; 2011c2aa98e2SPeter Wemm } 2012c2aa98e2SPeter Wemm a->q_mailer = m; 2013c2aa98e2SPeter Wemm 2014c2aa98e2SPeter Wemm /* figure out what host (if any) */ 2015c2aa98e2SPeter Wemm if (hostp == NULL) 2016c2aa98e2SPeter Wemm { 2017c2aa98e2SPeter Wemm if (!bitnset(M_LOCALMAILER, m->m_flags)) 2018c2aa98e2SPeter Wemm { 201906f25ae9SGregory Neil Shapiro syserr("554 5.3.5 buildaddr: no host"); 2020c2aa98e2SPeter Wemm goto badaddr; 2021c2aa98e2SPeter Wemm } 2022c2aa98e2SPeter Wemm a->q_host = NULL; 2023c2aa98e2SPeter Wemm } 2024c2aa98e2SPeter Wemm else 202540266059SGregory Neil Shapiro a->q_host = sm_rpool_strdup_x(e->e_rpool, hbuf); 2026c2aa98e2SPeter Wemm 2027c2aa98e2SPeter Wemm /* figure out the user */ 2028c2aa98e2SPeter Wemm p = ubuf; 2029c2aa98e2SPeter Wemm if (bitnset(M_CHECKUDB, m->m_flags) && *p == '@') 2030c2aa98e2SPeter Wemm { 2031c2aa98e2SPeter Wemm p++; 2032c2aa98e2SPeter Wemm tv++; 2033c2aa98e2SPeter Wemm a->q_flags |= QNOTREMOTE; 2034c2aa98e2SPeter Wemm } 2035c2aa98e2SPeter Wemm 2036c2aa98e2SPeter Wemm /* do special mapping for local mailer */ 2037c2aa98e2SPeter Wemm if (*p == '"') 2038c2aa98e2SPeter Wemm p++; 2039c2aa98e2SPeter Wemm if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags)) 2040c2aa98e2SPeter Wemm a->q_mailer = m = ProgMailer; 2041c2aa98e2SPeter Wemm else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags)) 2042c2aa98e2SPeter Wemm a->q_mailer = m = FileMailer; 2043c2aa98e2SPeter Wemm else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags)) 2044c2aa98e2SPeter Wemm { 2045c2aa98e2SPeter Wemm /* may be :include: */ 2046c2aa98e2SPeter Wemm stripquotes(ubuf); 204740266059SGregory Neil Shapiro if (sm_strncasecmp(ubuf, ":include:", 9) == 0) 2048c2aa98e2SPeter Wemm { 2049c2aa98e2SPeter Wemm /* if :include:, don't need further rewriting */ 2050c2aa98e2SPeter Wemm a->q_mailer = m = InclMailer; 205140266059SGregory Neil Shapiro a->q_user = sm_rpool_strdup_x(e->e_rpool, &ubuf[9]); 2052c2aa98e2SPeter Wemm return a; 2053c2aa98e2SPeter Wemm } 2054c2aa98e2SPeter Wemm } 2055c2aa98e2SPeter Wemm 2056c2aa98e2SPeter Wemm /* rewrite according recipient mailer rewriting rules */ 205740266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'h', a->q_host); 205806f25ae9SGregory Neil Shapiro 205940266059SGregory Neil Shapiro if (ConfigLevel >= 10 || 206006f25ae9SGregory Neil Shapiro !bitset(RF_SENDERADDR|RF_HEADERADDR, flags)) 2061c2aa98e2SPeter Wemm { 2062c2aa98e2SPeter Wemm /* sender addresses done later */ 206340266059SGregory Neil Shapiro (void) REWRITE(tv, 2, e); 2064c2aa98e2SPeter Wemm if (m->m_re_rwset > 0) 206540266059SGregory Neil Shapiro (void) REWRITE(tv, m->m_re_rwset, e); 2066c2aa98e2SPeter Wemm } 206740266059SGregory Neil Shapiro (void) REWRITE(tv, 4, e); 2068c2aa98e2SPeter Wemm 2069c2aa98e2SPeter Wemm /* save the result for the command line/RCPT argument */ 2070c2aa98e2SPeter Wemm cataddr(tv, NULL, ubuf, sizeof ubuf, '\0'); 207140266059SGregory Neil Shapiro a->q_user = sm_rpool_strdup_x(e->e_rpool, ubuf); 2072c2aa98e2SPeter Wemm 2073c2aa98e2SPeter Wemm /* 2074c2aa98e2SPeter Wemm ** Do mapping to lower case as requested by mailer 2075c2aa98e2SPeter Wemm */ 2076c2aa98e2SPeter Wemm 2077c2aa98e2SPeter Wemm if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags)) 2078c2aa98e2SPeter Wemm makelower(a->q_host); 2079c2aa98e2SPeter Wemm if (!bitnset(M_USR_UPPER, m->m_flags)) 2080c2aa98e2SPeter Wemm makelower(a->q_user); 2081c2aa98e2SPeter Wemm 2082c2aa98e2SPeter Wemm if (tTd(24, 6)) 2083c2aa98e2SPeter Wemm { 208440266059SGregory Neil Shapiro sm_dprintf("buildaddr => "); 208540266059SGregory Neil Shapiro printaddr(a, false); 2086c2aa98e2SPeter Wemm } 2087c2aa98e2SPeter Wemm return a; 2088c2aa98e2SPeter Wemm } 208913bd1963SGregory Neil Shapiro 209040266059SGregory Neil Shapiro /* 2091c2aa98e2SPeter Wemm ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 2092c2aa98e2SPeter Wemm ** 2093c2aa98e2SPeter Wemm ** Parameters: 2094c2aa98e2SPeter Wemm ** pvp -- parameter vector to rebuild. 2095c2aa98e2SPeter Wemm ** evp -- last parameter to include. Can be NULL to 2096c2aa98e2SPeter Wemm ** use entire pvp. 2097c2aa98e2SPeter Wemm ** buf -- buffer to build the string into. 2098c2aa98e2SPeter Wemm ** sz -- size of buf. 209940266059SGregory Neil Shapiro ** spacesub -- the space separator character; if '\0', 2100c2aa98e2SPeter Wemm ** use SpaceSub. 2101c2aa98e2SPeter Wemm ** 2102c2aa98e2SPeter Wemm ** Returns: 2103c2aa98e2SPeter Wemm ** none. 2104c2aa98e2SPeter Wemm ** 2105c2aa98e2SPeter Wemm ** Side Effects: 2106c2aa98e2SPeter Wemm ** Destroys buf. 2107c2aa98e2SPeter Wemm */ 2108c2aa98e2SPeter Wemm 2109c2aa98e2SPeter Wemm void 2110c2aa98e2SPeter Wemm cataddr(pvp, evp, buf, sz, spacesub) 2111c2aa98e2SPeter Wemm char **pvp; 2112c2aa98e2SPeter Wemm char **evp; 2113c2aa98e2SPeter Wemm char *buf; 2114c2aa98e2SPeter Wemm register int sz; 2115c2aa98e2SPeter Wemm int spacesub; 2116c2aa98e2SPeter Wemm { 211740266059SGregory Neil Shapiro bool oatomtok = false; 211840266059SGregory Neil Shapiro bool natomtok = false; 2119c2aa98e2SPeter Wemm register int i; 2120c2aa98e2SPeter Wemm register char *p; 2121c2aa98e2SPeter Wemm 212206f25ae9SGregory Neil Shapiro if (sz <= 0) 212306f25ae9SGregory Neil Shapiro return; 212406f25ae9SGregory Neil Shapiro 2125c2aa98e2SPeter Wemm if (spacesub == '\0') 2126c2aa98e2SPeter Wemm spacesub = SpaceSub; 2127c2aa98e2SPeter Wemm 2128c2aa98e2SPeter Wemm if (pvp == NULL) 2129c2aa98e2SPeter Wemm { 213006f25ae9SGregory Neil Shapiro *buf = '\0'; 2131c2aa98e2SPeter Wemm return; 2132c2aa98e2SPeter Wemm } 2133c2aa98e2SPeter Wemm p = buf; 2134c2aa98e2SPeter Wemm sz -= 2; 213540266059SGregory Neil Shapiro while (*pvp != NULL && sz > 0) 2136c2aa98e2SPeter Wemm { 2137c2aa98e2SPeter Wemm natomtok = (TokTypeTab[**pvp & 0xff] == ATM); 2138c2aa98e2SPeter Wemm if (oatomtok && natomtok) 213906f25ae9SGregory Neil Shapiro { 2140c2aa98e2SPeter Wemm *p++ = spacesub; 214140266059SGregory Neil Shapiro if (--sz <= 0) 214240266059SGregory Neil Shapiro break; 214306f25ae9SGregory Neil Shapiro } 214440266059SGregory Neil Shapiro if ((i = sm_strlcpy(p, *pvp, sz)) >= sz) 214540266059SGregory Neil Shapiro break; 2146c2aa98e2SPeter Wemm oatomtok = natomtok; 2147c2aa98e2SPeter Wemm p += i; 214806f25ae9SGregory Neil Shapiro sz -= i; 2149c2aa98e2SPeter Wemm if (pvp++ == evp) 2150c2aa98e2SPeter Wemm break; 2151c2aa98e2SPeter Wemm } 2152605302a5SGregory Neil Shapiro #if _FFR_CATCH_LONG_STRINGS 2153605302a5SGregory Neil Shapiro /* Don't silently truncate long strings */ 2154605302a5SGregory Neil Shapiro if (*pvp != NULL) 2155605302a5SGregory Neil Shapiro syserr("cataddr: string too long"); 2156605302a5SGregory Neil Shapiro #endif /* _FFR_CATCH_LONG_STRINGS */ 2157c2aa98e2SPeter Wemm *p = '\0'; 2158c2aa98e2SPeter Wemm } 215940266059SGregory Neil Shapiro /* 2160c2aa98e2SPeter Wemm ** SAMEADDR -- Determine if two addresses are the same 2161c2aa98e2SPeter Wemm ** 2162c2aa98e2SPeter Wemm ** This is not just a straight comparison -- if the mailer doesn't 2163c2aa98e2SPeter Wemm ** care about the host we just ignore it, etc. 2164c2aa98e2SPeter Wemm ** 2165c2aa98e2SPeter Wemm ** Parameters: 2166c2aa98e2SPeter Wemm ** a, b -- pointers to the internal forms to compare. 2167c2aa98e2SPeter Wemm ** 2168c2aa98e2SPeter Wemm ** Returns: 216940266059SGregory Neil Shapiro ** true -- they represent the same mailbox. 217040266059SGregory Neil Shapiro ** false -- they don't. 2171c2aa98e2SPeter Wemm ** 2172c2aa98e2SPeter Wemm ** Side Effects: 2173c2aa98e2SPeter Wemm ** none. 2174c2aa98e2SPeter Wemm */ 2175c2aa98e2SPeter Wemm 2176c2aa98e2SPeter Wemm bool 2177c2aa98e2SPeter Wemm sameaddr(a, b) 2178c2aa98e2SPeter Wemm register ADDRESS *a; 2179c2aa98e2SPeter Wemm register ADDRESS *b; 2180c2aa98e2SPeter Wemm { 2181c2aa98e2SPeter Wemm register ADDRESS *ca, *cb; 2182c2aa98e2SPeter Wemm 2183c2aa98e2SPeter Wemm /* if they don't have the same mailer, forget it */ 2184c2aa98e2SPeter Wemm if (a->q_mailer != b->q_mailer) 218540266059SGregory Neil Shapiro return false; 2186c2aa98e2SPeter Wemm 2187c2aa98e2SPeter Wemm /* if the user isn't the same, we can drop out */ 2188c2aa98e2SPeter Wemm if (strcmp(a->q_user, b->q_user) != 0) 218940266059SGregory Neil Shapiro return false; 2190c2aa98e2SPeter Wemm 2191c2aa98e2SPeter Wemm /* if we have good uids for both but they differ, these are different */ 2192c2aa98e2SPeter Wemm if (a->q_mailer == ProgMailer) 2193c2aa98e2SPeter Wemm { 2194c2aa98e2SPeter Wemm ca = getctladdr(a); 2195c2aa98e2SPeter Wemm cb = getctladdr(b); 2196c2aa98e2SPeter Wemm if (ca != NULL && cb != NULL && 2197c2aa98e2SPeter Wemm bitset(QGOODUID, ca->q_flags & cb->q_flags) && 2198c2aa98e2SPeter Wemm ca->q_uid != cb->q_uid) 219940266059SGregory Neil Shapiro return false; 2200c2aa98e2SPeter Wemm } 2201c2aa98e2SPeter Wemm 2202c2aa98e2SPeter Wemm /* otherwise compare hosts (but be careful for NULL ptrs) */ 2203c2aa98e2SPeter Wemm if (a->q_host == b->q_host) 2204c2aa98e2SPeter Wemm { 2205c2aa98e2SPeter Wemm /* probably both null pointers */ 220640266059SGregory Neil Shapiro return true; 2207c2aa98e2SPeter Wemm } 2208c2aa98e2SPeter Wemm if (a->q_host == NULL || b->q_host == NULL) 2209c2aa98e2SPeter Wemm { 2210c2aa98e2SPeter Wemm /* only one is a null pointer */ 221140266059SGregory Neil Shapiro return false; 2212c2aa98e2SPeter Wemm } 2213c2aa98e2SPeter Wemm if (strcmp(a->q_host, b->q_host) != 0) 221440266059SGregory Neil Shapiro return false; 2215c2aa98e2SPeter Wemm 221640266059SGregory Neil Shapiro return true; 2217c2aa98e2SPeter Wemm } 221840266059SGregory Neil Shapiro /* 2219c2aa98e2SPeter Wemm ** PRINTADDR -- print address (for debugging) 2220c2aa98e2SPeter Wemm ** 2221c2aa98e2SPeter Wemm ** Parameters: 2222c2aa98e2SPeter Wemm ** a -- the address to print 2223c2aa98e2SPeter Wemm ** follow -- follow the q_next chain. 2224c2aa98e2SPeter Wemm ** 2225c2aa98e2SPeter Wemm ** Returns: 2226c2aa98e2SPeter Wemm ** none. 2227c2aa98e2SPeter Wemm ** 2228c2aa98e2SPeter Wemm ** Side Effects: 2229c2aa98e2SPeter Wemm ** none. 2230c2aa98e2SPeter Wemm */ 2231c2aa98e2SPeter Wemm 2232c2aa98e2SPeter Wemm struct qflags 2233c2aa98e2SPeter Wemm { 2234c2aa98e2SPeter Wemm char *qf_name; 223540266059SGregory Neil Shapiro unsigned long qf_bit; 2236c2aa98e2SPeter Wemm }; 2237c2aa98e2SPeter Wemm 223806f25ae9SGregory Neil Shapiro static struct qflags AddressFlags[] = 2239c2aa98e2SPeter Wemm { 2240c2aa98e2SPeter Wemm { "QGOODUID", QGOODUID }, 2241c2aa98e2SPeter Wemm { "QPRIMARY", QPRIMARY }, 2242c2aa98e2SPeter Wemm { "QNOTREMOTE", QNOTREMOTE }, 2243c2aa98e2SPeter Wemm { "QSELFREF", QSELFREF }, 2244c2aa98e2SPeter Wemm { "QBOGUSSHELL", QBOGUSSHELL }, 2245c2aa98e2SPeter Wemm { "QUNSAFEADDR", QUNSAFEADDR }, 2246c2aa98e2SPeter Wemm { "QPINGONSUCCESS", QPINGONSUCCESS }, 2247c2aa98e2SPeter Wemm { "QPINGONFAILURE", QPINGONFAILURE }, 2248c2aa98e2SPeter Wemm { "QPINGONDELAY", QPINGONDELAY }, 2249c2aa98e2SPeter Wemm { "QHASNOTIFY", QHASNOTIFY }, 2250c2aa98e2SPeter Wemm { "QRELAYED", QRELAYED }, 2251c2aa98e2SPeter Wemm { "QEXPANDED", QEXPANDED }, 2252c2aa98e2SPeter Wemm { "QDELIVERED", QDELIVERED }, 2253c2aa98e2SPeter Wemm { "QDELAYED", QDELAYED }, 2254c2aa98e2SPeter Wemm { "QTHISPASS", QTHISPASS }, 2255c2aa98e2SPeter Wemm { "QRCPTOK", QRCPTOK }, 2256193538b7SGregory Neil Shapiro { NULL, 0 } 2257c2aa98e2SPeter Wemm }; 2258c2aa98e2SPeter Wemm 2259c2aa98e2SPeter Wemm void 2260c2aa98e2SPeter Wemm printaddr(a, follow) 2261c2aa98e2SPeter Wemm register ADDRESS *a; 2262c2aa98e2SPeter Wemm bool follow; 2263c2aa98e2SPeter Wemm { 2264c2aa98e2SPeter Wemm register MAILER *m; 2265c2aa98e2SPeter Wemm MAILER pseudomailer; 2266c2aa98e2SPeter Wemm register struct qflags *qfp; 2267c2aa98e2SPeter Wemm bool firstone; 2268c2aa98e2SPeter Wemm 2269c2aa98e2SPeter Wemm if (a == NULL) 2270c2aa98e2SPeter Wemm { 227140266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "[NULL]\n"); 2272c2aa98e2SPeter Wemm return; 2273c2aa98e2SPeter Wemm } 2274c2aa98e2SPeter Wemm 2275c2aa98e2SPeter Wemm while (a != NULL) 2276c2aa98e2SPeter Wemm { 227740266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%p=", a); 227840266059SGregory Neil Shapiro (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 2279c2aa98e2SPeter Wemm 2280c2aa98e2SPeter Wemm /* find the mailer -- carefully */ 2281c2aa98e2SPeter Wemm m = a->q_mailer; 2282c2aa98e2SPeter Wemm if (m == NULL) 2283c2aa98e2SPeter Wemm { 2284c2aa98e2SPeter Wemm m = &pseudomailer; 2285c2aa98e2SPeter Wemm m->m_mno = -1; 2286c2aa98e2SPeter Wemm m->m_name = "NULL"; 2287c2aa98e2SPeter Wemm } 2288c2aa98e2SPeter Wemm 228940266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 229040266059SGregory Neil Shapiro "%s:\n\tmailer %d (%s), host `%s'\n", 2291c2aa98e2SPeter Wemm a->q_paddr == NULL ? "<null>" : a->q_paddr, 2292c2aa98e2SPeter Wemm m->m_mno, m->m_name, 2293c2aa98e2SPeter Wemm a->q_host == NULL ? "<null>" : a->q_host); 229440266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 229540266059SGregory Neil Shapiro "\tuser `%s', ruser `%s'\n", 2296c2aa98e2SPeter Wemm a->q_user, 2297c2aa98e2SPeter Wemm a->q_ruser == NULL ? "<null>" : a->q_ruser); 229840266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\tstate="); 229906f25ae9SGregory Neil Shapiro switch (a->q_state) 230006f25ae9SGregory Neil Shapiro { 230106f25ae9SGregory Neil Shapiro case QS_OK: 230240266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "OK"); 230306f25ae9SGregory Neil Shapiro break; 230406f25ae9SGregory Neil Shapiro 230506f25ae9SGregory Neil Shapiro case QS_DONTSEND: 230640266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 230740266059SGregory Neil Shapiro "DONTSEND"); 230806f25ae9SGregory Neil Shapiro break; 230906f25ae9SGregory Neil Shapiro 231006f25ae9SGregory Neil Shapiro case QS_BADADDR: 231140266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 231240266059SGregory Neil Shapiro "BADADDR"); 231306f25ae9SGregory Neil Shapiro break; 231406f25ae9SGregory Neil Shapiro 231506f25ae9SGregory Neil Shapiro case QS_QUEUEUP: 231640266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 231740266059SGregory Neil Shapiro "QUEUEUP"); 231840266059SGregory Neil Shapiro break; 231940266059SGregory Neil Shapiro 232040266059SGregory Neil Shapiro case QS_RETRY: 232140266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "RETRY"); 232206f25ae9SGregory Neil Shapiro break; 232306f25ae9SGregory Neil Shapiro 232406f25ae9SGregory Neil Shapiro case QS_SENT: 232540266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "SENT"); 232606f25ae9SGregory Neil Shapiro break; 232706f25ae9SGregory Neil Shapiro 232806f25ae9SGregory Neil Shapiro case QS_VERIFIED: 232940266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 233040266059SGregory Neil Shapiro "VERIFIED"); 233106f25ae9SGregory Neil Shapiro break; 233206f25ae9SGregory Neil Shapiro 233306f25ae9SGregory Neil Shapiro case QS_EXPANDED: 233440266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 233540266059SGregory Neil Shapiro "EXPANDED"); 233606f25ae9SGregory Neil Shapiro break; 233706f25ae9SGregory Neil Shapiro 233806f25ae9SGregory Neil Shapiro case QS_SENDER: 233940266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 234040266059SGregory Neil Shapiro "SENDER"); 234106f25ae9SGregory Neil Shapiro break; 234206f25ae9SGregory Neil Shapiro 234306f25ae9SGregory Neil Shapiro case QS_CLONED: 234440266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 234540266059SGregory Neil Shapiro "CLONED"); 234606f25ae9SGregory Neil Shapiro break; 234706f25ae9SGregory Neil Shapiro 234806f25ae9SGregory Neil Shapiro case QS_DISCARDED: 234940266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 235040266059SGregory Neil Shapiro "DISCARDED"); 235106f25ae9SGregory Neil Shapiro break; 235206f25ae9SGregory Neil Shapiro 235306f25ae9SGregory Neil Shapiro case QS_REPLACED: 235440266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 235540266059SGregory Neil Shapiro "REPLACED"); 235606f25ae9SGregory Neil Shapiro break; 235706f25ae9SGregory Neil Shapiro 235806f25ae9SGregory Neil Shapiro case QS_REMOVED: 235940266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 236040266059SGregory Neil Shapiro "REMOVED"); 236106f25ae9SGregory Neil Shapiro break; 236206f25ae9SGregory Neil Shapiro 236306f25ae9SGregory Neil Shapiro case QS_DUPLICATE: 236440266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 236540266059SGregory Neil Shapiro "DUPLICATE"); 236606f25ae9SGregory Neil Shapiro break; 236706f25ae9SGregory Neil Shapiro 236806f25ae9SGregory Neil Shapiro case QS_INCLUDED: 236940266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 237040266059SGregory Neil Shapiro "INCLUDED"); 237106f25ae9SGregory Neil Shapiro break; 237206f25ae9SGregory Neil Shapiro 237306f25ae9SGregory Neil Shapiro default: 237440266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 237540266059SGregory Neil Shapiro "%d", a->q_state); 237606f25ae9SGregory Neil Shapiro break; 237706f25ae9SGregory Neil Shapiro } 237840266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 237940266059SGregory Neil Shapiro ", next=%p, alias %p, uid %d, gid %d\n", 238040266059SGregory Neil Shapiro a->q_next, a->q_alias, 2381c2aa98e2SPeter Wemm (int) a->q_uid, (int) a->q_gid); 238240266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "\tflags=%lx<", 238340266059SGregory Neil Shapiro a->q_flags); 238440266059SGregory Neil Shapiro firstone = true; 2385c2aa98e2SPeter Wemm for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++) 2386c2aa98e2SPeter Wemm { 2387c2aa98e2SPeter Wemm if (!bitset(qfp->qf_bit, a->q_flags)) 2388c2aa98e2SPeter Wemm continue; 2389c2aa98e2SPeter Wemm if (!firstone) 239040266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 239140266059SGregory Neil Shapiro ","); 239240266059SGregory Neil Shapiro firstone = false; 239340266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%s", 239440266059SGregory Neil Shapiro qfp->qf_name); 2395c2aa98e2SPeter Wemm } 239640266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, ">\n"); 239740266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 239840266059SGregory Neil Shapiro "\towner=%s, home=\"%s\", fullname=\"%s\"\n", 2399c2aa98e2SPeter Wemm a->q_owner == NULL ? "(none)" : a->q_owner, 2400c2aa98e2SPeter Wemm a->q_home == NULL ? "(none)" : a->q_home, 2401c2aa98e2SPeter Wemm a->q_fullname == NULL ? "(none)" : a->q_fullname); 240240266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 240340266059SGregory Neil Shapiro "\torcpt=\"%s\", statmta=%s, status=%s\n", 2404c2aa98e2SPeter Wemm a->q_orcpt == NULL ? "(none)" : a->q_orcpt, 2405c2aa98e2SPeter Wemm a->q_statmta == NULL ? "(none)" : a->q_statmta, 2406c2aa98e2SPeter Wemm a->q_status == NULL ? "(none)" : a->q_status); 240740266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 240840266059SGregory Neil Shapiro "\tfinalrcpt=\"%s\"\n", 240940266059SGregory Neil Shapiro a->q_finalrcpt == NULL ? "(none)" : a->q_finalrcpt); 241040266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 241140266059SGregory Neil Shapiro "\trstatus=\"%s\"\n", 2412c2aa98e2SPeter Wemm a->q_rstatus == NULL ? "(none)" : a->q_rstatus); 241340266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 241440266059SGregory Neil Shapiro "\tstatdate=%s\n", 241506f25ae9SGregory Neil Shapiro a->q_statdate == 0 ? "(none)" : ctime(&a->q_statdate)); 2416c2aa98e2SPeter Wemm 2417c2aa98e2SPeter Wemm if (!follow) 2418c2aa98e2SPeter Wemm return; 2419c2aa98e2SPeter Wemm a = a->q_next; 2420c2aa98e2SPeter Wemm } 2421c2aa98e2SPeter Wemm } 242240266059SGregory Neil Shapiro /* 242340266059SGregory Neil Shapiro ** EMPTYADDR -- return true if this address is empty (``<>'') 2424c2aa98e2SPeter Wemm ** 2425c2aa98e2SPeter Wemm ** Parameters: 2426c2aa98e2SPeter Wemm ** a -- pointer to the address 2427c2aa98e2SPeter Wemm ** 2428c2aa98e2SPeter Wemm ** Returns: 242940266059SGregory Neil Shapiro ** true -- if this address is "empty" (i.e., no one should 2430c2aa98e2SPeter Wemm ** ever generate replies to it. 243140266059SGregory Neil Shapiro ** false -- if it is a "regular" (read: replyable) address. 2432c2aa98e2SPeter Wemm */ 2433c2aa98e2SPeter Wemm 2434c2aa98e2SPeter Wemm bool 2435c2aa98e2SPeter Wemm emptyaddr(a) 2436c2aa98e2SPeter Wemm register ADDRESS *a; 2437c2aa98e2SPeter Wemm { 2438c2aa98e2SPeter Wemm return a->q_paddr == NULL || strcmp(a->q_paddr, "<>") == 0 || 2439c2aa98e2SPeter Wemm a->q_user == NULL || strcmp(a->q_user, "<>") == 0; 2440c2aa98e2SPeter Wemm } 244140266059SGregory Neil Shapiro /* 2442c2aa98e2SPeter Wemm ** REMOTENAME -- return the name relative to the current mailer 2443c2aa98e2SPeter Wemm ** 2444c2aa98e2SPeter Wemm ** Parameters: 2445c2aa98e2SPeter Wemm ** name -- the name to translate. 2446c2aa98e2SPeter Wemm ** m -- the mailer that we want to do rewriting relative 2447c2aa98e2SPeter Wemm ** to. 2448c2aa98e2SPeter Wemm ** flags -- fine tune operations. 2449c2aa98e2SPeter Wemm ** pstat -- pointer to status word. 2450c2aa98e2SPeter Wemm ** e -- the current envelope. 2451c2aa98e2SPeter Wemm ** 2452c2aa98e2SPeter Wemm ** Returns: 2453c2aa98e2SPeter Wemm ** the text string representing this address relative to 2454c2aa98e2SPeter Wemm ** the receiving mailer. 2455c2aa98e2SPeter Wemm ** 2456c2aa98e2SPeter Wemm ** Side Effects: 2457c2aa98e2SPeter Wemm ** none. 2458c2aa98e2SPeter Wemm ** 2459c2aa98e2SPeter Wemm ** Warnings: 2460c2aa98e2SPeter Wemm ** The text string returned is tucked away locally; 2461c2aa98e2SPeter Wemm ** copy it if you intend to save it. 2462c2aa98e2SPeter Wemm */ 2463c2aa98e2SPeter Wemm 2464c2aa98e2SPeter Wemm char * 2465c2aa98e2SPeter Wemm remotename(name, m, flags, pstat, e) 2466c2aa98e2SPeter Wemm char *name; 2467c2aa98e2SPeter Wemm struct mailer *m; 2468c2aa98e2SPeter Wemm int flags; 2469c2aa98e2SPeter Wemm int *pstat; 2470c2aa98e2SPeter Wemm register ENVELOPE *e; 2471c2aa98e2SPeter Wemm { 2472c2aa98e2SPeter Wemm register char **pvp; 247340266059SGregory Neil Shapiro char *SM_NONVOLATILE fancy; 247440266059SGregory Neil Shapiro char *oldg; 2475c2aa98e2SPeter Wemm int rwset; 2476c2aa98e2SPeter Wemm static char buf[MAXNAME + 1]; 2477c2aa98e2SPeter Wemm char lbuf[MAXNAME + 1]; 2478c2aa98e2SPeter Wemm char pvpbuf[PSBUFSIZE]; 247906f25ae9SGregory Neil Shapiro char addrtype[4]; 2480c2aa98e2SPeter Wemm 2481c2aa98e2SPeter Wemm if (tTd(12, 1)) 248240266059SGregory Neil Shapiro sm_dprintf("remotename(%s)\n", name); 2483c2aa98e2SPeter Wemm 2484c2aa98e2SPeter Wemm /* don't do anything if we are tagging it as special */ 2485c2aa98e2SPeter Wemm if (bitset(RF_SENDERADDR, flags)) 248606f25ae9SGregory Neil Shapiro { 2487c2aa98e2SPeter Wemm rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset 2488c2aa98e2SPeter Wemm : m->m_se_rwset; 248906f25ae9SGregory Neil Shapiro addrtype[2] = 's'; 249006f25ae9SGregory Neil Shapiro } 2491c2aa98e2SPeter Wemm else 249206f25ae9SGregory Neil Shapiro { 2493c2aa98e2SPeter Wemm rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset 2494c2aa98e2SPeter Wemm : m->m_re_rwset; 249506f25ae9SGregory Neil Shapiro addrtype[2] = 'r'; 249606f25ae9SGregory Neil Shapiro } 2497c2aa98e2SPeter Wemm if (rwset < 0) 249806f25ae9SGregory Neil Shapiro return name; 249906f25ae9SGregory Neil Shapiro addrtype[1] = ' '; 250006f25ae9SGregory Neil Shapiro addrtype[3] = '\0'; 250106f25ae9SGregory Neil Shapiro addrtype[0] = bitset(RF_HEADERADDR, flags) ? 'h' : 'e'; 250240266059SGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, macid("{addr_type}"), addrtype); 2503c2aa98e2SPeter Wemm 2504c2aa98e2SPeter Wemm /* 2505c2aa98e2SPeter Wemm ** Do a heuristic crack of this name to extract any comment info. 2506c2aa98e2SPeter Wemm ** This will leave the name as a comment and a $g macro. 2507c2aa98e2SPeter Wemm */ 2508c2aa98e2SPeter Wemm 2509c2aa98e2SPeter Wemm if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) 2510c2aa98e2SPeter Wemm fancy = "\201g"; 2511c2aa98e2SPeter Wemm else 2512d9986b26SGregory Neil Shapiro fancy = crackaddr(name, e); 2513c2aa98e2SPeter Wemm 2514c2aa98e2SPeter Wemm /* 2515c2aa98e2SPeter Wemm ** Turn the name into canonical form. 2516c2aa98e2SPeter Wemm ** Normally this will be RFC 822 style, i.e., "user@domain". 2517c2aa98e2SPeter Wemm ** If this only resolves to "user", and the "C" flag is 2518c2aa98e2SPeter Wemm ** specified in the sending mailer, then the sender's 2519c2aa98e2SPeter Wemm ** domain will be appended. 2520c2aa98e2SPeter Wemm */ 2521c2aa98e2SPeter Wemm 2522c2aa98e2SPeter Wemm pvp = prescan(name, '\0', pvpbuf, sizeof pvpbuf, NULL, NULL); 2523c2aa98e2SPeter Wemm if (pvp == NULL) 252406f25ae9SGregory Neil Shapiro return name; 252540266059SGregory Neil Shapiro if (REWRITE(pvp, 3, e) == EX_TEMPFAIL) 2526c2aa98e2SPeter Wemm *pstat = EX_TEMPFAIL; 2527c2aa98e2SPeter Wemm if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) 2528c2aa98e2SPeter Wemm { 2529c2aa98e2SPeter Wemm /* append from domain to this address */ 2530c2aa98e2SPeter Wemm register char **pxp = pvp; 253106f25ae9SGregory Neil Shapiro int l = MAXATOM; /* size of buffer for pvp */ 2532c2aa98e2SPeter Wemm 2533c2aa98e2SPeter Wemm /* see if there is an "@domain" in the current name */ 2534c2aa98e2SPeter Wemm while (*pxp != NULL && strcmp(*pxp, "@") != 0) 253506f25ae9SGregory Neil Shapiro { 2536c2aa98e2SPeter Wemm pxp++; 253706f25ae9SGregory Neil Shapiro --l; 253806f25ae9SGregory Neil Shapiro } 2539c2aa98e2SPeter Wemm if (*pxp == NULL) 2540c2aa98e2SPeter Wemm { 2541c2aa98e2SPeter Wemm /* no.... append the "@domain" from the sender */ 2542c2aa98e2SPeter Wemm register char **qxq = e->e_fromdomain; 2543c2aa98e2SPeter Wemm 2544c2aa98e2SPeter Wemm while ((*pxp++ = *qxq++) != NULL) 254506f25ae9SGregory Neil Shapiro { 254606f25ae9SGregory Neil Shapiro if (--l <= 0) 254706f25ae9SGregory Neil Shapiro { 254806f25ae9SGregory Neil Shapiro *--pxp = NULL; 254906f25ae9SGregory Neil Shapiro usrerr("553 5.1.0 remotename: too many tokens"); 255006f25ae9SGregory Neil Shapiro *pstat = EX_UNAVAILABLE; 255106f25ae9SGregory Neil Shapiro break; 255206f25ae9SGregory Neil Shapiro } 255306f25ae9SGregory Neil Shapiro } 255440266059SGregory Neil Shapiro if (REWRITE(pvp, 3, e) == EX_TEMPFAIL) 2555c2aa98e2SPeter Wemm *pstat = EX_TEMPFAIL; 2556c2aa98e2SPeter Wemm } 2557c2aa98e2SPeter Wemm } 2558c2aa98e2SPeter Wemm 2559c2aa98e2SPeter Wemm /* 2560c2aa98e2SPeter Wemm ** Do more specific rewriting. 2561c2aa98e2SPeter Wemm ** Rewrite using ruleset 1 or 2 depending on whether this is 2562c2aa98e2SPeter Wemm ** a sender address or not. 2563c2aa98e2SPeter Wemm ** Then run it through any receiving-mailer-specific rulesets. 2564c2aa98e2SPeter Wemm */ 2565c2aa98e2SPeter Wemm 2566c2aa98e2SPeter Wemm if (bitset(RF_SENDERADDR, flags)) 2567c2aa98e2SPeter Wemm { 256840266059SGregory Neil Shapiro if (REWRITE(pvp, 1, e) == EX_TEMPFAIL) 2569c2aa98e2SPeter Wemm *pstat = EX_TEMPFAIL; 2570c2aa98e2SPeter Wemm } 2571c2aa98e2SPeter Wemm else 2572c2aa98e2SPeter Wemm { 257340266059SGregory Neil Shapiro if (REWRITE(pvp, 2, e) == EX_TEMPFAIL) 2574c2aa98e2SPeter Wemm *pstat = EX_TEMPFAIL; 2575c2aa98e2SPeter Wemm } 2576c2aa98e2SPeter Wemm if (rwset > 0) 2577c2aa98e2SPeter Wemm { 257840266059SGregory Neil Shapiro if (REWRITE(pvp, rwset, e) == EX_TEMPFAIL) 2579c2aa98e2SPeter Wemm *pstat = EX_TEMPFAIL; 2580c2aa98e2SPeter Wemm } 2581c2aa98e2SPeter Wemm 2582c2aa98e2SPeter Wemm /* 2583c2aa98e2SPeter Wemm ** Do any final sanitation the address may require. 2584c2aa98e2SPeter Wemm ** This will normally be used to turn internal forms 2585c2aa98e2SPeter Wemm ** (e.g., user@host.LOCAL) into external form. This 2586c2aa98e2SPeter Wemm ** may be used as a default to the above rules. 2587c2aa98e2SPeter Wemm */ 2588c2aa98e2SPeter Wemm 258940266059SGregory Neil Shapiro if (REWRITE(pvp, 4, e) == EX_TEMPFAIL) 2590c2aa98e2SPeter Wemm *pstat = EX_TEMPFAIL; 2591c2aa98e2SPeter Wemm 2592c2aa98e2SPeter Wemm /* 2593c2aa98e2SPeter Wemm ** Now restore the comment information we had at the beginning. 2594c2aa98e2SPeter Wemm */ 2595c2aa98e2SPeter Wemm 2596c2aa98e2SPeter Wemm cataddr(pvp, NULL, lbuf, sizeof lbuf, '\0'); 259740266059SGregory Neil Shapiro oldg = macget(&e->e_macro, 'g'); 259840266059SGregory Neil Shapiro macset(&e->e_macro, 'g', lbuf); 2599c2aa98e2SPeter Wemm 260040266059SGregory Neil Shapiro SM_TRY 2601c2aa98e2SPeter Wemm /* need to make sure route-addrs have <angle brackets> */ 2602c2aa98e2SPeter Wemm if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@') 2603c2aa98e2SPeter Wemm expand("<\201g>", buf, sizeof buf, e); 2604c2aa98e2SPeter Wemm else 2605c2aa98e2SPeter Wemm expand(fancy, buf, sizeof buf, e); 260640266059SGregory Neil Shapiro SM_FINALLY 260740266059SGregory Neil Shapiro macset(&e->e_macro, 'g', oldg); 260840266059SGregory Neil Shapiro SM_END_TRY 2609c2aa98e2SPeter Wemm 2610c2aa98e2SPeter Wemm if (tTd(12, 1)) 261140266059SGregory Neil Shapiro sm_dprintf("remotename => `%s'\n", buf); 261206f25ae9SGregory Neil Shapiro return buf; 2613c2aa98e2SPeter Wemm } 261440266059SGregory Neil Shapiro /* 2615c2aa98e2SPeter Wemm ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 2616c2aa98e2SPeter Wemm ** 2617c2aa98e2SPeter Wemm ** Parameters: 2618c2aa98e2SPeter Wemm ** a -- the address to map (but just the user name part). 2619c2aa98e2SPeter Wemm ** sendq -- the sendq in which to install any replacement 2620c2aa98e2SPeter Wemm ** addresses. 2621c2aa98e2SPeter Wemm ** aliaslevel -- the alias nesting depth. 2622c2aa98e2SPeter Wemm ** e -- the envelope. 2623c2aa98e2SPeter Wemm ** 2624c2aa98e2SPeter Wemm ** Returns: 2625c2aa98e2SPeter Wemm ** none. 2626c2aa98e2SPeter Wemm */ 2627c2aa98e2SPeter Wemm 2628c2aa98e2SPeter Wemm #define Q_COPYFLAGS (QPRIMARY|QBOGUSSHELL|QUNSAFEADDR|\ 2629c2aa98e2SPeter Wemm Q_PINGFLAGS|QHASNOTIFY|\ 263040266059SGregory Neil Shapiro QRELAYED|QEXPANDED|QDELIVERED|QDELAYED|\ 263140266059SGregory Neil Shapiro QBYTRACE|QBYNDELAY|QBYNRELAY) 2632c2aa98e2SPeter Wemm 2633c2aa98e2SPeter Wemm void 2634c2aa98e2SPeter Wemm maplocaluser(a, sendq, aliaslevel, e) 2635c2aa98e2SPeter Wemm register ADDRESS *a; 2636c2aa98e2SPeter Wemm ADDRESS **sendq; 2637c2aa98e2SPeter Wemm int aliaslevel; 2638c2aa98e2SPeter Wemm ENVELOPE *e; 2639c2aa98e2SPeter Wemm { 2640c2aa98e2SPeter Wemm register char **pvp; 264140266059SGregory Neil Shapiro register ADDRESS *SM_NONVOLATILE a1 = NULL; 2642c2aa98e2SPeter Wemm auto char *delimptr; 2643c2aa98e2SPeter Wemm char pvpbuf[PSBUFSIZE]; 2644c2aa98e2SPeter Wemm 2645c2aa98e2SPeter Wemm if (tTd(29, 1)) 2646c2aa98e2SPeter Wemm { 264740266059SGregory Neil Shapiro sm_dprintf("maplocaluser: "); 264840266059SGregory Neil Shapiro printaddr(a, false); 2649c2aa98e2SPeter Wemm } 2650c2aa98e2SPeter Wemm pvp = prescan(a->q_user, '\0', pvpbuf, sizeof pvpbuf, &delimptr, NULL); 2651c2aa98e2SPeter Wemm if (pvp == NULL) 2652c2aa98e2SPeter Wemm { 2653c2aa98e2SPeter Wemm if (tTd(29, 9)) 265440266059SGregory Neil Shapiro sm_dprintf("maplocaluser: cannot prescan %s\n", 265506f25ae9SGregory Neil Shapiro a->q_user); 2656c2aa98e2SPeter Wemm return; 2657c2aa98e2SPeter Wemm } 2658c2aa98e2SPeter Wemm 265940266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'h', a->q_host); 266040266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'u', a->q_user); 266140266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'z', a->q_home); 2662c2aa98e2SPeter Wemm 266340266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e r"); 266440266059SGregory Neil Shapiro if (REWRITE(pvp, 5, e) == EX_TEMPFAIL) 2665c2aa98e2SPeter Wemm { 2666c2aa98e2SPeter Wemm if (tTd(29, 9)) 266740266059SGregory Neil Shapiro sm_dprintf("maplocaluser: rewrite tempfail\n"); 266806f25ae9SGregory Neil Shapiro a->q_state = QS_QUEUEUP; 2669c2aa98e2SPeter Wemm a->q_status = "4.4.3"; 2670c2aa98e2SPeter Wemm return; 2671c2aa98e2SPeter Wemm } 2672c2aa98e2SPeter Wemm if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 2673c2aa98e2SPeter Wemm { 2674c2aa98e2SPeter Wemm if (tTd(29, 9)) 267540266059SGregory Neil Shapiro sm_dprintf("maplocaluser: doesn't resolve\n"); 2676c2aa98e2SPeter Wemm return; 2677c2aa98e2SPeter Wemm } 2678c2aa98e2SPeter Wemm 267940266059SGregory Neil Shapiro SM_TRY 2680c2aa98e2SPeter Wemm a1 = buildaddr(pvp, NULL, 0, e); 268140266059SGregory Neil Shapiro SM_EXCEPT(exc, "E:mta.quickabort") 268240266059SGregory Neil Shapiro 268340266059SGregory Neil Shapiro /* 268440266059SGregory Neil Shapiro ** mark address as bad, S5 returned an error 268540266059SGregory Neil Shapiro ** and we gave that back to the SMTP client. 268640266059SGregory Neil Shapiro */ 268740266059SGregory Neil Shapiro 268840266059SGregory Neil Shapiro a->q_state = QS_DONTSEND; 268940266059SGregory Neil Shapiro sm_exc_raisenew_x(&EtypeQuickAbort, 2); 269040266059SGregory Neil Shapiro SM_END_TRY 269140266059SGregory Neil Shapiro 269240266059SGregory Neil Shapiro /* if non-null, mailer destination specified -- has it changed? */ 2693c2aa98e2SPeter Wemm if (a1 == NULL || sameaddr(a, a1)) 2694c2aa98e2SPeter Wemm { 2695c2aa98e2SPeter Wemm if (tTd(29, 9)) 269640266059SGregory Neil Shapiro sm_dprintf("maplocaluser: address unchanged\n"); 2697c2aa98e2SPeter Wemm return; 2698c2aa98e2SPeter Wemm } 2699c2aa98e2SPeter Wemm 2700c2aa98e2SPeter Wemm /* make new address take on flags and print attributes of old */ 2701c2aa98e2SPeter Wemm a1->q_flags &= ~Q_COPYFLAGS; 2702c2aa98e2SPeter Wemm a1->q_flags |= a->q_flags & Q_COPYFLAGS; 270340266059SGregory Neil Shapiro a1->q_paddr = sm_rpool_strdup_x(e->e_rpool, a->q_paddr); 270440266059SGregory Neil Shapiro a1->q_finalrcpt = a->q_finalrcpt; 270506f25ae9SGregory Neil Shapiro a1->q_orcpt = a->q_orcpt; 2706c2aa98e2SPeter Wemm 2707c2aa98e2SPeter Wemm /* mark old address as dead; insert new address */ 270806f25ae9SGregory Neil Shapiro a->q_state = QS_REPLACED; 2709c2aa98e2SPeter Wemm if (tTd(29, 5)) 2710c2aa98e2SPeter Wemm { 271140266059SGregory Neil Shapiro sm_dprintf("maplocaluser: QS_REPLACED "); 271240266059SGregory Neil Shapiro printaddr(a, false); 2713c2aa98e2SPeter Wemm } 2714c2aa98e2SPeter Wemm a1->q_alias = a; 271540266059SGregory Neil Shapiro allocaddr(a1, RF_COPYALL, sm_rpool_strdup_x(e->e_rpool, a->q_paddr), e); 2716c2aa98e2SPeter Wemm (void) recipient(a1, sendq, aliaslevel, e); 2717c2aa98e2SPeter Wemm } 271840266059SGregory Neil Shapiro /* 2719c2aa98e2SPeter Wemm ** DEQUOTE_INIT -- initialize dequote map 2720c2aa98e2SPeter Wemm ** 2721c2aa98e2SPeter Wemm ** Parameters: 2722c2aa98e2SPeter Wemm ** map -- the internal map structure. 2723c2aa98e2SPeter Wemm ** args -- arguments. 2724c2aa98e2SPeter Wemm ** 2725c2aa98e2SPeter Wemm ** Returns: 272640266059SGregory Neil Shapiro ** true. 2727c2aa98e2SPeter Wemm */ 2728c2aa98e2SPeter Wemm 2729c2aa98e2SPeter Wemm bool 2730c2aa98e2SPeter Wemm dequote_init(map, args) 2731c2aa98e2SPeter Wemm MAP *map; 2732c2aa98e2SPeter Wemm char *args; 2733c2aa98e2SPeter Wemm { 2734c2aa98e2SPeter Wemm register char *p = args; 2735c2aa98e2SPeter Wemm 273606f25ae9SGregory Neil Shapiro /* there is no check whether there is really an argument */ 2737c2aa98e2SPeter Wemm map->map_mflags |= MF_KEEPQUOTES; 2738c2aa98e2SPeter Wemm for (;;) 2739c2aa98e2SPeter Wemm { 2740c2aa98e2SPeter Wemm while (isascii(*p) && isspace(*p)) 2741c2aa98e2SPeter Wemm p++; 2742c2aa98e2SPeter Wemm if (*p != '-') 2743c2aa98e2SPeter Wemm break; 2744c2aa98e2SPeter Wemm switch (*++p) 2745c2aa98e2SPeter Wemm { 2746c2aa98e2SPeter Wemm case 'a': 2747c2aa98e2SPeter Wemm map->map_app = ++p; 2748c2aa98e2SPeter Wemm break; 2749c2aa98e2SPeter Wemm 275006f25ae9SGregory Neil Shapiro case 'D': 275106f25ae9SGregory Neil Shapiro map->map_mflags |= MF_DEFER; 275206f25ae9SGregory Neil Shapiro break; 275306f25ae9SGregory Neil Shapiro 275406f25ae9SGregory Neil Shapiro case 'S': 2755c2aa98e2SPeter Wemm case 's': 275606f25ae9SGregory Neil Shapiro map->map_spacesub = *++p; 2757c2aa98e2SPeter Wemm break; 2758c2aa98e2SPeter Wemm } 2759c2aa98e2SPeter Wemm while (*p != '\0' && !(isascii(*p) && isspace(*p))) 2760c2aa98e2SPeter Wemm p++; 2761c2aa98e2SPeter Wemm if (*p != '\0') 2762c2aa98e2SPeter Wemm *p = '\0'; 2763c2aa98e2SPeter Wemm } 2764c2aa98e2SPeter Wemm if (map->map_app != NULL) 2765c2aa98e2SPeter Wemm map->map_app = newstr(map->map_app); 2766c2aa98e2SPeter Wemm 276740266059SGregory Neil Shapiro return true; 2768c2aa98e2SPeter Wemm } 276940266059SGregory Neil Shapiro /* 2770c2aa98e2SPeter Wemm ** DEQUOTE_MAP -- unquote an address 2771c2aa98e2SPeter Wemm ** 2772c2aa98e2SPeter Wemm ** Parameters: 2773c2aa98e2SPeter Wemm ** map -- the internal map structure (ignored). 2774c2aa98e2SPeter Wemm ** name -- the name to dequote. 2775c2aa98e2SPeter Wemm ** av -- arguments (ignored). 2776c2aa98e2SPeter Wemm ** statp -- pointer to status out-parameter. 2777c2aa98e2SPeter Wemm ** 2778c2aa98e2SPeter Wemm ** Returns: 2779c2aa98e2SPeter Wemm ** NULL -- if there were no quotes, or if the resulting 2780c2aa98e2SPeter Wemm ** unquoted buffer would not be acceptable to prescan. 2781c2aa98e2SPeter Wemm ** else -- The dequoted buffer. 2782c2aa98e2SPeter Wemm */ 2783c2aa98e2SPeter Wemm 2784c2aa98e2SPeter Wemm /* ARGSUSED2 */ 2785c2aa98e2SPeter Wemm char * 2786c2aa98e2SPeter Wemm dequote_map(map, name, av, statp) 2787c2aa98e2SPeter Wemm MAP *map; 2788c2aa98e2SPeter Wemm char *name; 2789c2aa98e2SPeter Wemm char **av; 2790c2aa98e2SPeter Wemm int *statp; 2791c2aa98e2SPeter Wemm { 2792c2aa98e2SPeter Wemm register char *p; 2793c2aa98e2SPeter Wemm register char *q; 2794c2aa98e2SPeter Wemm register char c; 2795c2aa98e2SPeter Wemm int anglecnt = 0; 2796c2aa98e2SPeter Wemm int cmntcnt = 0; 2797c2aa98e2SPeter Wemm int quotecnt = 0; 2798c2aa98e2SPeter Wemm int spacecnt = 0; 279940266059SGregory Neil Shapiro bool quotemode = false; 280040266059SGregory Neil Shapiro bool bslashmode = false; 280106f25ae9SGregory Neil Shapiro char spacesub = map->map_spacesub; 2802c2aa98e2SPeter Wemm 2803c2aa98e2SPeter Wemm for (p = q = name; (c = *p++) != '\0'; ) 2804c2aa98e2SPeter Wemm { 2805c2aa98e2SPeter Wemm if (bslashmode) 2806c2aa98e2SPeter Wemm { 280740266059SGregory Neil Shapiro bslashmode = false; 2808c2aa98e2SPeter Wemm *q++ = c; 2809c2aa98e2SPeter Wemm continue; 2810c2aa98e2SPeter Wemm } 2811c2aa98e2SPeter Wemm 2812c2aa98e2SPeter Wemm if (c == ' ' && spacesub != '\0') 2813c2aa98e2SPeter Wemm c = spacesub; 2814c2aa98e2SPeter Wemm 2815c2aa98e2SPeter Wemm switch (c) 2816c2aa98e2SPeter Wemm { 2817c2aa98e2SPeter Wemm case '\\': 281840266059SGregory Neil Shapiro bslashmode = true; 2819c2aa98e2SPeter Wemm break; 2820c2aa98e2SPeter Wemm 2821c2aa98e2SPeter Wemm case '(': 2822c2aa98e2SPeter Wemm cmntcnt++; 2823c2aa98e2SPeter Wemm break; 2824c2aa98e2SPeter Wemm 2825c2aa98e2SPeter Wemm case ')': 2826c2aa98e2SPeter Wemm if (cmntcnt-- <= 0) 2827c2aa98e2SPeter Wemm return NULL; 2828c2aa98e2SPeter Wemm break; 2829c2aa98e2SPeter Wemm 2830c2aa98e2SPeter Wemm case ' ': 283106f25ae9SGregory Neil Shapiro case '\t': 2832c2aa98e2SPeter Wemm spacecnt++; 2833c2aa98e2SPeter Wemm break; 2834c2aa98e2SPeter Wemm } 2835c2aa98e2SPeter Wemm 2836c2aa98e2SPeter Wemm if (cmntcnt > 0) 2837c2aa98e2SPeter Wemm { 2838c2aa98e2SPeter Wemm *q++ = c; 2839c2aa98e2SPeter Wemm continue; 2840c2aa98e2SPeter Wemm } 2841c2aa98e2SPeter Wemm 2842c2aa98e2SPeter Wemm switch (c) 2843c2aa98e2SPeter Wemm { 2844c2aa98e2SPeter Wemm case '"': 2845c2aa98e2SPeter Wemm quotemode = !quotemode; 2846c2aa98e2SPeter Wemm quotecnt++; 2847c2aa98e2SPeter Wemm continue; 2848c2aa98e2SPeter Wemm 2849c2aa98e2SPeter Wemm case '<': 2850c2aa98e2SPeter Wemm anglecnt++; 2851c2aa98e2SPeter Wemm break; 2852c2aa98e2SPeter Wemm 2853c2aa98e2SPeter Wemm case '>': 2854c2aa98e2SPeter Wemm if (anglecnt-- <= 0) 2855c2aa98e2SPeter Wemm return NULL; 2856c2aa98e2SPeter Wemm break; 2857c2aa98e2SPeter Wemm } 2858c2aa98e2SPeter Wemm *q++ = c; 2859c2aa98e2SPeter Wemm } 2860c2aa98e2SPeter Wemm 2861c2aa98e2SPeter Wemm if (anglecnt != 0 || cmntcnt != 0 || bslashmode || 2862c2aa98e2SPeter Wemm quotemode || quotecnt <= 0 || spacecnt != 0) 2863c2aa98e2SPeter Wemm return NULL; 2864c2aa98e2SPeter Wemm *q++ = '\0'; 2865c2aa98e2SPeter Wemm return map_rewrite(map, name, strlen(name), NULL); 2866c2aa98e2SPeter Wemm } 286740266059SGregory Neil Shapiro /* 2868c2aa98e2SPeter Wemm ** RSCHECK -- check string(s) for validity using rewriting sets 2869c2aa98e2SPeter Wemm ** 2870c2aa98e2SPeter Wemm ** Parameters: 2871c2aa98e2SPeter Wemm ** rwset -- the rewriting set to use. 2872c2aa98e2SPeter Wemm ** p1 -- the first string to check. 2873c2aa98e2SPeter Wemm ** p2 -- the second string to check -- may be null. 2874c2aa98e2SPeter Wemm ** e -- the current envelope. 2875959366dcSGregory Neil Shapiro ** flags -- control some behavior, see RSF_ in sendmail.h 287640266059SGregory Neil Shapiro ** logl -- logging level. 2877193538b7SGregory Neil Shapiro ** host -- NULL or relay host. 287840266059SGregory Neil Shapiro ** logid -- id for sm_syslog. 2879c2aa98e2SPeter Wemm ** 2880c2aa98e2SPeter Wemm ** Returns: 2881c2aa98e2SPeter Wemm ** EX_OK -- if the rwset doesn't resolve to $#error 2882c2aa98e2SPeter Wemm ** else -- the failure status (message printed) 2883c2aa98e2SPeter Wemm */ 2884c2aa98e2SPeter Wemm 2885c2aa98e2SPeter Wemm int 2886959366dcSGregory Neil Shapiro rscheck(rwset, p1, p2, e, flags, logl, host, logid) 2887c2aa98e2SPeter Wemm char *rwset; 2888c2aa98e2SPeter Wemm char *p1; 2889c2aa98e2SPeter Wemm char *p2; 2890c2aa98e2SPeter Wemm ENVELOPE *e; 2891959366dcSGregory Neil Shapiro int flags; 289206f25ae9SGregory Neil Shapiro int logl; 2893193538b7SGregory Neil Shapiro char *host; 289440266059SGregory Neil Shapiro char *logid; 2895c2aa98e2SPeter Wemm { 289640266059SGregory Neil Shapiro char *volatile buf; 2897c2aa98e2SPeter Wemm int bufsize; 2898c2aa98e2SPeter Wemm int saveexitstat; 289940266059SGregory Neil Shapiro int volatile rstat = EX_OK; 2900c2aa98e2SPeter Wemm char **pvp; 2901c2aa98e2SPeter Wemm int rsno; 290240266059SGregory Neil Shapiro bool volatile discard = false; 2903c2aa98e2SPeter Wemm auto ADDRESS a1; 2904c2aa98e2SPeter Wemm bool saveQuickAbort = QuickAbort; 2905c2aa98e2SPeter Wemm bool saveSuprErrs = SuprErrs; 290640266059SGregory Neil Shapiro #if _FFR_QUARANTINE 290740266059SGregory Neil Shapiro bool quarantine = false; 290840266059SGregory Neil Shapiro char ubuf[BUFSIZ * 2]; 290940266059SGregory Neil Shapiro #endif /* _FFR_QUARANTINE */ 2910c2aa98e2SPeter Wemm char buf0[MAXLINE]; 2911c2aa98e2SPeter Wemm char pvpbuf[PSBUFSIZE]; 2912c2aa98e2SPeter Wemm extern char MsgBuf[]; 2913c2aa98e2SPeter Wemm 2914c2aa98e2SPeter Wemm if (tTd(48, 2)) 291540266059SGregory Neil Shapiro sm_dprintf("rscheck(%s, %s, %s)\n", rwset, p1, 2916c2aa98e2SPeter Wemm p2 == NULL ? "(NULL)" : p2); 2917c2aa98e2SPeter Wemm 2918c2aa98e2SPeter Wemm rsno = strtorwset(rwset, NULL, ST_FIND); 2919c2aa98e2SPeter Wemm if (rsno < 0) 2920c2aa98e2SPeter Wemm return EX_OK; 2921c2aa98e2SPeter Wemm 2922c2aa98e2SPeter Wemm if (p2 != NULL) 2923c2aa98e2SPeter Wemm { 2924c2aa98e2SPeter Wemm bufsize = strlen(p1) + strlen(p2) + 2; 2925c2aa98e2SPeter Wemm if (bufsize > sizeof buf0) 292640266059SGregory Neil Shapiro buf = sm_malloc_x(bufsize); 2927c2aa98e2SPeter Wemm else 2928c2aa98e2SPeter Wemm { 2929c2aa98e2SPeter Wemm buf = buf0; 2930c2aa98e2SPeter Wemm bufsize = sizeof buf0; 2931c2aa98e2SPeter Wemm } 293240266059SGregory Neil Shapiro (void) sm_snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2); 2933c2aa98e2SPeter Wemm } 2934c2aa98e2SPeter Wemm else 2935c2aa98e2SPeter Wemm { 2936c2aa98e2SPeter Wemm bufsize = strlen(p1) + 1; 2937c2aa98e2SPeter Wemm if (bufsize > sizeof buf0) 293840266059SGregory Neil Shapiro buf = sm_malloc_x(bufsize); 2939c2aa98e2SPeter Wemm else 2940c2aa98e2SPeter Wemm { 2941c2aa98e2SPeter Wemm buf = buf0; 2942c2aa98e2SPeter Wemm bufsize = sizeof buf0; 2943c2aa98e2SPeter Wemm } 294440266059SGregory Neil Shapiro (void) sm_strlcpy(buf, p1, bufsize); 2945c2aa98e2SPeter Wemm } 294640266059SGregory Neil Shapiro SM_TRY 294740266059SGregory Neil Shapiro { 294840266059SGregory Neil Shapiro SuprErrs = true; 294940266059SGregory Neil Shapiro QuickAbort = false; 295006f25ae9SGregory Neil Shapiro pvp = prescan(buf, '\0', pvpbuf, sizeof pvpbuf, NULL, 2951959366dcSGregory Neil Shapiro bitset(RSF_RMCOMM, flags) ? NULL : TokTypeNoC); 2952c2aa98e2SPeter Wemm SuprErrs = saveSuprErrs; 2953c2aa98e2SPeter Wemm if (pvp == NULL) 2954c2aa98e2SPeter Wemm { 2955c2aa98e2SPeter Wemm if (tTd(48, 2)) 295640266059SGregory Neil Shapiro sm_dprintf("rscheck: cannot prescan input\n"); 2957c2aa98e2SPeter Wemm /* 2958c2aa98e2SPeter Wemm syserr("rscheck: cannot prescan input: \"%s\"", 2959c2aa98e2SPeter Wemm shortenstring(buf, MAXSHORTSTR)); 2960c2aa98e2SPeter Wemm rstat = EX_DATAERR; 2961c2aa98e2SPeter Wemm */ 2962c2aa98e2SPeter Wemm goto finis; 2963c2aa98e2SPeter Wemm } 2964959366dcSGregory Neil Shapiro if (bitset(RSF_UNSTRUCTURED, flags)) 2965959366dcSGregory Neil Shapiro SuprErrs = true; 296640266059SGregory Neil Shapiro (void) REWRITE(pvp, rsno, e); 2967959366dcSGregory Neil Shapiro if (bitset(RSF_UNSTRUCTURED, flags)) 2968959366dcSGregory Neil Shapiro SuprErrs = saveSuprErrs; 2969c2aa98e2SPeter Wemm if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET || 2970c2aa98e2SPeter Wemm pvp[1] == NULL || (strcmp(pvp[1], "error") != 0 && 2971c2aa98e2SPeter Wemm strcmp(pvp[1], "discard") != 0)) 2972c2aa98e2SPeter Wemm { 2973c2aa98e2SPeter Wemm goto finis; 2974c2aa98e2SPeter Wemm } 2975c2aa98e2SPeter Wemm 2976c2aa98e2SPeter Wemm if (strcmp(pvp[1], "discard") == 0) 2977c2aa98e2SPeter Wemm { 2978c2aa98e2SPeter Wemm if (tTd(48, 2)) 297940266059SGregory Neil Shapiro sm_dprintf("rscheck: discard mailer selected\n"); 2980c2aa98e2SPeter Wemm e->e_flags |= EF_DISCARD; 298140266059SGregory Neil Shapiro discard = true; 2982c2aa98e2SPeter Wemm } 298340266059SGregory Neil Shapiro #if _FFR_QUARANTINE 298440266059SGregory Neil Shapiro else if (strcmp(pvp[1], "error") == 0 && 298540266059SGregory Neil Shapiro pvp[2] != NULL && (pvp[2][0] & 0377) == CANONHOST && 298640266059SGregory Neil Shapiro pvp[3] != NULL && strcmp(pvp[3], "quarantine") == 0) 298740266059SGregory Neil Shapiro { 298840266059SGregory Neil Shapiro if (pvp[4] == NULL || 298940266059SGregory Neil Shapiro (pvp[4][0] & 0377) != CANONUSER || 299040266059SGregory Neil Shapiro pvp[5] == NULL) 299140266059SGregory Neil Shapiro e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, 299240266059SGregory Neil Shapiro rwset); 299340266059SGregory Neil Shapiro else 299440266059SGregory Neil Shapiro { 299540266059SGregory Neil Shapiro cataddr(&(pvp[5]), NULL, ubuf, 299640266059SGregory Neil Shapiro sizeof ubuf, ' '); 299740266059SGregory Neil Shapiro e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, 299840266059SGregory Neil Shapiro ubuf); 299940266059SGregory Neil Shapiro } 300040266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 300140266059SGregory Neil Shapiro macid("{quarantine}"), e->e_quarmsg); 300240266059SGregory Neil Shapiro quarantine = true; 300340266059SGregory Neil Shapiro } 300440266059SGregory Neil Shapiro #endif /* _FFR_QUARANTINE */ 3005c2aa98e2SPeter Wemm else 3006c2aa98e2SPeter Wemm { 3007c2aa98e2SPeter Wemm int savelogusrerrs = LogUsrErrs; 300840266059SGregory Neil Shapiro static bool logged = false; 3009c2aa98e2SPeter Wemm 3010c2aa98e2SPeter Wemm /* got an error -- process it */ 3011c2aa98e2SPeter Wemm saveexitstat = ExitStat; 301240266059SGregory Neil Shapiro LogUsrErrs = false; 3013c2aa98e2SPeter Wemm (void) buildaddr(pvp, &a1, 0, e); 3014c2aa98e2SPeter Wemm LogUsrErrs = savelogusrerrs; 3015c2aa98e2SPeter Wemm rstat = ExitStat; 3016c2aa98e2SPeter Wemm ExitStat = saveexitstat; 3017c2aa98e2SPeter Wemm if (!logged) 3018c2aa98e2SPeter Wemm { 3019959366dcSGregory Neil Shapiro if (bitset(RSF_COUNT, flags)) 302040266059SGregory Neil Shapiro markstats(e, &a1, STATS_REJECT); 302140266059SGregory Neil Shapiro logged = true; 3022c2aa98e2SPeter Wemm } 3023c2aa98e2SPeter Wemm } 3024c2aa98e2SPeter Wemm 302540266059SGregory Neil Shapiro if (LogLevel > logl) 3026c2aa98e2SPeter Wemm { 3027c2aa98e2SPeter Wemm char *relay; 3028c2aa98e2SPeter Wemm char *p; 3029c2aa98e2SPeter Wemm char lbuf[MAXLINE]; 3030c2aa98e2SPeter Wemm 3031c2aa98e2SPeter Wemm p = lbuf; 3032c2aa98e2SPeter Wemm if (p2 != NULL) 3033c2aa98e2SPeter Wemm { 303440266059SGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(lbuf, p), 3035c2aa98e2SPeter Wemm ", arg2=%s", 3036c2aa98e2SPeter Wemm p2); 3037c2aa98e2SPeter Wemm p += strlen(p); 3038c2aa98e2SPeter Wemm } 3039193538b7SGregory Neil Shapiro 3040193538b7SGregory Neil Shapiro if (host != NULL) 3041193538b7SGregory Neil Shapiro relay = host; 3042193538b7SGregory Neil Shapiro else 3043193538b7SGregory Neil Shapiro relay = macvalue('_', e); 3044193538b7SGregory Neil Shapiro if (relay != NULL) 3045c2aa98e2SPeter Wemm { 304640266059SGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(lbuf, p), 3047c2aa98e2SPeter Wemm ", relay=%s", relay); 3048c2aa98e2SPeter Wemm p += strlen(p); 3049c2aa98e2SPeter Wemm } 3050c2aa98e2SPeter Wemm *p = '\0'; 3051c2aa98e2SPeter Wemm if (discard) 305240266059SGregory Neil Shapiro sm_syslog(LOG_NOTICE, logid, 3053c2aa98e2SPeter Wemm "ruleset=%s, arg1=%s%s, discard", 3054c2aa98e2SPeter Wemm rwset, p1, lbuf); 305540266059SGregory Neil Shapiro #if _FFR_QUARANTINE 305640266059SGregory Neil Shapiro else if (quarantine) 305740266059SGregory Neil Shapiro sm_syslog(LOG_NOTICE, logid, 305840266059SGregory Neil Shapiro "ruleset=%s, arg1=%s%s, quarantine=%s", 305940266059SGregory Neil Shapiro rwset, p1, lbuf, ubuf); 306040266059SGregory Neil Shapiro #endif /* _FFR_QUARANTINE */ 3061c2aa98e2SPeter Wemm else 306240266059SGregory Neil Shapiro sm_syslog(LOG_NOTICE, logid, 3063c2aa98e2SPeter Wemm "ruleset=%s, arg1=%s%s, reject=%s", 3064c2aa98e2SPeter Wemm rwset, p1, lbuf, MsgBuf); 3065c2aa98e2SPeter Wemm } 3066c2aa98e2SPeter Wemm 306740266059SGregory Neil Shapiro finis: ; 306840266059SGregory Neil Shapiro } 306940266059SGregory Neil Shapiro SM_FINALLY 307040266059SGregory Neil Shapiro { 3071c2aa98e2SPeter Wemm /* clean up */ 3072c2aa98e2SPeter Wemm if (buf != buf0) 30738774250cSGregory Neil Shapiro sm_free(buf); 307440266059SGregory Neil Shapiro QuickAbort = saveQuickAbort; 307540266059SGregory Neil Shapiro } 307640266059SGregory Neil Shapiro SM_END_TRY 3077c2aa98e2SPeter Wemm 307840266059SGregory Neil Shapiro setstat(rstat); 307940266059SGregory Neil Shapiro 308040266059SGregory Neil Shapiro /* rulesets don't set errno */ 308140266059SGregory Neil Shapiro errno = 0; 3082c2aa98e2SPeter Wemm if (rstat != EX_OK && QuickAbort) 308340266059SGregory Neil Shapiro sm_exc_raisenew_x(&EtypeQuickAbort, 2); 308440266059SGregory Neil Shapiro return rstat; 308540266059SGregory Neil Shapiro } 308640266059SGregory Neil Shapiro /* 308740266059SGregory Neil Shapiro ** RSCAP -- call rewriting set to return capabilities 308840266059SGregory Neil Shapiro ** 308940266059SGregory Neil Shapiro ** Parameters: 309040266059SGregory Neil Shapiro ** rwset -- the rewriting set to use. 309140266059SGregory Neil Shapiro ** p1 -- the first string to check. 309240266059SGregory Neil Shapiro ** p2 -- the second string to check -- may be null. 309340266059SGregory Neil Shapiro ** e -- the current envelope. 309440266059SGregory Neil Shapiro ** pvp -- pointer to token vector. 309540266059SGregory Neil Shapiro ** pvpbuf -- buffer space. 309640266059SGregory Neil Shapiro ** 309740266059SGregory Neil Shapiro ** Returns: 309840266059SGregory Neil Shapiro ** EX_UNAVAILABLE -- ruleset doesn't exist. 309940266059SGregory Neil Shapiro ** EX_DATAERR -- prescan() failed. 310040266059SGregory Neil Shapiro ** EX_OK -- rewrite() was successful. 310140266059SGregory Neil Shapiro ** else -- return status from rewrite(). 310240266059SGregory Neil Shapiro */ 310340266059SGregory Neil Shapiro 310440266059SGregory Neil Shapiro int 310540266059SGregory Neil Shapiro rscap(rwset, p1, p2, e, pvp, pvpbuf, size) 310640266059SGregory Neil Shapiro char *rwset; 310740266059SGregory Neil Shapiro char *p1; 310840266059SGregory Neil Shapiro char *p2; 310940266059SGregory Neil Shapiro ENVELOPE *e; 311040266059SGregory Neil Shapiro char ***pvp; 311140266059SGregory Neil Shapiro char *pvpbuf; 311240266059SGregory Neil Shapiro int size; 311340266059SGregory Neil Shapiro { 311440266059SGregory Neil Shapiro char *volatile buf; 311540266059SGregory Neil Shapiro int bufsize; 311640266059SGregory Neil Shapiro int volatile rstat = EX_OK; 311740266059SGregory Neil Shapiro int rsno; 311840266059SGregory Neil Shapiro bool saveQuickAbort = QuickAbort; 311940266059SGregory Neil Shapiro bool saveSuprErrs = SuprErrs; 312040266059SGregory Neil Shapiro char buf0[MAXLINE]; 312140266059SGregory Neil Shapiro extern char MsgBuf[]; 312240266059SGregory Neil Shapiro 312340266059SGregory Neil Shapiro if (tTd(48, 2)) 312440266059SGregory Neil Shapiro sm_dprintf("rscap(%s, %s, %s)\n", rwset, p1, 312540266059SGregory Neil Shapiro p2 == NULL ? "(NULL)" : p2); 312640266059SGregory Neil Shapiro 312740266059SGregory Neil Shapiro if (pvp != NULL) 312840266059SGregory Neil Shapiro *pvp = NULL; 312940266059SGregory Neil Shapiro rsno = strtorwset(rwset, NULL, ST_FIND); 313040266059SGregory Neil Shapiro if (rsno < 0) 313140266059SGregory Neil Shapiro return EX_UNAVAILABLE; 313240266059SGregory Neil Shapiro 313340266059SGregory Neil Shapiro if (p2 != NULL) 313440266059SGregory Neil Shapiro { 313540266059SGregory Neil Shapiro bufsize = strlen(p1) + strlen(p2) + 2; 313640266059SGregory Neil Shapiro if (bufsize > sizeof buf0) 313740266059SGregory Neil Shapiro buf = sm_malloc_x(bufsize); 313840266059SGregory Neil Shapiro else 313940266059SGregory Neil Shapiro { 314040266059SGregory Neil Shapiro buf = buf0; 314140266059SGregory Neil Shapiro bufsize = sizeof buf0; 314240266059SGregory Neil Shapiro } 314340266059SGregory Neil Shapiro (void) sm_snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2); 314440266059SGregory Neil Shapiro } 314540266059SGregory Neil Shapiro else 314640266059SGregory Neil Shapiro { 314740266059SGregory Neil Shapiro bufsize = strlen(p1) + 1; 314840266059SGregory Neil Shapiro if (bufsize > sizeof buf0) 314940266059SGregory Neil Shapiro buf = sm_malloc_x(bufsize); 315040266059SGregory Neil Shapiro else 315140266059SGregory Neil Shapiro { 315240266059SGregory Neil Shapiro buf = buf0; 315340266059SGregory Neil Shapiro bufsize = sizeof buf0; 315440266059SGregory Neil Shapiro } 315540266059SGregory Neil Shapiro (void) sm_strlcpy(buf, p1, bufsize); 315640266059SGregory Neil Shapiro } 315740266059SGregory Neil Shapiro SM_TRY 315840266059SGregory Neil Shapiro { 315940266059SGregory Neil Shapiro SuprErrs = true; 316040266059SGregory Neil Shapiro QuickAbort = false; 316140266059SGregory Neil Shapiro *pvp = prescan(buf, '\0', pvpbuf, size, NULL, NULL); 316240266059SGregory Neil Shapiro if (*pvp != NULL) 316340266059SGregory Neil Shapiro rstat = REWRITE(*pvp, rsno, e); 316440266059SGregory Neil Shapiro else 316540266059SGregory Neil Shapiro { 316640266059SGregory Neil Shapiro if (tTd(48, 2)) 316740266059SGregory Neil Shapiro sm_dprintf("rscap: cannot prescan input\n"); 316840266059SGregory Neil Shapiro rstat = EX_DATAERR; 316940266059SGregory Neil Shapiro } 317040266059SGregory Neil Shapiro } 317140266059SGregory Neil Shapiro SM_FINALLY 317240266059SGregory Neil Shapiro { 317340266059SGregory Neil Shapiro /* clean up */ 317440266059SGregory Neil Shapiro if (buf != buf0) 317540266059SGregory Neil Shapiro sm_free(buf); 317640266059SGregory Neil Shapiro SuprErrs = saveSuprErrs; 317740266059SGregory Neil Shapiro QuickAbort = saveQuickAbort; 317840266059SGregory Neil Shapiro 317940266059SGregory Neil Shapiro /* prevent information leak, this may contain rewrite error */ 318040266059SGregory Neil Shapiro MsgBuf[0] = '\0'; 318140266059SGregory Neil Shapiro } 318240266059SGregory Neil Shapiro SM_END_TRY 3183c2aa98e2SPeter Wemm return rstat; 3184c2aa98e2SPeter Wemm } 3185