xref: /illumos-gate/usr/src/cmd/sendmail/src/parseaddr.c (revision 2a8bcb4efb45d99ac41c94a75c396b362c414f7f)
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