xref: /freebsd/contrib/sendmail/libmilter/engine.c (revision 87569f75a91f298c52a71823c04d41cf53c88889)
1 /*
2  *  Copyright (c) 1999-2003 Sendmail, Inc. and its suppliers.
3  *	All rights reserved.
4  *
5  * By using this file, you agree to the terms and conditions set
6  * forth in the LICENSE file which can be found at the top level of
7  * the sendmail distribution.
8  *
9  */
10 
11 #include <sm/gen.h>
12 SM_RCSID("@(#)$Id: engine.c,v 8.120 2004/10/20 21:09:00 ca Exp $")
13 
14 #include "libmilter.h"
15 
16 #if NETINET || NETINET6
17 # include <arpa/inet.h>
18 #endif /* NETINET || NETINET6 */
19 
20 /* generic argument for functions in the command table */
21 struct arg_struct
22 {
23 	size_t		a_len;		/* length of buffer */
24 	char		*a_buf;		/* argument string */
25 	int		a_idx;		/* index for macro array */
26 	SMFICTX_PTR	a_ctx;		/* context */
27 };
28 
29 typedef struct arg_struct genarg;
30 
31 /* structure for commands received from MTA */
32 struct cmdfct_t
33 {
34 	char	cm_cmd;				/* command */
35 	int	cm_argt;			/* type of arguments expected */
36 	int	cm_next;			/* next state */
37 	int	cm_todo;			/* what to do next */
38 	int	cm_macros;			/* index for macros */
39 	int	(*cm_fct) __P((genarg *));	/* function to execute */
40 };
41 
42 typedef struct cmdfct_t cmdfct;
43 
44 /* possible values for cm_argt */
45 #define	CM_ARG0	0	/* no args */
46 #define	CM_ARG1	1	/* one arg (string) */
47 #define	CM_ARG2	2	/* two args (strings) */
48 #define	CM_ARGA	4	/* one string and _SOCK_ADDR */
49 #define	CM_ARGO	5	/* two integers */
50 #define	CM_ARGV	8	/* \0 separated list of args, NULL-terminated */
51 #define	CM_ARGN	9	/* \0 separated list of args (strings) */
52 
53 /* possible values for cm_todo */
54 #define	CT_CONT		0x0000	/* continue reading commands */
55 #define	CT_IGNO		0x0001	/* continue even when error  */
56 
57 /* not needed right now, done via return code instead */
58 #define	CT_KEEP		0x0004	/* keep buffer (contains symbols) */
59 #define	CT_END		0x0008	/* start replying */
60 
61 /* index in macro array: macros only for these commands */
62 #define	CI_NONE		(-1)
63 #define	CI_CONN		0
64 #define	CI_HELO		1
65 #define	CI_MAIL		2
66 #define CI_RCPT		3
67 #define CI_EOM		4
68 #if CI_EOM >= MAX_MACROS_ENTRIES
69 ERROR: do not compile with CI_EOM >= MAX_MACROS_ENTRIES
70 #endif
71 
72 /* function prototypes */
73 static int	st_abortfct __P((genarg *));
74 static int	st_macros __P((genarg *));
75 static int	st_optionneg __P((genarg *));
76 static int	st_bodychunk __P((genarg *));
77 static int	st_connectinfo __P((genarg *));
78 static int	st_bodyend __P((genarg *));
79 static int	st_helo __P((genarg *));
80 static int	st_header __P((genarg *));
81 static int	st_sender __P((genarg *));
82 static int	st_rcpt __P((genarg *));
83 #if SMFI_VERSION > 2
84 static int	st_unknown __P((genarg *));
85 #endif /* SMFI_VERSION > 2 */
86 #if SMFI_VERSION > 3
87 static int	st_data __P((genarg *));
88 #endif /* SMFI_VERSION > 3 */
89 static int	st_eoh __P((genarg *));
90 static int	st_quit __P((genarg *));
91 static int	sendreply __P((sfsistat, socket_t, struct timeval *, SMFICTX_PTR));
92 static void	fix_stm __P((SMFICTX_PTR));
93 static bool	trans_ok __P((int, int));
94 static char	**dec_argv __P((char *, size_t));
95 static int	dec_arg2 __P((char *, size_t, char **, char **));
96 
97 /* states */
98 #define ST_NONE	(-1)
99 #define ST_INIT	0	/* initial state */
100 #define ST_OPTS	1	/* option negotiation */
101 #define ST_CONN	2	/* connection info */
102 #define ST_HELO	3	/* helo */
103 #define ST_MAIL	4	/* mail from */
104 #define ST_RCPT	5	/* rcpt to */
105 #define ST_DATA	6	/* data */
106 #define ST_HDRS	7	/* headers */
107 #define ST_EOHS	8	/* end of headers */
108 #define ST_BODY	9	/* body */
109 #define ST_ENDM	10	/* end of message */
110 #define ST_QUIT	11	/* quit */
111 #define ST_ABRT	12	/* abort */
112 #define ST_UNKN 13	/* unknown SMTP command */
113 #define ST_LAST	ST_UNKN	/* last valid state */
114 #define ST_SKIP	15	/* not a state but required for the state table */
115 
116 /* in a mail transaction? must be before eom according to spec. */
117 #define ST_IN_MAIL(st)	((st) >= ST_MAIL && (st) < ST_ENDM)
118 
119 /*
120 **  set of next states
121 **  each state (ST_*) corresponds to bit in an int value (1 << state)
122 **  each state has a set of allowed transitions ('or' of bits of states)
123 **  so a state transition is valid if the mask of the next state
124 **  is set in the NX_* value
125 **  this function is coded in trans_ok(), see below.
126 */
127 
128 #define MI_MASK(x)	(0x0001 << (x))	/* generate a bit "mask" for a state */
129 #define NX_INIT	(MI_MASK(ST_OPTS))
130 #define NX_OPTS	(MI_MASK(ST_CONN) | MI_MASK(ST_UNKN))
131 #define NX_CONN	(MI_MASK(ST_HELO) | MI_MASK(ST_MAIL) | MI_MASK(ST_UNKN))
132 #define NX_HELO	(MI_MASK(ST_HELO) | MI_MASK(ST_MAIL) | MI_MASK(ST_UNKN))
133 #define NX_MAIL	(MI_MASK(ST_RCPT) | MI_MASK(ST_ABRT) | MI_MASK(ST_UNKN))
134 #define NX_RCPT	(MI_MASK(ST_HDRS) | MI_MASK(ST_EOHS) | MI_MASK(ST_DATA) | \
135 		 MI_MASK(ST_BODY) | MI_MASK(ST_ENDM) | \
136 		 MI_MASK(ST_RCPT) | MI_MASK(ST_ABRT) | MI_MASK(ST_UNKN))
137 #define NX_DATA	(MI_MASK(ST_EOHS) | MI_MASK(ST_HDRS) | MI_MASK(ST_ABRT))
138 #define NX_HDRS	(MI_MASK(ST_EOHS) | MI_MASK(ST_HDRS) | MI_MASK(ST_ABRT))
139 #define NX_EOHS	(MI_MASK(ST_BODY) | MI_MASK(ST_ENDM) | MI_MASK(ST_ABRT))
140 #define NX_BODY	(MI_MASK(ST_ENDM) | MI_MASK(ST_BODY) | MI_MASK(ST_ABRT))
141 #define NX_ENDM	(MI_MASK(ST_QUIT) | MI_MASK(ST_MAIL) | MI_MASK(ST_UNKN))
142 #define NX_QUIT	0
143 #define NX_ABRT	0
144 #define NX_UNKN (MI_MASK(ST_HELO) | MI_MASK(ST_MAIL) | \
145 		 MI_MASK(ST_RCPT) | MI_MASK(ST_ABRT) | \
146 		 MI_MASK(ST_DATA) | \
147 		 MI_MASK(ST_BODY) | MI_MASK(ST_UNKN) | \
148 		 MI_MASK(ST_ABRT) | MI_MASK(ST_QUIT))
149 #define NX_SKIP MI_MASK(ST_SKIP)
150 
151 static int next_states[] =
152 {
153 	NX_INIT,
154 	NX_OPTS,
155 	NX_CONN,
156 	NX_HELO,
157 	NX_MAIL,
158 	NX_RCPT,
159 	NX_DATA,
160 	NX_HDRS,
161 	NX_EOHS,
162 	NX_BODY,
163 	NX_ENDM,
164 	NX_QUIT,
165 	NX_ABRT,
166 	NX_UNKN
167 };
168 
169 /* commands received by milter */
170 static cmdfct cmds[] =
171 {
172 {SMFIC_ABORT,	CM_ARG0, ST_ABRT,  CT_CONT,	CI_NONE, st_abortfct	},
173 {SMFIC_MACRO,	CM_ARGV, ST_NONE,  CT_KEEP,	CI_NONE, st_macros	},
174 {SMFIC_BODY,	CM_ARG1, ST_BODY,  CT_CONT,	CI_NONE, st_bodychunk	},
175 {SMFIC_CONNECT,	CM_ARG2, ST_CONN,  CT_CONT,	CI_CONN, st_connectinfo	},
176 {SMFIC_BODYEOB,	CM_ARG1, ST_ENDM,  CT_CONT,	CI_EOM,  st_bodyend	},
177 {SMFIC_HELO,	CM_ARG1, ST_HELO,  CT_CONT,	CI_HELO, st_helo	},
178 {SMFIC_HEADER,	CM_ARG2, ST_HDRS,  CT_CONT,	CI_NONE, st_header	},
179 {SMFIC_MAIL,	CM_ARGV, ST_MAIL,  CT_CONT,	CI_MAIL, st_sender	},
180 {SMFIC_OPTNEG,	CM_ARGO, ST_OPTS,  CT_CONT,	CI_NONE, st_optionneg	},
181 {SMFIC_EOH,	CM_ARG0, ST_EOHS,  CT_CONT,	CI_NONE, st_eoh		},
182 {SMFIC_QUIT,	CM_ARG0, ST_QUIT,  CT_END,	CI_NONE, st_quit	},
183 #if SMFI_VERSION > 3
184 {SMFIC_DATA,	CM_ARG0, ST_DATA,  CT_CONT,	CI_NONE, st_data	},
185 #endif /* SMFI_VERSION > 3 */
186 {SMFIC_RCPT,	CM_ARGV, ST_RCPT,  CT_IGNO,	CI_RCPT, st_rcpt	}
187 #if SMFI_VERSION > 2
188 ,{SMFIC_UNKNOWN,CM_ARG1, ST_UNKN,  CT_IGNO,	CI_NONE, st_unknown	}
189 #endif /* SMFI_VERSION > 2 */
190 };
191 
192 /* additional (internal) reply codes */
193 #define _SMFIS_KEEP	20
194 #define _SMFIS_ABORT	21
195 #define _SMFIS_OPTIONS	22
196 #define _SMFIS_NOREPLY	23
197 #define _SMFIS_FAIL	(-1)
198 #define _SMFIS_NONE	(-2)
199 
200 /*
201 **  MI_ENGINE -- receive commands and process them
202 **
203 **	Parameters:
204 **		ctx -- context structure
205 **
206 **	Returns:
207 **		MI_FAILURE/MI_SUCCESS
208 */
209 int
210 mi_engine(ctx)
211 	SMFICTX_PTR ctx;
212 {
213 	size_t len;
214 	int i;
215 	socket_t sd;
216 	int ret = MI_SUCCESS;
217 	int ncmds = sizeof(cmds) / sizeof(cmdfct);
218 	int curstate = ST_INIT;
219 	int newstate;
220 	bool call_abort;
221 	sfsistat r;
222 	char cmd;
223 	char *buf = NULL;
224 	genarg arg;
225 	struct timeval timeout;
226 	int (*f) __P((genarg *));
227 	sfsistat (*fi_abort) __P((SMFICTX *));
228 	sfsistat (*fi_close) __P((SMFICTX *));
229 
230 	arg.a_ctx = ctx;
231 	sd = ctx->ctx_sd;
232 	fi_abort = ctx->ctx_smfi->xxfi_abort;
233 	mi_clr_macros(ctx, 0);
234 	fix_stm(ctx);
235 	r = _SMFIS_NONE;
236 	do
237 	{
238 		/* call abort only if in a mail transaction */
239 		call_abort = ST_IN_MAIL(curstate);
240 		timeout.tv_sec = ctx->ctx_timeout;
241 		timeout.tv_usec = 0;
242 		if (mi_stop() == MILTER_ABRT)
243 		{
244 			if (ctx->ctx_dbg > 3)
245 				sm_dprintf("[%d] milter_abort\n",
246 					(int) ctx->ctx_id);
247 			ret = MI_FAILURE;
248 			break;
249 		}
250 
251 		/*
252 		**  Notice: buf is allocated by mi_rd_cmd() and it will
253 		**  usually be free()d after it has been used in f().
254 		**  However, if the function returns _SMFIS_KEEP then buf
255 		**  contains macros and will not be free()d.
256 		**  Hence r must be set to _SMFIS_NONE if a new buf is
257 		**  allocated to avoid problem with housekeeping, esp.
258 		**  if the code "break"s out of the loop.
259 		*/
260 
261 		r = _SMFIS_NONE;
262 		if ((buf = mi_rd_cmd(sd, &timeout, &cmd, &len,
263 				     ctx->ctx_smfi->xxfi_name)) == NULL &&
264 		    cmd < SMFIC_VALIDCMD)
265 		{
266 			if (ctx->ctx_dbg > 5)
267 				sm_dprintf("[%d] mi_engine: mi_rd_cmd error (%x)\n",
268 					(int) ctx->ctx_id, (int) cmd);
269 
270 			/*
271 			**  eof is currently treated as failure ->
272 			**  abort() instead of close(), otherwise use:
273 			**  if (cmd != SMFIC_EOF)
274 			*/
275 
276 			ret = MI_FAILURE;
277 			break;
278 		}
279 		if (ctx->ctx_dbg > 4)
280 			sm_dprintf("[%d] got cmd '%c' len %d\n",
281 				(int) ctx->ctx_id, cmd, (int) len);
282 		for (i = 0; i < ncmds; i++)
283 		{
284 			if (cmd == cmds[i].cm_cmd)
285 				break;
286 		}
287 		if (i >= ncmds)
288 		{
289 			/* unknown command */
290 			if (ctx->ctx_dbg > 1)
291 				sm_dprintf("[%d] cmd '%c' unknown\n",
292 					(int) ctx->ctx_id, cmd);
293 			ret = MI_FAILURE;
294 			break;
295 		}
296 		if ((f = cmds[i].cm_fct) == NULL)
297 		{
298 			/* stop for now */
299 			if (ctx->ctx_dbg > 1)
300 				sm_dprintf("[%d] cmd '%c' not impl\n",
301 					(int) ctx->ctx_id, cmd);
302 			ret = MI_FAILURE;
303 			break;
304 		}
305 
306 		/* is new state ok? */
307 		newstate = cmds[i].cm_next;
308 		if (ctx->ctx_dbg > 5)
309 			sm_dprintf("[%d] cur %x new %x nextmask %x\n",
310 				(int) ctx->ctx_id,
311 				curstate, newstate, next_states[curstate]);
312 
313 		if (newstate != ST_NONE && !trans_ok(curstate, newstate))
314 		{
315 			if (ctx->ctx_dbg > 1)
316 				sm_dprintf("[%d] abort: cur %d (%x) new %d (%x) next %x\n",
317 					(int) ctx->ctx_id,
318 					curstate, MI_MASK(curstate),
319 					newstate, MI_MASK(newstate),
320 					next_states[curstate]);
321 
322 			/* call abort only if in a mail transaction */
323 			if (fi_abort != NULL && call_abort)
324 				(void) (*fi_abort)(ctx);
325 
326 			/*
327 			**  try to reach the new state from HELO
328 			**  if it can't be reached, ignore the command.
329 			*/
330 
331 			curstate = ST_HELO;
332 			if (!trans_ok(curstate, newstate))
333 			{
334 				if (buf != NULL)
335 				{
336 					free(buf);
337 					buf = NULL;
338 				}
339 				continue;
340 			}
341 		}
342 		arg.a_len = len;
343 		arg.a_buf = buf;
344 		if (newstate != ST_NONE)
345 		{
346 			curstate = newstate;
347 			ctx->ctx_state = curstate;
348 		}
349 		arg.a_idx = cmds[i].cm_macros;
350 		call_abort = ST_IN_MAIL(curstate);
351 
352 		/* call function to deal with command */
353 		r = (*f)(&arg);
354 		if (r != _SMFIS_KEEP && buf != NULL)
355 		{
356 			free(buf);
357 			buf = NULL;
358 		}
359 		if (sendreply(r, sd, &timeout, ctx) != MI_SUCCESS)
360 		{
361 			ret = MI_FAILURE;
362 			break;
363 		}
364 
365 		if (r == SMFIS_ACCEPT)
366 		{
367 			/* accept mail, no further actions taken */
368 			curstate = ST_HELO;
369 		}
370 		else if (r == SMFIS_REJECT || r == SMFIS_DISCARD ||
371 			 r ==  SMFIS_TEMPFAIL)
372 		{
373 			/*
374 			**  further actions depend on current state
375 			**  if the IGNO bit is set: "ignore" the error,
376 			**  i.e., stay in the current state
377 			*/
378 			if (!bitset(CT_IGNO, cmds[i].cm_todo))
379 				curstate = ST_HELO;
380 		}
381 		else if (r == _SMFIS_ABORT)
382 		{
383 			if (ctx->ctx_dbg > 5)
384 				sm_dprintf("[%d] function returned abort\n",
385 					(int) ctx->ctx_id);
386 			ret = MI_FAILURE;
387 			break;
388 		}
389 	} while (!bitset(CT_END, cmds[i].cm_todo));
390 
391 	if (ret != MI_SUCCESS)
392 	{
393 		/* call abort only if in a mail transaction */
394 		if (fi_abort != NULL && call_abort)
395 			(void) (*fi_abort)(ctx);
396 	}
397 
398 	/* close must always be called */
399 	if ((fi_close = ctx->ctx_smfi->xxfi_close) != NULL)
400 		(void) (*fi_close)(ctx);
401 	if (r != _SMFIS_KEEP && buf != NULL)
402 		free(buf);
403 	mi_clr_macros(ctx, 0);
404 	return ret;
405 }
406 /*
407 **  SENDREPLY -- send a reply to the MTA
408 **
409 **	Parameters:
410 **		r -- reply code
411 **		sd -- socket descriptor
412 **		timeout_ptr -- (ptr to) timeout to use for sending
413 **		ctx -- context structure
414 **
415 **	Returns:
416 **		MI_SUCCESS/MI_FAILURE
417 */
418 
419 static int
420 sendreply(r, sd, timeout_ptr, ctx)
421 	sfsistat r;
422 	socket_t sd;
423 	struct timeval *timeout_ptr;
424 	SMFICTX_PTR ctx;
425 {
426 	int ret = MI_SUCCESS;
427 
428 	switch (r)
429 	{
430 	  case SMFIS_CONTINUE:
431 		ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_CONTINUE, NULL, 0);
432 		break;
433 	  case SMFIS_TEMPFAIL:
434 	  case SMFIS_REJECT:
435 		if (ctx->ctx_reply != NULL &&
436 		    ((r == SMFIS_TEMPFAIL && *ctx->ctx_reply == '4') ||
437 		     (r == SMFIS_REJECT && *ctx->ctx_reply == '5')))
438 		{
439 			ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_REPLYCODE,
440 					ctx->ctx_reply,
441 					strlen(ctx->ctx_reply) + 1);
442 			free(ctx->ctx_reply);
443 			ctx->ctx_reply = NULL;
444 		}
445 		else
446 		{
447 			ret = mi_wr_cmd(sd, timeout_ptr, r == SMFIS_REJECT ?
448 					SMFIR_REJECT : SMFIR_TEMPFAIL, NULL, 0);
449 		}
450 		break;
451 	  case SMFIS_DISCARD:
452 		ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_DISCARD, NULL, 0);
453 		break;
454 	  case SMFIS_ACCEPT:
455 		ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_ACCEPT, NULL, 0);
456 		break;
457 	  case _SMFIS_OPTIONS:
458 		{
459 			char buf[MILTER_OPTLEN];
460 			mi_int32 v;
461 
462 			v = htonl(ctx->ctx_smfi->xxfi_version);
463 			(void) memcpy(&(buf[0]), (void *) &v, MILTER_LEN_BYTES);
464 			v = htonl(ctx->ctx_smfi->xxfi_flags);
465 			(void) memcpy(&(buf[MILTER_LEN_BYTES]), (void *) &v,
466 				      MILTER_LEN_BYTES);
467 			v = htonl(ctx->ctx_pflags);
468 			(void) memcpy(&(buf[MILTER_LEN_BYTES * 2]), (void *) &v,
469 				      MILTER_LEN_BYTES);
470 			ret = mi_wr_cmd(sd, timeout_ptr, SMFIC_OPTNEG, buf,
471 				       MILTER_OPTLEN);
472 		}
473 		break;
474 	  default:	/* don't send a reply */
475 		break;
476 	}
477 	return ret;
478 }
479 
480 /*
481 **  CLR_MACROS -- clear set of macros starting from a given index
482 **
483 **	Parameters:
484 **		ctx -- context structure
485 **		m -- index from which to clear all macros
486 **
487 **	Returns:
488 **		None.
489 */
490 void
491 mi_clr_macros(ctx, m)
492 	SMFICTX_PTR ctx;
493 	int m;
494 {
495 	int i;
496 
497 	for (i = m; i < MAX_MACROS_ENTRIES; i++)
498 	{
499 		if (ctx->ctx_mac_ptr[i] != NULL)
500 		{
501 			free(ctx->ctx_mac_ptr[i]);
502 			ctx->ctx_mac_ptr[i] = NULL;
503 		}
504 		if (ctx->ctx_mac_buf[i] != NULL)
505 		{
506 			free(ctx->ctx_mac_buf[i]);
507 			ctx->ctx_mac_buf[i] = NULL;
508 		}
509 	}
510 }
511 /*
512 **  ST_OPTIONNEG -- negotiate options
513 **
514 **	Parameters:
515 **		g -- generic argument structure
516 **
517 **	Returns:
518 **		abort/send options/continue
519 */
520 
521 static int
522 st_optionneg(g)
523 	genarg *g;
524 {
525 	mi_int32 i, v;
526 
527 	if (g == NULL || g->a_ctx->ctx_smfi == NULL)
528 		return SMFIS_CONTINUE;
529 	mi_clr_macros(g->a_ctx, g->a_idx + 1);
530 
531 	/* check for minimum length */
532 	if (g->a_len < MILTER_OPTLEN)
533 	{
534 		smi_log(SMI_LOG_ERR,
535 			"%s: st_optionneg[%d]: len too short %d < %d",
536 			g->a_ctx->ctx_smfi->xxfi_name,
537 			(int) g->a_ctx->ctx_id, (int) g->a_len,
538 			MILTER_OPTLEN);
539 		return _SMFIS_ABORT;
540 	}
541 
542 	(void) memcpy((void *) &i, (void *) &(g->a_buf[0]),
543 		      MILTER_LEN_BYTES);
544 	v = ntohl(i);
545 	if (v < g->a_ctx->ctx_smfi->xxfi_version)
546 	{
547 		/* hard failure for now! */
548 		smi_log(SMI_LOG_ERR,
549 			"%s: st_optionneg[%d]: version mismatch MTA: %d < milter: %d",
550 			g->a_ctx->ctx_smfi->xxfi_name,
551 			(int) g->a_ctx->ctx_id, (int) v,
552 			g->a_ctx->ctx_smfi->xxfi_version);
553 		return _SMFIS_ABORT;
554 	}
555 
556 	(void) memcpy((void *) &i, (void *) &(g->a_buf[MILTER_LEN_BYTES]),
557 		      MILTER_LEN_BYTES);
558 	v = ntohl(i);
559 
560 	/* no flags? set to default value for V1 actions */
561 	if (v == 0)
562 		v = SMFI_V1_ACTS;
563 	i = g->a_ctx->ctx_smfi->xxfi_flags;
564 	if ((v & i) != i)
565 	{
566 		smi_log(SMI_LOG_ERR,
567 			"%s: st_optionneg[%d]: 0x%x does not fulfill action requirements 0x%x",
568 			g->a_ctx->ctx_smfi->xxfi_name,
569 			(int) g->a_ctx->ctx_id, v, i);
570 		return _SMFIS_ABORT;
571 	}
572 
573 	(void) memcpy((void *) &i, (void *) &(g->a_buf[MILTER_LEN_BYTES * 2]),
574 		      MILTER_LEN_BYTES);
575 	v = ntohl(i);
576 
577 	/* no flags? set to default value for V1 protocol */
578 	if (v == 0)
579 		v = SMFI_V1_PROT;
580 	i = g->a_ctx->ctx_pflags;
581 	if ((v & i) != i)
582 	{
583 		smi_log(SMI_LOG_ERR,
584 			"%s: st_optionneg[%d]: 0x%x does not fulfill protocol requirements 0x%x",
585 			g->a_ctx->ctx_smfi->xxfi_name,
586 			(int) g->a_ctx->ctx_id, v, i);
587 		return _SMFIS_ABORT;
588 	}
589 
590 	return _SMFIS_OPTIONS;
591 }
592 /*
593 **  ST_CONNECTINFO -- receive connection information
594 **
595 **	Parameters:
596 **		g -- generic argument structure
597 **
598 **	Returns:
599 **		continue or filter-specified value
600 */
601 
602 static int
603 st_connectinfo(g)
604 	genarg *g;
605 {
606 	size_t l;
607 	size_t i;
608 	char *s, family;
609 	unsigned short port = 0;
610 	_SOCK_ADDR sockaddr;
611 	sfsistat (*fi_connect) __P((SMFICTX *, char *, _SOCK_ADDR *));
612 
613 	if (g == NULL)
614 		return _SMFIS_ABORT;
615 	mi_clr_macros(g->a_ctx, g->a_idx + 1);
616 	if (g->a_ctx->ctx_smfi == NULL ||
617 	    (fi_connect = g->a_ctx->ctx_smfi->xxfi_connect) == NULL)
618 		return SMFIS_CONTINUE;
619 
620 	s = g->a_buf;
621 	i = 0;
622 	l = g->a_len;
623 	while (s[i] != '\0' && i <= l)
624 		++i;
625 	if (i + 1 >= l)
626 		return _SMFIS_ABORT;
627 
628 	/* Move past trailing \0 in host string */
629 	i++;
630 	family = s[i++];
631 	(void) memset(&sockaddr, '\0', sizeof sockaddr);
632 	if (family != SMFIA_UNKNOWN)
633 	{
634 		if (i + sizeof port >= l)
635 		{
636 			smi_log(SMI_LOG_ERR,
637 				"%s: connect[%d]: wrong len %d >= %d",
638 				g->a_ctx->ctx_smfi->xxfi_name,
639 				(int) g->a_ctx->ctx_id, (int) i, (int) l);
640 			return _SMFIS_ABORT;
641 		}
642 		(void) memcpy((void *) &port, (void *) (s + i),
643 			      sizeof port);
644 		i += sizeof port;
645 
646 		/* make sure string is terminated */
647 		if (s[l - 1] != '\0')
648 			return _SMFIS_ABORT;
649 # if NETINET
650 		if (family == SMFIA_INET)
651 		{
652 			if (inet_aton(s + i, (struct in_addr *) &sockaddr.sin.sin_addr)
653 			    != 1)
654 			{
655 				smi_log(SMI_LOG_ERR,
656 					"%s: connect[%d]: inet_aton failed",
657 					g->a_ctx->ctx_smfi->xxfi_name,
658 					(int) g->a_ctx->ctx_id);
659 				return _SMFIS_ABORT;
660 			}
661 			sockaddr.sa.sa_family = AF_INET;
662 			if (port > 0)
663 				sockaddr.sin.sin_port = port;
664 		}
665 		else
666 # endif /* NETINET */
667 # if NETINET6
668 		if (family == SMFIA_INET6)
669 		{
670 			if (mi_inet_pton(AF_INET6, s + i,
671 					 &sockaddr.sin6.sin6_addr) != 1)
672 			{
673 				smi_log(SMI_LOG_ERR,
674 					"%s: connect[%d]: mi_inet_pton failed",
675 					g->a_ctx->ctx_smfi->xxfi_name,
676 					(int) g->a_ctx->ctx_id);
677 				return _SMFIS_ABORT;
678 			}
679 			sockaddr.sa.sa_family = AF_INET6;
680 			if (port > 0)
681 				sockaddr.sin6.sin6_port = port;
682 		}
683 		else
684 # endif /* NETINET6 */
685 # if NETUNIX
686 		if (family == SMFIA_UNIX)
687 		{
688 			if (sm_strlcpy(sockaddr.sunix.sun_path, s + i,
689 			    sizeof sockaddr.sunix.sun_path) >=
690 			    sizeof sockaddr.sunix.sun_path)
691 			{
692 				smi_log(SMI_LOG_ERR,
693 					"%s: connect[%d]: path too long",
694 					g->a_ctx->ctx_smfi->xxfi_name,
695 					(int) g->a_ctx->ctx_id);
696 				return _SMFIS_ABORT;
697 			}
698 			sockaddr.sunix.sun_family = AF_UNIX;
699 		}
700 		else
701 # endif /* NETUNIX */
702 		{
703 			smi_log(SMI_LOG_ERR,
704 				"%s: connect[%d]: unknown family %d",
705 				g->a_ctx->ctx_smfi->xxfi_name,
706 				(int) g->a_ctx->ctx_id, family);
707 			return _SMFIS_ABORT;
708 		}
709 	}
710 	return (*fi_connect)(g->a_ctx, g->a_buf,
711 			     family != SMFIA_UNKNOWN ? &sockaddr : NULL);
712 }
713 
714 /*
715 **  ST_EOH -- end of headers
716 **
717 **	Parameters:
718 **		g -- generic argument structure
719 **
720 **	Returns:
721 **		continue or filter-specified value
722 */
723 
724 static int
725 st_eoh(g)
726 	genarg *g;
727 {
728 	sfsistat (*fi_eoh) __P((SMFICTX *));
729 
730 	if (g == NULL)
731 		return _SMFIS_ABORT;
732 	if (g->a_ctx->ctx_smfi != NULL &&
733 	    (fi_eoh = g->a_ctx->ctx_smfi->xxfi_eoh) != NULL)
734 		return (*fi_eoh)(g->a_ctx);
735 	return SMFIS_CONTINUE;
736 }
737 
738 #if SMFI_VERSION > 3
739 /*
740 **  ST_DATA -- DATA command
741 **
742 **	Parameters:
743 **		g -- generic argument structure
744 **
745 **	Returns:
746 **		continue or filter-specified value
747 */
748 
749 static int
750 st_data(g)
751 	genarg *g;
752 {
753 	sfsistat (*fi_data) __P((SMFICTX *));
754 
755 	if (g == NULL)
756 		return _SMFIS_ABORT;
757 	if (g->a_ctx->ctx_smfi != NULL &&
758 	    (fi_data = g->a_ctx->ctx_smfi->xxfi_data) != NULL)
759 		return (*fi_data)(g->a_ctx);
760 	return SMFIS_CONTINUE;
761 }
762 #endif /* SMFI_VERSION > 3 */
763 
764 /*
765 **  ST_HELO -- helo/ehlo command
766 **
767 **	Parameters:
768 **		g -- generic argument structure
769 **
770 **	Returns:
771 **		continue or filter-specified value
772 */
773 static int
774 st_helo(g)
775 	genarg *g;
776 {
777 	sfsistat (*fi_helo) __P((SMFICTX *, char *));
778 
779 	if (g == NULL)
780 		return _SMFIS_ABORT;
781 	mi_clr_macros(g->a_ctx, g->a_idx + 1);
782 	if (g->a_ctx->ctx_smfi != NULL &&
783 	    (fi_helo = g->a_ctx->ctx_smfi->xxfi_helo) != NULL)
784 	{
785 		/* paranoia: check for terminating '\0' */
786 		if (g->a_len == 0 || g->a_buf[g->a_len - 1] != '\0')
787 			return MI_FAILURE;
788 		return (*fi_helo)(g->a_ctx, g->a_buf);
789 	}
790 	return SMFIS_CONTINUE;
791 }
792 /*
793 **  ST_HEADER -- header line
794 **
795 **	Parameters:
796 **		g -- generic argument structure
797 **
798 **	Returns:
799 **		continue or filter-specified value
800 */
801 
802 static int
803 st_header(g)
804 	genarg *g;
805 {
806 	char *hf, *hv;
807 	sfsistat (*fi_header) __P((SMFICTX *, char *, char *));
808 
809 	if (g == NULL)
810 		return _SMFIS_ABORT;
811 	if (g->a_ctx->ctx_smfi == NULL ||
812 	    (fi_header = g->a_ctx->ctx_smfi->xxfi_header) == NULL)
813 		return SMFIS_CONTINUE;
814 	if (dec_arg2(g->a_buf, g->a_len, &hf, &hv) == MI_SUCCESS)
815 		return (*fi_header)(g->a_ctx, hf, hv);
816 	else
817 		return _SMFIS_ABORT;
818 }
819 
820 #define ARGV_FCT(lf, rf, idx)					\
821 	char **argv;						\
822 	sfsistat (*lf) __P((SMFICTX *, char **));		\
823 	int r;							\
824 								\
825 	if (g == NULL)						\
826 		return _SMFIS_ABORT;				\
827 	mi_clr_macros(g->a_ctx, g->a_idx + 1);			\
828 	if (g->a_ctx->ctx_smfi == NULL ||			\
829 	    (lf = g->a_ctx->ctx_smfi->rf) == NULL)		\
830 		return SMFIS_CONTINUE;				\
831 	if ((argv = dec_argv(g->a_buf, g->a_len)) == NULL)	\
832 		return _SMFIS_ABORT;				\
833 	r = (*lf)(g->a_ctx, argv);				\
834 	free(argv);						\
835 	return r;
836 
837 /*
838 **  ST_SENDER -- MAIL FROM command
839 **
840 **	Parameters:
841 **		g -- generic argument structure
842 **
843 **	Returns:
844 **		continue or filter-specified value
845 */
846 
847 static int
848 st_sender(g)
849 	genarg *g;
850 {
851 	ARGV_FCT(fi_envfrom, xxfi_envfrom, CI_MAIL)
852 }
853 /*
854 **  ST_RCPT -- RCPT TO command
855 **
856 **	Parameters:
857 **		g -- generic argument structure
858 **
859 **	Returns:
860 **		continue or filter-specified value
861 */
862 
863 static int
864 st_rcpt(g)
865 	genarg *g;
866 {
867 	ARGV_FCT(fi_envrcpt, xxfi_envrcpt, CI_RCPT)
868 }
869 
870 #if SMFI_VERSION > 2
871 /*
872 **  ST_UNKNOWN -- unrecognized or unimplemented command
873 **
874 **	Parameters:
875 **		g -- generic argument structure
876 **
877 **	Returns:
878 **		continue or filter-specified value
879 */
880 
881 static int
882 st_unknown(g)
883 	genarg *g;
884 {
885 	sfsistat (*fi_unknown) __P((SMFICTX *, char *));
886 
887 	if (g == NULL)
888 		return _SMFIS_ABORT;
889 	mi_clr_macros(g->a_ctx, g->a_idx + 1);
890 	if (g->a_ctx->ctx_smfi != NULL &&
891 	    (fi_unknown = g->a_ctx->ctx_smfi->xxfi_unknown) != NULL)
892 		return (*fi_unknown)(g->a_ctx, g->a_buf);
893 	return SMFIS_CONTINUE;
894 }
895 #endif /* SMFI_VERSION > 2 */
896 
897 /*
898 **  ST_MACROS -- deal with macros received from the MTA
899 **
900 **	Parameters:
901 **		g -- generic argument structure
902 **
903 **	Returns:
904 **		continue/keep
905 **
906 **	Side effects:
907 **		set pointer in macro array to current values.
908 */
909 
910 static int
911 st_macros(g)
912 	genarg *g;
913 {
914 	int i;
915 	char **argv;
916 
917 	if (g == NULL || g->a_len < 1)
918 		return _SMFIS_FAIL;
919 	if ((argv = dec_argv(g->a_buf + 1, g->a_len - 1)) == NULL)
920 		return _SMFIS_FAIL;
921 	switch (g->a_buf[0])
922 	{
923 	  case SMFIC_CONNECT:
924 		i = CI_CONN;
925 		break;
926 	  case SMFIC_HELO:
927 		i = CI_HELO;
928 		break;
929 	  case SMFIC_MAIL:
930 		i = CI_MAIL;
931 		break;
932 	  case SMFIC_RCPT:
933 		i = CI_RCPT;
934 		break;
935 	  case SMFIC_BODYEOB:
936 		i = CI_EOM;
937 		break;
938 	  default:
939 		free(argv);
940 		return _SMFIS_FAIL;
941 	}
942 	if (g->a_ctx->ctx_mac_ptr[i] != NULL)
943 		free(g->a_ctx->ctx_mac_ptr[i]);
944 	if (g->a_ctx->ctx_mac_buf[i] != NULL)
945 		free(g->a_ctx->ctx_mac_buf[i]);
946 	g->a_ctx->ctx_mac_ptr[i] = argv;
947 	g->a_ctx->ctx_mac_buf[i] = g->a_buf;
948 	return _SMFIS_KEEP;
949 }
950 /*
951 **  ST_QUIT -- quit command
952 **
953 **	Parameters:
954 **		g -- generic argument structure
955 **
956 **	Returns:
957 **		noreply
958 */
959 
960 /* ARGSUSED */
961 static int
962 st_quit(g)
963 	genarg *g;
964 {
965 	return _SMFIS_NOREPLY;
966 }
967 /*
968 **  ST_BODYCHUNK -- deal with a piece of the mail body
969 **
970 **	Parameters:
971 **		g -- generic argument structure
972 **
973 **	Returns:
974 **		continue or filter-specified value
975 */
976 
977 static int
978 st_bodychunk(g)
979 	genarg *g;
980 {
981 	sfsistat (*fi_body) __P((SMFICTX *, unsigned char *, size_t));
982 
983 	if (g == NULL)
984 		return _SMFIS_ABORT;
985 	if (g->a_ctx->ctx_smfi != NULL &&
986 	    (fi_body = g->a_ctx->ctx_smfi->xxfi_body) != NULL)
987 		return (*fi_body)(g->a_ctx, (unsigned char *)g->a_buf,
988 				  g->a_len);
989 	return SMFIS_CONTINUE;
990 }
991 /*
992 **  ST_BODYEND -- deal with the last piece of the mail body
993 **
994 **	Parameters:
995 **		g -- generic argument structure
996 **
997 **	Returns:
998 **		continue or filter-specified value
999 **
1000 **	Side effects:
1001 **		sends a reply for the body part (if non-empty).
1002 */
1003 
1004 static int
1005 st_bodyend(g)
1006 	genarg *g;
1007 {
1008 	sfsistat r;
1009 	sfsistat (*fi_body) __P((SMFICTX *, unsigned char *, size_t));
1010 	sfsistat (*fi_eom) __P((SMFICTX *));
1011 
1012 	if (g == NULL)
1013 		return _SMFIS_ABORT;
1014 	r = SMFIS_CONTINUE;
1015 	if (g->a_ctx->ctx_smfi != NULL)
1016 	{
1017 		if ((fi_body = g->a_ctx->ctx_smfi->xxfi_body) != NULL &&
1018 		    g->a_len > 0)
1019 		{
1020 			socket_t sd;
1021 			struct timeval timeout;
1022 
1023 			timeout.tv_sec = g->a_ctx->ctx_timeout;
1024 			timeout.tv_usec = 0;
1025 			sd = g->a_ctx->ctx_sd;
1026 			r = (*fi_body)(g->a_ctx, (unsigned char *)g->a_buf,
1027 				       g->a_len);
1028 			if (r != SMFIS_CONTINUE &&
1029 			    sendreply(r, sd, &timeout, g->a_ctx) != MI_SUCCESS)
1030 				return _SMFIS_ABORT;
1031 		}
1032 	}
1033 	if (r == SMFIS_CONTINUE &&
1034 	    (fi_eom = g->a_ctx->ctx_smfi->xxfi_eom) != NULL)
1035 		return (*fi_eom)(g->a_ctx);
1036 	return r;
1037 }
1038 /*
1039 **  ST_ABORTFCT -- deal with aborts
1040 **
1041 **	Parameters:
1042 **		g -- generic argument structure
1043 **
1044 **	Returns:
1045 **		abort or filter-specified value
1046 */
1047 
1048 static int
1049 st_abortfct(g)
1050 	genarg *g;
1051 {
1052 	sfsistat (*fi_abort) __P((SMFICTX *));
1053 
1054 	if (g == NULL)
1055 		return _SMFIS_ABORT;
1056 	if (g != NULL && g->a_ctx->ctx_smfi != NULL &&
1057 	    (fi_abort = g->a_ctx->ctx_smfi->xxfi_abort) != NULL)
1058 		(void) (*fi_abort)(g->a_ctx);
1059 	return _SMFIS_NOREPLY;
1060 }
1061 /*
1062 **  TRANS_OK -- is the state transition ok?
1063 **
1064 **	Parameters:
1065 **		old -- old state
1066 **		new -- new state
1067 **
1068 **	Returns:
1069 **		state transition ok
1070 */
1071 
1072 static bool
1073 trans_ok(old, new)
1074 	int old, new;
1075 {
1076 	int s, n;
1077 
1078 	s = old;
1079 	do
1080 	{
1081 		/* is this state transition allowed? */
1082 		if ((MI_MASK(new) & next_states[s]) != 0)
1083 			return true;
1084 
1085 		/*
1086 		**  no: try next state;
1087 		**  this works since the relevant states are ordered
1088 		**  strict sequentially
1089 		*/
1090 
1091 		n = s + 1;
1092 
1093 		/*
1094 		**  can we actually "skip" this state?
1095 		**  see fix_stm() which sets this bit for those
1096 		**  states which the filter program is not interested in
1097 		*/
1098 
1099 		if (bitset(NX_SKIP, next_states[n]))
1100 			s = n;
1101 		else
1102 			return false;
1103 	} while (s <= ST_LAST);
1104 	return false;
1105 }
1106 /*
1107 **  FIX_STM -- add "skip" bits to the state transition table
1108 **
1109 **	Parameters:
1110 **		ctx -- context structure
1111 **
1112 **	Returns:
1113 **		None.
1114 **
1115 **	Side effects:
1116 **		may change state transition table.
1117 */
1118 
1119 static void
1120 fix_stm(ctx)
1121 	SMFICTX_PTR ctx;
1122 {
1123 	unsigned long fl;
1124 
1125 	if (ctx == NULL || ctx->ctx_smfi == NULL)
1126 		return;
1127 	fl = ctx->ctx_pflags;
1128 	if (bitset(SMFIP_NOCONNECT, fl))
1129 		next_states[ST_CONN] |= NX_SKIP;
1130 	if (bitset(SMFIP_NOHELO, fl))
1131 		next_states[ST_HELO] |= NX_SKIP;
1132 	if (bitset(SMFIP_NOMAIL, fl))
1133 		next_states[ST_MAIL] |= NX_SKIP;
1134 	if (bitset(SMFIP_NORCPT, fl))
1135 		next_states[ST_RCPT] |= NX_SKIP;
1136 	if (bitset(SMFIP_NOHDRS, fl))
1137 		next_states[ST_HDRS] |= NX_SKIP;
1138 	if (bitset(SMFIP_NOEOH, fl))
1139 		next_states[ST_EOHS] |= NX_SKIP;
1140 	if (bitset(SMFIP_NOBODY, fl))
1141 		next_states[ST_BODY] |= NX_SKIP;
1142 }
1143 /*
1144 **  DEC_ARGV -- split a buffer into a list of strings, NULL terminated
1145 **
1146 **	Parameters:
1147 **		buf -- buffer with several strings
1148 **		len -- length of buffer
1149 **
1150 **	Returns:
1151 **		array of pointers to the individual strings
1152 */
1153 
1154 static char **
1155 dec_argv(buf, len)
1156 	char *buf;
1157 	size_t len;
1158 {
1159 	char **s;
1160 	size_t i;
1161 	int elem, nelem;
1162 
1163 	nelem = 0;
1164 	for (i = 0; i < len; i++)
1165 	{
1166 		if (buf[i] == '\0')
1167 			++nelem;
1168 	}
1169 	if (nelem == 0)
1170 		return NULL;
1171 
1172 	/* last entry is only for the name */
1173 	s = (char **)malloc((nelem + 1) * (sizeof *s));
1174 	if (s == NULL)
1175 		return NULL;
1176 	s[0] = buf;
1177 	for (i = 0, elem = 0; i < len && elem < nelem; i++)
1178 	{
1179 		if (buf[i] == '\0')
1180 		{
1181 			++elem;
1182 			if (i + 1 >= len)
1183 				s[elem] = NULL;
1184 			else
1185 				s[elem] = &(buf[i + 1]);
1186 		}
1187 	}
1188 
1189 	/* overwrite last entry (already done above, just paranoia) */
1190 	s[elem] = NULL;
1191 	return s;
1192 }
1193 /*
1194 **  DEC_ARG2 -- split a buffer into two strings
1195 **
1196 **	Parameters:
1197 **		buf -- buffer with two strings
1198 **		len -- length of buffer
1199 **		s1,s2 -- pointer to result strings
1200 **
1201 **	Returns:
1202 **		MI_FAILURE/MI_SUCCESS
1203 */
1204 
1205 static int
1206 dec_arg2(buf, len, s1, s2)
1207 	char *buf;
1208 	size_t len;
1209 	char **s1;
1210 	char **s2;
1211 {
1212 	size_t i;
1213 
1214 	/* paranoia: check for terminating '\0' */
1215 	if (len == 0 || buf[len - 1] != '\0')
1216 		return MI_FAILURE;
1217 	*s1 = buf;
1218 	for (i = 1; i < len && buf[i] != '\0'; i++)
1219 		continue;
1220 	if (i >= len - 1)
1221 		return MI_FAILURE;
1222 	*s2 = buf + i + 1;
1223 	return MI_SUCCESS;
1224 }
1225 /*
1226 **  SENDOK -- is it ok for the filter to send stuff to the MTA?
1227 **
1228 **	Parameters:
1229 **		ctx -- context structure
1230 **		flag -- flag to check
1231 **
1232 **	Returns:
1233 **		sending allowed (in current state)
1234 */
1235 
1236 bool
1237 mi_sendok(ctx, flag)
1238 	SMFICTX_PTR ctx;
1239 	int flag;
1240 {
1241 	if (ctx == NULL || ctx->ctx_smfi == NULL)
1242 		return false;
1243 
1244 	/* did the milter request this operation? */
1245 	if (flag != 0 && !bitset(flag, ctx->ctx_smfi->xxfi_flags))
1246 		return false;
1247 
1248 	/* are we in the correct state? It must be "End of Message". */
1249 	return ctx->ctx_state == ST_ENDM;
1250 }
1251