xref: /illumos-gate/usr/src/cmd/sendmail/src/milter.c (revision e9af4bc0)
17c478bd9Sstevel@tonic-gate /*
2*e9af4bc0SJohn Beck  * Copyright (c) 1999-2009 Sendmail, Inc. and its suppliers.
37c478bd9Sstevel@tonic-gate  *	All rights reserved.
47c478bd9Sstevel@tonic-gate  *
57c478bd9Sstevel@tonic-gate  * By using this file, you agree to the terms and conditions set
67c478bd9Sstevel@tonic-gate  * forth in the LICENSE file which can be found at the top level of
77c478bd9Sstevel@tonic-gate  * the sendmail distribution.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  */
107c478bd9Sstevel@tonic-gate 
117c478bd9Sstevel@tonic-gate #include <sendmail.h>
127c478bd9Sstevel@tonic-gate 
13*e9af4bc0SJohn Beck SM_RCSID("@(#)$Id: milter.c,v 8.277 2009/11/06 00:57:06 ca Exp $")
147c478bd9Sstevel@tonic-gate 
157c478bd9Sstevel@tonic-gate #if MILTER
16058561cbSjbeck # include <sm/sendmail.h>
177c478bd9Sstevel@tonic-gate # include <libmilter/mfapi.h>
187c478bd9Sstevel@tonic-gate # include <libmilter/mfdef.h>
197c478bd9Sstevel@tonic-gate 
207c478bd9Sstevel@tonic-gate # include <errno.h>
2149218d4fSjbeck # include <sm/time.h>
227c478bd9Sstevel@tonic-gate # include <sys/uio.h>
237c478bd9Sstevel@tonic-gate 
247c478bd9Sstevel@tonic-gate # if NETINET || NETINET6
257c478bd9Sstevel@tonic-gate #  include <arpa/inet.h>
26058561cbSjbeck #  if MILTER_NO_NAGLE
277c478bd9Sstevel@tonic-gate #   include <netinet/tcp.h>
28058561cbSjbeck #  endif /* MILTER_NO_NAGLE */
297c478bd9Sstevel@tonic-gate # endif /* NETINET || NETINET6 */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate # include <sm/fdset.h>
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate static void	milter_connect_timeout __P((int));
347c478bd9Sstevel@tonic-gate static void	milter_error __P((struct milter *, ENVELOPE *));
357c478bd9Sstevel@tonic-gate static int	milter_open __P((struct milter *, bool, ENVELOPE *));
367c478bd9Sstevel@tonic-gate static void	milter_parse_timeouts __P((char *, struct milter *));
37058561cbSjbeck static char	*milter_sysread __P((struct milter *, char *, ssize_t, time_t,
38058561cbSjbeck 			ENVELOPE *, const char *));
39058561cbSjbeck static char	*milter_read __P((struct milter *, char *, ssize_t *, time_t,
40058561cbSjbeck 			ENVELOPE *, const char *));
41058561cbSjbeck static char	*milter_write __P((struct milter *, int, char *, ssize_t,
42058561cbSjbeck 			time_t, ENVELOPE *, const char *));
43058561cbSjbeck static char	*milter_send_command __P((struct milter *, int, void *,
44058561cbSjbeck 			ssize_t, ENVELOPE *, char *, const char *));
45058561cbSjbeck static char	*milter_command __P((int, void *, ssize_t, char **,
46058561cbSjbeck 			ENVELOPE *, char *, const char *, bool));
47058561cbSjbeck static char	*milter_body __P((struct milter *, ENVELOPE *, char *));
48058561cbSjbeck static int	milter_reopen_df __P((ENVELOPE *));
49058561cbSjbeck static int	milter_reset_df __P((ENVELOPE *));
50058561cbSjbeck static void	milter_quit_filter __P((struct milter *, ENVELOPE *));
51058561cbSjbeck static void	milter_abort_filter __P((struct milter *, ENVELOPE *));
52058561cbSjbeck static void	milter_send_macros __P((struct milter *, char **, int,
53058561cbSjbeck 			ENVELOPE *));
547800901eSjbeck static int	milter_negotiate __P((struct milter *, ENVELOPE *,
557800901eSjbeck 			milters_T *));
56058561cbSjbeck static void	milter_per_connection_check __P((ENVELOPE *));
57058561cbSjbeck static char	*milter_headers __P((struct milter *, ENVELOPE *, char *));
58058561cbSjbeck static void	milter_addheader __P((struct milter *, char *, ssize_t,
59058561cbSjbeck 			ENVELOPE *));
60058561cbSjbeck static void	milter_insheader __P((struct milter *, char *, ssize_t,
61058561cbSjbeck 			ENVELOPE *));
62058561cbSjbeck static void	milter_changeheader __P((struct milter *, char *, ssize_t,
63058561cbSjbeck 			ENVELOPE *));
64058561cbSjbeck static void	milter_chgfrom __P((char *, ssize_t, ENVELOPE *));
65058561cbSjbeck static void	milter_addrcpt __P((char *, ssize_t, ENVELOPE *));
66058561cbSjbeck static void	milter_addrcpt_par __P((char *, ssize_t, ENVELOPE *));
67058561cbSjbeck static void	milter_delrcpt __P((char *, ssize_t, ENVELOPE *));
68058561cbSjbeck static int	milter_replbody __P((char *, ssize_t, bool, ENVELOPE *));
69058561cbSjbeck static int	milter_set_macros __P((char *, char **, char *, int));
70058561cbSjbeck 
71058561cbSjbeck 
72058561cbSjbeck /* milter states */
73058561cbSjbeck # define SMFS_CLOSED		'C'	/* closed for all further actions */
74058561cbSjbeck # define SMFS_OPEN		'O'	/* connected to remote milter filter */
75058561cbSjbeck # define SMFS_INMSG		'M'	/* currently servicing a message */
76058561cbSjbeck # define SMFS_DONE		'D'	/* done with current message */
77058561cbSjbeck # define SMFS_CLOSABLE		'Q'	/* done with current connection */
78058561cbSjbeck # define SMFS_ERROR		'E'	/* error state */
79058561cbSjbeck # define SMFS_READY		'R'	/* ready for action */
80058561cbSjbeck # define SMFS_SKIP		'S'	/* skip body */
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate static char *MilterConnectMacros[MAXFILTERMACROS + 1];
837c478bd9Sstevel@tonic-gate static char *MilterHeloMacros[MAXFILTERMACROS + 1];
847c478bd9Sstevel@tonic-gate static char *MilterEnvFromMacros[MAXFILTERMACROS + 1];
857c478bd9Sstevel@tonic-gate static char *MilterEnvRcptMacros[MAXFILTERMACROS + 1];
867c478bd9Sstevel@tonic-gate static char *MilterDataMacros[MAXFILTERMACROS + 1];
877c478bd9Sstevel@tonic-gate static char *MilterEOMMacros[MAXFILTERMACROS + 1];
88058561cbSjbeck static char *MilterEOHMacros[MAXFILTERMACROS + 1];
897c478bd9Sstevel@tonic-gate static size_t MilterMaxDataSize = MILTER_MAX_DATA_SIZE;
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate # define MILTER_CHECK_DONE_MSG() \
927c478bd9Sstevel@tonic-gate 	if (*state == SMFIR_REPLYCODE || \
937c478bd9Sstevel@tonic-gate 	    *state == SMFIR_REJECT || \
947c478bd9Sstevel@tonic-gate 	    *state == SMFIR_DISCARD || \
957c478bd9Sstevel@tonic-gate 	    *state == SMFIR_TEMPFAIL) \
967c478bd9Sstevel@tonic-gate 	{ \
977c478bd9Sstevel@tonic-gate 		/* Abort the filters to let them know we are done with msg */ \
987c478bd9Sstevel@tonic-gate 		milter_abort(e); \
997c478bd9Sstevel@tonic-gate 	}
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate # define MILTER_CHECK_ERROR(initial, action) \
1027c478bd9Sstevel@tonic-gate 	if (!initial && tTd(71, 100)) \
1037c478bd9Sstevel@tonic-gate 	{ \
1047c478bd9Sstevel@tonic-gate 		if (e->e_quarmsg == NULL) \
1057c478bd9Sstevel@tonic-gate 		{ \
1067c478bd9Sstevel@tonic-gate 			e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, \
1077c478bd9Sstevel@tonic-gate 							 "filter failure"); \
1087c478bd9Sstevel@tonic-gate 			macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), \
1097c478bd9Sstevel@tonic-gate 				  e->e_quarmsg); \
1107c478bd9Sstevel@tonic-gate 		} \
1117c478bd9Sstevel@tonic-gate 	} \
1127c478bd9Sstevel@tonic-gate 	else if (tTd(71, 101)) \
1137c478bd9Sstevel@tonic-gate 	{ \
1147c478bd9Sstevel@tonic-gate 		if (e->e_quarmsg == NULL) \
1157c478bd9Sstevel@tonic-gate 		{ \
1167c478bd9Sstevel@tonic-gate 			e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, \
1177c478bd9Sstevel@tonic-gate 							 "filter failure"); \
1187c478bd9Sstevel@tonic-gate 			macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), \
1197c478bd9Sstevel@tonic-gate 				  e->e_quarmsg); \
1207c478bd9Sstevel@tonic-gate 		} \
1217c478bd9Sstevel@tonic-gate 	} \
1227c478bd9Sstevel@tonic-gate 	else if (bitnset(SMF_TEMPFAIL, m->mf_flags)) \
1237c478bd9Sstevel@tonic-gate 		*state = SMFIR_TEMPFAIL; \
1247c478bd9Sstevel@tonic-gate 	else if (bitnset(SMF_TEMPDROP, m->mf_flags)) \
1257c478bd9Sstevel@tonic-gate 		*state = SMFIR_SHUTDOWN; \
1267c478bd9Sstevel@tonic-gate 	else if (bitnset(SMF_REJECT, m->mf_flags)) \
1277c478bd9Sstevel@tonic-gate 		*state = SMFIR_REJECT; \
1287c478bd9Sstevel@tonic-gate 	else \
1297c478bd9Sstevel@tonic-gate 		action;
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate # define MILTER_CHECK_REPLYCODE(default) \
1327c478bd9Sstevel@tonic-gate 	if (response == NULL || \
1337c478bd9Sstevel@tonic-gate 	    strlen(response) + 1 != (size_t) rlen || \
1347c478bd9Sstevel@tonic-gate 	    rlen < 3 || \
1357c478bd9Sstevel@tonic-gate 	    (response[0] != '4' && response[0] != '5') || \
1367c478bd9Sstevel@tonic-gate 	    !isascii(response[1]) || !isdigit(response[1]) || \
1377c478bd9Sstevel@tonic-gate 	    !isascii(response[2]) || !isdigit(response[2])) \
1387c478bd9Sstevel@tonic-gate 	{ \
1397c478bd9Sstevel@tonic-gate 		if (response != NULL) \
1407c478bd9Sstevel@tonic-gate 			sm_free(response); /* XXX */ \
1417c478bd9Sstevel@tonic-gate 		response = newstr(default); \
1427c478bd9Sstevel@tonic-gate 	} \
1437c478bd9Sstevel@tonic-gate 	else \
1447c478bd9Sstevel@tonic-gate 	{ \
1457c478bd9Sstevel@tonic-gate 		char *ptr = response; \
1467c478bd9Sstevel@tonic-gate  \
1477c478bd9Sstevel@tonic-gate 		/* Check for unprotected %'s in the string */ \
1487c478bd9Sstevel@tonic-gate 		while (*ptr != '\0') \
1497c478bd9Sstevel@tonic-gate 		{ \
1507c478bd9Sstevel@tonic-gate 			if (*ptr == '%' && *++ptr != '%') \
1517c478bd9Sstevel@tonic-gate 			{ \
1527c478bd9Sstevel@tonic-gate 				sm_free(response); /* XXX */ \
1537c478bd9Sstevel@tonic-gate 				response = newstr(default); \
1547c478bd9Sstevel@tonic-gate 				break; \
1557c478bd9Sstevel@tonic-gate 			} \
1567c478bd9Sstevel@tonic-gate 			ptr++; \
1577c478bd9Sstevel@tonic-gate 		} \
1587c478bd9Sstevel@tonic-gate 	}
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate # define MILTER_DF_ERROR(msg) \
1617c478bd9Sstevel@tonic-gate { \
1627c478bd9Sstevel@tonic-gate 	int save_errno = errno; \
1637c478bd9Sstevel@tonic-gate  \
1647c478bd9Sstevel@tonic-gate 	if (tTd(64, 5)) \
1657c478bd9Sstevel@tonic-gate 	{ \
1667c478bd9Sstevel@tonic-gate 		sm_dprintf(msg, dfname, sm_errstring(save_errno)); \
1677c478bd9Sstevel@tonic-gate 		sm_dprintf("\n"); \
1687c478bd9Sstevel@tonic-gate 	} \
1697c478bd9Sstevel@tonic-gate 	if (MilterLogLevel > 0) \
1707c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_ERR, e->e_id, msg, dfname, sm_errstring(save_errno)); \
1717c478bd9Sstevel@tonic-gate 	if (SuperSafe == SAFE_REALLY) \
1727c478bd9Sstevel@tonic-gate 	{ \
1737c478bd9Sstevel@tonic-gate 		if (e->e_dfp != NULL) \
1747c478bd9Sstevel@tonic-gate 		{ \
1757c478bd9Sstevel@tonic-gate 			(void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT); \
1767c478bd9Sstevel@tonic-gate 			e->e_dfp = NULL; \
1777c478bd9Sstevel@tonic-gate 		} \
1787c478bd9Sstevel@tonic-gate 		e->e_flags &= ~EF_HAS_DF; \
1797c478bd9Sstevel@tonic-gate 	} \
1807c478bd9Sstevel@tonic-gate 	errno = save_errno; \
1817c478bd9Sstevel@tonic-gate }
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate /*
1847c478bd9Sstevel@tonic-gate **  MILTER_TIMEOUT -- make sure socket is ready in time
1857c478bd9Sstevel@tonic-gate **
1867c478bd9Sstevel@tonic-gate **	Parameters:
1877c478bd9Sstevel@tonic-gate **		routine -- routine name for debug/logging
1887c478bd9Sstevel@tonic-gate **		secs -- number of seconds in timeout
1897c478bd9Sstevel@tonic-gate **		write -- waiting to read or write?
1907c478bd9Sstevel@tonic-gate **		started -- whether this is part of a previous sequence
1917c478bd9Sstevel@tonic-gate **
1927c478bd9Sstevel@tonic-gate **	Assumes 'm' is a milter structure for the current socket.
1937c478bd9Sstevel@tonic-gate */
1947c478bd9Sstevel@tonic-gate 
195058561cbSjbeck # define MILTER_TIMEOUT(routine, secs, write, started, function) \
1967c478bd9Sstevel@tonic-gate { \
1977c478bd9Sstevel@tonic-gate 	int ret; \
1987c478bd9Sstevel@tonic-gate 	int save_errno; \
1997c478bd9Sstevel@tonic-gate 	fd_set fds; \
2007c478bd9Sstevel@tonic-gate 	struct timeval tv; \
2017c478bd9Sstevel@tonic-gate  \
2027c478bd9Sstevel@tonic-gate 	if (SM_FD_SETSIZE > 0 && m->mf_sock >= SM_FD_SETSIZE) \
2037c478bd9Sstevel@tonic-gate 	{ \
2047c478bd9Sstevel@tonic-gate 		if (tTd(64, 5)) \
2057c478bd9Sstevel@tonic-gate 			sm_dprintf("milter_%s(%s): socket %d is larger than FD_SETSIZE %d\n", \
2067c478bd9Sstevel@tonic-gate 				   (routine), m->mf_name, m->mf_sock, \
2077c478bd9Sstevel@tonic-gate 				   SM_FD_SETSIZE); \
2087c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 0) \
2097c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_ERR, e->e_id, \
2107c478bd9Sstevel@tonic-gate 				  "Milter (%s): socket(%s) %d is larger than FD_SETSIZE %d", \
2117c478bd9Sstevel@tonic-gate 				  m->mf_name, (routine), m->mf_sock, \
2127c478bd9Sstevel@tonic-gate 				  SM_FD_SETSIZE); \
2137c478bd9Sstevel@tonic-gate 		milter_error(m, e); \
2147c478bd9Sstevel@tonic-gate 		return NULL; \
2157c478bd9Sstevel@tonic-gate 	} \
2167c478bd9Sstevel@tonic-gate  \
2177c478bd9Sstevel@tonic-gate 	do \
2187c478bd9Sstevel@tonic-gate 	{ \
2197c478bd9Sstevel@tonic-gate 		FD_ZERO(&fds); \
2207c478bd9Sstevel@tonic-gate 		SM_FD_SET(m->mf_sock, &fds); \
2217c478bd9Sstevel@tonic-gate 		tv.tv_sec = (secs); \
2227c478bd9Sstevel@tonic-gate 		tv.tv_usec = 0; \
2237c478bd9Sstevel@tonic-gate 		ret = select(m->mf_sock + 1, \
2247c478bd9Sstevel@tonic-gate 			     (write) ? NULL : &fds, \
2257c478bd9Sstevel@tonic-gate 			     (write) ? &fds : NULL, \
2267c478bd9Sstevel@tonic-gate 			     NULL, &tv); \
2277c478bd9Sstevel@tonic-gate 	} while (ret < 0 && errno == EINTR); \
2287c478bd9Sstevel@tonic-gate  \
2297c478bd9Sstevel@tonic-gate 	switch (ret) \
2307c478bd9Sstevel@tonic-gate 	{ \
2317c478bd9Sstevel@tonic-gate 	  case 0: \
2327c478bd9Sstevel@tonic-gate 		if (tTd(64, 5)) \
233058561cbSjbeck 			sm_dprintf("milter_%s(%s): timeout, where=%s\n", \
234058561cbSjbeck 				(routine), m->mf_name, (function)); \
2357c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 0) \
2367c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_ERR, e->e_id, \
237058561cbSjbeck 				  "Milter (%s): timeout %s data %s, where=%s", \
238058561cbSjbeck 				  m->mf_name, \
2397c478bd9Sstevel@tonic-gate 				  started ? "during" : "before", \
240058561cbSjbeck 				  (routine), (function)); \
2417c478bd9Sstevel@tonic-gate 		milter_error(m, e); \
2427c478bd9Sstevel@tonic-gate 		return NULL; \
2437c478bd9Sstevel@tonic-gate  \
2447c478bd9Sstevel@tonic-gate 	  case -1: \
2457c478bd9Sstevel@tonic-gate 		save_errno = errno; \
2467c478bd9Sstevel@tonic-gate 		if (tTd(64, 5)) \
2477c478bd9Sstevel@tonic-gate 			sm_dprintf("milter_%s(%s): select: %s\n", (routine), \
2487c478bd9Sstevel@tonic-gate 				   m->mf_name, sm_errstring(save_errno)); \
2497c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 0) \
2507c478bd9Sstevel@tonic-gate 		{ \
2517c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_ERR, e->e_id, \
2527c478bd9Sstevel@tonic-gate 				  "Milter (%s): select(%s): %s", \
2537c478bd9Sstevel@tonic-gate 				  m->mf_name, (routine), \
2547c478bd9Sstevel@tonic-gate 				  sm_errstring(save_errno)); \
2557c478bd9Sstevel@tonic-gate 		} \
2567c478bd9Sstevel@tonic-gate 		milter_error(m, e); \
2577c478bd9Sstevel@tonic-gate 		return NULL; \
2587c478bd9Sstevel@tonic-gate  \
2597c478bd9Sstevel@tonic-gate 	  default: \
2607c478bd9Sstevel@tonic-gate 		if (SM_FD_ISSET(m->mf_sock, &fds)) \
2617c478bd9Sstevel@tonic-gate 			break; \
2627c478bd9Sstevel@tonic-gate 		if (tTd(64, 5)) \
2637c478bd9Sstevel@tonic-gate 			sm_dprintf("milter_%s(%s): socket not ready\n", \
2647c478bd9Sstevel@tonic-gate 				(routine), m->mf_name); \
2657c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 0) \
2667c478bd9Sstevel@tonic-gate 		{ \
2677c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_ERR, e->e_id, \
2687c478bd9Sstevel@tonic-gate 				  "Milter (%s): socket(%s) not ready", \
2697c478bd9Sstevel@tonic-gate 				  m->mf_name, (routine)); \
2707c478bd9Sstevel@tonic-gate 		} \
2717c478bd9Sstevel@tonic-gate 		milter_error(m, e); \
2727c478bd9Sstevel@tonic-gate 		return NULL; \
2737c478bd9Sstevel@tonic-gate 	} \
2747c478bd9Sstevel@tonic-gate }
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate /*
2777c478bd9Sstevel@tonic-gate **  Low level functions
2787c478bd9Sstevel@tonic-gate */
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate /*
2817c478bd9Sstevel@tonic-gate **  MILTER_READ -- read from a remote milter filter
2827c478bd9Sstevel@tonic-gate **
2837c478bd9Sstevel@tonic-gate **	Parameters:
2847c478bd9Sstevel@tonic-gate **		m -- milter to read from.
2857c478bd9Sstevel@tonic-gate **		cmd -- return param for command read.
2867c478bd9Sstevel@tonic-gate **		rlen -- return length of response string.
2877c478bd9Sstevel@tonic-gate **		to -- timeout in seconds.
2887c478bd9Sstevel@tonic-gate **		e -- current envelope.
2897c478bd9Sstevel@tonic-gate **
2907c478bd9Sstevel@tonic-gate **	Returns:
2917c478bd9Sstevel@tonic-gate **		response string (may be NULL)
2927c478bd9Sstevel@tonic-gate */
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate static char *
milter_sysread(m,buf,sz,to,e,where)295058561cbSjbeck milter_sysread(m, buf, sz, to, e, where)
2967c478bd9Sstevel@tonic-gate 	struct milter *m;
2977c478bd9Sstevel@tonic-gate 	char *buf;
2987c478bd9Sstevel@tonic-gate 	ssize_t sz;
2997c478bd9Sstevel@tonic-gate 	time_t to;
3007c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
301058561cbSjbeck 	const char *where;
3027c478bd9Sstevel@tonic-gate {
3037c478bd9Sstevel@tonic-gate 	time_t readstart = 0;
3047c478bd9Sstevel@tonic-gate 	ssize_t len, curl;
3057c478bd9Sstevel@tonic-gate 	bool started = false;
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	curl = 0;
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	if (to > 0)
3107c478bd9Sstevel@tonic-gate 		readstart = curtime();
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	for (;;)
3137c478bd9Sstevel@tonic-gate 	{
3147c478bd9Sstevel@tonic-gate 		if (to > 0)
3157c478bd9Sstevel@tonic-gate 		{
3167c478bd9Sstevel@tonic-gate 			time_t now;
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 			now = curtime();
3197c478bd9Sstevel@tonic-gate 			if (now - readstart >= to)
3207c478bd9Sstevel@tonic-gate 			{
3217c478bd9Sstevel@tonic-gate 				if (tTd(64, 5))
322058561cbSjbeck 					sm_dprintf("milter_sys_read (%s): timeout %s data read in %s",
323058561cbSjbeck 						  m->mf_name,
3247c478bd9Sstevel@tonic-gate 						  started ? "during" : "before",
325058561cbSjbeck 						  where);
3267c478bd9Sstevel@tonic-gate 				if (MilterLogLevel > 0)
3277c478bd9Sstevel@tonic-gate 					sm_syslog(LOG_ERR, e->e_id,
328058561cbSjbeck 						  "Milter (%s): timeout %s data read in %s",
329058561cbSjbeck 						  m->mf_name,
3307c478bd9Sstevel@tonic-gate 						  started ? "during" : "before",
331058561cbSjbeck 						  where);
3327c478bd9Sstevel@tonic-gate 				milter_error(m, e);
3337c478bd9Sstevel@tonic-gate 				return NULL;
3347c478bd9Sstevel@tonic-gate 			}
3357c478bd9Sstevel@tonic-gate 			to -= now - readstart;
3367c478bd9Sstevel@tonic-gate 			readstart = now;
337058561cbSjbeck 			MILTER_TIMEOUT("read", to, false, started, where);
3387c478bd9Sstevel@tonic-gate 		}
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 		len = read(m->mf_sock, buf + curl, sz - curl);
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 		if (len < 0)
3437c478bd9Sstevel@tonic-gate 		{
3447c478bd9Sstevel@tonic-gate 			int save_errno = errno;
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 			if (tTd(64, 5))
347058561cbSjbeck 				sm_dprintf("milter_sys_read(%s): read returned %ld: %s\n",
3487c478bd9Sstevel@tonic-gate 					m->mf_name, (long) len,
3497c478bd9Sstevel@tonic-gate 					sm_errstring(save_errno));
3507c478bd9Sstevel@tonic-gate 			if (MilterLogLevel > 0)
3517c478bd9Sstevel@tonic-gate 				sm_syslog(LOG_ERR, e->e_id,
3527c478bd9Sstevel@tonic-gate 					  "Milter (%s): read returned %ld: %s",
3537c478bd9Sstevel@tonic-gate 					  m->mf_name, (long) len,
3547c478bd9Sstevel@tonic-gate 					  sm_errstring(save_errno));
3557c478bd9Sstevel@tonic-gate 			milter_error(m, e);
3567c478bd9Sstevel@tonic-gate 			return NULL;
3577c478bd9Sstevel@tonic-gate 		}
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 		started = true;
3607c478bd9Sstevel@tonic-gate 		curl += len;
3617c478bd9Sstevel@tonic-gate 		if (len == 0 || curl >= sz)
3627c478bd9Sstevel@tonic-gate 			break;
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	}
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 	if (curl != sz)
3677c478bd9Sstevel@tonic-gate 	{
3687c478bd9Sstevel@tonic-gate 		if (tTd(64, 5))
369058561cbSjbeck 			sm_dprintf("milter_sys_read(%s): cmd read returned %ld, expecting %ld\n",
3707c478bd9Sstevel@tonic-gate 				m->mf_name, (long) curl, (long) sz);
3717c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 0)
3727c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_ERR, e->e_id,
373058561cbSjbeck 				  "milter_sys_read(%s): cmd read returned %ld, expecting %ld",
3747c478bd9Sstevel@tonic-gate 				  m->mf_name, (long) curl, (long) sz);
3757c478bd9Sstevel@tonic-gate 		milter_error(m, e);
3767c478bd9Sstevel@tonic-gate 		return NULL;
3777c478bd9Sstevel@tonic-gate 	}
3787c478bd9Sstevel@tonic-gate 	return buf;
3797c478bd9Sstevel@tonic-gate }
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate static char *
milter_read(m,cmd,rlen,to,e,where)382058561cbSjbeck milter_read(m, cmd, rlen, to, e, where)
3837c478bd9Sstevel@tonic-gate 	struct milter *m;
3847c478bd9Sstevel@tonic-gate 	char *cmd;
3857c478bd9Sstevel@tonic-gate 	ssize_t *rlen;
3867c478bd9Sstevel@tonic-gate 	time_t to;
3877c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
388058561cbSjbeck 	const char *where;
3897c478bd9Sstevel@tonic-gate {
3907c478bd9Sstevel@tonic-gate 	time_t readstart = 0;
3917c478bd9Sstevel@tonic-gate 	ssize_t expl;
3927c478bd9Sstevel@tonic-gate 	mi_int32 i;
393058561cbSjbeck # if MILTER_NO_NAGLE && defined(TCP_CORK)
3947c478bd9Sstevel@tonic-gate 	int cork = 0;
395058561cbSjbeck # endif /* MILTER_NO_NAGLE && defined(TCP_CORK) */
3967c478bd9Sstevel@tonic-gate 	char *buf;
3977c478bd9Sstevel@tonic-gate 	char data[MILTER_LEN_BYTES + 1];
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	if (m->mf_sock < 0)
4007c478bd9Sstevel@tonic-gate 	{
4017c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 0)
4027c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_ERR, e->e_id,
403058561cbSjbeck 				  "milter_read(%s): socket closed, where=%s",
404058561cbSjbeck 				  m->mf_name, where);
4057c478bd9Sstevel@tonic-gate 		milter_error(m, e);
4067c478bd9Sstevel@tonic-gate 		return NULL;
4077c478bd9Sstevel@tonic-gate 	}
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	*rlen = 0;
4107c478bd9Sstevel@tonic-gate 	*cmd = '\0';
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	if (to > 0)
4137c478bd9Sstevel@tonic-gate 		readstart = curtime();
4147c478bd9Sstevel@tonic-gate 
415058561cbSjbeck # if MILTER_NO_NAGLE && defined(TCP_CORK)
4167c478bd9Sstevel@tonic-gate 	setsockopt(m->mf_sock, IPPROTO_TCP, TCP_CORK, (char *)&cork,
4177c478bd9Sstevel@tonic-gate 		   sizeof(cork));
418058561cbSjbeck # endif /* MILTER_NO_NAGLE && defined(TCP_CORK) */
4197c478bd9Sstevel@tonic-gate 
420058561cbSjbeck 	if (milter_sysread(m, data, sizeof(data), to, e, where) == NULL)
4217c478bd9Sstevel@tonic-gate 		return NULL;
4227c478bd9Sstevel@tonic-gate 
423058561cbSjbeck # if MILTER_NO_NAGLE && defined(TCP_CORK)
4247c478bd9Sstevel@tonic-gate 	cork = 1;
4257c478bd9Sstevel@tonic-gate 	setsockopt(m->mf_sock, IPPROTO_TCP, TCP_CORK, (char *)&cork,
4267c478bd9Sstevel@tonic-gate 		   sizeof(cork));
427058561cbSjbeck # endif /* MILTER_NO_NAGLE && defined(TCP_CORK) */
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 	/* reset timeout */
4307c478bd9Sstevel@tonic-gate 	if (to > 0)
4317c478bd9Sstevel@tonic-gate 	{
4327c478bd9Sstevel@tonic-gate 		time_t now;
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 		now = curtime();
4357c478bd9Sstevel@tonic-gate 		if (now - readstart >= to)
4367c478bd9Sstevel@tonic-gate 		{
4377c478bd9Sstevel@tonic-gate 			if (tTd(64, 5))
438058561cbSjbeck 				sm_dprintf("milter_read(%s): timeout before data read, where=%s\n",
439058561cbSjbeck 					m->mf_name, where);
4407c478bd9Sstevel@tonic-gate 			if (MilterLogLevel > 0)
4417c478bd9Sstevel@tonic-gate 				sm_syslog(LOG_ERR, e->e_id,
442058561cbSjbeck 					  "Milter read(%s): timeout before data read, where=%s",
443058561cbSjbeck 					  m->mf_name, where);
4447c478bd9Sstevel@tonic-gate 			milter_error(m, e);
4457c478bd9Sstevel@tonic-gate 			return NULL;
4467c478bd9Sstevel@tonic-gate 		}
4477c478bd9Sstevel@tonic-gate 		to -= now - readstart;
4487c478bd9Sstevel@tonic-gate 	}
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	*cmd = data[MILTER_LEN_BYTES];
4517c478bd9Sstevel@tonic-gate 	data[MILTER_LEN_BYTES] = '\0';
4527c478bd9Sstevel@tonic-gate 	(void) memcpy(&i, data, MILTER_LEN_BYTES);
4537c478bd9Sstevel@tonic-gate 	expl = ntohl(i) - 1;
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 	if (tTd(64, 25))
4567c478bd9Sstevel@tonic-gate 		sm_dprintf("milter_read(%s): expecting %ld bytes\n",
4577c478bd9Sstevel@tonic-gate 			m->mf_name, (long) expl);
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	if (expl < 0)
4607c478bd9Sstevel@tonic-gate 	{
4617c478bd9Sstevel@tonic-gate 		if (tTd(64, 5))
462058561cbSjbeck 			sm_dprintf("milter_read(%s): read size %ld out of range, where=%s\n",
463058561cbSjbeck 				m->mf_name, (long) expl, where);
4647c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 0)
4657c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_ERR, e->e_id,
466058561cbSjbeck 				  "milter_read(%s): read size %ld out of range, where=%s",
467058561cbSjbeck 				  m->mf_name, (long) expl, where);
4687c478bd9Sstevel@tonic-gate 		milter_error(m, e);
4697c478bd9Sstevel@tonic-gate 		return NULL;
4707c478bd9Sstevel@tonic-gate 	}
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 	if (expl == 0)
4737c478bd9Sstevel@tonic-gate 		return NULL;
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 	buf = (char *) xalloc(expl);
4767c478bd9Sstevel@tonic-gate 
477058561cbSjbeck 	if (milter_sysread(m, buf, expl, to, e, where) == NULL)
4787c478bd9Sstevel@tonic-gate 	{
4797c478bd9Sstevel@tonic-gate 		sm_free(buf); /* XXX */
4807c478bd9Sstevel@tonic-gate 		return NULL;
4817c478bd9Sstevel@tonic-gate 	}
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 	if (tTd(64, 50))
4847c478bd9Sstevel@tonic-gate 		sm_dprintf("milter_read(%s): Returning %*s\n",
4857c478bd9Sstevel@tonic-gate 			m->mf_name, (int) expl, buf);
4867c478bd9Sstevel@tonic-gate 	*rlen = expl;
4877c478bd9Sstevel@tonic-gate 	return buf;
4887c478bd9Sstevel@tonic-gate }
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate /*
4917c478bd9Sstevel@tonic-gate **  MILTER_WRITE -- write to a remote milter filter
4927c478bd9Sstevel@tonic-gate **
4937c478bd9Sstevel@tonic-gate **	Parameters:
4947c478bd9Sstevel@tonic-gate **		m -- milter to read from.
4957c478bd9Sstevel@tonic-gate **		cmd -- command to send.
4967c478bd9Sstevel@tonic-gate **		buf -- optional command data.
4977c478bd9Sstevel@tonic-gate **		len -- length of buf.
4987c478bd9Sstevel@tonic-gate **		to -- timeout in seconds.
4997c478bd9Sstevel@tonic-gate **		e -- current envelope.
5007c478bd9Sstevel@tonic-gate **
5017c478bd9Sstevel@tonic-gate **	Returns:
5027c478bd9Sstevel@tonic-gate **		buf if successful, NULL otherwise
5037c478bd9Sstevel@tonic-gate **		Not actually used anywhere but function prototype
5047c478bd9Sstevel@tonic-gate **			must match milter_read()
5057c478bd9Sstevel@tonic-gate */
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate static char *
milter_write(m,cmd,buf,len,to,e,where)508058561cbSjbeck milter_write(m, cmd, buf, len, to, e, where)
5097c478bd9Sstevel@tonic-gate 	struct milter *m;
510058561cbSjbeck 	int cmd;
5117c478bd9Sstevel@tonic-gate 	char *buf;
5127c478bd9Sstevel@tonic-gate 	ssize_t len;
5137c478bd9Sstevel@tonic-gate 	time_t to;
5147c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
515058561cbSjbeck 	const char *where;
5167c478bd9Sstevel@tonic-gate {
5177c478bd9Sstevel@tonic-gate 	ssize_t sl, i;
5187c478bd9Sstevel@tonic-gate 	int num_vectors;
5197c478bd9Sstevel@tonic-gate 	mi_int32 nl;
520058561cbSjbeck 	char command = (char) cmd;
5217c478bd9Sstevel@tonic-gate 	char data[MILTER_LEN_BYTES + 1];
5227c478bd9Sstevel@tonic-gate 	bool started = false;
5237c478bd9Sstevel@tonic-gate 	struct iovec vector[2];
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 	/*
5267c478bd9Sstevel@tonic-gate 	**  At most two buffers will be written, though
5277c478bd9Sstevel@tonic-gate 	**  only one may actually be used (see num_vectors).
5287c478bd9Sstevel@tonic-gate 	**  The first is the size/command and the second is the command data.
5297c478bd9Sstevel@tonic-gate 	*/
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 	if (len < 0 || len > MilterMaxDataSize)
5327c478bd9Sstevel@tonic-gate 	{
5337c478bd9Sstevel@tonic-gate 		if (tTd(64, 5))
534*e9af4bc0SJohn Beck 		{
535*e9af4bc0SJohn Beck 			sm_dprintf("milter_write(%s): length %ld out of range, cmd=%c\n",
536*e9af4bc0SJohn Beck 				m->mf_name, (long) len, command);
537*e9af4bc0SJohn Beck 			sm_dprintf("milter_write(%s): buf=%s\n",
538*e9af4bc0SJohn Beck 				m->mf_name, str2prt(buf));
539*e9af4bc0SJohn Beck 		}
5407c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 0)
5417c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_ERR, e->e_id,
542*e9af4bc0SJohn Beck 				  "milter_write(%s): length %ld out of range, cmd=%c",
543*e9af4bc0SJohn Beck 				  m->mf_name, (long) len, command);
5447c478bd9Sstevel@tonic-gate 		milter_error(m, e);
5457c478bd9Sstevel@tonic-gate 		return NULL;
5467c478bd9Sstevel@tonic-gate 	}
5477c478bd9Sstevel@tonic-gate 	if (m->mf_sock < 0)
5487c478bd9Sstevel@tonic-gate 	{
5497c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 0)
5507c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_ERR, e->e_id,
5517c478bd9Sstevel@tonic-gate 				  "milter_write(%s): socket closed",
5527c478bd9Sstevel@tonic-gate 				  m->mf_name);
5537c478bd9Sstevel@tonic-gate 		milter_error(m, e);
5547c478bd9Sstevel@tonic-gate 		return NULL;
5557c478bd9Sstevel@tonic-gate 	}
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 	if (tTd(64, 20))
5587c478bd9Sstevel@tonic-gate 		sm_dprintf("milter_write(%s): cmd %c, len %ld\n",
559058561cbSjbeck 			   m->mf_name, command, (long) len);
5607c478bd9Sstevel@tonic-gate 
561058561cbSjbeck 	nl = htonl(len + 1);	/* add 1 for the command char */
5627c478bd9Sstevel@tonic-gate 	(void) memcpy(data, (char *) &nl, MILTER_LEN_BYTES);
563058561cbSjbeck 	data[MILTER_LEN_BYTES] = command;
5647c478bd9Sstevel@tonic-gate 	sl = MILTER_LEN_BYTES + 1;
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate 	/* set up the vector for the size / command */
5677c478bd9Sstevel@tonic-gate 	vector[0].iov_base = (void *) data;
5687c478bd9Sstevel@tonic-gate 	vector[0].iov_len  = sl;
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 	/*
5717c478bd9Sstevel@tonic-gate 	**  Determine if there is command data.  If so, there will be two
5727c478bd9Sstevel@tonic-gate 	**  vectors.  If not, there will be only one.  The vectors are set
5737c478bd9Sstevel@tonic-gate 	**  up here and 'num_vectors' and 'sl' are set appropriately.
5747c478bd9Sstevel@tonic-gate 	*/
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 	/* NOTE:  len<0 has already been checked for.  Pedantic */
5777c478bd9Sstevel@tonic-gate 	if (len <= 0 || buf == NULL)
5787c478bd9Sstevel@tonic-gate 	{
5797c478bd9Sstevel@tonic-gate 		/* There is no command data -- only a size / command data */
5807c478bd9Sstevel@tonic-gate 		num_vectors = 1;
5817c478bd9Sstevel@tonic-gate 	}
5827c478bd9Sstevel@tonic-gate 	else
5837c478bd9Sstevel@tonic-gate 	{
5847c478bd9Sstevel@tonic-gate 		/*
5857c478bd9Sstevel@tonic-gate 		**  There is both size / command and command data.
5867c478bd9Sstevel@tonic-gate 		**  Set up the vector for the command data.
5877c478bd9Sstevel@tonic-gate 		*/
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 		num_vectors = 2;
5907c478bd9Sstevel@tonic-gate 		sl += len;
5917c478bd9Sstevel@tonic-gate 		vector[1].iov_base = (void *) buf;
5927c478bd9Sstevel@tonic-gate 		vector[1].iov_len  = len;
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 		if (tTd(64, 50))
5957c478bd9Sstevel@tonic-gate 			sm_dprintf("milter_write(%s): Sending %*s\n",
5967c478bd9Sstevel@tonic-gate 				   m->mf_name, (int) len, buf);
5977c478bd9Sstevel@tonic-gate 	}
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate 	if (to > 0)
600058561cbSjbeck 		MILTER_TIMEOUT("write", to, true, started, where);
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 	/* write the vector(s) */
6037c478bd9Sstevel@tonic-gate 	i = writev(m->mf_sock, vector, num_vectors);
6047c478bd9Sstevel@tonic-gate 	if (i != sl)
6057c478bd9Sstevel@tonic-gate 	{
6067c478bd9Sstevel@tonic-gate 		int save_errno = errno;
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 		if (tTd(64, 5))
6097c478bd9Sstevel@tonic-gate 			sm_dprintf("milter_write(%s): write(%c) returned %ld, expected %ld: %s\n",
610058561cbSjbeck 				   m->mf_name, command, (long) i, (long) sl,
6117c478bd9Sstevel@tonic-gate 				   sm_errstring(save_errno));
6127c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 0)
6137c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_ERR, e->e_id,
6147c478bd9Sstevel@tonic-gate 				  "Milter (%s): write(%c) returned %ld, expected %ld: %s",
615058561cbSjbeck 				  m->mf_name, command, (long) i, (long) sl,
6167c478bd9Sstevel@tonic-gate 				  sm_errstring(save_errno));
6177c478bd9Sstevel@tonic-gate 		milter_error(m, e);
6187c478bd9Sstevel@tonic-gate 		return NULL;
6197c478bd9Sstevel@tonic-gate 	}
6207c478bd9Sstevel@tonic-gate 	return buf;
6217c478bd9Sstevel@tonic-gate }
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate /*
6247c478bd9Sstevel@tonic-gate **  Utility functions
6257c478bd9Sstevel@tonic-gate */
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate /*
6287c478bd9Sstevel@tonic-gate **  MILTER_OPEN -- connect to remote milter filter
6297c478bd9Sstevel@tonic-gate **
6307c478bd9Sstevel@tonic-gate **	Parameters:
6317c478bd9Sstevel@tonic-gate **		m -- milter to connect to.
6327c478bd9Sstevel@tonic-gate **		parseonly -- parse but don't connect.
6337c478bd9Sstevel@tonic-gate **		e -- current envelope.
6347c478bd9Sstevel@tonic-gate **
6357c478bd9Sstevel@tonic-gate **	Returns:
6367c478bd9Sstevel@tonic-gate **		connected socket if successful && !parseonly,
6377c478bd9Sstevel@tonic-gate **		0 upon parse success if parseonly,
6387c478bd9Sstevel@tonic-gate **		-1 otherwise.
6397c478bd9Sstevel@tonic-gate */
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate static jmp_buf	MilterConnectTimeout;
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate static int
milter_open(m,parseonly,e)6447c478bd9Sstevel@tonic-gate milter_open(m, parseonly, e)
6457c478bd9Sstevel@tonic-gate 	struct milter *m;
6467c478bd9Sstevel@tonic-gate 	bool parseonly;
6477c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
6487c478bd9Sstevel@tonic-gate {
6497c478bd9Sstevel@tonic-gate 	int sock = 0;
6507c478bd9Sstevel@tonic-gate 	SOCKADDR_LEN_T addrlen = 0;
6517c478bd9Sstevel@tonic-gate 	int addrno = 0;
6527c478bd9Sstevel@tonic-gate 	int save_errno;
6537c478bd9Sstevel@tonic-gate 	char *p;
6547c478bd9Sstevel@tonic-gate 	char *colon;
6557c478bd9Sstevel@tonic-gate 	char *at;
6567c478bd9Sstevel@tonic-gate 	struct hostent *hp = NULL;
6577c478bd9Sstevel@tonic-gate 	SOCKADDR addr;
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate 	if (m->mf_conn == NULL || m->mf_conn[0] == '\0')
6607c478bd9Sstevel@tonic-gate 	{
6617c478bd9Sstevel@tonic-gate 		if (tTd(64, 5))
6627c478bd9Sstevel@tonic-gate 			sm_dprintf("X%s: empty or missing socket information\n",
6637c478bd9Sstevel@tonic-gate 				   m->mf_name);
6647c478bd9Sstevel@tonic-gate 		if (parseonly)
6657c478bd9Sstevel@tonic-gate 			syserr("X%s: empty or missing socket information",
6667c478bd9Sstevel@tonic-gate 			       m->mf_name);
6677c478bd9Sstevel@tonic-gate 		else if (MilterLogLevel > 0)
6687c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_ERR, e->e_id,
6697c478bd9Sstevel@tonic-gate 				  "Milter (%s): empty or missing socket information",
6707c478bd9Sstevel@tonic-gate 				  m->mf_name);
6717c478bd9Sstevel@tonic-gate 		milter_error(m, e);
6727c478bd9Sstevel@tonic-gate 		return -1;
6737c478bd9Sstevel@tonic-gate 	}
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	/* protocol:filename or protocol:port@host */
676058561cbSjbeck 	memset(&addr, '\0', sizeof(addr));
6777c478bd9Sstevel@tonic-gate 	p = m->mf_conn;
6787c478bd9Sstevel@tonic-gate 	colon = strchr(p, ':');
6797c478bd9Sstevel@tonic-gate 	if (colon != NULL)
6807c478bd9Sstevel@tonic-gate 	{
6817c478bd9Sstevel@tonic-gate 		*colon = '\0';
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 		if (*p == '\0')
6847c478bd9Sstevel@tonic-gate 		{
6857c478bd9Sstevel@tonic-gate # if NETUNIX
6867c478bd9Sstevel@tonic-gate 			/* default to AF_UNIX */
6877c478bd9Sstevel@tonic-gate 			addr.sa.sa_family = AF_UNIX;
6887c478bd9Sstevel@tonic-gate # else /* NETUNIX */
6897c478bd9Sstevel@tonic-gate #  if NETINET
6907c478bd9Sstevel@tonic-gate 			/* default to AF_INET */
6917c478bd9Sstevel@tonic-gate 			addr.sa.sa_family = AF_INET;
6927c478bd9Sstevel@tonic-gate #  else /* NETINET */
6937c478bd9Sstevel@tonic-gate #   if NETINET6
6947c478bd9Sstevel@tonic-gate 			/* default to AF_INET6 */
6957c478bd9Sstevel@tonic-gate 			addr.sa.sa_family = AF_INET6;
6967c478bd9Sstevel@tonic-gate #   else /* NETINET6 */
6977c478bd9Sstevel@tonic-gate 			/* no protocols available */
6987c478bd9Sstevel@tonic-gate 			if (MilterLogLevel > 0)
6997c478bd9Sstevel@tonic-gate 				sm_syslog(LOG_ERR, e->e_id,
7007c478bd9Sstevel@tonic-gate 					  "Milter (%s): no valid socket protocols available",
7017c478bd9Sstevel@tonic-gate 					  m->mf_name);
7027c478bd9Sstevel@tonic-gate 			milter_error(m, e);
7037c478bd9Sstevel@tonic-gate 			return -1;
7047c478bd9Sstevel@tonic-gate #   endif /* NETINET6 */
7057c478bd9Sstevel@tonic-gate #  endif /* NETINET */
7067c478bd9Sstevel@tonic-gate # endif /* NETUNIX */
7077c478bd9Sstevel@tonic-gate 		}
7087c478bd9Sstevel@tonic-gate # if NETUNIX
7097c478bd9Sstevel@tonic-gate 		else if (sm_strcasecmp(p, "unix") == 0 ||
7107c478bd9Sstevel@tonic-gate 			 sm_strcasecmp(p, "local") == 0)
7117c478bd9Sstevel@tonic-gate 			addr.sa.sa_family = AF_UNIX;
7127c478bd9Sstevel@tonic-gate # endif /* NETUNIX */
7137c478bd9Sstevel@tonic-gate # if NETINET
7147c478bd9Sstevel@tonic-gate 		else if (sm_strcasecmp(p, "inet") == 0)
7157c478bd9Sstevel@tonic-gate 			addr.sa.sa_family = AF_INET;
7167c478bd9Sstevel@tonic-gate # endif /* NETINET */
7177c478bd9Sstevel@tonic-gate # if NETINET6
7187c478bd9Sstevel@tonic-gate 		else if (sm_strcasecmp(p, "inet6") == 0)
7197c478bd9Sstevel@tonic-gate 			addr.sa.sa_family = AF_INET6;
7207c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
7217c478bd9Sstevel@tonic-gate 		else
7227c478bd9Sstevel@tonic-gate 		{
7237c478bd9Sstevel@tonic-gate # ifdef EPROTONOSUPPORT
7247c478bd9Sstevel@tonic-gate 			errno = EPROTONOSUPPORT;
7257c478bd9Sstevel@tonic-gate # else /* EPROTONOSUPPORT */
7267c478bd9Sstevel@tonic-gate 			errno = EINVAL;
7277c478bd9Sstevel@tonic-gate # endif /* EPROTONOSUPPORT */
7287c478bd9Sstevel@tonic-gate 			if (tTd(64, 5))
7297c478bd9Sstevel@tonic-gate 				sm_dprintf("X%s: unknown socket type %s\n",
7307c478bd9Sstevel@tonic-gate 					m->mf_name, p);
7317c478bd9Sstevel@tonic-gate 			if (parseonly)
7327c478bd9Sstevel@tonic-gate 				syserr("X%s: unknown socket type %s",
7337c478bd9Sstevel@tonic-gate 				       m->mf_name, p);
7347c478bd9Sstevel@tonic-gate 			else if (MilterLogLevel > 0)
7357c478bd9Sstevel@tonic-gate 				sm_syslog(LOG_ERR, e->e_id,
7367c478bd9Sstevel@tonic-gate 					  "Milter (%s): unknown socket type %s",
7377c478bd9Sstevel@tonic-gate 					  m->mf_name, p);
7387c478bd9Sstevel@tonic-gate 			milter_error(m, e);
7397c478bd9Sstevel@tonic-gate 			return -1;
7407c478bd9Sstevel@tonic-gate 		}
7417c478bd9Sstevel@tonic-gate 		*colon++ = ':';
7427c478bd9Sstevel@tonic-gate 	}
7437c478bd9Sstevel@tonic-gate 	else
7447c478bd9Sstevel@tonic-gate 	{
7457c478bd9Sstevel@tonic-gate 		/* default to AF_UNIX */
7467c478bd9Sstevel@tonic-gate 		addr.sa.sa_family = AF_UNIX;
7477c478bd9Sstevel@tonic-gate 		colon = p;
7487c478bd9Sstevel@tonic-gate 	}
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate # if NETUNIX
7517c478bd9Sstevel@tonic-gate 	if (addr.sa.sa_family == AF_UNIX)
7527c478bd9Sstevel@tonic-gate 	{
7537c478bd9Sstevel@tonic-gate 		long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_EXECOK;
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 		at = colon;
756058561cbSjbeck 		if (strlen(colon) >= sizeof(addr.sunix.sun_path))
7577c478bd9Sstevel@tonic-gate 		{
7587c478bd9Sstevel@tonic-gate 			if (tTd(64, 5))
7597c478bd9Sstevel@tonic-gate 				sm_dprintf("X%s: local socket name %s too long\n",
7607c478bd9Sstevel@tonic-gate 					m->mf_name, colon);
7617c478bd9Sstevel@tonic-gate 			errno = EINVAL;
7627c478bd9Sstevel@tonic-gate 			if (parseonly)
7637c478bd9Sstevel@tonic-gate 				syserr("X%s: local socket name %s too long",
7647c478bd9Sstevel@tonic-gate 				       m->mf_name, colon);
7657c478bd9Sstevel@tonic-gate 			else if (MilterLogLevel > 0)
7667c478bd9Sstevel@tonic-gate 				sm_syslog(LOG_ERR, e->e_id,
7677c478bd9Sstevel@tonic-gate 					  "Milter (%s): local socket name %s too long",
7687c478bd9Sstevel@tonic-gate 					  m->mf_name, colon);
7697c478bd9Sstevel@tonic-gate 			milter_error(m, e);
7707c478bd9Sstevel@tonic-gate 			return -1;
7717c478bd9Sstevel@tonic-gate 		}
7727c478bd9Sstevel@tonic-gate 		errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff,
7737c478bd9Sstevel@tonic-gate 				 S_IRUSR|S_IWUSR, NULL);
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 		/* if just parsing .cf file, socket doesn't need to exist */
7767c478bd9Sstevel@tonic-gate 		if (parseonly && errno == ENOENT)
7777c478bd9Sstevel@tonic-gate 		{
7787c478bd9Sstevel@tonic-gate 			if (OpMode == MD_DAEMON ||
7797c478bd9Sstevel@tonic-gate 			    OpMode == MD_FGDAEMON)
7807c478bd9Sstevel@tonic-gate 				(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
7817c478bd9Sstevel@tonic-gate 						     "WARNING: X%s: local socket name %s missing\n",
7827c478bd9Sstevel@tonic-gate 						     m->mf_name, colon);
7837c478bd9Sstevel@tonic-gate 		}
7847c478bd9Sstevel@tonic-gate 		else if (errno != 0)
7857c478bd9Sstevel@tonic-gate 		{
7867c478bd9Sstevel@tonic-gate 			/* if not safe, don't create */
7877c478bd9Sstevel@tonic-gate 			save_errno = errno;
7887c478bd9Sstevel@tonic-gate 			if (tTd(64, 5))
7897c478bd9Sstevel@tonic-gate 				sm_dprintf("X%s: local socket name %s unsafe\n",
7907c478bd9Sstevel@tonic-gate 					m->mf_name, colon);
7917c478bd9Sstevel@tonic-gate 			errno = save_errno;
7927c478bd9Sstevel@tonic-gate 			if (parseonly)
7937c478bd9Sstevel@tonic-gate 			{
7947c478bd9Sstevel@tonic-gate 				if (OpMode == MD_DAEMON ||
7957c478bd9Sstevel@tonic-gate 				    OpMode == MD_FGDAEMON ||
7967c478bd9Sstevel@tonic-gate 				    OpMode == MD_SMTP)
7977c478bd9Sstevel@tonic-gate 					syserr("X%s: local socket name %s unsafe",
7987c478bd9Sstevel@tonic-gate 					       m->mf_name, colon);
7997c478bd9Sstevel@tonic-gate 			}
8007c478bd9Sstevel@tonic-gate 			else if (MilterLogLevel > 0)
8017c478bd9Sstevel@tonic-gate 				sm_syslog(LOG_ERR, e->e_id,
8027c478bd9Sstevel@tonic-gate 					  "Milter (%s): local socket name %s unsafe",
8037c478bd9Sstevel@tonic-gate 					  m->mf_name, colon);
8047c478bd9Sstevel@tonic-gate 			milter_error(m, e);
8057c478bd9Sstevel@tonic-gate 			return -1;
8067c478bd9Sstevel@tonic-gate 		}
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 		(void) sm_strlcpy(addr.sunix.sun_path, colon,
809058561cbSjbeck 			       sizeof(addr.sunix.sun_path));
810058561cbSjbeck 		addrlen = sizeof(struct sockaddr_un);
8117c478bd9Sstevel@tonic-gate 	}
8127c478bd9Sstevel@tonic-gate 	else
8137c478bd9Sstevel@tonic-gate # endif /* NETUNIX */
8147c478bd9Sstevel@tonic-gate # if NETINET || NETINET6
8157c478bd9Sstevel@tonic-gate 	if (false
8167c478bd9Sstevel@tonic-gate #  if NETINET
8177c478bd9Sstevel@tonic-gate 		 || addr.sa.sa_family == AF_INET
8187c478bd9Sstevel@tonic-gate #  endif /* NETINET */
8197c478bd9Sstevel@tonic-gate #  if NETINET6
8207c478bd9Sstevel@tonic-gate 		 || addr.sa.sa_family == AF_INET6
8217c478bd9Sstevel@tonic-gate #  endif /* NETINET6 */
8227c478bd9Sstevel@tonic-gate 		 )
8237c478bd9Sstevel@tonic-gate 	{
8247c478bd9Sstevel@tonic-gate 		unsigned short port;
8257c478bd9Sstevel@tonic-gate 
8267c478bd9Sstevel@tonic-gate 		/* Parse port@host */
8277c478bd9Sstevel@tonic-gate 		at = strchr(colon, '@');
8287c478bd9Sstevel@tonic-gate 		if (at == NULL)
8297c478bd9Sstevel@tonic-gate 		{
8307c478bd9Sstevel@tonic-gate 			if (tTd(64, 5))
8317c478bd9Sstevel@tonic-gate 				sm_dprintf("X%s: bad address %s (expected port@host)\n",
8327c478bd9Sstevel@tonic-gate 					m->mf_name, colon);
8337c478bd9Sstevel@tonic-gate 			if (parseonly)
8347c478bd9Sstevel@tonic-gate 				syserr("X%s: bad address %s (expected port@host)",
8357c478bd9Sstevel@tonic-gate 				       m->mf_name, colon);
8367c478bd9Sstevel@tonic-gate 			else if (MilterLogLevel > 0)
8377c478bd9Sstevel@tonic-gate 				sm_syslog(LOG_ERR, e->e_id,
8387c478bd9Sstevel@tonic-gate 					  "Milter (%s): bad address %s (expected port@host)",
8397c478bd9Sstevel@tonic-gate 					  m->mf_name, colon);
8407c478bd9Sstevel@tonic-gate 			milter_error(m, e);
8417c478bd9Sstevel@tonic-gate 			return -1;
8427c478bd9Sstevel@tonic-gate 		}
8437c478bd9Sstevel@tonic-gate 		*at = '\0';
8447c478bd9Sstevel@tonic-gate 		if (isascii(*colon) && isdigit(*colon))
8457c478bd9Sstevel@tonic-gate 			port = htons((unsigned short) atoi(colon));
8467c478bd9Sstevel@tonic-gate 		else
8477c478bd9Sstevel@tonic-gate 		{
8487c478bd9Sstevel@tonic-gate #  ifdef NO_GETSERVBYNAME
8497c478bd9Sstevel@tonic-gate 			if (tTd(64, 5))
8507c478bd9Sstevel@tonic-gate 				sm_dprintf("X%s: invalid port number %s\n",
8517c478bd9Sstevel@tonic-gate 					m->mf_name, colon);
8527c478bd9Sstevel@tonic-gate 			if (parseonly)
8537c478bd9Sstevel@tonic-gate 				syserr("X%s: invalid port number %s",
8547c478bd9Sstevel@tonic-gate 				       m->mf_name, colon);
8557c478bd9Sstevel@tonic-gate 			else if (MilterLogLevel > 0)
8567c478bd9Sstevel@tonic-gate 				sm_syslog(LOG_ERR, e->e_id,
8577c478bd9Sstevel@tonic-gate 					  "Milter (%s): invalid port number %s",
8587c478bd9Sstevel@tonic-gate 					  m->mf_name, colon);
8597c478bd9Sstevel@tonic-gate 			milter_error(m, e);
8607c478bd9Sstevel@tonic-gate 			return -1;
8617c478bd9Sstevel@tonic-gate #  else /* NO_GETSERVBYNAME */
862058561cbSjbeck 			struct servent *sp;
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 			sp = getservbyname(colon, "tcp");
8657c478bd9Sstevel@tonic-gate 			if (sp == NULL)
8667c478bd9Sstevel@tonic-gate 			{
8677c478bd9Sstevel@tonic-gate 				save_errno = errno;
8687c478bd9Sstevel@tonic-gate 				if (tTd(64, 5))
8697c478bd9Sstevel@tonic-gate 					sm_dprintf("X%s: unknown port name %s\n",
8707c478bd9Sstevel@tonic-gate 						m->mf_name, colon);
8717c478bd9Sstevel@tonic-gate 				errno = save_errno;
8727c478bd9Sstevel@tonic-gate 				if (parseonly)
8737c478bd9Sstevel@tonic-gate 					syserr("X%s: unknown port name %s",
8747c478bd9Sstevel@tonic-gate 					       m->mf_name, colon);
8757c478bd9Sstevel@tonic-gate 				else if (MilterLogLevel > 0)
8767c478bd9Sstevel@tonic-gate 					sm_syslog(LOG_ERR, e->e_id,
8777c478bd9Sstevel@tonic-gate 						  "Milter (%s): unknown port name %s",
8787c478bd9Sstevel@tonic-gate 						  m->mf_name, colon);
8797c478bd9Sstevel@tonic-gate 				milter_error(m, e);
8807c478bd9Sstevel@tonic-gate 				return -1;
8817c478bd9Sstevel@tonic-gate 			}
8827c478bd9Sstevel@tonic-gate 			port = sp->s_port;
8837c478bd9Sstevel@tonic-gate #  endif /* NO_GETSERVBYNAME */
8847c478bd9Sstevel@tonic-gate 		}
8857c478bd9Sstevel@tonic-gate 		*at++ = '@';
8867c478bd9Sstevel@tonic-gate 		if (*at == '[')
8877c478bd9Sstevel@tonic-gate 		{
8887c478bd9Sstevel@tonic-gate 			char *end;
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate 			end = strchr(at, ']');
8917c478bd9Sstevel@tonic-gate 			if (end != NULL)
8927c478bd9Sstevel@tonic-gate 			{
8937c478bd9Sstevel@tonic-gate 				bool found = false;
8947c478bd9Sstevel@tonic-gate #  if NETINET
8957c478bd9Sstevel@tonic-gate 				unsigned long hid = INADDR_NONE;
8967c478bd9Sstevel@tonic-gate #  endif /* NETINET */
8977c478bd9Sstevel@tonic-gate #  if NETINET6
8987c478bd9Sstevel@tonic-gate 				struct sockaddr_in6 hid6;
8997c478bd9Sstevel@tonic-gate #  endif /* NETINET6 */
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate 				*end = '\0';
9027c478bd9Sstevel@tonic-gate #  if NETINET
9037c478bd9Sstevel@tonic-gate 				if (addr.sa.sa_family == AF_INET &&
9047c478bd9Sstevel@tonic-gate 				    (hid = inet_addr(&at[1])) != INADDR_NONE)
9057c478bd9Sstevel@tonic-gate 				{
9067c478bd9Sstevel@tonic-gate 					addr.sin.sin_addr.s_addr = hid;
9077c478bd9Sstevel@tonic-gate 					addr.sin.sin_port = port;
9087c478bd9Sstevel@tonic-gate 					found = true;
9097c478bd9Sstevel@tonic-gate 				}
9107c478bd9Sstevel@tonic-gate #  endif /* NETINET */
9117c478bd9Sstevel@tonic-gate #  if NETINET6
912058561cbSjbeck 				(void) memset(&hid6, '\0', sizeof(hid6));
9137c478bd9Sstevel@tonic-gate 				if (addr.sa.sa_family == AF_INET6 &&
9147c478bd9Sstevel@tonic-gate 				    anynet_pton(AF_INET6, &at[1],
9157c478bd9Sstevel@tonic-gate 						&hid6.sin6_addr) == 1)
9167c478bd9Sstevel@tonic-gate 				{
9177c478bd9Sstevel@tonic-gate 					addr.sin6.sin6_addr = hid6.sin6_addr;
9187c478bd9Sstevel@tonic-gate 					addr.sin6.sin6_port = port;
9197c478bd9Sstevel@tonic-gate 					found = true;
9207c478bd9Sstevel@tonic-gate 				}
9217c478bd9Sstevel@tonic-gate #  endif /* NETINET6 */
9227c478bd9Sstevel@tonic-gate 				*end = ']';
9237c478bd9Sstevel@tonic-gate 				if (!found)
9247c478bd9Sstevel@tonic-gate 				{
9257c478bd9Sstevel@tonic-gate 					if (tTd(64, 5))
9267c478bd9Sstevel@tonic-gate 						sm_dprintf("X%s: Invalid numeric domain spec \"%s\"\n",
9277c478bd9Sstevel@tonic-gate 							m->mf_name, at);
9287c478bd9Sstevel@tonic-gate 					if (parseonly)
9297c478bd9Sstevel@tonic-gate 						syserr("X%s: Invalid numeric domain spec \"%s\"",
9307c478bd9Sstevel@tonic-gate 						       m->mf_name, at);
9317c478bd9Sstevel@tonic-gate 					else if (MilterLogLevel > 0)
9327c478bd9Sstevel@tonic-gate 						sm_syslog(LOG_ERR, e->e_id,
9337c478bd9Sstevel@tonic-gate 							  "Milter (%s): Invalid numeric domain spec \"%s\"",
9347c478bd9Sstevel@tonic-gate 							  m->mf_name, at);
9357c478bd9Sstevel@tonic-gate 					milter_error(m, e);
9367c478bd9Sstevel@tonic-gate 					return -1;
9377c478bd9Sstevel@tonic-gate 				}
9387c478bd9Sstevel@tonic-gate 			}
9397c478bd9Sstevel@tonic-gate 			else
9407c478bd9Sstevel@tonic-gate 			{
9417c478bd9Sstevel@tonic-gate 				if (tTd(64, 5))
9427c478bd9Sstevel@tonic-gate 					sm_dprintf("X%s: Invalid numeric domain spec \"%s\"\n",
9437c478bd9Sstevel@tonic-gate 						m->mf_name, at);
9447c478bd9Sstevel@tonic-gate 				if (parseonly)
9457c478bd9Sstevel@tonic-gate 					syserr("X%s: Invalid numeric domain spec \"%s\"",
9467c478bd9Sstevel@tonic-gate 					       m->mf_name, at);
9477c478bd9Sstevel@tonic-gate 				else if (MilterLogLevel > 0)
9487c478bd9Sstevel@tonic-gate 					sm_syslog(LOG_ERR, e->e_id,
9497c478bd9Sstevel@tonic-gate 						  "Milter (%s): Invalid numeric domain spec \"%s\"",
9507c478bd9Sstevel@tonic-gate 						  m->mf_name, at);
9517c478bd9Sstevel@tonic-gate 				milter_error(m, e);
9527c478bd9Sstevel@tonic-gate 				return -1;
9537c478bd9Sstevel@tonic-gate 			}
9547c478bd9Sstevel@tonic-gate 		}
9557c478bd9Sstevel@tonic-gate 		else
9567c478bd9Sstevel@tonic-gate 		{
9577c478bd9Sstevel@tonic-gate 			hp = sm_gethostbyname(at, addr.sa.sa_family);
9587c478bd9Sstevel@tonic-gate 			if (hp == NULL)
9597c478bd9Sstevel@tonic-gate 			{
9607c478bd9Sstevel@tonic-gate 				save_errno = errno;
9617c478bd9Sstevel@tonic-gate 				if (tTd(64, 5))
9627c478bd9Sstevel@tonic-gate 					sm_dprintf("X%s: Unknown host name %s\n",
9637c478bd9Sstevel@tonic-gate 						   m->mf_name, at);
9647c478bd9Sstevel@tonic-gate 				errno = save_errno;
9657c478bd9Sstevel@tonic-gate 				if (parseonly)
9667c478bd9Sstevel@tonic-gate 					syserr("X%s: Unknown host name %s",
9677c478bd9Sstevel@tonic-gate 					       m->mf_name, at);
9687c478bd9Sstevel@tonic-gate 				else if (MilterLogLevel > 0)
9697c478bd9Sstevel@tonic-gate 					sm_syslog(LOG_ERR, e->e_id,
9707c478bd9Sstevel@tonic-gate 						  "Milter (%s): Unknown host name %s",
9717c478bd9Sstevel@tonic-gate 						  m->mf_name, at);
9727c478bd9Sstevel@tonic-gate 				milter_error(m, e);
9737c478bd9Sstevel@tonic-gate 				return -1;
9747c478bd9Sstevel@tonic-gate 			}
9757c478bd9Sstevel@tonic-gate 			addr.sa.sa_family = hp->h_addrtype;
9767c478bd9Sstevel@tonic-gate 			switch (hp->h_addrtype)
9777c478bd9Sstevel@tonic-gate 			{
9787c478bd9Sstevel@tonic-gate #  if NETINET
9797c478bd9Sstevel@tonic-gate 			  case AF_INET:
9807c478bd9Sstevel@tonic-gate 				memmove(&addr.sin.sin_addr,
9817c478bd9Sstevel@tonic-gate 					hp->h_addr, INADDRSZ);
9827c478bd9Sstevel@tonic-gate 				addr.sin.sin_port = port;
983058561cbSjbeck 				addrlen = sizeof(struct sockaddr_in);
9847c478bd9Sstevel@tonic-gate 				addrno = 1;
9857c478bd9Sstevel@tonic-gate 				break;
9867c478bd9Sstevel@tonic-gate #  endif /* NETINET */
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate #  if NETINET6
9897c478bd9Sstevel@tonic-gate 			  case AF_INET6:
9907c478bd9Sstevel@tonic-gate 				memmove(&addr.sin6.sin6_addr,
9917c478bd9Sstevel@tonic-gate 					hp->h_addr, IN6ADDRSZ);
9927c478bd9Sstevel@tonic-gate 				addr.sin6.sin6_port = port;
993058561cbSjbeck 				addrlen = sizeof(struct sockaddr_in6);
9947c478bd9Sstevel@tonic-gate 				addrno = 1;
9957c478bd9Sstevel@tonic-gate 				break;
9967c478bd9Sstevel@tonic-gate #  endif /* NETINET6 */
9977c478bd9Sstevel@tonic-gate 
9987c478bd9Sstevel@tonic-gate 			  default:
9997c478bd9Sstevel@tonic-gate 				if (tTd(64, 5))
10007c478bd9Sstevel@tonic-gate 					sm_dprintf("X%s: Unknown protocol for %s (%d)\n",
10017c478bd9Sstevel@tonic-gate 						   m->mf_name, at,
10027c478bd9Sstevel@tonic-gate 						   hp->h_addrtype);
10037c478bd9Sstevel@tonic-gate 				if (parseonly)
10047c478bd9Sstevel@tonic-gate 					syserr("X%s: Unknown protocol for %s (%d)",
10057c478bd9Sstevel@tonic-gate 					       m->mf_name, at, hp->h_addrtype);
10067c478bd9Sstevel@tonic-gate 				else if (MilterLogLevel > 0)
10077c478bd9Sstevel@tonic-gate 					sm_syslog(LOG_ERR, e->e_id,
10087c478bd9Sstevel@tonic-gate 						  "Milter (%s): Unknown protocol for %s (%d)",
10097c478bd9Sstevel@tonic-gate 						  m->mf_name, at,
10107c478bd9Sstevel@tonic-gate 						  hp->h_addrtype);
10117c478bd9Sstevel@tonic-gate 				milter_error(m, e);
10127c478bd9Sstevel@tonic-gate #  if NETINET6
10137c478bd9Sstevel@tonic-gate 				freehostent(hp);
10147c478bd9Sstevel@tonic-gate #  endif /* NETINET6 */
10157c478bd9Sstevel@tonic-gate 				return -1;
10167c478bd9Sstevel@tonic-gate 			}
10177c478bd9Sstevel@tonic-gate 		}
10187c478bd9Sstevel@tonic-gate 	}
10197c478bd9Sstevel@tonic-gate 	else
10207c478bd9Sstevel@tonic-gate # endif /* NETINET || NETINET6 */
10217c478bd9Sstevel@tonic-gate 	{
10227c478bd9Sstevel@tonic-gate 		if (tTd(64, 5))
10237c478bd9Sstevel@tonic-gate 			sm_dprintf("X%s: unknown socket protocol\n",
10247c478bd9Sstevel@tonic-gate 				   m->mf_name);
10257c478bd9Sstevel@tonic-gate 		if (parseonly)
10267c478bd9Sstevel@tonic-gate 			syserr("X%s: unknown socket protocol", m->mf_name);
10277c478bd9Sstevel@tonic-gate 		else if (MilterLogLevel > 0)
10287c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_ERR, e->e_id,
10297c478bd9Sstevel@tonic-gate 				  "Milter (%s): unknown socket protocol",
10307c478bd9Sstevel@tonic-gate 				  m->mf_name);
10317c478bd9Sstevel@tonic-gate 		milter_error(m, e);
10327c478bd9Sstevel@tonic-gate 		return -1;
10337c478bd9Sstevel@tonic-gate 	}
10347c478bd9Sstevel@tonic-gate 
10357c478bd9Sstevel@tonic-gate 	/* just parsing through? */
10367c478bd9Sstevel@tonic-gate 	if (parseonly)
10377c478bd9Sstevel@tonic-gate 	{
10387c478bd9Sstevel@tonic-gate 		m->mf_state = SMFS_READY;
10397c478bd9Sstevel@tonic-gate # if NETINET6
10407c478bd9Sstevel@tonic-gate 		if (hp != NULL)
10417c478bd9Sstevel@tonic-gate 			freehostent(hp);
10427c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
10437c478bd9Sstevel@tonic-gate 		return 0;
10447c478bd9Sstevel@tonic-gate 	}
10457c478bd9Sstevel@tonic-gate 
10467c478bd9Sstevel@tonic-gate 	/* sanity check */
10477c478bd9Sstevel@tonic-gate 	if (m->mf_state != SMFS_READY &&
10487c478bd9Sstevel@tonic-gate 	    m->mf_state != SMFS_CLOSED)
10497c478bd9Sstevel@tonic-gate 	{
10507c478bd9Sstevel@tonic-gate 		/* shouldn't happen */
10517c478bd9Sstevel@tonic-gate 		if (tTd(64, 1))
10527c478bd9Sstevel@tonic-gate 			sm_dprintf("Milter (%s): Trying to open filter in state %c\n",
10537c478bd9Sstevel@tonic-gate 				   m->mf_name, (char) m->mf_state);
10547c478bd9Sstevel@tonic-gate 		milter_error(m, e);
10557c478bd9Sstevel@tonic-gate # if NETINET6
10567c478bd9Sstevel@tonic-gate 		if (hp != NULL)
10577c478bd9Sstevel@tonic-gate 			freehostent(hp);
10587c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
10597c478bd9Sstevel@tonic-gate 		return -1;
10607c478bd9Sstevel@tonic-gate 	}
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 	/* nope, actually connecting */
10637c478bd9Sstevel@tonic-gate 	for (;;)
10647c478bd9Sstevel@tonic-gate 	{
10657c478bd9Sstevel@tonic-gate 		sock = socket(addr.sa.sa_family, SOCK_STREAM, 0);
10667c478bd9Sstevel@tonic-gate 		if (sock < 0)
10677c478bd9Sstevel@tonic-gate 		{
10687c478bd9Sstevel@tonic-gate 			save_errno = errno;
10697c478bd9Sstevel@tonic-gate 			if (tTd(64, 5))
10707c478bd9Sstevel@tonic-gate 				sm_dprintf("Milter (%s): error creating socket: %s\n",
10717c478bd9Sstevel@tonic-gate 					   m->mf_name,
10727c478bd9Sstevel@tonic-gate 					   sm_errstring(save_errno));
10737c478bd9Sstevel@tonic-gate 			if (MilterLogLevel > 0)
10747c478bd9Sstevel@tonic-gate 				sm_syslog(LOG_ERR, e->e_id,
10757c478bd9Sstevel@tonic-gate 					  "Milter (%s): error creating socket: %s",
10767c478bd9Sstevel@tonic-gate 					  m->mf_name, sm_errstring(save_errno));
10777c478bd9Sstevel@tonic-gate 			milter_error(m, e);
10787c478bd9Sstevel@tonic-gate # if NETINET6
10797c478bd9Sstevel@tonic-gate 			if (hp != NULL)
10807c478bd9Sstevel@tonic-gate 				freehostent(hp);
10817c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
10827c478bd9Sstevel@tonic-gate 			return -1;
10837c478bd9Sstevel@tonic-gate 		}
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate 		if (setjmp(MilterConnectTimeout) == 0)
10867c478bd9Sstevel@tonic-gate 		{
10877c478bd9Sstevel@tonic-gate 			SM_EVENT *ev = NULL;
10887c478bd9Sstevel@tonic-gate 			int i;
10897c478bd9Sstevel@tonic-gate 
10907c478bd9Sstevel@tonic-gate 			if (m->mf_timeout[SMFTO_CONNECT] > 0)
10917c478bd9Sstevel@tonic-gate 				ev = sm_setevent(m->mf_timeout[SMFTO_CONNECT],
10927c478bd9Sstevel@tonic-gate 						 milter_connect_timeout, 0);
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate 			i = connect(sock, (struct sockaddr *) &addr, addrlen);
10957c478bd9Sstevel@tonic-gate 			save_errno = errno;
10967c478bd9Sstevel@tonic-gate 			if (ev != NULL)
10977c478bd9Sstevel@tonic-gate 				sm_clrevent(ev);
10987c478bd9Sstevel@tonic-gate 			errno = save_errno;
10997c478bd9Sstevel@tonic-gate 			if (i >= 0)
11007c478bd9Sstevel@tonic-gate 				break;
11017c478bd9Sstevel@tonic-gate 		}
11027c478bd9Sstevel@tonic-gate 
11037c478bd9Sstevel@tonic-gate 		/* couldn't connect.... try next address */
11047c478bd9Sstevel@tonic-gate 		save_errno = errno;
11057c478bd9Sstevel@tonic-gate 		p = CurHostName;
11067c478bd9Sstevel@tonic-gate 		CurHostName = at;
11077c478bd9Sstevel@tonic-gate 		if (tTd(64, 5))
11087c478bd9Sstevel@tonic-gate 			sm_dprintf("milter_open (%s): open %s failed: %s\n",
11097c478bd9Sstevel@tonic-gate 				   m->mf_name, at, sm_errstring(save_errno));
11107c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 13)
11117c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_INFO, e->e_id,
11127c478bd9Sstevel@tonic-gate 				  "Milter (%s): open %s failed: %s",
11137c478bd9Sstevel@tonic-gate 				  m->mf_name, at, sm_errstring(save_errno));
11147c478bd9Sstevel@tonic-gate 		CurHostName = p;
11157c478bd9Sstevel@tonic-gate 		(void) close(sock);
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate 		/* try next address */
11187c478bd9Sstevel@tonic-gate 		if (hp != NULL && hp->h_addr_list[addrno] != NULL)
11197c478bd9Sstevel@tonic-gate 		{
11207c478bd9Sstevel@tonic-gate 			switch (addr.sa.sa_family)
11217c478bd9Sstevel@tonic-gate 			{
11227c478bd9Sstevel@tonic-gate # if NETINET
11237c478bd9Sstevel@tonic-gate 			  case AF_INET:
11247c478bd9Sstevel@tonic-gate 				memmove(&addr.sin.sin_addr,
11257c478bd9Sstevel@tonic-gate 					hp->h_addr_list[addrno++],
11267c478bd9Sstevel@tonic-gate 					INADDRSZ);
11277c478bd9Sstevel@tonic-gate 				break;
11287c478bd9Sstevel@tonic-gate # endif /* NETINET */
11297c478bd9Sstevel@tonic-gate 
11307c478bd9Sstevel@tonic-gate # if NETINET6
11317c478bd9Sstevel@tonic-gate 			  case AF_INET6:
11327c478bd9Sstevel@tonic-gate 				memmove(&addr.sin6.sin6_addr,
11337c478bd9Sstevel@tonic-gate 					hp->h_addr_list[addrno++],
11347c478bd9Sstevel@tonic-gate 					IN6ADDRSZ);
11357c478bd9Sstevel@tonic-gate 				break;
11367c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
11377c478bd9Sstevel@tonic-gate 
11387c478bd9Sstevel@tonic-gate 			  default:
11397c478bd9Sstevel@tonic-gate 				if (tTd(64, 5))
11407c478bd9Sstevel@tonic-gate 					sm_dprintf("X%s: Unknown protocol for %s (%d)\n",
11417c478bd9Sstevel@tonic-gate 						   m->mf_name, at,
11427c478bd9Sstevel@tonic-gate 						   hp->h_addrtype);
11437c478bd9Sstevel@tonic-gate 				if (MilterLogLevel > 0)
11447c478bd9Sstevel@tonic-gate 					sm_syslog(LOG_ERR, e->e_id,
11457c478bd9Sstevel@tonic-gate 						  "Milter (%s): Unknown protocol for %s (%d)",
11467c478bd9Sstevel@tonic-gate 						  m->mf_name, at,
11477c478bd9Sstevel@tonic-gate 						  hp->h_addrtype);
11487c478bd9Sstevel@tonic-gate 				milter_error(m, e);
11497c478bd9Sstevel@tonic-gate # if NETINET6
11507c478bd9Sstevel@tonic-gate 				freehostent(hp);
11517c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
11527c478bd9Sstevel@tonic-gate 				return -1;
11537c478bd9Sstevel@tonic-gate 			}
11547c478bd9Sstevel@tonic-gate 			continue;
11557c478bd9Sstevel@tonic-gate 		}
11567c478bd9Sstevel@tonic-gate 		p = CurHostName;
11577c478bd9Sstevel@tonic-gate 		CurHostName = at;
11587c478bd9Sstevel@tonic-gate 		if (tTd(64, 5))
11597c478bd9Sstevel@tonic-gate 			sm_dprintf("X%s: error connecting to filter: %s\n",
11607c478bd9Sstevel@tonic-gate 				   m->mf_name, sm_errstring(save_errno));
11617c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 0)
11627c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_ERR, e->e_id,
11637c478bd9Sstevel@tonic-gate 				  "Milter (%s): error connecting to filter: %s",
11647c478bd9Sstevel@tonic-gate 				  m->mf_name, sm_errstring(save_errno));
11657c478bd9Sstevel@tonic-gate 		CurHostName = p;
11667c478bd9Sstevel@tonic-gate 		milter_error(m, e);
11677c478bd9Sstevel@tonic-gate # if NETINET6
11687c478bd9Sstevel@tonic-gate 		if (hp != NULL)
11697c478bd9Sstevel@tonic-gate 			freehostent(hp);
11707c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
11717c478bd9Sstevel@tonic-gate 		return -1;
11727c478bd9Sstevel@tonic-gate 	}
11737c478bd9Sstevel@tonic-gate 	m->mf_state = SMFS_OPEN;
11747c478bd9Sstevel@tonic-gate # if NETINET6
11757c478bd9Sstevel@tonic-gate 	if (hp != NULL)
11767c478bd9Sstevel@tonic-gate 	{
11777c478bd9Sstevel@tonic-gate 		freehostent(hp);
11787c478bd9Sstevel@tonic-gate 		hp = NULL;
11797c478bd9Sstevel@tonic-gate 	}
11807c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
1181058561cbSjbeck # if MILTER_NO_NAGLE && !defined(TCP_CORK)
11827c478bd9Sstevel@tonic-gate 	{
11837c478bd9Sstevel@tonic-gate 		int nodelay = 1;
11847c478bd9Sstevel@tonic-gate 
11857c478bd9Sstevel@tonic-gate 		setsockopt(m->mf_sock, IPPROTO_TCP, TCP_NODELAY,
11867c478bd9Sstevel@tonic-gate 			   (char *)&nodelay, sizeof(nodelay));
11877c478bd9Sstevel@tonic-gate 	}
1188058561cbSjbeck # endif /* MILTER_NO_NAGLE && !defined(TCP_CORK) */
11897c478bd9Sstevel@tonic-gate 	return sock;
11907c478bd9Sstevel@tonic-gate }
11917c478bd9Sstevel@tonic-gate 
11927c478bd9Sstevel@tonic-gate static void
milter_connect_timeout(ignore)11937c478bd9Sstevel@tonic-gate milter_connect_timeout(ignore)
11947c478bd9Sstevel@tonic-gate 	int ignore;
11957c478bd9Sstevel@tonic-gate {
11967c478bd9Sstevel@tonic-gate 	/*
11977c478bd9Sstevel@tonic-gate 	**  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
11987c478bd9Sstevel@tonic-gate 	**	ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
11997c478bd9Sstevel@tonic-gate 	**	DOING.
12007c478bd9Sstevel@tonic-gate 	*/
12017c478bd9Sstevel@tonic-gate 
12027c478bd9Sstevel@tonic-gate 	errno = ETIMEDOUT;
12037c478bd9Sstevel@tonic-gate 	longjmp(MilterConnectTimeout, 1);
12047c478bd9Sstevel@tonic-gate }
1205058561cbSjbeck 
12067c478bd9Sstevel@tonic-gate /*
12077c478bd9Sstevel@tonic-gate **  MILTER_SETUP -- setup structure for a mail filter
12087c478bd9Sstevel@tonic-gate **
12097c478bd9Sstevel@tonic-gate **	Parameters:
12107c478bd9Sstevel@tonic-gate **		line -- the options line.
12117c478bd9Sstevel@tonic-gate **
12127c478bd9Sstevel@tonic-gate **	Returns:
12137c478bd9Sstevel@tonic-gate **		none
12147c478bd9Sstevel@tonic-gate */
12157c478bd9Sstevel@tonic-gate 
12167c478bd9Sstevel@tonic-gate void
milter_setup(line)12177c478bd9Sstevel@tonic-gate milter_setup(line)
12187c478bd9Sstevel@tonic-gate 	char *line;
12197c478bd9Sstevel@tonic-gate {
12207c478bd9Sstevel@tonic-gate 	char fcode;
1221058561cbSjbeck 	char *p;
1222058561cbSjbeck 	struct milter *m;
12237c478bd9Sstevel@tonic-gate 	STAB *s;
12247c478bd9Sstevel@tonic-gate 
12257c478bd9Sstevel@tonic-gate 	/* collect the filter name */
12267c478bd9Sstevel@tonic-gate 	for (p = line;
12277c478bd9Sstevel@tonic-gate 	     *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p));
12287c478bd9Sstevel@tonic-gate 	     p++)
12297c478bd9Sstevel@tonic-gate 		continue;
12307c478bd9Sstevel@tonic-gate 	if (*p != '\0')
12317c478bd9Sstevel@tonic-gate 		*p++ = '\0';
12327c478bd9Sstevel@tonic-gate 	if (line[0] == '\0')
12337c478bd9Sstevel@tonic-gate 	{
12347c478bd9Sstevel@tonic-gate 		syserr("name required for mail filter");
12357c478bd9Sstevel@tonic-gate 		return;
12367c478bd9Sstevel@tonic-gate 	}
1237058561cbSjbeck 	m = (struct milter *) xalloc(sizeof(*m));
1238058561cbSjbeck 	memset((char *) m, '\0', sizeof(*m));
12397c478bd9Sstevel@tonic-gate 	m->mf_name = newstr(line);
12407c478bd9Sstevel@tonic-gate 	m->mf_state = SMFS_READY;
12417c478bd9Sstevel@tonic-gate 	m->mf_sock = -1;
12427c478bd9Sstevel@tonic-gate 	m->mf_timeout[SMFTO_CONNECT] = (time_t) 300;
12437c478bd9Sstevel@tonic-gate 	m->mf_timeout[SMFTO_WRITE] = (time_t) 10;
12447c478bd9Sstevel@tonic-gate 	m->mf_timeout[SMFTO_READ] = (time_t) 10;
12457c478bd9Sstevel@tonic-gate 	m->mf_timeout[SMFTO_EOM] = (time_t) 300;
12464aac33d3Sjbeck #if _FFR_MILTER_CHECK
1247058561cbSjbeck 	m->mf_mta_prot_version = SMFI_PROT_VERSION;
1248058561cbSjbeck 	m->mf_mta_prot_flags = SMFI_CURR_PROT;
1249058561cbSjbeck 	m->mf_mta_actions = SMFI_CURR_ACTS;
12504aac33d3Sjbeck #endif /* _FFR_MILTER_CHECK */
12517c478bd9Sstevel@tonic-gate 
12527c478bd9Sstevel@tonic-gate 	/* now scan through and assign info from the fields */
12537c478bd9Sstevel@tonic-gate 	while (*p != '\0')
12547c478bd9Sstevel@tonic-gate 	{
12557c478bd9Sstevel@tonic-gate 		char *delimptr;
12567c478bd9Sstevel@tonic-gate 
12577c478bd9Sstevel@tonic-gate 		while (*p != '\0' &&
12587c478bd9Sstevel@tonic-gate 		       (*p == ',' || (isascii(*p) && isspace(*p))))
12597c478bd9Sstevel@tonic-gate 			p++;
12607c478bd9Sstevel@tonic-gate 
12617c478bd9Sstevel@tonic-gate 		/* p now points to field code */
12627c478bd9Sstevel@tonic-gate 		fcode = *p;
12637c478bd9Sstevel@tonic-gate 		while (*p != '\0' && *p != '=' && *p != ',')
12647c478bd9Sstevel@tonic-gate 			p++;
12657c478bd9Sstevel@tonic-gate 		if (*p++ != '=')
12667c478bd9Sstevel@tonic-gate 		{
12677c478bd9Sstevel@tonic-gate 			syserr("X%s: `=' expected", m->mf_name);
12687c478bd9Sstevel@tonic-gate 			return;
12697c478bd9Sstevel@tonic-gate 		}
12707c478bd9Sstevel@tonic-gate 		while (isascii(*p) && isspace(*p))
12717c478bd9Sstevel@tonic-gate 			p++;
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate 		/* p now points to the field body */
12747c478bd9Sstevel@tonic-gate 		p = munchstring(p, &delimptr, ',');
12757c478bd9Sstevel@tonic-gate 
12767c478bd9Sstevel@tonic-gate 		/* install the field into the filter struct */
12777c478bd9Sstevel@tonic-gate 		switch (fcode)
12787c478bd9Sstevel@tonic-gate 		{
12797c478bd9Sstevel@tonic-gate 		  case 'S':		/* socket */
12807c478bd9Sstevel@tonic-gate 			if (p == NULL)
12817c478bd9Sstevel@tonic-gate 				m->mf_conn = NULL;
12827c478bd9Sstevel@tonic-gate 			else
12837c478bd9Sstevel@tonic-gate 				m->mf_conn = newstr(p);
12847c478bd9Sstevel@tonic-gate 			break;
12857c478bd9Sstevel@tonic-gate 
12867c478bd9Sstevel@tonic-gate 		  case 'F':		/* Milter flags configured on MTA */
12877c478bd9Sstevel@tonic-gate 			for (; *p != '\0'; p++)
12887c478bd9Sstevel@tonic-gate 			{
12897c478bd9Sstevel@tonic-gate 				if (!(isascii(*p) && isspace(*p)))
12907c478bd9Sstevel@tonic-gate 					setbitn(bitidx(*p), m->mf_flags);
12917c478bd9Sstevel@tonic-gate 			}
12927c478bd9Sstevel@tonic-gate 			break;
12937c478bd9Sstevel@tonic-gate 
12947c478bd9Sstevel@tonic-gate 		  case 'T':		/* timeouts */
12957c478bd9Sstevel@tonic-gate 			milter_parse_timeouts(p, m);
12967c478bd9Sstevel@tonic-gate 			break;
12977c478bd9Sstevel@tonic-gate 
12984aac33d3Sjbeck #if _FFR_MILTER_CHECK
1299058561cbSjbeck 		  case 'a':
1300058561cbSjbeck 			m->mf_mta_actions = strtoul(p, NULL, 0);
1301058561cbSjbeck 			break;
1302058561cbSjbeck 		  case 'f':
1303058561cbSjbeck 			m->mf_mta_prot_flags = strtoul(p, NULL, 0);
1304058561cbSjbeck 			break;
1305058561cbSjbeck 		  case 'v':
1306058561cbSjbeck 			m->mf_mta_prot_version = strtoul(p, NULL, 0);
1307058561cbSjbeck 			break;
13084aac33d3Sjbeck #endif /* _FFR_MILTER_CHECK */
1309058561cbSjbeck 
13107c478bd9Sstevel@tonic-gate 		  default:
13117c478bd9Sstevel@tonic-gate 			syserr("X%s: unknown filter equate %c=",
13127c478bd9Sstevel@tonic-gate 			       m->mf_name, fcode);
13137c478bd9Sstevel@tonic-gate 			break;
13147c478bd9Sstevel@tonic-gate 		}
13157c478bd9Sstevel@tonic-gate 		p = delimptr;
13167c478bd9Sstevel@tonic-gate 	}
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate 	/* early check for errors */
13197c478bd9Sstevel@tonic-gate 	(void) milter_open(m, true, CurEnv);
13207c478bd9Sstevel@tonic-gate 
13217c478bd9Sstevel@tonic-gate 	/* enter the filter into the symbol table */
13227c478bd9Sstevel@tonic-gate 	s = stab(m->mf_name, ST_MILTER, ST_ENTER);
13237c478bd9Sstevel@tonic-gate 	if (s->s_milter != NULL)
13247c478bd9Sstevel@tonic-gate 		syserr("X%s: duplicate filter definition", m->mf_name);
13257c478bd9Sstevel@tonic-gate 	else
13267c478bd9Sstevel@tonic-gate 		s->s_milter = m;
13277c478bd9Sstevel@tonic-gate }
1328058561cbSjbeck 
13297c478bd9Sstevel@tonic-gate /*
13307c478bd9Sstevel@tonic-gate **  MILTER_CONFIG -- parse option list into an array and check config
13317c478bd9Sstevel@tonic-gate **
13327c478bd9Sstevel@tonic-gate **	Called when reading configuration file.
13337c478bd9Sstevel@tonic-gate **
13347c478bd9Sstevel@tonic-gate **	Parameters:
13357c478bd9Sstevel@tonic-gate **		spec -- the filter list.
13367c478bd9Sstevel@tonic-gate **		list -- the array to fill in.
13377c478bd9Sstevel@tonic-gate **		max -- the maximum number of entries in list.
13387c478bd9Sstevel@tonic-gate **
13397c478bd9Sstevel@tonic-gate **	Returns:
13407c478bd9Sstevel@tonic-gate **		none
13417c478bd9Sstevel@tonic-gate */
13427c478bd9Sstevel@tonic-gate 
13437c478bd9Sstevel@tonic-gate void
milter_config(spec,list,max)13447c478bd9Sstevel@tonic-gate milter_config(spec, list, max)
13457c478bd9Sstevel@tonic-gate 	char *spec;
13467c478bd9Sstevel@tonic-gate 	struct milter **list;
13477c478bd9Sstevel@tonic-gate 	int max;
13487c478bd9Sstevel@tonic-gate {
13497c478bd9Sstevel@tonic-gate 	int numitems = 0;
1350058561cbSjbeck 	char *p;
13517c478bd9Sstevel@tonic-gate 
13527c478bd9Sstevel@tonic-gate 	/* leave one for the NULL signifying the end of the list */
13537c478bd9Sstevel@tonic-gate 	max--;
13547c478bd9Sstevel@tonic-gate 
13557c478bd9Sstevel@tonic-gate 	for (p = spec; p != NULL; )
13567c478bd9Sstevel@tonic-gate 	{
13577c478bd9Sstevel@tonic-gate 		STAB *s;
13587c478bd9Sstevel@tonic-gate 
13597c478bd9Sstevel@tonic-gate 		while (isascii(*p) && isspace(*p))
13607c478bd9Sstevel@tonic-gate 			p++;
13617c478bd9Sstevel@tonic-gate 		if (*p == '\0')
13627c478bd9Sstevel@tonic-gate 			break;
13637c478bd9Sstevel@tonic-gate 		spec = p;
13647c478bd9Sstevel@tonic-gate 
13657c478bd9Sstevel@tonic-gate 		if (numitems >= max)
13667c478bd9Sstevel@tonic-gate 		{
13677c478bd9Sstevel@tonic-gate 			syserr("Too many filters defined, %d max", max);
13687c478bd9Sstevel@tonic-gate 			if (max > 0)
13697c478bd9Sstevel@tonic-gate 				list[0] = NULL;
13707c478bd9Sstevel@tonic-gate 			return;
13717c478bd9Sstevel@tonic-gate 		}
13727c478bd9Sstevel@tonic-gate 		p = strpbrk(p, ";,");
13737c478bd9Sstevel@tonic-gate 		if (p != NULL)
13747c478bd9Sstevel@tonic-gate 			*p++ = '\0';
13757c478bd9Sstevel@tonic-gate 
13767c478bd9Sstevel@tonic-gate 		s = stab(spec, ST_MILTER, ST_FIND);
13777c478bd9Sstevel@tonic-gate 		if (s == NULL)
13787c478bd9Sstevel@tonic-gate 		{
13797c478bd9Sstevel@tonic-gate 			syserr("InputFilter %s not defined", spec);
13807c478bd9Sstevel@tonic-gate 			ExitStat = EX_CONFIG;
13817c478bd9Sstevel@tonic-gate 			return;
13827c478bd9Sstevel@tonic-gate 		}
13837c478bd9Sstevel@tonic-gate 		list[numitems++] = s->s_milter;
13847c478bd9Sstevel@tonic-gate 	}
13857c478bd9Sstevel@tonic-gate 	list[numitems] = NULL;
13867c478bd9Sstevel@tonic-gate 
13877c478bd9Sstevel@tonic-gate 	/* if not set, set to LogLevel */
13887c478bd9Sstevel@tonic-gate 	if (MilterLogLevel == -1)
13897c478bd9Sstevel@tonic-gate 		MilterLogLevel = LogLevel;
13907c478bd9Sstevel@tonic-gate }
1391058561cbSjbeck 
13927c478bd9Sstevel@tonic-gate /*
13937c478bd9Sstevel@tonic-gate **  MILTER_PARSE_TIMEOUTS -- parse timeout list
13947c478bd9Sstevel@tonic-gate **
13957c478bd9Sstevel@tonic-gate **	Called when reading configuration file.
13967c478bd9Sstevel@tonic-gate **
13977c478bd9Sstevel@tonic-gate **	Parameters:
13987c478bd9Sstevel@tonic-gate **		spec -- the timeout list.
13997c478bd9Sstevel@tonic-gate **		m -- milter to set.
14007c478bd9Sstevel@tonic-gate **
14017c478bd9Sstevel@tonic-gate **	Returns:
14027c478bd9Sstevel@tonic-gate **		none
14037c478bd9Sstevel@tonic-gate */
14047c478bd9Sstevel@tonic-gate 
14057c478bd9Sstevel@tonic-gate static void
milter_parse_timeouts(spec,m)14067c478bd9Sstevel@tonic-gate milter_parse_timeouts(spec, m)
14077c478bd9Sstevel@tonic-gate 	char *spec;
14087c478bd9Sstevel@tonic-gate 	struct milter *m;
14097c478bd9Sstevel@tonic-gate {
14107c478bd9Sstevel@tonic-gate 	char fcode;
14117c478bd9Sstevel@tonic-gate 	int tcode;
1412058561cbSjbeck 	char *p;
14137c478bd9Sstevel@tonic-gate 
14147c478bd9Sstevel@tonic-gate 	p = spec;
14157c478bd9Sstevel@tonic-gate 
14167c478bd9Sstevel@tonic-gate 	/* now scan through and assign info from the fields */
14177c478bd9Sstevel@tonic-gate 	while (*p != '\0')
14187c478bd9Sstevel@tonic-gate 	{
14197c478bd9Sstevel@tonic-gate 		char *delimptr;
14207c478bd9Sstevel@tonic-gate 
14217c478bd9Sstevel@tonic-gate 		while (*p != '\0' &&
14227c478bd9Sstevel@tonic-gate 		       (*p == ';' || (isascii(*p) && isspace(*p))))
14237c478bd9Sstevel@tonic-gate 			p++;
14247c478bd9Sstevel@tonic-gate 
14257c478bd9Sstevel@tonic-gate 		/* p now points to field code */
14267c478bd9Sstevel@tonic-gate 		fcode = *p;
14277c478bd9Sstevel@tonic-gate 		while (*p != '\0' && *p != ':')
14287c478bd9Sstevel@tonic-gate 			p++;
14297c478bd9Sstevel@tonic-gate 		if (*p++ != ':')
14307c478bd9Sstevel@tonic-gate 		{
14317c478bd9Sstevel@tonic-gate 			syserr("X%s, T=: `:' expected", m->mf_name);
14327c478bd9Sstevel@tonic-gate 			return;
14337c478bd9Sstevel@tonic-gate 		}
14347c478bd9Sstevel@tonic-gate 		while (isascii(*p) && isspace(*p))
14357c478bd9Sstevel@tonic-gate 			p++;
14367c478bd9Sstevel@tonic-gate 
14377c478bd9Sstevel@tonic-gate 		/* p now points to the field body */
14387c478bd9Sstevel@tonic-gate 		p = munchstring(p, &delimptr, ';');
14397c478bd9Sstevel@tonic-gate 		tcode = -1;
14407c478bd9Sstevel@tonic-gate 
14417c478bd9Sstevel@tonic-gate 		/* install the field into the filter struct */
14427c478bd9Sstevel@tonic-gate 		switch (fcode)
14437c478bd9Sstevel@tonic-gate 		{
14447c478bd9Sstevel@tonic-gate 		  case 'C':
14457c478bd9Sstevel@tonic-gate 			tcode = SMFTO_CONNECT;
14467c478bd9Sstevel@tonic-gate 			break;
14477c478bd9Sstevel@tonic-gate 
14487c478bd9Sstevel@tonic-gate 		  case 'S':
14497c478bd9Sstevel@tonic-gate 			tcode = SMFTO_WRITE;
14507c478bd9Sstevel@tonic-gate 			break;
14517c478bd9Sstevel@tonic-gate 
14527c478bd9Sstevel@tonic-gate 		  case 'R':
14537c478bd9Sstevel@tonic-gate 			tcode = SMFTO_READ;
14547c478bd9Sstevel@tonic-gate 			break;
14557c478bd9Sstevel@tonic-gate 
14567c478bd9Sstevel@tonic-gate 		  case 'E':
14577c478bd9Sstevel@tonic-gate 			tcode = SMFTO_EOM;
14587c478bd9Sstevel@tonic-gate 			break;
14597c478bd9Sstevel@tonic-gate 
14607c478bd9Sstevel@tonic-gate 		  default:
14617c478bd9Sstevel@tonic-gate 			if (tTd(64, 5))
14627c478bd9Sstevel@tonic-gate 				sm_dprintf("X%s: %c unknown\n",
14637c478bd9Sstevel@tonic-gate 					   m->mf_name, fcode);
14647c478bd9Sstevel@tonic-gate 			syserr("X%s: unknown filter timeout %c",
14657c478bd9Sstevel@tonic-gate 			       m->mf_name, fcode);
14667c478bd9Sstevel@tonic-gate 			break;
14677c478bd9Sstevel@tonic-gate 		}
14687c478bd9Sstevel@tonic-gate 		if (tcode >= 0)
14697c478bd9Sstevel@tonic-gate 		{
14707c478bd9Sstevel@tonic-gate 			m->mf_timeout[tcode] = convtime(p, 's');
14717c478bd9Sstevel@tonic-gate 			if (tTd(64, 5))
14727c478bd9Sstevel@tonic-gate 				sm_dprintf("X%s: %c=%ld\n",
14737c478bd9Sstevel@tonic-gate 					   m->mf_name, fcode,
14747c478bd9Sstevel@tonic-gate 					   (u_long) m->mf_timeout[tcode]);
14757c478bd9Sstevel@tonic-gate 		}
14767c478bd9Sstevel@tonic-gate 		p = delimptr;
14777c478bd9Sstevel@tonic-gate 	}
14787c478bd9Sstevel@tonic-gate }
1479058561cbSjbeck 
1480058561cbSjbeck /*
1481058561cbSjbeck **  MILTER_SET_MACROS -- set milter macros
1482058561cbSjbeck **
1483058561cbSjbeck **	Parameters:
1484058561cbSjbeck **		name -- name of milter.
1485058561cbSjbeck **		macros -- where to store macros.
1486058561cbSjbeck **		val -- the value of the option.
1487058561cbSjbeck **		nummac -- current number of macros
1488058561cbSjbeck **
1489058561cbSjbeck **	Returns:
1490058561cbSjbeck **		new number of macros
1491058561cbSjbeck */
1492058561cbSjbeck 
1493058561cbSjbeck static int
milter_set_macros(name,macros,val,nummac)1494058561cbSjbeck milter_set_macros(name, macros, val, nummac)
1495058561cbSjbeck 	char *name;
1496058561cbSjbeck 	char **macros;
1497058561cbSjbeck 	char *val;
1498058561cbSjbeck 	int nummac;
1499058561cbSjbeck {
1500058561cbSjbeck 	char *p;
1501058561cbSjbeck 
1502058561cbSjbeck 	p = newstr(val);
1503058561cbSjbeck 	while (*p != '\0')
1504058561cbSjbeck 	{
1505058561cbSjbeck 		char *macro;
1506058561cbSjbeck 
1507058561cbSjbeck 		/* Skip leading commas, spaces */
1508058561cbSjbeck 		while (*p != '\0' &&
1509058561cbSjbeck 		       (*p == ',' || (isascii(*p) && isspace(*p))))
1510058561cbSjbeck 			p++;
1511058561cbSjbeck 
1512058561cbSjbeck 		if (*p == '\0')
1513058561cbSjbeck 			break;
1514058561cbSjbeck 
1515058561cbSjbeck 		/* Find end of macro */
1516058561cbSjbeck 		macro = p;
1517058561cbSjbeck 		while (*p != '\0' && *p != ',' &&
1518058561cbSjbeck 		       isascii(*p) && !isspace(*p))
1519058561cbSjbeck 			p++;
1520058561cbSjbeck 		if (*p != '\0')
1521058561cbSjbeck 			*p++ = '\0';
1522058561cbSjbeck 
1523058561cbSjbeck 		if (nummac >= MAXFILTERMACROS)
1524058561cbSjbeck 		{
1525058561cbSjbeck 			syserr("milter_set_option: too many macros in Milter.%s (max %d)",
1526058561cbSjbeck 			       name, MAXFILTERMACROS);
1527058561cbSjbeck 			macros[nummac] = NULL;
1528058561cbSjbeck 			return -1;
1529058561cbSjbeck 		}
1530058561cbSjbeck 		macros[nummac++] = macro;
1531058561cbSjbeck 	}
1532058561cbSjbeck 	macros[nummac] = NULL;
1533058561cbSjbeck 	return nummac;
1534058561cbSjbeck }
1535058561cbSjbeck 
15367c478bd9Sstevel@tonic-gate /*
15377c478bd9Sstevel@tonic-gate **  MILTER_SET_OPTION -- set an individual milter option
15387c478bd9Sstevel@tonic-gate **
15397c478bd9Sstevel@tonic-gate **	Parameters:
15407c478bd9Sstevel@tonic-gate **		name -- the name of the option.
15417c478bd9Sstevel@tonic-gate **		val -- the value of the option.
15427c478bd9Sstevel@tonic-gate **		sticky -- if set, don't let other setoptions override
15437c478bd9Sstevel@tonic-gate **			this value.
15447c478bd9Sstevel@tonic-gate **
15457c478bd9Sstevel@tonic-gate **	Returns:
15467c478bd9Sstevel@tonic-gate **		none.
15477c478bd9Sstevel@tonic-gate */
15487c478bd9Sstevel@tonic-gate 
15497c478bd9Sstevel@tonic-gate /* set if Milter sub-option is stuck */
15507c478bd9Sstevel@tonic-gate static BITMAP256	StickyMilterOpt;
15517c478bd9Sstevel@tonic-gate 
15527c478bd9Sstevel@tonic-gate static struct milteropt
15537c478bd9Sstevel@tonic-gate {
15547c478bd9Sstevel@tonic-gate 	char		*mo_name;	/* long name of milter option */
15557c478bd9Sstevel@tonic-gate 	unsigned char	mo_code;	/* code for option */
15567c478bd9Sstevel@tonic-gate } MilterOptTab[] =
15577c478bd9Sstevel@tonic-gate {
1558058561cbSjbeck # define MO_MACROS_CONNECT		SMFIM_CONNECT
15597c478bd9Sstevel@tonic-gate 	{ "macros.connect",		MO_MACROS_CONNECT		},
1560058561cbSjbeck # define MO_MACROS_HELO			SMFIM_HELO
15617c478bd9Sstevel@tonic-gate 	{ "macros.helo",		MO_MACROS_HELO			},
1562058561cbSjbeck # define MO_MACROS_ENVFROM		SMFIM_ENVFROM
15637c478bd9Sstevel@tonic-gate 	{ "macros.envfrom",		MO_MACROS_ENVFROM		},
1564058561cbSjbeck # define MO_MACROS_ENVRCPT		SMFIM_ENVRCPT
15657c478bd9Sstevel@tonic-gate 	{ "macros.envrcpt",		MO_MACROS_ENVRCPT		},
1566058561cbSjbeck # define MO_MACROS_DATA			SMFIM_DATA
15677c478bd9Sstevel@tonic-gate 	{ "macros.data",		MO_MACROS_DATA			},
1568058561cbSjbeck # define MO_MACROS_EOM			SMFIM_EOM
15697c478bd9Sstevel@tonic-gate 	{ "macros.eom",			MO_MACROS_EOM			},
1570058561cbSjbeck # define MO_MACROS_EOH			SMFIM_EOH
1571058561cbSjbeck 	{ "macros.eoh",			MO_MACROS_EOH			},
1572058561cbSjbeck 
15737c478bd9Sstevel@tonic-gate # define MO_LOGLEVEL			0x07
15747c478bd9Sstevel@tonic-gate 	{ "loglevel",			MO_LOGLEVEL			},
1575*e9af4bc0SJohn Beck # if _FFR_MAXDATASIZE || _FFR_MDS_NEGOTIATE
1576058561cbSjbeck #  define MO_MAXDATASIZE		0x08
15777c478bd9Sstevel@tonic-gate 	{ "maxdatasize",		MO_MAXDATASIZE			},
1578*e9af4bc0SJohn Beck # endif /* _FFR_MAXDATASIZE || _FFR_MDS_NEGOTIATE */
1579058561cbSjbeck 	{ NULL,				(unsigned char)-1		},
15807c478bd9Sstevel@tonic-gate };
15817c478bd9Sstevel@tonic-gate 
15827c478bd9Sstevel@tonic-gate void
milter_set_option(name,val,sticky)15837c478bd9Sstevel@tonic-gate milter_set_option(name, val, sticky)
15847c478bd9Sstevel@tonic-gate 	char *name;
15857c478bd9Sstevel@tonic-gate 	char *val;
15867c478bd9Sstevel@tonic-gate 	bool sticky;
15877c478bd9Sstevel@tonic-gate {
1588058561cbSjbeck 	int nummac, r;
1589058561cbSjbeck 	struct milteropt *mo;
15907c478bd9Sstevel@tonic-gate 	char **macros = NULL;
15917c478bd9Sstevel@tonic-gate 
1592058561cbSjbeck 	nummac = 0;
15937c478bd9Sstevel@tonic-gate 	if (tTd(37, 2) || tTd(64, 5))
15947c478bd9Sstevel@tonic-gate 		sm_dprintf("milter_set_option(%s = %s)", name, val);
15957c478bd9Sstevel@tonic-gate 
15967c478bd9Sstevel@tonic-gate 	if (name == NULL)
15977c478bd9Sstevel@tonic-gate 	{
15987c478bd9Sstevel@tonic-gate 		syserr("milter_set_option: invalid Milter option, must specify suboption");
15997c478bd9Sstevel@tonic-gate 		return;
16007c478bd9Sstevel@tonic-gate 	}
16017c478bd9Sstevel@tonic-gate 
16027c478bd9Sstevel@tonic-gate 	for (mo = MilterOptTab; mo->mo_name != NULL; mo++)
16037c478bd9Sstevel@tonic-gate 	{
16047c478bd9Sstevel@tonic-gate 		if (sm_strcasecmp(mo->mo_name, name) == 0)
16057c478bd9Sstevel@tonic-gate 			break;
16067c478bd9Sstevel@tonic-gate 	}
16077c478bd9Sstevel@tonic-gate 
16087c478bd9Sstevel@tonic-gate 	if (mo->mo_name == NULL)
16097c478bd9Sstevel@tonic-gate 	{
16107c478bd9Sstevel@tonic-gate 		syserr("milter_set_option: invalid Milter option %s", name);
16117c478bd9Sstevel@tonic-gate 		return;
16127c478bd9Sstevel@tonic-gate 	}
16137c478bd9Sstevel@tonic-gate 
16147c478bd9Sstevel@tonic-gate 	/*
16157c478bd9Sstevel@tonic-gate 	**  See if this option is preset for us.
16167c478bd9Sstevel@tonic-gate 	*/
16177c478bd9Sstevel@tonic-gate 
16187c478bd9Sstevel@tonic-gate 	if (!sticky && bitnset(mo->mo_code, StickyMilterOpt))
16197c478bd9Sstevel@tonic-gate 	{
16207c478bd9Sstevel@tonic-gate 		if (tTd(37, 2) || tTd(64,5))
16217c478bd9Sstevel@tonic-gate 			sm_dprintf(" (ignored)\n");
16227c478bd9Sstevel@tonic-gate 		return;
16237c478bd9Sstevel@tonic-gate 	}
16247c478bd9Sstevel@tonic-gate 
16257c478bd9Sstevel@tonic-gate 	if (tTd(37, 2) || tTd(64,5))
16267c478bd9Sstevel@tonic-gate 		sm_dprintf("\n");
16277c478bd9Sstevel@tonic-gate 
16287c478bd9Sstevel@tonic-gate 	switch (mo->mo_code)
16297c478bd9Sstevel@tonic-gate 	{
16307c478bd9Sstevel@tonic-gate 	  case MO_LOGLEVEL:
16317c478bd9Sstevel@tonic-gate 		MilterLogLevel = atoi(val);
16327c478bd9Sstevel@tonic-gate 		break;
16337c478bd9Sstevel@tonic-gate 
1634*e9af4bc0SJohn Beck # if _FFR_MAXDATASIZE || _FFR_MDS_NEGOTIATE
16357c478bd9Sstevel@tonic-gate 	  case MO_MAXDATASIZE:
1636*e9af4bc0SJohn Beck #  if _FFR_MDS_NEGOTIATE
16377c478bd9Sstevel@tonic-gate 		MilterMaxDataSize = (size_t)atol(val);
1638*e9af4bc0SJohn Beck 		if (MilterMaxDataSize != MILTER_MDS_64K &&
1639*e9af4bc0SJohn Beck 		    MilterMaxDataSize != MILTER_MDS_256K &&
1640*e9af4bc0SJohn Beck 		    MilterMaxDataSize != MILTER_MDS_1M)
1641*e9af4bc0SJohn Beck 		{
1642*e9af4bc0SJohn Beck 			sm_syslog(LOG_WARNING, NOQID,
1643*e9af4bc0SJohn Beck 				"WARNING: Milter.%s=%d, allowed are only %d, %d, and %d",
1644*e9af4bc0SJohn Beck 				name, MilterMaxDataSize,
1645*e9af4bc0SJohn Beck 				MILTER_MDS_64K, MILTER_MDS_256K,
1646*e9af4bc0SJohn Beck 				MILTER_MDS_1M);
1647*e9af4bc0SJohn Beck 			if (MilterMaxDataSize < MILTER_MDS_64K)
1648*e9af4bc0SJohn Beck 				MilterMaxDataSize = MILTER_MDS_64K;
1649*e9af4bc0SJohn Beck 			else if (MilterMaxDataSize < MILTER_MDS_256K)
1650*e9af4bc0SJohn Beck 				MilterMaxDataSize = MILTER_MDS_256K;
1651*e9af4bc0SJohn Beck 			else
1652*e9af4bc0SJohn Beck 				MilterMaxDataSize = MILTER_MDS_1M;
1653*e9af4bc0SJohn Beck 		}
1654*e9af4bc0SJohn Beck #  endif /* _FFR_MDS_NEGOTIATE */
16557c478bd9Sstevel@tonic-gate 		break;
1656*e9af4bc0SJohn Beck # endif /* _FFR_MAXDATASIZE || _FFR_MDS_NEGOTIATE */
16577c478bd9Sstevel@tonic-gate 
16587c478bd9Sstevel@tonic-gate 	  case MO_MACROS_CONNECT:
16597c478bd9Sstevel@tonic-gate 		if (macros == NULL)
16607c478bd9Sstevel@tonic-gate 			macros = MilterConnectMacros;
16617c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
16627c478bd9Sstevel@tonic-gate 
16637c478bd9Sstevel@tonic-gate 	  case MO_MACROS_HELO:
16647c478bd9Sstevel@tonic-gate 		if (macros == NULL)
16657c478bd9Sstevel@tonic-gate 			macros = MilterHeloMacros;
16667c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
16677c478bd9Sstevel@tonic-gate 
16687c478bd9Sstevel@tonic-gate 	  case MO_MACROS_ENVFROM:
16697c478bd9Sstevel@tonic-gate 		if (macros == NULL)
16707c478bd9Sstevel@tonic-gate 			macros = MilterEnvFromMacros;
16717c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
16727c478bd9Sstevel@tonic-gate 
16737c478bd9Sstevel@tonic-gate 	  case MO_MACROS_ENVRCPT:
16747c478bd9Sstevel@tonic-gate 		if (macros == NULL)
16757c478bd9Sstevel@tonic-gate 			macros = MilterEnvRcptMacros;
16767c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
16777c478bd9Sstevel@tonic-gate 
1678058561cbSjbeck 	  case MO_MACROS_EOH:
1679058561cbSjbeck 		if (macros == NULL)
1680058561cbSjbeck 			macros = MilterEOHMacros;
1681058561cbSjbeck 		/* FALLTHROUGH */
1682058561cbSjbeck 
16837c478bd9Sstevel@tonic-gate 	  case MO_MACROS_EOM:
16847c478bd9Sstevel@tonic-gate 		if (macros == NULL)
16857c478bd9Sstevel@tonic-gate 			macros = MilterEOMMacros;
16867c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
16877c478bd9Sstevel@tonic-gate 
16887c478bd9Sstevel@tonic-gate 	  case MO_MACROS_DATA:
16897c478bd9Sstevel@tonic-gate 		if (macros == NULL)
16907c478bd9Sstevel@tonic-gate 			macros = MilterDataMacros;
16917c478bd9Sstevel@tonic-gate 
1692058561cbSjbeck 		r = milter_set_macros(name, macros, val, nummac);
1693058561cbSjbeck 		if (r >= 0)
1694058561cbSjbeck 			nummac = r;
16957c478bd9Sstevel@tonic-gate 		break;
16967c478bd9Sstevel@tonic-gate 
16977c478bd9Sstevel@tonic-gate 	  default:
16987c478bd9Sstevel@tonic-gate 		syserr("milter_set_option: invalid Milter option %s", name);
16997c478bd9Sstevel@tonic-gate 		break;
17007c478bd9Sstevel@tonic-gate 	}
17017c478bd9Sstevel@tonic-gate 	if (sticky)
17027c478bd9Sstevel@tonic-gate 		setbitn(mo->mo_code, StickyMilterOpt);
17037c478bd9Sstevel@tonic-gate }
1704058561cbSjbeck 
17057c478bd9Sstevel@tonic-gate /*
17067c478bd9Sstevel@tonic-gate **  MILTER_REOPEN_DF -- open & truncate the data file (for replbody)
17077c478bd9Sstevel@tonic-gate **
17087c478bd9Sstevel@tonic-gate **	Parameters:
17097c478bd9Sstevel@tonic-gate **		e -- current envelope.
17107c478bd9Sstevel@tonic-gate **
17117c478bd9Sstevel@tonic-gate **	Returns:
17127c478bd9Sstevel@tonic-gate **		0 if succesful, -1 otherwise
17137c478bd9Sstevel@tonic-gate */
17147c478bd9Sstevel@tonic-gate 
17157c478bd9Sstevel@tonic-gate static int
milter_reopen_df(e)17167c478bd9Sstevel@tonic-gate milter_reopen_df(e)
17177c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
17187c478bd9Sstevel@tonic-gate {
17197c478bd9Sstevel@tonic-gate 	char dfname[MAXPATHLEN];
17207c478bd9Sstevel@tonic-gate 
1721058561cbSjbeck 	(void) sm_strlcpy(dfname, queuename(e, DATAFL_LETTER), sizeof(dfname));
17227c478bd9Sstevel@tonic-gate 
17237c478bd9Sstevel@tonic-gate 	/*
17247c478bd9Sstevel@tonic-gate 	**  In SuperSafe == SAFE_REALLY mode, e->e_dfp is a read-only FP so
17257c478bd9Sstevel@tonic-gate 	**  close and reopen writable (later close and reopen
17267c478bd9Sstevel@tonic-gate 	**  read only again).
17277c478bd9Sstevel@tonic-gate 	**
17287c478bd9Sstevel@tonic-gate 	**  In SuperSafe != SAFE_REALLY mode, e->e_dfp still points at the
17297c478bd9Sstevel@tonic-gate 	**  buffered file I/O descriptor, still open for writing so there
17307c478bd9Sstevel@tonic-gate 	**  isn't any work to do here (except checking for consistency).
17317c478bd9Sstevel@tonic-gate 	*/
17327c478bd9Sstevel@tonic-gate 
17337c478bd9Sstevel@tonic-gate 	if (SuperSafe == SAFE_REALLY)
17347c478bd9Sstevel@tonic-gate 	{
17357c478bd9Sstevel@tonic-gate 		/* close read-only data file */
17367c478bd9Sstevel@tonic-gate 		if (bitset(EF_HAS_DF, e->e_flags) && e->e_dfp != NULL)
17377c478bd9Sstevel@tonic-gate 		{
17387c478bd9Sstevel@tonic-gate 			(void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT);
17397c478bd9Sstevel@tonic-gate 			e->e_flags &= ~EF_HAS_DF;
17407c478bd9Sstevel@tonic-gate 		}
17417c478bd9Sstevel@tonic-gate 
17427c478bd9Sstevel@tonic-gate 		/* open writable */
17437c478bd9Sstevel@tonic-gate 		if ((e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname,
17447c478bd9Sstevel@tonic-gate 					   SM_IO_RDWR_B, NULL)) == NULL)
17457c478bd9Sstevel@tonic-gate 		{
17467c478bd9Sstevel@tonic-gate 			MILTER_DF_ERROR("milter_reopen_df: sm_io_open %s: %s");
17477c478bd9Sstevel@tonic-gate 			return -1;
17487c478bd9Sstevel@tonic-gate 		}
17497c478bd9Sstevel@tonic-gate 	}
17507c478bd9Sstevel@tonic-gate 	else if (e->e_dfp == NULL)
17517c478bd9Sstevel@tonic-gate 	{
17527c478bd9Sstevel@tonic-gate 		/* shouldn't happen */
17537c478bd9Sstevel@tonic-gate 		errno = ENOENT;
17547c478bd9Sstevel@tonic-gate 		MILTER_DF_ERROR("milter_reopen_df: NULL e_dfp (%s: %s)");
17557c478bd9Sstevel@tonic-gate 		return -1;
17567c478bd9Sstevel@tonic-gate 	}
17577c478bd9Sstevel@tonic-gate 	return 0;
17587c478bd9Sstevel@tonic-gate }
1759058561cbSjbeck 
17607c478bd9Sstevel@tonic-gate /*
17617c478bd9Sstevel@tonic-gate **  MILTER_RESET_DF -- re-open read-only the data file (for replbody)
17627c478bd9Sstevel@tonic-gate **
17637c478bd9Sstevel@tonic-gate **	Parameters:
17647c478bd9Sstevel@tonic-gate **		e -- current envelope.
17657c478bd9Sstevel@tonic-gate **
17667c478bd9Sstevel@tonic-gate **	Returns:
17677c478bd9Sstevel@tonic-gate **		0 if succesful, -1 otherwise
17687c478bd9Sstevel@tonic-gate */
17697c478bd9Sstevel@tonic-gate 
17707c478bd9Sstevel@tonic-gate static int
milter_reset_df(e)17717c478bd9Sstevel@tonic-gate milter_reset_df(e)
17727c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
17737c478bd9Sstevel@tonic-gate {
17747c478bd9Sstevel@tonic-gate 	int afd;
17757c478bd9Sstevel@tonic-gate 	char dfname[MAXPATHLEN];
17767c478bd9Sstevel@tonic-gate 
1777058561cbSjbeck 	(void) sm_strlcpy(dfname, queuename(e, DATAFL_LETTER), sizeof(dfname));
17787c478bd9Sstevel@tonic-gate 
17797c478bd9Sstevel@tonic-gate 	if (sm_io_flush(e->e_dfp, SM_TIME_DEFAULT) != 0 ||
17807c478bd9Sstevel@tonic-gate 	    sm_io_error(e->e_dfp))
17817c478bd9Sstevel@tonic-gate 	{
17827c478bd9Sstevel@tonic-gate 		MILTER_DF_ERROR("milter_reset_df: error writing/flushing %s: %s");
17837c478bd9Sstevel@tonic-gate 		return -1;
17847c478bd9Sstevel@tonic-gate 	}
17857c478bd9Sstevel@tonic-gate 	else if (SuperSafe != SAFE_REALLY)
17867c478bd9Sstevel@tonic-gate 	{
17877c478bd9Sstevel@tonic-gate 		/* skip next few clauses */
17887c478bd9Sstevel@tonic-gate 		/* EMPTY */
17897c478bd9Sstevel@tonic-gate 	}
17907c478bd9Sstevel@tonic-gate 	else if ((afd = sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD, NULL)) >= 0
17917c478bd9Sstevel@tonic-gate 		 && fsync(afd) < 0)
17927c478bd9Sstevel@tonic-gate 	{
17937c478bd9Sstevel@tonic-gate 		MILTER_DF_ERROR("milter_reset_df: error sync'ing %s: %s");
17947c478bd9Sstevel@tonic-gate 		return -1;
17957c478bd9Sstevel@tonic-gate 	}
17967c478bd9Sstevel@tonic-gate 	else if (sm_io_close(e->e_dfp, SM_TIME_DEFAULT) < 0)
17977c478bd9Sstevel@tonic-gate 	{
17987c478bd9Sstevel@tonic-gate 		MILTER_DF_ERROR("milter_reset_df: error closing %s: %s");
17997c478bd9Sstevel@tonic-gate 		return -1;
18007c478bd9Sstevel@tonic-gate 	}
18017c478bd9Sstevel@tonic-gate 	else if ((e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname,
18027c478bd9Sstevel@tonic-gate 					SM_IO_RDONLY_B, NULL)) == NULL)
18037c478bd9Sstevel@tonic-gate 	{
18047c478bd9Sstevel@tonic-gate 		MILTER_DF_ERROR("milter_reset_df: error reopening %s: %s");
18057c478bd9Sstevel@tonic-gate 		return -1;
18067c478bd9Sstevel@tonic-gate 	}
18077c478bd9Sstevel@tonic-gate 	else
18087c478bd9Sstevel@tonic-gate 		e->e_flags |= EF_HAS_DF;
18097c478bd9Sstevel@tonic-gate 	return 0;
18107c478bd9Sstevel@tonic-gate }
1811058561cbSjbeck 
18127c478bd9Sstevel@tonic-gate /*
18137c478bd9Sstevel@tonic-gate **  MILTER_QUIT_FILTER -- close down a single filter
18147c478bd9Sstevel@tonic-gate **
18157c478bd9Sstevel@tonic-gate **	Parameters:
18167c478bd9Sstevel@tonic-gate **		m -- milter structure of filter to close down.
18177c478bd9Sstevel@tonic-gate **		e -- current envelope.
18187c478bd9Sstevel@tonic-gate **
18197c478bd9Sstevel@tonic-gate **	Returns:
18207c478bd9Sstevel@tonic-gate **		none
18217c478bd9Sstevel@tonic-gate */
18227c478bd9Sstevel@tonic-gate 
18237c478bd9Sstevel@tonic-gate static void
milter_quit_filter(m,e)18247c478bd9Sstevel@tonic-gate milter_quit_filter(m, e)
18257c478bd9Sstevel@tonic-gate 	struct milter *m;
18267c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
18277c478bd9Sstevel@tonic-gate {
18287c478bd9Sstevel@tonic-gate 	if (tTd(64, 10))
18297c478bd9Sstevel@tonic-gate 		sm_dprintf("milter_quit_filter(%s)\n", m->mf_name);
18307c478bd9Sstevel@tonic-gate 	if (MilterLogLevel > 18)
18317c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_INFO, e->e_id, "Milter (%s): quit filter",
18327c478bd9Sstevel@tonic-gate 			  m->mf_name);
18337c478bd9Sstevel@tonic-gate 
18347c478bd9Sstevel@tonic-gate 	/* Never replace error state */
18357c478bd9Sstevel@tonic-gate 	if (m->mf_state == SMFS_ERROR)
18367c478bd9Sstevel@tonic-gate 		return;
18377c478bd9Sstevel@tonic-gate 
18387c478bd9Sstevel@tonic-gate 	if (m->mf_sock < 0 ||
18397c478bd9Sstevel@tonic-gate 	    m->mf_state == SMFS_CLOSED ||
18407c478bd9Sstevel@tonic-gate 	    m->mf_state == SMFS_READY)
18417c478bd9Sstevel@tonic-gate 	{
18427c478bd9Sstevel@tonic-gate 		m->mf_sock = -1;
18437c478bd9Sstevel@tonic-gate 		m->mf_state = SMFS_CLOSED;
18447c478bd9Sstevel@tonic-gate 		return;
18457c478bd9Sstevel@tonic-gate 	}
18467c478bd9Sstevel@tonic-gate 
18477c478bd9Sstevel@tonic-gate 	(void) milter_write(m, SMFIC_QUIT, (char *) NULL, 0,
1848058561cbSjbeck 			    m->mf_timeout[SMFTO_WRITE], e, "quit_filter");
18497c478bd9Sstevel@tonic-gate 	if (m->mf_sock >= 0)
18507c478bd9Sstevel@tonic-gate 	{
18517c478bd9Sstevel@tonic-gate 		(void) close(m->mf_sock);
18527c478bd9Sstevel@tonic-gate 		m->mf_sock = -1;
18537c478bd9Sstevel@tonic-gate 	}
18547c478bd9Sstevel@tonic-gate 	if (m->mf_state != SMFS_ERROR)
18557c478bd9Sstevel@tonic-gate 		m->mf_state = SMFS_CLOSED;
18567c478bd9Sstevel@tonic-gate }
1857058561cbSjbeck 
18587c478bd9Sstevel@tonic-gate /*
18597c478bd9Sstevel@tonic-gate **  MILTER_ABORT_FILTER -- tell filter to abort current message
18607c478bd9Sstevel@tonic-gate **
18617c478bd9Sstevel@tonic-gate **	Parameters:
18627c478bd9Sstevel@tonic-gate **		m -- milter structure of filter to abort.
18637c478bd9Sstevel@tonic-gate **		e -- current envelope.
18647c478bd9Sstevel@tonic-gate **
18657c478bd9Sstevel@tonic-gate **	Returns:
18667c478bd9Sstevel@tonic-gate **		none
18677c478bd9Sstevel@tonic-gate */
18687c478bd9Sstevel@tonic-gate 
18697c478bd9Sstevel@tonic-gate static void
milter_abort_filter(m,e)18707c478bd9Sstevel@tonic-gate milter_abort_filter(m, e)
18717c478bd9Sstevel@tonic-gate 	struct milter *m;
18727c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
18737c478bd9Sstevel@tonic-gate {
18747c478bd9Sstevel@tonic-gate 	if (tTd(64, 10))
18757c478bd9Sstevel@tonic-gate 		sm_dprintf("milter_abort_filter(%s)\n", m->mf_name);
18767c478bd9Sstevel@tonic-gate 	if (MilterLogLevel > 10)
18777c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_INFO, e->e_id, "Milter (%s): abort filter",
18787c478bd9Sstevel@tonic-gate 			  m->mf_name);
18797c478bd9Sstevel@tonic-gate 
18807c478bd9Sstevel@tonic-gate 	if (m->mf_sock < 0 ||
18817c478bd9Sstevel@tonic-gate 	    m->mf_state != SMFS_INMSG)
18827c478bd9Sstevel@tonic-gate 		return;
18837c478bd9Sstevel@tonic-gate 
18847c478bd9Sstevel@tonic-gate 	(void) milter_write(m, SMFIC_ABORT, (char *) NULL, 0,
1885058561cbSjbeck 			    m->mf_timeout[SMFTO_WRITE], e, "abort_filter");
18867c478bd9Sstevel@tonic-gate 	if (m->mf_state != SMFS_ERROR)
18877c478bd9Sstevel@tonic-gate 		m->mf_state = SMFS_DONE;
18887c478bd9Sstevel@tonic-gate }
1889058561cbSjbeck 
18907c478bd9Sstevel@tonic-gate /*
18917c478bd9Sstevel@tonic-gate **  MILTER_SEND_MACROS -- provide macros to the filters
18927c478bd9Sstevel@tonic-gate **
18937c478bd9Sstevel@tonic-gate **	Parameters:
18947c478bd9Sstevel@tonic-gate **		m -- milter to send macros to.
18957c478bd9Sstevel@tonic-gate **		macros -- macros to send for filter smfi_getsymval().
18967c478bd9Sstevel@tonic-gate **		cmd -- which command the macros are associated with.
18977c478bd9Sstevel@tonic-gate **		e -- current envelope (for macro access).
18987c478bd9Sstevel@tonic-gate **
18997c478bd9Sstevel@tonic-gate **	Returns:
19007c478bd9Sstevel@tonic-gate **		none
19017c478bd9Sstevel@tonic-gate */
19027c478bd9Sstevel@tonic-gate 
19037c478bd9Sstevel@tonic-gate static void
milter_send_macros(m,macros,cmd,e)19047c478bd9Sstevel@tonic-gate milter_send_macros(m, macros, cmd, e)
19057c478bd9Sstevel@tonic-gate 	struct milter *m;
19067c478bd9Sstevel@tonic-gate 	char **macros;
1907058561cbSjbeck 	int cmd;
19087c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
19097c478bd9Sstevel@tonic-gate {
19107c478bd9Sstevel@tonic-gate 	int i;
19117c478bd9Sstevel@tonic-gate 	int mid;
1912058561cbSjbeck 	char command = (char) cmd;
19137c478bd9Sstevel@tonic-gate 	char *v;
19147c478bd9Sstevel@tonic-gate 	char *buf, *bp;
19157c478bd9Sstevel@tonic-gate 	char exp[MAXLINE];
19167c478bd9Sstevel@tonic-gate 	ssize_t s;
19177c478bd9Sstevel@tonic-gate 
19187c478bd9Sstevel@tonic-gate 	/* sanity check */
19197c478bd9Sstevel@tonic-gate 	if (macros == NULL || macros[0] == NULL)
19207c478bd9Sstevel@tonic-gate 		return;
19217c478bd9Sstevel@tonic-gate 
19227c478bd9Sstevel@tonic-gate 	/* put together data */
19237c478bd9Sstevel@tonic-gate 	s = 1;			/* for the command character */
19247c478bd9Sstevel@tonic-gate 	for (i = 0; macros[i] != NULL; i++)
19257c478bd9Sstevel@tonic-gate 	{
19267c478bd9Sstevel@tonic-gate 		mid = macid(macros[i]);
19277c478bd9Sstevel@tonic-gate 		if (mid == 0)
19287c478bd9Sstevel@tonic-gate 			continue;
19297c478bd9Sstevel@tonic-gate 		v = macvalue(mid, e);
19307c478bd9Sstevel@tonic-gate 		if (v == NULL)
19317c478bd9Sstevel@tonic-gate 			continue;
19327c478bd9Sstevel@tonic-gate 		expand(v, exp, sizeof(exp), e);
19337c478bd9Sstevel@tonic-gate 		s += strlen(macros[i]) + 1 + strlen(exp) + 1;
19347c478bd9Sstevel@tonic-gate 	}
19357c478bd9Sstevel@tonic-gate 
19367c478bd9Sstevel@tonic-gate 	if (s < 0)
19377c478bd9Sstevel@tonic-gate 		return;
19387c478bd9Sstevel@tonic-gate 
19397c478bd9Sstevel@tonic-gate 	buf = (char *) xalloc(s);
19407c478bd9Sstevel@tonic-gate 	bp = buf;
1941058561cbSjbeck 	*bp++ = command;
19427c478bd9Sstevel@tonic-gate 	for (i = 0; macros[i] != NULL; i++)
19437c478bd9Sstevel@tonic-gate 	{
19447c478bd9Sstevel@tonic-gate 		mid = macid(macros[i]);
19457c478bd9Sstevel@tonic-gate 		if (mid == 0)
19467c478bd9Sstevel@tonic-gate 			continue;
19477c478bd9Sstevel@tonic-gate 		v = macvalue(mid, e);
19487c478bd9Sstevel@tonic-gate 		if (v == NULL)
19497c478bd9Sstevel@tonic-gate 			continue;
19507c478bd9Sstevel@tonic-gate 		expand(v, exp, sizeof(exp), e);
19517c478bd9Sstevel@tonic-gate 
19527c478bd9Sstevel@tonic-gate 		if (tTd(64, 10))
19537c478bd9Sstevel@tonic-gate 			sm_dprintf("milter_send_macros(%s, %c): %s=%s\n",
1954058561cbSjbeck 				m->mf_name, command, macros[i], exp);
19557c478bd9Sstevel@tonic-gate 
19567c478bd9Sstevel@tonic-gate 		(void) sm_strlcpy(bp, macros[i], s - (bp - buf));
19577c478bd9Sstevel@tonic-gate 		bp += strlen(bp) + 1;
19587c478bd9Sstevel@tonic-gate 		(void) sm_strlcpy(bp, exp, s - (bp - buf));
19597c478bd9Sstevel@tonic-gate 		bp += strlen(bp) + 1;
19607c478bd9Sstevel@tonic-gate 	}
19617c478bd9Sstevel@tonic-gate 	(void) milter_write(m, SMFIC_MACRO, buf, s,
1962058561cbSjbeck 			    m->mf_timeout[SMFTO_WRITE], e, "send_macros");
19637c478bd9Sstevel@tonic-gate 	sm_free(buf);
19647c478bd9Sstevel@tonic-gate }
19657c478bd9Sstevel@tonic-gate 
19667c478bd9Sstevel@tonic-gate /*
19677c478bd9Sstevel@tonic-gate **  MILTER_SEND_COMMAND -- send a command and return the response for a filter
19687c478bd9Sstevel@tonic-gate **
19697c478bd9Sstevel@tonic-gate **	Parameters:
19707c478bd9Sstevel@tonic-gate **		m -- current milter filter
1971058561cbSjbeck **		cmd -- command to send.
19727c478bd9Sstevel@tonic-gate **		data -- optional command data.
19737c478bd9Sstevel@tonic-gate **		sz -- length of buf.
19747c478bd9Sstevel@tonic-gate **		e -- current envelope (for e->e_id).
19757c478bd9Sstevel@tonic-gate **		state -- return state word.
19767c478bd9Sstevel@tonic-gate **
19777c478bd9Sstevel@tonic-gate **	Returns:
19787c478bd9Sstevel@tonic-gate **		response string (may be NULL)
19797c478bd9Sstevel@tonic-gate */
19807c478bd9Sstevel@tonic-gate 
19817c478bd9Sstevel@tonic-gate static char *
milter_send_command(m,cmd,data,sz,e,state,where)1982058561cbSjbeck milter_send_command(m, cmd, data, sz, e, state, where)
19837c478bd9Sstevel@tonic-gate 	struct milter *m;
1984058561cbSjbeck 	int cmd;
19857c478bd9Sstevel@tonic-gate 	void *data;
19867c478bd9Sstevel@tonic-gate 	ssize_t sz;
19877c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
19887c478bd9Sstevel@tonic-gate 	char *state;
1989058561cbSjbeck 	const char *where;
19907c478bd9Sstevel@tonic-gate {
19917c478bd9Sstevel@tonic-gate 	char rcmd;
19927c478bd9Sstevel@tonic-gate 	ssize_t rlen;
19937c478bd9Sstevel@tonic-gate 	unsigned long skipflag;
19947c478bd9Sstevel@tonic-gate 	unsigned long norespflag = 0;
1995058561cbSjbeck 	char command = (char) cmd;
19967c478bd9Sstevel@tonic-gate 	char *action;
19977c478bd9Sstevel@tonic-gate 	char *defresponse;
19987c478bd9Sstevel@tonic-gate 	char *response;
19997c478bd9Sstevel@tonic-gate 
20007c478bd9Sstevel@tonic-gate 	if (tTd(64, 10))
20017c478bd9Sstevel@tonic-gate 		sm_dprintf("milter_send_command(%s): cmd %c len %ld\n",
20027c478bd9Sstevel@tonic-gate 			m->mf_name, (char) command, (long) sz);
20037c478bd9Sstevel@tonic-gate 
20047c478bd9Sstevel@tonic-gate 	/* find skip flag and default failure */
20057c478bd9Sstevel@tonic-gate 	switch (command)
20067c478bd9Sstevel@tonic-gate 	{
20077c478bd9Sstevel@tonic-gate 	  case SMFIC_CONNECT:
20087c478bd9Sstevel@tonic-gate 		skipflag = SMFIP_NOCONNECT;
2009058561cbSjbeck 		norespflag = SMFIP_NR_CONN;
20107c478bd9Sstevel@tonic-gate 		action = "connect";
20117c478bd9Sstevel@tonic-gate 		defresponse = "554 Command rejected";
20127c478bd9Sstevel@tonic-gate 		break;
20137c478bd9Sstevel@tonic-gate 
20147c478bd9Sstevel@tonic-gate 	  case SMFIC_HELO:
20157c478bd9Sstevel@tonic-gate 		skipflag = SMFIP_NOHELO;
2016058561cbSjbeck 		norespflag = SMFIP_NR_HELO;
20177c478bd9Sstevel@tonic-gate 		action = "helo";
20187c478bd9Sstevel@tonic-gate 		defresponse = "550 Command rejected";
20197c478bd9Sstevel@tonic-gate 		break;
20207c478bd9Sstevel@tonic-gate 
20217c478bd9Sstevel@tonic-gate 	  case SMFIC_MAIL:
20227c478bd9Sstevel@tonic-gate 		skipflag = SMFIP_NOMAIL;
2023058561cbSjbeck 		norespflag = SMFIP_NR_MAIL;
20247c478bd9Sstevel@tonic-gate 		action = "mail";
20257c478bd9Sstevel@tonic-gate 		defresponse = "550 5.7.1 Command rejected";
20267c478bd9Sstevel@tonic-gate 		break;
20277c478bd9Sstevel@tonic-gate 
20287c478bd9Sstevel@tonic-gate 	  case SMFIC_RCPT:
20297c478bd9Sstevel@tonic-gate 		skipflag = SMFIP_NORCPT;
2030058561cbSjbeck 		norespflag = SMFIP_NR_RCPT;
20317c478bd9Sstevel@tonic-gate 		action = "rcpt";
20327c478bd9Sstevel@tonic-gate 		defresponse = "550 5.7.1 Command rejected";
20337c478bd9Sstevel@tonic-gate 		break;
20347c478bd9Sstevel@tonic-gate 
20357c478bd9Sstevel@tonic-gate 	  case SMFIC_HEADER:
20367c478bd9Sstevel@tonic-gate 		skipflag = SMFIP_NOHDRS;
2037058561cbSjbeck 		norespflag = SMFIP_NR_HDR;
20387c478bd9Sstevel@tonic-gate 		action = "header";
20397c478bd9Sstevel@tonic-gate 		defresponse = "550 5.7.1 Command rejected";
20407c478bd9Sstevel@tonic-gate 		break;
20417c478bd9Sstevel@tonic-gate 
20427c478bd9Sstevel@tonic-gate 	  case SMFIC_BODY:
20437c478bd9Sstevel@tonic-gate 		skipflag = SMFIP_NOBODY;
2044058561cbSjbeck 		norespflag = SMFIP_NR_BODY;
20457c478bd9Sstevel@tonic-gate 		action = "body";
20467c478bd9Sstevel@tonic-gate 		defresponse = "554 5.7.1 Command rejected";
20477c478bd9Sstevel@tonic-gate 		break;
20487c478bd9Sstevel@tonic-gate 
20497c478bd9Sstevel@tonic-gate 	  case SMFIC_EOH:
20507c478bd9Sstevel@tonic-gate 		skipflag = SMFIP_NOEOH;
2051058561cbSjbeck 		norespflag = SMFIP_NR_EOH;
20527c478bd9Sstevel@tonic-gate 		action = "eoh";
20537c478bd9Sstevel@tonic-gate 		defresponse = "550 5.7.1 Command rejected";
20547c478bd9Sstevel@tonic-gate 		break;
20557c478bd9Sstevel@tonic-gate 
20567c478bd9Sstevel@tonic-gate 	  case SMFIC_UNKNOWN:
205749218d4fSjbeck 		skipflag = SMFIP_NOUNKNOWN;
2058058561cbSjbeck 		norespflag = SMFIP_NR_UNKN;
20597c478bd9Sstevel@tonic-gate 		action = "unknown";
20607c478bd9Sstevel@tonic-gate 		defresponse = "550 5.7.1 Command rejected";
20617c478bd9Sstevel@tonic-gate 		break;
20627c478bd9Sstevel@tonic-gate 
206349218d4fSjbeck 	  case SMFIC_DATA:
206449218d4fSjbeck 		skipflag = SMFIP_NODATA;
2065058561cbSjbeck 		norespflag = SMFIP_NR_DATA;
206649218d4fSjbeck 		action = "data";
206749218d4fSjbeck 		defresponse = "550 5.7.1 Command rejected";
206849218d4fSjbeck 		break;
206949218d4fSjbeck 
20707c478bd9Sstevel@tonic-gate 	  case SMFIC_BODYEOB:
20717c478bd9Sstevel@tonic-gate 	  case SMFIC_OPTNEG:
20727c478bd9Sstevel@tonic-gate 	  case SMFIC_MACRO:
20737c478bd9Sstevel@tonic-gate 	  case SMFIC_ABORT:
20747c478bd9Sstevel@tonic-gate 	  case SMFIC_QUIT:
20757c478bd9Sstevel@tonic-gate 		/* NOTE: not handled by milter_send_command() */
20767c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
20777c478bd9Sstevel@tonic-gate 
20787c478bd9Sstevel@tonic-gate 	  default:
20797c478bd9Sstevel@tonic-gate 		skipflag = 0;
20807c478bd9Sstevel@tonic-gate 		action = "default";
20817c478bd9Sstevel@tonic-gate 		defresponse = "550 5.7.1 Command rejected";
20827c478bd9Sstevel@tonic-gate 		break;
20837c478bd9Sstevel@tonic-gate 	}
20847c478bd9Sstevel@tonic-gate 
2085058561cbSjbeck 	if (tTd(64, 10))
2086058561cbSjbeck 		sm_dprintf("milter_send_command(%s): skip=%lx, pflags=%x\n",
2087058561cbSjbeck 			m->mf_name, skipflag, m->mf_pflags);
2088058561cbSjbeck 
20897c478bd9Sstevel@tonic-gate 	/* check if filter wants this command */
2090058561cbSjbeck 	if (skipflag != 0 && bitset(skipflag, m->mf_pflags))
20917c478bd9Sstevel@tonic-gate 		return NULL;
20927c478bd9Sstevel@tonic-gate 
20937c478bd9Sstevel@tonic-gate 	/* send the command to the filter */
20947c478bd9Sstevel@tonic-gate 	(void) milter_write(m, command, data, sz,
2095058561cbSjbeck 			    m->mf_timeout[SMFTO_WRITE], e, where);
20967c478bd9Sstevel@tonic-gate 	if (m->mf_state == SMFS_ERROR)
20977c478bd9Sstevel@tonic-gate 	{
20987c478bd9Sstevel@tonic-gate 		MILTER_CHECK_ERROR(false, return NULL);
20997c478bd9Sstevel@tonic-gate 		return NULL;
21007c478bd9Sstevel@tonic-gate 	}
21017c478bd9Sstevel@tonic-gate 
21027c478bd9Sstevel@tonic-gate 	/* check if filter sends response to this command */
21037c478bd9Sstevel@tonic-gate 	if (norespflag != 0 && bitset(norespflag, m->mf_pflags))
21047c478bd9Sstevel@tonic-gate 		return NULL;
21057c478bd9Sstevel@tonic-gate 
21067c478bd9Sstevel@tonic-gate 	/* get the response from the filter */
21077c478bd9Sstevel@tonic-gate 	response = milter_read(m, &rcmd, &rlen,
2108058561cbSjbeck 			       m->mf_timeout[SMFTO_READ], e, where);
21097c478bd9Sstevel@tonic-gate 	if (m->mf_state == SMFS_ERROR)
21107c478bd9Sstevel@tonic-gate 	{
21117c478bd9Sstevel@tonic-gate 		MILTER_CHECK_ERROR(false, return NULL);
21127c478bd9Sstevel@tonic-gate 		return NULL;
21137c478bd9Sstevel@tonic-gate 	}
21147c478bd9Sstevel@tonic-gate 
21157c478bd9Sstevel@tonic-gate 	if (tTd(64, 10))
21167c478bd9Sstevel@tonic-gate 		sm_dprintf("milter_send_command(%s): returned %c\n",
21177c478bd9Sstevel@tonic-gate 			   m->mf_name, (char) rcmd);
21187c478bd9Sstevel@tonic-gate 
21197c478bd9Sstevel@tonic-gate 	switch (rcmd)
21207c478bd9Sstevel@tonic-gate 	{
21217c478bd9Sstevel@tonic-gate 	  case SMFIR_REPLYCODE:
21227c478bd9Sstevel@tonic-gate 		MILTER_CHECK_REPLYCODE(defresponse);
21237c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 10)
2124058561cbSjbeck 			sm_syslog(LOG_INFO, e->e_id,
2125058561cbSjbeck 				  "milter=%s, action=%s, reject=%s",
21267c478bd9Sstevel@tonic-gate 				  m->mf_name, action, response);
21277c478bd9Sstevel@tonic-gate 		*state = rcmd;
21287c478bd9Sstevel@tonic-gate 		break;
21297c478bd9Sstevel@tonic-gate 
21307c478bd9Sstevel@tonic-gate 	  case SMFIR_REJECT:
21317c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 10)
2132058561cbSjbeck 			sm_syslog(LOG_INFO, e->e_id,
2133058561cbSjbeck 				  "milter=%s, action=%s, reject",
21347c478bd9Sstevel@tonic-gate 				  m->mf_name, action);
21357c478bd9Sstevel@tonic-gate 		*state = rcmd;
21367c478bd9Sstevel@tonic-gate 		break;
21377c478bd9Sstevel@tonic-gate 
21387c478bd9Sstevel@tonic-gate 	  case SMFIR_DISCARD:
21397c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 10)
2140058561cbSjbeck 			sm_syslog(LOG_INFO, e->e_id,
2141058561cbSjbeck 				  "milter=%s, action=%s, discard",
21427c478bd9Sstevel@tonic-gate 				  m->mf_name, action);
21437c478bd9Sstevel@tonic-gate 		*state = rcmd;
21447c478bd9Sstevel@tonic-gate 		break;
21457c478bd9Sstevel@tonic-gate 
21467c478bd9Sstevel@tonic-gate 	  case SMFIR_TEMPFAIL:
21477c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 10)
2148058561cbSjbeck 			sm_syslog(LOG_INFO, e->e_id,
2149058561cbSjbeck 				  "milter=%s, action=%s, tempfail",
21507c478bd9Sstevel@tonic-gate 				  m->mf_name, action);
21517c478bd9Sstevel@tonic-gate 		*state = rcmd;
21527c478bd9Sstevel@tonic-gate 		break;
21537c478bd9Sstevel@tonic-gate 
21547c478bd9Sstevel@tonic-gate 	  case SMFIR_ACCEPT:
21557c478bd9Sstevel@tonic-gate 		/* this filter is done with message/connection */
21567c478bd9Sstevel@tonic-gate 		if (command == SMFIC_HELO ||
21577c478bd9Sstevel@tonic-gate 		    command == SMFIC_CONNECT)
21587c478bd9Sstevel@tonic-gate 			m->mf_state = SMFS_CLOSABLE;
21597c478bd9Sstevel@tonic-gate 		else
21607c478bd9Sstevel@tonic-gate 			m->mf_state = SMFS_DONE;
21617c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 10)
2162058561cbSjbeck 			sm_syslog(LOG_INFO, e->e_id,
2163058561cbSjbeck 				  "milter=%s, action=%s, accepted",
21647c478bd9Sstevel@tonic-gate 				  m->mf_name, action);
21657c478bd9Sstevel@tonic-gate 		break;
21667c478bd9Sstevel@tonic-gate 
21677c478bd9Sstevel@tonic-gate 	  case SMFIR_CONTINUE:
21687c478bd9Sstevel@tonic-gate 		/* if MAIL command is ok, filter is in message state */
21697c478bd9Sstevel@tonic-gate 		if (command == SMFIC_MAIL)
21707c478bd9Sstevel@tonic-gate 			m->mf_state = SMFS_INMSG;
21717c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 12)
2172058561cbSjbeck 			sm_syslog(LOG_INFO, e->e_id,
2173058561cbSjbeck 				  "milter=%s, action=%s, continue",
2174058561cbSjbeck 				  m->mf_name, action);
2175058561cbSjbeck 		break;
2176058561cbSjbeck 
2177058561cbSjbeck 	  case SMFIR_SKIP:
2178058561cbSjbeck 		if (MilterLogLevel > 12)
2179058561cbSjbeck 			sm_syslog(LOG_INFO, e->e_id,
2180058561cbSjbeck 				  "milter=%s, action=%s, skip",
21817c478bd9Sstevel@tonic-gate 				  m->mf_name, action);
2182058561cbSjbeck 		m->mf_state = SMFS_SKIP;
21837c478bd9Sstevel@tonic-gate 		break;
21847c478bd9Sstevel@tonic-gate 
21857c478bd9Sstevel@tonic-gate 	  default:
21867c478bd9Sstevel@tonic-gate 		/* Invalid response to command */
21877c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 0)
21887c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_ERR, e->e_id,
21897c478bd9Sstevel@tonic-gate 				  "milter_send_command(%s): action=%s returned bogus response %c",
21907c478bd9Sstevel@tonic-gate 				  m->mf_name, action, rcmd);
21917c478bd9Sstevel@tonic-gate 		milter_error(m, e);
21927c478bd9Sstevel@tonic-gate 		break;
21937c478bd9Sstevel@tonic-gate 	}
21947c478bd9Sstevel@tonic-gate 
2195058561cbSjbeck 	if (*state != SMFIR_REPLYCODE && response != NULL)
21967c478bd9Sstevel@tonic-gate 	{
21977c478bd9Sstevel@tonic-gate 		sm_free(response); /* XXX */
21987c478bd9Sstevel@tonic-gate 		response = NULL;
21997c478bd9Sstevel@tonic-gate 	}
22007c478bd9Sstevel@tonic-gate 	return response;
22017c478bd9Sstevel@tonic-gate }
22027c478bd9Sstevel@tonic-gate 
22037c478bd9Sstevel@tonic-gate /*
22047c478bd9Sstevel@tonic-gate **  MILTER_COMMAND -- send a command and return the response for each filter
22057c478bd9Sstevel@tonic-gate **
22067c478bd9Sstevel@tonic-gate **	Parameters:
2207058561cbSjbeck **		cmd -- command to send.
22087c478bd9Sstevel@tonic-gate **		data -- optional command data.
22097c478bd9Sstevel@tonic-gate **		sz -- length of buf.
22107c478bd9Sstevel@tonic-gate **		macros -- macros to send for filter smfi_getsymval().
22117c478bd9Sstevel@tonic-gate **		e -- current envelope (for macro access).
22127c478bd9Sstevel@tonic-gate **		state -- return state word.
2213058561cbSjbeck **		where -- description of calling function (logging).
2214058561cbSjbeck **		cmd_error -- did the SMTP command cause an error?
22157c478bd9Sstevel@tonic-gate **
22167c478bd9Sstevel@tonic-gate **	Returns:
22177c478bd9Sstevel@tonic-gate **		response string (may be NULL)
22187c478bd9Sstevel@tonic-gate */
22197c478bd9Sstevel@tonic-gate 
22207c478bd9Sstevel@tonic-gate static char *
milter_command(cmd,data,sz,macros,e,state,where,cmd_error)2221058561cbSjbeck milter_command(cmd, data, sz, macros, e, state, where, cmd_error)
2222058561cbSjbeck 	int cmd;
22237c478bd9Sstevel@tonic-gate 	void *data;
22247c478bd9Sstevel@tonic-gate 	ssize_t sz;
22257c478bd9Sstevel@tonic-gate 	char **macros;
22267c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
22277c478bd9Sstevel@tonic-gate 	char *state;
2228058561cbSjbeck 	const char *where;
2229058561cbSjbeck 	bool cmd_error;
22307c478bd9Sstevel@tonic-gate {
22317c478bd9Sstevel@tonic-gate 	int i;
2232058561cbSjbeck 	char command = (char) cmd;
22337c478bd9Sstevel@tonic-gate 	char *response = NULL;
22347c478bd9Sstevel@tonic-gate 	time_t tn = 0;
22357c478bd9Sstevel@tonic-gate 
22367c478bd9Sstevel@tonic-gate 	if (tTd(64, 10))
22377c478bd9Sstevel@tonic-gate 		sm_dprintf("milter_command: cmd %c len %ld\n",
2238058561cbSjbeck 			command, (long) sz);
22397c478bd9Sstevel@tonic-gate 
22407c478bd9Sstevel@tonic-gate 	*state = SMFIR_CONTINUE;
22417c478bd9Sstevel@tonic-gate 	for (i = 0; InputFilters[i] != NULL; i++)
22427c478bd9Sstevel@tonic-gate 	{
22437c478bd9Sstevel@tonic-gate 		struct milter *m = InputFilters[i];
22447c478bd9Sstevel@tonic-gate 
22457c478bd9Sstevel@tonic-gate 		/* previous problem? */
22467c478bd9Sstevel@tonic-gate 		if (m->mf_state == SMFS_ERROR)
22477c478bd9Sstevel@tonic-gate 		{
22487c478bd9Sstevel@tonic-gate 			MILTER_CHECK_ERROR(false, continue);
22497c478bd9Sstevel@tonic-gate 			break;
22507c478bd9Sstevel@tonic-gate 		}
22517c478bd9Sstevel@tonic-gate 
22527c478bd9Sstevel@tonic-gate 		/* sanity check */
22537c478bd9Sstevel@tonic-gate 		if (m->mf_sock < 0 ||
22547c478bd9Sstevel@tonic-gate 		    (m->mf_state != SMFS_OPEN && m->mf_state != SMFS_INMSG))
22557c478bd9Sstevel@tonic-gate 			continue;
22567c478bd9Sstevel@tonic-gate 
22577c478bd9Sstevel@tonic-gate 		/* send macros (regardless of whether we send command) */
22587c478bd9Sstevel@tonic-gate 		if (macros != NULL && macros[0] != NULL)
22597c478bd9Sstevel@tonic-gate 		{
22607c478bd9Sstevel@tonic-gate 			milter_send_macros(m, macros, command, e);
22617c478bd9Sstevel@tonic-gate 			if (m->mf_state == SMFS_ERROR)
22627c478bd9Sstevel@tonic-gate 			{
22637c478bd9Sstevel@tonic-gate 				MILTER_CHECK_ERROR(false, continue);
22647c478bd9Sstevel@tonic-gate 				break;
22657c478bd9Sstevel@tonic-gate 			}
22667c478bd9Sstevel@tonic-gate 		}
22677c478bd9Sstevel@tonic-gate 
22687c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 21)
22697c478bd9Sstevel@tonic-gate 			tn = curtime();
22707c478bd9Sstevel@tonic-gate 
2271058561cbSjbeck 		/*
2272058561cbSjbeck 		**  send the command if
2273058561cbSjbeck 		**	there is no error
2274058561cbSjbeck 		**	or it's RCPT and the client asked for it:
2275058561cbSjbeck 		**	!cmd_error ||
2276058561cbSjbeck 		**	where == "rcpt" && m->mf_pflags & SMFIP_RCPT_REJ != 0
2277058561cbSjbeck 		**  negate that condition and use continue
2278058561cbSjbeck 		*/
2279058561cbSjbeck 
2280058561cbSjbeck 		if (cmd_error &&
2281058561cbSjbeck 		    (strcmp(where, "rcpt") != 0 ||
2282058561cbSjbeck 		     (m->mf_pflags & SMFIP_RCPT_REJ) == 0))
2283058561cbSjbeck 			continue;
2284058561cbSjbeck 
2285058561cbSjbeck 		response = milter_send_command(m, command, data, sz, e, state,
2286058561cbSjbeck 						where);
22877c478bd9Sstevel@tonic-gate 
22887c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 21)
22897c478bd9Sstevel@tonic-gate 		{
22907c478bd9Sstevel@tonic-gate 			/* log the time it took for the command per filter */
22917c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_INFO, e->e_id,
22927c478bd9Sstevel@tonic-gate 				  "Milter (%s): time command (%c), %d",
22937c478bd9Sstevel@tonic-gate 				  m->mf_name, command, (int) (tn - curtime()));
22947c478bd9Sstevel@tonic-gate 		}
22957c478bd9Sstevel@tonic-gate 
22967c478bd9Sstevel@tonic-gate 		if (*state != SMFIR_CONTINUE)
22977c478bd9Sstevel@tonic-gate 			break;
22987c478bd9Sstevel@tonic-gate 	}
22997c478bd9Sstevel@tonic-gate 	return response;
23007c478bd9Sstevel@tonic-gate }
2301058561cbSjbeck 
2302058561cbSjbeck static int milter_getsymlist __P((struct milter *, char *, int, int));
2303058561cbSjbeck 
2304058561cbSjbeck static int
milter_getsymlist(m,buf,rlen,offset)2305058561cbSjbeck milter_getsymlist(m, buf, rlen, offset)
2306058561cbSjbeck 	struct milter *m;
2307058561cbSjbeck 	char *buf;
2308058561cbSjbeck 	int rlen;
2309058561cbSjbeck 	int offset;
2310058561cbSjbeck {
2311058561cbSjbeck 	int i, r, nummac;
2312058561cbSjbeck 	mi_int32 v;
2313058561cbSjbeck 
2314058561cbSjbeck 	SM_ASSERT(m != NULL);
2315058561cbSjbeck 	SM_ASSERT(buf != NULL);
2316058561cbSjbeck 
2317058561cbSjbeck 	while (offset + MILTER_LEN_BYTES < rlen)
2318058561cbSjbeck 	{
2319058561cbSjbeck 		size_t len;
2320058561cbSjbeck 		char **macros;
2321058561cbSjbeck 
2322058561cbSjbeck 		nummac = 0;
2323058561cbSjbeck 		(void) memcpy((char *) &v, buf + offset, MILTER_LEN_BYTES);
2324058561cbSjbeck 		i = ntohl(v);
2325058561cbSjbeck 		if (i < SMFIM_FIRST || i > SMFIM_LAST)
2326058561cbSjbeck 			return -1;
2327058561cbSjbeck 		offset += MILTER_LEN_BYTES;
2328058561cbSjbeck 		macros = NULL;
2329058561cbSjbeck 
2330058561cbSjbeck 		switch (i)
2331058561cbSjbeck 		{
2332058561cbSjbeck 		  case MO_MACROS_CONNECT:
2333058561cbSjbeck 			if (macros == NULL)
2334058561cbSjbeck 				macros = MilterConnectMacros;
2335058561cbSjbeck 			/* FALLTHROUGH */
2336058561cbSjbeck 
2337058561cbSjbeck 		  case MO_MACROS_HELO:
2338058561cbSjbeck 			if (macros == NULL)
2339058561cbSjbeck 				macros = MilterHeloMacros;
2340058561cbSjbeck 			/* FALLTHROUGH */
2341058561cbSjbeck 
2342058561cbSjbeck 		  case MO_MACROS_ENVFROM:
2343058561cbSjbeck 			if (macros == NULL)
2344058561cbSjbeck 				macros = MilterEnvFromMacros;
2345058561cbSjbeck 			/* FALLTHROUGH */
2346058561cbSjbeck 
2347058561cbSjbeck 		  case MO_MACROS_ENVRCPT:
2348058561cbSjbeck 			if (macros == NULL)
2349058561cbSjbeck 				macros = MilterEnvRcptMacros;
2350058561cbSjbeck 			/* FALLTHROUGH */
2351058561cbSjbeck 
2352058561cbSjbeck 		  case MO_MACROS_EOM:
2353058561cbSjbeck 			if (macros == NULL)
2354058561cbSjbeck 				macros = MilterEOMMacros;
2355058561cbSjbeck 			/* FALLTHROUGH */
2356058561cbSjbeck 
2357058561cbSjbeck 		  case MO_MACROS_EOH:
2358058561cbSjbeck 			if (macros == NULL)
2359058561cbSjbeck 				macros = MilterEOHMacros;
2360058561cbSjbeck 			/* FALLTHROUGH */
2361058561cbSjbeck 
2362058561cbSjbeck 		  case MO_MACROS_DATA:
2363058561cbSjbeck 			if (macros == NULL)
2364058561cbSjbeck 				macros = MilterDataMacros;
2365058561cbSjbeck 
2366058561cbSjbeck 			len = strlen(buf + offset);
2367058561cbSjbeck 			if (len > 0)
2368058561cbSjbeck 			{
2369058561cbSjbeck 				r = milter_set_macros(m->mf_name, macros,
2370058561cbSjbeck 						buf + offset, nummac);
2371058561cbSjbeck 				if (r >= 0)
2372058561cbSjbeck 					nummac = r;
2373058561cbSjbeck 			}
2374058561cbSjbeck 			break;
2375058561cbSjbeck 
2376058561cbSjbeck 		  default:
2377058561cbSjbeck 			return -1;
2378058561cbSjbeck 		}
2379058561cbSjbeck 		if (len == 0)
2380058561cbSjbeck 			return -1;
2381058561cbSjbeck 		offset += len + 1;
2382058561cbSjbeck 	}
2383058561cbSjbeck 
2384058561cbSjbeck 	return 0;
2385058561cbSjbeck }
2386058561cbSjbeck 
23877c478bd9Sstevel@tonic-gate /*
23887c478bd9Sstevel@tonic-gate **  MILTER_NEGOTIATE -- get version and flags from filter
23897c478bd9Sstevel@tonic-gate **
23907c478bd9Sstevel@tonic-gate **	Parameters:
23917c478bd9Sstevel@tonic-gate **		m -- milter filter structure.
23927c478bd9Sstevel@tonic-gate **		e -- current envelope.
23937800901eSjbeck **		milters -- milters structure.
23947c478bd9Sstevel@tonic-gate **
23957c478bd9Sstevel@tonic-gate **	Returns:
23967c478bd9Sstevel@tonic-gate **		0 on success, -1 otherwise
23977c478bd9Sstevel@tonic-gate */
23987c478bd9Sstevel@tonic-gate 
23997c478bd9Sstevel@tonic-gate static int
milter_negotiate(m,e,milters)24007800901eSjbeck milter_negotiate(m, e, milters)
24017c478bd9Sstevel@tonic-gate 	struct milter *m;
24027c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
24037800901eSjbeck 	milters_T *milters;
24047c478bd9Sstevel@tonic-gate {
24057c478bd9Sstevel@tonic-gate 	char rcmd;
2406058561cbSjbeck 	mi_int32 fvers, fflags, pflags;
2407058561cbSjbeck 	mi_int32 mta_prot_vers, mta_prot_flags, mta_actions;
24087c478bd9Sstevel@tonic-gate 	ssize_t rlen;
240949218d4fSjbeck 	char *response;
24107c478bd9Sstevel@tonic-gate 	char data[MILTER_OPTLEN];
24117c478bd9Sstevel@tonic-gate 
24127c478bd9Sstevel@tonic-gate 	/* sanity check */
24137c478bd9Sstevel@tonic-gate 	if (m->mf_sock < 0 || m->mf_state != SMFS_OPEN)
24147c478bd9Sstevel@tonic-gate 	{
24157c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 0)
24167c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_ERR, e->e_id,
24177c478bd9Sstevel@tonic-gate 				  "Milter (%s): negotiate, impossible state",
24187c478bd9Sstevel@tonic-gate 				  m->mf_name);
24197c478bd9Sstevel@tonic-gate 		milter_error(m, e);
24207c478bd9Sstevel@tonic-gate 		return -1;
24217c478bd9Sstevel@tonic-gate 	}
24227c478bd9Sstevel@tonic-gate 
24234aac33d3Sjbeck #if _FFR_MILTER_CHECK
2424058561cbSjbeck 	mta_prot_vers = m->mf_mta_prot_version;
2425058561cbSjbeck 	mta_prot_flags = m->mf_mta_prot_flags;
2426058561cbSjbeck 	mta_actions = m->mf_mta_actions;
24274aac33d3Sjbeck #else /* _FFR_MILTER_CHECK */
2428058561cbSjbeck 	mta_prot_vers = SMFI_PROT_VERSION;
2429058561cbSjbeck 	mta_prot_flags = SMFI_CURR_PROT;
2430058561cbSjbeck 	mta_actions = SMFI_CURR_ACTS;
24314aac33d3Sjbeck #endif /* _FFR_MILTER_CHECK */
2432*e9af4bc0SJohn Beck #if _FFR_MDS_NEGOTIATE
2433*e9af4bc0SJohn Beck 	if (MilterMaxDataSize == MILTER_MDS_256K)
2434*e9af4bc0SJohn Beck 		mta_prot_flags |= SMFIP_MDS_256K;
2435*e9af4bc0SJohn Beck 	else if (MilterMaxDataSize == MILTER_MDS_1M)
2436*e9af4bc0SJohn Beck 		mta_prot_flags |= SMFIP_MDS_1M;
2437*e9af4bc0SJohn Beck #endif /* _FFR_MDS_NEGOTIATE */
2438058561cbSjbeck 
2439058561cbSjbeck 	fvers = htonl(mta_prot_vers);
2440058561cbSjbeck 	pflags = htonl(mta_prot_flags);
2441058561cbSjbeck 	fflags = htonl(mta_actions);
24427c478bd9Sstevel@tonic-gate 	(void) memcpy(data, (char *) &fvers, MILTER_LEN_BYTES);
24437c478bd9Sstevel@tonic-gate 	(void) memcpy(data + MILTER_LEN_BYTES,
24447c478bd9Sstevel@tonic-gate 		      (char *) &fflags, MILTER_LEN_BYTES);
24457c478bd9Sstevel@tonic-gate 	(void) memcpy(data + (MILTER_LEN_BYTES * 2),
24467c478bd9Sstevel@tonic-gate 		      (char *) &pflags, MILTER_LEN_BYTES);
2447058561cbSjbeck 	(void) milter_write(m, SMFIC_OPTNEG, data, sizeof(data),
2448058561cbSjbeck 			    m->mf_timeout[SMFTO_WRITE], e, "negotiate");
24497c478bd9Sstevel@tonic-gate 
24507c478bd9Sstevel@tonic-gate 	if (m->mf_state == SMFS_ERROR)
24517c478bd9Sstevel@tonic-gate 		return -1;
24527c478bd9Sstevel@tonic-gate 
2453058561cbSjbeck 	if (tTd(64, 5))
2454058561cbSjbeck 		sm_dprintf("milter_negotiate(%s): send: version %lu, fflags 0x%lx, pflags 0x%lx\n",
2455058561cbSjbeck 			m->mf_name, ntohl(fvers), ntohl(fflags), ntohl(pflags));
2456058561cbSjbeck 
2457058561cbSjbeck 	response = milter_read(m, &rcmd, &rlen, m->mf_timeout[SMFTO_READ], e,
2458058561cbSjbeck 				"negotiate");
24597c478bd9Sstevel@tonic-gate 	if (m->mf_state == SMFS_ERROR)
24607c478bd9Sstevel@tonic-gate 		return -1;
24617c478bd9Sstevel@tonic-gate 
24627c478bd9Sstevel@tonic-gate 	if (rcmd != SMFIC_OPTNEG)
24637c478bd9Sstevel@tonic-gate 	{
24647c478bd9Sstevel@tonic-gate 		if (tTd(64, 5))
24657c478bd9Sstevel@tonic-gate 			sm_dprintf("milter_negotiate(%s): returned %c instead of %c\n",
24667c478bd9Sstevel@tonic-gate 				m->mf_name, rcmd, SMFIC_OPTNEG);
24677c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 0)
24687c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_ERR, e->e_id,
24697c478bd9Sstevel@tonic-gate 				  "Milter (%s): negotiate: returned %c instead of %c",
24707c478bd9Sstevel@tonic-gate 				  m->mf_name, rcmd, SMFIC_OPTNEG);
24717c478bd9Sstevel@tonic-gate 		if (response != NULL)
24727c478bd9Sstevel@tonic-gate 			sm_free(response); /* XXX */
24737c478bd9Sstevel@tonic-gate 		milter_error(m, e);
24747c478bd9Sstevel@tonic-gate 		return -1;
24757c478bd9Sstevel@tonic-gate 	}
24767c478bd9Sstevel@tonic-gate 
24777c478bd9Sstevel@tonic-gate 	/* Make sure we have enough bytes for the version */
24787c478bd9Sstevel@tonic-gate 	if (response == NULL || rlen < MILTER_LEN_BYTES)
24797c478bd9Sstevel@tonic-gate 	{
24807c478bd9Sstevel@tonic-gate 		if (tTd(64, 5))
24817c478bd9Sstevel@tonic-gate 			sm_dprintf("milter_negotiate(%s): did not return valid info\n",
24827c478bd9Sstevel@tonic-gate 				m->mf_name);
24837c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 0)
24847c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_ERR, e->e_id,
24857c478bd9Sstevel@tonic-gate 				  "Milter (%s): negotiate: did not return valid info",
24867c478bd9Sstevel@tonic-gate 				  m->mf_name);
24877c478bd9Sstevel@tonic-gate 		if (response != NULL)
24887c478bd9Sstevel@tonic-gate 			sm_free(response); /* XXX */
24897c478bd9Sstevel@tonic-gate 		milter_error(m, e);
24907c478bd9Sstevel@tonic-gate 		return -1;
24917c478bd9Sstevel@tonic-gate 	}
24927c478bd9Sstevel@tonic-gate 
24937c478bd9Sstevel@tonic-gate 	/* extract information */
24947c478bd9Sstevel@tonic-gate 	(void) memcpy((char *) &fvers, response, MILTER_LEN_BYTES);
24957c478bd9Sstevel@tonic-gate 
24967c478bd9Sstevel@tonic-gate 	/* Now make sure we have enough for the feature bitmap */
2497058561cbSjbeck 	if (rlen < MILTER_OPTLEN)
24987c478bd9Sstevel@tonic-gate 	{
24997c478bd9Sstevel@tonic-gate 		if (tTd(64, 5))
25007c478bd9Sstevel@tonic-gate 			sm_dprintf("milter_negotiate(%s): did not return enough info\n",
25017c478bd9Sstevel@tonic-gate 				m->mf_name);
25027c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 0)
25037c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_ERR, e->e_id,
25047c478bd9Sstevel@tonic-gate 				  "Milter (%s): negotiate: did not return enough info",
25057c478bd9Sstevel@tonic-gate 				  m->mf_name);
25067c478bd9Sstevel@tonic-gate 		if (response != NULL)
25077c478bd9Sstevel@tonic-gate 			sm_free(response); /* XXX */
25087c478bd9Sstevel@tonic-gate 		milter_error(m, e);
25097c478bd9Sstevel@tonic-gate 		return -1;
25107c478bd9Sstevel@tonic-gate 	}
25117c478bd9Sstevel@tonic-gate 
25127c478bd9Sstevel@tonic-gate 	(void) memcpy((char *) &fflags, response + MILTER_LEN_BYTES,
25137c478bd9Sstevel@tonic-gate 		      MILTER_LEN_BYTES);
25147c478bd9Sstevel@tonic-gate 	(void) memcpy((char *) &pflags, response + (MILTER_LEN_BYTES * 2),
25157c478bd9Sstevel@tonic-gate 		      MILTER_LEN_BYTES);
25167c478bd9Sstevel@tonic-gate 
25177c478bd9Sstevel@tonic-gate 	m->mf_fvers = ntohl(fvers);
25187c478bd9Sstevel@tonic-gate 	m->mf_fflags = ntohl(fflags);
25197c478bd9Sstevel@tonic-gate 	m->mf_pflags = ntohl(pflags);
25207c478bd9Sstevel@tonic-gate 
25217c478bd9Sstevel@tonic-gate 	/* check for version compatibility */
25227c478bd9Sstevel@tonic-gate 	if (m->mf_fvers == 1 ||
25237c478bd9Sstevel@tonic-gate 	    m->mf_fvers > SMFI_VERSION)
25247c478bd9Sstevel@tonic-gate 	{
25257c478bd9Sstevel@tonic-gate 		if (tTd(64, 5))
25267c478bd9Sstevel@tonic-gate 			sm_dprintf("milter_negotiate(%s): version %d != MTA milter version %d\n",
25277c478bd9Sstevel@tonic-gate 				m->mf_name, m->mf_fvers, SMFI_VERSION);
25287c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 0)
25297c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_ERR, e->e_id,
25307c478bd9Sstevel@tonic-gate 				  "Milter (%s): negotiate: version %d != MTA milter version %d",
25317c478bd9Sstevel@tonic-gate 				  m->mf_name, m->mf_fvers, SMFI_VERSION);
25327c478bd9Sstevel@tonic-gate 		milter_error(m, e);
2533058561cbSjbeck 		goto error;
25347c478bd9Sstevel@tonic-gate 	}
25357c478bd9Sstevel@tonic-gate 
25367c478bd9Sstevel@tonic-gate 	/* check for filter feature mismatch */
2537058561cbSjbeck 	if ((m->mf_fflags & mta_actions) != m->mf_fflags)
25387c478bd9Sstevel@tonic-gate 	{
25397c478bd9Sstevel@tonic-gate 		if (tTd(64, 5))
25407c478bd9Sstevel@tonic-gate 			sm_dprintf("milter_negotiate(%s): filter abilities 0x%x != MTA milter abilities 0x%lx\n",
25417c478bd9Sstevel@tonic-gate 				m->mf_name, m->mf_fflags,
2542058561cbSjbeck 				(unsigned long) mta_actions);
25437c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 0)
25447c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_ERR, e->e_id,
25457c478bd9Sstevel@tonic-gate 				  "Milter (%s): negotiate: filter abilities 0x%x != MTA milter abilities 0x%lx",
25467c478bd9Sstevel@tonic-gate 				  m->mf_name, m->mf_fflags,
2547058561cbSjbeck 				  (unsigned long) mta_actions);
25487c478bd9Sstevel@tonic-gate 		milter_error(m, e);
2549058561cbSjbeck 		goto error;
25507c478bd9Sstevel@tonic-gate 	}
25517c478bd9Sstevel@tonic-gate 
2552*e9af4bc0SJohn Beck #if _FFR_MDS_NEGOTIATE
2553*e9af4bc0SJohn Beck 	/* use a table instead of sequence? */
2554*e9af4bc0SJohn Beck 	if (bitset(SMFIP_MDS_1M, m->mf_pflags))
2555*e9af4bc0SJohn Beck 	{
2556*e9af4bc0SJohn Beck 		if (MilterMaxDataSize != MILTER_MDS_1M)
2557*e9af4bc0SJohn Beck 		{
2558*e9af4bc0SJohn Beck 			/* this should not happen... */
2559*e9af4bc0SJohn Beck 			sm_syslog(LOG_WARNING, NOQID,
2560*e9af4bc0SJohn Beck 				  "WARNING: Milter.maxdatasize: configured=%d, set by libmilter=%d",
2561*e9af4bc0SJohn Beck 		    		  MilterMaxDataSize, MILTER_MDS_1M);
2562*e9af4bc0SJohn Beck 			MilterMaxDataSize = MILTER_MDS_1M;
2563*e9af4bc0SJohn Beck 		}
2564*e9af4bc0SJohn Beck 	}
2565*e9af4bc0SJohn Beck 	else if (bitset(SMFIP_MDS_256K, m->mf_pflags))
2566*e9af4bc0SJohn Beck 	{
2567*e9af4bc0SJohn Beck 		if (MilterMaxDataSize != MILTER_MDS_256K)
2568*e9af4bc0SJohn Beck 		{
2569*e9af4bc0SJohn Beck 			sm_syslog(LOG_WARNING, NOQID,
2570*e9af4bc0SJohn Beck 				  "WARNING: Milter.maxdatasize: configured=%d, set by libmilter=%d",
2571*e9af4bc0SJohn Beck 		    		  MilterMaxDataSize, MILTER_MDS_256K);
2572*e9af4bc0SJohn Beck 			MilterMaxDataSize = MILTER_MDS_256K;
2573*e9af4bc0SJohn Beck 		}
2574*e9af4bc0SJohn Beck 	}
2575*e9af4bc0SJohn Beck 	else if (MilterMaxDataSize != MILTER_MDS_64K)
2576*e9af4bc0SJohn Beck 	{
2577*e9af4bc0SJohn Beck 		sm_syslog(LOG_WARNING, NOQID,
2578*e9af4bc0SJohn Beck 			  "WARNING: Milter.maxdatasize: configured=%d, set by libmilter=%d",
2579*e9af4bc0SJohn Beck 	    		  MilterMaxDataSize, MILTER_MDS_64K);
2580*e9af4bc0SJohn Beck 		MilterMaxDataSize = MILTER_MDS_64K;
2581*e9af4bc0SJohn Beck 	}
2582*e9af4bc0SJohn Beck 	m->mf_pflags &= ~SMFI_INTERNAL;
2583*e9af4bc0SJohn Beck #endif /* _FFR_MDS_NEGOTIATE */
2584*e9af4bc0SJohn Beck 
25857c478bd9Sstevel@tonic-gate 	/* check for protocol feature mismatch */
2586058561cbSjbeck 	if ((m->mf_pflags & mta_prot_flags) != m->mf_pflags)
25877c478bd9Sstevel@tonic-gate 	{
25887c478bd9Sstevel@tonic-gate 		if (tTd(64, 5))
25897c478bd9Sstevel@tonic-gate 			sm_dprintf("milter_negotiate(%s): protocol abilities 0x%x != MTA milter abilities 0x%lx\n",
25907c478bd9Sstevel@tonic-gate 				m->mf_name, m->mf_pflags,
2591058561cbSjbeck 				(unsigned long) mta_prot_flags);
25927c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 0)
25937c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_ERR, e->e_id,
25947c478bd9Sstevel@tonic-gate 				  "Milter (%s): negotiate: protocol abilities 0x%x != MTA milter abilities 0x%lx",
25957c478bd9Sstevel@tonic-gate 				  m->mf_name, m->mf_pflags,
2596058561cbSjbeck 				  (unsigned long) mta_prot_flags);
25977c478bd9Sstevel@tonic-gate 		milter_error(m, e);
2598058561cbSjbeck 		goto error;
25997c478bd9Sstevel@tonic-gate 	}
26007c478bd9Sstevel@tonic-gate 
260149218d4fSjbeck 	if (m->mf_fvers <= 2)
260249218d4fSjbeck 		m->mf_pflags |= SMFIP_NOUNKNOWN;
260349218d4fSjbeck 	if (m->mf_fvers <= 3)
260449218d4fSjbeck 		m->mf_pflags |= SMFIP_NODATA;
260549218d4fSjbeck 
2606058561cbSjbeck 	if (rlen > MILTER_OPTLEN)
2607058561cbSjbeck 	{
2608058561cbSjbeck 		milter_getsymlist(m, response, rlen, MILTER_OPTLEN);
2609058561cbSjbeck 	}
2610058561cbSjbeck 
26117800901eSjbeck 	if (bitset(SMFIF_DELRCPT, m->mf_fflags))
26127800901eSjbeck 		milters->mis_flags |= MIS_FL_DEL_RCPT;
26137800901eSjbeck 	if (!bitset(SMFIP_NORCPT, m->mf_pflags) &&
26147800901eSjbeck 	    !bitset(SMFIP_NR_RCPT, m->mf_pflags))
26157800901eSjbeck 		milters->mis_flags |= MIS_FL_REJ_RCPT;
26167800901eSjbeck 
26177c478bd9Sstevel@tonic-gate 	if (tTd(64, 5))
2618058561cbSjbeck 		sm_dprintf("milter_negotiate(%s): received: version %u, fflags 0x%x, pflags 0x%x\n",
26197c478bd9Sstevel@tonic-gate 			m->mf_name, m->mf_fvers, m->mf_fflags, m->mf_pflags);
26207c478bd9Sstevel@tonic-gate 	return 0;
2621058561cbSjbeck 
2622058561cbSjbeck   error:
2623058561cbSjbeck 	if (response != NULL)
2624058561cbSjbeck 		sm_free(response); /* XXX */
2625058561cbSjbeck 	return -1;
26267c478bd9Sstevel@tonic-gate }
2627058561cbSjbeck 
26287c478bd9Sstevel@tonic-gate /*
26297c478bd9Sstevel@tonic-gate **  MILTER_PER_CONNECTION_CHECK -- checks on per-connection commands
26307c478bd9Sstevel@tonic-gate **
26317c478bd9Sstevel@tonic-gate **	Reduce code duplication by putting these checks in one place
26327c478bd9Sstevel@tonic-gate **
26337c478bd9Sstevel@tonic-gate **	Parameters:
26347c478bd9Sstevel@tonic-gate **		e -- current envelope.
26357c478bd9Sstevel@tonic-gate **
26367c478bd9Sstevel@tonic-gate **	Returns:
26377c478bd9Sstevel@tonic-gate **		none
26387c478bd9Sstevel@tonic-gate */
26397c478bd9Sstevel@tonic-gate 
26407c478bd9Sstevel@tonic-gate static void
milter_per_connection_check(e)26417c478bd9Sstevel@tonic-gate milter_per_connection_check(e)
26427c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
26437c478bd9Sstevel@tonic-gate {
26447c478bd9Sstevel@tonic-gate 	int i;
26457c478bd9Sstevel@tonic-gate 
26467c478bd9Sstevel@tonic-gate 	/* see if we are done with any of the filters */
26477c478bd9Sstevel@tonic-gate 	for (i = 0; InputFilters[i] != NULL; i++)
26487c478bd9Sstevel@tonic-gate 	{
26497c478bd9Sstevel@tonic-gate 		struct milter *m = InputFilters[i];
26507c478bd9Sstevel@tonic-gate 
26517c478bd9Sstevel@tonic-gate 		if (m->mf_state == SMFS_CLOSABLE)
26527c478bd9Sstevel@tonic-gate 			milter_quit_filter(m, e);
26537c478bd9Sstevel@tonic-gate 	}
26547c478bd9Sstevel@tonic-gate }
2655058561cbSjbeck 
26567c478bd9Sstevel@tonic-gate /*
26577c478bd9Sstevel@tonic-gate **  MILTER_ERROR -- Put a milter filter into error state
26587c478bd9Sstevel@tonic-gate **
26597c478bd9Sstevel@tonic-gate **	Parameters:
26607c478bd9Sstevel@tonic-gate **		m -- the broken filter.
26617c478bd9Sstevel@tonic-gate **		e -- current envelope.
26627c478bd9Sstevel@tonic-gate **
26637c478bd9Sstevel@tonic-gate **	Returns:
26647c478bd9Sstevel@tonic-gate **		none
26657c478bd9Sstevel@tonic-gate */
26667c478bd9Sstevel@tonic-gate 
26677c478bd9Sstevel@tonic-gate static void
milter_error(m,e)26687c478bd9Sstevel@tonic-gate milter_error(m, e)
26697c478bd9Sstevel@tonic-gate 	struct milter *m;
26707c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
26717c478bd9Sstevel@tonic-gate {
26727c478bd9Sstevel@tonic-gate 	/*
26737c478bd9Sstevel@tonic-gate 	**  We could send a quit here but we may have gotten here due to
26747c478bd9Sstevel@tonic-gate 	**  an I/O error so we don't want to try to make things worse.
26757c478bd9Sstevel@tonic-gate 	*/
26767c478bd9Sstevel@tonic-gate 
26777c478bd9Sstevel@tonic-gate 	if (m->mf_sock >= 0)
26787c478bd9Sstevel@tonic-gate 	{
26797c478bd9Sstevel@tonic-gate 		(void) close(m->mf_sock);
26807c478bd9Sstevel@tonic-gate 		m->mf_sock = -1;
26817c478bd9Sstevel@tonic-gate 	}
26827c478bd9Sstevel@tonic-gate 	m->mf_state = SMFS_ERROR;
26837c478bd9Sstevel@tonic-gate 
26847c478bd9Sstevel@tonic-gate 	if (MilterLogLevel > 0)
26857c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_INFO, e->e_id, "Milter (%s): to error state",
26867c478bd9Sstevel@tonic-gate 			  m->mf_name);
26877c478bd9Sstevel@tonic-gate }
2688058561cbSjbeck 
26897c478bd9Sstevel@tonic-gate /*
26907c478bd9Sstevel@tonic-gate **  MILTER_HEADERS -- send headers to a single milter filter
26917c478bd9Sstevel@tonic-gate **
26927c478bd9Sstevel@tonic-gate **	Parameters:
26937c478bd9Sstevel@tonic-gate **		m -- current filter.
26947c478bd9Sstevel@tonic-gate **		e -- current envelope.
26957c478bd9Sstevel@tonic-gate **		state -- return state from response.
26967c478bd9Sstevel@tonic-gate **
26977c478bd9Sstevel@tonic-gate **	Returns:
26987c478bd9Sstevel@tonic-gate **		response string (may be NULL)
26997c478bd9Sstevel@tonic-gate */
27007c478bd9Sstevel@tonic-gate 
27017c478bd9Sstevel@tonic-gate static char *
milter_headers(m,e,state)27027c478bd9Sstevel@tonic-gate milter_headers(m, e, state)
27037c478bd9Sstevel@tonic-gate 	struct milter *m;
27047c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
27057c478bd9Sstevel@tonic-gate 	char *state;
27067c478bd9Sstevel@tonic-gate {
27077c478bd9Sstevel@tonic-gate 	char *response = NULL;
27087c478bd9Sstevel@tonic-gate 	HDR *h;
27097c478bd9Sstevel@tonic-gate 
27107c478bd9Sstevel@tonic-gate 	if (MilterLogLevel > 17)
27117c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_INFO, e->e_id, "Milter (%s): headers, send",
27127c478bd9Sstevel@tonic-gate 			  m->mf_name);
27137c478bd9Sstevel@tonic-gate 
27147c478bd9Sstevel@tonic-gate 	for (h = e->e_header; h != NULL; h = h->h_link)
27157c478bd9Sstevel@tonic-gate 	{
2716058561cbSjbeck 		int len_n, len_v, len_t, len_f;
2717058561cbSjbeck 		char *buf, *hv;
27187c478bd9Sstevel@tonic-gate 
27197c478bd9Sstevel@tonic-gate 		/* don't send over deleted headers */
27207c478bd9Sstevel@tonic-gate 		if (h->h_value == NULL)
27217c478bd9Sstevel@tonic-gate 		{
27227c478bd9Sstevel@tonic-gate 			/* strip H_USER so not counted in milter_changeheader() */
27237c478bd9Sstevel@tonic-gate 			h->h_flags &= ~H_USER;
27247c478bd9Sstevel@tonic-gate 			continue;
27257c478bd9Sstevel@tonic-gate 		}
27267c478bd9Sstevel@tonic-gate 
27277c478bd9Sstevel@tonic-gate 		/* skip auto-generated */
27287c478bd9Sstevel@tonic-gate 		if (!bitset(H_USER, h->h_flags))
27297c478bd9Sstevel@tonic-gate 			continue;
27307c478bd9Sstevel@tonic-gate 
27317c478bd9Sstevel@tonic-gate 		if (tTd(64, 10))
2732058561cbSjbeck 			sm_dprintf("milter_headers: %s:%s\n",
27337c478bd9Sstevel@tonic-gate 				h->h_field, h->h_value);
27347c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 21)
27357c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_INFO, e->e_id, "Milter (%s): header, %s",
27367c478bd9Sstevel@tonic-gate 				  m->mf_name, h->h_field);
27377c478bd9Sstevel@tonic-gate 
2738058561cbSjbeck 		if (bitset(SMFIP_HDR_LEADSPC, m->mf_pflags)
2739058561cbSjbeck 		    || *(h->h_value) != ' ')
2740058561cbSjbeck 			hv = h->h_value;
2741058561cbSjbeck 		else
2742058561cbSjbeck 			hv = h->h_value + 1;
2743058561cbSjbeck 		len_f = strlen(h->h_field) + 1;
2744058561cbSjbeck 		len_t = len_f + strlen(hv) + 1;
2745058561cbSjbeck 		if (len_t < 0)
27467c478bd9Sstevel@tonic-gate 			continue;
2747058561cbSjbeck 		buf = (char *) xalloc(len_t);
2748058561cbSjbeck 
2749058561cbSjbeck 		/*
2750058561cbSjbeck 		**  Note: currently the call to dequote_internal_chars()
2751058561cbSjbeck 		**  is not required as h_field is supposed to be 7-bit US-ASCII.
2752058561cbSjbeck 		*/
2753058561cbSjbeck 
2754058561cbSjbeck 		len_n = dequote_internal_chars(h->h_field, buf, len_f);
2755058561cbSjbeck 		SM_ASSERT(len_n < len_f);
2756058561cbSjbeck 		len_v = dequote_internal_chars(hv, buf + len_n + 1,
2757058561cbSjbeck 						len_t - len_n - 1);
2758058561cbSjbeck 		SM_ASSERT(len_t >= len_n + 1 + len_v + 1);
2759058561cbSjbeck 		len_t = len_n + 1 + len_v + 1;
27607c478bd9Sstevel@tonic-gate 
27617c478bd9Sstevel@tonic-gate 		/* send it over */
27627c478bd9Sstevel@tonic-gate 		response = milter_send_command(m, SMFIC_HEADER, buf,
2763058561cbSjbeck 					       len_t, e, state, "header");
2764058561cbSjbeck 		sm_free(buf);
27657c478bd9Sstevel@tonic-gate 		if (m->mf_state == SMFS_ERROR ||
27667c478bd9Sstevel@tonic-gate 		    m->mf_state == SMFS_DONE ||
27677c478bd9Sstevel@tonic-gate 		    *state != SMFIR_CONTINUE)
27687c478bd9Sstevel@tonic-gate 			break;
27697c478bd9Sstevel@tonic-gate 	}
27707c478bd9Sstevel@tonic-gate 	if (MilterLogLevel > 17)
27717c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_INFO, e->e_id, "Milter (%s): headers, sent",
27727c478bd9Sstevel@tonic-gate 			  m->mf_name);
27737c478bd9Sstevel@tonic-gate 	return response;
27747c478bd9Sstevel@tonic-gate }
2775058561cbSjbeck 
27767c478bd9Sstevel@tonic-gate /*
27777c478bd9Sstevel@tonic-gate **  MILTER_BODY -- send the body to a filter
27787c478bd9Sstevel@tonic-gate **
27797c478bd9Sstevel@tonic-gate **	Parameters:
27807c478bd9Sstevel@tonic-gate **		m -- current filter.
27817c478bd9Sstevel@tonic-gate **		e -- current envelope.
27827c478bd9Sstevel@tonic-gate **		state -- return state from response.
27837c478bd9Sstevel@tonic-gate **
27847c478bd9Sstevel@tonic-gate **	Returns:
27857c478bd9Sstevel@tonic-gate **		response string (may be NULL)
27867c478bd9Sstevel@tonic-gate */
27877c478bd9Sstevel@tonic-gate 
27887c478bd9Sstevel@tonic-gate static char *
milter_body(m,e,state)27897c478bd9Sstevel@tonic-gate milter_body(m, e, state)
27907c478bd9Sstevel@tonic-gate 	struct milter *m;
27917c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
27927c478bd9Sstevel@tonic-gate 	char *state;
27937c478bd9Sstevel@tonic-gate {
27947c478bd9Sstevel@tonic-gate 	char bufchar = '\0';
27957c478bd9Sstevel@tonic-gate 	char prevchar = '\0';
27967c478bd9Sstevel@tonic-gate 	int c;
27977c478bd9Sstevel@tonic-gate 	char *response = NULL;
27987c478bd9Sstevel@tonic-gate 	char *bp;
27997c478bd9Sstevel@tonic-gate 	char buf[MILTER_CHUNK_SIZE];
28007c478bd9Sstevel@tonic-gate 
28017c478bd9Sstevel@tonic-gate 	if (tTd(64, 10))
28027c478bd9Sstevel@tonic-gate 		sm_dprintf("milter_body\n");
28037c478bd9Sstevel@tonic-gate 
28047c478bd9Sstevel@tonic-gate 	if (bfrewind(e->e_dfp) < 0)
28057c478bd9Sstevel@tonic-gate 	{
28067c478bd9Sstevel@tonic-gate 		ExitStat = EX_IOERR;
28077c478bd9Sstevel@tonic-gate 		*state = SMFIR_TEMPFAIL;
28087c478bd9Sstevel@tonic-gate 		syserr("milter_body: %s/%cf%s: rewind error",
28097c478bd9Sstevel@tonic-gate 		       qid_printqueue(e->e_qgrp, e->e_qdir),
28107c478bd9Sstevel@tonic-gate 		       DATAFL_LETTER, e->e_id);
28117c478bd9Sstevel@tonic-gate 		return NULL;
28127c478bd9Sstevel@tonic-gate 	}
28137c478bd9Sstevel@tonic-gate 
28147c478bd9Sstevel@tonic-gate 	if (MilterLogLevel > 17)
28157c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_INFO, e->e_id, "Milter (%s): body, send",
28167c478bd9Sstevel@tonic-gate 			  m->mf_name);
28177c478bd9Sstevel@tonic-gate 	bp = buf;
28187c478bd9Sstevel@tonic-gate 	while ((c = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT)) != SM_IO_EOF)
28197c478bd9Sstevel@tonic-gate 	{
28207c478bd9Sstevel@tonic-gate 		/*  Change LF to CRLF */
28217c478bd9Sstevel@tonic-gate 		if (c == '\n')
28227c478bd9Sstevel@tonic-gate 		{
2823058561cbSjbeck #if !_FFR_MILTER_CONVERT_ALL_LF_TO_CRLF
28247c478bd9Sstevel@tonic-gate 			/* Not a CRLF already? */
28257c478bd9Sstevel@tonic-gate 			if (prevchar != '\r')
2826058561cbSjbeck #endif /* !_FFR_MILTER_CONVERT_ALL_LF_TO_CRLF */
28277c478bd9Sstevel@tonic-gate 			{
28287c478bd9Sstevel@tonic-gate 				/* Room for CR now? */
2829058561cbSjbeck 				if (bp + 2 > &buf[sizeof(buf)])
28307c478bd9Sstevel@tonic-gate 				{
28317c478bd9Sstevel@tonic-gate 					/* No room, buffer LF */
28327c478bd9Sstevel@tonic-gate 					bufchar = c;
28337c478bd9Sstevel@tonic-gate 
28347c478bd9Sstevel@tonic-gate 					/* and send CR now */
28357c478bd9Sstevel@tonic-gate 					c = '\r';
28367c478bd9Sstevel@tonic-gate 				}
28377c478bd9Sstevel@tonic-gate 				else
28387c478bd9Sstevel@tonic-gate 				{
28397c478bd9Sstevel@tonic-gate 					/* Room to do it now */
28407c478bd9Sstevel@tonic-gate 					*bp++ = '\r';
28417c478bd9Sstevel@tonic-gate 					prevchar = '\r';
28427c478bd9Sstevel@tonic-gate 				}
28437c478bd9Sstevel@tonic-gate 			}
28447c478bd9Sstevel@tonic-gate 		}
28457c478bd9Sstevel@tonic-gate 		*bp++ = (char) c;
28467c478bd9Sstevel@tonic-gate 		prevchar = c;
2847058561cbSjbeck 		if (bp >= &buf[sizeof(buf)])
28487c478bd9Sstevel@tonic-gate 		{
28497c478bd9Sstevel@tonic-gate 			/* send chunk */
28507c478bd9Sstevel@tonic-gate 			response = milter_send_command(m, SMFIC_BODY, buf,
2851058561cbSjbeck 						       bp - buf, e, state,
2852058561cbSjbeck 							"body chunk");
28537c478bd9Sstevel@tonic-gate 			bp = buf;
28547c478bd9Sstevel@tonic-gate 			if (bufchar != '\0')
28557c478bd9Sstevel@tonic-gate 			{
28567c478bd9Sstevel@tonic-gate 				*bp++ = bufchar;
28577c478bd9Sstevel@tonic-gate 				bufchar = '\0';
28587c478bd9Sstevel@tonic-gate 				prevchar = bufchar;
28597c478bd9Sstevel@tonic-gate 			}
28607c478bd9Sstevel@tonic-gate 		}
28617c478bd9Sstevel@tonic-gate 		if (m->mf_state == SMFS_ERROR ||
28627c478bd9Sstevel@tonic-gate 		    m->mf_state == SMFS_DONE ||
2863058561cbSjbeck 		    m->mf_state == SMFS_SKIP ||
28647c478bd9Sstevel@tonic-gate 		    *state != SMFIR_CONTINUE)
28657c478bd9Sstevel@tonic-gate 			break;
28667c478bd9Sstevel@tonic-gate 	}
28677c478bd9Sstevel@tonic-gate 
28687c478bd9Sstevel@tonic-gate 	/* check for read errors */
28697c478bd9Sstevel@tonic-gate 	if (sm_io_error(e->e_dfp))
28707c478bd9Sstevel@tonic-gate 	{
28717c478bd9Sstevel@tonic-gate 		ExitStat = EX_IOERR;
28727c478bd9Sstevel@tonic-gate 		if (*state == SMFIR_CONTINUE ||
2873058561cbSjbeck 		    *state == SMFIR_ACCEPT ||
2874058561cbSjbeck 		    m->mf_state == SMFS_SKIP)
28757c478bd9Sstevel@tonic-gate 		{
28767c478bd9Sstevel@tonic-gate 			*state = SMFIR_TEMPFAIL;
28777c478bd9Sstevel@tonic-gate 			if (response != NULL)
28787c478bd9Sstevel@tonic-gate 			{
28797c478bd9Sstevel@tonic-gate 				sm_free(response); /* XXX */
28807c478bd9Sstevel@tonic-gate 				response = NULL;
28817c478bd9Sstevel@tonic-gate 			}
28827c478bd9Sstevel@tonic-gate 		}
28837c478bd9Sstevel@tonic-gate 		syserr("milter_body: %s/%cf%s: read error",
28847c478bd9Sstevel@tonic-gate 		       qid_printqueue(e->e_qgrp, e->e_qdir),
28857c478bd9Sstevel@tonic-gate 		       DATAFL_LETTER, e->e_id);
28867c478bd9Sstevel@tonic-gate 		return response;
28877c478bd9Sstevel@tonic-gate 	}
28887c478bd9Sstevel@tonic-gate 
28897c478bd9Sstevel@tonic-gate 	/* send last body chunk */
28907c478bd9Sstevel@tonic-gate 	if (bp > buf &&
28917c478bd9Sstevel@tonic-gate 	    m->mf_state != SMFS_ERROR &&
28927c478bd9Sstevel@tonic-gate 	    m->mf_state != SMFS_DONE &&
2893058561cbSjbeck 	    m->mf_state != SMFS_SKIP &&
28947c478bd9Sstevel@tonic-gate 	    *state == SMFIR_CONTINUE)
28957c478bd9Sstevel@tonic-gate 	{
28967c478bd9Sstevel@tonic-gate 		/* send chunk */
28977c478bd9Sstevel@tonic-gate 		response = milter_send_command(m, SMFIC_BODY, buf, bp - buf,
2898058561cbSjbeck 					       e, state, "last body chunk");
28997c478bd9Sstevel@tonic-gate 		bp = buf;
29007c478bd9Sstevel@tonic-gate 	}
29017c478bd9Sstevel@tonic-gate 	if (MilterLogLevel > 17)
29027c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_INFO, e->e_id, "Milter (%s): body, sent",
29037c478bd9Sstevel@tonic-gate 			  m->mf_name);
2904058561cbSjbeck 	if (m->mf_state == SMFS_SKIP)
2905058561cbSjbeck 	{
2906058561cbSjbeck 		*state = SMFIR_CONTINUE;
2907058561cbSjbeck 		m->mf_state = SMFS_READY;
2908058561cbSjbeck 	}
2909058561cbSjbeck 
29107c478bd9Sstevel@tonic-gate 	return response;
29117c478bd9Sstevel@tonic-gate }
29127c478bd9Sstevel@tonic-gate 
29137c478bd9Sstevel@tonic-gate /*
29147c478bd9Sstevel@tonic-gate **  Actions
29157c478bd9Sstevel@tonic-gate */
29167c478bd9Sstevel@tonic-gate 
2917058561cbSjbeck /*
2918058561cbSjbeck **  ADDLEADINGSPACE -- Add a leading space to a string
2919058561cbSjbeck **
2920058561cbSjbeck **	Parameters:
2921058561cbSjbeck **		str -- string
2922058561cbSjbeck **		rp -- resource pool for allocations
2923058561cbSjbeck **
2924058561cbSjbeck **	Returns:
2925058561cbSjbeck **		pointer to new string
2926058561cbSjbeck */
2927058561cbSjbeck 
2928058561cbSjbeck static char *addleadingspace __P((char *, SM_RPOOL_T *));
2929058561cbSjbeck 
2930058561cbSjbeck static char *
addleadingspace(str,rp)2931058561cbSjbeck addleadingspace(str, rp)
2932058561cbSjbeck 	char *str;
2933058561cbSjbeck 	SM_RPOOL_T *rp;
2934058561cbSjbeck {
2935058561cbSjbeck 	size_t l;
2936058561cbSjbeck 	char *new;
2937058561cbSjbeck 
2938058561cbSjbeck 	SM_ASSERT(str != NULL);
2939058561cbSjbeck 	l = strlen(str);
2940058561cbSjbeck 	SM_ASSERT(l + 2 > l);
2941058561cbSjbeck 	new = sm_rpool_malloc_x(rp, l + 2);
2942058561cbSjbeck 	new[0] = ' ';
2943058561cbSjbeck 	new[1] = '\0';
2944058561cbSjbeck 	sm_strlcpy(new + 1, str, l + 1);
2945058561cbSjbeck 	return new;
2946058561cbSjbeck }
2947058561cbSjbeck 
29487c478bd9Sstevel@tonic-gate /*
29497c478bd9Sstevel@tonic-gate **  MILTER_ADDHEADER -- Add the supplied header to the message
29507c478bd9Sstevel@tonic-gate **
29517c478bd9Sstevel@tonic-gate **	Parameters:
2952058561cbSjbeck **		m -- current filter.
29537c478bd9Sstevel@tonic-gate **		response -- encoded form of header/value.
29547c478bd9Sstevel@tonic-gate **		rlen -- length of response.
29557c478bd9Sstevel@tonic-gate **		e -- current envelope.
29567c478bd9Sstevel@tonic-gate **
29577c478bd9Sstevel@tonic-gate **	Returns:
29587c478bd9Sstevel@tonic-gate **		none
29597c478bd9Sstevel@tonic-gate */
29607c478bd9Sstevel@tonic-gate 
29617c478bd9Sstevel@tonic-gate static void
milter_addheader(m,response,rlen,e)2962058561cbSjbeck milter_addheader(m, response, rlen, e)
2963058561cbSjbeck 	struct milter *m;
29647c478bd9Sstevel@tonic-gate 	char *response;
29657c478bd9Sstevel@tonic-gate 	ssize_t rlen;
29667c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
29677c478bd9Sstevel@tonic-gate {
2968058561cbSjbeck 	int mh_v_len;
2969058561cbSjbeck 	char *val, *mh_value;
29707c478bd9Sstevel@tonic-gate 	HDR *h;
29717c478bd9Sstevel@tonic-gate 
29727c478bd9Sstevel@tonic-gate 	if (tTd(64, 10))
29737c478bd9Sstevel@tonic-gate 		sm_dprintf("milter_addheader: ");
29747c478bd9Sstevel@tonic-gate 
29757c478bd9Sstevel@tonic-gate 	/* sanity checks */
29767c478bd9Sstevel@tonic-gate 	if (response == NULL)
29777c478bd9Sstevel@tonic-gate 	{
29787c478bd9Sstevel@tonic-gate 		if (tTd(64, 10))
29797c478bd9Sstevel@tonic-gate 			sm_dprintf("NULL response\n");
29807c478bd9Sstevel@tonic-gate 		return;
29817c478bd9Sstevel@tonic-gate 	}
29827c478bd9Sstevel@tonic-gate 
29837c478bd9Sstevel@tonic-gate 	if (rlen < 2 || strlen(response) + 1 >= (size_t) rlen)
29847c478bd9Sstevel@tonic-gate 	{
29857c478bd9Sstevel@tonic-gate 		if (tTd(64, 10))
2986058561cbSjbeck 			sm_dprintf("didn't follow protocol (total len %d != rlen %d)\n",
2987058561cbSjbeck 				   (int) strlen(response), (int) (rlen - 1));
29887c478bd9Sstevel@tonic-gate 		return;
29897c478bd9Sstevel@tonic-gate 	}
29907c478bd9Sstevel@tonic-gate 
29917c478bd9Sstevel@tonic-gate 	/* Find separating NUL */
29927c478bd9Sstevel@tonic-gate 	val = response + strlen(response) + 1;
29937c478bd9Sstevel@tonic-gate 
29947c478bd9Sstevel@tonic-gate 	/* another sanity check */
29957c478bd9Sstevel@tonic-gate 	if (strlen(response) + strlen(val) + 2 != (size_t) rlen)
29967c478bd9Sstevel@tonic-gate 	{
29977c478bd9Sstevel@tonic-gate 		if (tTd(64, 10))
29987c478bd9Sstevel@tonic-gate 			sm_dprintf("didn't follow protocol (part len)\n");
29997c478bd9Sstevel@tonic-gate 		return;
30007c478bd9Sstevel@tonic-gate 	}
30017c478bd9Sstevel@tonic-gate 
30027c478bd9Sstevel@tonic-gate 	if (*response == '\0')
30037c478bd9Sstevel@tonic-gate 	{
30047c478bd9Sstevel@tonic-gate 		if (tTd(64, 10))
30057c478bd9Sstevel@tonic-gate 			sm_dprintf("empty field name\n");
30067c478bd9Sstevel@tonic-gate 		return;
30077c478bd9Sstevel@tonic-gate 	}
30087c478bd9Sstevel@tonic-gate 
30097c478bd9Sstevel@tonic-gate 	for (h = e->e_header; h != NULL; h = h->h_link)
30107c478bd9Sstevel@tonic-gate 	{
30117c478bd9Sstevel@tonic-gate 		if (sm_strcasecmp(h->h_field, response) == 0 &&
30127c478bd9Sstevel@tonic-gate 		    !bitset(H_USER, h->h_flags) &&
30137c478bd9Sstevel@tonic-gate 		    !bitset(H_TRACE, h->h_flags))
30147c478bd9Sstevel@tonic-gate 			break;
30157c478bd9Sstevel@tonic-gate 	}
30167c478bd9Sstevel@tonic-gate 
3017058561cbSjbeck 	mh_v_len = 0;
3018058561cbSjbeck 	mh_value = quote_internal_chars(val, NULL, &mh_v_len);
3019058561cbSjbeck 
30207c478bd9Sstevel@tonic-gate 	/* add to e_msgsize */
30217c478bd9Sstevel@tonic-gate 	e->e_msgsize += strlen(response) + 2 + strlen(val);
30227c478bd9Sstevel@tonic-gate 
30237c478bd9Sstevel@tonic-gate 	if (h != NULL)
30247c478bd9Sstevel@tonic-gate 	{
30257c478bd9Sstevel@tonic-gate 		if (tTd(64, 10))
30267c478bd9Sstevel@tonic-gate 			sm_dprintf("Replace default header %s value with %s\n",
3027058561cbSjbeck 				   h->h_field, mh_value);
30287c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 8)
30297c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_INFO, e->e_id,
30307c478bd9Sstevel@tonic-gate 				  "Milter change: default header %s value with %s",
3031058561cbSjbeck 				  h->h_field, mh_value);
3032058561cbSjbeck 		if (bitset(SMFIP_HDR_LEADSPC, m->mf_pflags))
3033058561cbSjbeck 			h->h_value = mh_value;
3034058561cbSjbeck 		else
3035058561cbSjbeck 		{
3036*e9af4bc0SJohn Beck 			h->h_value = addleadingspace(mh_value, e->e_rpool);
3037058561cbSjbeck 			SM_FREE(mh_value);
3038058561cbSjbeck 		}
30397c478bd9Sstevel@tonic-gate 		h->h_flags |= H_USER;
30407c478bd9Sstevel@tonic-gate 	}
30417c478bd9Sstevel@tonic-gate 	else
30427c478bd9Sstevel@tonic-gate 	{
30437c478bd9Sstevel@tonic-gate 		if (tTd(64, 10))
3044058561cbSjbeck 			sm_dprintf("Add %s: %s\n", response, mh_value);
30457c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 8)
3046058561cbSjbeck 			sm_syslog(LOG_INFO, e->e_id,
3047058561cbSjbeck 				  "Milter add: header: %s: %s",
3048058561cbSjbeck 				  response, mh_value);
3049058561cbSjbeck 		addheader(newstr(response), mh_value, H_USER, e,
3050058561cbSjbeck 			!bitset(SMFIP_HDR_LEADSPC, m->mf_pflags));
3051058561cbSjbeck 		SM_FREE(mh_value);
30527c478bd9Sstevel@tonic-gate 	}
30537c478bd9Sstevel@tonic-gate }
3054058561cbSjbeck 
30557c478bd9Sstevel@tonic-gate /*
30567c478bd9Sstevel@tonic-gate **  MILTER_INSHEADER -- Insert the supplied header
30577c478bd9Sstevel@tonic-gate **
30587c478bd9Sstevel@tonic-gate **	Parameters:
3059058561cbSjbeck **		m -- current filter.
30607c478bd9Sstevel@tonic-gate **		response -- encoded form of header/value.
30617c478bd9Sstevel@tonic-gate **		rlen -- length of response.
30627c478bd9Sstevel@tonic-gate **		e -- current envelope.
30637c478bd9Sstevel@tonic-gate **
30647c478bd9Sstevel@tonic-gate **	Returns:
30657c478bd9Sstevel@tonic-gate **		none
30667c478bd9Sstevel@tonic-gate **
306749218d4fSjbeck **	Notes:
306849218d4fSjbeck **		Unlike milter_addheader(), this does not attempt to determine
306949218d4fSjbeck **		if the header already exists in the envelope, even a
307049218d4fSjbeck **		deleted version.  It just blindly inserts.
30717c478bd9Sstevel@tonic-gate */
30727c478bd9Sstevel@tonic-gate 
30737c478bd9Sstevel@tonic-gate static void
milter_insheader(m,response,rlen,e)3074058561cbSjbeck milter_insheader(m, response, rlen, e)
3075058561cbSjbeck 	struct milter *m;
30767c478bd9Sstevel@tonic-gate 	char *response;
30777c478bd9Sstevel@tonic-gate 	ssize_t rlen;
30787c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
30797c478bd9Sstevel@tonic-gate {
30807c478bd9Sstevel@tonic-gate 	mi_int32 idx, i;
3081058561cbSjbeck 	int mh_v_len;
3082058561cbSjbeck 	char *field, *val, *mh_value;
30837c478bd9Sstevel@tonic-gate 
30847c478bd9Sstevel@tonic-gate 	if (tTd(64, 10))
30857c478bd9Sstevel@tonic-gate 		sm_dprintf("milter_insheader: ");
30867c478bd9Sstevel@tonic-gate 
30877c478bd9Sstevel@tonic-gate 	/* sanity checks */
30887c478bd9Sstevel@tonic-gate 	if (response == NULL)
30897c478bd9Sstevel@tonic-gate 	{
30907c478bd9Sstevel@tonic-gate 		if (tTd(64, 10))
30917c478bd9Sstevel@tonic-gate 			sm_dprintf("NULL response\n");
30927c478bd9Sstevel@tonic-gate 		return;
30937c478bd9Sstevel@tonic-gate 	}
30947c478bd9Sstevel@tonic-gate 
30957c478bd9Sstevel@tonic-gate 	if (rlen < 2 || strlen(response) + 1 >= (size_t) rlen)
30967c478bd9Sstevel@tonic-gate 	{
30977c478bd9Sstevel@tonic-gate 		if (tTd(64, 10))
30987c478bd9Sstevel@tonic-gate 			sm_dprintf("didn't follow protocol (total len)\n");
30997c478bd9Sstevel@tonic-gate 		return;
31007c478bd9Sstevel@tonic-gate 	}
31017c478bd9Sstevel@tonic-gate 
31027c478bd9Sstevel@tonic-gate 	/* decode */
31037c478bd9Sstevel@tonic-gate 	(void) memcpy((char *) &i, response, MILTER_LEN_BYTES);
31047c478bd9Sstevel@tonic-gate 	idx = ntohl(i);
31057c478bd9Sstevel@tonic-gate 	field = response + MILTER_LEN_BYTES;
31067c478bd9Sstevel@tonic-gate 	val = field + strlen(field) + 1;
31077c478bd9Sstevel@tonic-gate 
31087c478bd9Sstevel@tonic-gate 	/* another sanity check */
31097c478bd9Sstevel@tonic-gate 	if (MILTER_LEN_BYTES + strlen(field) + 1 +
31107c478bd9Sstevel@tonic-gate 	    strlen(val) + 1 != (size_t) rlen)
31117c478bd9Sstevel@tonic-gate 	{
31127c478bd9Sstevel@tonic-gate 		if (tTd(64, 10))
31137c478bd9Sstevel@tonic-gate 			sm_dprintf("didn't follow protocol (part len)\n");
31147c478bd9Sstevel@tonic-gate 		return;
31157c478bd9Sstevel@tonic-gate 	}
31167c478bd9Sstevel@tonic-gate 
31177c478bd9Sstevel@tonic-gate 	if (*field == '\0')
31187c478bd9Sstevel@tonic-gate 	{
31197c478bd9Sstevel@tonic-gate 		if (tTd(64, 10))
31207c478bd9Sstevel@tonic-gate 			sm_dprintf("empty field name\n");
31217c478bd9Sstevel@tonic-gate 		return;
31227c478bd9Sstevel@tonic-gate 	}
31237c478bd9Sstevel@tonic-gate 
31247c478bd9Sstevel@tonic-gate 	/* add to e_msgsize */
31257c478bd9Sstevel@tonic-gate 	e->e_msgsize += strlen(response) + 2 + strlen(val);
31267c478bd9Sstevel@tonic-gate 
31277c478bd9Sstevel@tonic-gate 	if (tTd(64, 10))
3128058561cbSjbeck 		sm_dprintf("Insert (%d) %s: %s\n", idx, field, val);
31297c478bd9Sstevel@tonic-gate 	if (MilterLogLevel > 8)
31307c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_INFO, e->e_id,
313149218d4fSjbeck 			  "Milter insert (%d): header: %s: %s",
31327c478bd9Sstevel@tonic-gate 			  idx, field, val);
3133058561cbSjbeck 	mh_v_len = 0;
3134058561cbSjbeck 	mh_value = quote_internal_chars(val, NULL, &mh_v_len);
3135058561cbSjbeck 	insheader(idx, newstr(field), mh_value, H_USER, e,
3136058561cbSjbeck 		!bitset(SMFIP_HDR_LEADSPC, m->mf_pflags));
3137058561cbSjbeck 	SM_FREE(mh_value);
31387c478bd9Sstevel@tonic-gate }
3139058561cbSjbeck 
31407c478bd9Sstevel@tonic-gate /*
31417c478bd9Sstevel@tonic-gate **  MILTER_CHANGEHEADER -- Change the supplied header in the message
31427c478bd9Sstevel@tonic-gate **
31437c478bd9Sstevel@tonic-gate **	Parameters:
3144058561cbSjbeck **		m -- current filter.
31457c478bd9Sstevel@tonic-gate **		response -- encoded form of header/index/value.
31467c478bd9Sstevel@tonic-gate **		rlen -- length of response.
31477c478bd9Sstevel@tonic-gate **		e -- current envelope.
31487c478bd9Sstevel@tonic-gate **
31497c478bd9Sstevel@tonic-gate **	Returns:
31507c478bd9Sstevel@tonic-gate **		none
31517c478bd9Sstevel@tonic-gate */
31527c478bd9Sstevel@tonic-gate 
31537c478bd9Sstevel@tonic-gate static void
milter_changeheader(m,response,rlen,e)3154058561cbSjbeck milter_changeheader(m, response, rlen, e)
3155058561cbSjbeck 	struct milter *m;
31567c478bd9Sstevel@tonic-gate 	char *response;
31577c478bd9Sstevel@tonic-gate 	ssize_t rlen;
31587c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
31597c478bd9Sstevel@tonic-gate {
31607c478bd9Sstevel@tonic-gate 	mi_int32 i, index;
3161058561cbSjbeck 	int mh_v_len;
3162058561cbSjbeck 	char *field, *val, *mh_value;
31637c478bd9Sstevel@tonic-gate 	HDR *h, *sysheader;
31647c478bd9Sstevel@tonic-gate 
31657c478bd9Sstevel@tonic-gate 	if (tTd(64, 10))
31667c478bd9Sstevel@tonic-gate 		sm_dprintf("milter_changeheader: ");
31677c478bd9Sstevel@tonic-gate 
31687c478bd9Sstevel@tonic-gate 	/* sanity checks */
31697c478bd9Sstevel@tonic-gate 	if (response == NULL)
31707c478bd9Sstevel@tonic-gate 	{
31717c478bd9Sstevel@tonic-gate 		if (tTd(64, 10))
31727c478bd9Sstevel@tonic-gate 			sm_dprintf("NULL response\n");
31737c478bd9Sstevel@tonic-gate 		return;
31747c478bd9Sstevel@tonic-gate 	}
31757c478bd9Sstevel@tonic-gate 
31767c478bd9Sstevel@tonic-gate 	if (rlen < 2 || strlen(response) + 1 >= (size_t) rlen)
31777c478bd9Sstevel@tonic-gate 	{
31787c478bd9Sstevel@tonic-gate 		if (tTd(64, 10))
31797c478bd9Sstevel@tonic-gate 			sm_dprintf("didn't follow protocol (total len)\n");
31807c478bd9Sstevel@tonic-gate 		return;
31817c478bd9Sstevel@tonic-gate 	}
31827c478bd9Sstevel@tonic-gate 
31837c478bd9Sstevel@tonic-gate 	/* Find separating NUL */
31847c478bd9Sstevel@tonic-gate 	(void) memcpy((char *) &i, response, MILTER_LEN_BYTES);
31857c478bd9Sstevel@tonic-gate 	index = ntohl(i);
31867c478bd9Sstevel@tonic-gate 	field = response + MILTER_LEN_BYTES;
31877c478bd9Sstevel@tonic-gate 	val = field + strlen(field) + 1;
31887c478bd9Sstevel@tonic-gate 
31897c478bd9Sstevel@tonic-gate 	/* another sanity check */
31907c478bd9Sstevel@tonic-gate 	if (MILTER_LEN_BYTES + strlen(field) + 1 +
31917c478bd9Sstevel@tonic-gate 	    strlen(val) + 1 != (size_t) rlen)
31927c478bd9Sstevel@tonic-gate 	{
31937c478bd9Sstevel@tonic-gate 		if (tTd(64, 10))
31947c478bd9Sstevel@tonic-gate 			sm_dprintf("didn't follow protocol (part len)\n");
31957c478bd9Sstevel@tonic-gate 		return;
31967c478bd9Sstevel@tonic-gate 	}
31977c478bd9Sstevel@tonic-gate 
31987c478bd9Sstevel@tonic-gate 	if (*field == '\0')
31997c478bd9Sstevel@tonic-gate 	{
32007c478bd9Sstevel@tonic-gate 		if (tTd(64, 10))
32017c478bd9Sstevel@tonic-gate 			sm_dprintf("empty field name\n");
32027c478bd9Sstevel@tonic-gate 		return;
32037c478bd9Sstevel@tonic-gate 	}
32047c478bd9Sstevel@tonic-gate 
3205058561cbSjbeck 	mh_v_len = 0;
3206058561cbSjbeck 	mh_value = quote_internal_chars(val, NULL, &mh_v_len);
3207058561cbSjbeck 
32087c478bd9Sstevel@tonic-gate 	sysheader = NULL;
32097c478bd9Sstevel@tonic-gate 	for (h = e->e_header; h != NULL; h = h->h_link)
32107c478bd9Sstevel@tonic-gate 	{
32117c478bd9Sstevel@tonic-gate 		if (sm_strcasecmp(h->h_field, field) == 0)
32127c478bd9Sstevel@tonic-gate 		{
3213058561cbSjbeck 			if (bitset(H_USER, h->h_flags) && --index <= 0)
32147c478bd9Sstevel@tonic-gate 			{
32157c478bd9Sstevel@tonic-gate 				sysheader = NULL;
32167c478bd9Sstevel@tonic-gate 				break;
32177c478bd9Sstevel@tonic-gate 			}
32187c478bd9Sstevel@tonic-gate 			else if (!bitset(H_USER, h->h_flags) &&
32197c478bd9Sstevel@tonic-gate 				 !bitset(H_TRACE, h->h_flags))
32207c478bd9Sstevel@tonic-gate 			{
32217c478bd9Sstevel@tonic-gate 				/*
32227c478bd9Sstevel@tonic-gate 				**  DRUMS msg-fmt draft says can only have
32237c478bd9Sstevel@tonic-gate 				**  multiple occurences of trace fields,
32247c478bd9Sstevel@tonic-gate 				**  so make sure we replace any non-trace,
32257c478bd9Sstevel@tonic-gate 				**  non-user field.
32267c478bd9Sstevel@tonic-gate 				*/
32277c478bd9Sstevel@tonic-gate 
32287c478bd9Sstevel@tonic-gate 				sysheader = h;
32297c478bd9Sstevel@tonic-gate 			}
32307c478bd9Sstevel@tonic-gate 		}
32317c478bd9Sstevel@tonic-gate 	}
32327c478bd9Sstevel@tonic-gate 
32337c478bd9Sstevel@tonic-gate 	/* if not found as user-provided header at index, use sysheader */
32347c478bd9Sstevel@tonic-gate 	if (h == NULL)
32357c478bd9Sstevel@tonic-gate 		h = sysheader;
32367c478bd9Sstevel@tonic-gate 
32377c478bd9Sstevel@tonic-gate 	if (h == NULL)
32387c478bd9Sstevel@tonic-gate 	{
32397c478bd9Sstevel@tonic-gate 		if (*val == '\0')
32407c478bd9Sstevel@tonic-gate 		{
32417c478bd9Sstevel@tonic-gate 			if (tTd(64, 10))
32427c478bd9Sstevel@tonic-gate 				sm_dprintf("Delete (noop) %s\n", field);
32437c478bd9Sstevel@tonic-gate 			if (MilterLogLevel > 8)
32447c478bd9Sstevel@tonic-gate 				sm_syslog(LOG_INFO, e->e_id,
32457c478bd9Sstevel@tonic-gate 					"Milter delete (noop): header: %s"
32467c478bd9Sstevel@tonic-gate 					, field);
32477c478bd9Sstevel@tonic-gate 		}
32487c478bd9Sstevel@tonic-gate 		else
32497c478bd9Sstevel@tonic-gate 		{
32507c478bd9Sstevel@tonic-gate 			/* treat modify value with no existing header as add */
32517c478bd9Sstevel@tonic-gate 			if (tTd(64, 10))
3252058561cbSjbeck 				sm_dprintf("Add %s: %s\n", field, mh_value);
32537c478bd9Sstevel@tonic-gate 			if (MilterLogLevel > 8)
32547c478bd9Sstevel@tonic-gate 				sm_syslog(LOG_INFO, e->e_id,
32557c478bd9Sstevel@tonic-gate 					"Milter change (add): header: %s: %s"
3256058561cbSjbeck 					, field, mh_value);
3257058561cbSjbeck 			addheader(newstr(field), mh_value, H_USER, e,
3258058561cbSjbeck 				!bitset(SMFIP_HDR_LEADSPC, m->mf_pflags));
32597c478bd9Sstevel@tonic-gate 		}
32607c478bd9Sstevel@tonic-gate 		return;
32617c478bd9Sstevel@tonic-gate 	}
32627c478bd9Sstevel@tonic-gate 
32637c478bd9Sstevel@tonic-gate 	if (tTd(64, 10))
32647c478bd9Sstevel@tonic-gate 	{
32657c478bd9Sstevel@tonic-gate 		if (*val == '\0')
32667c478bd9Sstevel@tonic-gate 		{
3267058561cbSjbeck 			sm_dprintf("Delete%s %s:%s\n",
32687c478bd9Sstevel@tonic-gate 				   h == sysheader ? " (default header)" : "",
32697c478bd9Sstevel@tonic-gate 				   field,
32707c478bd9Sstevel@tonic-gate 				   h->h_value == NULL ? "<NULL>" : h->h_value);
32717c478bd9Sstevel@tonic-gate 		}
32727c478bd9Sstevel@tonic-gate 		else
32737c478bd9Sstevel@tonic-gate 		{
32747c478bd9Sstevel@tonic-gate 			sm_dprintf("Change%s %s: from %s to %s\n",
32757c478bd9Sstevel@tonic-gate 				   h == sysheader ? " (default header)" : "",
32767c478bd9Sstevel@tonic-gate 				   field,
32777c478bd9Sstevel@tonic-gate 				   h->h_value == NULL ? "<NULL>" : h->h_value,
3278058561cbSjbeck 				   mh_value);
32797c478bd9Sstevel@tonic-gate 		}
32807c478bd9Sstevel@tonic-gate 	}
32817c478bd9Sstevel@tonic-gate 
32827c478bd9Sstevel@tonic-gate 	if (MilterLogLevel > 8)
32837c478bd9Sstevel@tonic-gate 	{
32847c478bd9Sstevel@tonic-gate 		if (*val == '\0')
32857c478bd9Sstevel@tonic-gate 		{
32867c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_INFO, e->e_id,
3287058561cbSjbeck 				  "Milter delete: header%s %s:%s",
32887c478bd9Sstevel@tonic-gate 				  h == sysheader ? " (default header)" : "",
32897c478bd9Sstevel@tonic-gate 				  field,
32907c478bd9Sstevel@tonic-gate 				  h->h_value == NULL ? "<NULL>" : h->h_value);
32917c478bd9Sstevel@tonic-gate 		}
32927c478bd9Sstevel@tonic-gate 		else
32937c478bd9Sstevel@tonic-gate 		{
32947c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_INFO, e->e_id,
32957c478bd9Sstevel@tonic-gate 				  "Milter change: header%s %s: from %s to %s",
32967c478bd9Sstevel@tonic-gate 				  h == sysheader ? " (default header)" : "",
32977c478bd9Sstevel@tonic-gate 				  field,
32987c478bd9Sstevel@tonic-gate 				  h->h_value == NULL ? "<NULL>" : h->h_value,
3299058561cbSjbeck 				  mh_value);
33007c478bd9Sstevel@tonic-gate 		}
33017c478bd9Sstevel@tonic-gate 	}
33027c478bd9Sstevel@tonic-gate 
33037c478bd9Sstevel@tonic-gate 	if (h != sysheader && h->h_value != NULL)
33047c478bd9Sstevel@tonic-gate 	{
33057c478bd9Sstevel@tonic-gate 		size_t l;
33067c478bd9Sstevel@tonic-gate 
33077c478bd9Sstevel@tonic-gate 		l = strlen(h->h_value);
33087c478bd9Sstevel@tonic-gate 		if (l > e->e_msgsize)
33097c478bd9Sstevel@tonic-gate 			e->e_msgsize = 0;
33107c478bd9Sstevel@tonic-gate 		else
33117c478bd9Sstevel@tonic-gate 			e->e_msgsize -= l;
33127c478bd9Sstevel@tonic-gate 		/* rpool, don't free: sm_free(h->h_value); XXX */
33137c478bd9Sstevel@tonic-gate 	}
33147c478bd9Sstevel@tonic-gate 
33157c478bd9Sstevel@tonic-gate 	if (*val == '\0')
33167c478bd9Sstevel@tonic-gate 	{
33177c478bd9Sstevel@tonic-gate 		/* Remove "Field: " from message size */
33187c478bd9Sstevel@tonic-gate 		if (h != sysheader)
33197c478bd9Sstevel@tonic-gate 		{
33207c478bd9Sstevel@tonic-gate 			size_t l;
33217c478bd9Sstevel@tonic-gate 
33227c478bd9Sstevel@tonic-gate 			l = strlen(h->h_field) + 2;
33237c478bd9Sstevel@tonic-gate 			if (l > e->e_msgsize)
33247c478bd9Sstevel@tonic-gate 				e->e_msgsize = 0;
33257c478bd9Sstevel@tonic-gate 			else
33267c478bd9Sstevel@tonic-gate 				e->e_msgsize -= l;
33277c478bd9Sstevel@tonic-gate 		}
33287c478bd9Sstevel@tonic-gate 		h->h_value = NULL;
3329058561cbSjbeck 		SM_FREE(mh_value);
33307c478bd9Sstevel@tonic-gate 	}
33317c478bd9Sstevel@tonic-gate 	else
33327c478bd9Sstevel@tonic-gate 	{
3333058561cbSjbeck 		if (bitset(SMFIP_HDR_LEADSPC, m->mf_pflags))
3334058561cbSjbeck 			h->h_value = mh_value;
3335058561cbSjbeck 		else
3336058561cbSjbeck 		{
3337*e9af4bc0SJohn Beck 			h->h_value = addleadingspace(mh_value, e->e_rpool);
3338058561cbSjbeck 			SM_FREE(mh_value);
3339058561cbSjbeck 		}
33407c478bd9Sstevel@tonic-gate 		h->h_flags |= H_USER;
33417c478bd9Sstevel@tonic-gate 		e->e_msgsize += strlen(h->h_value);
33427c478bd9Sstevel@tonic-gate 	}
33437c478bd9Sstevel@tonic-gate }
3344058561cbSjbeck 
3345058561cbSjbeck /*
3346058561cbSjbeck **  MILTER_SPLIT_RESPONSE -- Split response into fields.
3347058561cbSjbeck **
3348058561cbSjbeck **	Parameters:
3349058561cbSjbeck **		response -- encoded repsonse.
3350058561cbSjbeck **		rlen -- length of response.
3351058561cbSjbeck **		pargc -- number of arguments (ouput)
3352058561cbSjbeck **
3353058561cbSjbeck **	Returns:
3354058561cbSjbeck **		array of pointers to the individual strings
3355058561cbSjbeck */
3356058561cbSjbeck 
3357058561cbSjbeck static char **milter_split_response __P((char *, ssize_t, int *));
3358058561cbSjbeck 
3359058561cbSjbeck static char **
milter_split_response(response,rlen,pargc)3360058561cbSjbeck milter_split_response(response, rlen, pargc)
3361058561cbSjbeck 	char *response;
3362058561cbSjbeck 	ssize_t rlen;
3363058561cbSjbeck 	int *pargc;
3364058561cbSjbeck {
3365058561cbSjbeck 	char **s;
3366058561cbSjbeck 	size_t i;
3367058561cbSjbeck 	int elem, nelem;
3368058561cbSjbeck 
3369058561cbSjbeck 	SM_ASSERT(response != NULL);
3370058561cbSjbeck 	SM_ASSERT(pargc != NULL);
3371058561cbSjbeck 	*pargc = 0;
3372058561cbSjbeck 	if (rlen < 2 || strlen(response) >= (size_t) rlen)
3373058561cbSjbeck 	{
3374058561cbSjbeck 		if (tTd(64, 10))
3375058561cbSjbeck 			sm_dprintf("didn't follow protocol (total len %d != rlen %d)\n",
3376058561cbSjbeck 				   (int) strlen(response), (int) (rlen - 1));
3377058561cbSjbeck 		return NULL;
3378058561cbSjbeck 	}
3379058561cbSjbeck 
3380058561cbSjbeck 	nelem = 0;
3381058561cbSjbeck 	for (i = 0; i < rlen; i++)
3382058561cbSjbeck 	{
3383058561cbSjbeck 		if (response[i] == '\0')
3384058561cbSjbeck 			++nelem;
3385058561cbSjbeck 	}
3386058561cbSjbeck 	if (nelem == 0)
3387058561cbSjbeck 		return NULL;
3388058561cbSjbeck 
3389058561cbSjbeck 	/* last entry is only for the name */
3390*e9af4bc0SJohn Beck 	s = (char **)malloc((nelem + 1) * (sizeof(*s)));
3391058561cbSjbeck 	if (s == NULL)
3392058561cbSjbeck 		return NULL;
3393058561cbSjbeck 	s[0] = response;
3394058561cbSjbeck 	for (i = 0, elem = 0; i < rlen && elem < nelem; i++)
3395058561cbSjbeck 	{
3396058561cbSjbeck 		if (response[i] == '\0')
3397058561cbSjbeck 		{
3398058561cbSjbeck 			++elem;
3399058561cbSjbeck 			if (i + 1 >= rlen)
3400058561cbSjbeck 				s[elem] = NULL;
3401058561cbSjbeck 			else
3402058561cbSjbeck 				s[elem] = &(response[i + 1]);
3403058561cbSjbeck 		}
3404058561cbSjbeck 	}
3405058561cbSjbeck 	*pargc = nelem;
3406058561cbSjbeck 
3407058561cbSjbeck 	if (tTd(64, 10))
3408058561cbSjbeck 	{
3409058561cbSjbeck 		for (elem = 0; elem < nelem; elem++)
3410058561cbSjbeck 			sm_dprintf("argv[%d]=\"%s\"\n", elem, s[elem]);
3411058561cbSjbeck 	}
3412058561cbSjbeck 
3413058561cbSjbeck 	/* overwrite last entry (already done above, just paranoia) */
3414058561cbSjbeck 	s[elem] = NULL;
3415058561cbSjbeck 	return s;
3416058561cbSjbeck }
3417058561cbSjbeck 
3418058561cbSjbeck /*
3419058561cbSjbeck **  MILTER_CHGFROM -- Change the envelope sender address
3420058561cbSjbeck **
3421058561cbSjbeck **	Parameters:
3422058561cbSjbeck **		response -- encoded form of recipient address.
3423058561cbSjbeck **		rlen -- length of response.
3424058561cbSjbeck **		e -- current envelope.
3425058561cbSjbeck **
3426058561cbSjbeck **	Returns:
3427058561cbSjbeck **		none
3428058561cbSjbeck */
3429058561cbSjbeck 
3430058561cbSjbeck static void
milter_chgfrom(response,rlen,e)3431058561cbSjbeck milter_chgfrom(response, rlen, e)
3432058561cbSjbeck 	char *response;
3433058561cbSjbeck 	ssize_t rlen;
3434058561cbSjbeck 	ENVELOPE *e;
3435058561cbSjbeck {
3436058561cbSjbeck 	int olderrors, argc;
3437058561cbSjbeck 	char **argv;
3438058561cbSjbeck 
3439058561cbSjbeck 	if (tTd(64, 10))
3440058561cbSjbeck 		sm_dprintf("milter_chgfrom: ");
3441058561cbSjbeck 
3442058561cbSjbeck 	/* sanity checks */
3443058561cbSjbeck 	if (response == NULL)
3444058561cbSjbeck 	{
3445058561cbSjbeck 		if (tTd(64, 10))
3446058561cbSjbeck 			sm_dprintf("NULL response\n");
3447058561cbSjbeck 		return;
3448058561cbSjbeck 	}
3449058561cbSjbeck 
3450058561cbSjbeck 	if (*response == '\0' ||
3451058561cbSjbeck 	    strlen(response) + 1 > (size_t) rlen)
3452058561cbSjbeck 	{
3453058561cbSjbeck 		if (tTd(64, 10))
3454058561cbSjbeck 			sm_dprintf("didn't follow protocol (total len %d != rlen %d)\n",
3455058561cbSjbeck 				   (int) strlen(response), (int) (rlen - 1));
3456058561cbSjbeck 		return;
3457058561cbSjbeck 	}
3458058561cbSjbeck 
3459058561cbSjbeck 	if (tTd(64, 10))
3460058561cbSjbeck 		sm_dprintf("%s\n", response);
3461058561cbSjbeck 	if (MilterLogLevel > 8)
3462058561cbSjbeck 		sm_syslog(LOG_INFO, e->e_id, "Milter chgfrom: %s", response);
3463058561cbSjbeck 	argv = milter_split_response(response, rlen, &argc);
3464058561cbSjbeck 	if (argc < 1 || argc > 2)
3465058561cbSjbeck 	{
3466058561cbSjbeck 		if (tTd(64, 10))
3467058561cbSjbeck 			sm_dprintf("didn't follow protocol argc=%d\n", argc);
3468058561cbSjbeck 		return;
3469058561cbSjbeck 	}
3470058561cbSjbeck 
3471058561cbSjbeck 	olderrors = Errors;
3472058561cbSjbeck 	setsender(argv[0], e, NULL, '\0', false);
3473058561cbSjbeck 	if (argc == 2)
3474058561cbSjbeck 	{
3475058561cbSjbeck 		reset_mail_esmtp_args(e);
3476058561cbSjbeck 
3477058561cbSjbeck 		/*
3478058561cbSjbeck 		**  need "features" here: how to get those? via e?
3479058561cbSjbeck 		**  "fake" it for now: allow everything.
3480058561cbSjbeck 		*/
3481058561cbSjbeck 
3482058561cbSjbeck 		parse_esmtp_args(e, NULL, argv[0], argv[1], "MAIL", NULL,
3483058561cbSjbeck 				mail_esmtp_args);
3484058561cbSjbeck 	}
3485058561cbSjbeck 	Errors = olderrors;
3486058561cbSjbeck 	return;
3487058561cbSjbeck }
3488058561cbSjbeck 
3489058561cbSjbeck /*
3490058561cbSjbeck **  MILTER_ADDRCPT_PAR -- Add the supplied recipient to the message
3491058561cbSjbeck **
3492058561cbSjbeck **	Parameters:
3493058561cbSjbeck **		response -- encoded form of recipient address.
3494058561cbSjbeck **		rlen -- length of response.
3495058561cbSjbeck **		e -- current envelope.
3496058561cbSjbeck **
3497058561cbSjbeck **	Returns:
3498058561cbSjbeck **		none
3499058561cbSjbeck */
3500058561cbSjbeck 
3501058561cbSjbeck static void
milter_addrcpt_par(response,rlen,e)3502058561cbSjbeck milter_addrcpt_par(response, rlen, e)
3503058561cbSjbeck 	char *response;
3504058561cbSjbeck 	ssize_t rlen;
3505058561cbSjbeck 	ENVELOPE *e;
3506058561cbSjbeck {
3507058561cbSjbeck 	int olderrors, argc;
3508058561cbSjbeck 	char *delimptr;
3509058561cbSjbeck 	char **argv;
3510058561cbSjbeck 	ADDRESS *a;
3511058561cbSjbeck 
3512058561cbSjbeck 	if (tTd(64, 10))
3513058561cbSjbeck 		sm_dprintf("milter_addrcpt_par: ");
3514058561cbSjbeck 
3515058561cbSjbeck 	/* sanity checks */
3516058561cbSjbeck 	if (response == NULL)
3517058561cbSjbeck 	{
3518058561cbSjbeck 		if (tTd(64, 10))
3519058561cbSjbeck 			sm_dprintf("NULL response\n");
3520058561cbSjbeck 		return;
3521058561cbSjbeck 	}
3522058561cbSjbeck 
3523058561cbSjbeck 	if (tTd(64, 10))
3524058561cbSjbeck 		sm_dprintf("%s\n", response);
3525058561cbSjbeck 	if (MilterLogLevel > 8)
3526058561cbSjbeck 		sm_syslog(LOG_INFO, e->e_id, "Milter add: rcpt: %s", response);
3527058561cbSjbeck 
3528058561cbSjbeck 	argv = milter_split_response(response, rlen, &argc);
3529058561cbSjbeck 	if (argc < 1 || argc > 2)
3530058561cbSjbeck 	{
3531058561cbSjbeck 		if (tTd(64, 10))
3532058561cbSjbeck 			sm_dprintf("didn't follow protocol argc=%d\n", argc);
3533058561cbSjbeck 		return;
3534058561cbSjbeck 	}
3535058561cbSjbeck 	olderrors = Errors;
3536058561cbSjbeck 
3537058561cbSjbeck 	/* how to set ESMTP arguments? */
3538058561cbSjbeck 	a = parseaddr(argv[0], NULLADDR, RF_COPYALL, ' ', &delimptr, e, true);
3539058561cbSjbeck 
3540058561cbSjbeck 	if (a != NULL && olderrors == Errors)
3541058561cbSjbeck 	{
3542058561cbSjbeck 		parse_esmtp_args(e, a, argv[0], argv[1], "RCPT", NULL,
3543058561cbSjbeck 				rcpt_esmtp_args);
3544058561cbSjbeck 		if (olderrors == Errors)
3545058561cbSjbeck 			a = recipient(a, &e->e_sendqueue, 0, e);
3546058561cbSjbeck 		else
3547058561cbSjbeck 			sm_dprintf("olderrors=%d, Errors=%d\n",
3548058561cbSjbeck 				olderrors, Errors);
3549058561cbSjbeck 	}
3550058561cbSjbeck 	else
3551058561cbSjbeck 	{
3552058561cbSjbeck 		sm_dprintf("a=%p, olderrors=%d, Errors=%d\n",
3553058561cbSjbeck 			a, olderrors, Errors);
3554058561cbSjbeck 	}
3555058561cbSjbeck 
3556058561cbSjbeck 	Errors = olderrors;
3557058561cbSjbeck 	return;
3558058561cbSjbeck }
3559058561cbSjbeck 
35607c478bd9Sstevel@tonic-gate /*
35617c478bd9Sstevel@tonic-gate **  MILTER_ADDRCPT -- Add the supplied recipient to the message
35627c478bd9Sstevel@tonic-gate **
35637c478bd9Sstevel@tonic-gate **	Parameters:
35647c478bd9Sstevel@tonic-gate **		response -- encoded form of recipient address.
35657c478bd9Sstevel@tonic-gate **		rlen -- length of response.
35667c478bd9Sstevel@tonic-gate **		e -- current envelope.
35677c478bd9Sstevel@tonic-gate **
35687c478bd9Sstevel@tonic-gate **	Returns:
35697c478bd9Sstevel@tonic-gate **		none
35707c478bd9Sstevel@tonic-gate */
35717c478bd9Sstevel@tonic-gate 
35727c478bd9Sstevel@tonic-gate static void
milter_addrcpt(response,rlen,e)35737c478bd9Sstevel@tonic-gate milter_addrcpt(response, rlen, e)
35747c478bd9Sstevel@tonic-gate 	char *response;
35757c478bd9Sstevel@tonic-gate 	ssize_t rlen;
35767c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
35777c478bd9Sstevel@tonic-gate {
35787c478bd9Sstevel@tonic-gate 	int olderrors;
35797c478bd9Sstevel@tonic-gate 
35807c478bd9Sstevel@tonic-gate 	if (tTd(64, 10))
35817c478bd9Sstevel@tonic-gate 		sm_dprintf("milter_addrcpt: ");
35827c478bd9Sstevel@tonic-gate 
35837c478bd9Sstevel@tonic-gate 	/* sanity checks */
35847c478bd9Sstevel@tonic-gate 	if (response == NULL)
35857c478bd9Sstevel@tonic-gate 	{
35867c478bd9Sstevel@tonic-gate 		if (tTd(64, 10))
35877c478bd9Sstevel@tonic-gate 			sm_dprintf("NULL response\n");
35887c478bd9Sstevel@tonic-gate 		return;
35897c478bd9Sstevel@tonic-gate 	}
35907c478bd9Sstevel@tonic-gate 
35917c478bd9Sstevel@tonic-gate 	if (*response == '\0' ||
35927c478bd9Sstevel@tonic-gate 	    strlen(response) + 1 != (size_t) rlen)
35937c478bd9Sstevel@tonic-gate 	{
35947c478bd9Sstevel@tonic-gate 		if (tTd(64, 10))
35957c478bd9Sstevel@tonic-gate 			sm_dprintf("didn't follow protocol (total len %d != rlen %d)\n",
35967c478bd9Sstevel@tonic-gate 				   (int) strlen(response), (int) (rlen - 1));
35977c478bd9Sstevel@tonic-gate 		return;
35987c478bd9Sstevel@tonic-gate 	}
35997c478bd9Sstevel@tonic-gate 
36007c478bd9Sstevel@tonic-gate 	if (tTd(64, 10))
36017c478bd9Sstevel@tonic-gate 		sm_dprintf("%s\n", response);
36027c478bd9Sstevel@tonic-gate 	if (MilterLogLevel > 8)
36037c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_INFO, e->e_id, "Milter add: rcpt: %s", response);
36047c478bd9Sstevel@tonic-gate 	olderrors = Errors;
36057c478bd9Sstevel@tonic-gate 	(void) sendtolist(response, NULLADDR, &e->e_sendqueue, 0, e);
36067c478bd9Sstevel@tonic-gate 	Errors = olderrors;
36077c478bd9Sstevel@tonic-gate 	return;
36087c478bd9Sstevel@tonic-gate }
3609058561cbSjbeck 
36107c478bd9Sstevel@tonic-gate /*
36117c478bd9Sstevel@tonic-gate **  MILTER_DELRCPT -- Delete the supplied recipient from the message
36127c478bd9Sstevel@tonic-gate **
36137c478bd9Sstevel@tonic-gate **	Parameters:
36147c478bd9Sstevel@tonic-gate **		response -- encoded form of recipient address.
36157c478bd9Sstevel@tonic-gate **		rlen -- length of response.
36167c478bd9Sstevel@tonic-gate **		e -- current envelope.
36177c478bd9Sstevel@tonic-gate **
36187c478bd9Sstevel@tonic-gate **	Returns:
36197c478bd9Sstevel@tonic-gate **		none
36207c478bd9Sstevel@tonic-gate */
36217c478bd9Sstevel@tonic-gate 
36227c478bd9Sstevel@tonic-gate static void
milter_delrcpt(response,rlen,e)36237c478bd9Sstevel@tonic-gate milter_delrcpt(response, rlen, e)
36247c478bd9Sstevel@tonic-gate 	char *response;
36257c478bd9Sstevel@tonic-gate 	ssize_t rlen;
36267c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
36277c478bd9Sstevel@tonic-gate {
36287c478bd9Sstevel@tonic-gate 	if (tTd(64, 10))
36297c478bd9Sstevel@tonic-gate 		sm_dprintf("milter_delrcpt: ");
36307c478bd9Sstevel@tonic-gate 
36317c478bd9Sstevel@tonic-gate 	/* sanity checks */
36327c478bd9Sstevel@tonic-gate 	if (response == NULL)
36337c478bd9Sstevel@tonic-gate 	{
36347c478bd9Sstevel@tonic-gate 		if (tTd(64, 10))
36357c478bd9Sstevel@tonic-gate 			sm_dprintf("NULL response\n");
36367c478bd9Sstevel@tonic-gate 		return;
36377c478bd9Sstevel@tonic-gate 	}
36387c478bd9Sstevel@tonic-gate 
36397c478bd9Sstevel@tonic-gate 	if (*response == '\0' ||
36407c478bd9Sstevel@tonic-gate 	    strlen(response) + 1 != (size_t) rlen)
36417c478bd9Sstevel@tonic-gate 	{
36427c478bd9Sstevel@tonic-gate 		if (tTd(64, 10))
3643058561cbSjbeck 			sm_dprintf("didn't follow protocol (total len %d != rlen %d)\n",
3644058561cbSjbeck 				   (int) strlen(response), (int) (rlen - 1));
36457c478bd9Sstevel@tonic-gate 		return;
36467c478bd9Sstevel@tonic-gate 	}
36477c478bd9Sstevel@tonic-gate 
36487c478bd9Sstevel@tonic-gate 	if (tTd(64, 10))
36497c478bd9Sstevel@tonic-gate 		sm_dprintf("%s\n", response);
36507c478bd9Sstevel@tonic-gate 	if (MilterLogLevel > 8)
36517c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_INFO, e->e_id, "Milter delete: rcpt %s",
36527c478bd9Sstevel@tonic-gate 			  response);
36537c478bd9Sstevel@tonic-gate 	(void) removefromlist(response, &e->e_sendqueue, e);
36547c478bd9Sstevel@tonic-gate 	return;
36557c478bd9Sstevel@tonic-gate }
3656058561cbSjbeck 
36577c478bd9Sstevel@tonic-gate /*
36587c478bd9Sstevel@tonic-gate **  MILTER_REPLBODY -- Replace the current data file with new body
36597c478bd9Sstevel@tonic-gate **
36607c478bd9Sstevel@tonic-gate **	Parameters:
36617c478bd9Sstevel@tonic-gate **		response -- encoded form of new body.
36627c478bd9Sstevel@tonic-gate **		rlen -- length of response.
36637c478bd9Sstevel@tonic-gate **		newfilter -- if first time called by a new filter
36647c478bd9Sstevel@tonic-gate **		e -- current envelope.
36657c478bd9Sstevel@tonic-gate **
36667c478bd9Sstevel@tonic-gate **	Returns:
36677c478bd9Sstevel@tonic-gate **		0 upon success, -1 upon failure
36687c478bd9Sstevel@tonic-gate */
36697c478bd9Sstevel@tonic-gate 
36707c478bd9Sstevel@tonic-gate static int
milter_replbody(response,rlen,newfilter,e)36717c478bd9Sstevel@tonic-gate milter_replbody(response, rlen, newfilter, e)
36727c478bd9Sstevel@tonic-gate 	char *response;
36737c478bd9Sstevel@tonic-gate 	ssize_t rlen;
36747c478bd9Sstevel@tonic-gate 	bool newfilter;
36757c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
36767c478bd9Sstevel@tonic-gate {
36777c478bd9Sstevel@tonic-gate 	static char prevchar;
36787c478bd9Sstevel@tonic-gate 	int i;
36797c478bd9Sstevel@tonic-gate 
36807c478bd9Sstevel@tonic-gate 	if (tTd(64, 10))
36817c478bd9Sstevel@tonic-gate 		sm_dprintf("milter_replbody\n");
36827c478bd9Sstevel@tonic-gate 
36837c478bd9Sstevel@tonic-gate 	/* If a new filter, reset previous character and truncate data file */
36847c478bd9Sstevel@tonic-gate 	if (newfilter)
36857c478bd9Sstevel@tonic-gate 	{
36867c478bd9Sstevel@tonic-gate 		off_t prevsize;
36877c478bd9Sstevel@tonic-gate 		char dfname[MAXPATHLEN];
36887c478bd9Sstevel@tonic-gate 
36897c478bd9Sstevel@tonic-gate 		(void) sm_strlcpy(dfname, queuename(e, DATAFL_LETTER),
3690058561cbSjbeck 				  sizeof(dfname));
36917c478bd9Sstevel@tonic-gate 
36927c478bd9Sstevel@tonic-gate 		/* Reset prevchar */
36937c478bd9Sstevel@tonic-gate 		prevchar = '\0';
36947c478bd9Sstevel@tonic-gate 
36957c478bd9Sstevel@tonic-gate 		/* Get the current data file information */
36967c478bd9Sstevel@tonic-gate 		prevsize = sm_io_getinfo(e->e_dfp, SM_IO_WHAT_SIZE, NULL);
36977c478bd9Sstevel@tonic-gate 		if (prevsize < 0)
36987c478bd9Sstevel@tonic-gate 			prevsize = 0;
36997c478bd9Sstevel@tonic-gate 
37007c478bd9Sstevel@tonic-gate 		/* truncate current data file */
37017c478bd9Sstevel@tonic-gate 		if (sm_io_getinfo(e->e_dfp, SM_IO_WHAT_ISTYPE, BF_FILE_TYPE))
37027c478bd9Sstevel@tonic-gate 		{
37037c478bd9Sstevel@tonic-gate 			if (sm_io_setinfo(e->e_dfp, SM_BF_TRUNCATE, NULL) < 0)
37047c478bd9Sstevel@tonic-gate 			{
37057c478bd9Sstevel@tonic-gate 				MILTER_DF_ERROR("milter_replbody: sm_io truncate %s: %s");
37067c478bd9Sstevel@tonic-gate 				return -1;
37077c478bd9Sstevel@tonic-gate 			}
37087c478bd9Sstevel@tonic-gate 		}
37097c478bd9Sstevel@tonic-gate 		else
37107c478bd9Sstevel@tonic-gate 		{
37117c478bd9Sstevel@tonic-gate 			int err;
37127c478bd9Sstevel@tonic-gate 
37137c478bd9Sstevel@tonic-gate 			err = sm_io_error(e->e_dfp);
37147c478bd9Sstevel@tonic-gate 			(void) sm_io_flush(e->e_dfp, SM_TIME_DEFAULT);
37157c478bd9Sstevel@tonic-gate 
37167c478bd9Sstevel@tonic-gate 			/*
37177c478bd9Sstevel@tonic-gate 			**  Clear error if tried to fflush()
37187c478bd9Sstevel@tonic-gate 			**  a read-only file pointer and
37197c478bd9Sstevel@tonic-gate 			**  there wasn't a previous error.
37207c478bd9Sstevel@tonic-gate 			*/
37217c478bd9Sstevel@tonic-gate 
37227c478bd9Sstevel@tonic-gate 			if (err == 0)
37237c478bd9Sstevel@tonic-gate 				sm_io_clearerr(e->e_dfp);
37247c478bd9Sstevel@tonic-gate 
37257c478bd9Sstevel@tonic-gate 			/* errno is set implicitly by fseek() before return */
37267c478bd9Sstevel@tonic-gate 			err = sm_io_seek(e->e_dfp, SM_TIME_DEFAULT,
37277c478bd9Sstevel@tonic-gate 					 0, SEEK_SET);
37287c478bd9Sstevel@tonic-gate 			if (err < 0)
37297c478bd9Sstevel@tonic-gate 			{
37307c478bd9Sstevel@tonic-gate 				MILTER_DF_ERROR("milter_replbody: sm_io_seek %s: %s");
37317c478bd9Sstevel@tonic-gate 				return -1;
37327c478bd9Sstevel@tonic-gate 			}
37337c478bd9Sstevel@tonic-gate # if NOFTRUNCATE
37347c478bd9Sstevel@tonic-gate 			/* XXX: Not much we can do except rewind it */
37357c478bd9Sstevel@tonic-gate 			errno = EINVAL;
37367c478bd9Sstevel@tonic-gate 			MILTER_DF_ERROR("milter_replbody: ftruncate not available on this platform (%s:%s)");
37377c478bd9Sstevel@tonic-gate 			return -1;
37387c478bd9Sstevel@tonic-gate # else /* NOFTRUNCATE */
37397c478bd9Sstevel@tonic-gate 			err = ftruncate(sm_io_getinfo(e->e_dfp,
37407c478bd9Sstevel@tonic-gate 						      SM_IO_WHAT_FD, NULL),
37417c478bd9Sstevel@tonic-gate 					0);
37427c478bd9Sstevel@tonic-gate 			if (err < 0)
37437c478bd9Sstevel@tonic-gate 			{
37447c478bd9Sstevel@tonic-gate 				MILTER_DF_ERROR("milter_replbody: sm_io ftruncate %s: %s");
37457c478bd9Sstevel@tonic-gate 				return -1;
37467c478bd9Sstevel@tonic-gate 			}
37477c478bd9Sstevel@tonic-gate # endif /* NOFTRUNCATE */
37487c478bd9Sstevel@tonic-gate 		}
37497c478bd9Sstevel@tonic-gate 
37507c478bd9Sstevel@tonic-gate 		if (prevsize > e->e_msgsize)
37517c478bd9Sstevel@tonic-gate 			e->e_msgsize = 0;
37527c478bd9Sstevel@tonic-gate 		else
37537c478bd9Sstevel@tonic-gate 			e->e_msgsize -= prevsize;
37547c478bd9Sstevel@tonic-gate 	}
37557c478bd9Sstevel@tonic-gate 
37567c478bd9Sstevel@tonic-gate 	if (newfilter && MilterLogLevel > 8)
37577c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_INFO, e->e_id, "Milter message: body replaced");
37587c478bd9Sstevel@tonic-gate 
37597c478bd9Sstevel@tonic-gate 	if (response == NULL)
37607c478bd9Sstevel@tonic-gate 	{
37617c478bd9Sstevel@tonic-gate 		/* Flush the buffered '\r' */
37627c478bd9Sstevel@tonic-gate 		if (prevchar == '\r')
37637c478bd9Sstevel@tonic-gate 		{
37647c478bd9Sstevel@tonic-gate 			(void) sm_io_putc(e->e_dfp, SM_TIME_DEFAULT, prevchar);
37657c478bd9Sstevel@tonic-gate 			e->e_msgsize++;
37667c478bd9Sstevel@tonic-gate 		}
37677c478bd9Sstevel@tonic-gate 		return 0;
37687c478bd9Sstevel@tonic-gate 	}
37697c478bd9Sstevel@tonic-gate 
37707c478bd9Sstevel@tonic-gate 	for (i = 0; i < rlen; i++)
37717c478bd9Sstevel@tonic-gate 	{
37727c478bd9Sstevel@tonic-gate 		/* Buffered char from last chunk */
37737c478bd9Sstevel@tonic-gate 		if (i == 0 && prevchar == '\r')
37747c478bd9Sstevel@tonic-gate 		{
37757c478bd9Sstevel@tonic-gate 			/* Not CRLF, output prevchar */
37767c478bd9Sstevel@tonic-gate 			if (response[i] != '\n')
37777c478bd9Sstevel@tonic-gate 			{
37787c478bd9Sstevel@tonic-gate 				(void) sm_io_putc(e->e_dfp, SM_TIME_DEFAULT,
37797c478bd9Sstevel@tonic-gate 						  prevchar);
37807c478bd9Sstevel@tonic-gate 				e->e_msgsize++;
37817c478bd9Sstevel@tonic-gate 			}
37827c478bd9Sstevel@tonic-gate 			prevchar = '\0';
37837c478bd9Sstevel@tonic-gate 		}
37847c478bd9Sstevel@tonic-gate 
37857c478bd9Sstevel@tonic-gate 		/* Turn CRLF into LF */
37867c478bd9Sstevel@tonic-gate 		if (response[i] == '\r')
37877c478bd9Sstevel@tonic-gate 		{
37887c478bd9Sstevel@tonic-gate 			/* check if at end of chunk */
37897c478bd9Sstevel@tonic-gate 			if (i + 1 < rlen)
37907c478bd9Sstevel@tonic-gate 			{
37917c478bd9Sstevel@tonic-gate 				/* If LF, strip CR */
37927c478bd9Sstevel@tonic-gate 				if (response[i + 1] == '\n')
37937c478bd9Sstevel@tonic-gate 					i++;
37947c478bd9Sstevel@tonic-gate 			}
37957c478bd9Sstevel@tonic-gate 			else
37967c478bd9Sstevel@tonic-gate 			{
37977c478bd9Sstevel@tonic-gate 				/* check next chunk */
37987c478bd9Sstevel@tonic-gate 				prevchar = '\r';
37997c478bd9Sstevel@tonic-gate 				continue;
38007c478bd9Sstevel@tonic-gate 			}
38017c478bd9Sstevel@tonic-gate 		}
38027c478bd9Sstevel@tonic-gate 		(void) sm_io_putc(e->e_dfp, SM_TIME_DEFAULT, response[i]);
38037c478bd9Sstevel@tonic-gate 		e->e_msgsize++;
38047c478bd9Sstevel@tonic-gate 	}
38057c478bd9Sstevel@tonic-gate 	return 0;
38067c478bd9Sstevel@tonic-gate }
38077c478bd9Sstevel@tonic-gate 
38087c478bd9Sstevel@tonic-gate /*
38097c478bd9Sstevel@tonic-gate **  MTA callouts
38107c478bd9Sstevel@tonic-gate */
38117c478bd9Sstevel@tonic-gate 
38127c478bd9Sstevel@tonic-gate /*
38137c478bd9Sstevel@tonic-gate **  MILTER_INIT -- open and negotiate with all of the filters
38147c478bd9Sstevel@tonic-gate **
38157c478bd9Sstevel@tonic-gate **	Parameters:
38167c478bd9Sstevel@tonic-gate **		e -- current envelope.
38177c478bd9Sstevel@tonic-gate **		state -- return state from response.
38187800901eSjbeck **		milters -- milters structure.
38197c478bd9Sstevel@tonic-gate **
38207c478bd9Sstevel@tonic-gate **	Returns:
38217c478bd9Sstevel@tonic-gate **		true iff at least one filter is active
38227c478bd9Sstevel@tonic-gate */
38237c478bd9Sstevel@tonic-gate 
38247c478bd9Sstevel@tonic-gate /* ARGSUSED */
38257c478bd9Sstevel@tonic-gate bool
milter_init(e,state,milters)38267800901eSjbeck milter_init(e, state, milters)
38277c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
38287c478bd9Sstevel@tonic-gate 	char *state;
38297800901eSjbeck 	milters_T *milters;
38307c478bd9Sstevel@tonic-gate {
38317c478bd9Sstevel@tonic-gate 	int i;
38327c478bd9Sstevel@tonic-gate 
38337c478bd9Sstevel@tonic-gate 	if (tTd(64, 10))
38347c478bd9Sstevel@tonic-gate 		sm_dprintf("milter_init\n");
38357c478bd9Sstevel@tonic-gate 
38367800901eSjbeck 	memset(milters, '\0', sizeof(*milters));
38377c478bd9Sstevel@tonic-gate 	*state = SMFIR_CONTINUE;
38387c478bd9Sstevel@tonic-gate 	if (InputFilters[0] == NULL)
38397c478bd9Sstevel@tonic-gate 	{
38407c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 10)
38417c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_INFO, e->e_id,
38427c478bd9Sstevel@tonic-gate 				  "Milter: no active filter");
38437c478bd9Sstevel@tonic-gate 		return false;
38447c478bd9Sstevel@tonic-gate 	}
38457c478bd9Sstevel@tonic-gate 
38467c478bd9Sstevel@tonic-gate 	for (i = 0; InputFilters[i] != NULL; i++)
38477c478bd9Sstevel@tonic-gate 	{
38487c478bd9Sstevel@tonic-gate 		struct milter *m = InputFilters[i];
38497c478bd9Sstevel@tonic-gate 
38507c478bd9Sstevel@tonic-gate 		m->mf_sock = milter_open(m, false, e);
38517c478bd9Sstevel@tonic-gate 		if (m->mf_state == SMFS_ERROR)
38527c478bd9Sstevel@tonic-gate 		{
38537c478bd9Sstevel@tonic-gate 			MILTER_CHECK_ERROR(true, continue);
38547c478bd9Sstevel@tonic-gate 			break;
38557c478bd9Sstevel@tonic-gate 		}
38567c478bd9Sstevel@tonic-gate 
38577c478bd9Sstevel@tonic-gate 		if (m->mf_sock < 0 ||
38587800901eSjbeck 		    milter_negotiate(m, e, milters) < 0 ||
38597c478bd9Sstevel@tonic-gate 		    m->mf_state == SMFS_ERROR)
38607c478bd9Sstevel@tonic-gate 		{
38617c478bd9Sstevel@tonic-gate 			if (tTd(64, 5))
38627c478bd9Sstevel@tonic-gate 				sm_dprintf("milter_init(%s): failed to %s\n",
38637c478bd9Sstevel@tonic-gate 					   m->mf_name,
38647c478bd9Sstevel@tonic-gate 					   m->mf_sock < 0 ? "open" :
38657c478bd9Sstevel@tonic-gate 							    "negotiate");
38667c478bd9Sstevel@tonic-gate 			if (MilterLogLevel > 0)
38677c478bd9Sstevel@tonic-gate 				sm_syslog(LOG_ERR, e->e_id,
38687c478bd9Sstevel@tonic-gate 					  "Milter (%s): init failed to %s",
38697c478bd9Sstevel@tonic-gate 					  m->mf_name,
38707c478bd9Sstevel@tonic-gate 					  m->mf_sock < 0 ? "open" :
38717c478bd9Sstevel@tonic-gate 							   "negotiate");
38727c478bd9Sstevel@tonic-gate 
3873*e9af4bc0SJohn Beck 			/* if negotiation failure, close socket */
38747c478bd9Sstevel@tonic-gate 			milter_error(m, e);
38757c478bd9Sstevel@tonic-gate 			MILTER_CHECK_ERROR(true, continue);
38767c478bd9Sstevel@tonic-gate 			continue;
38777c478bd9Sstevel@tonic-gate 		}
38787c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 9)
38797c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_INFO, e->e_id,
38807c478bd9Sstevel@tonic-gate 				  "Milter (%s): init success to %s",
38817c478bd9Sstevel@tonic-gate 				  m->mf_name,
38827c478bd9Sstevel@tonic-gate 				  m->mf_sock < 0 ? "open" : "negotiate");
38837c478bd9Sstevel@tonic-gate 	}
38847c478bd9Sstevel@tonic-gate 
38857c478bd9Sstevel@tonic-gate 	/*
38867c478bd9Sstevel@tonic-gate 	**  If something temp/perm failed with one of the filters,
38877c478bd9Sstevel@tonic-gate 	**  we won't be using any of them, so clear any existing
38887c478bd9Sstevel@tonic-gate 	**  connections.
38897c478bd9Sstevel@tonic-gate 	*/
38907c478bd9Sstevel@tonic-gate 
38917c478bd9Sstevel@tonic-gate 	if (*state != SMFIR_CONTINUE)
38927c478bd9Sstevel@tonic-gate 		milter_quit(e);
38937c478bd9Sstevel@tonic-gate 
38947c478bd9Sstevel@tonic-gate 	return true;
38957c478bd9Sstevel@tonic-gate }
3896058561cbSjbeck 
38977c478bd9Sstevel@tonic-gate /*
38987c478bd9Sstevel@tonic-gate **  MILTER_CONNECT -- send connection info to milter filters
38997c478bd9Sstevel@tonic-gate **
39007c478bd9Sstevel@tonic-gate **	Parameters:
39017c478bd9Sstevel@tonic-gate **		hostname -- hostname of remote machine.
39027c478bd9Sstevel@tonic-gate **		addr -- address of remote machine.
39037c478bd9Sstevel@tonic-gate **		e -- current envelope.
39047c478bd9Sstevel@tonic-gate **		state -- return state from response.
39057c478bd9Sstevel@tonic-gate **
39067c478bd9Sstevel@tonic-gate **	Returns:
39077c478bd9Sstevel@tonic-gate **		response string (may be NULL)
39087c478bd9Sstevel@tonic-gate */
39097c478bd9Sstevel@tonic-gate 
39107c478bd9Sstevel@tonic-gate char *
milter_connect(hostname,addr,e,state)39117c478bd9Sstevel@tonic-gate milter_connect(hostname, addr, e, state)
39127c478bd9Sstevel@tonic-gate 	char *hostname;
39137c478bd9Sstevel@tonic-gate 	SOCKADDR addr;
39147c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
39157c478bd9Sstevel@tonic-gate 	char *state;
39167c478bd9Sstevel@tonic-gate {
39177c478bd9Sstevel@tonic-gate 	char family;
39187c478bd9Sstevel@tonic-gate 	unsigned short port;
39197c478bd9Sstevel@tonic-gate 	char *buf, *bp;
39207c478bd9Sstevel@tonic-gate 	char *response;
39217c478bd9Sstevel@tonic-gate 	char *sockinfo = NULL;
39227c478bd9Sstevel@tonic-gate 	ssize_t s;
39237c478bd9Sstevel@tonic-gate # if NETINET6
39247c478bd9Sstevel@tonic-gate 	char buf6[INET6_ADDRSTRLEN];
39257c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
39267c478bd9Sstevel@tonic-gate 
39277c478bd9Sstevel@tonic-gate 	if (tTd(64, 10))
39287c478bd9Sstevel@tonic-gate 		sm_dprintf("milter_connect(%s)\n", hostname);
39297c478bd9Sstevel@tonic-gate 	if (MilterLogLevel > 9)
39307c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_INFO, e->e_id, "Milter: connect to filters");
39317c478bd9Sstevel@tonic-gate 
39327c478bd9Sstevel@tonic-gate 	/* gather data */
39337c478bd9Sstevel@tonic-gate 	switch (addr.sa.sa_family)
39347c478bd9Sstevel@tonic-gate 	{
39357c478bd9Sstevel@tonic-gate # if NETUNIX
39367c478bd9Sstevel@tonic-gate 	  case AF_UNIX:
39377c478bd9Sstevel@tonic-gate 		family = SMFIA_UNIX;
39387c478bd9Sstevel@tonic-gate 		port = htons(0);
39397c478bd9Sstevel@tonic-gate 		sockinfo = addr.sunix.sun_path;
39407c478bd9Sstevel@tonic-gate 		break;
39417c478bd9Sstevel@tonic-gate # endif /* NETUNIX */
39427c478bd9Sstevel@tonic-gate 
39437c478bd9Sstevel@tonic-gate # if NETINET
39447c478bd9Sstevel@tonic-gate 	  case AF_INET:
39457c478bd9Sstevel@tonic-gate 		family = SMFIA_INET;
39467c478bd9Sstevel@tonic-gate 		port = addr.sin.sin_port;
39477c478bd9Sstevel@tonic-gate 		sockinfo = (char *) inet_ntoa(addr.sin.sin_addr);
39487c478bd9Sstevel@tonic-gate 		break;
39497c478bd9Sstevel@tonic-gate # endif /* NETINET */
39507c478bd9Sstevel@tonic-gate 
39517c478bd9Sstevel@tonic-gate # if NETINET6
39527c478bd9Sstevel@tonic-gate 	  case AF_INET6:
39537c478bd9Sstevel@tonic-gate 		if (IN6_IS_ADDR_V4MAPPED(&addr.sin6.sin6_addr))
39547c478bd9Sstevel@tonic-gate 			family = SMFIA_INET;
39557c478bd9Sstevel@tonic-gate 		else
39567c478bd9Sstevel@tonic-gate 			family = SMFIA_INET6;
39577c478bd9Sstevel@tonic-gate 		port = addr.sin6.sin6_port;
39587c478bd9Sstevel@tonic-gate 		sockinfo = anynet_ntop(&addr.sin6.sin6_addr, buf6,
3959058561cbSjbeck 				       sizeof(buf6));
39607c478bd9Sstevel@tonic-gate 		if (sockinfo == NULL)
39617c478bd9Sstevel@tonic-gate 			sockinfo = "";
39627c478bd9Sstevel@tonic-gate 		break;
39637c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
39647c478bd9Sstevel@tonic-gate 
39657c478bd9Sstevel@tonic-gate 	  default:
39667c478bd9Sstevel@tonic-gate 		family = SMFIA_UNKNOWN;
39677c478bd9Sstevel@tonic-gate 		break;
39687c478bd9Sstevel@tonic-gate 	}
39697c478bd9Sstevel@tonic-gate 
39707c478bd9Sstevel@tonic-gate 	s = strlen(hostname) + 1 + sizeof(family);
39717c478bd9Sstevel@tonic-gate 	if (family != SMFIA_UNKNOWN)
39727c478bd9Sstevel@tonic-gate 		s += sizeof(port) + strlen(sockinfo) + 1;
39737c478bd9Sstevel@tonic-gate 
39747c478bd9Sstevel@tonic-gate 	buf = (char *) xalloc(s);
39757c478bd9Sstevel@tonic-gate 	bp = buf;
39767c478bd9Sstevel@tonic-gate 
39777c478bd9Sstevel@tonic-gate 	/* put together data */
39787c478bd9Sstevel@tonic-gate 	(void) memcpy(bp, hostname, strlen(hostname));
39797c478bd9Sstevel@tonic-gate 	bp += strlen(hostname);
39807c478bd9Sstevel@tonic-gate 	*bp++ = '\0';
3981058561cbSjbeck 	(void) memcpy(bp, &family, sizeof(family));
3982058561cbSjbeck 	bp += sizeof(family);
39837c478bd9Sstevel@tonic-gate 	if (family != SMFIA_UNKNOWN)
39847c478bd9Sstevel@tonic-gate 	{
3985058561cbSjbeck 		(void) memcpy(bp, &port, sizeof(port));
3986058561cbSjbeck 		bp += sizeof(port);
39877c478bd9Sstevel@tonic-gate 
39887c478bd9Sstevel@tonic-gate 		/* include trailing '\0' */
39897c478bd9Sstevel@tonic-gate 		(void) memcpy(bp, sockinfo, strlen(sockinfo) + 1);
39907c478bd9Sstevel@tonic-gate 	}
39917c478bd9Sstevel@tonic-gate 
3992058561cbSjbeck 	response = milter_command(SMFIC_CONNECT, buf, s, MilterConnectMacros,
3993058561cbSjbeck 				e, state, "connect", false);
39947c478bd9Sstevel@tonic-gate 	sm_free(buf); /* XXX */
39957c478bd9Sstevel@tonic-gate 
39967c478bd9Sstevel@tonic-gate 	/*
39977c478bd9Sstevel@tonic-gate 	**  If this message connection is done for,
39987c478bd9Sstevel@tonic-gate 	**  close the filters.
39997c478bd9Sstevel@tonic-gate 	*/
40007c478bd9Sstevel@tonic-gate 
40017c478bd9Sstevel@tonic-gate 	if (*state != SMFIR_CONTINUE)
40027c478bd9Sstevel@tonic-gate 	{
40037c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 9)
40047c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_INFO, e->e_id, "Milter: connect, ending");
40057c478bd9Sstevel@tonic-gate 		milter_quit(e);
40067c478bd9Sstevel@tonic-gate 	}
40077c478bd9Sstevel@tonic-gate 	else
40087c478bd9Sstevel@tonic-gate 		milter_per_connection_check(e);
40097c478bd9Sstevel@tonic-gate 
40107c478bd9Sstevel@tonic-gate 	/*
40117c478bd9Sstevel@tonic-gate 	**  SMFIR_REPLYCODE can't work with connect due to
40127c478bd9Sstevel@tonic-gate 	**  the requirements of SMTP.  Therefore, ignore the
40137c478bd9Sstevel@tonic-gate 	**  reply code text but keep the state it would reflect.
40147c478bd9Sstevel@tonic-gate 	*/
40157c478bd9Sstevel@tonic-gate 
40167c478bd9Sstevel@tonic-gate 	if (*state == SMFIR_REPLYCODE)
40177c478bd9Sstevel@tonic-gate 	{
40187c478bd9Sstevel@tonic-gate 		if (response != NULL &&
40197c478bd9Sstevel@tonic-gate 		    *response == '4')
40207c478bd9Sstevel@tonic-gate 		{
40217c478bd9Sstevel@tonic-gate 			if (strncmp(response, "421 ", 4) == 0)
40227c478bd9Sstevel@tonic-gate 				*state = SMFIR_SHUTDOWN;
40237c478bd9Sstevel@tonic-gate 			else
40247c478bd9Sstevel@tonic-gate 				*state = SMFIR_TEMPFAIL;
40257c478bd9Sstevel@tonic-gate 		}
40267c478bd9Sstevel@tonic-gate 		else
40277c478bd9Sstevel@tonic-gate 			*state = SMFIR_REJECT;
40287c478bd9Sstevel@tonic-gate 		if (response != NULL)
40297c478bd9Sstevel@tonic-gate 		{
40307c478bd9Sstevel@tonic-gate 			sm_free(response); /* XXX */
40317c478bd9Sstevel@tonic-gate 			response = NULL;
40327c478bd9Sstevel@tonic-gate 		}
40337c478bd9Sstevel@tonic-gate 	}
40347c478bd9Sstevel@tonic-gate 	return response;
40357c478bd9Sstevel@tonic-gate }
4036058561cbSjbeck 
40377c478bd9Sstevel@tonic-gate /*
40387c478bd9Sstevel@tonic-gate **  MILTER_HELO -- send SMTP HELO/EHLO command info to milter filters
40397c478bd9Sstevel@tonic-gate **
40407c478bd9Sstevel@tonic-gate **	Parameters:
40417c478bd9Sstevel@tonic-gate **		helo -- argument to SMTP HELO/EHLO command.
40427c478bd9Sstevel@tonic-gate **		e -- current envelope.
40437c478bd9Sstevel@tonic-gate **		state -- return state from response.
40447c478bd9Sstevel@tonic-gate **
40457c478bd9Sstevel@tonic-gate **	Returns:
40467c478bd9Sstevel@tonic-gate **		response string (may be NULL)
40477c478bd9Sstevel@tonic-gate */
40487c478bd9Sstevel@tonic-gate 
40497c478bd9Sstevel@tonic-gate char *
milter_helo(helo,e,state)40507c478bd9Sstevel@tonic-gate milter_helo(helo, e, state)
40517c478bd9Sstevel@tonic-gate 	char *helo;
40527c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
40537c478bd9Sstevel@tonic-gate 	char *state;
40547c478bd9Sstevel@tonic-gate {
40557c478bd9Sstevel@tonic-gate 	int i;
40567c478bd9Sstevel@tonic-gate 	char *response;
40577c478bd9Sstevel@tonic-gate 
40587c478bd9Sstevel@tonic-gate 	if (tTd(64, 10))
40597c478bd9Sstevel@tonic-gate 		sm_dprintf("milter_helo(%s)\n", helo);
40607c478bd9Sstevel@tonic-gate 
40617c478bd9Sstevel@tonic-gate 	/* HELO/EHLO can come at any point */
40627c478bd9Sstevel@tonic-gate 	for (i = 0; InputFilters[i] != NULL; i++)
40637c478bd9Sstevel@tonic-gate 	{
40647c478bd9Sstevel@tonic-gate 		struct milter *m = InputFilters[i];
40657c478bd9Sstevel@tonic-gate 
40667c478bd9Sstevel@tonic-gate 		switch (m->mf_state)
40677c478bd9Sstevel@tonic-gate 		{
40687c478bd9Sstevel@tonic-gate 		  case SMFS_INMSG:
40697c478bd9Sstevel@tonic-gate 			/* abort in message filters */
40707c478bd9Sstevel@tonic-gate 			milter_abort_filter(m, e);
40717c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
40727c478bd9Sstevel@tonic-gate 
40737c478bd9Sstevel@tonic-gate 		  case SMFS_DONE:
40747c478bd9Sstevel@tonic-gate 			/* reset done filters */
40757c478bd9Sstevel@tonic-gate 			m->mf_state = SMFS_OPEN;
40767c478bd9Sstevel@tonic-gate 			break;
40777c478bd9Sstevel@tonic-gate 		}
40787c478bd9Sstevel@tonic-gate 	}
40797c478bd9Sstevel@tonic-gate 
40807c478bd9Sstevel@tonic-gate 	response = milter_command(SMFIC_HELO, helo, strlen(helo) + 1,
4081058561cbSjbeck 				  MilterHeloMacros, e, state, "helo", false);
40827c478bd9Sstevel@tonic-gate 	milter_per_connection_check(e);
40837c478bd9Sstevel@tonic-gate 	return response;
40847c478bd9Sstevel@tonic-gate }
4085058561cbSjbeck 
40867c478bd9Sstevel@tonic-gate /*
40877c478bd9Sstevel@tonic-gate **  MILTER_ENVFROM -- send SMTP MAIL command info to milter filters
40887c478bd9Sstevel@tonic-gate **
40897c478bd9Sstevel@tonic-gate **	Parameters:
40907c478bd9Sstevel@tonic-gate **		args -- SMTP MAIL command args (args[0] == sender).
40917c478bd9Sstevel@tonic-gate **		e -- current envelope.
40927c478bd9Sstevel@tonic-gate **		state -- return state from response.
40937c478bd9Sstevel@tonic-gate **
40947c478bd9Sstevel@tonic-gate **	Returns:
40957c478bd9Sstevel@tonic-gate **		response string (may be NULL)
40967c478bd9Sstevel@tonic-gate */
40977c478bd9Sstevel@tonic-gate 
40987c478bd9Sstevel@tonic-gate char *
milter_envfrom(args,e,state)40997c478bd9Sstevel@tonic-gate milter_envfrom(args, e, state)
41007c478bd9Sstevel@tonic-gate 	char **args;
41017c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
41027c478bd9Sstevel@tonic-gate 	char *state;
41037c478bd9Sstevel@tonic-gate {
41047c478bd9Sstevel@tonic-gate 	int i;
41057c478bd9Sstevel@tonic-gate 	char *buf, *bp;
41067c478bd9Sstevel@tonic-gate 	char *response;
41077c478bd9Sstevel@tonic-gate 	ssize_t s;
41087c478bd9Sstevel@tonic-gate 
41097c478bd9Sstevel@tonic-gate 	if (tTd(64, 10))
41107c478bd9Sstevel@tonic-gate 	{
41117c478bd9Sstevel@tonic-gate 		sm_dprintf("milter_envfrom:");
41127c478bd9Sstevel@tonic-gate 		for (i = 0; args[i] != NULL; i++)
41137c478bd9Sstevel@tonic-gate 			sm_dprintf(" %s", args[i]);
41147c478bd9Sstevel@tonic-gate 		sm_dprintf("\n");
41157c478bd9Sstevel@tonic-gate 	}
41167c478bd9Sstevel@tonic-gate 
41177c478bd9Sstevel@tonic-gate 	/* sanity check */
41187c478bd9Sstevel@tonic-gate 	if (args[0] == NULL)
41197c478bd9Sstevel@tonic-gate 	{
41207c478bd9Sstevel@tonic-gate 		*state = SMFIR_REJECT;
41217c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 10)
41227c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_INFO, e->e_id,
41237c478bd9Sstevel@tonic-gate 				  "Milter: reject, no sender");
41247c478bd9Sstevel@tonic-gate 		return NULL;
41257c478bd9Sstevel@tonic-gate 	}
41267c478bd9Sstevel@tonic-gate 
41277c478bd9Sstevel@tonic-gate 	/* new message, so ... */
41287c478bd9Sstevel@tonic-gate 	for (i = 0; InputFilters[i] != NULL; i++)
41297c478bd9Sstevel@tonic-gate 	{
41307c478bd9Sstevel@tonic-gate 		struct milter *m = InputFilters[i];
41317c478bd9Sstevel@tonic-gate 
41327c478bd9Sstevel@tonic-gate 		switch (m->mf_state)
41337c478bd9Sstevel@tonic-gate 		{
41347c478bd9Sstevel@tonic-gate 		  case SMFS_INMSG:
41357c478bd9Sstevel@tonic-gate 			/* abort in message filters */
41367c478bd9Sstevel@tonic-gate 			milter_abort_filter(m, e);
41377c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
41387c478bd9Sstevel@tonic-gate 
41397c478bd9Sstevel@tonic-gate 		  case SMFS_DONE:
41407c478bd9Sstevel@tonic-gate 			/* reset done filters */
41417c478bd9Sstevel@tonic-gate 			m->mf_state = SMFS_OPEN;
41427c478bd9Sstevel@tonic-gate 			break;
41437c478bd9Sstevel@tonic-gate 		}
41447c478bd9Sstevel@tonic-gate 	}
41457c478bd9Sstevel@tonic-gate 
41467c478bd9Sstevel@tonic-gate 	/* put together data */
41477c478bd9Sstevel@tonic-gate 	s = 0;
41487c478bd9Sstevel@tonic-gate 	for (i = 0; args[i] != NULL; i++)
41497c478bd9Sstevel@tonic-gate 		s += strlen(args[i]) + 1;
41507c478bd9Sstevel@tonic-gate 
41517c478bd9Sstevel@tonic-gate 	if (s < 0)
41527c478bd9Sstevel@tonic-gate 	{
41537c478bd9Sstevel@tonic-gate 		*state = SMFIR_TEMPFAIL;
41547c478bd9Sstevel@tonic-gate 		return NULL;
41557c478bd9Sstevel@tonic-gate 	}
41567c478bd9Sstevel@tonic-gate 
41577c478bd9Sstevel@tonic-gate 	buf = (char *) xalloc(s);
41587c478bd9Sstevel@tonic-gate 	bp = buf;
41597c478bd9Sstevel@tonic-gate 	for (i = 0; args[i] != NULL; i++)
41607c478bd9Sstevel@tonic-gate 	{
41617c478bd9Sstevel@tonic-gate 		(void) sm_strlcpy(bp, args[i], s - (bp - buf));
41627c478bd9Sstevel@tonic-gate 		bp += strlen(bp) + 1;
41637c478bd9Sstevel@tonic-gate 	}
41647c478bd9Sstevel@tonic-gate 
41657c478bd9Sstevel@tonic-gate 	if (MilterLogLevel > 14)
4166058561cbSjbeck 		sm_syslog(LOG_INFO, e->e_id, "Milter: sender: %s", buf);
41677c478bd9Sstevel@tonic-gate 
41687c478bd9Sstevel@tonic-gate 	/* send it over */
4169058561cbSjbeck 	response = milter_command(SMFIC_MAIL, buf, s, MilterEnvFromMacros,
4170058561cbSjbeck 				e, state, "mail", false);
41717c478bd9Sstevel@tonic-gate 	sm_free(buf); /* XXX */
41727c478bd9Sstevel@tonic-gate 
41737c478bd9Sstevel@tonic-gate 	/*
41747c478bd9Sstevel@tonic-gate 	**  If filter rejects/discards a per message command,
41757c478bd9Sstevel@tonic-gate 	**  abort the other filters since we are done with the
41767c478bd9Sstevel@tonic-gate 	**  current message.
41777c478bd9Sstevel@tonic-gate 	*/
41787c478bd9Sstevel@tonic-gate 
41797c478bd9Sstevel@tonic-gate 	MILTER_CHECK_DONE_MSG();
41807c478bd9Sstevel@tonic-gate 	if (MilterLogLevel > 10 && *state == SMFIR_REJECT)
4181058561cbSjbeck 		sm_syslog(LOG_INFO, e->e_id, "Milter: reject, sender");
41827c478bd9Sstevel@tonic-gate 	return response;
41837c478bd9Sstevel@tonic-gate }
41847c478bd9Sstevel@tonic-gate 
41857c478bd9Sstevel@tonic-gate /*
41867c478bd9Sstevel@tonic-gate **  MILTER_ENVRCPT -- send SMTP RCPT command info to milter filters
41877c478bd9Sstevel@tonic-gate **
41887c478bd9Sstevel@tonic-gate **	Parameters:
41897c478bd9Sstevel@tonic-gate **		args -- SMTP MAIL command args (args[0] == recipient).
41907c478bd9Sstevel@tonic-gate **		e -- current envelope.
41917c478bd9Sstevel@tonic-gate **		state -- return state from response.
4192058561cbSjbeck **		rcpt_error -- does RCPT have an error?
41937c478bd9Sstevel@tonic-gate **
41947c478bd9Sstevel@tonic-gate **	Returns:
41957c478bd9Sstevel@tonic-gate **		response string (may be NULL)
41967c478bd9Sstevel@tonic-gate */
41977c478bd9Sstevel@tonic-gate 
41987c478bd9Sstevel@tonic-gate char *
milter_envrcpt(args,e,state,rcpt_error)4199058561cbSjbeck milter_envrcpt(args, e, state, rcpt_error)
42007c478bd9Sstevel@tonic-gate 	char **args;
42017c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
42027c478bd9Sstevel@tonic-gate 	char *state;
4203058561cbSjbeck 	bool rcpt_error;
42047c478bd9Sstevel@tonic-gate {
42057c478bd9Sstevel@tonic-gate 	int i;
42067c478bd9Sstevel@tonic-gate 	char *buf, *bp;
42077c478bd9Sstevel@tonic-gate 	char *response;
42087c478bd9Sstevel@tonic-gate 	ssize_t s;
42097c478bd9Sstevel@tonic-gate 
42107c478bd9Sstevel@tonic-gate 	if (tTd(64, 10))
42117c478bd9Sstevel@tonic-gate 	{
42127c478bd9Sstevel@tonic-gate 		sm_dprintf("milter_envrcpt:");
42137c478bd9Sstevel@tonic-gate 		for (i = 0; args[i] != NULL; i++)
42147c478bd9Sstevel@tonic-gate 			sm_dprintf(" %s", args[i]);
42157c478bd9Sstevel@tonic-gate 		sm_dprintf("\n");
42167c478bd9Sstevel@tonic-gate 	}
42177c478bd9Sstevel@tonic-gate 
42187c478bd9Sstevel@tonic-gate 	/* sanity check */
42197c478bd9Sstevel@tonic-gate 	if (args[0] == NULL)
42207c478bd9Sstevel@tonic-gate 	{
42217c478bd9Sstevel@tonic-gate 		*state = SMFIR_REJECT;
42227c478bd9Sstevel@tonic-gate 		if (MilterLogLevel > 10)
42237c478bd9Sstevel@tonic-gate 			sm_syslog(LOG_INFO, e->e_id, "Milter: reject, no rcpt");
42247c478bd9Sstevel@tonic-gate 		return NULL;
42257c478bd9Sstevel@tonic-gate 	}
42267c478bd9Sstevel@tonic-gate 
42277c478bd9Sstevel@tonic-gate 	/* put together data */
42287c478bd9Sstevel@tonic-gate 	s = 0;
42297c478bd9Sstevel@tonic-gate 	for (i = 0; args[i] != NULL; i++)
42307c478bd9Sstevel@tonic-gate 		s += strlen(args[i]) + 1;
42317c478bd9Sstevel@tonic-gate 
42327c478bd9Sstevel@tonic-gate 	if (s < 0)
42337c478bd9Sstevel@tonic-gate 	{
42347c478bd9Sstevel@tonic-gate 		*state = SMFIR_TEMPFAIL;
42357c478bd9Sstevel@tonic-gate 		return NULL;
42367c478bd9Sstevel@tonic-gate 	}
42377c478bd9Sstevel@tonic-gate 
42387c478bd9Sstevel@tonic-gate 	buf = (char *) xalloc(s);
42397c478bd9Sstevel@tonic-gate 	bp = buf;
42407c478bd9Sstevel@tonic-gate 	for (i = 0; args[i] != NULL; i++)
42417c478bd9Sstevel@tonic-gate 	{
42427c478bd9Sstevel@tonic-gate 		(void) sm_strlcpy(bp, args[i], s - (bp - buf));
42437c478bd9Sstevel@tonic-gate 		bp += strlen(bp) + 1;
42447c478bd9Sstevel@tonic-gate 	}
42457c478bd9Sstevel@tonic-gate 
42467c478bd9Sstevel@tonic-gate 	if (MilterLogLevel > 14)
42477c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_INFO, e->e_id, "Milter: rcpts: %s", buf);
42487c478bd9Sstevel@tonic-gate 
42497c478bd9Sstevel@tonic-gate 	/* send it over */
4250058561cbSjbeck 	response = milter_command(SMFIC_RCPT, buf, s, MilterEnvRcptMacros,
4251058561cbSjbeck 				e, state, "rcpt", rcpt_error);
42527c478bd9Sstevel@tonic-gate 	sm_free(buf); /* XXX */
42537c478bd9Sstevel@tonic-gate 	return response;
42547c478bd9Sstevel@tonic-gate }
42557c478bd9Sstevel@tonic-gate 
42567c478bd9Sstevel@tonic-gate /*
42577c478bd9Sstevel@tonic-gate **  MILTER_DATA_CMD -- send SMTP DATA command info to milter filters
42587c478bd9Sstevel@tonic-gate **
42597c478bd9Sstevel@tonic-gate **	Parameters:
42607c478bd9Sstevel@tonic-gate **		e -- current envelope.
42617c478bd9Sstevel@tonic-gate **		state -- return state from response.
42627c478bd9Sstevel@tonic-gate **
42637c478bd9Sstevel@tonic-gate **	Returns:
42647c478bd9Sstevel@tonic-gate **		response string (may be NULL)
42657c478bd9Sstevel@tonic-gate */
42667c478bd9Sstevel@tonic-gate 
42677c478bd9Sstevel@tonic-gate char *
milter_data_cmd(e,state)42687c478bd9Sstevel@tonic-gate milter_data_cmd(e, state)
42697c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
42707c478bd9Sstevel@tonic-gate 	char *state;
42717c478bd9Sstevel@tonic-gate {
42727c478bd9Sstevel@tonic-gate 	if (tTd(64, 10))
42737c478bd9Sstevel@tonic-gate 		sm_dprintf("milter_data_cmd\n");
42747c478bd9Sstevel@tonic-gate 
42757c478bd9Sstevel@tonic-gate 	/* send it over */
4276058561cbSjbeck 	return milter_command(SMFIC_DATA, NULL, 0, MilterDataMacros, e, state,
4277058561cbSjbeck 				"data", false);
42787c478bd9Sstevel@tonic-gate }
42797c478bd9Sstevel@tonic-gate 
42807c478bd9Sstevel@tonic-gate /*
42817c478bd9Sstevel@tonic-gate **  MILTER_DATA -- send message headers/body and gather final message results
42827c478bd9Sstevel@tonic-gate **
42837c478bd9Sstevel@tonic-gate **	Parameters:
42847c478bd9Sstevel@tonic-gate **		e -- current envelope.
42857c478bd9Sstevel@tonic-gate **		state -- return state from response.
42867c478bd9Sstevel@tonic-gate **
42877c478bd9Sstevel@tonic-gate **	Returns:
42887c478bd9Sstevel@tonic-gate **		response string (may be NULL)
42897c478bd9Sstevel@tonic-gate **
42907c478bd9Sstevel@tonic-gate **	Side effects:
42917c478bd9Sstevel@tonic-gate **		- Uses e->e_dfp for access to the body
42927c478bd9Sstevel@tonic-gate **		- Can call the various milter action routines to
42937c478bd9Sstevel@tonic-gate **		  modify the envelope or message.
42947c478bd9Sstevel@tonic-gate */
42957c478bd9Sstevel@tonic-gate 
42967c478bd9Sstevel@tonic-gate # define MILTER_CHECK_RESULTS() \
42977c478bd9Sstevel@tonic-gate 	if (*state == SMFIR_ACCEPT || \
42987c478bd9Sstevel@tonic-gate 	    m->mf_state == SMFS_DONE || \
42997c478bd9Sstevel@tonic-gate 	    m->mf_state == SMFS_ERROR) \
43007c478bd9Sstevel@tonic-gate 	{ \
43017c478bd9Sstevel@tonic-gate 		if (m->mf_state != SMFS_ERROR) \
43027c478bd9Sstevel@tonic-gate 			m->mf_state = SMFS_DONE; \
43037c478bd9Sstevel@tonic-gate 		continue;	/* to next filter */ \
43047c478bd9Sstevel@tonic-gate 	} \
43057c478bd9Sstevel@tonic-gate 	if (*state != SMFIR_CONTINUE) \
43067c478bd9Sstevel@tonic-gate 	{ \
43077c478bd9Sstevel@tonic-gate 		m->mf_state = SMFS_DONE; \
43087c478bd9Sstevel@tonic-gate 		goto finishup; \
43097c478bd9Sstevel@tonic-gate 	}
43107c478bd9Sstevel@tonic-gate 
43117c478bd9Sstevel@tonic-gate char *
milter_data(e,state)43127c478bd9Sstevel@tonic-gate milter_data(e, state)
43137c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
43147c478bd9Sstevel@tonic-gate 	char *state;
43157c478bd9Sstevel@tonic-gate {
43167c478bd9Sstevel@tonic-gate 	bool replbody = false;		/* milter_replbody() called? */
43177c478bd9Sstevel@tonic-gate 	bool replfailed = false;	/* milter_replbody() failed? */
43187c478bd9Sstevel@tonic-gate 	bool rewind = false;		/* rewind data file? */
43197c478bd9Sstevel@tonic-gate 	bool dfopen = false;		/* data file open for writing? */
43207c478bd9Sstevel@tonic-gate 	bool newfilter;			/* reset on each new filter */
43217c478bd9Sstevel@tonic-gate 	char rcmd;
43227c478bd9Sstevel@tonic-gate 	int i;
43237c478bd9Sstevel@tonic-gate 	int save_errno;
43247c478bd9Sstevel@tonic-gate 	char *response = NULL;
43257c478bd9Sstevel@tonic-gate 	time_t eomsent;
43267c478bd9Sstevel@tonic-gate 	ssize_t rlen;
43277c478bd9Sstevel@tonic-gate 
43287c478bd9Sstevel@tonic-gate 	if (tTd(64, 10))
43297c478bd9Sstevel@tonic-gate 		sm_dprintf("milter_data\n");
43307c478bd9Sstevel@tonic-gate 
43317c478bd9Sstevel@tonic-gate 	*state = SMFIR_CONTINUE;
43327c478bd9Sstevel@tonic-gate 
43337c478bd9Sstevel@tonic-gate 	/*
43347c478bd9Sstevel@tonic-gate 	**  XXX: Should actually send body chunks to each filter
43357c478bd9Sstevel@tonic-gate 	**  a chunk at a time instead of sending the whole body to
43367c478bd9Sstevel@tonic-gate 	**  each filter in turn.  However, only if the filters don't
43377c478bd9Sstevel@tonic-gate 	**  change the body.
43387c478bd9Sstevel@tonic-gate 	*/
43397c478bd9Sstevel@tonic-gate 
43407c478bd9Sstevel@tonic-gate 	for (i = 0; InputFilters[i] != NULL; i++)
43417c478bd9Sstevel@tonic-gate 	{
43427c478bd9Sstevel@tonic-gate 		struct milter *m = InputFilters[i];
43437c478bd9Sstevel@tonic-gate 
43447c478bd9Sstevel@tonic-gate 		if (*state != SMFIR_CONTINUE &&
43457c478bd9Sstevel@tonic-gate 		    *state != SMFIR_ACCEPT)
43467c478bd9Sstevel@tonic-gate 		{
43477c478bd9Sstevel@tonic-gate 			/*
43487c478bd9Sstevel@tonic-gate 			**  A previous filter has dealt with the message,
43497c478bd9Sstevel@tonic-gate 			**  safe to stop processing the filters.
43507c478bd9Sstevel@tonic-gate 			*/
43517c478bd9Sstevel@tonic-gate 
43527c478bd9Sstevel@tonic-gate 			break;
43537c478bd9Sstevel@tonic-gate 		}
43547c478bd9Sstevel@tonic-gate 
43557c478bd9Sstevel@tonic-gate 		/* Now reset state for later evaluation */
43567c478bd9Sstevel@tonic-gate 		*state = SMFIR_CONTINUE;
43577c478bd9Sstevel@tonic-gate 		newfilter = true;
43587c478bd9Sstevel@tonic-gate 
43597c478bd9Sstevel@tonic-gate 		/* previous problem? */
43607c478bd9Sstevel@tonic-gate 		if (m->mf_state == SMFS_ERROR)
43617c478bd9Sstevel@tonic-gate 		{
43627c478bd9Sstevel@tonic-gate 			MILTER_CHECK_ERROR(false, continue);
43637c478bd9Sstevel@tonic-gate 			break;
43647c478bd9Sstevel@tonic-gate 		}
43657c478bd9Sstevel@tonic-gate 
43667c478bd9Sstevel@tonic-gate 		/* sanity checks */
43677c478bd9Sstevel@tonic-gate 		if (m->mf_sock < 0 ||
43687c478bd9Sstevel@tonic-gate 		    (m->mf_state != SMFS_OPEN && m->mf_state != SMFS_INMSG))
43697c478bd9Sstevel@tonic-gate 			continue;
43707c478bd9Sstevel@tonic-gate 
43717c478bd9Sstevel@tonic-gate 		m->mf_state = SMFS_INMSG;
43727c478bd9Sstevel@tonic-gate 
43737c478bd9Sstevel@tonic-gate 		/* check if filter wants the headers */
43747c478bd9Sstevel@tonic-gate 		if (!bitset(SMFIP_NOHDRS, m->mf_pflags))
43757c478bd9Sstevel@tonic-gate 		{
43767c478bd9Sstevel@tonic-gate 			response = milter_headers(m, e, state);
43777c478bd9Sstevel@tonic-gate 			MILTER_CHECK_RESULTS();
43787c478bd9Sstevel@tonic-gate 		}
43797c478bd9Sstevel@tonic-gate 
43807c478bd9Sstevel@tonic-gate 		/* check if filter wants EOH */
43817c478bd9Sstevel@tonic-gate 		if (!bitset(SMFIP_NOEOH, m->mf_pflags))
43827c478bd9Sstevel@tonic-gate 		{
43837c478bd9Sstevel@tonic-gate 			if (tTd(64, 10))
43847c478bd9Sstevel@tonic-gate 				sm_dprintf("milter_data: eoh\n");
43857c478bd9Sstevel@tonic-gate 
4386058561cbSjbeck 			if (MilterEOHMacros[0] != NULL)
4387058561cbSjbeck 			{
4388058561cbSjbeck 				milter_send_macros(m, MilterEOHMacros,
4389058561cbSjbeck 					   SMFIC_EOH, e);
4390058561cbSjbeck 				MILTER_CHECK_RESULTS();
4391058561cbSjbeck 			}
4392058561cbSjbeck 
43937c478bd9Sstevel@tonic-gate 			/* send it over */
43947c478bd9Sstevel@tonic-gate 			response = milter_send_command(m, SMFIC_EOH, NULL, 0,
4395058561cbSjbeck 						       e, state, "eoh");
43967c478bd9Sstevel@tonic-gate 			MILTER_CHECK_RESULTS();
43977c478bd9Sstevel@tonic-gate 		}
43987c478bd9Sstevel@tonic-gate 
43997c478bd9Sstevel@tonic-gate 		/* check if filter wants the body */
44007c478bd9Sstevel@tonic-gate 		if (!bitset(SMFIP_NOBODY, m->mf_pflags) &&
44017c478bd9Sstevel@tonic-gate 		    e->e_dfp != NULL)
44027c478bd9Sstevel@tonic-gate 		{
44037c478bd9Sstevel@tonic-gate 			rewind = true;
44047c478bd9Sstevel@tonic-gate 			response = milter_body(m, e, state);
44057c478bd9Sstevel@tonic-gate 			MILTER_CHECK_RESULTS();
44067c478bd9Sstevel@tonic-gate 		}
44077c478bd9Sstevel@tonic-gate 
44087c478bd9Sstevel@tonic-gate 		if (MilterEOMMacros[0] != NULL)
44097c478bd9Sstevel@tonic-gate 		{
44107c478bd9Sstevel@tonic-gate 			milter_send_macros(m, MilterEOMMacros,
44117c478bd9Sstevel@tonic-gate 					   SMFIC_BODYEOB, e);
44127c478bd9Sstevel@tonic-gate 			MILTER_CHECK_RESULTS();
44137c478bd9Sstevel@tonic-gate 		}
44147c478bd9Sstevel@tonic-gate 
44157c478bd9Sstevel@tonic-gate 		/* send the final body chunk */
44167c478bd9Sstevel@tonic-gate 		(void) milter_write(m, SMFIC_BODYEOB, NULL, 0,
4417058561cbSjbeck 				    m->mf_timeout[SMFTO_WRITE], e, "eom");
44187c478bd9Sstevel@tonic-gate 
44197c478bd9Sstevel@tonic-gate 		/* Get time EOM sent for timeout */
44207c478bd9Sstevel@tonic-gate 		eomsent = curtime();
44217c478bd9Sstevel@tonic-gate 
44227c478bd9Sstevel@tonic-gate 		/* deal with the possibility of multiple responses */
44237c478bd9Sstevel@tonic-gate 		while (*state == SMFIR_CONTINUE)
44247c478bd9Sstevel@tonic-gate 		{
44257c478bd9Sstevel@tonic-gate 			/* Check total timeout from EOM to final ACK/NAK */
44267c478bd9Sstevel@tonic-gate 			if (m->mf_timeout[SMFTO_EOM] > 0 &&
44277c478bd9Sstevel@tonic-gate 			    curtime() - eomsent >= m->mf_timeout[SMFTO_EOM])
44287c478bd9Sstevel@tonic-gate 			{
44297c478bd9Sstevel@tonic-gate 				if (tTd(64, 5))
44307c478bd9Sstevel@tonic-gate 					sm_dprintf("milter_data(%s): EOM ACK/NAK timeout\n",
44317c478bd9Sstevel@tonic-gate 						m->mf_name);
44327c478bd9Sstevel@tonic-gate 				if (MilterLogLevel > 0)
44337c478bd9Sstevel@tonic-gate 					sm_syslog(LOG_ERR, e->e_id,
44347c478bd9Sstevel@tonic-gate 						  "milter_data(%s): EOM ACK/NAK timeout",
44357c478bd9Sstevel@tonic-gate 						  m->mf_name);
44367c478bd9Sstevel@tonic-gate 				milter_error(m, e);
44377c478bd9Sstevel@tonic-gate 				MILTER_CHECK_ERROR(false, break);
44387c478bd9Sstevel@tonic-gate 				break;
44397c478bd9Sstevel@tonic-gate 			}
44407c478bd9Sstevel@tonic-gate 
44417c478bd9Sstevel@tonic-gate 			response = milter_read(m, &rcmd, &rlen,
4442058561cbSjbeck 					       m->mf_timeout[SMFTO_READ], e,
4443*e9af4bc0SJohn Beck 						"eom");
44447c478bd9Sstevel@tonic-gate 			if (m->mf_state == SMFS_ERROR)
44457c478bd9Sstevel@tonic-gate 				break;
44467c478bd9Sstevel@tonic-gate 
44477c478bd9Sstevel@tonic-gate 			if (tTd(64, 10))
44487c478bd9Sstevel@tonic-gate 				sm_dprintf("milter_data(%s): state %c\n",
44497c478bd9Sstevel@tonic-gate 					   m->mf_name, (char) rcmd);
44507c478bd9Sstevel@tonic-gate 
44517c478bd9Sstevel@tonic-gate 			switch (rcmd)
44527c478bd9Sstevel@tonic-gate 			{
44537c478bd9Sstevel@tonic-gate 			  case SMFIR_REPLYCODE:
44547c478bd9Sstevel@tonic-gate 				MILTER_CHECK_REPLYCODE("554 5.7.1 Command rejected");
44557c478bd9Sstevel@tonic-gate 				if (MilterLogLevel > 12)
44567c478bd9Sstevel@tonic-gate 					sm_syslog(LOG_INFO, e->e_id, "milter=%s, reject=%s",
44577c478bd9Sstevel@tonic-gate 						  m->mf_name, response);
44587c478bd9Sstevel@tonic-gate 				*state = rcmd;
44597c478bd9Sstevel@tonic-gate 				m->mf_state = SMFS_DONE;
44607c478bd9Sstevel@tonic-gate 				break;
44617c478bd9Sstevel@tonic-gate 
44627c478bd9Sstevel@tonic-gate 			  case SMFIR_REJECT: /* log msg at end of function */
44637c478bd9Sstevel@tonic-gate 				if (MilterLogLevel > 12)
44647c478bd9Sstevel@tonic-gate 					sm_syslog(LOG_INFO, e->e_id, "milter=%s, reject",
44657c478bd9Sstevel@tonic-gate 						  m->mf_name);
44667c478bd9Sstevel@tonic-gate 				*state = rcmd;
44677c478bd9Sstevel@tonic-gate 				m->mf_state = SMFS_DONE;
44687c478bd9Sstevel@tonic-gate 				break;
44697c478bd9Sstevel@tonic-gate 
44707c478bd9Sstevel@tonic-gate 			  case SMFIR_DISCARD:
44717c478bd9Sstevel@tonic-gate 				if (MilterLogLevel > 12)
44727c478bd9Sstevel@tonic-gate 					sm_syslog(LOG_INFO, e->e_id, "milter=%s, discard",
44737c478bd9Sstevel@tonic-gate 						  m->mf_name);
44747c478bd9Sstevel@tonic-gate 				*state = rcmd;
44757c478bd9Sstevel@tonic-gate 				m->mf_state = SMFS_DONE;
44767c478bd9Sstevel@tonic-gate 				break;
44777c478bd9Sstevel@tonic-gate 
44787c478bd9Sstevel@tonic-gate 			  case SMFIR_TEMPFAIL:
44797c478bd9Sstevel@tonic-gate 				if (MilterLogLevel > 12)
44807c478bd9Sstevel@tonic-gate 					sm_syslog(LOG_INFO, e->e_id, "milter=%s, tempfail",
44817c478bd9Sstevel@tonic-gate 						  m->mf_name);
44827c478bd9Sstevel@tonic-gate 				*state = rcmd;
44837c478bd9Sstevel@tonic-gate 				m->mf_state = SMFS_DONE;
44847c478bd9Sstevel@tonic-gate 				break;
44857c478bd9Sstevel@tonic-gate 
44867c478bd9Sstevel@tonic-gate 			  case SMFIR_CONTINUE:
44877c478bd9Sstevel@tonic-gate 			  case SMFIR_ACCEPT:
44887c478bd9Sstevel@tonic-gate 				/* this filter is done with message */
44897c478bd9Sstevel@tonic-gate 				if (replfailed)
44907c478bd9Sstevel@tonic-gate 					*state = SMFIR_TEMPFAIL;
44917c478bd9Sstevel@tonic-gate 				else
44927c478bd9Sstevel@tonic-gate 					*state = SMFIR_ACCEPT;
44937c478bd9Sstevel@tonic-gate 				m->mf_state = SMFS_DONE;
44947c478bd9Sstevel@tonic-gate 				break;
44957c478bd9Sstevel@tonic-gate 
44967c478bd9Sstevel@tonic-gate 			  case SMFIR_PROGRESS:
44977c478bd9Sstevel@tonic-gate 				break;
44987c478bd9Sstevel@tonic-gate 
44997c478bd9Sstevel@tonic-gate 			  case SMFIR_QUARANTINE:
45007c478bd9Sstevel@tonic-gate 				if (!bitset(SMFIF_QUARANTINE, m->mf_fflags))
45017c478bd9Sstevel@tonic-gate 				{
45027c478bd9Sstevel@tonic-gate 					if (MilterLogLevel > 9)
45037c478bd9Sstevel@tonic-gate 						sm_syslog(LOG_WARNING, e->e_id,
45047c478bd9Sstevel@tonic-gate 							  "milter_data(%s): lied about quarantining, honoring request anyway",
45057c478bd9Sstevel@tonic-gate 							  m->mf_name);
45067c478bd9Sstevel@tonic-gate 				}
45077c478bd9Sstevel@tonic-gate 				if (response == NULL)
45087c478bd9Sstevel@tonic-gate 					response = newstr("");
45097c478bd9Sstevel@tonic-gate 				if (MilterLogLevel > 3)
45107c478bd9Sstevel@tonic-gate 					sm_syslog(LOG_INFO, e->e_id,
45117c478bd9Sstevel@tonic-gate 						  "milter=%s, quarantine=%s",
45127c478bd9Sstevel@tonic-gate 						  m->mf_name, response);
45137c478bd9Sstevel@tonic-gate 				e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool,
45147c478bd9Sstevel@tonic-gate 								 response);
45157c478bd9Sstevel@tonic-gate 				macdefine(&e->e_macro, A_PERM,
45167c478bd9Sstevel@tonic-gate 					  macid("{quarantine}"), e->e_quarmsg);
45177c478bd9Sstevel@tonic-gate 				break;
45187c478bd9Sstevel@tonic-gate 
45197c478bd9Sstevel@tonic-gate 			  case SMFIR_ADDHEADER:
45207c478bd9Sstevel@tonic-gate 				if (!bitset(SMFIF_ADDHDRS, m->mf_fflags))
45217c478bd9Sstevel@tonic-gate 				{
45227c478bd9Sstevel@tonic-gate 					if (MilterLogLevel > 9)
45237c478bd9Sstevel@tonic-gate 						sm_syslog(LOG_WARNING, e->e_id,
45247c478bd9Sstevel@tonic-gate 							  "milter_data(%s): lied about adding headers, honoring request anyway",
45257c478bd9Sstevel@tonic-gate 							  m->mf_name);
45267c478bd9Sstevel@tonic-gate 				}
4527058561cbSjbeck 				milter_addheader(m, response, rlen, e);
45287c478bd9Sstevel@tonic-gate 				break;
45297c478bd9Sstevel@tonic-gate 
45307c478bd9Sstevel@tonic-gate 			  case SMFIR_INSHEADER:
45317c478bd9Sstevel@tonic-gate 				if (!bitset(SMFIF_ADDHDRS, m->mf_fflags))
45327c478bd9Sstevel@tonic-gate 				{
45337c478bd9Sstevel@tonic-gate 					if (MilterLogLevel > 9)
45347c478bd9Sstevel@tonic-gate 						sm_syslog(LOG_WARNING, e->e_id,
45357c478bd9Sstevel@tonic-gate 							  "milter_data(%s): lied about adding headers, honoring request anyway",
45367c478bd9Sstevel@tonic-gate 							  m->mf_name);
45377c478bd9Sstevel@tonic-gate 				}
4538058561cbSjbeck 				milter_insheader(m, response, rlen, e);
45397c478bd9Sstevel@tonic-gate 				break;
45407c478bd9Sstevel@tonic-gate 
45417c478bd9Sstevel@tonic-gate 			  case SMFIR_CHGHEADER:
45427c478bd9Sstevel@tonic-gate 				if (!bitset(SMFIF_CHGHDRS, m->mf_fflags))
45437c478bd9Sstevel@tonic-gate 				{
45447c478bd9Sstevel@tonic-gate 					if (MilterLogLevel > 9)
45457c478bd9Sstevel@tonic-gate 						sm_syslog(LOG_WARNING, e->e_id,
45467c478bd9Sstevel@tonic-gate 							  "milter_data(%s): lied about changing headers, honoring request anyway",
45477c478bd9Sstevel@tonic-gate 							  m->mf_name);
45487c478bd9Sstevel@tonic-gate 				}
4549058561cbSjbeck 				milter_changeheader(m, response, rlen, e);
4550058561cbSjbeck 				break;
4551058561cbSjbeck 
4552058561cbSjbeck 			  case SMFIR_CHGFROM:
4553058561cbSjbeck 				if (!bitset(SMFIF_CHGFROM, m->mf_fflags))
4554058561cbSjbeck 				{
4555058561cbSjbeck 					if (MilterLogLevel > 9)
4556058561cbSjbeck 						sm_syslog(LOG_WARNING, e->e_id,
4557058561cbSjbeck 							  "milter_data(%s) lied about changing sender, honoring request anyway",
4558058561cbSjbeck 							  m->mf_name);
4559058561cbSjbeck 				}
4560058561cbSjbeck 				milter_chgfrom(response, rlen, e);
45617c478bd9Sstevel@tonic-gate 				break;
45627c478bd9Sstevel@tonic-gate 
45637c478bd9Sstevel@tonic-gate 			  case SMFIR_ADDRCPT:
45647c478bd9Sstevel@tonic-gate 				if (!bitset(SMFIF_ADDRCPT, m->mf_fflags))
45657c478bd9Sstevel@tonic-gate 				{
45667c478bd9Sstevel@tonic-gate 					if (MilterLogLevel > 9)
45677c478bd9Sstevel@tonic-gate 						sm_syslog(LOG_WARNING, e->e_id,
45687c478bd9Sstevel@tonic-gate 							  "milter_data(%s) lied about adding recipients, honoring request anyway",
45697c478bd9Sstevel@tonic-gate 							  m->mf_name);
45707c478bd9Sstevel@tonic-gate 				}
45717c478bd9Sstevel@tonic-gate 				milter_addrcpt(response, rlen, e);
45727c478bd9Sstevel@tonic-gate 				break;
45737c478bd9Sstevel@tonic-gate 
4574058561cbSjbeck 			  case SMFIR_ADDRCPT_PAR:
4575058561cbSjbeck 				if (!bitset(SMFIF_ADDRCPT_PAR, m->mf_fflags))
4576058561cbSjbeck 				{
4577058561cbSjbeck 					if (MilterLogLevel > 9)
4578058561cbSjbeck 						sm_syslog(LOG_WARNING, e->e_id,
4579058561cbSjbeck 							  "milter_data(%s) lied about adding recipients with parameters, honoring request anyway",
4580058561cbSjbeck 							  m->mf_name);
4581058561cbSjbeck 				}
4582058561cbSjbeck 				milter_addrcpt_par(response, rlen, e);
4583058561cbSjbeck 				break;
4584058561cbSjbeck 
45857c478bd9Sstevel@tonic-gate 			  case SMFIR_DELRCPT:
45867c478bd9Sstevel@tonic-gate 				if (!bitset(SMFIF_DELRCPT, m->mf_fflags))
45877c478bd9Sstevel@tonic-gate 				{
45887c478bd9Sstevel@tonic-gate 					if (MilterLogLevel > 9)
45897c478bd9Sstevel@tonic-gate 						sm_syslog(LOG_WARNING, e->e_id,
45907c478bd9Sstevel@tonic-gate 							  "milter_data(%s): lied about removing recipients, honoring request anyway",
45917c478bd9Sstevel@tonic-gate 							  m->mf_name);
45927c478bd9Sstevel@tonic-gate 				}
45937c478bd9Sstevel@tonic-gate 				milter_delrcpt(response, rlen, e);
45947c478bd9Sstevel@tonic-gate 				break;
45957c478bd9Sstevel@tonic-gate 
45967c478bd9Sstevel@tonic-gate 			  case SMFIR_REPLBODY:
45977c478bd9Sstevel@tonic-gate 				if (!bitset(SMFIF_MODBODY, m->mf_fflags))
45987c478bd9Sstevel@tonic-gate 				{
45997c478bd9Sstevel@tonic-gate 					if (MilterLogLevel > 0)
46007c478bd9Sstevel@tonic-gate 						sm_syslog(LOG_ERR, e->e_id,
46017c478bd9Sstevel@tonic-gate 							  "milter_data(%s): lied about replacing body, rejecting request and tempfailing message",
46027c478bd9Sstevel@tonic-gate 							  m->mf_name);
46037c478bd9Sstevel@tonic-gate 					replfailed = true;
46047c478bd9Sstevel@tonic-gate 					break;
46057c478bd9Sstevel@tonic-gate 				}
46067c478bd9Sstevel@tonic-gate 
46077c478bd9Sstevel@tonic-gate 				/* already failed in attempt */
46087c478bd9Sstevel@tonic-gate 				if (replfailed)
46097c478bd9Sstevel@tonic-gate 					break;
46107c478bd9Sstevel@tonic-gate 
46117c478bd9Sstevel@tonic-gate 				if (!dfopen)
46127c478bd9Sstevel@tonic-gate 				{
46137c478bd9Sstevel@tonic-gate 					if (milter_reopen_df(e) < 0)
46147c478bd9Sstevel@tonic-gate 					{
46157c478bd9Sstevel@tonic-gate 						replfailed = true;
46167c478bd9Sstevel@tonic-gate 						break;
46177c478bd9Sstevel@tonic-gate 					}
46187c478bd9Sstevel@tonic-gate 					dfopen = true;
46197c478bd9Sstevel@tonic-gate 					rewind = true;
46207c478bd9Sstevel@tonic-gate 				}
46217c478bd9Sstevel@tonic-gate 
46227c478bd9Sstevel@tonic-gate 				if (milter_replbody(response, rlen,
46237c478bd9Sstevel@tonic-gate 						    newfilter, e) < 0)
46247c478bd9Sstevel@tonic-gate 					replfailed = true;
46257c478bd9Sstevel@tonic-gate 				newfilter = false;
46267c478bd9Sstevel@tonic-gate 				replbody = true;
46277c478bd9Sstevel@tonic-gate 				break;
46287c478bd9Sstevel@tonic-gate 
46297c478bd9Sstevel@tonic-gate 			  default:
46307c478bd9Sstevel@tonic-gate 				/* Invalid response to command */
46317c478bd9Sstevel@tonic-gate 				if (MilterLogLevel > 0)
46327c478bd9Sstevel@tonic-gate 					sm_syslog(LOG_ERR, e->e_id,
46337c478bd9Sstevel@tonic-gate 						  "milter_data(%s): returned bogus response %c",
46347c478bd9Sstevel@tonic-gate 						  m->mf_name, rcmd);
46357c478bd9Sstevel@tonic-gate 				milter_error(m, e);
46367c478bd9Sstevel@tonic-gate 				break;
46377c478bd9Sstevel@tonic-gate 			}
46387c478bd9Sstevel@tonic-gate 			if (rcmd != SMFIR_REPLYCODE && response != NULL)
46397c478bd9Sstevel@tonic-gate 			{
46407c478bd9Sstevel@tonic-gate 				sm_free(response); /* XXX */
46417c478bd9Sstevel@tonic-gate 				response = NULL;
46427c478bd9Sstevel@tonic-gate 			}
46437c478bd9Sstevel@tonic-gate 
46447c478bd9Sstevel@tonic-gate 			if (m->mf_state == SMFS_ERROR)
46457c478bd9Sstevel@tonic-gate 				break;
46467c478bd9Sstevel@tonic-gate 		}
46477c478bd9Sstevel@tonic-gate 
46487c478bd9Sstevel@tonic-gate 		if (replbody && !replfailed)
46497c478bd9Sstevel@tonic-gate 		{
46507c478bd9Sstevel@tonic-gate 			/* flush possible buffered character */
46517c478bd9Sstevel@tonic-gate 			milter_replbody(NULL, 0, !replbody, e);
46527c478bd9Sstevel@tonic-gate 			replbody = false;
46537c478bd9Sstevel@tonic-gate 		}
46547c478bd9Sstevel@tonic-gate 
46557c478bd9Sstevel@tonic-gate 		if (m->mf_state == SMFS_ERROR)
46567c478bd9Sstevel@tonic-gate 		{
46577c478bd9Sstevel@tonic-gate 			MILTER_CHECK_ERROR(false, continue);
46587c478bd9Sstevel@tonic-gate 			goto finishup;
46597c478bd9Sstevel@tonic-gate 		}
46607c478bd9Sstevel@tonic-gate 	}
46617c478bd9Sstevel@tonic-gate 
46627c478bd9Sstevel@tonic-gate finishup:
46637c478bd9Sstevel@tonic-gate 	/* leave things in the expected state if we touched it */
46647c478bd9Sstevel@tonic-gate 	if (replfailed)
46657c478bd9Sstevel@tonic-gate 	{
46667c478bd9Sstevel@tonic-gate 		if (*state == SMFIR_CONTINUE ||
46677c478bd9Sstevel@tonic-gate 		    *state == SMFIR_ACCEPT)
46687c478bd9Sstevel@tonic-gate 		{
46697c478bd9Sstevel@tonic-gate 			*state = SMFIR_TEMPFAIL;
46707c478bd9Sstevel@tonic-gate 			SM_FREE_CLR(response);
46717c478bd9Sstevel@tonic-gate 		}
46727c478bd9Sstevel@tonic-gate 
46737c478bd9Sstevel@tonic-gate 		if (dfopen)
46747c478bd9Sstevel@tonic-gate 		{
46757c478bd9Sstevel@tonic-gate 			(void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT);
46767c478bd9Sstevel@tonic-gate 			e->e_dfp = NULL;
46777c478bd9Sstevel@tonic-gate 			e->e_flags &= ~EF_HAS_DF;
46787c478bd9Sstevel@tonic-gate 			dfopen = false;
46797c478bd9Sstevel@tonic-gate 		}
46807c478bd9Sstevel@tonic-gate 		rewind = false;
46817c478bd9Sstevel@tonic-gate 	}
46827c478bd9Sstevel@tonic-gate 
46837c478bd9Sstevel@tonic-gate 	if ((dfopen && milter_reset_df(e) < 0) ||
46847c478bd9Sstevel@tonic-gate 	    (rewind && bfrewind(e->e_dfp) < 0))
46857c478bd9Sstevel@tonic-gate 	{
46867c478bd9Sstevel@tonic-gate 		save_errno = errno;
46877c478bd9Sstevel@tonic-gate 		ExitStat = EX_IOERR;
46887c478bd9Sstevel@tonic-gate 
46897c478bd9Sstevel@tonic-gate 		/*
46907c478bd9Sstevel@tonic-gate 		**  If filter told us to keep message but we had
46917c478bd9Sstevel@tonic-gate 		**  an error, we can't really keep it, tempfail it.
46927c478bd9Sstevel@tonic-gate 		*/
46937c478bd9Sstevel@tonic-gate 
46947c478bd9Sstevel@tonic-gate 		if (*state == SMFIR_CONTINUE ||
46957c478bd9Sstevel@tonic-gate 		    *state == SMFIR_ACCEPT)
46967c478bd9Sstevel@tonic-gate 		{
46977c478bd9Sstevel@tonic-gate 			*state = SMFIR_TEMPFAIL;
46987c478bd9Sstevel@tonic-gate 			SM_FREE_CLR(response);
46997c478bd9Sstevel@tonic-gate 		}
47007c478bd9Sstevel@tonic-gate 
47017c478bd9Sstevel@tonic-gate 		errno = save_errno;
47027c478bd9Sstevel@tonic-gate 		syserr("milter_data: %s/%cf%s: read error",
47037c478bd9Sstevel@tonic-gate 		       qid_printqueue(e->e_qgrp, e->e_qdir),
47047c478bd9Sstevel@tonic-gate 		       DATAFL_LETTER, e->e_id);
47057c478bd9Sstevel@tonic-gate 	}
47067c478bd9Sstevel@tonic-gate 
47077c478bd9Sstevel@tonic-gate 	MILTER_CHECK_DONE_MSG();
47087c478bd9Sstevel@tonic-gate 	if (MilterLogLevel > 10 && *state == SMFIR_REJECT)
47097c478bd9Sstevel@tonic-gate 		sm_syslog(LOG_INFO, e->e_id, "Milter: reject, data");
47107c478bd9Sstevel@tonic-gate 	return response;
47117c478bd9Sstevel@tonic-gate }
47127c478bd9Sstevel@tonic-gate 
47137c478bd9Sstevel@tonic-gate /*
47147c478bd9Sstevel@tonic-gate **  MILTER_UNKNOWN -- send any unrecognized or unimplemented command
47157c478bd9Sstevel@tonic-gate **			string to milter filters
47167c478bd9Sstevel@tonic-gate **
47177c478bd9Sstevel@tonic-gate **	Parameters:
4718058561cbSjbeck **		smtpcmd -- the string itself.
47197c478bd9Sstevel@tonic-gate **		e -- current envelope.
47207c478bd9Sstevel@tonic-gate **		state -- return state from response.
47217c478bd9Sstevel@tonic-gate **
47227c478bd9Sstevel@tonic-gate **
47237c478bd9Sstevel@tonic-gate **	Returns:
47247c478bd9Sstevel@tonic-gate **		response string (may be NULL)
47257c478bd9Sstevel@tonic-gate */
47267c478bd9Sstevel@tonic-gate 
47277c478bd9Sstevel@tonic-gate char *
milter_unknown(smtpcmd,e,state)4728058561cbSjbeck milter_unknown(smtpcmd, e, state)
4729058561cbSjbeck 	char *smtpcmd;
47307c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
47317c478bd9Sstevel@tonic-gate 	char *state;
47327c478bd9Sstevel@tonic-gate {
47337c478bd9Sstevel@tonic-gate 	if (tTd(64, 10))
4734058561cbSjbeck 		sm_dprintf("milter_unknown(%s)\n", smtpcmd);
47357c478bd9Sstevel@tonic-gate 
4736058561cbSjbeck 	return milter_command(SMFIC_UNKNOWN, smtpcmd, strlen(smtpcmd) + 1,
4737058561cbSjbeck 				NULL, e, state, "unknown", false);
47387c478bd9Sstevel@tonic-gate }
47397c478bd9Sstevel@tonic-gate 
47407c478bd9Sstevel@tonic-gate /*
47417c478bd9Sstevel@tonic-gate **  MILTER_QUIT -- informs the filter(s) we are done and closes connection(s)
47427c478bd9Sstevel@tonic-gate **
47437c478bd9Sstevel@tonic-gate **	Parameters:
47447c478bd9Sstevel@tonic-gate **		e -- current envelope.
47457c478bd9Sstevel@tonic-gate **
47467c478bd9Sstevel@tonic-gate **	Returns:
47477c478bd9Sstevel@tonic-gate **		none
47487c478bd9Sstevel@tonic-gate */
47497c478bd9Sstevel@tonic-gate 
47507c478bd9Sstevel@tonic-gate void
milter_quit(e)47517c478bd9Sstevel@tonic-gate milter_quit(e)
47527c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
47537c478bd9Sstevel@tonic-gate {
47547c478bd9Sstevel@tonic-gate 	int i;
47557c478bd9Sstevel@tonic-gate 
47567c478bd9Sstevel@tonic-gate 	if (tTd(64, 10))
47577c478bd9Sstevel@tonic-gate 		sm_dprintf("milter_quit(%s)\n", e->e_id);
47587c478bd9Sstevel@tonic-gate 
47597c478bd9Sstevel@tonic-gate 	for (i = 0; InputFilters[i] != NULL; i++)
47607c478bd9Sstevel@tonic-gate 		milter_quit_filter(InputFilters[i], e);
47617c478bd9Sstevel@tonic-gate }
4762058561cbSjbeck 
47637c478bd9Sstevel@tonic-gate /*
47647c478bd9Sstevel@tonic-gate **  MILTER_ABORT -- informs the filter(s) that we are aborting current message
47657c478bd9Sstevel@tonic-gate **
47667c478bd9Sstevel@tonic-gate **	Parameters:
47677c478bd9Sstevel@tonic-gate **		e -- current envelope.
47687c478bd9Sstevel@tonic-gate **
47697c478bd9Sstevel@tonic-gate **	Returns:
47707c478bd9Sstevel@tonic-gate **		none
47717c478bd9Sstevel@tonic-gate */
47727c478bd9Sstevel@tonic-gate 
47737c478bd9Sstevel@tonic-gate void
milter_abort(e)47747c478bd9Sstevel@tonic-gate milter_abort(e)
47757c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
47767c478bd9Sstevel@tonic-gate {
47777c478bd9Sstevel@tonic-gate 	int i;
47787c478bd9Sstevel@tonic-gate 
47797c478bd9Sstevel@tonic-gate 	if (tTd(64, 10))
47807c478bd9Sstevel@tonic-gate 		sm_dprintf("milter_abort\n");
47817c478bd9Sstevel@tonic-gate 
47827c478bd9Sstevel@tonic-gate 	for (i = 0; InputFilters[i] != NULL; i++)
47837c478bd9Sstevel@tonic-gate 	{
47847c478bd9Sstevel@tonic-gate 		struct milter *m = InputFilters[i];
47857c478bd9Sstevel@tonic-gate 
47867c478bd9Sstevel@tonic-gate 		/* sanity checks */
47877c478bd9Sstevel@tonic-gate 		if (m->mf_sock < 0 || m->mf_state != SMFS_INMSG)
47887c478bd9Sstevel@tonic-gate 			continue;
47897c478bd9Sstevel@tonic-gate 
47907c478bd9Sstevel@tonic-gate 		milter_abort_filter(m, e);
47917c478bd9Sstevel@tonic-gate 	}
47927c478bd9Sstevel@tonic-gate }
47937c478bd9Sstevel@tonic-gate #endif /* MILTER */
4794