17c478bd9Sstevel@tonic-gate /*
2058561cbSjbeck * Copyright (c) 1998-2006 Sendmail, Inc. and its suppliers.
37c478bd9Sstevel@tonic-gate * All rights reserved.
47c478bd9Sstevel@tonic-gate * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
57c478bd9Sstevel@tonic-gate * Copyright (c) 1988, 1993
67c478bd9Sstevel@tonic-gate * The Regents of the University of California. All rights reserved.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set
97c478bd9Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of
107c478bd9Sstevel@tonic-gate * the sendmail distribution.
117c478bd9Sstevel@tonic-gate *
127c478bd9Sstevel@tonic-gate */
137c478bd9Sstevel@tonic-gate
147c478bd9Sstevel@tonic-gate #include <sendmail.h>
157c478bd9Sstevel@tonic-gate
16*d4660949Sjbeck SM_RCSID("@(#)$Id: parseaddr.c,v 8.403 2008/02/08 02:27:35 ca Exp $")
17058561cbSjbeck
18058561cbSjbeck #include <sm/sendmail.h>
19058561cbSjbeck #include "map.h"
207c478bd9Sstevel@tonic-gate
217c478bd9Sstevel@tonic-gate static void allocaddr __P((ADDRESS *, int, char *, ENVELOPE *));
227c478bd9Sstevel@tonic-gate static int callsubr __P((char**, int, ENVELOPE *));
237c478bd9Sstevel@tonic-gate static char *map_lookup __P((STAB *, char *, char **, int *, ENVELOPE *));
247c478bd9Sstevel@tonic-gate static ADDRESS *buildaddr __P((char **, ADDRESS *, int, ENVELOPE *));
257c478bd9Sstevel@tonic-gate static bool hasctrlchar __P((register char *, bool, bool));
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate /* replacement for illegal characters in addresses */
287c478bd9Sstevel@tonic-gate #define BAD_CHAR_REPLACEMENT '?'
297c478bd9Sstevel@tonic-gate
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate ** PARSEADDR -- Parse an address
327c478bd9Sstevel@tonic-gate **
337c478bd9Sstevel@tonic-gate ** Parses an address and breaks it up into three parts: a
347c478bd9Sstevel@tonic-gate ** net to transmit the message on, the host to transmit it
357c478bd9Sstevel@tonic-gate ** to, and a user on that host. These are loaded into an
367c478bd9Sstevel@tonic-gate ** ADDRESS header with the values squirreled away if necessary.
377c478bd9Sstevel@tonic-gate ** The "user" part may not be a real user; the process may
387c478bd9Sstevel@tonic-gate ** just reoccur on that machine. For example, on a machine
397c478bd9Sstevel@tonic-gate ** with an arpanet connection, the address
407c478bd9Sstevel@tonic-gate ** csvax.bill@berkeley
417c478bd9Sstevel@tonic-gate ** will break up to a "user" of 'csvax.bill' and a host
427c478bd9Sstevel@tonic-gate ** of 'berkeley' -- to be transmitted over the arpanet.
437c478bd9Sstevel@tonic-gate **
447c478bd9Sstevel@tonic-gate ** Parameters:
457c478bd9Sstevel@tonic-gate ** addr -- the address to parse.
467c478bd9Sstevel@tonic-gate ** a -- a pointer to the address descriptor buffer.
477c478bd9Sstevel@tonic-gate ** If NULL, an address will be created.
487c478bd9Sstevel@tonic-gate ** flags -- describe detail for parsing. See RF_ definitions
497c478bd9Sstevel@tonic-gate ** in sendmail.h.
507c478bd9Sstevel@tonic-gate ** delim -- the character to terminate the address, passed
517c478bd9Sstevel@tonic-gate ** to prescan.
527c478bd9Sstevel@tonic-gate ** delimptr -- if non-NULL, set to the location of the
537c478bd9Sstevel@tonic-gate ** delim character that was found.
547c478bd9Sstevel@tonic-gate ** e -- the envelope that will contain this address.
557c478bd9Sstevel@tonic-gate ** isrcpt -- true if the address denotes a recipient; false
567c478bd9Sstevel@tonic-gate ** indicates a sender.
577c478bd9Sstevel@tonic-gate **
587c478bd9Sstevel@tonic-gate ** Returns:
597c478bd9Sstevel@tonic-gate ** A pointer to the address descriptor header (`a' if
607c478bd9Sstevel@tonic-gate ** `a' is non-NULL).
617c478bd9Sstevel@tonic-gate ** NULL on error.
627c478bd9Sstevel@tonic-gate **
637c478bd9Sstevel@tonic-gate ** Side Effects:
647c478bd9Sstevel@tonic-gate ** e->e_to = addr
657c478bd9Sstevel@tonic-gate */
667c478bd9Sstevel@tonic-gate
677c478bd9Sstevel@tonic-gate /* following delimiters are inherent to the internal algorithms */
687c478bd9Sstevel@tonic-gate #define DELIMCHARS "()<>,;\r\n" /* default word delimiters */
697c478bd9Sstevel@tonic-gate
707c478bd9Sstevel@tonic-gate ADDRESS *
parseaddr(addr,a,flags,delim,delimptr,e,isrcpt)717c478bd9Sstevel@tonic-gate parseaddr(addr, a, flags, delim, delimptr, e, isrcpt)
727c478bd9Sstevel@tonic-gate char *addr;
737c478bd9Sstevel@tonic-gate register ADDRESS *a;
747c478bd9Sstevel@tonic-gate int flags;
757c478bd9Sstevel@tonic-gate int delim;
767c478bd9Sstevel@tonic-gate char **delimptr;
777c478bd9Sstevel@tonic-gate register ENVELOPE *e;
787c478bd9Sstevel@tonic-gate bool isrcpt;
797c478bd9Sstevel@tonic-gate {
807c478bd9Sstevel@tonic-gate char **pvp;
817c478bd9Sstevel@tonic-gate auto char *delimptrbuf;
827c478bd9Sstevel@tonic-gate bool qup;
837c478bd9Sstevel@tonic-gate char pvpbuf[PSBUFSIZE];
847c478bd9Sstevel@tonic-gate
857c478bd9Sstevel@tonic-gate /*
867c478bd9Sstevel@tonic-gate ** Initialize and prescan address.
877c478bd9Sstevel@tonic-gate */
887c478bd9Sstevel@tonic-gate
897c478bd9Sstevel@tonic-gate e->e_to = addr;
907c478bd9Sstevel@tonic-gate if (tTd(20, 1))
917c478bd9Sstevel@tonic-gate sm_dprintf("\n--parseaddr(%s)\n", addr);
927c478bd9Sstevel@tonic-gate
937c478bd9Sstevel@tonic-gate if (delimptr == NULL)
947c478bd9Sstevel@tonic-gate delimptr = &delimptrbuf;
957c478bd9Sstevel@tonic-gate
96058561cbSjbeck pvp = prescan(addr, delim, pvpbuf, sizeof(pvpbuf), delimptr,
97058561cbSjbeck ExtTokenTab, false);
987c478bd9Sstevel@tonic-gate if (pvp == NULL)
997c478bd9Sstevel@tonic-gate {
1007c478bd9Sstevel@tonic-gate if (tTd(20, 1))
1017c478bd9Sstevel@tonic-gate sm_dprintf("parseaddr-->NULL\n");
1027c478bd9Sstevel@tonic-gate return NULL;
1037c478bd9Sstevel@tonic-gate }
1047c478bd9Sstevel@tonic-gate
1057c478bd9Sstevel@tonic-gate if (invalidaddr(addr, delim == '\0' ? NULL : *delimptr, isrcpt))
1067c478bd9Sstevel@tonic-gate {
1077c478bd9Sstevel@tonic-gate if (tTd(20, 1))
1087c478bd9Sstevel@tonic-gate sm_dprintf("parseaddr-->bad address\n");
1097c478bd9Sstevel@tonic-gate return NULL;
1107c478bd9Sstevel@tonic-gate }
1117c478bd9Sstevel@tonic-gate
1127c478bd9Sstevel@tonic-gate /*
1137c478bd9Sstevel@tonic-gate ** Save addr if we are going to have to.
1147c478bd9Sstevel@tonic-gate **
1157c478bd9Sstevel@tonic-gate ** We have to do this early because there is a chance that
1167c478bd9Sstevel@tonic-gate ** the map lookups in the rewriting rules could clobber
1177c478bd9Sstevel@tonic-gate ** static memory somewhere.
1187c478bd9Sstevel@tonic-gate */
1197c478bd9Sstevel@tonic-gate
1207c478bd9Sstevel@tonic-gate if (bitset(RF_COPYPADDR, flags) && addr != NULL)
1217c478bd9Sstevel@tonic-gate {
1227c478bd9Sstevel@tonic-gate char savec = **delimptr;
1237c478bd9Sstevel@tonic-gate
1247c478bd9Sstevel@tonic-gate if (savec != '\0')
1257c478bd9Sstevel@tonic-gate **delimptr = '\0';
1267c478bd9Sstevel@tonic-gate e->e_to = addr = sm_rpool_strdup_x(e->e_rpool, addr);
1277c478bd9Sstevel@tonic-gate if (savec != '\0')
1287c478bd9Sstevel@tonic-gate **delimptr = savec;
1297c478bd9Sstevel@tonic-gate }
1307c478bd9Sstevel@tonic-gate
1317c478bd9Sstevel@tonic-gate /*
1327c478bd9Sstevel@tonic-gate ** Apply rewriting rules.
1337c478bd9Sstevel@tonic-gate ** Ruleset 0 does basic parsing. It must resolve.
1347c478bd9Sstevel@tonic-gate */
1357c478bd9Sstevel@tonic-gate
1367c478bd9Sstevel@tonic-gate qup = false;
1377c478bd9Sstevel@tonic-gate if (REWRITE(pvp, 3, e) == EX_TEMPFAIL)
1387c478bd9Sstevel@tonic-gate qup = true;
1397c478bd9Sstevel@tonic-gate if (REWRITE(pvp, 0, e) == EX_TEMPFAIL)
1407c478bd9Sstevel@tonic-gate qup = true;
1417c478bd9Sstevel@tonic-gate
1427c478bd9Sstevel@tonic-gate /*
1437c478bd9Sstevel@tonic-gate ** Build canonical address from pvp.
1447c478bd9Sstevel@tonic-gate */
1457c478bd9Sstevel@tonic-gate
1467c478bd9Sstevel@tonic-gate a = buildaddr(pvp, a, flags, e);
1477c478bd9Sstevel@tonic-gate
1487c478bd9Sstevel@tonic-gate if (hasctrlchar(a->q_user, isrcpt, true))
1497c478bd9Sstevel@tonic-gate {
1507c478bd9Sstevel@tonic-gate if (tTd(20, 1))
1517c478bd9Sstevel@tonic-gate sm_dprintf("parseaddr-->bad q_user\n");
1527c478bd9Sstevel@tonic-gate
1537c478bd9Sstevel@tonic-gate /*
1547c478bd9Sstevel@tonic-gate ** Just mark the address as bad so DSNs work.
1557c478bd9Sstevel@tonic-gate ** hasctrlchar() has to make sure that the address
1567c478bd9Sstevel@tonic-gate ** has been sanitized, e.g., shortened.
1577c478bd9Sstevel@tonic-gate */
1587c478bd9Sstevel@tonic-gate
1597c478bd9Sstevel@tonic-gate a->q_state = QS_BADADDR;
1607c478bd9Sstevel@tonic-gate }
1617c478bd9Sstevel@tonic-gate
1627c478bd9Sstevel@tonic-gate /*
1637c478bd9Sstevel@tonic-gate ** Make local copies of the host & user and then
1647c478bd9Sstevel@tonic-gate ** transport them out.
1657c478bd9Sstevel@tonic-gate */
1667c478bd9Sstevel@tonic-gate
1677c478bd9Sstevel@tonic-gate allocaddr(a, flags, addr, e);
1687c478bd9Sstevel@tonic-gate if (QS_IS_BADADDR(a->q_state))
1697c478bd9Sstevel@tonic-gate {
1707c478bd9Sstevel@tonic-gate /* weed out bad characters in the printable address too */
1717c478bd9Sstevel@tonic-gate (void) hasctrlchar(a->q_paddr, isrcpt, false);
1727c478bd9Sstevel@tonic-gate return a;
1737c478bd9Sstevel@tonic-gate }
1747c478bd9Sstevel@tonic-gate
1757c478bd9Sstevel@tonic-gate /*
1767c478bd9Sstevel@tonic-gate ** Select a queue directory for recipient addresses.
1777c478bd9Sstevel@tonic-gate ** This is done here and in split_across_queue_groups(),
1787c478bd9Sstevel@tonic-gate ** but the latter applies to addresses after aliasing,
1797c478bd9Sstevel@tonic-gate ** and only if splitting is done.
1807c478bd9Sstevel@tonic-gate */
1817c478bd9Sstevel@tonic-gate
1827c478bd9Sstevel@tonic-gate if ((a->q_qgrp == NOAQGRP || a->q_qgrp == ENVQGRP) &&
183058561cbSjbeck !bitset(RF_SENDERADDR|RF_HEADERADDR|RF_RM_ADDR, flags) &&
1847c478bd9Sstevel@tonic-gate OpMode != MD_INITALIAS)
1857c478bd9Sstevel@tonic-gate {
1867c478bd9Sstevel@tonic-gate int r;
1877c478bd9Sstevel@tonic-gate
1887c478bd9Sstevel@tonic-gate /* call ruleset which should return a queue group name */
1897c478bd9Sstevel@tonic-gate r = rscap(RS_QUEUEGROUP, a->q_user, NULL, e, &pvp, pvpbuf,
1907c478bd9Sstevel@tonic-gate sizeof(pvpbuf));
1917c478bd9Sstevel@tonic-gate if (r == EX_OK &&
1927c478bd9Sstevel@tonic-gate pvp != NULL && pvp[0] != NULL &&
1937c478bd9Sstevel@tonic-gate (pvp[0][0] & 0377) == CANONNET &&
1947c478bd9Sstevel@tonic-gate pvp[1] != NULL && pvp[1][0] != '\0')
1957c478bd9Sstevel@tonic-gate {
1967c478bd9Sstevel@tonic-gate r = name2qid(pvp[1]);
1977c478bd9Sstevel@tonic-gate if (r == NOQGRP && LogLevel > 10)
1987c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID,
1997c478bd9Sstevel@tonic-gate "can't find queue group name %s, selection ignored",
2007c478bd9Sstevel@tonic-gate pvp[1]);
2017c478bd9Sstevel@tonic-gate if (tTd(20, 4) && r != NOQGRP)
2027c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID,
2037c478bd9Sstevel@tonic-gate "queue group name %s -> %d",
2047c478bd9Sstevel@tonic-gate pvp[1], r);
2057c478bd9Sstevel@tonic-gate a->q_qgrp = r == NOQGRP ? ENVQGRP : r;
2067c478bd9Sstevel@tonic-gate }
2077c478bd9Sstevel@tonic-gate }
2087c478bd9Sstevel@tonic-gate
2097c478bd9Sstevel@tonic-gate /*
2107c478bd9Sstevel@tonic-gate ** If there was a parsing failure, mark it for queueing.
2117c478bd9Sstevel@tonic-gate */
2127c478bd9Sstevel@tonic-gate
2137c478bd9Sstevel@tonic-gate if (qup && OpMode != MD_INITALIAS)
2147c478bd9Sstevel@tonic-gate {
2157c478bd9Sstevel@tonic-gate char *msg = "Transient parse error -- message queued for future delivery";
2167c478bd9Sstevel@tonic-gate
2177c478bd9Sstevel@tonic-gate if (e->e_sendmode == SM_DEFER)
2187c478bd9Sstevel@tonic-gate msg = "Deferring message until queue run";
2197c478bd9Sstevel@tonic-gate if (tTd(20, 1))
2207800901eSjbeck sm_dprintf("parseaddr: queueing message\n");
2217c478bd9Sstevel@tonic-gate message(msg);
2227c478bd9Sstevel@tonic-gate if (e->e_message == NULL && e->e_sendmode != SM_DEFER)
2237c478bd9Sstevel@tonic-gate e->e_message = sm_rpool_strdup_x(e->e_rpool, msg);
2247c478bd9Sstevel@tonic-gate a->q_state = QS_QUEUEUP;
2257c478bd9Sstevel@tonic-gate a->q_status = "4.4.3";
2267c478bd9Sstevel@tonic-gate }
2277c478bd9Sstevel@tonic-gate
2287c478bd9Sstevel@tonic-gate /*
2297c478bd9Sstevel@tonic-gate ** Compute return value.
2307c478bd9Sstevel@tonic-gate */
2317c478bd9Sstevel@tonic-gate
2327c478bd9Sstevel@tonic-gate if (tTd(20, 1))
2337c478bd9Sstevel@tonic-gate {
2347c478bd9Sstevel@tonic-gate sm_dprintf("parseaddr-->");
2357c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), a, false);
2367c478bd9Sstevel@tonic-gate }
2377c478bd9Sstevel@tonic-gate
2387c478bd9Sstevel@tonic-gate return a;
2397c478bd9Sstevel@tonic-gate }
2407c478bd9Sstevel@tonic-gate /*
2417c478bd9Sstevel@tonic-gate ** INVALIDADDR -- check for address containing characters used for macros
2427c478bd9Sstevel@tonic-gate **
2437c478bd9Sstevel@tonic-gate ** Parameters:
2447c478bd9Sstevel@tonic-gate ** addr -- the address to check.
2457c478bd9Sstevel@tonic-gate ** delimptr -- if non-NULL: end of address to check, i.e.,
2467c478bd9Sstevel@tonic-gate ** a pointer in the address string.
2477c478bd9Sstevel@tonic-gate ** isrcpt -- true iff the address is for a recipient.
2487c478bd9Sstevel@tonic-gate **
2497c478bd9Sstevel@tonic-gate ** Returns:
2507c478bd9Sstevel@tonic-gate ** true -- if the address has characters that are reservered
2517c478bd9Sstevel@tonic-gate ** for macros or is too long.
2527c478bd9Sstevel@tonic-gate ** false -- otherwise.
2537c478bd9Sstevel@tonic-gate */
2547c478bd9Sstevel@tonic-gate
2557c478bd9Sstevel@tonic-gate bool
invalidaddr(addr,delimptr,isrcpt)2567c478bd9Sstevel@tonic-gate invalidaddr(addr, delimptr, isrcpt)
2577c478bd9Sstevel@tonic-gate register char *addr;
2587c478bd9Sstevel@tonic-gate char *delimptr;
2597c478bd9Sstevel@tonic-gate bool isrcpt;
2607c478bd9Sstevel@tonic-gate {
2617c478bd9Sstevel@tonic-gate bool result = false;
2627c478bd9Sstevel@tonic-gate char savedelim = '\0';
2637c478bd9Sstevel@tonic-gate char *b = addr;
2647c478bd9Sstevel@tonic-gate int len = 0;
2657c478bd9Sstevel@tonic-gate
2667c478bd9Sstevel@tonic-gate if (delimptr != NULL)
2677c478bd9Sstevel@tonic-gate {
2687c478bd9Sstevel@tonic-gate /* delimptr points to the end of the address to test */
2697c478bd9Sstevel@tonic-gate savedelim = *delimptr;
2707c478bd9Sstevel@tonic-gate if (savedelim != '\0') /* if that isn't '\0' already: */
2717c478bd9Sstevel@tonic-gate *delimptr = '\0'; /* set it */
2727c478bd9Sstevel@tonic-gate }
2737c478bd9Sstevel@tonic-gate for (; *addr != '\0'; addr++)
2747c478bd9Sstevel@tonic-gate {
275058561cbSjbeck if (!EightBitAddrOK && (*addr & 0340) == 0200)
2767c478bd9Sstevel@tonic-gate {
2777c478bd9Sstevel@tonic-gate setstat(EX_USAGE);
2787c478bd9Sstevel@tonic-gate result = true;
2797c478bd9Sstevel@tonic-gate *addr = BAD_CHAR_REPLACEMENT;
2807c478bd9Sstevel@tonic-gate }
2817c478bd9Sstevel@tonic-gate if (++len > MAXNAME - 1)
2827c478bd9Sstevel@tonic-gate {
2837c478bd9Sstevel@tonic-gate char saved = *addr;
2847c478bd9Sstevel@tonic-gate
2857c478bd9Sstevel@tonic-gate *addr = '\0';
2867c478bd9Sstevel@tonic-gate usrerr("553 5.1.0 Address \"%s\" too long (%d bytes max)",
2877c478bd9Sstevel@tonic-gate b, MAXNAME - 1);
2887c478bd9Sstevel@tonic-gate *addr = saved;
2897c478bd9Sstevel@tonic-gate result = true;
2907c478bd9Sstevel@tonic-gate goto delim;
2917c478bd9Sstevel@tonic-gate }
2927c478bd9Sstevel@tonic-gate }
2937c478bd9Sstevel@tonic-gate if (result)
2947c478bd9Sstevel@tonic-gate {
2957c478bd9Sstevel@tonic-gate if (isrcpt)
2967c478bd9Sstevel@tonic-gate usrerr("501 5.1.3 8-bit character in mailbox address \"%s\"",
2977c478bd9Sstevel@tonic-gate b);
2987c478bd9Sstevel@tonic-gate else
2997c478bd9Sstevel@tonic-gate usrerr("501 5.1.7 8-bit character in mailbox address \"%s\"",
3007c478bd9Sstevel@tonic-gate b);
3017c478bd9Sstevel@tonic-gate }
3027c478bd9Sstevel@tonic-gate delim:
3037c478bd9Sstevel@tonic-gate if (delimptr != NULL && savedelim != '\0')
3047c478bd9Sstevel@tonic-gate *delimptr = savedelim; /* restore old character at delimptr */
3057c478bd9Sstevel@tonic-gate return result;
3067c478bd9Sstevel@tonic-gate }
3077c478bd9Sstevel@tonic-gate /*
3087c478bd9Sstevel@tonic-gate ** HASCTRLCHAR -- check for address containing meta-characters
3097c478bd9Sstevel@tonic-gate **
3107c478bd9Sstevel@tonic-gate ** Checks that the address contains no meta-characters, and contains
3117c478bd9Sstevel@tonic-gate ** no "non-printable" characters unless they are quoted or escaped.
3127c478bd9Sstevel@tonic-gate ** Quoted or escaped characters are literals.
3137c478bd9Sstevel@tonic-gate **
3147c478bd9Sstevel@tonic-gate ** Parameters:
3157c478bd9Sstevel@tonic-gate ** addr -- the address to check.
3167c478bd9Sstevel@tonic-gate ** isrcpt -- true if the address is for a recipient; false
3177c478bd9Sstevel@tonic-gate ** indicates a from.
3187c478bd9Sstevel@tonic-gate ** complain -- true if an error should issued if the address
3197c478bd9Sstevel@tonic-gate ** is invalid and should be "repaired".
3207c478bd9Sstevel@tonic-gate **
3217c478bd9Sstevel@tonic-gate ** Returns:
3227c478bd9Sstevel@tonic-gate ** true -- if the address has any "wierd" characters or
3237c478bd9Sstevel@tonic-gate ** non-printable characters or if a quote is unbalanced.
3247c478bd9Sstevel@tonic-gate ** false -- otherwise.
3257c478bd9Sstevel@tonic-gate */
3267c478bd9Sstevel@tonic-gate
3277c478bd9Sstevel@tonic-gate static bool
hasctrlchar(addr,isrcpt,complain)3287c478bd9Sstevel@tonic-gate hasctrlchar(addr, isrcpt, complain)
3297c478bd9Sstevel@tonic-gate register char *addr;
3307c478bd9Sstevel@tonic-gate bool isrcpt, complain;
3317c478bd9Sstevel@tonic-gate {
3327c478bd9Sstevel@tonic-gate bool quoted = false;
3337c478bd9Sstevel@tonic-gate int len = 0;
3347c478bd9Sstevel@tonic-gate char *result = NULL;
3357c478bd9Sstevel@tonic-gate char *b = addr;
3367c478bd9Sstevel@tonic-gate
3377c478bd9Sstevel@tonic-gate if (addr == NULL)
3387c478bd9Sstevel@tonic-gate return false;
3397c478bd9Sstevel@tonic-gate for (; *addr != '\0'; addr++)
3407c478bd9Sstevel@tonic-gate {
3417c478bd9Sstevel@tonic-gate if (++len > MAXNAME - 1)
3427c478bd9Sstevel@tonic-gate {
3437c478bd9Sstevel@tonic-gate if (complain)
3447c478bd9Sstevel@tonic-gate {
3457c478bd9Sstevel@tonic-gate (void) shorten_rfc822_string(b, MAXNAME - 1);
3467c478bd9Sstevel@tonic-gate usrerr("553 5.1.0 Address \"%s\" too long (%d bytes max)",
3477c478bd9Sstevel@tonic-gate b, MAXNAME - 1);
3487c478bd9Sstevel@tonic-gate return true;
3497c478bd9Sstevel@tonic-gate }
3507c478bd9Sstevel@tonic-gate result = "too long";
3517c478bd9Sstevel@tonic-gate }
352058561cbSjbeck if (!EightBitAddrOK && !quoted && (*addr < 32 || *addr == 127))
3537c478bd9Sstevel@tonic-gate {
3547c478bd9Sstevel@tonic-gate result = "non-printable character";
3557c478bd9Sstevel@tonic-gate *addr = BAD_CHAR_REPLACEMENT;
3567c478bd9Sstevel@tonic-gate continue;
3577c478bd9Sstevel@tonic-gate }
3587c478bd9Sstevel@tonic-gate if (*addr == '"')
3597c478bd9Sstevel@tonic-gate quoted = !quoted;
3607c478bd9Sstevel@tonic-gate else if (*addr == '\\')
3617c478bd9Sstevel@tonic-gate {
3627c478bd9Sstevel@tonic-gate /* XXX Generic problem: no '\0' in strings. */
3637c478bd9Sstevel@tonic-gate if (*++addr == '\0')
3647c478bd9Sstevel@tonic-gate {
3657c478bd9Sstevel@tonic-gate result = "trailing \\ character";
3667c478bd9Sstevel@tonic-gate *--addr = BAD_CHAR_REPLACEMENT;
3677c478bd9Sstevel@tonic-gate break;
3687c478bd9Sstevel@tonic-gate }
3697c478bd9Sstevel@tonic-gate }
370058561cbSjbeck if (!EightBitAddrOK && (*addr & 0340) == 0200)
3717c478bd9Sstevel@tonic-gate {
3727c478bd9Sstevel@tonic-gate setstat(EX_USAGE);
3737c478bd9Sstevel@tonic-gate result = "8-bit character";
3747c478bd9Sstevel@tonic-gate *addr = BAD_CHAR_REPLACEMENT;
3757c478bd9Sstevel@tonic-gate continue;
3767c478bd9Sstevel@tonic-gate }
3777c478bd9Sstevel@tonic-gate }
3787c478bd9Sstevel@tonic-gate if (quoted)
3797c478bd9Sstevel@tonic-gate result = "unbalanced quote"; /* unbalanced quote */
3807c478bd9Sstevel@tonic-gate if (result != NULL && complain)
3817c478bd9Sstevel@tonic-gate {
3827c478bd9Sstevel@tonic-gate if (isrcpt)
3837c478bd9Sstevel@tonic-gate usrerr("501 5.1.3 Syntax error in mailbox address \"%s\" (%s)",
3847c478bd9Sstevel@tonic-gate b, result);
3857c478bd9Sstevel@tonic-gate else
3867c478bd9Sstevel@tonic-gate usrerr("501 5.1.7 Syntax error in mailbox address \"%s\" (%s)",
3877c478bd9Sstevel@tonic-gate b, result);
3887c478bd9Sstevel@tonic-gate }
3897c478bd9Sstevel@tonic-gate return result != NULL;
3907c478bd9Sstevel@tonic-gate }
3917c478bd9Sstevel@tonic-gate /*
3927c478bd9Sstevel@tonic-gate ** ALLOCADDR -- do local allocations of address on demand.
3937c478bd9Sstevel@tonic-gate **
3947c478bd9Sstevel@tonic-gate ** Also lowercases the host name if requested.
3957c478bd9Sstevel@tonic-gate **
3967c478bd9Sstevel@tonic-gate ** Parameters:
3977c478bd9Sstevel@tonic-gate ** a -- the address to reallocate.
3987c478bd9Sstevel@tonic-gate ** flags -- the copy flag (see RF_ definitions in sendmail.h
3997c478bd9Sstevel@tonic-gate ** for a description).
4007c478bd9Sstevel@tonic-gate ** paddr -- the printname of the address.
4017c478bd9Sstevel@tonic-gate ** e -- envelope
4027c478bd9Sstevel@tonic-gate **
4037c478bd9Sstevel@tonic-gate ** Returns:
4047c478bd9Sstevel@tonic-gate ** none.
4057c478bd9Sstevel@tonic-gate **
4067c478bd9Sstevel@tonic-gate ** Side Effects:
4077c478bd9Sstevel@tonic-gate ** Copies portions of a into local buffers as requested.
4087c478bd9Sstevel@tonic-gate */
4097c478bd9Sstevel@tonic-gate
4107c478bd9Sstevel@tonic-gate static void
allocaddr(a,flags,paddr,e)4117c478bd9Sstevel@tonic-gate allocaddr(a, flags, paddr, e)
4127c478bd9Sstevel@tonic-gate register ADDRESS *a;
4137c478bd9Sstevel@tonic-gate int flags;
4147c478bd9Sstevel@tonic-gate char *paddr;
4157c478bd9Sstevel@tonic-gate ENVELOPE *e;
4167c478bd9Sstevel@tonic-gate {
4177c478bd9Sstevel@tonic-gate if (tTd(24, 4))
4187c478bd9Sstevel@tonic-gate sm_dprintf("allocaddr(flags=%x, paddr=%s)\n", flags, paddr);
4197c478bd9Sstevel@tonic-gate
4207c478bd9Sstevel@tonic-gate a->q_paddr = paddr;
4217c478bd9Sstevel@tonic-gate
4227c478bd9Sstevel@tonic-gate if (a->q_user == NULL)
4237c478bd9Sstevel@tonic-gate a->q_user = "";
4247c478bd9Sstevel@tonic-gate if (a->q_host == NULL)
4257c478bd9Sstevel@tonic-gate a->q_host = "";
4267c478bd9Sstevel@tonic-gate
4277c478bd9Sstevel@tonic-gate if (bitset(RF_COPYPARSE, flags))
4287c478bd9Sstevel@tonic-gate {
4297c478bd9Sstevel@tonic-gate a->q_host = sm_rpool_strdup_x(e->e_rpool, a->q_host);
4307c478bd9Sstevel@tonic-gate if (a->q_user != a->q_paddr)
4317c478bd9Sstevel@tonic-gate a->q_user = sm_rpool_strdup_x(e->e_rpool, a->q_user);
4327c478bd9Sstevel@tonic-gate }
4337c478bd9Sstevel@tonic-gate
4347c478bd9Sstevel@tonic-gate if (a->q_paddr == NULL)
4357c478bd9Sstevel@tonic-gate a->q_paddr = sm_rpool_strdup_x(e->e_rpool, a->q_user);
4367c478bd9Sstevel@tonic-gate a->q_qgrp = NOAQGRP;
4377c478bd9Sstevel@tonic-gate }
438058561cbSjbeck
4397c478bd9Sstevel@tonic-gate /*
4407c478bd9Sstevel@tonic-gate ** PRESCAN -- Prescan name and make it canonical
4417c478bd9Sstevel@tonic-gate **
4427c478bd9Sstevel@tonic-gate ** Scans a name and turns it into a set of tokens. This process
4437c478bd9Sstevel@tonic-gate ** deletes blanks and comments (in parentheses) (if the token type
4447c478bd9Sstevel@tonic-gate ** for left paren is SPC).
4457c478bd9Sstevel@tonic-gate **
4467c478bd9Sstevel@tonic-gate ** This routine knows about quoted strings and angle brackets.
4477c478bd9Sstevel@tonic-gate **
4487c478bd9Sstevel@tonic-gate ** There are certain subtleties to this routine. The one that
4497c478bd9Sstevel@tonic-gate ** comes to mind now is that backslashes on the ends of names
4507c478bd9Sstevel@tonic-gate ** are silently stripped off; this is intentional. The problem
4517c478bd9Sstevel@tonic-gate ** is that some versions of sndmsg (like at LBL) set the kill
4527c478bd9Sstevel@tonic-gate ** character to something other than @ when reading addresses;
4537c478bd9Sstevel@tonic-gate ** so people type "csvax.eric\@berkeley" -- which screws up the
4547c478bd9Sstevel@tonic-gate ** berknet mailer.
4557c478bd9Sstevel@tonic-gate **
4567c478bd9Sstevel@tonic-gate ** Parameters:
4577c478bd9Sstevel@tonic-gate ** addr -- the name to chomp.
4587c478bd9Sstevel@tonic-gate ** delim -- the delimiter for the address, normally
4597c478bd9Sstevel@tonic-gate ** '\0' or ','; \0 is accepted in any case.
4607c478bd9Sstevel@tonic-gate ** If '\t' then we are reading the .cf file.
4617c478bd9Sstevel@tonic-gate ** pvpbuf -- place to put the saved text -- note that
4627c478bd9Sstevel@tonic-gate ** the pointers are static.
4637c478bd9Sstevel@tonic-gate ** pvpbsize -- size of pvpbuf.
4647c478bd9Sstevel@tonic-gate ** delimptr -- if non-NULL, set to the location of the
4657c478bd9Sstevel@tonic-gate ** terminating delimiter.
4667c478bd9Sstevel@tonic-gate ** toktab -- if set, a token table to use for parsing.
4677c478bd9Sstevel@tonic-gate ** If NULL, use the default table.
4687c478bd9Sstevel@tonic-gate ** ignore -- if true, ignore unbalanced addresses
4697c478bd9Sstevel@tonic-gate **
4707c478bd9Sstevel@tonic-gate ** Returns:
4717c478bd9Sstevel@tonic-gate ** A pointer to a vector of tokens.
4727c478bd9Sstevel@tonic-gate ** NULL on error.
4737c478bd9Sstevel@tonic-gate */
4747c478bd9Sstevel@tonic-gate
4757c478bd9Sstevel@tonic-gate /* states and character types */
4767c478bd9Sstevel@tonic-gate #define OPR 0 /* operator */
4777c478bd9Sstevel@tonic-gate #define ATM 1 /* atom */
4787c478bd9Sstevel@tonic-gate #define QST 2 /* in quoted string */
4797c478bd9Sstevel@tonic-gate #define SPC 3 /* chewing up spaces */
4807c478bd9Sstevel@tonic-gate #define ONE 4 /* pick up one character */
4817c478bd9Sstevel@tonic-gate #define ILL 5 /* illegal character */
4827c478bd9Sstevel@tonic-gate
4837c478bd9Sstevel@tonic-gate #define NSTATES 6 /* number of states */
4847c478bd9Sstevel@tonic-gate #define TYPE 017 /* mask to select state type */
4857c478bd9Sstevel@tonic-gate
4867c478bd9Sstevel@tonic-gate /* meta bits for table */
4877c478bd9Sstevel@tonic-gate #define M 020 /* meta character; don't pass through */
4887c478bd9Sstevel@tonic-gate #define B 040 /* cause a break */
4897c478bd9Sstevel@tonic-gate #define MB M|B /* meta-break */
4907c478bd9Sstevel@tonic-gate
4917c478bd9Sstevel@tonic-gate static short StateTab[NSTATES][NSTATES] =
4927c478bd9Sstevel@tonic-gate {
4937c478bd9Sstevel@tonic-gate /* oldst chtype> OPR ATM QST SPC ONE ILL */
4947c478bd9Sstevel@tonic-gate /*OPR*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|MB },
4957c478bd9Sstevel@tonic-gate /*ATM*/ { OPR|B, ATM, QST|B, SPC|MB, ONE|B, ILL|MB },
4967c478bd9Sstevel@tonic-gate /*QST*/ { QST, QST, OPR, QST, QST, QST },
4977c478bd9Sstevel@tonic-gate /*SPC*/ { OPR, ATM, QST, SPC|M, ONE, ILL|MB },
4987c478bd9Sstevel@tonic-gate /*ONE*/ { OPR, OPR, OPR, OPR, OPR, ILL|MB },
499058561cbSjbeck /*ILL*/ { OPR|B, ATM|B, QST|B, SPC|MB, ONE|B, ILL|M }
5007c478bd9Sstevel@tonic-gate };
5017c478bd9Sstevel@tonic-gate
502058561cbSjbeck /* these all get modified with the OperatorChars */
503058561cbSjbeck
504058561cbSjbeck /* token type table for external strings */
505058561cbSjbeck unsigned char ExtTokenTab[256] =
506058561cbSjbeck {
507058561cbSjbeck /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
508058561cbSjbeck ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM,
509058561cbSjbeck /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
510058561cbSjbeck ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
511058561cbSjbeck /* sp ! " # $ % & ' ( ) * + , - . / */
512058561cbSjbeck SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, SPC,SPC,ATM,ATM,ATM,ATM,ATM,ATM,
513058561cbSjbeck /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
514058561cbSjbeck ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
515058561cbSjbeck /* @ A B C D E F G H I J K L M N O */
516058561cbSjbeck ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
517058561cbSjbeck /* P Q R S T U V W X Y Z [ \ ] ^ _ */
518058561cbSjbeck ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
519058561cbSjbeck /* ` a b c d e f g h i j k l m n o */
520058561cbSjbeck ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
521058561cbSjbeck /* p q r s t u v w x y z { | } ~ del */
522058561cbSjbeck ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
523058561cbSjbeck
524058561cbSjbeck /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
525058561cbSjbeck ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
526058561cbSjbeck /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
527058561cbSjbeck ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
528058561cbSjbeck /* sp ! " # $ % & ' ( ) * + , - . / */
529058561cbSjbeck ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
530058561cbSjbeck /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
531058561cbSjbeck ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
532058561cbSjbeck /* @ A B C D E F G H I J K L M N O */
533058561cbSjbeck ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
534058561cbSjbeck /* P Q R S T U V W X Y Z [ \ ] ^ _ */
535058561cbSjbeck ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
536058561cbSjbeck /* ` a b c d e f g h i j k l m n o */
537058561cbSjbeck ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
538058561cbSjbeck /* p q r s t u v w x y z { | } ~ del */
539058561cbSjbeck ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM
540058561cbSjbeck };
541058561cbSjbeck
542058561cbSjbeck /* token type table for internal strings */
543058561cbSjbeck unsigned char IntTokenTab[256] =
5447c478bd9Sstevel@tonic-gate {
5457c478bd9Sstevel@tonic-gate /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
5467c478bd9Sstevel@tonic-gate ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM,
5477c478bd9Sstevel@tonic-gate /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
5487c478bd9Sstevel@tonic-gate ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
5497c478bd9Sstevel@tonic-gate /* sp ! " # $ % & ' ( ) * + , - . / */
5507c478bd9Sstevel@tonic-gate SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, SPC,SPC,ATM,ATM,ATM,ATM,ATM,ATM,
5517c478bd9Sstevel@tonic-gate /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
5527c478bd9Sstevel@tonic-gate ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
5537c478bd9Sstevel@tonic-gate /* @ A B C D E F G H I J K L M N O */
5547c478bd9Sstevel@tonic-gate ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
5557c478bd9Sstevel@tonic-gate /* P Q R S T U V W X Y Z [ \ ] ^ _ */
5567c478bd9Sstevel@tonic-gate ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
5577c478bd9Sstevel@tonic-gate /* ` a b c d e f g h i j k l m n o */
5587c478bd9Sstevel@tonic-gate ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
5597c478bd9Sstevel@tonic-gate /* p q r s t u v w x y z { | } ~ del */
5607c478bd9Sstevel@tonic-gate ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
5617c478bd9Sstevel@tonic-gate
5627c478bd9Sstevel@tonic-gate /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
5637c478bd9Sstevel@tonic-gate OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
5647c478bd9Sstevel@tonic-gate /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
5657c478bd9Sstevel@tonic-gate OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
5667c478bd9Sstevel@tonic-gate /* sp ! " # $ % & ' ( ) * + , - . / */
5677c478bd9Sstevel@tonic-gate ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
5687c478bd9Sstevel@tonic-gate /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
5697c478bd9Sstevel@tonic-gate ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
5707c478bd9Sstevel@tonic-gate /* @ A B C D E F G H I J K L M N O */
5717c478bd9Sstevel@tonic-gate ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
5727c478bd9Sstevel@tonic-gate /* P Q R S T U V W X Y Z [ \ ] ^ _ */
5737c478bd9Sstevel@tonic-gate ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
5747c478bd9Sstevel@tonic-gate /* ` a b c d e f g h i j k l m n o */
5757c478bd9Sstevel@tonic-gate ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
5767c478bd9Sstevel@tonic-gate /* p q r s t u v w x y z { | } ~ del */
577058561cbSjbeck ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ONE
5787c478bd9Sstevel@tonic-gate };
5797c478bd9Sstevel@tonic-gate
5807c478bd9Sstevel@tonic-gate /* token type table for MIME parsing */
5817c478bd9Sstevel@tonic-gate unsigned char MimeTokenTab[256] =
5827c478bd9Sstevel@tonic-gate {
5837c478bd9Sstevel@tonic-gate /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
5847c478bd9Sstevel@tonic-gate ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,SPC,SPC,SPC,SPC,SPC,ILL,ILL,
5857c478bd9Sstevel@tonic-gate /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
5867c478bd9Sstevel@tonic-gate ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
5877c478bd9Sstevel@tonic-gate /* sp ! " # $ % & ' ( ) * + , - . / */
5887c478bd9Sstevel@tonic-gate SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, SPC,SPC,ATM,ATM,OPR,ATM,ATM,OPR,
5897c478bd9Sstevel@tonic-gate /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
5907c478bd9Sstevel@tonic-gate ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,OPR,OPR,OPR,OPR,OPR,OPR,
5917c478bd9Sstevel@tonic-gate /* @ A B C D E F G H I J K L M N O */
5927c478bd9Sstevel@tonic-gate OPR,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
5937c478bd9Sstevel@tonic-gate /* P Q R S T U V W X Y Z [ \ ] ^ _ */
5947c478bd9Sstevel@tonic-gate ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,OPR,OPR,OPR,ATM,ATM,
5957c478bd9Sstevel@tonic-gate /* ` a b c d e f g h i j k l m n o */
5967c478bd9Sstevel@tonic-gate ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
5977c478bd9Sstevel@tonic-gate /* p q r s t u v w x y z { | } ~ del */
5987c478bd9Sstevel@tonic-gate ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
5997c478bd9Sstevel@tonic-gate
6007c478bd9Sstevel@tonic-gate /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
6017c478bd9Sstevel@tonic-gate ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
6027c478bd9Sstevel@tonic-gate /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
6037c478bd9Sstevel@tonic-gate ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
6047c478bd9Sstevel@tonic-gate /* sp ! " # $ % & ' ( ) * + , - . / */
6057c478bd9Sstevel@tonic-gate ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
6067c478bd9Sstevel@tonic-gate /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
6077c478bd9Sstevel@tonic-gate ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
6087c478bd9Sstevel@tonic-gate /* @ A B C D E F G H I J K L M N O */
6097c478bd9Sstevel@tonic-gate ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
6107c478bd9Sstevel@tonic-gate /* P Q R S T U V W X Y Z [ \ ] ^ _ */
6117c478bd9Sstevel@tonic-gate ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
6127c478bd9Sstevel@tonic-gate /* ` a b c d e f g h i j k l m n o */
6137c478bd9Sstevel@tonic-gate ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL,
6147c478bd9Sstevel@tonic-gate /* p q r s t u v w x y z { | } ~ del */
615058561cbSjbeck ILL,ILL,ILL,ILL,ILL,ILL,ILL,ILL, ILL,ILL,ILL,ILL,ILL,ILL,ILL,ONE
6167c478bd9Sstevel@tonic-gate };
6177c478bd9Sstevel@tonic-gate
6187c478bd9Sstevel@tonic-gate /* token type table: don't strip comments */
6197c478bd9Sstevel@tonic-gate unsigned char TokTypeNoC[256] =
6207c478bd9Sstevel@tonic-gate {
6217c478bd9Sstevel@tonic-gate /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
6227c478bd9Sstevel@tonic-gate ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,SPC,SPC,SPC,SPC,SPC,ATM,ATM,
6237c478bd9Sstevel@tonic-gate /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
6247c478bd9Sstevel@tonic-gate ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
6257c478bd9Sstevel@tonic-gate /* sp ! " # $ % & ' ( ) * + , - . / */
6267c478bd9Sstevel@tonic-gate SPC,ATM,QST,ATM,ATM,ATM,ATM,ATM, OPR,OPR,ATM,ATM,ATM,ATM,ATM,ATM,
6277c478bd9Sstevel@tonic-gate /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
6287c478bd9Sstevel@tonic-gate ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
6297c478bd9Sstevel@tonic-gate /* @ A B C D E F G H I J K L M N O */
6307c478bd9Sstevel@tonic-gate ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
6317c478bd9Sstevel@tonic-gate /* P Q R S T U V W X Y Z [ \ ] ^ _ */
6327c478bd9Sstevel@tonic-gate ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
6337c478bd9Sstevel@tonic-gate /* ` a b c d e f g h i j k l m n o */
6347c478bd9Sstevel@tonic-gate ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
6357c478bd9Sstevel@tonic-gate /* p q r s t u v w x y z { | } ~ del */
6367c478bd9Sstevel@tonic-gate ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
6377c478bd9Sstevel@tonic-gate
6387c478bd9Sstevel@tonic-gate /* nul soh stx etx eot enq ack bel bs ht nl vt np cr so si */
6397c478bd9Sstevel@tonic-gate OPR,OPR,ONE,OPR,OPR,OPR,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
6407c478bd9Sstevel@tonic-gate /* dle dc1 dc2 dc3 dc4 nak syn etb can em sub esc fs gs rs us */
6417c478bd9Sstevel@tonic-gate OPR,OPR,OPR,ONE,ONE,ONE,OPR,OPR, OPR,OPR,OPR,OPR,OPR,OPR,OPR,OPR,
6427c478bd9Sstevel@tonic-gate /* sp ! " # $ % & ' ( ) * + , - . / */
6437c478bd9Sstevel@tonic-gate ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
6447c478bd9Sstevel@tonic-gate /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
6457c478bd9Sstevel@tonic-gate ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
6467c478bd9Sstevel@tonic-gate /* @ A B C D E F G H I J K L M N O */
6477c478bd9Sstevel@tonic-gate ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
6487c478bd9Sstevel@tonic-gate /* P Q R S T U V W X Y Z [ \ ] ^ _ */
6497c478bd9Sstevel@tonic-gate ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
6507c478bd9Sstevel@tonic-gate /* ` a b c d e f g h i j k l m n o */
6517c478bd9Sstevel@tonic-gate ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM,
6527c478bd9Sstevel@tonic-gate /* p q r s t u v w x y z { | } ~ del */
653058561cbSjbeck ATM,ATM,ATM,ATM,ATM,ATM,ATM,ATM, ATM,ATM,ATM,ATM,ATM,ATM,ATM,ONE
6547c478bd9Sstevel@tonic-gate };
6557c478bd9Sstevel@tonic-gate
6567c478bd9Sstevel@tonic-gate
6577c478bd9Sstevel@tonic-gate #define NOCHAR (-1) /* signal nothing in lookahead token */
6587c478bd9Sstevel@tonic-gate
6597c478bd9Sstevel@tonic-gate char **
prescan(addr,delim,pvpbuf,pvpbsize,delimptr,toktab,ignore)6607c478bd9Sstevel@tonic-gate prescan(addr, delim, pvpbuf, pvpbsize, delimptr, toktab, ignore)
6617c478bd9Sstevel@tonic-gate char *addr;
6627c478bd9Sstevel@tonic-gate int delim;
6637c478bd9Sstevel@tonic-gate char pvpbuf[];
6647c478bd9Sstevel@tonic-gate int pvpbsize;
6657c478bd9Sstevel@tonic-gate char **delimptr;
6667c478bd9Sstevel@tonic-gate unsigned char *toktab;
6677c478bd9Sstevel@tonic-gate bool ignore;
6687c478bd9Sstevel@tonic-gate {
6697c478bd9Sstevel@tonic-gate register char *p;
6707c478bd9Sstevel@tonic-gate register char *q;
6717c478bd9Sstevel@tonic-gate register int c;
6727c478bd9Sstevel@tonic-gate char **avp;
6737c478bd9Sstevel@tonic-gate bool bslashmode;
6747c478bd9Sstevel@tonic-gate bool route_syntax;
6757c478bd9Sstevel@tonic-gate int cmntcnt;
6767c478bd9Sstevel@tonic-gate int anglecnt;
6777c478bd9Sstevel@tonic-gate char *tok;
6787c478bd9Sstevel@tonic-gate int state;
6797c478bd9Sstevel@tonic-gate int newstate;
6807c478bd9Sstevel@tonic-gate char *saveto = CurEnv->e_to;
6817c478bd9Sstevel@tonic-gate static char *av[MAXATOM + 1];
6827c478bd9Sstevel@tonic-gate static bool firsttime = true;
6837c478bd9Sstevel@tonic-gate
6847c478bd9Sstevel@tonic-gate if (firsttime)
6857c478bd9Sstevel@tonic-gate {
6867c478bd9Sstevel@tonic-gate /* initialize the token type table */
6877c478bd9Sstevel@tonic-gate char obuf[50];
6887c478bd9Sstevel@tonic-gate
6897c478bd9Sstevel@tonic-gate firsttime = false;
6907c478bd9Sstevel@tonic-gate if (OperatorChars == NULL)
6917c478bd9Sstevel@tonic-gate {
6927c478bd9Sstevel@tonic-gate if (ConfigLevel < 7)
6937c478bd9Sstevel@tonic-gate OperatorChars = macvalue('o', CurEnv);
6947c478bd9Sstevel@tonic-gate if (OperatorChars == NULL)
6957c478bd9Sstevel@tonic-gate OperatorChars = ".:@[]";
6967c478bd9Sstevel@tonic-gate }
697058561cbSjbeck expand(OperatorChars, obuf, sizeof(obuf) - sizeof(DELIMCHARS),
6987c478bd9Sstevel@tonic-gate CurEnv);
699058561cbSjbeck (void) sm_strlcat(obuf, DELIMCHARS, sizeof(obuf));
7007c478bd9Sstevel@tonic-gate for (p = obuf; *p != '\0'; p++)
7017c478bd9Sstevel@tonic-gate {
702058561cbSjbeck if (IntTokenTab[*p & 0xff] == ATM)
703058561cbSjbeck IntTokenTab[*p & 0xff] = OPR;
704058561cbSjbeck if (ExtTokenTab[*p & 0xff] == ATM)
705058561cbSjbeck ExtTokenTab[*p & 0xff] = OPR;
7067c478bd9Sstevel@tonic-gate if (TokTypeNoC[*p & 0xff] == ATM)
7077c478bd9Sstevel@tonic-gate TokTypeNoC[*p & 0xff] = OPR;
7087c478bd9Sstevel@tonic-gate }
7097c478bd9Sstevel@tonic-gate }
7107c478bd9Sstevel@tonic-gate if (toktab == NULL)
711058561cbSjbeck toktab = ExtTokenTab;
7127c478bd9Sstevel@tonic-gate
7137c478bd9Sstevel@tonic-gate /* make sure error messages don't have garbage on them */
7147c478bd9Sstevel@tonic-gate errno = 0;
7157c478bd9Sstevel@tonic-gate
7167c478bd9Sstevel@tonic-gate q = pvpbuf;
7177c478bd9Sstevel@tonic-gate bslashmode = false;
7187c478bd9Sstevel@tonic-gate route_syntax = false;
7197c478bd9Sstevel@tonic-gate cmntcnt = 0;
7207c478bd9Sstevel@tonic-gate anglecnt = 0;
7217c478bd9Sstevel@tonic-gate avp = av;
7227c478bd9Sstevel@tonic-gate state = ATM;
7237c478bd9Sstevel@tonic-gate c = NOCHAR;
7247c478bd9Sstevel@tonic-gate p = addr;
7257c478bd9Sstevel@tonic-gate CurEnv->e_to = p;
7267c478bd9Sstevel@tonic-gate if (tTd(22, 11))
7277c478bd9Sstevel@tonic-gate {
7287c478bd9Sstevel@tonic-gate sm_dprintf("prescan: ");
7297c478bd9Sstevel@tonic-gate xputs(sm_debug_file(), p);
7307c478bd9Sstevel@tonic-gate sm_dprintf("\n");
7317c478bd9Sstevel@tonic-gate }
7327c478bd9Sstevel@tonic-gate
7337c478bd9Sstevel@tonic-gate do
7347c478bd9Sstevel@tonic-gate {
7357c478bd9Sstevel@tonic-gate /* read a token */
7367c478bd9Sstevel@tonic-gate tok = q;
7377c478bd9Sstevel@tonic-gate for (;;)
7387c478bd9Sstevel@tonic-gate {
7397c478bd9Sstevel@tonic-gate /* store away any old lookahead character */
7407c478bd9Sstevel@tonic-gate if (c != NOCHAR && !bslashmode)
7417c478bd9Sstevel@tonic-gate {
7427c478bd9Sstevel@tonic-gate /* see if there is room */
7437c478bd9Sstevel@tonic-gate if (q >= &pvpbuf[pvpbsize - 5])
7447c478bd9Sstevel@tonic-gate {
7457c478bd9Sstevel@tonic-gate addrtoolong:
7467c478bd9Sstevel@tonic-gate usrerr("553 5.1.1 Address too long");
7477c478bd9Sstevel@tonic-gate if (strlen(addr) > MAXNAME)
7487c478bd9Sstevel@tonic-gate addr[MAXNAME] = '\0';
7497c478bd9Sstevel@tonic-gate returnnull:
7507c478bd9Sstevel@tonic-gate if (delimptr != NULL)
7517c478bd9Sstevel@tonic-gate {
7527c478bd9Sstevel@tonic-gate if (p > addr)
7537c478bd9Sstevel@tonic-gate --p;
7547c478bd9Sstevel@tonic-gate *delimptr = p;
7557c478bd9Sstevel@tonic-gate }
7567c478bd9Sstevel@tonic-gate CurEnv->e_to = saveto;
7577c478bd9Sstevel@tonic-gate return NULL;
7587c478bd9Sstevel@tonic-gate }
7597c478bd9Sstevel@tonic-gate
7607c478bd9Sstevel@tonic-gate /* squirrel it away */
7617c478bd9Sstevel@tonic-gate #if !ALLOW_255
762058561cbSjbeck if ((char) c == (char) -1 && !tTd(82, 101) &&
763058561cbSjbeck !EightBitAddrOK)
7647c478bd9Sstevel@tonic-gate c &= 0x7f;
7657c478bd9Sstevel@tonic-gate #endif /* !ALLOW_255 */
7667c478bd9Sstevel@tonic-gate *q++ = c;
7677c478bd9Sstevel@tonic-gate }
7687c478bd9Sstevel@tonic-gate
7697c478bd9Sstevel@tonic-gate /* read a new input character */
7707c478bd9Sstevel@tonic-gate c = (*p++) & 0x00ff;
7717c478bd9Sstevel@tonic-gate if (c == '\0')
7727c478bd9Sstevel@tonic-gate {
7737c478bd9Sstevel@tonic-gate /* diagnose and patch up bad syntax */
7747c478bd9Sstevel@tonic-gate if (ignore)
7757c478bd9Sstevel@tonic-gate break;
7767c478bd9Sstevel@tonic-gate else if (state == QST)
7777c478bd9Sstevel@tonic-gate {
7787c478bd9Sstevel@tonic-gate usrerr("553 Unbalanced '\"'");
7797c478bd9Sstevel@tonic-gate c = '"';
7807c478bd9Sstevel@tonic-gate }
7817c478bd9Sstevel@tonic-gate else if (cmntcnt > 0)
7827c478bd9Sstevel@tonic-gate {
7837c478bd9Sstevel@tonic-gate usrerr("553 Unbalanced '('");
7847c478bd9Sstevel@tonic-gate c = ')';
7857c478bd9Sstevel@tonic-gate }
7867c478bd9Sstevel@tonic-gate else if (anglecnt > 0)
7877c478bd9Sstevel@tonic-gate {
7887c478bd9Sstevel@tonic-gate c = '>';
7897c478bd9Sstevel@tonic-gate usrerr("553 Unbalanced '<'");
7907c478bd9Sstevel@tonic-gate }
7917c478bd9Sstevel@tonic-gate else
7927c478bd9Sstevel@tonic-gate break;
7937c478bd9Sstevel@tonic-gate
7947c478bd9Sstevel@tonic-gate p--;
7957c478bd9Sstevel@tonic-gate }
7967c478bd9Sstevel@tonic-gate else if (c == delim && cmntcnt <= 0 && state != QST)
7977c478bd9Sstevel@tonic-gate {
7987c478bd9Sstevel@tonic-gate if (anglecnt <= 0)
7997c478bd9Sstevel@tonic-gate break;
8007c478bd9Sstevel@tonic-gate
8017c478bd9Sstevel@tonic-gate /* special case for better error management */
8027c478bd9Sstevel@tonic-gate if (delim == ',' && !route_syntax && !ignore)
8037c478bd9Sstevel@tonic-gate {
8047c478bd9Sstevel@tonic-gate usrerr("553 Unbalanced '<'");
8057c478bd9Sstevel@tonic-gate c = '>';
8067c478bd9Sstevel@tonic-gate p--;
8077c478bd9Sstevel@tonic-gate }
8087c478bd9Sstevel@tonic-gate }
8097c478bd9Sstevel@tonic-gate
8107c478bd9Sstevel@tonic-gate if (tTd(22, 101))
8117c478bd9Sstevel@tonic-gate sm_dprintf("c=%c, s=%d; ", c, state);
8127c478bd9Sstevel@tonic-gate
8137c478bd9Sstevel@tonic-gate /* chew up special characters */
8147c478bd9Sstevel@tonic-gate *q = '\0';
8157c478bd9Sstevel@tonic-gate if (bslashmode)
8167c478bd9Sstevel@tonic-gate {
8177c478bd9Sstevel@tonic-gate bslashmode = false;
8187c478bd9Sstevel@tonic-gate
8197c478bd9Sstevel@tonic-gate /* kludge \! for naive users */
8207c478bd9Sstevel@tonic-gate if (cmntcnt > 0)
8217c478bd9Sstevel@tonic-gate {
8227c478bd9Sstevel@tonic-gate c = NOCHAR;
8237c478bd9Sstevel@tonic-gate continue;
8247c478bd9Sstevel@tonic-gate }
8257c478bd9Sstevel@tonic-gate else if (c != '!' || state == QST)
8267c478bd9Sstevel@tonic-gate {
8277c478bd9Sstevel@tonic-gate /* see if there is room */
8287c478bd9Sstevel@tonic-gate if (q >= &pvpbuf[pvpbsize - 5])
8297c478bd9Sstevel@tonic-gate goto addrtoolong;
8307c478bd9Sstevel@tonic-gate *q++ = '\\';
8317c478bd9Sstevel@tonic-gate continue;
8327c478bd9Sstevel@tonic-gate }
8337c478bd9Sstevel@tonic-gate }
8347c478bd9Sstevel@tonic-gate
8357c478bd9Sstevel@tonic-gate if (c == '\\')
8367c478bd9Sstevel@tonic-gate {
8377c478bd9Sstevel@tonic-gate bslashmode = true;
8387c478bd9Sstevel@tonic-gate }
8397c478bd9Sstevel@tonic-gate else if (state == QST)
8407c478bd9Sstevel@tonic-gate {
8417c478bd9Sstevel@tonic-gate /* EMPTY */
8427c478bd9Sstevel@tonic-gate /* do nothing, just avoid next clauses */
8437c478bd9Sstevel@tonic-gate }
8447c478bd9Sstevel@tonic-gate else if (c == '(' && toktab['('] == SPC)
8457c478bd9Sstevel@tonic-gate {
8467c478bd9Sstevel@tonic-gate cmntcnt++;
8477c478bd9Sstevel@tonic-gate c = NOCHAR;
8487c478bd9Sstevel@tonic-gate }
8497c478bd9Sstevel@tonic-gate else if (c == ')' && toktab['('] == SPC)
8507c478bd9Sstevel@tonic-gate {
8517c478bd9Sstevel@tonic-gate if (cmntcnt <= 0)
8527c478bd9Sstevel@tonic-gate {
8537c478bd9Sstevel@tonic-gate if (!ignore)
8547c478bd9Sstevel@tonic-gate {
8557c478bd9Sstevel@tonic-gate usrerr("553 Unbalanced ')'");
8567c478bd9Sstevel@tonic-gate c = NOCHAR;
8577c478bd9Sstevel@tonic-gate }
8587c478bd9Sstevel@tonic-gate }
8597c478bd9Sstevel@tonic-gate else
8607c478bd9Sstevel@tonic-gate cmntcnt--;
8617c478bd9Sstevel@tonic-gate }
8627c478bd9Sstevel@tonic-gate else if (cmntcnt > 0)
8637c478bd9Sstevel@tonic-gate {
8647c478bd9Sstevel@tonic-gate c = NOCHAR;
8657c478bd9Sstevel@tonic-gate }
8667c478bd9Sstevel@tonic-gate else if (c == '<')
8677c478bd9Sstevel@tonic-gate {
8687c478bd9Sstevel@tonic-gate char *ptr = p;
8697c478bd9Sstevel@tonic-gate
8707c478bd9Sstevel@tonic-gate anglecnt++;
8717c478bd9Sstevel@tonic-gate while (isascii(*ptr) && isspace(*ptr))
8727c478bd9Sstevel@tonic-gate ptr++;
8737c478bd9Sstevel@tonic-gate if (*ptr == '@')
8747c478bd9Sstevel@tonic-gate route_syntax = true;
8757c478bd9Sstevel@tonic-gate }
8767c478bd9Sstevel@tonic-gate else if (c == '>')
8777c478bd9Sstevel@tonic-gate {
8787c478bd9Sstevel@tonic-gate if (anglecnt <= 0)
8797c478bd9Sstevel@tonic-gate {
8807c478bd9Sstevel@tonic-gate if (!ignore)
8817c478bd9Sstevel@tonic-gate {
8827c478bd9Sstevel@tonic-gate usrerr("553 Unbalanced '>'");
8837c478bd9Sstevel@tonic-gate c = NOCHAR;
8847c478bd9Sstevel@tonic-gate }
8857c478bd9Sstevel@tonic-gate }
8867c478bd9Sstevel@tonic-gate else
8877c478bd9Sstevel@tonic-gate anglecnt--;
8887c478bd9Sstevel@tonic-gate route_syntax = false;
8897c478bd9Sstevel@tonic-gate }
8907c478bd9Sstevel@tonic-gate else if (delim == ' ' && isascii(c) && isspace(c))
8917c478bd9Sstevel@tonic-gate c = ' ';
8927c478bd9Sstevel@tonic-gate
8937c478bd9Sstevel@tonic-gate if (c == NOCHAR)
8947c478bd9Sstevel@tonic-gate continue;
8957c478bd9Sstevel@tonic-gate
8967c478bd9Sstevel@tonic-gate /* see if this is end of input */
8977c478bd9Sstevel@tonic-gate if (c == delim && anglecnt <= 0 && state != QST)
8987c478bd9Sstevel@tonic-gate break;
8997c478bd9Sstevel@tonic-gate
9007c478bd9Sstevel@tonic-gate newstate = StateTab[state][toktab[c & 0xff]];
9017c478bd9Sstevel@tonic-gate if (tTd(22, 101))
9027c478bd9Sstevel@tonic-gate sm_dprintf("ns=%02o\n", newstate);
9037c478bd9Sstevel@tonic-gate state = newstate & TYPE;
9047c478bd9Sstevel@tonic-gate if (state == ILL)
9057c478bd9Sstevel@tonic-gate {
9067c478bd9Sstevel@tonic-gate if (isascii(c) && isprint(c))
9077c478bd9Sstevel@tonic-gate usrerr("553 Illegal character %c", c);
9087c478bd9Sstevel@tonic-gate else
9097c478bd9Sstevel@tonic-gate usrerr("553 Illegal character 0x%02x",
9107c478bd9Sstevel@tonic-gate c & 0x0ff);
9117c478bd9Sstevel@tonic-gate }
9127c478bd9Sstevel@tonic-gate if (bitset(M, newstate))
9137c478bd9Sstevel@tonic-gate c = NOCHAR;
9147c478bd9Sstevel@tonic-gate if (bitset(B, newstate))
9157c478bd9Sstevel@tonic-gate break;
9167c478bd9Sstevel@tonic-gate }
9177c478bd9Sstevel@tonic-gate
9187c478bd9Sstevel@tonic-gate /* new token */
9197c478bd9Sstevel@tonic-gate if (tok != q)
9207c478bd9Sstevel@tonic-gate {
9217c478bd9Sstevel@tonic-gate /* see if there is room */
9227c478bd9Sstevel@tonic-gate if (q >= &pvpbuf[pvpbsize - 5])
9237c478bd9Sstevel@tonic-gate goto addrtoolong;
9247c478bd9Sstevel@tonic-gate *q++ = '\0';
9257c478bd9Sstevel@tonic-gate if (tTd(22, 36))
9267c478bd9Sstevel@tonic-gate {
9277c478bd9Sstevel@tonic-gate sm_dprintf("tok=");
9287c478bd9Sstevel@tonic-gate xputs(sm_debug_file(), tok);
9297c478bd9Sstevel@tonic-gate sm_dprintf("\n");
9307c478bd9Sstevel@tonic-gate }
9317c478bd9Sstevel@tonic-gate if (avp >= &av[MAXATOM])
9327c478bd9Sstevel@tonic-gate {
9337c478bd9Sstevel@tonic-gate usrerr("553 5.1.0 prescan: too many tokens");
9347c478bd9Sstevel@tonic-gate goto returnnull;
9357c478bd9Sstevel@tonic-gate }
9367c478bd9Sstevel@tonic-gate if (q - tok > MAXNAME)
9377c478bd9Sstevel@tonic-gate {
9387c478bd9Sstevel@tonic-gate usrerr("553 5.1.0 prescan: token too long");
9397c478bd9Sstevel@tonic-gate goto returnnull;
9407c478bd9Sstevel@tonic-gate }
9417c478bd9Sstevel@tonic-gate *avp++ = tok;
9427c478bd9Sstevel@tonic-gate }
9437c478bd9Sstevel@tonic-gate } while (c != '\0' && (c != delim || anglecnt > 0));
9447c478bd9Sstevel@tonic-gate *avp = NULL;
9457c478bd9Sstevel@tonic-gate if (delimptr != NULL)
9467c478bd9Sstevel@tonic-gate {
9477c478bd9Sstevel@tonic-gate if (p > addr)
9487c478bd9Sstevel@tonic-gate p--;
9497c478bd9Sstevel@tonic-gate *delimptr = p;
9507c478bd9Sstevel@tonic-gate }
9517c478bd9Sstevel@tonic-gate if (tTd(22, 12))
9527c478bd9Sstevel@tonic-gate {
9537c478bd9Sstevel@tonic-gate sm_dprintf("prescan==>");
9547c478bd9Sstevel@tonic-gate printav(sm_debug_file(), av);
9557c478bd9Sstevel@tonic-gate }
9567c478bd9Sstevel@tonic-gate CurEnv->e_to = saveto;
9577c478bd9Sstevel@tonic-gate if (av[0] == NULL)
9587c478bd9Sstevel@tonic-gate {
9597c478bd9Sstevel@tonic-gate if (tTd(22, 1))
9607c478bd9Sstevel@tonic-gate sm_dprintf("prescan: null leading token\n");
9617c478bd9Sstevel@tonic-gate return NULL;
9627c478bd9Sstevel@tonic-gate }
9637c478bd9Sstevel@tonic-gate return av;
9647c478bd9Sstevel@tonic-gate }
9657c478bd9Sstevel@tonic-gate /*
9667c478bd9Sstevel@tonic-gate ** REWRITE -- apply rewrite rules to token vector.
9677c478bd9Sstevel@tonic-gate **
9687c478bd9Sstevel@tonic-gate ** This routine is an ordered production system. Each rewrite
9697c478bd9Sstevel@tonic-gate ** rule has a LHS (called the pattern) and a RHS (called the
9707c478bd9Sstevel@tonic-gate ** rewrite); 'rwr' points the the current rewrite rule.
9717c478bd9Sstevel@tonic-gate **
9727c478bd9Sstevel@tonic-gate ** For each rewrite rule, 'avp' points the address vector we
9737c478bd9Sstevel@tonic-gate ** are trying to match against, and 'pvp' points to the pattern.
9747c478bd9Sstevel@tonic-gate ** If pvp points to a special match value (MATCHZANY, MATCHANY,
9757c478bd9Sstevel@tonic-gate ** MATCHONE, MATCHCLASS, MATCHNCLASS) then the address in avp
9767c478bd9Sstevel@tonic-gate ** matched is saved away in the match vector (pointed to by 'mvp').
9777c478bd9Sstevel@tonic-gate **
9787c478bd9Sstevel@tonic-gate ** When a match between avp & pvp does not match, we try to
9797c478bd9Sstevel@tonic-gate ** back out. If we back up over MATCHONE, MATCHCLASS, or MATCHNCLASS
9807c478bd9Sstevel@tonic-gate ** we must also back out the match in mvp. If we reach a
9817c478bd9Sstevel@tonic-gate ** MATCHANY or MATCHZANY we just extend the match and start
9827c478bd9Sstevel@tonic-gate ** over again.
9837c478bd9Sstevel@tonic-gate **
9847c478bd9Sstevel@tonic-gate ** When we finally match, we rewrite the address vector
9857c478bd9Sstevel@tonic-gate ** and try over again.
9867c478bd9Sstevel@tonic-gate **
9877c478bd9Sstevel@tonic-gate ** Parameters:
9887c478bd9Sstevel@tonic-gate ** pvp -- pointer to token vector.
9897c478bd9Sstevel@tonic-gate ** ruleset -- the ruleset to use for rewriting.
9907c478bd9Sstevel@tonic-gate ** reclevel -- recursion level (to catch loops).
9917c478bd9Sstevel@tonic-gate ** e -- the current envelope.
9927c478bd9Sstevel@tonic-gate ** maxatom -- maximum length of buffer (usually MAXATOM)
9937c478bd9Sstevel@tonic-gate **
9947c478bd9Sstevel@tonic-gate ** Returns:
9957c478bd9Sstevel@tonic-gate ** A status code. If EX_TEMPFAIL, higher level code should
9967c478bd9Sstevel@tonic-gate ** attempt recovery.
9977c478bd9Sstevel@tonic-gate **
9987c478bd9Sstevel@tonic-gate ** Side Effects:
9997c478bd9Sstevel@tonic-gate ** pvp is modified.
10007c478bd9Sstevel@tonic-gate */
10017c478bd9Sstevel@tonic-gate
10027c478bd9Sstevel@tonic-gate struct match
10037c478bd9Sstevel@tonic-gate {
10047c478bd9Sstevel@tonic-gate char **match_first; /* first token matched */
10057c478bd9Sstevel@tonic-gate char **match_last; /* last token matched */
10067c478bd9Sstevel@tonic-gate char **match_pattern; /* pointer to pattern */
10077c478bd9Sstevel@tonic-gate };
10087c478bd9Sstevel@tonic-gate
10097c478bd9Sstevel@tonic-gate int
rewrite(pvp,ruleset,reclevel,e,maxatom)10107c478bd9Sstevel@tonic-gate rewrite(pvp, ruleset, reclevel, e, maxatom)
10117c478bd9Sstevel@tonic-gate char **pvp;
10127c478bd9Sstevel@tonic-gate int ruleset;
10137c478bd9Sstevel@tonic-gate int reclevel;
10147c478bd9Sstevel@tonic-gate register ENVELOPE *e;
10157c478bd9Sstevel@tonic-gate int maxatom;
10167c478bd9Sstevel@tonic-gate {
10177c478bd9Sstevel@tonic-gate register char *ap; /* address pointer */
10187c478bd9Sstevel@tonic-gate register char *rp; /* rewrite pointer */
10197c478bd9Sstevel@tonic-gate register char *rulename; /* ruleset name */
10207c478bd9Sstevel@tonic-gate register char *prefix;
10217c478bd9Sstevel@tonic-gate register char **avp; /* address vector pointer */
10227c478bd9Sstevel@tonic-gate register char **rvp; /* rewrite vector pointer */
10237c478bd9Sstevel@tonic-gate register struct match *mlp; /* cur ptr into mlist */
10247c478bd9Sstevel@tonic-gate register struct rewrite *rwr; /* pointer to current rewrite rule */
10257c478bd9Sstevel@tonic-gate int ruleno; /* current rule number */
10267c478bd9Sstevel@tonic-gate int rstat = EX_OK; /* return status */
10277c478bd9Sstevel@tonic-gate int loopcount;
10287c478bd9Sstevel@tonic-gate struct match mlist[MAXMATCH]; /* stores match on LHS */
10297c478bd9Sstevel@tonic-gate char *npvp[MAXATOM + 1]; /* temporary space for rebuild */
10307c478bd9Sstevel@tonic-gate char buf[MAXLINE];
10317c478bd9Sstevel@tonic-gate char name[6];
10327c478bd9Sstevel@tonic-gate
10337c478bd9Sstevel@tonic-gate /*
10347c478bd9Sstevel@tonic-gate ** mlp will not exceed mlist[] because readcf enforces
10357c478bd9Sstevel@tonic-gate ** the upper limit of entries when reading rulesets.
10367c478bd9Sstevel@tonic-gate */
10377c478bd9Sstevel@tonic-gate
10387c478bd9Sstevel@tonic-gate if (ruleset < 0 || ruleset >= MAXRWSETS)
10397c478bd9Sstevel@tonic-gate {
10407c478bd9Sstevel@tonic-gate syserr("554 5.3.5 rewrite: illegal ruleset number %d", ruleset);
10417c478bd9Sstevel@tonic-gate return EX_CONFIG;
10427c478bd9Sstevel@tonic-gate }
10437c478bd9Sstevel@tonic-gate rulename = RuleSetNames[ruleset];
10447c478bd9Sstevel@tonic-gate if (rulename == NULL)
10457c478bd9Sstevel@tonic-gate {
1046058561cbSjbeck (void) sm_snprintf(name, sizeof(name), "%d", ruleset);
10477c478bd9Sstevel@tonic-gate rulename = name;
10487c478bd9Sstevel@tonic-gate }
10497c478bd9Sstevel@tonic-gate if (OpMode == MD_TEST)
10507c478bd9Sstevel@tonic-gate prefix = "";
10517c478bd9Sstevel@tonic-gate else
10527c478bd9Sstevel@tonic-gate prefix = "rewrite: ruleset ";
10537c478bd9Sstevel@tonic-gate if (OpMode == MD_TEST)
10547c478bd9Sstevel@tonic-gate {
10557c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
10567c478bd9Sstevel@tonic-gate "%s%-16.16s input:", prefix, rulename);
10577c478bd9Sstevel@tonic-gate printav(smioout, pvp);
10587c478bd9Sstevel@tonic-gate }
10597c478bd9Sstevel@tonic-gate else if (tTd(21, 1))
10607c478bd9Sstevel@tonic-gate {
10617c478bd9Sstevel@tonic-gate sm_dprintf("%s%-16.16s input:", prefix, rulename);
10627c478bd9Sstevel@tonic-gate printav(sm_debug_file(), pvp);
10637c478bd9Sstevel@tonic-gate }
10647c478bd9Sstevel@tonic-gate if (reclevel++ > MaxRuleRecursion)
10657c478bd9Sstevel@tonic-gate {
10667c478bd9Sstevel@tonic-gate syserr("rewrite: excessive recursion (max %d), ruleset %s",
10677c478bd9Sstevel@tonic-gate MaxRuleRecursion, rulename);
10687c478bd9Sstevel@tonic-gate return EX_CONFIG;
10697c478bd9Sstevel@tonic-gate }
10707c478bd9Sstevel@tonic-gate if (pvp == NULL)
10717c478bd9Sstevel@tonic-gate return EX_USAGE;
10727c478bd9Sstevel@tonic-gate if (maxatom <= 0)
10737c478bd9Sstevel@tonic-gate return EX_USAGE;
10747c478bd9Sstevel@tonic-gate
10757c478bd9Sstevel@tonic-gate /*
10767c478bd9Sstevel@tonic-gate ** Run through the list of rewrite rules, applying
10777c478bd9Sstevel@tonic-gate ** any that match.
10787c478bd9Sstevel@tonic-gate */
10797c478bd9Sstevel@tonic-gate
10807c478bd9Sstevel@tonic-gate ruleno = 1;
10817c478bd9Sstevel@tonic-gate loopcount = 0;
10827c478bd9Sstevel@tonic-gate for (rwr = RewriteRules[ruleset]; rwr != NULL; )
10837c478bd9Sstevel@tonic-gate {
10847c478bd9Sstevel@tonic-gate int status;
10857c478bd9Sstevel@tonic-gate
10867c478bd9Sstevel@tonic-gate /* if already canonical, quit now */
10877c478bd9Sstevel@tonic-gate if (pvp[0] != NULL && (pvp[0][0] & 0377) == CANONNET)
10887c478bd9Sstevel@tonic-gate break;
10897c478bd9Sstevel@tonic-gate
10907c478bd9Sstevel@tonic-gate if (tTd(21, 12))
10917c478bd9Sstevel@tonic-gate {
10927c478bd9Sstevel@tonic-gate if (tTd(21, 15))
10937c478bd9Sstevel@tonic-gate sm_dprintf("-----trying rule (line %d):",
10947c478bd9Sstevel@tonic-gate rwr->r_line);
10957c478bd9Sstevel@tonic-gate else
10967c478bd9Sstevel@tonic-gate sm_dprintf("-----trying rule:");
10977c478bd9Sstevel@tonic-gate printav(sm_debug_file(), rwr->r_lhs);
10987c478bd9Sstevel@tonic-gate }
10997c478bd9Sstevel@tonic-gate
11007c478bd9Sstevel@tonic-gate /* try to match on this rule */
11017c478bd9Sstevel@tonic-gate mlp = mlist;
11027c478bd9Sstevel@tonic-gate rvp = rwr->r_lhs;
11037c478bd9Sstevel@tonic-gate avp = pvp;
11047c478bd9Sstevel@tonic-gate if (++loopcount > 100)
11057c478bd9Sstevel@tonic-gate {
11067c478bd9Sstevel@tonic-gate syserr("554 5.3.5 Infinite loop in ruleset %s, rule %d",
11077c478bd9Sstevel@tonic-gate rulename, ruleno);
11087c478bd9Sstevel@tonic-gate if (tTd(21, 1))
11097c478bd9Sstevel@tonic-gate {
11107c478bd9Sstevel@tonic-gate sm_dprintf("workspace: ");
11117c478bd9Sstevel@tonic-gate printav(sm_debug_file(), pvp);
11127c478bd9Sstevel@tonic-gate }
11137c478bd9Sstevel@tonic-gate break;
11147c478bd9Sstevel@tonic-gate }
11157c478bd9Sstevel@tonic-gate
11167c478bd9Sstevel@tonic-gate while ((ap = *avp) != NULL || *rvp != NULL)
11177c478bd9Sstevel@tonic-gate {
11187c478bd9Sstevel@tonic-gate rp = *rvp;
11197c478bd9Sstevel@tonic-gate if (tTd(21, 35))
11207c478bd9Sstevel@tonic-gate {
11217c478bd9Sstevel@tonic-gate sm_dprintf("ADVANCE rp=");
11227c478bd9Sstevel@tonic-gate xputs(sm_debug_file(), rp);
11237c478bd9Sstevel@tonic-gate sm_dprintf(", ap=");
11247c478bd9Sstevel@tonic-gate xputs(sm_debug_file(), ap);
11257c478bd9Sstevel@tonic-gate sm_dprintf("\n");
11267c478bd9Sstevel@tonic-gate }
11277c478bd9Sstevel@tonic-gate if (rp == NULL)
11287c478bd9Sstevel@tonic-gate {
11297c478bd9Sstevel@tonic-gate /* end-of-pattern before end-of-address */
11307c478bd9Sstevel@tonic-gate goto backup;
11317c478bd9Sstevel@tonic-gate }
1132058561cbSjbeck if (ap == NULL &&
1133058561cbSjbeck (rp[0] & 0377) != MATCHZANY &&
1134058561cbSjbeck (rp[0] & 0377) != MATCHZERO)
11357c478bd9Sstevel@tonic-gate {
11367c478bd9Sstevel@tonic-gate /* end-of-input with patterns left */
11377c478bd9Sstevel@tonic-gate goto backup;
11387c478bd9Sstevel@tonic-gate }
11397c478bd9Sstevel@tonic-gate
1140058561cbSjbeck switch (rp[0] & 0377)
11417c478bd9Sstevel@tonic-gate {
11427c478bd9Sstevel@tonic-gate case MATCHCLASS:
11437c478bd9Sstevel@tonic-gate /* match any phrase in a class */
11447c478bd9Sstevel@tonic-gate mlp->match_pattern = rvp;
11457c478bd9Sstevel@tonic-gate mlp->match_first = avp;
11467c478bd9Sstevel@tonic-gate extendclass:
11477c478bd9Sstevel@tonic-gate ap = *avp;
11487c478bd9Sstevel@tonic-gate if (ap == NULL)
11497c478bd9Sstevel@tonic-gate goto backup;
11507c478bd9Sstevel@tonic-gate mlp->match_last = avp++;
11517c478bd9Sstevel@tonic-gate cataddr(mlp->match_first, mlp->match_last,
1152058561cbSjbeck buf, sizeof(buf), '\0', true);
11537c478bd9Sstevel@tonic-gate if (!wordinclass(buf, rp[1]))
11547c478bd9Sstevel@tonic-gate {
11557c478bd9Sstevel@tonic-gate if (tTd(21, 36))
11567c478bd9Sstevel@tonic-gate {
11577c478bd9Sstevel@tonic-gate sm_dprintf("EXTEND rp=");
11587c478bd9Sstevel@tonic-gate xputs(sm_debug_file(), rp);
11597c478bd9Sstevel@tonic-gate sm_dprintf(", ap=");
11607c478bd9Sstevel@tonic-gate xputs(sm_debug_file(), ap);
11617c478bd9Sstevel@tonic-gate sm_dprintf("\n");
11627c478bd9Sstevel@tonic-gate }
11637c478bd9Sstevel@tonic-gate goto extendclass;
11647c478bd9Sstevel@tonic-gate }
11657c478bd9Sstevel@tonic-gate if (tTd(21, 36))
11667c478bd9Sstevel@tonic-gate sm_dprintf("CLMATCH\n");
11677c478bd9Sstevel@tonic-gate mlp++;
11687c478bd9Sstevel@tonic-gate break;
11697c478bd9Sstevel@tonic-gate
11707c478bd9Sstevel@tonic-gate case MATCHNCLASS:
11717c478bd9Sstevel@tonic-gate /* match any token not in a class */
11727c478bd9Sstevel@tonic-gate if (wordinclass(ap, rp[1]))
11737c478bd9Sstevel@tonic-gate goto backup;
11747c478bd9Sstevel@tonic-gate
11757c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
11767c478bd9Sstevel@tonic-gate
11777c478bd9Sstevel@tonic-gate case MATCHONE:
11787c478bd9Sstevel@tonic-gate case MATCHANY:
11797c478bd9Sstevel@tonic-gate /* match exactly one token */
11807c478bd9Sstevel@tonic-gate mlp->match_pattern = rvp;
11817c478bd9Sstevel@tonic-gate mlp->match_first = avp;
11827c478bd9Sstevel@tonic-gate mlp->match_last = avp++;
11837c478bd9Sstevel@tonic-gate mlp++;
11847c478bd9Sstevel@tonic-gate break;
11857c478bd9Sstevel@tonic-gate
11867c478bd9Sstevel@tonic-gate case MATCHZANY:
11877c478bd9Sstevel@tonic-gate /* match zero or more tokens */
11887c478bd9Sstevel@tonic-gate mlp->match_pattern = rvp;
11897c478bd9Sstevel@tonic-gate mlp->match_first = avp;
11907c478bd9Sstevel@tonic-gate mlp->match_last = avp - 1;
11917c478bd9Sstevel@tonic-gate mlp++;
11927c478bd9Sstevel@tonic-gate break;
11937c478bd9Sstevel@tonic-gate
11947c478bd9Sstevel@tonic-gate case MATCHZERO:
11957c478bd9Sstevel@tonic-gate /* match zero tokens */
11967c478bd9Sstevel@tonic-gate break;
11977c478bd9Sstevel@tonic-gate
11987c478bd9Sstevel@tonic-gate case MACRODEXPAND:
11997c478bd9Sstevel@tonic-gate /*
12007c478bd9Sstevel@tonic-gate ** Match against run-time macro.
12017c478bd9Sstevel@tonic-gate ** This algorithm is broken for the
12027c478bd9Sstevel@tonic-gate ** general case (no recursive macros,
12037c478bd9Sstevel@tonic-gate ** improper tokenization) but should
12047c478bd9Sstevel@tonic-gate ** work for the usual cases.
12057c478bd9Sstevel@tonic-gate */
12067c478bd9Sstevel@tonic-gate
12077c478bd9Sstevel@tonic-gate ap = macvalue(rp[1], e);
12087c478bd9Sstevel@tonic-gate mlp->match_first = avp;
12097c478bd9Sstevel@tonic-gate if (tTd(21, 2))
12107c478bd9Sstevel@tonic-gate sm_dprintf("rewrite: LHS $&{%s} => \"%s\"\n",
12117c478bd9Sstevel@tonic-gate macname(rp[1]),
12127c478bd9Sstevel@tonic-gate ap == NULL ? "(NULL)" : ap);
12137c478bd9Sstevel@tonic-gate
12147c478bd9Sstevel@tonic-gate if (ap == NULL)
12157c478bd9Sstevel@tonic-gate break;
12167c478bd9Sstevel@tonic-gate while (*ap != '\0')
12177c478bd9Sstevel@tonic-gate {
12187c478bd9Sstevel@tonic-gate if (*avp == NULL ||
12197c478bd9Sstevel@tonic-gate sm_strncasecmp(ap, *avp,
12207c478bd9Sstevel@tonic-gate strlen(*avp)) != 0)
12217c478bd9Sstevel@tonic-gate {
12227c478bd9Sstevel@tonic-gate /* no match */
12237c478bd9Sstevel@tonic-gate avp = mlp->match_first;
12247c478bd9Sstevel@tonic-gate goto backup;
12257c478bd9Sstevel@tonic-gate }
12267c478bd9Sstevel@tonic-gate ap += strlen(*avp++);
12277c478bd9Sstevel@tonic-gate }
12287c478bd9Sstevel@tonic-gate
12297c478bd9Sstevel@tonic-gate /* match */
12307c478bd9Sstevel@tonic-gate break;
12317c478bd9Sstevel@tonic-gate
12327c478bd9Sstevel@tonic-gate default:
12337c478bd9Sstevel@tonic-gate /* must have exact match */
12347c478bd9Sstevel@tonic-gate if (sm_strcasecmp(rp, ap))
12357c478bd9Sstevel@tonic-gate goto backup;
12367c478bd9Sstevel@tonic-gate avp++;
12377c478bd9Sstevel@tonic-gate break;
12387c478bd9Sstevel@tonic-gate }
12397c478bd9Sstevel@tonic-gate
12407c478bd9Sstevel@tonic-gate /* successful match on this token */
12417c478bd9Sstevel@tonic-gate rvp++;
12427c478bd9Sstevel@tonic-gate continue;
12437c478bd9Sstevel@tonic-gate
12447c478bd9Sstevel@tonic-gate backup:
12457c478bd9Sstevel@tonic-gate /* match failed -- back up */
12467c478bd9Sstevel@tonic-gate while (--mlp >= mlist)
12477c478bd9Sstevel@tonic-gate {
12487c478bd9Sstevel@tonic-gate rvp = mlp->match_pattern;
12497c478bd9Sstevel@tonic-gate rp = *rvp;
12507c478bd9Sstevel@tonic-gate avp = mlp->match_last + 1;
12517c478bd9Sstevel@tonic-gate ap = *avp;
12527c478bd9Sstevel@tonic-gate
12537c478bd9Sstevel@tonic-gate if (tTd(21, 36))
12547c478bd9Sstevel@tonic-gate {
12557c478bd9Sstevel@tonic-gate sm_dprintf("BACKUP rp=");
12567c478bd9Sstevel@tonic-gate xputs(sm_debug_file(), rp);
12577c478bd9Sstevel@tonic-gate sm_dprintf(", ap=");
12587c478bd9Sstevel@tonic-gate xputs(sm_debug_file(), ap);
12597c478bd9Sstevel@tonic-gate sm_dprintf("\n");
12607c478bd9Sstevel@tonic-gate }
12617c478bd9Sstevel@tonic-gate
12627c478bd9Sstevel@tonic-gate if (ap == NULL)
12637c478bd9Sstevel@tonic-gate {
12647c478bd9Sstevel@tonic-gate /* run off the end -- back up again */
12657c478bd9Sstevel@tonic-gate continue;
12667c478bd9Sstevel@tonic-gate }
1267058561cbSjbeck
1268058561cbSjbeck if ((rp[0] & 0377) == MATCHANY ||
1269058561cbSjbeck (rp[0] & 0377) == MATCHZANY)
12707c478bd9Sstevel@tonic-gate {
12717c478bd9Sstevel@tonic-gate /* extend binding and continue */
12727c478bd9Sstevel@tonic-gate mlp->match_last = avp++;
12737c478bd9Sstevel@tonic-gate rvp++;
12747c478bd9Sstevel@tonic-gate mlp++;
12757c478bd9Sstevel@tonic-gate break;
12767c478bd9Sstevel@tonic-gate }
1277058561cbSjbeck if ((rp[0] & 0377) == MATCHCLASS)
12787c478bd9Sstevel@tonic-gate {
12797c478bd9Sstevel@tonic-gate /* extend binding and try again */
12807c478bd9Sstevel@tonic-gate mlp->match_last = avp;
12817c478bd9Sstevel@tonic-gate goto extendclass;
12827c478bd9Sstevel@tonic-gate }
12837c478bd9Sstevel@tonic-gate }
12847c478bd9Sstevel@tonic-gate
12857c478bd9Sstevel@tonic-gate if (mlp < mlist)
12867c478bd9Sstevel@tonic-gate {
12877c478bd9Sstevel@tonic-gate /* total failure to match */
12887c478bd9Sstevel@tonic-gate break;
12897c478bd9Sstevel@tonic-gate }
12907c478bd9Sstevel@tonic-gate }
12917c478bd9Sstevel@tonic-gate
12927c478bd9Sstevel@tonic-gate /*
12937c478bd9Sstevel@tonic-gate ** See if we successfully matched
12947c478bd9Sstevel@tonic-gate */
12957c478bd9Sstevel@tonic-gate
12967c478bd9Sstevel@tonic-gate if (mlp < mlist || *rvp != NULL)
12977c478bd9Sstevel@tonic-gate {
12987c478bd9Sstevel@tonic-gate if (tTd(21, 10))
12997c478bd9Sstevel@tonic-gate sm_dprintf("----- rule fails\n");
13007c478bd9Sstevel@tonic-gate rwr = rwr->r_next;
13017c478bd9Sstevel@tonic-gate ruleno++;
13027c478bd9Sstevel@tonic-gate loopcount = 0;
13037c478bd9Sstevel@tonic-gate continue;
13047c478bd9Sstevel@tonic-gate }
13057c478bd9Sstevel@tonic-gate
13067c478bd9Sstevel@tonic-gate rvp = rwr->r_rhs;
13077c478bd9Sstevel@tonic-gate if (tTd(21, 12))
13087c478bd9Sstevel@tonic-gate {
13097c478bd9Sstevel@tonic-gate sm_dprintf("-----rule matches:");
13107c478bd9Sstevel@tonic-gate printav(sm_debug_file(), rvp);
13117c478bd9Sstevel@tonic-gate }
13127c478bd9Sstevel@tonic-gate
13137c478bd9Sstevel@tonic-gate rp = *rvp;
13147c478bd9Sstevel@tonic-gate if (rp != NULL)
13157c478bd9Sstevel@tonic-gate {
1316058561cbSjbeck if ((rp[0] & 0377) == CANONUSER)
13177c478bd9Sstevel@tonic-gate {
13187c478bd9Sstevel@tonic-gate rvp++;
13197c478bd9Sstevel@tonic-gate rwr = rwr->r_next;
13207c478bd9Sstevel@tonic-gate ruleno++;
13217c478bd9Sstevel@tonic-gate loopcount = 0;
13227c478bd9Sstevel@tonic-gate }
1323058561cbSjbeck else if ((rp[0] & 0377) == CANONHOST)
13247c478bd9Sstevel@tonic-gate {
13257c478bd9Sstevel@tonic-gate rvp++;
13267c478bd9Sstevel@tonic-gate rwr = NULL;
13277c478bd9Sstevel@tonic-gate }
13287c478bd9Sstevel@tonic-gate }
13297c478bd9Sstevel@tonic-gate
13307c478bd9Sstevel@tonic-gate /* substitute */
13317c478bd9Sstevel@tonic-gate for (avp = npvp; *rvp != NULL; rvp++)
13327c478bd9Sstevel@tonic-gate {
13337c478bd9Sstevel@tonic-gate register struct match *m;
13347c478bd9Sstevel@tonic-gate register char **pp;
13357c478bd9Sstevel@tonic-gate
13367c478bd9Sstevel@tonic-gate rp = *rvp;
1337058561cbSjbeck if ((rp[0] & 0377) == MATCHREPL)
13387c478bd9Sstevel@tonic-gate {
13397c478bd9Sstevel@tonic-gate /* substitute from LHS */
13407c478bd9Sstevel@tonic-gate m = &mlist[rp[1] - '1'];
13417c478bd9Sstevel@tonic-gate if (m < mlist || m >= mlp)
13427c478bd9Sstevel@tonic-gate {
13437c478bd9Sstevel@tonic-gate syserr("554 5.3.5 rewrite: ruleset %s: replacement $%c out of bounds",
13447c478bd9Sstevel@tonic-gate rulename, rp[1]);
13457c478bd9Sstevel@tonic-gate return EX_CONFIG;
13467c478bd9Sstevel@tonic-gate }
13477c478bd9Sstevel@tonic-gate if (tTd(21, 15))
13487c478bd9Sstevel@tonic-gate {
13497c478bd9Sstevel@tonic-gate sm_dprintf("$%c:", rp[1]);
13507c478bd9Sstevel@tonic-gate pp = m->match_first;
13517c478bd9Sstevel@tonic-gate while (pp <= m->match_last)
13527c478bd9Sstevel@tonic-gate {
13537c478bd9Sstevel@tonic-gate sm_dprintf(" %p=\"", *pp);
13547c478bd9Sstevel@tonic-gate sm_dflush();
13557c478bd9Sstevel@tonic-gate sm_dprintf("%s\"", *pp++);
13567c478bd9Sstevel@tonic-gate }
13577c478bd9Sstevel@tonic-gate sm_dprintf("\n");
13587c478bd9Sstevel@tonic-gate }
13597c478bd9Sstevel@tonic-gate pp = m->match_first;
13607c478bd9Sstevel@tonic-gate while (pp <= m->match_last)
13617c478bd9Sstevel@tonic-gate {
13627c478bd9Sstevel@tonic-gate if (avp >= &npvp[maxatom])
13637c478bd9Sstevel@tonic-gate goto toolong;
13647c478bd9Sstevel@tonic-gate *avp++ = *pp++;
13657c478bd9Sstevel@tonic-gate }
13667c478bd9Sstevel@tonic-gate }
13677c478bd9Sstevel@tonic-gate else
13687c478bd9Sstevel@tonic-gate {
13697c478bd9Sstevel@tonic-gate /* some sort of replacement */
13707c478bd9Sstevel@tonic-gate if (avp >= &npvp[maxatom])
13717c478bd9Sstevel@tonic-gate {
13727c478bd9Sstevel@tonic-gate toolong:
13737c478bd9Sstevel@tonic-gate syserr("554 5.3.0 rewrite: expansion too long");
13747c478bd9Sstevel@tonic-gate if (LogLevel > 9)
13757c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
13767c478bd9Sstevel@tonic-gate "rewrite: expansion too long, ruleset=%s, ruleno=%d",
13777c478bd9Sstevel@tonic-gate rulename, ruleno);
13787c478bd9Sstevel@tonic-gate return EX_DATAERR;
13797c478bd9Sstevel@tonic-gate }
1380058561cbSjbeck if ((rp[0] & 0377) != MACRODEXPAND)
13817c478bd9Sstevel@tonic-gate {
1382058561cbSjbeck /* vanilla replacement from RHS */
13837c478bd9Sstevel@tonic-gate *avp++ = rp;
13847c478bd9Sstevel@tonic-gate }
13857c478bd9Sstevel@tonic-gate else
13867c478bd9Sstevel@tonic-gate {
13877c478bd9Sstevel@tonic-gate /* $&{x} replacement */
13887c478bd9Sstevel@tonic-gate char *mval = macvalue(rp[1], e);
13897c478bd9Sstevel@tonic-gate char **xpvp;
1390445f2479Sjbeck size_t trsize = 0;
13917c478bd9Sstevel@tonic-gate static size_t pvpb1_size = 0;
13927c478bd9Sstevel@tonic-gate static char **pvpb1 = NULL;
13937c478bd9Sstevel@tonic-gate char pvpbuf[PSBUFSIZE];
13947c478bd9Sstevel@tonic-gate
13957c478bd9Sstevel@tonic-gate if (tTd(21, 2))
13967c478bd9Sstevel@tonic-gate sm_dprintf("rewrite: RHS $&{%s} => \"%s\"\n",
13977c478bd9Sstevel@tonic-gate macname(rp[1]),
13987c478bd9Sstevel@tonic-gate mval == NULL ? "(NULL)" : mval);
13997c478bd9Sstevel@tonic-gate if (mval == NULL || *mval == '\0')
14007c478bd9Sstevel@tonic-gate continue;
14017c478bd9Sstevel@tonic-gate
14027c478bd9Sstevel@tonic-gate /* save the remainder of the input */
14037c478bd9Sstevel@tonic-gate for (xpvp = pvp; *xpvp != NULL; xpvp++)
1404058561cbSjbeck trsize += sizeof(*xpvp);
1405445f2479Sjbeck if (trsize > pvpb1_size)
14067c478bd9Sstevel@tonic-gate {
14077c478bd9Sstevel@tonic-gate if (pvpb1 != NULL)
14087c478bd9Sstevel@tonic-gate sm_free(pvpb1);
14097c478bd9Sstevel@tonic-gate pvpb1 = (char **)
14107c478bd9Sstevel@tonic-gate sm_pmalloc_x(trsize);
14117c478bd9Sstevel@tonic-gate pvpb1_size = trsize;
14127c478bd9Sstevel@tonic-gate }
14137c478bd9Sstevel@tonic-gate
14147c478bd9Sstevel@tonic-gate memmove((char *) pvpb1,
14157c478bd9Sstevel@tonic-gate (char *) pvp,
14167c478bd9Sstevel@tonic-gate trsize);
14177c478bd9Sstevel@tonic-gate
14187c478bd9Sstevel@tonic-gate /* scan the new replacement */
14197c478bd9Sstevel@tonic-gate xpvp = prescan(mval, '\0', pvpbuf,
1420058561cbSjbeck sizeof(pvpbuf), NULL,
14217c478bd9Sstevel@tonic-gate NULL, false);
14227c478bd9Sstevel@tonic-gate if (xpvp == NULL)
14237c478bd9Sstevel@tonic-gate {
14247c478bd9Sstevel@tonic-gate /* prescan pre-printed error */
14257c478bd9Sstevel@tonic-gate return EX_DATAERR;
14267c478bd9Sstevel@tonic-gate }
14277c478bd9Sstevel@tonic-gate
14287c478bd9Sstevel@tonic-gate /* insert it into the output stream */
14297c478bd9Sstevel@tonic-gate while (*xpvp != NULL)
14307c478bd9Sstevel@tonic-gate {
14317c478bd9Sstevel@tonic-gate if (tTd(21, 19))
14327c478bd9Sstevel@tonic-gate sm_dprintf(" ... %s\n",
14337c478bd9Sstevel@tonic-gate *xpvp);
14347c478bd9Sstevel@tonic-gate *avp++ = sm_rpool_strdup_x(
14357c478bd9Sstevel@tonic-gate e->e_rpool, *xpvp);
14367c478bd9Sstevel@tonic-gate if (avp >= &npvp[maxatom])
14377c478bd9Sstevel@tonic-gate goto toolong;
14387c478bd9Sstevel@tonic-gate xpvp++;
14397c478bd9Sstevel@tonic-gate }
14407c478bd9Sstevel@tonic-gate if (tTd(21, 19))
14417c478bd9Sstevel@tonic-gate sm_dprintf(" ... DONE\n");
14427c478bd9Sstevel@tonic-gate
14437c478bd9Sstevel@tonic-gate /* restore the old trailing input */
14447c478bd9Sstevel@tonic-gate memmove((char *) pvp,
14457c478bd9Sstevel@tonic-gate (char *) pvpb1,
14467c478bd9Sstevel@tonic-gate trsize);
14477c478bd9Sstevel@tonic-gate }
14487c478bd9Sstevel@tonic-gate }
14497c478bd9Sstevel@tonic-gate }
14507c478bd9Sstevel@tonic-gate *avp++ = NULL;
14517c478bd9Sstevel@tonic-gate
14527c478bd9Sstevel@tonic-gate /*
14537c478bd9Sstevel@tonic-gate ** Check for any hostname/keyword lookups.
14547c478bd9Sstevel@tonic-gate */
14557c478bd9Sstevel@tonic-gate
14567c478bd9Sstevel@tonic-gate for (rvp = npvp; *rvp != NULL; rvp++)
14577c478bd9Sstevel@tonic-gate {
14587c478bd9Sstevel@tonic-gate char **hbrvp;
14597c478bd9Sstevel@tonic-gate char **xpvp;
1460445f2479Sjbeck size_t trsize;
14617c478bd9Sstevel@tonic-gate char *replac;
14627c478bd9Sstevel@tonic-gate int endtoken;
1463*d4660949Sjbeck bool external;
14647c478bd9Sstevel@tonic-gate STAB *map;
14657c478bd9Sstevel@tonic-gate char *mapname;
14667c478bd9Sstevel@tonic-gate char **key_rvp;
14677c478bd9Sstevel@tonic-gate char **arg_rvp;
14687c478bd9Sstevel@tonic-gate char **default_rvp;
1469445f2479Sjbeck char cbuf[MAXKEY];
14707c478bd9Sstevel@tonic-gate char *pvpb1[MAXATOM + 1];
14717c478bd9Sstevel@tonic-gate char *argvect[MAX_MAP_ARGS];
14727c478bd9Sstevel@tonic-gate char pvpbuf[PSBUFSIZE];
14737c478bd9Sstevel@tonic-gate char *nullpvp[1];
14747c478bd9Sstevel@tonic-gate
14757c478bd9Sstevel@tonic-gate hbrvp = rvp;
1476058561cbSjbeck if ((rvp[0][0] & 0377) == HOSTBEGIN)
14777c478bd9Sstevel@tonic-gate {
14787c478bd9Sstevel@tonic-gate endtoken = HOSTEND;
14797c478bd9Sstevel@tonic-gate mapname = "host";
14807c478bd9Sstevel@tonic-gate }
1481058561cbSjbeck else if ((rvp[0][0] & 0377) == LOOKUPBEGIN)
14827c478bd9Sstevel@tonic-gate {
14837c478bd9Sstevel@tonic-gate endtoken = LOOKUPEND;
14847c478bd9Sstevel@tonic-gate mapname = *++rvp;
14857c478bd9Sstevel@tonic-gate if (mapname == NULL)
14863ee0e492Sjbeck {
14877c478bd9Sstevel@tonic-gate syserr("554 5.3.0 rewrite: missing mapname");
14883ee0e492Sjbeck /* NOTREACHED */
14893ee0e492Sjbeck SM_ASSERT(0);
14903ee0e492Sjbeck }
14917c478bd9Sstevel@tonic-gate }
1492058561cbSjbeck else
1493058561cbSjbeck continue;
1494058561cbSjbeck
1495058561cbSjbeck /*
1496058561cbSjbeck ** Got a hostname/keyword lookup.
1497058561cbSjbeck **
1498058561cbSjbeck ** This could be optimized fairly easily.
1499058561cbSjbeck */
1500058561cbSjbeck
15017c478bd9Sstevel@tonic-gate map = stab(mapname, ST_MAP, ST_FIND);
15027c478bd9Sstevel@tonic-gate if (map == NULL)
15037c478bd9Sstevel@tonic-gate syserr("554 5.3.0 rewrite: map %s not found",
15047c478bd9Sstevel@tonic-gate mapname);
15057c478bd9Sstevel@tonic-gate
15067c478bd9Sstevel@tonic-gate /* extract the match part */
15077c478bd9Sstevel@tonic-gate key_rvp = ++rvp;
15087c478bd9Sstevel@tonic-gate if (key_rvp == NULL)
15093ee0e492Sjbeck {
15107c478bd9Sstevel@tonic-gate syserr("554 5.3.0 rewrite: missing key for map %s",
15117c478bd9Sstevel@tonic-gate mapname);
15123ee0e492Sjbeck /* NOTREACHED */
15133ee0e492Sjbeck SM_ASSERT(0);
15143ee0e492Sjbeck }
15157c478bd9Sstevel@tonic-gate default_rvp = NULL;
15167c478bd9Sstevel@tonic-gate arg_rvp = argvect;
15177c478bd9Sstevel@tonic-gate xpvp = NULL;
15187c478bd9Sstevel@tonic-gate replac = pvpbuf;
1519058561cbSjbeck while (*rvp != NULL && ((rvp[0][0] & 0377) != endtoken))
15207c478bd9Sstevel@tonic-gate {
1521058561cbSjbeck int nodetype = rvp[0][0] & 0377;
15227c478bd9Sstevel@tonic-gate
15237c478bd9Sstevel@tonic-gate if (nodetype != CANONHOST &&
15247c478bd9Sstevel@tonic-gate nodetype != CANONUSER)
15257c478bd9Sstevel@tonic-gate {
15267c478bd9Sstevel@tonic-gate rvp++;
15277c478bd9Sstevel@tonic-gate continue;
15287c478bd9Sstevel@tonic-gate }
15297c478bd9Sstevel@tonic-gate
15307c478bd9Sstevel@tonic-gate *rvp++ = NULL;
15317c478bd9Sstevel@tonic-gate
15327c478bd9Sstevel@tonic-gate if (xpvp != NULL)
15337c478bd9Sstevel@tonic-gate {
15347c478bd9Sstevel@tonic-gate cataddr(xpvp, NULL, replac,
1535058561cbSjbeck &pvpbuf[sizeof(pvpbuf)] - replac,
1536058561cbSjbeck '\0', false);
15377c478bd9Sstevel@tonic-gate if (arg_rvp <
15387c478bd9Sstevel@tonic-gate &argvect[MAX_MAP_ARGS - 1])
15397c478bd9Sstevel@tonic-gate *++arg_rvp = replac;
15407c478bd9Sstevel@tonic-gate replac += strlen(replac) + 1;
15417c478bd9Sstevel@tonic-gate xpvp = NULL;
15427c478bd9Sstevel@tonic-gate }
15437c478bd9Sstevel@tonic-gate switch (nodetype)
15447c478bd9Sstevel@tonic-gate {
15457c478bd9Sstevel@tonic-gate case CANONHOST:
15467c478bd9Sstevel@tonic-gate xpvp = rvp;
15477c478bd9Sstevel@tonic-gate break;
15487c478bd9Sstevel@tonic-gate
15497c478bd9Sstevel@tonic-gate case CANONUSER:
15507c478bd9Sstevel@tonic-gate default_rvp = rvp;
15517c478bd9Sstevel@tonic-gate break;
15527c478bd9Sstevel@tonic-gate }
15537c478bd9Sstevel@tonic-gate }
15547c478bd9Sstevel@tonic-gate if (*rvp != NULL)
15557c478bd9Sstevel@tonic-gate *rvp++ = NULL;
15567c478bd9Sstevel@tonic-gate if (xpvp != NULL)
15577c478bd9Sstevel@tonic-gate {
15587c478bd9Sstevel@tonic-gate cataddr(xpvp, NULL, replac,
1559058561cbSjbeck &pvpbuf[sizeof(pvpbuf)] - replac,
1560058561cbSjbeck '\0', false);
15617c478bd9Sstevel@tonic-gate if (arg_rvp < &argvect[MAX_MAP_ARGS - 1])
15627c478bd9Sstevel@tonic-gate *++arg_rvp = replac;
15637c478bd9Sstevel@tonic-gate }
15647c478bd9Sstevel@tonic-gate if (arg_rvp >= &argvect[MAX_MAP_ARGS - 1])
15657c478bd9Sstevel@tonic-gate argvect[MAX_MAP_ARGS - 1] = NULL;
15667c478bd9Sstevel@tonic-gate else
15677c478bd9Sstevel@tonic-gate *++arg_rvp = NULL;
15687c478bd9Sstevel@tonic-gate
15697c478bd9Sstevel@tonic-gate /* save the remainder of the input string */
1570058561cbSjbeck trsize = (avp - rvp + 1) * sizeof(*rvp);
15717c478bd9Sstevel@tonic-gate memmove((char *) pvpb1, (char *) rvp, trsize);
15727c478bd9Sstevel@tonic-gate
15737c478bd9Sstevel@tonic-gate /* look it up */
1574058561cbSjbeck cataddr(key_rvp, NULL, cbuf, sizeof(cbuf),
1575058561cbSjbeck map == NULL ? '\0' : map->s_map.map_spacesub,
1576058561cbSjbeck true);
15777c478bd9Sstevel@tonic-gate argvect[0] = cbuf;
15787c478bd9Sstevel@tonic-gate replac = map_lookup(map, cbuf, argvect, &rstat, e);
1579*d4660949Sjbeck external = replac != NULL;
15807c478bd9Sstevel@tonic-gate
15817c478bd9Sstevel@tonic-gate /* if no replacement, use default */
15827c478bd9Sstevel@tonic-gate if (replac == NULL && default_rvp != NULL)
15837c478bd9Sstevel@tonic-gate {
15847c478bd9Sstevel@tonic-gate /* create the default */
1585058561cbSjbeck cataddr(default_rvp, NULL, cbuf, sizeof(cbuf),
1586058561cbSjbeck '\0', false);
15877c478bd9Sstevel@tonic-gate replac = cbuf;
15887c478bd9Sstevel@tonic-gate }
15897c478bd9Sstevel@tonic-gate
15907c478bd9Sstevel@tonic-gate if (replac == NULL)
15917c478bd9Sstevel@tonic-gate {
15927c478bd9Sstevel@tonic-gate xpvp = key_rvp;
15937c478bd9Sstevel@tonic-gate }
15947c478bd9Sstevel@tonic-gate else if (*replac == '\0')
15957c478bd9Sstevel@tonic-gate {
15967c478bd9Sstevel@tonic-gate /* null replacement */
15977c478bd9Sstevel@tonic-gate nullpvp[0] = NULL;
15987c478bd9Sstevel@tonic-gate xpvp = nullpvp;
15997c478bd9Sstevel@tonic-gate }
16007c478bd9Sstevel@tonic-gate else
16017c478bd9Sstevel@tonic-gate {
16027c478bd9Sstevel@tonic-gate /* scan the new replacement */
16037c478bd9Sstevel@tonic-gate xpvp = prescan(replac, '\0', pvpbuf,
1604*d4660949Sjbeck sizeof(pvpbuf), NULL,
1605*d4660949Sjbeck external ? NULL : IntTokenTab,
1606058561cbSjbeck false);
16077c478bd9Sstevel@tonic-gate if (xpvp == NULL)
16087c478bd9Sstevel@tonic-gate {
16097c478bd9Sstevel@tonic-gate /* prescan already printed error */
16107c478bd9Sstevel@tonic-gate return EX_DATAERR;
16117c478bd9Sstevel@tonic-gate }
16127c478bd9Sstevel@tonic-gate }
16137c478bd9Sstevel@tonic-gate
16147c478bd9Sstevel@tonic-gate /* append it to the token list */
16157c478bd9Sstevel@tonic-gate for (avp = hbrvp; *xpvp != NULL; xpvp++)
16167c478bd9Sstevel@tonic-gate {
16177c478bd9Sstevel@tonic-gate *avp++ = sm_rpool_strdup_x(e->e_rpool, *xpvp);
16187c478bd9Sstevel@tonic-gate if (avp >= &npvp[maxatom])
16197c478bd9Sstevel@tonic-gate goto toolong;
16207c478bd9Sstevel@tonic-gate }
16217c478bd9Sstevel@tonic-gate
16227c478bd9Sstevel@tonic-gate /* restore the old trailing information */
16237c478bd9Sstevel@tonic-gate rvp = avp - 1;
16247c478bd9Sstevel@tonic-gate for (xpvp = pvpb1; (*avp++ = *xpvp++) != NULL; )
16257c478bd9Sstevel@tonic-gate if (avp >= &npvp[maxatom])
16267c478bd9Sstevel@tonic-gate goto toolong;
16277c478bd9Sstevel@tonic-gate }
16287c478bd9Sstevel@tonic-gate
16297c478bd9Sstevel@tonic-gate /*
16307c478bd9Sstevel@tonic-gate ** Check for subroutine calls.
16317c478bd9Sstevel@tonic-gate */
16327c478bd9Sstevel@tonic-gate
16337c478bd9Sstevel@tonic-gate status = callsubr(npvp, reclevel, e);
16347c478bd9Sstevel@tonic-gate if (rstat == EX_OK || status == EX_TEMPFAIL)
16357c478bd9Sstevel@tonic-gate rstat = status;
16367c478bd9Sstevel@tonic-gate
16377c478bd9Sstevel@tonic-gate /* copy vector back into original space. */
16387c478bd9Sstevel@tonic-gate for (avp = npvp; *avp++ != NULL;)
16397c478bd9Sstevel@tonic-gate continue;
16407c478bd9Sstevel@tonic-gate memmove((char *) pvp, (char *) npvp,
1641058561cbSjbeck (int) (avp - npvp) * sizeof(*avp));
16427c478bd9Sstevel@tonic-gate
16437c478bd9Sstevel@tonic-gate if (tTd(21, 4))
16447c478bd9Sstevel@tonic-gate {
16457c478bd9Sstevel@tonic-gate sm_dprintf("rewritten as:");
16467c478bd9Sstevel@tonic-gate printav(sm_debug_file(), pvp);
16477c478bd9Sstevel@tonic-gate }
16487c478bd9Sstevel@tonic-gate }
16497c478bd9Sstevel@tonic-gate
16507c478bd9Sstevel@tonic-gate if (OpMode == MD_TEST)
16517c478bd9Sstevel@tonic-gate {
16527c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
16537c478bd9Sstevel@tonic-gate "%s%-16.16s returns:", prefix, rulename);
16547c478bd9Sstevel@tonic-gate printav(smioout, pvp);
16557c478bd9Sstevel@tonic-gate }
16567c478bd9Sstevel@tonic-gate else if (tTd(21, 1))
16577c478bd9Sstevel@tonic-gate {
16587c478bd9Sstevel@tonic-gate sm_dprintf("%s%-16.16s returns:", prefix, rulename);
16597c478bd9Sstevel@tonic-gate printav(sm_debug_file(), pvp);
16607c478bd9Sstevel@tonic-gate }
16617c478bd9Sstevel@tonic-gate return rstat;
16627c478bd9Sstevel@tonic-gate }
16637c478bd9Sstevel@tonic-gate /*
16647c478bd9Sstevel@tonic-gate ** CALLSUBR -- call subroutines in rewrite vector
16657c478bd9Sstevel@tonic-gate **
16667c478bd9Sstevel@tonic-gate ** Parameters:
16677c478bd9Sstevel@tonic-gate ** pvp -- pointer to token vector.
16687c478bd9Sstevel@tonic-gate ** reclevel -- the current recursion level.
16697c478bd9Sstevel@tonic-gate ** e -- the current envelope.
16707c478bd9Sstevel@tonic-gate **
16717c478bd9Sstevel@tonic-gate ** Returns:
16727c478bd9Sstevel@tonic-gate ** The status from the subroutine call.
16737c478bd9Sstevel@tonic-gate **
16747c478bd9Sstevel@tonic-gate ** Side Effects:
16757c478bd9Sstevel@tonic-gate ** pvp is modified.
16767c478bd9Sstevel@tonic-gate */
16777c478bd9Sstevel@tonic-gate
16787c478bd9Sstevel@tonic-gate static int
callsubr(pvp,reclevel,e)16797c478bd9Sstevel@tonic-gate callsubr(pvp, reclevel, e)
16807c478bd9Sstevel@tonic-gate char **pvp;
16817c478bd9Sstevel@tonic-gate int reclevel;
16827c478bd9Sstevel@tonic-gate ENVELOPE *e;
16837c478bd9Sstevel@tonic-gate {
16847c478bd9Sstevel@tonic-gate char **avp;
16857c478bd9Sstevel@tonic-gate register int i;
16867c478bd9Sstevel@tonic-gate int subr, j;
16877c478bd9Sstevel@tonic-gate int nsubr;
16887c478bd9Sstevel@tonic-gate int status;
16897c478bd9Sstevel@tonic-gate int rstat = EX_OK;
16907c478bd9Sstevel@tonic-gate #define MAX_SUBR 16
16917c478bd9Sstevel@tonic-gate int subrnumber[MAX_SUBR];
16927c478bd9Sstevel@tonic-gate int subrindex[MAX_SUBR];
16937c478bd9Sstevel@tonic-gate
16947c478bd9Sstevel@tonic-gate nsubr = 0;
16957c478bd9Sstevel@tonic-gate
16967c478bd9Sstevel@tonic-gate /*
16977c478bd9Sstevel@tonic-gate ** Look for subroutine calls in pvp, collect them into subr*[]
16987c478bd9Sstevel@tonic-gate ** We will perform the calls in the next loop, because we will
16997c478bd9Sstevel@tonic-gate ** call the "last" subroutine first to avoid recursive calls
17007c478bd9Sstevel@tonic-gate ** and too much copying.
17017c478bd9Sstevel@tonic-gate */
17027c478bd9Sstevel@tonic-gate
17037c478bd9Sstevel@tonic-gate for (avp = pvp, j = 0; *avp != NULL; avp++, j++)
17047c478bd9Sstevel@tonic-gate {
1705058561cbSjbeck if ((avp[0][0] & 0377) == CALLSUBR && avp[1] != NULL)
17067c478bd9Sstevel@tonic-gate {
17077c478bd9Sstevel@tonic-gate stripquotes(avp[1]);
17087c478bd9Sstevel@tonic-gate subr = strtorwset(avp[1], NULL, ST_FIND);
17097c478bd9Sstevel@tonic-gate if (subr < 0)
17107c478bd9Sstevel@tonic-gate {
17117c478bd9Sstevel@tonic-gate syserr("554 5.3.5 Unknown ruleset %s", avp[1]);
17127c478bd9Sstevel@tonic-gate return EX_CONFIG;
17137c478bd9Sstevel@tonic-gate }
17147c478bd9Sstevel@tonic-gate
17157c478bd9Sstevel@tonic-gate /*
17167c478bd9Sstevel@tonic-gate ** XXX instead of doing this we could optimize
17177c478bd9Sstevel@tonic-gate ** the rules after reading them: just remove
17187c478bd9Sstevel@tonic-gate ** calls to empty rulesets
17197c478bd9Sstevel@tonic-gate */
17207c478bd9Sstevel@tonic-gate
17217c478bd9Sstevel@tonic-gate /* subroutine is an empty ruleset? don't call it */
17227c478bd9Sstevel@tonic-gate if (RewriteRules[subr] == NULL)
17237c478bd9Sstevel@tonic-gate {
17247c478bd9Sstevel@tonic-gate if (tTd(21, 3))
17257c478bd9Sstevel@tonic-gate sm_dprintf("-----skip subr %s (%d)\n",
17267c478bd9Sstevel@tonic-gate avp[1], subr);
17277c478bd9Sstevel@tonic-gate for (i = 2; avp[i] != NULL; i++)
17287c478bd9Sstevel@tonic-gate avp[i - 2] = avp[i];
17297c478bd9Sstevel@tonic-gate avp[i - 2] = NULL;
17307c478bd9Sstevel@tonic-gate continue;
17317c478bd9Sstevel@tonic-gate }
17327c478bd9Sstevel@tonic-gate if (++nsubr >= MAX_SUBR)
17337c478bd9Sstevel@tonic-gate {
17347c478bd9Sstevel@tonic-gate syserr("554 5.3.0 Too many subroutine calls (%d max)",
17357c478bd9Sstevel@tonic-gate MAX_SUBR);
17367c478bd9Sstevel@tonic-gate return EX_CONFIG;
17377c478bd9Sstevel@tonic-gate }
17387c478bd9Sstevel@tonic-gate subrnumber[nsubr] = subr;
17397c478bd9Sstevel@tonic-gate subrindex[nsubr] = j;
17407c478bd9Sstevel@tonic-gate }
17417c478bd9Sstevel@tonic-gate }
17427c478bd9Sstevel@tonic-gate
17437c478bd9Sstevel@tonic-gate /*
17447c478bd9Sstevel@tonic-gate ** Perform the actual subroutines calls, "last" one first, i.e.,
17457c478bd9Sstevel@tonic-gate ** go from the right to the left through all calls,
17467c478bd9Sstevel@tonic-gate ** do the rewriting in place.
17477c478bd9Sstevel@tonic-gate */
17487c478bd9Sstevel@tonic-gate
17497c478bd9Sstevel@tonic-gate for (; nsubr > 0; nsubr--)
17507c478bd9Sstevel@tonic-gate {
17517c478bd9Sstevel@tonic-gate subr = subrnumber[nsubr];
17527c478bd9Sstevel@tonic-gate avp = pvp + subrindex[nsubr];
17537c478bd9Sstevel@tonic-gate
17547c478bd9Sstevel@tonic-gate /* remove the subroutine call and name */
17557c478bd9Sstevel@tonic-gate for (i = 2; avp[i] != NULL; i++)
17567c478bd9Sstevel@tonic-gate avp[i - 2] = avp[i];
17577c478bd9Sstevel@tonic-gate avp[i - 2] = NULL;
17587c478bd9Sstevel@tonic-gate
17597c478bd9Sstevel@tonic-gate /*
17607c478bd9Sstevel@tonic-gate ** Now we need to call the ruleset specified for
17617c478bd9Sstevel@tonic-gate ** the subroutine. We can do this in place since
17627c478bd9Sstevel@tonic-gate ** we call the "last" subroutine first.
17637c478bd9Sstevel@tonic-gate */
17647c478bd9Sstevel@tonic-gate
17657c478bd9Sstevel@tonic-gate status = rewrite(avp, subr, reclevel, e,
17667c478bd9Sstevel@tonic-gate MAXATOM - subrindex[nsubr]);
17677c478bd9Sstevel@tonic-gate if (status != EX_OK && status != EX_TEMPFAIL)
17687c478bd9Sstevel@tonic-gate return status;
17697c478bd9Sstevel@tonic-gate if (rstat == EX_OK || status == EX_TEMPFAIL)
17707c478bd9Sstevel@tonic-gate rstat = status;
17717c478bd9Sstevel@tonic-gate }
17727c478bd9Sstevel@tonic-gate return rstat;
17737c478bd9Sstevel@tonic-gate }
17747c478bd9Sstevel@tonic-gate /*
17757c478bd9Sstevel@tonic-gate ** MAP_LOOKUP -- do lookup in map
17767c478bd9Sstevel@tonic-gate **
17777c478bd9Sstevel@tonic-gate ** Parameters:
17787c478bd9Sstevel@tonic-gate ** smap -- the map to use for the lookup.
17797c478bd9Sstevel@tonic-gate ** key -- the key to look up.
17807c478bd9Sstevel@tonic-gate ** argvect -- arguments to pass to the map lookup.
17817c478bd9Sstevel@tonic-gate ** pstat -- a pointer to an integer in which to store the
17827c478bd9Sstevel@tonic-gate ** status from the lookup.
17837c478bd9Sstevel@tonic-gate ** e -- the current envelope.
17847c478bd9Sstevel@tonic-gate **
17857c478bd9Sstevel@tonic-gate ** Returns:
17867c478bd9Sstevel@tonic-gate ** The result of the lookup.
17877c478bd9Sstevel@tonic-gate ** NULL -- if there was no data for the given key.
17887c478bd9Sstevel@tonic-gate */
17897c478bd9Sstevel@tonic-gate
17907c478bd9Sstevel@tonic-gate static char *
map_lookup(smap,key,argvect,pstat,e)17917c478bd9Sstevel@tonic-gate map_lookup(smap, key, argvect, pstat, e)
17927c478bd9Sstevel@tonic-gate STAB *smap;
17937c478bd9Sstevel@tonic-gate char key[];
17947c478bd9Sstevel@tonic-gate char **argvect;
17957c478bd9Sstevel@tonic-gate int *pstat;
17967c478bd9Sstevel@tonic-gate ENVELOPE *e;
17977c478bd9Sstevel@tonic-gate {
17987c478bd9Sstevel@tonic-gate auto int status = EX_OK;
17997c478bd9Sstevel@tonic-gate MAP *map;
18007c478bd9Sstevel@tonic-gate char *replac;
18017c478bd9Sstevel@tonic-gate
18027c478bd9Sstevel@tonic-gate if (smap == NULL)
18037c478bd9Sstevel@tonic-gate return NULL;
18047c478bd9Sstevel@tonic-gate
18057c478bd9Sstevel@tonic-gate map = &smap->s_map;
18067c478bd9Sstevel@tonic-gate DYNOPENMAP(map);
18077c478bd9Sstevel@tonic-gate
18087c478bd9Sstevel@tonic-gate if (e->e_sendmode == SM_DEFER &&
18097c478bd9Sstevel@tonic-gate bitset(MF_DEFER, map->map_mflags))
18107c478bd9Sstevel@tonic-gate {
18117c478bd9Sstevel@tonic-gate /* don't do any map lookups */
18127c478bd9Sstevel@tonic-gate if (tTd(60, 1))
18137c478bd9Sstevel@tonic-gate sm_dprintf("map_lookup(%s, %s) => DEFERRED\n",
18147c478bd9Sstevel@tonic-gate smap->s_name, key);
18157c478bd9Sstevel@tonic-gate *pstat = EX_TEMPFAIL;
18167c478bd9Sstevel@tonic-gate return NULL;
18177c478bd9Sstevel@tonic-gate }
18187c478bd9Sstevel@tonic-gate
18197c478bd9Sstevel@tonic-gate if (!bitset(MF_KEEPQUOTES, map->map_mflags))
18207c478bd9Sstevel@tonic-gate stripquotes(key);
18217c478bd9Sstevel@tonic-gate
18227c478bd9Sstevel@tonic-gate if (tTd(60, 1))
18237c478bd9Sstevel@tonic-gate {
1824058561cbSjbeck sm_dprintf("map_lookup(%s, ", smap->s_name);
1825058561cbSjbeck xputs(sm_debug_file(), key);
18267c478bd9Sstevel@tonic-gate if (tTd(60, 5))
18277c478bd9Sstevel@tonic-gate {
18287c478bd9Sstevel@tonic-gate int i;
18297c478bd9Sstevel@tonic-gate
18307c478bd9Sstevel@tonic-gate for (i = 0; argvect[i] != NULL; i++)
18317c478bd9Sstevel@tonic-gate sm_dprintf(", %%%d=%s", i, argvect[i]);
18327c478bd9Sstevel@tonic-gate }
18337c478bd9Sstevel@tonic-gate sm_dprintf(") => ");
18347c478bd9Sstevel@tonic-gate }
18357c478bd9Sstevel@tonic-gate replac = (*map->map_class->map_lookup)(map, key, argvect, &status);
18367c478bd9Sstevel@tonic-gate if (tTd(60, 1))
18377c478bd9Sstevel@tonic-gate sm_dprintf("%s (%d)\n",
18387c478bd9Sstevel@tonic-gate replac != NULL ? replac : "NOT FOUND",
18397c478bd9Sstevel@tonic-gate status);
18407c478bd9Sstevel@tonic-gate
18417c478bd9Sstevel@tonic-gate /* should recover if status == EX_TEMPFAIL */
18427c478bd9Sstevel@tonic-gate if (status == EX_TEMPFAIL && !bitset(MF_NODEFER, map->map_mflags))
18437c478bd9Sstevel@tonic-gate {
18447c478bd9Sstevel@tonic-gate *pstat = EX_TEMPFAIL;
18457c478bd9Sstevel@tonic-gate if (tTd(60, 1))
18467c478bd9Sstevel@tonic-gate sm_dprintf("map_lookup(%s, %s) tempfail: errno=%d\n",
18477c478bd9Sstevel@tonic-gate smap->s_name, key, errno);
18487c478bd9Sstevel@tonic-gate if (e->e_message == NULL)
18497c478bd9Sstevel@tonic-gate {
18507c478bd9Sstevel@tonic-gate char mbuf[320];
18517c478bd9Sstevel@tonic-gate
1852058561cbSjbeck (void) sm_snprintf(mbuf, sizeof(mbuf),
18537c478bd9Sstevel@tonic-gate "%.80s map: lookup (%s): deferred",
18547c478bd9Sstevel@tonic-gate smap->s_name,
18557c478bd9Sstevel@tonic-gate shortenstring(key, MAXSHORTSTR));
18567c478bd9Sstevel@tonic-gate e->e_message = sm_rpool_strdup_x(e->e_rpool, mbuf);
18577c478bd9Sstevel@tonic-gate }
18587c478bd9Sstevel@tonic-gate }
18597c478bd9Sstevel@tonic-gate if (status == EX_TEMPFAIL && map->map_tapp != NULL)
18607c478bd9Sstevel@tonic-gate {
18617c478bd9Sstevel@tonic-gate size_t i = strlen(key) + strlen(map->map_tapp) + 1;
18627c478bd9Sstevel@tonic-gate static char *rwbuf = NULL;
18637c478bd9Sstevel@tonic-gate static size_t rwbuflen = 0;
18647c478bd9Sstevel@tonic-gate
18657c478bd9Sstevel@tonic-gate if (i > rwbuflen)
18667c478bd9Sstevel@tonic-gate {
18677c478bd9Sstevel@tonic-gate if (rwbuf != NULL)
18687c478bd9Sstevel@tonic-gate sm_free(rwbuf);
18697c478bd9Sstevel@tonic-gate rwbuflen = i;
18707c478bd9Sstevel@tonic-gate rwbuf = (char *) sm_pmalloc_x(rwbuflen);
18717c478bd9Sstevel@tonic-gate }
18727c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(rwbuf, rwbuflen, 2, key, map->map_tapp);
18737c478bd9Sstevel@tonic-gate if (tTd(60, 4))
18747c478bd9Sstevel@tonic-gate sm_dprintf("map_lookup tempfail: returning \"%s\"\n",
18757c478bd9Sstevel@tonic-gate rwbuf);
18767c478bd9Sstevel@tonic-gate return rwbuf;
18777c478bd9Sstevel@tonic-gate }
18787c478bd9Sstevel@tonic-gate return replac;
18797c478bd9Sstevel@tonic-gate }
18807c478bd9Sstevel@tonic-gate /*
18817c478bd9Sstevel@tonic-gate ** INITERRMAILERS -- initialize error and discard mailers
18827c478bd9Sstevel@tonic-gate **
18837c478bd9Sstevel@tonic-gate ** Parameters:
18847c478bd9Sstevel@tonic-gate ** none.
18857c478bd9Sstevel@tonic-gate **
18867c478bd9Sstevel@tonic-gate ** Returns:
18877c478bd9Sstevel@tonic-gate ** none.
18887c478bd9Sstevel@tonic-gate **
18897c478bd9Sstevel@tonic-gate ** Side Effects:
18907c478bd9Sstevel@tonic-gate ** initializes error and discard mailers.
18917c478bd9Sstevel@tonic-gate */
18927c478bd9Sstevel@tonic-gate
18937c478bd9Sstevel@tonic-gate static MAILER discardmailer;
18947c478bd9Sstevel@tonic-gate static MAILER errormailer;
18957c478bd9Sstevel@tonic-gate static char *discardargv[] = { "DISCARD", NULL };
18967c478bd9Sstevel@tonic-gate static char *errorargv[] = { "ERROR", NULL };
18977c478bd9Sstevel@tonic-gate
18987c478bd9Sstevel@tonic-gate void
initerrmailers()18997c478bd9Sstevel@tonic-gate initerrmailers()
19007c478bd9Sstevel@tonic-gate {
19017c478bd9Sstevel@tonic-gate if (discardmailer.m_name == NULL)
19027c478bd9Sstevel@tonic-gate {
19037c478bd9Sstevel@tonic-gate /* initialize the discard mailer */
19047c478bd9Sstevel@tonic-gate discardmailer.m_name = "*discard*";
19057c478bd9Sstevel@tonic-gate discardmailer.m_mailer = "DISCARD";
19067c478bd9Sstevel@tonic-gate discardmailer.m_argv = discardargv;
19077c478bd9Sstevel@tonic-gate }
19087c478bd9Sstevel@tonic-gate if (errormailer.m_name == NULL)
19097c478bd9Sstevel@tonic-gate {
19107c478bd9Sstevel@tonic-gate /* initialize the bogus mailer */
19117c478bd9Sstevel@tonic-gate errormailer.m_name = "*error*";
19127c478bd9Sstevel@tonic-gate errormailer.m_mailer = "ERROR";
19137c478bd9Sstevel@tonic-gate errormailer.m_argv = errorargv;
19147c478bd9Sstevel@tonic-gate }
19157c478bd9Sstevel@tonic-gate }
19167c478bd9Sstevel@tonic-gate /*
19177c478bd9Sstevel@tonic-gate ** BUILDADDR -- build address from token vector.
19187c478bd9Sstevel@tonic-gate **
19197c478bd9Sstevel@tonic-gate ** Parameters:
19207c478bd9Sstevel@tonic-gate ** tv -- token vector.
19217c478bd9Sstevel@tonic-gate ** a -- pointer to address descriptor to fill.
19227c478bd9Sstevel@tonic-gate ** If NULL, one will be allocated.
19237c478bd9Sstevel@tonic-gate ** flags -- info regarding whether this is a sender or
19247c478bd9Sstevel@tonic-gate ** a recipient.
19257c478bd9Sstevel@tonic-gate ** e -- the current envelope.
19267c478bd9Sstevel@tonic-gate **
19277c478bd9Sstevel@tonic-gate ** Returns:
19287c478bd9Sstevel@tonic-gate ** NULL if there was an error.
19297c478bd9Sstevel@tonic-gate ** 'a' otherwise.
19307c478bd9Sstevel@tonic-gate **
19317c478bd9Sstevel@tonic-gate ** Side Effects:
19327c478bd9Sstevel@tonic-gate ** fills in 'a'
19337c478bd9Sstevel@tonic-gate */
19347c478bd9Sstevel@tonic-gate
19357c478bd9Sstevel@tonic-gate static struct errcodes
19367c478bd9Sstevel@tonic-gate {
19377c478bd9Sstevel@tonic-gate char *ec_name; /* name of error code */
19387c478bd9Sstevel@tonic-gate int ec_code; /* numeric code */
19397c478bd9Sstevel@tonic-gate } ErrorCodes[] =
19407c478bd9Sstevel@tonic-gate {
19417c478bd9Sstevel@tonic-gate { "usage", EX_USAGE },
19427c478bd9Sstevel@tonic-gate { "nouser", EX_NOUSER },
19437c478bd9Sstevel@tonic-gate { "nohost", EX_NOHOST },
19447c478bd9Sstevel@tonic-gate { "unavailable", EX_UNAVAILABLE },
19457c478bd9Sstevel@tonic-gate { "software", EX_SOFTWARE },
19467c478bd9Sstevel@tonic-gate { "tempfail", EX_TEMPFAIL },
19477c478bd9Sstevel@tonic-gate { "protocol", EX_PROTOCOL },
19487c478bd9Sstevel@tonic-gate { "config", EX_CONFIG },
19497c478bd9Sstevel@tonic-gate { NULL, EX_UNAVAILABLE }
19507c478bd9Sstevel@tonic-gate };
19517c478bd9Sstevel@tonic-gate
19527c478bd9Sstevel@tonic-gate static ADDRESS *
buildaddr(tv,a,flags,e)19537c478bd9Sstevel@tonic-gate buildaddr(tv, a, flags, e)
19547c478bd9Sstevel@tonic-gate register char **tv;
19557c478bd9Sstevel@tonic-gate register ADDRESS *a;
19567c478bd9Sstevel@tonic-gate int flags;
19577c478bd9Sstevel@tonic-gate register ENVELOPE *e;
19587c478bd9Sstevel@tonic-gate {
19597c478bd9Sstevel@tonic-gate bool tempfail = false;
19607c478bd9Sstevel@tonic-gate int maxatom;
19617c478bd9Sstevel@tonic-gate struct mailer **mp;
19627c478bd9Sstevel@tonic-gate register struct mailer *m;
19637c478bd9Sstevel@tonic-gate register char *p;
19647c478bd9Sstevel@tonic-gate char *mname;
19657c478bd9Sstevel@tonic-gate char **hostp;
19667c478bd9Sstevel@tonic-gate char hbuf[MAXNAME + 1];
19677c478bd9Sstevel@tonic-gate static char ubuf[MAXNAME + 2];
19687c478bd9Sstevel@tonic-gate
19697c478bd9Sstevel@tonic-gate if (tTd(24, 5))
19707c478bd9Sstevel@tonic-gate {
19717c478bd9Sstevel@tonic-gate sm_dprintf("buildaddr, flags=%x, tv=", flags);
19727c478bd9Sstevel@tonic-gate printav(sm_debug_file(), tv);
19737c478bd9Sstevel@tonic-gate }
19747c478bd9Sstevel@tonic-gate
19757c478bd9Sstevel@tonic-gate maxatom = MAXATOM;
19767c478bd9Sstevel@tonic-gate if (a == NULL)
1977058561cbSjbeck a = (ADDRESS *) sm_rpool_malloc_x(e->e_rpool, sizeof(*a));
1978058561cbSjbeck memset((char *) a, '\0', sizeof(*a));
19797c478bd9Sstevel@tonic-gate hbuf[0] = '\0';
19807c478bd9Sstevel@tonic-gate
19817c478bd9Sstevel@tonic-gate /* set up default error return flags */
19827c478bd9Sstevel@tonic-gate a->q_flags |= DefaultNotify;
19837c478bd9Sstevel@tonic-gate
19847c478bd9Sstevel@tonic-gate /* figure out what net/mailer to use */
19857c478bd9Sstevel@tonic-gate if (*tv == NULL || (**tv & 0377) != CANONNET)
19867c478bd9Sstevel@tonic-gate {
19877c478bd9Sstevel@tonic-gate syserr("554 5.3.5 buildaddr: no mailer in parsed address");
19887c478bd9Sstevel@tonic-gate badaddr:
19897c478bd9Sstevel@tonic-gate /*
19907c478bd9Sstevel@tonic-gate ** ExitStat may have been set by an earlier map open
19917c478bd9Sstevel@tonic-gate ** failure (to a permanent error (EX_OSERR) in syserr())
19927c478bd9Sstevel@tonic-gate ** so we also need to check if this particular $#error
19937c478bd9Sstevel@tonic-gate ** return wanted a 4XX failure.
19947c478bd9Sstevel@tonic-gate **
19957c478bd9Sstevel@tonic-gate ** XXX the real fix is probably to set ExitStat correctly,
19967c478bd9Sstevel@tonic-gate ** i.e., to EX_TEMPFAIL if the map open is just a temporary
19977c478bd9Sstevel@tonic-gate ** error.
19987c478bd9Sstevel@tonic-gate */
19997c478bd9Sstevel@tonic-gate
20007c478bd9Sstevel@tonic-gate if (ExitStat == EX_TEMPFAIL || tempfail)
20017c478bd9Sstevel@tonic-gate a->q_state = QS_QUEUEUP;
20027c478bd9Sstevel@tonic-gate else
20037c478bd9Sstevel@tonic-gate {
20047c478bd9Sstevel@tonic-gate a->q_state = QS_BADADDR;
20057c478bd9Sstevel@tonic-gate a->q_mailer = &errormailer;
20067c478bd9Sstevel@tonic-gate }
20077c478bd9Sstevel@tonic-gate return a;
20087c478bd9Sstevel@tonic-gate }
20097c478bd9Sstevel@tonic-gate mname = *++tv;
20107c478bd9Sstevel@tonic-gate --maxatom;
20117c478bd9Sstevel@tonic-gate
20127c478bd9Sstevel@tonic-gate /* extract host and user portions */
20137c478bd9Sstevel@tonic-gate if (*++tv != NULL && (**tv & 0377) == CANONHOST)
20147c478bd9Sstevel@tonic-gate {
20157c478bd9Sstevel@tonic-gate hostp = ++tv;
20167c478bd9Sstevel@tonic-gate --maxatom;
20177c478bd9Sstevel@tonic-gate }
20187c478bd9Sstevel@tonic-gate else
20197c478bd9Sstevel@tonic-gate hostp = NULL;
20207c478bd9Sstevel@tonic-gate --maxatom;
20217c478bd9Sstevel@tonic-gate while (*tv != NULL && (**tv & 0377) != CANONUSER)
20227c478bd9Sstevel@tonic-gate {
20237c478bd9Sstevel@tonic-gate tv++;
20247c478bd9Sstevel@tonic-gate --maxatom;
20257c478bd9Sstevel@tonic-gate }
20267c478bd9Sstevel@tonic-gate if (*tv == NULL)
20277c478bd9Sstevel@tonic-gate {
20287c478bd9Sstevel@tonic-gate syserr("554 5.3.5 buildaddr: no user");
20297c478bd9Sstevel@tonic-gate goto badaddr;
20307c478bd9Sstevel@tonic-gate }
20317c478bd9Sstevel@tonic-gate if (tv == hostp)
20327c478bd9Sstevel@tonic-gate hostp = NULL;
20337c478bd9Sstevel@tonic-gate else if (hostp != NULL)
2034058561cbSjbeck cataddr(hostp, tv - 1, hbuf, sizeof(hbuf), '\0', false);
2035058561cbSjbeck cataddr(++tv, NULL, ubuf, sizeof(ubuf), ' ', false);
20367c478bd9Sstevel@tonic-gate --maxatom;
20377c478bd9Sstevel@tonic-gate
20387c478bd9Sstevel@tonic-gate /* save away the host name */
20397c478bd9Sstevel@tonic-gate if (sm_strcasecmp(mname, "error") == 0)
20407c478bd9Sstevel@tonic-gate {
20417c478bd9Sstevel@tonic-gate /* Set up triplet for use by -bv */
20427c478bd9Sstevel@tonic-gate a->q_mailer = &errormailer;
20437c478bd9Sstevel@tonic-gate a->q_user = sm_rpool_strdup_x(e->e_rpool, ubuf);
20447c478bd9Sstevel@tonic-gate /* XXX wrong place? */
20457c478bd9Sstevel@tonic-gate
20467c478bd9Sstevel@tonic-gate if (hostp != NULL)
20477c478bd9Sstevel@tonic-gate {
20487c478bd9Sstevel@tonic-gate register struct errcodes *ep;
20497c478bd9Sstevel@tonic-gate
20507c478bd9Sstevel@tonic-gate a->q_host = sm_rpool_strdup_x(e->e_rpool, hbuf);
20517c478bd9Sstevel@tonic-gate if (strchr(hbuf, '.') != NULL)
20527c478bd9Sstevel@tonic-gate {
20537c478bd9Sstevel@tonic-gate a->q_status = sm_rpool_strdup_x(e->e_rpool,
20547c478bd9Sstevel@tonic-gate hbuf);
20557c478bd9Sstevel@tonic-gate setstat(dsntoexitstat(hbuf));
20567c478bd9Sstevel@tonic-gate }
20577c478bd9Sstevel@tonic-gate else if (isascii(hbuf[0]) && isdigit(hbuf[0]))
20587c478bd9Sstevel@tonic-gate {
20597c478bd9Sstevel@tonic-gate setstat(atoi(hbuf));
20607c478bd9Sstevel@tonic-gate }
20617c478bd9Sstevel@tonic-gate else
20627c478bd9Sstevel@tonic-gate {
20637c478bd9Sstevel@tonic-gate for (ep = ErrorCodes; ep->ec_name != NULL; ep++)
20647c478bd9Sstevel@tonic-gate if (sm_strcasecmp(ep->ec_name, hbuf) == 0)
20657c478bd9Sstevel@tonic-gate break;
20667c478bd9Sstevel@tonic-gate setstat(ep->ec_code);
20677c478bd9Sstevel@tonic-gate }
20687c478bd9Sstevel@tonic-gate }
20697c478bd9Sstevel@tonic-gate else
20707c478bd9Sstevel@tonic-gate {
20717c478bd9Sstevel@tonic-gate a->q_host = NULL;
20727c478bd9Sstevel@tonic-gate setstat(EX_UNAVAILABLE);
20737c478bd9Sstevel@tonic-gate }
20747c478bd9Sstevel@tonic-gate stripquotes(ubuf);
20757c478bd9Sstevel@tonic-gate if (ISSMTPCODE(ubuf) && ubuf[3] == ' ')
20767c478bd9Sstevel@tonic-gate {
20777c478bd9Sstevel@tonic-gate char fmt[16];
20787c478bd9Sstevel@tonic-gate int off;
20797c478bd9Sstevel@tonic-gate
20807c478bd9Sstevel@tonic-gate if ((off = isenhsc(ubuf + 4, ' ')) > 0)
20817c478bd9Sstevel@tonic-gate {
20827c478bd9Sstevel@tonic-gate ubuf[off + 4] = '\0';
20837c478bd9Sstevel@tonic-gate off += 5;
20847c478bd9Sstevel@tonic-gate }
20857c478bd9Sstevel@tonic-gate else
20867c478bd9Sstevel@tonic-gate {
20877c478bd9Sstevel@tonic-gate off = 4;
20887c478bd9Sstevel@tonic-gate ubuf[3] = '\0';
20897c478bd9Sstevel@tonic-gate }
2090058561cbSjbeck (void) sm_strlcpyn(fmt, sizeof(fmt), 2, ubuf, " %s");
20917c478bd9Sstevel@tonic-gate if (off > 4)
20927c478bd9Sstevel@tonic-gate usrerr(fmt, ubuf + off);
20937c478bd9Sstevel@tonic-gate else if (isenhsc(hbuf, '\0') > 0)
20947c478bd9Sstevel@tonic-gate usrerrenh(hbuf, fmt, ubuf + off);
20957c478bd9Sstevel@tonic-gate else
20967c478bd9Sstevel@tonic-gate usrerr(fmt, ubuf + off);
20977c478bd9Sstevel@tonic-gate /* XXX ubuf[off - 1] = ' '; */
20987c478bd9Sstevel@tonic-gate if (ubuf[0] == '4')
20997c478bd9Sstevel@tonic-gate tempfail = true;
21007c478bd9Sstevel@tonic-gate }
21017c478bd9Sstevel@tonic-gate else
21027c478bd9Sstevel@tonic-gate {
21037c478bd9Sstevel@tonic-gate usrerr("553 5.3.0 %s", ubuf);
21047c478bd9Sstevel@tonic-gate }
21057c478bd9Sstevel@tonic-gate goto badaddr;
21067c478bd9Sstevel@tonic-gate }
21077c478bd9Sstevel@tonic-gate
21087c478bd9Sstevel@tonic-gate for (mp = Mailer; (m = *mp++) != NULL; )
21097c478bd9Sstevel@tonic-gate {
21107c478bd9Sstevel@tonic-gate if (sm_strcasecmp(m->m_name, mname) == 0)
21117c478bd9Sstevel@tonic-gate break;
21127c478bd9Sstevel@tonic-gate }
21137c478bd9Sstevel@tonic-gate if (m == NULL)
21147c478bd9Sstevel@tonic-gate {
21157c478bd9Sstevel@tonic-gate syserr("554 5.3.5 buildaddr: unknown mailer %s", mname);
21167c478bd9Sstevel@tonic-gate goto badaddr;
21177c478bd9Sstevel@tonic-gate }
21187c478bd9Sstevel@tonic-gate a->q_mailer = m;
21197c478bd9Sstevel@tonic-gate
21207c478bd9Sstevel@tonic-gate /* figure out what host (if any) */
21217c478bd9Sstevel@tonic-gate if (hostp == NULL)
21227c478bd9Sstevel@tonic-gate {
21237c478bd9Sstevel@tonic-gate if (!bitnset(M_LOCALMAILER, m->m_flags))
21247c478bd9Sstevel@tonic-gate {
21257c478bd9Sstevel@tonic-gate syserr("554 5.3.5 buildaddr: no host");
21267c478bd9Sstevel@tonic-gate goto badaddr;
21277c478bd9Sstevel@tonic-gate }
21287c478bd9Sstevel@tonic-gate a->q_host = NULL;
21297c478bd9Sstevel@tonic-gate }
21307c478bd9Sstevel@tonic-gate else
21317c478bd9Sstevel@tonic-gate a->q_host = sm_rpool_strdup_x(e->e_rpool, hbuf);
21327c478bd9Sstevel@tonic-gate
21337c478bd9Sstevel@tonic-gate /* figure out the user */
21347c478bd9Sstevel@tonic-gate p = ubuf;
21357c478bd9Sstevel@tonic-gate if (bitnset(M_CHECKUDB, m->m_flags) && *p == '@')
21367c478bd9Sstevel@tonic-gate {
21377c478bd9Sstevel@tonic-gate p++;
21387c478bd9Sstevel@tonic-gate tv++;
21397c478bd9Sstevel@tonic-gate --maxatom;
21407c478bd9Sstevel@tonic-gate a->q_flags |= QNOTREMOTE;
21417c478bd9Sstevel@tonic-gate }
21427c478bd9Sstevel@tonic-gate
21437c478bd9Sstevel@tonic-gate /* do special mapping for local mailer */
21447c478bd9Sstevel@tonic-gate if (*p == '"')
21457c478bd9Sstevel@tonic-gate p++;
21467c478bd9Sstevel@tonic-gate if (*p == '|' && bitnset(M_CHECKPROG, m->m_flags))
21477c478bd9Sstevel@tonic-gate a->q_mailer = m = ProgMailer;
21487c478bd9Sstevel@tonic-gate else if (*p == '/' && bitnset(M_CHECKFILE, m->m_flags))
21497c478bd9Sstevel@tonic-gate a->q_mailer = m = FileMailer;
21507c478bd9Sstevel@tonic-gate else if (*p == ':' && bitnset(M_CHECKINCLUDE, m->m_flags))
21517c478bd9Sstevel@tonic-gate {
21527c478bd9Sstevel@tonic-gate /* may be :include: */
21537c478bd9Sstevel@tonic-gate stripquotes(ubuf);
21547c478bd9Sstevel@tonic-gate if (sm_strncasecmp(ubuf, ":include:", 9) == 0)
21557c478bd9Sstevel@tonic-gate {
21567c478bd9Sstevel@tonic-gate /* if :include:, don't need further rewriting */
21577c478bd9Sstevel@tonic-gate a->q_mailer = m = InclMailer;
21587c478bd9Sstevel@tonic-gate a->q_user = sm_rpool_strdup_x(e->e_rpool, &ubuf[9]);
21597c478bd9Sstevel@tonic-gate return a;
21607c478bd9Sstevel@tonic-gate }
21617c478bd9Sstevel@tonic-gate }
21627c478bd9Sstevel@tonic-gate
21637c478bd9Sstevel@tonic-gate /* rewrite according recipient mailer rewriting rules */
21647c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'h', a->q_host);
21657c478bd9Sstevel@tonic-gate
21667c478bd9Sstevel@tonic-gate if (ConfigLevel >= 10 ||
21677c478bd9Sstevel@tonic-gate !bitset(RF_SENDERADDR|RF_HEADERADDR, flags))
21687c478bd9Sstevel@tonic-gate {
21697c478bd9Sstevel@tonic-gate /* sender addresses done later */
21707c478bd9Sstevel@tonic-gate (void) rewrite(tv, 2, 0, e, maxatom);
21717c478bd9Sstevel@tonic-gate if (m->m_re_rwset > 0)
21727c478bd9Sstevel@tonic-gate (void) rewrite(tv, m->m_re_rwset, 0, e, maxatom);
21737c478bd9Sstevel@tonic-gate }
21747c478bd9Sstevel@tonic-gate (void) rewrite(tv, 4, 0, e, maxatom);
21757c478bd9Sstevel@tonic-gate
21767c478bd9Sstevel@tonic-gate /* save the result for the command line/RCPT argument */
2177058561cbSjbeck cataddr(tv, NULL, ubuf, sizeof(ubuf), '\0', true);
21787c478bd9Sstevel@tonic-gate a->q_user = sm_rpool_strdup_x(e->e_rpool, ubuf);
21797c478bd9Sstevel@tonic-gate
21807c478bd9Sstevel@tonic-gate /*
21817c478bd9Sstevel@tonic-gate ** Do mapping to lower case as requested by mailer
21827c478bd9Sstevel@tonic-gate */
21837c478bd9Sstevel@tonic-gate
21847c478bd9Sstevel@tonic-gate if (a->q_host != NULL && !bitnset(M_HST_UPPER, m->m_flags))
21857c478bd9Sstevel@tonic-gate makelower(a->q_host);
21867c478bd9Sstevel@tonic-gate if (!bitnset(M_USR_UPPER, m->m_flags))
21877c478bd9Sstevel@tonic-gate makelower(a->q_user);
21887c478bd9Sstevel@tonic-gate
21897c478bd9Sstevel@tonic-gate if (tTd(24, 6))
21907c478bd9Sstevel@tonic-gate {
21917c478bd9Sstevel@tonic-gate sm_dprintf("buildaddr => ");
21927c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), a, false);
21937c478bd9Sstevel@tonic-gate }
21947c478bd9Sstevel@tonic-gate return a;
21957c478bd9Sstevel@tonic-gate }
21967c478bd9Sstevel@tonic-gate
21977c478bd9Sstevel@tonic-gate /*
21987c478bd9Sstevel@tonic-gate ** CATADDR -- concatenate pieces of addresses (putting in <LWSP> subs)
21997c478bd9Sstevel@tonic-gate **
22007c478bd9Sstevel@tonic-gate ** Parameters:
22017c478bd9Sstevel@tonic-gate ** pvp -- parameter vector to rebuild.
22027c478bd9Sstevel@tonic-gate ** evp -- last parameter to include. Can be NULL to
22037c478bd9Sstevel@tonic-gate ** use entire pvp.
22047c478bd9Sstevel@tonic-gate ** buf -- buffer to build the string into.
22057c478bd9Sstevel@tonic-gate ** sz -- size of buf.
22067c478bd9Sstevel@tonic-gate ** spacesub -- the space separator character; if '\0',
22077c478bd9Sstevel@tonic-gate ** use SpaceSub.
2208058561cbSjbeck ** external -- convert to external form?
2209058561cbSjbeck ** (no metacharacters; METAQUOTEs removed, see below)
22107c478bd9Sstevel@tonic-gate **
22117c478bd9Sstevel@tonic-gate ** Returns:
22127c478bd9Sstevel@tonic-gate ** none.
22137c478bd9Sstevel@tonic-gate **
22147c478bd9Sstevel@tonic-gate ** Side Effects:
22157c478bd9Sstevel@tonic-gate ** Destroys buf.
2216058561cbSjbeck **
2217058561cbSjbeck ** Notes:
2218058561cbSjbeck ** There are two formats for strings: internal and external.
2219058561cbSjbeck ** The external format is just an eight-bit clean string (no
2220058561cbSjbeck ** null bytes, everything else OK). The internal format can
2221058561cbSjbeck ** include sendmail metacharacters. The special character
2222058561cbSjbeck ** METAQUOTE essentially quotes the character following, stripping
2223058561cbSjbeck ** it of all special semantics.
2224058561cbSjbeck **
2225058561cbSjbeck ** The cataddr routine needs to be aware of whether it is producing
2226058561cbSjbeck ** an internal or external form as output (it only takes internal
2227058561cbSjbeck ** form as input).
2228058561cbSjbeck **
2229058561cbSjbeck ** The parseaddr routine has a similar issue on input, but that
2230058561cbSjbeck ** is flagged on the basis of which token table is passed in.
22317c478bd9Sstevel@tonic-gate */
22327c478bd9Sstevel@tonic-gate
22337c478bd9Sstevel@tonic-gate void
cataddr(pvp,evp,buf,sz,spacesub,external)2234058561cbSjbeck cataddr(pvp, evp, buf, sz, spacesub, external)
22357c478bd9Sstevel@tonic-gate char **pvp;
22367c478bd9Sstevel@tonic-gate char **evp;
22377c478bd9Sstevel@tonic-gate char *buf;
22387c478bd9Sstevel@tonic-gate register int sz;
22397c478bd9Sstevel@tonic-gate int spacesub;
2240058561cbSjbeck bool external;
22417c478bd9Sstevel@tonic-gate {
2242058561cbSjbeck bool oatomtok, natomtok;
2243058561cbSjbeck char *p;
2244058561cbSjbeck
2245058561cbSjbeck oatomtok = natomtok = false;
2246058561cbSjbeck if (tTd(59, 14))
2247058561cbSjbeck {
2248058561cbSjbeck sm_dprintf("cataddr(%d) <==", external);
2249058561cbSjbeck printav(sm_debug_file(), pvp);
2250058561cbSjbeck }
22517c478bd9Sstevel@tonic-gate
22527c478bd9Sstevel@tonic-gate if (sz <= 0)
22537c478bd9Sstevel@tonic-gate return;
22547c478bd9Sstevel@tonic-gate
22557c478bd9Sstevel@tonic-gate if (spacesub == '\0')
22567c478bd9Sstevel@tonic-gate spacesub = SpaceSub;
22577c478bd9Sstevel@tonic-gate
22587c478bd9Sstevel@tonic-gate if (pvp == NULL)
22597c478bd9Sstevel@tonic-gate {
22607c478bd9Sstevel@tonic-gate *buf = '\0';
22617c478bd9Sstevel@tonic-gate return;
22627c478bd9Sstevel@tonic-gate }
22637c478bd9Sstevel@tonic-gate p = buf;
22647c478bd9Sstevel@tonic-gate sz -= 2;
22657c478bd9Sstevel@tonic-gate while (*pvp != NULL && sz > 0)
22667c478bd9Sstevel@tonic-gate {
2267058561cbSjbeck char *q;
2268058561cbSjbeck
2269*d4660949Sjbeck natomtok = (IntTokenTab[**pvp & 0xff] == ATM);
22707c478bd9Sstevel@tonic-gate if (oatomtok && natomtok)
22717c478bd9Sstevel@tonic-gate {
22727c478bd9Sstevel@tonic-gate *p++ = spacesub;
22737c478bd9Sstevel@tonic-gate if (--sz <= 0)
22747c478bd9Sstevel@tonic-gate break;
22757c478bd9Sstevel@tonic-gate }
2276058561cbSjbeck for (q = *pvp; *q != '\0'; )
2277058561cbSjbeck {
2278058561cbSjbeck int c;
2279058561cbSjbeck
2280058561cbSjbeck if (--sz <= 0)
2281058561cbSjbeck break;
2282058561cbSjbeck *p++ = c = *q++;
2283058561cbSjbeck
2284058561cbSjbeck /*
2285058561cbSjbeck ** If the current character (c) is METAQUOTE and we
2286058561cbSjbeck ** want the "external" form and the next character
2287058561cbSjbeck ** is not NUL, then overwrite METAQUOTE with that
2288058561cbSjbeck ** character (i.e., METAQUOTE ch is changed to
2289058561cbSjbeck ** ch). p[-1] is used because p is advanced (above).
2290058561cbSjbeck */
2291058561cbSjbeck
2292058561cbSjbeck if ((c & 0377) == METAQUOTE && external && *q != '\0')
2293058561cbSjbeck p[-1] = *q++;
2294058561cbSjbeck }
22957c478bd9Sstevel@tonic-gate if (sz <= 0)
22967c478bd9Sstevel@tonic-gate break;
22977c478bd9Sstevel@tonic-gate oatomtok = natomtok;
22987c478bd9Sstevel@tonic-gate if (pvp++ == evp)
22997c478bd9Sstevel@tonic-gate break;
23007c478bd9Sstevel@tonic-gate }
23017c478bd9Sstevel@tonic-gate
23027c478bd9Sstevel@tonic-gate #if 0
23037c478bd9Sstevel@tonic-gate /*
23047c478bd9Sstevel@tonic-gate ** Silently truncate long strings: even though this doesn't
23057c478bd9Sstevel@tonic-gate ** seem like a good idea it is necessary because header checks
23067c478bd9Sstevel@tonic-gate ** send the whole header value to rscheck() and hence rewrite().
23077c478bd9Sstevel@tonic-gate ** The latter however sometimes uses a "short" buffer (e.g.,
23087c478bd9Sstevel@tonic-gate ** cbuf[MAXNAME + 1]) to call cataddr() which then triggers this
23097c478bd9Sstevel@tonic-gate ** error function. One possible fix to the problem is to pass
23107c478bd9Sstevel@tonic-gate ** flags to rscheck() and rewrite() to distinguish the various
23117c478bd9Sstevel@tonic-gate ** calls and only trigger the error if necessary. For now just
23127c478bd9Sstevel@tonic-gate ** undo the change from 8.13.0.
23137c478bd9Sstevel@tonic-gate */
23147c478bd9Sstevel@tonic-gate
23157c478bd9Sstevel@tonic-gate if (sz <= 0)
23167c478bd9Sstevel@tonic-gate usrerr("cataddr: string too long");
23177c478bd9Sstevel@tonic-gate #endif
23187c478bd9Sstevel@tonic-gate *p = '\0';
2319058561cbSjbeck
2320058561cbSjbeck if (tTd(59, 14))
2321058561cbSjbeck sm_dprintf(" cataddr => %s\n", str2prt(buf));
23227c478bd9Sstevel@tonic-gate }
2323058561cbSjbeck
23247c478bd9Sstevel@tonic-gate /*
23257c478bd9Sstevel@tonic-gate ** SAMEADDR -- Determine if two addresses are the same
23267c478bd9Sstevel@tonic-gate **
23277c478bd9Sstevel@tonic-gate ** This is not just a straight comparison -- if the mailer doesn't
23287c478bd9Sstevel@tonic-gate ** care about the host we just ignore it, etc.
23297c478bd9Sstevel@tonic-gate **
23307c478bd9Sstevel@tonic-gate ** Parameters:
23317c478bd9Sstevel@tonic-gate ** a, b -- pointers to the internal forms to compare.
23327c478bd9Sstevel@tonic-gate **
23337c478bd9Sstevel@tonic-gate ** Returns:
23347c478bd9Sstevel@tonic-gate ** true -- they represent the same mailbox.
23357c478bd9Sstevel@tonic-gate ** false -- they don't.
23367c478bd9Sstevel@tonic-gate **
23377c478bd9Sstevel@tonic-gate ** Side Effects:
23387c478bd9Sstevel@tonic-gate ** none.
23397c478bd9Sstevel@tonic-gate */
23407c478bd9Sstevel@tonic-gate
23417c478bd9Sstevel@tonic-gate bool
sameaddr(a,b)23427c478bd9Sstevel@tonic-gate sameaddr(a, b)
23437c478bd9Sstevel@tonic-gate register ADDRESS *a;
23447c478bd9Sstevel@tonic-gate register ADDRESS *b;
23457c478bd9Sstevel@tonic-gate {
23467c478bd9Sstevel@tonic-gate register ADDRESS *ca, *cb;
23477c478bd9Sstevel@tonic-gate
23487c478bd9Sstevel@tonic-gate /* if they don't have the same mailer, forget it */
23497c478bd9Sstevel@tonic-gate if (a->q_mailer != b->q_mailer)
23507c478bd9Sstevel@tonic-gate return false;
23517c478bd9Sstevel@tonic-gate
23527c478bd9Sstevel@tonic-gate /* if the user isn't the same, we can drop out */
23537c478bd9Sstevel@tonic-gate if (strcmp(a->q_user, b->q_user) != 0)
23547c478bd9Sstevel@tonic-gate return false;
23557c478bd9Sstevel@tonic-gate
23567c478bd9Sstevel@tonic-gate /* if we have good uids for both but they differ, these are different */
23577c478bd9Sstevel@tonic-gate if (a->q_mailer == ProgMailer)
23587c478bd9Sstevel@tonic-gate {
23597c478bd9Sstevel@tonic-gate ca = getctladdr(a);
23607c478bd9Sstevel@tonic-gate cb = getctladdr(b);
23617c478bd9Sstevel@tonic-gate if (ca != NULL && cb != NULL &&
23627c478bd9Sstevel@tonic-gate bitset(QGOODUID, ca->q_flags & cb->q_flags) &&
23637c478bd9Sstevel@tonic-gate ca->q_uid != cb->q_uid)
23647c478bd9Sstevel@tonic-gate return false;
23657c478bd9Sstevel@tonic-gate }
23667c478bd9Sstevel@tonic-gate
23677c478bd9Sstevel@tonic-gate /* otherwise compare hosts (but be careful for NULL ptrs) */
23687c478bd9Sstevel@tonic-gate if (a->q_host == b->q_host)
23697c478bd9Sstevel@tonic-gate {
23707c478bd9Sstevel@tonic-gate /* probably both null pointers */
23717c478bd9Sstevel@tonic-gate return true;
23727c478bd9Sstevel@tonic-gate }
23737c478bd9Sstevel@tonic-gate if (a->q_host == NULL || b->q_host == NULL)
23747c478bd9Sstevel@tonic-gate {
23757c478bd9Sstevel@tonic-gate /* only one is a null pointer */
23767c478bd9Sstevel@tonic-gate return false;
23777c478bd9Sstevel@tonic-gate }
23787c478bd9Sstevel@tonic-gate if (strcmp(a->q_host, b->q_host) != 0)
23797c478bd9Sstevel@tonic-gate return false;
23807c478bd9Sstevel@tonic-gate
23817c478bd9Sstevel@tonic-gate return true;
23827c478bd9Sstevel@tonic-gate }
23837c478bd9Sstevel@tonic-gate /*
23847c478bd9Sstevel@tonic-gate ** PRINTADDR -- print address (for debugging)
23857c478bd9Sstevel@tonic-gate **
23867c478bd9Sstevel@tonic-gate ** Parameters:
23877c478bd9Sstevel@tonic-gate ** a -- the address to print
23887c478bd9Sstevel@tonic-gate ** follow -- follow the q_next chain.
23897c478bd9Sstevel@tonic-gate **
23907c478bd9Sstevel@tonic-gate ** Returns:
23917c478bd9Sstevel@tonic-gate ** none.
23927c478bd9Sstevel@tonic-gate **
23937c478bd9Sstevel@tonic-gate ** Side Effects:
23947c478bd9Sstevel@tonic-gate ** none.
23957c478bd9Sstevel@tonic-gate */
23967c478bd9Sstevel@tonic-gate
23977c478bd9Sstevel@tonic-gate struct qflags
23987c478bd9Sstevel@tonic-gate {
23997c478bd9Sstevel@tonic-gate char *qf_name;
24007c478bd9Sstevel@tonic-gate unsigned long qf_bit;
24017c478bd9Sstevel@tonic-gate };
24027c478bd9Sstevel@tonic-gate
24037c478bd9Sstevel@tonic-gate static struct qflags AddressFlags[] =
24047c478bd9Sstevel@tonic-gate {
24057c478bd9Sstevel@tonic-gate { "QGOODUID", QGOODUID },
24067c478bd9Sstevel@tonic-gate { "QPRIMARY", QPRIMARY },
24077c478bd9Sstevel@tonic-gate { "QNOTREMOTE", QNOTREMOTE },
24087c478bd9Sstevel@tonic-gate { "QSELFREF", QSELFREF },
24097c478bd9Sstevel@tonic-gate { "QBOGUSSHELL", QBOGUSSHELL },
24107c478bd9Sstevel@tonic-gate { "QUNSAFEADDR", QUNSAFEADDR },
24117c478bd9Sstevel@tonic-gate { "QPINGONSUCCESS", QPINGONSUCCESS },
24127c478bd9Sstevel@tonic-gate { "QPINGONFAILURE", QPINGONFAILURE },
24137c478bd9Sstevel@tonic-gate { "QPINGONDELAY", QPINGONDELAY },
24147c478bd9Sstevel@tonic-gate { "QHASNOTIFY", QHASNOTIFY },
24157c478bd9Sstevel@tonic-gate { "QRELAYED", QRELAYED },
24167c478bd9Sstevel@tonic-gate { "QEXPANDED", QEXPANDED },
24177c478bd9Sstevel@tonic-gate { "QDELIVERED", QDELIVERED },
24187c478bd9Sstevel@tonic-gate { "QDELAYED", QDELAYED },
24197c478bd9Sstevel@tonic-gate { "QTHISPASS", QTHISPASS },
24207c478bd9Sstevel@tonic-gate { "QRCPTOK", QRCPTOK },
24217c478bd9Sstevel@tonic-gate { NULL, 0 }
24227c478bd9Sstevel@tonic-gate };
24237c478bd9Sstevel@tonic-gate
24247c478bd9Sstevel@tonic-gate void
printaddr(fp,a,follow)24257c478bd9Sstevel@tonic-gate printaddr(fp, a, follow)
24267c478bd9Sstevel@tonic-gate SM_FILE_T *fp;
24277c478bd9Sstevel@tonic-gate register ADDRESS *a;
24287c478bd9Sstevel@tonic-gate bool follow;
24297c478bd9Sstevel@tonic-gate {
24307c478bd9Sstevel@tonic-gate register MAILER *m;
24317c478bd9Sstevel@tonic-gate MAILER pseudomailer;
24327c478bd9Sstevel@tonic-gate register struct qflags *qfp;
24337c478bd9Sstevel@tonic-gate bool firstone;
24347c478bd9Sstevel@tonic-gate
24357c478bd9Sstevel@tonic-gate if (a == NULL)
24367c478bd9Sstevel@tonic-gate {
24377c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "[NULL]\n");
24387c478bd9Sstevel@tonic-gate return;
24397c478bd9Sstevel@tonic-gate }
24407c478bd9Sstevel@tonic-gate
24417c478bd9Sstevel@tonic-gate while (a != NULL)
24427c478bd9Sstevel@tonic-gate {
24437c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%p=", a);
24447c478bd9Sstevel@tonic-gate (void) sm_io_flush(fp, SM_TIME_DEFAULT);
24457c478bd9Sstevel@tonic-gate
24467c478bd9Sstevel@tonic-gate /* find the mailer -- carefully */
24477c478bd9Sstevel@tonic-gate m = a->q_mailer;
24487c478bd9Sstevel@tonic-gate if (m == NULL)
24497c478bd9Sstevel@tonic-gate {
24507c478bd9Sstevel@tonic-gate m = &pseudomailer;
24517c478bd9Sstevel@tonic-gate m->m_mno = -1;
24527c478bd9Sstevel@tonic-gate m->m_name = "NULL";
24537c478bd9Sstevel@tonic-gate }
24547c478bd9Sstevel@tonic-gate
24557c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
24567c478bd9Sstevel@tonic-gate "%s:\n\tmailer %d (%s), host `%s'\n",
24577c478bd9Sstevel@tonic-gate a->q_paddr == NULL ? "<null>" : a->q_paddr,
24587c478bd9Sstevel@tonic-gate m->m_mno, m->m_name,
24597c478bd9Sstevel@tonic-gate a->q_host == NULL ? "<null>" : a->q_host);
24607c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
24617c478bd9Sstevel@tonic-gate "\tuser `%s', ruser `%s'\n",
24627c478bd9Sstevel@tonic-gate a->q_user,
24637c478bd9Sstevel@tonic-gate a->q_ruser == NULL ? "<null>" : a->q_ruser);
24647c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\tstate=");
24657c478bd9Sstevel@tonic-gate switch (a->q_state)
24667c478bd9Sstevel@tonic-gate {
24677c478bd9Sstevel@tonic-gate case QS_OK:
24687c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "OK");
24697c478bd9Sstevel@tonic-gate break;
24707c478bd9Sstevel@tonic-gate
24717c478bd9Sstevel@tonic-gate case QS_DONTSEND:
24727c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
24737c478bd9Sstevel@tonic-gate "DONTSEND");
24747c478bd9Sstevel@tonic-gate break;
24757c478bd9Sstevel@tonic-gate
24767c478bd9Sstevel@tonic-gate case QS_BADADDR:
24777c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
24787c478bd9Sstevel@tonic-gate "BADADDR");
24797c478bd9Sstevel@tonic-gate break;
24807c478bd9Sstevel@tonic-gate
24817c478bd9Sstevel@tonic-gate case QS_QUEUEUP:
24827c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
24837c478bd9Sstevel@tonic-gate "QUEUEUP");
24847c478bd9Sstevel@tonic-gate break;
24857c478bd9Sstevel@tonic-gate
24867c478bd9Sstevel@tonic-gate case QS_RETRY:
24877c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "RETRY");
24887c478bd9Sstevel@tonic-gate break;
24897c478bd9Sstevel@tonic-gate
24907c478bd9Sstevel@tonic-gate case QS_SENT:
24917c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "SENT");
24927c478bd9Sstevel@tonic-gate break;
24937c478bd9Sstevel@tonic-gate
24947c478bd9Sstevel@tonic-gate case QS_VERIFIED:
24957c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
24967c478bd9Sstevel@tonic-gate "VERIFIED");
24977c478bd9Sstevel@tonic-gate break;
24987c478bd9Sstevel@tonic-gate
24997c478bd9Sstevel@tonic-gate case QS_EXPANDED:
25007c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
25017c478bd9Sstevel@tonic-gate "EXPANDED");
25027c478bd9Sstevel@tonic-gate break;
25037c478bd9Sstevel@tonic-gate
25047c478bd9Sstevel@tonic-gate case QS_SENDER:
25057c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
25067c478bd9Sstevel@tonic-gate "SENDER");
25077c478bd9Sstevel@tonic-gate break;
25087c478bd9Sstevel@tonic-gate
25097c478bd9Sstevel@tonic-gate case QS_CLONED:
25107c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
25117c478bd9Sstevel@tonic-gate "CLONED");
25127c478bd9Sstevel@tonic-gate break;
25137c478bd9Sstevel@tonic-gate
25147c478bd9Sstevel@tonic-gate case QS_DISCARDED:
25157c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
25167c478bd9Sstevel@tonic-gate "DISCARDED");
25177c478bd9Sstevel@tonic-gate break;
25187c478bd9Sstevel@tonic-gate
25197c478bd9Sstevel@tonic-gate case QS_REPLACED:
25207c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
25217c478bd9Sstevel@tonic-gate "REPLACED");
25227c478bd9Sstevel@tonic-gate break;
25237c478bd9Sstevel@tonic-gate
25247c478bd9Sstevel@tonic-gate case QS_REMOVED:
25257c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
25267c478bd9Sstevel@tonic-gate "REMOVED");
25277c478bd9Sstevel@tonic-gate break;
25287c478bd9Sstevel@tonic-gate
25297c478bd9Sstevel@tonic-gate case QS_DUPLICATE:
25307c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
25317c478bd9Sstevel@tonic-gate "DUPLICATE");
25327c478bd9Sstevel@tonic-gate break;
25337c478bd9Sstevel@tonic-gate
25347c478bd9Sstevel@tonic-gate case QS_INCLUDED:
25357c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
25367c478bd9Sstevel@tonic-gate "INCLUDED");
25377c478bd9Sstevel@tonic-gate break;
25387c478bd9Sstevel@tonic-gate
25397c478bd9Sstevel@tonic-gate default:
25407c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
25417c478bd9Sstevel@tonic-gate "%d", a->q_state);
25427c478bd9Sstevel@tonic-gate break;
25437c478bd9Sstevel@tonic-gate }
25447c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
25457c478bd9Sstevel@tonic-gate ", next=%p, alias %p, uid %d, gid %d\n",
25467c478bd9Sstevel@tonic-gate a->q_next, a->q_alias,
25477c478bd9Sstevel@tonic-gate (int) a->q_uid, (int) a->q_gid);
25487c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "\tflags=%lx<",
25497c478bd9Sstevel@tonic-gate a->q_flags);
25507c478bd9Sstevel@tonic-gate firstone = true;
25517c478bd9Sstevel@tonic-gate for (qfp = AddressFlags; qfp->qf_name != NULL; qfp++)
25527c478bd9Sstevel@tonic-gate {
25537c478bd9Sstevel@tonic-gate if (!bitset(qfp->qf_bit, a->q_flags))
25547c478bd9Sstevel@tonic-gate continue;
25557c478bd9Sstevel@tonic-gate if (!firstone)
25567c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
25577c478bd9Sstevel@tonic-gate ",");
25587c478bd9Sstevel@tonic-gate firstone = false;
25597c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s",
25607c478bd9Sstevel@tonic-gate qfp->qf_name);
25617c478bd9Sstevel@tonic-gate }
25627c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, ">\n");
25637c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
25647c478bd9Sstevel@tonic-gate "\towner=%s, home=\"%s\", fullname=\"%s\"\n",
25657c478bd9Sstevel@tonic-gate a->q_owner == NULL ? "(none)" : a->q_owner,
25667c478bd9Sstevel@tonic-gate a->q_home == NULL ? "(none)" : a->q_home,
25677c478bd9Sstevel@tonic-gate a->q_fullname == NULL ? "(none)" : a->q_fullname);
25687c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
25697c478bd9Sstevel@tonic-gate "\torcpt=\"%s\", statmta=%s, status=%s\n",
25707c478bd9Sstevel@tonic-gate a->q_orcpt == NULL ? "(none)" : a->q_orcpt,
25717c478bd9Sstevel@tonic-gate a->q_statmta == NULL ? "(none)" : a->q_statmta,
25727c478bd9Sstevel@tonic-gate a->q_status == NULL ? "(none)" : a->q_status);
25737c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
25747c478bd9Sstevel@tonic-gate "\tfinalrcpt=\"%s\"\n",
25757c478bd9Sstevel@tonic-gate a->q_finalrcpt == NULL ? "(none)" : a->q_finalrcpt);
25767c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
25777c478bd9Sstevel@tonic-gate "\trstatus=\"%s\"\n",
25787c478bd9Sstevel@tonic-gate a->q_rstatus == NULL ? "(none)" : a->q_rstatus);
25797c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(fp, SM_TIME_DEFAULT,
25807c478bd9Sstevel@tonic-gate "\tstatdate=%s\n",
25817c478bd9Sstevel@tonic-gate a->q_statdate == 0 ? "(none)" : ctime(&a->q_statdate));
25827c478bd9Sstevel@tonic-gate
25837c478bd9Sstevel@tonic-gate if (!follow)
25847c478bd9Sstevel@tonic-gate return;
25857c478bd9Sstevel@tonic-gate a = a->q_next;
25867c478bd9Sstevel@tonic-gate }
25877c478bd9Sstevel@tonic-gate }
25887c478bd9Sstevel@tonic-gate /*
25897c478bd9Sstevel@tonic-gate ** EMPTYADDR -- return true if this address is empty (``<>'')
25907c478bd9Sstevel@tonic-gate **
25917c478bd9Sstevel@tonic-gate ** Parameters:
25927c478bd9Sstevel@tonic-gate ** a -- pointer to the address
25937c478bd9Sstevel@tonic-gate **
25947c478bd9Sstevel@tonic-gate ** Returns:
25957c478bd9Sstevel@tonic-gate ** true -- if this address is "empty" (i.e., no one should
25967c478bd9Sstevel@tonic-gate ** ever generate replies to it.
25977c478bd9Sstevel@tonic-gate ** false -- if it is a "regular" (read: replyable) address.
25987c478bd9Sstevel@tonic-gate */
25997c478bd9Sstevel@tonic-gate
26007c478bd9Sstevel@tonic-gate bool
emptyaddr(a)26017c478bd9Sstevel@tonic-gate emptyaddr(a)
26027c478bd9Sstevel@tonic-gate register ADDRESS *a;
26037c478bd9Sstevel@tonic-gate {
26047c478bd9Sstevel@tonic-gate return a->q_paddr == NULL || strcmp(a->q_paddr, "<>") == 0 ||
26057c478bd9Sstevel@tonic-gate a->q_user == NULL || strcmp(a->q_user, "<>") == 0;
26067c478bd9Sstevel@tonic-gate }
26077c478bd9Sstevel@tonic-gate /*
26087c478bd9Sstevel@tonic-gate ** REMOTENAME -- return the name relative to the current mailer
26097c478bd9Sstevel@tonic-gate **
26107c478bd9Sstevel@tonic-gate ** Parameters:
26117c478bd9Sstevel@tonic-gate ** name -- the name to translate.
26127c478bd9Sstevel@tonic-gate ** m -- the mailer that we want to do rewriting relative to.
26137c478bd9Sstevel@tonic-gate ** flags -- fine tune operations.
26147c478bd9Sstevel@tonic-gate ** pstat -- pointer to status word.
26157c478bd9Sstevel@tonic-gate ** e -- the current envelope.
26167c478bd9Sstevel@tonic-gate **
26177c478bd9Sstevel@tonic-gate ** Returns:
26187c478bd9Sstevel@tonic-gate ** the text string representing this address relative to
26197c478bd9Sstevel@tonic-gate ** the receiving mailer.
26207c478bd9Sstevel@tonic-gate **
26217c478bd9Sstevel@tonic-gate ** Side Effects:
26227c478bd9Sstevel@tonic-gate ** none.
26237c478bd9Sstevel@tonic-gate **
26247c478bd9Sstevel@tonic-gate ** Warnings:
26257c478bd9Sstevel@tonic-gate ** The text string returned is tucked away locally;
26267c478bd9Sstevel@tonic-gate ** copy it if you intend to save it.
26277c478bd9Sstevel@tonic-gate */
26287c478bd9Sstevel@tonic-gate
26297c478bd9Sstevel@tonic-gate char *
remotename(name,m,flags,pstat,e)26307c478bd9Sstevel@tonic-gate remotename(name, m, flags, pstat, e)
26317c478bd9Sstevel@tonic-gate char *name;
26327c478bd9Sstevel@tonic-gate struct mailer *m;
26337c478bd9Sstevel@tonic-gate int flags;
26347c478bd9Sstevel@tonic-gate int *pstat;
26357c478bd9Sstevel@tonic-gate register ENVELOPE *e;
26367c478bd9Sstevel@tonic-gate {
26377c478bd9Sstevel@tonic-gate register char **pvp;
26387c478bd9Sstevel@tonic-gate char *SM_NONVOLATILE fancy;
26397c478bd9Sstevel@tonic-gate char *oldg;
26407c478bd9Sstevel@tonic-gate int rwset;
26417c478bd9Sstevel@tonic-gate static char buf[MAXNAME + 1];
26427c478bd9Sstevel@tonic-gate char lbuf[MAXNAME + 1];
26437c478bd9Sstevel@tonic-gate char pvpbuf[PSBUFSIZE];
26447c478bd9Sstevel@tonic-gate char addrtype[4];
26457c478bd9Sstevel@tonic-gate
26467c478bd9Sstevel@tonic-gate if (tTd(12, 1))
2647058561cbSjbeck {
2648058561cbSjbeck sm_dprintf("remotename(");
2649058561cbSjbeck xputs(sm_debug_file(), name);
2650058561cbSjbeck sm_dprintf(")\n");
2651058561cbSjbeck }
26527c478bd9Sstevel@tonic-gate
26537c478bd9Sstevel@tonic-gate /* don't do anything if we are tagging it as special */
26547c478bd9Sstevel@tonic-gate if (bitset(RF_SENDERADDR, flags))
26557c478bd9Sstevel@tonic-gate {
26567c478bd9Sstevel@tonic-gate rwset = bitset(RF_HEADERADDR, flags) ? m->m_sh_rwset
26577c478bd9Sstevel@tonic-gate : m->m_se_rwset;
26587c478bd9Sstevel@tonic-gate addrtype[2] = 's';
26597c478bd9Sstevel@tonic-gate }
26607c478bd9Sstevel@tonic-gate else
26617c478bd9Sstevel@tonic-gate {
26627c478bd9Sstevel@tonic-gate rwset = bitset(RF_HEADERADDR, flags) ? m->m_rh_rwset
26637c478bd9Sstevel@tonic-gate : m->m_re_rwset;
26647c478bd9Sstevel@tonic-gate addrtype[2] = 'r';
26657c478bd9Sstevel@tonic-gate }
26667c478bd9Sstevel@tonic-gate if (rwset < 0)
26677c478bd9Sstevel@tonic-gate return name;
26687c478bd9Sstevel@tonic-gate addrtype[1] = ' ';
26697c478bd9Sstevel@tonic-gate addrtype[3] = '\0';
26707c478bd9Sstevel@tonic-gate addrtype[0] = bitset(RF_HEADERADDR, flags) ? 'h' : 'e';
26717c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_TEMP, macid("{addr_type}"), addrtype);
26727c478bd9Sstevel@tonic-gate
26737c478bd9Sstevel@tonic-gate /*
26747c478bd9Sstevel@tonic-gate ** Do a heuristic crack of this name to extract any comment info.
26757c478bd9Sstevel@tonic-gate ** This will leave the name as a comment and a $g macro.
26767c478bd9Sstevel@tonic-gate */
26777c478bd9Sstevel@tonic-gate
26787c478bd9Sstevel@tonic-gate if (bitset(RF_CANONICAL, flags) || bitnset(M_NOCOMMENT, m->m_flags))
26797c478bd9Sstevel@tonic-gate fancy = "\201g";
26807c478bd9Sstevel@tonic-gate else
26817c478bd9Sstevel@tonic-gate fancy = crackaddr(name, e);
26827c478bd9Sstevel@tonic-gate
26837c478bd9Sstevel@tonic-gate /*
26847c478bd9Sstevel@tonic-gate ** Turn the name into canonical form.
26857c478bd9Sstevel@tonic-gate ** Normally this will be RFC 822 style, i.e., "user@domain".
26867c478bd9Sstevel@tonic-gate ** If this only resolves to "user", and the "C" flag is
26877c478bd9Sstevel@tonic-gate ** specified in the sending mailer, then the sender's
26887c478bd9Sstevel@tonic-gate ** domain will be appended.
26897c478bd9Sstevel@tonic-gate */
26907c478bd9Sstevel@tonic-gate
2691058561cbSjbeck pvp = prescan(name, '\0', pvpbuf, sizeof(pvpbuf), NULL, NULL, false);
26927c478bd9Sstevel@tonic-gate if (pvp == NULL)
26937c478bd9Sstevel@tonic-gate return name;
26947c478bd9Sstevel@tonic-gate if (REWRITE(pvp, 3, e) == EX_TEMPFAIL)
26957c478bd9Sstevel@tonic-gate *pstat = EX_TEMPFAIL;
26967c478bd9Sstevel@tonic-gate if (bitset(RF_ADDDOMAIN, flags) && e->e_fromdomain != NULL)
26977c478bd9Sstevel@tonic-gate {
26987c478bd9Sstevel@tonic-gate /* append from domain to this address */
26997c478bd9Sstevel@tonic-gate register char **pxp = pvp;
27007c478bd9Sstevel@tonic-gate int l = MAXATOM; /* size of buffer for pvp */
27017c478bd9Sstevel@tonic-gate
27027c478bd9Sstevel@tonic-gate /* see if there is an "@domain" in the current name */
27037c478bd9Sstevel@tonic-gate while (*pxp != NULL && strcmp(*pxp, "@") != 0)
27047c478bd9Sstevel@tonic-gate {
27057c478bd9Sstevel@tonic-gate pxp++;
27067c478bd9Sstevel@tonic-gate --l;
27077c478bd9Sstevel@tonic-gate }
27087c478bd9Sstevel@tonic-gate if (*pxp == NULL)
27097c478bd9Sstevel@tonic-gate {
27107c478bd9Sstevel@tonic-gate /* no.... append the "@domain" from the sender */
27117c478bd9Sstevel@tonic-gate register char **qxq = e->e_fromdomain;
27127c478bd9Sstevel@tonic-gate
27137c478bd9Sstevel@tonic-gate while ((*pxp++ = *qxq++) != NULL)
27147c478bd9Sstevel@tonic-gate {
27157c478bd9Sstevel@tonic-gate if (--l <= 0)
27167c478bd9Sstevel@tonic-gate {
27177c478bd9Sstevel@tonic-gate *--pxp = NULL;
27187c478bd9Sstevel@tonic-gate usrerr("553 5.1.0 remotename: too many tokens");
27197c478bd9Sstevel@tonic-gate *pstat = EX_UNAVAILABLE;
27207c478bd9Sstevel@tonic-gate break;
27217c478bd9Sstevel@tonic-gate }
27227c478bd9Sstevel@tonic-gate }
27237c478bd9Sstevel@tonic-gate if (REWRITE(pvp, 3, e) == EX_TEMPFAIL)
27247c478bd9Sstevel@tonic-gate *pstat = EX_TEMPFAIL;
27257c478bd9Sstevel@tonic-gate }
27267c478bd9Sstevel@tonic-gate }
27277c478bd9Sstevel@tonic-gate
27287c478bd9Sstevel@tonic-gate /*
27297c478bd9Sstevel@tonic-gate ** Do more specific rewriting.
27307c478bd9Sstevel@tonic-gate ** Rewrite using ruleset 1 or 2 depending on whether this is
27317c478bd9Sstevel@tonic-gate ** a sender address or not.
27327c478bd9Sstevel@tonic-gate ** Then run it through any receiving-mailer-specific rulesets.
27337c478bd9Sstevel@tonic-gate */
27347c478bd9Sstevel@tonic-gate
27357c478bd9Sstevel@tonic-gate if (bitset(RF_SENDERADDR, flags))
27367c478bd9Sstevel@tonic-gate {
27377c478bd9Sstevel@tonic-gate if (REWRITE(pvp, 1, e) == EX_TEMPFAIL)
27387c478bd9Sstevel@tonic-gate *pstat = EX_TEMPFAIL;
27397c478bd9Sstevel@tonic-gate }
27407c478bd9Sstevel@tonic-gate else
27417c478bd9Sstevel@tonic-gate {
27427c478bd9Sstevel@tonic-gate if (REWRITE(pvp, 2, e) == EX_TEMPFAIL)
27437c478bd9Sstevel@tonic-gate *pstat = EX_TEMPFAIL;
27447c478bd9Sstevel@tonic-gate }
27457c478bd9Sstevel@tonic-gate if (rwset > 0)
27467c478bd9Sstevel@tonic-gate {
27477c478bd9Sstevel@tonic-gate if (REWRITE(pvp, rwset, e) == EX_TEMPFAIL)
27487c478bd9Sstevel@tonic-gate *pstat = EX_TEMPFAIL;
27497c478bd9Sstevel@tonic-gate }
27507c478bd9Sstevel@tonic-gate
27517c478bd9Sstevel@tonic-gate /*
27527c478bd9Sstevel@tonic-gate ** Do any final sanitation the address may require.
27537c478bd9Sstevel@tonic-gate ** This will normally be used to turn internal forms
27547c478bd9Sstevel@tonic-gate ** (e.g., user@host.LOCAL) into external form. This
27557c478bd9Sstevel@tonic-gate ** may be used as a default to the above rules.
27567c478bd9Sstevel@tonic-gate */
27577c478bd9Sstevel@tonic-gate
27587c478bd9Sstevel@tonic-gate if (REWRITE(pvp, 4, e) == EX_TEMPFAIL)
27597c478bd9Sstevel@tonic-gate *pstat = EX_TEMPFAIL;
27607c478bd9Sstevel@tonic-gate
27617c478bd9Sstevel@tonic-gate /*
27627c478bd9Sstevel@tonic-gate ** Now restore the comment information we had at the beginning.
27637c478bd9Sstevel@tonic-gate */
27647c478bd9Sstevel@tonic-gate
2765058561cbSjbeck cataddr(pvp, NULL, lbuf, sizeof(lbuf), '\0', false);
27667c478bd9Sstevel@tonic-gate oldg = macget(&e->e_macro, 'g');
27677c478bd9Sstevel@tonic-gate macset(&e->e_macro, 'g', lbuf);
27687c478bd9Sstevel@tonic-gate
27697c478bd9Sstevel@tonic-gate SM_TRY
27707c478bd9Sstevel@tonic-gate /* need to make sure route-addrs have <angle brackets> */
27717c478bd9Sstevel@tonic-gate if (bitset(RF_CANONICAL, flags) && lbuf[0] == '@')
2772058561cbSjbeck expand("<\201g>", buf, sizeof(buf), e);
27737c478bd9Sstevel@tonic-gate else
2774058561cbSjbeck expand(fancy, buf, sizeof(buf), e);
27757c478bd9Sstevel@tonic-gate SM_FINALLY
27767c478bd9Sstevel@tonic-gate macset(&e->e_macro, 'g', oldg);
27777c478bd9Sstevel@tonic-gate SM_END_TRY
27787c478bd9Sstevel@tonic-gate
27797c478bd9Sstevel@tonic-gate if (tTd(12, 1))
2780058561cbSjbeck {
2781058561cbSjbeck sm_dprintf("remotename => `");
2782058561cbSjbeck xputs(sm_debug_file(), buf);
2783058561cbSjbeck sm_dprintf("'\n");
2784058561cbSjbeck }
27857c478bd9Sstevel@tonic-gate return buf;
27867c478bd9Sstevel@tonic-gate }
27877c478bd9Sstevel@tonic-gate /*
27887c478bd9Sstevel@tonic-gate ** MAPLOCALUSER -- run local username through ruleset 5 for final redirection
27897c478bd9Sstevel@tonic-gate **
27907c478bd9Sstevel@tonic-gate ** Parameters:
27917c478bd9Sstevel@tonic-gate ** a -- the address to map (but just the user name part).
27927c478bd9Sstevel@tonic-gate ** sendq -- the sendq in which to install any replacement
27937c478bd9Sstevel@tonic-gate ** addresses.
27947c478bd9Sstevel@tonic-gate ** aliaslevel -- the alias nesting depth.
27957c478bd9Sstevel@tonic-gate ** e -- the envelope.
27967c478bd9Sstevel@tonic-gate **
27977c478bd9Sstevel@tonic-gate ** Returns:
27987c478bd9Sstevel@tonic-gate ** none.
27997c478bd9Sstevel@tonic-gate */
28007c478bd9Sstevel@tonic-gate
28017c478bd9Sstevel@tonic-gate #define Q_COPYFLAGS (QPRIMARY|QBOGUSSHELL|QUNSAFEADDR|\
28027c478bd9Sstevel@tonic-gate Q_PINGFLAGS|QHASNOTIFY|\
28037c478bd9Sstevel@tonic-gate QRELAYED|QEXPANDED|QDELIVERED|QDELAYED|\
28047c478bd9Sstevel@tonic-gate QBYTRACE|QBYNDELAY|QBYNRELAY)
28057c478bd9Sstevel@tonic-gate
28067c478bd9Sstevel@tonic-gate void
maplocaluser(a,sendq,aliaslevel,e)28077c478bd9Sstevel@tonic-gate maplocaluser(a, sendq, aliaslevel, e)
28087c478bd9Sstevel@tonic-gate register ADDRESS *a;
28097c478bd9Sstevel@tonic-gate ADDRESS **sendq;
28107c478bd9Sstevel@tonic-gate int aliaslevel;
28117c478bd9Sstevel@tonic-gate ENVELOPE *e;
28127c478bd9Sstevel@tonic-gate {
28137c478bd9Sstevel@tonic-gate register char **pvp;
28147c478bd9Sstevel@tonic-gate register ADDRESS *SM_NONVOLATILE a1 = NULL;
28157c478bd9Sstevel@tonic-gate char pvpbuf[PSBUFSIZE];
28167c478bd9Sstevel@tonic-gate
28177c478bd9Sstevel@tonic-gate if (tTd(29, 1))
28187c478bd9Sstevel@tonic-gate {
28197c478bd9Sstevel@tonic-gate sm_dprintf("maplocaluser: ");
28207c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), a, false);
28217c478bd9Sstevel@tonic-gate }
2822058561cbSjbeck pvp = prescan(a->q_user, '\0', pvpbuf, sizeof(pvpbuf), NULL, NULL,
2823058561cbSjbeck false);
28247c478bd9Sstevel@tonic-gate if (pvp == NULL)
28257c478bd9Sstevel@tonic-gate {
28267c478bd9Sstevel@tonic-gate if (tTd(29, 9))
28277c478bd9Sstevel@tonic-gate sm_dprintf("maplocaluser: cannot prescan %s\n",
28287c478bd9Sstevel@tonic-gate a->q_user);
28297c478bd9Sstevel@tonic-gate return;
28307c478bd9Sstevel@tonic-gate }
28317c478bd9Sstevel@tonic-gate
28327c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'h', a->q_host);
28337c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'u', a->q_user);
28347c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'z', a->q_home);
28357c478bd9Sstevel@tonic-gate
28367c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e r");
28377c478bd9Sstevel@tonic-gate if (REWRITE(pvp, 5, e) == EX_TEMPFAIL)
28387c478bd9Sstevel@tonic-gate {
28397c478bd9Sstevel@tonic-gate if (tTd(29, 9))
28407c478bd9Sstevel@tonic-gate sm_dprintf("maplocaluser: rewrite tempfail\n");
28417c478bd9Sstevel@tonic-gate a->q_state = QS_QUEUEUP;
28427c478bd9Sstevel@tonic-gate a->q_status = "4.4.3";
28437c478bd9Sstevel@tonic-gate return;
28447c478bd9Sstevel@tonic-gate }
28457c478bd9Sstevel@tonic-gate if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET)
28467c478bd9Sstevel@tonic-gate {
28477c478bd9Sstevel@tonic-gate if (tTd(29, 9))
28487c478bd9Sstevel@tonic-gate sm_dprintf("maplocaluser: doesn't resolve\n");
28497c478bd9Sstevel@tonic-gate return;
28507c478bd9Sstevel@tonic-gate }
28517c478bd9Sstevel@tonic-gate
28527c478bd9Sstevel@tonic-gate SM_TRY
28537c478bd9Sstevel@tonic-gate a1 = buildaddr(pvp, NULL, 0, e);
28547c478bd9Sstevel@tonic-gate SM_EXCEPT(exc, "E:mta.quickabort")
28557c478bd9Sstevel@tonic-gate
28567c478bd9Sstevel@tonic-gate /*
28577c478bd9Sstevel@tonic-gate ** mark address as bad, S5 returned an error
28587c478bd9Sstevel@tonic-gate ** and we gave that back to the SMTP client.
28597c478bd9Sstevel@tonic-gate */
28607c478bd9Sstevel@tonic-gate
28617c478bd9Sstevel@tonic-gate a->q_state = QS_DONTSEND;
28627c478bd9Sstevel@tonic-gate sm_exc_raisenew_x(&EtypeQuickAbort, 2);
28637c478bd9Sstevel@tonic-gate SM_END_TRY
28647c478bd9Sstevel@tonic-gate
28657c478bd9Sstevel@tonic-gate /* if non-null, mailer destination specified -- has it changed? */
28667c478bd9Sstevel@tonic-gate if (a1 == NULL || sameaddr(a, a1))
28677c478bd9Sstevel@tonic-gate {
28687c478bd9Sstevel@tonic-gate if (tTd(29, 9))
28697c478bd9Sstevel@tonic-gate sm_dprintf("maplocaluser: address unchanged\n");
28707c478bd9Sstevel@tonic-gate return;
28717c478bd9Sstevel@tonic-gate }
28727c478bd9Sstevel@tonic-gate
28737c478bd9Sstevel@tonic-gate /* make new address take on flags and print attributes of old */
28747c478bd9Sstevel@tonic-gate a1->q_flags &= ~Q_COPYFLAGS;
28757c478bd9Sstevel@tonic-gate a1->q_flags |= a->q_flags & Q_COPYFLAGS;
28767c478bd9Sstevel@tonic-gate a1->q_paddr = sm_rpool_strdup_x(e->e_rpool, a->q_paddr);
28777c478bd9Sstevel@tonic-gate a1->q_finalrcpt = a->q_finalrcpt;
28787c478bd9Sstevel@tonic-gate a1->q_orcpt = a->q_orcpt;
28797c478bd9Sstevel@tonic-gate
28807c478bd9Sstevel@tonic-gate /* mark old address as dead; insert new address */
28817c478bd9Sstevel@tonic-gate a->q_state = QS_REPLACED;
28827c478bd9Sstevel@tonic-gate if (tTd(29, 5))
28837c478bd9Sstevel@tonic-gate {
28847c478bd9Sstevel@tonic-gate sm_dprintf("maplocaluser: QS_REPLACED ");
28857c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), a, false);
28867c478bd9Sstevel@tonic-gate }
28877c478bd9Sstevel@tonic-gate a1->q_alias = a;
28887c478bd9Sstevel@tonic-gate allocaddr(a1, RF_COPYALL, sm_rpool_strdup_x(e->e_rpool, a->q_paddr), e);
28897c478bd9Sstevel@tonic-gate (void) recipient(a1, sendq, aliaslevel, e);
28907c478bd9Sstevel@tonic-gate }
28917c478bd9Sstevel@tonic-gate /*
28927c478bd9Sstevel@tonic-gate ** DEQUOTE_INIT -- initialize dequote map
28937c478bd9Sstevel@tonic-gate **
28947c478bd9Sstevel@tonic-gate ** Parameters:
28957c478bd9Sstevel@tonic-gate ** map -- the internal map structure.
28967c478bd9Sstevel@tonic-gate ** args -- arguments.
28977c478bd9Sstevel@tonic-gate **
28987c478bd9Sstevel@tonic-gate ** Returns:
28997c478bd9Sstevel@tonic-gate ** true.
29007c478bd9Sstevel@tonic-gate */
29017c478bd9Sstevel@tonic-gate
29027c478bd9Sstevel@tonic-gate bool
dequote_init(map,args)29037c478bd9Sstevel@tonic-gate dequote_init(map, args)
29047c478bd9Sstevel@tonic-gate MAP *map;
29057c478bd9Sstevel@tonic-gate char *args;
29067c478bd9Sstevel@tonic-gate {
29077c478bd9Sstevel@tonic-gate register char *p = args;
29087c478bd9Sstevel@tonic-gate
29097c478bd9Sstevel@tonic-gate /* there is no check whether there is really an argument */
29107c478bd9Sstevel@tonic-gate map->map_mflags |= MF_KEEPQUOTES;
29117c478bd9Sstevel@tonic-gate for (;;)
29127c478bd9Sstevel@tonic-gate {
29137c478bd9Sstevel@tonic-gate while (isascii(*p) && isspace(*p))
29147c478bd9Sstevel@tonic-gate p++;
29157c478bd9Sstevel@tonic-gate if (*p != '-')
29167c478bd9Sstevel@tonic-gate break;
29177c478bd9Sstevel@tonic-gate switch (*++p)
29187c478bd9Sstevel@tonic-gate {
29197c478bd9Sstevel@tonic-gate case 'a':
29207c478bd9Sstevel@tonic-gate map->map_app = ++p;
29217c478bd9Sstevel@tonic-gate break;
29227c478bd9Sstevel@tonic-gate
29237c478bd9Sstevel@tonic-gate case 'D':
29247c478bd9Sstevel@tonic-gate map->map_mflags |= MF_DEFER;
29257c478bd9Sstevel@tonic-gate break;
29267c478bd9Sstevel@tonic-gate
29277c478bd9Sstevel@tonic-gate case 'S':
29287c478bd9Sstevel@tonic-gate case 's':
29297c478bd9Sstevel@tonic-gate map->map_spacesub = *++p;
29307c478bd9Sstevel@tonic-gate break;
29317c478bd9Sstevel@tonic-gate }
29327c478bd9Sstevel@tonic-gate while (*p != '\0' && !(isascii(*p) && isspace(*p)))
29337c478bd9Sstevel@tonic-gate p++;
29347c478bd9Sstevel@tonic-gate if (*p != '\0')
29357c478bd9Sstevel@tonic-gate *p = '\0';
29367c478bd9Sstevel@tonic-gate }
29377c478bd9Sstevel@tonic-gate if (map->map_app != NULL)
29387c478bd9Sstevel@tonic-gate map->map_app = newstr(map->map_app);
29397c478bd9Sstevel@tonic-gate
29407c478bd9Sstevel@tonic-gate return true;
29417c478bd9Sstevel@tonic-gate }
29427c478bd9Sstevel@tonic-gate /*
29437c478bd9Sstevel@tonic-gate ** DEQUOTE_MAP -- unquote an address
29447c478bd9Sstevel@tonic-gate **
29457c478bd9Sstevel@tonic-gate ** Parameters:
29467c478bd9Sstevel@tonic-gate ** map -- the internal map structure (ignored).
29477c478bd9Sstevel@tonic-gate ** name -- the name to dequote.
29487c478bd9Sstevel@tonic-gate ** av -- arguments (ignored).
29497c478bd9Sstevel@tonic-gate ** statp -- pointer to status out-parameter.
29507c478bd9Sstevel@tonic-gate **
29517c478bd9Sstevel@tonic-gate ** Returns:
29527c478bd9Sstevel@tonic-gate ** NULL -- if there were no quotes, or if the resulting
29537c478bd9Sstevel@tonic-gate ** unquoted buffer would not be acceptable to prescan.
29547c478bd9Sstevel@tonic-gate ** else -- The dequoted buffer.
29557c478bd9Sstevel@tonic-gate */
29567c478bd9Sstevel@tonic-gate
29577c478bd9Sstevel@tonic-gate /* ARGSUSED2 */
29587c478bd9Sstevel@tonic-gate char *
dequote_map(map,name,av,statp)29597c478bd9Sstevel@tonic-gate dequote_map(map, name, av, statp)
29607c478bd9Sstevel@tonic-gate MAP *map;
29617c478bd9Sstevel@tonic-gate char *name;
29627c478bd9Sstevel@tonic-gate char **av;
29637c478bd9Sstevel@tonic-gate int *statp;
29647c478bd9Sstevel@tonic-gate {
29657c478bd9Sstevel@tonic-gate register char *p;
29667c478bd9Sstevel@tonic-gate register char *q;
29677c478bd9Sstevel@tonic-gate register char c;
29687c478bd9Sstevel@tonic-gate int anglecnt = 0;
29697c478bd9Sstevel@tonic-gate int cmntcnt = 0;
29707c478bd9Sstevel@tonic-gate int quotecnt = 0;
29717c478bd9Sstevel@tonic-gate int spacecnt = 0;
29727c478bd9Sstevel@tonic-gate bool quotemode = false;
29737c478bd9Sstevel@tonic-gate bool bslashmode = false;
29747c478bd9Sstevel@tonic-gate char spacesub = map->map_spacesub;
29757c478bd9Sstevel@tonic-gate
29767c478bd9Sstevel@tonic-gate for (p = q = name; (c = *p++) != '\0'; )
29777c478bd9Sstevel@tonic-gate {
29787c478bd9Sstevel@tonic-gate if (bslashmode)
29797c478bd9Sstevel@tonic-gate {
29807c478bd9Sstevel@tonic-gate bslashmode = false;
29817c478bd9Sstevel@tonic-gate *q++ = c;
29827c478bd9Sstevel@tonic-gate continue;
29837c478bd9Sstevel@tonic-gate }
29847c478bd9Sstevel@tonic-gate
29857c478bd9Sstevel@tonic-gate if (c == ' ' && spacesub != '\0')
29867c478bd9Sstevel@tonic-gate c = spacesub;
29877c478bd9Sstevel@tonic-gate
29887c478bd9Sstevel@tonic-gate switch (c)
29897c478bd9Sstevel@tonic-gate {
29907c478bd9Sstevel@tonic-gate case '\\':
29917c478bd9Sstevel@tonic-gate bslashmode = true;
29927c478bd9Sstevel@tonic-gate break;
29937c478bd9Sstevel@tonic-gate
29947c478bd9Sstevel@tonic-gate case '(':
29957c478bd9Sstevel@tonic-gate cmntcnt++;
29967c478bd9Sstevel@tonic-gate break;
29977c478bd9Sstevel@tonic-gate
29987c478bd9Sstevel@tonic-gate case ')':
29997c478bd9Sstevel@tonic-gate if (cmntcnt-- <= 0)
30007c478bd9Sstevel@tonic-gate return NULL;
30017c478bd9Sstevel@tonic-gate break;
30027c478bd9Sstevel@tonic-gate
30037c478bd9Sstevel@tonic-gate case ' ':
30047c478bd9Sstevel@tonic-gate case '\t':
30057c478bd9Sstevel@tonic-gate spacecnt++;
30067c478bd9Sstevel@tonic-gate break;
30077c478bd9Sstevel@tonic-gate }
30087c478bd9Sstevel@tonic-gate
30097c478bd9Sstevel@tonic-gate if (cmntcnt > 0)
30107c478bd9Sstevel@tonic-gate {
30117c478bd9Sstevel@tonic-gate *q++ = c;
30127c478bd9Sstevel@tonic-gate continue;
30137c478bd9Sstevel@tonic-gate }
30147c478bd9Sstevel@tonic-gate
30157c478bd9Sstevel@tonic-gate switch (c)
30167c478bd9Sstevel@tonic-gate {
30177c478bd9Sstevel@tonic-gate case '"':
30187c478bd9Sstevel@tonic-gate quotemode = !quotemode;
30197c478bd9Sstevel@tonic-gate quotecnt++;
30207c478bd9Sstevel@tonic-gate continue;
30217c478bd9Sstevel@tonic-gate
30227c478bd9Sstevel@tonic-gate case '<':
30237c478bd9Sstevel@tonic-gate anglecnt++;
30247c478bd9Sstevel@tonic-gate break;
30257c478bd9Sstevel@tonic-gate
30267c478bd9Sstevel@tonic-gate case '>':
30277c478bd9Sstevel@tonic-gate if (anglecnt-- <= 0)
30287c478bd9Sstevel@tonic-gate return NULL;
30297c478bd9Sstevel@tonic-gate break;
30307c478bd9Sstevel@tonic-gate }
30317c478bd9Sstevel@tonic-gate *q++ = c;
30327c478bd9Sstevel@tonic-gate }
30337c478bd9Sstevel@tonic-gate
30347c478bd9Sstevel@tonic-gate if (anglecnt != 0 || cmntcnt != 0 || bslashmode ||
30357c478bd9Sstevel@tonic-gate quotemode || quotecnt <= 0 || spacecnt != 0)
30367c478bd9Sstevel@tonic-gate return NULL;
30377c478bd9Sstevel@tonic-gate *q++ = '\0';
30387c478bd9Sstevel@tonic-gate return map_rewrite(map, name, strlen(name), NULL);
30397c478bd9Sstevel@tonic-gate }
30407c478bd9Sstevel@tonic-gate /*
30417c478bd9Sstevel@tonic-gate ** RSCHECK -- check string(s) for validity using rewriting sets
30427c478bd9Sstevel@tonic-gate **
30437c478bd9Sstevel@tonic-gate ** Parameters:
30447c478bd9Sstevel@tonic-gate ** rwset -- the rewriting set to use.
30457c478bd9Sstevel@tonic-gate ** p1 -- the first string to check.
30467c478bd9Sstevel@tonic-gate ** p2 -- the second string to check -- may be null.
30477c478bd9Sstevel@tonic-gate ** e -- the current envelope.
30487c478bd9Sstevel@tonic-gate ** flags -- control some behavior, see RSF_ in sendmail.h
30497c478bd9Sstevel@tonic-gate ** logl -- logging level.
30507c478bd9Sstevel@tonic-gate ** host -- NULL or relay host.
30517c478bd9Sstevel@tonic-gate ** logid -- id for sm_syslog.
3052058561cbSjbeck ** addr -- if not NULL and ruleset returns $#error:
3053058561cbSjbeck ** store mailer triple here.
30547c478bd9Sstevel@tonic-gate **
30557c478bd9Sstevel@tonic-gate ** Returns:
30567c478bd9Sstevel@tonic-gate ** EX_OK -- if the rwset doesn't resolve to $#error
30577c478bd9Sstevel@tonic-gate ** else -- the failure status (message printed)
30587c478bd9Sstevel@tonic-gate */
30597c478bd9Sstevel@tonic-gate
30607c478bd9Sstevel@tonic-gate int
rscheck(rwset,p1,p2,e,flags,logl,host,logid,addr)3061058561cbSjbeck rscheck(rwset, p1, p2, e, flags, logl, host, logid, addr)
30627c478bd9Sstevel@tonic-gate char *rwset;
30637c478bd9Sstevel@tonic-gate char *p1;
30647c478bd9Sstevel@tonic-gate char *p2;
30657c478bd9Sstevel@tonic-gate ENVELOPE *e;
30667c478bd9Sstevel@tonic-gate int flags;
30677c478bd9Sstevel@tonic-gate int logl;
30687c478bd9Sstevel@tonic-gate char *host;
30697c478bd9Sstevel@tonic-gate char *logid;
3070058561cbSjbeck ADDRESS *addr;
30717c478bd9Sstevel@tonic-gate {
30727c478bd9Sstevel@tonic-gate char *volatile buf;
3073445f2479Sjbeck size_t bufsize;
30747c478bd9Sstevel@tonic-gate int saveexitstat;
30757c478bd9Sstevel@tonic-gate int volatile rstat = EX_OK;
30767c478bd9Sstevel@tonic-gate char **pvp;
30777c478bd9Sstevel@tonic-gate int rsno;
30787c478bd9Sstevel@tonic-gate bool volatile discard = false;
30797c478bd9Sstevel@tonic-gate bool saveQuickAbort = QuickAbort;
30807c478bd9Sstevel@tonic-gate bool saveSuprErrs = SuprErrs;
30817c478bd9Sstevel@tonic-gate bool quarantine = false;
30827c478bd9Sstevel@tonic-gate char ubuf[BUFSIZ * 2];
30837c478bd9Sstevel@tonic-gate char buf0[MAXLINE];
30847c478bd9Sstevel@tonic-gate char pvpbuf[PSBUFSIZE];
30857c478bd9Sstevel@tonic-gate extern char MsgBuf[];
30867c478bd9Sstevel@tonic-gate
30877c478bd9Sstevel@tonic-gate if (tTd(48, 2))
30887c478bd9Sstevel@tonic-gate sm_dprintf("rscheck(%s, %s, %s)\n", rwset, p1,
30897c478bd9Sstevel@tonic-gate p2 == NULL ? "(NULL)" : p2);
30907c478bd9Sstevel@tonic-gate
30917c478bd9Sstevel@tonic-gate rsno = strtorwset(rwset, NULL, ST_FIND);
30927c478bd9Sstevel@tonic-gate if (rsno < 0)
30937c478bd9Sstevel@tonic-gate return EX_OK;
30947c478bd9Sstevel@tonic-gate
30957c478bd9Sstevel@tonic-gate if (p2 != NULL)
30967c478bd9Sstevel@tonic-gate {
30977c478bd9Sstevel@tonic-gate bufsize = strlen(p1) + strlen(p2) + 2;
3098058561cbSjbeck if (bufsize > sizeof(buf0))
30997c478bd9Sstevel@tonic-gate buf = sm_malloc_x(bufsize);
31007c478bd9Sstevel@tonic-gate else
31017c478bd9Sstevel@tonic-gate {
31027c478bd9Sstevel@tonic-gate buf = buf0;
3103058561cbSjbeck bufsize = sizeof(buf0);
31047c478bd9Sstevel@tonic-gate }
31057c478bd9Sstevel@tonic-gate (void) sm_snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2);
31067c478bd9Sstevel@tonic-gate }
31077c478bd9Sstevel@tonic-gate else
31087c478bd9Sstevel@tonic-gate {
31097c478bd9Sstevel@tonic-gate bufsize = strlen(p1) + 1;
3110058561cbSjbeck if (bufsize > sizeof(buf0))
31117c478bd9Sstevel@tonic-gate buf = sm_malloc_x(bufsize);
31127c478bd9Sstevel@tonic-gate else
31137c478bd9Sstevel@tonic-gate {
31147c478bd9Sstevel@tonic-gate buf = buf0;
3115058561cbSjbeck bufsize = sizeof(buf0);
31167c478bd9Sstevel@tonic-gate }
31177c478bd9Sstevel@tonic-gate (void) sm_strlcpy(buf, p1, bufsize);
31187c478bd9Sstevel@tonic-gate }
31197c478bd9Sstevel@tonic-gate SM_TRY
31207c478bd9Sstevel@tonic-gate {
31217c478bd9Sstevel@tonic-gate SuprErrs = true;
31227c478bd9Sstevel@tonic-gate QuickAbort = false;
3123058561cbSjbeck pvp = prescan(buf, '\0', pvpbuf, sizeof(pvpbuf), NULL,
3124058561cbSjbeck bitset(RSF_RMCOMM, flags) ?
3125058561cbSjbeck IntTokenTab : TokTypeNoC,
31267c478bd9Sstevel@tonic-gate bitset(RSF_RMCOMM, flags) ? false : true);
31277c478bd9Sstevel@tonic-gate SuprErrs = saveSuprErrs;
31287c478bd9Sstevel@tonic-gate if (pvp == NULL)
31297c478bd9Sstevel@tonic-gate {
31307c478bd9Sstevel@tonic-gate if (tTd(48, 2))
31317c478bd9Sstevel@tonic-gate sm_dprintf("rscheck: cannot prescan input\n");
31327c478bd9Sstevel@tonic-gate /*
31337c478bd9Sstevel@tonic-gate syserr("rscheck: cannot prescan input: \"%s\"",
31347c478bd9Sstevel@tonic-gate shortenstring(buf, MAXSHORTSTR));
31357c478bd9Sstevel@tonic-gate rstat = EX_DATAERR;
31367c478bd9Sstevel@tonic-gate */
31377c478bd9Sstevel@tonic-gate goto finis;
31387c478bd9Sstevel@tonic-gate }
31397c478bd9Sstevel@tonic-gate if (bitset(RSF_UNSTRUCTURED, flags))
31407c478bd9Sstevel@tonic-gate SuprErrs = true;
31417c478bd9Sstevel@tonic-gate (void) REWRITE(pvp, rsno, e);
31427c478bd9Sstevel@tonic-gate if (bitset(RSF_UNSTRUCTURED, flags))
31437c478bd9Sstevel@tonic-gate SuprErrs = saveSuprErrs;
31447c478bd9Sstevel@tonic-gate if (pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET ||
31457c478bd9Sstevel@tonic-gate pvp[1] == NULL || (strcmp(pvp[1], "error") != 0 &&
31467c478bd9Sstevel@tonic-gate strcmp(pvp[1], "discard") != 0))
31477c478bd9Sstevel@tonic-gate {
31487c478bd9Sstevel@tonic-gate goto finis;
31497c478bd9Sstevel@tonic-gate }
31507c478bd9Sstevel@tonic-gate
31517c478bd9Sstevel@tonic-gate if (strcmp(pvp[1], "discard") == 0)
31527c478bd9Sstevel@tonic-gate {
31537c478bd9Sstevel@tonic-gate if (tTd(48, 2))
31547c478bd9Sstevel@tonic-gate sm_dprintf("rscheck: discard mailer selected\n");
31557c478bd9Sstevel@tonic-gate e->e_flags |= EF_DISCARD;
31567c478bd9Sstevel@tonic-gate discard = true;
31577c478bd9Sstevel@tonic-gate }
31587c478bd9Sstevel@tonic-gate else if (strcmp(pvp[1], "error") == 0 &&
31597c478bd9Sstevel@tonic-gate pvp[2] != NULL && (pvp[2][0] & 0377) == CANONHOST &&
31607c478bd9Sstevel@tonic-gate pvp[3] != NULL && strcmp(pvp[3], "quarantine") == 0)
31617c478bd9Sstevel@tonic-gate {
31627c478bd9Sstevel@tonic-gate if (pvp[4] == NULL ||
31637c478bd9Sstevel@tonic-gate (pvp[4][0] & 0377) != CANONUSER ||
31647c478bd9Sstevel@tonic-gate pvp[5] == NULL)
31657c478bd9Sstevel@tonic-gate e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool,
31667c478bd9Sstevel@tonic-gate rwset);
31677c478bd9Sstevel@tonic-gate else
31687c478bd9Sstevel@tonic-gate {
31697c478bd9Sstevel@tonic-gate cataddr(&(pvp[5]), NULL, ubuf,
3170058561cbSjbeck sizeof(ubuf), ' ', true);
31717c478bd9Sstevel@tonic-gate e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool,
31727c478bd9Sstevel@tonic-gate ubuf);
31737c478bd9Sstevel@tonic-gate }
31747c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM,
31757c478bd9Sstevel@tonic-gate macid("{quarantine}"), e->e_quarmsg);
31767c478bd9Sstevel@tonic-gate quarantine = true;
31777c478bd9Sstevel@tonic-gate }
31787c478bd9Sstevel@tonic-gate else
31797c478bd9Sstevel@tonic-gate {
3180058561cbSjbeck auto ADDRESS a1;
31817c478bd9Sstevel@tonic-gate int savelogusrerrs = LogUsrErrs;
31827c478bd9Sstevel@tonic-gate static bool logged = false;
31837c478bd9Sstevel@tonic-gate
31847c478bd9Sstevel@tonic-gate /* got an error -- process it */
31857c478bd9Sstevel@tonic-gate saveexitstat = ExitStat;
31867c478bd9Sstevel@tonic-gate LogUsrErrs = false;
31877c478bd9Sstevel@tonic-gate (void) buildaddr(pvp, &a1, 0, e);
3188058561cbSjbeck if (addr != NULL)
3189058561cbSjbeck {
3190058561cbSjbeck addr->q_mailer = a1.q_mailer;
3191058561cbSjbeck addr->q_user = a1.q_user;
3192058561cbSjbeck addr->q_host = a1.q_host;
3193058561cbSjbeck }
31947c478bd9Sstevel@tonic-gate LogUsrErrs = savelogusrerrs;
31957c478bd9Sstevel@tonic-gate rstat = ExitStat;
31967c478bd9Sstevel@tonic-gate ExitStat = saveexitstat;
31977c478bd9Sstevel@tonic-gate if (!logged)
31987c478bd9Sstevel@tonic-gate {
31997c478bd9Sstevel@tonic-gate if (bitset(RSF_COUNT, flags))
32007c478bd9Sstevel@tonic-gate markstats(e, &a1, STATS_REJECT);
32017c478bd9Sstevel@tonic-gate logged = true;
32027c478bd9Sstevel@tonic-gate }
32037c478bd9Sstevel@tonic-gate }
32047c478bd9Sstevel@tonic-gate
32057c478bd9Sstevel@tonic-gate if (LogLevel > logl)
32067c478bd9Sstevel@tonic-gate {
32077c478bd9Sstevel@tonic-gate char *relay;
32087c478bd9Sstevel@tonic-gate char *p;
32097c478bd9Sstevel@tonic-gate char lbuf[MAXLINE];
32107c478bd9Sstevel@tonic-gate
32117c478bd9Sstevel@tonic-gate p = lbuf;
32127c478bd9Sstevel@tonic-gate if (p2 != NULL)
32137c478bd9Sstevel@tonic-gate {
32147c478bd9Sstevel@tonic-gate (void) sm_snprintf(p, SPACELEFT(lbuf, p),
32157c478bd9Sstevel@tonic-gate ", arg2=%s",
32167c478bd9Sstevel@tonic-gate p2);
32177c478bd9Sstevel@tonic-gate p += strlen(p);
32187c478bd9Sstevel@tonic-gate }
32197c478bd9Sstevel@tonic-gate
32207c478bd9Sstevel@tonic-gate if (host != NULL)
32217c478bd9Sstevel@tonic-gate relay = host;
32227c478bd9Sstevel@tonic-gate else
32237c478bd9Sstevel@tonic-gate relay = macvalue('_', e);
32247c478bd9Sstevel@tonic-gate if (relay != NULL)
32257c478bd9Sstevel@tonic-gate {
32267c478bd9Sstevel@tonic-gate (void) sm_snprintf(p, SPACELEFT(lbuf, p),
32277c478bd9Sstevel@tonic-gate ", relay=%s", relay);
32287c478bd9Sstevel@tonic-gate p += strlen(p);
32297c478bd9Sstevel@tonic-gate }
32307c478bd9Sstevel@tonic-gate *p = '\0';
32317c478bd9Sstevel@tonic-gate if (discard)
32327c478bd9Sstevel@tonic-gate sm_syslog(LOG_NOTICE, logid,
32337c478bd9Sstevel@tonic-gate "ruleset=%s, arg1=%s%s, discard",
32347c478bd9Sstevel@tonic-gate rwset, p1, lbuf);
32357c478bd9Sstevel@tonic-gate else if (quarantine)
32367c478bd9Sstevel@tonic-gate sm_syslog(LOG_NOTICE, logid,
32377c478bd9Sstevel@tonic-gate "ruleset=%s, arg1=%s%s, quarantine=%s",
32387c478bd9Sstevel@tonic-gate rwset, p1, lbuf, ubuf);
32397c478bd9Sstevel@tonic-gate else
32407c478bd9Sstevel@tonic-gate sm_syslog(LOG_NOTICE, logid,
32417c478bd9Sstevel@tonic-gate "ruleset=%s, arg1=%s%s, reject=%s",
32427c478bd9Sstevel@tonic-gate rwset, p1, lbuf, MsgBuf);
32437c478bd9Sstevel@tonic-gate }
32447c478bd9Sstevel@tonic-gate
32457c478bd9Sstevel@tonic-gate finis: ;
32467c478bd9Sstevel@tonic-gate }
32477c478bd9Sstevel@tonic-gate SM_FINALLY
32487c478bd9Sstevel@tonic-gate {
32497c478bd9Sstevel@tonic-gate /* clean up */
32507c478bd9Sstevel@tonic-gate if (buf != buf0)
32517c478bd9Sstevel@tonic-gate sm_free(buf);
32527c478bd9Sstevel@tonic-gate QuickAbort = saveQuickAbort;
32537c478bd9Sstevel@tonic-gate }
32547c478bd9Sstevel@tonic-gate SM_END_TRY
32557c478bd9Sstevel@tonic-gate
32567c478bd9Sstevel@tonic-gate setstat(rstat);
32577c478bd9Sstevel@tonic-gate
32587c478bd9Sstevel@tonic-gate /* rulesets don't set errno */
32597c478bd9Sstevel@tonic-gate errno = 0;
32607c478bd9Sstevel@tonic-gate if (rstat != EX_OK && QuickAbort)
32617c478bd9Sstevel@tonic-gate sm_exc_raisenew_x(&EtypeQuickAbort, 2);
32627c478bd9Sstevel@tonic-gate return rstat;
32637c478bd9Sstevel@tonic-gate }
32647c478bd9Sstevel@tonic-gate /*
32657c478bd9Sstevel@tonic-gate ** RSCAP -- call rewriting set to return capabilities
32667c478bd9Sstevel@tonic-gate **
32677c478bd9Sstevel@tonic-gate ** Parameters:
32687c478bd9Sstevel@tonic-gate ** rwset -- the rewriting set to use.
32697c478bd9Sstevel@tonic-gate ** p1 -- the first string to check.
32707c478bd9Sstevel@tonic-gate ** p2 -- the second string to check -- may be null.
32717c478bd9Sstevel@tonic-gate ** e -- the current envelope.
32727c478bd9Sstevel@tonic-gate ** pvp -- pointer to token vector.
32737c478bd9Sstevel@tonic-gate ** pvpbuf -- buffer space.
32747c478bd9Sstevel@tonic-gate ** size -- size of buffer space.
32757c478bd9Sstevel@tonic-gate **
32767c478bd9Sstevel@tonic-gate ** Returns:
32777c478bd9Sstevel@tonic-gate ** EX_UNAVAILABLE -- ruleset doesn't exist.
32787c478bd9Sstevel@tonic-gate ** EX_DATAERR -- prescan() failed.
32797c478bd9Sstevel@tonic-gate ** EX_OK -- rewrite() was successful.
32807c478bd9Sstevel@tonic-gate ** else -- return status from rewrite().
32817c478bd9Sstevel@tonic-gate */
32827c478bd9Sstevel@tonic-gate
32837c478bd9Sstevel@tonic-gate int
rscap(rwset,p1,p2,e,pvp,pvpbuf,size)32847c478bd9Sstevel@tonic-gate rscap(rwset, p1, p2, e, pvp, pvpbuf, size)
32857c478bd9Sstevel@tonic-gate char *rwset;
32867c478bd9Sstevel@tonic-gate char *p1;
32877c478bd9Sstevel@tonic-gate char *p2;
32887c478bd9Sstevel@tonic-gate ENVELOPE *e;
32897c478bd9Sstevel@tonic-gate char ***pvp;
32907c478bd9Sstevel@tonic-gate char *pvpbuf;
32917c478bd9Sstevel@tonic-gate int size;
32927c478bd9Sstevel@tonic-gate {
32937c478bd9Sstevel@tonic-gate char *volatile buf;
3294445f2479Sjbeck size_t bufsize;
32957c478bd9Sstevel@tonic-gate int volatile rstat = EX_OK;
32967c478bd9Sstevel@tonic-gate int rsno;
32977c478bd9Sstevel@tonic-gate bool saveQuickAbort = QuickAbort;
32987c478bd9Sstevel@tonic-gate bool saveSuprErrs = SuprErrs;
32997c478bd9Sstevel@tonic-gate char buf0[MAXLINE];
33007c478bd9Sstevel@tonic-gate extern char MsgBuf[];
33017c478bd9Sstevel@tonic-gate
33027c478bd9Sstevel@tonic-gate if (tTd(48, 2))
33037c478bd9Sstevel@tonic-gate sm_dprintf("rscap(%s, %s, %s)\n", rwset, p1,
33047c478bd9Sstevel@tonic-gate p2 == NULL ? "(NULL)" : p2);
33057c478bd9Sstevel@tonic-gate
33063ee0e492Sjbeck SM_REQUIRE(pvp != NULL);
33077c478bd9Sstevel@tonic-gate rsno = strtorwset(rwset, NULL, ST_FIND);
33087c478bd9Sstevel@tonic-gate if (rsno < 0)
33097c478bd9Sstevel@tonic-gate return EX_UNAVAILABLE;
33107c478bd9Sstevel@tonic-gate
33117c478bd9Sstevel@tonic-gate if (p2 != NULL)
33127c478bd9Sstevel@tonic-gate {
33137c478bd9Sstevel@tonic-gate bufsize = strlen(p1) + strlen(p2) + 2;
3314058561cbSjbeck if (bufsize > sizeof(buf0))
33157c478bd9Sstevel@tonic-gate buf = sm_malloc_x(bufsize);
33167c478bd9Sstevel@tonic-gate else
33177c478bd9Sstevel@tonic-gate {
33187c478bd9Sstevel@tonic-gate buf = buf0;
3319058561cbSjbeck bufsize = sizeof(buf0);
33207c478bd9Sstevel@tonic-gate }
33217c478bd9Sstevel@tonic-gate (void) sm_snprintf(buf, bufsize, "%s%c%s", p1, CONDELSE, p2);
33227c478bd9Sstevel@tonic-gate }
33237c478bd9Sstevel@tonic-gate else
33247c478bd9Sstevel@tonic-gate {
33257c478bd9Sstevel@tonic-gate bufsize = strlen(p1) + 1;
3326058561cbSjbeck if (bufsize > sizeof(buf0))
33277c478bd9Sstevel@tonic-gate buf = sm_malloc_x(bufsize);
33287c478bd9Sstevel@tonic-gate else
33297c478bd9Sstevel@tonic-gate {
33307c478bd9Sstevel@tonic-gate buf = buf0;
3331058561cbSjbeck bufsize = sizeof(buf0);
33327c478bd9Sstevel@tonic-gate }
33337c478bd9Sstevel@tonic-gate (void) sm_strlcpy(buf, p1, bufsize);
33347c478bd9Sstevel@tonic-gate }
33357c478bd9Sstevel@tonic-gate SM_TRY
33367c478bd9Sstevel@tonic-gate {
33377c478bd9Sstevel@tonic-gate SuprErrs = true;
33387c478bd9Sstevel@tonic-gate QuickAbort = false;
3339058561cbSjbeck *pvp = prescan(buf, '\0', pvpbuf, size, NULL, IntTokenTab,
3340058561cbSjbeck false);
33417c478bd9Sstevel@tonic-gate if (*pvp != NULL)
33427c478bd9Sstevel@tonic-gate rstat = rewrite(*pvp, rsno, 0, e, size);
33437c478bd9Sstevel@tonic-gate else
33447c478bd9Sstevel@tonic-gate {
33457c478bd9Sstevel@tonic-gate if (tTd(48, 2))
33467c478bd9Sstevel@tonic-gate sm_dprintf("rscap: cannot prescan input\n");
33477c478bd9Sstevel@tonic-gate rstat = EX_DATAERR;
33487c478bd9Sstevel@tonic-gate }
33497c478bd9Sstevel@tonic-gate }
33507c478bd9Sstevel@tonic-gate SM_FINALLY
33517c478bd9Sstevel@tonic-gate {
33527c478bd9Sstevel@tonic-gate /* clean up */
33537c478bd9Sstevel@tonic-gate if (buf != buf0)
33547c478bd9Sstevel@tonic-gate sm_free(buf);
33557c478bd9Sstevel@tonic-gate SuprErrs = saveSuprErrs;
33567c478bd9Sstevel@tonic-gate QuickAbort = saveQuickAbort;
33577c478bd9Sstevel@tonic-gate
33587c478bd9Sstevel@tonic-gate /* prevent information leak, this may contain rewrite error */
33597c478bd9Sstevel@tonic-gate MsgBuf[0] = '\0';
33607c478bd9Sstevel@tonic-gate }
33617c478bd9Sstevel@tonic-gate SM_END_TRY
33627c478bd9Sstevel@tonic-gate return rstat;
33637c478bd9Sstevel@tonic-gate }
3364