engine.c revision 110560
1139749Simp/*
229415Sjmg *  Copyright (c) 1999-2002 Sendmail, Inc. and its suppliers.
329415Sjmg *	All rights reserved.
429415Sjmg *
529415Sjmg * By using this file, you agree to the terms and conditions set
629415Sjmg * forth in the LICENSE file which can be found at the top level of
729415Sjmg * the sendmail distribution.
829415Sjmg *
929415Sjmg */
1029415Sjmg
11139749Simp#include <sm/gen.h>
12139749SimpSM_RCSID("@(#)$Id: engine.c,v 8.109.2.4 2002/12/03 17:27:32 ca Exp $")
13139749Simp
14139749Simp#include "libmilter.h"
15139749Simp
16139749Simp#if NETINET || NETINET6
17139749Simp# include <arpa/inet.h>
18139749Simp#endif /* NETINET || NETINET6 */
19139749Simp
20139749Simp/* generic argument for functions in the command table */
21139749Simpstruct arg_struct
22139749Simp{
23139749Simp	size_t		a_len;		/* length of buffer */
24139749Simp	char		*a_buf;		/* argument string */
25139749Simp	int		a_idx;		/* index for macro array */
26139749Simp	SMFICTX_PTR	a_ctx;		/* context */
27139749Simp};
28139749Simp
29139749Simptypedef struct arg_struct genarg;
30139749Simp
31139749Simp/* structure for commands received from MTA */
32139749Simpstruct cmdfct_t
33139749Simp{
34139749Simp	char	cm_cmd;				/* command */
35139749Simp	int	cm_argt;			/* type of arguments expected */
36139749Simp	int	cm_next;			/* next state */
37139749Simp	int	cm_todo;			/* what to do next */
38139749Simp	int	cm_macros;			/* index for macros */
3929415Sjmg	int	(*cm_fct) __P((genarg *));	/* function to execute */
4029415Sjmg};
4129415Sjmg
4229415Sjmgtypedef struct cmdfct_t cmdfct;
4329415Sjmg
4429415Sjmg/* possible values for cm_argt */
4529415Sjmg#define	CM_ARG0	0	/* no args */
4629415Sjmg#define	CM_ARG1	1	/* one arg (string) */
4729415Sjmg#define	CM_ARG2	2	/* two args (strings) */
4829415Sjmg#define	CM_ARGA	4	/* one string and _SOCK_ADDR */
4929415Sjmg#define	CM_ARGO	5	/* two integers */
5029415Sjmg#define	CM_ARGV	8	/* \0 separated list of args, NULL-terminated */
5129415Sjmg#define	CM_ARGN	9	/* \0 separated list of args (strings) */
5229415Sjmg
5329415Sjmg/* possible values for cm_todo */
5474763Scg#define	CT_CONT		0x0000	/* continue reading commands */
5574763Scg#define	CT_IGNO		0x0001	/* continue even when error  */
5674763Scg
5774763Scg/* not needed right now, done via return code instead */
5874763Scg#define	CT_KEEP		0x0004	/* keep buffer (contains symbols) */
5974763Scg#define	CT_END		0x0008	/* start replying */
6074763Scg
6174763Scg/* index in macro array: macros only for these commands */
6274763Scg#define	CI_NONE	(-1)
6374763Scg#define	CI_CONN	0
6474763Scg#define	CI_HELO	1
6574763Scg#define	CI_MAIL	2
6674763Scg#define	CI_RCPT	3
6774763Scg#if CI_RCPT >= MAX_MACROS_ENTRIES
6874763ScgERROR: do not compile with CI_RCPT >= MAX_MACROS_ENTRIES
6974763Scg#endif
7074763Scg
7129415Sjmg/* function prototypes */
7229415Sjmgstatic int	st_abortfct __P((genarg *));
7329415Sjmgstatic int	st_macros __P((genarg *));
7429415Sjmgstatic int	st_optionneg __P((genarg *));
7529415Sjmgstatic int	st_bodychunk __P((genarg *));
7650723Scgstatic int	st_connectinfo __P((genarg *));
7750723Scgstatic int	st_bodyend __P((genarg *));
7850723Scgstatic int	st_helo __P((genarg *));
7929415Sjmgstatic int	st_header __P((genarg *));
8029415Sjmgstatic int	st_sender __P((genarg *));
8129415Sjmgstatic int	st_rcpt __P((genarg *));
8229415Sjmgstatic int	st_eoh __P((genarg *));
8329415Sjmgstatic int	st_quit __P((genarg *));
8429415Sjmgstatic int	sendreply __P((sfsistat, socket_t, struct timeval *, SMFICTX_PTR));
8529415Sjmgstatic void	fix_stm __P((SMFICTX_PTR));
8650723Scgstatic bool	trans_ok __P((int, int));
8729415Sjmgstatic char	**dec_argv __P((char *, size_t));
8829415Sjmgstatic int	dec_arg2 __P((char *, size_t, char **, char **));
8929415Sjmg
9029415Sjmg/* states */
9129415Sjmg#define ST_NONE	(-1)
9250723Scg#define ST_INIT	0	/* initial state */
9329415Sjmg#define ST_OPTS	1	/* option negotiation */
9450723Scg#define ST_CONN	2	/* connection info */
9529415Sjmg#define ST_HELO	3	/* helo */
9629415Sjmg#define ST_MAIL	4	/* mail from */
9729415Sjmg#define ST_RCPT	5	/* rcpt to */
9829415Sjmg#define ST_HDRS	6	/* headers */
9929415Sjmg#define ST_EOHS	7	/* end of headers */
10029415Sjmg#define ST_BODY	8	/* body */
10129415Sjmg#define ST_ENDM	9	/* end of message */
10250723Scg#define ST_QUIT	10	/* quit */
10329415Sjmg#define ST_ABRT	11	/* abort */
10429415Sjmg#define ST_LAST	ST_ABRT
10529415Sjmg#define ST_SKIP	15	/* not a state but required for the state table */
10629415Sjmg
10729415Sjmg/* in a mail transaction? must be before eom according to spec. */
10829415Sjmg#define ST_IN_MAIL(st)	((st) >= ST_MAIL && (st) < ST_ENDM)
10929415Sjmg
11029415Sjmg/*
11129415Sjmg**  set of next states
11229415Sjmg**  each state (ST_*) corresponds to bit in an int value (1 << state)
11329415Sjmg**  each state has a set of allowed transitions ('or' of bits of states)
11429415Sjmg**  so a state transition is valid if the mask of the next state
11550723Scg**  is set in the NX_* value
11629415Sjmg**  this function is coded in trans_ok(), see below.
11729415Sjmg*/
11829415Sjmg
11929415Sjmg#define MI_MASK(x)	(0x0001 << (x))	/* generate a bit "mask" for a state */
12050723Scg#define NX_INIT	(MI_MASK(ST_OPTS))
12129415Sjmg#define NX_OPTS	(MI_MASK(ST_CONN))
12229415Sjmg#define NX_CONN	(MI_MASK(ST_HELO) | MI_MASK(ST_MAIL))
12329415Sjmg#define NX_HELO	(MI_MASK(ST_HELO) | MI_MASK(ST_MAIL))
12429415Sjmg#define NX_MAIL	(MI_MASK(ST_RCPT) | MI_MASK(ST_ABRT))
12529415Sjmg#define NX_RCPT	(MI_MASK(ST_HDRS) | MI_MASK(ST_EOHS) | \
12629415Sjmg		 MI_MASK(ST_BODY) | MI_MASK(ST_ENDM) | \
12729415Sjmg		 MI_MASK(ST_RCPT) | MI_MASK(ST_ABRT))
12829415Sjmg#define NX_HDRS	(MI_MASK(ST_EOHS) | MI_MASK(ST_HDRS) | MI_MASK(ST_ABRT))
12929415Sjmg#define NX_EOHS	(MI_MASK(ST_BODY) | MI_MASK(ST_ENDM) | MI_MASK(ST_ABRT))
13029415Sjmg#define NX_BODY	(MI_MASK(ST_ENDM) | MI_MASK(ST_BODY) | MI_MASK(ST_ABRT))
13129415Sjmg#define NX_ENDM	(MI_MASK(ST_QUIT) | MI_MASK(ST_MAIL))
13229415Sjmg#define NX_QUIT	0
13329415Sjmg#define NX_ABRT	0
13429415Sjmg#define NX_SKIP MI_MASK(ST_SKIP)
13529415Sjmg
13629415Sjmgstatic int next_states[] =
13729415Sjmg{
13829415Sjmg	NX_INIT,
13929415Sjmg	NX_OPTS,
14029415Sjmg	NX_CONN,
14129415Sjmg	NX_HELO,
14229415Sjmg	NX_MAIL,
14329415Sjmg	NX_RCPT,
14429415Sjmg	NX_HDRS,
14529415Sjmg	NX_EOHS,
14629415Sjmg	NX_BODY,
14729415Sjmg	NX_ENDM,
14829415Sjmg	NX_QUIT,
14929415Sjmg	NX_ABRT
15029415Sjmg};
15129415Sjmg
15229415Sjmg/* commands received by milter */
15350723Scgstatic cmdfct cmds[] =
15450723Scg{
15574711Scg{SMFIC_ABORT,	CM_ARG0, ST_ABRT,  CT_CONT,	CI_NONE, st_abortfct	},
15629415Sjmg{SMFIC_MACRO,	CM_ARGV, ST_NONE,  CT_KEEP,	CI_NONE, st_macros	},
15729415Sjmg{SMFIC_BODY,	CM_ARG1, ST_BODY,  CT_CONT,	CI_NONE, st_bodychunk	},
15829415Sjmg{SMFIC_CONNECT,	CM_ARG2, ST_CONN,  CT_CONT,	CI_CONN, st_connectinfo	},
15950723Scg{SMFIC_BODYEOB,	CM_ARG1, ST_ENDM,  CT_CONT,	CI_NONE, st_bodyend	},
16029415Sjmg{SMFIC_HELO,	CM_ARG1, ST_HELO,  CT_CONT,	CI_HELO, st_helo	},
16150723Scg{SMFIC_HEADER,	CM_ARG2, ST_HDRS,  CT_CONT,	CI_NONE, st_header	},
16229415Sjmg{SMFIC_MAIL,	CM_ARGV, ST_MAIL,  CT_CONT,	CI_MAIL, st_sender	},
16350723Scg{SMFIC_OPTNEG,	CM_ARGO, ST_OPTS,  CT_CONT,	CI_NONE, st_optionneg	},
16429415Sjmg{SMFIC_EOH,	CM_ARG0, ST_EOHS,  CT_CONT,	CI_NONE, st_eoh		},
16529415Sjmg{SMFIC_QUIT,	CM_ARG0, ST_QUIT,  CT_END,	CI_NONE, st_quit	},
16629415Sjmg{SMFIC_RCPT,	CM_ARGV, ST_RCPT,  CT_IGNO,	CI_RCPT, st_rcpt	}
16729415Sjmg};
16829415Sjmg
16929415Sjmg/* additional (internal) reply codes */
17029415Sjmg#define _SMFIS_KEEP	20
17150723Scg#define _SMFIS_ABORT	21
17229415Sjmg#define _SMFIS_OPTIONS	22
17329415Sjmg#define _SMFIS_NOREPLY	23
17429415Sjmg#define _SMFIS_FAIL	(-1)
17529415Sjmg#define _SMFIS_NONE	(-2)
17629415Sjmg
17729415Sjmg/*
17829415Sjmg**  MI_ENGINE -- receive commands and process them
17929415Sjmg**
18029415Sjmg**	Parameters:
18129415Sjmg**		ctx -- context structure
18229415Sjmg**
18329415Sjmg**	Returns:
18429415Sjmg**		MI_FAILURE/MI_SUCCESS
18529415Sjmg*/
18629415Sjmgint
18729415Sjmgmi_engine(ctx)
18829415Sjmg	SMFICTX_PTR ctx;
18929415Sjmg{
19029415Sjmg	size_t len;
19129415Sjmg	int i;
19229415Sjmg	socket_t sd;
19329415Sjmg	int ret = MI_SUCCESS;
19430869Sjmg	int ncmds = sizeof(cmds) / sizeof(cmdfct);
19530869Sjmg	int curstate = ST_INIT;
19629415Sjmg	int newstate;
19729415Sjmg	bool call_abort;
19829415Sjmg	sfsistat r;
19929415Sjmg	char cmd;
20030869Sjmg	char *buf = NULL;
20174711Scg	genarg arg;
20274711Scg	struct timeval timeout;
20374711Scg	int (*f) __P((genarg *));
20429415Sjmg	sfsistat (*fi_abort) __P((SMFICTX *));
20530869Sjmg	sfsistat (*fi_close) __P((SMFICTX *));
20630869Sjmg
20729415Sjmg	arg.a_ctx = ctx;
20829415Sjmg	sd = ctx->ctx_sd;
20929415Sjmg	fi_abort = ctx->ctx_smfi->xxfi_abort;
21029415Sjmg	mi_clr_macros(ctx, 0);
21130869Sjmg	fix_stm(ctx);
21230869Sjmg	r = _SMFIS_NONE;
21330869Sjmg	do
21430869Sjmg	{
21530869Sjmg		/* call abort only if in a mail transaction */
21629415Sjmg		call_abort = ST_IN_MAIL(curstate);
21729415Sjmg		timeout.tv_sec = ctx->ctx_timeout;
21830869Sjmg		timeout.tv_usec = 0;
21930869Sjmg		if (mi_stop() == MILTER_ABRT)
22030869Sjmg		{
22130869Sjmg			if (ctx->ctx_dbg > 3)
22274797Scg				sm_dprintf("[%d] milter_abort\n",
22360711Snyan					(int) ctx->ctx_id);
22474797Scg			ret = MI_FAILURE;
22530869Sjmg			break;
22660711Snyan		}
22729415Sjmg
22829415Sjmg		/*
22929415Sjmg		**  Notice: buf is allocated by mi_rd_cmd() and it will
23029415Sjmg		**  usually be free()d after it has been used in f().
23174797Scg		**  However, if the function returns _SMFIS_KEEP then buf
23260711Snyan		**  contains macros and will not be free()d.
23374797Scg		**  Hence r must be set to _SMFIS_NONE if a new buf is
23430869Sjmg		**  allocated to avoid problem with housekeeping, esp.
23560711Snyan		**  if the code "break"s out of the loop.
23629415Sjmg		*/
23730869Sjmg
23830869Sjmg		r = _SMFIS_NONE;
23929415Sjmg		if ((buf = mi_rd_cmd(sd, &timeout, &cmd, &len,
24030869Sjmg				     ctx->ctx_smfi->xxfi_name)) == NULL &&
24130869Sjmg		    cmd < SMFIC_VALIDCMD)
24230869Sjmg		{
24330869Sjmg			if (ctx->ctx_dbg > 5)
24429415Sjmg				sm_dprintf("[%d] mi_engine: mi_rd_cmd error (%x)\n",
24529415Sjmg					(int) ctx->ctx_id, (int) cmd);
24630869Sjmg
24730869Sjmg			/*
24830869Sjmg			**  eof is currently treated as failure ->
24930869Sjmg			**  abort() instead of close(), otherwise use:
25030869Sjmg			**  if (cmd != SMFIC_EOF)
25130869Sjmg			*/
25230869Sjmg
25330869Sjmg			ret = MI_FAILURE;
25430869Sjmg			break;
25530869Sjmg		}
25674711Scg		if (ctx->ctx_dbg > 4)
25774711Scg			sm_dprintf("[%d] got cmd '%c' len %d\n",
25874711Scg				(int) ctx->ctx_id, cmd, (int) len);
25974711Scg		for (i = 0; i < ncmds; i++)
26074711Scg		{
26174711Scg			if (cmd == cmds[i].cm_cmd)
26274711Scg				break;
26374711Scg		}
26474711Scg		if (i >= ncmds)
26574711Scg		{
26674711Scg			/* unknown command */
26774711Scg			if (ctx->ctx_dbg > 1)
26874711Scg				sm_dprintf("[%d] cmd '%c' unknown\n",
26974711Scg					(int) ctx->ctx_id, cmd);
27074711Scg			ret = MI_FAILURE;
27174711Scg			break;
27274711Scg		}
27374711Scg		if ((f = cmds[i].cm_fct) == NULL)
27474711Scg		{
27574711Scg			/* stop for now */
27674711Scg			if (ctx->ctx_dbg > 1)
27774711Scg				sm_dprintf("[%d] cmd '%c' not impl\n",
27874711Scg					(int) ctx->ctx_id, cmd);
27974711Scg			ret = MI_FAILURE;
28030869Sjmg			break;
28130869Sjmg		}
28230869Sjmg
28330869Sjmg		/* is new state ok? */
28429415Sjmg		newstate = cmds[i].cm_next;
28529415Sjmg		if (ctx->ctx_dbg > 5)
28630869Sjmg			sm_dprintf("[%d] cur %x new %x nextmask %x\n",
28730869Sjmg				(int) ctx->ctx_id,
28829415Sjmg				curstate, newstate, next_states[curstate]);
28929415Sjmg
29030869Sjmg		if (newstate != ST_NONE && !trans_ok(curstate, newstate))
29129415Sjmg		{
29229415Sjmg			if (ctx->ctx_dbg > 1)
29329415Sjmg				sm_dprintf("[%d] abort: cur %d (%x) new %d (%x) next %x\n",
29430869Sjmg					(int) ctx->ctx_id,
29530869Sjmg					curstate, MI_MASK(curstate),
29630869Sjmg					newstate, MI_MASK(newstate),
29729415Sjmg					next_states[curstate]);
29830869Sjmg
29930869Sjmg			/* call abort only if in a mail transaction */
30030869Sjmg			if (fi_abort != NULL && call_abort)
30130869Sjmg				(void) (*fi_abort)(ctx);
30229415Sjmg
30329415Sjmg			/*
30430869Sjmg			**  try to reach the new state from HELO
30530869Sjmg			**  if it can't be reached, ignore the command.
30630869Sjmg			*/
30730869Sjmg
30830869Sjmg			curstate = ST_HELO;
30950723Scg			if (!trans_ok(curstate, newstate))
31050723Scg			{
31150723Scg				if (buf != NULL)
31250723Scg				{
31350723Scg					free(buf);
31450723Scg					buf = NULL;
31550723Scg				}
31650723Scg				continue;
31750723Scg			}
31850723Scg		}
31950723Scg		arg.a_len = len;
32050723Scg		arg.a_buf = buf;
32150723Scg		if (newstate != ST_NONE)
32250723Scg		{
32350723Scg			curstate = newstate;
32450723Scg			ctx->ctx_state = curstate;
32550723Scg		}
32650723Scg		arg.a_idx = cmds[i].cm_macros;
32750723Scg
32850723Scg		/* call function to deal with command */
32950723Scg		r = (*f)(&arg);
33050723Scg		if (r != _SMFIS_KEEP && buf != NULL)
33150723Scg		{
33250723Scg			free(buf);
33350723Scg			buf = NULL;
33450723Scg		}
33550723Scg		if (sendreply(r, sd, &timeout, ctx) != MI_SUCCESS)
33650723Scg		{
33750723Scg			ret = MI_FAILURE;
33850723Scg			break;
33950723Scg		}
34050723Scg
34150723Scg		call_abort = ST_IN_MAIL(curstate);
34250723Scg		if (r == SMFIS_ACCEPT)
34350723Scg		{
34450723Scg			/* accept mail, no further actions taken */
34550723Scg			curstate = ST_HELO;
34650723Scg		}
34750723Scg		else if (r == SMFIS_REJECT || r == SMFIS_DISCARD ||
34850723Scg			 r ==  SMFIS_TEMPFAIL)
34950723Scg		{
35050723Scg			/*
35150723Scg			**  further actions depend on current state
35250723Scg			**  if the IGNO bit is set: "ignore" the error,
35350723Scg			**  i.e., stay in the current state
35450723Scg			*/
35550723Scg			if (!bitset(CT_IGNO, cmds[i].cm_todo))
35650723Scg				curstate = ST_HELO;
35750723Scg		}
35850723Scg		else if (r == _SMFIS_ABORT)
35950723Scg		{
36050723Scg			if (ctx->ctx_dbg > 5)
36150723Scg				sm_dprintf("[%d] function returned abort\n",
36250723Scg					(int) ctx->ctx_id);
36350723Scg			ret = MI_FAILURE;
36450723Scg			break;
36550723Scg		}
36650723Scg	} while (!bitset(CT_END, cmds[i].cm_todo));
36750723Scg
36850723Scg	if (ret != MI_SUCCESS)
36950723Scg	{
37050723Scg		/* call abort only if in a mail transaction */
37150723Scg		if (fi_abort != NULL && call_abort)
37250723Scg			(void) (*fi_abort)(ctx);
37350723Scg	}
37450723Scg
37550723Scg	/* close must always be called */
37650723Scg	if ((fi_close = ctx->ctx_smfi->xxfi_close) != NULL)
37750723Scg		(void) (*fi_close)(ctx);
37850723Scg	if (r != _SMFIS_KEEP && buf != NULL)
37950723Scg		free(buf);
38050723Scg	mi_clr_macros(ctx, 0);
38150723Scg	return ret;
38250723Scg}
38350723Scg/*
38450723Scg**  SENDREPLY -- send a reply to the MTA
38550723Scg**
38650723Scg**	Parameters:
38750723Scg**		r -- reply code
38850723Scg**		sd -- socket descriptor
38950723Scg**		timeout_ptr -- (ptr to) timeout to use for sending
39050723Scg**		ctx -- context structure
39150723Scg**
39250723Scg**	Returns:
39350723Scg**		MI_SUCCESS/MI_FAILURE
39450723Scg*/
39550723Scg
39650723Scgstatic int
39750723Scgsendreply(r, sd, timeout_ptr, ctx)
39850723Scg	sfsistat r;
39950723Scg	socket_t sd;
40050723Scg	struct timeval *timeout_ptr;
40150723Scg	SMFICTX_PTR ctx;
40250723Scg{
40350723Scg	int ret = MI_SUCCESS;
40450723Scg
40550723Scg	switch (r)
40650723Scg	{
40750723Scg	  case SMFIS_CONTINUE:
40850723Scg		ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_CONTINUE, NULL, 0);
40950723Scg		break;
41050723Scg	  case SMFIS_TEMPFAIL:
41150723Scg	  case SMFIS_REJECT:
41250723Scg		if (ctx->ctx_reply != NULL &&
41350723Scg		    ((r == SMFIS_TEMPFAIL && *ctx->ctx_reply == '4') ||
41450723Scg		     (r == SMFIS_REJECT && *ctx->ctx_reply == '5')))
41550723Scg		{
41650723Scg			ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_REPLYCODE,
41750723Scg					ctx->ctx_reply,
41850723Scg					strlen(ctx->ctx_reply) + 1);
41950723Scg			free(ctx->ctx_reply);
42050723Scg			ctx->ctx_reply = NULL;
42150723Scg		}
42250723Scg		else
42350723Scg		{
42450723Scg			ret = mi_wr_cmd(sd, timeout_ptr, r == SMFIS_REJECT ?
42550723Scg					SMFIR_REJECT : SMFIR_TEMPFAIL, NULL, 0);
426		}
427		break;
428	  case SMFIS_DISCARD:
429		ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_DISCARD, NULL, 0);
430		break;
431	  case SMFIS_ACCEPT:
432		ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_ACCEPT, NULL, 0);
433		break;
434	  case _SMFIS_OPTIONS:
435		{
436			char buf[MILTER_OPTLEN];
437			mi_int32 v;
438
439			v = htonl(ctx->ctx_smfi->xxfi_version);
440			(void) memcpy(&(buf[0]), (void *) &v, MILTER_LEN_BYTES);
441			v = htonl(ctx->ctx_smfi->xxfi_flags);
442			(void) memcpy(&(buf[MILTER_LEN_BYTES]), (void *) &v,
443				      MILTER_LEN_BYTES);
444			v = htonl(ctx->ctx_pflags);
445			(void) memcpy(&(buf[MILTER_LEN_BYTES * 2]), (void *) &v,
446				      MILTER_LEN_BYTES);
447			ret = mi_wr_cmd(sd, timeout_ptr, SMFIC_OPTNEG, buf,
448				       MILTER_OPTLEN);
449		}
450		break;
451	  default:	/* don't send a reply */
452		break;
453	}
454	return ret;
455}
456
457/*
458**  CLR_MACROS -- clear set of macros starting from a given index
459**
460**	Parameters:
461**		ctx -- context structure
462**		m -- index from which to clear all macros
463**
464**	Returns:
465**		None.
466*/
467void
468mi_clr_macros(ctx, m)
469	SMFICTX_PTR ctx;
470	int m;
471{
472	int i;
473
474	for (i = m; i < MAX_MACROS_ENTRIES; i++)
475	{
476		if (ctx->ctx_mac_ptr[i] != NULL)
477		{
478			free(ctx->ctx_mac_ptr[i]);
479			ctx->ctx_mac_ptr[i] = NULL;
480		}
481		if (ctx->ctx_mac_buf[i] != NULL)
482		{
483			free(ctx->ctx_mac_buf[i]);
484			ctx->ctx_mac_buf[i] = NULL;
485		}
486	}
487}
488/*
489**  ST_OPTIONNEG -- negotiate options
490**
491**	Parameters:
492**		g -- generic argument structure
493**
494**	Returns:
495**		abort/send options/continue
496*/
497
498static int
499st_optionneg(g)
500	genarg *g;
501{
502	mi_int32 i, v;
503
504	if (g == NULL || g->a_ctx->ctx_smfi == NULL)
505		return SMFIS_CONTINUE;
506	mi_clr_macros(g->a_ctx, g->a_idx + 1);
507
508	/* check for minimum length */
509	if (g->a_len < MILTER_OPTLEN)
510	{
511		smi_log(SMI_LOG_ERR,
512			"%s: st_optionneg[%d]: len too short %d < %d",
513			g->a_ctx->ctx_smfi->xxfi_name,
514			(int) g->a_ctx->ctx_id, (int) g->a_len,
515			MILTER_OPTLEN);
516		return _SMFIS_ABORT;
517	}
518
519	(void) memcpy((void *) &i, (void *) &(g->a_buf[0]),
520		      MILTER_LEN_BYTES);
521	v = ntohl(i);
522	if (v < g->a_ctx->ctx_smfi->xxfi_version)
523	{
524		/* hard failure for now! */
525		smi_log(SMI_LOG_ERR,
526			"%s: st_optionneg[%d]: version mismatch MTA: %d < milter: %d",
527			g->a_ctx->ctx_smfi->xxfi_name,
528			(int) g->a_ctx->ctx_id, (int) v,
529			g->a_ctx->ctx_smfi->xxfi_version);
530		return _SMFIS_ABORT;
531	}
532
533	(void) memcpy((void *) &i, (void *) &(g->a_buf[MILTER_LEN_BYTES]),
534		      MILTER_LEN_BYTES);
535	v = ntohl(i);
536
537	/* no flags? set to default value for V1 actions */
538	if (v == 0)
539		v = SMFI_V1_ACTS;
540	i = g->a_ctx->ctx_smfi->xxfi_flags;
541	if ((v & i) != i)
542	{
543		smi_log(SMI_LOG_ERR,
544			"%s: st_optionneg[%d]: 0x%x does not fulfill action requirements 0x%x",
545			g->a_ctx->ctx_smfi->xxfi_name,
546			(int) g->a_ctx->ctx_id, v, i);
547		return _SMFIS_ABORT;
548	}
549
550	(void) memcpy((void *) &i, (void *) &(g->a_buf[MILTER_LEN_BYTES * 2]),
551		      MILTER_LEN_BYTES);
552	v = ntohl(i);
553
554	/* no flags? set to default value for V1 protocol */
555	if (v == 0)
556		v = SMFI_V1_PROT;
557	i = g->a_ctx->ctx_pflags;
558	if ((v & i) != i)
559	{
560		smi_log(SMI_LOG_ERR,
561			"%s: st_optionneg[%d]: 0x%x does not fulfill protocol requirements 0x%x",
562			g->a_ctx->ctx_smfi->xxfi_name,
563			(int) g->a_ctx->ctx_id, v, i);
564		return _SMFIS_ABORT;
565	}
566
567	return _SMFIS_OPTIONS;
568}
569/*
570**  ST_CONNECTINFO -- receive connection information
571**
572**	Parameters:
573**		g -- generic argument structure
574**
575**	Returns:
576**		continue or filter-specified value
577*/
578
579static int
580st_connectinfo(g)
581	genarg *g;
582{
583	size_t l;
584	size_t i;
585	char *s, family;
586	unsigned short port = 0;
587	_SOCK_ADDR sockaddr;
588	sfsistat (*fi_connect) __P((SMFICTX *, char *, _SOCK_ADDR *));
589
590	if (g == NULL)
591		return _SMFIS_ABORT;
592	mi_clr_macros(g->a_ctx, g->a_idx + 1);
593	if (g->a_ctx->ctx_smfi == NULL ||
594	    (fi_connect = g->a_ctx->ctx_smfi->xxfi_connect) == NULL)
595		return SMFIS_CONTINUE;
596
597	s = g->a_buf;
598	i = 0;
599	l = g->a_len;
600	while (s[i] != '\0' && i <= l)
601		++i;
602	if (i >= l)
603		return _SMFIS_ABORT;
604
605	/* Move past trailing \0 in host string */
606	i++;
607	family = s[i++];
608	memset(&sockaddr, '\0', sizeof sockaddr);
609	if (family != SMFIA_UNKNOWN)
610	{
611		(void) memcpy((void *) &port, (void *) (s + i),
612			      sizeof port);
613		if ((i += sizeof port) >= l)
614		{
615			smi_log(SMI_LOG_ERR,
616				"%s: connect[%d]: wrong len %d >= %d",
617				g->a_ctx->ctx_smfi->xxfi_name,
618				(int) g->a_ctx->ctx_id, (int) i, (int) l);
619			return _SMFIS_ABORT;
620		}
621
622		/* make sure string is terminated */
623		if (s[l - 1] != '\0')
624			return _SMFIS_ABORT;
625# if NETINET
626		if (family == SMFIA_INET)
627		{
628			if (inet_aton(s + i, (struct in_addr *) &sockaddr.sin.sin_addr)
629			    != 1)
630			{
631				smi_log(SMI_LOG_ERR,
632					"%s: connect[%d]: inet_aton failed",
633					g->a_ctx->ctx_smfi->xxfi_name,
634					(int) g->a_ctx->ctx_id);
635				return _SMFIS_ABORT;
636			}
637			sockaddr.sa.sa_family = AF_INET;
638			if (port > 0)
639				sockaddr.sin.sin_port = port;
640		}
641		else
642# endif /* NETINET */
643# if NETINET6
644		if (family == SMFIA_INET6)
645		{
646			if (mi_inet_pton(AF_INET6, s + i,
647					 &sockaddr.sin6.sin6_addr) != 1)
648			{
649				smi_log(SMI_LOG_ERR,
650					"%s: connect[%d]: mi_inet_pton failed",
651					g->a_ctx->ctx_smfi->xxfi_name,
652					(int) g->a_ctx->ctx_id);
653				return _SMFIS_ABORT;
654			}
655			sockaddr.sa.sa_family = AF_INET6;
656			if (port > 0)
657				sockaddr.sin6.sin6_port = port;
658		}
659		else
660# endif /* NETINET6 */
661# if NETUNIX
662		if (family == SMFIA_UNIX)
663		{
664			if (sm_strlcpy(sockaddr.sunix.sun_path, s + i,
665			    sizeof sockaddr.sunix.sun_path) >=
666			    sizeof sockaddr.sunix.sun_path)
667			{
668				smi_log(SMI_LOG_ERR,
669					"%s: connect[%d]: path too long",
670					g->a_ctx->ctx_smfi->xxfi_name,
671					(int) g->a_ctx->ctx_id);
672				return _SMFIS_ABORT;
673			}
674			sockaddr.sunix.sun_family = AF_UNIX;
675		}
676		else
677# endif /* NETUNIX */
678		{
679			smi_log(SMI_LOG_ERR,
680				"%s: connect[%d]: unknown family %d",
681				g->a_ctx->ctx_smfi->xxfi_name,
682				(int) g->a_ctx->ctx_id, family);
683			return _SMFIS_ABORT;
684		}
685	}
686	return (*fi_connect)(g->a_ctx, g->a_buf,
687			     family != SMFIA_UNKNOWN ? &sockaddr : NULL);
688}
689/*
690**  ST_EOH -- end of headers
691**
692**	Parameters:
693**		g -- generic argument structure
694**
695**	Returns:
696**		continue or filter-specified value
697*/
698
699static int
700st_eoh(g)
701	genarg *g;
702{
703	sfsistat (*fi_eoh) __P((SMFICTX *));
704
705	if (g == NULL)
706		return _SMFIS_ABORT;
707	if (g->a_ctx->ctx_smfi != NULL &&
708	    (fi_eoh = g->a_ctx->ctx_smfi->xxfi_eoh) != NULL)
709		return (*fi_eoh)(g->a_ctx);
710	return SMFIS_CONTINUE;
711}
712/*
713**  ST_HELO -- helo/ehlo command
714**
715**	Parameters:
716**		g -- generic argument structure
717**
718**	Returns:
719**		continue or filter-specified value
720*/
721static int
722st_helo(g)
723	genarg *g;
724{
725	sfsistat (*fi_helo) __P((SMFICTX *, char *));
726
727	if (g == NULL)
728		return _SMFIS_ABORT;
729	mi_clr_macros(g->a_ctx, g->a_idx + 1);
730	if (g->a_ctx->ctx_smfi != NULL &&
731	    (fi_helo = g->a_ctx->ctx_smfi->xxfi_helo) != NULL)
732		return (*fi_helo)(g->a_ctx, g->a_buf);
733	return SMFIS_CONTINUE;
734}
735/*
736**  ST_HEADER -- header line
737**
738**	Parameters:
739**		g -- generic argument structure
740**
741**	Returns:
742**		continue or filter-specified value
743*/
744
745static int
746st_header(g)
747	genarg *g;
748{
749	char *hf, *hv;
750	sfsistat (*fi_header) __P((SMFICTX *, char *, char *));
751
752	if (g == NULL)
753		return _SMFIS_ABORT;
754	if (g->a_ctx->ctx_smfi == NULL ||
755	    (fi_header = g->a_ctx->ctx_smfi->xxfi_header) == NULL)
756		return SMFIS_CONTINUE;
757	if (dec_arg2(g->a_buf, g->a_len, &hf, &hv) == MI_SUCCESS)
758		return (*fi_header)(g->a_ctx, hf, hv);
759	else
760		return _SMFIS_ABORT;
761}
762
763#define ARGV_FCT(lf, rf, idx)					\
764	char **argv;						\
765	sfsistat (*lf) __P((SMFICTX *, char **));		\
766	int r;							\
767								\
768	if (g == NULL)						\
769		return _SMFIS_ABORT;				\
770	mi_clr_macros(g->a_ctx, g->a_idx + 1);			\
771	if (g->a_ctx->ctx_smfi == NULL ||			\
772	    (lf = g->a_ctx->ctx_smfi->rf) == NULL)		\
773		return SMFIS_CONTINUE;				\
774	if ((argv = dec_argv(g->a_buf, g->a_len)) == NULL)	\
775		return _SMFIS_ABORT;				\
776	r = (*lf)(g->a_ctx, argv);				\
777	free(argv);						\
778	return r;
779
780/*
781**  ST_SENDER -- MAIL FROM command
782**
783**	Parameters:
784**		g -- generic argument structure
785**
786**	Returns:
787**		continue or filter-specified value
788*/
789
790static int
791st_sender(g)
792	genarg *g;
793{
794	ARGV_FCT(fi_envfrom, xxfi_envfrom, CI_MAIL)
795}
796/*
797**  ST_RCPT -- RCPT TO command
798**
799**	Parameters:
800**		g -- generic argument structure
801**
802**	Returns:
803**		continue or filter-specified value
804*/
805
806static int
807st_rcpt(g)
808	genarg *g;
809{
810	ARGV_FCT(fi_envrcpt, xxfi_envrcpt, CI_RCPT)
811}
812/*
813**  ST_MACROS -- deal with macros received from the MTA
814**
815**	Parameters:
816**		g -- generic argument structure
817**
818**	Returns:
819**		continue/keep
820**
821**	Side effects:
822**		set pointer in macro array to current values.
823*/
824
825static int
826st_macros(g)
827	genarg *g;
828{
829	int i;
830	char **argv;
831
832	if (g == NULL || g->a_len < 1)
833		return _SMFIS_FAIL;
834	if ((argv = dec_argv(g->a_buf + 1, g->a_len - 1)) == NULL)
835		return _SMFIS_FAIL;
836	switch (g->a_buf[0])
837	{
838	  case SMFIC_CONNECT:
839		i = CI_CONN;
840		break;
841	  case SMFIC_HELO:
842		i = CI_HELO;
843		break;
844	  case SMFIC_MAIL:
845		i = CI_MAIL;
846		break;
847	  case SMFIC_RCPT:
848		i = CI_RCPT;
849		break;
850	  default:
851		free(argv);
852		return _SMFIS_FAIL;
853	}
854	if (g->a_ctx->ctx_mac_ptr[i] != NULL)
855		free(g->a_ctx->ctx_mac_ptr[i]);
856	if (g->a_ctx->ctx_mac_buf[i] != NULL)
857		free(g->a_ctx->ctx_mac_buf[i]);
858	g->a_ctx->ctx_mac_ptr[i] = argv;
859	g->a_ctx->ctx_mac_buf[i] = g->a_buf;
860	return _SMFIS_KEEP;
861}
862/*
863**  ST_QUIT -- quit command
864**
865**	Parameters:
866**		g -- generic argument structure
867**
868**	Returns:
869**		noreply
870*/
871
872static int
873st_quit(g)
874	genarg *g;
875{
876	return _SMFIS_NOREPLY;
877}
878/*
879**  ST_BODYCHUNK -- deal with a piece of the mail body
880**
881**	Parameters:
882**		g -- generic argument structure
883**
884**	Returns:
885**		continue or filter-specified value
886*/
887
888static int
889st_bodychunk(g)
890	genarg *g;
891{
892	sfsistat (*fi_body) __P((SMFICTX *, unsigned char *, size_t));
893
894	if (g == NULL)
895		return _SMFIS_ABORT;
896	if (g->a_ctx->ctx_smfi != NULL &&
897	    (fi_body = g->a_ctx->ctx_smfi->xxfi_body) != NULL)
898		return (*fi_body)(g->a_ctx, (unsigned char *)g->a_buf,
899				  g->a_len);
900	return SMFIS_CONTINUE;
901}
902/*
903**  ST_BODYEND -- deal with the last piece of the mail body
904**
905**	Parameters:
906**		g -- generic argument structure
907**
908**	Returns:
909**		continue or filter-specified value
910**
911**	Side effects:
912**		sends a reply for the body part (if non-empty).
913*/
914
915static int
916st_bodyend(g)
917	genarg *g;
918{
919	sfsistat r;
920	sfsistat (*fi_body) __P((SMFICTX *, unsigned char *, size_t));
921	sfsistat (*fi_eom) __P((SMFICTX *));
922
923	if (g == NULL)
924		return _SMFIS_ABORT;
925	r = SMFIS_CONTINUE;
926	if (g->a_ctx->ctx_smfi != NULL)
927	{
928		if ((fi_body = g->a_ctx->ctx_smfi->xxfi_body) != NULL &&
929		    g->a_len > 0)
930		{
931			socket_t sd;
932			struct timeval timeout;
933
934			timeout.tv_sec = g->a_ctx->ctx_timeout;
935			timeout.tv_usec = 0;
936			sd = g->a_ctx->ctx_sd;
937			r = (*fi_body)(g->a_ctx, (unsigned char *)g->a_buf,
938				       g->a_len);
939			if (r != SMFIS_CONTINUE &&
940			    sendreply(r, sd, &timeout, g->a_ctx) != MI_SUCCESS)
941				return _SMFIS_ABORT;
942		}
943	}
944	if (r == SMFIS_CONTINUE &&
945	    (fi_eom = g->a_ctx->ctx_smfi->xxfi_eom) != NULL)
946		return (*fi_eom)(g->a_ctx);
947	return r;
948}
949/*
950**  ST_ABORTFCT -- deal with aborts
951**
952**	Parameters:
953**		g -- generic argument structure
954**
955**	Returns:
956**		abort or filter-specified value
957*/
958
959static int
960st_abortfct(g)
961	genarg *g;
962{
963	sfsistat (*fi_abort) __P((SMFICTX *));
964
965	if (g == NULL)
966		return _SMFIS_ABORT;
967	if (g != NULL && g->a_ctx->ctx_smfi != NULL &&
968	    (fi_abort = g->a_ctx->ctx_smfi->xxfi_abort) != NULL)
969		(void) (*fi_abort)(g->a_ctx);
970	return _SMFIS_NOREPLY;
971}
972/*
973**  TRANS_OK -- is the state transition ok?
974**
975**	Parameters:
976**		old -- old state
977**		new -- new state
978**
979**	Returns:
980**		state transition ok
981*/
982
983static bool
984trans_ok(old, new)
985	int old, new;
986{
987	int s, n;
988
989	s = old;
990	do
991	{
992		/* is this state transition allowed? */
993		if ((MI_MASK(new) & next_states[s]) != 0)
994			return true;
995
996		/*
997		**  no: try next state;
998		**  this works since the relevant states are ordered
999		**  strict sequentially
1000		*/
1001
1002		n = s + 1;
1003
1004		/*
1005		**  can we actually "skip" this state?
1006		**  see fix_stm() which sets this bit for those
1007		**  states which the filter program is not interested in
1008		*/
1009
1010		if (bitset(NX_SKIP, next_states[n]))
1011			s = n;
1012		else
1013			return false;
1014	} while (s <= ST_LAST);
1015	return false;
1016}
1017/*
1018**  FIX_STM -- add "skip" bits to the state transition table
1019**
1020**	Parameters:
1021**		ctx -- context structure
1022**
1023**	Returns:
1024**		None.
1025**
1026**	Side effects:
1027**		may change state transition table.
1028*/
1029
1030static void
1031fix_stm(ctx)
1032	SMFICTX_PTR ctx;
1033{
1034	unsigned long fl;
1035
1036	if (ctx == NULL || ctx->ctx_smfi == NULL)
1037		return;
1038	fl = ctx->ctx_pflags;
1039	if (bitset(SMFIP_NOCONNECT, fl))
1040		next_states[ST_CONN] |= NX_SKIP;
1041	if (bitset(SMFIP_NOHELO, fl))
1042		next_states[ST_HELO] |= NX_SKIP;
1043	if (bitset(SMFIP_NOMAIL, fl))
1044		next_states[ST_MAIL] |= NX_SKIP;
1045	if (bitset(SMFIP_NORCPT, fl))
1046		next_states[ST_RCPT] |= NX_SKIP;
1047	if (bitset(SMFIP_NOHDRS, fl))
1048		next_states[ST_HDRS] |= NX_SKIP;
1049	if (bitset(SMFIP_NOEOH, fl))
1050		next_states[ST_EOHS] |= NX_SKIP;
1051	if (bitset(SMFIP_NOBODY, fl))
1052		next_states[ST_BODY] |= NX_SKIP;
1053}
1054/*
1055**  DEC_ARGV -- split a buffer into a list of strings, NULL terminated
1056**
1057**	Parameters:
1058**		buf -- buffer with several strings
1059**		len -- length of buffer
1060**
1061**	Returns:
1062**		array of pointers to the individual strings
1063*/
1064
1065static char **
1066dec_argv(buf, len)
1067	char *buf;
1068	size_t len;
1069{
1070	char **s;
1071	size_t i;
1072	int elem, nelem;
1073
1074	nelem = 0;
1075	for (i = 0; i < len; i++)
1076	{
1077		if (buf[i] == '\0')
1078			++nelem;
1079	}
1080	if (nelem == 0)
1081		return NULL;
1082
1083	/* last entry is only for the name */
1084	s = (char **)malloc((nelem + 1) * (sizeof *s));
1085	if (s == NULL)
1086		return NULL;
1087	s[0] = buf;
1088	for (i = 0, elem = 0; i < len && elem < nelem; i++)
1089	{
1090		if (buf[i] == '\0')
1091			s[++elem] = &(buf[i + 1]);
1092	}
1093
1094	/* overwrite last entry */
1095	s[elem] = NULL;
1096	return s;
1097}
1098/*
1099**  DEC_ARG2 -- split a buffer into two strings
1100**
1101**	Parameters:
1102**		buf -- buffer with two strings
1103**		len -- length of buffer
1104**		s1,s2 -- pointer to result strings
1105**
1106**	Returns:
1107**		MI_FAILURE/MI_SUCCESS
1108*/
1109
1110static int
1111dec_arg2(buf, len, s1, s2)
1112	char *buf;
1113	size_t len;
1114	char **s1;
1115	char **s2;
1116{
1117	size_t i;
1118
1119	*s1 = buf;
1120	for (i = 1; i < len && buf[i] != '\0'; i++)
1121		continue;
1122	if (i >= len - 1)
1123		return MI_FAILURE;
1124	*s2 = buf + i + 1;
1125	return MI_SUCCESS;
1126}
1127/*
1128**  SENDOK -- is it ok for the filter to send stuff to the MTA?
1129**
1130**	Parameters:
1131**		ctx -- context structure
1132**		flag -- flag to check
1133**
1134**	Returns:
1135**		sending allowed (in current state)
1136*/
1137
1138bool
1139mi_sendok(ctx, flag)
1140	SMFICTX_PTR ctx;
1141	int flag;
1142{
1143	if (ctx == NULL || ctx->ctx_smfi == NULL)
1144		return false;
1145
1146	/* did the milter request this operation? */
1147	if (flag != 0 && !bitset(flag, ctx->ctx_smfi->xxfi_flags))
1148		return false;
1149
1150	/* are we in the correct state? It must be "End of Message". */
1151	return ctx->ctx_state == ST_ENDM;
1152}
1153