2 * Copyright (c) 1999-2002 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.109.2.5 2003/08/04 18:14:33 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 */
67 #if CI_RCPT >= MAX_MACROS_ENTRIES
68 ERROR
: do not compile with CI_RCPT
>= MAX_MACROS_ENTRIES
71 /* function prototypes */
72 static int st_abortfct
__P((genarg
*));
73 static int st_macros
__P((genarg
*));
74 static int st_optionneg
__P((genarg
*));
75 static int st_bodychunk
__P((genarg
*));
76 static int st_connectinfo
__P((genarg
*));
77 static int st_bodyend
__P((genarg
*));
78 static int st_helo
__P((genarg
*));
79 static int st_header
__P((genarg
*));
80 static int st_sender
__P((genarg
*));
81 static int st_rcpt
__P((genarg
*));
82 static int st_eoh
__P((genarg
*));
83 static int st_quit
__P((genarg
*));
84 static int sendreply
__P((sfsistat
, socket_t
, struct timeval
*, SMFICTX_PTR
));
85 static void fix_stm
__P((SMFICTX_PTR
));
86 static bool trans_ok
__P((int, int));
87 static char **dec_argv
__P((char *, size_t));
88 static int dec_arg2
__P((char *, size_t, char **, char **));
92 #define ST_INIT 0 /* initial state */
93 #define ST_OPTS 1 /* option negotiation */
94 #define ST_CONN 2 /* connection info */
95 #define ST_HELO 3 /* helo */
96 #define ST_MAIL 4 /* mail from */
97 #define ST_RCPT 5 /* rcpt to */
98 #define ST_HDRS 6 /* headers */
99 #define ST_EOHS 7 /* end of headers */
100 #define ST_BODY 8 /* body */
101 #define ST_ENDM 9 /* end of message */
102 #define ST_QUIT 10 /* quit */
103 #define ST_ABRT 11 /* abort */
104 #define ST_LAST ST_ABRT
105 #define ST_SKIP 15 /* not a state but required for the state table */
107 /* in a mail transaction? must be before eom according to spec. */
108 #define ST_IN_MAIL(st) ((st) >= ST_MAIL && (st) < ST_ENDM)
111 ** set of next states
112 ** each state (ST_*) corresponds to bit in an int value (1 << state)
113 ** each state has a set of allowed transitions ('or' of bits of states)
114 ** so a state transition is valid if the mask of the next state
115 ** is set in the NX_* value
116 ** this function is coded in trans_ok(), see below.
119 #define MI_MASK(x) (0x0001 << (x)) /* generate a bit "mask" for a state */
120 #define NX_INIT (MI_MASK(ST_OPTS))
121 #define NX_OPTS (MI_MASK(ST_CONN))
122 #define NX_CONN (MI_MASK(ST_HELO) | MI_MASK(ST_MAIL))
123 #define NX_HELO (MI_MASK(ST_HELO) | MI_MASK(ST_MAIL))
124 #define NX_MAIL (MI_MASK(ST_RCPT) | MI_MASK(ST_ABRT))
125 #define NX_RCPT (MI_MASK(ST_HDRS) | MI_MASK(ST_EOHS) | \
126 MI_MASK(ST_BODY) | MI_MASK(ST_ENDM) | \
127 MI_MASK(ST_RCPT) | MI_MASK(ST_ABRT))
128 #define NX_HDRS (MI_MASK(ST_EOHS) | MI_MASK(ST_HDRS) | MI_MASK(ST_ABRT))
129 #define NX_EOHS (MI_MASK(ST_BODY) | MI_MASK(ST_ENDM) | MI_MASK(ST_ABRT))
130 #define NX_BODY (MI_MASK(ST_ENDM) | MI_MASK(ST_BODY) | MI_MASK(ST_ABRT))
131 #define NX_ENDM (MI_MASK(ST_QUIT) | MI_MASK(ST_MAIL))
134 #define NX_SKIP MI_MASK(ST_SKIP)
136 static int next_states
[] =
152 /* commands received by milter */
153 static cmdfct cmds
[] =
155 {SMFIC_ABORT
, CM_ARG0
, ST_ABRT
, CT_CONT
, CI_NONE
, st_abortfct
},
156 {SMFIC_MACRO
, CM_ARGV
, ST_NONE
, CT_KEEP
, CI_NONE
, st_macros
},
157 {SMFIC_BODY
, CM_ARG1
, ST_BODY
, CT_CONT
, CI_NONE
, st_bodychunk
},
158 {SMFIC_CONNECT
, CM_ARG2
, ST_CONN
, CT_CONT
, CI_CONN
, st_connectinfo
},
159 {SMFIC_BODYEOB
, CM_ARG1
, ST_ENDM
, CT_CONT
, CI_NONE
, st_bodyend
},
160 {SMFIC_HELO
, CM_ARG1
, ST_HELO
, CT_CONT
, CI_HELO
, st_helo
},
161 {SMFIC_HEADER
, CM_ARG2
, ST_HDRS
, CT_CONT
, CI_NONE
, st_header
},
162 {SMFIC_MAIL
, CM_ARGV
, ST_MAIL
, CT_CONT
, CI_MAIL
, st_sender
},
163 {SMFIC_OPTNEG
, CM_ARGO
, ST_OPTS
, CT_CONT
, CI_NONE
, st_optionneg
},
164 {SMFIC_EOH
, CM_ARG0
, ST_EOHS
, CT_CONT
, CI_NONE
, st_eoh
},
165 {SMFIC_QUIT
, CM_ARG0
, ST_QUIT
, CT_END
, CI_NONE
, st_quit
},
166 {SMFIC_RCPT
, CM_ARGV
, ST_RCPT
, CT_IGNO
, CI_RCPT
, st_rcpt
}
169 /* additional (internal) reply codes */
170 #define _SMFIS_KEEP 20
171 #define _SMFIS_ABORT 21
172 #define _SMFIS_OPTIONS 22
173 #define _SMFIS_NOREPLY 23
174 #define _SMFIS_FAIL (-1)
175 #define _SMFIS_NONE (-2)
178 ** MI_ENGINE -- receive commands and process them
181 ** ctx -- context structure
184 ** MI_FAILURE/MI_SUCCESS
193 int ret
= MI_SUCCESS
;
194 int ncmds
= sizeof(cmds
) / sizeof(cmdfct
);
195 int curstate
= ST_INIT
;
202 struct timeval timeout
;
203 int (*f
) __P((genarg
*));
204 sfsistat (*fi_abort
) __P((SMFICTX
*));
205 sfsistat (*fi_close
) __P((SMFICTX
*));
209 fi_abort
= ctx
->ctx_smfi
->xxfi_abort
;
210 mi_clr_macros(ctx
, 0);
215 /* call abort only if in a mail transaction */
216 call_abort
= ST_IN_MAIL(curstate
);
217 timeout
.tv_sec
= ctx
->ctx_timeout
;
219 if (mi_stop() == MILTER_ABRT
)
221 if (ctx
->ctx_dbg
> 3)
222 sm_dprintf("[%d] milter_abort\n",
229 ** Notice: buf is allocated by mi_rd_cmd() and it will
230 ** usually be free()d after it has been used in f().
231 ** However, if the function returns _SMFIS_KEEP then buf
232 ** contains macros and will not be free()d.
233 ** Hence r must be set to _SMFIS_NONE if a new buf is
234 ** allocated to avoid problem with housekeeping, esp.
235 ** if the code "break"s out of the loop.
239 if ((buf
= mi_rd_cmd(sd
, &timeout
, &cmd
, &len
,
240 ctx
->ctx_smfi
->xxfi_name
)) == NULL
&&
241 cmd
< SMFIC_VALIDCMD
)
243 if (ctx
->ctx_dbg
> 5)
244 sm_dprintf("[%d] mi_engine: mi_rd_cmd error (%x)\n",
245 (int) ctx
->ctx_id
, (int) cmd
);
248 ** eof is currently treated as failure ->
249 ** abort() instead of close(), otherwise use:
250 ** if (cmd != SMFIC_EOF)
256 if (ctx
->ctx_dbg
> 4)
257 sm_dprintf("[%d] got cmd '%c' len %d\n",
258 (int) ctx
->ctx_id
, cmd
, (int) len
);
259 for (i
= 0; i
< ncmds
; i
++)
261 if (cmd
== cmds
[i
].cm_cmd
)
266 /* unknown command */
267 if (ctx
->ctx_dbg
> 1)
268 sm_dprintf("[%d] cmd '%c' unknown\n",
269 (int) ctx
->ctx_id
, cmd
);
273 if ((f
= cmds
[i
].cm_fct
) == NULL
)
276 if (ctx
->ctx_dbg
> 1)
277 sm_dprintf("[%d] cmd '%c' not impl\n",
278 (int) ctx
->ctx_id
, cmd
);
283 /* is new state ok? */
284 newstate
= cmds
[i
].cm_next
;
285 if (ctx
->ctx_dbg
> 5)
286 sm_dprintf("[%d] cur %x new %x nextmask %x\n",
288 curstate
, newstate
, next_states
[curstate
]);
290 if (newstate
!= ST_NONE
&& !trans_ok(curstate
, newstate
))
292 if (ctx
->ctx_dbg
> 1)
293 sm_dprintf("[%d] abort: cur %d (%x) new %d (%x) next %x\n",
295 curstate
, MI_MASK(curstate
),
296 newstate
, MI_MASK(newstate
),
297 next_states
[curstate
]);
299 /* call abort only if in a mail transaction */
300 if (fi_abort
!= NULL
&& call_abort
)
301 (void) (*fi_abort
)(ctx
);
304 ** try to reach the new state from HELO
305 ** if it can't be reached, ignore the command.
309 if (!trans_ok(curstate
, newstate
))
321 if (newstate
!= ST_NONE
)
324 ctx
->ctx_state
= curstate
;
326 arg
.a_idx
= cmds
[i
].cm_macros
;
328 /* call function to deal with command */
330 if (r
!= _SMFIS_KEEP
&& buf
!= NULL
)
335 if (sendreply(r
, sd
, &timeout
, ctx
) != MI_SUCCESS
)
341 call_abort
= ST_IN_MAIL(curstate
);
342 if (r
== SMFIS_ACCEPT
)
344 /* accept mail, no further actions taken */
347 else if (r
== SMFIS_REJECT
|| r
== SMFIS_DISCARD
||
351 ** further actions depend on current state
352 ** if the IGNO bit is set: "ignore" the error,
353 ** i.e., stay in the current state
355 if (!bitset(CT_IGNO
, cmds
[i
].cm_todo
))
358 else if (r
== _SMFIS_ABORT
)
360 if (ctx
->ctx_dbg
> 5)
361 sm_dprintf("[%d] function returned abort\n",
366 } while (!bitset(CT_END
, cmds
[i
].cm_todo
));
368 if (ret
!= MI_SUCCESS
)
370 /* call abort only if in a mail transaction */
371 if (fi_abort
!= NULL
&& call_abort
)
372 (void) (*fi_abort
)(ctx
);
375 /* close must always be called */
376 if ((fi_close
= ctx
->ctx_smfi
->xxfi_close
) != NULL
)
377 (void) (*fi_close
)(ctx
);
378 if (r
!= _SMFIS_KEEP
&& buf
!= NULL
)
380 mi_clr_macros(ctx
, 0);
384 ** SENDREPLY -- send a reply to the MTA
388 ** sd -- socket descriptor
389 ** timeout_ptr -- (ptr to) timeout to use for sending
390 ** ctx -- context structure
393 ** MI_SUCCESS/MI_FAILURE
397 sendreply(r
, sd
, timeout_ptr
, ctx
)
400 struct timeval
*timeout_ptr
;
403 int ret
= MI_SUCCESS
;
408 ret
= mi_wr_cmd(sd
, timeout_ptr
, SMFIR_CONTINUE
, NULL
, 0);
412 if (ctx
->ctx_reply
!= NULL
&&
413 ((r
== SMFIS_TEMPFAIL
&& *ctx
->ctx_reply
== '4') ||
414 (r
== SMFIS_REJECT
&& *ctx
->ctx_reply
== '5')))
416 ret
= mi_wr_cmd(sd
, timeout_ptr
, SMFIR_REPLYCODE
,
418 strlen(ctx
->ctx_reply
) + 1);
419 free(ctx
->ctx_reply
);
420 ctx
->ctx_reply
= NULL
;
424 ret
= mi_wr_cmd(sd
, timeout_ptr
, r
== SMFIS_REJECT
?
425 SMFIR_REJECT
: SMFIR_TEMPFAIL
, NULL
, 0);
429 ret
= mi_wr_cmd(sd
, timeout_ptr
, SMFIR_DISCARD
, NULL
, 0);
432 ret
= mi_wr_cmd(sd
, timeout_ptr
, SMFIR_ACCEPT
, NULL
, 0);
436 char buf
[MILTER_OPTLEN
];
439 v
= htonl(ctx
->ctx_smfi
->xxfi_version
);
440 (void) memcpy(&(buf
[0]), (void *) &v
, MILTER_LEN_BYTES
);
441 v
= htonl(ctx
->ctx_smfi
->xxfi_flags
);
442 (void) memcpy(&(buf
[MILTER_LEN_BYTES
]), (void *) &v
,
444 v
= htonl(ctx
->ctx_pflags
);
445 (void) memcpy(&(buf
[MILTER_LEN_BYTES
* 2]), (void *) &v
,
447 ret
= mi_wr_cmd(sd
, timeout_ptr
, SMFIC_OPTNEG
, buf
,
451 default: /* don't send a reply */
458 ** CLR_MACROS -- clear set of macros starting from a given index
461 ** ctx -- context structure
462 ** m -- index from which to clear all macros
468 mi_clr_macros(ctx
, m
)
474 for (i
= m
; i
< MAX_MACROS_ENTRIES
; i
++)
476 if (ctx
->ctx_mac_ptr
[i
] != NULL
)
478 free(ctx
->ctx_mac_ptr
[i
]);
479 ctx
->ctx_mac_ptr
[i
] = NULL
;
481 if (ctx
->ctx_mac_buf
[i
] != NULL
)
483 free(ctx
->ctx_mac_buf
[i
]);
484 ctx
->ctx_mac_buf
[i
] = NULL
;
489 ** ST_OPTIONNEG -- negotiate options
492 ** g -- generic argument structure
495 ** abort/send options/continue
504 if (g
== NULL
|| g
->a_ctx
->ctx_smfi
== NULL
)
505 return SMFIS_CONTINUE
;
506 mi_clr_macros(g
->a_ctx
, g
->a_idx
+ 1);
508 /* check for minimum length */
509 if (g
->a_len
< MILTER_OPTLEN
)
512 "%s: st_optionneg[%d]: len too short %d < %d",
513 g
->a_ctx
->ctx_smfi
->xxfi_name
,
514 (int) g
->a_ctx
->ctx_id
, (int) g
->a_len
,
519 (void) memcpy((void *) &i
, (void *) &(g
->a_buf
[0]),
522 if (v
< g
->a_ctx
->ctx_smfi
->xxfi_version
)
524 /* hard failure for now! */
526 "%s: st_optionneg[%d]: version mismatch MTA: %d < milter: %d",
527 g
->a_ctx
->ctx_smfi
->xxfi_name
,
528 (int) g
->a_ctx
->ctx_id
, (int) v
,
529 g
->a_ctx
->ctx_smfi
->xxfi_version
);
533 (void) memcpy((void *) &i
, (void *) &(g
->a_buf
[MILTER_LEN_BYTES
]),
537 /* no flags? set to default value for V1 actions */
540 i
= g
->a_ctx
->ctx_smfi
->xxfi_flags
;
544 "%s: st_optionneg[%d]: 0x%x does not fulfill action requirements 0x%x",
545 g
->a_ctx
->ctx_smfi
->xxfi_name
,
546 (int) g
->a_ctx
->ctx_id
, v
, i
);
550 (void) memcpy((void *) &i
, (void *) &(g
->a_buf
[MILTER_LEN_BYTES
* 2]),
554 /* no flags? set to default value for V1 protocol */
557 i
= g
->a_ctx
->ctx_pflags
;
561 "%s: st_optionneg[%d]: 0x%x does not fulfill protocol requirements 0x%x",
562 g
->a_ctx
->ctx_smfi
->xxfi_name
,
563 (int) g
->a_ctx
->ctx_id
, v
, i
);
567 return _SMFIS_OPTIONS
;
570 ** ST_CONNECTINFO -- receive connection information
573 ** g -- generic argument structure
576 ** continue or filter-specified value
586 unsigned short port
= 0;
588 sfsistat (*fi_connect
) __P((SMFICTX
*, char *, _SOCK_ADDR
*));
592 mi_clr_macros(g
->a_ctx
, g
->a_idx
+ 1);
593 if (g
->a_ctx
->ctx_smfi
== NULL
||
594 (fi_connect
= g
->a_ctx
->ctx_smfi
->xxfi_connect
) == NULL
)
595 return SMFIS_CONTINUE
;
600 while (s
[i
] != '\0' && i
<= l
)
605 /* Move past trailing \0 in host string */
608 (void) memset(&sockaddr
, '\0', sizeof sockaddr
);
609 if (family
!= SMFIA_UNKNOWN
)
611 (void) memcpy((void *) &port
, (void *) (s
+ i
),
613 if ((i
+= sizeof port
) >= l
)
616 "%s: connect[%d]: wrong len %d >= %d",
617 g
->a_ctx
->ctx_smfi
->xxfi_name
,
618 (int) g
->a_ctx
->ctx_id
, (int) i
, (int) l
);
622 /* make sure string is terminated */
623 if (s
[l
- 1] != '\0')
626 if (family
== SMFIA_INET
)
628 if (inet_aton(s
+ i
, (struct in_addr
*) &sockaddr
.sin
.sin_addr
)
632 "%s: connect[%d]: inet_aton failed",
633 g
->a_ctx
->ctx_smfi
->xxfi_name
,
634 (int) g
->a_ctx
->ctx_id
);
637 sockaddr
.sa
.sa_family
= AF_INET
;
639 sockaddr
.sin
.sin_port
= port
;
642 # endif /* NETINET */
644 if (family
== SMFIA_INET6
)
646 if (mi_inet_pton(AF_INET6
, s
+ i
,
647 &sockaddr
.sin6
.sin6_addr
) != 1)
650 "%s: connect[%d]: mi_inet_pton failed",
651 g
->a_ctx
->ctx_smfi
->xxfi_name
,
652 (int) g
->a_ctx
->ctx_id
);
655 sockaddr
.sa
.sa_family
= AF_INET6
;
657 sockaddr
.sin6
.sin6_port
= port
;
660 # endif /* NETINET6 */
662 if (family
== SMFIA_UNIX
)
664 if (sm_strlcpy(sockaddr
.sunix
.sun_path
, s
+ i
,
665 sizeof sockaddr
.sunix
.sun_path
) >=
666 sizeof sockaddr
.sunix
.sun_path
)
669 "%s: connect[%d]: path too long",
670 g
->a_ctx
->ctx_smfi
->xxfi_name
,
671 (int) g
->a_ctx
->ctx_id
);
674 sockaddr
.sunix
.sun_family
= AF_UNIX
;
677 # endif /* NETUNIX */
680 "%s: connect[%d]: unknown family %d",
681 g
->a_ctx
->ctx_smfi
->xxfi_name
,
682 (int) g
->a_ctx
->ctx_id
, family
);
686 return (*fi_connect
)(g
->a_ctx
, g
->a_buf
,
687 family
!= SMFIA_UNKNOWN
? &sockaddr
: NULL
);
690 ** ST_EOH -- end of headers
693 ** g -- generic argument structure
696 ** continue or filter-specified value
703 sfsistat (*fi_eoh
) __P((SMFICTX
*));
707 if (g
->a_ctx
->ctx_smfi
!= NULL
&&
708 (fi_eoh
= g
->a_ctx
->ctx_smfi
->xxfi_eoh
) != NULL
)
709 return (*fi_eoh
)(g
->a_ctx
);
710 return SMFIS_CONTINUE
;
713 ** ST_HELO -- helo/ehlo command
716 ** g -- generic argument structure
719 ** continue or filter-specified value
725 sfsistat (*fi_helo
) __P((SMFICTX
*, char *));
729 mi_clr_macros(g
->a_ctx
, g
->a_idx
+ 1);
730 if (g
->a_ctx
->ctx_smfi
!= NULL
&&
731 (fi_helo
= g
->a_ctx
->ctx_smfi
->xxfi_helo
) != NULL
)
732 return (*fi_helo
)(g
->a_ctx
, g
->a_buf
);
733 return SMFIS_CONTINUE
;
736 ** ST_HEADER -- header line
739 ** g -- generic argument structure
742 ** continue or filter-specified value
750 sfsistat (*fi_header
) __P((SMFICTX
*, char *, char *));
754 if (g
->a_ctx
->ctx_smfi
== NULL
||
755 (fi_header
= g
->a_ctx
->ctx_smfi
->xxfi_header
) == NULL
)
756 return SMFIS_CONTINUE
;
757 if (dec_arg2(g
->a_buf
, g
->a_len
, &hf
, &hv
) == MI_SUCCESS
)
758 return (*fi_header
)(g
->a_ctx
, hf
, hv
);
763 #define ARGV_FCT(lf, rf, idx) \
765 sfsistat (*lf) __P((SMFICTX *, char **)); \
769 return _SMFIS_ABORT; \
770 mi_clr_macros(g->a_ctx, g->a_idx + 1); \
771 if (g->a_ctx->ctx_smfi == NULL || \
772 (lf = g->a_ctx->ctx_smfi->rf) == NULL) \
773 return SMFIS_CONTINUE; \
774 if ((argv = dec_argv(g->a_buf, g->a_len)) == NULL) \
775 return _SMFIS_ABORT; \
776 r = (*lf)(g->a_ctx, argv); \
781 ** ST_SENDER -- MAIL FROM command
784 ** g -- generic argument structure
787 ** continue or filter-specified value
794 ARGV_FCT(fi_envfrom
, xxfi_envfrom
, CI_MAIL
)
797 ** ST_RCPT -- RCPT TO command
800 ** g -- generic argument structure
803 ** continue or filter-specified value
810 ARGV_FCT(fi_envrcpt
, xxfi_envrcpt
, CI_RCPT
)
813 ** ST_MACROS -- deal with macros received from the MTA
816 ** g -- generic argument structure
822 ** set pointer in macro array to current values.
832 if (g
== NULL
|| g
->a_len
< 1)
834 if ((argv
= dec_argv(g
->a_buf
+ 1, g
->a_len
- 1)) == NULL
)
854 if (g
->a_ctx
->ctx_mac_ptr
[i
] != NULL
)
855 free(g
->a_ctx
->ctx_mac_ptr
[i
]);
856 if (g
->a_ctx
->ctx_mac_buf
[i
] != NULL
)
857 free(g
->a_ctx
->ctx_mac_buf
[i
]);
858 g
->a_ctx
->ctx_mac_ptr
[i
] = argv
;
859 g
->a_ctx
->ctx_mac_buf
[i
] = g
->a_buf
;
863 ** ST_QUIT -- quit command
866 ** g -- generic argument structure
877 return _SMFIS_NOREPLY
;
880 ** ST_BODYCHUNK -- deal with a piece of the mail body
883 ** g -- generic argument structure
886 ** continue or filter-specified value
893 sfsistat (*fi_body
) __P((SMFICTX
*, unsigned char *, size_t));
897 if (g
->a_ctx
->ctx_smfi
!= NULL
&&
898 (fi_body
= g
->a_ctx
->ctx_smfi
->xxfi_body
) != NULL
)
899 return (*fi_body
)(g
->a_ctx
, (unsigned char *)g
->a_buf
,
901 return SMFIS_CONTINUE
;
904 ** ST_BODYEND -- deal with the last piece of the mail body
907 ** g -- generic argument structure
910 ** continue or filter-specified value
913 ** sends a reply for the body part (if non-empty).
921 sfsistat (*fi_body
) __P((SMFICTX
*, unsigned char *, size_t));
922 sfsistat (*fi_eom
) __P((SMFICTX
*));
927 if (g
->a_ctx
->ctx_smfi
!= NULL
)
929 if ((fi_body
= g
->a_ctx
->ctx_smfi
->xxfi_body
) != NULL
&&
933 struct timeval timeout
;
935 timeout
.tv_sec
= g
->a_ctx
->ctx_timeout
;
937 sd
= g
->a_ctx
->ctx_sd
;
938 r
= (*fi_body
)(g
->a_ctx
, (unsigned char *)g
->a_buf
,
940 if (r
!= SMFIS_CONTINUE
&&
941 sendreply(r
, sd
, &timeout
, g
->a_ctx
) != MI_SUCCESS
)
945 if (r
== SMFIS_CONTINUE
&&
946 (fi_eom
= g
->a_ctx
->ctx_smfi
->xxfi_eom
) != NULL
)
947 return (*fi_eom
)(g
->a_ctx
);
951 ** ST_ABORTFCT -- deal with aborts
954 ** g -- generic argument structure
957 ** abort or filter-specified value
964 sfsistat (*fi_abort
) __P((SMFICTX
*));
968 if (g
!= NULL
&& g
->a_ctx
->ctx_smfi
!= NULL
&&
969 (fi_abort
= g
->a_ctx
->ctx_smfi
->xxfi_abort
) != NULL
)
970 (void) (*fi_abort
)(g
->a_ctx
);
971 return _SMFIS_NOREPLY
;
974 ** TRANS_OK -- is the state transition ok?
981 ** state transition ok
993 /* is this state transition allowed? */
994 if ((MI_MASK(new) & next_states
[s
]) != 0)
998 ** no: try next state;
999 ** this works since the relevant states are ordered
1000 ** strict sequentially
1006 ** can we actually "skip" this state?
1007 ** see fix_stm() which sets this bit for those
1008 ** states which the filter program is not interested in
1011 if (bitset(NX_SKIP
, next_states
[n
]))
1015 } while (s
<= ST_LAST
);
1019 ** FIX_STM -- add "skip" bits to the state transition table
1022 ** ctx -- context structure
1028 ** may change state transition table.
1037 if (ctx
== NULL
|| ctx
->ctx_smfi
== NULL
)
1039 fl
= ctx
->ctx_pflags
;
1040 if (bitset(SMFIP_NOCONNECT
, fl
))
1041 next_states
[ST_CONN
] |= NX_SKIP
;
1042 if (bitset(SMFIP_NOHELO
, fl
))
1043 next_states
[ST_HELO
] |= NX_SKIP
;
1044 if (bitset(SMFIP_NOMAIL
, fl
))
1045 next_states
[ST_MAIL
] |= NX_SKIP
;
1046 if (bitset(SMFIP_NORCPT
, fl
))
1047 next_states
[ST_RCPT
] |= NX_SKIP
;
1048 if (bitset(SMFIP_NOHDRS
, fl
))
1049 next_states
[ST_HDRS
] |= NX_SKIP
;
1050 if (bitset(SMFIP_NOEOH
, fl
))
1051 next_states
[ST_EOHS
] |= NX_SKIP
;
1052 if (bitset(SMFIP_NOBODY
, fl
))
1053 next_states
[ST_BODY
] |= NX_SKIP
;
1056 ** DEC_ARGV -- split a buffer into a list of strings, NULL terminated
1059 ** buf -- buffer with several strings
1060 ** len -- length of buffer
1063 ** array of pointers to the individual strings
1076 for (i
= 0; i
< len
; i
++)
1084 /* last entry is only for the name */
1085 s
= (char **)malloc((nelem
+ 1) * (sizeof *s
));
1089 for (i
= 0, elem
= 0; i
< len
&& elem
< nelem
; i
++)
1092 s
[++elem
] = &(buf
[i
+ 1]);
1095 /* overwrite last entry */
1100 ** DEC_ARG2 -- split a buffer into two strings
1103 ** buf -- buffer with two strings
1104 ** len -- length of buffer
1105 ** s1,s2 -- pointer to result strings
1108 ** MI_FAILURE/MI_SUCCESS
1112 dec_arg2(buf
, len
, s1
, s2
)
1121 for (i
= 1; i
< len
&& buf
[i
] != '\0'; i
++)
1129 ** SENDOK -- is it ok for the filter to send stuff to the MTA?
1132 ** ctx -- context structure
1133 ** flag -- flag to check
1136 ** sending allowed (in current state)
1140 mi_sendok(ctx
, flag
)
1144 if (ctx
== NULL
|| ctx
->ctx_smfi
== NULL
)
1147 /* did the milter request this operation? */
1148 if (flag
!= 0 && !bitset(flag
, ctx
->ctx_smfi
->xxfi_flags
))
1151 /* are we in the correct state? It must be "End of Message". */
1152 return ctx
->ctx_state
== ST_ENDM
;