engine.c revision 203004
1184610Salfred/*
2184610Salfred *  Copyright (c) 1999-2004, 2006-2008 Sendmail, Inc. and its suppliers.
3184610Salfred *	All rights reserved.
4184610Salfred *
5184610Salfred * By using this file, you agree to the terms and conditions set
6187494Semax * forth in the LICENSE file which can be found at the top level of
7184610Salfred * the sendmail distribution.
8184610Salfred *
9184610Salfred */
10184610Salfred
11184610Salfred#include <sm/gen.h>
12184610SalfredSM_RCSID("@(#)$Id: engine.c,v 8.166 2009/11/06 00:57:07 ca Exp $")
13184610Salfred
14184610Salfred#include "libmilter.h"
15184610Salfred
16184610Salfred#if NETINET || NETINET6
17184610Salfred# include <arpa/inet.h>
18184610Salfred#endif /* NETINET || NETINET6 */
19184610Salfred
20184610Salfred/* generic argument for functions in the command table */
21184610Salfredstruct arg_struct
22184610Salfred{
23184610Salfred	size_t		a_len;		/* length of buffer */
24184610Salfred	char		*a_buf;		/* argument string */
25184610Salfred	int		a_idx;		/* index for macro array */
26184610Salfred	SMFICTX_PTR	a_ctx;		/* context */
27184610Salfred};
28184610Salfred
29184610Salfredtypedef struct arg_struct genarg;
30184610Salfred
31184610Salfred/* structure for commands received from MTA */
32184610Salfredstruct cmdfct_t
33184610Salfred{
34187494Semax	char	cm_cmd;				/* command */
35187494Semax	int	cm_argt;			/* type of arguments expected */
36187741Semax	int	cm_next;			/* next state */
37187494Semax	int	cm_todo;			/* what to do next */
38187494Semax	int	cm_macros;			/* index for macros */
39187494Semax	int	(*cm_fct) __P((genarg *));	/* function to execute */
40187741Semax};
41187494Semax
42187741Semaxtypedef struct cmdfct_t cmdfct;
43187741Semax
44187741Semax/* possible values for cm_argt */
45187494Semax#define	CM_ARG0	0	/* no args */
46187741Semax#define	CM_ARG1	1	/* one arg (string) */
47187741Semax#define	CM_ARG2	2	/* two args (strings) */
48187741Semax#define	CM_ARGA	4	/* one string and _SOCK_ADDR */
49187741Semax#define	CM_ARGO	5	/* two integers */
50187494Semax#define	CM_ARGV	8	/* \0 separated list of args, NULL-terminated */
51187494Semax#define	CM_ARGN	9	/* \0 separated list of args (strings) */
52187494Semax
53187494Semax/* possible values for cm_todo */
54187741Semax#define	CT_CONT		0x0000	/* continue reading commands */
55187494Semax#define	CT_IGNO		0x0001	/* continue even when error  */
56187494Semax
57187494Semax/* not needed right now, done via return code instead */
58187494Semax#define	CT_KEEP		0x0004	/* keep buffer (contains symbols) */
59187494Semax#define	CT_END		0x0008	/* last command of session, stop replying */
60187494Semax
61187494Semax/* index in macro array: macros only for these commands */
62187741Semax#define	CI_NONE		(-1)
63187741Semax#define	CI_CONN		0
64187741Semax#define	CI_HELO		1
65187741Semax#define	CI_MAIL		2
66187741Semax#define CI_RCPT		3
67187741Semax#define CI_DATA		4
68187494Semax#define CI_EOM		5
69187741Semax#define CI_EOH		6
70187741Semax#define CI_LAST		CI_EOH
71187741Semax#if CI_LAST < CI_DATA
72187741SemaxERROR: do not compile with CI_LAST < CI_DATA
73187741Semax#endif
74187494Semax#if CI_LAST < CI_EOM
75187494SemaxERROR: do not compile with CI_LAST < CI_EOM
76187494Semax#endif
77187494Semax#if CI_LAST < CI_EOH
78187494SemaxERROR: do not compile with CI_LAST < CI_EOH
79187494Semax#endif
80187741Semax#if CI_LAST < CI_ENVRCPT
81187741SemaxERROR: do not compile with CI_LAST < CI_ENVRCPT
82187741Semax#endif
83187741Semax#if CI_LAST < CI_ENVFROM
84187494SemaxERROR: do not compile with CI_LAST < CI_ENVFROM
85187494Semax#endif
86187741Semax#if CI_LAST < CI_HELO
87187741SemaxERROR: do not compile with CI_LAST < CI_HELO
88187741Semax#endif
89187741Semax#if CI_LAST < CI_CONNECT
90189002SedERROR: do not compile with CI_LAST < CI_CONNECT
91187741Semax#endif
92187741Semax#if CI_LAST >= MAX_MACROS_ENTRIES
93187494SemaxERROR: do not compile with CI_LAST >= MAX_MACROS_ENTRIES
94187494Semax#endif
95188746Sthompsa
96188942Sthompsa/* function prototypes */
97188942Sthompsastatic int	st_abortfct __P((genarg *));
98188942Sthompsastatic int	st_macros __P((genarg *));
99184610Salfredstatic int	st_optionneg __P((genarg *));
100184610Salfredstatic int	st_bodychunk __P((genarg *));
101184610Salfredstatic int	st_connectinfo __P((genarg *));
102188942Sthompsastatic int	st_bodyend __P((genarg *));
103188942Sthompsastatic int	st_helo __P((genarg *));
104188942Sthompsastatic int	st_header __P((genarg *));
105188942Sthompsastatic int	st_sender __P((genarg *));
106188942Sthompsastatic int	st_rcpt __P((genarg *));
107188942Sthompsastatic int	st_unknown __P((genarg *));
108188942Sthompsastatic int	st_data __P((genarg *));
109188942Sthompsastatic int	st_eoh __P((genarg *));
110184610Salfredstatic int	st_quit __P((genarg *));
111184610Salfredstatic int	sendreply __P((sfsistat, socket_t, struct timeval *, SMFICTX_PTR));
112187494Semaxstatic void	fix_stm __P((SMFICTX_PTR));
113184610Salfredstatic bool	trans_ok __P((int, int));
114184610Salfredstatic char	**dec_argv __P((char *, size_t));
115184610Salfredstatic int	dec_arg2 __P((char *, size_t, char **, char **));
116184610Salfredstatic void	mi_clr_symlist __P((SMFICTX_PTR));
117184610Salfred
118184610Salfred#if _FFR_WORKERS_POOL
119184610Salfredstatic bool     mi_rd_socket_ready __P((int));
120184610Salfred#endif /* _FFR_WORKERS_POOL */
121188942Sthompsa
122184610Salfred/* states */
123187494Semax#define ST_NONE	(-1)
124187494Semax#define ST_INIT	0	/* initial state */
125187494Semax#define ST_OPTS	1	/* option negotiation */
126187494Semax#define ST_CONN	2	/* connection info */
127184610Salfred#define ST_HELO	3	/* helo */
128187741Semax#define ST_MAIL	4	/* mail from */
129187494Semax#define ST_RCPT	5	/* rcpt to */
130184610Salfred#define ST_DATA	6	/* data */
131187741Semax#define ST_HDRS	7	/* headers */
132187741Semax#define ST_EOHS	8	/* end of headers */
133187494Semax#define ST_BODY	9	/* body */
134187494Semax#define ST_ENDM	10	/* end of message */
135187494Semax#define ST_QUIT	11	/* quit */
136187494Semax#define ST_ABRT	12	/* abort */
137187494Semax#define ST_UNKN 13	/* unknown SMTP command */
138187494Semax#define ST_Q_NC	14	/* quit, new connection follows */
139187494Semax#define ST_LAST	ST_Q_NC	/* last valid state */
140187494Semax#define ST_SKIP	16	/* not a state but required for the state table */
141184610Salfred
142184610Salfred/* in a mail transaction? must be before eom according to spec. */
143187494Semax#define ST_IN_MAIL(st)	((st) >= ST_MAIL && (st) < ST_ENDM)
144184610Salfred
145187494Semax/*
146187494Semax**  set of next states
147187494Semax**  each state (ST_*) corresponds to bit in an int value (1 << state)
148184610Salfred**  each state has a set of allowed transitions ('or' of bits of states)
149187494Semax**  so a state transition is valid if the mask of the next state
150187494Semax**  is set in the NX_* value
151184610Salfred**  this function is coded in trans_ok(), see below.
152184610Salfred*/
153184610Salfred
154184610Salfred#define MI_MASK(x)	(0x0001 << (x))	/* generate a bit "mask" for a state */
155184610Salfred#define NX_INIT	(MI_MASK(ST_OPTS))
156187494Semax#define NX_OPTS	(MI_MASK(ST_CONN) | MI_MASK(ST_UNKN))
157184610Salfred#define NX_CONN	(MI_MASK(ST_HELO) | MI_MASK(ST_MAIL) | MI_MASK(ST_UNKN))
158187494Semax#define NX_HELO	(MI_MASK(ST_HELO) | MI_MASK(ST_MAIL) | MI_MASK(ST_UNKN))
159187494Semax#define NX_MAIL	(MI_MASK(ST_RCPT) | MI_MASK(ST_ABRT) | MI_MASK(ST_UNKN))
160187494Semax#define NX_RCPT	(MI_MASK(ST_HDRS) | MI_MASK(ST_EOHS) | MI_MASK(ST_DATA) | \
161187494Semax		 MI_MASK(ST_BODY) | MI_MASK(ST_ENDM) | \
162187494Semax		 MI_MASK(ST_RCPT) | MI_MASK(ST_ABRT) | MI_MASK(ST_UNKN))
163187494Semax#define NX_DATA	(MI_MASK(ST_EOHS) | MI_MASK(ST_HDRS) | MI_MASK(ST_ABRT))
164187494Semax#define NX_HDRS	(MI_MASK(ST_EOHS) | MI_MASK(ST_HDRS) | MI_MASK(ST_ABRT))
165184610Salfred#define NX_EOHS	(MI_MASK(ST_BODY) | MI_MASK(ST_ENDM) | MI_MASK(ST_ABRT))
166187494Semax#define NX_BODY	(MI_MASK(ST_ENDM) | MI_MASK(ST_BODY) | MI_MASK(ST_ABRT))
167187494Semax#define NX_ENDM	(MI_MASK(ST_QUIT) | MI_MASK(ST_MAIL) | MI_MASK(ST_UNKN) | \
168184610Salfred		MI_MASK(ST_Q_NC))
169184610Salfred#define NX_QUIT	0
170184610Salfred#define NX_ABRT	0
171184610Salfred#define NX_UNKN (MI_MASK(ST_HELO) | MI_MASK(ST_MAIL) | \
172184610Salfred		 MI_MASK(ST_RCPT) | MI_MASK(ST_ABRT) | \
173187494Semax		 MI_MASK(ST_DATA) | \
174187494Semax		 MI_MASK(ST_BODY) | MI_MASK(ST_UNKN) | \
175184610Salfred		 MI_MASK(ST_ABRT) | MI_MASK(ST_QUIT) | MI_MASK(ST_Q_NC))
176184610Salfred#define NX_Q_NC	(MI_MASK(ST_CONN) | MI_MASK(ST_UNKN))
177184610Salfred#define NX_SKIP MI_MASK(ST_SKIP)
178184610Salfred
179184610Salfredstatic int next_states[] =
180184610Salfred{
181184610Salfred	  NX_INIT
182184610Salfred	, NX_OPTS
183184610Salfred	, NX_CONN
184184610Salfred	, NX_HELO
185184610Salfred	, NX_MAIL
186184610Salfred	, NX_RCPT
187184610Salfred	, NX_DATA
188184610Salfred	, NX_HDRS
189184610Salfred	, NX_EOHS
190184610Salfred	, NX_BODY
191184610Salfred	, NX_ENDM
192184610Salfred	, NX_QUIT
193184610Salfred	, NX_ABRT
194184610Salfred	, NX_UNKN
195184610Salfred	, NX_Q_NC
196184610Salfred};
197184610Salfred
198184610Salfred#define SIZE_NEXT_STATES	(sizeof(next_states) / sizeof(next_states[0]))
199184610Salfred
200184610Salfred/* commands received by milter */
201184610Salfredstatic cmdfct cmds[] =
202184610Salfred{
203184610Salfred  {SMFIC_ABORT,	CM_ARG0, ST_ABRT,  CT_CONT,	CI_NONE, st_abortfct	}
204184610Salfred, {SMFIC_MACRO,	CM_ARGV, ST_NONE,  CT_KEEP,	CI_NONE, st_macros	}
205184610Salfred, {SMFIC_BODY,	CM_ARG1, ST_BODY,  CT_CONT,	CI_NONE, st_bodychunk	}
206184610Salfred, {SMFIC_CONNECT, CM_ARG2, ST_CONN,  CT_CONT,	CI_CONN, st_connectinfo	}
207184610Salfred, {SMFIC_BODYEOB, CM_ARG1, ST_ENDM,  CT_CONT,	CI_EOM,  st_bodyend	}
208184610Salfred, {SMFIC_HELO,	CM_ARG1, ST_HELO,  CT_CONT,	CI_HELO, st_helo	}
209184610Salfred, {SMFIC_HEADER, CM_ARG2, ST_HDRS,  CT_CONT,	CI_NONE, st_header	}
210184610Salfred, {SMFIC_MAIL,	CM_ARGV, ST_MAIL,  CT_CONT,	CI_MAIL, st_sender	}
211184610Salfred, {SMFIC_OPTNEG, CM_ARGO, ST_OPTS,  CT_CONT,	CI_NONE, st_optionneg	}
212184610Salfred, {SMFIC_EOH,	CM_ARG0, ST_EOHS,  CT_CONT,	CI_EOH,  st_eoh		}
213184610Salfred, {SMFIC_QUIT,	CM_ARG0, ST_QUIT,  CT_END,	CI_NONE, st_quit	}
214184610Salfred, {SMFIC_DATA,	CM_ARG0, ST_DATA,  CT_CONT,	CI_DATA, st_data	}
215184610Salfred, {SMFIC_RCPT,	CM_ARGV, ST_RCPT,  CT_IGNO,	CI_RCPT, st_rcpt	}
216184610Salfred, {SMFIC_UNKNOWN, CM_ARG1, ST_UNKN,  CT_IGNO,	CI_NONE, st_unknown	}
217187494Semax, {SMFIC_QUIT_NC, CM_ARG0, ST_Q_NC,  CT_CONT,	CI_NONE, st_quit	}
218184610Salfred};
219184610Salfred
220184610Salfred/*
221187494Semax**  Additional (internal) reply codes;
222187494Semax**  must be coordinated wit libmilter/mfapi.h
223187494Semax*/
224187494Semax
225187494Semax#define _SMFIS_KEEP	20
226187494Semax#define _SMFIS_ABORT	21
227187494Semax#define _SMFIS_OPTIONS	22
228187494Semax#define _SMFIS_NOREPLY	SMFIS_NOREPLY
229187494Semax#define _SMFIS_FAIL	(-1)
230187494Semax#define _SMFIS_NONE	(-2)
231187494Semax
232187494Semax/*
233184610Salfred**  MI_ENGINE -- receive commands and process them
234184610Salfred**
235187494Semax**	Parameters:
236187494Semax**		ctx -- context structure
237187494Semax**
238187494Semax**	Returns:
239187494Semax**		MI_FAILURE/MI_SUCCESS
240187494Semax*/
241184610Salfred
242187494Semaxint
243187494Semaxmi_engine(ctx)
244187494Semax	SMFICTX_PTR ctx;
245187494Semax{
246187494Semax	size_t len;
247187494Semax	int i;
248184610Salfred	socket_t sd;
249187741Semax	int ret = MI_SUCCESS;
250187741Semax	int ncmds = sizeof(cmds) / sizeof(cmdfct);
251184610Salfred	int curstate = ST_INIT;
252187494Semax	int newstate;
253187494Semax	bool call_abort;
254187494Semax	sfsistat r;
255187494Semax	char cmd;
256187494Semax	char *buf = NULL;
257187494Semax	genarg arg;
258187494Semax	struct timeval timeout;
259187494Semax	int (*f) __P((genarg *));
260187494Semax	sfsistat (*fi_abort) __P((SMFICTX *));
261187494Semax	sfsistat (*fi_close) __P((SMFICTX *));
262187494Semax
263187494Semax	arg.a_ctx = ctx;
264187494Semax	sd = ctx->ctx_sd;
265187494Semax	fi_abort = ctx->ctx_smfi->xxfi_abort;
266184610Salfred#if _FFR_WORKERS_POOL
267187494Semax	curstate = ctx->ctx_state;
268187494Semax	if (curstate == ST_INIT)
269187494Semax	{
270187494Semax		mi_clr_macros(ctx, 0);
271187494Semax		fix_stm(ctx);
272184610Salfred	}
273187494Semax#else   /* _FFR_WORKERS_POOL */
274187494Semax	mi_clr_macros(ctx, 0);
275187494Semax	fix_stm(ctx);
276187494Semax#endif  /* _FFR_WORKERS_POOL */
277187494Semax	r = _SMFIS_NONE;
278187741Semax	do
279187494Semax	{
280187741Semax		/* call abort only if in a mail transaction */
281187494Semax		call_abort = ST_IN_MAIL(curstate);
282184610Salfred		timeout.tv_sec = ctx->ctx_timeout;
283187494Semax		timeout.tv_usec = 0;
284187494Semax		if (mi_stop() == MILTER_ABRT)
285187494Semax		{
286187494Semax			if (ctx->ctx_dbg > 3)
287187494Semax				sm_dprintf("[%ld] milter_abort\n",
288187741Semax					(long) ctx->ctx_id);
289187494Semax			ret = MI_FAILURE;
290187494Semax			break;
291187494Semax		}
292184610Salfred
293187494Semax		/*
294187494Semax		**  Notice: buf is allocated by mi_rd_cmd() and it will
295187494Semax		**  usually be free()d after it has been used in f().
296187494Semax		**  However, if the function returns _SMFIS_KEEP then buf
297187494Semax		**  contains macros and will not be free()d.
298187741Semax		**  Hence r must be set to _SMFIS_NONE if a new buf is
299187494Semax		**  allocated to avoid problem with housekeeping, esp.
300187494Semax		**  if the code "break"s out of the loop.
301187494Semax		*/
302184610Salfred
303187494Semax#if _FFR_WORKERS_POOL
304187494Semax		/* Is the socket ready to be read ??? */
305187494Semax		if (!mi_rd_socket_ready(sd))
306187494Semax		{
307187494Semax			ret = MI_CONTINUE;
308187741Semax			break;
309187494Semax		}
310187494Semax#endif  /* _FFR_WORKERS_POOL */
311187494Semax
312184610Salfred		r = _SMFIS_NONE;
313184610Salfred		if ((buf = mi_rd_cmd(sd, &timeout, &cmd, &len,
314187494Semax				     ctx->ctx_smfi->xxfi_name)) == NULL &&
315187494Semax		    cmd < SMFIC_VALIDCMD)
316187494Semax		{
317184610Salfred			if (ctx->ctx_dbg > 5)
318187494Semax				sm_dprintf("[%ld] mi_engine: mi_rd_cmd error (%x)\n",
319187494Semax					(long) ctx->ctx_id, (int) cmd);
320187494Semax
321187494Semax			/*
322187494Semax			**  eof is currently treated as failure ->
323187741Semax			**  abort() instead of close(), otherwise use:
324187494Semax			**  if (cmd != SMFIC_EOF)
325187494Semax			*/
326187494Semax
327187494Semax			ret = MI_FAILURE;
328184610Salfred			break;
329187494Semax		}
330187494Semax		if (ctx->ctx_dbg > 4)
331187494Semax			sm_dprintf("[%ld] got cmd '%c' len %d\n",
332187494Semax				(long) ctx->ctx_id, cmd, (int) len);
333187494Semax		for (i = 0; i < ncmds; i++)
334187741Semax		{
335187494Semax			if (cmd == cmds[i].cm_cmd)
336187494Semax				break;
337187494Semax		}
338187494Semax		if (i >= ncmds)
339184610Salfred		{
340187494Semax			/* unknown command */
341187494Semax			if (ctx->ctx_dbg > 1)
342187494Semax				sm_dprintf("[%ld] cmd '%c' unknown\n",
343187494Semax					(long) ctx->ctx_id, cmd);
344187494Semax			ret = MI_FAILURE;
345187741Semax			break;
346187494Semax		}
347187494Semax		if ((f = cmds[i].cm_fct) == NULL)
348187494Semax		{
349187494Semax			/* stop for now */
350184610Salfred			if (ctx->ctx_dbg > 1)
351187494Semax				sm_dprintf("[%ld] cmd '%c' not impl\n",
352187494Semax					(long) ctx->ctx_id, cmd);
353187494Semax			ret = MI_FAILURE;
354187494Semax			break;
355187494Semax		}
356187741Semax
357187494Semax		/* is new state ok? */
358187494Semax		newstate = cmds[i].cm_next;
359187494Semax		if (ctx->ctx_dbg > 5)
360187494Semax			sm_dprintf("[%ld] cur %x new %x nextmask %x\n",
361184610Salfred				(long) ctx->ctx_id,
362184610Salfred				curstate, newstate, next_states[curstate]);
363184610Salfred
364184610Salfred		if (newstate != ST_NONE && !trans_ok(curstate, newstate))
365184610Salfred		{
366184610Salfred			if (ctx->ctx_dbg > 1)
367184610Salfred				sm_dprintf("[%ld] abort: cur %d (%x) new %d (%x) next %x\n",
368184610Salfred					(long) ctx->ctx_id,
369187494Semax					curstate, MI_MASK(curstate),
370184610Salfred					newstate, MI_MASK(newstate),
371184610Salfred					next_states[curstate]);
372184610Salfred
373187741Semax			/* call abort only if in a mail transaction */
374187741Semax			if (fi_abort != NULL && call_abort)
375187741Semax				(void) (*fi_abort)(ctx);
376184610Salfred
377187494Semax			/*
378184610Salfred			**  try to reach the new state from HELO
379184610Salfred			**  if it can't be reached, ignore the command.
380184610Salfred			*/
381187741Semax
382187741Semax			curstate = ST_HELO;
383187494Semax			if (!trans_ok(curstate, newstate))
384187494Semax			{
385187494Semax				if (buf != NULL)
386187494Semax				{
387184610Salfred					free(buf);
388184610Salfred					buf = NULL;
389187494Semax				}
390184610Salfred				continue;
391184610Salfred			}
392184610Salfred		}
393187494Semax		arg.a_len = len;
394187494Semax		arg.a_buf = buf;
395184610Salfred		if (newstate != ST_NONE)
396184610Salfred		{
397184610Salfred			curstate = newstate;
398184610Salfred			ctx->ctx_state = curstate;
399184610Salfred		}
400187494Semax		arg.a_idx = cmds[i].cm_macros;
401184610Salfred		call_abort = ST_IN_MAIL(curstate);
402187494Semax
403184610Salfred		/* call function to deal with command */
404187494Semax		MI_MONITOR_BEGIN(ctx, cmd);
405187494Semax		r = (*f)(&arg);
406184610Salfred		MI_MONITOR_END(ctx, cmd);
407187494Semax		if (r != _SMFIS_KEEP && buf != NULL)
408187865Semax		{
409187865Semax			free(buf);
410187865Semax			buf = NULL;
411184610Salfred		}
412187494Semax		if (sendreply(r, sd, &timeout, ctx) != MI_SUCCESS)
413184610Salfred		{
414187494Semax			ret = MI_FAILURE;
415184610Salfred			break;
416187494Semax		}
417184610Salfred
418184610Salfred		if (r == SMFIS_ACCEPT)
419187494Semax		{
420187494Semax			/* accept mail, no further actions taken */
421184610Salfred			curstate = ST_HELO;
422184610Salfred		}
423184610Salfred		else if (r == SMFIS_REJECT || r == SMFIS_DISCARD ||
424184610Salfred			 r ==  SMFIS_TEMPFAIL)
425184610Salfred		{
426187494Semax			/*
427187494Semax			**  further actions depend on current state
428187494Semax			**  if the IGNO bit is set: "ignore" the error,
429190728Sthompsa			**  i.e., stay in the current state
430187494Semax			*/
431187741Semax			if (!bitset(CT_IGNO, cmds[i].cm_todo))
432187741Semax				curstate = ST_HELO;
433184610Salfred		}
434184610Salfred		else if (r == _SMFIS_ABORT)
435184610Salfred		{
436187741Semax			if (ctx->ctx_dbg > 5)
437187741Semax				sm_dprintf("[%ld] function returned abort\n",
438184610Salfred					(long) ctx->ctx_id);
439187494Semax			ret = MI_FAILURE;
440187494Semax			break;
441187494Semax		}
442187494Semax	} while (!bitset(CT_END, cmds[i].cm_todo));
443187494Semax
444187741Semax	ctx->ctx_state = curstate;
445187494Semax
446187494Semax	if (ret == MI_FAILURE)
447187494Semax	{
448187494Semax		/* call abort only if in a mail transaction */
449187741Semax		if (fi_abort != NULL && call_abort)
450187741Semax			(void) (*fi_abort)(ctx);
451187494Semax	}
452187494Semax
453187494Semax	/* has close been called? */
454187494Semax	if (ctx->ctx_state != ST_QUIT
455187494Semax#if _FFR_WORKERS_POOL
456187494Semax	   && ret != MI_CONTINUE
457184610Salfred#endif /* _FFR_WORKERS_POOL */
458184610Salfred	   )
459184610Salfred	{
460184610Salfred		if ((fi_close = ctx->ctx_smfi->xxfi_close) != NULL)
461187494Semax			(void) (*fi_close)(ctx);
462187741Semax	}
463187741Semax	if (r != _SMFIS_KEEP && buf != NULL)
464187494Semax		free(buf);
465187494Semax#if !_FFR_WORKERS_POOL
466184610Salfred	mi_clr_macros(ctx, 0);
467184610Salfred#endif /* _FFR_WORKERS_POOL */
468187494Semax	return ret;
469184610Salfred}
470187494Semax
471187741Semaxstatic size_t milter_addsymlist __P((SMFICTX_PTR, char *, char **));
472184610Salfred
473184610Salfredstatic size_t
474184610Salfredmilter_addsymlist(ctx, buf, newbuf)
475184610Salfred	SMFICTX_PTR ctx;
476184610Salfred	char *buf;
477184610Salfred	char **newbuf;
478184610Salfred{
479184610Salfred	size_t len;
480184610Salfred	int i;
481184610Salfred	mi_int32 v;
482184610Salfred	char *buffer;
483184610Salfred
484184610Salfred	SM_ASSERT(ctx != NULL);
485184610Salfred	SM_ASSERT(buf != NULL);
486184610Salfred	SM_ASSERT(newbuf != NULL);
487184610Salfred	len = 0;
488184610Salfred	for (i = 0; i < MAX_MACROS_ENTRIES; i++)
489184610Salfred	{
490184610Salfred		if (ctx->ctx_mac_list[i] != NULL)
491184610Salfred		{
492187741Semax			len += strlen(ctx->ctx_mac_list[i]) + 1 +
493187741Semax				MILTER_LEN_BYTES;
494184610Salfred		}
495184610Salfred	}
496184610Salfred	if (len > 0)
497187494Semax	{
498184610Salfred		size_t offset;
499184610Salfred
500190728Sthompsa		SM_ASSERT(len + MILTER_OPTLEN > len);
501187494Semax		len += MILTER_OPTLEN;
502190728Sthompsa		buffer = malloc(len);
503190728Sthompsa		if (buffer != NULL)
504190728Sthompsa		{
505190728Sthompsa			(void) memcpy(buffer, buf, MILTER_OPTLEN);
506190728Sthompsa			offset = MILTER_OPTLEN;
507190728Sthompsa			for (i = 0; i < MAX_MACROS_ENTRIES; i++)
508190728Sthompsa			{
509184610Salfred				size_t l;
510190728Sthompsa
511190728Sthompsa				if (ctx->ctx_mac_list[i] == NULL)
512190728Sthompsa					continue;
513190728Sthompsa
514190728Sthompsa				SM_ASSERT(offset + MILTER_LEN_BYTES < len);
515184610Salfred				v = htonl(i);
516187494Semax				(void) memcpy(buffer + offset, (void *) &v,
517190728Sthompsa						MILTER_LEN_BYTES);
518190728Sthompsa				offset += MILTER_LEN_BYTES;
519190728Sthompsa				l = strlen(ctx->ctx_mac_list[i]) + 1;
520190728Sthompsa				SM_ASSERT(offset + l <= len);
521190728Sthompsa				(void) memcpy(buffer + offset,
522190728Sthompsa						ctx->ctx_mac_list[i], l);
523190728Sthompsa				offset += l;
524190728Sthompsa			}
525190728Sthompsa		}
526190728Sthompsa		else
527184610Salfred		{
528184610Salfred			/* oops ... */
529184610Salfred		}
530187741Semax	}
531187494Semax	else
532187494Semax	{
533187741Semax		len = MILTER_OPTLEN;
534187494Semax		buffer = buf;
535184610Salfred	}
536184610Salfred	*newbuf = buffer;
537184610Salfred	return len;
538187741Semax}
539187741Semax
540187741Semax/*
541187741Semax**  GET_NR_BIT -- get "no reply" bit matching state
542184610Salfred**
543184610Salfred**	Parameters:
544184610Salfred**		state -- current protocol stage
545187494Semax**
546187494Semax**	Returns:
547184610Salfred**		0: no matching bit
548184610Salfred**		>0: the matching "no reply" bit
549187494Semax*/
550184610Salfred
551184610Salfredstatic unsigned long get_nr_bit __P((int));
552184610Salfred
553184610Salfredstatic unsigned long
554184610Salfredget_nr_bit(state)
555187494Semax	int state;
556184610Salfred{
557184610Salfred	unsigned long bit;
558187494Semax
559187494Semax	switch (state)
560184610Salfred	{
561184610Salfred	  case ST_CONN:
562184610Salfred		bit = SMFIP_NR_CONN;
563184610Salfred		break;
564184610Salfred	  case ST_HELO:
565187494Semax		bit = SMFIP_NR_HELO;
566187494Semax		break;
567184610Salfred	  case ST_MAIL:
568187494Semax		bit = SMFIP_NR_MAIL;
569187494Semax		break;
570187494Semax	  case ST_RCPT:
571187494Semax		bit = SMFIP_NR_RCPT;
572187494Semax		break;
573184610Salfred	  case ST_DATA:
574184610Salfred		bit = SMFIP_NR_DATA;
575187741Semax		break;
576187741Semax	  case ST_UNKN:
577187741Semax		bit = SMFIP_NR_UNKN;
578187494Semax		break;
579187494Semax	  case ST_HDRS:
580184610Salfred		bit = SMFIP_NR_HDR;
581187494Semax		break;
582187741Semax	  case ST_EOHS:
583184610Salfred		bit = SMFIP_NR_EOH;
584184610Salfred		break;
585184610Salfred	  case ST_BODY:
586187741Semax		bit = SMFIP_NR_BODY;
587184610Salfred		break;
588187741Semax	  default:
589187741Semax		bit = 0;
590187494Semax		break;
591184610Salfred	}
592187494Semax	return bit;
593184610Salfred}
594187494Semax
595187494Semax/*
596187494Semax**  SENDREPLY -- send a reply to the MTA
597187494Semax**
598187494Semax**	Parameters:
599187494Semax**		r -- reply code
600184610Salfred**		sd -- socket descriptor
601184610Salfred**		timeout_ptr -- (ptr to) timeout to use for sending
602184610Salfred**		ctx -- context structure
603187741Semax**
604187494Semax**	Returns:
605187494Semax**		MI_SUCCESS/MI_FAILURE
606184610Salfred*/
607184610Salfred
608184610Salfredstatic int
609187741Semaxsendreply(r, sd, timeout_ptr, ctx)
610187741Semax	sfsistat r;
611187741Semax	socket_t sd;
612187494Semax	struct timeval *timeout_ptr;
613184610Salfred	SMFICTX_PTR ctx;
614184610Salfred{
615187494Semax	int ret;
616187494Semax	unsigned long bit;
617187741Semax
618184610Salfred	ret = MI_SUCCESS;
619187741Semax
620184610Salfred	bit = get_nr_bit(ctx->ctx_state);
621184610Salfred	if (bit != 0 && (ctx->ctx_pflags & bit) != 0 && r != SMFIS_NOREPLY)
622187494Semax	{
623187741Semax		if (r >= SMFIS_CONTINUE && r < _SMFIS_KEEP)
624184610Salfred		{
625184610Salfred			/* milter said it wouldn't reply, but it lied... */
626187494Semax			smi_log(SMI_LOG_ERR,
627184610Salfred				"%s: milter claimed not to reply in state %d but did anyway %d\n",
628184610Salfred				ctx->ctx_smfi->xxfi_name,
629184610Salfred				ctx->ctx_state, r);
630184610Salfred
631187494Semax		}
632187494Semax
633187494Semax		/*
634184610Salfred		**  Force specified behavior, otherwise libmilter
635184610Salfred		**  and MTA will fail to communicate properly.
636184610Salfred		*/
637184610Salfred
638184610Salfred		switch (r)
639184610Salfred		{
640187494Semax		  case SMFIS_CONTINUE:
641184610Salfred		  case SMFIS_TEMPFAIL:
642184610Salfred		  case SMFIS_REJECT:
643184610Salfred		  case SMFIS_DISCARD:
644184610Salfred		  case SMFIS_ACCEPT:
645187494Semax		  case SMFIS_SKIP:
646184610Salfred		  case _SMFIS_OPTIONS:
647187494Semax			r = SMFIS_NOREPLY;
648187494Semax			break;
649187494Semax		}
650187494Semax	}
651187494Semax
652187494Semax	switch (r)
653187494Semax	{
654184610Salfred	  case SMFIS_CONTINUE:
655187494Semax		ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_CONTINUE, NULL, 0);
656187741Semax		break;
657187494Semax	  case SMFIS_TEMPFAIL:
658184610Salfred	  case SMFIS_REJECT:
659187494Semax		if (ctx->ctx_reply != NULL &&
660184610Salfred		    ((r == SMFIS_TEMPFAIL && *ctx->ctx_reply == '4') ||
661187494Semax		     (r == SMFIS_REJECT && *ctx->ctx_reply == '5')))
662187494Semax		{
663187494Semax			ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_REPLYCODE,
664187494Semax					ctx->ctx_reply,
665187494Semax					strlen(ctx->ctx_reply) + 1);
666187494Semax			free(ctx->ctx_reply);
667184610Salfred			ctx->ctx_reply = NULL;
668184610Salfred		}
669184610Salfred		else
670187741Semax		{
671187494Semax			ret = mi_wr_cmd(sd, timeout_ptr, r == SMFIS_REJECT ?
672187494Semax					SMFIR_REJECT : SMFIR_TEMPFAIL, NULL, 0);
673184610Salfred		}
674187494Semax		break;
675187494Semax	  case SMFIS_DISCARD:
676184610Salfred		ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_DISCARD, NULL, 0);
677184610Salfred		break;
678187494Semax	  case SMFIS_ACCEPT:
679184610Salfred		ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_ACCEPT, NULL, 0);
680184610Salfred		break;
681187494Semax	  case SMFIS_SKIP:
682187494Semax		ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_SKIP, NULL, 0);
683184610Salfred		break;
684187494Semax	  case _SMFIS_OPTIONS:
685184610Salfred		{
686184610Salfred			mi_int32 v;
687187494Semax			size_t len;
688187494Semax			char *buffer;
689184610Salfred			char buf[MILTER_OPTLEN];
690187494Semax
691187494Semax			v = htonl(ctx->ctx_prot_vers2mta);
692187494Semax			(void) memcpy(&(buf[0]), (void *) &v,
693187494Semax				      MILTER_LEN_BYTES);
694187494Semax			v = htonl(ctx->ctx_aflags);
695187494Semax			(void) memcpy(&(buf[MILTER_LEN_BYTES]), (void *) &v,
696187494Semax				      MILTER_LEN_BYTES);
697187494Semax			v = htonl(ctx->ctx_pflags2mta);
698187494Semax			(void) memcpy(&(buf[MILTER_LEN_BYTES * 2]),
699187494Semax				      (void *) &v, MILTER_LEN_BYTES);
700187494Semax			len = milter_addsymlist(ctx, buf, &buffer);
701187494Semax			if (buffer != NULL)
702187494Semax				ret = mi_wr_cmd(sd, timeout_ptr, SMFIC_OPTNEG,
703187494Semax						buffer, len);
704187494Semax			else
705187494Semax				ret = MI_FAILURE;
706187494Semax		}
707187494Semax		break;
708187494Semax	  case SMFIS_NOREPLY:
709187494Semax		if (bit != 0 &&
710187494Semax		    (ctx->ctx_pflags & bit) != 0 &&
711187494Semax		    (ctx->ctx_mta_pflags & bit) == 0)
712184610Salfred		{
713184610Salfred			/*
714187494Semax			**  milter doesn't want to send a reply,
715187494Semax			**  but the MTA doesn't have that feature: fake it.
716187494Semax			*/
717187494Semax
718187494Semax			ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_CONTINUE, NULL,
719184610Salfred					0);
720187494Semax		}
721187494Semax		break;
722184610Salfred	  default:	/* don't send a reply */
723184610Salfred		break;
724187494Semax	}
725187494Semax	return ret;
726184610Salfred}
727187494Semax
728187494Semax/*
729184610Salfred**  CLR_MACROS -- clear set of macros starting from a given index
730187741Semax**
731187494Semax**	Parameters:
732187494Semax**		ctx -- context structure
733184610Salfred**		m -- index from which to clear all macros
734184610Salfred**
735187494Semax**	Returns:
736187494Semax**		None.
737184610Salfred*/
738187741Semax
739187741Semaxvoid
740187494Semaxmi_clr_macros(ctx, m)
741184610Salfred	SMFICTX_PTR ctx;
742187494Semax	int m;
743187494Semax{
744187494Semax	int i;
745187494Semax
746184610Salfred	for (i = m; i < MAX_MACROS_ENTRIES; i++)
747187494Semax	{
748187741Semax		if (ctx->ctx_mac_ptr[i] != NULL)
749187741Semax		{
750187741Semax			free(ctx->ctx_mac_ptr[i]);
751187741Semax			ctx->ctx_mac_ptr[i] = NULL;
752187494Semax		}
753184610Salfred		if (ctx->ctx_mac_buf[i] != NULL)
754187494Semax		{
755184610Salfred			free(ctx->ctx_mac_buf[i]);
756187494Semax			ctx->ctx_mac_buf[i] = NULL;
757187494Semax		}
758187494Semax	}
759187494Semax}
760187494Semax
761187494Semax/*
762184610Salfred**  MI_CLR_SYMLIST -- clear list of macros
763187494Semax**
764184610Salfred**	Parameters:
765187741Semax**		ctx -- context structure
766187494Semax**
767187494Semax**	Returns:
768187494Semax**		None.
769184610Salfred*/
770187494Semax
771184610Salfredstatic void
772184610Salfredmi_clr_symlist(ctx)
773184610Salfred	SMFICTX *ctx;
774187494Semax{
775184610Salfred	int i;
776184610Salfred
777187494Semax	SM_ASSERT(ctx != NULL);
778187494Semax	for (i = SMFIM_FIRST; i <= SMFIM_LAST; i++)
779184610Salfred	{
780187494Semax		if (ctx->ctx_mac_list[i] != NULL)
781184610Salfred		{
782184610Salfred			free(ctx->ctx_mac_list[i]);
783187494Semax			ctx->ctx_mac_list[i] = NULL;
784187494Semax		}
785184610Salfred	}
786184610Salfred}
787187494Semax
788187494Semax/*
789187494Semax**  MI_CLR_CTX -- clear context
790184610Salfred**
791187494Semax**	Parameters:
792187494Semax**		ctx -- context structure
793184610Salfred**
794187494Semax**	Returns:
795187494Semax**		None.
796184610Salfred*/
797184610Salfred
798184610Salfredvoid
799187494Semaxmi_clr_ctx(ctx)
800187494Semax	SMFICTX *ctx;
801184610Salfred{
802187494Semax	SM_ASSERT(ctx != NULL);
803187494Semax	if (ValidSocket(ctx->ctx_sd))
804187494Semax	{
805184610Salfred		(void) closesocket(ctx->ctx_sd);
806187494Semax		ctx->ctx_sd = INVALID_SOCKET;
807187494Semax	}
808184610Salfred	if (ctx->ctx_reply != NULL)
809184610Salfred	{
810187494Semax		free(ctx->ctx_reply);
811187494Semax		ctx->ctx_reply = NULL;
812187494Semax	}
813187494Semax	if (ctx->ctx_privdata != NULL)
814187494Semax	{
815184610Salfred		smi_log(SMI_LOG_WARN,
816187494Semax			"%s: private data not NULL",
817187494Semax			ctx->ctx_smfi->xxfi_name);
818184610Salfred	}
819184610Salfred	mi_clr_macros(ctx, 0);
820187494Semax	mi_clr_symlist(ctx);
821187494Semax	free(ctx);
822184610Salfred}
823187494Semax
824187494Semax/*
825184610Salfred**  ST_OPTIONNEG -- negotiate options
826187741Semax**
827187494Semax**	Parameters:
828187494Semax**		g -- generic argument structure
829184610Salfred**
830187494Semax**	Returns:
831187494Semax**		abort/send options/continue
832187494Semax*/
833184610Salfred
834187741Semaxstatic int
835187741Semaxst_optionneg(g)
836187494Semax	genarg *g;
837184610Salfred{
838187494Semax	mi_int32 i, v, fake_pflags, internal_pflags;
839187494Semax	SMFICTX_PTR ctx;
840187494Semax#if _FFR_MILTER_CHECK
841187494Semax	bool testmode = false;
842184610Salfred#endif /* _FFR_MILTER_CHECK */
843187494Semax	int (*fi_negotiate) __P((SMFICTX *,
844187741Semax					unsigned long, unsigned long,
845187741Semax					unsigned long, unsigned long,
846187741Semax					unsigned long *, unsigned long *,
847187741Semax					unsigned long *, unsigned long *));
848187494Semax
849187494Semax	if (g == NULL || g->a_ctx->ctx_smfi == NULL)
850187494Semax		return SMFIS_CONTINUE;
851184610Salfred	ctx = g->a_ctx;
852187494Semax	mi_clr_macros(ctx, g->a_idx + 1);
853187494Semax	ctx->ctx_prot_vers = SMFI_PROT_VERSION;
854187494Semax
855187494Semax	/* check for minimum length */
856187494Semax	if (g->a_len < MILTER_OPTLEN)
857184610Salfred	{
858184610Salfred		smi_log(SMI_LOG_ERR,
859184610Salfred			"%s: st_optionneg[%ld]: len too short %d < %d",
860184610Salfred			ctx->ctx_smfi->xxfi_name,
861187741Semax			(long) ctx->ctx_id, (int) g->a_len,
862187494Semax			MILTER_OPTLEN);
863184610Salfred		return _SMFIS_ABORT;
864184610Salfred	}
865184610Salfred
866187741Semax	/* protocol version */
867187741Semax	(void) memcpy((void *) &i, (void *) &(g->a_buf[0]), MILTER_LEN_BYTES);
868187741Semax	v = ntohl(i);
869187494Semax
870184610Salfred#define SMFI_PROT_VERSION_MIN	2
871187494Semax
872187741Semax	/* check for minimum version */
873187494Semax	if (v < SMFI_PROT_VERSION_MIN)
874187741Semax	{
875184610Salfred		smi_log(SMI_LOG_ERR,
876187741Semax			"%s: st_optionneg[%ld]: protocol version too old %d < %d",
877184610Salfred			ctx->ctx_smfi->xxfi_name,
878184610Salfred			(long) ctx->ctx_id, v, SMFI_PROT_VERSION_MIN);
879187494Semax		return _SMFIS_ABORT;
880187741Semax	}
881184610Salfred	ctx->ctx_mta_prot_vers = v;
882187494Semax	if (ctx->ctx_prot_vers < ctx->ctx_mta_prot_vers)
883184610Salfred		ctx->ctx_prot_vers2mta = ctx->ctx_prot_vers;
884187494Semax	else
885187494Semax		ctx->ctx_prot_vers2mta = ctx->ctx_mta_prot_vers;
886184610Salfred
887184610Salfred	(void) memcpy((void *) &i, (void *) &(g->a_buf[MILTER_LEN_BYTES]),
888184610Salfred		      MILTER_LEN_BYTES);
889187494Semax	v = ntohl(i);
890184610Salfred
891187494Semax	/* no flags? set to default value for V1 actions */
892187494Semax	if (v == 0)
893184610Salfred		v = SMFI_V1_ACTS;
894184610Salfred	ctx->ctx_mta_aflags = v;	/* MTA action flags */
895184610Salfred
896184610Salfred	internal_pflags = 0;
897187494Semax	(void) memcpy((void *) &i, (void *) &(g->a_buf[MILTER_LEN_BYTES * 2]),
898184610Salfred		      MILTER_LEN_BYTES);
899187494Semax	v = ntohl(i);
900184610Salfred
901187494Semax	/* no flags? set to default value for V1 protocol */
902187494Semax	if (v == 0)
903184610Salfred		v = SMFI_V1_PROT;
904187494Semax#if _FFR_MDS_NEGOTIATE
905184610Salfred	else if (ctx->ctx_smfi->xxfi_version >= SMFI_VERSION_MDS)
906184610Salfred	{
907187741Semax		/*
908187741Semax		**  Allow changing the size only if milter is compiled
909187741Semax		**  against a version that supports this.
910187741Semax		**  If a milter is dynamically linked against a newer
911187494Semax		**  libmilter version, we don't want to "surprise"
912184610Salfred		**  it with a larger buffer as it may rely on it
913187494Semax		**  even though it is not documented as a limit.
914184610Salfred		*/
915187494Semax
916187494Semax		if (bitset(SMFIP_MDS_1M, v))
917187494Semax		{
918187494Semax			internal_pflags |= SMFIP_MDS_1M;
919187494Semax			(void) smfi_setmaxdatasize(MILTER_MDS_1M);
920187494Semax		}
921184610Salfred		else if (bitset(SMFIP_MDS_256K, v))
922184610Salfred		{
923184610Salfred			internal_pflags |= SMFIP_MDS_256K;
924187741Semax			(void) smfi_setmaxdatasize(MILTER_MDS_256K);
925187494Semax		}
926184610Salfred	}
927187494Semax# if 0
928187494Semax	/* don't log this for now... */
929187494Semax	else if (ctx->ctx_smfi->xxfi_version < SMFI_VERSION_MDS &&
930187494Semax		 bitset(SMFIP_MDS_1M|SMFIP_MDS_256K, v))
931187494Semax	{
932187494Semax		smi_log(SMI_LOG_WARN,
933184610Salfred			"%s: st_optionneg[%ld]: milter version=%X, trying flags=%X",
934187494Semax			ctx->ctx_smfi->xxfi_name,
935187494Semax			(long) ctx->ctx_id, ctx->ctx_smfi->xxfi_version, v);
936187494Semax	}
937187494Semax# endif /* 0 */
938184610Salfred#endif /* _FFR_MDS_NEGOTIATE */
939187494Semax
940187494Semax	/*
941184610Salfred	**  MTA protocol flags.
942187494Semax	**  We pass the internal flags to the milter as "read only",
943187494Semax	**  i.e., a milter can read them so it knows which size
944187494Semax	**  will be used, but any changes by a milter will be ignored
945187494Semax	**  (see below, search for SMFI_INTERNAL).
946187494Semax	*/
947184610Salfred
948187741Semax	ctx->ctx_mta_pflags = (v & ~SMFI_INTERNAL) | internal_pflags;
949187494Semax
950187494Semax	/*
951187494Semax	**  Copy flags from milter struct into libmilter context;
952184610Salfred	**  this variable will be used later on to check whether
953187494Semax	**  the MTA "actions" can fulfill the milter requirements,
954187494Semax	**  but it may be overwritten by the negotiate callback.
955187494Semax	*/
956187494Semax
957187494Semax	ctx->ctx_aflags = ctx->ctx_smfi->xxfi_flags;
958184610Salfred	fake_pflags = SMFIP_NR_CONN
959187494Semax			|SMFIP_NR_HELO
960187494Semax			|SMFIP_NR_MAIL
961187494Semax			|SMFIP_NR_RCPT
962187494Semax			|SMFIP_NR_DATA
963187494Semax			|SMFIP_NR_UNKN
964187741Semax			|SMFIP_NR_HDR
965184610Salfred			|SMFIP_NR_EOH
966187494Semax			|SMFIP_NR_BODY
967187494Semax			;
968187494Semax
969184610Salfred	if (g->a_ctx->ctx_smfi != NULL &&
970187494Semax	    g->a_ctx->ctx_smfi->xxfi_version > 4 &&
971187494Semax	    (fi_negotiate = g->a_ctx->ctx_smfi->xxfi_negotiate) != NULL)
972187494Semax	{
973187494Semax		int r;
974187494Semax		unsigned long m_aflags, m_pflags, m_f2, m_f3;
975187494Semax
976187494Semax		/*
977187494Semax		**  let milter decide whether the features offered by the
978187494Semax		**  MTA are "good enough".
979184610Salfred		**  Notes:
980187494Semax		**  - libmilter can "fake" some features (e.g., SMFIP_NR_HDR)
981187494Semax		**  - m_f2, m_f3 are for future extensions
982187494Semax		*/
983187494Semax
984187494Semax		m_f2 = m_f3 = 0;
985184610Salfred		m_aflags = ctx->ctx_mta_aflags;
986184610Salfred		m_pflags = ctx->ctx_pflags;
987187494Semax		if ((SMFIP_SKIP & ctx->ctx_mta_pflags) != 0)
988187494Semax			m_pflags |= SMFIP_SKIP;
989187494Semax		r = fi_negotiate(g->a_ctx,
990187494Semax				ctx->ctx_mta_aflags,
991187494Semax				ctx->ctx_mta_pflags|fake_pflags,
992187494Semax				0, 0,
993187494Semax				&m_aflags, &m_pflags, &m_f2, &m_f3);
994187494Semax
995187494Semax#if _FFR_MILTER_CHECK
996187494Semax		testmode = bitset(SMFIP_TEST, m_pflags);
997187494Semax		if (testmode)
998184610Salfred			m_pflags &= ~SMFIP_TEST;
999187494Semax#endif /* _FFR_MILTER_CHECK */
1000187494Semax
1001184610Salfred		/*
1002184610Salfred		**  Types of protocol flags (pflags):
1003187494Semax		**  1. do NOT send protocol step X
1004187494Semax		**  2. MTA can do/understand something extra (SKIP,
1005187494Semax		**	send unknown RCPTs)
1006184610Salfred		**  3. MTA can deal with "no reply" for various protocol steps
1007187494Semax		**  Note: this mean that it isn't possible to simply set all
1008187494Semax		**	flags to get "everything":
1009184610Salfred		**	setting a flag of type 1 turns off a step
1010187494Semax		**		(it should be the other way around:
1011187494Semax		**		a flag means a protocol step can be sent)
1012187494Semax		**	setting a flag of type 3 requires that milter
1013184610Salfred		**	never sends a reply for the corresponding step.
1014187494Semax		**  Summary: the "negation" of protocol flags is causing
1015187494Semax		**	problems, but at least for type 3 there is no simple
1016187494Semax		**	solution.
1017184610Salfred		**
1018187494Semax		**  What should "all options" mean?
1019187494Semax		**  send all protocol steps _except_ those for which there is
1020187494Semax		**	no callback (currently registered in ctx_pflags)
1021187494Semax		**  expect SKIP as return code?		Yes
1022184610Salfred		**  send unknown RCPTs?			No,
1023187494Semax		**				must be explicitly requested?
1024187494Semax		**  "no reply" for some protocol steps?	No,
1025184610Salfred		**				must be explicitly requested.
1026187741Semax		*/
1027187494Semax
1028187494Semax		if (SMFIS_ALL_OPTS == r)
1029184610Salfred		{
1030187494Semax			ctx->ctx_aflags = ctx->ctx_mta_aflags;
1031187494Semax			ctx->ctx_pflags2mta = ctx->ctx_pflags;
1032184610Salfred			if ((SMFIP_SKIP & ctx->ctx_mta_pflags) != 0)
1033187494Semax				ctx->ctx_pflags2mta |= SMFIP_SKIP;
1034187494Semax		}
1035184610Salfred		else if (r != SMFIS_CONTINUE)
1036187494Semax		{
1037187494Semax			smi_log(SMI_LOG_ERR,
1038187494Semax				"%s: st_optionneg[%ld]: xxfi_negotiate returned %d (protocol options=0x%lx, actions=0x%lx)",
1039187494Semax				ctx->ctx_smfi->xxfi_name,
1040187494Semax				(long) ctx->ctx_id, r, ctx->ctx_mta_pflags,
1041184610Salfred				ctx->ctx_mta_aflags);
1042184610Salfred			return _SMFIS_ABORT;
1043184610Salfred		}
1044184610Salfred		else
1045187741Semax		{
1046187494Semax			ctx->ctx_aflags = m_aflags;
1047187494Semax			ctx->ctx_pflags = m_pflags;
1048184610Salfred			ctx->ctx_pflags2mta = m_pflags;
1049184610Salfred		}
1050184610Salfred
1051187741Semax		/* check whether some flags need to be "faked" */
1052187741Semax		i = ctx->ctx_pflags2mta;
1053187741Semax		if ((ctx->ctx_mta_pflags & i) != i)
1054187494Semax		{
1055184610Salfred			unsigned int idx;
1056184610Salfred			unsigned long b;
1057187494Semax
1058184610Salfred			/*
1059187494Semax			**  If some behavior can be faked (set in fake_pflags),
1060187494Semax			**  but the MTA doesn't support it, then unset
1061184610Salfred			**  that flag in the value that is sent to the MTA.
1062187494Semax			*/
1063187494Semax
1064187741Semax			for (idx = 0; idx < 32; idx++)
1065187494Semax			{
1066187741Semax				b = 1 << idx;
1067184610Salfred				if ((ctx->ctx_mta_pflags & b) != b &&
1068187494Semax				    (fake_pflags & b) == b)
1069187494Semax					ctx->ctx_pflags2mta &= ~b;
1070187494Semax			}
1071184610Salfred		}
1072187494Semax	}
1073187494Semax	else
1074187494Semax	{
1075187494Semax		/*
1076184610Salfred		**  Set the protocol flags based on the values determined
1077187494Semax		**  in mi_listener() which checked the defined callbacks.
1078187494Semax		*/
1079187494Semax
1080184610Salfred		ctx->ctx_pflags2mta = ctx->ctx_pflags;
1081187494Semax	}
1082187494Semax
1083187494Semax	/* check whether actions and protocol requirements can be satisfied */
1084184610Salfred	i = ctx->ctx_aflags;
1085187494Semax	if ((i & ctx->ctx_mta_aflags) != i)
1086187494Semax	{
1087187741Semax		smi_log(SMI_LOG_ERR,
1088187494Semax			"%s: st_optionneg[%ld]: 0x%lx does not fulfill action requirements 0x%x",
1089187741Semax			ctx->ctx_smfi->xxfi_name,
1090184610Salfred			(long) ctx->ctx_id, ctx->ctx_mta_aflags, i);
1091184610Salfred		return _SMFIS_ABORT;
1092187494Semax	}
1093187494Semax
1094187494Semax	i = ctx->ctx_pflags2mta;
1095187494Semax	if ((ctx->ctx_mta_pflags & i) != i)
1096187494Semax	{
1097187494Semax		/*
1098187494Semax		**  Older MTAs do not support some protocol steps.
1099187494Semax		**  As this protocol is a bit "wierd" (it asks for steps
1100187494Semax		**  NOT to be taken/sent) we have to check whether we
1101187494Semax		**  should turn off those "negative" requests.
1102187494Semax		**  Currently these are only SMFIP_NODATA and SMFIP_NOUNKNOWN.
1103187494Semax		*/
1104187494Semax
1105184610Salfred		if (bitset(SMFIP_NODATA, ctx->ctx_pflags2mta) &&
1106187494Semax		    !bitset(SMFIP_NODATA, ctx->ctx_mta_pflags))
1107184610Salfred			ctx->ctx_pflags2mta &= ~SMFIP_NODATA;
1108187494Semax		if (bitset(SMFIP_NOUNKNOWN, ctx->ctx_pflags2mta) &&
1109187494Semax		    !bitset(SMFIP_NOUNKNOWN, ctx->ctx_mta_pflags))
1110187494Semax			ctx->ctx_pflags2mta &= ~SMFIP_NOUNKNOWN;
1111187494Semax		i = ctx->ctx_pflags2mta;
1112184610Salfred	}
1113187494Semax
1114187741Semax	if ((ctx->ctx_mta_pflags & i) != i)
1115187494Semax	{
1116184610Salfred		smi_log(SMI_LOG_ERR,
1117184610Salfred			"%s: st_optionneg[%ld]: 0x%lx does not fulfill protocol requirements 0x%x",
1118184610Salfred			ctx->ctx_smfi->xxfi_name,
1119187741Semax			(long) ctx->ctx_id, ctx->ctx_mta_pflags, i);
1120187741Semax		return _SMFIS_ABORT;
1121187741Semax	}
1122187741Semax	fix_stm(ctx);
1123187741Semax
1124187741Semax	if (ctx->ctx_dbg > 3)
1125187741Semax		sm_dprintf("[%ld] milter_negotiate:"
1126187741Semax			" mta_actions=0x%lx, mta_flags=0x%lx"
1127187741Semax			" actions=0x%lx, flags=0x%lx\n"
1128187741Semax			, (long) ctx->ctx_id
1129187741Semax			, ctx->ctx_mta_aflags, ctx->ctx_mta_pflags
1130187741Semax			, ctx->ctx_aflags, ctx->ctx_pflags);
1131187741Semax
1132187741Semax#if _FFR_MILTER_CHECK
1133187741Semax	if (ctx->ctx_dbg > 3)
1134187741Semax		sm_dprintf("[%ld] milter_negotiate:"
1135187741Semax			" testmode=%d, pflags2mta=%X, internal_pflags=%X\n"
1136187741Semax			, (long) ctx->ctx_id, testmode
1137187741Semax			, ctx->ctx_pflags2mta, internal_pflags);
1138187741Semax
1139187741Semax	/* in test mode: take flags without further modifications */
1140187741Semax	if (!testmode)
1141187741Semax		/* Warning: check statement below! */
1142187741Semax#endif /* _FFR_MILTER_CHECK */
1143187741Semax
1144187741Semax	/*
1145187741Semax	**  Remove the internal flags that might have been set by a milter
1146187741Semax	**  and set only those determined above.
1147187741Semax	*/
1148187741Semax
1149187741Semax	ctx->ctx_pflags2mta = (ctx->ctx_pflags2mta & ~SMFI_INTERNAL)
1150187741Semax			      | internal_pflags;
1151187741Semax	return _SMFIS_OPTIONS;
1152187741Semax}
1153187741Semax
1154187741Semax/*
1155187741Semax**  ST_CONNECTINFO -- receive connection information
1156187741Semax**
1157187741Semax**	Parameters:
1158187741Semax**		g -- generic argument structure
1159187741Semax**
1160187741Semax**	Returns:
1161187741Semax**		continue or filter-specified value
1162187741Semax*/
1163187741Semax
1164187741Semaxstatic int
1165187741Semaxst_connectinfo(g)
1166184610Salfred	genarg *g;
1167184610Salfred{
1168187494Semax	size_t l;
1169184610Salfred	size_t i;
1170184610Salfred	char *s, family;
1171184610Salfred	unsigned short port = 0;
1172184610Salfred	_SOCK_ADDR sockaddr;
1173187741Semax	sfsistat (*fi_connect) __P((SMFICTX *, char *, _SOCK_ADDR *));
1174187494Semax
1175184610Salfred	if (g == NULL)
1176184610Salfred		return _SMFIS_ABORT;
1177187741Semax	mi_clr_macros(g->a_ctx, g->a_idx + 1);
1178187494Semax	if (g->a_ctx->ctx_smfi == NULL ||
1179184610Salfred	    (fi_connect = g->a_ctx->ctx_smfi->xxfi_connect) == NULL)
1180187741Semax		return SMFIS_CONTINUE;
1181184610Salfred
1182187741Semax	s = g->a_buf;
1183187741Semax	i = 0;
1184187741Semax	l = g->a_len;
1185187741Semax	while (s[i] != '\0' && i <= l)
1186187741Semax		++i;
1187187741Semax	if (i + 1 >= l)
1188187741Semax		return _SMFIS_ABORT;
1189187741Semax
1190187741Semax	/* Move past trailing \0 in host string */
1191187741Semax	i++;
1192187741Semax	family = s[i++];
1193187741Semax	(void) memset(&sockaddr, '\0', sizeof sockaddr);
1194187741Semax	if (family != SMFIA_UNKNOWN)
1195187741Semax	{
1196187741Semax		if (i + sizeof port >= l)
1197187741Semax		{
1198187741Semax			smi_log(SMI_LOG_ERR,
1199187494Semax				"%s: connect[%ld]: wrong len %d >= %d",
1200187741Semax				g->a_ctx->ctx_smfi->xxfi_name,
1201187741Semax				(long) g->a_ctx->ctx_id, (int) i, (int) l);
1202187494Semax			return _SMFIS_ABORT;
1203187494Semax		}
1204187494Semax		(void) memcpy((void *) &port, (void *) (s + i),
1205187494Semax			      sizeof port);
1206187494Semax		i += sizeof port;
1207187494Semax
1208187741Semax		/* make sure string is terminated */
1209187494Semax		if (s[l - 1] != '\0')
1210187494Semax			return _SMFIS_ABORT;
1211187494Semax# if NETINET
1212187741Semax		if (family == SMFIA_INET)
1213187494Semax		{
1214187494Semax			if (inet_aton(s + i, (struct in_addr *) &sockaddr.sin.sin_addr)
1215187494Semax			    != 1)
1216187494Semax			{
1217187494Semax				smi_log(SMI_LOG_ERR,
1218184610Salfred					"%s: connect[%ld]: inet_aton failed",
1219187494Semax					g->a_ctx->ctx_smfi->xxfi_name,
1220187494Semax					(long) g->a_ctx->ctx_id);
1221184610Salfred				return _SMFIS_ABORT;
1222184610Salfred			}
1223187494Semax			sockaddr.sa.sa_family = AF_INET;
1224187494Semax			if (port > 0)
1225184610Salfred				sockaddr.sin.sin_port = port;
1226187741Semax		}
1227187741Semax		else
1228184610Salfred# endif /* NETINET */
1229187741Semax# if NETINET6
1230187494Semax		if (family == SMFIA_INET6)
1231187494Semax		{
1232187741Semax			if (mi_inet_pton(AF_INET6, s + i,
1233187494Semax					 &sockaddr.sin6.sin6_addr) != 1)
1234187741Semax			{
1235187741Semax				smi_log(SMI_LOG_ERR,
1236187741Semax					"%s: connect[%ld]: mi_inet_pton failed",
1237187741Semax					g->a_ctx->ctx_smfi->xxfi_name,
1238187741Semax					(long) g->a_ctx->ctx_id);
1239187494Semax				return _SMFIS_ABORT;
1240187741Semax			}
1241187741Semax			sockaddr.sa.sa_family = AF_INET6;
1242187741Semax			if (port > 0)
1243187494Semax				sockaddr.sin6.sin6_port = port;
1244187741Semax		}
1245187494Semax		else
1246187494Semax# endif /* NETINET6 */
1247187494Semax# if NETUNIX
1248187494Semax		if (family == SMFIA_UNIX)
1249187494Semax		{
1250187741Semax			if (sm_strlcpy(sockaddr.sunix.sun_path, s + i,
1251187741Semax			    sizeof sockaddr.sunix.sun_path) >=
1252187494Semax			    sizeof sockaddr.sunix.sun_path)
1253187494Semax			{
1254187494Semax				smi_log(SMI_LOG_ERR,
1255187494Semax					"%s: connect[%ld]: path too long",
1256187494Semax					g->a_ctx->ctx_smfi->xxfi_name,
1257187494Semax					(long) g->a_ctx->ctx_id);
1258187494Semax				return _SMFIS_ABORT;
1259187494Semax			}
1260187494Semax			sockaddr.sunix.sun_family = AF_UNIX;
1261187494Semax		}
1262187494Semax		else
1263187494Semax# endif /* NETUNIX */
1264187494Semax		{
1265187494Semax			smi_log(SMI_LOG_ERR,
1266187741Semax				"%s: connect[%ld]: unknown family %d",
1267187741Semax				g->a_ctx->ctx_smfi->xxfi_name,
1268184610Salfred				(long) g->a_ctx->ctx_id, family);
1269187494Semax			return _SMFIS_ABORT;
1270187494Semax		}
1271187494Semax	}
1272187741Semax	return (*fi_connect)(g->a_ctx, g->a_buf,
1273187494Semax			     family != SMFIA_UNKNOWN ? &sockaddr : NULL);
1274187741Semax}
1275184610Salfred
1276184610Salfred/*
1277187494Semax**  ST_EOH -- end of headers
1278187494Semax**
1279187741Semax**	Parameters:
1280187494Semax**		g -- generic argument structure
1281187741Semax**
1282184610Salfred**	Returns:
1283187494Semax**		continue or filter-specified value
1284187494Semax*/
1285187494Semax
1286187494Semaxstatic int
1287187494Semaxst_eoh(g)
1288187494Semax	genarg *g;
1289187494Semax{
1290184610Salfred	sfsistat (*fi_eoh) __P((SMFICTX *));
1291187494Semax
1292187494Semax	if (g == NULL)
1293187494Semax		return _SMFIS_ABORT;
1294187494Semax	if (g->a_ctx->ctx_smfi != NULL &&
1295184610Salfred	    (fi_eoh = g->a_ctx->ctx_smfi->xxfi_eoh) != NULL)
1296187494Semax		return (*fi_eoh)(g->a_ctx);
1297187494Semax	return SMFIS_CONTINUE;
1298187494Semax}
1299187494Semax
1300187494Semax/*
1301184610Salfred**  ST_DATA -- DATA command
1302184610Salfred**
1303187494Semax**	Parameters:
1304187494Semax**		g -- generic argument structure
1305184610Salfred**
1306184610Salfred**	Returns:
1307184610Salfred**		continue or filter-specified value
1308187494Semax*/
1309184610Salfred
1310187494Semaxstatic int
1311187494Semaxst_data(g)
1312187494Semax	genarg *g;
1313187494Semax{
1314187494Semax	sfsistat (*fi_data) __P((SMFICTX *));
1315187494Semax
1316187494Semax	if (g == NULL)
1317187494Semax		return _SMFIS_ABORT;
1318187494Semax	if (g->a_ctx->ctx_smfi != NULL &&
1319184610Salfred	    g->a_ctx->ctx_smfi->xxfi_version > 3 &&
1320187494Semax	    (fi_data = g->a_ctx->ctx_smfi->xxfi_data) != NULL)
1321187494Semax		return (*fi_data)(g->a_ctx);
1322184610Salfred	return SMFIS_CONTINUE;
1323187494Semax}
1324187494Semax
1325187494Semax/*
1326187494Semax**  ST_HELO -- helo/ehlo command
1327184610Salfred**
1328187494Semax**	Parameters:
1329187494Semax**		g -- generic argument structure
1330187494Semax**
1331187494Semax**	Returns:
1332184610Salfred**		continue or filter-specified value
1333187494Semax*/
1334187494Semax
1335184610Salfredstatic int
1336187741Semaxst_helo(g)
1337187741Semax	genarg *g;
1338187741Semax{
1339187741Semax	sfsistat (*fi_helo) __P((SMFICTX *, char *));
1340187494Semax
1341187741Semax	if (g == NULL)
1342184610Salfred		return _SMFIS_ABORT;
1343187494Semax	mi_clr_macros(g->a_ctx, g->a_idx + 1);
1344187741Semax	if (g->a_ctx->ctx_smfi != NULL &&
1345184610Salfred	    (fi_helo = g->a_ctx->ctx_smfi->xxfi_helo) != NULL)
1346187494Semax	{
1347187494Semax		/* paranoia: check for terminating '\0' */
1348184610Salfred		if (g->a_len == 0 || g->a_buf[g->a_len - 1] != '\0')
1349187494Semax			return MI_FAILURE;
1350187494Semax		return (*fi_helo)(g->a_ctx, g->a_buf);
1351187494Semax	}
1352187494Semax	return SMFIS_CONTINUE;
1353184610Salfred}
1354187494Semax
1355187494Semax/*
1356187494Semax**  ST_HEADER -- header line
1357187494Semax**
1358184610Salfred**	Parameters:
1359187494Semax**		g -- generic argument structure
1360184610Salfred**
1361187741Semax**	Returns:
1362187494Semax**		continue or filter-specified value
1363187741Semax*/
1364184610Salfred
1365184610Salfredstatic int
1366187494Semaxst_header(g)
1367184610Salfred	genarg *g;
1368184610Salfred{
1369187494Semax	char *hf, *hv;
1370187494Semax	sfsistat (*fi_header) __P((SMFICTX *, char *, char *));
1371184610Salfred
1372184610Salfred	if (g == NULL)
1373184610Salfred		return _SMFIS_ABORT;
1374184610Salfred	if (g->a_ctx->ctx_smfi == NULL ||
1375184610Salfred	    (fi_header = g->a_ctx->ctx_smfi->xxfi_header) == NULL)
1376187741Semax		return SMFIS_CONTINUE;
1377184610Salfred	if (dec_arg2(g->a_buf, g->a_len, &hf, &hv) == MI_SUCCESS)
1378187741Semax		return (*fi_header)(g->a_ctx, hf, hv);
1379184610Salfred	else
1380187741Semax		return _SMFIS_ABORT;
1381187741Semax}
1382184610Salfred
1383187494Semax#define ARGV_FCT(lf, rf, idx)					\
1384187741Semax	char **argv;						\
1385184610Salfred	sfsistat (*lf) __P((SMFICTX *, char **));		\
1386187494Semax	int r;							\
1387184610Salfred								\
1388187741Semax	if (g == NULL)						\
1389187741Semax		return _SMFIS_ABORT;				\
1390184610Salfred	mi_clr_macros(g->a_ctx, g->a_idx + 1);			\
1391187494Semax	if (g->a_ctx->ctx_smfi == NULL ||			\
1392187494Semax	    (lf = g->a_ctx->ctx_smfi->rf) == NULL)		\
1393187494Semax		return SMFIS_CONTINUE;				\
1394187494Semax	if ((argv = dec_argv(g->a_buf, g->a_len)) == NULL)	\
1395184610Salfred		return _SMFIS_ABORT;				\
1396187741Semax	r = (*lf)(g->a_ctx, argv);				\
1397184610Salfred	free(argv);						\
1398187494Semax	return r;
1399187494Semax
1400187494Semax/*
1401184610Salfred**  ST_SENDER -- MAIL FROM command
1402187494Semax**
1403187494Semax**	Parameters:
1404184610Salfred**		g -- generic argument structure
1405184610Salfred**
1406184610Salfred**	Returns:
1407184610Salfred**		continue or filter-specified value
1408184610Salfred*/
1409187494Semax
1410187494Semaxstatic int
1411187494Semaxst_sender(g)
1412187494Semax	genarg *g;
1413184610Salfred{
1414184610Salfred	ARGV_FCT(fi_envfrom, xxfi_envfrom, CI_MAIL)
1415184610Salfred}
1416184610Salfred
1417184610Salfred/*
1418184610Salfred**  ST_RCPT -- RCPT TO command
1419184610Salfred**
1420184610Salfred**	Parameters:
1421187494Semax**		g -- generic argument structure
1422184610Salfred**
1423187494Semax**	Returns:
1424187494Semax**		continue or filter-specified value
1425187494Semax*/
1426187494Semax
1427187494Semaxstatic int
1428187494Semaxst_rcpt(g)
1429187494Semax	genarg *g;
1430187494Semax{
1431187494Semax	ARGV_FCT(fi_envrcpt, xxfi_envrcpt, CI_RCPT)
1432187494Semax}
1433187741Semax
1434187494Semax/*
1435187494Semax**  ST_UNKNOWN -- unrecognized or unimplemented command
1436187494Semax**
1437187494Semax**	Parameters:
1438187494Semax**		g -- generic argument structure
1439187494Semax**
1440187494Semax**	Returns:
1441187494Semax**		continue or filter-specified value
1442184610Salfred*/
1443184610Salfred
1444184610Salfredstatic int
1445184610Salfredst_unknown(g)
1446184610Salfred	genarg *g;
1447184610Salfred{
1448184610Salfred	sfsistat (*fi_unknown) __P((SMFICTX *, const char *));
1449184610Salfred
1450184610Salfred	if (g == NULL)
1451184610Salfred		return _SMFIS_ABORT;
1452184610Salfred	if (g->a_ctx->ctx_smfi != NULL &&
1453187494Semax	    g->a_ctx->ctx_smfi->xxfi_version > 2 &&
1454184610Salfred	    (fi_unknown = g->a_ctx->ctx_smfi->xxfi_unknown) != NULL)
1455187494Semax		return (*fi_unknown)(g->a_ctx, (const char *) g->a_buf);
1456187494Semax	return SMFIS_CONTINUE;
1457187494Semax}
1458187494Semax
1459184610Salfred/*
1460184610Salfred**  ST_MACROS -- deal with macros received from the MTA
1461184610Salfred**
1462184610Salfred**	Parameters:
1463184610Salfred**		g -- generic argument structure
1464187494Semax**
1465184610Salfred**	Returns:
1466187494Semax**		continue/keep
1467187494Semax**
1468187494Semax**	Side effects:
1469187494Semax**		set pointer in macro array to current values.
1470184610Salfred*/
1471184610Salfred
1472184610Salfredstatic int
1473187494Semaxst_macros(g)
1474184610Salfred	genarg *g;
1475187494Semax{
1476187494Semax	int i;
1477184610Salfred	char **argv;
1478187494Semax
1479187494Semax	if (g == NULL || g->a_len < 1)
1480184610Salfred		return _SMFIS_FAIL;
1481187494Semax	if ((argv = dec_argv(g->a_buf + 1, g->a_len - 1)) == NULL)
1482187494Semax		return _SMFIS_FAIL;
1483187494Semax	switch (g->a_buf[0])
1484187494Semax	{
1485184610Salfred	  case SMFIC_CONNECT:
1486187494Semax		i = CI_CONN;
1487187494Semax		break;
1488187494Semax	  case SMFIC_HELO:
1489184610Salfred		i = CI_HELO;
1490187494Semax		break;
1491187494Semax	  case SMFIC_MAIL:
1492187494Semax		i = CI_MAIL;
1493184610Salfred		break;
1494187494Semax	  case SMFIC_RCPT:
1495187494Semax		i = CI_RCPT;
1496187494Semax		break;
1497187494Semax	  case SMFIC_DATA:
1498184610Salfred		i = CI_DATA;
1499187494Semax		break;
1500187494Semax	  case SMFIC_BODYEOB:
1501184610Salfred		i = CI_EOM;
1502184610Salfred		break;
1503184610Salfred	  case SMFIC_EOH:
1504184610Salfred		i = CI_EOH;
1505184610Salfred		break;
1506184610Salfred	  default:
1507184610Salfred		free(argv);
1508187494Semax		return _SMFIS_FAIL;
1509184610Salfred	}
1510187494Semax	if (g->a_ctx->ctx_mac_ptr[i] != NULL)
1511184610Salfred		free(g->a_ctx->ctx_mac_ptr[i]);
1512184610Salfred	if (g->a_ctx->ctx_mac_buf[i] != NULL)
1513184610Salfred		free(g->a_ctx->ctx_mac_buf[i]);
1514184610Salfred	g->a_ctx->ctx_mac_ptr[i] = argv;
1515184610Salfred	g->a_ctx->ctx_mac_buf[i] = g->a_buf;
1516184610Salfred	return _SMFIS_KEEP;
1517184610Salfred}
1518184610Salfred
1519184610Salfred/*
1520184610Salfred**  ST_QUIT -- quit command
1521184610Salfred**
1522184610Salfred**	Parameters:
1523184610Salfred**		g -- generic argument structure
1524184610Salfred**
1525184610Salfred**	Returns:
1526187494Semax**		noreply
1527187494Semax*/
1528187494Semax
1529187494Semax/* ARGSUSED */
1530187494Semaxstatic int
1531187494Semaxst_quit(g)
1532187494Semax	genarg *g;
1533187494Semax{
1534184610Salfred	sfsistat (*fi_close) __P((SMFICTX *));
1535184610Salfred
1536184610Salfred	if (g == NULL)
1537187494Semax		return _SMFIS_ABORT;
1538187494Semax	if (g->a_ctx->ctx_smfi != NULL &&
1539184610Salfred	    (fi_close = g->a_ctx->ctx_smfi->xxfi_close) != NULL)
1540184610Salfred		(void) (*fi_close)(g->a_ctx);
1541184610Salfred	mi_clr_macros(g->a_ctx, 0);
1542184610Salfred	return _SMFIS_NOREPLY;
1543184610Salfred}
1544187494Semax
1545184610Salfred/*
1546187494Semax**  ST_BODYCHUNK -- deal with a piece of the mail body
1547184610Salfred**
1548187494Semax**	Parameters:
1549187494Semax**		g -- generic argument structure
1550187494Semax**
1551184610Salfred**	Returns:
1552184610Salfred**		continue or filter-specified value
1553184610Salfred*/
1554187494Semax
1555184610Salfredstatic int
1556184610Salfredst_bodychunk(g)
1557184610Salfred	genarg *g;
1558184610Salfred{
1559184610Salfred	sfsistat (*fi_body) __P((SMFICTX *, unsigned char *, size_t));
1560184610Salfred
1561184610Salfred	if (g == NULL)
1562184610Salfred		return _SMFIS_ABORT;
1563184610Salfred	if (g->a_ctx->ctx_smfi != NULL &&
1564184610Salfred	    (fi_body = g->a_ctx->ctx_smfi->xxfi_body) != NULL)
1565184610Salfred		return (*fi_body)(g->a_ctx, (unsigned char *)g->a_buf,
1566184610Salfred				  g->a_len);
1567187494Semax	return SMFIS_CONTINUE;
1568184610Salfred}
1569184610Salfred
1570184610Salfred/*
1571184610Salfred**  ST_BODYEND -- deal with the last piece of the mail body
1572187494Semax**
1573184610Salfred**	Parameters:
1574184610Salfred**		g -- generic argument structure
1575187494Semax**
1576187494Semax**	Returns:
1577184610Salfred**		continue or filter-specified value
1578184610Salfred**
1579184610Salfred**	Side effects:
1580184610Salfred**		sends a reply for the body part (if non-empty).
1581184610Salfred*/
1582187494Semax
1583187494Semaxstatic int
1584187494Semaxst_bodyend(g)
1585187494Semax	genarg *g;
1586184610Salfred{
1587184610Salfred	sfsistat r;
1588184610Salfred	sfsistat (*fi_body) __P((SMFICTX *, unsigned char *, size_t));
1589184610Salfred	sfsistat (*fi_eom) __P((SMFICTX *));
1590184610Salfred
1591187494Semax	if (g == NULL)
1592187494Semax		return _SMFIS_ABORT;
1593184610Salfred	r = SMFIS_CONTINUE;
1594184610Salfred	if (g->a_ctx->ctx_smfi != NULL)
1595187494Semax	{
1596187494Semax		if ((fi_body = g->a_ctx->ctx_smfi->xxfi_body) != NULL &&
1597187494Semax		    g->a_len > 0)
1598187494Semax		{
1599187494Semax			socket_t sd;
1600187494Semax			struct timeval timeout;
1601187494Semax
1602187494Semax			timeout.tv_sec = g->a_ctx->ctx_timeout;
1603187494Semax			timeout.tv_usec = 0;
1604187494Semax			sd = g->a_ctx->ctx_sd;
1605187494Semax			r = (*fi_body)(g->a_ctx, (unsigned char *)g->a_buf,
1606187494Semax				       g->a_len);
1607184610Salfred			if (r != SMFIS_CONTINUE &&
1608184610Salfred			    sendreply(r, sd, &timeout, g->a_ctx) != MI_SUCCESS)
1609187494Semax				return _SMFIS_ABORT;
1610187494Semax		}
1611187494Semax	}
1612187494Semax	if (r == SMFIS_CONTINUE &&
1613187494Semax	    (fi_eom = g->a_ctx->ctx_smfi->xxfi_eom) != NULL)
1614184610Salfred		return (*fi_eom)(g->a_ctx);
1615187494Semax	return r;
1616184610Salfred}
1617184610Salfred
1618184610Salfred/*
1619187494Semax**  ST_ABORTFCT -- deal with aborts
1620187494Semax**
1621187494Semax**	Parameters:
1622187494Semax**		g -- generic argument structure
1623187494Semax**
1624184610Salfred**	Returns:
1625187494Semax**		abort or filter-specified value
1626184610Salfred*/
1627184610Salfred
1628184610Salfredstatic int
1629184610Salfredst_abortfct(g)
1630187494Semax	genarg *g;
1631184610Salfred{
1632184610Salfred	sfsistat (*fi_abort) __P((SMFICTX *));
1633184610Salfred
1634187494Semax	if (g == NULL)
1635187494Semax		return _SMFIS_ABORT;
1636184610Salfred	if (g != NULL && g->a_ctx->ctx_smfi != NULL &&
1637184610Salfred	    (fi_abort = g->a_ctx->ctx_smfi->xxfi_abort) != NULL)
1638184610Salfred		(void) (*fi_abort)(g->a_ctx);
1639184610Salfred	return _SMFIS_NOREPLY;
1640187494Semax}
1641184610Salfred
1642184610Salfred/*
1643187741Semax**  TRANS_OK -- is the state transition ok?
1644184610Salfred**
1645187494Semax**	Parameters:
1646187741Semax**		old -- old state
1647187494Semax**		new -- new state
1648187494Semax**
1649187494Semax**	Returns:
1650187494Semax**		state transition ok
1651184610Salfred*/
1652184610Salfred
1653187494Semaxstatic bool
1654187494Semaxtrans_ok(old, new)
1655184610Salfred	int old, new;
1656187494Semax{
1657187741Semax	int s, n;
1658184610Salfred
1659184610Salfred	s = old;
1660184610Salfred	if (s >= SIZE_NEXT_STATES)
1661184610Salfred		return false;
1662187494Semax	do
1663187494Semax	{
1664187494Semax		/* is this state transition allowed? */
1665187494Semax		if ((MI_MASK(new) & next_states[s]) != 0)
1666187494Semax			return true;
1667187494Semax
1668187494Semax		/*
1669187494Semax		**  no: try next state;
1670187494Semax		**  this works since the relevant states are ordered
1671187494Semax		**  strict sequentially
1672187494Semax		*/
1673187494Semax
1674187494Semax		n = s + 1;
1675187494Semax		if (n >= SIZE_NEXT_STATES)
1676187494Semax			return false;
1677187494Semax
1678187494Semax		/*
1679187494Semax		**  can we actually "skip" this state?
1680187494Semax		**  see fix_stm() which sets this bit for those
1681187494Semax		**  states which the filter program is not interested in
1682187494Semax		*/
1683187494Semax
1684187494Semax		if (bitset(NX_SKIP, next_states[n]))
1685187494Semax			s = n;
1686187494Semax		else
1687187494Semax			return false;
1688187494Semax	} while (s < SIZE_NEXT_STATES);
1689187494Semax	return false;
1690187494Semax}
1691187494Semax
1692187494Semax/*
1693187494Semax**  FIX_STM -- add "skip" bits to the state transition table
1694187494Semax**
1695184610Salfred**	Parameters:
1696187494Semax**		ctx -- context structure
1697184610Salfred**
1698187494Semax**	Returns:
1699187494Semax**		None.
1700187494Semax**
1701187494Semax**	Side effects:
1702187494Semax**		may change state transition table.
1703187494Semax*/
1704187494Semax
1705187494Semaxstatic void
1706187494Semaxfix_stm(ctx)
1707187494Semax	SMFICTX_PTR ctx;
1708187494Semax{
1709187494Semax	unsigned long fl;
1710187494Semax
1711187494Semax	if (ctx == NULL || ctx->ctx_smfi == NULL)
1712187494Semax		return;
1713187494Semax	fl = ctx->ctx_pflags;
1714187494Semax	if (bitset(SMFIP_NOCONNECT, fl))
1715187494Semax		next_states[ST_CONN] |= NX_SKIP;
1716187494Semax	if (bitset(SMFIP_NOHELO, fl))
1717189275Sthompsa		next_states[ST_HELO] |= NX_SKIP;
1718187494Semax	if (bitset(SMFIP_NOMAIL, fl))
1719187494Semax		next_states[ST_MAIL] |= NX_SKIP;
1720187494Semax	if (bitset(SMFIP_NORCPT, fl))
1721188942Sthompsa		next_states[ST_RCPT] |= NX_SKIP;
1722187494Semax	if (bitset(SMFIP_NOHDRS, fl))
1723		next_states[ST_HDRS] |= NX_SKIP;
1724	if (bitset(SMFIP_NOEOH, fl))
1725		next_states[ST_EOHS] |= NX_SKIP;
1726	if (bitset(SMFIP_NOBODY, fl))
1727		next_states[ST_BODY] |= NX_SKIP;
1728	if (bitset(SMFIP_NODATA, fl))
1729		next_states[ST_DATA] |= NX_SKIP;
1730	if (bitset(SMFIP_NOUNKNOWN, fl))
1731		next_states[ST_UNKN] |= NX_SKIP;
1732}
1733
1734/*
1735**  DEC_ARGV -- split a buffer into a list of strings, NULL terminated
1736**
1737**	Parameters:
1738**		buf -- buffer with several strings
1739**		len -- length of buffer
1740**
1741**	Returns:
1742**		array of pointers to the individual strings
1743*/
1744
1745static char **
1746dec_argv(buf, len)
1747	char *buf;
1748	size_t len;
1749{
1750	char **s;
1751	size_t i;
1752	int elem, nelem;
1753
1754	nelem = 0;
1755	for (i = 0; i < len; i++)
1756	{
1757		if (buf[i] == '\0')
1758			++nelem;
1759	}
1760	if (nelem == 0)
1761		return NULL;
1762
1763	/* last entry is only for the name */
1764	s = (char **)malloc((nelem + 1) * (sizeof *s));
1765	if (s == NULL)
1766		return NULL;
1767	s[0] = buf;
1768	for (i = 0, elem = 0; i < len && elem < nelem; i++)
1769	{
1770		if (buf[i] == '\0')
1771		{
1772			++elem;
1773			if (i + 1 >= len)
1774				s[elem] = NULL;
1775			else
1776				s[elem] = &(buf[i + 1]);
1777		}
1778	}
1779
1780	/* overwrite last entry (already done above, just paranoia) */
1781	s[elem] = NULL;
1782	return s;
1783}
1784
1785/*
1786**  DEC_ARG2 -- split a buffer into two strings
1787**
1788**	Parameters:
1789**		buf -- buffer with two strings
1790**		len -- length of buffer
1791**		s1,s2 -- pointer to result strings
1792**
1793**	Returns:
1794**		MI_FAILURE/MI_SUCCESS
1795*/
1796
1797static int
1798dec_arg2(buf, len, s1, s2)
1799	char *buf;
1800	size_t len;
1801	char **s1;
1802	char **s2;
1803{
1804	size_t i;
1805
1806	/* paranoia: check for terminating '\0' */
1807	if (len == 0 || buf[len - 1] != '\0')
1808		return MI_FAILURE;
1809	*s1 = buf;
1810	for (i = 1; i < len && buf[i] != '\0'; i++)
1811		continue;
1812	if (i >= len - 1)
1813		return MI_FAILURE;
1814	*s2 = buf + i + 1;
1815	return MI_SUCCESS;
1816}
1817
1818/*
1819**  SENDOK -- is it ok for the filter to send stuff to the MTA?
1820**
1821**	Parameters:
1822**		ctx -- context structure
1823**		flag -- flag to check
1824**
1825**	Returns:
1826**		sending allowed (in current state)
1827*/
1828
1829bool
1830mi_sendok(ctx, flag)
1831	SMFICTX_PTR ctx;
1832	int flag;
1833{
1834	if (ctx == NULL || ctx->ctx_smfi == NULL)
1835		return false;
1836
1837	/* did the milter request this operation? */
1838	if (flag != 0 && !bitset(flag, ctx->ctx_aflags))
1839		return false;
1840
1841	/* are we in the correct state? It must be "End of Message". */
1842	return ctx->ctx_state == ST_ENDM;
1843}
1844
1845#if _FFR_WORKERS_POOL
1846/*
1847**  MI_RD_SOCKET_READY - checks if the socket is ready for read(2)
1848**
1849**	Parameters:
1850**		sd -- socket_t
1851**
1852**	Returns:
1853**		true iff socket is ready for read(2)
1854*/
1855
1856#define MI_RD_CMD_TO  1
1857#define MI_RD_MAX_ERR 16
1858
1859static bool
1860mi_rd_socket_ready (sd)
1861	socket_t sd;
1862{
1863	int n;
1864	int nerr = 0;
1865#if SM_CONF_POLL
1866	struct pollfd pfd;
1867#else /* SM_CONF_POLL */
1868	fd_set	rd_set, exc_set;
1869#endif /* SM_CONF_POLL */
1870
1871	do
1872	{
1873#if SM_CONF_POLL
1874		pfd.fd = sd;
1875		pfd.events = POLLIN;
1876		pfd.revents = 0;
1877
1878		n = poll(&pfd, 1, MI_RD_CMD_TO);
1879#else /* SM_CONF_POLL */
1880		struct timeval timeout;
1881
1882		FD_ZERO(&rd_set);
1883		FD_ZERO(&exc_set);
1884		FD_SET(sd, &rd_set);
1885		FD_SET(sd, &exc_set);
1886
1887		timeout.tv_sec = MI_RD_CMD_TO / 1000;
1888		timeout.tv_usec = 0;
1889		n = select(sd + 1, &rd_set, NULL, &exc_set, &timeout);
1890#endif /* SM_CONF_POLL */
1891
1892		if (n < 0)
1893		{
1894			if (errno == EINTR)
1895			{
1896				nerr++;
1897				continue;
1898			}
1899			return true;
1900		}
1901
1902		if (n == 0)
1903			return false;
1904		break;
1905	} while (nerr < MI_RD_MAX_ERR);
1906	if (nerr >= MI_RD_MAX_ERR)
1907		return false;
1908
1909#if SM_CONF_POLL
1910	return (pfd.revents != 0);
1911#else /* SM_CONF_POLL */
1912	return FD_ISSET(sd, &rd_set) || FD_ISSET(sd, &exc_set);
1913#endif /* SM_CONF_POLL */
1914}
1915#endif /* _FFR_WORKERS_POOL */
1916