2 * Copyright (c) 1999-2004, 2006 Sendmail, Inc. and its suppliers.
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.
12 SM_RCSID("@(#)$Id: engine.c,v 8.121 2006/04/18 21:01:46 ca Exp $")
14 #include "libmilter.h"
16 #if NETINET || NETINET6
17 # include <arpa/inet.h>
18 #endif /* NETINET || NETINET6 */
20 /* generic argument for functions in the command table */
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 */
29 typedef struct arg_struct genarg;
31 /* structure for commands received from MTA */
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 */
42 typedef struct cmdfct_t cmdfct;
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) */
53 /* possible values for cm_todo */
54 #define CT_CONT 0x0000 /* continue reading commands */
55 #define CT_IGNO 0x0001 /* continue even when error */
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 */
61 /* index in macro array: macros only for these commands */
68 #if CI_EOM >= MAX_MACROS_ENTRIES
69 ERROR: do not compile with CI_EOM >= MAX_MACROS_ENTRIES
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 *));
84 static int st_unknown __P((genarg *));
85 #endif /* SMFI_VERSION > 2 */
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 **));
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 */
116 /* in a mail transaction? must be before eom according to spec. */
117 #define ST_IN_MAIL(st) ((st) >= ST_MAIL && (st) < ST_ENDM)
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.
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))
144 #define NX_UNKN (MI_MASK(ST_HELO) | MI_MASK(ST_MAIL) | \
145 MI_MASK(ST_RCPT) | MI_MASK(ST_ABRT) | \
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)
151 static int next_states[] =
169 #define SIZE_NEXT_STATES (sizeof(next_states) / sizeof(next_states[0]))
171 /* commands received by milter */
172 static cmdfct cmds[] =
174 {SMFIC_ABORT, CM_ARG0, ST_ABRT, CT_CONT, CI_NONE, st_abortfct },
175 {SMFIC_MACRO, CM_ARGV, ST_NONE, CT_KEEP, CI_NONE, st_macros },
176 {SMFIC_BODY, CM_ARG1, ST_BODY, CT_CONT, CI_NONE, st_bodychunk },
177 {SMFIC_CONNECT, CM_ARG2, ST_CONN, CT_CONT, CI_CONN, st_connectinfo },
178 {SMFIC_BODYEOB, CM_ARG1, ST_ENDM, CT_CONT, CI_EOM, st_bodyend },
179 {SMFIC_HELO, CM_ARG1, ST_HELO, CT_CONT, CI_HELO, st_helo },
180 {SMFIC_HEADER, CM_ARG2, ST_HDRS, CT_CONT, CI_NONE, st_header },
181 {SMFIC_MAIL, CM_ARGV, ST_MAIL, CT_CONT, CI_MAIL, st_sender },
182 {SMFIC_OPTNEG, CM_ARGO, ST_OPTS, CT_CONT, CI_NONE, st_optionneg },
183 {SMFIC_EOH, CM_ARG0, ST_EOHS, CT_CONT, CI_NONE, st_eoh },
184 {SMFIC_QUIT, CM_ARG0, ST_QUIT, CT_END, CI_NONE, st_quit },
186 {SMFIC_DATA, CM_ARG0, ST_DATA, CT_CONT, CI_NONE, st_data },
187 #endif /* SMFI_VERSION > 3 */
188 {SMFIC_RCPT, CM_ARGV, ST_RCPT, CT_IGNO, CI_RCPT, st_rcpt }
190 ,{SMFIC_UNKNOWN,CM_ARG1, ST_UNKN, CT_IGNO, CI_NONE, st_unknown }
191 #endif /* SMFI_VERSION > 2 */
194 /* additional (internal) reply codes */
195 #define _SMFIS_KEEP 20
196 #define _SMFIS_ABORT 21
197 #define _SMFIS_OPTIONS 22
198 #define _SMFIS_NOREPLY 23
199 #define _SMFIS_FAIL (-1)
200 #define _SMFIS_NONE (-2)
203 ** MI_ENGINE -- receive commands and process them
206 ** ctx -- context structure
209 ** MI_FAILURE/MI_SUCCESS
218 int ret = MI_SUCCESS;
219 int ncmds = sizeof(cmds) / sizeof(cmdfct);
220 int curstate = ST_INIT;
227 struct timeval timeout;
228 int (*f) __P((genarg *));
229 sfsistat (*fi_abort) __P((SMFICTX *));
230 sfsistat (*fi_close) __P((SMFICTX *));
234 fi_abort = ctx->ctx_smfi->xxfi_abort;
235 mi_clr_macros(ctx, 0);
240 /* call abort only if in a mail transaction */
241 call_abort = ST_IN_MAIL(curstate);
242 timeout.tv_sec = ctx->ctx_timeout;
244 if (mi_stop() == MILTER_ABRT)
246 if (ctx->ctx_dbg > 3)
247 sm_dprintf("[%d] milter_abort\n",
254 ** Notice: buf is allocated by mi_rd_cmd() and it will
255 ** usually be free()d after it has been used in f().
256 ** However, if the function returns _SMFIS_KEEP then buf
257 ** contains macros and will not be free()d.
258 ** Hence r must be set to _SMFIS_NONE if a new buf is
259 ** allocated to avoid problem with housekeeping, esp.
260 ** if the code "break"s out of the loop.
264 if ((buf = mi_rd_cmd(sd, &timeout, &cmd, &len,
265 ctx->ctx_smfi->xxfi_name)) == NULL &&
266 cmd < SMFIC_VALIDCMD)
268 if (ctx->ctx_dbg > 5)
269 sm_dprintf("[%d] mi_engine: mi_rd_cmd error (%x)\n",
270 (int) ctx->ctx_id, (int) cmd);
273 ** eof is currently treated as failure ->
274 ** abort() instead of close(), otherwise use:
275 ** if (cmd != SMFIC_EOF)
281 if (ctx->ctx_dbg > 4)
282 sm_dprintf("[%d] got cmd '%c' len %d\n",
283 (int) ctx->ctx_id, cmd, (int) len);
284 for (i = 0; i < ncmds; i++)
286 if (cmd == cmds[i].cm_cmd)
291 /* unknown command */
292 if (ctx->ctx_dbg > 1)
293 sm_dprintf("[%d] cmd '%c' unknown\n",
294 (int) ctx->ctx_id, cmd);
298 if ((f = cmds[i].cm_fct) == NULL)
301 if (ctx->ctx_dbg > 1)
302 sm_dprintf("[%d] cmd '%c' not impl\n",
303 (int) ctx->ctx_id, cmd);
308 /* is new state ok? */
309 newstate = cmds[i].cm_next;
310 if (ctx->ctx_dbg > 5)
311 sm_dprintf("[%d] cur %x new %x nextmask %x\n",
313 curstate, newstate, next_states[curstate]);
315 if (newstate != ST_NONE && !trans_ok(curstate, newstate))
317 if (ctx->ctx_dbg > 1)
318 sm_dprintf("[%d] abort: cur %d (%x) new %d (%x) next %x\n",
320 curstate, MI_MASK(curstate),
321 newstate, MI_MASK(newstate),
322 next_states[curstate]);
324 /* call abort only if in a mail transaction */
325 if (fi_abort != NULL && call_abort)
326 (void) (*fi_abort)(ctx);
329 ** try to reach the new state from HELO
330 ** if it can't be reached, ignore the command.
334 if (!trans_ok(curstate, newstate))
346 if (newstate != ST_NONE)
349 ctx->ctx_state = curstate;
351 arg.a_idx = cmds[i].cm_macros;
352 call_abort = ST_IN_MAIL(curstate);
354 /* call function to deal with command */
356 if (r != _SMFIS_KEEP && buf != NULL)
361 if (sendreply(r, sd, &timeout, ctx) != MI_SUCCESS)
367 if (r == SMFIS_ACCEPT)
369 /* accept mail, no further actions taken */
372 else if (r == SMFIS_REJECT || r == SMFIS_DISCARD ||
376 ** further actions depend on current state
377 ** if the IGNO bit is set: "ignore" the error,
378 ** i.e., stay in the current state
380 if (!bitset(CT_IGNO, cmds[i].cm_todo))
383 else if (r == _SMFIS_ABORT)
385 if (ctx->ctx_dbg > 5)
386 sm_dprintf("[%d] function returned abort\n",
391 } while (!bitset(CT_END, cmds[i].cm_todo));
393 if (ret != MI_SUCCESS)
395 /* call abort only if in a mail transaction */
396 if (fi_abort != NULL && call_abort)
397 (void) (*fi_abort)(ctx);
400 /* close must always be called */
401 if ((fi_close = ctx->ctx_smfi->xxfi_close) != NULL)
402 (void) (*fi_close)(ctx);
403 if (r != _SMFIS_KEEP && buf != NULL)
405 mi_clr_macros(ctx, 0);
409 ** SENDREPLY -- send a reply to the MTA
413 ** sd -- socket descriptor
414 ** timeout_ptr -- (ptr to) timeout to use for sending
415 ** ctx -- context structure
418 ** MI_SUCCESS/MI_FAILURE
422 sendreply(r, sd, timeout_ptr, ctx)
425 struct timeval *timeout_ptr;
428 int ret = MI_SUCCESS;
433 ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_CONTINUE, NULL, 0);
437 if (ctx->ctx_reply != NULL &&
438 ((r == SMFIS_TEMPFAIL && *ctx->ctx_reply == '4') ||
439 (r == SMFIS_REJECT && *ctx->ctx_reply == '5')))
441 ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_REPLYCODE,
443 strlen(ctx->ctx_reply) + 1);
444 free(ctx->ctx_reply);
445 ctx->ctx_reply = NULL;
449 ret = mi_wr_cmd(sd, timeout_ptr, r == SMFIS_REJECT ?
450 SMFIR_REJECT : SMFIR_TEMPFAIL, NULL, 0);
454 ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_DISCARD, NULL, 0);
457 ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_ACCEPT, NULL, 0);
461 char buf[MILTER_OPTLEN];
464 v = htonl(ctx->ctx_smfi->xxfi_version);
465 (void) memcpy(&(buf[0]), (void *) &v, MILTER_LEN_BYTES);
466 v = htonl(ctx->ctx_smfi->xxfi_flags);
467 (void) memcpy(&(buf[MILTER_LEN_BYTES]), (void *) &v,
469 v = htonl(ctx->ctx_pflags);
470 (void) memcpy(&(buf[MILTER_LEN_BYTES * 2]), (void *) &v,
472 ret = mi_wr_cmd(sd, timeout_ptr, SMFIC_OPTNEG, buf,
476 default: /* don't send a reply */
483 ** CLR_MACROS -- clear set of macros starting from a given index
486 ** ctx -- context structure
487 ** m -- index from which to clear all macros
493 mi_clr_macros(ctx, m)
499 for (i = m; i < MAX_MACROS_ENTRIES; i++)
501 if (ctx->ctx_mac_ptr[i] != NULL)
503 free(ctx->ctx_mac_ptr[i]);
504 ctx->ctx_mac_ptr[i] = NULL;
506 if (ctx->ctx_mac_buf[i] != NULL)
508 free(ctx->ctx_mac_buf[i]);
509 ctx->ctx_mac_buf[i] = NULL;
514 ** ST_OPTIONNEG -- negotiate options
517 ** g -- generic argument structure
520 ** abort/send options/continue
529 if (g == NULL || g->a_ctx->ctx_smfi == NULL)
530 return SMFIS_CONTINUE;
531 mi_clr_macros(g->a_ctx, g->a_idx + 1);
533 /* check for minimum length */
534 if (g->a_len < MILTER_OPTLEN)
537 "%s: st_optionneg[%d]: len too short %d < %d",
538 g->a_ctx->ctx_smfi->xxfi_name,
539 (int) g->a_ctx->ctx_id, (int) g->a_len,
544 (void) memcpy((void *) &i, (void *) &(g->a_buf[0]),
547 if (v < g->a_ctx->ctx_smfi->xxfi_version)
549 /* hard failure for now! */
551 "%s: st_optionneg[%d]: version mismatch MTA: %d < milter: %d",
552 g->a_ctx->ctx_smfi->xxfi_name,
553 (int) g->a_ctx->ctx_id, (int) v,
554 g->a_ctx->ctx_smfi->xxfi_version);
558 (void) memcpy((void *) &i, (void *) &(g->a_buf[MILTER_LEN_BYTES]),
562 /* no flags? set to default value for V1 actions */
565 i = g->a_ctx->ctx_smfi->xxfi_flags;
569 "%s: st_optionneg[%d]: 0x%x does not fulfill action requirements 0x%x",
570 g->a_ctx->ctx_smfi->xxfi_name,
571 (int) g->a_ctx->ctx_id, v, i);
575 (void) memcpy((void *) &i, (void *) &(g->a_buf[MILTER_LEN_BYTES * 2]),
579 /* no flags? set to default value for V1 protocol */
582 i = g->a_ctx->ctx_pflags;
586 "%s: st_optionneg[%d]: 0x%x does not fulfill protocol requirements 0x%x",
587 g->a_ctx->ctx_smfi->xxfi_name,
588 (int) g->a_ctx->ctx_id, v, i);
592 return _SMFIS_OPTIONS;
595 ** ST_CONNECTINFO -- receive connection information
598 ** g -- generic argument structure
601 ** continue or filter-specified value
611 unsigned short port = 0;
613 sfsistat (*fi_connect) __P((SMFICTX *, char *, _SOCK_ADDR *));
617 mi_clr_macros(g->a_ctx, g->a_idx + 1);
618 if (g->a_ctx->ctx_smfi == NULL ||
619 (fi_connect = g->a_ctx->ctx_smfi->xxfi_connect) == NULL)
620 return SMFIS_CONTINUE;
625 while (s[i] != '\0' && i <= l)
630 /* Move past trailing \0 in host string */
633 (void) memset(&sockaddr, '\0', sizeof sockaddr);
634 if (family != SMFIA_UNKNOWN)
636 if (i + sizeof port >= l)
639 "%s: connect[%d]: wrong len %d >= %d",
640 g->a_ctx->ctx_smfi->xxfi_name,
641 (int) g->a_ctx->ctx_id, (int) i, (int) l);
644 (void) memcpy((void *) &port, (void *) (s + i),
648 /* make sure string is terminated */
649 if (s[l - 1] != '\0')
652 if (family == SMFIA_INET)
654 if (inet_aton(s + i, (struct in_addr *) &sockaddr.sin.sin_addr)
658 "%s: connect[%d]: inet_aton failed",
659 g->a_ctx->ctx_smfi->xxfi_name,
660 (int) g->a_ctx->ctx_id);
663 sockaddr.sa.sa_family = AF_INET;
665 sockaddr.sin.sin_port = port;
668 # endif /* NETINET */
670 if (family == SMFIA_INET6)
672 if (mi_inet_pton(AF_INET6, s + i,
673 &sockaddr.sin6.sin6_addr) != 1)
676 "%s: connect[%d]: mi_inet_pton failed",
677 g->a_ctx->ctx_smfi->xxfi_name,
678 (int) g->a_ctx->ctx_id);
681 sockaddr.sa.sa_family = AF_INET6;
683 sockaddr.sin6.sin6_port = port;
686 # endif /* NETINET6 */
688 if (family == SMFIA_UNIX)
690 if (sm_strlcpy(sockaddr.sunix.sun_path, s + i,
691 sizeof sockaddr.sunix.sun_path) >=
692 sizeof sockaddr.sunix.sun_path)
695 "%s: connect[%d]: path too long",
696 g->a_ctx->ctx_smfi->xxfi_name,
697 (int) g->a_ctx->ctx_id);
700 sockaddr.sunix.sun_family = AF_UNIX;
703 # endif /* NETUNIX */
706 "%s: connect[%d]: unknown family %d",
707 g->a_ctx->ctx_smfi->xxfi_name,
708 (int) g->a_ctx->ctx_id, family);
712 return (*fi_connect)(g->a_ctx, g->a_buf,
713 family != SMFIA_UNKNOWN ? &sockaddr : NULL);
717 ** ST_EOH -- end of headers
720 ** g -- generic argument structure
723 ** continue or filter-specified value
730 sfsistat (*fi_eoh) __P((SMFICTX *));
734 if (g->a_ctx->ctx_smfi != NULL &&
735 (fi_eoh = g->a_ctx->ctx_smfi->xxfi_eoh) != NULL)
736 return (*fi_eoh)(g->a_ctx);
737 return SMFIS_CONTINUE;
742 ** ST_DATA -- DATA command
745 ** g -- generic argument structure
748 ** continue or filter-specified value
755 sfsistat (*fi_data) __P((SMFICTX *));
759 if (g->a_ctx->ctx_smfi != NULL &&
760 (fi_data = g->a_ctx->ctx_smfi->xxfi_data) != NULL)
761 return (*fi_data)(g->a_ctx);
762 return SMFIS_CONTINUE;
764 #endif /* SMFI_VERSION > 3 */
767 ** ST_HELO -- helo/ehlo command
770 ** g -- generic argument structure
773 ** continue or filter-specified value
779 sfsistat (*fi_helo) __P((SMFICTX *, char *));
783 mi_clr_macros(g->a_ctx, g->a_idx + 1);
784 if (g->a_ctx->ctx_smfi != NULL &&
785 (fi_helo = g->a_ctx->ctx_smfi->xxfi_helo) != NULL)
787 /* paranoia: check for terminating '\0' */
788 if (g->a_len == 0 || g->a_buf[g->a_len - 1] != '\0')
790 return (*fi_helo)(g->a_ctx, g->a_buf);
792 return SMFIS_CONTINUE;
795 ** ST_HEADER -- header line
798 ** g -- generic argument structure
801 ** continue or filter-specified value
809 sfsistat (*fi_header) __P((SMFICTX *, char *, char *));
813 if (g->a_ctx->ctx_smfi == NULL ||
814 (fi_header = g->a_ctx->ctx_smfi->xxfi_header) == NULL)
815 return SMFIS_CONTINUE;
816 if (dec_arg2(g->a_buf, g->a_len, &hf, &hv) == MI_SUCCESS)
817 return (*fi_header)(g->a_ctx, hf, hv);
822 #define ARGV_FCT(lf, rf, idx) \
824 sfsistat (*lf) __P((SMFICTX *, char **)); \
828 return _SMFIS_ABORT; \
829 mi_clr_macros(g->a_ctx, g->a_idx + 1); \
830 if (g->a_ctx->ctx_smfi == NULL || \
831 (lf = g->a_ctx->ctx_smfi->rf) == NULL) \
832 return SMFIS_CONTINUE; \
833 if ((argv = dec_argv(g->a_buf, g->a_len)) == NULL) \
834 return _SMFIS_ABORT; \
835 r = (*lf)(g->a_ctx, argv); \
840 ** ST_SENDER -- MAIL FROM command
843 ** g -- generic argument structure
846 ** continue or filter-specified value
853 ARGV_FCT(fi_envfrom, xxfi_envfrom, CI_MAIL)
856 ** ST_RCPT -- RCPT TO command
859 ** g -- generic argument structure
862 ** continue or filter-specified value
869 ARGV_FCT(fi_envrcpt, xxfi_envrcpt, CI_RCPT)
874 ** ST_UNKNOWN -- unrecognized or unimplemented command
877 ** g -- generic argument structure
880 ** continue or filter-specified value
887 sfsistat (*fi_unknown) __P((SMFICTX *, char *));
891 mi_clr_macros(g->a_ctx, g->a_idx + 1);
892 if (g->a_ctx->ctx_smfi != NULL &&
893 (fi_unknown = g->a_ctx->ctx_smfi->xxfi_unknown) != NULL)
894 return (*fi_unknown)(g->a_ctx, g->a_buf);
895 return SMFIS_CONTINUE;
897 #endif /* SMFI_VERSION > 2 */
900 ** ST_MACROS -- deal with macros received from the MTA
903 ** g -- generic argument structure
909 ** set pointer in macro array to current values.
919 if (g == NULL || g->a_len < 1)
921 if ((argv = dec_argv(g->a_buf + 1, g->a_len - 1)) == NULL)
944 if (g->a_ctx->ctx_mac_ptr[i] != NULL)
945 free(g->a_ctx->ctx_mac_ptr[i]);
946 if (g->a_ctx->ctx_mac_buf[i] != NULL)
947 free(g->a_ctx->ctx_mac_buf[i]);
948 g->a_ctx->ctx_mac_ptr[i] = argv;
949 g->a_ctx->ctx_mac_buf[i] = g->a_buf;
953 ** ST_QUIT -- quit command
956 ** g -- generic argument structure
967 return _SMFIS_NOREPLY;
970 ** ST_BODYCHUNK -- deal with a piece of the mail body
973 ** g -- generic argument structure
976 ** continue or filter-specified value
983 sfsistat (*fi_body) __P((SMFICTX *, unsigned char *, size_t));
987 if (g->a_ctx->ctx_smfi != NULL &&
988 (fi_body = g->a_ctx->ctx_smfi->xxfi_body) != NULL)
989 return (*fi_body)(g->a_ctx, (unsigned char *)g->a_buf,
991 return SMFIS_CONTINUE;
994 ** ST_BODYEND -- deal with the last piece of the mail body
997 ** g -- generic argument structure
1000 ** continue or filter-specified value
1003 ** sends a reply for the body part (if non-empty).
1011 sfsistat (*fi_body) __P((SMFICTX *, unsigned char *, size_t));
1012 sfsistat (*fi_eom) __P((SMFICTX *));
1015 return _SMFIS_ABORT;
1017 if (g->a_ctx->ctx_smfi != NULL)
1019 if ((fi_body = g->a_ctx->ctx_smfi->xxfi_body) != NULL &&
1023 struct timeval timeout;
1025 timeout.tv_sec = g->a_ctx->ctx_timeout;
1026 timeout.tv_usec = 0;
1027 sd = g->a_ctx->ctx_sd;
1028 r = (*fi_body)(g->a_ctx, (unsigned char *)g->a_buf,
1030 if (r != SMFIS_CONTINUE &&
1031 sendreply(r, sd, &timeout, g->a_ctx) != MI_SUCCESS)
1032 return _SMFIS_ABORT;
1035 if (r == SMFIS_CONTINUE &&
1036 (fi_eom = g->a_ctx->ctx_smfi->xxfi_eom) != NULL)
1037 return (*fi_eom)(g->a_ctx);
1041 ** ST_ABORTFCT -- deal with aborts
1044 ** g -- generic argument structure
1047 ** abort or filter-specified value
1054 sfsistat (*fi_abort) __P((SMFICTX *));
1057 return _SMFIS_ABORT;
1058 if (g != NULL && g->a_ctx->ctx_smfi != NULL &&
1059 (fi_abort = g->a_ctx->ctx_smfi->xxfi_abort) != NULL)
1060 (void) (*fi_abort)(g->a_ctx);
1061 return _SMFIS_NOREPLY;
1064 ** TRANS_OK -- is the state transition ok?
1071 ** state transition ok
1081 if (s >= SIZE_NEXT_STATES)
1085 /* is this state transition allowed? */
1086 if ((MI_MASK(new) & next_states[s]) != 0)
1090 ** no: try next state;
1091 ** this works since the relevant states are ordered
1092 ** strict sequentially
1096 if (n >= SIZE_NEXT_STATES)
1100 ** can we actually "skip" this state?
1101 ** see fix_stm() which sets this bit for those
1102 ** states which the filter program is not interested in
1105 if (bitset(NX_SKIP, next_states[n]))
1109 } while (s < SIZE_NEXT_STATES);
1113 ** FIX_STM -- add "skip" bits to the state transition table
1116 ** ctx -- context structure
1122 ** may change state transition table.
1131 if (ctx == NULL || ctx->ctx_smfi == NULL)
1133 fl = ctx->ctx_pflags;
1134 if (bitset(SMFIP_NOCONNECT, fl))
1135 next_states[ST_CONN] |= NX_SKIP;
1136 if (bitset(SMFIP_NOHELO, fl))
1137 next_states[ST_HELO] |= NX_SKIP;
1138 if (bitset(SMFIP_NOMAIL, fl))
1139 next_states[ST_MAIL] |= NX_SKIP;
1140 if (bitset(SMFIP_NORCPT, fl))
1141 next_states[ST_RCPT] |= NX_SKIP;
1142 if (bitset(SMFIP_NOHDRS, fl))
1143 next_states[ST_HDRS] |= NX_SKIP;
1144 if (bitset(SMFIP_NOEOH, fl))
1145 next_states[ST_EOHS] |= NX_SKIP;
1146 if (bitset(SMFIP_NOBODY, fl))
1147 next_states[ST_BODY] |= NX_SKIP;
1150 ** DEC_ARGV -- split a buffer into a list of strings, NULL terminated
1153 ** buf -- buffer with several strings
1154 ** len -- length of buffer
1157 ** array of pointers to the individual strings
1170 for (i = 0; i < len; i++)
1178 /* last entry is only for the name */
1179 s = (char **)malloc((nelem + 1) * (sizeof *s));
1183 for (i = 0, elem = 0; i < len && elem < nelem; i++)
1191 s[elem] = &(buf[i + 1]);
1195 /* overwrite last entry (already done above, just paranoia) */
1200 ** DEC_ARG2 -- split a buffer into two strings
1203 ** buf -- buffer with two strings
1204 ** len -- length of buffer
1205 ** s1,s2 -- pointer to result strings
1208 ** MI_FAILURE/MI_SUCCESS
1212 dec_arg2(buf, len, s1, s2)
1220 /* paranoia: check for terminating '\0' */
1221 if (len == 0 || buf[len - 1] != '\0')
1224 for (i = 1; i < len && buf[i] != '\0'; i++)
1232 ** SENDOK -- is it ok for the filter to send stuff to the MTA?
1235 ** ctx -- context structure
1236 ** flag -- flag to check
1239 ** sending allowed (in current state)
1243 mi_sendok(ctx, flag)
1247 if (ctx == NULL || ctx->ctx_smfi == NULL)
1250 /* did the milter request this operation? */
1251 if (flag != 0 && !bitset(flag, ctx->ctx_smfi->xxfi_flags))
1254 /* are we in the correct state? It must be "End of Message". */
1255 return ctx->ctx_state == ST_ENDM;