xref: /freebsd/contrib/sendmail/src/milter.c (revision b6bacd3150f411c3de886f7615bc22129b6974ad)
106f25ae9SGregory Neil Shapiro /*
2e92d3f3fSGregory Neil Shapiro  * Copyright (c) 1999-2004 Sendmail, Inc. and its suppliers.
306f25ae9SGregory Neil Shapiro  *	All rights reserved.
406f25ae9SGregory Neil Shapiro  *
506f25ae9SGregory Neil Shapiro  * By using this file, you agree to the terms and conditions set
606f25ae9SGregory Neil Shapiro  * forth in the LICENSE file which can be found at the top level of
706f25ae9SGregory Neil Shapiro  * the sendmail distribution.
806f25ae9SGregory Neil Shapiro  *
906f25ae9SGregory Neil Shapiro  */
1006f25ae9SGregory Neil Shapiro 
1106f25ae9SGregory Neil Shapiro #include <sendmail.h>
1240266059SGregory Neil Shapiro 
13b6bacd31SGregory Neil Shapiro SM_RCSID("@(#)$Id: milter.c,v 8.228 2004/11/09 18:54:55 ca Exp $")
1440266059SGregory Neil Shapiro 
1540266059SGregory Neil Shapiro #if MILTER
1640266059SGregory Neil Shapiro # include <libmilter/mfapi.h>
1740266059SGregory Neil Shapiro # include <libmilter/mfdef.h>
1840266059SGregory Neil Shapiro 
1906f25ae9SGregory Neil Shapiro # include <errno.h>
2006f25ae9SGregory Neil Shapiro # include <sys/time.h>
21e92d3f3fSGregory Neil Shapiro # include <sys/uio.h>
2206f25ae9SGregory Neil Shapiro 
2306f25ae9SGregory Neil Shapiro # if NETINET || NETINET6
2406f25ae9SGregory Neil Shapiro #  include <arpa/inet.h>
25e92d3f3fSGregory Neil Shapiro #  if _FFR_MILTER_NAGLE
26e92d3f3fSGregory Neil Shapiro #   include <netinet/tcp.h>
27e92d3f3fSGregory Neil Shapiro #  endif /* _FFR_MILTER_NAGLE */
2806f25ae9SGregory Neil Shapiro # endif /* NETINET || NETINET6 */
2906f25ae9SGregory Neil Shapiro 
3040266059SGregory Neil Shapiro # include <sm/fdset.h>
3106f25ae9SGregory Neil Shapiro 
32b6bacd31SGregory Neil Shapiro static void	milter_connect_timeout __P((int));
3340266059SGregory Neil Shapiro static void	milter_error __P((struct milter *, ENVELOPE *));
3406f25ae9SGregory Neil Shapiro static int	milter_open __P((struct milter *, bool, ENVELOPE *));
3506f25ae9SGregory Neil Shapiro static void	milter_parse_timeouts __P((char *, struct milter *));
3606f25ae9SGregory Neil Shapiro 
3706f25ae9SGregory Neil Shapiro static char *MilterConnectMacros[MAXFILTERMACROS + 1];
3806f25ae9SGregory Neil Shapiro static char *MilterHeloMacros[MAXFILTERMACROS + 1];
3906f25ae9SGregory Neil Shapiro static char *MilterEnvFromMacros[MAXFILTERMACROS + 1];
4006f25ae9SGregory Neil Shapiro static char *MilterEnvRcptMacros[MAXFILTERMACROS + 1];
41e92d3f3fSGregory Neil Shapiro static char *MilterDataMacros[MAXFILTERMACROS + 1];
42323f6dcbSGregory Neil Shapiro static char *MilterEOMMacros[MAXFILTERMACROS + 1];
43e92d3f3fSGregory Neil Shapiro static size_t MilterMaxDataSize = MILTER_MAX_DATA_SIZE;
4406f25ae9SGregory Neil Shapiro 
4506f25ae9SGregory Neil Shapiro # define MILTER_CHECK_DONE_MSG() \
4606f25ae9SGregory Neil Shapiro 	if (*state == SMFIR_REPLYCODE || \
4706f25ae9SGregory Neil Shapiro 	    *state == SMFIR_REJECT || \
4806f25ae9SGregory Neil Shapiro 	    *state == SMFIR_DISCARD || \
4906f25ae9SGregory Neil Shapiro 	    *state == SMFIR_TEMPFAIL) \
5006f25ae9SGregory Neil Shapiro 	{ \
5106f25ae9SGregory Neil Shapiro 		/* Abort the filters to let them know we are done with msg */ \
5206f25ae9SGregory Neil Shapiro 		milter_abort(e); \
5306f25ae9SGregory Neil Shapiro 	}
5406f25ae9SGregory Neil Shapiro 
555ef517c0SGregory Neil Shapiro # define MILTER_CHECK_ERROR(initial, action) \
565ef517c0SGregory Neil Shapiro 	if (!initial && tTd(71, 100)) \
575ef517c0SGregory Neil Shapiro 	{ \
585ef517c0SGregory Neil Shapiro 		if (e->e_quarmsg == NULL) \
595ef517c0SGregory Neil Shapiro 		{ \
605ef517c0SGregory Neil Shapiro 			e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, \
615ef517c0SGregory Neil Shapiro 							 "filter failure"); \
625ef517c0SGregory Neil Shapiro 			macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), \
635ef517c0SGregory Neil Shapiro 				  e->e_quarmsg); \
645ef517c0SGregory Neil Shapiro 		} \
655ef517c0SGregory Neil Shapiro 	} \
665ef517c0SGregory Neil Shapiro 	else if (tTd(71, 101)) \
67959366dcSGregory Neil Shapiro 	{ \
68959366dcSGregory Neil Shapiro 		if (e->e_quarmsg == NULL) \
69959366dcSGregory Neil Shapiro 		{ \
70959366dcSGregory Neil Shapiro 			e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, \
71959366dcSGregory Neil Shapiro 							 "filter failure"); \
72959366dcSGregory Neil Shapiro 			macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), \
73959366dcSGregory Neil Shapiro 				  e->e_quarmsg); \
74959366dcSGregory Neil Shapiro 		} \
75959366dcSGregory Neil Shapiro 	} \
76959366dcSGregory Neil Shapiro 	else if (bitnset(SMF_TEMPFAIL, m->mf_flags)) \
77959366dcSGregory Neil Shapiro 		*state = SMFIR_TEMPFAIL; \
78b6bacd31SGregory Neil Shapiro 	else if (bitnset(SMF_TEMPDROP, m->mf_flags)) \
79b6bacd31SGregory Neil Shapiro 		*state = SMFIR_SHUTDOWN; \
80959366dcSGregory Neil Shapiro 	else if (bitnset(SMF_REJECT, m->mf_flags)) \
81959366dcSGregory Neil Shapiro 		*state = SMFIR_REJECT; \
82959366dcSGregory Neil Shapiro 	else \
83959366dcSGregory Neil Shapiro 		action;
8406f25ae9SGregory Neil Shapiro 
8506f25ae9SGregory Neil Shapiro # define MILTER_CHECK_REPLYCODE(default) \
8606f25ae9SGregory Neil Shapiro 	if (response == NULL || \
8706f25ae9SGregory Neil Shapiro 	    strlen(response) + 1 != (size_t) rlen || \
8806f25ae9SGregory Neil Shapiro 	    rlen < 3 || \
8906f25ae9SGregory Neil Shapiro 	    (response[0] != '4' && response[0] != '5') || \
9006f25ae9SGregory Neil Shapiro 	    !isascii(response[1]) || !isdigit(response[1]) || \
9106f25ae9SGregory Neil Shapiro 	    !isascii(response[2]) || !isdigit(response[2])) \
9206f25ae9SGregory Neil Shapiro 	{ \
9306f25ae9SGregory Neil Shapiro 		if (response != NULL) \
9440266059SGregory Neil Shapiro 			sm_free(response); /* XXX */ \
9506f25ae9SGregory Neil Shapiro 		response = newstr(default); \
9606f25ae9SGregory Neil Shapiro 	} \
9706f25ae9SGregory Neil Shapiro 	else \
9806f25ae9SGregory Neil Shapiro 	{ \
9906f25ae9SGregory Neil Shapiro 		char *ptr = response; \
10006f25ae9SGregory Neil Shapiro  \
10106f25ae9SGregory Neil Shapiro 		/* Check for unprotected %'s in the string */ \
10206f25ae9SGregory Neil Shapiro 		while (*ptr != '\0') \
10306f25ae9SGregory Neil Shapiro 		{ \
10406f25ae9SGregory Neil Shapiro 			if (*ptr == '%' && *++ptr != '%') \
10506f25ae9SGregory Neil Shapiro 			{ \
10640266059SGregory Neil Shapiro 				sm_free(response); /* XXX */ \
10706f25ae9SGregory Neil Shapiro 				response = newstr(default); \
10806f25ae9SGregory Neil Shapiro 				break; \
10906f25ae9SGregory Neil Shapiro 			} \
11006f25ae9SGregory Neil Shapiro 			ptr++; \
11106f25ae9SGregory Neil Shapiro 		} \
11206f25ae9SGregory Neil Shapiro 	}
11306f25ae9SGregory Neil Shapiro 
11406f25ae9SGregory Neil Shapiro # define MILTER_DF_ERROR(msg) \
11506f25ae9SGregory Neil Shapiro { \
11606f25ae9SGregory Neil Shapiro 	int save_errno = errno; \
11706f25ae9SGregory Neil Shapiro  \
11806f25ae9SGregory Neil Shapiro 	if (tTd(64, 5)) \
11906f25ae9SGregory Neil Shapiro 	{ \
12040266059SGregory Neil Shapiro 		sm_dprintf(msg, dfname, sm_errstring(save_errno)); \
12140266059SGregory Neil Shapiro 		sm_dprintf("\n"); \
12206f25ae9SGregory Neil Shapiro 	} \
12340266059SGregory Neil Shapiro 	if (MilterLogLevel > 0) \
12440266059SGregory Neil Shapiro 		sm_syslog(LOG_ERR, e->e_id, msg, dfname, sm_errstring(save_errno)); \
12540266059SGregory Neil Shapiro 	if (SuperSafe == SAFE_REALLY) \
12606f25ae9SGregory Neil Shapiro 	{ \
12706f25ae9SGregory Neil Shapiro 		if (e->e_dfp != NULL) \
12806f25ae9SGregory Neil Shapiro 		{ \
12940266059SGregory Neil Shapiro 			(void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT); \
13006f25ae9SGregory Neil Shapiro 			e->e_dfp = NULL; \
13106f25ae9SGregory Neil Shapiro 		} \
13206f25ae9SGregory Neil Shapiro 		e->e_flags &= ~EF_HAS_DF; \
13306f25ae9SGregory Neil Shapiro 	} \
13406f25ae9SGregory Neil Shapiro 	errno = save_errno; \
13506f25ae9SGregory Neil Shapiro }
13606f25ae9SGregory Neil Shapiro 
13706f25ae9SGregory Neil Shapiro /*
13806f25ae9SGregory Neil Shapiro **  MILTER_TIMEOUT -- make sure socket is ready in time
13906f25ae9SGregory Neil Shapiro **
14006f25ae9SGregory Neil Shapiro **	Parameters:
14106f25ae9SGregory Neil Shapiro **		routine -- routine name for debug/logging
14206f25ae9SGregory Neil Shapiro **		secs -- number of seconds in timeout
14306f25ae9SGregory Neil Shapiro **		write -- waiting to read or write?
14440266059SGregory Neil Shapiro **		started -- whether this is part of a previous sequence
14506f25ae9SGregory Neil Shapiro **
14606f25ae9SGregory Neil Shapiro **	Assumes 'm' is a milter structure for the current socket.
14706f25ae9SGregory Neil Shapiro */
14806f25ae9SGregory Neil Shapiro 
14940266059SGregory Neil Shapiro # define MILTER_TIMEOUT(routine, secs, write, started) \
15006f25ae9SGregory Neil Shapiro { \
15106f25ae9SGregory Neil Shapiro 	int ret; \
15206f25ae9SGregory Neil Shapiro 	int save_errno; \
15306f25ae9SGregory Neil Shapiro 	fd_set fds; \
15406f25ae9SGregory Neil Shapiro 	struct timeval tv; \
15506f25ae9SGregory Neil Shapiro  \
15640266059SGregory Neil Shapiro 	if (SM_FD_SETSIZE > 0 && m->mf_sock >= SM_FD_SETSIZE) \
15706f25ae9SGregory Neil Shapiro 	{ \
15806f25ae9SGregory Neil Shapiro 		if (tTd(64, 5)) \
15940266059SGregory Neil Shapiro 			sm_dprintf("milter_%s(%s): socket %d is larger than FD_SETSIZE %d\n", \
16040266059SGregory Neil Shapiro 				   (routine), m->mf_name, m->mf_sock, \
16140266059SGregory Neil Shapiro 				   SM_FD_SETSIZE); \
16240266059SGregory Neil Shapiro 		if (MilterLogLevel > 0) \
16306f25ae9SGregory Neil Shapiro 			sm_syslog(LOG_ERR, e->e_id, \
16440266059SGregory Neil Shapiro 				  "Milter (%s): socket(%s) %d is larger than FD_SETSIZE %d", \
16540266059SGregory Neil Shapiro 				  m->mf_name, (routine), m->mf_sock, \
16640266059SGregory Neil Shapiro 				  SM_FD_SETSIZE); \
16740266059SGregory Neil Shapiro 		milter_error(m, e); \
16806f25ae9SGregory Neil Shapiro 		return NULL; \
16906f25ae9SGregory Neil Shapiro 	} \
17006f25ae9SGregory Neil Shapiro  \
171605302a5SGregory Neil Shapiro 	do \
172605302a5SGregory Neil Shapiro 	{ \
17306f25ae9SGregory Neil Shapiro 		FD_ZERO(&fds); \
174193538b7SGregory Neil Shapiro 		SM_FD_SET(m->mf_sock, &fds); \
17540266059SGregory Neil Shapiro 		tv.tv_sec = (secs); \
17606f25ae9SGregory Neil Shapiro 		tv.tv_usec = 0; \
17706f25ae9SGregory Neil Shapiro 		ret = select(m->mf_sock + 1, \
17840266059SGregory Neil Shapiro 			     (write) ? NULL : &fds, \
17940266059SGregory Neil Shapiro 			     (write) ? &fds : NULL, \
18006f25ae9SGregory Neil Shapiro 			     NULL, &tv); \
181605302a5SGregory Neil Shapiro 	} while (ret < 0 && errno == EINTR); \
18206f25ae9SGregory Neil Shapiro  \
18306f25ae9SGregory Neil Shapiro 	switch (ret) \
18406f25ae9SGregory Neil Shapiro 	{ \
18506f25ae9SGregory Neil Shapiro 	  case 0: \
18606f25ae9SGregory Neil Shapiro 		if (tTd(64, 5)) \
18740266059SGregory Neil Shapiro 			sm_dprintf("milter_%s(%s): timeout\n", (routine), \
18840266059SGregory Neil Shapiro 				   m->mf_name); \
18940266059SGregory Neil Shapiro 		if (MilterLogLevel > 0) \
19040266059SGregory Neil Shapiro 			sm_syslog(LOG_ERR, e->e_id, \
19140266059SGregory Neil Shapiro 				  "Milter (%s): %s %s %s %s", \
19240266059SGregory Neil Shapiro 				  m->mf_name, "timeout", \
19340266059SGregory Neil Shapiro 				  started ? "during" : "before", \
19440266059SGregory Neil Shapiro 				  "data", (routine)); \
19540266059SGregory Neil Shapiro 		milter_error(m, e); \
19606f25ae9SGregory Neil Shapiro 		return NULL; \
19706f25ae9SGregory Neil Shapiro  \
19806f25ae9SGregory Neil Shapiro 	  case -1: \
19906f25ae9SGregory Neil Shapiro 		save_errno = errno; \
20006f25ae9SGregory Neil Shapiro 		if (tTd(64, 5)) \
20140266059SGregory Neil Shapiro 			sm_dprintf("milter_%s(%s): select: %s\n", (routine), \
20240266059SGregory Neil Shapiro 				   m->mf_name, sm_errstring(save_errno)); \
20340266059SGregory Neil Shapiro 		if (MilterLogLevel > 0) \
20440266059SGregory Neil Shapiro 		{ \
20506f25ae9SGregory Neil Shapiro 			sm_syslog(LOG_ERR, e->e_id, \
20640266059SGregory Neil Shapiro 				  "Milter (%s): select(%s): %s", \
20740266059SGregory Neil Shapiro 				  m->mf_name, (routine), \
20840266059SGregory Neil Shapiro 				  sm_errstring(save_errno)); \
20940266059SGregory Neil Shapiro 		} \
21040266059SGregory Neil Shapiro 		milter_error(m, e); \
21106f25ae9SGregory Neil Shapiro 		return NULL; \
21206f25ae9SGregory Neil Shapiro  \
21306f25ae9SGregory Neil Shapiro 	  default: \
214193538b7SGregory Neil Shapiro 		if (SM_FD_ISSET(m->mf_sock, &fds)) \
21506f25ae9SGregory Neil Shapiro 			break; \
21606f25ae9SGregory Neil Shapiro 		if (tTd(64, 5)) \
21740266059SGregory Neil Shapiro 			sm_dprintf("milter_%s(%s): socket not ready\n", \
21840266059SGregory Neil Shapiro 				(routine), m->mf_name); \
21940266059SGregory Neil Shapiro 		if (MilterLogLevel > 0) \
22040266059SGregory Neil Shapiro 		{ \
22106f25ae9SGregory Neil Shapiro 			sm_syslog(LOG_ERR, e->e_id, \
22240266059SGregory Neil Shapiro 				  "Milter (%s): socket(%s) not ready", \
22340266059SGregory Neil Shapiro 				  m->mf_name, (routine)); \
22440266059SGregory Neil Shapiro 		} \
22540266059SGregory Neil Shapiro 		milter_error(m, e); \
22606f25ae9SGregory Neil Shapiro 		return NULL; \
22706f25ae9SGregory Neil Shapiro 	} \
22806f25ae9SGregory Neil Shapiro }
22906f25ae9SGregory Neil Shapiro 
23006f25ae9SGregory Neil Shapiro /*
23106f25ae9SGregory Neil Shapiro **  Low level functions
23206f25ae9SGregory Neil Shapiro */
23306f25ae9SGregory Neil Shapiro 
23440266059SGregory Neil Shapiro /*
23506f25ae9SGregory Neil Shapiro **  MILTER_READ -- read from a remote milter filter
23606f25ae9SGregory Neil Shapiro **
23706f25ae9SGregory Neil Shapiro **	Parameters:
23806f25ae9SGregory Neil Shapiro **		m -- milter to read from.
23906f25ae9SGregory Neil Shapiro **		cmd -- return param for command read.
24006f25ae9SGregory Neil Shapiro **		rlen -- return length of response string.
24106f25ae9SGregory Neil Shapiro **		to -- timeout in seconds.
24206f25ae9SGregory Neil Shapiro **		e -- current envelope.
24306f25ae9SGregory Neil Shapiro **
24406f25ae9SGregory Neil Shapiro **	Returns:
24506f25ae9SGregory Neil Shapiro **		response string (may be NULL)
24606f25ae9SGregory Neil Shapiro */
24706f25ae9SGregory Neil Shapiro 
24806f25ae9SGregory Neil Shapiro static char *
24906f25ae9SGregory Neil Shapiro milter_sysread(m, buf, sz, to, e)
25006f25ae9SGregory Neil Shapiro 	struct milter *m;
25106f25ae9SGregory Neil Shapiro 	char *buf;
25206f25ae9SGregory Neil Shapiro 	ssize_t sz;
25306f25ae9SGregory Neil Shapiro 	time_t to;
25406f25ae9SGregory Neil Shapiro 	ENVELOPE *e;
25506f25ae9SGregory Neil Shapiro {
25642e5d165SGregory Neil Shapiro 	time_t readstart = 0;
25706f25ae9SGregory Neil Shapiro 	ssize_t len, curl;
25840266059SGregory Neil Shapiro 	bool started = false;
25906f25ae9SGregory Neil Shapiro 
26006f25ae9SGregory Neil Shapiro 	curl = 0;
26106f25ae9SGregory Neil Shapiro 
26206f25ae9SGregory Neil Shapiro 	if (to > 0)
26306f25ae9SGregory Neil Shapiro 		readstart = curtime();
26406f25ae9SGregory Neil Shapiro 
26506f25ae9SGregory Neil Shapiro 	for (;;)
26606f25ae9SGregory Neil Shapiro 	{
26706f25ae9SGregory Neil Shapiro 		if (to > 0)
26806f25ae9SGregory Neil Shapiro 		{
26906f25ae9SGregory Neil Shapiro 			time_t now;
27006f25ae9SGregory Neil Shapiro 
27106f25ae9SGregory Neil Shapiro 			now = curtime();
27206f25ae9SGregory Neil Shapiro 			if (now - readstart >= to)
27306f25ae9SGregory Neil Shapiro 			{
27406f25ae9SGregory Neil Shapiro 				if (tTd(64, 5))
27540266059SGregory Neil Shapiro 					sm_dprintf("milter_read (%s): %s %s %s",
27640266059SGregory Neil Shapiro 						  m->mf_name, "timeout",
27740266059SGregory Neil Shapiro 						  started ? "during" : "before",
27840266059SGregory Neil Shapiro 						  "data read");
27940266059SGregory Neil Shapiro 				if (MilterLogLevel > 0)
28006f25ae9SGregory Neil Shapiro 					sm_syslog(LOG_ERR, e->e_id,
28140266059SGregory Neil Shapiro 						  "Milter (%s): %s %s %s",
28240266059SGregory Neil Shapiro 						  m->mf_name, "timeout",
28340266059SGregory Neil Shapiro 						  started ? "during" : "before",
28440266059SGregory Neil Shapiro 						  "data read");
28540266059SGregory Neil Shapiro 				milter_error(m, e);
28606f25ae9SGregory Neil Shapiro 				return NULL;
28706f25ae9SGregory Neil Shapiro 			}
28806f25ae9SGregory Neil Shapiro 			to -= now - readstart;
28906f25ae9SGregory Neil Shapiro 			readstart = now;
29040266059SGregory Neil Shapiro 			MILTER_TIMEOUT("read", to, false, started);
29106f25ae9SGregory Neil Shapiro 		}
29206f25ae9SGregory Neil Shapiro 
29306f25ae9SGregory Neil Shapiro 		len = read(m->mf_sock, buf + curl, sz - curl);
29406f25ae9SGregory Neil Shapiro 
29506f25ae9SGregory Neil Shapiro 		if (len < 0)
29606f25ae9SGregory Neil Shapiro 		{
29706f25ae9SGregory Neil Shapiro 			int save_errno = errno;
29806f25ae9SGregory Neil Shapiro 
29906f25ae9SGregory Neil Shapiro 			if (tTd(64, 5))
30040266059SGregory Neil Shapiro 				sm_dprintf("milter_read(%s): read returned %ld: %s\n",
30106f25ae9SGregory Neil Shapiro 					m->mf_name, (long) len,
30240266059SGregory Neil Shapiro 					sm_errstring(save_errno));
30340266059SGregory Neil Shapiro 			if (MilterLogLevel > 0)
30406f25ae9SGregory Neil Shapiro 				sm_syslog(LOG_ERR, e->e_id,
30540266059SGregory Neil Shapiro 					  "Milter (%s): read returned %ld: %s",
30606f25ae9SGregory Neil Shapiro 					  m->mf_name, (long) len,
30740266059SGregory Neil Shapiro 					  sm_errstring(save_errno));
30840266059SGregory Neil Shapiro 			milter_error(m, e);
30906f25ae9SGregory Neil Shapiro 			return NULL;
31006f25ae9SGregory Neil Shapiro 		}
31106f25ae9SGregory Neil Shapiro 
31240266059SGregory Neil Shapiro 		started = true;
31306f25ae9SGregory Neil Shapiro 		curl += len;
314602a2b1bSGregory Neil Shapiro 		if (len == 0 || curl >= sz)
31506f25ae9SGregory Neil Shapiro 			break;
31606f25ae9SGregory Neil Shapiro 
31706f25ae9SGregory Neil Shapiro 	}
31806f25ae9SGregory Neil Shapiro 
31906f25ae9SGregory Neil Shapiro 	if (curl != sz)
32006f25ae9SGregory Neil Shapiro 	{
32106f25ae9SGregory Neil Shapiro 		if (tTd(64, 5))
32240266059SGregory Neil Shapiro 			sm_dprintf("milter_read(%s): cmd read returned %ld, expecting %ld\n",
32306f25ae9SGregory Neil Shapiro 				m->mf_name, (long) curl, (long) sz);
32440266059SGregory Neil Shapiro 		if (MilterLogLevel > 0)
32506f25ae9SGregory Neil Shapiro 			sm_syslog(LOG_ERR, e->e_id,
32640266059SGregory Neil Shapiro 				  "milter_read(%s): cmd read returned %ld, expecting %ld",
32706f25ae9SGregory Neil Shapiro 				  m->mf_name, (long) curl, (long) sz);
32840266059SGregory Neil Shapiro 		milter_error(m, e);
32906f25ae9SGregory Neil Shapiro 		return NULL;
33006f25ae9SGregory Neil Shapiro 	}
33106f25ae9SGregory Neil Shapiro 	return buf;
33206f25ae9SGregory Neil Shapiro }
33306f25ae9SGregory Neil Shapiro 
33406f25ae9SGregory Neil Shapiro static char *
33506f25ae9SGregory Neil Shapiro milter_read(m, cmd, rlen, to, e)
33606f25ae9SGregory Neil Shapiro 	struct milter *m;
33706f25ae9SGregory Neil Shapiro 	char *cmd;
33806f25ae9SGregory Neil Shapiro 	ssize_t *rlen;
33906f25ae9SGregory Neil Shapiro 	time_t to;
34006f25ae9SGregory Neil Shapiro 	ENVELOPE *e;
34106f25ae9SGregory Neil Shapiro {
34242e5d165SGregory Neil Shapiro 	time_t readstart = 0;
34306f25ae9SGregory Neil Shapiro 	ssize_t expl;
34406f25ae9SGregory Neil Shapiro 	mi_int32 i;
345e92d3f3fSGregory Neil Shapiro # if _FFR_MILTER_NAGLE
346e92d3f3fSGregory Neil Shapiro #  ifdef TCP_CORK
347e92d3f3fSGregory Neil Shapiro 	int cork = 0;
348e92d3f3fSGregory Neil Shapiro #  endif
349e92d3f3fSGregory Neil Shapiro # endif /* _FFR_MILTER_NAGLE */
35006f25ae9SGregory Neil Shapiro 	char *buf;
35106f25ae9SGregory Neil Shapiro 	char data[MILTER_LEN_BYTES + 1];
35206f25ae9SGregory Neil Shapiro 
35306f25ae9SGregory Neil Shapiro 	*rlen = 0;
35406f25ae9SGregory Neil Shapiro 	*cmd = '\0';
35506f25ae9SGregory Neil Shapiro 
35606f25ae9SGregory Neil Shapiro 	if (to > 0)
35706f25ae9SGregory Neil Shapiro 		readstart = curtime();
35806f25ae9SGregory Neil Shapiro 
359e92d3f3fSGregory Neil Shapiro # if _FFR_MILTER_NAGLE
360e92d3f3fSGregory Neil Shapiro #  ifdef TCP_CORK
361e92d3f3fSGregory Neil Shapiro 	setsockopt(m->mf_sock, IPPROTO_TCP, TCP_CORK, (char *)&cork,
362e92d3f3fSGregory Neil Shapiro 		   sizeof(cork));
363e92d3f3fSGregory Neil Shapiro #  endif
364e92d3f3fSGregory Neil Shapiro # endif /* _FFR_MILTER_NAGLE */
365e92d3f3fSGregory Neil Shapiro 
36606f25ae9SGregory Neil Shapiro 	if (milter_sysread(m, data, sizeof data, to, e) == NULL)
36706f25ae9SGregory Neil Shapiro 		return NULL;
36806f25ae9SGregory Neil Shapiro 
369e92d3f3fSGregory Neil Shapiro # if _FFR_MILTER_NAGLE
370e92d3f3fSGregory Neil Shapiro #  ifdef TCP_CORK
371e92d3f3fSGregory Neil Shapiro 	cork = 1;
372e92d3f3fSGregory Neil Shapiro 	setsockopt(m->mf_sock, IPPROTO_TCP, TCP_CORK, (char *)&cork,
373e92d3f3fSGregory Neil Shapiro 		   sizeof(cork));
374e92d3f3fSGregory Neil Shapiro #  endif
375e92d3f3fSGregory Neil Shapiro # endif /* _FFR_MILTER_NAGLE */
376e92d3f3fSGregory Neil Shapiro 
37706f25ae9SGregory Neil Shapiro 	/* reset timeout */
37806f25ae9SGregory Neil Shapiro 	if (to > 0)
37906f25ae9SGregory Neil Shapiro 	{
38006f25ae9SGregory Neil Shapiro 		time_t now;
38106f25ae9SGregory Neil Shapiro 
38206f25ae9SGregory Neil Shapiro 		now = curtime();
38306f25ae9SGregory Neil Shapiro 		if (now - readstart >= to)
38406f25ae9SGregory Neil Shapiro 		{
38506f25ae9SGregory Neil Shapiro 			if (tTd(64, 5))
38640266059SGregory Neil Shapiro 				sm_dprintf("milter_read(%s): timeout before data read\n",
38706f25ae9SGregory Neil Shapiro 					m->mf_name);
38840266059SGregory Neil Shapiro 			if (MilterLogLevel > 0)
38906f25ae9SGregory Neil Shapiro 				sm_syslog(LOG_ERR, e->e_id,
39040266059SGregory Neil Shapiro 					  "Milter read(%s): timeout before data read",
39106f25ae9SGregory Neil Shapiro 					  m->mf_name);
39240266059SGregory Neil Shapiro 			milter_error(m, e);
39306f25ae9SGregory Neil Shapiro 			return NULL;
39406f25ae9SGregory Neil Shapiro 		}
39506f25ae9SGregory Neil Shapiro 		to -= now - readstart;
39606f25ae9SGregory Neil Shapiro 	}
39706f25ae9SGregory Neil Shapiro 
39806f25ae9SGregory Neil Shapiro 	*cmd = data[MILTER_LEN_BYTES];
39906f25ae9SGregory Neil Shapiro 	data[MILTER_LEN_BYTES] = '\0';
40006f25ae9SGregory Neil Shapiro 	(void) memcpy(&i, data, MILTER_LEN_BYTES);
40106f25ae9SGregory Neil Shapiro 	expl = ntohl(i) - 1;
40206f25ae9SGregory Neil Shapiro 
40306f25ae9SGregory Neil Shapiro 	if (tTd(64, 25))
40440266059SGregory Neil Shapiro 		sm_dprintf("milter_read(%s): expecting %ld bytes\n",
40506f25ae9SGregory Neil Shapiro 			m->mf_name, (long) expl);
40606f25ae9SGregory Neil Shapiro 
40706f25ae9SGregory Neil Shapiro 	if (expl < 0)
40806f25ae9SGregory Neil Shapiro 	{
40906f25ae9SGregory Neil Shapiro 		if (tTd(64, 5))
41040266059SGregory Neil Shapiro 			sm_dprintf("milter_read(%s): read size %ld out of range\n",
41106f25ae9SGregory Neil Shapiro 				m->mf_name, (long) expl);
41240266059SGregory Neil Shapiro 		if (MilterLogLevel > 0)
41306f25ae9SGregory Neil Shapiro 			sm_syslog(LOG_ERR, e->e_id,
41406f25ae9SGregory Neil Shapiro 				  "milter_read(%s): read size %ld out of range",
41506f25ae9SGregory Neil Shapiro 				  m->mf_name, (long) expl);
41640266059SGregory Neil Shapiro 		milter_error(m, e);
41706f25ae9SGregory Neil Shapiro 		return NULL;
41806f25ae9SGregory Neil Shapiro 	}
41906f25ae9SGregory Neil Shapiro 
42006f25ae9SGregory Neil Shapiro 	if (expl == 0)
42106f25ae9SGregory Neil Shapiro 		return NULL;
42206f25ae9SGregory Neil Shapiro 
42306f25ae9SGregory Neil Shapiro 	buf = (char *) xalloc(expl);
42406f25ae9SGregory Neil Shapiro 
42506f25ae9SGregory Neil Shapiro 	if (milter_sysread(m, buf, expl, to, e) == NULL)
42606f25ae9SGregory Neil Shapiro 	{
42740266059SGregory Neil Shapiro 		sm_free(buf); /* XXX */
42806f25ae9SGregory Neil Shapiro 		return NULL;
42906f25ae9SGregory Neil Shapiro 	}
43006f25ae9SGregory Neil Shapiro 
43106f25ae9SGregory Neil Shapiro 	if (tTd(64, 50))
43240266059SGregory Neil Shapiro 		sm_dprintf("milter_read(%s): Returning %*s\n",
43306f25ae9SGregory Neil Shapiro 			m->mf_name, (int) expl, buf);
43406f25ae9SGregory Neil Shapiro 	*rlen = expl;
43506f25ae9SGregory Neil Shapiro 	return buf;
43606f25ae9SGregory Neil Shapiro }
437e92d3f3fSGregory Neil Shapiro 
43840266059SGregory Neil Shapiro /*
43906f25ae9SGregory Neil Shapiro **  MILTER_WRITE -- write to a remote milter filter
44006f25ae9SGregory Neil Shapiro **
44106f25ae9SGregory Neil Shapiro **	Parameters:
44206f25ae9SGregory Neil Shapiro **		m -- milter to read from.
44306f25ae9SGregory Neil Shapiro **		cmd -- command to send.
44406f25ae9SGregory Neil Shapiro **		buf -- optional command data.
44506f25ae9SGregory Neil Shapiro **		len -- length of buf.
44606f25ae9SGregory Neil Shapiro **		to -- timeout in seconds.
44706f25ae9SGregory Neil Shapiro **		e -- current envelope.
44806f25ae9SGregory Neil Shapiro **
44906f25ae9SGregory Neil Shapiro **	Returns:
45006f25ae9SGregory Neil Shapiro **		buf if successful, NULL otherwise
45106f25ae9SGregory Neil Shapiro **		Not actually used anywhere but function prototype
45206f25ae9SGregory Neil Shapiro **			must match milter_read()
45306f25ae9SGregory Neil Shapiro */
45406f25ae9SGregory Neil Shapiro 
45506f25ae9SGregory Neil Shapiro static char *
45606f25ae9SGregory Neil Shapiro milter_write(m, cmd, buf, len, to, e)
45706f25ae9SGregory Neil Shapiro 	struct milter *m;
45806f25ae9SGregory Neil Shapiro 	char cmd;
45906f25ae9SGregory Neil Shapiro 	char *buf;
46006f25ae9SGregory Neil Shapiro 	ssize_t len;
46106f25ae9SGregory Neil Shapiro 	time_t to;
46206f25ae9SGregory Neil Shapiro 	ENVELOPE *e;
46306f25ae9SGregory Neil Shapiro {
46406f25ae9SGregory Neil Shapiro 	time_t writestart = (time_t) 0;
46506f25ae9SGregory Neil Shapiro 	ssize_t sl, i;
466e92d3f3fSGregory Neil Shapiro 	int num_vectors;
46706f25ae9SGregory Neil Shapiro 	mi_int32 nl;
46806f25ae9SGregory Neil Shapiro 	char data[MILTER_LEN_BYTES + 1];
46940266059SGregory Neil Shapiro 	bool started = false;
470e92d3f3fSGregory Neil Shapiro 	struct iovec vector[2];
47106f25ae9SGregory Neil Shapiro 
472e92d3f3fSGregory Neil Shapiro 	/*
473e92d3f3fSGregory Neil Shapiro 	**  At most two buffers will be written, though
474e92d3f3fSGregory Neil Shapiro 	**  only one may actually be used (see num_vectors).
475e92d3f3fSGregory Neil Shapiro 	**  The first is the size/command and the second is the command data.
476e92d3f3fSGregory Neil Shapiro 	*/
477e92d3f3fSGregory Neil Shapiro 
478e92d3f3fSGregory Neil Shapiro 	if (len < 0 || len > MilterMaxDataSize)
47906f25ae9SGregory Neil Shapiro 	{
48006f25ae9SGregory Neil Shapiro 		if (tTd(64, 5))
48140266059SGregory Neil Shapiro 			sm_dprintf("milter_write(%s): length %ld out of range\n",
48206f25ae9SGregory Neil Shapiro 				m->mf_name, (long) len);
48340266059SGregory Neil Shapiro 		if (MilterLogLevel > 0)
48406f25ae9SGregory Neil Shapiro 			sm_syslog(LOG_ERR, e->e_id,
48506f25ae9SGregory Neil Shapiro 				  "milter_write(%s): length %ld out of range",
48606f25ae9SGregory Neil Shapiro 				  m->mf_name, (long) len);
48740266059SGregory Neil Shapiro 		milter_error(m, e);
48806f25ae9SGregory Neil Shapiro 		return NULL;
48906f25ae9SGregory Neil Shapiro 	}
49006f25ae9SGregory Neil Shapiro 
49106f25ae9SGregory Neil Shapiro 	if (tTd(64, 20))
49240266059SGregory Neil Shapiro 		sm_dprintf("milter_write(%s): cmd %c, len %ld\n",
49306f25ae9SGregory Neil Shapiro 			   m->mf_name, cmd, (long) len);
49406f25ae9SGregory Neil Shapiro 
49506f25ae9SGregory Neil Shapiro 	nl = htonl(len + 1);	/* add 1 for the cmd char */
49606f25ae9SGregory Neil Shapiro 	(void) memcpy(data, (char *) &nl, MILTER_LEN_BYTES);
49706f25ae9SGregory Neil Shapiro 	data[MILTER_LEN_BYTES] = cmd;
49806f25ae9SGregory Neil Shapiro 	sl = MILTER_LEN_BYTES + 1;
49906f25ae9SGregory Neil Shapiro 
500e92d3f3fSGregory Neil Shapiro 	/* set up the vector for the size / command */
501e92d3f3fSGregory Neil Shapiro 	vector[0].iov_base = (void *) data;
502e92d3f3fSGregory Neil Shapiro 	vector[0].iov_len  = sl;
503e92d3f3fSGregory Neil Shapiro 
504e92d3f3fSGregory Neil Shapiro 	/*
505e92d3f3fSGregory Neil Shapiro 	**  Determine if there is command data.  If so, there will be two
506e92d3f3fSGregory Neil Shapiro 	**  vectors.  If not, there will be only one.  The vectors are set
507e92d3f3fSGregory Neil Shapiro 	**  up here and 'num_vectors' and 'sl' are set appropriately.
508e92d3f3fSGregory Neil Shapiro 	*/
509e92d3f3fSGregory Neil Shapiro 
510e92d3f3fSGregory Neil Shapiro 	/* NOTE:  len<0 has already been checked for.  Pedantic */
511e92d3f3fSGregory Neil Shapiro 	if (len <= 0 || buf == NULL)
512e92d3f3fSGregory Neil Shapiro 	{
513e92d3f3fSGregory Neil Shapiro 		/* There is no command data -- only a size / command data */
514e92d3f3fSGregory Neil Shapiro 		num_vectors = 1;
515e92d3f3fSGregory Neil Shapiro 	}
516e92d3f3fSGregory Neil Shapiro 	else
517e92d3f3fSGregory Neil Shapiro 	{
518e92d3f3fSGregory Neil Shapiro 		/*
519e92d3f3fSGregory Neil Shapiro 		**  There is both size / command and command data.
520e92d3f3fSGregory Neil Shapiro 		**  Set up the vector for the command data.
521e92d3f3fSGregory Neil Shapiro 		*/
522e92d3f3fSGregory Neil Shapiro 
523e92d3f3fSGregory Neil Shapiro 		num_vectors = 2;
524e92d3f3fSGregory Neil Shapiro 		sl += len;
525e92d3f3fSGregory Neil Shapiro 		vector[1].iov_base = (void *) buf;
526e92d3f3fSGregory Neil Shapiro 		vector[1].iov_len  = len;
527e92d3f3fSGregory Neil Shapiro 
528e92d3f3fSGregory Neil Shapiro 		if (tTd(64, 50))
529e92d3f3fSGregory Neil Shapiro 			sm_dprintf("milter_write(%s): Sending %*s\n",
530e92d3f3fSGregory Neil Shapiro 				   m->mf_name, (int) len, buf);
531e92d3f3fSGregory Neil Shapiro 	}
532e92d3f3fSGregory Neil Shapiro 
53306f25ae9SGregory Neil Shapiro 	if (to > 0)
53406f25ae9SGregory Neil Shapiro 	{
53506f25ae9SGregory Neil Shapiro 		writestart = curtime();
53640266059SGregory Neil Shapiro 		MILTER_TIMEOUT("write", to, true, started);
53706f25ae9SGregory Neil Shapiro 	}
53806f25ae9SGregory Neil Shapiro 
539e92d3f3fSGregory Neil Shapiro 	/* write the vector(s) */
540e92d3f3fSGregory Neil Shapiro 	i = writev(m->mf_sock, vector, num_vectors);
54106f25ae9SGregory Neil Shapiro 	if (i != sl)
54206f25ae9SGregory Neil Shapiro 	{
54306f25ae9SGregory Neil Shapiro 		int save_errno = errno;
54406f25ae9SGregory Neil Shapiro 
54506f25ae9SGregory Neil Shapiro 		if (tTd(64, 5))
54640266059SGregory Neil Shapiro 			sm_dprintf("milter_write(%s): write(%c) returned %ld, expected %ld: %s\n",
54706f25ae9SGregory Neil Shapiro 				   m->mf_name, cmd, (long) i, (long) sl,
54840266059SGregory Neil Shapiro 				   sm_errstring(save_errno));
54940266059SGregory Neil Shapiro 		if (MilterLogLevel > 0)
55006f25ae9SGregory Neil Shapiro 			sm_syslog(LOG_ERR, e->e_id,
55140266059SGregory Neil Shapiro 				  "Milter (%s): write(%c) returned %ld, expected %ld: %s",
55206f25ae9SGregory Neil Shapiro 				  m->mf_name, cmd, (long) i, (long) sl,
55340266059SGregory Neil Shapiro 				  sm_errstring(save_errno));
55440266059SGregory Neil Shapiro 		milter_error(m, e);
55506f25ae9SGregory Neil Shapiro 		return NULL;
55606f25ae9SGregory Neil Shapiro 	}
55706f25ae9SGregory Neil Shapiro 	return buf;
55806f25ae9SGregory Neil Shapiro }
55906f25ae9SGregory Neil Shapiro 
56006f25ae9SGregory Neil Shapiro /*
56106f25ae9SGregory Neil Shapiro **  Utility functions
56206f25ae9SGregory Neil Shapiro */
56306f25ae9SGregory Neil Shapiro 
56440266059SGregory Neil Shapiro /*
56506f25ae9SGregory Neil Shapiro **  MILTER_OPEN -- connect to remote milter filter
56606f25ae9SGregory Neil Shapiro **
56706f25ae9SGregory Neil Shapiro **	Parameters:
56806f25ae9SGregory Neil Shapiro **		m -- milter to connect to.
56906f25ae9SGregory Neil Shapiro **		parseonly -- parse but don't connect.
57006f25ae9SGregory Neil Shapiro **		e -- current envelope.
57106f25ae9SGregory Neil Shapiro **
57206f25ae9SGregory Neil Shapiro **	Returns:
573d9986b26SGregory Neil Shapiro **		connected socket if successful && !parseonly,
57406f25ae9SGregory Neil Shapiro **		0 upon parse success if parseonly,
57506f25ae9SGregory Neil Shapiro **		-1 otherwise.
57606f25ae9SGregory Neil Shapiro */
57706f25ae9SGregory Neil Shapiro 
57813058a91SGregory Neil Shapiro static jmp_buf	MilterConnectTimeout;
57913058a91SGregory Neil Shapiro 
58006f25ae9SGregory Neil Shapiro static int
58106f25ae9SGregory Neil Shapiro milter_open(m, parseonly, e)
58206f25ae9SGregory Neil Shapiro 	struct milter *m;
58306f25ae9SGregory Neil Shapiro 	bool parseonly;
58406f25ae9SGregory Neil Shapiro 	ENVELOPE *e;
58506f25ae9SGregory Neil Shapiro {
58606f25ae9SGregory Neil Shapiro 	int sock = 0;
58706f25ae9SGregory Neil Shapiro 	SOCKADDR_LEN_T addrlen = 0;
58806f25ae9SGregory Neil Shapiro 	int addrno = 0;
58906f25ae9SGregory Neil Shapiro 	int save_errno;
59006f25ae9SGregory Neil Shapiro 	char *p;
59106f25ae9SGregory Neil Shapiro 	char *colon;
59206f25ae9SGregory Neil Shapiro 	char *at;
59306f25ae9SGregory Neil Shapiro 	struct hostent *hp = NULL;
59406f25ae9SGregory Neil Shapiro 	SOCKADDR addr;
59506f25ae9SGregory Neil Shapiro 
59606f25ae9SGregory Neil Shapiro 	if (m->mf_conn == NULL || m->mf_conn[0] == '\0')
59706f25ae9SGregory Neil Shapiro 	{
59806f25ae9SGregory Neil Shapiro 		if (tTd(64, 5))
59940266059SGregory Neil Shapiro 			sm_dprintf("X%s: empty or missing socket information\n",
60006f25ae9SGregory Neil Shapiro 				   m->mf_name);
60106f25ae9SGregory Neil Shapiro 		if (parseonly)
60206f25ae9SGregory Neil Shapiro 			syserr("X%s: empty or missing socket information",
60306f25ae9SGregory Neil Shapiro 			       m->mf_name);
60413bd1963SGregory Neil Shapiro 		else if (MilterLogLevel > 0)
60506f25ae9SGregory Neil Shapiro 			sm_syslog(LOG_ERR, e->e_id,
60640266059SGregory Neil Shapiro 				  "Milter (%s): empty or missing socket information",
60706f25ae9SGregory Neil Shapiro 				  m->mf_name);
60840266059SGregory Neil Shapiro 		milter_error(m, e);
60906f25ae9SGregory Neil Shapiro 		return -1;
61006f25ae9SGregory Neil Shapiro 	}
61106f25ae9SGregory Neil Shapiro 
61206f25ae9SGregory Neil Shapiro 	/* protocol:filename or protocol:port@host */
613605302a5SGregory Neil Shapiro 	memset(&addr, '\0', sizeof addr);
61406f25ae9SGregory Neil Shapiro 	p = m->mf_conn;
61506f25ae9SGregory Neil Shapiro 	colon = strchr(p, ':');
61606f25ae9SGregory Neil Shapiro 	if (colon != NULL)
61706f25ae9SGregory Neil Shapiro 	{
61806f25ae9SGregory Neil Shapiro 		*colon = '\0';
61906f25ae9SGregory Neil Shapiro 
62006f25ae9SGregory Neil Shapiro 		if (*p == '\0')
62106f25ae9SGregory Neil Shapiro 		{
62206f25ae9SGregory Neil Shapiro # if NETUNIX
62306f25ae9SGregory Neil Shapiro 			/* default to AF_UNIX */
62406f25ae9SGregory Neil Shapiro 			addr.sa.sa_family = AF_UNIX;
62506f25ae9SGregory Neil Shapiro # else /* NETUNIX */
62606f25ae9SGregory Neil Shapiro #  if NETINET
62706f25ae9SGregory Neil Shapiro 			/* default to AF_INET */
62806f25ae9SGregory Neil Shapiro 			addr.sa.sa_family = AF_INET;
62906f25ae9SGregory Neil Shapiro #  else /* NETINET */
63006f25ae9SGregory Neil Shapiro #   if NETINET6
63106f25ae9SGregory Neil Shapiro 			/* default to AF_INET6 */
63206f25ae9SGregory Neil Shapiro 			addr.sa.sa_family = AF_INET6;
63306f25ae9SGregory Neil Shapiro #   else /* NETINET6 */
63406f25ae9SGregory Neil Shapiro 			/* no protocols available */
63513bd1963SGregory Neil Shapiro 			if (MilterLogLevel > 0)
63606f25ae9SGregory Neil Shapiro 				sm_syslog(LOG_ERR, e->e_id,
63740266059SGregory Neil Shapiro 					  "Milter (%s): no valid socket protocols available",
63806f25ae9SGregory Neil Shapiro 					  m->mf_name);
63940266059SGregory Neil Shapiro 			milter_error(m, e);
64006f25ae9SGregory Neil Shapiro 			return -1;
64106f25ae9SGregory Neil Shapiro #   endif /* NETINET6 */
64206f25ae9SGregory Neil Shapiro #  endif /* NETINET */
64306f25ae9SGregory Neil Shapiro # endif /* NETUNIX */
64406f25ae9SGregory Neil Shapiro 		}
64506f25ae9SGregory Neil Shapiro # if NETUNIX
64640266059SGregory Neil Shapiro 		else if (sm_strcasecmp(p, "unix") == 0 ||
64740266059SGregory Neil Shapiro 			 sm_strcasecmp(p, "local") == 0)
64806f25ae9SGregory Neil Shapiro 			addr.sa.sa_family = AF_UNIX;
64906f25ae9SGregory Neil Shapiro # endif /* NETUNIX */
65006f25ae9SGregory Neil Shapiro # if NETINET
65140266059SGregory Neil Shapiro 		else if (sm_strcasecmp(p, "inet") == 0)
65206f25ae9SGregory Neil Shapiro 			addr.sa.sa_family = AF_INET;
65306f25ae9SGregory Neil Shapiro # endif /* NETINET */
65406f25ae9SGregory Neil Shapiro # if NETINET6
65540266059SGregory Neil Shapiro 		else if (sm_strcasecmp(p, "inet6") == 0)
65606f25ae9SGregory Neil Shapiro 			addr.sa.sa_family = AF_INET6;
65706f25ae9SGregory Neil Shapiro # endif /* NETINET6 */
65806f25ae9SGregory Neil Shapiro 		else
65906f25ae9SGregory Neil Shapiro 		{
66006f25ae9SGregory Neil Shapiro # ifdef EPROTONOSUPPORT
66106f25ae9SGregory Neil Shapiro 			errno = EPROTONOSUPPORT;
66206f25ae9SGregory Neil Shapiro # else /* EPROTONOSUPPORT */
66306f25ae9SGregory Neil Shapiro 			errno = EINVAL;
66406f25ae9SGregory Neil Shapiro # endif /* EPROTONOSUPPORT */
66506f25ae9SGregory Neil Shapiro 			if (tTd(64, 5))
66640266059SGregory Neil Shapiro 				sm_dprintf("X%s: unknown socket type %s\n",
66706f25ae9SGregory Neil Shapiro 					m->mf_name, p);
66806f25ae9SGregory Neil Shapiro 			if (parseonly)
66906f25ae9SGregory Neil Shapiro 				syserr("X%s: unknown socket type %s",
67006f25ae9SGregory Neil Shapiro 				       m->mf_name, p);
67113bd1963SGregory Neil Shapiro 			else if (MilterLogLevel > 0)
67206f25ae9SGregory Neil Shapiro 				sm_syslog(LOG_ERR, e->e_id,
67340266059SGregory Neil Shapiro 					  "Milter (%s): unknown socket type %s",
67406f25ae9SGregory Neil Shapiro 					  m->mf_name, p);
67540266059SGregory Neil Shapiro 			milter_error(m, e);
67606f25ae9SGregory Neil Shapiro 			return -1;
67706f25ae9SGregory Neil Shapiro 		}
67806f25ae9SGregory Neil Shapiro 		*colon++ = ':';
67906f25ae9SGregory Neil Shapiro 	}
68006f25ae9SGregory Neil Shapiro 	else
68106f25ae9SGregory Neil Shapiro 	{
68206f25ae9SGregory Neil Shapiro 		/* default to AF_UNIX */
68306f25ae9SGregory Neil Shapiro 		addr.sa.sa_family = AF_UNIX;
68406f25ae9SGregory Neil Shapiro 		colon = p;
68506f25ae9SGregory Neil Shapiro 	}
68606f25ae9SGregory Neil Shapiro 
68706f25ae9SGregory Neil Shapiro # if NETUNIX
68806f25ae9SGregory Neil Shapiro 	if (addr.sa.sa_family == AF_UNIX)
68906f25ae9SGregory Neil Shapiro 	{
69006f25ae9SGregory Neil Shapiro 		long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_EXECOK;
69106f25ae9SGregory Neil Shapiro 
69206f25ae9SGregory Neil Shapiro 		at = colon;
69306f25ae9SGregory Neil Shapiro 		if (strlen(colon) >= sizeof addr.sunix.sun_path)
69406f25ae9SGregory Neil Shapiro 		{
69506f25ae9SGregory Neil Shapiro 			if (tTd(64, 5))
69640266059SGregory Neil Shapiro 				sm_dprintf("X%s: local socket name %s too long\n",
69706f25ae9SGregory Neil Shapiro 					m->mf_name, colon);
69806f25ae9SGregory Neil Shapiro 			errno = EINVAL;
69906f25ae9SGregory Neil Shapiro 			if (parseonly)
70006f25ae9SGregory Neil Shapiro 				syserr("X%s: local socket name %s too long",
70106f25ae9SGregory Neil Shapiro 				       m->mf_name, colon);
70213bd1963SGregory Neil Shapiro 			else if (MilterLogLevel > 0)
70306f25ae9SGregory Neil Shapiro 				sm_syslog(LOG_ERR, e->e_id,
70440266059SGregory Neil Shapiro 					  "Milter (%s): local socket name %s too long",
70506f25ae9SGregory Neil Shapiro 					  m->mf_name, colon);
70640266059SGregory Neil Shapiro 			milter_error(m, e);
70706f25ae9SGregory Neil Shapiro 			return -1;
70806f25ae9SGregory Neil Shapiro 		}
70906f25ae9SGregory Neil Shapiro 		errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff,
71006f25ae9SGregory Neil Shapiro 				 S_IRUSR|S_IWUSR, NULL);
71106f25ae9SGregory Neil Shapiro 
71206f25ae9SGregory Neil Shapiro 		/* if just parsing .cf file, socket doesn't need to exist */
71306f25ae9SGregory Neil Shapiro 		if (parseonly && errno == ENOENT)
71406f25ae9SGregory Neil Shapiro 		{
71506f25ae9SGregory Neil Shapiro 			if (OpMode == MD_DAEMON ||
71606f25ae9SGregory Neil Shapiro 			    OpMode == MD_FGDAEMON)
71740266059SGregory Neil Shapiro 				(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
71806f25ae9SGregory Neil Shapiro 						     "WARNING: X%s: local socket name %s missing\n",
71906f25ae9SGregory Neil Shapiro 						     m->mf_name, colon);
72006f25ae9SGregory Neil Shapiro 		}
72106f25ae9SGregory Neil Shapiro 		else if (errno != 0)
72206f25ae9SGregory Neil Shapiro 		{
72306f25ae9SGregory Neil Shapiro 			/* if not safe, don't create */
72406f25ae9SGregory Neil Shapiro 			save_errno = errno;
72506f25ae9SGregory Neil Shapiro 			if (tTd(64, 5))
72640266059SGregory Neil Shapiro 				sm_dprintf("X%s: local socket name %s unsafe\n",
72706f25ae9SGregory Neil Shapiro 					m->mf_name, colon);
72806f25ae9SGregory Neil Shapiro 			errno = save_errno;
72906f25ae9SGregory Neil Shapiro 			if (parseonly)
73006f25ae9SGregory Neil Shapiro 			{
73106f25ae9SGregory Neil Shapiro 				if (OpMode == MD_DAEMON ||
73206f25ae9SGregory Neil Shapiro 				    OpMode == MD_FGDAEMON ||
73306f25ae9SGregory Neil Shapiro 				    OpMode == MD_SMTP)
73406f25ae9SGregory Neil Shapiro 					syserr("X%s: local socket name %s unsafe",
73506f25ae9SGregory Neil Shapiro 					       m->mf_name, colon);
73606f25ae9SGregory Neil Shapiro 			}
73713bd1963SGregory Neil Shapiro 			else if (MilterLogLevel > 0)
73806f25ae9SGregory Neil Shapiro 				sm_syslog(LOG_ERR, e->e_id,
73940266059SGregory Neil Shapiro 					  "Milter (%s): local socket name %s unsafe",
74006f25ae9SGregory Neil Shapiro 					  m->mf_name, colon);
74140266059SGregory Neil Shapiro 			milter_error(m, e);
74206f25ae9SGregory Neil Shapiro 			return -1;
74306f25ae9SGregory Neil Shapiro 		}
74406f25ae9SGregory Neil Shapiro 
74540266059SGregory Neil Shapiro 		(void) sm_strlcpy(addr.sunix.sun_path, colon,
74606f25ae9SGregory Neil Shapiro 			       sizeof addr.sunix.sun_path);
74706f25ae9SGregory Neil Shapiro 		addrlen = sizeof (struct sockaddr_un);
74806f25ae9SGregory Neil Shapiro 	}
74906f25ae9SGregory Neil Shapiro 	else
75006f25ae9SGregory Neil Shapiro # endif /* NETUNIX */
75106f25ae9SGregory Neil Shapiro # if NETINET || NETINET6
75240266059SGregory Neil Shapiro 	if (false
75306f25ae9SGregory Neil Shapiro #  if NETINET
75406f25ae9SGregory Neil Shapiro 		 || addr.sa.sa_family == AF_INET
75506f25ae9SGregory Neil Shapiro #  endif /* NETINET */
75606f25ae9SGregory Neil Shapiro #  if NETINET6
75706f25ae9SGregory Neil Shapiro 		 || addr.sa.sa_family == AF_INET6
75806f25ae9SGregory Neil Shapiro #  endif /* NETINET6 */
75906f25ae9SGregory Neil Shapiro 		 )
76006f25ae9SGregory Neil Shapiro 	{
76140266059SGregory Neil Shapiro 		unsigned short port;
76206f25ae9SGregory Neil Shapiro 
76306f25ae9SGregory Neil Shapiro 		/* Parse port@host */
76406f25ae9SGregory Neil Shapiro 		at = strchr(colon, '@');
76506f25ae9SGregory Neil Shapiro 		if (at == NULL)
76606f25ae9SGregory Neil Shapiro 		{
76706f25ae9SGregory Neil Shapiro 			if (tTd(64, 5))
76840266059SGregory Neil Shapiro 				sm_dprintf("X%s: bad address %s (expected port@host)\n",
76906f25ae9SGregory Neil Shapiro 					m->mf_name, colon);
77006f25ae9SGregory Neil Shapiro 			if (parseonly)
77106f25ae9SGregory Neil Shapiro 				syserr("X%s: bad address %s (expected port@host)",
77206f25ae9SGregory Neil Shapiro 				       m->mf_name, colon);
77313bd1963SGregory Neil Shapiro 			else if (MilterLogLevel > 0)
77406f25ae9SGregory Neil Shapiro 				sm_syslog(LOG_ERR, e->e_id,
77540266059SGregory Neil Shapiro 					  "Milter (%s): bad address %s (expected port@host)",
77606f25ae9SGregory Neil Shapiro 					  m->mf_name, colon);
77740266059SGregory Neil Shapiro 			milter_error(m, e);
77806f25ae9SGregory Neil Shapiro 			return -1;
77906f25ae9SGregory Neil Shapiro 		}
78006f25ae9SGregory Neil Shapiro 		*at = '\0';
78106f25ae9SGregory Neil Shapiro 		if (isascii(*colon) && isdigit(*colon))
78240266059SGregory Neil Shapiro 			port = htons((unsigned short) atoi(colon));
78306f25ae9SGregory Neil Shapiro 		else
78406f25ae9SGregory Neil Shapiro 		{
78506f25ae9SGregory Neil Shapiro #  ifdef NO_GETSERVBYNAME
78606f25ae9SGregory Neil Shapiro 			if (tTd(64, 5))
78740266059SGregory Neil Shapiro 				sm_dprintf("X%s: invalid port number %s\n",
78806f25ae9SGregory Neil Shapiro 					m->mf_name, colon);
78906f25ae9SGregory Neil Shapiro 			if (parseonly)
79006f25ae9SGregory Neil Shapiro 				syserr("X%s: invalid port number %s",
79106f25ae9SGregory Neil Shapiro 				       m->mf_name, colon);
79213bd1963SGregory Neil Shapiro 			else if (MilterLogLevel > 0)
79306f25ae9SGregory Neil Shapiro 				sm_syslog(LOG_ERR, e->e_id,
79440266059SGregory Neil Shapiro 					  "Milter (%s): invalid port number %s",
79506f25ae9SGregory Neil Shapiro 					  m->mf_name, colon);
79640266059SGregory Neil Shapiro 			milter_error(m, e);
79706f25ae9SGregory Neil Shapiro 			return -1;
79806f25ae9SGregory Neil Shapiro #  else /* NO_GETSERVBYNAME */
79906f25ae9SGregory Neil Shapiro 			register struct servent *sp;
80006f25ae9SGregory Neil Shapiro 
80106f25ae9SGregory Neil Shapiro 			sp = getservbyname(colon, "tcp");
80206f25ae9SGregory Neil Shapiro 			if (sp == NULL)
80306f25ae9SGregory Neil Shapiro 			{
80406f25ae9SGregory Neil Shapiro 				save_errno = errno;
80506f25ae9SGregory Neil Shapiro 				if (tTd(64, 5))
80640266059SGregory Neil Shapiro 					sm_dprintf("X%s: unknown port name %s\n",
80706f25ae9SGregory Neil Shapiro 						m->mf_name, colon);
80806f25ae9SGregory Neil Shapiro 				errno = save_errno;
80906f25ae9SGregory Neil Shapiro 				if (parseonly)
81006f25ae9SGregory Neil Shapiro 					syserr("X%s: unknown port name %s",
81106f25ae9SGregory Neil Shapiro 					       m->mf_name, colon);
81213bd1963SGregory Neil Shapiro 				else if (MilterLogLevel > 0)
81306f25ae9SGregory Neil Shapiro 					sm_syslog(LOG_ERR, e->e_id,
81440266059SGregory Neil Shapiro 						  "Milter (%s): unknown port name %s",
81506f25ae9SGregory Neil Shapiro 						  m->mf_name, colon);
81640266059SGregory Neil Shapiro 				milter_error(m, e);
81706f25ae9SGregory Neil Shapiro 				return -1;
81806f25ae9SGregory Neil Shapiro 			}
81906f25ae9SGregory Neil Shapiro 			port = sp->s_port;
82006f25ae9SGregory Neil Shapiro #  endif /* NO_GETSERVBYNAME */
82106f25ae9SGregory Neil Shapiro 		}
82206f25ae9SGregory Neil Shapiro 		*at++ = '@';
82306f25ae9SGregory Neil Shapiro 		if (*at == '[')
82406f25ae9SGregory Neil Shapiro 		{
82506f25ae9SGregory Neil Shapiro 			char *end;
82606f25ae9SGregory Neil Shapiro 
82706f25ae9SGregory Neil Shapiro 			end = strchr(at, ']');
82806f25ae9SGregory Neil Shapiro 			if (end != NULL)
82906f25ae9SGregory Neil Shapiro 			{
83040266059SGregory Neil Shapiro 				bool found = false;
83106f25ae9SGregory Neil Shapiro #  if NETINET
83206f25ae9SGregory Neil Shapiro 				unsigned long hid = INADDR_NONE;
83306f25ae9SGregory Neil Shapiro #  endif /* NETINET */
83406f25ae9SGregory Neil Shapiro #  if NETINET6
83506f25ae9SGregory Neil Shapiro 				struct sockaddr_in6 hid6;
83606f25ae9SGregory Neil Shapiro #  endif /* NETINET6 */
83706f25ae9SGregory Neil Shapiro 
83806f25ae9SGregory Neil Shapiro 				*end = '\0';
83906f25ae9SGregory Neil Shapiro #  if NETINET
84006f25ae9SGregory Neil Shapiro 				if (addr.sa.sa_family == AF_INET &&
84106f25ae9SGregory Neil Shapiro 				    (hid = inet_addr(&at[1])) != INADDR_NONE)
84206f25ae9SGregory Neil Shapiro 				{
84306f25ae9SGregory Neil Shapiro 					addr.sin.sin_addr.s_addr = hid;
84406f25ae9SGregory Neil Shapiro 					addr.sin.sin_port = port;
84540266059SGregory Neil Shapiro 					found = true;
84606f25ae9SGregory Neil Shapiro 				}
84706f25ae9SGregory Neil Shapiro #  endif /* NETINET */
84806f25ae9SGregory Neil Shapiro #  if NETINET6
84906f25ae9SGregory Neil Shapiro 				(void) memset(&hid6, '\0', sizeof hid6);
85006f25ae9SGregory Neil Shapiro 				if (addr.sa.sa_family == AF_INET6 &&
85140266059SGregory Neil Shapiro 				    anynet_pton(AF_INET6, &at[1],
85206f25ae9SGregory Neil Shapiro 						&hid6.sin6_addr) == 1)
85306f25ae9SGregory Neil Shapiro 				{
85406f25ae9SGregory Neil Shapiro 					addr.sin6.sin6_addr = hid6.sin6_addr;
85506f25ae9SGregory Neil Shapiro 					addr.sin6.sin6_port = port;
85640266059SGregory Neil Shapiro 					found = true;
85706f25ae9SGregory Neil Shapiro 				}
85806f25ae9SGregory Neil Shapiro #  endif /* NETINET6 */
85906f25ae9SGregory Neil Shapiro 				*end = ']';
86006f25ae9SGregory Neil Shapiro 				if (!found)
86106f25ae9SGregory Neil Shapiro 				{
86206f25ae9SGregory Neil Shapiro 					if (tTd(64, 5))
86340266059SGregory Neil Shapiro 						sm_dprintf("X%s: Invalid numeric domain spec \"%s\"\n",
86406f25ae9SGregory Neil Shapiro 							m->mf_name, at);
86506f25ae9SGregory Neil Shapiro 					if (parseonly)
86606f25ae9SGregory Neil Shapiro 						syserr("X%s: Invalid numeric domain spec \"%s\"",
86706f25ae9SGregory Neil Shapiro 						       m->mf_name, at);
86813bd1963SGregory Neil Shapiro 					else if (MilterLogLevel > 0)
86906f25ae9SGregory Neil Shapiro 						sm_syslog(LOG_ERR, e->e_id,
87040266059SGregory Neil Shapiro 							  "Milter (%s): Invalid numeric domain spec \"%s\"",
87106f25ae9SGregory Neil Shapiro 							  m->mf_name, at);
87240266059SGregory Neil Shapiro 					milter_error(m, e);
87306f25ae9SGregory Neil Shapiro 					return -1;
87406f25ae9SGregory Neil Shapiro 				}
87506f25ae9SGregory Neil Shapiro 			}
87606f25ae9SGregory Neil Shapiro 			else
87706f25ae9SGregory Neil Shapiro 			{
87806f25ae9SGregory Neil Shapiro 				if (tTd(64, 5))
87940266059SGregory Neil Shapiro 					sm_dprintf("X%s: Invalid numeric domain spec \"%s\"\n",
88006f25ae9SGregory Neil Shapiro 						m->mf_name, at);
88106f25ae9SGregory Neil Shapiro 				if (parseonly)
88206f25ae9SGregory Neil Shapiro 					syserr("X%s: Invalid numeric domain spec \"%s\"",
88306f25ae9SGregory Neil Shapiro 					       m->mf_name, at);
88413bd1963SGregory Neil Shapiro 				else if (MilterLogLevel > 0)
88506f25ae9SGregory Neil Shapiro 					sm_syslog(LOG_ERR, e->e_id,
88640266059SGregory Neil Shapiro 						  "Milter (%s): Invalid numeric domain spec \"%s\"",
88706f25ae9SGregory Neil Shapiro 						  m->mf_name, at);
88840266059SGregory Neil Shapiro 				milter_error(m, e);
88906f25ae9SGregory Neil Shapiro 				return -1;
89006f25ae9SGregory Neil Shapiro 			}
89106f25ae9SGregory Neil Shapiro 		}
89206f25ae9SGregory Neil Shapiro 		else
89306f25ae9SGregory Neil Shapiro 		{
89406f25ae9SGregory Neil Shapiro 			hp = sm_gethostbyname(at, addr.sa.sa_family);
89506f25ae9SGregory Neil Shapiro 			if (hp == NULL)
89606f25ae9SGregory Neil Shapiro 			{
89706f25ae9SGregory Neil Shapiro 				save_errno = errno;
89806f25ae9SGregory Neil Shapiro 				if (tTd(64, 5))
89940266059SGregory Neil Shapiro 					sm_dprintf("X%s: Unknown host name %s\n",
90006f25ae9SGregory Neil Shapiro 						   m->mf_name, at);
90106f25ae9SGregory Neil Shapiro 				errno = save_errno;
90206f25ae9SGregory Neil Shapiro 				if (parseonly)
90306f25ae9SGregory Neil Shapiro 					syserr("X%s: Unknown host name %s",
90406f25ae9SGregory Neil Shapiro 					       m->mf_name, at);
90513bd1963SGregory Neil Shapiro 				else if (MilterLogLevel > 0)
90606f25ae9SGregory Neil Shapiro 					sm_syslog(LOG_ERR, e->e_id,
90740266059SGregory Neil Shapiro 						  "Milter (%s): Unknown host name %s",
90806f25ae9SGregory Neil Shapiro 						  m->mf_name, at);
90940266059SGregory Neil Shapiro 				milter_error(m, e);
91006f25ae9SGregory Neil Shapiro 				return -1;
91106f25ae9SGregory Neil Shapiro 			}
91206f25ae9SGregory Neil Shapiro 			addr.sa.sa_family = hp->h_addrtype;
91306f25ae9SGregory Neil Shapiro 			switch (hp->h_addrtype)
91406f25ae9SGregory Neil Shapiro 			{
91506f25ae9SGregory Neil Shapiro #  if NETINET
91606f25ae9SGregory Neil Shapiro 			  case AF_INET:
91706f25ae9SGregory Neil Shapiro 				memmove(&addr.sin.sin_addr,
91840266059SGregory Neil Shapiro 					hp->h_addr, INADDRSZ);
91906f25ae9SGregory Neil Shapiro 				addr.sin.sin_port = port;
92006f25ae9SGregory Neil Shapiro 				addrlen = sizeof (struct sockaddr_in);
92106f25ae9SGregory Neil Shapiro 				addrno = 1;
92206f25ae9SGregory Neil Shapiro 				break;
92306f25ae9SGregory Neil Shapiro #  endif /* NETINET */
92406f25ae9SGregory Neil Shapiro 
92506f25ae9SGregory Neil Shapiro #  if NETINET6
92606f25ae9SGregory Neil Shapiro 			  case AF_INET6:
92706f25ae9SGregory Neil Shapiro 				memmove(&addr.sin6.sin6_addr,
92840266059SGregory Neil Shapiro 					hp->h_addr, IN6ADDRSZ);
92906f25ae9SGregory Neil Shapiro 				addr.sin6.sin6_port = port;
93006f25ae9SGregory Neil Shapiro 				addrlen = sizeof (struct sockaddr_in6);
93106f25ae9SGregory Neil Shapiro 				addrno = 1;
93206f25ae9SGregory Neil Shapiro 				break;
93306f25ae9SGregory Neil Shapiro #  endif /* NETINET6 */
93406f25ae9SGregory Neil Shapiro 
93506f25ae9SGregory Neil Shapiro 			  default:
93606f25ae9SGregory Neil Shapiro 				if (tTd(64, 5))
93740266059SGregory Neil Shapiro 					sm_dprintf("X%s: Unknown protocol for %s (%d)\n",
93806f25ae9SGregory Neil Shapiro 						   m->mf_name, at,
93906f25ae9SGregory Neil Shapiro 						   hp->h_addrtype);
94006f25ae9SGregory Neil Shapiro 				if (parseonly)
94106f25ae9SGregory Neil Shapiro 					syserr("X%s: Unknown protocol for %s (%d)",
94206f25ae9SGregory Neil Shapiro 					       m->mf_name, at, hp->h_addrtype);
94313bd1963SGregory Neil Shapiro 				else if (MilterLogLevel > 0)
94406f25ae9SGregory Neil Shapiro 					sm_syslog(LOG_ERR, e->e_id,
94540266059SGregory Neil Shapiro 						  "Milter (%s): Unknown protocol for %s (%d)",
94606f25ae9SGregory Neil Shapiro 						  m->mf_name, at,
94706f25ae9SGregory Neil Shapiro 						  hp->h_addrtype);
94840266059SGregory Neil Shapiro 				milter_error(m, e);
94940266059SGregory Neil Shapiro #  if NETINET6
950193538b7SGregory Neil Shapiro 				freehostent(hp);
95140266059SGregory Neil Shapiro #  endif /* NETINET6 */
95206f25ae9SGregory Neil Shapiro 				return -1;
95306f25ae9SGregory Neil Shapiro 			}
95406f25ae9SGregory Neil Shapiro 		}
95506f25ae9SGregory Neil Shapiro 	}
95606f25ae9SGregory Neil Shapiro 	else
95706f25ae9SGregory Neil Shapiro # endif /* NETINET || NETINET6 */
95806f25ae9SGregory Neil Shapiro 	{
95906f25ae9SGregory Neil Shapiro 		if (tTd(64, 5))
96040266059SGregory Neil Shapiro 			sm_dprintf("X%s: unknown socket protocol\n",
96140266059SGregory Neil Shapiro 				   m->mf_name);
96206f25ae9SGregory Neil Shapiro 		if (parseonly)
96306f25ae9SGregory Neil Shapiro 			syserr("X%s: unknown socket protocol", m->mf_name);
96413bd1963SGregory Neil Shapiro 		else if (MilterLogLevel > 0)
96506f25ae9SGregory Neil Shapiro 			sm_syslog(LOG_ERR, e->e_id,
96640266059SGregory Neil Shapiro 				  "Milter (%s): unknown socket protocol",
96740266059SGregory Neil Shapiro 				  m->mf_name);
96840266059SGregory Neil Shapiro 		milter_error(m, e);
96906f25ae9SGregory Neil Shapiro 		return -1;
97006f25ae9SGregory Neil Shapiro 	}
97106f25ae9SGregory Neil Shapiro 
97206f25ae9SGregory Neil Shapiro 	/* just parsing through? */
97306f25ae9SGregory Neil Shapiro 	if (parseonly)
97406f25ae9SGregory Neil Shapiro 	{
97506f25ae9SGregory Neil Shapiro 		m->mf_state = SMFS_READY;
97640266059SGregory Neil Shapiro # if NETINET6
977193538b7SGregory Neil Shapiro 		if (hp != NULL)
978193538b7SGregory Neil Shapiro 			freehostent(hp);
97940266059SGregory Neil Shapiro # endif /* NETINET6 */
98006f25ae9SGregory Neil Shapiro 		return 0;
98106f25ae9SGregory Neil Shapiro 	}
98206f25ae9SGregory Neil Shapiro 
98306f25ae9SGregory Neil Shapiro 	/* sanity check */
98406f25ae9SGregory Neil Shapiro 	if (m->mf_state != SMFS_READY &&
98506f25ae9SGregory Neil Shapiro 	    m->mf_state != SMFS_CLOSED)
98606f25ae9SGregory Neil Shapiro 	{
98706f25ae9SGregory Neil Shapiro 		/* shouldn't happen */
98806f25ae9SGregory Neil Shapiro 		if (tTd(64, 1))
98940266059SGregory Neil Shapiro 			sm_dprintf("Milter (%s): Trying to open filter in state %c\n",
99006f25ae9SGregory Neil Shapiro 				   m->mf_name, (char) m->mf_state);
99140266059SGregory Neil Shapiro 		milter_error(m, e);
99240266059SGregory Neil Shapiro # if NETINET6
993193538b7SGregory Neil Shapiro 		if (hp != NULL)
994193538b7SGregory Neil Shapiro 			freehostent(hp);
99540266059SGregory Neil Shapiro # endif /* NETINET6 */
99606f25ae9SGregory Neil Shapiro 		return -1;
99706f25ae9SGregory Neil Shapiro 	}
99806f25ae9SGregory Neil Shapiro 
99906f25ae9SGregory Neil Shapiro 	/* nope, actually connecting */
100006f25ae9SGregory Neil Shapiro 	for (;;)
100106f25ae9SGregory Neil Shapiro 	{
100206f25ae9SGregory Neil Shapiro 		sock = socket(addr.sa.sa_family, SOCK_STREAM, 0);
100306f25ae9SGregory Neil Shapiro 		if (sock < 0)
100406f25ae9SGregory Neil Shapiro 		{
100506f25ae9SGregory Neil Shapiro 			save_errno = errno;
100606f25ae9SGregory Neil Shapiro 			if (tTd(64, 5))
100740266059SGregory Neil Shapiro 				sm_dprintf("Milter (%s): error creating socket: %s\n",
100840266059SGregory Neil Shapiro 					   m->mf_name,
100940266059SGregory Neil Shapiro 					   sm_errstring(save_errno));
101040266059SGregory Neil Shapiro 			if (MilterLogLevel > 0)
101106f25ae9SGregory Neil Shapiro 				sm_syslog(LOG_ERR, e->e_id,
101240266059SGregory Neil Shapiro 					  "Milter (%s): error creating socket: %s",
101340266059SGregory Neil Shapiro 					  m->mf_name, sm_errstring(save_errno));
101440266059SGregory Neil Shapiro 			milter_error(m, e);
101540266059SGregory Neil Shapiro # if NETINET6
1016193538b7SGregory Neil Shapiro 			if (hp != NULL)
1017193538b7SGregory Neil Shapiro 				freehostent(hp);
101840266059SGregory Neil Shapiro # endif /* NETINET6 */
101906f25ae9SGregory Neil Shapiro 			return -1;
102006f25ae9SGregory Neil Shapiro 		}
102106f25ae9SGregory Neil Shapiro 
102213058a91SGregory Neil Shapiro 		if (setjmp(MilterConnectTimeout) == 0)
102313058a91SGregory Neil Shapiro 		{
102440266059SGregory Neil Shapiro 			SM_EVENT *ev = NULL;
102513058a91SGregory Neil Shapiro 			int i;
102613058a91SGregory Neil Shapiro 
102713058a91SGregory Neil Shapiro 			if (m->mf_timeout[SMFTO_CONNECT] > 0)
102840266059SGregory Neil Shapiro 				ev = sm_setevent(m->mf_timeout[SMFTO_CONNECT],
102913058a91SGregory Neil Shapiro 						 milter_connect_timeout, 0);
103013058a91SGregory Neil Shapiro 
103113058a91SGregory Neil Shapiro 			i = connect(sock, (struct sockaddr *) &addr, addrlen);
103213058a91SGregory Neil Shapiro 			save_errno = errno;
103313058a91SGregory Neil Shapiro 			if (ev != NULL)
103440266059SGregory Neil Shapiro 				sm_clrevent(ev);
103513058a91SGregory Neil Shapiro 			errno = save_errno;
103613058a91SGregory Neil Shapiro 			if (i >= 0)
103706f25ae9SGregory Neil Shapiro 				break;
103813058a91SGregory Neil Shapiro 		}
103906f25ae9SGregory Neil Shapiro 
104006f25ae9SGregory Neil Shapiro 		/* couldn't connect.... try next address */
104106f25ae9SGregory Neil Shapiro 		save_errno = errno;
104242e5d165SGregory Neil Shapiro 		p = CurHostName;
104342e5d165SGregory Neil Shapiro 		CurHostName = at;
104406f25ae9SGregory Neil Shapiro 		if (tTd(64, 5))
104540266059SGregory Neil Shapiro 			sm_dprintf("milter_open (%s): open %s failed: %s\n",
104640266059SGregory Neil Shapiro 				   m->mf_name, at, sm_errstring(save_errno));
104740266059SGregory Neil Shapiro 		if (MilterLogLevel > 13)
104806f25ae9SGregory Neil Shapiro 			sm_syslog(LOG_INFO, e->e_id,
104940266059SGregory Neil Shapiro 				  "Milter (%s): open %s failed: %s",
105040266059SGregory Neil Shapiro 				  m->mf_name, at, sm_errstring(save_errno));
105142e5d165SGregory Neil Shapiro 		CurHostName = p;
105206f25ae9SGregory Neil Shapiro 		(void) close(sock);
105306f25ae9SGregory Neil Shapiro 
105406f25ae9SGregory Neil Shapiro 		/* try next address */
105506f25ae9SGregory Neil Shapiro 		if (hp != NULL && hp->h_addr_list[addrno] != NULL)
105606f25ae9SGregory Neil Shapiro 		{
105706f25ae9SGregory Neil Shapiro 			switch (addr.sa.sa_family)
105806f25ae9SGregory Neil Shapiro 			{
105906f25ae9SGregory Neil Shapiro # if NETINET
106006f25ae9SGregory Neil Shapiro 			  case AF_INET:
106106f25ae9SGregory Neil Shapiro 				memmove(&addr.sin.sin_addr,
106206f25ae9SGregory Neil Shapiro 					hp->h_addr_list[addrno++],
106306f25ae9SGregory Neil Shapiro 					INADDRSZ);
106406f25ae9SGregory Neil Shapiro 				break;
106506f25ae9SGregory Neil Shapiro # endif /* NETINET */
106606f25ae9SGregory Neil Shapiro 
106706f25ae9SGregory Neil Shapiro # if NETINET6
106806f25ae9SGregory Neil Shapiro 			  case AF_INET6:
106906f25ae9SGregory Neil Shapiro 				memmove(&addr.sin6.sin6_addr,
107006f25ae9SGregory Neil Shapiro 					hp->h_addr_list[addrno++],
107106f25ae9SGregory Neil Shapiro 					IN6ADDRSZ);
107206f25ae9SGregory Neil Shapiro 				break;
107306f25ae9SGregory Neil Shapiro # endif /* NETINET6 */
107406f25ae9SGregory Neil Shapiro 
107506f25ae9SGregory Neil Shapiro 			  default:
107606f25ae9SGregory Neil Shapiro 				if (tTd(64, 5))
107740266059SGregory Neil Shapiro 					sm_dprintf("X%s: Unknown protocol for %s (%d)\n",
107806f25ae9SGregory Neil Shapiro 						   m->mf_name, at,
107906f25ae9SGregory Neil Shapiro 						   hp->h_addrtype);
108040266059SGregory Neil Shapiro 				if (MilterLogLevel > 0)
108106f25ae9SGregory Neil Shapiro 					sm_syslog(LOG_ERR, e->e_id,
108240266059SGregory Neil Shapiro 						  "Milter (%s): Unknown protocol for %s (%d)",
108306f25ae9SGregory Neil Shapiro 						  m->mf_name, at,
108406f25ae9SGregory Neil Shapiro 						  hp->h_addrtype);
108540266059SGregory Neil Shapiro 				milter_error(m, e);
108640266059SGregory Neil Shapiro # if NETINET6
1087193538b7SGregory Neil Shapiro 				freehostent(hp);
108840266059SGregory Neil Shapiro # endif /* NETINET6 */
108906f25ae9SGregory Neil Shapiro 				return -1;
109006f25ae9SGregory Neil Shapiro 			}
109106f25ae9SGregory Neil Shapiro 			continue;
109206f25ae9SGregory Neil Shapiro 		}
109313058a91SGregory Neil Shapiro 		p = CurHostName;
109413058a91SGregory Neil Shapiro 		CurHostName = at;
109506f25ae9SGregory Neil Shapiro 		if (tTd(64, 5))
109640266059SGregory Neil Shapiro 			sm_dprintf("X%s: error connecting to filter: %s\n",
109740266059SGregory Neil Shapiro 				   m->mf_name, sm_errstring(save_errno));
109840266059SGregory Neil Shapiro 		if (MilterLogLevel > 0)
109906f25ae9SGregory Neil Shapiro 			sm_syslog(LOG_ERR, e->e_id,
110040266059SGregory Neil Shapiro 				  "Milter (%s): error connecting to filter: %s",
110140266059SGregory Neil Shapiro 				  m->mf_name, sm_errstring(save_errno));
110213058a91SGregory Neil Shapiro 		CurHostName = p;
110340266059SGregory Neil Shapiro 		milter_error(m, e);
110440266059SGregory Neil Shapiro # if NETINET6
1105193538b7SGregory Neil Shapiro 		if (hp != NULL)
1106193538b7SGregory Neil Shapiro 			freehostent(hp);
110740266059SGregory Neil Shapiro # endif /* NETINET6 */
110806f25ae9SGregory Neil Shapiro 		return -1;
110906f25ae9SGregory Neil Shapiro 	}
111006f25ae9SGregory Neil Shapiro 	m->mf_state = SMFS_OPEN;
111140266059SGregory Neil Shapiro # if NETINET6
1112193538b7SGregory Neil Shapiro 	if (hp != NULL)
1113193538b7SGregory Neil Shapiro 	{
1114193538b7SGregory Neil Shapiro 		freehostent(hp);
1115193538b7SGregory Neil Shapiro 		hp = NULL;
1116193538b7SGregory Neil Shapiro 	}
111740266059SGregory Neil Shapiro # endif /* NETINET6 */
1118e92d3f3fSGregory Neil Shapiro # if _FFR_MILTER_NAGLE
1119e92d3f3fSGregory Neil Shapiro #  ifndef TCP_CORK
1120e92d3f3fSGregory Neil Shapiro 	{
1121e92d3f3fSGregory Neil Shapiro 		int nodelay = 1;
1122e92d3f3fSGregory Neil Shapiro 
1123e92d3f3fSGregory Neil Shapiro 		setsockopt(m->mf_sock, IPPROTO_TCP, TCP_NODELAY,
1124e92d3f3fSGregory Neil Shapiro 			   (char *)&nodelay, sizeof(nodelay));
1125e92d3f3fSGregory Neil Shapiro 	}
1126e92d3f3fSGregory Neil Shapiro #  endif /* TCP_CORK */
1127e92d3f3fSGregory Neil Shapiro # endif /* _FFR_MILTER_NAGLE */
112806f25ae9SGregory Neil Shapiro 	return sock;
112906f25ae9SGregory Neil Shapiro }
113013058a91SGregory Neil Shapiro 
113113058a91SGregory Neil Shapiro static void
1132b6bacd31SGregory Neil Shapiro milter_connect_timeout(ignore)
1133b6bacd31SGregory Neil Shapiro 	int ignore;
113413058a91SGregory Neil Shapiro {
113513058a91SGregory Neil Shapiro 	/*
113613058a91SGregory Neil Shapiro 	**  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
113713058a91SGregory Neil Shapiro 	**	ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
113813058a91SGregory Neil Shapiro 	**	DOING.
113913058a91SGregory Neil Shapiro 	*/
114013058a91SGregory Neil Shapiro 
114113058a91SGregory Neil Shapiro 	errno = ETIMEDOUT;
114213058a91SGregory Neil Shapiro 	longjmp(MilterConnectTimeout, 1);
114313058a91SGregory Neil Shapiro }
114440266059SGregory Neil Shapiro /*
114506f25ae9SGregory Neil Shapiro **  MILTER_SETUP -- setup structure for a mail filter
114606f25ae9SGregory Neil Shapiro **
114706f25ae9SGregory Neil Shapiro **	Parameters:
114806f25ae9SGregory Neil Shapiro **		line -- the options line.
114906f25ae9SGregory Neil Shapiro **
115006f25ae9SGregory Neil Shapiro **	Returns:
115106f25ae9SGregory Neil Shapiro **		none
115206f25ae9SGregory Neil Shapiro */
115306f25ae9SGregory Neil Shapiro 
115406f25ae9SGregory Neil Shapiro void
115506f25ae9SGregory Neil Shapiro milter_setup(line)
115606f25ae9SGregory Neil Shapiro 	char *line;
115706f25ae9SGregory Neil Shapiro {
115806f25ae9SGregory Neil Shapiro 	char fcode;
115906f25ae9SGregory Neil Shapiro 	register char *p;
116006f25ae9SGregory Neil Shapiro 	register struct milter *m;
116106f25ae9SGregory Neil Shapiro 	STAB *s;
116206f25ae9SGregory Neil Shapiro 
116342e5d165SGregory Neil Shapiro 	/* collect the filter name */
116406f25ae9SGregory Neil Shapiro 	for (p = line;
116506f25ae9SGregory Neil Shapiro 	     *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p));
116606f25ae9SGregory Neil Shapiro 	     p++)
116706f25ae9SGregory Neil Shapiro 		continue;
116806f25ae9SGregory Neil Shapiro 	if (*p != '\0')
116906f25ae9SGregory Neil Shapiro 		*p++ = '\0';
117006f25ae9SGregory Neil Shapiro 	if (line[0] == '\0')
117106f25ae9SGregory Neil Shapiro 	{
117206f25ae9SGregory Neil Shapiro 		syserr("name required for mail filter");
117306f25ae9SGregory Neil Shapiro 		return;
117406f25ae9SGregory Neil Shapiro 	}
117506f25ae9SGregory Neil Shapiro 	m = (struct milter *) xalloc(sizeof *m);
117606f25ae9SGregory Neil Shapiro 	memset((char *) m, '\0', sizeof *m);
117706f25ae9SGregory Neil Shapiro 	m->mf_name = newstr(line);
117806f25ae9SGregory Neil Shapiro 	m->mf_state = SMFS_READY;
117906f25ae9SGregory Neil Shapiro 	m->mf_sock = -1;
118040266059SGregory Neil Shapiro 	m->mf_timeout[SMFTO_CONNECT] = (time_t) 300;
118106f25ae9SGregory Neil Shapiro 	m->mf_timeout[SMFTO_WRITE] = (time_t) 10;
118206f25ae9SGregory Neil Shapiro 	m->mf_timeout[SMFTO_READ] = (time_t) 10;
118306f25ae9SGregory Neil Shapiro 	m->mf_timeout[SMFTO_EOM] = (time_t) 300;
118406f25ae9SGregory Neil Shapiro 
118506f25ae9SGregory Neil Shapiro 	/* now scan through and assign info from the fields */
118606f25ae9SGregory Neil Shapiro 	while (*p != '\0')
118706f25ae9SGregory Neil Shapiro 	{
118806f25ae9SGregory Neil Shapiro 		char *delimptr;
118906f25ae9SGregory Neil Shapiro 
119006f25ae9SGregory Neil Shapiro 		while (*p != '\0' &&
119106f25ae9SGregory Neil Shapiro 		       (*p == ',' || (isascii(*p) && isspace(*p))))
119206f25ae9SGregory Neil Shapiro 			p++;
119306f25ae9SGregory Neil Shapiro 
119406f25ae9SGregory Neil Shapiro 		/* p now points to field code */
119506f25ae9SGregory Neil Shapiro 		fcode = *p;
119606f25ae9SGregory Neil Shapiro 		while (*p != '\0' && *p != '=' && *p != ',')
119706f25ae9SGregory Neil Shapiro 			p++;
119806f25ae9SGregory Neil Shapiro 		if (*p++ != '=')
119906f25ae9SGregory Neil Shapiro 		{
120006f25ae9SGregory Neil Shapiro 			syserr("X%s: `=' expected", m->mf_name);
120106f25ae9SGregory Neil Shapiro 			return;
120206f25ae9SGregory Neil Shapiro 		}
120306f25ae9SGregory Neil Shapiro 		while (isascii(*p) && isspace(*p))
120406f25ae9SGregory Neil Shapiro 			p++;
120506f25ae9SGregory Neil Shapiro 
120606f25ae9SGregory Neil Shapiro 		/* p now points to the field body */
120706f25ae9SGregory Neil Shapiro 		p = munchstring(p, &delimptr, ',');
120806f25ae9SGregory Neil Shapiro 
120942e5d165SGregory Neil Shapiro 		/* install the field into the filter struct */
121006f25ae9SGregory Neil Shapiro 		switch (fcode)
121106f25ae9SGregory Neil Shapiro 		{
121206f25ae9SGregory Neil Shapiro 		  case 'S':		/* socket */
121306f25ae9SGregory Neil Shapiro 			if (p == NULL)
121406f25ae9SGregory Neil Shapiro 				m->mf_conn = NULL;
121506f25ae9SGregory Neil Shapiro 			else
121606f25ae9SGregory Neil Shapiro 				m->mf_conn = newstr(p);
121706f25ae9SGregory Neil Shapiro 			break;
121806f25ae9SGregory Neil Shapiro 
121906f25ae9SGregory Neil Shapiro 		  case 'F':		/* Milter flags configured on MTA */
122006f25ae9SGregory Neil Shapiro 			for (; *p != '\0'; p++)
122106f25ae9SGregory Neil Shapiro 			{
122206f25ae9SGregory Neil Shapiro 				if (!(isascii(*p) && isspace(*p)))
1223193538b7SGregory Neil Shapiro 					setbitn(bitidx(*p), m->mf_flags);
122406f25ae9SGregory Neil Shapiro 			}
122506f25ae9SGregory Neil Shapiro 			break;
122606f25ae9SGregory Neil Shapiro 
122706f25ae9SGregory Neil Shapiro 		  case 'T':		/* timeouts */
122806f25ae9SGregory Neil Shapiro 			milter_parse_timeouts(p, m);
122906f25ae9SGregory Neil Shapiro 			break;
123006f25ae9SGregory Neil Shapiro 
123106f25ae9SGregory Neil Shapiro 		  default:
123206f25ae9SGregory Neil Shapiro 			syserr("X%s: unknown filter equate %c=",
123306f25ae9SGregory Neil Shapiro 			       m->mf_name, fcode);
123406f25ae9SGregory Neil Shapiro 			break;
123506f25ae9SGregory Neil Shapiro 		}
123606f25ae9SGregory Neil Shapiro 		p = delimptr;
123706f25ae9SGregory Neil Shapiro 	}
123806f25ae9SGregory Neil Shapiro 
123906f25ae9SGregory Neil Shapiro 	/* early check for errors */
124040266059SGregory Neil Shapiro 	(void) milter_open(m, true, CurEnv);
124106f25ae9SGregory Neil Shapiro 
124242e5d165SGregory Neil Shapiro 	/* enter the filter into the symbol table */
124306f25ae9SGregory Neil Shapiro 	s = stab(m->mf_name, ST_MILTER, ST_ENTER);
124406f25ae9SGregory Neil Shapiro 	if (s->s_milter != NULL)
124506f25ae9SGregory Neil Shapiro 		syserr("X%s: duplicate filter definition", m->mf_name);
124606f25ae9SGregory Neil Shapiro 	else
124706f25ae9SGregory Neil Shapiro 		s->s_milter = m;
124806f25ae9SGregory Neil Shapiro }
124940266059SGregory Neil Shapiro /*
125040266059SGregory Neil Shapiro **  MILTER_CONFIG -- parse option list into an array and check config
125106f25ae9SGregory Neil Shapiro **
125206f25ae9SGregory Neil Shapiro **	Called when reading configuration file.
125306f25ae9SGregory Neil Shapiro **
125406f25ae9SGregory Neil Shapiro **	Parameters:
125506f25ae9SGregory Neil Shapiro **		spec -- the filter list.
125606f25ae9SGregory Neil Shapiro **		list -- the array to fill in.
125706f25ae9SGregory Neil Shapiro **		max -- the maximum number of entries in list.
125806f25ae9SGregory Neil Shapiro **
125906f25ae9SGregory Neil Shapiro **	Returns:
126006f25ae9SGregory Neil Shapiro **		none
126106f25ae9SGregory Neil Shapiro */
126206f25ae9SGregory Neil Shapiro 
126306f25ae9SGregory Neil Shapiro void
126440266059SGregory Neil Shapiro milter_config(spec, list, max)
126506f25ae9SGregory Neil Shapiro 	char *spec;
126606f25ae9SGregory Neil Shapiro 	struct milter **list;
126706f25ae9SGregory Neil Shapiro 	int max;
126806f25ae9SGregory Neil Shapiro {
126906f25ae9SGregory Neil Shapiro 	int numitems = 0;
127006f25ae9SGregory Neil Shapiro 	register char *p;
127106f25ae9SGregory Neil Shapiro 
127206f25ae9SGregory Neil Shapiro 	/* leave one for the NULL signifying the end of the list */
127306f25ae9SGregory Neil Shapiro 	max--;
127406f25ae9SGregory Neil Shapiro 
127506f25ae9SGregory Neil Shapiro 	for (p = spec; p != NULL; )
127606f25ae9SGregory Neil Shapiro 	{
127706f25ae9SGregory Neil Shapiro 		STAB *s;
127806f25ae9SGregory Neil Shapiro 
127906f25ae9SGregory Neil Shapiro 		while (isascii(*p) && isspace(*p))
128006f25ae9SGregory Neil Shapiro 			p++;
128106f25ae9SGregory Neil Shapiro 		if (*p == '\0')
128206f25ae9SGregory Neil Shapiro 			break;
128306f25ae9SGregory Neil Shapiro 		spec = p;
128406f25ae9SGregory Neil Shapiro 
128506f25ae9SGregory Neil Shapiro 		if (numitems >= max)
128606f25ae9SGregory Neil Shapiro 		{
128706f25ae9SGregory Neil Shapiro 			syserr("Too many filters defined, %d max", max);
128806f25ae9SGregory Neil Shapiro 			if (max > 0)
128906f25ae9SGregory Neil Shapiro 				list[0] = NULL;
129006f25ae9SGregory Neil Shapiro 			return;
129106f25ae9SGregory Neil Shapiro 		}
129240266059SGregory Neil Shapiro 		p = strpbrk(p, ";,");
129306f25ae9SGregory Neil Shapiro 		if (p != NULL)
129406f25ae9SGregory Neil Shapiro 			*p++ = '\0';
129506f25ae9SGregory Neil Shapiro 
129606f25ae9SGregory Neil Shapiro 		s = stab(spec, ST_MILTER, ST_FIND);
129706f25ae9SGregory Neil Shapiro 		if (s == NULL)
129806f25ae9SGregory Neil Shapiro 		{
129906f25ae9SGregory Neil Shapiro 			syserr("InputFilter %s not defined", spec);
130006f25ae9SGregory Neil Shapiro 			ExitStat = EX_CONFIG;
130106f25ae9SGregory Neil Shapiro 			return;
130206f25ae9SGregory Neil Shapiro 		}
130306f25ae9SGregory Neil Shapiro 		list[numitems++] = s->s_milter;
130406f25ae9SGregory Neil Shapiro 	}
130506f25ae9SGregory Neil Shapiro 	list[numitems] = NULL;
130640266059SGregory Neil Shapiro 
130740266059SGregory Neil Shapiro 	/* if not set, set to LogLevel */
130840266059SGregory Neil Shapiro 	if (MilterLogLevel == -1)
130940266059SGregory Neil Shapiro 		MilterLogLevel = LogLevel;
131006f25ae9SGregory Neil Shapiro }
131140266059SGregory Neil Shapiro /*
131206f25ae9SGregory Neil Shapiro **  MILTER_PARSE_TIMEOUTS -- parse timeout list
131306f25ae9SGregory Neil Shapiro **
131406f25ae9SGregory Neil Shapiro **	Called when reading configuration file.
131506f25ae9SGregory Neil Shapiro **
131606f25ae9SGregory Neil Shapiro **	Parameters:
131706f25ae9SGregory Neil Shapiro **		spec -- the timeout list.
131806f25ae9SGregory Neil Shapiro **		m -- milter to set.
131906f25ae9SGregory Neil Shapiro **
132006f25ae9SGregory Neil Shapiro **	Returns:
132106f25ae9SGregory Neil Shapiro **		none
132206f25ae9SGregory Neil Shapiro */
132306f25ae9SGregory Neil Shapiro 
132406f25ae9SGregory Neil Shapiro static void
132506f25ae9SGregory Neil Shapiro milter_parse_timeouts(spec, m)
132606f25ae9SGregory Neil Shapiro 	char *spec;
132706f25ae9SGregory Neil Shapiro 	struct milter *m;
132806f25ae9SGregory Neil Shapiro {
132906f25ae9SGregory Neil Shapiro 	char fcode;
1330e92d3f3fSGregory Neil Shapiro 	int tcode;
133106f25ae9SGregory Neil Shapiro 	register char *p;
133206f25ae9SGregory Neil Shapiro 
133306f25ae9SGregory Neil Shapiro 	p = spec;
133406f25ae9SGregory Neil Shapiro 
133506f25ae9SGregory Neil Shapiro 	/* now scan through and assign info from the fields */
133606f25ae9SGregory Neil Shapiro 	while (*p != '\0')
133706f25ae9SGregory Neil Shapiro 	{
133806f25ae9SGregory Neil Shapiro 		char *delimptr;
133906f25ae9SGregory Neil Shapiro 
134006f25ae9SGregory Neil Shapiro 		while (*p != '\0' &&
134106f25ae9SGregory Neil Shapiro 		       (*p == ';' || (isascii(*p) && isspace(*p))))
134206f25ae9SGregory Neil Shapiro 			p++;
134306f25ae9SGregory Neil Shapiro 
134406f25ae9SGregory Neil Shapiro 		/* p now points to field code */
134506f25ae9SGregory Neil Shapiro 		fcode = *p;
134606f25ae9SGregory Neil Shapiro 		while (*p != '\0' && *p != ':')
134706f25ae9SGregory Neil Shapiro 			p++;
134806f25ae9SGregory Neil Shapiro 		if (*p++ != ':')
134906f25ae9SGregory Neil Shapiro 		{
135006f25ae9SGregory Neil Shapiro 			syserr("X%s, T=: `:' expected", m->mf_name);
135106f25ae9SGregory Neil Shapiro 			return;
135206f25ae9SGregory Neil Shapiro 		}
135306f25ae9SGregory Neil Shapiro 		while (isascii(*p) && isspace(*p))
135406f25ae9SGregory Neil Shapiro 			p++;
135506f25ae9SGregory Neil Shapiro 
135606f25ae9SGregory Neil Shapiro 		/* p now points to the field body */
135706f25ae9SGregory Neil Shapiro 		p = munchstring(p, &delimptr, ';');
1358e92d3f3fSGregory Neil Shapiro 		tcode = -1;
135906f25ae9SGregory Neil Shapiro 
136042e5d165SGregory Neil Shapiro 		/* install the field into the filter struct */
136106f25ae9SGregory Neil Shapiro 		switch (fcode)
136206f25ae9SGregory Neil Shapiro 		{
1363c86d5965SGregory Neil Shapiro 		  case 'C':
1364e92d3f3fSGregory Neil Shapiro 			tcode = SMFTO_CONNECT;
1365c86d5965SGregory Neil Shapiro 			break;
1366c86d5965SGregory Neil Shapiro 
136706f25ae9SGregory Neil Shapiro 		  case 'S':
1368e92d3f3fSGregory Neil Shapiro 			tcode = SMFTO_WRITE;
136906f25ae9SGregory Neil Shapiro 			break;
137006f25ae9SGregory Neil Shapiro 
137106f25ae9SGregory Neil Shapiro 		  case 'R':
1372e92d3f3fSGregory Neil Shapiro 			tcode = SMFTO_READ;
137306f25ae9SGregory Neil Shapiro 			break;
137406f25ae9SGregory Neil Shapiro 
137506f25ae9SGregory Neil Shapiro 		  case 'E':
1376e92d3f3fSGregory Neil Shapiro 			tcode = SMFTO_EOM;
137706f25ae9SGregory Neil Shapiro 			break;
137806f25ae9SGregory Neil Shapiro 
137906f25ae9SGregory Neil Shapiro 		  default:
138006f25ae9SGregory Neil Shapiro 			if (tTd(64, 5))
138140266059SGregory Neil Shapiro 				sm_dprintf("X%s: %c unknown\n",
138206f25ae9SGregory Neil Shapiro 					   m->mf_name, fcode);
138306f25ae9SGregory Neil Shapiro 			syserr("X%s: unknown filter timeout %c",
138406f25ae9SGregory Neil Shapiro 			       m->mf_name, fcode);
138506f25ae9SGregory Neil Shapiro 			break;
138606f25ae9SGregory Neil Shapiro 		}
1387e92d3f3fSGregory Neil Shapiro 		if (tcode >= 0)
1388e92d3f3fSGregory Neil Shapiro 		{
1389e92d3f3fSGregory Neil Shapiro 			m->mf_timeout[tcode] = convtime(p, 's');
1390e92d3f3fSGregory Neil Shapiro 			if (tTd(64, 5))
1391e92d3f3fSGregory Neil Shapiro 				sm_dprintf("X%s: %c=%ld\n",
1392e92d3f3fSGregory Neil Shapiro 					   m->mf_name, fcode,
1393e92d3f3fSGregory Neil Shapiro 					   (u_long) m->mf_timeout[tcode]);
1394e92d3f3fSGregory Neil Shapiro 		}
139506f25ae9SGregory Neil Shapiro 		p = delimptr;
139606f25ae9SGregory Neil Shapiro 	}
139706f25ae9SGregory Neil Shapiro }
139840266059SGregory Neil Shapiro /*
139906f25ae9SGregory Neil Shapiro **  MILTER_SET_OPTION -- set an individual milter option
140006f25ae9SGregory Neil Shapiro **
140106f25ae9SGregory Neil Shapiro **	Parameters:
140206f25ae9SGregory Neil Shapiro **		name -- the name of the option.
140306f25ae9SGregory Neil Shapiro **		val -- the value of the option.
140406f25ae9SGregory Neil Shapiro **		sticky -- if set, don't let other setoptions override
140506f25ae9SGregory Neil Shapiro **			this value.
140606f25ae9SGregory Neil Shapiro **
140706f25ae9SGregory Neil Shapiro **	Returns:
140806f25ae9SGregory Neil Shapiro **		none.
140906f25ae9SGregory Neil Shapiro */
141006f25ae9SGregory Neil Shapiro 
141106f25ae9SGregory Neil Shapiro /* set if Milter sub-option is stuck */
141206f25ae9SGregory Neil Shapiro static BITMAP256	StickyMilterOpt;
141306f25ae9SGregory Neil Shapiro 
141406f25ae9SGregory Neil Shapiro static struct milteropt
141506f25ae9SGregory Neil Shapiro {
141606f25ae9SGregory Neil Shapiro 	char		*mo_name;	/* long name of milter option */
141740266059SGregory Neil Shapiro 	unsigned char	mo_code;	/* code for option */
141806f25ae9SGregory Neil Shapiro } MilterOptTab[] =
141906f25ae9SGregory Neil Shapiro {
142006f25ae9SGregory Neil Shapiro # define MO_MACROS_CONNECT		0x01
142106f25ae9SGregory Neil Shapiro 	{ "macros.connect",		MO_MACROS_CONNECT		},
142206f25ae9SGregory Neil Shapiro # define MO_MACROS_HELO			0x02
142306f25ae9SGregory Neil Shapiro 	{ "macros.helo",		MO_MACROS_HELO			},
142406f25ae9SGregory Neil Shapiro # define MO_MACROS_ENVFROM		0x03
142506f25ae9SGregory Neil Shapiro 	{ "macros.envfrom",		MO_MACROS_ENVFROM		},
142606f25ae9SGregory Neil Shapiro # define MO_MACROS_ENVRCPT		0x04
142706f25ae9SGregory Neil Shapiro 	{ "macros.envrcpt",		MO_MACROS_ENVRCPT		},
1428e92d3f3fSGregory Neil Shapiro # define MO_MACROS_DATA			0x05
1429e92d3f3fSGregory Neil Shapiro 	{ "macros.data",		MO_MACROS_DATA			},
1430323f6dcbSGregory Neil Shapiro # define MO_MACROS_EOM			0x06
1431323f6dcbSGregory Neil Shapiro 	{ "macros.eom",			MO_MACROS_EOM			},
1432e92d3f3fSGregory Neil Shapiro # define MO_LOGLEVEL			0x07
1433e92d3f3fSGregory Neil Shapiro 	{ "loglevel",			MO_LOGLEVEL			},
1434e92d3f3fSGregory Neil Shapiro # if _FFR_MAXDATASIZE
1435e92d3f3fSGregory Neil Shapiro #  define MO_MAXDATASIZE			0x08
1436e92d3f3fSGregory Neil Shapiro 	{ "maxdatasize",		MO_MAXDATASIZE			},
1437e92d3f3fSGregory Neil Shapiro # endif /* _FFR_MAXDATASIZE */
143806f25ae9SGregory Neil Shapiro 	{ NULL,				0				},
143906f25ae9SGregory Neil Shapiro };
144006f25ae9SGregory Neil Shapiro 
144106f25ae9SGregory Neil Shapiro void
144206f25ae9SGregory Neil Shapiro milter_set_option(name, val, sticky)
144306f25ae9SGregory Neil Shapiro 	char *name;
144406f25ae9SGregory Neil Shapiro 	char *val;
144506f25ae9SGregory Neil Shapiro 	bool sticky;
144606f25ae9SGregory Neil Shapiro {
144706f25ae9SGregory Neil Shapiro 	int nummac = 0;
144806f25ae9SGregory Neil Shapiro 	register struct milteropt *mo;
144906f25ae9SGregory Neil Shapiro 	char *p;
145006f25ae9SGregory Neil Shapiro 	char **macros = NULL;
145106f25ae9SGregory Neil Shapiro 
145206f25ae9SGregory Neil Shapiro 	if (tTd(37, 2) || tTd(64, 5))
145340266059SGregory Neil Shapiro 		sm_dprintf("milter_set_option(%s = %s)", name, val);
145406f25ae9SGregory Neil Shapiro 
1455739ac4d4SGregory Neil Shapiro 	if (name == NULL)
1456739ac4d4SGregory Neil Shapiro 	{
1457739ac4d4SGregory Neil Shapiro 		syserr("milter_set_option: invalid Milter option, must specify suboption");
1458739ac4d4SGregory Neil Shapiro 		return;
1459739ac4d4SGregory Neil Shapiro 	}
1460739ac4d4SGregory Neil Shapiro 
146106f25ae9SGregory Neil Shapiro 	for (mo = MilterOptTab; mo->mo_name != NULL; mo++)
146206f25ae9SGregory Neil Shapiro 	{
146340266059SGregory Neil Shapiro 		if (sm_strcasecmp(mo->mo_name, name) == 0)
146406f25ae9SGregory Neil Shapiro 			break;
146506f25ae9SGregory Neil Shapiro 	}
146606f25ae9SGregory Neil Shapiro 
146706f25ae9SGregory Neil Shapiro 	if (mo->mo_name == NULL)
146840266059SGregory Neil Shapiro 	{
146906f25ae9SGregory Neil Shapiro 		syserr("milter_set_option: invalid Milter option %s", name);
147040266059SGregory Neil Shapiro 		return;
147140266059SGregory Neil Shapiro 	}
147206f25ae9SGregory Neil Shapiro 
147306f25ae9SGregory Neil Shapiro 	/*
147406f25ae9SGregory Neil Shapiro 	**  See if this option is preset for us.
147506f25ae9SGregory Neil Shapiro 	*/
147606f25ae9SGregory Neil Shapiro 
147706f25ae9SGregory Neil Shapiro 	if (!sticky && bitnset(mo->mo_code, StickyMilterOpt))
147806f25ae9SGregory Neil Shapiro 	{
147906f25ae9SGregory Neil Shapiro 		if (tTd(37, 2) || tTd(64,5))
148040266059SGregory Neil Shapiro 			sm_dprintf(" (ignored)\n");
148106f25ae9SGregory Neil Shapiro 		return;
148206f25ae9SGregory Neil Shapiro 	}
148306f25ae9SGregory Neil Shapiro 
148406f25ae9SGregory Neil Shapiro 	if (tTd(37, 2) || tTd(64,5))
148540266059SGregory Neil Shapiro 		sm_dprintf("\n");
148606f25ae9SGregory Neil Shapiro 
148706f25ae9SGregory Neil Shapiro 	switch (mo->mo_code)
148806f25ae9SGregory Neil Shapiro 	{
148940266059SGregory Neil Shapiro 	  case MO_LOGLEVEL:
149040266059SGregory Neil Shapiro 		MilterLogLevel = atoi(val);
149140266059SGregory Neil Shapiro 		break;
149240266059SGregory Neil Shapiro 
1493e92d3f3fSGregory Neil Shapiro #if _FFR_MAXDATASIZE
1494e92d3f3fSGregory Neil Shapiro 	  case MO_MAXDATASIZE:
1495e92d3f3fSGregory Neil Shapiro 		MilterMaxDataSize = (size_t)atol(val);
1496e92d3f3fSGregory Neil Shapiro 		break;
1497e92d3f3fSGregory Neil Shapiro #endif /* _FFR_MAXDATASIZE */
1498e92d3f3fSGregory Neil Shapiro 
149906f25ae9SGregory Neil Shapiro 	  case MO_MACROS_CONNECT:
150006f25ae9SGregory Neil Shapiro 		if (macros == NULL)
150106f25ae9SGregory Neil Shapiro 			macros = MilterConnectMacros;
150206f25ae9SGregory Neil Shapiro 		/* FALLTHROUGH */
150306f25ae9SGregory Neil Shapiro 
150406f25ae9SGregory Neil Shapiro 	  case MO_MACROS_HELO:
150506f25ae9SGregory Neil Shapiro 		if (macros == NULL)
150606f25ae9SGregory Neil Shapiro 			macros = MilterHeloMacros;
150706f25ae9SGregory Neil Shapiro 		/* FALLTHROUGH */
150806f25ae9SGregory Neil Shapiro 
150906f25ae9SGregory Neil Shapiro 	  case MO_MACROS_ENVFROM:
151006f25ae9SGregory Neil Shapiro 		if (macros == NULL)
151106f25ae9SGregory Neil Shapiro 			macros = MilterEnvFromMacros;
151206f25ae9SGregory Neil Shapiro 		/* FALLTHROUGH */
151306f25ae9SGregory Neil Shapiro 
151406f25ae9SGregory Neil Shapiro 	  case MO_MACROS_ENVRCPT:
151506f25ae9SGregory Neil Shapiro 		if (macros == NULL)
151606f25ae9SGregory Neil Shapiro 			macros = MilterEnvRcptMacros;
1517323f6dcbSGregory Neil Shapiro 		/* FALLTHROUGH */
1518323f6dcbSGregory Neil Shapiro 
1519323f6dcbSGregory Neil Shapiro 	  case MO_MACROS_EOM:
1520323f6dcbSGregory Neil Shapiro 		if (macros == NULL)
1521323f6dcbSGregory Neil Shapiro 			macros = MilterEOMMacros;
1522e92d3f3fSGregory Neil Shapiro 		/* FALLTHROUGH */
1523e92d3f3fSGregory Neil Shapiro 
1524e92d3f3fSGregory Neil Shapiro 	  case MO_MACROS_DATA:
1525e92d3f3fSGregory Neil Shapiro 		if (macros == NULL)
1526e92d3f3fSGregory Neil Shapiro 			macros = MilterDataMacros;
152706f25ae9SGregory Neil Shapiro 
152806f25ae9SGregory Neil Shapiro 		p = newstr(val);
152906f25ae9SGregory Neil Shapiro 		while (*p != '\0')
153006f25ae9SGregory Neil Shapiro 		{
153106f25ae9SGregory Neil Shapiro 			char *macro;
153206f25ae9SGregory Neil Shapiro 
153306f25ae9SGregory Neil Shapiro 			/* Skip leading commas, spaces */
153406f25ae9SGregory Neil Shapiro 			while (*p != '\0' &&
153506f25ae9SGregory Neil Shapiro 			       (*p == ',' || (isascii(*p) && isspace(*p))))
153606f25ae9SGregory Neil Shapiro 				p++;
153706f25ae9SGregory Neil Shapiro 
153806f25ae9SGregory Neil Shapiro 			if (*p == '\0')
153906f25ae9SGregory Neil Shapiro 				break;
154006f25ae9SGregory Neil Shapiro 
154106f25ae9SGregory Neil Shapiro 			/* Find end of macro */
154206f25ae9SGregory Neil Shapiro 			macro = p;
154306f25ae9SGregory Neil Shapiro 			while (*p != '\0' && *p != ',' &&
154406f25ae9SGregory Neil Shapiro 			       isascii(*p) && !isspace(*p))
154506f25ae9SGregory Neil Shapiro 				p++;
154606f25ae9SGregory Neil Shapiro 			if (*p != '\0')
154706f25ae9SGregory Neil Shapiro 				*p++ = '\0';
154806f25ae9SGregory Neil Shapiro 
154906f25ae9SGregory Neil Shapiro 			if (nummac >= MAXFILTERMACROS)
155006f25ae9SGregory Neil Shapiro 			{
155106f25ae9SGregory Neil Shapiro 				syserr("milter_set_option: too many macros in Milter.%s (max %d)",
155206f25ae9SGregory Neil Shapiro 				       name, MAXFILTERMACROS);
155306f25ae9SGregory Neil Shapiro 				macros[nummac] = NULL;
155406f25ae9SGregory Neil Shapiro 				break;
155506f25ae9SGregory Neil Shapiro 			}
155606f25ae9SGregory Neil Shapiro 			macros[nummac++] = macro;
155706f25ae9SGregory Neil Shapiro 		}
155806f25ae9SGregory Neil Shapiro 		macros[nummac] = NULL;
155906f25ae9SGregory Neil Shapiro 		break;
156006f25ae9SGregory Neil Shapiro 
156106f25ae9SGregory Neil Shapiro 	  default:
156206f25ae9SGregory Neil Shapiro 		syserr("milter_set_option: invalid Milter option %s", name);
156306f25ae9SGregory Neil Shapiro 		break;
156406f25ae9SGregory Neil Shapiro 	}
156506f25ae9SGregory Neil Shapiro 	if (sticky)
156606f25ae9SGregory Neil Shapiro 		setbitn(mo->mo_code, StickyMilterOpt);
156706f25ae9SGregory Neil Shapiro }
156840266059SGregory Neil Shapiro /*
156940266059SGregory Neil Shapiro **  MILTER_REOPEN_DF -- open & truncate the data file (for replbody)
157006f25ae9SGregory Neil Shapiro **
157106f25ae9SGregory Neil Shapiro **	Parameters:
157206f25ae9SGregory Neil Shapiro **		e -- current envelope.
157306f25ae9SGregory Neil Shapiro **
157406f25ae9SGregory Neil Shapiro **	Returns:
157506f25ae9SGregory Neil Shapiro **		0 if succesful, -1 otherwise
157606f25ae9SGregory Neil Shapiro */
157706f25ae9SGregory Neil Shapiro 
157806f25ae9SGregory Neil Shapiro static int
157906f25ae9SGregory Neil Shapiro milter_reopen_df(e)
158006f25ae9SGregory Neil Shapiro 	ENVELOPE *e;
158106f25ae9SGregory Neil Shapiro {
158206f25ae9SGregory Neil Shapiro 	char dfname[MAXPATHLEN];
158306f25ae9SGregory Neil Shapiro 
158440266059SGregory Neil Shapiro 	(void) sm_strlcpy(dfname, queuename(e, DATAFL_LETTER), sizeof dfname);
158506f25ae9SGregory Neil Shapiro 
158606f25ae9SGregory Neil Shapiro 	/*
158740266059SGregory Neil Shapiro 	**  In SuperSafe == SAFE_REALLY mode, e->e_dfp is a read-only FP so
158806f25ae9SGregory Neil Shapiro 	**  close and reopen writable (later close and reopen
158906f25ae9SGregory Neil Shapiro 	**  read only again).
159006f25ae9SGregory Neil Shapiro 	**
159140266059SGregory Neil Shapiro 	**  In SuperSafe != SAFE_REALLY mode, e->e_dfp still points at the
1592e92d3f3fSGregory Neil Shapiro 	**  buffered file I/O descriptor, still open for writing so there
1593e92d3f3fSGregory Neil Shapiro 	**  isn't any work to do here (except checking for consistency).
159406f25ae9SGregory Neil Shapiro 	*/
159506f25ae9SGregory Neil Shapiro 
159640266059SGregory Neil Shapiro 	if (SuperSafe == SAFE_REALLY)
159706f25ae9SGregory Neil Shapiro 	{
159840266059SGregory Neil Shapiro 		/* close read-only data file */
159906f25ae9SGregory Neil Shapiro 		if (bitset(EF_HAS_DF, e->e_flags) && e->e_dfp != NULL)
160006f25ae9SGregory Neil Shapiro 		{
160140266059SGregory Neil Shapiro 			(void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT);
160206f25ae9SGregory Neil Shapiro 			e->e_flags &= ~EF_HAS_DF;
160306f25ae9SGregory Neil Shapiro 		}
160406f25ae9SGregory Neil Shapiro 
160506f25ae9SGregory Neil Shapiro 		/* open writable */
160640266059SGregory Neil Shapiro 		if ((e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname,
1607a7ec597cSGregory Neil Shapiro 					   SM_IO_RDWR_B, NULL)) == NULL)
160806f25ae9SGregory Neil Shapiro 		{
160940266059SGregory Neil Shapiro 			MILTER_DF_ERROR("milter_reopen_df: sm_io_open %s: %s");
161006f25ae9SGregory Neil Shapiro 			return -1;
161106f25ae9SGregory Neil Shapiro 		}
161206f25ae9SGregory Neil Shapiro 	}
161306f25ae9SGregory Neil Shapiro 	else if (e->e_dfp == NULL)
161406f25ae9SGregory Neil Shapiro 	{
161506f25ae9SGregory Neil Shapiro 		/* shouldn't happen */
161606f25ae9SGregory Neil Shapiro 		errno = ENOENT;
161706f25ae9SGregory Neil Shapiro 		MILTER_DF_ERROR("milter_reopen_df: NULL e_dfp (%s: %s)");
161806f25ae9SGregory Neil Shapiro 		return -1;
161906f25ae9SGregory Neil Shapiro 	}
162006f25ae9SGregory Neil Shapiro 	return 0;
162106f25ae9SGregory Neil Shapiro }
162240266059SGregory Neil Shapiro /*
162340266059SGregory Neil Shapiro **  MILTER_RESET_DF -- re-open read-only the data file (for replbody)
162406f25ae9SGregory Neil Shapiro **
162506f25ae9SGregory Neil Shapiro **	Parameters:
162606f25ae9SGregory Neil Shapiro **		e -- current envelope.
162706f25ae9SGregory Neil Shapiro **
162806f25ae9SGregory Neil Shapiro **	Returns:
162906f25ae9SGregory Neil Shapiro **		0 if succesful, -1 otherwise
163006f25ae9SGregory Neil Shapiro */
163106f25ae9SGregory Neil Shapiro 
163206f25ae9SGregory Neil Shapiro static int
163306f25ae9SGregory Neil Shapiro milter_reset_df(e)
163406f25ae9SGregory Neil Shapiro 	ENVELOPE *e;
163506f25ae9SGregory Neil Shapiro {
163606f25ae9SGregory Neil Shapiro 	int afd;
163706f25ae9SGregory Neil Shapiro 	char dfname[MAXPATHLEN];
163806f25ae9SGregory Neil Shapiro 
163940266059SGregory Neil Shapiro 	(void) sm_strlcpy(dfname, queuename(e, DATAFL_LETTER), sizeof dfname);
164006f25ae9SGregory Neil Shapiro 
164140266059SGregory Neil Shapiro 	if (sm_io_flush(e->e_dfp, SM_TIME_DEFAULT) != 0 ||
164240266059SGregory Neil Shapiro 	    sm_io_error(e->e_dfp))
164306f25ae9SGregory Neil Shapiro 	{
164406f25ae9SGregory Neil Shapiro 		MILTER_DF_ERROR("milter_reset_df: error writing/flushing %s: %s");
164506f25ae9SGregory Neil Shapiro 		return -1;
164606f25ae9SGregory Neil Shapiro 	}
164740266059SGregory Neil Shapiro 	else if (SuperSafe != SAFE_REALLY)
164806f25ae9SGregory Neil Shapiro 	{
164906f25ae9SGregory Neil Shapiro 		/* skip next few clauses */
165006f25ae9SGregory Neil Shapiro 		/* EMPTY */
165106f25ae9SGregory Neil Shapiro 	}
165240266059SGregory Neil Shapiro 	else if ((afd = sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD, NULL)) >= 0
165340266059SGregory Neil Shapiro 		 && fsync(afd) < 0)
165406f25ae9SGregory Neil Shapiro 	{
165506f25ae9SGregory Neil Shapiro 		MILTER_DF_ERROR("milter_reset_df: error sync'ing %s: %s");
165606f25ae9SGregory Neil Shapiro 		return -1;
165706f25ae9SGregory Neil Shapiro 	}
165840266059SGregory Neil Shapiro 	else if (sm_io_close(e->e_dfp, SM_TIME_DEFAULT) < 0)
165906f25ae9SGregory Neil Shapiro 	{
166006f25ae9SGregory Neil Shapiro 		MILTER_DF_ERROR("milter_reset_df: error closing %s: %s");
166106f25ae9SGregory Neil Shapiro 		return -1;
166206f25ae9SGregory Neil Shapiro 	}
166340266059SGregory Neil Shapiro 	else if ((e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname,
1664a7ec597cSGregory Neil Shapiro 					SM_IO_RDONLY_B, NULL)) == NULL)
166506f25ae9SGregory Neil Shapiro 	{
166606f25ae9SGregory Neil Shapiro 		MILTER_DF_ERROR("milter_reset_df: error reopening %s: %s");
166706f25ae9SGregory Neil Shapiro 		return -1;
166806f25ae9SGregory Neil Shapiro 	}
166906f25ae9SGregory Neil Shapiro 	else
167006f25ae9SGregory Neil Shapiro 		e->e_flags |= EF_HAS_DF;
167106f25ae9SGregory Neil Shapiro 	return 0;
167206f25ae9SGregory Neil Shapiro }
167340266059SGregory Neil Shapiro /*
167406f25ae9SGregory Neil Shapiro **  MILTER_CAN_DELRCPTS -- can any milter filters delete recipients?
167506f25ae9SGregory Neil Shapiro **
167606f25ae9SGregory Neil Shapiro **	Parameters:
167706f25ae9SGregory Neil Shapiro **		none
167806f25ae9SGregory Neil Shapiro **
167906f25ae9SGregory Neil Shapiro **	Returns:
168040266059SGregory Neil Shapiro **		true if any filter deletes recipients, false otherwise
168106f25ae9SGregory Neil Shapiro */
168206f25ae9SGregory Neil Shapiro 
168306f25ae9SGregory Neil Shapiro bool
168406f25ae9SGregory Neil Shapiro milter_can_delrcpts()
168506f25ae9SGregory Neil Shapiro {
168640266059SGregory Neil Shapiro 	bool can = false;
168706f25ae9SGregory Neil Shapiro 	int i;
168806f25ae9SGregory Neil Shapiro 
168906f25ae9SGregory Neil Shapiro 	if (tTd(64, 10))
169040266059SGregory Neil Shapiro 		sm_dprintf("milter_can_delrcpts:");
169106f25ae9SGregory Neil Shapiro 
169206f25ae9SGregory Neil Shapiro 	for (i = 0; InputFilters[i] != NULL; i++)
169306f25ae9SGregory Neil Shapiro 	{
169406f25ae9SGregory Neil Shapiro 		struct milter *m = InputFilters[i];
169506f25ae9SGregory Neil Shapiro 
169606f25ae9SGregory Neil Shapiro 		if (bitset(SMFIF_DELRCPT, m->mf_fflags))
169706f25ae9SGregory Neil Shapiro 		{
169840266059SGregory Neil Shapiro 			can = true;
169906f25ae9SGregory Neil Shapiro 			break;
170006f25ae9SGregory Neil Shapiro 		}
170106f25ae9SGregory Neil Shapiro 	}
170206f25ae9SGregory Neil Shapiro 	if (tTd(64, 10))
170340266059SGregory Neil Shapiro 		sm_dprintf("%s\n", can ? "true" : "false");
170406f25ae9SGregory Neil Shapiro 
170506f25ae9SGregory Neil Shapiro 	return can;
170606f25ae9SGregory Neil Shapiro }
170740266059SGregory Neil Shapiro /*
170806f25ae9SGregory Neil Shapiro **  MILTER_QUIT_FILTER -- close down a single filter
170906f25ae9SGregory Neil Shapiro **
171006f25ae9SGregory Neil Shapiro **	Parameters:
171106f25ae9SGregory Neil Shapiro **		m -- milter structure of filter to close down.
171206f25ae9SGregory Neil Shapiro **		e -- current envelope.
171306f25ae9SGregory Neil Shapiro **
171406f25ae9SGregory Neil Shapiro **	Returns:
171506f25ae9SGregory Neil Shapiro **		none
171606f25ae9SGregory Neil Shapiro */
171706f25ae9SGregory Neil Shapiro 
171806f25ae9SGregory Neil Shapiro static void
171906f25ae9SGregory Neil Shapiro milter_quit_filter(m, e)
172006f25ae9SGregory Neil Shapiro 	struct milter *m;
172106f25ae9SGregory Neil Shapiro 	ENVELOPE *e;
172206f25ae9SGregory Neil Shapiro {
172306f25ae9SGregory Neil Shapiro 	if (tTd(64, 10))
172440266059SGregory Neil Shapiro 		sm_dprintf("milter_quit_filter(%s)\n", m->mf_name);
172540266059SGregory Neil Shapiro 	if (MilterLogLevel > 18)
172640266059SGregory Neil Shapiro 		sm_syslog(LOG_INFO, e->e_id, "Milter (%s): quit filter",
172740266059SGregory Neil Shapiro 			  m->mf_name);
172806f25ae9SGregory Neil Shapiro 
172906f25ae9SGregory Neil Shapiro 	/* Never replace error state */
173006f25ae9SGregory Neil Shapiro 	if (m->mf_state == SMFS_ERROR)
173106f25ae9SGregory Neil Shapiro 		return;
173206f25ae9SGregory Neil Shapiro 
173306f25ae9SGregory Neil Shapiro 	if (m->mf_sock < 0 ||
173406f25ae9SGregory Neil Shapiro 	    m->mf_state == SMFS_CLOSED ||
173506f25ae9SGregory Neil Shapiro 	    m->mf_state == SMFS_READY)
173606f25ae9SGregory Neil Shapiro 	{
173706f25ae9SGregory Neil Shapiro 		m->mf_sock = -1;
173806f25ae9SGregory Neil Shapiro 		m->mf_state = SMFS_CLOSED;
173906f25ae9SGregory Neil Shapiro 		return;
174006f25ae9SGregory Neil Shapiro 	}
174106f25ae9SGregory Neil Shapiro 
174206f25ae9SGregory Neil Shapiro 	(void) milter_write(m, SMFIC_QUIT, (char *) NULL, 0,
174306f25ae9SGregory Neil Shapiro 			    m->mf_timeout[SMFTO_WRITE], e);
1744193538b7SGregory Neil Shapiro 	if (m->mf_sock >= 0)
1745193538b7SGregory Neil Shapiro 	{
174606f25ae9SGregory Neil Shapiro 		(void) close(m->mf_sock);
174706f25ae9SGregory Neil Shapiro 		m->mf_sock = -1;
1748193538b7SGregory Neil Shapiro 	}
174906f25ae9SGregory Neil Shapiro 	if (m->mf_state != SMFS_ERROR)
175006f25ae9SGregory Neil Shapiro 		m->mf_state = SMFS_CLOSED;
175106f25ae9SGregory Neil Shapiro }
175240266059SGregory Neil Shapiro /*
175306f25ae9SGregory Neil Shapiro **  MILTER_ABORT_FILTER -- tell filter to abort current message
175406f25ae9SGregory Neil Shapiro **
175506f25ae9SGregory Neil Shapiro **	Parameters:
175606f25ae9SGregory Neil Shapiro **		m -- milter structure of filter to abort.
175706f25ae9SGregory Neil Shapiro **		e -- current envelope.
175806f25ae9SGregory Neil Shapiro **
175906f25ae9SGregory Neil Shapiro **	Returns:
176006f25ae9SGregory Neil Shapiro **		none
176106f25ae9SGregory Neil Shapiro */
176206f25ae9SGregory Neil Shapiro 
176306f25ae9SGregory Neil Shapiro static void
176406f25ae9SGregory Neil Shapiro milter_abort_filter(m, e)
176506f25ae9SGregory Neil Shapiro 	struct milter *m;
176606f25ae9SGregory Neil Shapiro 	ENVELOPE *e;
176706f25ae9SGregory Neil Shapiro {
176806f25ae9SGregory Neil Shapiro 	if (tTd(64, 10))
176940266059SGregory Neil Shapiro 		sm_dprintf("milter_abort_filter(%s)\n", m->mf_name);
177040266059SGregory Neil Shapiro 	if (MilterLogLevel > 10)
177140266059SGregory Neil Shapiro 		sm_syslog(LOG_INFO, e->e_id, "Milter (%s): abort filter",
177240266059SGregory Neil Shapiro 			  m->mf_name);
177306f25ae9SGregory Neil Shapiro 
177406f25ae9SGregory Neil Shapiro 	if (m->mf_sock < 0 ||
177506f25ae9SGregory Neil Shapiro 	    m->mf_state != SMFS_INMSG)
177606f25ae9SGregory Neil Shapiro 		return;
177706f25ae9SGregory Neil Shapiro 
177806f25ae9SGregory Neil Shapiro 	(void) milter_write(m, SMFIC_ABORT, (char *) NULL, 0,
177906f25ae9SGregory Neil Shapiro 			    m->mf_timeout[SMFTO_WRITE], e);
178006f25ae9SGregory Neil Shapiro 	if (m->mf_state != SMFS_ERROR)
178106f25ae9SGregory Neil Shapiro 		m->mf_state = SMFS_DONE;
178206f25ae9SGregory Neil Shapiro }
178340266059SGregory Neil Shapiro /*
178406f25ae9SGregory Neil Shapiro **  MILTER_SEND_MACROS -- provide macros to the filters
178506f25ae9SGregory Neil Shapiro **
178606f25ae9SGregory Neil Shapiro **	Parameters:
178706f25ae9SGregory Neil Shapiro **		m -- milter to send macros to.
178806f25ae9SGregory Neil Shapiro **		macros -- macros to send for filter smfi_getsymval().
178906f25ae9SGregory Neil Shapiro **		cmd -- which command the macros are associated with.
179006f25ae9SGregory Neil Shapiro **		e -- current envelope (for macro access).
179106f25ae9SGregory Neil Shapiro **
179206f25ae9SGregory Neil Shapiro **	Returns:
179306f25ae9SGregory Neil Shapiro **		none
179406f25ae9SGregory Neil Shapiro */
179506f25ae9SGregory Neil Shapiro 
179606f25ae9SGregory Neil Shapiro static void
179706f25ae9SGregory Neil Shapiro milter_send_macros(m, macros, cmd, e)
179806f25ae9SGregory Neil Shapiro 	struct milter *m;
179906f25ae9SGregory Neil Shapiro 	char **macros;
180006f25ae9SGregory Neil Shapiro 	char cmd;
180106f25ae9SGregory Neil Shapiro 	ENVELOPE *e;
180206f25ae9SGregory Neil Shapiro {
180306f25ae9SGregory Neil Shapiro 	int i;
180406f25ae9SGregory Neil Shapiro 	int mid;
180506f25ae9SGregory Neil Shapiro 	char *v;
180606f25ae9SGregory Neil Shapiro 	char *buf, *bp;
18076a2f2ff3SGregory Neil Shapiro 	char exp[MAXLINE];
180806f25ae9SGregory Neil Shapiro 	ssize_t s;
180906f25ae9SGregory Neil Shapiro 
181006f25ae9SGregory Neil Shapiro 	/* sanity check */
181106f25ae9SGregory Neil Shapiro 	if (macros == NULL || macros[0] == NULL)
181206f25ae9SGregory Neil Shapiro 		return;
181306f25ae9SGregory Neil Shapiro 
181406f25ae9SGregory Neil Shapiro 	/* put together data */
181506f25ae9SGregory Neil Shapiro 	s = 1;			/* for the command character */
181606f25ae9SGregory Neil Shapiro 	for (i = 0; macros[i] != NULL; i++)
181706f25ae9SGregory Neil Shapiro 	{
181840266059SGregory Neil Shapiro 		mid = macid(macros[i]);
1819193538b7SGregory Neil Shapiro 		if (mid == 0)
182006f25ae9SGregory Neil Shapiro 			continue;
182106f25ae9SGregory Neil Shapiro 		v = macvalue(mid, e);
182206f25ae9SGregory Neil Shapiro 		if (v == NULL)
182306f25ae9SGregory Neil Shapiro 			continue;
18246a2f2ff3SGregory Neil Shapiro 		expand(v, exp, sizeof(exp), e);
18256a2f2ff3SGregory Neil Shapiro 		s += strlen(macros[i]) + 1 + strlen(exp) + 1;
182606f25ae9SGregory Neil Shapiro 	}
182706f25ae9SGregory Neil Shapiro 
182840266059SGregory Neil Shapiro 	if (s < 0)
182940266059SGregory Neil Shapiro 		return;
183040266059SGregory Neil Shapiro 
183106f25ae9SGregory Neil Shapiro 	buf = (char *) xalloc(s);
183206f25ae9SGregory Neil Shapiro 	bp = buf;
183306f25ae9SGregory Neil Shapiro 	*bp++ = cmd;
183406f25ae9SGregory Neil Shapiro 	for (i = 0; macros[i] != NULL; i++)
183506f25ae9SGregory Neil Shapiro 	{
183640266059SGregory Neil Shapiro 		mid = macid(macros[i]);
1837193538b7SGregory Neil Shapiro 		if (mid == 0)
183806f25ae9SGregory Neil Shapiro 			continue;
183906f25ae9SGregory Neil Shapiro 		v = macvalue(mid, e);
184006f25ae9SGregory Neil Shapiro 		if (v == NULL)
184106f25ae9SGregory Neil Shapiro 			continue;
18426a2f2ff3SGregory Neil Shapiro 		expand(v, exp, sizeof(exp), e);
184306f25ae9SGregory Neil Shapiro 
184406f25ae9SGregory Neil Shapiro 		if (tTd(64, 10))
184540266059SGregory Neil Shapiro 			sm_dprintf("milter_send_macros(%s, %c): %s=%s\n",
18466a2f2ff3SGregory Neil Shapiro 				m->mf_name, cmd, macros[i], exp);
184706f25ae9SGregory Neil Shapiro 
184840266059SGregory Neil Shapiro 		(void) sm_strlcpy(bp, macros[i], s - (bp - buf));
184906f25ae9SGregory Neil Shapiro 		bp += strlen(bp) + 1;
18506a2f2ff3SGregory Neil Shapiro 		(void) sm_strlcpy(bp, exp, s - (bp - buf));
185106f25ae9SGregory Neil Shapiro 		bp += strlen(bp) + 1;
185206f25ae9SGregory Neil Shapiro 	}
185306f25ae9SGregory Neil Shapiro 	(void) milter_write(m, SMFIC_MACRO, buf, s,
185406f25ae9SGregory Neil Shapiro 			    m->mf_timeout[SMFTO_WRITE], e);
185540266059SGregory Neil Shapiro 	sm_free(buf); /* XXX */
185606f25ae9SGregory Neil Shapiro }
185706f25ae9SGregory Neil Shapiro 
185840266059SGregory Neil Shapiro /*
185906f25ae9SGregory Neil Shapiro **  MILTER_SEND_COMMAND -- send a command and return the response for a filter
186006f25ae9SGregory Neil Shapiro **
186106f25ae9SGregory Neil Shapiro **	Parameters:
186206f25ae9SGregory Neil Shapiro **		m -- current milter filter
186306f25ae9SGregory Neil Shapiro **		command -- command to send.
186406f25ae9SGregory Neil Shapiro **		data -- optional command data.
186506f25ae9SGregory Neil Shapiro **		sz -- length of buf.
186606f25ae9SGregory Neil Shapiro **		e -- current envelope (for e->e_id).
186706f25ae9SGregory Neil Shapiro **		state -- return state word.
186806f25ae9SGregory Neil Shapiro **
186906f25ae9SGregory Neil Shapiro **	Returns:
187006f25ae9SGregory Neil Shapiro **		response string (may be NULL)
187106f25ae9SGregory Neil Shapiro */
187206f25ae9SGregory Neil Shapiro 
187306f25ae9SGregory Neil Shapiro static char *
187406f25ae9SGregory Neil Shapiro milter_send_command(m, command, data, sz, e, state)
187506f25ae9SGregory Neil Shapiro 	struct milter *m;
187606f25ae9SGregory Neil Shapiro 	char command;
187706f25ae9SGregory Neil Shapiro 	void *data;
187806f25ae9SGregory Neil Shapiro 	ssize_t sz;
187906f25ae9SGregory Neil Shapiro 	ENVELOPE *e;
188006f25ae9SGregory Neil Shapiro 	char *state;
188106f25ae9SGregory Neil Shapiro {
188206f25ae9SGregory Neil Shapiro 	char rcmd;
188306f25ae9SGregory Neil Shapiro 	ssize_t rlen;
188440266059SGregory Neil Shapiro 	unsigned long skipflag;
1885e92d3f3fSGregory Neil Shapiro #if _FFR_MILTER_NOHDR_RESP
1886e92d3f3fSGregory Neil Shapiro 	unsigned long norespflag = 0;
1887e92d3f3fSGregory Neil Shapiro #endif /* _FFR_MILTER_NOHDR_RESP */
188840266059SGregory Neil Shapiro 	char *action;
188906f25ae9SGregory Neil Shapiro 	char *defresponse;
189006f25ae9SGregory Neil Shapiro 	char *response;
189106f25ae9SGregory Neil Shapiro 
189206f25ae9SGregory Neil Shapiro 	if (tTd(64, 10))
189340266059SGregory Neil Shapiro 		sm_dprintf("milter_send_command(%s): cmd %c len %ld\n",
189406f25ae9SGregory Neil Shapiro 			m->mf_name, (char) command, (long) sz);
189506f25ae9SGregory Neil Shapiro 
189606f25ae9SGregory Neil Shapiro 	/* find skip flag and default failure */
189706f25ae9SGregory Neil Shapiro 	switch (command)
189806f25ae9SGregory Neil Shapiro 	{
189906f25ae9SGregory Neil Shapiro 	  case SMFIC_CONNECT:
190006f25ae9SGregory Neil Shapiro 		skipflag = SMFIP_NOCONNECT;
190140266059SGregory Neil Shapiro 		action = "connect";
190206f25ae9SGregory Neil Shapiro 		defresponse = "554 Command rejected";
190306f25ae9SGregory Neil Shapiro 		break;
190406f25ae9SGregory Neil Shapiro 
190506f25ae9SGregory Neil Shapiro 	  case SMFIC_HELO:
190606f25ae9SGregory Neil Shapiro 		skipflag = SMFIP_NOHELO;
190740266059SGregory Neil Shapiro 		action = "helo";
190806f25ae9SGregory Neil Shapiro 		defresponse = "550 Command rejected";
190906f25ae9SGregory Neil Shapiro 		break;
191006f25ae9SGregory Neil Shapiro 
191106f25ae9SGregory Neil Shapiro 	  case SMFIC_MAIL:
191206f25ae9SGregory Neil Shapiro 		skipflag = SMFIP_NOMAIL;
191340266059SGregory Neil Shapiro 		action = "mail";
191406f25ae9SGregory Neil Shapiro 		defresponse = "550 5.7.1 Command rejected";
191506f25ae9SGregory Neil Shapiro 		break;
191606f25ae9SGregory Neil Shapiro 
191706f25ae9SGregory Neil Shapiro 	  case SMFIC_RCPT:
191806f25ae9SGregory Neil Shapiro 		skipflag = SMFIP_NORCPT;
191940266059SGregory Neil Shapiro 		action = "rcpt";
192006f25ae9SGregory Neil Shapiro 		defresponse = "550 5.7.1 Command rejected";
192106f25ae9SGregory Neil Shapiro 		break;
192206f25ae9SGregory Neil Shapiro 
192306f25ae9SGregory Neil Shapiro 	  case SMFIC_HEADER:
192406f25ae9SGregory Neil Shapiro 		skipflag = SMFIP_NOHDRS;
1925e92d3f3fSGregory Neil Shapiro #if _FFR_MILTER_NOHDR_RESP
1926e92d3f3fSGregory Neil Shapiro 		norespflag = SMFIP_NOHREPL;
1927e92d3f3fSGregory Neil Shapiro #endif /* _FFR_MILTER_NOHDR_RESP */
192840266059SGregory Neil Shapiro 		action = "header";
192906f25ae9SGregory Neil Shapiro 		defresponse = "550 5.7.1 Command rejected";
193006f25ae9SGregory Neil Shapiro 		break;
193106f25ae9SGregory Neil Shapiro 
193206f25ae9SGregory Neil Shapiro 	  case SMFIC_BODY:
193306f25ae9SGregory Neil Shapiro 		skipflag = SMFIP_NOBODY;
193440266059SGregory Neil Shapiro 		action = "body";
193506f25ae9SGregory Neil Shapiro 		defresponse = "554 5.7.1 Command rejected";
193606f25ae9SGregory Neil Shapiro 		break;
193706f25ae9SGregory Neil Shapiro 
193806f25ae9SGregory Neil Shapiro 	  case SMFIC_EOH:
193906f25ae9SGregory Neil Shapiro 		skipflag = SMFIP_NOEOH;
194040266059SGregory Neil Shapiro 		action = "eoh";
194106f25ae9SGregory Neil Shapiro 		defresponse = "550 5.7.1 Command rejected";
194206f25ae9SGregory Neil Shapiro 		break;
194306f25ae9SGregory Neil Shapiro 
1944e92d3f3fSGregory Neil Shapiro #if SMFI_VERSION > 2
1945e92d3f3fSGregory Neil Shapiro 	  case SMFIC_UNKNOWN:
1946e92d3f3fSGregory Neil Shapiro 		action = "unknown";
1947e92d3f3fSGregory Neil Shapiro 		defresponse = "550 5.7.1 Command rejected";
1948e92d3f3fSGregory Neil Shapiro 		break;
1949e92d3f3fSGregory Neil Shapiro #endif /* SMFI_VERSION > 2 */
1950e92d3f3fSGregory Neil Shapiro 
195106f25ae9SGregory Neil Shapiro 	  case SMFIC_BODYEOB:
195206f25ae9SGregory Neil Shapiro 	  case SMFIC_OPTNEG:
195306f25ae9SGregory Neil Shapiro 	  case SMFIC_MACRO:
195406f25ae9SGregory Neil Shapiro 	  case SMFIC_ABORT:
195506f25ae9SGregory Neil Shapiro 	  case SMFIC_QUIT:
195606f25ae9SGregory Neil Shapiro 		/* NOTE: not handled by milter_send_command() */
195706f25ae9SGregory Neil Shapiro 		/* FALLTHROUGH */
195806f25ae9SGregory Neil Shapiro 
195906f25ae9SGregory Neil Shapiro 	  default:
196006f25ae9SGregory Neil Shapiro 		skipflag = 0;
196140266059SGregory Neil Shapiro 		action = "default";
196206f25ae9SGregory Neil Shapiro 		defresponse = "550 5.7.1 Command rejected";
196306f25ae9SGregory Neil Shapiro 		break;
196406f25ae9SGregory Neil Shapiro 	}
196506f25ae9SGregory Neil Shapiro 
196606f25ae9SGregory Neil Shapiro 	/* check if filter wants this command */
196706f25ae9SGregory Neil Shapiro 	if (skipflag != 0 &&
196806f25ae9SGregory Neil Shapiro 	    bitset(skipflag, m->mf_pflags))
196906f25ae9SGregory Neil Shapiro 		return NULL;
197006f25ae9SGregory Neil Shapiro 
197140266059SGregory Neil Shapiro 	/* send the command to the filter */
197206f25ae9SGregory Neil Shapiro 	(void) milter_write(m, command, data, sz,
197306f25ae9SGregory Neil Shapiro 			    m->mf_timeout[SMFTO_WRITE], e);
197406f25ae9SGregory Neil Shapiro 	if (m->mf_state == SMFS_ERROR)
197506f25ae9SGregory Neil Shapiro 	{
19765ef517c0SGregory Neil Shapiro 		MILTER_CHECK_ERROR(false, return NULL);
197706f25ae9SGregory Neil Shapiro 		return NULL;
197806f25ae9SGregory Neil Shapiro 	}
197906f25ae9SGregory Neil Shapiro 
1980e92d3f3fSGregory Neil Shapiro #if _FFR_MILTER_NOHDR_RESP
1981e92d3f3fSGregory Neil Shapiro 	/* check if filter sends response to this command */
1982e92d3f3fSGregory Neil Shapiro 	if (norespflag != 0 && bitset(norespflag, m->mf_pflags))
1983e92d3f3fSGregory Neil Shapiro 		return NULL;
1984e92d3f3fSGregory Neil Shapiro #endif /* _FFR_MILTER_NOHDR_RESP */
1985e92d3f3fSGregory Neil Shapiro 
198640266059SGregory Neil Shapiro 	/* get the response from the filter */
198706f25ae9SGregory Neil Shapiro 	response = milter_read(m, &rcmd, &rlen,
198806f25ae9SGregory Neil Shapiro 			       m->mf_timeout[SMFTO_READ], e);
198906f25ae9SGregory Neil Shapiro 	if (m->mf_state == SMFS_ERROR)
199006f25ae9SGregory Neil Shapiro 	{
19915ef517c0SGregory Neil Shapiro 		MILTER_CHECK_ERROR(false, return NULL);
199206f25ae9SGregory Neil Shapiro 		return NULL;
199306f25ae9SGregory Neil Shapiro 	}
199406f25ae9SGregory Neil Shapiro 
199506f25ae9SGregory Neil Shapiro 	if (tTd(64, 10))
199640266059SGregory Neil Shapiro 		sm_dprintf("milter_send_command(%s): returned %c\n",
199706f25ae9SGregory Neil Shapiro 			   m->mf_name, (char) rcmd);
199806f25ae9SGregory Neil Shapiro 
199906f25ae9SGregory Neil Shapiro 	switch (rcmd)
200006f25ae9SGregory Neil Shapiro 	{
200106f25ae9SGregory Neil Shapiro 	  case SMFIR_REPLYCODE:
200206f25ae9SGregory Neil Shapiro 		MILTER_CHECK_REPLYCODE(defresponse);
200340266059SGregory Neil Shapiro 		if (MilterLogLevel > 10)
200440266059SGregory Neil Shapiro 			sm_syslog(LOG_INFO, e->e_id, "milter=%s, action=%s, reject=%s",
200540266059SGregory Neil Shapiro 				  m->mf_name, action, response);
200640266059SGregory Neil Shapiro 		*state = rcmd;
200740266059SGregory Neil Shapiro 		break;
200806f25ae9SGregory Neil Shapiro 
200906f25ae9SGregory Neil Shapiro 	  case SMFIR_REJECT:
201040266059SGregory Neil Shapiro 		if (MilterLogLevel > 10)
201140266059SGregory Neil Shapiro 			sm_syslog(LOG_INFO, e->e_id, "milter=%s, action=%s, reject",
201240266059SGregory Neil Shapiro 				  m->mf_name, action);
201340266059SGregory Neil Shapiro 		*state = rcmd;
201440266059SGregory Neil Shapiro 		break;
201540266059SGregory Neil Shapiro 
201606f25ae9SGregory Neil Shapiro 	  case SMFIR_DISCARD:
201740266059SGregory Neil Shapiro 		if (MilterLogLevel > 10)
201840266059SGregory Neil Shapiro 			sm_syslog(LOG_INFO, e->e_id, "milter=%s, action=%s, discard",
201940266059SGregory Neil Shapiro 				  m->mf_name, action);
202040266059SGregory Neil Shapiro 		*state = rcmd;
202140266059SGregory Neil Shapiro 		break;
202240266059SGregory Neil Shapiro 
202306f25ae9SGregory Neil Shapiro 	  case SMFIR_TEMPFAIL:
202440266059SGregory Neil Shapiro 		if (MilterLogLevel > 10)
202540266059SGregory Neil Shapiro 			sm_syslog(LOG_INFO, e->e_id, "milter=%s, action=%s, tempfail",
202640266059SGregory Neil Shapiro 				  m->mf_name, action);
202706f25ae9SGregory Neil Shapiro 		*state = rcmd;
202806f25ae9SGregory Neil Shapiro 		break;
202906f25ae9SGregory Neil Shapiro 
203006f25ae9SGregory Neil Shapiro 	  case SMFIR_ACCEPT:
203106f25ae9SGregory Neil Shapiro 		/* this filter is done with message/connection */
2032602a2b1bSGregory Neil Shapiro 		if (command == SMFIC_HELO ||
2033602a2b1bSGregory Neil Shapiro 		    command == SMFIC_CONNECT)
2034602a2b1bSGregory Neil Shapiro 			m->mf_state = SMFS_CLOSABLE;
2035602a2b1bSGregory Neil Shapiro 		else
203606f25ae9SGregory Neil Shapiro 			m->mf_state = SMFS_DONE;
203740266059SGregory Neil Shapiro 		if (MilterLogLevel > 10)
203840266059SGregory Neil Shapiro 			sm_syslog(LOG_INFO, e->e_id, "milter=%s, action=%s, accepted",
203940266059SGregory Neil Shapiro 				  m->mf_name, action);
204006f25ae9SGregory Neil Shapiro 		break;
204106f25ae9SGregory Neil Shapiro 
204206f25ae9SGregory Neil Shapiro 	  case SMFIR_CONTINUE:
204306f25ae9SGregory Neil Shapiro 		/* if MAIL command is ok, filter is in message state */
204406f25ae9SGregory Neil Shapiro 		if (command == SMFIC_MAIL)
204506f25ae9SGregory Neil Shapiro 			m->mf_state = SMFS_INMSG;
204640266059SGregory Neil Shapiro 		if (MilterLogLevel > 12)
204740266059SGregory Neil Shapiro 			sm_syslog(LOG_INFO, e->e_id, "milter=%s, action=%s, continue",
204840266059SGregory Neil Shapiro 				  m->mf_name, action);
204906f25ae9SGregory Neil Shapiro 		break;
205006f25ae9SGregory Neil Shapiro 
205106f25ae9SGregory Neil Shapiro 	  default:
205206f25ae9SGregory Neil Shapiro 		/* Invalid response to command */
205340266059SGregory Neil Shapiro 		if (MilterLogLevel > 0)
205406f25ae9SGregory Neil Shapiro 			sm_syslog(LOG_ERR, e->e_id,
205540266059SGregory Neil Shapiro 				  "milter_send_command(%s): action=%s returned bogus response %c",
205640266059SGregory Neil Shapiro 				  m->mf_name, action, rcmd);
205740266059SGregory Neil Shapiro 		milter_error(m, e);
205806f25ae9SGregory Neil Shapiro 		break;
205906f25ae9SGregory Neil Shapiro 	}
206006f25ae9SGregory Neil Shapiro 
206106f25ae9SGregory Neil Shapiro 	if (*state != SMFIR_REPLYCODE &&
206206f25ae9SGregory Neil Shapiro 	    response != NULL)
206306f25ae9SGregory Neil Shapiro 	{
206440266059SGregory Neil Shapiro 		sm_free(response); /* XXX */
206506f25ae9SGregory Neil Shapiro 		response = NULL;
206606f25ae9SGregory Neil Shapiro 	}
206706f25ae9SGregory Neil Shapiro 	return response;
206806f25ae9SGregory Neil Shapiro }
206906f25ae9SGregory Neil Shapiro 
207040266059SGregory Neil Shapiro /*
207106f25ae9SGregory Neil Shapiro **  MILTER_COMMAND -- send a command and return the response for each filter
207206f25ae9SGregory Neil Shapiro **
207306f25ae9SGregory Neil Shapiro **	Parameters:
207406f25ae9SGregory Neil Shapiro **		command -- command to send.
207506f25ae9SGregory Neil Shapiro **		data -- optional command data.
207606f25ae9SGregory Neil Shapiro **		sz -- length of buf.
207706f25ae9SGregory Neil Shapiro **		macros -- macros to send for filter smfi_getsymval().
207806f25ae9SGregory Neil Shapiro **		e -- current envelope (for macro access).
207906f25ae9SGregory Neil Shapiro **		state -- return state word.
208006f25ae9SGregory Neil Shapiro **
208106f25ae9SGregory Neil Shapiro **	Returns:
208206f25ae9SGregory Neil Shapiro **		response string (may be NULL)
208306f25ae9SGregory Neil Shapiro */
208406f25ae9SGregory Neil Shapiro 
208506f25ae9SGregory Neil Shapiro static char *
208606f25ae9SGregory Neil Shapiro milter_command(command, data, sz, macros, e, state)
208706f25ae9SGregory Neil Shapiro 	char command;
208806f25ae9SGregory Neil Shapiro 	void *data;
208906f25ae9SGregory Neil Shapiro 	ssize_t sz;
209006f25ae9SGregory Neil Shapiro 	char **macros;
209106f25ae9SGregory Neil Shapiro 	ENVELOPE *e;
209206f25ae9SGregory Neil Shapiro 	char *state;
209306f25ae9SGregory Neil Shapiro {
209406f25ae9SGregory Neil Shapiro 	int i;
209506f25ae9SGregory Neil Shapiro 	char *response = NULL;
209640266059SGregory Neil Shapiro 	time_t tn = 0;
209706f25ae9SGregory Neil Shapiro 
209806f25ae9SGregory Neil Shapiro 	if (tTd(64, 10))
209940266059SGregory Neil Shapiro 		sm_dprintf("milter_command: cmd %c len %ld\n",
210006f25ae9SGregory Neil Shapiro 			(char) command, (long) sz);
210106f25ae9SGregory Neil Shapiro 
210206f25ae9SGregory Neil Shapiro 	*state = SMFIR_CONTINUE;
210306f25ae9SGregory Neil Shapiro 	for (i = 0; InputFilters[i] != NULL; i++)
210406f25ae9SGregory Neil Shapiro 	{
210506f25ae9SGregory Neil Shapiro 		struct milter *m = InputFilters[i];
210606f25ae9SGregory Neil Shapiro 
2107193538b7SGregory Neil Shapiro 		/* previous problem? */
2108193538b7SGregory Neil Shapiro 		if (m->mf_state == SMFS_ERROR)
2109193538b7SGregory Neil Shapiro 		{
21105ef517c0SGregory Neil Shapiro 			MILTER_CHECK_ERROR(false, continue);
2111193538b7SGregory Neil Shapiro 			break;
2112193538b7SGregory Neil Shapiro 		}
2113193538b7SGregory Neil Shapiro 
211406f25ae9SGregory Neil Shapiro 		/* sanity check */
211506f25ae9SGregory Neil Shapiro 		if (m->mf_sock < 0 ||
211606f25ae9SGregory Neil Shapiro 		    (m->mf_state != SMFS_OPEN && m->mf_state != SMFS_INMSG))
211706f25ae9SGregory Neil Shapiro 			continue;
211806f25ae9SGregory Neil Shapiro 
211906f25ae9SGregory Neil Shapiro 		/* send macros (regardless of whether we send command) */
212006f25ae9SGregory Neil Shapiro 		if (macros != NULL && macros[0] != NULL)
212106f25ae9SGregory Neil Shapiro 		{
212206f25ae9SGregory Neil Shapiro 			milter_send_macros(m, macros, command, e);
212306f25ae9SGregory Neil Shapiro 			if (m->mf_state == SMFS_ERROR)
212406f25ae9SGregory Neil Shapiro 			{
21255ef517c0SGregory Neil Shapiro 				MILTER_CHECK_ERROR(false, continue);
212606f25ae9SGregory Neil Shapiro 				break;
212706f25ae9SGregory Neil Shapiro 			}
212806f25ae9SGregory Neil Shapiro 		}
212906f25ae9SGregory Neil Shapiro 
213040266059SGregory Neil Shapiro 		if (MilterLogLevel > 21)
213140266059SGregory Neil Shapiro 			tn = curtime();
213240266059SGregory Neil Shapiro 
213306f25ae9SGregory Neil Shapiro 		response = milter_send_command(m, command, data, sz, e, state);
213440266059SGregory Neil Shapiro 
213540266059SGregory Neil Shapiro 		if (MilterLogLevel > 21)
213640266059SGregory Neil Shapiro 		{
213740266059SGregory Neil Shapiro 			/* log the time it took for the command per filter */
213840266059SGregory Neil Shapiro 			sm_syslog(LOG_INFO, e->e_id,
213940266059SGregory Neil Shapiro 				  "Milter (%s): time command (%c), %d",
214040266059SGregory Neil Shapiro 				  m->mf_name, command, (int) (tn - curtime()));
214140266059SGregory Neil Shapiro 		}
214240266059SGregory Neil Shapiro 
214306f25ae9SGregory Neil Shapiro 		if (*state != SMFIR_CONTINUE)
214406f25ae9SGregory Neil Shapiro 			break;
214506f25ae9SGregory Neil Shapiro 	}
214606f25ae9SGregory Neil Shapiro 	return response;
214706f25ae9SGregory Neil Shapiro }
214840266059SGregory Neil Shapiro /*
214906f25ae9SGregory Neil Shapiro **  MILTER_NEGOTIATE -- get version and flags from filter
215006f25ae9SGregory Neil Shapiro **
215106f25ae9SGregory Neil Shapiro **	Parameters:
215206f25ae9SGregory Neil Shapiro **		m -- milter filter structure.
215306f25ae9SGregory Neil Shapiro **		e -- current envelope.
215406f25ae9SGregory Neil Shapiro **
215506f25ae9SGregory Neil Shapiro **	Returns:
215606f25ae9SGregory Neil Shapiro **		0 on success, -1 otherwise
215706f25ae9SGregory Neil Shapiro */
215806f25ae9SGregory Neil Shapiro 
215906f25ae9SGregory Neil Shapiro static int
216006f25ae9SGregory Neil Shapiro milter_negotiate(m, e)
216106f25ae9SGregory Neil Shapiro 	struct milter *m;
216206f25ae9SGregory Neil Shapiro 	ENVELOPE *e;
216306f25ae9SGregory Neil Shapiro {
216406f25ae9SGregory Neil Shapiro 	char rcmd;
216506f25ae9SGregory Neil Shapiro 	mi_int32 fvers;
216606f25ae9SGregory Neil Shapiro 	mi_int32 fflags;
216706f25ae9SGregory Neil Shapiro 	mi_int32 pflags;
216806f25ae9SGregory Neil Shapiro 	char *response;
216906f25ae9SGregory Neil Shapiro 	ssize_t rlen;
217006f25ae9SGregory Neil Shapiro 	char data[MILTER_OPTLEN];
217106f25ae9SGregory Neil Shapiro 
217206f25ae9SGregory Neil Shapiro 	/* sanity check */
217306f25ae9SGregory Neil Shapiro 	if (m->mf_sock < 0 || m->mf_state != SMFS_OPEN)
217406f25ae9SGregory Neil Shapiro 	{
217540266059SGregory Neil Shapiro 		if (MilterLogLevel > 0)
217606f25ae9SGregory Neil Shapiro 			sm_syslog(LOG_ERR, e->e_id,
217740266059SGregory Neil Shapiro 				  "Milter (%s): negotiate, impossible state",
217806f25ae9SGregory Neil Shapiro 				  m->mf_name);
217940266059SGregory Neil Shapiro 		milter_error(m, e);
218006f25ae9SGregory Neil Shapiro 		return -1;
218106f25ae9SGregory Neil Shapiro 	}
218206f25ae9SGregory Neil Shapiro 
218306f25ae9SGregory Neil Shapiro 	fvers = htonl(SMFI_VERSION);
218406f25ae9SGregory Neil Shapiro 	fflags = htonl(SMFI_CURR_ACTS);
218506f25ae9SGregory Neil Shapiro 	pflags = htonl(SMFI_CURR_PROT);
218606f25ae9SGregory Neil Shapiro 	(void) memcpy(data, (char *) &fvers, MILTER_LEN_BYTES);
218706f25ae9SGregory Neil Shapiro 	(void) memcpy(data + MILTER_LEN_BYTES,
218806f25ae9SGregory Neil Shapiro 		      (char *) &fflags, MILTER_LEN_BYTES);
218906f25ae9SGregory Neil Shapiro 	(void) memcpy(data + (MILTER_LEN_BYTES * 2),
219006f25ae9SGregory Neil Shapiro 		      (char *) &pflags, MILTER_LEN_BYTES);
219106f25ae9SGregory Neil Shapiro 	(void) milter_write(m, SMFIC_OPTNEG, data, sizeof data,
219206f25ae9SGregory Neil Shapiro 			    m->mf_timeout[SMFTO_WRITE], e);
219306f25ae9SGregory Neil Shapiro 
219406f25ae9SGregory Neil Shapiro 	if (m->mf_state == SMFS_ERROR)
219506f25ae9SGregory Neil Shapiro 		return -1;
219606f25ae9SGregory Neil Shapiro 
219706f25ae9SGregory Neil Shapiro 	response = milter_read(m, &rcmd, &rlen, m->mf_timeout[SMFTO_READ], e);
219806f25ae9SGregory Neil Shapiro 	if (m->mf_state == SMFS_ERROR)
219906f25ae9SGregory Neil Shapiro 		return -1;
220006f25ae9SGregory Neil Shapiro 
220106f25ae9SGregory Neil Shapiro 	if (rcmd != SMFIC_OPTNEG)
220206f25ae9SGregory Neil Shapiro 	{
220306f25ae9SGregory Neil Shapiro 		if (tTd(64, 5))
220440266059SGregory Neil Shapiro 			sm_dprintf("milter_negotiate(%s): returned %c instead of %c\n",
220506f25ae9SGregory Neil Shapiro 				m->mf_name, rcmd, SMFIC_OPTNEG);
220640266059SGregory Neil Shapiro 		if (MilterLogLevel > 0)
220706f25ae9SGregory Neil Shapiro 			sm_syslog(LOG_ERR, e->e_id,
220840266059SGregory Neil Shapiro 				  "Milter (%s): negotiate: returned %c instead of %c",
220906f25ae9SGregory Neil Shapiro 				  m->mf_name, rcmd, SMFIC_OPTNEG);
221006f25ae9SGregory Neil Shapiro 		if (response != NULL)
221140266059SGregory Neil Shapiro 			sm_free(response); /* XXX */
221240266059SGregory Neil Shapiro 		milter_error(m, e);
221306f25ae9SGregory Neil Shapiro 		return -1;
221406f25ae9SGregory Neil Shapiro 	}
221506f25ae9SGregory Neil Shapiro 
221606f25ae9SGregory Neil Shapiro 	/* Make sure we have enough bytes for the version */
221706f25ae9SGregory Neil Shapiro 	if (response == NULL || rlen < MILTER_LEN_BYTES)
221806f25ae9SGregory Neil Shapiro 	{
221906f25ae9SGregory Neil Shapiro 		if (tTd(64, 5))
222040266059SGregory Neil Shapiro 			sm_dprintf("milter_negotiate(%s): did not return valid info\n",
222106f25ae9SGregory Neil Shapiro 				m->mf_name);
222240266059SGregory Neil Shapiro 		if (MilterLogLevel > 0)
222306f25ae9SGregory Neil Shapiro 			sm_syslog(LOG_ERR, e->e_id,
222440266059SGregory Neil Shapiro 				  "Milter (%s): negotiate: did not return valid info",
222506f25ae9SGregory Neil Shapiro 				  m->mf_name);
222606f25ae9SGregory Neil Shapiro 		if (response != NULL)
222740266059SGregory Neil Shapiro 			sm_free(response); /* XXX */
222840266059SGregory Neil Shapiro 		milter_error(m, e);
222906f25ae9SGregory Neil Shapiro 		return -1;
223006f25ae9SGregory Neil Shapiro 	}
223106f25ae9SGregory Neil Shapiro 
223206f25ae9SGregory Neil Shapiro 	/* extract information */
223306f25ae9SGregory Neil Shapiro 	(void) memcpy((char *) &fvers, response, MILTER_LEN_BYTES);
223406f25ae9SGregory Neil Shapiro 
223506f25ae9SGregory Neil Shapiro 	/* Now make sure we have enough for the feature bitmap */
223606f25ae9SGregory Neil Shapiro 	if (rlen != MILTER_OPTLEN)
223706f25ae9SGregory Neil Shapiro 	{
223806f25ae9SGregory Neil Shapiro 		if (tTd(64, 5))
223940266059SGregory Neil Shapiro 			sm_dprintf("milter_negotiate(%s): did not return enough info\n",
224006f25ae9SGregory Neil Shapiro 				m->mf_name);
224140266059SGregory Neil Shapiro 		if (MilterLogLevel > 0)
224206f25ae9SGregory Neil Shapiro 			sm_syslog(LOG_ERR, e->e_id,
224340266059SGregory Neil Shapiro 				  "Milter (%s): negotiate: did not return enough info",
224406f25ae9SGregory Neil Shapiro 				  m->mf_name);
224506f25ae9SGregory Neil Shapiro 		if (response != NULL)
224640266059SGregory Neil Shapiro 			sm_free(response); /* XXX */
224740266059SGregory Neil Shapiro 		milter_error(m, e);
224806f25ae9SGregory Neil Shapiro 		return -1;
224906f25ae9SGregory Neil Shapiro 	}
225006f25ae9SGregory Neil Shapiro 
225106f25ae9SGregory Neil Shapiro 	(void) memcpy((char *) &fflags, response + MILTER_LEN_BYTES,
225206f25ae9SGregory Neil Shapiro 		      MILTER_LEN_BYTES);
225306f25ae9SGregory Neil Shapiro 	(void) memcpy((char *) &pflags, response + (MILTER_LEN_BYTES * 2),
225406f25ae9SGregory Neil Shapiro 		      MILTER_LEN_BYTES);
225540266059SGregory Neil Shapiro 	sm_free(response); /* XXX */
225606f25ae9SGregory Neil Shapiro 	response = NULL;
225706f25ae9SGregory Neil Shapiro 
225806f25ae9SGregory Neil Shapiro 	m->mf_fvers = ntohl(fvers);
225906f25ae9SGregory Neil Shapiro 	m->mf_fflags = ntohl(fflags);
226006f25ae9SGregory Neil Shapiro 	m->mf_pflags = ntohl(pflags);
226106f25ae9SGregory Neil Shapiro 
226206f25ae9SGregory Neil Shapiro 	/* check for version compatibility */
226306f25ae9SGregory Neil Shapiro 	if (m->mf_fvers == 1 ||
226406f25ae9SGregory Neil Shapiro 	    m->mf_fvers > SMFI_VERSION)
226506f25ae9SGregory Neil Shapiro 	{
226606f25ae9SGregory Neil Shapiro 		if (tTd(64, 5))
2267605302a5SGregory Neil Shapiro 			sm_dprintf("milter_negotiate(%s): version %d != MTA milter version %d\n",
226806f25ae9SGregory Neil Shapiro 				m->mf_name, m->mf_fvers, SMFI_VERSION);
226940266059SGregory Neil Shapiro 		if (MilterLogLevel > 0)
227006f25ae9SGregory Neil Shapiro 			sm_syslog(LOG_ERR, e->e_id,
2271605302a5SGregory Neil Shapiro 				  "Milter (%s): negotiate: version %d != MTA milter version %d",
227206f25ae9SGregory Neil Shapiro 				  m->mf_name, m->mf_fvers, SMFI_VERSION);
227340266059SGregory Neil Shapiro 		milter_error(m, e);
227406f25ae9SGregory Neil Shapiro 		return -1;
227506f25ae9SGregory Neil Shapiro 	}
227606f25ae9SGregory Neil Shapiro 
227706f25ae9SGregory Neil Shapiro 	/* check for filter feature mismatch */
227806f25ae9SGregory Neil Shapiro 	if ((m->mf_fflags & SMFI_CURR_ACTS) != m->mf_fflags)
227906f25ae9SGregory Neil Shapiro 	{
228006f25ae9SGregory Neil Shapiro 		if (tTd(64, 5))
2281605302a5SGregory Neil Shapiro 			sm_dprintf("milter_negotiate(%s): filter abilities 0x%x != MTA milter abilities 0x%lx\n",
228206f25ae9SGregory Neil Shapiro 				m->mf_name, m->mf_fflags,
2283605302a5SGregory Neil Shapiro 				SMFI_CURR_ACTS);
228440266059SGregory Neil Shapiro 		if (MilterLogLevel > 0)
228506f25ae9SGregory Neil Shapiro 			sm_syslog(LOG_ERR, e->e_id,
2286605302a5SGregory Neil Shapiro 				  "Milter (%s): negotiate: filter abilities 0x%x != MTA milter abilities 0x%lx",
228706f25ae9SGregory Neil Shapiro 				  m->mf_name, m->mf_fflags,
228840266059SGregory Neil Shapiro 				  (unsigned long) SMFI_CURR_ACTS);
228940266059SGregory Neil Shapiro 		milter_error(m, e);
229006f25ae9SGregory Neil Shapiro 		return -1;
229106f25ae9SGregory Neil Shapiro 	}
229206f25ae9SGregory Neil Shapiro 
229306f25ae9SGregory Neil Shapiro 	/* check for protocol feature mismatch */
229406f25ae9SGregory Neil Shapiro 	if ((m->mf_pflags & SMFI_CURR_PROT) != m->mf_pflags)
229506f25ae9SGregory Neil Shapiro 	{
229606f25ae9SGregory Neil Shapiro 		if (tTd(64, 5))
2297605302a5SGregory Neil Shapiro 			sm_dprintf("milter_negotiate(%s): protocol abilities 0x%x != MTA milter abilities 0x%lx\n",
229806f25ae9SGregory Neil Shapiro 				m->mf_name, m->mf_pflags,
229940266059SGregory Neil Shapiro 				(unsigned long) SMFI_CURR_PROT);
230040266059SGregory Neil Shapiro 		if (MilterLogLevel > 0)
230106f25ae9SGregory Neil Shapiro 			sm_syslog(LOG_ERR, e->e_id,
2302605302a5SGregory Neil Shapiro 				  "Milter (%s): negotiate: protocol abilities 0x%x != MTA milter abilities 0x%lx",
230306f25ae9SGregory Neil Shapiro 				  m->mf_name, m->mf_pflags,
230440266059SGregory Neil Shapiro 				  (unsigned long) SMFI_CURR_PROT);
230540266059SGregory Neil Shapiro 		milter_error(m, e);
230606f25ae9SGregory Neil Shapiro 		return -1;
230706f25ae9SGregory Neil Shapiro 	}
230806f25ae9SGregory Neil Shapiro 
230906f25ae9SGregory Neil Shapiro 	if (tTd(64, 5))
2310605302a5SGregory Neil Shapiro 		sm_dprintf("milter_negotiate(%s): version %u, fflags 0x%x, pflags 0x%x\n",
231106f25ae9SGregory Neil Shapiro 			m->mf_name, m->mf_fvers, m->mf_fflags, m->mf_pflags);
231206f25ae9SGregory Neil Shapiro 	return 0;
231306f25ae9SGregory Neil Shapiro }
231440266059SGregory Neil Shapiro /*
231506f25ae9SGregory Neil Shapiro **  MILTER_PER_CONNECTION_CHECK -- checks on per-connection commands
231606f25ae9SGregory Neil Shapiro **
231706f25ae9SGregory Neil Shapiro **	Reduce code duplication by putting these checks in one place
231806f25ae9SGregory Neil Shapiro **
231906f25ae9SGregory Neil Shapiro **	Parameters:
232006f25ae9SGregory Neil Shapiro **		e -- current envelope.
232106f25ae9SGregory Neil Shapiro **
232206f25ae9SGregory Neil Shapiro **	Returns:
232306f25ae9SGregory Neil Shapiro **		none
232406f25ae9SGregory Neil Shapiro */
232506f25ae9SGregory Neil Shapiro 
232606f25ae9SGregory Neil Shapiro static void
232706f25ae9SGregory Neil Shapiro milter_per_connection_check(e)
232806f25ae9SGregory Neil Shapiro 	ENVELOPE *e;
232906f25ae9SGregory Neil Shapiro {
233006f25ae9SGregory Neil Shapiro 	int i;
233106f25ae9SGregory Neil Shapiro 
233206f25ae9SGregory Neil Shapiro 	/* see if we are done with any of the filters */
233306f25ae9SGregory Neil Shapiro 	for (i = 0; InputFilters[i] != NULL; i++)
233406f25ae9SGregory Neil Shapiro 	{
233506f25ae9SGregory Neil Shapiro 		struct milter *m = InputFilters[i];
233606f25ae9SGregory Neil Shapiro 
2337602a2b1bSGregory Neil Shapiro 		if (m->mf_state == SMFS_CLOSABLE)
233806f25ae9SGregory Neil Shapiro 			milter_quit_filter(m, e);
233906f25ae9SGregory Neil Shapiro 	}
234006f25ae9SGregory Neil Shapiro }
234140266059SGregory Neil Shapiro /*
234206f25ae9SGregory Neil Shapiro **  MILTER_ERROR -- Put a milter filter into error state
234306f25ae9SGregory Neil Shapiro **
234406f25ae9SGregory Neil Shapiro **	Parameters:
234506f25ae9SGregory Neil Shapiro **		m -- the broken filter.
2346b6bacd31SGregory Neil Shapiro **		e -- current envelope.
234706f25ae9SGregory Neil Shapiro **
234806f25ae9SGregory Neil Shapiro **	Returns:
234906f25ae9SGregory Neil Shapiro **		none
235006f25ae9SGregory Neil Shapiro */
235106f25ae9SGregory Neil Shapiro 
235206f25ae9SGregory Neil Shapiro static void
235340266059SGregory Neil Shapiro milter_error(m, e)
235406f25ae9SGregory Neil Shapiro 	struct milter *m;
235540266059SGregory Neil Shapiro 	ENVELOPE *e;
235606f25ae9SGregory Neil Shapiro {
235706f25ae9SGregory Neil Shapiro 	/*
2358b6bacd31SGregory Neil Shapiro 	**  We could send a quit here but we may have gotten here due to
2359b6bacd31SGregory Neil Shapiro 	**  an I/O error so we don't want to try to make things worse.
236006f25ae9SGregory Neil Shapiro 	*/
236106f25ae9SGregory Neil Shapiro 
236206f25ae9SGregory Neil Shapiro 	if (m->mf_sock >= 0)
236306f25ae9SGregory Neil Shapiro 	{
236406f25ae9SGregory Neil Shapiro 		(void) close(m->mf_sock);
236506f25ae9SGregory Neil Shapiro 		m->mf_sock = -1;
236606f25ae9SGregory Neil Shapiro 	}
236706f25ae9SGregory Neil Shapiro 	m->mf_state = SMFS_ERROR;
236840266059SGregory Neil Shapiro 
236940266059SGregory Neil Shapiro 	if (MilterLogLevel > 0)
237040266059SGregory Neil Shapiro 		sm_syslog(LOG_INFO, e->e_id, "Milter (%s): to error state",
237140266059SGregory Neil Shapiro 			  m->mf_name);
237206f25ae9SGregory Neil Shapiro }
237340266059SGregory Neil Shapiro /*
237406f25ae9SGregory Neil Shapiro **  MILTER_HEADERS -- send headers to a single milter filter
237506f25ae9SGregory Neil Shapiro **
237606f25ae9SGregory Neil Shapiro **	Parameters:
237706f25ae9SGregory Neil Shapiro **		m -- current filter.
237806f25ae9SGregory Neil Shapiro **		e -- current envelope.
237906f25ae9SGregory Neil Shapiro **		state -- return state from response.
238006f25ae9SGregory Neil Shapiro **
238106f25ae9SGregory Neil Shapiro **	Returns:
238206f25ae9SGregory Neil Shapiro **		response string (may be NULL)
238306f25ae9SGregory Neil Shapiro */
238406f25ae9SGregory Neil Shapiro 
238506f25ae9SGregory Neil Shapiro static char *
238606f25ae9SGregory Neil Shapiro milter_headers(m, e, state)
238706f25ae9SGregory Neil Shapiro 	struct milter *m;
238806f25ae9SGregory Neil Shapiro 	ENVELOPE *e;
238906f25ae9SGregory Neil Shapiro 	char *state;
239006f25ae9SGregory Neil Shapiro {
239106f25ae9SGregory Neil Shapiro 	char *response = NULL;
239206f25ae9SGregory Neil Shapiro 	HDR *h;
239306f25ae9SGregory Neil Shapiro 
239440266059SGregory Neil Shapiro 	if (MilterLogLevel > 17)
239540266059SGregory Neil Shapiro 		sm_syslog(LOG_INFO, e->e_id, "Milter (%s): headers, send",
239640266059SGregory Neil Shapiro 			  m->mf_name);
239740266059SGregory Neil Shapiro 
239806f25ae9SGregory Neil Shapiro 	for (h = e->e_header; h != NULL; h = h->h_link)
239906f25ae9SGregory Neil Shapiro 	{
240006f25ae9SGregory Neil Shapiro 		char *buf;
240106f25ae9SGregory Neil Shapiro 		ssize_t s;
240206f25ae9SGregory Neil Shapiro 
240306f25ae9SGregory Neil Shapiro 		/* don't send over deleted headers */
240406f25ae9SGregory Neil Shapiro 		if (h->h_value == NULL)
240506f25ae9SGregory Neil Shapiro 		{
2406e92d3f3fSGregory Neil Shapiro 			/* strip H_USER so not counted in milter_changeheader() */
240706f25ae9SGregory Neil Shapiro 			h->h_flags &= ~H_USER;
240806f25ae9SGregory Neil Shapiro 			continue;
240906f25ae9SGregory Neil Shapiro 		}
241006f25ae9SGregory Neil Shapiro 
241106f25ae9SGregory Neil Shapiro 		/* skip auto-generated */
241206f25ae9SGregory Neil Shapiro 		if (!bitset(H_USER, h->h_flags))
241306f25ae9SGregory Neil Shapiro 			continue;
241406f25ae9SGregory Neil Shapiro 
241506f25ae9SGregory Neil Shapiro 		if (tTd(64, 10))
241640266059SGregory Neil Shapiro 			sm_dprintf("milter_headers: %s: %s\n",
241706f25ae9SGregory Neil Shapiro 				h->h_field, h->h_value);
241840266059SGregory Neil Shapiro 		if (MilterLogLevel > 21)
241940266059SGregory Neil Shapiro 			sm_syslog(LOG_INFO, e->e_id, "Milter (%s): header, %s",
242040266059SGregory Neil Shapiro 				  m->mf_name, h->h_field);
242106f25ae9SGregory Neil Shapiro 
242240266059SGregory Neil Shapiro 		s = strlen(h->h_field) + 1 + strlen(h->h_value) + 1;
242340266059SGregory Neil Shapiro 		if (s < 0)
242440266059SGregory Neil Shapiro 			continue;
242506f25ae9SGregory Neil Shapiro 		buf = (char *) xalloc(s);
242640266059SGregory Neil Shapiro 		(void) sm_snprintf(buf, s, "%s%c%s",
242740266059SGregory Neil Shapiro 			h->h_field, '\0', h->h_value);
242806f25ae9SGregory Neil Shapiro 
242906f25ae9SGregory Neil Shapiro 		/* send it over */
243006f25ae9SGregory Neil Shapiro 		response = milter_send_command(m, SMFIC_HEADER, buf,
243106f25ae9SGregory Neil Shapiro 					       s, e, state);
243240266059SGregory Neil Shapiro 		sm_free(buf); /* XXX */
243306f25ae9SGregory Neil Shapiro 		if (m->mf_state == SMFS_ERROR ||
243406f25ae9SGregory Neil Shapiro 		    m->mf_state == SMFS_DONE ||
243506f25ae9SGregory Neil Shapiro 		    *state != SMFIR_CONTINUE)
243606f25ae9SGregory Neil Shapiro 			break;
243706f25ae9SGregory Neil Shapiro 	}
243840266059SGregory Neil Shapiro 	if (MilterLogLevel > 17)
243940266059SGregory Neil Shapiro 		sm_syslog(LOG_INFO, e->e_id, "Milter (%s): headers, sent",
244040266059SGregory Neil Shapiro 			  m->mf_name);
244106f25ae9SGregory Neil Shapiro 	return response;
244206f25ae9SGregory Neil Shapiro }
244340266059SGregory Neil Shapiro /*
244406f25ae9SGregory Neil Shapiro **  MILTER_BODY -- send the body to a filter
244506f25ae9SGregory Neil Shapiro **
244606f25ae9SGregory Neil Shapiro **	Parameters:
244706f25ae9SGregory Neil Shapiro **		m -- current filter.
244806f25ae9SGregory Neil Shapiro **		e -- current envelope.
244906f25ae9SGregory Neil Shapiro **		state -- return state from response.
245006f25ae9SGregory Neil Shapiro **
245106f25ae9SGregory Neil Shapiro **	Returns:
245206f25ae9SGregory Neil Shapiro **		response string (may be NULL)
245306f25ae9SGregory Neil Shapiro */
245406f25ae9SGregory Neil Shapiro 
245506f25ae9SGregory Neil Shapiro static char *
245606f25ae9SGregory Neil Shapiro milter_body(m, e, state)
245706f25ae9SGregory Neil Shapiro 	struct milter *m;
245806f25ae9SGregory Neil Shapiro 	ENVELOPE *e;
245906f25ae9SGregory Neil Shapiro 	char *state;
246006f25ae9SGregory Neil Shapiro {
246106f25ae9SGregory Neil Shapiro 	char bufchar = '\0';
246206f25ae9SGregory Neil Shapiro 	char prevchar = '\0';
246306f25ae9SGregory Neil Shapiro 	int c;
246406f25ae9SGregory Neil Shapiro 	char *response = NULL;
246506f25ae9SGregory Neil Shapiro 	char *bp;
246606f25ae9SGregory Neil Shapiro 	char buf[MILTER_CHUNK_SIZE];
246706f25ae9SGregory Neil Shapiro 
246806f25ae9SGregory Neil Shapiro 	if (tTd(64, 10))
246940266059SGregory Neil Shapiro 		sm_dprintf("milter_body\n");
247006f25ae9SGregory Neil Shapiro 
247106f25ae9SGregory Neil Shapiro 	if (bfrewind(e->e_dfp) < 0)
247206f25ae9SGregory Neil Shapiro 	{
247306f25ae9SGregory Neil Shapiro 		ExitStat = EX_IOERR;
247406f25ae9SGregory Neil Shapiro 		*state = SMFIR_TEMPFAIL;
247540266059SGregory Neil Shapiro 		syserr("milter_body: %s/%cf%s: rewind error",
247640266059SGregory Neil Shapiro 		       qid_printqueue(e->e_qgrp, e->e_qdir),
247740266059SGregory Neil Shapiro 		       DATAFL_LETTER, e->e_id);
247806f25ae9SGregory Neil Shapiro 		return NULL;
247906f25ae9SGregory Neil Shapiro 	}
248006f25ae9SGregory Neil Shapiro 
248140266059SGregory Neil Shapiro 	if (MilterLogLevel > 17)
248240266059SGregory Neil Shapiro 		sm_syslog(LOG_INFO, e->e_id, "Milter (%s): body, send",
248340266059SGregory Neil Shapiro 			  m->mf_name);
248406f25ae9SGregory Neil Shapiro 	bp = buf;
248540266059SGregory Neil Shapiro 	while ((c = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT)) != SM_IO_EOF)
248606f25ae9SGregory Neil Shapiro 	{
248706f25ae9SGregory Neil Shapiro 		/*  Change LF to CRLF */
248806f25ae9SGregory Neil Shapiro 		if (c == '\n')
248906f25ae9SGregory Neil Shapiro 		{
249006f25ae9SGregory Neil Shapiro 			/* Not a CRLF already? */
249106f25ae9SGregory Neil Shapiro 			if (prevchar != '\r')
249206f25ae9SGregory Neil Shapiro 			{
249306f25ae9SGregory Neil Shapiro 				/* Room for CR now? */
249406f25ae9SGregory Neil Shapiro 				if (bp + 2 > &buf[sizeof buf])
249506f25ae9SGregory Neil Shapiro 				{
249606f25ae9SGregory Neil Shapiro 					/* No room, buffer LF */
249706f25ae9SGregory Neil Shapiro 					bufchar = c;
249806f25ae9SGregory Neil Shapiro 
249906f25ae9SGregory Neil Shapiro 					/* and send CR now */
250006f25ae9SGregory Neil Shapiro 					c = '\r';
250106f25ae9SGregory Neil Shapiro 				}
250206f25ae9SGregory Neil Shapiro 				else
250306f25ae9SGregory Neil Shapiro 				{
250406f25ae9SGregory Neil Shapiro 					/* Room to do it now */
250506f25ae9SGregory Neil Shapiro 					*bp++ = '\r';
250606f25ae9SGregory Neil Shapiro 					prevchar = '\r';
250706f25ae9SGregory Neil Shapiro 				}
250806f25ae9SGregory Neil Shapiro 			}
250906f25ae9SGregory Neil Shapiro 		}
251006f25ae9SGregory Neil Shapiro 		*bp++ = (char) c;
251106f25ae9SGregory Neil Shapiro 		prevchar = c;
251206f25ae9SGregory Neil Shapiro 		if (bp >= &buf[sizeof buf])
251306f25ae9SGregory Neil Shapiro 		{
251406f25ae9SGregory Neil Shapiro 			/* send chunk */
251506f25ae9SGregory Neil Shapiro 			response = milter_send_command(m, SMFIC_BODY, buf,
251606f25ae9SGregory Neil Shapiro 						       bp - buf, e, state);
251706f25ae9SGregory Neil Shapiro 			bp = buf;
251806f25ae9SGregory Neil Shapiro 			if (bufchar != '\0')
251906f25ae9SGregory Neil Shapiro 			{
252006f25ae9SGregory Neil Shapiro 				*bp++ = bufchar;
252106f25ae9SGregory Neil Shapiro 				bufchar = '\0';
252206f25ae9SGregory Neil Shapiro 				prevchar = bufchar;
252306f25ae9SGregory Neil Shapiro 			}
252406f25ae9SGregory Neil Shapiro 		}
252506f25ae9SGregory Neil Shapiro 		if (m->mf_state == SMFS_ERROR ||
252606f25ae9SGregory Neil Shapiro 		    m->mf_state == SMFS_DONE ||
252706f25ae9SGregory Neil Shapiro 		    *state != SMFIR_CONTINUE)
252806f25ae9SGregory Neil Shapiro 			break;
252906f25ae9SGregory Neil Shapiro 	}
253006f25ae9SGregory Neil Shapiro 
253106f25ae9SGregory Neil Shapiro 	/* check for read errors */
253240266059SGregory Neil Shapiro 	if (sm_io_error(e->e_dfp))
253306f25ae9SGregory Neil Shapiro 	{
253406f25ae9SGregory Neil Shapiro 		ExitStat = EX_IOERR;
253506f25ae9SGregory Neil Shapiro 		if (*state == SMFIR_CONTINUE ||
253606f25ae9SGregory Neil Shapiro 		    *state == SMFIR_ACCEPT)
253706f25ae9SGregory Neil Shapiro 		{
253806f25ae9SGregory Neil Shapiro 			*state = SMFIR_TEMPFAIL;
253906f25ae9SGregory Neil Shapiro 			if (response != NULL)
254006f25ae9SGregory Neil Shapiro 			{
254140266059SGregory Neil Shapiro 				sm_free(response); /* XXX */
254206f25ae9SGregory Neil Shapiro 				response = NULL;
254306f25ae9SGregory Neil Shapiro 			}
254406f25ae9SGregory Neil Shapiro 		}
254540266059SGregory Neil Shapiro 		syserr("milter_body: %s/%cf%s: read error",
254640266059SGregory Neil Shapiro 		       qid_printqueue(e->e_qgrp, e->e_qdir),
254740266059SGregory Neil Shapiro 		       DATAFL_LETTER, e->e_id);
254806f25ae9SGregory Neil Shapiro 		return response;
254906f25ae9SGregory Neil Shapiro 	}
255006f25ae9SGregory Neil Shapiro 
255106f25ae9SGregory Neil Shapiro 	/* send last body chunk */
255206f25ae9SGregory Neil Shapiro 	if (bp > buf &&
255306f25ae9SGregory Neil Shapiro 	    m->mf_state != SMFS_ERROR &&
255406f25ae9SGregory Neil Shapiro 	    m->mf_state != SMFS_DONE &&
255506f25ae9SGregory Neil Shapiro 	    *state == SMFIR_CONTINUE)
255606f25ae9SGregory Neil Shapiro 	{
255706f25ae9SGregory Neil Shapiro 		/* send chunk */
255806f25ae9SGregory Neil Shapiro 		response = milter_send_command(m, SMFIC_BODY, buf, bp - buf,
255906f25ae9SGregory Neil Shapiro 					       e, state);
256006f25ae9SGregory Neil Shapiro 		bp = buf;
256106f25ae9SGregory Neil Shapiro 	}
256240266059SGregory Neil Shapiro 	if (MilterLogLevel > 17)
256340266059SGregory Neil Shapiro 		sm_syslog(LOG_INFO, e->e_id, "Milter (%s): body, sent",
256440266059SGregory Neil Shapiro 			  m->mf_name);
256506f25ae9SGregory Neil Shapiro 	return response;
256606f25ae9SGregory Neil Shapiro }
256706f25ae9SGregory Neil Shapiro 
256806f25ae9SGregory Neil Shapiro /*
256906f25ae9SGregory Neil Shapiro **  Actions
257006f25ae9SGregory Neil Shapiro */
257106f25ae9SGregory Neil Shapiro 
257240266059SGregory Neil Shapiro /*
257306f25ae9SGregory Neil Shapiro **  MILTER_ADDHEADER -- Add the supplied header to the message
257406f25ae9SGregory Neil Shapiro **
257506f25ae9SGregory Neil Shapiro **	Parameters:
257606f25ae9SGregory Neil Shapiro **		response -- encoded form of header/value.
257706f25ae9SGregory Neil Shapiro **		rlen -- length of response.
257806f25ae9SGregory Neil Shapiro **		e -- current envelope.
257906f25ae9SGregory Neil Shapiro **
258006f25ae9SGregory Neil Shapiro **	Returns:
258106f25ae9SGregory Neil Shapiro **		none
258206f25ae9SGregory Neil Shapiro */
258306f25ae9SGregory Neil Shapiro 
258406f25ae9SGregory Neil Shapiro static void
258506f25ae9SGregory Neil Shapiro milter_addheader(response, rlen, e)
258606f25ae9SGregory Neil Shapiro 	char *response;
258706f25ae9SGregory Neil Shapiro 	ssize_t rlen;
258806f25ae9SGregory Neil Shapiro 	ENVELOPE *e;
258906f25ae9SGregory Neil Shapiro {
259006f25ae9SGregory Neil Shapiro 	char *val;
2591193538b7SGregory Neil Shapiro 	HDR *h;
259206f25ae9SGregory Neil Shapiro 
259306f25ae9SGregory Neil Shapiro 	if (tTd(64, 10))
259440266059SGregory Neil Shapiro 		sm_dprintf("milter_addheader: ");
259506f25ae9SGregory Neil Shapiro 
259606f25ae9SGregory Neil Shapiro 	/* sanity checks */
259706f25ae9SGregory Neil Shapiro 	if (response == NULL)
259806f25ae9SGregory Neil Shapiro 	{
259906f25ae9SGregory Neil Shapiro 		if (tTd(64, 10))
260040266059SGregory Neil Shapiro 			sm_dprintf("NULL response\n");
260106f25ae9SGregory Neil Shapiro 		return;
260206f25ae9SGregory Neil Shapiro 	}
260306f25ae9SGregory Neil Shapiro 
260406f25ae9SGregory Neil Shapiro 	if (rlen < 2 || strlen(response) + 1 >= (size_t) rlen)
260506f25ae9SGregory Neil Shapiro 	{
260606f25ae9SGregory Neil Shapiro 		if (tTd(64, 10))
260740266059SGregory Neil Shapiro 			sm_dprintf("didn't follow protocol (total len)\n");
260806f25ae9SGregory Neil Shapiro 		return;
260906f25ae9SGregory Neil Shapiro 	}
261006f25ae9SGregory Neil Shapiro 
261106f25ae9SGregory Neil Shapiro 	/* Find separating NUL */
261206f25ae9SGregory Neil Shapiro 	val = response + strlen(response) + 1;
261306f25ae9SGregory Neil Shapiro 
261406f25ae9SGregory Neil Shapiro 	/* another sanity check */
261506f25ae9SGregory Neil Shapiro 	if (strlen(response) + strlen(val) + 2 != (size_t) rlen)
261606f25ae9SGregory Neil Shapiro 	{
261706f25ae9SGregory Neil Shapiro 		if (tTd(64, 10))
261840266059SGregory Neil Shapiro 			sm_dprintf("didn't follow protocol (part len)\n");
261906f25ae9SGregory Neil Shapiro 		return;
262006f25ae9SGregory Neil Shapiro 	}
262106f25ae9SGregory Neil Shapiro 
262206f25ae9SGregory Neil Shapiro 	if (*response == '\0')
262306f25ae9SGregory Neil Shapiro 	{
262406f25ae9SGregory Neil Shapiro 		if (tTd(64, 10))
262540266059SGregory Neil Shapiro 			sm_dprintf("empty field name\n");
262606f25ae9SGregory Neil Shapiro 		return;
262706f25ae9SGregory Neil Shapiro 	}
262806f25ae9SGregory Neil Shapiro 
2629193538b7SGregory Neil Shapiro 	for (h = e->e_header; h != NULL; h = h->h_link)
2630193538b7SGregory Neil Shapiro 	{
263140266059SGregory Neil Shapiro 		if (sm_strcasecmp(h->h_field, response) == 0 &&
2632193538b7SGregory Neil Shapiro 		    !bitset(H_USER, h->h_flags) &&
2633193538b7SGregory Neil Shapiro 		    !bitset(H_TRACE, h->h_flags))
2634193538b7SGregory Neil Shapiro 			break;
2635193538b7SGregory Neil Shapiro 	}
2636193538b7SGregory Neil Shapiro 
263706f25ae9SGregory Neil Shapiro 	/* add to e_msgsize */
263806f25ae9SGregory Neil Shapiro 	e->e_msgsize += strlen(response) + 2 + strlen(val);
263906f25ae9SGregory Neil Shapiro 
2640193538b7SGregory Neil Shapiro 	if (h != NULL)
2641193538b7SGregory Neil Shapiro 	{
2642193538b7SGregory Neil Shapiro 		if (tTd(64, 10))
264340266059SGregory Neil Shapiro 			sm_dprintf("Replace default header %s value with %s\n",
264440266059SGregory Neil Shapiro 				   h->h_field, val);
264540266059SGregory Neil Shapiro 		if (MilterLogLevel > 8)
264640266059SGregory Neil Shapiro 			sm_syslog(LOG_INFO, e->e_id,
264740266059SGregory Neil Shapiro 				  "Milter change: default header %s value with %s",
2648193538b7SGregory Neil Shapiro 				  h->h_field, val);
2649193538b7SGregory Neil Shapiro 		h->h_value = newstr(val);
2650193538b7SGregory Neil Shapiro 		h->h_flags |= H_USER;
2651193538b7SGregory Neil Shapiro 	}
2652193538b7SGregory Neil Shapiro 	else
2653193538b7SGregory Neil Shapiro 	{
265406f25ae9SGregory Neil Shapiro 		if (tTd(64, 10))
265540266059SGregory Neil Shapiro 			sm_dprintf("Add %s: %s\n", response, val);
265640266059SGregory Neil Shapiro 		if (MilterLogLevel > 8)
265740266059SGregory Neil Shapiro 			sm_syslog(LOG_INFO, e->e_id, "Milter add: header: %s: %s",
265840266059SGregory Neil Shapiro 				  response, val);
265940266059SGregory Neil Shapiro 		addheader(newstr(response), val, H_USER, e);
266006f25ae9SGregory Neil Shapiro 	}
2661193538b7SGregory Neil Shapiro }
266240266059SGregory Neil Shapiro /*
2663e92d3f3fSGregory Neil Shapiro **  MILTER_INSHEADER -- Insert the supplied header
2664e92d3f3fSGregory Neil Shapiro **
2665e92d3f3fSGregory Neil Shapiro **	Parameters:
2666e92d3f3fSGregory Neil Shapiro **		response -- encoded form of header/value.
2667e92d3f3fSGregory Neil Shapiro **		rlen -- length of response.
2668e92d3f3fSGregory Neil Shapiro **		e -- current envelope.
2669e92d3f3fSGregory Neil Shapiro **
2670e92d3f3fSGregory Neil Shapiro **	Returns:
2671e92d3f3fSGregory Neil Shapiro **		none
2672e92d3f3fSGregory Neil Shapiro **
2673e92d3f3fSGregory Neil Shapiro **  	Notes:
2674e92d3f3fSGregory Neil Shapiro **  		Unlike milter_addheader(), this does not attempt to determine
2675e92d3f3fSGregory Neil Shapiro **  		if the header already exists in the envelope, even a
2676e92d3f3fSGregory Neil Shapiro **  		deleted version.  It just blindly inserts.
2677e92d3f3fSGregory Neil Shapiro */
2678e92d3f3fSGregory Neil Shapiro 
2679e92d3f3fSGregory Neil Shapiro static void
2680e92d3f3fSGregory Neil Shapiro milter_insheader(response, rlen, e)
2681e92d3f3fSGregory Neil Shapiro 	char *response;
2682e92d3f3fSGregory Neil Shapiro 	ssize_t rlen;
2683e92d3f3fSGregory Neil Shapiro 	ENVELOPE *e;
2684e92d3f3fSGregory Neil Shapiro {
2685e92d3f3fSGregory Neil Shapiro 	mi_int32 idx, i;
2686e92d3f3fSGregory Neil Shapiro 	char *field;
2687e92d3f3fSGregory Neil Shapiro 	char *val;
2688e92d3f3fSGregory Neil Shapiro 
2689e92d3f3fSGregory Neil Shapiro 	if (tTd(64, 10))
2690e92d3f3fSGregory Neil Shapiro 		sm_dprintf("milter_insheader: ");
2691e92d3f3fSGregory Neil Shapiro 
2692e92d3f3fSGregory Neil Shapiro 	/* sanity checks */
2693e92d3f3fSGregory Neil Shapiro 	if (response == NULL)
2694e92d3f3fSGregory Neil Shapiro 	{
2695e92d3f3fSGregory Neil Shapiro 		if (tTd(64, 10))
2696e92d3f3fSGregory Neil Shapiro 			sm_dprintf("NULL response\n");
2697e92d3f3fSGregory Neil Shapiro 		return;
2698e92d3f3fSGregory Neil Shapiro 	}
2699e92d3f3fSGregory Neil Shapiro 
2700e92d3f3fSGregory Neil Shapiro 	if (rlen < 2 || strlen(response) + 1 >= (size_t) rlen)
2701e92d3f3fSGregory Neil Shapiro 	{
2702e92d3f3fSGregory Neil Shapiro 		if (tTd(64, 10))
2703e92d3f3fSGregory Neil Shapiro 			sm_dprintf("didn't follow protocol (total len)\n");
2704e92d3f3fSGregory Neil Shapiro 		return;
2705e92d3f3fSGregory Neil Shapiro 	}
2706e92d3f3fSGregory Neil Shapiro 
2707e92d3f3fSGregory Neil Shapiro 	/* decode */
2708e92d3f3fSGregory Neil Shapiro 	(void) memcpy((char *) &i, response, MILTER_LEN_BYTES);
2709e92d3f3fSGregory Neil Shapiro 	idx = ntohl(i);
2710e92d3f3fSGregory Neil Shapiro 	field = response + MILTER_LEN_BYTES;
2711e92d3f3fSGregory Neil Shapiro 	val = field + strlen(field) + 1;
2712e92d3f3fSGregory Neil Shapiro 
2713e92d3f3fSGregory Neil Shapiro 	/* another sanity check */
2714e92d3f3fSGregory Neil Shapiro 	if (MILTER_LEN_BYTES + strlen(field) + 1 +
2715e92d3f3fSGregory Neil Shapiro 	    strlen(val) + 1 != (size_t) rlen)
2716e92d3f3fSGregory Neil Shapiro 	{
2717e92d3f3fSGregory Neil Shapiro 		if (tTd(64, 10))
2718e92d3f3fSGregory Neil Shapiro 			sm_dprintf("didn't follow protocol (part len)\n");
2719e92d3f3fSGregory Neil Shapiro 		return;
2720e92d3f3fSGregory Neil Shapiro 	}
2721e92d3f3fSGregory Neil Shapiro 
2722e92d3f3fSGregory Neil Shapiro 	if (*field == '\0')
2723e92d3f3fSGregory Neil Shapiro 	{
2724e92d3f3fSGregory Neil Shapiro 		if (tTd(64, 10))
2725e92d3f3fSGregory Neil Shapiro 			sm_dprintf("empty field name\n");
2726e92d3f3fSGregory Neil Shapiro 		return;
2727e92d3f3fSGregory Neil Shapiro 	}
2728e92d3f3fSGregory Neil Shapiro 
2729e92d3f3fSGregory Neil Shapiro 	/* add to e_msgsize */
2730e92d3f3fSGregory Neil Shapiro 	e->e_msgsize += strlen(response) + 2 + strlen(val);
2731e92d3f3fSGregory Neil Shapiro 
2732e92d3f3fSGregory Neil Shapiro 	if (tTd(64, 10))
2733e92d3f3fSGregory Neil Shapiro 		sm_dprintf("Insert (%d) %s: %s\n", idx, response, val);
2734e92d3f3fSGregory Neil Shapiro 	if (MilterLogLevel > 8)
2735e92d3f3fSGregory Neil Shapiro 		sm_syslog(LOG_INFO, e->e_id,
2736e92d3f3fSGregory Neil Shapiro 		          "Milter insert (%d): header: %s: %s",
2737e92d3f3fSGregory Neil Shapiro 			  idx, field, val);
2738e92d3f3fSGregory Neil Shapiro 	insheader(idx, newstr(field), val, H_USER, e);
2739e92d3f3fSGregory Neil Shapiro }
2740e92d3f3fSGregory Neil Shapiro /*
274106f25ae9SGregory Neil Shapiro **  MILTER_CHANGEHEADER -- Change the supplied header in the message
274206f25ae9SGregory Neil Shapiro **
274306f25ae9SGregory Neil Shapiro **	Parameters:
274406f25ae9SGregory Neil Shapiro **		response -- encoded form of header/index/value.
274506f25ae9SGregory Neil Shapiro **		rlen -- length of response.
274606f25ae9SGregory Neil Shapiro **		e -- current envelope.
274706f25ae9SGregory Neil Shapiro **
274806f25ae9SGregory Neil Shapiro **	Returns:
274906f25ae9SGregory Neil Shapiro **		none
275006f25ae9SGregory Neil Shapiro */
275106f25ae9SGregory Neil Shapiro 
275206f25ae9SGregory Neil Shapiro static void
275306f25ae9SGregory Neil Shapiro milter_changeheader(response, rlen, e)
275406f25ae9SGregory Neil Shapiro 	char *response;
275506f25ae9SGregory Neil Shapiro 	ssize_t rlen;
275606f25ae9SGregory Neil Shapiro 	ENVELOPE *e;
275706f25ae9SGregory Neil Shapiro {
275806f25ae9SGregory Neil Shapiro 	mi_int32 i, index;
275906f25ae9SGregory Neil Shapiro 	char *field, *val;
2760193538b7SGregory Neil Shapiro 	HDR *h, *sysheader;
276106f25ae9SGregory Neil Shapiro 
276206f25ae9SGregory Neil Shapiro 	if (tTd(64, 10))
276340266059SGregory Neil Shapiro 		sm_dprintf("milter_changeheader: ");
276406f25ae9SGregory Neil Shapiro 
276506f25ae9SGregory Neil Shapiro 	/* sanity checks */
276606f25ae9SGregory Neil Shapiro 	if (response == NULL)
276706f25ae9SGregory Neil Shapiro 	{
276806f25ae9SGregory Neil Shapiro 		if (tTd(64, 10))
276940266059SGregory Neil Shapiro 			sm_dprintf("NULL response\n");
277006f25ae9SGregory Neil Shapiro 		return;
277106f25ae9SGregory Neil Shapiro 	}
277206f25ae9SGregory Neil Shapiro 
277306f25ae9SGregory Neil Shapiro 	if (rlen < 2 || strlen(response) + 1 >= (size_t) rlen)
277406f25ae9SGregory Neil Shapiro 	{
277506f25ae9SGregory Neil Shapiro 		if (tTd(64, 10))
277640266059SGregory Neil Shapiro 			sm_dprintf("didn't follow protocol (total len)\n");
277706f25ae9SGregory Neil Shapiro 		return;
277806f25ae9SGregory Neil Shapiro 	}
277906f25ae9SGregory Neil Shapiro 
278006f25ae9SGregory Neil Shapiro 	/* Find separating NUL */
278106f25ae9SGregory Neil Shapiro 	(void) memcpy((char *) &i, response, MILTER_LEN_BYTES);
278206f25ae9SGregory Neil Shapiro 	index = ntohl(i);
278306f25ae9SGregory Neil Shapiro 	field = response + MILTER_LEN_BYTES;
278406f25ae9SGregory Neil Shapiro 	val = field + strlen(field) + 1;
278506f25ae9SGregory Neil Shapiro 
278606f25ae9SGregory Neil Shapiro 	/* another sanity check */
278706f25ae9SGregory Neil Shapiro 	if (MILTER_LEN_BYTES + strlen(field) + 1 +
278806f25ae9SGregory Neil Shapiro 	    strlen(val) + 1 != (size_t) rlen)
278906f25ae9SGregory Neil Shapiro 	{
279006f25ae9SGregory Neil Shapiro 		if (tTd(64, 10))
279140266059SGregory Neil Shapiro 			sm_dprintf("didn't follow protocol (part len)\n");
279206f25ae9SGregory Neil Shapiro 		return;
279306f25ae9SGregory Neil Shapiro 	}
279406f25ae9SGregory Neil Shapiro 
279506f25ae9SGregory Neil Shapiro 	if (*field == '\0')
279606f25ae9SGregory Neil Shapiro 	{
279706f25ae9SGregory Neil Shapiro 		if (tTd(64, 10))
279840266059SGregory Neil Shapiro 			sm_dprintf("empty field name\n");
279906f25ae9SGregory Neil Shapiro 		return;
280006f25ae9SGregory Neil Shapiro 	}
280106f25ae9SGregory Neil Shapiro 
2802193538b7SGregory Neil Shapiro 	sysheader = NULL;
280306f25ae9SGregory Neil Shapiro 	for (h = e->e_header; h != NULL; h = h->h_link)
280406f25ae9SGregory Neil Shapiro 	{
280540266059SGregory Neil Shapiro 		if (sm_strcasecmp(h->h_field, field) == 0)
2806193538b7SGregory Neil Shapiro 		{
280706f25ae9SGregory Neil Shapiro 			if (bitset(H_USER, h->h_flags) &&
280806f25ae9SGregory Neil Shapiro 			    --index <= 0)
2809193538b7SGregory Neil Shapiro 			{
2810193538b7SGregory Neil Shapiro 				sysheader = NULL;
281106f25ae9SGregory Neil Shapiro 				break;
281206f25ae9SGregory Neil Shapiro 			}
2813193538b7SGregory Neil Shapiro 			else if (!bitset(H_USER, h->h_flags) &&
2814193538b7SGregory Neil Shapiro 				 !bitset(H_TRACE, h->h_flags))
2815193538b7SGregory Neil Shapiro 			{
2816193538b7SGregory Neil Shapiro 				/*
2817193538b7SGregory Neil Shapiro 				**  DRUMS msg-fmt draft says can only have
2818193538b7SGregory Neil Shapiro 				**  multiple occurences of trace fields,
2819193538b7SGregory Neil Shapiro 				**  so make sure we replace any non-trace,
2820193538b7SGregory Neil Shapiro 				**  non-user field.
2821193538b7SGregory Neil Shapiro 				*/
2822193538b7SGregory Neil Shapiro 
2823193538b7SGregory Neil Shapiro 				sysheader = h;
2824193538b7SGregory Neil Shapiro 			}
2825193538b7SGregory Neil Shapiro 		}
2826193538b7SGregory Neil Shapiro 	}
2827193538b7SGregory Neil Shapiro 
2828193538b7SGregory Neil Shapiro 	/* if not found as user-provided header at index, use sysheader */
2829193538b7SGregory Neil Shapiro 	if (h == NULL)
2830193538b7SGregory Neil Shapiro 		h = sysheader;
283106f25ae9SGregory Neil Shapiro 
283206f25ae9SGregory Neil Shapiro 	if (h == NULL)
283306f25ae9SGregory Neil Shapiro 	{
283406f25ae9SGregory Neil Shapiro 		if (*val == '\0')
283506f25ae9SGregory Neil Shapiro 		{
283606f25ae9SGregory Neil Shapiro 			if (tTd(64, 10))
2837b6bacd31SGregory Neil Shapiro 				sm_dprintf("Delete (noop) %s\n", field);
2838b6bacd31SGregory Neil Shapiro 			if (MilterLogLevel > 8)
2839b6bacd31SGregory Neil Shapiro 				sm_syslog(LOG_INFO, e->e_id,
2840b6bacd31SGregory Neil Shapiro 					"Milter delete (noop): header: %s"
2841b6bacd31SGregory Neil Shapiro 					, field);
284206f25ae9SGregory Neil Shapiro 		}
284306f25ae9SGregory Neil Shapiro 		else
284406f25ae9SGregory Neil Shapiro 		{
284506f25ae9SGregory Neil Shapiro 			/* treat modify value with no existing header as add */
284606f25ae9SGregory Neil Shapiro 			if (tTd(64, 10))
284740266059SGregory Neil Shapiro 				sm_dprintf("Add %s: %s\n", field, val);
2848b6bacd31SGregory Neil Shapiro 			if (MilterLogLevel > 8)
2849b6bacd31SGregory Neil Shapiro 				sm_syslog(LOG_INFO, e->e_id,
2850b6bacd31SGregory Neil Shapiro 					"Milter change (add): header: %s: %s"
2851b6bacd31SGregory Neil Shapiro 					, field, val);
285240266059SGregory Neil Shapiro 			addheader(newstr(field), val, H_USER, e);
285306f25ae9SGregory Neil Shapiro 		}
285406f25ae9SGregory Neil Shapiro 		return;
285506f25ae9SGregory Neil Shapiro 	}
285606f25ae9SGregory Neil Shapiro 
285706f25ae9SGregory Neil Shapiro 	if (tTd(64, 10))
285806f25ae9SGregory Neil Shapiro 	{
285906f25ae9SGregory Neil Shapiro 		if (*val == '\0')
286006f25ae9SGregory Neil Shapiro 		{
286140266059SGregory Neil Shapiro 			sm_dprintf("Delete%s %s: %s\n",
2862193538b7SGregory Neil Shapiro 				   h == sysheader ? " (default header)" : "",
2863193538b7SGregory Neil Shapiro 				   field,
286406f25ae9SGregory Neil Shapiro 				   h->h_value == NULL ? "<NULL>" : h->h_value);
286506f25ae9SGregory Neil Shapiro 		}
286606f25ae9SGregory Neil Shapiro 		else
286706f25ae9SGregory Neil Shapiro 		{
286840266059SGregory Neil Shapiro 			sm_dprintf("Change%s %s: from %s to %s\n",
286940266059SGregory Neil Shapiro 				   h == sysheader ? " (default header)" : "",
287040266059SGregory Neil Shapiro 				   field,
287140266059SGregory Neil Shapiro 				   h->h_value == NULL ? "<NULL>" : h->h_value,
287240266059SGregory Neil Shapiro 				   val);
287340266059SGregory Neil Shapiro 		}
287440266059SGregory Neil Shapiro 	}
287540266059SGregory Neil Shapiro 
287640266059SGregory Neil Shapiro 	if (MilterLogLevel > 8)
287740266059SGregory Neil Shapiro 	{
287840266059SGregory Neil Shapiro 		if (*val == '\0')
287940266059SGregory Neil Shapiro 		{
288040266059SGregory Neil Shapiro 			sm_syslog(LOG_INFO, e->e_id,
288140266059SGregory Neil Shapiro 				  "Milter delete: header%s %s: %s",
288240266059SGregory Neil Shapiro 				  h == sysheader ? " (default header)" : "",
288340266059SGregory Neil Shapiro 				  field,
288440266059SGregory Neil Shapiro 				  h->h_value == NULL ? "<NULL>" : h->h_value);
288540266059SGregory Neil Shapiro 		}
288640266059SGregory Neil Shapiro 		else
288740266059SGregory Neil Shapiro 		{
288840266059SGregory Neil Shapiro 			sm_syslog(LOG_INFO, e->e_id,
288940266059SGregory Neil Shapiro 				  "Milter change: header%s %s: from %s to %s",
2890193538b7SGregory Neil Shapiro 				  h == sysheader ? " (default header)" : "",
289106f25ae9SGregory Neil Shapiro 				  field,
289206f25ae9SGregory Neil Shapiro 				  h->h_value == NULL ? "<NULL>" : h->h_value,
289306f25ae9SGregory Neil Shapiro 				  val);
289406f25ae9SGregory Neil Shapiro 		}
289506f25ae9SGregory Neil Shapiro 	}
289606f25ae9SGregory Neil Shapiro 
2897193538b7SGregory Neil Shapiro 	if (h != sysheader && h->h_value != NULL)
289806f25ae9SGregory Neil Shapiro 	{
289940266059SGregory Neil Shapiro 		size_t l;
290040266059SGregory Neil Shapiro 
290140266059SGregory Neil Shapiro 		l = strlen(h->h_value);
290240266059SGregory Neil Shapiro 		if (l > e->e_msgsize)
290340266059SGregory Neil Shapiro 			e->e_msgsize = 0;
290440266059SGregory Neil Shapiro 		else
290540266059SGregory Neil Shapiro 			e->e_msgsize -= l;
290640266059SGregory Neil Shapiro 		/* rpool, don't free: sm_free(h->h_value); XXX */
290706f25ae9SGregory Neil Shapiro 	}
290806f25ae9SGregory Neil Shapiro 
290906f25ae9SGregory Neil Shapiro 	if (*val == '\0')
291006f25ae9SGregory Neil Shapiro 	{
291106f25ae9SGregory Neil Shapiro 		/* Remove "Field: " from message size */
2912193538b7SGregory Neil Shapiro 		if (h != sysheader)
291340266059SGregory Neil Shapiro 		{
291440266059SGregory Neil Shapiro 			size_t l;
291540266059SGregory Neil Shapiro 
291640266059SGregory Neil Shapiro 			l = strlen(h->h_field) + 2;
291740266059SGregory Neil Shapiro 			if (l > e->e_msgsize)
291840266059SGregory Neil Shapiro 				e->e_msgsize = 0;
291940266059SGregory Neil Shapiro 			else
292040266059SGregory Neil Shapiro 				e->e_msgsize -= l;
292140266059SGregory Neil Shapiro 		}
292206f25ae9SGregory Neil Shapiro 		h->h_value = NULL;
292306f25ae9SGregory Neil Shapiro 	}
292406f25ae9SGregory Neil Shapiro 	else
292506f25ae9SGregory Neil Shapiro 	{
292606f25ae9SGregory Neil Shapiro 		h->h_value = newstr(val);
2927193538b7SGregory Neil Shapiro 		h->h_flags |= H_USER;
292806f25ae9SGregory Neil Shapiro 		e->e_msgsize += strlen(h->h_value);
292906f25ae9SGregory Neil Shapiro 	}
293006f25ae9SGregory Neil Shapiro }
293140266059SGregory Neil Shapiro /*
293206f25ae9SGregory Neil Shapiro **  MILTER_ADDRCPT -- Add the supplied recipient to the message
293306f25ae9SGregory Neil Shapiro **
293406f25ae9SGregory Neil Shapiro **	Parameters:
293506f25ae9SGregory Neil Shapiro **		response -- encoded form of recipient address.
293606f25ae9SGregory Neil Shapiro **		rlen -- length of response.
293706f25ae9SGregory Neil Shapiro **		e -- current envelope.
293806f25ae9SGregory Neil Shapiro **
293906f25ae9SGregory Neil Shapiro **	Returns:
294006f25ae9SGregory Neil Shapiro **		none
294106f25ae9SGregory Neil Shapiro */
294206f25ae9SGregory Neil Shapiro 
294306f25ae9SGregory Neil Shapiro static void
294406f25ae9SGregory Neil Shapiro milter_addrcpt(response, rlen, e)
294506f25ae9SGregory Neil Shapiro 	char *response;
294606f25ae9SGregory Neil Shapiro 	ssize_t rlen;
294706f25ae9SGregory Neil Shapiro 	ENVELOPE *e;
294806f25ae9SGregory Neil Shapiro {
2949a7ec597cSGregory Neil Shapiro 	int olderrors;
2950a7ec597cSGregory Neil Shapiro 
295106f25ae9SGregory Neil Shapiro 	if (tTd(64, 10))
295240266059SGregory Neil Shapiro 		sm_dprintf("milter_addrcpt: ");
295306f25ae9SGregory Neil Shapiro 
295406f25ae9SGregory Neil Shapiro 	/* sanity checks */
295506f25ae9SGregory Neil Shapiro 	if (response == NULL)
295606f25ae9SGregory Neil Shapiro 	{
295706f25ae9SGregory Neil Shapiro 		if (tTd(64, 10))
295840266059SGregory Neil Shapiro 			sm_dprintf("NULL response\n");
295906f25ae9SGregory Neil Shapiro 		return;
296006f25ae9SGregory Neil Shapiro 	}
296106f25ae9SGregory Neil Shapiro 
296206f25ae9SGregory Neil Shapiro 	if (*response == '\0' ||
296306f25ae9SGregory Neil Shapiro 	    strlen(response) + 1 != (size_t) rlen)
296406f25ae9SGregory Neil Shapiro 	{
296506f25ae9SGregory Neil Shapiro 		if (tTd(64, 10))
296640266059SGregory Neil Shapiro 			sm_dprintf("didn't follow protocol (total len %d != rlen %d)\n",
296740266059SGregory Neil Shapiro 				   (int) strlen(response), (int) (rlen - 1));
296806f25ae9SGregory Neil Shapiro 		return;
296906f25ae9SGregory Neil Shapiro 	}
297006f25ae9SGregory Neil Shapiro 
297106f25ae9SGregory Neil Shapiro 	if (tTd(64, 10))
297240266059SGregory Neil Shapiro 		sm_dprintf("%s\n", response);
297340266059SGregory Neil Shapiro 	if (MilterLogLevel > 8)
297440266059SGregory Neil Shapiro 		sm_syslog(LOG_INFO, e->e_id, "Milter add: rcpt: %s", response);
2975a7ec597cSGregory Neil Shapiro 	olderrors = Errors;
297606f25ae9SGregory Neil Shapiro 	(void) sendtolist(response, NULLADDR, &e->e_sendqueue, 0, e);
2977a7ec597cSGregory Neil Shapiro 	Errors = olderrors;
297806f25ae9SGregory Neil Shapiro 	return;
297906f25ae9SGregory Neil Shapiro }
298040266059SGregory Neil Shapiro /*
298106f25ae9SGregory Neil Shapiro **  MILTER_DELRCPT -- Delete the supplied recipient from the message
298206f25ae9SGregory Neil Shapiro **
298306f25ae9SGregory Neil Shapiro **	Parameters:
298406f25ae9SGregory Neil Shapiro **		response -- encoded form of recipient address.
298506f25ae9SGregory Neil Shapiro **		rlen -- length of response.
298606f25ae9SGregory Neil Shapiro **		e -- current envelope.
298706f25ae9SGregory Neil Shapiro **
298806f25ae9SGregory Neil Shapiro **	Returns:
298906f25ae9SGregory Neil Shapiro **		none
299006f25ae9SGregory Neil Shapiro */
299106f25ae9SGregory Neil Shapiro 
299206f25ae9SGregory Neil Shapiro static void
299306f25ae9SGregory Neil Shapiro milter_delrcpt(response, rlen, e)
299406f25ae9SGregory Neil Shapiro 	char *response;
299506f25ae9SGregory Neil Shapiro 	ssize_t rlen;
299606f25ae9SGregory Neil Shapiro 	ENVELOPE *e;
299706f25ae9SGregory Neil Shapiro {
299806f25ae9SGregory Neil Shapiro 	if (tTd(64, 10))
299940266059SGregory Neil Shapiro 		sm_dprintf("milter_delrcpt: ");
300006f25ae9SGregory Neil Shapiro 
300106f25ae9SGregory Neil Shapiro 	/* sanity checks */
300206f25ae9SGregory Neil Shapiro 	if (response == NULL)
300306f25ae9SGregory Neil Shapiro 	{
300406f25ae9SGregory Neil Shapiro 		if (tTd(64, 10))
300540266059SGregory Neil Shapiro 			sm_dprintf("NULL response\n");
300606f25ae9SGregory Neil Shapiro 		return;
300706f25ae9SGregory Neil Shapiro 	}
300806f25ae9SGregory Neil Shapiro 
300906f25ae9SGregory Neil Shapiro 	if (*response == '\0' ||
301006f25ae9SGregory Neil Shapiro 	    strlen(response) + 1 != (size_t) rlen)
301106f25ae9SGregory Neil Shapiro 	{
301206f25ae9SGregory Neil Shapiro 		if (tTd(64, 10))
301340266059SGregory Neil Shapiro 			sm_dprintf("didn't follow protocol (total len)\n");
301406f25ae9SGregory Neil Shapiro 		return;
301506f25ae9SGregory Neil Shapiro 	}
301606f25ae9SGregory Neil Shapiro 
301706f25ae9SGregory Neil Shapiro 	if (tTd(64, 10))
301840266059SGregory Neil Shapiro 		sm_dprintf("%s\n", response);
301940266059SGregory Neil Shapiro 	if (MilterLogLevel > 8)
302040266059SGregory Neil Shapiro 		sm_syslog(LOG_INFO, e->e_id, "Milter delete: rcpt %s",
302140266059SGregory Neil Shapiro 			  response);
302206f25ae9SGregory Neil Shapiro 	(void) removefromlist(response, &e->e_sendqueue, e);
302306f25ae9SGregory Neil Shapiro 	return;
302406f25ae9SGregory Neil Shapiro }
302540266059SGregory Neil Shapiro /*
302640266059SGregory Neil Shapiro **  MILTER_REPLBODY -- Replace the current data file with new body
302706f25ae9SGregory Neil Shapiro **
302806f25ae9SGregory Neil Shapiro **	Parameters:
302906f25ae9SGregory Neil Shapiro **		response -- encoded form of new body.
303006f25ae9SGregory Neil Shapiro **		rlen -- length of response.
303106f25ae9SGregory Neil Shapiro **		newfilter -- if first time called by a new filter
303206f25ae9SGregory Neil Shapiro **		e -- current envelope.
303306f25ae9SGregory Neil Shapiro **
303406f25ae9SGregory Neil Shapiro **	Returns:
303506f25ae9SGregory Neil Shapiro **		0 upon success, -1 upon failure
303606f25ae9SGregory Neil Shapiro */
303706f25ae9SGregory Neil Shapiro 
303806f25ae9SGregory Neil Shapiro static int
303906f25ae9SGregory Neil Shapiro milter_replbody(response, rlen, newfilter, e)
304006f25ae9SGregory Neil Shapiro 	char *response;
304106f25ae9SGregory Neil Shapiro 	ssize_t rlen;
304206f25ae9SGregory Neil Shapiro 	bool newfilter;
304306f25ae9SGregory Neil Shapiro 	ENVELOPE *e;
304406f25ae9SGregory Neil Shapiro {
304506f25ae9SGregory Neil Shapiro 	static char prevchar;
304606f25ae9SGregory Neil Shapiro 	int i;
304706f25ae9SGregory Neil Shapiro 
304806f25ae9SGregory Neil Shapiro 	if (tTd(64, 10))
304940266059SGregory Neil Shapiro 		sm_dprintf("milter_replbody\n");
305006f25ae9SGregory Neil Shapiro 
305140266059SGregory Neil Shapiro 	/* If a new filter, reset previous character and truncate data file */
305206f25ae9SGregory Neil Shapiro 	if (newfilter)
305306f25ae9SGregory Neil Shapiro 	{
3054605302a5SGregory Neil Shapiro 		off_t prevsize;
305506f25ae9SGregory Neil Shapiro 		char dfname[MAXPATHLEN];
305606f25ae9SGregory Neil Shapiro 
305740266059SGregory Neil Shapiro 		(void) sm_strlcpy(dfname, queuename(e, DATAFL_LETTER),
305840266059SGregory Neil Shapiro 				  sizeof dfname);
305906f25ae9SGregory Neil Shapiro 
306006f25ae9SGregory Neil Shapiro 		/* Reset prevchar */
306106f25ae9SGregory Neil Shapiro 		prevchar = '\0';
306206f25ae9SGregory Neil Shapiro 
306340266059SGregory Neil Shapiro 		/* Get the current data file information */
3064605302a5SGregory Neil Shapiro 		prevsize = sm_io_getinfo(e->e_dfp, SM_IO_WHAT_SIZE, NULL);
3065605302a5SGregory Neil Shapiro 		if (prevsize < 0)
3066605302a5SGregory Neil Shapiro 			prevsize = 0;
306706f25ae9SGregory Neil Shapiro 
306840266059SGregory Neil Shapiro 		/* truncate current data file */
306940266059SGregory Neil Shapiro 		if (sm_io_getinfo(e->e_dfp, SM_IO_WHAT_ISTYPE, BF_FILE_TYPE))
307006f25ae9SGregory Neil Shapiro 		{
307140266059SGregory Neil Shapiro 			if (sm_io_setinfo(e->e_dfp, SM_BF_TRUNCATE, NULL) < 0)
307240266059SGregory Neil Shapiro 			{
307340266059SGregory Neil Shapiro 				MILTER_DF_ERROR("milter_replbody: sm_io truncate %s: %s");
307406f25ae9SGregory Neil Shapiro 				return -1;
307506f25ae9SGregory Neil Shapiro 			}
307640266059SGregory Neil Shapiro 		}
307706f25ae9SGregory Neil Shapiro 		else
307806f25ae9SGregory Neil Shapiro 		{
307940266059SGregory Neil Shapiro 			int err;
308040266059SGregory Neil Shapiro 
308140266059SGregory Neil Shapiro 			err = sm_io_error(e->e_dfp);
308240266059SGregory Neil Shapiro 			(void) sm_io_flush(e->e_dfp, SM_TIME_DEFAULT);
308340266059SGregory Neil Shapiro 
308440266059SGregory Neil Shapiro 			/*
308540266059SGregory Neil Shapiro 			**  Clear error if tried to fflush()
308640266059SGregory Neil Shapiro 			**  a read-only file pointer and
308740266059SGregory Neil Shapiro 			**  there wasn't a previous error.
308840266059SGregory Neil Shapiro 			*/
308940266059SGregory Neil Shapiro 
309040266059SGregory Neil Shapiro 			if (err == 0)
309140266059SGregory Neil Shapiro 				sm_io_clearerr(e->e_dfp);
309240266059SGregory Neil Shapiro 
309340266059SGregory Neil Shapiro 			/* errno is set implicitly by fseek() before return */
309440266059SGregory Neil Shapiro 			err = sm_io_seek(e->e_dfp, SM_TIME_DEFAULT,
309540266059SGregory Neil Shapiro 					 0, SEEK_SET);
30966a2f2ff3SGregory Neil Shapiro 			if (err < 0)
30976a2f2ff3SGregory Neil Shapiro 			{
30986a2f2ff3SGregory Neil Shapiro 				MILTER_DF_ERROR("milter_replbody: sm_io_seek %s: %s");
30996a2f2ff3SGregory Neil Shapiro 				return -1;
31006a2f2ff3SGregory Neil Shapiro 			}
31016a2f2ff3SGregory Neil Shapiro # if NOFTRUNCATE
31026a2f2ff3SGregory Neil Shapiro 			/* XXX: Not much we can do except rewind it */
31036a2f2ff3SGregory Neil Shapiro 			errno = EINVAL;
31046a2f2ff3SGregory Neil Shapiro 			MILTER_DF_ERROR("milter_replbody: ftruncate not available on this platform (%s:%s)");
31056a2f2ff3SGregory Neil Shapiro 			return -1;
310640266059SGregory Neil Shapiro # else /* NOFTRUNCATE */
310740266059SGregory Neil Shapiro 			err = ftruncate(sm_io_getinfo(e->e_dfp,
310840266059SGregory Neil Shapiro 						      SM_IO_WHAT_FD, NULL),
310940266059SGregory Neil Shapiro 					0);
311040266059SGregory Neil Shapiro 			if (err < 0)
311140266059SGregory Neil Shapiro 			{
311240266059SGregory Neil Shapiro 				MILTER_DF_ERROR("milter_replbody: sm_io ftruncate %s: %s");
311340266059SGregory Neil Shapiro 				return -1;
311440266059SGregory Neil Shapiro 			}
31156a2f2ff3SGregory Neil Shapiro # endif /* NOFTRUNCATE */
311640266059SGregory Neil Shapiro 		}
311740266059SGregory Neil Shapiro 
311806f25ae9SGregory Neil Shapiro 		if (prevsize > e->e_msgsize)
311906f25ae9SGregory Neil Shapiro 			e->e_msgsize = 0;
312006f25ae9SGregory Neil Shapiro 		else
312106f25ae9SGregory Neil Shapiro 			e->e_msgsize -= prevsize;
312206f25ae9SGregory Neil Shapiro 	}
312340266059SGregory Neil Shapiro 
312440266059SGregory Neil Shapiro 	if (newfilter && MilterLogLevel > 8)
312540266059SGregory Neil Shapiro 		sm_syslog(LOG_INFO, e->e_id, "Milter message: body replaced");
312606f25ae9SGregory Neil Shapiro 
312706f25ae9SGregory Neil Shapiro 	if (response == NULL)
312806f25ae9SGregory Neil Shapiro 	{
312906f25ae9SGregory Neil Shapiro 		/* Flush the buffered '\r' */
313006f25ae9SGregory Neil Shapiro 		if (prevchar == '\r')
313106f25ae9SGregory Neil Shapiro 		{
313240266059SGregory Neil Shapiro 			(void) sm_io_putc(e->e_dfp, SM_TIME_DEFAULT, prevchar);
313306f25ae9SGregory Neil Shapiro 			e->e_msgsize++;
313406f25ae9SGregory Neil Shapiro 		}
313506f25ae9SGregory Neil Shapiro 		return 0;
313606f25ae9SGregory Neil Shapiro 	}
313706f25ae9SGregory Neil Shapiro 
313806f25ae9SGregory Neil Shapiro 	for (i = 0; i < rlen; i++)
313906f25ae9SGregory Neil Shapiro 	{
314006f25ae9SGregory Neil Shapiro 		/* Buffered char from last chunk */
314106f25ae9SGregory Neil Shapiro 		if (i == 0 && prevchar == '\r')
314206f25ae9SGregory Neil Shapiro 		{
314306f25ae9SGregory Neil Shapiro 			/* Not CRLF, output prevchar */
314406f25ae9SGregory Neil Shapiro 			if (response[i] != '\n')
314506f25ae9SGregory Neil Shapiro 			{
314640266059SGregory Neil Shapiro 				(void) sm_io_putc(e->e_dfp, SM_TIME_DEFAULT,
314740266059SGregory Neil Shapiro 						  prevchar);
314806f25ae9SGregory Neil Shapiro 				e->e_msgsize++;
314906f25ae9SGregory Neil Shapiro 			}
315006f25ae9SGregory Neil Shapiro 			prevchar = '\0';
315106f25ae9SGregory Neil Shapiro 		}
315206f25ae9SGregory Neil Shapiro 
315306f25ae9SGregory Neil Shapiro 		/* Turn CRLF into LF */
315406f25ae9SGregory Neil Shapiro 		if (response[i] == '\r')
315506f25ae9SGregory Neil Shapiro 		{
315606f25ae9SGregory Neil Shapiro 			/* check if at end of chunk */
315706f25ae9SGregory Neil Shapiro 			if (i + 1 < rlen)
315806f25ae9SGregory Neil Shapiro 			{
315906f25ae9SGregory Neil Shapiro 				/* If LF, strip CR */
316006f25ae9SGregory Neil Shapiro 				if (response[i + 1] == '\n')
316106f25ae9SGregory Neil Shapiro 					i++;
316206f25ae9SGregory Neil Shapiro 			}
316306f25ae9SGregory Neil Shapiro 			else
316406f25ae9SGregory Neil Shapiro 			{
316506f25ae9SGregory Neil Shapiro 				/* check next chunk */
316606f25ae9SGregory Neil Shapiro 				prevchar = '\r';
316706f25ae9SGregory Neil Shapiro 				continue;
316806f25ae9SGregory Neil Shapiro 			}
316906f25ae9SGregory Neil Shapiro 		}
317040266059SGregory Neil Shapiro 		(void) sm_io_putc(e->e_dfp, SM_TIME_DEFAULT, response[i]);
317106f25ae9SGregory Neil Shapiro 		e->e_msgsize++;
317206f25ae9SGregory Neil Shapiro 	}
317306f25ae9SGregory Neil Shapiro 	return 0;
317406f25ae9SGregory Neil Shapiro }
317506f25ae9SGregory Neil Shapiro 
317606f25ae9SGregory Neil Shapiro /*
317706f25ae9SGregory Neil Shapiro **  MTA callouts
317806f25ae9SGregory Neil Shapiro */
317906f25ae9SGregory Neil Shapiro 
318040266059SGregory Neil Shapiro /*
318106f25ae9SGregory Neil Shapiro **  MILTER_INIT -- open and negotiate with all of the filters
318206f25ae9SGregory Neil Shapiro **
318306f25ae9SGregory Neil Shapiro **	Parameters:
318406f25ae9SGregory Neil Shapiro **		e -- current envelope.
318506f25ae9SGregory Neil Shapiro **		state -- return state from response.
318606f25ae9SGregory Neil Shapiro **
318706f25ae9SGregory Neil Shapiro **	Returns:
318840266059SGregory Neil Shapiro **		true iff at least one filter is active
318906f25ae9SGregory Neil Shapiro */
319006f25ae9SGregory Neil Shapiro 
319106f25ae9SGregory Neil Shapiro /* ARGSUSED */
319240266059SGregory Neil Shapiro bool
319306f25ae9SGregory Neil Shapiro milter_init(e, state)
319406f25ae9SGregory Neil Shapiro 	ENVELOPE *e;
319506f25ae9SGregory Neil Shapiro 	char *state;
319606f25ae9SGregory Neil Shapiro {
319706f25ae9SGregory Neil Shapiro 	int i;
319806f25ae9SGregory Neil Shapiro 
319906f25ae9SGregory Neil Shapiro 	if (tTd(64, 10))
320040266059SGregory Neil Shapiro 		sm_dprintf("milter_init\n");
320106f25ae9SGregory Neil Shapiro 
320206f25ae9SGregory Neil Shapiro 	*state = SMFIR_CONTINUE;
320340266059SGregory Neil Shapiro 	if (InputFilters[0] == NULL)
320440266059SGregory Neil Shapiro 	{
320540266059SGregory Neil Shapiro 		if (MilterLogLevel > 10)
320640266059SGregory Neil Shapiro 			sm_syslog(LOG_INFO, e->e_id,
320740266059SGregory Neil Shapiro 				  "Milter: no active filter");
320840266059SGregory Neil Shapiro 		return false;
320940266059SGregory Neil Shapiro 	}
321040266059SGregory Neil Shapiro 
321106f25ae9SGregory Neil Shapiro 	for (i = 0; InputFilters[i] != NULL; i++)
321206f25ae9SGregory Neil Shapiro 	{
321306f25ae9SGregory Neil Shapiro 		struct milter *m = InputFilters[i];
321406f25ae9SGregory Neil Shapiro 
321540266059SGregory Neil Shapiro 		m->mf_sock = milter_open(m, false, e);
321606f25ae9SGregory Neil Shapiro 		if (m->mf_state == SMFS_ERROR)
321706f25ae9SGregory Neil Shapiro 		{
32185ef517c0SGregory Neil Shapiro 			MILTER_CHECK_ERROR(true, continue);
321906f25ae9SGregory Neil Shapiro 			break;
322006f25ae9SGregory Neil Shapiro 		}
322106f25ae9SGregory Neil Shapiro 
322206f25ae9SGregory Neil Shapiro 		if (m->mf_sock < 0 ||
322306f25ae9SGregory Neil Shapiro 		    milter_negotiate(m, e) < 0 ||
322406f25ae9SGregory Neil Shapiro 		    m->mf_state == SMFS_ERROR)
322506f25ae9SGregory Neil Shapiro 		{
322606f25ae9SGregory Neil Shapiro 			if (tTd(64, 5))
322740266059SGregory Neil Shapiro 				sm_dprintf("milter_init(%s): failed to %s\n",
322806f25ae9SGregory Neil Shapiro 					   m->mf_name,
322940266059SGregory Neil Shapiro 					   m->mf_sock < 0 ? "open" :
323040266059SGregory Neil Shapiro 							    "negotiate");
323140266059SGregory Neil Shapiro 			if (MilterLogLevel > 0)
323240266059SGregory Neil Shapiro 				sm_syslog(LOG_ERR, e->e_id,
323340266059SGregory Neil Shapiro 					  "Milter (%s): init failed to %s",
323440266059SGregory Neil Shapiro 					  m->mf_name,
323540266059SGregory Neil Shapiro 					  m->mf_sock < 0 ? "open" :
323640266059SGregory Neil Shapiro 							   "negotiate");
323706f25ae9SGregory Neil Shapiro 
323806f25ae9SGregory Neil Shapiro 			/* if negotation failure, close socket */
323940266059SGregory Neil Shapiro 			milter_error(m, e);
32405ef517c0SGregory Neil Shapiro 			MILTER_CHECK_ERROR(true, continue);
3241e92d3f3fSGregory Neil Shapiro 			continue;
324206f25ae9SGregory Neil Shapiro 		}
324340266059SGregory Neil Shapiro 		if (MilterLogLevel > 9)
324440266059SGregory Neil Shapiro 			sm_syslog(LOG_INFO, e->e_id,
324540266059SGregory Neil Shapiro 				  "Milter (%s): init success to %s",
324640266059SGregory Neil Shapiro 				  m->mf_name,
324740266059SGregory Neil Shapiro 				  m->mf_sock < 0 ? "open" : "negotiate");
324806f25ae9SGregory Neil Shapiro 	}
324906f25ae9SGregory Neil Shapiro 
325006f25ae9SGregory Neil Shapiro 	/*
325106f25ae9SGregory Neil Shapiro 	**  If something temp/perm failed with one of the filters,
325206f25ae9SGregory Neil Shapiro 	**  we won't be using any of them, so clear any existing
325306f25ae9SGregory Neil Shapiro 	**  connections.
325406f25ae9SGregory Neil Shapiro 	*/
325506f25ae9SGregory Neil Shapiro 
325606f25ae9SGregory Neil Shapiro 	if (*state != SMFIR_CONTINUE)
325706f25ae9SGregory Neil Shapiro 		milter_quit(e);
325840266059SGregory Neil Shapiro 
325940266059SGregory Neil Shapiro 	return true;
326006f25ae9SGregory Neil Shapiro }
326140266059SGregory Neil Shapiro /*
326206f25ae9SGregory Neil Shapiro **  MILTER_CONNECT -- send connection info to milter filters
326306f25ae9SGregory Neil Shapiro **
326406f25ae9SGregory Neil Shapiro **	Parameters:
326506f25ae9SGregory Neil Shapiro **		hostname -- hostname of remote machine.
326606f25ae9SGregory Neil Shapiro **		addr -- address of remote machine.
326706f25ae9SGregory Neil Shapiro **		e -- current envelope.
326806f25ae9SGregory Neil Shapiro **		state -- return state from response.
326906f25ae9SGregory Neil Shapiro **
327006f25ae9SGregory Neil Shapiro **	Returns:
327106f25ae9SGregory Neil Shapiro **		response string (may be NULL)
327206f25ae9SGregory Neil Shapiro */
327306f25ae9SGregory Neil Shapiro 
327406f25ae9SGregory Neil Shapiro char *
327506f25ae9SGregory Neil Shapiro milter_connect(hostname, addr, e, state)
327606f25ae9SGregory Neil Shapiro 	char *hostname;
327706f25ae9SGregory Neil Shapiro 	SOCKADDR addr;
327806f25ae9SGregory Neil Shapiro 	ENVELOPE *e;
327906f25ae9SGregory Neil Shapiro 	char *state;
328006f25ae9SGregory Neil Shapiro {
328106f25ae9SGregory Neil Shapiro 	char family;
328240266059SGregory Neil Shapiro 	unsigned short port;
328306f25ae9SGregory Neil Shapiro 	char *buf, *bp;
328406f25ae9SGregory Neil Shapiro 	char *response;
328506f25ae9SGregory Neil Shapiro 	char *sockinfo = NULL;
328606f25ae9SGregory Neil Shapiro 	ssize_t s;
328706f25ae9SGregory Neil Shapiro # if NETINET6
328806f25ae9SGregory Neil Shapiro 	char buf6[INET6_ADDRSTRLEN];
328906f25ae9SGregory Neil Shapiro # endif /* NETINET6 */
329006f25ae9SGregory Neil Shapiro 
329106f25ae9SGregory Neil Shapiro 	if (tTd(64, 10))
329240266059SGregory Neil Shapiro 		sm_dprintf("milter_connect(%s)\n", hostname);
329340266059SGregory Neil Shapiro 	if (MilterLogLevel > 9)
329440266059SGregory Neil Shapiro 		sm_syslog(LOG_INFO, e->e_id, "Milter: connect to filters");
329506f25ae9SGregory Neil Shapiro 
329606f25ae9SGregory Neil Shapiro 	/* gather data */
329706f25ae9SGregory Neil Shapiro 	switch (addr.sa.sa_family)
329806f25ae9SGregory Neil Shapiro 	{
329906f25ae9SGregory Neil Shapiro # if NETUNIX
330006f25ae9SGregory Neil Shapiro 	  case AF_UNIX:
330106f25ae9SGregory Neil Shapiro 		family = SMFIA_UNIX;
330206f25ae9SGregory Neil Shapiro 		port = htons(0);
330306f25ae9SGregory Neil Shapiro 		sockinfo = addr.sunix.sun_path;
330406f25ae9SGregory Neil Shapiro 		break;
330506f25ae9SGregory Neil Shapiro # endif /* NETUNIX */
330606f25ae9SGregory Neil Shapiro 
330706f25ae9SGregory Neil Shapiro # if NETINET
330806f25ae9SGregory Neil Shapiro 	  case AF_INET:
330906f25ae9SGregory Neil Shapiro 		family = SMFIA_INET;
3310605302a5SGregory Neil Shapiro 		port = addr.sin.sin_port;
331106f25ae9SGregory Neil Shapiro 		sockinfo = (char *) inet_ntoa(addr.sin.sin_addr);
331206f25ae9SGregory Neil Shapiro 		break;
331306f25ae9SGregory Neil Shapiro # endif /* NETINET */
331406f25ae9SGregory Neil Shapiro 
331506f25ae9SGregory Neil Shapiro # if NETINET6
331606f25ae9SGregory Neil Shapiro 	  case AF_INET6:
331713058a91SGregory Neil Shapiro 		if (IN6_IS_ADDR_V4MAPPED(&addr.sin6.sin6_addr))
331813058a91SGregory Neil Shapiro 			family = SMFIA_INET;
331913058a91SGregory Neil Shapiro 		else
332006f25ae9SGregory Neil Shapiro 			family = SMFIA_INET6;
3321605302a5SGregory Neil Shapiro 		port = addr.sin6.sin6_port;
332206f25ae9SGregory Neil Shapiro 		sockinfo = anynet_ntop(&addr.sin6.sin6_addr, buf6,
332306f25ae9SGregory Neil Shapiro 				       sizeof buf6);
332406f25ae9SGregory Neil Shapiro 		if (sockinfo == NULL)
332506f25ae9SGregory Neil Shapiro 			sockinfo = "";
332606f25ae9SGregory Neil Shapiro 		break;
332706f25ae9SGregory Neil Shapiro # endif /* NETINET6 */
332806f25ae9SGregory Neil Shapiro 
332906f25ae9SGregory Neil Shapiro 	  default:
333006f25ae9SGregory Neil Shapiro 		family = SMFIA_UNKNOWN;
333106f25ae9SGregory Neil Shapiro 		break;
333206f25ae9SGregory Neil Shapiro 	}
333306f25ae9SGregory Neil Shapiro 
333406f25ae9SGregory Neil Shapiro 	s = strlen(hostname) + 1 + sizeof(family);
333506f25ae9SGregory Neil Shapiro 	if (family != SMFIA_UNKNOWN)
333606f25ae9SGregory Neil Shapiro 		s += sizeof(port) + strlen(sockinfo) + 1;
333706f25ae9SGregory Neil Shapiro 
333806f25ae9SGregory Neil Shapiro 	buf = (char *) xalloc(s);
333906f25ae9SGregory Neil Shapiro 	bp = buf;
334006f25ae9SGregory Neil Shapiro 
334106f25ae9SGregory Neil Shapiro 	/* put together data */
334206f25ae9SGregory Neil Shapiro 	(void) memcpy(bp, hostname, strlen(hostname));
334306f25ae9SGregory Neil Shapiro 	bp += strlen(hostname);
334406f25ae9SGregory Neil Shapiro 	*bp++ = '\0';
334506f25ae9SGregory Neil Shapiro 	(void) memcpy(bp, &family, sizeof family);
334606f25ae9SGregory Neil Shapiro 	bp += sizeof family;
334706f25ae9SGregory Neil Shapiro 	if (family != SMFIA_UNKNOWN)
334806f25ae9SGregory Neil Shapiro 	{
334906f25ae9SGregory Neil Shapiro 		(void) memcpy(bp, &port, sizeof port);
335006f25ae9SGregory Neil Shapiro 		bp += sizeof port;
335106f25ae9SGregory Neil Shapiro 
335206f25ae9SGregory Neil Shapiro 		/* include trailing '\0' */
335306f25ae9SGregory Neil Shapiro 		(void) memcpy(bp, sockinfo, strlen(sockinfo) + 1);
335406f25ae9SGregory Neil Shapiro 	}
335506f25ae9SGregory Neil Shapiro 
335606f25ae9SGregory Neil Shapiro 	response = milter_command(SMFIC_CONNECT, buf, s,
335706f25ae9SGregory Neil Shapiro 				  MilterConnectMacros, e, state);
335840266059SGregory Neil Shapiro 	sm_free(buf); /* XXX */
335906f25ae9SGregory Neil Shapiro 
336006f25ae9SGregory Neil Shapiro 	/*
336106f25ae9SGregory Neil Shapiro 	**  If this message connection is done for,
336206f25ae9SGregory Neil Shapiro 	**  close the filters.
336306f25ae9SGregory Neil Shapiro 	*/
336406f25ae9SGregory Neil Shapiro 
336506f25ae9SGregory Neil Shapiro 	if (*state != SMFIR_CONTINUE)
336640266059SGregory Neil Shapiro 	{
336740266059SGregory Neil Shapiro 		if (MilterLogLevel > 9)
336840266059SGregory Neil Shapiro 			sm_syslog(LOG_INFO, e->e_id, "Milter: connect, ending");
336906f25ae9SGregory Neil Shapiro 		milter_quit(e);
337040266059SGregory Neil Shapiro 	}
337106f25ae9SGregory Neil Shapiro 	else
337206f25ae9SGregory Neil Shapiro 		milter_per_connection_check(e);
337306f25ae9SGregory Neil Shapiro 
337406f25ae9SGregory Neil Shapiro 	/*
337506f25ae9SGregory Neil Shapiro 	**  SMFIR_REPLYCODE can't work with connect due to
337606f25ae9SGregory Neil Shapiro 	**  the requirements of SMTP.  Therefore, ignore the
337706f25ae9SGregory Neil Shapiro 	**  reply code text but keep the state it would reflect.
337806f25ae9SGregory Neil Shapiro 	*/
337906f25ae9SGregory Neil Shapiro 
338006f25ae9SGregory Neil Shapiro 	if (*state == SMFIR_REPLYCODE)
338106f25ae9SGregory Neil Shapiro 	{
338206f25ae9SGregory Neil Shapiro 		if (response != NULL &&
338306f25ae9SGregory Neil Shapiro 		    *response == '4')
338413bd1963SGregory Neil Shapiro 		{
338513bd1963SGregory Neil Shapiro 			if (strncmp(response, "421 ", 4) == 0)
338613bd1963SGregory Neil Shapiro 				*state = SMFIR_SHUTDOWN;
338713bd1963SGregory Neil Shapiro 			else
338806f25ae9SGregory Neil Shapiro 				*state = SMFIR_TEMPFAIL;
338913bd1963SGregory Neil Shapiro 		}
339006f25ae9SGregory Neil Shapiro 		else
339106f25ae9SGregory Neil Shapiro 			*state = SMFIR_REJECT;
339206f25ae9SGregory Neil Shapiro 		if (response != NULL)
339306f25ae9SGregory Neil Shapiro 		{
339440266059SGregory Neil Shapiro 			sm_free(response); /* XXX */
339506f25ae9SGregory Neil Shapiro 			response = NULL;
339606f25ae9SGregory Neil Shapiro 		}
339706f25ae9SGregory Neil Shapiro 	}
339806f25ae9SGregory Neil Shapiro 	return response;
339906f25ae9SGregory Neil Shapiro }
340040266059SGregory Neil Shapiro /*
340106f25ae9SGregory Neil Shapiro **  MILTER_HELO -- send SMTP HELO/EHLO command info to milter filters
340206f25ae9SGregory Neil Shapiro **
340306f25ae9SGregory Neil Shapiro **	Parameters:
340406f25ae9SGregory Neil Shapiro **		helo -- argument to SMTP HELO/EHLO command.
340506f25ae9SGregory Neil Shapiro **		e -- current envelope.
340606f25ae9SGregory Neil Shapiro **		state -- return state from response.
340706f25ae9SGregory Neil Shapiro **
340806f25ae9SGregory Neil Shapiro **	Returns:
340906f25ae9SGregory Neil Shapiro **		response string (may be NULL)
341006f25ae9SGregory Neil Shapiro */
341106f25ae9SGregory Neil Shapiro 
341206f25ae9SGregory Neil Shapiro char *
341306f25ae9SGregory Neil Shapiro milter_helo(helo, e, state)
341406f25ae9SGregory Neil Shapiro 	char *helo;
341506f25ae9SGregory Neil Shapiro 	ENVELOPE *e;
341606f25ae9SGregory Neil Shapiro 	char *state;
341706f25ae9SGregory Neil Shapiro {
3418602a2b1bSGregory Neil Shapiro 	int i;
341906f25ae9SGregory Neil Shapiro 	char *response;
342006f25ae9SGregory Neil Shapiro 
342106f25ae9SGregory Neil Shapiro 	if (tTd(64, 10))
342240266059SGregory Neil Shapiro 		sm_dprintf("milter_helo(%s)\n", helo);
342306f25ae9SGregory Neil Shapiro 
342440266059SGregory Neil Shapiro 	/* HELO/EHLO can come at any point */
3425602a2b1bSGregory Neil Shapiro 	for (i = 0; InputFilters[i] != NULL; i++)
3426602a2b1bSGregory Neil Shapiro 	{
3427602a2b1bSGregory Neil Shapiro 		struct milter *m = InputFilters[i];
3428602a2b1bSGregory Neil Shapiro 
3429602a2b1bSGregory Neil Shapiro 		switch (m->mf_state)
3430602a2b1bSGregory Neil Shapiro 		{
3431602a2b1bSGregory Neil Shapiro 		  case SMFS_INMSG:
3432602a2b1bSGregory Neil Shapiro 			/* abort in message filters */
3433602a2b1bSGregory Neil Shapiro 			milter_abort_filter(m, e);
3434602a2b1bSGregory Neil Shapiro 			/* FALLTHROUGH */
3435602a2b1bSGregory Neil Shapiro 
3436602a2b1bSGregory Neil Shapiro 		  case SMFS_DONE:
3437602a2b1bSGregory Neil Shapiro 			/* reset done filters */
3438602a2b1bSGregory Neil Shapiro 			m->mf_state = SMFS_OPEN;
3439602a2b1bSGregory Neil Shapiro 			break;
3440602a2b1bSGregory Neil Shapiro 		}
3441602a2b1bSGregory Neil Shapiro 	}
3442602a2b1bSGregory Neil Shapiro 
344306f25ae9SGregory Neil Shapiro 	response = milter_command(SMFIC_HELO, helo, strlen(helo) + 1,
344406f25ae9SGregory Neil Shapiro 				  MilterHeloMacros, e, state);
344506f25ae9SGregory Neil Shapiro 	milter_per_connection_check(e);
344606f25ae9SGregory Neil Shapiro 	return response;
344706f25ae9SGregory Neil Shapiro }
344840266059SGregory Neil Shapiro /*
344906f25ae9SGregory Neil Shapiro **  MILTER_ENVFROM -- send SMTP MAIL command info to milter filters
345006f25ae9SGregory Neil Shapiro **
345106f25ae9SGregory Neil Shapiro **	Parameters:
345206f25ae9SGregory Neil Shapiro **		args -- SMTP MAIL command args (args[0] == sender).
345306f25ae9SGregory Neil Shapiro **		e -- current envelope.
345406f25ae9SGregory Neil Shapiro **		state -- return state from response.
345506f25ae9SGregory Neil Shapiro **
345606f25ae9SGregory Neil Shapiro **	Returns:
345706f25ae9SGregory Neil Shapiro **		response string (may be NULL)
345806f25ae9SGregory Neil Shapiro */
345906f25ae9SGregory Neil Shapiro 
346006f25ae9SGregory Neil Shapiro char *
346106f25ae9SGregory Neil Shapiro milter_envfrom(args, e, state)
346206f25ae9SGregory Neil Shapiro 	char **args;
346306f25ae9SGregory Neil Shapiro 	ENVELOPE *e;
346406f25ae9SGregory Neil Shapiro 	char *state;
346506f25ae9SGregory Neil Shapiro {
346606f25ae9SGregory Neil Shapiro 	int i;
346706f25ae9SGregory Neil Shapiro 	char *buf, *bp;
346806f25ae9SGregory Neil Shapiro 	char *response;
346906f25ae9SGregory Neil Shapiro 	ssize_t s;
347006f25ae9SGregory Neil Shapiro 
347106f25ae9SGregory Neil Shapiro 	if (tTd(64, 10))
347206f25ae9SGregory Neil Shapiro 	{
347340266059SGregory Neil Shapiro 		sm_dprintf("milter_envfrom:");
347406f25ae9SGregory Neil Shapiro 		for (i = 0; args[i] != NULL; i++)
347540266059SGregory Neil Shapiro 			sm_dprintf(" %s", args[i]);
347640266059SGregory Neil Shapiro 		sm_dprintf("\n");
347706f25ae9SGregory Neil Shapiro 	}
347806f25ae9SGregory Neil Shapiro 
347906f25ae9SGregory Neil Shapiro 	/* sanity check */
348006f25ae9SGregory Neil Shapiro 	if (args[0] == NULL)
348106f25ae9SGregory Neil Shapiro 	{
348206f25ae9SGregory Neil Shapiro 		*state = SMFIR_REJECT;
348340266059SGregory Neil Shapiro 		if (MilterLogLevel > 10)
348440266059SGregory Neil Shapiro 			sm_syslog(LOG_INFO, e->e_id,
348540266059SGregory Neil Shapiro 				  "Milter: reject, no sender");
348606f25ae9SGregory Neil Shapiro 		return NULL;
348706f25ae9SGregory Neil Shapiro 	}
348806f25ae9SGregory Neil Shapiro 
348906f25ae9SGregory Neil Shapiro 	/* new message, so ... */
349006f25ae9SGregory Neil Shapiro 	for (i = 0; InputFilters[i] != NULL; i++)
349106f25ae9SGregory Neil Shapiro 	{
349206f25ae9SGregory Neil Shapiro 		struct milter *m = InputFilters[i];
349306f25ae9SGregory Neil Shapiro 
349406f25ae9SGregory Neil Shapiro 		switch (m->mf_state)
349506f25ae9SGregory Neil Shapiro 		{
349606f25ae9SGregory Neil Shapiro 		  case SMFS_INMSG:
349706f25ae9SGregory Neil Shapiro 			/* abort in message filters */
349806f25ae9SGregory Neil Shapiro 			milter_abort_filter(m, e);
349906f25ae9SGregory Neil Shapiro 			/* FALLTHROUGH */
350006f25ae9SGregory Neil Shapiro 
350106f25ae9SGregory Neil Shapiro 		  case SMFS_DONE:
350206f25ae9SGregory Neil Shapiro 			/* reset done filters */
350306f25ae9SGregory Neil Shapiro 			m->mf_state = SMFS_OPEN;
350406f25ae9SGregory Neil Shapiro 			break;
350506f25ae9SGregory Neil Shapiro 		}
350606f25ae9SGregory Neil Shapiro 	}
350706f25ae9SGregory Neil Shapiro 
350806f25ae9SGregory Neil Shapiro 	/* put together data */
350906f25ae9SGregory Neil Shapiro 	s = 0;
351006f25ae9SGregory Neil Shapiro 	for (i = 0; args[i] != NULL; i++)
351106f25ae9SGregory Neil Shapiro 		s += strlen(args[i]) + 1;
351240266059SGregory Neil Shapiro 
351340266059SGregory Neil Shapiro 	if (s < 0)
351440266059SGregory Neil Shapiro 	{
351540266059SGregory Neil Shapiro 		*state = SMFIR_TEMPFAIL;
351640266059SGregory Neil Shapiro 		return NULL;
351740266059SGregory Neil Shapiro 	}
351840266059SGregory Neil Shapiro 
351906f25ae9SGregory Neil Shapiro 	buf = (char *) xalloc(s);
352006f25ae9SGregory Neil Shapiro 	bp = buf;
352106f25ae9SGregory Neil Shapiro 	for (i = 0; args[i] != NULL; i++)
352206f25ae9SGregory Neil Shapiro 	{
352340266059SGregory Neil Shapiro 		(void) sm_strlcpy(bp, args[i], s - (bp - buf));
352406f25ae9SGregory Neil Shapiro 		bp += strlen(bp) + 1;
352506f25ae9SGregory Neil Shapiro 	}
352606f25ae9SGregory Neil Shapiro 
352740266059SGregory Neil Shapiro 	if (MilterLogLevel > 14)
352840266059SGregory Neil Shapiro 		sm_syslog(LOG_INFO, e->e_id, "Milter: senders: %s", buf);
352940266059SGregory Neil Shapiro 
353006f25ae9SGregory Neil Shapiro 	/* send it over */
353106f25ae9SGregory Neil Shapiro 	response = milter_command(SMFIC_MAIL, buf, s,
353206f25ae9SGregory Neil Shapiro 				  MilterEnvFromMacros, e, state);
353340266059SGregory Neil Shapiro 	sm_free(buf); /* XXX */
353406f25ae9SGregory Neil Shapiro 
353506f25ae9SGregory Neil Shapiro 	/*
353606f25ae9SGregory Neil Shapiro 	**  If filter rejects/discards a per message command,
353706f25ae9SGregory Neil Shapiro 	**  abort the other filters since we are done with the
353806f25ae9SGregory Neil Shapiro 	**  current message.
353906f25ae9SGregory Neil Shapiro 	*/
354006f25ae9SGregory Neil Shapiro 
354106f25ae9SGregory Neil Shapiro 	MILTER_CHECK_DONE_MSG();
354240266059SGregory Neil Shapiro 	if (MilterLogLevel > 10 && *state == SMFIR_REJECT)
354340266059SGregory Neil Shapiro 		sm_syslog(LOG_INFO, e->e_id, "Milter: reject, senders");
354406f25ae9SGregory Neil Shapiro 	return response;
354506f25ae9SGregory Neil Shapiro }
3546e92d3f3fSGregory Neil Shapiro 
354740266059SGregory Neil Shapiro /*
354806f25ae9SGregory Neil Shapiro **  MILTER_ENVRCPT -- send SMTP RCPT command info to milter filters
354906f25ae9SGregory Neil Shapiro **
355006f25ae9SGregory Neil Shapiro **	Parameters:
355106f25ae9SGregory Neil Shapiro **		args -- SMTP MAIL command args (args[0] == recipient).
355206f25ae9SGregory Neil Shapiro **		e -- current envelope.
355306f25ae9SGregory Neil Shapiro **		state -- return state from response.
355406f25ae9SGregory Neil Shapiro **
355506f25ae9SGregory Neil Shapiro **	Returns:
355606f25ae9SGregory Neil Shapiro **		response string (may be NULL)
355706f25ae9SGregory Neil Shapiro */
355806f25ae9SGregory Neil Shapiro 
355906f25ae9SGregory Neil Shapiro char *
356006f25ae9SGregory Neil Shapiro milter_envrcpt(args, e, state)
356106f25ae9SGregory Neil Shapiro 	char **args;
356206f25ae9SGregory Neil Shapiro 	ENVELOPE *e;
356306f25ae9SGregory Neil Shapiro 	char *state;
356406f25ae9SGregory Neil Shapiro {
356506f25ae9SGregory Neil Shapiro 	int i;
356606f25ae9SGregory Neil Shapiro 	char *buf, *bp;
356706f25ae9SGregory Neil Shapiro 	char *response;
356806f25ae9SGregory Neil Shapiro 	ssize_t s;
356906f25ae9SGregory Neil Shapiro 
357006f25ae9SGregory Neil Shapiro 	if (tTd(64, 10))
357106f25ae9SGregory Neil Shapiro 	{
357240266059SGregory Neil Shapiro 		sm_dprintf("milter_envrcpt:");
357306f25ae9SGregory Neil Shapiro 		for (i = 0; args[i] != NULL; i++)
357440266059SGregory Neil Shapiro 			sm_dprintf(" %s", args[i]);
357540266059SGregory Neil Shapiro 		sm_dprintf("\n");
357606f25ae9SGregory Neil Shapiro 	}
357706f25ae9SGregory Neil Shapiro 
357806f25ae9SGregory Neil Shapiro 	/* sanity check */
357906f25ae9SGregory Neil Shapiro 	if (args[0] == NULL)
358006f25ae9SGregory Neil Shapiro 	{
358106f25ae9SGregory Neil Shapiro 		*state = SMFIR_REJECT;
358240266059SGregory Neil Shapiro 		if (MilterLogLevel > 10)
358340266059SGregory Neil Shapiro 			sm_syslog(LOG_INFO, e->e_id, "Milter: reject, no rcpt");
358406f25ae9SGregory Neil Shapiro 		return NULL;
358506f25ae9SGregory Neil Shapiro 	}
358606f25ae9SGregory Neil Shapiro 
358706f25ae9SGregory Neil Shapiro 	/* put together data */
358806f25ae9SGregory Neil Shapiro 	s = 0;
358906f25ae9SGregory Neil Shapiro 	for (i = 0; args[i] != NULL; i++)
359006f25ae9SGregory Neil Shapiro 		s += strlen(args[i]) + 1;
359140266059SGregory Neil Shapiro 
359240266059SGregory Neil Shapiro 	if (s < 0)
359340266059SGregory Neil Shapiro 	{
359440266059SGregory Neil Shapiro 		*state = SMFIR_TEMPFAIL;
359540266059SGregory Neil Shapiro 		return NULL;
359640266059SGregory Neil Shapiro 	}
359740266059SGregory Neil Shapiro 
359806f25ae9SGregory Neil Shapiro 	buf = (char *) xalloc(s);
359906f25ae9SGregory Neil Shapiro 	bp = buf;
360006f25ae9SGregory Neil Shapiro 	for (i = 0; args[i] != NULL; i++)
360106f25ae9SGregory Neil Shapiro 	{
360240266059SGregory Neil Shapiro 		(void) sm_strlcpy(bp, args[i], s - (bp - buf));
360306f25ae9SGregory Neil Shapiro 		bp += strlen(bp) + 1;
360406f25ae9SGregory Neil Shapiro 	}
360506f25ae9SGregory Neil Shapiro 
360640266059SGregory Neil Shapiro 	if (MilterLogLevel > 14)
360740266059SGregory Neil Shapiro 		sm_syslog(LOG_INFO, e->e_id, "Milter: rcpts: %s", buf);
360840266059SGregory Neil Shapiro 
360906f25ae9SGregory Neil Shapiro 	/* send it over */
361006f25ae9SGregory Neil Shapiro 	response = milter_command(SMFIC_RCPT, buf, s,
361106f25ae9SGregory Neil Shapiro 				  MilterEnvRcptMacros, e, state);
361240266059SGregory Neil Shapiro 	sm_free(buf); /* XXX */
361306f25ae9SGregory Neil Shapiro 	return response;
361406f25ae9SGregory Neil Shapiro }
3615e92d3f3fSGregory Neil Shapiro 
3616e92d3f3fSGregory Neil Shapiro #if SMFI_VERSION > 3
3617e92d3f3fSGregory Neil Shapiro /*
3618e92d3f3fSGregory Neil Shapiro **  MILTER_DATA_CMD -- send SMTP DATA command info to milter filters
3619e92d3f3fSGregory Neil Shapiro **
3620e92d3f3fSGregory Neil Shapiro **	Parameters:
3621e92d3f3fSGregory Neil Shapiro **		e -- current envelope.
3622e92d3f3fSGregory Neil Shapiro **		state -- return state from response.
3623e92d3f3fSGregory Neil Shapiro **
3624e92d3f3fSGregory Neil Shapiro **	Returns:
3625e92d3f3fSGregory Neil Shapiro **		response string (may be NULL)
3626e92d3f3fSGregory Neil Shapiro */
3627e92d3f3fSGregory Neil Shapiro 
3628e92d3f3fSGregory Neil Shapiro char *
3629e92d3f3fSGregory Neil Shapiro milter_data_cmd(e, state)
3630e92d3f3fSGregory Neil Shapiro 	ENVELOPE *e;
3631e92d3f3fSGregory Neil Shapiro 	char *state;
3632e92d3f3fSGregory Neil Shapiro {
3633e92d3f3fSGregory Neil Shapiro 	if (tTd(64, 10))
3634e92d3f3fSGregory Neil Shapiro 		sm_dprintf("milter_data_cmd\n");
3635e92d3f3fSGregory Neil Shapiro 
3636e92d3f3fSGregory Neil Shapiro 	/* send it over */
3637e92d3f3fSGregory Neil Shapiro 	return milter_command(SMFIC_DATA, NULL, 0, MilterDataMacros, e, state);
3638e92d3f3fSGregory Neil Shapiro }
3639e92d3f3fSGregory Neil Shapiro #endif /* SMFI_VERSION > 3 */
3640e92d3f3fSGregory Neil Shapiro 
364140266059SGregory Neil Shapiro /*
364206f25ae9SGregory Neil Shapiro **  MILTER_DATA -- send message headers/body and gather final message results
364306f25ae9SGregory Neil Shapiro **
364406f25ae9SGregory Neil Shapiro **	Parameters:
364506f25ae9SGregory Neil Shapiro **		e -- current envelope.
364606f25ae9SGregory Neil Shapiro **		state -- return state from response.
364706f25ae9SGregory Neil Shapiro **
364806f25ae9SGregory Neil Shapiro **	Returns:
364906f25ae9SGregory Neil Shapiro **		response string (may be NULL)
365006f25ae9SGregory Neil Shapiro **
365106f25ae9SGregory Neil Shapiro **	Side effects:
365206f25ae9SGregory Neil Shapiro **		- Uses e->e_dfp for access to the body
365306f25ae9SGregory Neil Shapiro **		- Can call the various milter action routines to
365406f25ae9SGregory Neil Shapiro **		  modify the envelope or message.
365506f25ae9SGregory Neil Shapiro */
365606f25ae9SGregory Neil Shapiro 
365706f25ae9SGregory Neil Shapiro # define MILTER_CHECK_RESULTS() \
365806f25ae9SGregory Neil Shapiro 	if (*state == SMFIR_ACCEPT || \
365906f25ae9SGregory Neil Shapiro 	    m->mf_state == SMFS_DONE || \
366006f25ae9SGregory Neil Shapiro 	    m->mf_state == SMFS_ERROR) \
366106f25ae9SGregory Neil Shapiro 	{ \
366206f25ae9SGregory Neil Shapiro 		if (m->mf_state != SMFS_ERROR) \
366306f25ae9SGregory Neil Shapiro 			m->mf_state = SMFS_DONE; \
366406f25ae9SGregory Neil Shapiro 		continue;	/* to next filter */ \
366506f25ae9SGregory Neil Shapiro 	} \
366606f25ae9SGregory Neil Shapiro 	if (*state != SMFIR_CONTINUE) \
366706f25ae9SGregory Neil Shapiro 	{ \
366806f25ae9SGregory Neil Shapiro 		m->mf_state = SMFS_DONE; \
366906f25ae9SGregory Neil Shapiro 		goto finishup; \
367006f25ae9SGregory Neil Shapiro 	}
367106f25ae9SGregory Neil Shapiro 
367206f25ae9SGregory Neil Shapiro char *
367306f25ae9SGregory Neil Shapiro milter_data(e, state)
367406f25ae9SGregory Neil Shapiro 	ENVELOPE *e;
367506f25ae9SGregory Neil Shapiro 	char *state;
367606f25ae9SGregory Neil Shapiro {
367740266059SGregory Neil Shapiro 	bool replbody = false;		/* milter_replbody() called? */
367840266059SGregory Neil Shapiro 	bool replfailed = false;	/* milter_replbody() failed? */
367940266059SGregory Neil Shapiro 	bool rewind = false;		/* rewind data file? */
368040266059SGregory Neil Shapiro 	bool dfopen = false;		/* data file open for writing? */
368106f25ae9SGregory Neil Shapiro 	bool newfilter;			/* reset on each new filter */
368206f25ae9SGregory Neil Shapiro 	char rcmd;
368306f25ae9SGregory Neil Shapiro 	int i;
368406f25ae9SGregory Neil Shapiro 	int save_errno;
368506f25ae9SGregory Neil Shapiro 	char *response = NULL;
368606f25ae9SGregory Neil Shapiro 	time_t eomsent;
368706f25ae9SGregory Neil Shapiro 	ssize_t rlen;
368806f25ae9SGregory Neil Shapiro 
368906f25ae9SGregory Neil Shapiro 	if (tTd(64, 10))
369040266059SGregory Neil Shapiro 		sm_dprintf("milter_data\n");
369106f25ae9SGregory Neil Shapiro 
369206f25ae9SGregory Neil Shapiro 	*state = SMFIR_CONTINUE;
369306f25ae9SGregory Neil Shapiro 
369406f25ae9SGregory Neil Shapiro 	/*
369506f25ae9SGregory Neil Shapiro 	**  XXX: Should actually send body chunks to each filter
369606f25ae9SGregory Neil Shapiro 	**  a chunk at a time instead of sending the whole body to
369706f25ae9SGregory Neil Shapiro 	**  each filter in turn.  However, only if the filters don't
369806f25ae9SGregory Neil Shapiro 	**  change the body.
369906f25ae9SGregory Neil Shapiro 	*/
370006f25ae9SGregory Neil Shapiro 
370106f25ae9SGregory Neil Shapiro 	for (i = 0; InputFilters[i] != NULL; i++)
370206f25ae9SGregory Neil Shapiro 	{
370306f25ae9SGregory Neil Shapiro 		struct milter *m = InputFilters[i];
370406f25ae9SGregory Neil Shapiro 
370506f25ae9SGregory Neil Shapiro 		if (*state != SMFIR_CONTINUE &&
370606f25ae9SGregory Neil Shapiro 		    *state != SMFIR_ACCEPT)
370706f25ae9SGregory Neil Shapiro 		{
370806f25ae9SGregory Neil Shapiro 			/*
370906f25ae9SGregory Neil Shapiro 			**  A previous filter has dealt with the message,
371006f25ae9SGregory Neil Shapiro 			**  safe to stop processing the filters.
371106f25ae9SGregory Neil Shapiro 			*/
371206f25ae9SGregory Neil Shapiro 
371306f25ae9SGregory Neil Shapiro 			break;
371406f25ae9SGregory Neil Shapiro 		}
371506f25ae9SGregory Neil Shapiro 
371606f25ae9SGregory Neil Shapiro 		/* Now reset state for later evaluation */
371706f25ae9SGregory Neil Shapiro 		*state = SMFIR_CONTINUE;
371840266059SGregory Neil Shapiro 		newfilter = true;
371906f25ae9SGregory Neil Shapiro 
3720193538b7SGregory Neil Shapiro 		/* previous problem? */
3721193538b7SGregory Neil Shapiro 		if (m->mf_state == SMFS_ERROR)
3722193538b7SGregory Neil Shapiro 		{
37235ef517c0SGregory Neil Shapiro 			MILTER_CHECK_ERROR(false, continue);
3724193538b7SGregory Neil Shapiro 			break;
3725193538b7SGregory Neil Shapiro 		}
3726193538b7SGregory Neil Shapiro 
372706f25ae9SGregory Neil Shapiro 		/* sanity checks */
372806f25ae9SGregory Neil Shapiro 		if (m->mf_sock < 0 ||
372906f25ae9SGregory Neil Shapiro 		    (m->mf_state != SMFS_OPEN && m->mf_state != SMFS_INMSG))
373006f25ae9SGregory Neil Shapiro 			continue;
373106f25ae9SGregory Neil Shapiro 
373206f25ae9SGregory Neil Shapiro 		m->mf_state = SMFS_INMSG;
373306f25ae9SGregory Neil Shapiro 
373406f25ae9SGregory Neil Shapiro 		/* check if filter wants the headers */
373506f25ae9SGregory Neil Shapiro 		if (!bitset(SMFIP_NOHDRS, m->mf_pflags))
373606f25ae9SGregory Neil Shapiro 		{
373706f25ae9SGregory Neil Shapiro 			response = milter_headers(m, e, state);
373806f25ae9SGregory Neil Shapiro 			MILTER_CHECK_RESULTS();
373906f25ae9SGregory Neil Shapiro 		}
374006f25ae9SGregory Neil Shapiro 
374106f25ae9SGregory Neil Shapiro 		/* check if filter wants EOH */
374206f25ae9SGregory Neil Shapiro 		if (!bitset(SMFIP_NOEOH, m->mf_pflags))
374306f25ae9SGregory Neil Shapiro 		{
374406f25ae9SGregory Neil Shapiro 			if (tTd(64, 10))
374540266059SGregory Neil Shapiro 				sm_dprintf("milter_data: eoh\n");
374606f25ae9SGregory Neil Shapiro 
374706f25ae9SGregory Neil Shapiro 			/* send it over */
374806f25ae9SGregory Neil Shapiro 			response = milter_send_command(m, SMFIC_EOH, NULL, 0,
374906f25ae9SGregory Neil Shapiro 						       e, state);
375006f25ae9SGregory Neil Shapiro 			MILTER_CHECK_RESULTS();
375106f25ae9SGregory Neil Shapiro 		}
375206f25ae9SGregory Neil Shapiro 
375306f25ae9SGregory Neil Shapiro 		/* check if filter wants the body */
375406f25ae9SGregory Neil Shapiro 		if (!bitset(SMFIP_NOBODY, m->mf_pflags) &&
375506f25ae9SGregory Neil Shapiro 		    e->e_dfp != NULL)
375606f25ae9SGregory Neil Shapiro 		{
375740266059SGregory Neil Shapiro 			rewind = true;
375806f25ae9SGregory Neil Shapiro 			response = milter_body(m, e, state);
375906f25ae9SGregory Neil Shapiro 			MILTER_CHECK_RESULTS();
376006f25ae9SGregory Neil Shapiro 		}
376106f25ae9SGregory Neil Shapiro 
3762323f6dcbSGregory Neil Shapiro 		if (MilterEOMMacros[0] != NULL)
3763e92d3f3fSGregory Neil Shapiro 			milter_send_macros(m, MilterEOMMacros,
3764e92d3f3fSGregory Neil Shapiro 					   SMFIC_BODYEOB, e);
3765323f6dcbSGregory Neil Shapiro 
376606f25ae9SGregory Neil Shapiro 		/* send the final body chunk */
376706f25ae9SGregory Neil Shapiro 		(void) milter_write(m, SMFIC_BODYEOB, NULL, 0,
376806f25ae9SGregory Neil Shapiro 				    m->mf_timeout[SMFTO_WRITE], e);
376906f25ae9SGregory Neil Shapiro 
377006f25ae9SGregory Neil Shapiro 		/* Get time EOM sent for timeout */
377106f25ae9SGregory Neil Shapiro 		eomsent = curtime();
377206f25ae9SGregory Neil Shapiro 
377306f25ae9SGregory Neil Shapiro 		/* deal with the possibility of multiple responses */
377406f25ae9SGregory Neil Shapiro 		while (*state == SMFIR_CONTINUE)
377506f25ae9SGregory Neil Shapiro 		{
377606f25ae9SGregory Neil Shapiro 			/* Check total timeout from EOM to final ACK/NAK */
377706f25ae9SGregory Neil Shapiro 			if (m->mf_timeout[SMFTO_EOM] > 0 &&
377806f25ae9SGregory Neil Shapiro 			    curtime() - eomsent >= m->mf_timeout[SMFTO_EOM])
377906f25ae9SGregory Neil Shapiro 			{
378006f25ae9SGregory Neil Shapiro 				if (tTd(64, 5))
378140266059SGregory Neil Shapiro 					sm_dprintf("milter_data(%s): EOM ACK/NAK timeout\n",
378206f25ae9SGregory Neil Shapiro 						m->mf_name);
378340266059SGregory Neil Shapiro 				if (MilterLogLevel > 0)
378406f25ae9SGregory Neil Shapiro 					sm_syslog(LOG_ERR, e->e_id,
378540266059SGregory Neil Shapiro 						  "milter_data(%s): EOM ACK/NAK timeout",
378606f25ae9SGregory Neil Shapiro 						  m->mf_name);
378740266059SGregory Neil Shapiro 				milter_error(m, e);
37885ef517c0SGregory Neil Shapiro 				MILTER_CHECK_ERROR(false, break);
378906f25ae9SGregory Neil Shapiro 				break;
379006f25ae9SGregory Neil Shapiro 			}
379106f25ae9SGregory Neil Shapiro 
379206f25ae9SGregory Neil Shapiro 			response = milter_read(m, &rcmd, &rlen,
379306f25ae9SGregory Neil Shapiro 					       m->mf_timeout[SMFTO_READ], e);
379406f25ae9SGregory Neil Shapiro 			if (m->mf_state == SMFS_ERROR)
379506f25ae9SGregory Neil Shapiro 				break;
379606f25ae9SGregory Neil Shapiro 
379706f25ae9SGregory Neil Shapiro 			if (tTd(64, 10))
379840266059SGregory Neil Shapiro 				sm_dprintf("milter_data(%s): state %c\n",
379906f25ae9SGregory Neil Shapiro 					   m->mf_name, (char) rcmd);
380006f25ae9SGregory Neil Shapiro 
380106f25ae9SGregory Neil Shapiro 			switch (rcmd)
380206f25ae9SGregory Neil Shapiro 			{
380306f25ae9SGregory Neil Shapiro 			  case SMFIR_REPLYCODE:
380406f25ae9SGregory Neil Shapiro 				MILTER_CHECK_REPLYCODE("554 5.7.1 Command rejected");
380540266059SGregory Neil Shapiro 				if (MilterLogLevel > 12)
380640266059SGregory Neil Shapiro 					sm_syslog(LOG_INFO, e->e_id, "milter=%s, reject=%s",
380740266059SGregory Neil Shapiro 						  m->mf_name, response);
380806f25ae9SGregory Neil Shapiro 				*state = rcmd;
380906f25ae9SGregory Neil Shapiro 				m->mf_state = SMFS_DONE;
381006f25ae9SGregory Neil Shapiro 				break;
381106f25ae9SGregory Neil Shapiro 
381240266059SGregory Neil Shapiro 			  case SMFIR_REJECT: /* log msg at end of function */
381340266059SGregory Neil Shapiro 				if (MilterLogLevel > 12)
381440266059SGregory Neil Shapiro 					sm_syslog(LOG_INFO, e->e_id, "milter=%s, reject",
381540266059SGregory Neil Shapiro 						  m->mf_name);
381640266059SGregory Neil Shapiro 				*state = rcmd;
381740266059SGregory Neil Shapiro 				m->mf_state = SMFS_DONE;
381840266059SGregory Neil Shapiro 				break;
381940266059SGregory Neil Shapiro 
382006f25ae9SGregory Neil Shapiro 			  case SMFIR_DISCARD:
382140266059SGregory Neil Shapiro 				if (MilterLogLevel > 12)
382240266059SGregory Neil Shapiro 					sm_syslog(LOG_INFO, e->e_id, "milter=%s, discard",
382340266059SGregory Neil Shapiro 						  m->mf_name);
382440266059SGregory Neil Shapiro 				*state = rcmd;
382540266059SGregory Neil Shapiro 				m->mf_state = SMFS_DONE;
382640266059SGregory Neil Shapiro 				break;
382740266059SGregory Neil Shapiro 
382806f25ae9SGregory Neil Shapiro 			  case SMFIR_TEMPFAIL:
382940266059SGregory Neil Shapiro 				if (MilterLogLevel > 12)
383040266059SGregory Neil Shapiro 					sm_syslog(LOG_INFO, e->e_id, "milter=%s, tempfail",
383140266059SGregory Neil Shapiro 						  m->mf_name);
383206f25ae9SGregory Neil Shapiro 				*state = rcmd;
383306f25ae9SGregory Neil Shapiro 				m->mf_state = SMFS_DONE;
383406f25ae9SGregory Neil Shapiro 				break;
383506f25ae9SGregory Neil Shapiro 
383606f25ae9SGregory Neil Shapiro 			  case SMFIR_CONTINUE:
383706f25ae9SGregory Neil Shapiro 			  case SMFIR_ACCEPT:
383806f25ae9SGregory Neil Shapiro 				/* this filter is done with message */
383906f25ae9SGregory Neil Shapiro 				if (replfailed)
384006f25ae9SGregory Neil Shapiro 					*state = SMFIR_TEMPFAIL;
384106f25ae9SGregory Neil Shapiro 				else
384206f25ae9SGregory Neil Shapiro 					*state = SMFIR_ACCEPT;
384306f25ae9SGregory Neil Shapiro 				m->mf_state = SMFS_DONE;
384406f25ae9SGregory Neil Shapiro 				break;
384506f25ae9SGregory Neil Shapiro 
384606f25ae9SGregory Neil Shapiro 			  case SMFIR_PROGRESS:
384706f25ae9SGregory Neil Shapiro 				break;
384806f25ae9SGregory Neil Shapiro 
384940266059SGregory Neil Shapiro 			  case SMFIR_QUARANTINE:
385040266059SGregory Neil Shapiro 				if (!bitset(SMFIF_QUARANTINE, m->mf_fflags))
385140266059SGregory Neil Shapiro 				{
385240266059SGregory Neil Shapiro 					if (MilterLogLevel > 9)
385340266059SGregory Neil Shapiro 						sm_syslog(LOG_WARNING, e->e_id,
385440266059SGregory Neil Shapiro 							  "milter_data(%s): lied about quarantining, honoring request anyway",
385540266059SGregory Neil Shapiro 							  m->mf_name);
385640266059SGregory Neil Shapiro 				}
385740266059SGregory Neil Shapiro 				if (response == NULL)
385840266059SGregory Neil Shapiro 					response = newstr("");
385940266059SGregory Neil Shapiro 				if (MilterLogLevel > 3)
386040266059SGregory Neil Shapiro 					sm_syslog(LOG_INFO, e->e_id,
386140266059SGregory Neil Shapiro 						  "milter=%s, quarantine=%s",
386240266059SGregory Neil Shapiro 						  m->mf_name, response);
386340266059SGregory Neil Shapiro 				e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool,
386440266059SGregory Neil Shapiro 								 response);
386540266059SGregory Neil Shapiro 				macdefine(&e->e_macro, A_PERM,
386640266059SGregory Neil Shapiro 					  macid("{quarantine}"), e->e_quarmsg);
386740266059SGregory Neil Shapiro 				break;
386840266059SGregory Neil Shapiro 
386906f25ae9SGregory Neil Shapiro 			  case SMFIR_ADDHEADER:
387006f25ae9SGregory Neil Shapiro 				if (!bitset(SMFIF_ADDHDRS, m->mf_fflags))
387106f25ae9SGregory Neil Shapiro 				{
387240266059SGregory Neil Shapiro 					if (MilterLogLevel > 9)
387306f25ae9SGregory Neil Shapiro 						sm_syslog(LOG_WARNING, e->e_id,
387406f25ae9SGregory Neil Shapiro 							  "milter_data(%s): lied about adding headers, honoring request anyway",
387506f25ae9SGregory Neil Shapiro 							  m->mf_name);
387606f25ae9SGregory Neil Shapiro 				}
387706f25ae9SGregory Neil Shapiro 				milter_addheader(response, rlen, e);
387806f25ae9SGregory Neil Shapiro 				break;
387906f25ae9SGregory Neil Shapiro 
3880e92d3f3fSGregory Neil Shapiro 			  case SMFIR_INSHEADER:
3881e92d3f3fSGregory Neil Shapiro 				if (!bitset(SMFIF_ADDHDRS, m->mf_fflags))
3882e92d3f3fSGregory Neil Shapiro 				{
3883e92d3f3fSGregory Neil Shapiro 					if (MilterLogLevel > 9)
3884e92d3f3fSGregory Neil Shapiro 						sm_syslog(LOG_WARNING, e->e_id,
3885e92d3f3fSGregory Neil Shapiro 							  "milter_data(%s): lied about adding headers, honoring request anyway",
3886e92d3f3fSGregory Neil Shapiro 							  m->mf_name);
3887e92d3f3fSGregory Neil Shapiro 				}
3888e92d3f3fSGregory Neil Shapiro 				milter_insheader(response, rlen, e);
3889e92d3f3fSGregory Neil Shapiro 				break;
3890e92d3f3fSGregory Neil Shapiro 
389106f25ae9SGregory Neil Shapiro 			  case SMFIR_CHGHEADER:
389206f25ae9SGregory Neil Shapiro 				if (!bitset(SMFIF_CHGHDRS, m->mf_fflags))
389306f25ae9SGregory Neil Shapiro 				{
389440266059SGregory Neil Shapiro 					if (MilterLogLevel > 9)
389506f25ae9SGregory Neil Shapiro 						sm_syslog(LOG_WARNING, e->e_id,
389606f25ae9SGregory Neil Shapiro 							  "milter_data(%s): lied about changing headers, honoring request anyway",
389706f25ae9SGregory Neil Shapiro 							  m->mf_name);
389806f25ae9SGregory Neil Shapiro 				}
389906f25ae9SGregory Neil Shapiro 				milter_changeheader(response, rlen, e);
390006f25ae9SGregory Neil Shapiro 				break;
390106f25ae9SGregory Neil Shapiro 
390206f25ae9SGregory Neil Shapiro 			  case SMFIR_ADDRCPT:
390306f25ae9SGregory Neil Shapiro 				if (!bitset(SMFIF_ADDRCPT, m->mf_fflags))
390406f25ae9SGregory Neil Shapiro 				{
390540266059SGregory Neil Shapiro 					if (MilterLogLevel > 9)
390606f25ae9SGregory Neil Shapiro 						sm_syslog(LOG_WARNING, e->e_id,
390706f25ae9SGregory Neil Shapiro 							  "milter_data(%s) lied about adding recipients, honoring request anyway",
390806f25ae9SGregory Neil Shapiro 							  m->mf_name);
390906f25ae9SGregory Neil Shapiro 				}
391006f25ae9SGregory Neil Shapiro 				milter_addrcpt(response, rlen, e);
391106f25ae9SGregory Neil Shapiro 				break;
391206f25ae9SGregory Neil Shapiro 
391306f25ae9SGregory Neil Shapiro 			  case SMFIR_DELRCPT:
391406f25ae9SGregory Neil Shapiro 				if (!bitset(SMFIF_DELRCPT, m->mf_fflags))
391506f25ae9SGregory Neil Shapiro 				{
391640266059SGregory Neil Shapiro 					if (MilterLogLevel > 9)
391706f25ae9SGregory Neil Shapiro 						sm_syslog(LOG_WARNING, e->e_id,
391806f25ae9SGregory Neil Shapiro 							  "milter_data(%s): lied about removing recipients, honoring request anyway",
391906f25ae9SGregory Neil Shapiro 							  m->mf_name);
392006f25ae9SGregory Neil Shapiro 				}
392106f25ae9SGregory Neil Shapiro 				milter_delrcpt(response, rlen, e);
392206f25ae9SGregory Neil Shapiro 				break;
392306f25ae9SGregory Neil Shapiro 
392406f25ae9SGregory Neil Shapiro 			  case SMFIR_REPLBODY:
392506f25ae9SGregory Neil Shapiro 				if (!bitset(SMFIF_MODBODY, m->mf_fflags))
392606f25ae9SGregory Neil Shapiro 				{
3927e92d3f3fSGregory Neil Shapiro 					if (MilterLogLevel > 0)
392806f25ae9SGregory Neil Shapiro 						sm_syslog(LOG_ERR, e->e_id,
392906f25ae9SGregory Neil Shapiro 							  "milter_data(%s): lied about replacing body, rejecting request and tempfailing message",
393006f25ae9SGregory Neil Shapiro 							  m->mf_name);
393140266059SGregory Neil Shapiro 					replfailed = true;
393206f25ae9SGregory Neil Shapiro 					break;
393306f25ae9SGregory Neil Shapiro 				}
393406f25ae9SGregory Neil Shapiro 
393506f25ae9SGregory Neil Shapiro 				/* already failed in attempt */
393606f25ae9SGregory Neil Shapiro 				if (replfailed)
393706f25ae9SGregory Neil Shapiro 					break;
393806f25ae9SGregory Neil Shapiro 
393906f25ae9SGregory Neil Shapiro 				if (!dfopen)
394006f25ae9SGregory Neil Shapiro 				{
394106f25ae9SGregory Neil Shapiro 					if (milter_reopen_df(e) < 0)
394206f25ae9SGregory Neil Shapiro 					{
394340266059SGregory Neil Shapiro 						replfailed = true;
394406f25ae9SGregory Neil Shapiro 						break;
394506f25ae9SGregory Neil Shapiro 					}
394640266059SGregory Neil Shapiro 					dfopen = true;
394740266059SGregory Neil Shapiro 					rewind = true;
394806f25ae9SGregory Neil Shapiro 				}
394906f25ae9SGregory Neil Shapiro 
395006f25ae9SGregory Neil Shapiro 				if (milter_replbody(response, rlen,
395106f25ae9SGregory Neil Shapiro 						    newfilter, e) < 0)
395240266059SGregory Neil Shapiro 					replfailed = true;
395340266059SGregory Neil Shapiro 				newfilter = false;
395440266059SGregory Neil Shapiro 				replbody = true;
395506f25ae9SGregory Neil Shapiro 				break;
395606f25ae9SGregory Neil Shapiro 
395706f25ae9SGregory Neil Shapiro 			  default:
395806f25ae9SGregory Neil Shapiro 				/* Invalid response to command */
395940266059SGregory Neil Shapiro 				if (MilterLogLevel > 0)
396006f25ae9SGregory Neil Shapiro 					sm_syslog(LOG_ERR, e->e_id,
396106f25ae9SGregory Neil Shapiro 						  "milter_data(%s): returned bogus response %c",
396206f25ae9SGregory Neil Shapiro 						  m->mf_name, rcmd);
396340266059SGregory Neil Shapiro 				milter_error(m, e);
396406f25ae9SGregory Neil Shapiro 				break;
396506f25ae9SGregory Neil Shapiro 			}
396640266059SGregory Neil Shapiro 			if (rcmd != SMFIR_REPLYCODE && response != NULL)
396706f25ae9SGregory Neil Shapiro 			{
396840266059SGregory Neil Shapiro 				sm_free(response); /* XXX */
396906f25ae9SGregory Neil Shapiro 				response = NULL;
397006f25ae9SGregory Neil Shapiro 			}
397106f25ae9SGregory Neil Shapiro 
397206f25ae9SGregory Neil Shapiro 			if (m->mf_state == SMFS_ERROR)
397306f25ae9SGregory Neil Shapiro 				break;
397406f25ae9SGregory Neil Shapiro 		}
397506f25ae9SGregory Neil Shapiro 
397606f25ae9SGregory Neil Shapiro 		if (replbody && !replfailed)
397706f25ae9SGregory Neil Shapiro 		{
397806f25ae9SGregory Neil Shapiro 			/* flush possible buffered character */
397906f25ae9SGregory Neil Shapiro 			milter_replbody(NULL, 0, !replbody, e);
398040266059SGregory Neil Shapiro 			replbody = false;
398106f25ae9SGregory Neil Shapiro 		}
398206f25ae9SGregory Neil Shapiro 
398306f25ae9SGregory Neil Shapiro 		if (m->mf_state == SMFS_ERROR)
398406f25ae9SGregory Neil Shapiro 		{
39855ef517c0SGregory Neil Shapiro 			MILTER_CHECK_ERROR(false, continue);
398606f25ae9SGregory Neil Shapiro 			goto finishup;
398706f25ae9SGregory Neil Shapiro 		}
398806f25ae9SGregory Neil Shapiro 	}
398906f25ae9SGregory Neil Shapiro 
399006f25ae9SGregory Neil Shapiro finishup:
399106f25ae9SGregory Neil Shapiro 	/* leave things in the expected state if we touched it */
399206f25ae9SGregory Neil Shapiro 	if (replfailed)
399306f25ae9SGregory Neil Shapiro 	{
399406f25ae9SGregory Neil Shapiro 		if (*state == SMFIR_CONTINUE ||
399506f25ae9SGregory Neil Shapiro 		    *state == SMFIR_ACCEPT)
399606f25ae9SGregory Neil Shapiro 		{
399706f25ae9SGregory Neil Shapiro 			*state = SMFIR_TEMPFAIL;
399840266059SGregory Neil Shapiro 			SM_FREE_CLR(response);
399906f25ae9SGregory Neil Shapiro 		}
400006f25ae9SGregory Neil Shapiro 
400106f25ae9SGregory Neil Shapiro 		if (dfopen)
400206f25ae9SGregory Neil Shapiro 		{
400340266059SGregory Neil Shapiro 			(void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT);
400406f25ae9SGregory Neil Shapiro 			e->e_dfp = NULL;
400506f25ae9SGregory Neil Shapiro 			e->e_flags &= ~EF_HAS_DF;
400640266059SGregory Neil Shapiro 			dfopen = false;
400706f25ae9SGregory Neil Shapiro 		}
400840266059SGregory Neil Shapiro 		rewind = false;
400906f25ae9SGregory Neil Shapiro 	}
401006f25ae9SGregory Neil Shapiro 
401106f25ae9SGregory Neil Shapiro 	if ((dfopen && milter_reset_df(e) < 0) ||
401206f25ae9SGregory Neil Shapiro 	    (rewind && bfrewind(e->e_dfp) < 0))
401306f25ae9SGregory Neil Shapiro 	{
401406f25ae9SGregory Neil Shapiro 		save_errno = errno;
401506f25ae9SGregory Neil Shapiro 		ExitStat = EX_IOERR;
401606f25ae9SGregory Neil Shapiro 
401706f25ae9SGregory Neil Shapiro 		/*
401806f25ae9SGregory Neil Shapiro 		**  If filter told us to keep message but we had
401906f25ae9SGregory Neil Shapiro 		**  an error, we can't really keep it, tempfail it.
402006f25ae9SGregory Neil Shapiro 		*/
402106f25ae9SGregory Neil Shapiro 
402206f25ae9SGregory Neil Shapiro 		if (*state == SMFIR_CONTINUE ||
402306f25ae9SGregory Neil Shapiro 		    *state == SMFIR_ACCEPT)
402406f25ae9SGregory Neil Shapiro 		{
402506f25ae9SGregory Neil Shapiro 			*state = SMFIR_TEMPFAIL;
402640266059SGregory Neil Shapiro 			SM_FREE_CLR(response);
402706f25ae9SGregory Neil Shapiro 		}
402806f25ae9SGregory Neil Shapiro 
402906f25ae9SGregory Neil Shapiro 		errno = save_errno;
403040266059SGregory Neil Shapiro 		syserr("milter_data: %s/%cf%s: read error",
403140266059SGregory Neil Shapiro 		       qid_printqueue(e->e_qgrp, e->e_qdir),
403240266059SGregory Neil Shapiro 		       DATAFL_LETTER, e->e_id);
403306f25ae9SGregory Neil Shapiro 	}
403440266059SGregory Neil Shapiro 
403506f25ae9SGregory Neil Shapiro 	MILTER_CHECK_DONE_MSG();
403640266059SGregory Neil Shapiro 	if (MilterLogLevel > 10 && *state == SMFIR_REJECT)
403740266059SGregory Neil Shapiro 		sm_syslog(LOG_INFO, e->e_id, "Milter: reject, data");
403806f25ae9SGregory Neil Shapiro 	return response;
403906f25ae9SGregory Neil Shapiro }
4040e92d3f3fSGregory Neil Shapiro 
4041e92d3f3fSGregory Neil Shapiro #if SMFI_VERSION > 2
4042e92d3f3fSGregory Neil Shapiro /*
4043e92d3f3fSGregory Neil Shapiro **  MILTER_UNKNOWN -- send any unrecognized or unimplemented command
4044e92d3f3fSGregory Neil Shapiro **			string to milter filters
4045e92d3f3fSGregory Neil Shapiro **
4046e92d3f3fSGregory Neil Shapiro **	Parameters:
4047e92d3f3fSGregory Neil Shapiro **		cmd -- the string itself.
4048e92d3f3fSGregory Neil Shapiro **		e -- current envelope.
4049e92d3f3fSGregory Neil Shapiro **		state -- return state from response.
4050e92d3f3fSGregory Neil Shapiro **
4051e92d3f3fSGregory Neil Shapiro **
4052e92d3f3fSGregory Neil Shapiro **	Returns:
4053e92d3f3fSGregory Neil Shapiro **		response string (may be NULL)
4054e92d3f3fSGregory Neil Shapiro */
4055e92d3f3fSGregory Neil Shapiro 
4056e92d3f3fSGregory Neil Shapiro char *
4057e92d3f3fSGregory Neil Shapiro milter_unknown(cmd, e, state)
4058e92d3f3fSGregory Neil Shapiro 	char *cmd;
4059e92d3f3fSGregory Neil Shapiro 	ENVELOPE *e;
4060e92d3f3fSGregory Neil Shapiro 	char *state;
4061e92d3f3fSGregory Neil Shapiro {
4062e92d3f3fSGregory Neil Shapiro 	if (tTd(64, 10))
4063e92d3f3fSGregory Neil Shapiro 		sm_dprintf("milter_unknown(%s)\n", cmd);
4064e92d3f3fSGregory Neil Shapiro 
4065e92d3f3fSGregory Neil Shapiro 	return milter_command(SMFIC_UNKNOWN, cmd, strlen(cmd) + 1,
4066e92d3f3fSGregory Neil Shapiro 				NULL, e, state);
4067e92d3f3fSGregory Neil Shapiro }
4068e92d3f3fSGregory Neil Shapiro #endif /* SMFI_VERSION > 2 */
4069e92d3f3fSGregory Neil Shapiro 
407040266059SGregory Neil Shapiro /*
407106f25ae9SGregory Neil Shapiro **  MILTER_QUIT -- informs the filter(s) we are done and closes connection(s)
407206f25ae9SGregory Neil Shapiro **
407306f25ae9SGregory Neil Shapiro **	Parameters:
407406f25ae9SGregory Neil Shapiro **		e -- current envelope.
407506f25ae9SGregory Neil Shapiro **
407606f25ae9SGregory Neil Shapiro **	Returns:
407706f25ae9SGregory Neil Shapiro **		none
407806f25ae9SGregory Neil Shapiro */
407906f25ae9SGregory Neil Shapiro 
408006f25ae9SGregory Neil Shapiro void
408106f25ae9SGregory Neil Shapiro milter_quit(e)
408206f25ae9SGregory Neil Shapiro 	ENVELOPE *e;
408306f25ae9SGregory Neil Shapiro {
408406f25ae9SGregory Neil Shapiro 	int i;
408506f25ae9SGregory Neil Shapiro 
408606f25ae9SGregory Neil Shapiro 	if (tTd(64, 10))
408740266059SGregory Neil Shapiro 		sm_dprintf("milter_quit(%s)\n", e->e_id);
408806f25ae9SGregory Neil Shapiro 
408906f25ae9SGregory Neil Shapiro 	for (i = 0; InputFilters[i] != NULL; i++)
409006f25ae9SGregory Neil Shapiro 		milter_quit_filter(InputFilters[i], e);
409106f25ae9SGregory Neil Shapiro }
409240266059SGregory Neil Shapiro /*
409306f25ae9SGregory Neil Shapiro **  MILTER_ABORT -- informs the filter(s) that we are aborting current message
409406f25ae9SGregory Neil Shapiro **
409506f25ae9SGregory Neil Shapiro **	Parameters:
409606f25ae9SGregory Neil Shapiro **		e -- current envelope.
409706f25ae9SGregory Neil Shapiro **
409806f25ae9SGregory Neil Shapiro **	Returns:
409906f25ae9SGregory Neil Shapiro **		none
410006f25ae9SGregory Neil Shapiro */
410106f25ae9SGregory Neil Shapiro 
410206f25ae9SGregory Neil Shapiro void
410306f25ae9SGregory Neil Shapiro milter_abort(e)
410406f25ae9SGregory Neil Shapiro 	ENVELOPE *e;
410506f25ae9SGregory Neil Shapiro {
410606f25ae9SGregory Neil Shapiro 	int i;
410706f25ae9SGregory Neil Shapiro 
410806f25ae9SGregory Neil Shapiro 	if (tTd(64, 10))
410940266059SGregory Neil Shapiro 		sm_dprintf("milter_abort\n");
411006f25ae9SGregory Neil Shapiro 
411106f25ae9SGregory Neil Shapiro 	for (i = 0; InputFilters[i] != NULL; i++)
411206f25ae9SGregory Neil Shapiro 	{
411306f25ae9SGregory Neil Shapiro 		struct milter *m = InputFilters[i];
411406f25ae9SGregory Neil Shapiro 
411506f25ae9SGregory Neil Shapiro 		/* sanity checks */
411606f25ae9SGregory Neil Shapiro 		if (m->mf_sock < 0 || m->mf_state != SMFS_INMSG)
411706f25ae9SGregory Neil Shapiro 			continue;
411806f25ae9SGregory Neil Shapiro 
411906f25ae9SGregory Neil Shapiro 		milter_abort_filter(m, e);
412006f25ae9SGregory Neil Shapiro 	}
412106f25ae9SGregory Neil Shapiro }
412240266059SGregory Neil Shapiro #endif /* MILTER */
4123