1c2aa98e2SPeter Wemm /* 25dd76dd0SGregory Neil Shapiro * Copyright (c) 1998-2006 Proofpoint, 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 164313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: parseaddr.c,v 8.407 2013-11-22 20:51:56 ca Exp $") 17d0cef73dSGregory Neil Shapiro 18d0cef73dSGregory Neil Shapiro #include <sm/sendmail.h> 19d0cef73dSGregory Neil Shapiro #include "map.h" 2040266059SGregory Neil Shapiro 2140266059SGregory Neil Shapiro static void allocaddr __P((ADDRESS *, int, char *, ENVELOPE *)); 2206f25ae9SGregory Neil Shapiro static int callsubr __P((char**, int, ENVELOPE *)); 2306f25ae9SGregory Neil Shapiro static char *map_lookup __P((STAB *, char *, char **, int *, ENVELOPE *)); 2406f25ae9SGregory Neil Shapiro static ADDRESS *buildaddr __P((char **, ADDRESS *, int, ENVELOPE *)); 25605302a5SGregory Neil Shapiro static bool hasctrlchar __P((register char *, bool, bool)); 26605302a5SGregory Neil Shapiro 27605302a5SGregory Neil Shapiro /* replacement for illegal characters in addresses */ 28605302a5SGregory Neil Shapiro #define BAD_CHAR_REPLACEMENT '?' 29c2aa98e2SPeter Wemm 30c2aa98e2SPeter Wemm /* 31c2aa98e2SPeter Wemm ** PARSEADDR -- Parse an address 32c2aa98e2SPeter Wemm ** 33c2aa98e2SPeter Wemm ** Parses an address and breaks it up into three parts: a 34c2aa98e2SPeter Wemm ** net to transmit the message on, the host to transmit it 35c2aa98e2SPeter Wemm ** to, and a user on that host. These are loaded into an 36c2aa98e2SPeter Wemm ** ADDRESS header with the values squirreled away if necessary. 37c2aa98e2SPeter Wemm ** The "user" part may not be a real user; the process may 38c2aa98e2SPeter Wemm ** just reoccur on that machine. For example, on a machine 39c2aa98e2SPeter Wemm ** with an arpanet connection, the address 40c2aa98e2SPeter Wemm ** csvax.bill@berkeley 41c2aa98e2SPeter Wemm ** will break up to a "user" of 'csvax.bill' and a host 42c2aa98e2SPeter Wemm ** of 'berkeley' -- to be transmitted over the arpanet. 43c2aa98e2SPeter Wemm ** 44c2aa98e2SPeter Wemm ** Parameters: 45c2aa98e2SPeter Wemm ** addr -- the address to parse. 46c2aa98e2SPeter Wemm ** a -- a pointer to the address descriptor buffer. 4740266059SGregory Neil Shapiro ** If NULL, an address will be created. 48c2aa98e2SPeter Wemm ** flags -- describe detail for parsing. See RF_ definitions 49c2aa98e2SPeter Wemm ** in sendmail.h. 50c2aa98e2SPeter Wemm ** delim -- the character to terminate the address, passed 51c2aa98e2SPeter Wemm ** to prescan. 52c2aa98e2SPeter Wemm ** delimptr -- if non-NULL, set to the location of the 53c2aa98e2SPeter Wemm ** delim character that was found. 54c2aa98e2SPeter Wemm ** e -- the envelope that will contain this address. 5540266059SGregory Neil Shapiro ** isrcpt -- true if the address denotes a recipient; false 5640266059SGregory Neil Shapiro ** indicates a sender. 57c2aa98e2SPeter Wemm ** 58c2aa98e2SPeter Wemm ** Returns: 59c2aa98e2SPeter Wemm ** A pointer to the address descriptor header (`a' if 60c2aa98e2SPeter Wemm ** `a' is non-NULL). 61c2aa98e2SPeter Wemm ** NULL on error. 62c2aa98e2SPeter Wemm ** 63c2aa98e2SPeter Wemm ** Side Effects: 6440266059SGregory Neil Shapiro ** e->e_to = addr 65c2aa98e2SPeter Wemm */ 66c2aa98e2SPeter Wemm 67c2aa98e2SPeter Wemm /* following delimiters are inherent to the internal algorithms */ 68c2aa98e2SPeter Wemm #define DELIMCHARS "()<>,;\r\n" /* default word delimiters */ 69c2aa98e2SPeter Wemm 70c2aa98e2SPeter Wemm ADDRESS * 7140266059SGregory Neil Shapiro parseaddr(addr, a, flags, delim, delimptr, e, isrcpt) 72c2aa98e2SPeter Wemm char *addr; 73c2aa98e2SPeter Wemm register ADDRESS *a; 74c2aa98e2SPeter Wemm int flags; 75c2aa98e2SPeter Wemm int delim; 76c2aa98e2SPeter Wemm char **delimptr; 77c2aa98e2SPeter Wemm register ENVELOPE *e; 7840266059SGregory Neil Shapiro bool isrcpt; 79c2aa98e2SPeter Wemm { 8040266059SGregory Neil Shapiro char **pvp; 81c2aa98e2SPeter Wemm auto char *delimptrbuf; 8206f25ae9SGregory Neil Shapiro bool qup; 83c2aa98e2SPeter Wemm char pvpbuf[PSBUFSIZE]; 84c2aa98e2SPeter Wemm 85c2aa98e2SPeter Wemm /* 86c2aa98e2SPeter Wemm ** Initialize and prescan address. 87c2aa98e2SPeter Wemm */ 88c2aa98e2SPeter Wemm 89c2aa98e2SPeter Wemm e->e_to = addr; 90c2aa98e2SPeter Wemm if (tTd(20, 1)) 9140266059SGregory Neil Shapiro sm_dprintf("\n--parseaddr(%s)\n", addr); 92c2aa98e2SPeter Wemm 93c2aa98e2SPeter Wemm if (delimptr == NULL) 94c2aa98e2SPeter Wemm delimptr = &delimptrbuf; 95c2aa98e2SPeter Wemm 96d0cef73dSGregory Neil Shapiro pvp = prescan(addr, delim, pvpbuf, sizeof(pvpbuf), delimptr, 97d0cef73dSGregory Neil Shapiro ExtTokenTab, false); 98c2aa98e2SPeter Wemm if (pvp == NULL) 99c2aa98e2SPeter Wemm { 100c2aa98e2SPeter Wemm if (tTd(20, 1)) 10140266059SGregory Neil Shapiro sm_dprintf("parseaddr-->NULL\n"); 10206f25ae9SGregory Neil Shapiro return NULL; 103c2aa98e2SPeter Wemm } 104c2aa98e2SPeter Wemm 10540266059SGregory Neil Shapiro if (invalidaddr(addr, delim == '\0' ? NULL : *delimptr, isrcpt)) 106c2aa98e2SPeter Wemm { 107c2aa98e2SPeter Wemm if (tTd(20, 1)) 10840266059SGregory Neil Shapiro sm_dprintf("parseaddr-->bad address\n"); 109c2aa98e2SPeter Wemm return NULL; 110c2aa98e2SPeter Wemm } 111c2aa98e2SPeter Wemm 112c2aa98e2SPeter Wemm /* 113c2aa98e2SPeter Wemm ** Save addr if we are going to have to. 114c2aa98e2SPeter Wemm ** 115c2aa98e2SPeter Wemm ** We have to do this early because there is a chance that 116c2aa98e2SPeter Wemm ** the map lookups in the rewriting rules could clobber 117c2aa98e2SPeter Wemm ** static memory somewhere. 118c2aa98e2SPeter Wemm */ 119c2aa98e2SPeter Wemm 120c2aa98e2SPeter Wemm if (bitset(RF_COPYPADDR, flags) && addr != NULL) 121c2aa98e2SPeter Wemm { 122c2aa98e2SPeter Wemm char savec = **delimptr; 123c2aa98e2SPeter Wemm 124c2aa98e2SPeter Wemm if (savec != '\0') 125c2aa98e2SPeter Wemm **delimptr = '\0'; 12640266059SGregory Neil Shapiro e->e_to = addr = sm_rpool_strdup_x(e->e_rpool, addr); 127c2aa98e2SPeter Wemm if (savec != '\0') 128c2aa98e2SPeter Wemm **delimptr = savec; 129c2aa98e2SPeter Wemm } 130c2aa98e2SPeter Wemm 131c2aa98e2SPeter Wemm /* 132c2aa98e2SPeter Wemm ** Apply rewriting rules. 133c2aa98e2SPeter Wemm ** Ruleset 0 does basic parsing. It must resolve. 134c2aa98e2SPeter Wemm */ 135c2aa98e2SPeter Wemm 13640266059SGregory Neil Shapiro qup = false; 137*5b0945b5SGregory Neil Shapiro e->e_flags |= EF_SECURE; 13840266059SGregory Neil Shapiro if (REWRITE(pvp, 3, e) == EX_TEMPFAIL) 13940266059SGregory Neil Shapiro qup = true; 14040266059SGregory Neil Shapiro if (REWRITE(pvp, 0, e) == EX_TEMPFAIL) 14140266059SGregory Neil Shapiro qup = true; 142c2aa98e2SPeter Wemm 143c2aa98e2SPeter Wemm /* 144c2aa98e2SPeter Wemm ** Build canonical address from pvp. 145c2aa98e2SPeter Wemm */ 146c2aa98e2SPeter Wemm 147c2aa98e2SPeter Wemm a = buildaddr(pvp, a, flags, e); 148c2aa98e2SPeter Wemm 149605302a5SGregory Neil Shapiro if (hasctrlchar(a->q_user, isrcpt, true)) 15040266059SGregory Neil Shapiro { 15140266059SGregory Neil Shapiro if (tTd(20, 1)) 15240266059SGregory Neil Shapiro sm_dprintf("parseaddr-->bad q_user\n"); 153605302a5SGregory Neil Shapiro 154605302a5SGregory Neil Shapiro /* 155605302a5SGregory Neil Shapiro ** Just mark the address as bad so DSNs work. 156605302a5SGregory Neil Shapiro ** hasctrlchar() has to make sure that the address 157605302a5SGregory Neil Shapiro ** has been sanitized, e.g., shortened. 158605302a5SGregory Neil Shapiro */ 159605302a5SGregory Neil Shapiro 160605302a5SGregory Neil Shapiro a->q_state = QS_BADADDR; 16140266059SGregory Neil Shapiro } 16240266059SGregory Neil Shapiro 163c2aa98e2SPeter Wemm /* 164c2aa98e2SPeter Wemm ** Make local copies of the host & user and then 165c2aa98e2SPeter Wemm ** transport them out. 166c2aa98e2SPeter Wemm */ 167c2aa98e2SPeter Wemm 16840266059SGregory Neil Shapiro allocaddr(a, flags, addr, e); 169*5b0945b5SGregory Neil Shapiro e->e_flags &= ~EF_SECURE; 17006f25ae9SGregory Neil Shapiro if (QS_IS_BADADDR(a->q_state)) 171605302a5SGregory Neil Shapiro { 172605302a5SGregory Neil Shapiro /* weed out bad characters in the printable address too */ 173605302a5SGregory Neil Shapiro (void) hasctrlchar(a->q_paddr, isrcpt, false); 174c2aa98e2SPeter Wemm return a; 175605302a5SGregory Neil Shapiro } 176c2aa98e2SPeter Wemm 177c2aa98e2SPeter Wemm /* 17840266059SGregory Neil Shapiro ** Select a queue directory for recipient addresses. 17940266059SGregory Neil Shapiro ** This is done here and in split_across_queue_groups(), 18040266059SGregory Neil Shapiro ** but the latter applies to addresses after aliasing, 18140266059SGregory Neil Shapiro ** and only if splitting is done. 18240266059SGregory Neil Shapiro */ 18340266059SGregory Neil Shapiro 18440266059SGregory Neil Shapiro if ((a->q_qgrp == NOAQGRP || a->q_qgrp == ENVQGRP) && 185d0cef73dSGregory Neil Shapiro !bitset(RF_SENDERADDR|RF_HEADERADDR|RF_RM_ADDR, flags) && 18640266059SGregory Neil Shapiro OpMode != MD_INITALIAS) 18740266059SGregory Neil Shapiro { 18840266059SGregory Neil Shapiro int r; 18940266059SGregory Neil Shapiro 19040266059SGregory Neil Shapiro /* call ruleset which should return a queue group name */ 19140266059SGregory Neil Shapiro r = rscap(RS_QUEUEGROUP, a->q_user, NULL, e, &pvp, pvpbuf, 19240266059SGregory Neil Shapiro sizeof(pvpbuf)); 19340266059SGregory Neil Shapiro if (r == EX_OK && 19440266059SGregory Neil Shapiro pvp != NULL && pvp[0] != NULL && 19540266059SGregory Neil Shapiro (pvp[0][0] & 0377) == CANONNET && 19640266059SGregory Neil Shapiro pvp[1] != NULL && pvp[1][0] != '\0') 19740266059SGregory Neil Shapiro { 19840266059SGregory Neil Shapiro r = name2qid(pvp[1]); 19940266059SGregory Neil Shapiro if (r == NOQGRP && LogLevel > 10) 20040266059SGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID, 20140266059SGregory Neil Shapiro "can't find queue group name %s, selection ignored", 20240266059SGregory Neil Shapiro pvp[1]); 20340266059SGregory Neil Shapiro if (tTd(20, 4) && r != NOQGRP) 20440266059SGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID, 20540266059SGregory Neil Shapiro "queue group name %s -> %d", 20640266059SGregory Neil Shapiro pvp[1], r); 20740266059SGregory Neil Shapiro a->q_qgrp = r == NOQGRP ? ENVQGRP : r; 20840266059SGregory Neil Shapiro } 20940266059SGregory Neil Shapiro } 21040266059SGregory Neil Shapiro 21140266059SGregory Neil Shapiro /* 212c2aa98e2SPeter Wemm ** If there was a parsing failure, mark it for queueing. 213c2aa98e2SPeter Wemm */ 214c2aa98e2SPeter Wemm 21506f25ae9SGregory Neil Shapiro if (qup && OpMode != MD_INITALIAS) 216c2aa98e2SPeter Wemm { 217c2aa98e2SPeter Wemm char *msg = "Transient parse error -- message queued for future delivery"; 218c2aa98e2SPeter Wemm 219c2aa98e2SPeter Wemm if (e->e_sendmode == SM_DEFER) 220c2aa98e2SPeter Wemm msg = "Deferring message until queue run"; 221c2aa98e2SPeter Wemm if (tTd(20, 1)) 222ffb83623SGregory Neil Shapiro sm_dprintf("parseaddr: queueing message\n"); 223*5b0945b5SGregory Neil Shapiro message("%s", msg); 224c2aa98e2SPeter Wemm if (e->e_message == NULL && e->e_sendmode != SM_DEFER) 22540266059SGregory Neil Shapiro e->e_message = sm_rpool_strdup_x(e->e_rpool, msg); 22606f25ae9SGregory Neil Shapiro a->q_state = QS_QUEUEUP; 227c2aa98e2SPeter Wemm a->q_status = "4.4.3"; 228c2aa98e2SPeter Wemm } 229c2aa98e2SPeter Wemm 230c2aa98e2SPeter Wemm /* 231c2aa98e2SPeter Wemm ** Compute return value. 232c2aa98e2SPeter Wemm */ 233c2aa98e2SPeter Wemm 234c2aa98e2SPeter Wemm if (tTd(20, 1)) 235c2aa98e2SPeter Wemm { 23640266059SGregory Neil Shapiro sm_dprintf("parseaddr-->"); 237e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), a, false); 238c2aa98e2SPeter Wemm } 239c2aa98e2SPeter Wemm 24006f25ae9SGregory Neil Shapiro return a; 241c2aa98e2SPeter Wemm } 24240266059SGregory Neil Shapiro /* 24340266059SGregory Neil Shapiro ** INVALIDADDR -- check for address containing characters used for macros 244c2aa98e2SPeter Wemm ** 245c2aa98e2SPeter Wemm ** Parameters: 246c2aa98e2SPeter Wemm ** addr -- the address to check. 247ba00ec3dSGregory Neil Shapiro ** note: this is the complete address (including display part) 24840266059SGregory Neil Shapiro ** delimptr -- if non-NULL: end of address to check, i.e., 24940266059SGregory Neil Shapiro ** a pointer in the address string. 25040266059SGregory Neil Shapiro ** isrcpt -- true iff the address is for a recipient. 251c2aa98e2SPeter Wemm ** 252c2aa98e2SPeter Wemm ** Returns: 25340266059SGregory Neil Shapiro ** true -- if the address has characters that are reservered 25440266059SGregory Neil Shapiro ** for macros or is too long. 25540266059SGregory Neil Shapiro ** false -- otherwise. 256c2aa98e2SPeter Wemm */ 257c2aa98e2SPeter Wemm 258c2aa98e2SPeter Wemm bool 25940266059SGregory Neil Shapiro invalidaddr(addr, delimptr, isrcpt) 260c2aa98e2SPeter Wemm register char *addr; 261c2aa98e2SPeter Wemm char *delimptr; 26240266059SGregory Neil Shapiro bool isrcpt; 263c2aa98e2SPeter Wemm { 26440266059SGregory Neil Shapiro bool result = false; 265c2aa98e2SPeter Wemm char savedelim = '\0'; 266605302a5SGregory Neil Shapiro char *b = addr; 26740266059SGregory Neil Shapiro int len = 0; 268c2aa98e2SPeter Wemm 269c2aa98e2SPeter Wemm if (delimptr != NULL) 270c2aa98e2SPeter Wemm { 27140266059SGregory Neil Shapiro /* delimptr points to the end of the address to test */ 272c2aa98e2SPeter Wemm savedelim = *delimptr; 27340266059SGregory Neil Shapiro if (savedelim != '\0') /* if that isn't '\0' already: */ 27440266059SGregory Neil Shapiro *delimptr = '\0'; /* set it */ 275c2aa98e2SPeter Wemm } 276c2aa98e2SPeter Wemm for (; *addr != '\0'; addr++) 277c2aa98e2SPeter Wemm { 278*5b0945b5SGregory Neil Shapiro #if !_FFR_EAI 279d0cef73dSGregory Neil Shapiro if (!EightBitAddrOK && (*addr & 0340) == 0200) 28040266059SGregory Neil Shapiro { 28140266059SGregory Neil Shapiro setstat(EX_USAGE); 28240266059SGregory Neil Shapiro result = true; 283605302a5SGregory Neil Shapiro *addr = BAD_CHAR_REPLACEMENT; 284c2aa98e2SPeter Wemm } 285*5b0945b5SGregory Neil Shapiro #endif 28640266059SGregory Neil Shapiro if (++len > MAXNAME - 1) 287c2aa98e2SPeter Wemm { 288605302a5SGregory Neil Shapiro char saved = *addr; 289605302a5SGregory Neil Shapiro 290605302a5SGregory Neil Shapiro *addr = '\0'; 291605302a5SGregory Neil Shapiro usrerr("553 5.1.0 Address \"%s\" too long (%d bytes max)", 292605302a5SGregory Neil Shapiro b, MAXNAME - 1); 293605302a5SGregory Neil Shapiro *addr = saved; 29440266059SGregory Neil Shapiro result = true; 29540266059SGregory Neil Shapiro goto delim; 296c2aa98e2SPeter Wemm } 29740266059SGregory Neil Shapiro } 29840266059SGregory Neil Shapiro if (result) 29940266059SGregory Neil Shapiro { 30040266059SGregory Neil Shapiro if (isrcpt) 301605302a5SGregory Neil Shapiro usrerr("501 5.1.3 8-bit character in mailbox address \"%s\"", 302605302a5SGregory Neil Shapiro b); 30340266059SGregory Neil Shapiro else 304605302a5SGregory Neil Shapiro usrerr("501 5.1.7 8-bit character in mailbox address \"%s\"", 305605302a5SGregory Neil Shapiro b); 30640266059SGregory Neil Shapiro } 30740266059SGregory Neil Shapiro delim: 30840266059SGregory Neil Shapiro if (delimptr != NULL && savedelim != '\0') 30940266059SGregory Neil Shapiro *delimptr = savedelim; /* restore old character at delimptr */ 31040266059SGregory Neil Shapiro return result; 31140266059SGregory Neil Shapiro } 31240266059SGregory Neil Shapiro /* 31340266059SGregory Neil Shapiro ** HASCTRLCHAR -- check for address containing meta-characters 31440266059SGregory Neil Shapiro ** 31540266059SGregory Neil Shapiro ** Checks that the address contains no meta-characters, and contains 31640266059SGregory Neil Shapiro ** no "non-printable" characters unless they are quoted or escaped. 31740266059SGregory Neil Shapiro ** Quoted or escaped characters are literals. 31840266059SGregory Neil Shapiro ** 31940266059SGregory Neil Shapiro ** Parameters: 32040266059SGregory Neil Shapiro ** addr -- the address to check. 32140266059SGregory Neil Shapiro ** isrcpt -- true if the address is for a recipient; false 32240266059SGregory Neil Shapiro ** indicates a from. 323605302a5SGregory Neil Shapiro ** complain -- true if an error should issued if the address 324605302a5SGregory Neil Shapiro ** is invalid and should be "repaired". 32540266059SGregory Neil Shapiro ** 32640266059SGregory Neil Shapiro ** Returns: 3276f9c8e5bSGregory Neil Shapiro ** true -- if the address has any "weird" characters or 32840266059SGregory Neil Shapiro ** non-printable characters or if a quote is unbalanced. 32940266059SGregory Neil Shapiro ** false -- otherwise. 33040266059SGregory Neil Shapiro */ 33140266059SGregory Neil Shapiro 33240266059SGregory Neil Shapiro static bool 333605302a5SGregory Neil Shapiro hasctrlchar(addr, isrcpt, complain) 33440266059SGregory Neil Shapiro register char *addr; 335605302a5SGregory Neil Shapiro bool isrcpt, complain; 33640266059SGregory Neil Shapiro { 33740266059SGregory Neil Shapiro bool quoted = false; 338605302a5SGregory Neil Shapiro int len = 0; 339605302a5SGregory Neil Shapiro char *result = NULL; 340605302a5SGregory Neil Shapiro char *b = addr; 34140266059SGregory Neil Shapiro 34240266059SGregory Neil Shapiro if (addr == NULL) 34340266059SGregory Neil Shapiro return false; 34440266059SGregory Neil Shapiro for (; *addr != '\0'; addr++) 34540266059SGregory Neil Shapiro { 346605302a5SGregory Neil Shapiro if (++len > MAXNAME - 1) 347605302a5SGregory Neil Shapiro { 348605302a5SGregory Neil Shapiro if (complain) 349605302a5SGregory Neil Shapiro { 350605302a5SGregory Neil Shapiro (void) shorten_rfc822_string(b, MAXNAME - 1); 351605302a5SGregory Neil Shapiro usrerr("553 5.1.0 Address \"%s\" too long (%d bytes max)", 352605302a5SGregory Neil Shapiro b, MAXNAME - 1); 353605302a5SGregory Neil Shapiro return true; 354605302a5SGregory Neil Shapiro } 355605302a5SGregory Neil Shapiro result = "too long"; 356605302a5SGregory Neil Shapiro } 357*5b0945b5SGregory Neil Shapiro if (!quoted && ((unsigned char)*addr < 32 || *addr == 127)) 35840266059SGregory Neil Shapiro { 359605302a5SGregory Neil Shapiro result = "non-printable character"; 360605302a5SGregory Neil Shapiro *addr = BAD_CHAR_REPLACEMENT; 361605302a5SGregory Neil Shapiro continue; 36240266059SGregory Neil Shapiro } 36340266059SGregory Neil Shapiro if (*addr == '"') 36440266059SGregory Neil Shapiro quoted = !quoted; 36540266059SGregory Neil Shapiro else if (*addr == '\\') 36640266059SGregory Neil Shapiro { 36740266059SGregory Neil Shapiro /* XXX Generic problem: no '\0' in strings. */ 36840266059SGregory Neil Shapiro if (*++addr == '\0') 36940266059SGregory Neil Shapiro { 370605302a5SGregory Neil Shapiro result = "trailing \\ character"; 371605302a5SGregory Neil Shapiro *--addr = BAD_CHAR_REPLACEMENT; 37240266059SGregory Neil Shapiro break; 37340266059SGregory Neil Shapiro } 37440266059SGregory Neil Shapiro } 375*5b0945b5SGregory Neil Shapiro #if !_FFR_EAI 376d0cef73dSGregory Neil Shapiro if (!EightBitAddrOK && (*addr & 0340) == 0200) 37740266059SGregory Neil Shapiro { 378c2aa98e2SPeter Wemm setstat(EX_USAGE); 379605302a5SGregory Neil Shapiro result = "8-bit character"; 380605302a5SGregory Neil Shapiro *addr = BAD_CHAR_REPLACEMENT; 381605302a5SGregory Neil Shapiro continue; 38240266059SGregory Neil Shapiro } 383*5b0945b5SGregory Neil Shapiro #endif 38440266059SGregory Neil Shapiro } 38540266059SGregory Neil Shapiro if (quoted) 386605302a5SGregory Neil Shapiro result = "unbalanced quote"; /* unbalanced quote */ 387605302a5SGregory Neil Shapiro if (result != NULL && complain) 38840266059SGregory Neil Shapiro { 38940266059SGregory Neil Shapiro if (isrcpt) 390605302a5SGregory Neil Shapiro usrerr("501 5.1.3 Syntax error in mailbox address \"%s\" (%s)", 391605302a5SGregory Neil Shapiro b, result); 39240266059SGregory Neil Shapiro else 393605302a5SGregory Neil Shapiro usrerr("501 5.1.7 Syntax error in mailbox address \"%s\" (%s)", 394605302a5SGregory Neil Shapiro b, result); 39540266059SGregory Neil Shapiro } 396605302a5SGregory Neil Shapiro return result != NULL; 39740266059SGregory Neil Shapiro } 39840266059SGregory Neil Shapiro /* 399c2aa98e2SPeter Wemm ** ALLOCADDR -- do local allocations of address on demand. 400c2aa98e2SPeter Wemm ** 401c2aa98e2SPeter Wemm ** Also lowercases the host name if requested. 402c2aa98e2SPeter Wemm ** 403c2aa98e2SPeter Wemm ** Parameters: 404c2aa98e2SPeter Wemm ** a -- the address to reallocate. 405c2aa98e2SPeter Wemm ** flags -- the copy flag (see RF_ definitions in sendmail.h 406c2aa98e2SPeter Wemm ** for a description). 407c2aa98e2SPeter Wemm ** paddr -- the printname of the address. 40840266059SGregory Neil Shapiro ** e -- envelope 409c2aa98e2SPeter Wemm ** 410c2aa98e2SPeter Wemm ** Returns: 411c2aa98e2SPeter Wemm ** none. 412c2aa98e2SPeter Wemm ** 413c2aa98e2SPeter Wemm ** Side Effects: 414c2aa98e2SPeter Wemm ** Copies portions of a into local buffers as requested. 415c2aa98e2SPeter Wemm */ 416c2aa98e2SPeter Wemm 41706f25ae9SGregory Neil Shapiro static void 41840266059SGregory Neil Shapiro allocaddr(a, flags, paddr, e) 419c2aa98e2SPeter Wemm register ADDRESS *a; 420c2aa98e2SPeter Wemm int flags; 421c2aa98e2SPeter Wemm char *paddr; 42240266059SGregory Neil Shapiro ENVELOPE *e; 423c2aa98e2SPeter Wemm { 424c2aa98e2SPeter Wemm if (tTd(24, 4)) 425*5b0945b5SGregory Neil Shapiro sm_dprintf("allocaddr(flags=%x, paddr=%s, ad=%d)\n", flags, paddr, bitset(EF_SECURE, e->e_flags)); 426c2aa98e2SPeter Wemm 427c2aa98e2SPeter Wemm a->q_paddr = paddr; 428c2aa98e2SPeter Wemm 429c2aa98e2SPeter Wemm if (a->q_user == NULL) 43040266059SGregory Neil Shapiro a->q_user = ""; 431c2aa98e2SPeter Wemm if (a->q_host == NULL) 43240266059SGregory Neil Shapiro a->q_host = ""; 433c2aa98e2SPeter Wemm 434*5b0945b5SGregory Neil Shapiro if (bitset(EF_SECURE, e->e_flags)) 435*5b0945b5SGregory Neil Shapiro a->q_flags |= QSECURE; 436*5b0945b5SGregory Neil Shapiro 437c2aa98e2SPeter Wemm if (bitset(RF_COPYPARSE, flags)) 438c2aa98e2SPeter Wemm { 43940266059SGregory Neil Shapiro a->q_host = sm_rpool_strdup_x(e->e_rpool, a->q_host); 440c2aa98e2SPeter Wemm if (a->q_user != a->q_paddr) 44140266059SGregory Neil Shapiro a->q_user = sm_rpool_strdup_x(e->e_rpool, a->q_user); 442c2aa98e2SPeter Wemm } 443c2aa98e2SPeter Wemm 444c2aa98e2SPeter Wemm if (a->q_paddr == NULL) 44540266059SGregory Neil Shapiro a->q_paddr = sm_rpool_strdup_x(e->e_rpool, a->q_user); 44640266059SGregory Neil Shapiro a->q_qgrp = NOAQGRP; 447c2aa98e2SPeter Wemm } 448d0cef73dSGregory Neil Shapiro 44940266059SGregory Neil Shapiro /* 450c2aa98e2SPeter Wemm ** PRESCAN -- Prescan name and make it canonical 451c2aa98e2SPeter Wemm ** 452c2aa98e2SPeter Wemm ** Scans a name and turns it into a set of tokens. This process 45306f25ae9SGregory Neil Shapiro ** deletes blanks and comments (in parentheses) (if the token type 45406f25ae9SGregory Neil Shapiro ** for left paren is SPC). 455c2aa98e2SPeter Wemm ** 456c2aa98e2SPeter Wemm ** This routine knows about quoted strings and angle brackets. 457c2aa98e2SPeter Wemm ** 458c2aa98e2SPeter Wemm ** There are certain subtleties to this routine. The one that 459c2aa98e2SPeter Wemm ** comes to mind now is that backslashes on the ends of names 460c2aa98e2SPeter Wemm ** are silently stripped off; this is intentional. The problem 461c2aa98e2SPeter Wemm ** is that some versions of sndmsg (like at LBL) set the kill 462c2aa98e2SPeter Wemm ** character to something other than @ when reading addresses; 463c2aa98e2SPeter Wemm ** so people type "csvax.eric\@berkeley" -- which screws up the 464c2aa98e2SPeter Wemm ** berknet mailer. 465c2aa98e2SPeter Wemm ** 466c2aa98e2SPeter Wemm ** Parameters: 467c2aa98e2SPeter Wemm ** addr -- the name to chomp. 468c2aa98e2SPeter Wemm ** delim -- the delimiter for the address, normally 469c2aa98e2SPeter Wemm ** '\0' or ','; \0 is accepted in any case. 470c2aa98e2SPeter Wemm ** If '\t' then we are reading the .cf file. 471c2aa98e2SPeter Wemm ** pvpbuf -- place to put the saved text -- note that 472c2aa98e2SPeter Wemm ** the pointers are static. 473c2aa98e2SPeter Wemm ** pvpbsize -- size of pvpbuf. 474c2aa98e2SPeter Wemm ** delimptr -- if non-NULL, set to the location of the 475c2aa98e2SPeter Wemm ** terminating delimiter. 476c2aa98e2SPeter Wemm ** toktab -- if set, a token table to use for parsing. 477c2aa98e2SPeter Wemm ** If NULL, use the default table. 478e92d3f3fSGregory Neil Shapiro ** ignore -- if true, ignore unbalanced addresses 479c2aa98e2SPeter Wemm ** 480c2aa98e2SPeter Wemm ** Returns: 481c2aa98e2SPeter Wemm ** A pointer to a vector of tokens. 482c2aa98e2SPeter Wemm ** NULL on error. 483c2aa98e2SPeter Wemm */ 484c2aa98e2SPeter Wemm 485c2aa98e2SPeter Wemm /* states and character types */ 486c2aa98e2SPeter Wemm #define OPR 0 /* operator */ 487c2aa98e2SPeter Wemm #define ATM 1 /* atom */ 488c2aa98e2SPeter Wemm #define QST 2 /* in quoted string */ 489c2aa98e2SPeter Wemm #define SPC 3 /* chewing up spaces */ 490c2aa98e2SPeter Wemm #define ONE 4 /* pick up one character */ 491c2aa98e2SPeter Wemm #define ILL 5 /* illegal character */ 492c2aa98e2SPeter Wemm 493c2aa98e2SPeter Wemm #define NSTATES 6 /* number of states */ 494c2aa98e2SPeter Wemm #define TYPE 017 /* mask to select state type */ 495c2aa98e2SPeter Wemm 496c2aa98e2SPeter Wemm /* meta bits for table */ 497c2aa98e2SPeter Wemm #define M 020 /* meta character; don't pass through */ 498c2aa98e2SPeter Wemm #define B 040 /* cause a break */ 499c2aa98e2SPeter Wemm #define MB M|B /* meta-break */ 500c2aa98e2SPeter Wemm 501c2aa98e2SPeter Wemm static short StateTab[NSTATES][NSTATES] = 502c2aa98e2SPeter Wemm { 503c2aa98e2SPeter Wemm /* oldst chtype> OPR ATM QST SPC ONE ILL */ 504c2aa98e2SPeter Wemm /*OPR*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|MB }, 505c2aa98e2SPeter Wemm /*ATM*/ { OPR|B, ATM, QST|B, SPC|MB, ONE|B, ILL|MB }, 506c2aa98e2SPeter Wemm /*QST*/ { QST, QST, OPR, QST, QST, QST }, 507c2aa98e2SPeter Wemm /*SPC*/ { OPR, ATM, QST, SPC|M, ONE, ILL|MB }, 508c2aa98e2SPeter Wemm /*ONE*/ { OPR, OPR, OPR, OPR, OPR, ILL|MB }, 509d0cef73dSGregory Neil Shapiro /*ILL*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|M } 510c2aa98e2SPeter Wemm }; 511c2aa98e2SPeter Wemm 512d0cef73dSGregory Neil Shapiro /* these all get modified with the OperatorChars */ 513d0cef73dSGregory Neil Shapiro 514d0cef73dSGregory Neil Shapiro /* token type table for external strings */ 515d0cef73dSGregory Neil Shapiro unsigned char ExtTokenTab[256] = 516d0cef73dSGregory Neil Shapiro { 517d0cef73dSGregory Neil Shapiro /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 518d0cef73dSGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM, 519d0cef73dSGregory Neil Shapiro /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 520d0cef73dSGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 521d0cef73dSGregory Neil Shapiro /* sp ! " # $ % & ' ( ) * + , - . / */ 522d0cef73dSGregory Neil Shapiro SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, SPC,SPC,ATM,ATM,ATM,ATM,ATM,ATM, 523d0cef73dSGregory Neil Shapiro /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 524d0cef73dSGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 525d0cef73dSGregory Neil Shapiro /* @ A B C D E F G H I J K L M N O */ 526d0cef73dSGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 527d0cef73dSGregory Neil Shapiro /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 528d0cef73dSGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 529d0cef73dSGregory Neil Shapiro /* ` a b c d e f g h i j k l m n o */ 530d0cef73dSGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 531d0cef73dSGregory Neil Shapiro /* p q r s t u v w x y z { | } ~ del */ 532d0cef73dSGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 533d0cef73dSGregory Neil Shapiro 534d0cef73dSGregory Neil Shapiro /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 535d0cef73dSGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 536d0cef73dSGregory Neil Shapiro /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 537d0cef73dSGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 538d0cef73dSGregory Neil Shapiro /* sp ! " # $ % & ' ( ) * + , - . / */ 539d0cef73dSGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 540d0cef73dSGregory Neil Shapiro /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 541d0cef73dSGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 542d0cef73dSGregory Neil Shapiro /* @ A B C D E F G H I J K L M N O */ 543d0cef73dSGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 544d0cef73dSGregory Neil Shapiro /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 545d0cef73dSGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 546d0cef73dSGregory Neil Shapiro /* ` a b c d e f g h i j k l m n o */ 547d0cef73dSGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 548d0cef73dSGregory Neil Shapiro /* p q r s t u v w x y z { | } ~ del */ 549d0cef73dSGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM 550d0cef73dSGregory Neil Shapiro }; 551d0cef73dSGregory Neil Shapiro 552d0cef73dSGregory Neil Shapiro /* token type table for internal strings */ 553d0cef73dSGregory Neil Shapiro unsigned char IntTokenTab[256] = 554c2aa98e2SPeter Wemm { 555c2aa98e2SPeter Wemm /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 556c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM, 557c2aa98e2SPeter Wemm /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 558c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 559c2aa98e2SPeter Wemm /* sp ! " # $ % & ' ( ) * + , - . / */ 56006f25ae9SGregory Neil Shapiro SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, SPC,SPC,ATM,ATM,ATM,ATM,ATM,ATM, 561c2aa98e2SPeter Wemm /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 562c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 563c2aa98e2SPeter Wemm /* @ A B C D E F G H I J K L M N O */ 564c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 565c2aa98e2SPeter Wemm /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 566c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 567c2aa98e2SPeter Wemm /* ` a b c d e f g h i j k l m n o */ 568c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 569c2aa98e2SPeter Wemm /* p q r s t u v w x y z { | } ~ del */ 570c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 571c2aa98e2SPeter Wemm 572c2aa98e2SPeter Wemm /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 573c2aa98e2SPeter Wemm OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 574c2aa98e2SPeter Wemm /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 575c2aa98e2SPeter Wemm OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 576c2aa98e2SPeter Wemm /* sp ! " # $ % & ' ( ) * + , - . / */ 577c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 578c2aa98e2SPeter Wemm /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 579c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 580c2aa98e2SPeter Wemm /* @ A B C D E F G H I J K L M N O */ 581c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 582c2aa98e2SPeter Wemm /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 583c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 584c2aa98e2SPeter Wemm /* ` a b c d e f g h i j k l m n o */ 585c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 586c2aa98e2SPeter Wemm /* p q r s t u v w x y z { | } ~ del */ 587d0cef73dSGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ONE 588c2aa98e2SPeter Wemm }; 589c2aa98e2SPeter Wemm 590c2aa98e2SPeter Wemm /* token type table for MIME parsing */ 59140266059SGregory Neil Shapiro unsigned char MimeTokenTab[256] = 592c2aa98e2SPeter Wemm { 593c2aa98e2SPeter Wemm /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 594c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,SPC,SPC,SPC,SPC,SPC,ILL,ILL, 595c2aa98e2SPeter Wemm /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 596c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 597c2aa98e2SPeter Wemm /* sp ! " # $ % & ' ( ) * + , - . / */ 59806f25ae9SGregory Neil Shapiro SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, SPC,SPC,ATM,ATM,OPR,ATM,ATM,OPR, 599c2aa98e2SPeter Wemm /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 600c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,OPR,OPR,OPR,OPR,OPR,OPR, 601c2aa98e2SPeter Wemm /* @ A B C D E F G H I J K L M N O */ 602c2aa98e2SPeter Wemm OPR,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 603c2aa98e2SPeter Wemm /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 604c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,OPR,OPR,OPR,ATM,ATM, 605c2aa98e2SPeter Wemm /* ` a b c d e f g h i j k l m n o */ 606c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 607c2aa98e2SPeter Wemm /* p q r s t u v w x y z { | } ~ del */ 608c2aa98e2SPeter Wemm ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 609c2aa98e2SPeter Wemm 610c2aa98e2SPeter Wemm /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 611c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 612c2aa98e2SPeter Wemm /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 613c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 614c2aa98e2SPeter Wemm /* sp ! " # $ % & ' ( ) * + , - . / */ 615c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 616c2aa98e2SPeter Wemm /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 617c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 618c2aa98e2SPeter Wemm /* @ A B C D E F G H I J K L M N O */ 619c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 620c2aa98e2SPeter Wemm /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 621c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 622c2aa98e2SPeter Wemm /* ` a b c d e f g h i j k l m n o */ 623c2aa98e2SPeter Wemm ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, 624c2aa98e2SPeter Wemm /* p q r s t u v w x y z { | } ~ del */ 625d0cef73dSGregory Neil Shapiro ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ONE 626c2aa98e2SPeter Wemm }; 627c2aa98e2SPeter Wemm 62806f25ae9SGregory Neil Shapiro /* token type table: don't strip comments */ 62940266059SGregory Neil Shapiro unsigned char TokTypeNoC[256] = 63006f25ae9SGregory Neil Shapiro { 63106f25ae9SGregory Neil Shapiro /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 63206f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM, 63306f25ae9SGregory Neil Shapiro /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 63406f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 63506f25ae9SGregory Neil Shapiro /* sp ! " # $ % & ' ( ) * + , - . / */ 63606f25ae9SGregory Neil Shapiro SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, OPR,OPR,ATM,ATM,ATM,ATM,ATM,ATM, 63706f25ae9SGregory Neil Shapiro /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 63806f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 63906f25ae9SGregory Neil Shapiro /* @ A B C D E F G H I J K L M N O */ 64006f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 64106f25ae9SGregory Neil Shapiro /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 64206f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 64306f25ae9SGregory Neil Shapiro /* ` a b c d e f g h i j k l m n o */ 64406f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 64506f25ae9SGregory Neil Shapiro /* p q r s t u v w x y z { | } ~ del */ 64606f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 64706f25ae9SGregory Neil Shapiro 64806f25ae9SGregory Neil Shapiro /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */ 64906f25ae9SGregory Neil Shapiro OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 65006f25ae9SGregory Neil Shapiro /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */ 65106f25ae9SGregory Neil Shapiro OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR, 65206f25ae9SGregory Neil Shapiro /* sp ! " # $ % & ' ( ) * + , - . / */ 65306f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 65406f25ae9SGregory Neil Shapiro /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 65506f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 65606f25ae9SGregory Neil Shapiro /* @ A B C D E F G H I J K L M N O */ 65706f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 65806f25ae9SGregory Neil Shapiro /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 65906f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 66006f25ae9SGregory Neil Shapiro /* ` a b c d e f g h i j k l m n o */ 66106f25ae9SGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, 66206f25ae9SGregory Neil Shapiro /* p q r s t u v w x y z { | } ~ del */ 663d0cef73dSGregory Neil Shapiro ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ONE 66406f25ae9SGregory Neil Shapiro }; 66506f25ae9SGregory Neil Shapiro 666c2aa98e2SPeter Wemm 6675ef517c0SGregory Neil Shapiro #define NOCHAR (-1) /* signal nothing in lookahead token */ 668c2aa98e2SPeter Wemm 669c2aa98e2SPeter Wemm char ** 670e92d3f3fSGregory Neil Shapiro prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab, ignore) 671c2aa98e2SPeter Wemm char *addr; 672c2aa98e2SPeter Wemm int delim; 673c2aa98e2SPeter Wemm char pvpbuf[]; 674c2aa98e2SPeter Wemm int pvpbsize; 675c2aa98e2SPeter Wemm char **delimptr; 67640266059SGregory Neil Shapiro unsigned char *toktab; 677e92d3f3fSGregory Neil Shapiro bool ignore; 678c2aa98e2SPeter Wemm { 679c2aa98e2SPeter Wemm register char *p; 680c2aa98e2SPeter Wemm register char *q; 681c2aa98e2SPeter Wemm register int c; 682c2aa98e2SPeter Wemm char **avp; 683c2aa98e2SPeter Wemm bool bslashmode; 684c2aa98e2SPeter Wemm bool route_syntax; 685c2aa98e2SPeter Wemm int cmntcnt; 686c2aa98e2SPeter Wemm int anglecnt; 687c2aa98e2SPeter Wemm char *tok; 688c2aa98e2SPeter Wemm int state; 689c2aa98e2SPeter Wemm int newstate; 690c2aa98e2SPeter Wemm char *saveto = CurEnv->e_to; 691c2aa98e2SPeter Wemm static char *av[MAXATOM + 1]; 69240266059SGregory Neil Shapiro static bool firsttime = true; 693c2aa98e2SPeter Wemm 694c2aa98e2SPeter Wemm if (firsttime) 695c2aa98e2SPeter Wemm { 696c2aa98e2SPeter Wemm /* initialize the token type table */ 697c2aa98e2SPeter Wemm char obuf[50]; 698c2aa98e2SPeter Wemm 69940266059SGregory Neil Shapiro firsttime = false; 700c2aa98e2SPeter Wemm if (OperatorChars == NULL) 701c2aa98e2SPeter Wemm { 702c2aa98e2SPeter Wemm if (ConfigLevel < 7) 703c2aa98e2SPeter Wemm OperatorChars = macvalue('o', CurEnv); 704c2aa98e2SPeter Wemm if (OperatorChars == NULL) 705c2aa98e2SPeter Wemm OperatorChars = ".:@[]"; 706c2aa98e2SPeter Wemm } 707d0cef73dSGregory Neil Shapiro expand(OperatorChars, obuf, sizeof(obuf) - sizeof(DELIMCHARS), 70806f25ae9SGregory Neil Shapiro CurEnv); 709d0cef73dSGregory Neil Shapiro (void) sm_strlcat(obuf, DELIMCHARS, sizeof(obuf)); 710c2aa98e2SPeter Wemm for (p = obuf; *p != '\0'; p++) 711c2aa98e2SPeter Wemm { 712d0cef73dSGregory Neil Shapiro if (IntTokenTab[*p & 0xff] == ATM) 713d0cef73dSGregory Neil Shapiro IntTokenTab[*p & 0xff] = OPR; 714d0cef73dSGregory Neil Shapiro if (ExtTokenTab[*p & 0xff] == ATM) 715d0cef73dSGregory Neil Shapiro ExtTokenTab[*p & 0xff] = OPR; 71606f25ae9SGregory Neil Shapiro if (TokTypeNoC[*p & 0xff] == ATM) 71706f25ae9SGregory Neil Shapiro TokTypeNoC[*p & 0xff] = OPR; 718c2aa98e2SPeter Wemm } 719c2aa98e2SPeter Wemm } 720c2aa98e2SPeter Wemm if (toktab == NULL) 721d0cef73dSGregory Neil Shapiro toktab = ExtTokenTab; 722c2aa98e2SPeter Wemm 723c2aa98e2SPeter Wemm /* make sure error messages don't have garbage on them */ 724c2aa98e2SPeter Wemm errno = 0; 725c2aa98e2SPeter Wemm 726c2aa98e2SPeter Wemm q = pvpbuf; 72740266059SGregory Neil Shapiro bslashmode = false; 72840266059SGregory Neil Shapiro route_syntax = false; 729c2aa98e2SPeter Wemm cmntcnt = 0; 730c2aa98e2SPeter Wemm anglecnt = 0; 731c2aa98e2SPeter Wemm avp = av; 732c2aa98e2SPeter Wemm state = ATM; 733c2aa98e2SPeter Wemm c = NOCHAR; 734c2aa98e2SPeter Wemm p = addr; 735c2aa98e2SPeter Wemm CurEnv->e_to = p; 736c2aa98e2SPeter Wemm if (tTd(22, 11)) 737c2aa98e2SPeter Wemm { 73840266059SGregory Neil Shapiro sm_dprintf("prescan: "); 739e92d3f3fSGregory Neil Shapiro xputs(sm_debug_file(), p); 74040266059SGregory Neil Shapiro sm_dprintf("\n"); 741c2aa98e2SPeter Wemm } 742c2aa98e2SPeter Wemm 743c2aa98e2SPeter Wemm do 744c2aa98e2SPeter Wemm { 745c2aa98e2SPeter Wemm /* read a token */ 746c2aa98e2SPeter Wemm tok = q; 747c2aa98e2SPeter Wemm for (;;) 748c2aa98e2SPeter Wemm { 749c2aa98e2SPeter Wemm /* store away any old lookahead character */ 750c2aa98e2SPeter Wemm if (c != NOCHAR && !bslashmode) 751c2aa98e2SPeter Wemm { 752c2aa98e2SPeter Wemm /* see if there is room */ 753c2aa98e2SPeter Wemm if (q >= &pvpbuf[pvpbsize - 5]) 754c2aa98e2SPeter Wemm { 7555ef517c0SGregory Neil Shapiro addrtoolong: 75606f25ae9SGregory Neil Shapiro usrerr("553 5.1.1 Address too long"); 75740266059SGregory Neil Shapiro if (strlen(addr) > MAXNAME) 758c2aa98e2SPeter Wemm addr[MAXNAME] = '\0'; 759c2aa98e2SPeter Wemm returnnull: 760c2aa98e2SPeter Wemm if (delimptr != NULL) 76158fec675SJacques Vidrine { 76258fec675SJacques Vidrine if (p > addr) 763a7ec597cSGregory Neil Shapiro --p; 764c2aa98e2SPeter Wemm *delimptr = p; 76558fec675SJacques Vidrine } 766c2aa98e2SPeter Wemm CurEnv->e_to = saveto; 76706f25ae9SGregory Neil Shapiro return NULL; 768c2aa98e2SPeter Wemm } 769c2aa98e2SPeter Wemm 770c2aa98e2SPeter Wemm /* squirrel it away */ 7715ef517c0SGregory Neil Shapiro #if !ALLOW_255 772d0cef73dSGregory Neil Shapiro if ((char) c == (char) -1 && !tTd(82, 101) && 773d0cef73dSGregory Neil Shapiro !EightBitAddrOK) 7745ef517c0SGregory Neil Shapiro c &= 0x7f; 7755ef517c0SGregory Neil Shapiro #endif /* !ALLOW_255 */ 776c2aa98e2SPeter Wemm *q++ = c; 777c2aa98e2SPeter Wemm } 778c2aa98e2SPeter Wemm 779c2aa98e2SPeter Wemm /* read a new input character */ 7805ef517c0SGregory Neil Shapiro c = (*p++) & 0x00ff; 781c2aa98e2SPeter Wemm if (c == '\0') 782c2aa98e2SPeter Wemm { 783c2aa98e2SPeter Wemm /* diagnose and patch up bad syntax */ 784e92d3f3fSGregory Neil Shapiro if (ignore) 785e92d3f3fSGregory Neil Shapiro break; 786e92d3f3fSGregory Neil Shapiro else if (state == QST) 787c2aa98e2SPeter Wemm { 78840266059SGregory Neil Shapiro usrerr("553 Unbalanced '\"'"); 789c2aa98e2SPeter Wemm c = '"'; 790c2aa98e2SPeter Wemm } 791c2aa98e2SPeter Wemm else if (cmntcnt > 0) 792c2aa98e2SPeter Wemm { 79340266059SGregory Neil Shapiro usrerr("553 Unbalanced '('"); 794c2aa98e2SPeter Wemm c = ')'; 795c2aa98e2SPeter Wemm } 796c2aa98e2SPeter Wemm else if (anglecnt > 0) 797c2aa98e2SPeter Wemm { 798c2aa98e2SPeter Wemm c = '>'; 79940266059SGregory Neil Shapiro usrerr("553 Unbalanced '<'"); 800c2aa98e2SPeter Wemm } 801c2aa98e2SPeter Wemm else 802c2aa98e2SPeter Wemm break; 803c2aa98e2SPeter Wemm 804c2aa98e2SPeter Wemm p--; 805c2aa98e2SPeter Wemm } 806c2aa98e2SPeter Wemm else if (c == delim && cmntcnt <= 0 && state != QST) 807c2aa98e2SPeter Wemm { 808c2aa98e2SPeter Wemm if (anglecnt <= 0) 809c2aa98e2SPeter Wemm break; 810c2aa98e2SPeter Wemm 811c2aa98e2SPeter Wemm /* special case for better error management */ 812e92d3f3fSGregory Neil Shapiro if (delim == ',' && !route_syntax && !ignore) 813c2aa98e2SPeter Wemm { 81440266059SGregory Neil Shapiro usrerr("553 Unbalanced '<'"); 815c2aa98e2SPeter Wemm c = '>'; 816c2aa98e2SPeter Wemm p--; 817c2aa98e2SPeter Wemm } 818c2aa98e2SPeter Wemm } 819c2aa98e2SPeter Wemm 820c2aa98e2SPeter Wemm if (tTd(22, 101)) 82140266059SGregory Neil Shapiro sm_dprintf("c=%c, s=%d; ", c, state); 822c2aa98e2SPeter Wemm 823c2aa98e2SPeter Wemm /* chew up special characters */ 824c2aa98e2SPeter Wemm *q = '\0'; 825c2aa98e2SPeter Wemm if (bslashmode) 826c2aa98e2SPeter Wemm { 82740266059SGregory Neil Shapiro bslashmode = false; 828c2aa98e2SPeter Wemm 829c2aa98e2SPeter Wemm /* kludge \! for naive users */ 830c2aa98e2SPeter Wemm if (cmntcnt > 0) 831c2aa98e2SPeter Wemm { 832c2aa98e2SPeter Wemm c = NOCHAR; 833c2aa98e2SPeter Wemm continue; 834c2aa98e2SPeter Wemm } 835c2aa98e2SPeter Wemm else if (c != '!' || state == QST) 836c2aa98e2SPeter Wemm { 8375ef517c0SGregory Neil Shapiro /* see if there is room */ 8385ef517c0SGregory Neil Shapiro if (q >= &pvpbuf[pvpbsize - 5]) 8395ef517c0SGregory Neil Shapiro goto addrtoolong; 840c2aa98e2SPeter Wemm *q++ = '\\'; 841c2aa98e2SPeter Wemm continue; 842c2aa98e2SPeter Wemm } 843c2aa98e2SPeter Wemm } 844c2aa98e2SPeter Wemm 845c2aa98e2SPeter Wemm if (c == '\\') 846c2aa98e2SPeter Wemm { 84740266059SGregory Neil Shapiro bslashmode = true; 848c2aa98e2SPeter Wemm } 849c2aa98e2SPeter Wemm else if (state == QST) 850c2aa98e2SPeter Wemm { 85106f25ae9SGregory Neil Shapiro /* EMPTY */ 852c2aa98e2SPeter Wemm /* do nothing, just avoid next clauses */ 853c2aa98e2SPeter Wemm } 85406f25ae9SGregory Neil Shapiro else if (c == '(' && toktab['('] == SPC) 855c2aa98e2SPeter Wemm { 856c2aa98e2SPeter Wemm cmntcnt++; 857c2aa98e2SPeter Wemm c = NOCHAR; 858c2aa98e2SPeter Wemm } 85906f25ae9SGregory Neil Shapiro else if (c == ')' && toktab['('] == SPC) 860c2aa98e2SPeter Wemm { 861c2aa98e2SPeter Wemm if (cmntcnt <= 0) 862c2aa98e2SPeter Wemm { 863e92d3f3fSGregory Neil Shapiro if (!ignore) 864e92d3f3fSGregory Neil Shapiro { 86540266059SGregory Neil Shapiro usrerr("553 Unbalanced ')'"); 866c2aa98e2SPeter Wemm c = NOCHAR; 867c2aa98e2SPeter Wemm } 868e92d3f3fSGregory Neil Shapiro } 869c2aa98e2SPeter Wemm else 870c2aa98e2SPeter Wemm cmntcnt--; 871c2aa98e2SPeter Wemm } 872c2aa98e2SPeter Wemm else if (cmntcnt > 0) 87306f25ae9SGregory Neil Shapiro { 874c2aa98e2SPeter Wemm c = NOCHAR; 87506f25ae9SGregory Neil Shapiro } 876c2aa98e2SPeter Wemm else if (c == '<') 877c2aa98e2SPeter Wemm { 87806f25ae9SGregory Neil Shapiro char *ptr = p; 879c2aa98e2SPeter Wemm 880c2aa98e2SPeter Wemm anglecnt++; 881*5b0945b5SGregory Neil Shapiro while (SM_ISSPACE(*ptr)) 88206f25ae9SGregory Neil Shapiro ptr++; 88306f25ae9SGregory Neil Shapiro if (*ptr == '@') 88440266059SGregory Neil Shapiro route_syntax = true; 885c2aa98e2SPeter Wemm } 886c2aa98e2SPeter Wemm else if (c == '>') 887c2aa98e2SPeter Wemm { 888c2aa98e2SPeter Wemm if (anglecnt <= 0) 889c2aa98e2SPeter Wemm { 890e92d3f3fSGregory Neil Shapiro if (!ignore) 891e92d3f3fSGregory Neil Shapiro { 89240266059SGregory Neil Shapiro usrerr("553 Unbalanced '>'"); 893c2aa98e2SPeter Wemm c = NOCHAR; 894c2aa98e2SPeter Wemm } 895e92d3f3fSGregory Neil Shapiro } 896c2aa98e2SPeter Wemm else 897c2aa98e2SPeter Wemm anglecnt--; 89840266059SGregory Neil Shapiro route_syntax = false; 899c2aa98e2SPeter Wemm } 900*5b0945b5SGregory Neil Shapiro else if (delim == ' ' && SM_ISSPACE(c)) 901c2aa98e2SPeter Wemm c = ' '; 902c2aa98e2SPeter Wemm 903c2aa98e2SPeter Wemm if (c == NOCHAR) 904c2aa98e2SPeter Wemm continue; 905c2aa98e2SPeter Wemm 906c2aa98e2SPeter Wemm /* see if this is end of input */ 907c2aa98e2SPeter Wemm if (c == delim && anglecnt <= 0 && state != QST) 908c2aa98e2SPeter Wemm break; 909c2aa98e2SPeter Wemm 910c2aa98e2SPeter Wemm newstate = StateTab[state][toktab[c & 0xff]]; 911c2aa98e2SPeter Wemm if (tTd(22, 101)) 91240266059SGregory Neil Shapiro sm_dprintf("ns=%02o\n", newstate); 913c2aa98e2SPeter Wemm state = newstate & TYPE; 914c2aa98e2SPeter Wemm if (state == ILL) 915c2aa98e2SPeter Wemm { 916c2aa98e2SPeter Wemm if (isascii(c) && isprint(c)) 91740266059SGregory Neil Shapiro usrerr("553 Illegal character %c", c); 918c2aa98e2SPeter Wemm else 91940266059SGregory Neil Shapiro usrerr("553 Illegal character 0x%02x", 92040266059SGregory Neil Shapiro c & 0x0ff); 921c2aa98e2SPeter Wemm } 922c2aa98e2SPeter Wemm if (bitset(M, newstate)) 923c2aa98e2SPeter Wemm c = NOCHAR; 924c2aa98e2SPeter Wemm if (bitset(B, newstate)) 925c2aa98e2SPeter Wemm break; 926c2aa98e2SPeter Wemm } 927c2aa98e2SPeter Wemm 928c2aa98e2SPeter Wemm /* new token */ 929c2aa98e2SPeter Wemm if (tok != q) 930c2aa98e2SPeter Wemm { 9315ef517c0SGregory Neil Shapiro /* see if there is room */ 9325ef517c0SGregory Neil Shapiro if (q >= &pvpbuf[pvpbsize - 5]) 9335ef517c0SGregory Neil Shapiro goto addrtoolong; 934c2aa98e2SPeter Wemm *q++ = '\0'; 935c2aa98e2SPeter Wemm if (tTd(22, 36)) 936c2aa98e2SPeter Wemm { 93740266059SGregory Neil Shapiro sm_dprintf("tok="); 938e92d3f3fSGregory Neil Shapiro xputs(sm_debug_file(), tok); 93940266059SGregory Neil Shapiro sm_dprintf("\n"); 940c2aa98e2SPeter Wemm } 941c2aa98e2SPeter Wemm if (avp >= &av[MAXATOM]) 942c2aa98e2SPeter Wemm { 94306f25ae9SGregory Neil Shapiro usrerr("553 5.1.0 prescan: too many tokens"); 944c2aa98e2SPeter Wemm goto returnnull; 945c2aa98e2SPeter Wemm } 946c2aa98e2SPeter Wemm if (q - tok > MAXNAME) 947c2aa98e2SPeter Wemm { 94806f25ae9SGregory Neil Shapiro usrerr("553 5.1.0 prescan: token too long"); 949c2aa98e2SPeter Wemm goto returnnull; 950c2aa98e2SPeter Wemm } 951c2aa98e2SPeter Wemm *avp++ = tok; 952c2aa98e2SPeter Wemm } 953c2aa98e2SPeter Wemm } while (c != '\0' && (c != delim || anglecnt > 0)); 954c2aa98e2SPeter Wemm *avp = NULL; 955c2aa98e2SPeter Wemm if (delimptr != NULL) 956a7ec597cSGregory Neil Shapiro { 957a7ec597cSGregory Neil Shapiro if (p > addr) 958a7ec597cSGregory Neil Shapiro p--; 959c2aa98e2SPeter Wemm *delimptr = p; 960a7ec597cSGregory Neil Shapiro } 961c2aa98e2SPeter Wemm if (tTd(22, 12)) 962c2aa98e2SPeter Wemm { 96340266059SGregory Neil Shapiro sm_dprintf("prescan==>"); 964e92d3f3fSGregory Neil Shapiro printav(sm_debug_file(), av); 965c2aa98e2SPeter Wemm } 966c2aa98e2SPeter Wemm CurEnv->e_to = saveto; 967c2aa98e2SPeter Wemm if (av[0] == NULL) 968c2aa98e2SPeter Wemm { 969c2aa98e2SPeter Wemm if (tTd(22, 1)) 97040266059SGregory Neil Shapiro sm_dprintf("prescan: null leading token\n"); 97106f25ae9SGregory Neil Shapiro return NULL; 972c2aa98e2SPeter Wemm } 97306f25ae9SGregory Neil Shapiro return av; 974c2aa98e2SPeter Wemm } 97540266059SGregory Neil Shapiro /* 976c2aa98e2SPeter Wemm ** REWRITE -- apply rewrite rules to token vector. 977c2aa98e2SPeter Wemm ** 978c2aa98e2SPeter Wemm ** This routine is an ordered production system. Each rewrite 979c2aa98e2SPeter Wemm ** rule has a LHS (called the pattern) and a RHS (called the 980c2aa98e2SPeter Wemm ** rewrite); 'rwr' points the the current rewrite rule. 981c2aa98e2SPeter Wemm ** 982c2aa98e2SPeter Wemm ** For each rewrite rule, 'avp' points the address vector we 983c2aa98e2SPeter Wemm ** are trying to match against, and 'pvp' points to the pattern. 984c2aa98e2SPeter Wemm ** If pvp points to a special match value (MATCHZANY, MATCHANY, 985c2aa98e2SPeter Wemm ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp 986c2aa98e2SPeter Wemm ** matched is saved away in the match vector (pointed to by 'mvp'). 987c2aa98e2SPeter Wemm ** 988c2aa98e2SPeter Wemm ** When a match between avp & pvp does not match, we try to 989c2aa98e2SPeter Wemm ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS 990c2aa98e2SPeter Wemm ** we must also back out the match in mvp. If we reach a 991c2aa98e2SPeter Wemm ** MATCHANY or MATCHZANY we just extend the match and start 992c2aa98e2SPeter Wemm ** over again. 993c2aa98e2SPeter Wemm ** 994c2aa98e2SPeter Wemm ** When we finally match, we rewrite the address vector 995c2aa98e2SPeter Wemm ** and try over again. 996c2aa98e2SPeter Wemm ** 997c2aa98e2SPeter Wemm ** Parameters: 998c2aa98e2SPeter Wemm ** pvp -- pointer to token vector. 999c2aa98e2SPeter Wemm ** ruleset -- the ruleset to use for rewriting. 1000c2aa98e2SPeter Wemm ** reclevel -- recursion level (to catch loops). 1001c2aa98e2SPeter Wemm ** e -- the current envelope. 100240266059SGregory Neil Shapiro ** maxatom -- maximum length of buffer (usually MAXATOM) 1003c2aa98e2SPeter Wemm ** 1004c2aa98e2SPeter Wemm ** Returns: 1005c2aa98e2SPeter Wemm ** A status code. If EX_TEMPFAIL, higher level code should 1006c2aa98e2SPeter Wemm ** attempt recovery. 1007c2aa98e2SPeter Wemm ** 1008c2aa98e2SPeter Wemm ** Side Effects: 1009c2aa98e2SPeter Wemm ** pvp is modified. 1010c2aa98e2SPeter Wemm */ 1011c2aa98e2SPeter Wemm 1012c2aa98e2SPeter Wemm struct match 1013c2aa98e2SPeter Wemm { 101406f25ae9SGregory Neil Shapiro char **match_first; /* first token matched */ 101506f25ae9SGregory Neil Shapiro char **match_last; /* last token matched */ 101606f25ae9SGregory Neil Shapiro char **match_pattern; /* pointer to pattern */ 1017c2aa98e2SPeter Wemm }; 1018c2aa98e2SPeter Wemm 1019c2aa98e2SPeter Wemm int 102040266059SGregory Neil Shapiro rewrite(pvp, ruleset, reclevel, e, maxatom) 1021c2aa98e2SPeter Wemm char **pvp; 1022c2aa98e2SPeter Wemm int ruleset; 1023c2aa98e2SPeter Wemm int reclevel; 1024c2aa98e2SPeter Wemm register ENVELOPE *e; 102540266059SGregory Neil Shapiro int maxatom; 1026c2aa98e2SPeter Wemm { 1027c2aa98e2SPeter Wemm register char *ap; /* address pointer */ 1028c2aa98e2SPeter Wemm register char *rp; /* rewrite pointer */ 102906f25ae9SGregory Neil Shapiro register char *rulename; /* ruleset name */ 103006f25ae9SGregory Neil Shapiro register char *prefix; 1031c2aa98e2SPeter Wemm register char **avp; /* address vector pointer */ 1032c2aa98e2SPeter Wemm register char **rvp; /* rewrite vector pointer */ 1033c2aa98e2SPeter Wemm register struct match *mlp; /* cur ptr into mlist */ 1034c2aa98e2SPeter Wemm register struct rewrite *rwr; /* pointer to current rewrite rule */ 1035c2aa98e2SPeter Wemm int ruleno; /* current rule number */ 1036c2aa98e2SPeter Wemm int rstat = EX_OK; /* return status */ 1037c2aa98e2SPeter Wemm int loopcount; 1038c2aa98e2SPeter Wemm struct match mlist[MAXMATCH]; /* stores match on LHS */ 1039c2aa98e2SPeter Wemm char *npvp[MAXATOM + 1]; /* temporary space for rebuild */ 1040c2aa98e2SPeter Wemm char buf[MAXLINE]; 104106f25ae9SGregory Neil Shapiro char name[6]; 1042c2aa98e2SPeter Wemm 1043a7ec597cSGregory Neil Shapiro /* 1044a7ec597cSGregory Neil Shapiro ** mlp will not exceed mlist[] because readcf enforces 1045a7ec597cSGregory Neil Shapiro ** the upper limit of entries when reading rulesets. 1046a7ec597cSGregory Neil Shapiro */ 1047a7ec597cSGregory Neil Shapiro 1048c2aa98e2SPeter Wemm if (ruleset < 0 || ruleset >= MAXRWSETS) 1049c2aa98e2SPeter Wemm { 105006f25ae9SGregory Neil Shapiro syserr("554 5.3.5 rewrite: illegal ruleset number %d", ruleset); 1051c2aa98e2SPeter Wemm return EX_CONFIG; 1052c2aa98e2SPeter Wemm } 105306f25ae9SGregory Neil Shapiro rulename = RuleSetNames[ruleset]; 105406f25ae9SGregory Neil Shapiro if (rulename == NULL) 105506f25ae9SGregory Neil Shapiro { 1056d0cef73dSGregory Neil Shapiro (void) sm_snprintf(name, sizeof(name), "%d", ruleset); 105706f25ae9SGregory Neil Shapiro rulename = name; 105806f25ae9SGregory Neil Shapiro } 105906f25ae9SGregory Neil Shapiro if (OpMode == MD_TEST) 106006f25ae9SGregory Neil Shapiro prefix = ""; 106106f25ae9SGregory Neil Shapiro else 106206f25ae9SGregory Neil Shapiro prefix = "rewrite: ruleset "; 106306f25ae9SGregory Neil Shapiro if (OpMode == MD_TEST) 106406f25ae9SGregory Neil Shapiro { 106540266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 106640266059SGregory Neil Shapiro "%s%-16.16s input:", prefix, rulename); 1067e92d3f3fSGregory Neil Shapiro printav(smioout, pvp); 106806f25ae9SGregory Neil Shapiro } 106906f25ae9SGregory Neil Shapiro else if (tTd(21, 1)) 107006f25ae9SGregory Neil Shapiro { 107140266059SGregory Neil Shapiro sm_dprintf("%s%-16.16s input:", prefix, rulename); 1072e92d3f3fSGregory Neil Shapiro printav(sm_debug_file(), pvp); 107306f25ae9SGregory Neil Shapiro } 1074c2aa98e2SPeter Wemm if (reclevel++ > MaxRuleRecursion) 1075c2aa98e2SPeter Wemm { 107606f25ae9SGregory Neil Shapiro syserr("rewrite: excessive recursion (max %d), ruleset %s", 107706f25ae9SGregory Neil Shapiro MaxRuleRecursion, rulename); 1078c2aa98e2SPeter Wemm return EX_CONFIG; 1079c2aa98e2SPeter Wemm } 1080c2aa98e2SPeter Wemm if (pvp == NULL) 1081c2aa98e2SPeter Wemm return EX_USAGE; 1082a7ec597cSGregory Neil Shapiro if (maxatom <= 0) 1083a7ec597cSGregory Neil Shapiro return EX_USAGE; 1084c2aa98e2SPeter Wemm 1085c2aa98e2SPeter Wemm /* 1086c2aa98e2SPeter Wemm ** Run through the list of rewrite rules, applying 1087c2aa98e2SPeter Wemm ** any that match. 1088c2aa98e2SPeter Wemm */ 1089c2aa98e2SPeter Wemm 1090c2aa98e2SPeter Wemm ruleno = 1; 1091c2aa98e2SPeter Wemm loopcount = 0; 1092c2aa98e2SPeter Wemm for (rwr = RewriteRules[ruleset]; rwr != NULL; ) 1093c2aa98e2SPeter Wemm { 109406f25ae9SGregory Neil Shapiro int status; 1095c2aa98e2SPeter Wemm 1096c2aa98e2SPeter Wemm /* if already canonical, quit now */ 1097c2aa98e2SPeter Wemm if (pvp[0] != NULL && (pvp[0][0] & 0377) == CANONNET) 1098c2aa98e2SPeter Wemm break; 1099c2aa98e2SPeter Wemm 1100c2aa98e2SPeter Wemm if (tTd(21, 12)) 1101c2aa98e2SPeter Wemm { 110206f25ae9SGregory Neil Shapiro if (tTd(21, 15)) 110340266059SGregory Neil Shapiro sm_dprintf("-----trying rule (line %d):", 110406f25ae9SGregory Neil Shapiro rwr->r_line); 110506f25ae9SGregory Neil Shapiro else 110640266059SGregory Neil Shapiro sm_dprintf("-----trying rule:"); 1107e92d3f3fSGregory Neil Shapiro printav(sm_debug_file(), rwr->r_lhs); 1108c2aa98e2SPeter Wemm } 1109c2aa98e2SPeter Wemm 1110c2aa98e2SPeter Wemm /* try to match on this rule */ 1111c2aa98e2SPeter Wemm mlp = mlist; 1112c2aa98e2SPeter Wemm rvp = rwr->r_lhs; 1113c2aa98e2SPeter Wemm avp = pvp; 1114c2aa98e2SPeter Wemm if (++loopcount > 100) 1115c2aa98e2SPeter Wemm { 111606f25ae9SGregory Neil Shapiro syserr("554 5.3.5 Infinite loop in ruleset %s, rule %d", 111706f25ae9SGregory Neil Shapiro rulename, ruleno); 1118c2aa98e2SPeter Wemm if (tTd(21, 1)) 1119c2aa98e2SPeter Wemm { 112040266059SGregory Neil Shapiro sm_dprintf("workspace: "); 1121e92d3f3fSGregory Neil Shapiro printav(sm_debug_file(), pvp); 1122c2aa98e2SPeter Wemm } 1123c2aa98e2SPeter Wemm break; 1124c2aa98e2SPeter Wemm } 1125c2aa98e2SPeter Wemm 1126c2aa98e2SPeter Wemm while ((ap = *avp) != NULL || *rvp != NULL) 1127c2aa98e2SPeter Wemm { 1128c2aa98e2SPeter Wemm rp = *rvp; 1129c2aa98e2SPeter Wemm if (tTd(21, 35)) 1130c2aa98e2SPeter Wemm { 113140266059SGregory Neil Shapiro sm_dprintf("ADVANCE rp="); 1132e92d3f3fSGregory Neil Shapiro xputs(sm_debug_file(), rp); 113340266059SGregory Neil Shapiro sm_dprintf(", ap="); 1134e92d3f3fSGregory Neil Shapiro xputs(sm_debug_file(), ap); 113540266059SGregory Neil Shapiro sm_dprintf("\n"); 1136c2aa98e2SPeter Wemm } 1137c2aa98e2SPeter Wemm if (rp == NULL) 1138c2aa98e2SPeter Wemm { 1139c2aa98e2SPeter Wemm /* end-of-pattern before end-of-address */ 1140c2aa98e2SPeter Wemm goto backup; 1141c2aa98e2SPeter Wemm } 1142d0cef73dSGregory Neil Shapiro if (ap == NULL && 1143d0cef73dSGregory Neil Shapiro (rp[0] & 0377) != MATCHZANY && 1144d0cef73dSGregory Neil Shapiro (rp[0] & 0377) != MATCHZERO) 1145c2aa98e2SPeter Wemm { 1146c2aa98e2SPeter Wemm /* end-of-input with patterns left */ 1147c2aa98e2SPeter Wemm goto backup; 1148c2aa98e2SPeter Wemm } 1149c2aa98e2SPeter Wemm 1150d0cef73dSGregory Neil Shapiro switch (rp[0] & 0377) 1151c2aa98e2SPeter Wemm { 1152c2aa98e2SPeter Wemm case MATCHCLASS: 1153c2aa98e2SPeter Wemm /* match any phrase in a class */ 115406f25ae9SGregory Neil Shapiro mlp->match_pattern = rvp; 115506f25ae9SGregory Neil Shapiro mlp->match_first = avp; 1156c2aa98e2SPeter Wemm extendclass: 1157c2aa98e2SPeter Wemm ap = *avp; 1158c2aa98e2SPeter Wemm if (ap == NULL) 1159c2aa98e2SPeter Wemm goto backup; 116006f25ae9SGregory Neil Shapiro mlp->match_last = avp++; 116106f25ae9SGregory Neil Shapiro cataddr(mlp->match_first, mlp->match_last, 1162d0cef73dSGregory Neil Shapiro buf, sizeof(buf), '\0', true); 1163c2aa98e2SPeter Wemm if (!wordinclass(buf, rp[1])) 1164c2aa98e2SPeter Wemm { 1165c2aa98e2SPeter Wemm if (tTd(21, 36)) 1166c2aa98e2SPeter Wemm { 116740266059SGregory Neil Shapiro sm_dprintf("EXTEND rp="); 1168e92d3f3fSGregory Neil Shapiro xputs(sm_debug_file(), rp); 116940266059SGregory Neil Shapiro sm_dprintf(", ap="); 1170e92d3f3fSGregory Neil Shapiro xputs(sm_debug_file(), ap); 117140266059SGregory Neil Shapiro sm_dprintf("\n"); 1172c2aa98e2SPeter Wemm } 1173c2aa98e2SPeter Wemm goto extendclass; 1174c2aa98e2SPeter Wemm } 1175c2aa98e2SPeter Wemm if (tTd(21, 36)) 117640266059SGregory Neil Shapiro sm_dprintf("CLMATCH\n"); 1177c2aa98e2SPeter Wemm mlp++; 1178c2aa98e2SPeter Wemm break; 1179c2aa98e2SPeter Wemm 1180c2aa98e2SPeter Wemm case MATCHNCLASS: 1181c2aa98e2SPeter Wemm /* match any token not in a class */ 1182c2aa98e2SPeter Wemm if (wordinclass(ap, rp[1])) 1183c2aa98e2SPeter Wemm goto backup; 1184c2aa98e2SPeter Wemm 118506f25ae9SGregory Neil Shapiro /* FALLTHROUGH */ 1186c2aa98e2SPeter Wemm 1187c2aa98e2SPeter Wemm case MATCHONE: 1188c2aa98e2SPeter Wemm case MATCHANY: 1189c2aa98e2SPeter Wemm /* match exactly one token */ 119006f25ae9SGregory Neil Shapiro mlp->match_pattern = rvp; 119106f25ae9SGregory Neil Shapiro mlp->match_first = avp; 119206f25ae9SGregory Neil Shapiro mlp->match_last = avp++; 1193c2aa98e2SPeter Wemm mlp++; 1194c2aa98e2SPeter Wemm break; 1195c2aa98e2SPeter Wemm 1196c2aa98e2SPeter Wemm case MATCHZANY: 1197c2aa98e2SPeter Wemm /* match zero or more tokens */ 119806f25ae9SGregory Neil Shapiro mlp->match_pattern = rvp; 119906f25ae9SGregory Neil Shapiro mlp->match_first = avp; 120006f25ae9SGregory Neil Shapiro mlp->match_last = avp - 1; 1201c2aa98e2SPeter Wemm mlp++; 1202c2aa98e2SPeter Wemm break; 1203c2aa98e2SPeter Wemm 1204c2aa98e2SPeter Wemm case MATCHZERO: 1205c2aa98e2SPeter Wemm /* match zero tokens */ 1206c2aa98e2SPeter Wemm break; 1207c2aa98e2SPeter Wemm 1208c2aa98e2SPeter Wemm case MACRODEXPAND: 1209c2aa98e2SPeter Wemm /* 1210c2aa98e2SPeter Wemm ** Match against run-time macro. 1211c2aa98e2SPeter Wemm ** This algorithm is broken for the 1212c2aa98e2SPeter Wemm ** general case (no recursive macros, 1213c2aa98e2SPeter Wemm ** improper tokenization) but should 1214c2aa98e2SPeter Wemm ** work for the usual cases. 1215c2aa98e2SPeter Wemm */ 1216c2aa98e2SPeter Wemm 1217c2aa98e2SPeter Wemm ap = macvalue(rp[1], e); 121806f25ae9SGregory Neil Shapiro mlp->match_first = avp; 1219c2aa98e2SPeter Wemm if (tTd(21, 2)) 1220739ac4d4SGregory Neil Shapiro sm_dprintf("rewrite: LHS $&{%s} => \"%s\"\n", 1221c2aa98e2SPeter Wemm macname(rp[1]), 1222c2aa98e2SPeter Wemm ap == NULL ? "(NULL)" : ap); 1223c2aa98e2SPeter Wemm 1224c2aa98e2SPeter Wemm if (ap == NULL) 1225c2aa98e2SPeter Wemm break; 1226c2aa98e2SPeter Wemm while (*ap != '\0') 1227c2aa98e2SPeter Wemm { 1228c2aa98e2SPeter Wemm if (*avp == NULL || 122940266059SGregory Neil Shapiro sm_strncasecmp(ap, *avp, 123040266059SGregory Neil Shapiro strlen(*avp)) != 0) 1231c2aa98e2SPeter Wemm { 1232c2aa98e2SPeter Wemm /* no match */ 123306f25ae9SGregory Neil Shapiro avp = mlp->match_first; 1234c2aa98e2SPeter Wemm goto backup; 1235c2aa98e2SPeter Wemm } 1236c2aa98e2SPeter Wemm ap += strlen(*avp++); 1237c2aa98e2SPeter Wemm } 1238c2aa98e2SPeter Wemm 1239c2aa98e2SPeter Wemm /* match */ 1240c2aa98e2SPeter Wemm break; 1241c2aa98e2SPeter Wemm 1242c2aa98e2SPeter Wemm default: 1243c2aa98e2SPeter Wemm /* must have exact match */ 1244c2aa98e2SPeter Wemm if (sm_strcasecmp(rp, ap)) 1245c2aa98e2SPeter Wemm goto backup; 1246c2aa98e2SPeter Wemm avp++; 1247c2aa98e2SPeter Wemm break; 1248c2aa98e2SPeter Wemm } 1249c2aa98e2SPeter Wemm 1250c2aa98e2SPeter Wemm /* successful match on this token */ 1251c2aa98e2SPeter Wemm rvp++; 1252c2aa98e2SPeter Wemm continue; 1253c2aa98e2SPeter Wemm 1254c2aa98e2SPeter Wemm backup: 1255c2aa98e2SPeter Wemm /* match failed -- back up */ 1256c2aa98e2SPeter Wemm while (--mlp >= mlist) 1257c2aa98e2SPeter Wemm { 125806f25ae9SGregory Neil Shapiro rvp = mlp->match_pattern; 1259c2aa98e2SPeter Wemm rp = *rvp; 126006f25ae9SGregory Neil Shapiro avp = mlp->match_last + 1; 1261c2aa98e2SPeter Wemm ap = *avp; 1262c2aa98e2SPeter Wemm 1263c2aa98e2SPeter Wemm if (tTd(21, 36)) 1264c2aa98e2SPeter Wemm { 126540266059SGregory Neil Shapiro sm_dprintf("BACKUP rp="); 1266e92d3f3fSGregory Neil Shapiro xputs(sm_debug_file(), rp); 126740266059SGregory Neil Shapiro sm_dprintf(", ap="); 1268e92d3f3fSGregory Neil Shapiro xputs(sm_debug_file(), ap); 126940266059SGregory Neil Shapiro sm_dprintf("\n"); 1270c2aa98e2SPeter Wemm } 1271c2aa98e2SPeter Wemm 1272c2aa98e2SPeter Wemm if (ap == NULL) 1273c2aa98e2SPeter Wemm { 1274c2aa98e2SPeter Wemm /* run off the end -- back up again */ 1275c2aa98e2SPeter Wemm continue; 1276c2aa98e2SPeter Wemm } 1277d0cef73dSGregory Neil Shapiro 1278d0cef73dSGregory Neil Shapiro if ((rp[0] & 0377) == MATCHANY || 1279d0cef73dSGregory Neil Shapiro (rp[0] & 0377) == MATCHZANY) 1280c2aa98e2SPeter Wemm { 1281c2aa98e2SPeter Wemm /* extend binding and continue */ 128206f25ae9SGregory Neil Shapiro mlp->match_last = avp++; 1283c2aa98e2SPeter Wemm rvp++; 1284c2aa98e2SPeter Wemm mlp++; 1285c2aa98e2SPeter Wemm break; 1286c2aa98e2SPeter Wemm } 1287d0cef73dSGregory Neil Shapiro if ((rp[0] & 0377) == MATCHCLASS) 1288c2aa98e2SPeter Wemm { 1289c2aa98e2SPeter Wemm /* extend binding and try again */ 129006f25ae9SGregory Neil Shapiro mlp->match_last = avp; 1291c2aa98e2SPeter Wemm goto extendclass; 1292c2aa98e2SPeter Wemm } 1293c2aa98e2SPeter Wemm } 1294c2aa98e2SPeter Wemm 1295c2aa98e2SPeter Wemm if (mlp < mlist) 1296c2aa98e2SPeter Wemm { 1297c2aa98e2SPeter Wemm /* total failure to match */ 1298c2aa98e2SPeter Wemm break; 1299c2aa98e2SPeter Wemm } 1300c2aa98e2SPeter Wemm } 1301c2aa98e2SPeter Wemm 1302c2aa98e2SPeter Wemm /* 1303c2aa98e2SPeter Wemm ** See if we successfully matched 1304c2aa98e2SPeter Wemm */ 1305c2aa98e2SPeter Wemm 1306c2aa98e2SPeter Wemm if (mlp < mlist || *rvp != NULL) 1307c2aa98e2SPeter Wemm { 1308c2aa98e2SPeter Wemm if (tTd(21, 10)) 130940266059SGregory Neil Shapiro sm_dprintf("----- rule fails\n"); 1310c2aa98e2SPeter Wemm rwr = rwr->r_next; 1311c2aa98e2SPeter Wemm ruleno++; 1312c2aa98e2SPeter Wemm loopcount = 0; 1313c2aa98e2SPeter Wemm continue; 1314c2aa98e2SPeter Wemm } 1315c2aa98e2SPeter Wemm 1316c2aa98e2SPeter Wemm rvp = rwr->r_rhs; 1317c2aa98e2SPeter Wemm if (tTd(21, 12)) 1318c2aa98e2SPeter Wemm { 131940266059SGregory Neil Shapiro sm_dprintf("-----rule matches:"); 1320e92d3f3fSGregory Neil Shapiro printav(sm_debug_file(), rvp); 1321c2aa98e2SPeter Wemm } 1322c2aa98e2SPeter Wemm 1323c2aa98e2SPeter Wemm rp = *rvp; 132406f25ae9SGregory Neil Shapiro if (rp != NULL) 132506f25ae9SGregory Neil Shapiro { 1326d0cef73dSGregory Neil Shapiro if ((rp[0] & 0377) == CANONUSER) 1327c2aa98e2SPeter Wemm { 1328c2aa98e2SPeter Wemm rvp++; 1329c2aa98e2SPeter Wemm rwr = rwr->r_next; 1330c2aa98e2SPeter Wemm ruleno++; 1331c2aa98e2SPeter Wemm loopcount = 0; 1332c2aa98e2SPeter Wemm } 1333d0cef73dSGregory Neil Shapiro else if ((rp[0] & 0377) == CANONHOST) 1334c2aa98e2SPeter Wemm { 1335c2aa98e2SPeter Wemm rvp++; 1336c2aa98e2SPeter Wemm rwr = NULL; 1337c2aa98e2SPeter Wemm } 133806f25ae9SGregory Neil Shapiro } 1339c2aa98e2SPeter Wemm 1340c2aa98e2SPeter Wemm /* substitute */ 1341c2aa98e2SPeter Wemm for (avp = npvp; *rvp != NULL; rvp++) 1342c2aa98e2SPeter Wemm { 1343c2aa98e2SPeter Wemm register struct match *m; 1344c2aa98e2SPeter Wemm register char **pp; 1345c2aa98e2SPeter Wemm 1346c2aa98e2SPeter Wemm rp = *rvp; 1347d0cef73dSGregory Neil Shapiro if ((rp[0] & 0377) == MATCHREPL) 1348c2aa98e2SPeter Wemm { 1349c2aa98e2SPeter Wemm /* substitute from LHS */ 1350c2aa98e2SPeter Wemm m = &mlist[rp[1] - '1']; 1351c2aa98e2SPeter Wemm if (m < mlist || m >= mlp) 1352c2aa98e2SPeter Wemm { 135306f25ae9SGregory Neil Shapiro syserr("554 5.3.5 rewrite: ruleset %s: replacement $%c out of bounds", 135406f25ae9SGregory Neil Shapiro rulename, rp[1]); 1355c2aa98e2SPeter Wemm return EX_CONFIG; 1356c2aa98e2SPeter Wemm } 1357c2aa98e2SPeter Wemm if (tTd(21, 15)) 1358c2aa98e2SPeter Wemm { 135940266059SGregory Neil Shapiro sm_dprintf("$%c:", rp[1]); 136006f25ae9SGregory Neil Shapiro pp = m->match_first; 136106f25ae9SGregory Neil Shapiro while (pp <= m->match_last) 1362c2aa98e2SPeter Wemm { 1363*5b0945b5SGregory Neil Shapiro sm_dprintf(" %p=\"", (void *)*pp); 136440266059SGregory Neil Shapiro sm_dflush(); 136540266059SGregory Neil Shapiro sm_dprintf("%s\"", *pp++); 1366c2aa98e2SPeter Wemm } 136740266059SGregory Neil Shapiro sm_dprintf("\n"); 1368c2aa98e2SPeter Wemm } 136906f25ae9SGregory Neil Shapiro pp = m->match_first; 137006f25ae9SGregory Neil Shapiro while (pp <= m->match_last) 1371c2aa98e2SPeter Wemm { 137240266059SGregory Neil Shapiro if (avp >= &npvp[maxatom]) 1373a7ec597cSGregory Neil Shapiro goto toolong; 1374c2aa98e2SPeter Wemm *avp++ = *pp++; 1375c2aa98e2SPeter Wemm } 1376c2aa98e2SPeter Wemm } 1377c2aa98e2SPeter Wemm else 1378c2aa98e2SPeter Wemm { 1379c2aa98e2SPeter Wemm /* some sort of replacement */ 138040266059SGregory Neil Shapiro if (avp >= &npvp[maxatom]) 1381c2aa98e2SPeter Wemm { 1382c2aa98e2SPeter Wemm toolong: 138306f25ae9SGregory Neil Shapiro syserr("554 5.3.0 rewrite: expansion too long"); 138440266059SGregory Neil Shapiro if (LogLevel > 9) 138540266059SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 138640266059SGregory Neil Shapiro "rewrite: expansion too long, ruleset=%s, ruleno=%d", 138740266059SGregory Neil Shapiro rulename, ruleno); 1388c2aa98e2SPeter Wemm return EX_DATAERR; 1389c2aa98e2SPeter Wemm } 1390d0cef73dSGregory Neil Shapiro if ((rp[0] & 0377) != MACRODEXPAND) 1391c2aa98e2SPeter Wemm { 1392d0cef73dSGregory Neil Shapiro /* vanilla replacement from RHS */ 1393c2aa98e2SPeter Wemm *avp++ = rp; 1394c2aa98e2SPeter Wemm } 1395c2aa98e2SPeter Wemm else 1396c2aa98e2SPeter Wemm { 1397739ac4d4SGregory Neil Shapiro /* $&{x} replacement */ 1398c2aa98e2SPeter Wemm char *mval = macvalue(rp[1], e); 1399c2aa98e2SPeter Wemm char **xpvp; 14004e4196cbSGregory Neil Shapiro size_t trsize = 0; 1401c2aa98e2SPeter Wemm static size_t pvpb1_size = 0; 1402c2aa98e2SPeter Wemm static char **pvpb1 = NULL; 1403c2aa98e2SPeter Wemm char pvpbuf[PSBUFSIZE]; 1404c2aa98e2SPeter Wemm 1405c2aa98e2SPeter Wemm if (tTd(21, 2)) 1406739ac4d4SGregory Neil Shapiro sm_dprintf("rewrite: RHS $&{%s} => \"%s\"\n", 1407c2aa98e2SPeter Wemm macname(rp[1]), 1408c2aa98e2SPeter Wemm mval == NULL ? "(NULL)" : mval); 1409c2aa98e2SPeter Wemm if (mval == NULL || *mval == '\0') 1410c2aa98e2SPeter Wemm continue; 1411c2aa98e2SPeter Wemm 1412c2aa98e2SPeter Wemm /* save the remainder of the input */ 1413c2aa98e2SPeter Wemm for (xpvp = pvp; *xpvp != NULL; xpvp++) 1414d0cef73dSGregory Neil Shapiro trsize += sizeof(*xpvp); 14154e4196cbSGregory Neil Shapiro if (trsize > pvpb1_size) 1416c2aa98e2SPeter Wemm { 1417c2aa98e2SPeter Wemm if (pvpb1 != NULL) 14188774250cSGregory Neil Shapiro sm_free(pvpb1); 141940266059SGregory Neil Shapiro pvpb1 = (char **) 142040266059SGregory Neil Shapiro sm_pmalloc_x(trsize); 1421c2aa98e2SPeter Wemm pvpb1_size = trsize; 1422c2aa98e2SPeter Wemm } 1423c2aa98e2SPeter Wemm 142406f25ae9SGregory Neil Shapiro memmove((char *) pvpb1, 142506f25ae9SGregory Neil Shapiro (char *) pvp, 142606f25ae9SGregory Neil Shapiro trsize); 1427c2aa98e2SPeter Wemm 1428c2aa98e2SPeter Wemm /* scan the new replacement */ 1429c2aa98e2SPeter Wemm xpvp = prescan(mval, '\0', pvpbuf, 1430d0cef73dSGregory Neil Shapiro sizeof(pvpbuf), NULL, 1431e92d3f3fSGregory Neil Shapiro NULL, false); 1432c2aa98e2SPeter Wemm if (xpvp == NULL) 1433c2aa98e2SPeter Wemm { 1434c2aa98e2SPeter Wemm /* prescan pre-printed error */ 1435c2aa98e2SPeter Wemm return EX_DATAERR; 1436c2aa98e2SPeter Wemm } 1437c2aa98e2SPeter Wemm 1438c2aa98e2SPeter Wemm /* insert it into the output stream */ 1439c2aa98e2SPeter Wemm while (*xpvp != NULL) 1440c2aa98e2SPeter Wemm { 1441c2aa98e2SPeter Wemm if (tTd(21, 19)) 144240266059SGregory Neil Shapiro sm_dprintf(" ... %s\n", 144306f25ae9SGregory Neil Shapiro *xpvp); 144440266059SGregory Neil Shapiro *avp++ = sm_rpool_strdup_x( 144540266059SGregory Neil Shapiro e->e_rpool, *xpvp); 144640266059SGregory Neil Shapiro if (avp >= &npvp[maxatom]) 1447c2aa98e2SPeter Wemm goto toolong; 1448c2aa98e2SPeter Wemm xpvp++; 1449c2aa98e2SPeter Wemm } 1450c2aa98e2SPeter Wemm if (tTd(21, 19)) 145140266059SGregory Neil Shapiro sm_dprintf(" ... DONE\n"); 1452c2aa98e2SPeter Wemm 1453c2aa98e2SPeter Wemm /* restore the old trailing input */ 145406f25ae9SGregory Neil Shapiro memmove((char *) pvp, 145506f25ae9SGregory Neil Shapiro (char *) pvpb1, 145606f25ae9SGregory Neil Shapiro trsize); 1457c2aa98e2SPeter Wemm } 1458c2aa98e2SPeter Wemm } 1459c2aa98e2SPeter Wemm } 1460c2aa98e2SPeter Wemm *avp++ = NULL; 1461c2aa98e2SPeter Wemm 1462c2aa98e2SPeter Wemm /* 1463c2aa98e2SPeter Wemm ** Check for any hostname/keyword lookups. 1464c2aa98e2SPeter Wemm */ 1465c2aa98e2SPeter Wemm 1466c2aa98e2SPeter Wemm for (rvp = npvp; *rvp != NULL; rvp++) 1467c2aa98e2SPeter Wemm { 1468c2aa98e2SPeter Wemm char **hbrvp; 1469c2aa98e2SPeter Wemm char **xpvp; 14704e4196cbSGregory Neil Shapiro size_t trsize; 1471c2aa98e2SPeter Wemm char *replac; 1472c2aa98e2SPeter Wemm int endtoken; 1473e3793f76SGregory Neil Shapiro bool external; 1474c2aa98e2SPeter Wemm STAB *map; 1475c2aa98e2SPeter Wemm char *mapname; 1476c2aa98e2SPeter Wemm char **key_rvp; 1477c2aa98e2SPeter Wemm char **arg_rvp; 1478c2aa98e2SPeter Wemm char **default_rvp; 14794e4196cbSGregory Neil Shapiro char cbuf[MAXKEY]; 1480c2aa98e2SPeter Wemm char *pvpb1[MAXATOM + 1]; 1481a7ec597cSGregory Neil Shapiro char *argvect[MAX_MAP_ARGS]; 1482c2aa98e2SPeter Wemm char pvpbuf[PSBUFSIZE]; 1483c2aa98e2SPeter Wemm char *nullpvp[1]; 1484c2aa98e2SPeter Wemm 1485c2aa98e2SPeter Wemm hbrvp = rvp; 1486d0cef73dSGregory Neil Shapiro if ((rvp[0][0] & 0377) == HOSTBEGIN) 1487c2aa98e2SPeter Wemm { 1488c2aa98e2SPeter Wemm endtoken = HOSTEND; 1489c2aa98e2SPeter Wemm mapname = "host"; 1490c2aa98e2SPeter Wemm } 1491d0cef73dSGregory Neil Shapiro else if ((rvp[0][0] & 0377) == LOOKUPBEGIN) 1492c2aa98e2SPeter Wemm { 1493c2aa98e2SPeter Wemm endtoken = LOOKUPEND; 1494c2aa98e2SPeter Wemm mapname = *++rvp; 1495a7ec597cSGregory Neil Shapiro if (mapname == NULL) 1496af9557fdSGregory Neil Shapiro { 1497a7ec597cSGregory Neil Shapiro syserr("554 5.3.0 rewrite: missing mapname"); 1498af9557fdSGregory Neil Shapiro /* NOTREACHED */ 1499af9557fdSGregory Neil Shapiro SM_ASSERT(0); 1500af9557fdSGregory Neil Shapiro } 1501c2aa98e2SPeter Wemm } 1502d0cef73dSGregory Neil Shapiro else 1503d0cef73dSGregory Neil Shapiro continue; 1504d0cef73dSGregory Neil Shapiro 1505d0cef73dSGregory Neil Shapiro /* 1506d0cef73dSGregory Neil Shapiro ** Got a hostname/keyword lookup. 1507d0cef73dSGregory Neil Shapiro ** 1508d0cef73dSGregory Neil Shapiro ** This could be optimized fairly easily. 1509d0cef73dSGregory Neil Shapiro */ 1510d0cef73dSGregory Neil Shapiro 1511c2aa98e2SPeter Wemm map = stab(mapname, ST_MAP, ST_FIND); 1512c2aa98e2SPeter Wemm if (map == NULL) 1513a7ec597cSGregory Neil Shapiro syserr("554 5.3.0 rewrite: map %s not found", 1514a7ec597cSGregory Neil Shapiro mapname); 1515c2aa98e2SPeter Wemm 1516c2aa98e2SPeter Wemm /* extract the match part */ 1517c2aa98e2SPeter Wemm key_rvp = ++rvp; 1518a7ec597cSGregory Neil Shapiro if (key_rvp == NULL) 1519af9557fdSGregory Neil Shapiro { 1520a7ec597cSGregory Neil Shapiro syserr("554 5.3.0 rewrite: missing key for map %s", 1521a7ec597cSGregory Neil Shapiro mapname); 1522af9557fdSGregory Neil Shapiro /* NOTREACHED */ 1523af9557fdSGregory Neil Shapiro SM_ASSERT(0); 1524af9557fdSGregory Neil Shapiro } 1525c2aa98e2SPeter Wemm default_rvp = NULL; 1526c2aa98e2SPeter Wemm arg_rvp = argvect; 1527c2aa98e2SPeter Wemm xpvp = NULL; 1528c2aa98e2SPeter Wemm replac = pvpbuf; 1529d0cef73dSGregory Neil Shapiro while (*rvp != NULL && ((rvp[0][0] & 0377) != endtoken)) 1530c2aa98e2SPeter Wemm { 1531d0cef73dSGregory Neil Shapiro int nodetype = rvp[0][0] & 0377; 1532c2aa98e2SPeter Wemm 1533a7ec597cSGregory Neil Shapiro if (nodetype != CANONHOST && 1534a7ec597cSGregory Neil Shapiro nodetype != CANONUSER) 1535c2aa98e2SPeter Wemm { 1536c2aa98e2SPeter Wemm rvp++; 1537c2aa98e2SPeter Wemm continue; 1538c2aa98e2SPeter Wemm } 1539c2aa98e2SPeter Wemm 1540c2aa98e2SPeter Wemm *rvp++ = NULL; 1541c2aa98e2SPeter Wemm 1542c2aa98e2SPeter Wemm if (xpvp != NULL) 1543c2aa98e2SPeter Wemm { 1544c2aa98e2SPeter Wemm cataddr(xpvp, NULL, replac, 1545d0cef73dSGregory Neil Shapiro &pvpbuf[sizeof(pvpbuf)] - replac, 1546d0cef73dSGregory Neil Shapiro '\0', false); 1547a7ec597cSGregory Neil Shapiro if (arg_rvp < 1548a7ec597cSGregory Neil Shapiro &argvect[MAX_MAP_ARGS - 1]) 1549c2aa98e2SPeter Wemm *++arg_rvp = replac; 1550c2aa98e2SPeter Wemm replac += strlen(replac) + 1; 1551c2aa98e2SPeter Wemm xpvp = NULL; 1552c2aa98e2SPeter Wemm } 1553c2aa98e2SPeter Wemm switch (nodetype) 1554c2aa98e2SPeter Wemm { 1555c2aa98e2SPeter Wemm case CANONHOST: 1556c2aa98e2SPeter Wemm xpvp = rvp; 1557c2aa98e2SPeter Wemm break; 1558c2aa98e2SPeter Wemm 1559c2aa98e2SPeter Wemm case CANONUSER: 1560c2aa98e2SPeter Wemm default_rvp = rvp; 1561c2aa98e2SPeter Wemm break; 1562c2aa98e2SPeter Wemm } 1563c2aa98e2SPeter Wemm } 1564c2aa98e2SPeter Wemm if (*rvp != NULL) 1565c2aa98e2SPeter Wemm *rvp++ = NULL; 1566c2aa98e2SPeter Wemm if (xpvp != NULL) 1567c2aa98e2SPeter Wemm { 1568c2aa98e2SPeter Wemm cataddr(xpvp, NULL, replac, 1569d0cef73dSGregory Neil Shapiro &pvpbuf[sizeof(pvpbuf)] - replac, 1570d0cef73dSGregory Neil Shapiro '\0', false); 1571a7ec597cSGregory Neil Shapiro if (arg_rvp < &argvect[MAX_MAP_ARGS - 1]) 1572c2aa98e2SPeter Wemm *++arg_rvp = replac; 1573c2aa98e2SPeter Wemm } 1574a7ec597cSGregory Neil Shapiro if (arg_rvp >= &argvect[MAX_MAP_ARGS - 1]) 1575a7ec597cSGregory Neil Shapiro argvect[MAX_MAP_ARGS - 1] = NULL; 1576a7ec597cSGregory Neil Shapiro else 1577c2aa98e2SPeter Wemm *++arg_rvp = NULL; 1578c2aa98e2SPeter Wemm 1579c2aa98e2SPeter Wemm /* save the remainder of the input string */ 1580d0cef73dSGregory Neil Shapiro trsize = (avp - rvp + 1) * sizeof(*rvp); 158106f25ae9SGregory Neil Shapiro memmove((char *) pvpb1, (char *) rvp, trsize); 1582c2aa98e2SPeter Wemm 1583c2aa98e2SPeter Wemm /* look it up */ 1584d0cef73dSGregory Neil Shapiro cataddr(key_rvp, NULL, cbuf, sizeof(cbuf), 1585d0cef73dSGregory Neil Shapiro map == NULL ? '\0' : map->s_map.map_spacesub, 1586d0cef73dSGregory Neil Shapiro true); 158706f25ae9SGregory Neil Shapiro argvect[0] = cbuf; 158806f25ae9SGregory Neil Shapiro replac = map_lookup(map, cbuf, argvect, &rstat, e); 1589e3793f76SGregory Neil Shapiro external = replac != NULL; 1590c2aa98e2SPeter Wemm 1591c2aa98e2SPeter Wemm /* if no replacement, use default */ 1592c2aa98e2SPeter Wemm if (replac == NULL && default_rvp != NULL) 1593c2aa98e2SPeter Wemm { 1594c2aa98e2SPeter Wemm /* create the default */ 1595d0cef73dSGregory Neil Shapiro cataddr(default_rvp, NULL, cbuf, sizeof(cbuf), 1596d0cef73dSGregory Neil Shapiro '\0', false); 159706f25ae9SGregory Neil Shapiro replac = cbuf; 1598c2aa98e2SPeter Wemm } 1599c2aa98e2SPeter Wemm 1600c2aa98e2SPeter Wemm if (replac == NULL) 1601c2aa98e2SPeter Wemm { 1602c2aa98e2SPeter Wemm xpvp = key_rvp; 1603c2aa98e2SPeter Wemm } 1604c2aa98e2SPeter Wemm else if (*replac == '\0') 1605c2aa98e2SPeter Wemm { 1606c2aa98e2SPeter Wemm /* null replacement */ 1607c2aa98e2SPeter Wemm nullpvp[0] = NULL; 1608c2aa98e2SPeter Wemm xpvp = nullpvp; 1609c2aa98e2SPeter Wemm } 1610c2aa98e2SPeter Wemm else 1611c2aa98e2SPeter Wemm { 1612c2aa98e2SPeter Wemm /* scan the new replacement */ 1613c2aa98e2SPeter Wemm xpvp = prescan(replac, '\0', pvpbuf, 1614e3793f76SGregory Neil Shapiro sizeof(pvpbuf), NULL, 1615e3793f76SGregory Neil Shapiro external ? NULL : IntTokenTab, 1616d0cef73dSGregory Neil Shapiro false); 1617c2aa98e2SPeter Wemm if (xpvp == NULL) 1618c2aa98e2SPeter Wemm { 1619c2aa98e2SPeter Wemm /* prescan already printed error */ 1620c2aa98e2SPeter Wemm return EX_DATAERR; 1621c2aa98e2SPeter Wemm } 1622c2aa98e2SPeter Wemm } 1623c2aa98e2SPeter Wemm 1624c2aa98e2SPeter Wemm /* append it to the token list */ 1625c2aa98e2SPeter Wemm for (avp = hbrvp; *xpvp != NULL; xpvp++) 1626c2aa98e2SPeter Wemm { 162740266059SGregory Neil Shapiro *avp++ = sm_rpool_strdup_x(e->e_rpool, *xpvp); 162840266059SGregory Neil Shapiro if (avp >= &npvp[maxatom]) 1629c2aa98e2SPeter Wemm goto toolong; 1630c2aa98e2SPeter Wemm } 1631c2aa98e2SPeter Wemm 1632c2aa98e2SPeter Wemm /* restore the old trailing information */ 1633c2aa98e2SPeter Wemm rvp = avp - 1; 1634c2aa98e2SPeter Wemm for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; ) 163540266059SGregory Neil Shapiro if (avp >= &npvp[maxatom]) 1636c2aa98e2SPeter Wemm goto toolong; 1637c2aa98e2SPeter Wemm } 1638c2aa98e2SPeter Wemm 1639c2aa98e2SPeter Wemm /* 1640c2aa98e2SPeter Wemm ** Check for subroutine calls. 1641c2aa98e2SPeter Wemm */ 1642c2aa98e2SPeter Wemm 164306f25ae9SGregory Neil Shapiro status = callsubr(npvp, reclevel, e); 164406f25ae9SGregory Neil Shapiro if (rstat == EX_OK || status == EX_TEMPFAIL) 164506f25ae9SGregory Neil Shapiro rstat = status; 1646c2aa98e2SPeter Wemm 1647c2aa98e2SPeter Wemm /* copy vector back into original space. */ 1648c2aa98e2SPeter Wemm for (avp = npvp; *avp++ != NULL;) 1649c2aa98e2SPeter Wemm continue; 165006f25ae9SGregory Neil Shapiro memmove((char *) pvp, (char *) npvp, 1651d0cef73dSGregory Neil Shapiro (int) (avp - npvp) * sizeof(*avp)); 1652c2aa98e2SPeter Wemm 1653c2aa98e2SPeter Wemm if (tTd(21, 4)) 1654c2aa98e2SPeter Wemm { 165540266059SGregory Neil Shapiro sm_dprintf("rewritten as:"); 1656e92d3f3fSGregory Neil Shapiro printav(sm_debug_file(), pvp); 1657c2aa98e2SPeter Wemm } 1658c2aa98e2SPeter Wemm } 1659c2aa98e2SPeter Wemm 166006f25ae9SGregory Neil Shapiro if (OpMode == MD_TEST) 1661c2aa98e2SPeter Wemm { 166240266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 166340266059SGregory Neil Shapiro "%s%-16.16s returns:", prefix, rulename); 1664e92d3f3fSGregory Neil Shapiro printav(smioout, pvp); 1665c2aa98e2SPeter Wemm } 166606f25ae9SGregory Neil Shapiro else if (tTd(21, 1)) 166706f25ae9SGregory Neil Shapiro { 166840266059SGregory Neil Shapiro sm_dprintf("%s%-16.16s returns:", prefix, rulename); 1669e92d3f3fSGregory Neil Shapiro printav(sm_debug_file(), pvp); 167006f25ae9SGregory Neil Shapiro } 1671c2aa98e2SPeter Wemm return rstat; 1672c2aa98e2SPeter Wemm } 167340266059SGregory Neil Shapiro /* 1674c2aa98e2SPeter Wemm ** CALLSUBR -- call subroutines in rewrite vector 1675c2aa98e2SPeter Wemm ** 1676c2aa98e2SPeter Wemm ** Parameters: 1677c2aa98e2SPeter Wemm ** pvp -- pointer to token vector. 1678c2aa98e2SPeter Wemm ** reclevel -- the current recursion level. 1679c2aa98e2SPeter Wemm ** e -- the current envelope. 1680c2aa98e2SPeter Wemm ** 1681c2aa98e2SPeter Wemm ** Returns: 1682c2aa98e2SPeter Wemm ** The status from the subroutine call. 1683c2aa98e2SPeter Wemm ** 1684c2aa98e2SPeter Wemm ** Side Effects: 1685c2aa98e2SPeter Wemm ** pvp is modified. 1686c2aa98e2SPeter Wemm */ 1687c2aa98e2SPeter Wemm 168806f25ae9SGregory Neil Shapiro static int 1689c2aa98e2SPeter Wemm callsubr(pvp, reclevel, e) 1690c2aa98e2SPeter Wemm char **pvp; 1691c2aa98e2SPeter Wemm int reclevel; 1692c2aa98e2SPeter Wemm ENVELOPE *e; 1693c2aa98e2SPeter Wemm { 1694c2aa98e2SPeter Wemm char **avp; 1695c2aa98e2SPeter Wemm register int i; 169640266059SGregory Neil Shapiro int subr, j; 169740266059SGregory Neil Shapiro int nsubr; 169806f25ae9SGregory Neil Shapiro int status; 1699c2aa98e2SPeter Wemm int rstat = EX_OK; 170040266059SGregory Neil Shapiro #define MAX_SUBR 16 170140266059SGregory Neil Shapiro int subrnumber[MAX_SUBR]; 170240266059SGregory Neil Shapiro int subrindex[MAX_SUBR]; 1703c2aa98e2SPeter Wemm 170440266059SGregory Neil Shapiro nsubr = 0; 170540266059SGregory Neil Shapiro 170640266059SGregory Neil Shapiro /* 170740266059SGregory Neil Shapiro ** Look for subroutine calls in pvp, collect them into subr*[] 170840266059SGregory Neil Shapiro ** We will perform the calls in the next loop, because we will 170940266059SGregory Neil Shapiro ** call the "last" subroutine first to avoid recursive calls 171040266059SGregory Neil Shapiro ** and too much copying. 171140266059SGregory Neil Shapiro */ 171240266059SGregory Neil Shapiro 171340266059SGregory Neil Shapiro for (avp = pvp, j = 0; *avp != NULL; avp++, j++) 1714c2aa98e2SPeter Wemm { 1715d0cef73dSGregory Neil Shapiro if ((avp[0][0] & 0377) == CALLSUBR && avp[1] != NULL) 1716c2aa98e2SPeter Wemm { 1717c2aa98e2SPeter Wemm stripquotes(avp[1]); 1718c2aa98e2SPeter Wemm subr = strtorwset(avp[1], NULL, ST_FIND); 1719c2aa98e2SPeter Wemm if (subr < 0) 1720c2aa98e2SPeter Wemm { 172140266059SGregory Neil Shapiro syserr("554 5.3.5 Unknown ruleset %s", avp[1]); 1722c2aa98e2SPeter Wemm return EX_CONFIG; 1723c2aa98e2SPeter Wemm } 1724c2aa98e2SPeter Wemm 1725c2aa98e2SPeter Wemm /* 172640266059SGregory Neil Shapiro ** XXX instead of doing this we could optimize 172740266059SGregory Neil Shapiro ** the rules after reading them: just remove 172840266059SGregory Neil Shapiro ** calls to empty rulesets 1729c2aa98e2SPeter Wemm */ 1730c2aa98e2SPeter Wemm 173140266059SGregory Neil Shapiro /* subroutine is an empty ruleset? don't call it */ 173240266059SGregory Neil Shapiro if (RewriteRules[subr] == NULL) 173340266059SGregory Neil Shapiro { 173440266059SGregory Neil Shapiro if (tTd(21, 3)) 173540266059SGregory Neil Shapiro sm_dprintf("-----skip subr %s (%d)\n", 173640266059SGregory Neil Shapiro avp[1], subr); 1737c2aa98e2SPeter Wemm for (i = 2; avp[i] != NULL; i++) 173840266059SGregory Neil Shapiro avp[i - 2] = avp[i]; 173940266059SGregory Neil Shapiro avp[i - 2] = NULL; 174040266059SGregory Neil Shapiro continue; 174140266059SGregory Neil Shapiro } 174240266059SGregory Neil Shapiro if (++nsubr >= MAX_SUBR) 174340266059SGregory Neil Shapiro { 174440266059SGregory Neil Shapiro syserr("554 5.3.0 Too many subroutine calls (%d max)", 174540266059SGregory Neil Shapiro MAX_SUBR); 174640266059SGregory Neil Shapiro return EX_CONFIG; 174740266059SGregory Neil Shapiro } 174840266059SGregory Neil Shapiro subrnumber[nsubr] = subr; 174940266059SGregory Neil Shapiro subrindex[nsubr] = j; 175040266059SGregory Neil Shapiro } 175140266059SGregory Neil Shapiro } 1752c2aa98e2SPeter Wemm 175340266059SGregory Neil Shapiro /* 175440266059SGregory Neil Shapiro ** Perform the actual subroutines calls, "last" one first, i.e., 175540266059SGregory Neil Shapiro ** go from the right to the left through all calls, 175640266059SGregory Neil Shapiro ** do the rewriting in place. 175740266059SGregory Neil Shapiro */ 175840266059SGregory Neil Shapiro 175940266059SGregory Neil Shapiro for (; nsubr > 0; nsubr--) 176040266059SGregory Neil Shapiro { 176140266059SGregory Neil Shapiro subr = subrnumber[nsubr]; 176240266059SGregory Neil Shapiro avp = pvp + subrindex[nsubr]; 176340266059SGregory Neil Shapiro 176440266059SGregory Neil Shapiro /* remove the subroutine call and name */ 176540266059SGregory Neil Shapiro for (i = 2; avp[i] != NULL; i++) 176640266059SGregory Neil Shapiro avp[i - 2] = avp[i]; 176740266059SGregory Neil Shapiro avp[i - 2] = NULL; 1768c2aa98e2SPeter Wemm 1769c2aa98e2SPeter Wemm /* 1770c2aa98e2SPeter Wemm ** Now we need to call the ruleset specified for 1771a7ec597cSGregory Neil Shapiro ** the subroutine. We can do this in place since 177240266059SGregory Neil Shapiro ** we call the "last" subroutine first. 1773c2aa98e2SPeter Wemm */ 1774c2aa98e2SPeter Wemm 177540266059SGregory Neil Shapiro status = rewrite(avp, subr, reclevel, e, 177640266059SGregory Neil Shapiro MAXATOM - subrindex[nsubr]); 177740266059SGregory Neil Shapiro if (status != EX_OK && status != EX_TEMPFAIL) 177840266059SGregory Neil Shapiro return status; 177906f25ae9SGregory Neil Shapiro if (rstat == EX_OK || status == EX_TEMPFAIL) 178006f25ae9SGregory Neil Shapiro rstat = status; 1781c2aa98e2SPeter Wemm } 1782c2aa98e2SPeter Wemm return rstat; 1783c2aa98e2SPeter Wemm } 178440266059SGregory Neil Shapiro /* 1785c2aa98e2SPeter Wemm ** MAP_LOOKUP -- do lookup in map 1786c2aa98e2SPeter Wemm ** 1787c2aa98e2SPeter Wemm ** Parameters: 178840266059SGregory Neil Shapiro ** smap -- the map to use for the lookup. 1789c2aa98e2SPeter Wemm ** key -- the key to look up. 1790c2aa98e2SPeter Wemm ** argvect -- arguments to pass to the map lookup. 1791c2aa98e2SPeter Wemm ** pstat -- a pointer to an integer in which to store the 1792c2aa98e2SPeter Wemm ** status from the lookup. 1793c2aa98e2SPeter Wemm ** e -- the current envelope. 1794c2aa98e2SPeter Wemm ** 1795c2aa98e2SPeter Wemm ** Returns: 1796c2aa98e2SPeter Wemm ** The result of the lookup. 1797c2aa98e2SPeter Wemm ** NULL -- if there was no data for the given key. 1798c2aa98e2SPeter Wemm */ 1799c2aa98e2SPeter Wemm 180006f25ae9SGregory Neil Shapiro static char * 180106f25ae9SGregory Neil Shapiro map_lookup(smap, key, argvect, pstat, e) 180206f25ae9SGregory Neil Shapiro STAB *smap; 1803c2aa98e2SPeter Wemm char key[]; 1804c2aa98e2SPeter Wemm char **argvect; 1805c2aa98e2SPeter Wemm int *pstat; 1806c2aa98e2SPeter Wemm ENVELOPE *e; 1807c2aa98e2SPeter Wemm { 180806f25ae9SGregory Neil Shapiro auto int status = EX_OK; 180906f25ae9SGregory Neil Shapiro MAP *map; 1810c2aa98e2SPeter Wemm char *replac; 1811c2aa98e2SPeter Wemm 181206f25ae9SGregory Neil Shapiro if (smap == NULL) 181306f25ae9SGregory Neil Shapiro return NULL; 181406f25ae9SGregory Neil Shapiro 181506f25ae9SGregory Neil Shapiro map = &smap->s_map; 181606f25ae9SGregory Neil Shapiro DYNOPENMAP(map); 1817*5b0945b5SGregory Neil Shapiro map->map_mflags |= MF_SECURE; /* default: secure */ 181806f25ae9SGregory Neil Shapiro 181906f25ae9SGregory Neil Shapiro if (e->e_sendmode == SM_DEFER && 182006f25ae9SGregory Neil Shapiro bitset(MF_DEFER, map->map_mflags)) 1821c2aa98e2SPeter Wemm { 1822c2aa98e2SPeter Wemm /* don't do any map lookups */ 1823c2aa98e2SPeter Wemm if (tTd(60, 1)) 182440266059SGregory Neil Shapiro sm_dprintf("map_lookup(%s, %s) => DEFERRED\n", 182506f25ae9SGregory Neil Shapiro smap->s_name, key); 1826c2aa98e2SPeter Wemm *pstat = EX_TEMPFAIL; 1827c2aa98e2SPeter Wemm return NULL; 1828c2aa98e2SPeter Wemm } 1829c2aa98e2SPeter Wemm 183006f25ae9SGregory Neil Shapiro if (!bitset(MF_KEEPQUOTES, map->map_mflags)) 1831c2aa98e2SPeter Wemm stripquotes(key); 1832c2aa98e2SPeter Wemm 1833c2aa98e2SPeter Wemm if (tTd(60, 1)) 1834065a643dSPeter Wemm { 1835d0cef73dSGregory Neil Shapiro sm_dprintf("map_lookup(%s, ", smap->s_name); 1836d0cef73dSGregory Neil Shapiro xputs(sm_debug_file(), key); 1837065a643dSPeter Wemm if (tTd(60, 5)) 1838065a643dSPeter Wemm { 1839065a643dSPeter Wemm int i; 1840065a643dSPeter Wemm 1841065a643dSPeter Wemm for (i = 0; argvect[i] != NULL; i++) 184240266059SGregory Neil Shapiro sm_dprintf(", %%%d=%s", i, argvect[i]); 1843065a643dSPeter Wemm } 184440266059SGregory Neil Shapiro sm_dprintf(") => "); 1845065a643dSPeter Wemm } 184606f25ae9SGregory Neil Shapiro replac = (*map->map_class->map_lookup)(map, key, argvect, &status); 1847*5b0945b5SGregory Neil Shapiro if (bitset(MF_SECURE, map->map_mflags)) 1848*5b0945b5SGregory Neil Shapiro map->map_mflags &= ~MF_SECURE; 1849*5b0945b5SGregory Neil Shapiro else 1850*5b0945b5SGregory Neil Shapiro e->e_flags &= ~EF_SECURE; 1851*5b0945b5SGregory Neil Shapiro 1852c2aa98e2SPeter Wemm if (tTd(60, 1)) 1853*5b0945b5SGregory Neil Shapiro sm_dprintf("%s (%d), ad=%d\n", 1854c2aa98e2SPeter Wemm replac != NULL ? replac : "NOT FOUND", 1855*5b0945b5SGregory Neil Shapiro status, bitset(MF_SECURE, map->map_mflags)); 1856c2aa98e2SPeter Wemm 185706f25ae9SGregory Neil Shapiro /* should recover if status == EX_TEMPFAIL */ 185806f25ae9SGregory Neil Shapiro if (status == EX_TEMPFAIL && !bitset(MF_NODEFER, map->map_mflags)) 1859c2aa98e2SPeter Wemm { 1860c2aa98e2SPeter Wemm *pstat = EX_TEMPFAIL; 1861c2aa98e2SPeter Wemm if (tTd(60, 1)) 186240266059SGregory Neil Shapiro sm_dprintf("map_lookup(%s, %s) tempfail: errno=%d\n", 186306f25ae9SGregory Neil Shapiro smap->s_name, key, errno); 1864c2aa98e2SPeter Wemm if (e->e_message == NULL) 1865c2aa98e2SPeter Wemm { 1866c2aa98e2SPeter Wemm char mbuf[320]; 1867c2aa98e2SPeter Wemm 1868d0cef73dSGregory Neil Shapiro (void) sm_snprintf(mbuf, sizeof(mbuf), 1869c2aa98e2SPeter Wemm "%.80s map: lookup (%s): deferred", 187006f25ae9SGregory Neil Shapiro smap->s_name, 1871c2aa98e2SPeter Wemm shortenstring(key, MAXSHORTSTR)); 187240266059SGregory Neil Shapiro e->e_message = sm_rpool_strdup_x(e->e_rpool, mbuf); 1873c2aa98e2SPeter Wemm } 1874c2aa98e2SPeter Wemm } 187506f25ae9SGregory Neil Shapiro if (status == EX_TEMPFAIL && map->map_tapp != NULL) 1876c2aa98e2SPeter Wemm { 187706f25ae9SGregory Neil Shapiro size_t i = strlen(key) + strlen(map->map_tapp) + 1; 1878c2aa98e2SPeter Wemm static char *rwbuf = NULL; 1879c2aa98e2SPeter Wemm static size_t rwbuflen = 0; 1880c2aa98e2SPeter Wemm 1881c2aa98e2SPeter Wemm if (i > rwbuflen) 1882c2aa98e2SPeter Wemm { 1883c2aa98e2SPeter Wemm if (rwbuf != NULL) 18848774250cSGregory Neil Shapiro sm_free(rwbuf); 1885c2aa98e2SPeter Wemm rwbuflen = i; 188640266059SGregory Neil Shapiro rwbuf = (char *) sm_pmalloc_x(rwbuflen); 1887c2aa98e2SPeter Wemm } 188840266059SGregory Neil Shapiro (void) sm_strlcpyn(rwbuf, rwbuflen, 2, key, map->map_tapp); 1889c2aa98e2SPeter Wemm if (tTd(60, 4)) 189040266059SGregory Neil Shapiro sm_dprintf("map_lookup tempfail: returning \"%s\"\n", 1891c2aa98e2SPeter Wemm rwbuf); 1892c2aa98e2SPeter Wemm return rwbuf; 1893c2aa98e2SPeter Wemm } 1894c2aa98e2SPeter Wemm return replac; 1895c2aa98e2SPeter Wemm } 189640266059SGregory Neil Shapiro /* 189706f25ae9SGregory Neil Shapiro ** INITERRMAILERS -- initialize error and discard mailers 189806f25ae9SGregory Neil Shapiro ** 189906f25ae9SGregory Neil Shapiro ** Parameters: 190006f25ae9SGregory Neil Shapiro ** none. 190106f25ae9SGregory Neil Shapiro ** 190206f25ae9SGregory Neil Shapiro ** Returns: 190306f25ae9SGregory Neil Shapiro ** none. 190406f25ae9SGregory Neil Shapiro ** 190506f25ae9SGregory Neil Shapiro ** Side Effects: 190606f25ae9SGregory Neil Shapiro ** initializes error and discard mailers. 190706f25ae9SGregory Neil Shapiro */ 190806f25ae9SGregory Neil Shapiro 190906f25ae9SGregory Neil Shapiro static MAILER discardmailer; 191006f25ae9SGregory Neil Shapiro static MAILER errormailer; 191106f25ae9SGregory Neil Shapiro static char *discardargv[] = { "DISCARD", NULL }; 191206f25ae9SGregory Neil Shapiro static char *errorargv[] = { "ERROR", NULL }; 191306f25ae9SGregory Neil Shapiro 191406f25ae9SGregory Neil Shapiro void 191506f25ae9SGregory Neil Shapiro initerrmailers() 191606f25ae9SGregory Neil Shapiro { 191706f25ae9SGregory Neil Shapiro if (discardmailer.m_name == NULL) 191806f25ae9SGregory Neil Shapiro { 191906f25ae9SGregory Neil Shapiro /* initialize the discard mailer */ 192006f25ae9SGregory Neil Shapiro discardmailer.m_name = "*discard*"; 192106f25ae9SGregory Neil Shapiro discardmailer.m_mailer = "DISCARD"; 192206f25ae9SGregory Neil Shapiro discardmailer.m_argv = discardargv; 192306f25ae9SGregory Neil Shapiro } 192406f25ae9SGregory Neil Shapiro if (errormailer.m_name == NULL) 192506f25ae9SGregory Neil Shapiro { 192606f25ae9SGregory Neil Shapiro /* initialize the bogus mailer */ 192706f25ae9SGregory Neil Shapiro errormailer.m_name = "*error*"; 192806f25ae9SGregory Neil Shapiro errormailer.m_mailer = "ERROR"; 192906f25ae9SGregory Neil Shapiro errormailer.m_argv = errorargv; 193006f25ae9SGregory Neil Shapiro } 193106f25ae9SGregory Neil Shapiro } 193240266059SGregory Neil Shapiro /* 1933c2aa98e2SPeter Wemm ** BUILDADDR -- build address from token vector. 1934c2aa98e2SPeter Wemm ** 1935c2aa98e2SPeter Wemm ** Parameters: 1936c2aa98e2SPeter Wemm ** tv -- token vector. 1937c2aa98e2SPeter Wemm ** a -- pointer to address descriptor to fill. 1938c2aa98e2SPeter Wemm ** If NULL, one will be allocated. 1939c2aa98e2SPeter Wemm ** flags -- info regarding whether this is a sender or 1940c2aa98e2SPeter Wemm ** a recipient. 1941c2aa98e2SPeter Wemm ** e -- the current envelope. 1942c2aa98e2SPeter Wemm ** 1943c2aa98e2SPeter Wemm ** Returns: 1944c2aa98e2SPeter Wemm ** NULL if there was an error. 1945c2aa98e2SPeter Wemm ** 'a' otherwise. 1946c2aa98e2SPeter Wemm ** 1947c2aa98e2SPeter Wemm ** Side Effects: 1948c2aa98e2SPeter Wemm ** fills in 'a' 1949c2aa98e2SPeter Wemm */ 1950c2aa98e2SPeter Wemm 195106f25ae9SGregory Neil Shapiro static struct errcodes 1952c2aa98e2SPeter Wemm { 1953c2aa98e2SPeter Wemm char *ec_name; /* name of error code */ 1954c2aa98e2SPeter Wemm int ec_code; /* numeric code */ 1955c2aa98e2SPeter Wemm } ErrorCodes[] = 1956c2aa98e2SPeter Wemm { 1957c2aa98e2SPeter Wemm { "usage", EX_USAGE }, 1958c2aa98e2SPeter Wemm { "nouser", EX_NOUSER }, 1959c2aa98e2SPeter Wemm { "nohost", EX_NOHOST }, 1960c2aa98e2SPeter Wemm { "unavailable", EX_UNAVAILABLE }, 1961c2aa98e2SPeter Wemm { "software", EX_SOFTWARE }, 1962c2aa98e2SPeter Wemm { "tempfail", EX_TEMPFAIL }, 1963c2aa98e2SPeter Wemm { "protocol", EX_PROTOCOL }, 1964c2aa98e2SPeter Wemm { "config", EX_CONFIG }, 1965c2aa98e2SPeter Wemm { NULL, EX_UNAVAILABLE } 1966c2aa98e2SPeter Wemm }; 1967c2aa98e2SPeter Wemm 196806f25ae9SGregory Neil Shapiro static ADDRESS * 1969c2aa98e2SPeter Wemm buildaddr(tv, a, flags, e) 1970c2aa98e2SPeter Wemm register char **tv; 1971c2aa98e2SPeter Wemm register ADDRESS *a; 1972c2aa98e2SPeter Wemm int flags; 1973c2aa98e2SPeter Wemm register ENVELOPE *e; 1974c2aa98e2SPeter Wemm { 1975605302a5SGregory Neil Shapiro bool tempfail = false; 1976a7ec597cSGregory Neil Shapiro int maxatom; 1977c2aa98e2SPeter Wemm struct mailer **mp; 1978c2aa98e2SPeter Wemm register struct mailer *m; 1979c2aa98e2SPeter Wemm register char *p; 1980c2aa98e2SPeter Wemm char *mname; 1981c2aa98e2SPeter Wemm char **hostp; 1982c2aa98e2SPeter Wemm char hbuf[MAXNAME + 1]; 1983065a643dSPeter Wemm static char ubuf[MAXNAME + 2]; 1984c2aa98e2SPeter Wemm 1985c2aa98e2SPeter Wemm if (tTd(24, 5)) 1986c2aa98e2SPeter Wemm { 198740266059SGregory Neil Shapiro sm_dprintf("buildaddr, flags=%x, tv=", flags); 1988e92d3f3fSGregory Neil Shapiro printav(sm_debug_file(), tv); 1989c2aa98e2SPeter Wemm } 1990c2aa98e2SPeter Wemm 1991a7ec597cSGregory Neil Shapiro maxatom = MAXATOM; 1992c2aa98e2SPeter Wemm if (a == NULL) 1993d0cef73dSGregory Neil Shapiro a = (ADDRESS *) sm_rpool_malloc_x(e->e_rpool, sizeof(*a)); 1994d0cef73dSGregory Neil Shapiro memset((char *) a, '\0', sizeof(*a)); 199506f25ae9SGregory Neil Shapiro hbuf[0] = '\0'; 1996c2aa98e2SPeter Wemm 1997c2aa98e2SPeter Wemm /* set up default error return flags */ 1998c2aa98e2SPeter Wemm a->q_flags |= DefaultNotify; 1999c2aa98e2SPeter Wemm 2000c2aa98e2SPeter Wemm /* figure out what net/mailer to use */ 2001c2aa98e2SPeter Wemm if (*tv == NULL || (**tv & 0377) != CANONNET) 2002c2aa98e2SPeter Wemm { 200306f25ae9SGregory Neil Shapiro syserr("554 5.3.5 buildaddr: no mailer in parsed address"); 2004c2aa98e2SPeter Wemm badaddr: 2005605302a5SGregory Neil Shapiro /* 2006605302a5SGregory Neil Shapiro ** ExitStat may have been set by an earlier map open 2007605302a5SGregory Neil Shapiro ** failure (to a permanent error (EX_OSERR) in syserr()) 2008605302a5SGregory Neil Shapiro ** so we also need to check if this particular $#error 2009605302a5SGregory Neil Shapiro ** return wanted a 4XX failure. 2010605302a5SGregory Neil Shapiro ** 2011605302a5SGregory Neil Shapiro ** XXX the real fix is probably to set ExitStat correctly, 2012605302a5SGregory Neil Shapiro ** i.e., to EX_TEMPFAIL if the map open is just a temporary 2013605302a5SGregory Neil Shapiro ** error. 2014605302a5SGregory Neil Shapiro */ 2015605302a5SGregory Neil Shapiro 2016605302a5SGregory Neil Shapiro if (ExitStat == EX_TEMPFAIL || tempfail) 201706f25ae9SGregory Neil Shapiro a->q_state = QS_QUEUEUP; 201806f25ae9SGregory Neil Shapiro else 2019c2aa98e2SPeter Wemm { 202006f25ae9SGregory Neil Shapiro a->q_state = QS_BADADDR; 202106f25ae9SGregory Neil Shapiro a->q_mailer = &errormailer; 2022c2aa98e2SPeter Wemm } 2023c2aa98e2SPeter Wemm return a; 2024c2aa98e2SPeter Wemm } 2025c2aa98e2SPeter Wemm mname = *++tv; 2026a7ec597cSGregory Neil Shapiro --maxatom; 2027c2aa98e2SPeter Wemm 2028c2aa98e2SPeter Wemm /* extract host and user portions */ 2029c2aa98e2SPeter Wemm if (*++tv != NULL && (**tv & 0377) == CANONHOST) 2030a7ec597cSGregory Neil Shapiro { 2031c2aa98e2SPeter Wemm hostp = ++tv; 2032a7ec597cSGregory Neil Shapiro --maxatom; 2033a7ec597cSGregory Neil Shapiro } 2034c2aa98e2SPeter Wemm else 2035c2aa98e2SPeter Wemm hostp = NULL; 2036a7ec597cSGregory Neil Shapiro --maxatom; 2037c2aa98e2SPeter Wemm while (*tv != NULL && (**tv & 0377) != CANONUSER) 2038a7ec597cSGregory Neil Shapiro { 2039c2aa98e2SPeter Wemm tv++; 2040a7ec597cSGregory Neil Shapiro --maxatom; 2041a7ec597cSGregory Neil Shapiro } 2042c2aa98e2SPeter Wemm if (*tv == NULL) 2043c2aa98e2SPeter Wemm { 204406f25ae9SGregory Neil Shapiro syserr("554 5.3.5 buildaddr: no user"); 2045c2aa98e2SPeter Wemm goto badaddr; 2046c2aa98e2SPeter Wemm } 2047c2aa98e2SPeter Wemm if (tv == hostp) 2048c2aa98e2SPeter Wemm hostp = NULL; 2049c2aa98e2SPeter Wemm else if (hostp != NULL) 2050d0cef73dSGregory Neil Shapiro cataddr(hostp, tv - 1, hbuf, sizeof(hbuf), '\0', false); 2051d0cef73dSGregory Neil Shapiro cataddr(++tv, NULL, ubuf, sizeof(ubuf), ' ', false); 2052a7ec597cSGregory Neil Shapiro --maxatom; 2053c2aa98e2SPeter Wemm 2054c2aa98e2SPeter Wemm /* save away the host name */ 205540266059SGregory Neil Shapiro if (sm_strcasecmp(mname, "error") == 0) 2056c2aa98e2SPeter Wemm { 205706f25ae9SGregory Neil Shapiro /* Set up triplet for use by -bv */ 205806f25ae9SGregory Neil Shapiro a->q_mailer = &errormailer; 205940266059SGregory Neil Shapiro a->q_user = sm_rpool_strdup_x(e->e_rpool, ubuf); 206040266059SGregory Neil Shapiro /* XXX wrong place? */ 206106f25ae9SGregory Neil Shapiro 2062c2aa98e2SPeter Wemm if (hostp != NULL) 2063c2aa98e2SPeter Wemm { 2064c2aa98e2SPeter Wemm register struct errcodes *ep; 2065c2aa98e2SPeter Wemm 206640266059SGregory Neil Shapiro a->q_host = sm_rpool_strdup_x(e->e_rpool, hbuf); 2067c2aa98e2SPeter Wemm if (strchr(hbuf, '.') != NULL) 2068c2aa98e2SPeter Wemm { 206940266059SGregory Neil Shapiro a->q_status = sm_rpool_strdup_x(e->e_rpool, 207040266059SGregory Neil Shapiro hbuf); 2071c2aa98e2SPeter Wemm setstat(dsntoexitstat(hbuf)); 2072c2aa98e2SPeter Wemm } 2073c2aa98e2SPeter Wemm else if (isascii(hbuf[0]) && isdigit(hbuf[0])) 2074c2aa98e2SPeter Wemm { 2075c2aa98e2SPeter Wemm setstat(atoi(hbuf)); 2076c2aa98e2SPeter Wemm } 2077c2aa98e2SPeter Wemm else 2078c2aa98e2SPeter Wemm { 2079c2aa98e2SPeter Wemm for (ep = ErrorCodes; ep->ec_name != NULL; ep++) 208040266059SGregory Neil Shapiro if (sm_strcasecmp(ep->ec_name, hbuf) == 0) 2081c2aa98e2SPeter Wemm break; 2082c2aa98e2SPeter Wemm setstat(ep->ec_code); 2083c2aa98e2SPeter Wemm } 2084c2aa98e2SPeter Wemm } 2085c2aa98e2SPeter Wemm else 208606f25ae9SGregory Neil Shapiro { 208706f25ae9SGregory Neil Shapiro a->q_host = NULL; 2088c2aa98e2SPeter Wemm setstat(EX_UNAVAILABLE); 2089c2aa98e2SPeter Wemm } 209006f25ae9SGregory Neil Shapiro stripquotes(ubuf); 209106f25ae9SGregory Neil Shapiro if (ISSMTPCODE(ubuf) && ubuf[3] == ' ') 209206f25ae9SGregory Neil Shapiro { 209306f25ae9SGregory Neil Shapiro char fmt[16]; 209406f25ae9SGregory Neil Shapiro int off; 209506f25ae9SGregory Neil Shapiro 209606f25ae9SGregory Neil Shapiro if ((off = isenhsc(ubuf + 4, ' ')) > 0) 209706f25ae9SGregory Neil Shapiro { 209806f25ae9SGregory Neil Shapiro ubuf[off + 4] = '\0'; 209906f25ae9SGregory Neil Shapiro off += 5; 2100c2aa98e2SPeter Wemm } 2101c2aa98e2SPeter Wemm else 2102c2aa98e2SPeter Wemm { 210306f25ae9SGregory Neil Shapiro off = 4; 210406f25ae9SGregory Neil Shapiro ubuf[3] = '\0'; 210506f25ae9SGregory Neil Shapiro } 2106d0cef73dSGregory Neil Shapiro (void) sm_strlcpyn(fmt, sizeof(fmt), 2, ubuf, " %s"); 210706f25ae9SGregory Neil Shapiro if (off > 4) 210806f25ae9SGregory Neil Shapiro usrerr(fmt, ubuf + off); 210906f25ae9SGregory Neil Shapiro else if (isenhsc(hbuf, '\0') > 0) 211006f25ae9SGregory Neil Shapiro usrerrenh(hbuf, fmt, ubuf + off); 211106f25ae9SGregory Neil Shapiro else 211206f25ae9SGregory Neil Shapiro usrerr(fmt, ubuf + off); 211306f25ae9SGregory Neil Shapiro /* XXX ubuf[off - 1] = ' '; */ 2114605302a5SGregory Neil Shapiro if (ubuf[0] == '4') 2115605302a5SGregory Neil Shapiro tempfail = true; 211606f25ae9SGregory Neil Shapiro } 211706f25ae9SGregory Neil Shapiro else 211806f25ae9SGregory Neil Shapiro { 211906f25ae9SGregory Neil Shapiro usrerr("553 5.3.0 %s", ubuf); 2120c2aa98e2SPeter Wemm } 2121c2aa98e2SPeter Wemm goto badaddr; 2122c2aa98e2SPeter Wemm } 2123c2aa98e2SPeter Wemm 2124c2aa98e2SPeter Wemm for (mp = Mailer; (m = *mp++) != NULL; ) 2125c2aa98e2SPeter Wemm { 212640266059SGregory Neil Shapiro if (sm_strcasecmp(m->m_name, mname) == 0) 2127c2aa98e2SPeter Wemm break; 2128c2aa98e2SPeter Wemm } 2129c2aa98e2SPeter Wemm if (m == NULL) 2130c2aa98e2SPeter Wemm { 213106f25ae9SGregory Neil Shapiro syserr("554 5.3.5 buildaddr: unknown mailer %s", mname); 2132c2aa98e2SPeter Wemm goto badaddr; 2133c2aa98e2SPeter Wemm } 2134c2aa98e2SPeter Wemm a->q_mailer = m; 2135c2aa98e2SPeter Wemm 2136c2aa98e2SPeter Wemm /* figure out what host (if any) */ 2137c2aa98e2SPeter Wemm if (hostp == NULL) 2138c2aa98e2SPeter Wemm { 2139c2aa98e2SPeter Wemm if (!bitnset(M_LOCALMAILER, m->m_flags)) 2140c2aa98e2SPeter Wemm { 214106f25ae9SGregory Neil Shapiro syserr("554 5.3.5 buildaddr: no host"); 2142c2aa98e2SPeter Wemm goto badaddr; 2143c2aa98e2SPeter Wemm } 2144c2aa98e2SPeter Wemm a->q_host = NULL; 2145c2aa98e2SPeter Wemm } 2146c2aa98e2SPeter Wemm else 214740266059SGregory Neil Shapiro a->q_host = sm_rpool_strdup_x(e->e_rpool, hbuf); 2148c2aa98e2SPeter Wemm 2149c2aa98e2SPeter Wemm /* figure out the user */ 2150c2aa98e2SPeter Wemm p = ubuf; 2151c2aa98e2SPeter Wemm if (bitnset(M_CHECKUDB, m->m_flags) && *p == '@') 2152c2aa98e2SPeter Wemm { 2153c2aa98e2SPeter Wemm p++; 2154c2aa98e2SPeter Wemm tv++; 2155a7ec597cSGregory Neil Shapiro --maxatom; 2156c2aa98e2SPeter Wemm a->q_flags |= QNOTREMOTE; 2157c2aa98e2SPeter Wemm } 2158c2aa98e2SPeter Wemm 2159c2aa98e2SPeter Wemm /* do special mapping for local mailer */ 2160c2aa98e2SPeter Wemm if (*p == '"') 2161c2aa98e2SPeter Wemm p++; 2162c2aa98e2SPeter Wemm if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags)) 2163c2aa98e2SPeter Wemm a->q_mailer = m = ProgMailer; 2164c2aa98e2SPeter Wemm else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags)) 2165c2aa98e2SPeter Wemm a->q_mailer = m = FileMailer; 2166c2aa98e2SPeter Wemm else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags)) 2167c2aa98e2SPeter Wemm { 2168c2aa98e2SPeter Wemm /* may be :include: */ 2169c2aa98e2SPeter Wemm stripquotes(ubuf); 217040266059SGregory Neil Shapiro if (sm_strncasecmp(ubuf, ":include:", 9) == 0) 2171c2aa98e2SPeter Wemm { 2172c2aa98e2SPeter Wemm /* if :include:, don't need further rewriting */ 2173c2aa98e2SPeter Wemm a->q_mailer = m = InclMailer; 217440266059SGregory Neil Shapiro a->q_user = sm_rpool_strdup_x(e->e_rpool, &ubuf[9]); 2175c2aa98e2SPeter Wemm return a; 2176c2aa98e2SPeter Wemm } 2177c2aa98e2SPeter Wemm } 2178c2aa98e2SPeter Wemm 2179c2aa98e2SPeter Wemm /* rewrite according recipient mailer rewriting rules */ 218040266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'h', a->q_host); 218106f25ae9SGregory Neil Shapiro 218240266059SGregory Neil Shapiro if (ConfigLevel >= 10 || 218306f25ae9SGregory Neil Shapiro !bitset(RF_SENDERADDR|RF_HEADERADDR, flags)) 2184c2aa98e2SPeter Wemm { 2185c2aa98e2SPeter Wemm /* sender addresses done later */ 2186a7ec597cSGregory Neil Shapiro (void) rewrite(tv, 2, 0, e, maxatom); 2187c2aa98e2SPeter Wemm if (m->m_re_rwset > 0) 2188a7ec597cSGregory Neil Shapiro (void) rewrite(tv, m->m_re_rwset, 0, e, maxatom); 2189c2aa98e2SPeter Wemm } 2190a7ec597cSGregory Neil Shapiro (void) rewrite(tv, 4, 0, e, maxatom); 2191c2aa98e2SPeter Wemm 2192c2aa98e2SPeter Wemm /* save the result for the command line/RCPT argument */ 2193d0cef73dSGregory Neil Shapiro cataddr(tv, NULL, ubuf, sizeof(ubuf), '\0', true); 219440266059SGregory Neil Shapiro a->q_user = sm_rpool_strdup_x(e->e_rpool, ubuf); 2195c2aa98e2SPeter Wemm 2196c2aa98e2SPeter Wemm /* 2197c2aa98e2SPeter Wemm ** Do mapping to lower case as requested by mailer 2198c2aa98e2SPeter Wemm */ 2199c2aa98e2SPeter Wemm 2200c2aa98e2SPeter Wemm if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags)) 2201c2aa98e2SPeter Wemm makelower(a->q_host); 2202c2aa98e2SPeter Wemm if (!bitnset(M_USR_UPPER, m->m_flags)) 2203c2aa98e2SPeter Wemm makelower(a->q_user); 2204c2aa98e2SPeter Wemm 2205c2aa98e2SPeter Wemm if (tTd(24, 6)) 2206c2aa98e2SPeter Wemm { 220740266059SGregory Neil Shapiro sm_dprintf("buildaddr => "); 2208e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), a, false); 2209c2aa98e2SPeter Wemm } 2210c2aa98e2SPeter Wemm return a; 2211c2aa98e2SPeter Wemm } 221213bd1963SGregory Neil Shapiro 221340266059SGregory Neil Shapiro /* 2214c2aa98e2SPeter Wemm ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs) 2215c2aa98e2SPeter Wemm ** 2216c2aa98e2SPeter Wemm ** Parameters: 2217c2aa98e2SPeter Wemm ** pvp -- parameter vector to rebuild. 2218c2aa98e2SPeter Wemm ** evp -- last parameter to include. Can be NULL to 2219c2aa98e2SPeter Wemm ** use entire pvp. 2220c2aa98e2SPeter Wemm ** buf -- buffer to build the string into. 2221c2aa98e2SPeter Wemm ** sz -- size of buf. 2222da7d7b9cSGregory Neil Shapiro ** spacesub -- the space separator character; 2223da7d7b9cSGregory Neil Shapiro ** '\0': SpaceSub. 2224da7d7b9cSGregory Neil Shapiro ** NOSPACESEP: no separator 2225d0cef73dSGregory Neil Shapiro ** external -- convert to external form? 2226d0cef73dSGregory Neil Shapiro ** (no metacharacters; METAQUOTEs removed, see below) 2227c2aa98e2SPeter Wemm ** 2228c2aa98e2SPeter Wemm ** Returns: 2229c2aa98e2SPeter Wemm ** none. 2230c2aa98e2SPeter Wemm ** 2231c2aa98e2SPeter Wemm ** Side Effects: 2232c2aa98e2SPeter Wemm ** Destroys buf. 2233d0cef73dSGregory Neil Shapiro ** 2234d0cef73dSGregory Neil Shapiro ** Notes: 2235d0cef73dSGregory Neil Shapiro ** There are two formats for strings: internal and external. 2236d0cef73dSGregory Neil Shapiro ** The external format is just an eight-bit clean string (no 2237d0cef73dSGregory Neil Shapiro ** null bytes, everything else OK). The internal format can 2238d0cef73dSGregory Neil Shapiro ** include sendmail metacharacters. The special character 2239d0cef73dSGregory Neil Shapiro ** METAQUOTE essentially quotes the character following, stripping 2240d0cef73dSGregory Neil Shapiro ** it of all special semantics. 2241d0cef73dSGregory Neil Shapiro ** 2242d0cef73dSGregory Neil Shapiro ** The cataddr routine needs to be aware of whether it is producing 2243d0cef73dSGregory Neil Shapiro ** an internal or external form as output (it only takes internal 2244d0cef73dSGregory Neil Shapiro ** form as input). 2245d0cef73dSGregory Neil Shapiro ** 2246d0cef73dSGregory Neil Shapiro ** The parseaddr routine has a similar issue on input, but that 2247d0cef73dSGregory Neil Shapiro ** is flagged on the basis of which token table is passed in. 2248c2aa98e2SPeter Wemm */ 2249c2aa98e2SPeter Wemm 2250c2aa98e2SPeter Wemm void 2251d0cef73dSGregory Neil Shapiro cataddr(pvp, evp, buf, sz, spacesub, external) 2252c2aa98e2SPeter Wemm char **pvp; 2253c2aa98e2SPeter Wemm char **evp; 2254c2aa98e2SPeter Wemm char *buf; 2255c2aa98e2SPeter Wemm register int sz; 2256c2aa98e2SPeter Wemm int spacesub; 2257d0cef73dSGregory Neil Shapiro bool external; 2258c2aa98e2SPeter Wemm { 2259d0cef73dSGregory Neil Shapiro bool oatomtok, natomtok; 2260d0cef73dSGregory Neil Shapiro char *p; 2261d0cef73dSGregory Neil Shapiro 2262d0cef73dSGregory Neil Shapiro oatomtok = natomtok = false; 2263d0cef73dSGregory Neil Shapiro if (tTd(59, 14)) 2264d0cef73dSGregory Neil Shapiro { 2265d0cef73dSGregory Neil Shapiro sm_dprintf("cataddr(%d) <==", external); 2266d0cef73dSGregory Neil Shapiro printav(sm_debug_file(), pvp); 2267d0cef73dSGregory Neil Shapiro } 2268c2aa98e2SPeter Wemm 226906f25ae9SGregory Neil Shapiro if (sz <= 0) 227006f25ae9SGregory Neil Shapiro return; 227106f25ae9SGregory Neil Shapiro 2272c2aa98e2SPeter Wemm if (spacesub == '\0') 2273c2aa98e2SPeter Wemm spacesub = SpaceSub; 2274c2aa98e2SPeter Wemm 2275c2aa98e2SPeter Wemm if (pvp == NULL) 2276c2aa98e2SPeter Wemm { 227706f25ae9SGregory Neil Shapiro *buf = '\0'; 2278c2aa98e2SPeter Wemm return; 2279c2aa98e2SPeter Wemm } 2280c2aa98e2SPeter Wemm p = buf; 2281c2aa98e2SPeter Wemm sz -= 2; 228240266059SGregory Neil Shapiro while (*pvp != NULL && sz > 0) 2283c2aa98e2SPeter Wemm { 2284d0cef73dSGregory Neil Shapiro char *q; 2285d0cef73dSGregory Neil Shapiro 2286e3793f76SGregory Neil Shapiro natomtok = (IntTokenTab[**pvp & 0xff] == ATM); 2287da7d7b9cSGregory Neil Shapiro if (oatomtok && natomtok && spacesub != NOSPACESEP) 228806f25ae9SGregory Neil Shapiro { 2289c2aa98e2SPeter Wemm *p++ = spacesub; 229040266059SGregory Neil Shapiro if (--sz <= 0) 229140266059SGregory Neil Shapiro break; 229206f25ae9SGregory Neil Shapiro } 2293d0cef73dSGregory Neil Shapiro for (q = *pvp; *q != '\0'; ) 2294d0cef73dSGregory Neil Shapiro { 2295d0cef73dSGregory Neil Shapiro int c; 2296d0cef73dSGregory Neil Shapiro 2297d0cef73dSGregory Neil Shapiro if (--sz <= 0) 2298d0cef73dSGregory Neil Shapiro break; 2299d0cef73dSGregory Neil Shapiro *p++ = c = *q++; 2300d0cef73dSGregory Neil Shapiro 2301d0cef73dSGregory Neil Shapiro /* 2302d0cef73dSGregory Neil Shapiro ** If the current character (c) is METAQUOTE and we 2303d0cef73dSGregory Neil Shapiro ** want the "external" form and the next character 2304d0cef73dSGregory Neil Shapiro ** is not NUL, then overwrite METAQUOTE with that 2305*5b0945b5SGregory Neil Shapiro ** character (i.e., METAQUOTE ch is changed to ch). 2306*5b0945b5SGregory Neil Shapiro ** p[-1] is used because p is advanced (above). 2307d0cef73dSGregory Neil Shapiro */ 2308d0cef73dSGregory Neil Shapiro 2309d0cef73dSGregory Neil Shapiro if ((c & 0377) == METAQUOTE && external && *q != '\0') 2310d0cef73dSGregory Neil Shapiro p[-1] = *q++; 2311d0cef73dSGregory Neil Shapiro } 2312e92d3f3fSGregory Neil Shapiro if (sz <= 0) 231340266059SGregory Neil Shapiro break; 2314c2aa98e2SPeter Wemm oatomtok = natomtok; 2315c2aa98e2SPeter Wemm if (pvp++ == evp) 2316c2aa98e2SPeter Wemm break; 2317c2aa98e2SPeter Wemm } 2318e92d3f3fSGregory Neil Shapiro 231913d88268SGregory Neil Shapiro #if 0 232013d88268SGregory Neil Shapiro /* 232113d88268SGregory Neil Shapiro ** Silently truncate long strings: even though this doesn't 232213d88268SGregory Neil Shapiro ** seem like a good idea it is necessary because header checks 232313d88268SGregory Neil Shapiro ** send the whole header value to rscheck() and hence rewrite(). 232413d88268SGregory Neil Shapiro ** The latter however sometimes uses a "short" buffer (e.g., 232513d88268SGregory Neil Shapiro ** cbuf[MAXNAME + 1]) to call cataddr() which then triggers this 232613d88268SGregory Neil Shapiro ** error function. One possible fix to the problem is to pass 232713d88268SGregory Neil Shapiro ** flags to rscheck() and rewrite() to distinguish the various 232813d88268SGregory Neil Shapiro ** calls and only trigger the error if necessary. For now just 232913d88268SGregory Neil Shapiro ** undo the change from 8.13.0. 233013d88268SGregory Neil Shapiro */ 233113d88268SGregory Neil Shapiro 2332e92d3f3fSGregory Neil Shapiro if (sz <= 0) 2333b6bacd31SGregory Neil Shapiro usrerr("cataddr: string too long"); 233413d88268SGregory Neil Shapiro #endif 2335c2aa98e2SPeter Wemm *p = '\0'; 2336d0cef73dSGregory Neil Shapiro 2337d0cef73dSGregory Neil Shapiro if (tTd(59, 14)) 2338d0cef73dSGregory Neil Shapiro sm_dprintf(" cataddr => %s\n", str2prt(buf)); 2339c2aa98e2SPeter Wemm } 2340d0cef73dSGregory Neil Shapiro 234140266059SGregory Neil Shapiro /* 2342c2aa98e2SPeter Wemm ** SAMEADDR -- Determine if two addresses are the same 2343c2aa98e2SPeter Wemm ** 2344c2aa98e2SPeter Wemm ** This is not just a straight comparison -- if the mailer doesn't 2345c2aa98e2SPeter Wemm ** care about the host we just ignore it, etc. 2346c2aa98e2SPeter Wemm ** 2347c2aa98e2SPeter Wemm ** Parameters: 2348c2aa98e2SPeter Wemm ** a, b -- pointers to the internal forms to compare. 2349c2aa98e2SPeter Wemm ** 2350c2aa98e2SPeter Wemm ** Returns: 235140266059SGregory Neil Shapiro ** true -- they represent the same mailbox. 235240266059SGregory Neil Shapiro ** false -- they don't. 2353c2aa98e2SPeter Wemm ** 2354c2aa98e2SPeter Wemm ** Side Effects: 2355c2aa98e2SPeter Wemm ** none. 2356c2aa98e2SPeter Wemm */ 2357c2aa98e2SPeter Wemm 2358c2aa98e2SPeter Wemm bool 2359c2aa98e2SPeter Wemm sameaddr(a, b) 2360c2aa98e2SPeter Wemm register ADDRESS *a; 2361c2aa98e2SPeter Wemm register ADDRESS *b; 2362c2aa98e2SPeter Wemm { 2363c2aa98e2SPeter Wemm register ADDRESS *ca, *cb; 2364c2aa98e2SPeter Wemm 2365c2aa98e2SPeter Wemm /* if they don't have the same mailer, forget it */ 2366c2aa98e2SPeter Wemm if (a->q_mailer != b->q_mailer) 236740266059SGregory Neil Shapiro return false; 2368c2aa98e2SPeter Wemm 2369552d4955SGregory Neil Shapiro /* 2370552d4955SGregory Neil Shapiro ** Addresses resolving to error mailer 2371552d4955SGregory Neil Shapiro ** should not be considered identical 2372552d4955SGregory Neil Shapiro */ 2373552d4955SGregory Neil Shapiro 2374552d4955SGregory Neil Shapiro if (a->q_mailer == &errormailer) 2375552d4955SGregory Neil Shapiro return false; 2376552d4955SGregory Neil Shapiro 2377c2aa98e2SPeter Wemm /* if the user isn't the same, we can drop out */ 2378c2aa98e2SPeter Wemm if (strcmp(a->q_user, b->q_user) != 0) 237940266059SGregory Neil Shapiro return false; 2380c2aa98e2SPeter Wemm 2381da7d7b9cSGregory Neil Shapiro /* do the required flags match? */ 2382da7d7b9cSGregory Neil Shapiro if (!ADDR_FLAGS_MATCH(a, b)) 2383da7d7b9cSGregory Neil Shapiro return false; 2384da7d7b9cSGregory Neil Shapiro 2385c2aa98e2SPeter Wemm /* if we have good uids for both but they differ, these are different */ 2386c2aa98e2SPeter Wemm if (a->q_mailer == ProgMailer) 2387c2aa98e2SPeter Wemm { 2388c2aa98e2SPeter Wemm ca = getctladdr(a); 2389c2aa98e2SPeter Wemm cb = getctladdr(b); 2390c2aa98e2SPeter Wemm if (ca != NULL && cb != NULL && 2391c2aa98e2SPeter Wemm bitset(QGOODUID, ca->q_flags & cb->q_flags) && 2392c2aa98e2SPeter Wemm ca->q_uid != cb->q_uid) 239340266059SGregory Neil Shapiro return false; 2394c2aa98e2SPeter Wemm } 2395c2aa98e2SPeter Wemm 2396c2aa98e2SPeter Wemm /* otherwise compare hosts (but be careful for NULL ptrs) */ 2397c2aa98e2SPeter Wemm if (a->q_host == b->q_host) 2398c2aa98e2SPeter Wemm { 2399c2aa98e2SPeter Wemm /* probably both null pointers */ 240040266059SGregory Neil Shapiro return true; 2401c2aa98e2SPeter Wemm } 2402c2aa98e2SPeter Wemm if (a->q_host == NULL || b->q_host == NULL) 2403c2aa98e2SPeter Wemm { 2404c2aa98e2SPeter Wemm /* only one is a null pointer */ 240540266059SGregory Neil Shapiro return false; 2406c2aa98e2SPeter Wemm } 2407c2aa98e2SPeter Wemm if (strcmp(a->q_host, b->q_host) != 0) 240840266059SGregory Neil Shapiro return false; 2409c2aa98e2SPeter Wemm 241040266059SGregory Neil Shapiro return true; 2411c2aa98e2SPeter Wemm } 241240266059SGregory Neil Shapiro /* 2413c2aa98e2SPeter Wemm ** PRINTADDR -- print address (for debugging) 2414c2aa98e2SPeter Wemm ** 2415c2aa98e2SPeter Wemm ** Parameters: 2416c2aa98e2SPeter Wemm ** a -- the address to print 2417c2aa98e2SPeter Wemm ** follow -- follow the q_next chain. 2418c2aa98e2SPeter Wemm ** 2419c2aa98e2SPeter Wemm ** Returns: 2420c2aa98e2SPeter Wemm ** none. 2421c2aa98e2SPeter Wemm ** 2422c2aa98e2SPeter Wemm ** Side Effects: 2423c2aa98e2SPeter Wemm ** none. 2424c2aa98e2SPeter Wemm */ 2425c2aa98e2SPeter Wemm 2426c2aa98e2SPeter Wemm struct qflags 2427c2aa98e2SPeter Wemm { 2428c2aa98e2SPeter Wemm char *qf_name; 242940266059SGregory Neil Shapiro unsigned long qf_bit; 2430c2aa98e2SPeter Wemm }; 2431c2aa98e2SPeter Wemm 2432da7d7b9cSGregory Neil Shapiro /* :'a,.s;^#define \(Q[A-Z]*\) .*; { "\1", \1 },; */ 243306f25ae9SGregory Neil Shapiro static struct qflags AddressFlags[] = 2434c2aa98e2SPeter Wemm { 2435c2aa98e2SPeter Wemm { "QGOODUID", QGOODUID }, 2436c2aa98e2SPeter Wemm { "QPRIMARY", QPRIMARY }, 2437c2aa98e2SPeter Wemm { "QNOTREMOTE", QNOTREMOTE }, 2438c2aa98e2SPeter Wemm { "QSELFREF", QSELFREF }, 2439c2aa98e2SPeter Wemm { "QBOGUSSHELL", QBOGUSSHELL }, 2440c2aa98e2SPeter Wemm { "QUNSAFEADDR", QUNSAFEADDR }, 2441c2aa98e2SPeter Wemm { "QPINGONSUCCESS", QPINGONSUCCESS }, 2442c2aa98e2SPeter Wemm { "QPINGONFAILURE", QPINGONFAILURE }, 2443c2aa98e2SPeter Wemm { "QPINGONDELAY", QPINGONDELAY }, 2444c2aa98e2SPeter Wemm { "QHASNOTIFY", QHASNOTIFY }, 2445c2aa98e2SPeter Wemm { "QRELAYED", QRELAYED }, 2446c2aa98e2SPeter Wemm { "QEXPANDED", QEXPANDED }, 2447c2aa98e2SPeter Wemm { "QDELIVERED", QDELIVERED }, 2448c2aa98e2SPeter Wemm { "QDELAYED", QDELAYED }, 2449c2aa98e2SPeter Wemm { "QTHISPASS", QTHISPASS }, 2450da7d7b9cSGregory Neil Shapiro { "QALIAS", QALIAS }, 2451da7d7b9cSGregory Neil Shapiro { "QBYTRACE", QBYTRACE }, 2452da7d7b9cSGregory Neil Shapiro { "QBYNDELAY", QBYNDELAY }, 2453da7d7b9cSGregory Neil Shapiro { "QBYNRELAY", QBYNRELAY }, 2454da7d7b9cSGregory Neil Shapiro { "QINTBCC", QINTBCC }, 2455da7d7b9cSGregory Neil Shapiro { "QDYNMAILER", QDYNMAILER }, 2456c2aa98e2SPeter Wemm { "QRCPTOK", QRCPTOK }, 2457*5b0945b5SGregory Neil Shapiro { "QSECURE", QSECURE }, 2458*5b0945b5SGregory Neil Shapiro { "QTHISPASS", QTHISPASS }, 2459*5b0945b5SGregory Neil Shapiro { "QRCPTOK", QRCPTOK }, 2460*5b0945b5SGregory Neil Shapiro { "QQUEUED", QQUEUED }, 2461193538b7SGregory Neil Shapiro { NULL, 0 } 2462c2aa98e2SPeter Wemm }; 2463c2aa98e2SPeter Wemm 2464c2aa98e2SPeter Wemm void 2465e92d3f3fSGregory Neil Shapiro printaddr(fp, a, follow) 2466e92d3f3fSGregory Neil Shapiro SM_FILE_T *fp; 2467c2aa98e2SPeter Wemm register ADDRESS *a; 2468c2aa98e2SPeter Wemm bool follow; 2469c2aa98e2SPeter Wemm { 2470c2aa98e2SPeter Wemm register MAILER *m; 2471c2aa98e2SPeter Wemm MAILER pseudomailer; 2472c2aa98e2SPeter Wemm register struct qflags *qfp; 2473c2aa98e2SPeter Wemm bool firstone; 2474c2aa98e2SPeter Wemm 2475c2aa98e2SPeter Wemm if (a == NULL) 2476c2aa98e2SPeter Wemm { 2477e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "[NULL]\n"); 2478c2aa98e2SPeter Wemm return; 2479c2aa98e2SPeter Wemm } 2480c2aa98e2SPeter Wemm 2481c2aa98e2SPeter Wemm while (a != NULL) 2482c2aa98e2SPeter Wemm { 2483*5b0945b5SGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%p=", (void *)a); 2484e92d3f3fSGregory Neil Shapiro (void) sm_io_flush(fp, SM_TIME_DEFAULT); 2485c2aa98e2SPeter Wemm 2486c2aa98e2SPeter Wemm /* find the mailer -- carefully */ 2487c2aa98e2SPeter Wemm m = a->q_mailer; 2488c2aa98e2SPeter Wemm if (m == NULL) 2489c2aa98e2SPeter Wemm { 2490c2aa98e2SPeter Wemm m = &pseudomailer; 2491c2aa98e2SPeter Wemm m->m_mno = -1; 2492c2aa98e2SPeter Wemm m->m_name = "NULL"; 2493c2aa98e2SPeter Wemm } 2494c2aa98e2SPeter Wemm 2495e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 249640266059SGregory Neil Shapiro "%s:\n\tmailer %d (%s), host `%s'\n", 2497c2aa98e2SPeter Wemm a->q_paddr == NULL ? "<null>" : a->q_paddr, 2498c2aa98e2SPeter Wemm m->m_mno, m->m_name, 2499c2aa98e2SPeter Wemm a->q_host == NULL ? "<null>" : a->q_host); 2500e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 250140266059SGregory Neil Shapiro "\tuser `%s', ruser `%s'\n", 2502c2aa98e2SPeter Wemm a->q_user, 2503c2aa98e2SPeter Wemm a->q_ruser == NULL ? "<null>" : a->q_ruser); 2504e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\tstate="); 250506f25ae9SGregory Neil Shapiro switch (a->q_state) 250606f25ae9SGregory Neil Shapiro { 250706f25ae9SGregory Neil Shapiro case QS_OK: 2508e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "OK"); 250906f25ae9SGregory Neil Shapiro break; 251006f25ae9SGregory Neil Shapiro 251106f25ae9SGregory Neil Shapiro case QS_DONTSEND: 2512e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 251340266059SGregory Neil Shapiro "DONTSEND"); 251406f25ae9SGregory Neil Shapiro break; 251506f25ae9SGregory Neil Shapiro 251606f25ae9SGregory Neil Shapiro case QS_BADADDR: 2517e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 251840266059SGregory Neil Shapiro "BADADDR"); 251906f25ae9SGregory Neil Shapiro break; 252006f25ae9SGregory Neil Shapiro 252106f25ae9SGregory Neil Shapiro case QS_QUEUEUP: 2522e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 252340266059SGregory Neil Shapiro "QUEUEUP"); 252440266059SGregory Neil Shapiro break; 252540266059SGregory Neil Shapiro 252640266059SGregory Neil Shapiro case QS_RETRY: 2527e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "RETRY"); 252806f25ae9SGregory Neil Shapiro break; 252906f25ae9SGregory Neil Shapiro 253006f25ae9SGregory Neil Shapiro case QS_SENT: 2531e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "SENT"); 253206f25ae9SGregory Neil Shapiro break; 253306f25ae9SGregory Neil Shapiro 253406f25ae9SGregory Neil Shapiro case QS_VERIFIED: 2535e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 253640266059SGregory Neil Shapiro "VERIFIED"); 253706f25ae9SGregory Neil Shapiro break; 253806f25ae9SGregory Neil Shapiro 253906f25ae9SGregory Neil Shapiro case QS_EXPANDED: 2540e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 254140266059SGregory Neil Shapiro "EXPANDED"); 254206f25ae9SGregory Neil Shapiro break; 254306f25ae9SGregory Neil Shapiro 254406f25ae9SGregory Neil Shapiro case QS_SENDER: 2545e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 254640266059SGregory Neil Shapiro "SENDER"); 254706f25ae9SGregory Neil Shapiro break; 254806f25ae9SGregory Neil Shapiro 254906f25ae9SGregory Neil Shapiro case QS_CLONED: 2550e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 255140266059SGregory Neil Shapiro "CLONED"); 255206f25ae9SGregory Neil Shapiro break; 255306f25ae9SGregory Neil Shapiro 255406f25ae9SGregory Neil Shapiro case QS_DISCARDED: 2555e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 255640266059SGregory Neil Shapiro "DISCARDED"); 255706f25ae9SGregory Neil Shapiro break; 255806f25ae9SGregory Neil Shapiro 255906f25ae9SGregory Neil Shapiro case QS_REPLACED: 2560e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 256140266059SGregory Neil Shapiro "REPLACED"); 256206f25ae9SGregory Neil Shapiro break; 256306f25ae9SGregory Neil Shapiro 256406f25ae9SGregory Neil Shapiro case QS_REMOVED: 2565e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 256640266059SGregory Neil Shapiro "REMOVED"); 256706f25ae9SGregory Neil Shapiro break; 256806f25ae9SGregory Neil Shapiro 256906f25ae9SGregory Neil Shapiro case QS_DUPLICATE: 2570e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 257140266059SGregory Neil Shapiro "DUPLICATE"); 257206f25ae9SGregory Neil Shapiro break; 257306f25ae9SGregory Neil Shapiro 257406f25ae9SGregory Neil Shapiro case QS_INCLUDED: 2575e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 257640266059SGregory Neil Shapiro "INCLUDED"); 257706f25ae9SGregory Neil Shapiro break; 257806f25ae9SGregory Neil Shapiro 257906f25ae9SGregory Neil Shapiro default: 2580e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 258140266059SGregory Neil Shapiro "%d", a->q_state); 258206f25ae9SGregory Neil Shapiro break; 258306f25ae9SGregory Neil Shapiro } 2584e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 258540266059SGregory Neil Shapiro ", next=%p, alias %p, uid %d, gid %d\n", 2586*5b0945b5SGregory Neil Shapiro (void *)a->q_next, (void *)a->q_alias, 2587c2aa98e2SPeter Wemm (int) a->q_uid, (int) a->q_gid); 2588e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\tflags=%lx<", 258940266059SGregory Neil Shapiro a->q_flags); 259040266059SGregory Neil Shapiro firstone = true; 2591c2aa98e2SPeter Wemm for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++) 2592c2aa98e2SPeter Wemm { 2593c2aa98e2SPeter Wemm if (!bitset(qfp->qf_bit, a->q_flags)) 2594c2aa98e2SPeter Wemm continue; 2595c2aa98e2SPeter Wemm if (!firstone) 2596e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 259740266059SGregory Neil Shapiro ","); 259840266059SGregory Neil Shapiro firstone = false; 2599e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s", 260040266059SGregory Neil Shapiro qfp->qf_name); 2601c2aa98e2SPeter Wemm } 2602e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, ">\n"); 2603e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 260440266059SGregory Neil Shapiro "\towner=%s, home=\"%s\", fullname=\"%s\"\n", 2605c2aa98e2SPeter Wemm a->q_owner == NULL ? "(none)" : a->q_owner, 2606c2aa98e2SPeter Wemm a->q_home == NULL ? "(none)" : a->q_home, 2607c2aa98e2SPeter Wemm a->q_fullname == NULL ? "(none)" : a->q_fullname); 2608e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 260940266059SGregory Neil Shapiro "\torcpt=\"%s\", statmta=%s, status=%s\n", 2610c2aa98e2SPeter Wemm a->q_orcpt == NULL ? "(none)" : a->q_orcpt, 2611c2aa98e2SPeter Wemm a->q_statmta == NULL ? "(none)" : a->q_statmta, 2612c2aa98e2SPeter Wemm a->q_status == NULL ? "(none)" : a->q_status); 2613e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 261440266059SGregory Neil Shapiro "\tfinalrcpt=\"%s\"\n", 261540266059SGregory Neil Shapiro a->q_finalrcpt == NULL ? "(none)" : a->q_finalrcpt); 2616e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 261740266059SGregory Neil Shapiro "\trstatus=\"%s\"\n", 2618c2aa98e2SPeter Wemm a->q_rstatus == NULL ? "(none)" : a->q_rstatus); 2619e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 262040266059SGregory Neil Shapiro "\tstatdate=%s\n", 262106f25ae9SGregory Neil Shapiro a->q_statdate == 0 ? "(none)" : ctime(&a->q_statdate)); 2622c2aa98e2SPeter Wemm 2623c2aa98e2SPeter Wemm if (!follow) 2624c2aa98e2SPeter Wemm return; 2625c2aa98e2SPeter Wemm a = a->q_next; 2626c2aa98e2SPeter Wemm } 2627c2aa98e2SPeter Wemm } 262840266059SGregory Neil Shapiro /* 262940266059SGregory Neil Shapiro ** EMPTYADDR -- return true if this address is empty (``<>'') 2630c2aa98e2SPeter Wemm ** 2631c2aa98e2SPeter Wemm ** Parameters: 2632c2aa98e2SPeter Wemm ** a -- pointer to the address 2633c2aa98e2SPeter Wemm ** 2634c2aa98e2SPeter Wemm ** Returns: 263540266059SGregory Neil Shapiro ** true -- if this address is "empty" (i.e., no one should 2636c2aa98e2SPeter Wemm ** ever generate replies to it. 263740266059SGregory Neil Shapiro ** false -- if it is a "regular" (read: replyable) address. 2638c2aa98e2SPeter Wemm */ 2639c2aa98e2SPeter Wemm 2640c2aa98e2SPeter Wemm bool 2641c2aa98e2SPeter Wemm emptyaddr(a) 2642c2aa98e2SPeter Wemm register ADDRESS *a; 2643c2aa98e2SPeter Wemm { 2644c2aa98e2SPeter Wemm return a->q_paddr == NULL || strcmp(a->q_paddr, "<>") == 0 || 2645c2aa98e2SPeter Wemm a->q_user == NULL || strcmp(a->q_user, "<>") == 0; 2646c2aa98e2SPeter Wemm } 264740266059SGregory Neil Shapiro /* 2648c2aa98e2SPeter Wemm ** REMOTENAME -- return the name relative to the current mailer 2649c2aa98e2SPeter Wemm ** 2650c2aa98e2SPeter Wemm ** Parameters: 2651c2aa98e2SPeter Wemm ** name -- the name to translate. 2652a7ec597cSGregory Neil Shapiro ** m -- the mailer that we want to do rewriting relative to. 2653c2aa98e2SPeter Wemm ** flags -- fine tune operations. 2654c2aa98e2SPeter Wemm ** pstat -- pointer to status word. 2655c2aa98e2SPeter Wemm ** e -- the current envelope. 2656c2aa98e2SPeter Wemm ** 2657c2aa98e2SPeter Wemm ** Returns: 2658c2aa98e2SPeter Wemm ** the text string representing this address relative to 2659c2aa98e2SPeter Wemm ** the receiving mailer. 2660c2aa98e2SPeter Wemm ** 2661c2aa98e2SPeter Wemm ** Side Effects: 2662c2aa98e2SPeter Wemm ** none. 2663c2aa98e2SPeter Wemm ** 2664c2aa98e2SPeter Wemm ** Warnings: 2665c2aa98e2SPeter Wemm ** The text string returned is tucked away locally; 2666c2aa98e2SPeter Wemm ** copy it if you intend to save it. 2667c2aa98e2SPeter Wemm */ 2668c2aa98e2SPeter Wemm 2669c2aa98e2SPeter Wemm char * 2670c2aa98e2SPeter Wemm remotename(name, m, flags, pstat, e) 2671c2aa98e2SPeter Wemm char *name; 2672c2aa98e2SPeter Wemm struct mailer *m; 2673c2aa98e2SPeter Wemm int flags; 2674c2aa98e2SPeter Wemm int *pstat; 2675c2aa98e2SPeter Wemm register ENVELOPE *e; 2676c2aa98e2SPeter Wemm { 2677c2aa98e2SPeter Wemm register char **pvp; 267840266059SGregory Neil Shapiro char *SM_NONVOLATILE fancy; 267940266059SGregory Neil Shapiro char *oldg; 2680c2aa98e2SPeter Wemm int rwset; 2681c2aa98e2SPeter Wemm static char buf[MAXNAME + 1]; 2682c2aa98e2SPeter Wemm char lbuf[MAXNAME + 1]; 2683c2aa98e2SPeter Wemm char pvpbuf[PSBUFSIZE]; 268406f25ae9SGregory Neil Shapiro char addrtype[4]; 2685c2aa98e2SPeter Wemm 2686c2aa98e2SPeter Wemm if (tTd(12, 1)) 2687d0cef73dSGregory Neil Shapiro { 2688d0cef73dSGregory Neil Shapiro sm_dprintf("remotename("); 2689d0cef73dSGregory Neil Shapiro xputs(sm_debug_file(), name); 2690d0cef73dSGregory Neil Shapiro sm_dprintf(")\n"); 2691d0cef73dSGregory Neil Shapiro } 2692c2aa98e2SPeter Wemm 2693c2aa98e2SPeter Wemm /* don't do anything if we are tagging it as special */ 2694c2aa98e2SPeter Wemm if (bitset(RF_SENDERADDR, flags)) 269506f25ae9SGregory Neil Shapiro { 2696c2aa98e2SPeter Wemm rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset 2697c2aa98e2SPeter Wemm : m->m_se_rwset; 269806f25ae9SGregory Neil Shapiro addrtype[2] = 's'; 269906f25ae9SGregory Neil Shapiro } 2700c2aa98e2SPeter Wemm else 270106f25ae9SGregory Neil Shapiro { 2702c2aa98e2SPeter Wemm rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset 2703c2aa98e2SPeter Wemm : m->m_re_rwset; 270406f25ae9SGregory Neil Shapiro addrtype[2] = 'r'; 270506f25ae9SGregory Neil Shapiro } 2706c2aa98e2SPeter Wemm if (rwset < 0) 270706f25ae9SGregory Neil Shapiro return name; 270806f25ae9SGregory Neil Shapiro addrtype[1] = ' '; 270906f25ae9SGregory Neil Shapiro addrtype[3] = '\0'; 271006f25ae9SGregory Neil Shapiro addrtype[0] = bitset(RF_HEADERADDR, flags) ? 'h' : 'e'; 271140266059SGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, macid("{addr_type}"), addrtype); 2712c2aa98e2SPeter Wemm 2713c2aa98e2SPeter Wemm /* 2714c2aa98e2SPeter Wemm ** Do a heuristic crack of this name to extract any comment info. 2715c2aa98e2SPeter Wemm ** This will leave the name as a comment and a $g macro. 2716c2aa98e2SPeter Wemm */ 2717c2aa98e2SPeter Wemm 2718c2aa98e2SPeter Wemm if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags)) 2719c2aa98e2SPeter Wemm fancy = "\201g"; 2720c2aa98e2SPeter Wemm else 2721d9986b26SGregory Neil Shapiro fancy = crackaddr(name, e); 2722c2aa98e2SPeter Wemm 2723c2aa98e2SPeter Wemm /* 2724c2aa98e2SPeter Wemm ** Turn the name into canonical form. 2725c2aa98e2SPeter Wemm ** Normally this will be RFC 822 style, i.e., "user@domain". 2726c2aa98e2SPeter Wemm ** If this only resolves to "user", and the "C" flag is 2727c2aa98e2SPeter Wemm ** specified in the sending mailer, then the sender's 2728c2aa98e2SPeter Wemm ** domain will be appended. 2729c2aa98e2SPeter Wemm */ 2730c2aa98e2SPeter Wemm 2731d0cef73dSGregory Neil Shapiro pvp = prescan(name, '\0', pvpbuf, sizeof(pvpbuf), NULL, NULL, false); 2732c2aa98e2SPeter Wemm if (pvp == NULL) 273306f25ae9SGregory Neil Shapiro return name; 273440266059SGregory Neil Shapiro if (REWRITE(pvp, 3, e) == EX_TEMPFAIL) 2735c2aa98e2SPeter Wemm *pstat = EX_TEMPFAIL; 2736c2aa98e2SPeter Wemm if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL) 2737c2aa98e2SPeter Wemm { 2738c2aa98e2SPeter Wemm /* append from domain to this address */ 2739c2aa98e2SPeter Wemm register char **pxp = pvp; 274006f25ae9SGregory Neil Shapiro int l = MAXATOM; /* size of buffer for pvp */ 2741c2aa98e2SPeter Wemm 2742c2aa98e2SPeter Wemm /* see if there is an "@domain" in the current name */ 2743c2aa98e2SPeter Wemm while (*pxp != NULL && strcmp(*pxp, "@") != 0) 274406f25ae9SGregory Neil Shapiro { 2745c2aa98e2SPeter Wemm pxp++; 274606f25ae9SGregory Neil Shapiro --l; 274706f25ae9SGregory Neil Shapiro } 2748c2aa98e2SPeter Wemm if (*pxp == NULL) 2749c2aa98e2SPeter Wemm { 2750c2aa98e2SPeter Wemm /* no.... append the "@domain" from the sender */ 2751c2aa98e2SPeter Wemm register char **qxq = e->e_fromdomain; 2752c2aa98e2SPeter Wemm 2753c2aa98e2SPeter Wemm while ((*pxp++ = *qxq++) != NULL) 275406f25ae9SGregory Neil Shapiro { 275506f25ae9SGregory Neil Shapiro if (--l <= 0) 275606f25ae9SGregory Neil Shapiro { 275706f25ae9SGregory Neil Shapiro *--pxp = NULL; 275806f25ae9SGregory Neil Shapiro usrerr("553 5.1.0 remotename: too many tokens"); 275906f25ae9SGregory Neil Shapiro *pstat = EX_UNAVAILABLE; 276006f25ae9SGregory Neil Shapiro break; 276106f25ae9SGregory Neil Shapiro } 276206f25ae9SGregory Neil Shapiro } 276340266059SGregory Neil Shapiro if (REWRITE(pvp, 3, e) == EX_TEMPFAIL) 2764c2aa98e2SPeter Wemm *pstat = EX_TEMPFAIL; 2765c2aa98e2SPeter Wemm } 2766c2aa98e2SPeter Wemm } 2767c2aa98e2SPeter Wemm 2768c2aa98e2SPeter Wemm /* 2769c2aa98e2SPeter Wemm ** Do more specific rewriting. 2770c2aa98e2SPeter Wemm ** Rewrite using ruleset 1 or 2 depending on whether this is 2771c2aa98e2SPeter Wemm ** a sender address or not. 2772c2aa98e2SPeter Wemm ** Then run it through any receiving-mailer-specific rulesets. 2773c2aa98e2SPeter Wemm */ 2774c2aa98e2SPeter Wemm 2775c2aa98e2SPeter Wemm if (bitset(RF_SENDERADDR, flags)) 2776c2aa98e2SPeter Wemm { 277740266059SGregory Neil Shapiro if (REWRITE(pvp, 1, e) == EX_TEMPFAIL) 2778c2aa98e2SPeter Wemm *pstat = EX_TEMPFAIL; 2779c2aa98e2SPeter Wemm } 2780c2aa98e2SPeter Wemm else 2781c2aa98e2SPeter Wemm { 278240266059SGregory Neil Shapiro if (REWRITE(pvp, 2, e) == EX_TEMPFAIL) 2783c2aa98e2SPeter Wemm *pstat = EX_TEMPFAIL; 2784c2aa98e2SPeter Wemm } 2785c2aa98e2SPeter Wemm if (rwset > 0) 2786c2aa98e2SPeter Wemm { 278740266059SGregory Neil Shapiro if (REWRITE(pvp, rwset, e) == EX_TEMPFAIL) 2788c2aa98e2SPeter Wemm *pstat = EX_TEMPFAIL; 2789c2aa98e2SPeter Wemm } 2790c2aa98e2SPeter Wemm 2791c2aa98e2SPeter Wemm /* 2792c2aa98e2SPeter Wemm ** Do any final sanitation the address may require. 2793c2aa98e2SPeter Wemm ** This will normally be used to turn internal forms 2794c2aa98e2SPeter Wemm ** (e.g., user@host.LOCAL) into external form. This 2795c2aa98e2SPeter Wemm ** may be used as a default to the above rules. 2796c2aa98e2SPeter Wemm */ 2797c2aa98e2SPeter Wemm 279840266059SGregory Neil Shapiro if (REWRITE(pvp, 4, e) == EX_TEMPFAIL) 2799c2aa98e2SPeter Wemm *pstat = EX_TEMPFAIL; 2800c2aa98e2SPeter Wemm 2801c2aa98e2SPeter Wemm /* 2802c2aa98e2SPeter Wemm ** Now restore the comment information we had at the beginning. 2803c2aa98e2SPeter Wemm */ 2804c2aa98e2SPeter Wemm 2805d0cef73dSGregory Neil Shapiro cataddr(pvp, NULL, lbuf, sizeof(lbuf), '\0', false); 280640266059SGregory Neil Shapiro oldg = macget(&e->e_macro, 'g'); 280740266059SGregory Neil Shapiro macset(&e->e_macro, 'g', lbuf); 2808c2aa98e2SPeter Wemm 280940266059SGregory Neil Shapiro SM_TRY 2810c2aa98e2SPeter Wemm /* need to make sure route-addrs have <angle brackets> */ 2811c2aa98e2SPeter Wemm if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@') 2812d0cef73dSGregory Neil Shapiro expand("<\201g>", buf, sizeof(buf), e); 2813c2aa98e2SPeter Wemm else 2814d0cef73dSGregory Neil Shapiro expand(fancy, buf, sizeof(buf), e); 281540266059SGregory Neil Shapiro SM_FINALLY 281640266059SGregory Neil Shapiro macset(&e->e_macro, 'g', oldg); 281740266059SGregory Neil Shapiro SM_END_TRY 2818c2aa98e2SPeter Wemm 2819c2aa98e2SPeter Wemm if (tTd(12, 1)) 2820d0cef73dSGregory Neil Shapiro { 2821d0cef73dSGregory Neil Shapiro sm_dprintf("remotename => `"); 2822d0cef73dSGregory Neil Shapiro xputs(sm_debug_file(), buf); 2823da7d7b9cSGregory Neil Shapiro sm_dprintf("', stat=%d\n", *pstat); 2824d0cef73dSGregory Neil Shapiro } 282506f25ae9SGregory Neil Shapiro return buf; 2826c2aa98e2SPeter Wemm } 282740266059SGregory Neil Shapiro /* 2828c2aa98e2SPeter Wemm ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection 2829c2aa98e2SPeter Wemm ** 2830c2aa98e2SPeter Wemm ** Parameters: 2831c2aa98e2SPeter Wemm ** a -- the address to map (but just the user name part). 2832c2aa98e2SPeter Wemm ** sendq -- the sendq in which to install any replacement 2833c2aa98e2SPeter Wemm ** addresses. 2834c2aa98e2SPeter Wemm ** aliaslevel -- the alias nesting depth. 2835c2aa98e2SPeter Wemm ** e -- the envelope. 2836c2aa98e2SPeter Wemm ** 2837c2aa98e2SPeter Wemm ** Returns: 2838c2aa98e2SPeter Wemm ** none. 2839c2aa98e2SPeter Wemm */ 2840c2aa98e2SPeter Wemm 2841c2aa98e2SPeter Wemm #define Q_COPYFLAGS (QPRIMARY|QBOGUSSHELL|QUNSAFEADDR|\ 2842c2aa98e2SPeter Wemm Q_PINGFLAGS|QHASNOTIFY|\ 284340266059SGregory Neil Shapiro QRELAYED|QEXPANDED|QDELIVERED|QDELAYED|\ 284440266059SGregory Neil Shapiro QBYTRACE|QBYNDELAY|QBYNRELAY) 2845c2aa98e2SPeter Wemm 2846c2aa98e2SPeter Wemm void 2847c2aa98e2SPeter Wemm maplocaluser(a, sendq, aliaslevel, e) 2848c2aa98e2SPeter Wemm register ADDRESS *a; 2849c2aa98e2SPeter Wemm ADDRESS **sendq; 2850c2aa98e2SPeter Wemm int aliaslevel; 2851c2aa98e2SPeter Wemm ENVELOPE *e; 2852c2aa98e2SPeter Wemm { 2853c2aa98e2SPeter Wemm register char **pvp; 285440266059SGregory Neil Shapiro register ADDRESS *SM_NONVOLATILE a1 = NULL; 2855c2aa98e2SPeter Wemm char pvpbuf[PSBUFSIZE]; 2856c2aa98e2SPeter Wemm 2857c2aa98e2SPeter Wemm if (tTd(29, 1)) 2858c2aa98e2SPeter Wemm { 285940266059SGregory Neil Shapiro sm_dprintf("maplocaluser: "); 2860e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), a, false); 2861c2aa98e2SPeter Wemm } 2862d0cef73dSGregory Neil Shapiro pvp = prescan(a->q_user, '\0', pvpbuf, sizeof(pvpbuf), NULL, NULL, 2863d0cef73dSGregory Neil Shapiro false); 2864c2aa98e2SPeter Wemm if (pvp == NULL) 2865c2aa98e2SPeter Wemm { 2866c2aa98e2SPeter Wemm if (tTd(29, 9)) 286740266059SGregory Neil Shapiro sm_dprintf("maplocaluser: cannot prescan %s\n", 286806f25ae9SGregory Neil Shapiro a->q_user); 2869c2aa98e2SPeter Wemm return; 2870c2aa98e2SPeter Wemm } 2871c2aa98e2SPeter Wemm 287240266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'h', a->q_host); 287340266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'u', a->q_user); 287440266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'z', a->q_home); 2875c2aa98e2SPeter Wemm 287640266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e r"); 287740266059SGregory Neil Shapiro if (REWRITE(pvp, 5, e) == EX_TEMPFAIL) 2878c2aa98e2SPeter Wemm { 2879c2aa98e2SPeter Wemm if (tTd(29, 9)) 288040266059SGregory Neil Shapiro sm_dprintf("maplocaluser: rewrite tempfail\n"); 288106f25ae9SGregory Neil Shapiro a->q_state = QS_QUEUEUP; 2882c2aa98e2SPeter Wemm a->q_status = "4.4.3"; 2883c2aa98e2SPeter Wemm return; 2884c2aa98e2SPeter Wemm } 2885c2aa98e2SPeter Wemm if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 2886c2aa98e2SPeter Wemm { 2887c2aa98e2SPeter Wemm if (tTd(29, 9)) 288840266059SGregory Neil Shapiro sm_dprintf("maplocaluser: doesn't resolve\n"); 2889c2aa98e2SPeter Wemm return; 2890c2aa98e2SPeter Wemm } 2891c2aa98e2SPeter Wemm 289240266059SGregory Neil Shapiro SM_TRY 2893c2aa98e2SPeter Wemm a1 = buildaddr(pvp, NULL, 0, e); 289440266059SGregory Neil Shapiro SM_EXCEPT(exc, "E:mta.quickabort") 289540266059SGregory Neil Shapiro 289640266059SGregory Neil Shapiro /* 289740266059SGregory Neil Shapiro ** mark address as bad, S5 returned an error 289840266059SGregory Neil Shapiro ** and we gave that back to the SMTP client. 289940266059SGregory Neil Shapiro */ 290040266059SGregory Neil Shapiro 290140266059SGregory Neil Shapiro a->q_state = QS_DONTSEND; 290240266059SGregory Neil Shapiro sm_exc_raisenew_x(&EtypeQuickAbort, 2); 290340266059SGregory Neil Shapiro SM_END_TRY 290440266059SGregory Neil Shapiro 290540266059SGregory Neil Shapiro /* if non-null, mailer destination specified -- has it changed? */ 2906c2aa98e2SPeter Wemm if (a1 == NULL || sameaddr(a, a1)) 2907c2aa98e2SPeter Wemm { 2908c2aa98e2SPeter Wemm if (tTd(29, 9)) 290940266059SGregory Neil Shapiro sm_dprintf("maplocaluser: address unchanged\n"); 2910c2aa98e2SPeter Wemm return; 2911c2aa98e2SPeter Wemm } 2912c2aa98e2SPeter Wemm 2913c2aa98e2SPeter Wemm /* make new address take on flags and print attributes of old */ 2914c2aa98e2SPeter Wemm a1->q_flags &= ~Q_COPYFLAGS; 2915c2aa98e2SPeter Wemm a1->q_flags |= a->q_flags & Q_COPYFLAGS; 291640266059SGregory Neil Shapiro a1->q_paddr = sm_rpool_strdup_x(e->e_rpool, a->q_paddr); 291740266059SGregory Neil Shapiro a1->q_finalrcpt = a->q_finalrcpt; 291806f25ae9SGregory Neil Shapiro a1->q_orcpt = a->q_orcpt; 2919c2aa98e2SPeter Wemm 2920c2aa98e2SPeter Wemm /* mark old address as dead; insert new address */ 292106f25ae9SGregory Neil Shapiro a->q_state = QS_REPLACED; 2922c2aa98e2SPeter Wemm if (tTd(29, 5)) 2923c2aa98e2SPeter Wemm { 292440266059SGregory Neil Shapiro sm_dprintf("maplocaluser: QS_REPLACED "); 2925e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), a, false); 2926c2aa98e2SPeter Wemm } 2927c2aa98e2SPeter Wemm a1->q_alias = a; 292840266059SGregory Neil Shapiro allocaddr(a1, RF_COPYALL, sm_rpool_strdup_x(e->e_rpool, a->q_paddr), e); 2929c2aa98e2SPeter Wemm (void) recipient(a1, sendq, aliaslevel, e); 2930c2aa98e2SPeter Wemm } 293140266059SGregory Neil Shapiro /* 2932c2aa98e2SPeter Wemm ** DEQUOTE_INIT -- initialize dequote map 2933c2aa98e2SPeter Wemm ** 2934c2aa98e2SPeter Wemm ** Parameters: 2935c2aa98e2SPeter Wemm ** map -- the internal map structure. 2936c2aa98e2SPeter Wemm ** args -- arguments. 2937c2aa98e2SPeter Wemm ** 2938c2aa98e2SPeter Wemm ** Returns: 293940266059SGregory Neil Shapiro ** true. 2940c2aa98e2SPeter Wemm */ 2941c2aa98e2SPeter Wemm 2942c2aa98e2SPeter Wemm bool 2943c2aa98e2SPeter Wemm dequote_init(map, args) 2944c2aa98e2SPeter Wemm MAP *map; 2945c2aa98e2SPeter Wemm char *args; 2946c2aa98e2SPeter Wemm { 2947c2aa98e2SPeter Wemm register char *p = args; 2948c2aa98e2SPeter Wemm 294906f25ae9SGregory Neil Shapiro /* there is no check whether there is really an argument */ 2950c2aa98e2SPeter Wemm map->map_mflags |= MF_KEEPQUOTES; 2951c2aa98e2SPeter Wemm for (;;) 2952c2aa98e2SPeter Wemm { 2953*5b0945b5SGregory Neil Shapiro while (SM_ISSPACE(*p)) 2954c2aa98e2SPeter Wemm p++; 2955c2aa98e2SPeter Wemm if (*p != '-') 2956c2aa98e2SPeter Wemm break; 2957c2aa98e2SPeter Wemm switch (*++p) 2958c2aa98e2SPeter Wemm { 2959c2aa98e2SPeter Wemm case 'a': 2960c2aa98e2SPeter Wemm map->map_app = ++p; 2961c2aa98e2SPeter Wemm break; 2962c2aa98e2SPeter Wemm 296306f25ae9SGregory Neil Shapiro case 'D': 296406f25ae9SGregory Neil Shapiro map->map_mflags |= MF_DEFER; 296506f25ae9SGregory Neil Shapiro break; 296606f25ae9SGregory Neil Shapiro 296706f25ae9SGregory Neil Shapiro case 'S': 2968c2aa98e2SPeter Wemm case 's': 296906f25ae9SGregory Neil Shapiro map->map_spacesub = *++p; 2970c2aa98e2SPeter Wemm break; 2971c2aa98e2SPeter Wemm } 2972*5b0945b5SGregory Neil Shapiro while (*p != '\0' && !(SM_ISSPACE(*p))) 2973c2aa98e2SPeter Wemm p++; 2974c2aa98e2SPeter Wemm if (*p != '\0') 2975c2aa98e2SPeter Wemm *p = '\0'; 2976c2aa98e2SPeter Wemm } 2977c2aa98e2SPeter Wemm if (map->map_app != NULL) 2978c2aa98e2SPeter Wemm map->map_app = newstr(map->map_app); 2979c2aa98e2SPeter Wemm 298040266059SGregory Neil Shapiro return true; 2981c2aa98e2SPeter Wemm } 298240266059SGregory Neil Shapiro /* 2983c2aa98e2SPeter Wemm ** DEQUOTE_MAP -- unquote an address 2984c2aa98e2SPeter Wemm ** 2985c2aa98e2SPeter Wemm ** Parameters: 2986c2aa98e2SPeter Wemm ** map -- the internal map structure (ignored). 2987c2aa98e2SPeter Wemm ** name -- the name to dequote. 2988c2aa98e2SPeter Wemm ** av -- arguments (ignored). 2989c2aa98e2SPeter Wemm ** statp -- pointer to status out-parameter. 2990c2aa98e2SPeter Wemm ** 2991c2aa98e2SPeter Wemm ** Returns: 2992c2aa98e2SPeter Wemm ** NULL -- if there were no quotes, or if the resulting 2993c2aa98e2SPeter Wemm ** unquoted buffer would not be acceptable to prescan. 2994c2aa98e2SPeter Wemm ** else -- The dequoted buffer. 2995c2aa98e2SPeter Wemm */ 2996c2aa98e2SPeter Wemm 2997c2aa98e2SPeter Wemm /* ARGSUSED2 */ 2998c2aa98e2SPeter Wemm char * 2999c2aa98e2SPeter Wemm dequote_map(map, name, av, statp) 3000c2aa98e2SPeter Wemm MAP *map; 3001c2aa98e2SPeter Wemm char *name; 3002c2aa98e2SPeter Wemm char **av; 3003c2aa98e2SPeter Wemm int *statp; 3004c2aa98e2SPeter Wemm { 3005c2aa98e2SPeter Wemm register char *p; 3006c2aa98e2SPeter Wemm register char *q; 3007c2aa98e2SPeter Wemm register char c; 3008c2aa98e2SPeter Wemm int anglecnt = 0; 3009c2aa98e2SPeter Wemm int cmntcnt = 0; 3010c2aa98e2SPeter Wemm int quotecnt = 0; 3011c2aa98e2SPeter Wemm int spacecnt = 0; 301240266059SGregory Neil Shapiro bool quotemode = false; 301340266059SGregory Neil Shapiro bool bslashmode = false; 301406f25ae9SGregory Neil Shapiro char spacesub = map->map_spacesub; 3015c2aa98e2SPeter Wemm 3016c2aa98e2SPeter Wemm for (p = q = name; (c = *p++) != '\0'; ) 3017c2aa98e2SPeter Wemm { 3018c2aa98e2SPeter Wemm if (bslashmode) 3019c2aa98e2SPeter Wemm { 302040266059SGregory Neil Shapiro bslashmode = false; 3021c2aa98e2SPeter Wemm *q++ = c; 3022c2aa98e2SPeter Wemm continue; 3023c2aa98e2SPeter Wemm } 3024c2aa98e2SPeter Wemm 3025c2aa98e2SPeter Wemm if (c == ' ' && spacesub != '\0') 3026c2aa98e2SPeter Wemm c = spacesub; 3027c2aa98e2SPeter Wemm 3028c2aa98e2SPeter Wemm switch (c) 3029c2aa98e2SPeter Wemm { 3030c2aa98e2SPeter Wemm case '\\': 303140266059SGregory Neil Shapiro bslashmode = true; 3032c2aa98e2SPeter Wemm break; 3033c2aa98e2SPeter Wemm 3034c2aa98e2SPeter Wemm case '(': 3035c2aa98e2SPeter Wemm cmntcnt++; 3036c2aa98e2SPeter Wemm break; 3037c2aa98e2SPeter Wemm 3038c2aa98e2SPeter Wemm case ')': 3039c2aa98e2SPeter Wemm if (cmntcnt-- <= 0) 3040c2aa98e2SPeter Wemm return NULL; 3041c2aa98e2SPeter Wemm break; 3042c2aa98e2SPeter Wemm 3043c2aa98e2SPeter Wemm case ' ': 304406f25ae9SGregory Neil Shapiro case '\t': 3045c2aa98e2SPeter Wemm spacecnt++; 3046c2aa98e2SPeter Wemm break; 3047c2aa98e2SPeter Wemm } 3048c2aa98e2SPeter Wemm 3049c2aa98e2SPeter Wemm if (cmntcnt > 0) 3050c2aa98e2SPeter Wemm { 3051c2aa98e2SPeter Wemm *q++ = c; 3052c2aa98e2SPeter Wemm continue; 3053c2aa98e2SPeter Wemm } 3054c2aa98e2SPeter Wemm 3055c2aa98e2SPeter Wemm switch (c) 3056c2aa98e2SPeter Wemm { 3057c2aa98e2SPeter Wemm case '"': 3058c2aa98e2SPeter Wemm quotemode = !quotemode; 3059c2aa98e2SPeter Wemm quotecnt++; 3060c2aa98e2SPeter Wemm continue; 3061c2aa98e2SPeter Wemm 3062c2aa98e2SPeter Wemm case '<': 3063c2aa98e2SPeter Wemm anglecnt++; 3064c2aa98e2SPeter Wemm break; 3065c2aa98e2SPeter Wemm 3066c2aa98e2SPeter Wemm case '>': 3067c2aa98e2SPeter Wemm if (anglecnt-- <= 0) 3068c2aa98e2SPeter Wemm return NULL; 3069c2aa98e2SPeter Wemm break; 3070c2aa98e2SPeter Wemm } 3071c2aa98e2SPeter Wemm *q++ = c; 3072c2aa98e2SPeter Wemm } 3073c2aa98e2SPeter Wemm 3074c2aa98e2SPeter Wemm if (anglecnt != 0 || cmntcnt != 0 || bslashmode || 3075c2aa98e2SPeter Wemm quotemode || quotecnt <= 0 || spacecnt != 0) 3076c2aa98e2SPeter Wemm return NULL; 3077c2aa98e2SPeter Wemm *q++ = '\0'; 3078c2aa98e2SPeter Wemm return map_rewrite(map, name, strlen(name), NULL); 3079c2aa98e2SPeter Wemm } 308040266059SGregory Neil Shapiro /* 3081c2aa98e2SPeter Wemm ** RSCHECK -- check string(s) for validity using rewriting sets 3082c2aa98e2SPeter Wemm ** 3083c2aa98e2SPeter Wemm ** Parameters: 3084c2aa98e2SPeter Wemm ** rwset -- the rewriting set to use. 3085c2aa98e2SPeter Wemm ** p1 -- the first string to check. 3086*5b0945b5SGregory Neil Shapiro ** p2 -- the second string to check -- may be NULL. 3087c2aa98e2SPeter Wemm ** e -- the current envelope. 3088959366dcSGregory Neil Shapiro ** flags -- control some behavior, see RSF_ in sendmail.h 308940266059SGregory Neil Shapiro ** logl -- logging level. 3090193538b7SGregory Neil Shapiro ** host -- NULL or relay host. 309140266059SGregory Neil Shapiro ** logid -- id for sm_syslog. 3092d0cef73dSGregory Neil Shapiro ** addr -- if not NULL and ruleset returns $#error: 3093d0cef73dSGregory Neil Shapiro ** store mailer triple here. 3094da7d7b9cSGregory Neil Shapiro ** addrstr -- if not NULL and ruleset does not return $#: 3095da7d7b9cSGregory Neil Shapiro ** address string 3096c2aa98e2SPeter Wemm ** 3097c2aa98e2SPeter Wemm ** Returns: 3098c2aa98e2SPeter Wemm ** EX_OK -- if the rwset doesn't resolve to $#error 3099c2aa98e2SPeter Wemm ** else -- the failure status (message printed) 3100c2aa98e2SPeter Wemm */ 3101c2aa98e2SPeter Wemm 3102c2aa98e2SPeter Wemm int 3103da7d7b9cSGregory Neil Shapiro rscheck(rwset, p1, p2, e, flags, logl, host, logid, addr, addrstr) 3104c2aa98e2SPeter Wemm char *rwset; 3105*5b0945b5SGregory Neil Shapiro const char *p1; 3106*5b0945b5SGregory Neil Shapiro const char *p2; 3107c2aa98e2SPeter Wemm ENVELOPE *e; 3108959366dcSGregory Neil Shapiro int flags; 310906f25ae9SGregory Neil Shapiro int logl; 3110*5b0945b5SGregory Neil Shapiro const char *host; 3111*5b0945b5SGregory Neil Shapiro const char *logid; 3112d0cef73dSGregory Neil Shapiro ADDRESS *addr; 3113da7d7b9cSGregory Neil Shapiro char **addrstr; 3114c2aa98e2SPeter Wemm { 311540266059SGregory Neil Shapiro char *volatile buf; 31164e4196cbSGregory Neil Shapiro size_t bufsize; 3117c2aa98e2SPeter Wemm int saveexitstat; 311840266059SGregory Neil Shapiro int volatile rstat = EX_OK; 3119c2aa98e2SPeter Wemm char **pvp; 3120c2aa98e2SPeter Wemm int rsno; 312140266059SGregory Neil Shapiro bool volatile discard = false; 3122c2aa98e2SPeter Wemm bool saveQuickAbort = QuickAbort; 3123c2aa98e2SPeter Wemm bool saveSuprErrs = SuprErrs; 312440266059SGregory Neil Shapiro bool quarantine = false; 312540266059SGregory Neil Shapiro char ubuf[BUFSIZ * 2]; 3126c2aa98e2SPeter Wemm char buf0[MAXLINE]; 3127c2aa98e2SPeter Wemm char pvpbuf[PSBUFSIZE]; 3128c2aa98e2SPeter Wemm extern char MsgBuf[]; 3129c2aa98e2SPeter Wemm 3130c2aa98e2SPeter Wemm if (tTd(48, 2)) 313140266059SGregory Neil Shapiro sm_dprintf("rscheck(%s, %s, %s)\n", rwset, p1, 3132c2aa98e2SPeter Wemm p2 == NULL ? "(NULL)" : p2); 3133c2aa98e2SPeter Wemm 3134c2aa98e2SPeter Wemm rsno = strtorwset(rwset, NULL, ST_FIND); 3135c2aa98e2SPeter Wemm if (rsno < 0) 3136c2aa98e2SPeter Wemm return EX_OK; 3137c2aa98e2SPeter Wemm 3138c2aa98e2SPeter Wemm if (p2 != NULL) 3139c2aa98e2SPeter Wemm { 3140c2aa98e2SPeter Wemm bufsize = strlen(p1) + strlen(p2) + 2; 3141d0cef73dSGregory Neil Shapiro if (bufsize > sizeof(buf0)) 314240266059SGregory Neil Shapiro buf = sm_malloc_x(bufsize); 3143c2aa98e2SPeter Wemm else 3144c2aa98e2SPeter Wemm { 3145c2aa98e2SPeter Wemm buf = buf0; 3146d0cef73dSGregory Neil Shapiro bufsize = sizeof(buf0); 3147c2aa98e2SPeter Wemm } 314840266059SGregory Neil Shapiro (void) sm_snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2); 3149c2aa98e2SPeter Wemm } 3150c2aa98e2SPeter Wemm else 3151c2aa98e2SPeter Wemm { 3152c2aa98e2SPeter Wemm bufsize = strlen(p1) + 1; 3153d0cef73dSGregory Neil Shapiro if (bufsize > sizeof(buf0)) 315440266059SGregory Neil Shapiro buf = sm_malloc_x(bufsize); 3155c2aa98e2SPeter Wemm else 3156c2aa98e2SPeter Wemm { 3157c2aa98e2SPeter Wemm buf = buf0; 3158d0cef73dSGregory Neil Shapiro bufsize = sizeof(buf0); 3159c2aa98e2SPeter Wemm } 316040266059SGregory Neil Shapiro (void) sm_strlcpy(buf, p1, bufsize); 3161c2aa98e2SPeter Wemm } 316240266059SGregory Neil Shapiro SM_TRY 316340266059SGregory Neil Shapiro { 316440266059SGregory Neil Shapiro SuprErrs = true; 316540266059SGregory Neil Shapiro QuickAbort = false; 3166d0cef73dSGregory Neil Shapiro pvp = prescan(buf, '\0', pvpbuf, sizeof(pvpbuf), NULL, 3167d0cef73dSGregory Neil Shapiro bitset(RSF_RMCOMM, flags) ? 3168d0cef73dSGregory Neil Shapiro IntTokenTab : TokTypeNoC, 3169e92d3f3fSGregory Neil Shapiro bitset(RSF_RMCOMM, flags) ? false : true); 3170c2aa98e2SPeter Wemm SuprErrs = saveSuprErrs; 3171c2aa98e2SPeter Wemm if (pvp == NULL) 3172c2aa98e2SPeter Wemm { 3173c2aa98e2SPeter Wemm if (tTd(48, 2)) 317440266059SGregory Neil Shapiro sm_dprintf("rscheck: cannot prescan input\n"); 3175c2aa98e2SPeter Wemm /* 3176c2aa98e2SPeter Wemm syserr("rscheck: cannot prescan input: \"%s\"", 3177c2aa98e2SPeter Wemm shortenstring(buf, MAXSHORTSTR)); 3178c2aa98e2SPeter Wemm rstat = EX_DATAERR; 3179c2aa98e2SPeter Wemm */ 3180c2aa98e2SPeter Wemm goto finis; 3181c2aa98e2SPeter Wemm } 3182959366dcSGregory Neil Shapiro if (bitset(RSF_UNSTRUCTURED, flags)) 3183959366dcSGregory Neil Shapiro SuprErrs = true; 318440266059SGregory Neil Shapiro (void) REWRITE(pvp, rsno, e); 3185959366dcSGregory Neil Shapiro if (bitset(RSF_UNSTRUCTURED, flags)) 3186959366dcSGregory Neil Shapiro SuprErrs = saveSuprErrs; 3187da7d7b9cSGregory Neil Shapiro 3188da7d7b9cSGregory Neil Shapiro if (pvp[0] != NULL && (pvp[0][0] & 0377) != CANONNET && 3189da7d7b9cSGregory Neil Shapiro bitset(RSF_ADDR, flags) && addrstr != NULL) 3190da7d7b9cSGregory Neil Shapiro { 3191da7d7b9cSGregory Neil Shapiro cataddr(&(pvp[0]), NULL, ubuf, sizeof(ubuf), 3192da7d7b9cSGregory Neil Shapiro bitset(RSF_STRING, flags) ? NOSPACESEP : ' ', 3193da7d7b9cSGregory Neil Shapiro true); 3194da7d7b9cSGregory Neil Shapiro *addrstr = sm_rpool_strdup_x(e->e_rpool, ubuf); 3195da7d7b9cSGregory Neil Shapiro goto finis; 3196da7d7b9cSGregory Neil Shapiro } 3197da7d7b9cSGregory Neil Shapiro 3198c2aa98e2SPeter Wemm if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET || 3199c2aa98e2SPeter Wemm pvp[1] == NULL || (strcmp(pvp[1], "error") != 0 && 3200c2aa98e2SPeter Wemm strcmp(pvp[1], "discard") != 0)) 3201c2aa98e2SPeter Wemm { 3202c2aa98e2SPeter Wemm goto finis; 3203c2aa98e2SPeter Wemm } 3204c2aa98e2SPeter Wemm 3205c2aa98e2SPeter Wemm if (strcmp(pvp[1], "discard") == 0) 3206c2aa98e2SPeter Wemm { 3207c2aa98e2SPeter Wemm if (tTd(48, 2)) 320840266059SGregory Neil Shapiro sm_dprintf("rscheck: discard mailer selected\n"); 3209c2aa98e2SPeter Wemm e->e_flags |= EF_DISCARD; 321040266059SGregory Neil Shapiro discard = true; 3211c2aa98e2SPeter Wemm } 321240266059SGregory Neil Shapiro else if (strcmp(pvp[1], "error") == 0 && 321340266059SGregory Neil Shapiro pvp[2] != NULL && (pvp[2][0] & 0377) == CANONHOST && 321440266059SGregory Neil Shapiro pvp[3] != NULL && strcmp(pvp[3], "quarantine") == 0) 321540266059SGregory Neil Shapiro { 321640266059SGregory Neil Shapiro if (pvp[4] == NULL || 321740266059SGregory Neil Shapiro (pvp[4][0] & 0377) != CANONUSER || 321840266059SGregory Neil Shapiro pvp[5] == NULL) 321940266059SGregory Neil Shapiro e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, 322040266059SGregory Neil Shapiro rwset); 322140266059SGregory Neil Shapiro else 322240266059SGregory Neil Shapiro { 322340266059SGregory Neil Shapiro cataddr(&(pvp[5]), NULL, ubuf, 3224d0cef73dSGregory Neil Shapiro sizeof(ubuf), ' ', true); 322540266059SGregory Neil Shapiro e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, 322640266059SGregory Neil Shapiro ubuf); 322740266059SGregory Neil Shapiro } 322840266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 322940266059SGregory Neil Shapiro macid("{quarantine}"), e->e_quarmsg); 323040266059SGregory Neil Shapiro quarantine = true; 323140266059SGregory Neil Shapiro } 3232c2aa98e2SPeter Wemm else 3233c2aa98e2SPeter Wemm { 3234d0cef73dSGregory Neil Shapiro auto ADDRESS a1; 3235c2aa98e2SPeter Wemm int savelogusrerrs = LogUsrErrs; 323640266059SGregory Neil Shapiro static bool logged = false; 3237c2aa98e2SPeter Wemm 3238c2aa98e2SPeter Wemm /* got an error -- process it */ 3239c2aa98e2SPeter Wemm saveexitstat = ExitStat; 324040266059SGregory Neil Shapiro LogUsrErrs = false; 3241c2aa98e2SPeter Wemm (void) buildaddr(pvp, &a1, 0, e); 3242d0cef73dSGregory Neil Shapiro if (addr != NULL) 3243d0cef73dSGregory Neil Shapiro { 3244d0cef73dSGregory Neil Shapiro addr->q_mailer = a1.q_mailer; 3245d0cef73dSGregory Neil Shapiro addr->q_user = a1.q_user; 3246d0cef73dSGregory Neil Shapiro addr->q_host = a1.q_host; 3247d0cef73dSGregory Neil Shapiro } 3248c2aa98e2SPeter Wemm LogUsrErrs = savelogusrerrs; 3249c2aa98e2SPeter Wemm rstat = ExitStat; 3250c2aa98e2SPeter Wemm ExitStat = saveexitstat; 3251c2aa98e2SPeter Wemm if (!logged) 3252c2aa98e2SPeter Wemm { 3253959366dcSGregory Neil Shapiro if (bitset(RSF_COUNT, flags)) 325440266059SGregory Neil Shapiro markstats(e, &a1, STATS_REJECT); 325540266059SGregory Neil Shapiro logged = true; 3256c2aa98e2SPeter Wemm } 3257c2aa98e2SPeter Wemm } 3258c2aa98e2SPeter Wemm 325940266059SGregory Neil Shapiro if (LogLevel > logl) 3260c2aa98e2SPeter Wemm { 3261*5b0945b5SGregory Neil Shapiro const char *relay; 3262c2aa98e2SPeter Wemm char *p; 3263c2aa98e2SPeter Wemm char lbuf[MAXLINE]; 3264c2aa98e2SPeter Wemm 3265c2aa98e2SPeter Wemm p = lbuf; 3266c2aa98e2SPeter Wemm if (p2 != NULL) 3267c2aa98e2SPeter Wemm { 326840266059SGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(lbuf, p), 3269c2aa98e2SPeter Wemm ", arg2=%s", 3270c2aa98e2SPeter Wemm p2); 3271c2aa98e2SPeter Wemm p += strlen(p); 3272c2aa98e2SPeter Wemm } 3273193538b7SGregory Neil Shapiro 3274193538b7SGregory Neil Shapiro if (host != NULL) 3275193538b7SGregory Neil Shapiro relay = host; 3276193538b7SGregory Neil Shapiro else 3277193538b7SGregory Neil Shapiro relay = macvalue('_', e); 3278193538b7SGregory Neil Shapiro if (relay != NULL) 3279c2aa98e2SPeter Wemm { 328040266059SGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(lbuf, p), 3281c2aa98e2SPeter Wemm ", relay=%s", relay); 3282c2aa98e2SPeter Wemm p += strlen(p); 3283c2aa98e2SPeter Wemm } 3284c2aa98e2SPeter Wemm *p = '\0'; 3285c2aa98e2SPeter Wemm if (discard) 328640266059SGregory Neil Shapiro sm_syslog(LOG_NOTICE, logid, 3287c2aa98e2SPeter Wemm "ruleset=%s, arg1=%s%s, discard", 3288c2aa98e2SPeter Wemm rwset, p1, lbuf); 328940266059SGregory Neil Shapiro else if (quarantine) 329040266059SGregory Neil Shapiro sm_syslog(LOG_NOTICE, logid, 329140266059SGregory Neil Shapiro "ruleset=%s, arg1=%s%s, quarantine=%s", 329240266059SGregory Neil Shapiro rwset, p1, lbuf, ubuf); 3293c2aa98e2SPeter Wemm else 329440266059SGregory Neil Shapiro sm_syslog(LOG_NOTICE, logid, 3295c2aa98e2SPeter Wemm "ruleset=%s, arg1=%s%s, reject=%s", 3296c2aa98e2SPeter Wemm rwset, p1, lbuf, MsgBuf); 3297c2aa98e2SPeter Wemm } 3298c2aa98e2SPeter Wemm 329940266059SGregory Neil Shapiro finis: ; 330040266059SGregory Neil Shapiro } 330140266059SGregory Neil Shapiro SM_FINALLY 330240266059SGregory Neil Shapiro { 3303c2aa98e2SPeter Wemm /* clean up */ 3304c2aa98e2SPeter Wemm if (buf != buf0) 33058774250cSGregory Neil Shapiro sm_free(buf); 330640266059SGregory Neil Shapiro QuickAbort = saveQuickAbort; 330740266059SGregory Neil Shapiro } 330840266059SGregory Neil Shapiro SM_END_TRY 3309c2aa98e2SPeter Wemm 331040266059SGregory Neil Shapiro setstat(rstat); 331140266059SGregory Neil Shapiro 331240266059SGregory Neil Shapiro /* rulesets don't set errno */ 331340266059SGregory Neil Shapiro errno = 0; 3314c2aa98e2SPeter Wemm if (rstat != EX_OK && QuickAbort) 331540266059SGregory Neil Shapiro sm_exc_raisenew_x(&EtypeQuickAbort, 2); 331640266059SGregory Neil Shapiro return rstat; 331740266059SGregory Neil Shapiro } 3318*5b0945b5SGregory Neil Shapiro 331940266059SGregory Neil Shapiro /* 332040266059SGregory Neil Shapiro ** RSCAP -- call rewriting set to return capabilities 332140266059SGregory Neil Shapiro ** 332240266059SGregory Neil Shapiro ** Parameters: 332340266059SGregory Neil Shapiro ** rwset -- the rewriting set to use. 332440266059SGregory Neil Shapiro ** p1 -- the first string to check. 3325*5b0945b5SGregory Neil Shapiro ** p2 -- the second string to check -- may be NULL. 332640266059SGregory Neil Shapiro ** e -- the current envelope. 332740266059SGregory Neil Shapiro ** pvp -- pointer to token vector. 332840266059SGregory Neil Shapiro ** pvpbuf -- buffer space. 3329a7ec597cSGregory Neil Shapiro ** size -- size of buffer space. 333040266059SGregory Neil Shapiro ** 333140266059SGregory Neil Shapiro ** Returns: 333240266059SGregory Neil Shapiro ** EX_UNAVAILABLE -- ruleset doesn't exist. 333340266059SGregory Neil Shapiro ** EX_DATAERR -- prescan() failed. 333440266059SGregory Neil Shapiro ** EX_OK -- rewrite() was successful. 333540266059SGregory Neil Shapiro ** else -- return status from rewrite(). 333640266059SGregory Neil Shapiro */ 333740266059SGregory Neil Shapiro 333840266059SGregory Neil Shapiro int 333940266059SGregory Neil Shapiro rscap(rwset, p1, p2, e, pvp, pvpbuf, size) 334040266059SGregory Neil Shapiro char *rwset; 334140266059SGregory Neil Shapiro char *p1; 334240266059SGregory Neil Shapiro char *p2; 334340266059SGregory Neil Shapiro ENVELOPE *e; 334440266059SGregory Neil Shapiro char ***pvp; 334540266059SGregory Neil Shapiro char *pvpbuf; 334640266059SGregory Neil Shapiro int size; 334740266059SGregory Neil Shapiro { 334840266059SGregory Neil Shapiro char *volatile buf; 33494e4196cbSGregory Neil Shapiro size_t bufsize; 335040266059SGregory Neil Shapiro int volatile rstat = EX_OK; 335140266059SGregory Neil Shapiro int rsno; 335240266059SGregory Neil Shapiro bool saveQuickAbort = QuickAbort; 335340266059SGregory Neil Shapiro bool saveSuprErrs = SuprErrs; 335440266059SGregory Neil Shapiro char buf0[MAXLINE]; 335540266059SGregory Neil Shapiro extern char MsgBuf[]; 335640266059SGregory Neil Shapiro 335740266059SGregory Neil Shapiro if (tTd(48, 2)) 335840266059SGregory Neil Shapiro sm_dprintf("rscap(%s, %s, %s)\n", rwset, p1, 335940266059SGregory Neil Shapiro p2 == NULL ? "(NULL)" : p2); 336040266059SGregory Neil Shapiro 3361af9557fdSGregory Neil Shapiro SM_REQUIRE(pvp != NULL); 336240266059SGregory Neil Shapiro rsno = strtorwset(rwset, NULL, ST_FIND); 336340266059SGregory Neil Shapiro if (rsno < 0) 336440266059SGregory Neil Shapiro return EX_UNAVAILABLE; 336540266059SGregory Neil Shapiro 336640266059SGregory Neil Shapiro if (p2 != NULL) 336740266059SGregory Neil Shapiro { 336840266059SGregory Neil Shapiro bufsize = strlen(p1) + strlen(p2) + 2; 3369d0cef73dSGregory Neil Shapiro if (bufsize > sizeof(buf0)) 337040266059SGregory Neil Shapiro buf = sm_malloc_x(bufsize); 337140266059SGregory Neil Shapiro else 337240266059SGregory Neil Shapiro { 337340266059SGregory Neil Shapiro buf = buf0; 3374d0cef73dSGregory Neil Shapiro bufsize = sizeof(buf0); 337540266059SGregory Neil Shapiro } 337640266059SGregory Neil Shapiro (void) sm_snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2); 337740266059SGregory Neil Shapiro } 337840266059SGregory Neil Shapiro else 337940266059SGregory Neil Shapiro { 338040266059SGregory Neil Shapiro bufsize = strlen(p1) + 1; 3381d0cef73dSGregory Neil Shapiro if (bufsize > sizeof(buf0)) 338240266059SGregory Neil Shapiro buf = sm_malloc_x(bufsize); 338340266059SGregory Neil Shapiro else 338440266059SGregory Neil Shapiro { 338540266059SGregory Neil Shapiro buf = buf0; 3386d0cef73dSGregory Neil Shapiro bufsize = sizeof(buf0); 338740266059SGregory Neil Shapiro } 338840266059SGregory Neil Shapiro (void) sm_strlcpy(buf, p1, bufsize); 338940266059SGregory Neil Shapiro } 339040266059SGregory Neil Shapiro SM_TRY 339140266059SGregory Neil Shapiro { 339240266059SGregory Neil Shapiro SuprErrs = true; 339340266059SGregory Neil Shapiro QuickAbort = false; 3394d0cef73dSGregory Neil Shapiro *pvp = prescan(buf, '\0', pvpbuf, size, NULL, IntTokenTab, 3395d0cef73dSGregory Neil Shapiro false); 339640266059SGregory Neil Shapiro if (*pvp != NULL) 3397a7ec597cSGregory Neil Shapiro rstat = rewrite(*pvp, rsno, 0, e, size); 339840266059SGregory Neil Shapiro else 339940266059SGregory Neil Shapiro { 340040266059SGregory Neil Shapiro if (tTd(48, 2)) 340140266059SGregory Neil Shapiro sm_dprintf("rscap: cannot prescan input\n"); 340240266059SGregory Neil Shapiro rstat = EX_DATAERR; 340340266059SGregory Neil Shapiro } 340440266059SGregory Neil Shapiro } 340540266059SGregory Neil Shapiro SM_FINALLY 340640266059SGregory Neil Shapiro { 340740266059SGregory Neil Shapiro /* clean up */ 340840266059SGregory Neil Shapiro if (buf != buf0) 340940266059SGregory Neil Shapiro sm_free(buf); 341040266059SGregory Neil Shapiro SuprErrs = saveSuprErrs; 341140266059SGregory Neil Shapiro QuickAbort = saveQuickAbort; 341240266059SGregory Neil Shapiro 341340266059SGregory Neil Shapiro /* prevent information leak, this may contain rewrite error */ 341440266059SGregory Neil Shapiro MsgBuf[0] = '\0'; 341540266059SGregory Neil Shapiro } 341640266059SGregory Neil Shapiro SM_END_TRY 3417c2aa98e2SPeter Wemm return rstat; 3418c2aa98e2SPeter Wemm } 3419