Update zoneinfo database.
[dragonfly/netmp.git] / contrib / sendmail / libmilter / engine.c
blob623b2c2efc4150961a77ed9ec3f307596a103da8
1 /*
2 * Copyright (c) 1999-2002 Sendmail, Inc. and its suppliers.
3 * All rights reserved.
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.
9 */
11 #include <sm/gen.h>
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 */
21 struct arg_struct
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 */
32 struct cmdfct_t
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 */
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 #if CI_RCPT >= MAX_MACROS_ENTRIES
68 ERROR: do not compile with CI_RCPT >= MAX_MACROS_ENTRIES
69 #endif
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 **));
90 /* states */
91 #define ST_NONE (-1)
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))
132 #define NX_QUIT 0
133 #define NX_ABRT 0
134 #define NX_SKIP MI_MASK(ST_SKIP)
136 static int next_states[] =
138 NX_INIT,
139 NX_OPTS,
140 NX_CONN,
141 NX_HELO,
142 NX_MAIL,
143 NX_RCPT,
144 NX_HDRS,
145 NX_EOHS,
146 NX_BODY,
147 NX_ENDM,
148 NX_QUIT,
149 NX_ABRT
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
180 ** Parameters:
181 ** ctx -- context structure
183 ** Returns:
184 ** MI_FAILURE/MI_SUCCESS
187 mi_engine(ctx)
188 SMFICTX_PTR ctx;
190 size_t len;
191 int i;
192 socket_t sd;
193 int ret = MI_SUCCESS;
194 int ncmds = sizeof(cmds) / sizeof(cmdfct);
195 int curstate = ST_INIT;
196 int newstate;
197 bool call_abort;
198 sfsistat r;
199 char cmd;
200 char *buf = NULL;
201 genarg arg;
202 struct timeval timeout;
203 int (*f) __P((genarg *));
204 sfsistat (*fi_abort) __P((SMFICTX *));
205 sfsistat (*fi_close) __P((SMFICTX *));
207 arg.a_ctx = ctx;
208 sd = ctx->ctx_sd;
209 fi_abort = ctx->ctx_smfi->xxfi_abort;
210 mi_clr_macros(ctx, 0);
211 fix_stm(ctx);
212 r = _SMFIS_NONE;
215 /* call abort only if in a mail transaction */
216 call_abort = ST_IN_MAIL(curstate);
217 timeout.tv_sec = ctx->ctx_timeout;
218 timeout.tv_usec = 0;
219 if (mi_stop() == MILTER_ABRT)
221 if (ctx->ctx_dbg > 3)
222 sm_dprintf("[%d] milter_abort\n",
223 (int) ctx->ctx_id);
224 ret = MI_FAILURE;
225 break;
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.
238 r = _SMFIS_NONE;
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)
253 ret = MI_FAILURE;
254 break;
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)
262 break;
264 if (i >= ncmds)
266 /* unknown command */
267 if (ctx->ctx_dbg > 1)
268 sm_dprintf("[%d] cmd '%c' unknown\n",
269 (int) ctx->ctx_id, cmd);
270 ret = MI_FAILURE;
271 break;
273 if ((f = cmds[i].cm_fct) == NULL)
275 /* stop for now */
276 if (ctx->ctx_dbg > 1)
277 sm_dprintf("[%d] cmd '%c' not impl\n",
278 (int) ctx->ctx_id, cmd);
279 ret = MI_FAILURE;
280 break;
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",
287 (int) ctx->ctx_id,
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",
294 (int) ctx->ctx_id,
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.
308 curstate = ST_HELO;
309 if (!trans_ok(curstate, newstate))
311 if (buf != NULL)
313 free(buf);
314 buf = NULL;
316 continue;
319 arg.a_len = len;
320 arg.a_buf = buf;
321 if (newstate != ST_NONE)
323 curstate = newstate;
324 ctx->ctx_state = curstate;
326 arg.a_idx = cmds[i].cm_macros;
328 /* call function to deal with command */
329 r = (*f)(&arg);
330 if (r != _SMFIS_KEEP && buf != NULL)
332 free(buf);
333 buf = NULL;
335 if (sendreply(r, sd, &timeout, ctx) != MI_SUCCESS)
337 ret = MI_FAILURE;
338 break;
341 call_abort = ST_IN_MAIL(curstate);
342 if (r == SMFIS_ACCEPT)
344 /* accept mail, no further actions taken */
345 curstate = ST_HELO;
347 else if (r == SMFIS_REJECT || r == SMFIS_DISCARD ||
348 r == SMFIS_TEMPFAIL)
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))
356 curstate = ST_HELO;
358 else if (r == _SMFIS_ABORT)
360 if (ctx->ctx_dbg > 5)
361 sm_dprintf("[%d] function returned abort\n",
362 (int) ctx->ctx_id);
363 ret = MI_FAILURE;
364 break;
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)
379 free(buf);
380 mi_clr_macros(ctx, 0);
381 return ret;
384 ** SENDREPLY -- send a reply to the MTA
386 ** Parameters:
387 ** r -- reply code
388 ** sd -- socket descriptor
389 ** timeout_ptr -- (ptr to) timeout to use for sending
390 ** ctx -- context structure
392 ** Returns:
393 ** MI_SUCCESS/MI_FAILURE
396 static int
397 sendreply(r, sd, timeout_ptr, ctx)
398 sfsistat r;
399 socket_t sd;
400 struct timeval *timeout_ptr;
401 SMFICTX_PTR ctx;
403 int ret = MI_SUCCESS;
405 switch (r)
407 case SMFIS_CONTINUE:
408 ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_CONTINUE, NULL, 0);
409 break;
410 case SMFIS_TEMPFAIL:
411 case SMFIS_REJECT:
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,
417 ctx->ctx_reply,
418 strlen(ctx->ctx_reply) + 1);
419 free(ctx->ctx_reply);
420 ctx->ctx_reply = NULL;
422 else
424 ret = mi_wr_cmd(sd, timeout_ptr, r == SMFIS_REJECT ?
425 SMFIR_REJECT : SMFIR_TEMPFAIL, NULL, 0);
427 break;
428 case SMFIS_DISCARD:
429 ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_DISCARD, NULL, 0);
430 break;
431 case SMFIS_ACCEPT:
432 ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_ACCEPT, NULL, 0);
433 break;
434 case _SMFIS_OPTIONS:
436 char buf[MILTER_OPTLEN];
437 mi_int32 v;
439 v = htonl(ctx->ctx_smfi->xxfi_version);
440 (void) memcpy(&(buf[0]), (void *) &v, MILTER_LEN_BYTES);
441 v = htonl(ctx->ctx_smfi->xxfi_flags);
442 (void) memcpy(&(buf[MILTER_LEN_BYTES]), (void *) &v,
443 MILTER_LEN_BYTES);
444 v = htonl(ctx->ctx_pflags);
445 (void) memcpy(&(buf[MILTER_LEN_BYTES * 2]), (void *) &v,
446 MILTER_LEN_BYTES);
447 ret = mi_wr_cmd(sd, timeout_ptr, SMFIC_OPTNEG, buf,
448 MILTER_OPTLEN);
450 break;
451 default: /* don't send a reply */
452 break;
454 return ret;
458 ** CLR_MACROS -- clear set of macros starting from a given index
460 ** Parameters:
461 ** ctx -- context structure
462 ** m -- index from which to clear all macros
464 ** Returns:
465 ** None.
467 void
468 mi_clr_macros(ctx, m)
469 SMFICTX_PTR ctx;
470 int m;
472 int i;
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
491 ** Parameters:
492 ** g -- generic argument structure
494 ** Returns:
495 ** abort/send options/continue
498 static int
499 st_optionneg(g)
500 genarg *g;
502 mi_int32 i, v;
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)
511 smi_log(SMI_LOG_ERR,
512 "%s: st_optionneg[%d]: len too short %d < %d",
513 g->a_ctx->ctx_smfi->xxfi_name,
514 (int) g->a_ctx->ctx_id, (int) g->a_len,
515 MILTER_OPTLEN);
516 return _SMFIS_ABORT;
519 (void) memcpy((void *) &i, (void *) &(g->a_buf[0]),
520 MILTER_LEN_BYTES);
521 v = ntohl(i);
522 if (v < g->a_ctx->ctx_smfi->xxfi_version)
524 /* hard failure for now! */
525 smi_log(SMI_LOG_ERR,
526 "%s: st_optionneg[%d]: version mismatch MTA: %d < milter: %d",
527 g->a_ctx->ctx_smfi->xxfi_name,
528 (int) g->a_ctx->ctx_id, (int) v,
529 g->a_ctx->ctx_smfi->xxfi_version);
530 return _SMFIS_ABORT;
533 (void) memcpy((void *) &i, (void *) &(g->a_buf[MILTER_LEN_BYTES]),
534 MILTER_LEN_BYTES);
535 v = ntohl(i);
537 /* no flags? set to default value for V1 actions */
538 if (v == 0)
539 v = SMFI_V1_ACTS;
540 i = g->a_ctx->ctx_smfi->xxfi_flags;
541 if ((v & i) != i)
543 smi_log(SMI_LOG_ERR,
544 "%s: st_optionneg[%d]: 0x%x does not fulfill action requirements 0x%x",
545 g->a_ctx->ctx_smfi->xxfi_name,
546 (int) g->a_ctx->ctx_id, v, i);
547 return _SMFIS_ABORT;
550 (void) memcpy((void *) &i, (void *) &(g->a_buf[MILTER_LEN_BYTES * 2]),
551 MILTER_LEN_BYTES);
552 v = ntohl(i);
554 /* no flags? set to default value for V1 protocol */
555 if (v == 0)
556 v = SMFI_V1_PROT;
557 i = g->a_ctx->ctx_pflags;
558 if ((v & i) != i)
560 smi_log(SMI_LOG_ERR,
561 "%s: st_optionneg[%d]: 0x%x does not fulfill protocol requirements 0x%x",
562 g->a_ctx->ctx_smfi->xxfi_name,
563 (int) g->a_ctx->ctx_id, v, i);
564 return _SMFIS_ABORT;
567 return _SMFIS_OPTIONS;
570 ** ST_CONNECTINFO -- receive connection information
572 ** Parameters:
573 ** g -- generic argument structure
575 ** Returns:
576 ** continue or filter-specified value
579 static int
580 st_connectinfo(g)
581 genarg *g;
583 size_t l;
584 size_t i;
585 char *s, family;
586 unsigned short port = 0;
587 _SOCK_ADDR sockaddr;
588 sfsistat (*fi_connect) __P((SMFICTX *, char *, _SOCK_ADDR *));
590 if (g == NULL)
591 return _SMFIS_ABORT;
592 mi_clr_macros(g->a_ctx, g->a_idx + 1);
593 if (g->a_ctx->ctx_smfi == NULL ||
594 (fi_connect = g->a_ctx->ctx_smfi->xxfi_connect) == NULL)
595 return SMFIS_CONTINUE;
597 s = g->a_buf;
598 i = 0;
599 l = g->a_len;
600 while (s[i] != '\0' && i <= l)
601 ++i;
602 if (i >= l)
603 return _SMFIS_ABORT;
605 /* Move past trailing \0 in host string */
606 i++;
607 family = s[i++];
608 (void) memset(&sockaddr, '\0', sizeof sockaddr);
609 if (family != SMFIA_UNKNOWN)
611 (void) memcpy((void *) &port, (void *) (s + i),
612 sizeof port);
613 if ((i += sizeof port) >= l)
615 smi_log(SMI_LOG_ERR,
616 "%s: connect[%d]: wrong len %d >= %d",
617 g->a_ctx->ctx_smfi->xxfi_name,
618 (int) g->a_ctx->ctx_id, (int) i, (int) l);
619 return _SMFIS_ABORT;
622 /* make sure string is terminated */
623 if (s[l - 1] != '\0')
624 return _SMFIS_ABORT;
625 # if NETINET
626 if (family == SMFIA_INET)
628 if (inet_aton(s + i, (struct in_addr *) &sockaddr.sin.sin_addr)
629 != 1)
631 smi_log(SMI_LOG_ERR,
632 "%s: connect[%d]: inet_aton failed",
633 g->a_ctx->ctx_smfi->xxfi_name,
634 (int) g->a_ctx->ctx_id);
635 return _SMFIS_ABORT;
637 sockaddr.sa.sa_family = AF_INET;
638 if (port > 0)
639 sockaddr.sin.sin_port = port;
641 else
642 # endif /* NETINET */
643 # if NETINET6
644 if (family == SMFIA_INET6)
646 if (mi_inet_pton(AF_INET6, s + i,
647 &sockaddr.sin6.sin6_addr) != 1)
649 smi_log(SMI_LOG_ERR,
650 "%s: connect[%d]: mi_inet_pton failed",
651 g->a_ctx->ctx_smfi->xxfi_name,
652 (int) g->a_ctx->ctx_id);
653 return _SMFIS_ABORT;
655 sockaddr.sa.sa_family = AF_INET6;
656 if (port > 0)
657 sockaddr.sin6.sin6_port = port;
659 else
660 # endif /* NETINET6 */
661 # if NETUNIX
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)
668 smi_log(SMI_LOG_ERR,
669 "%s: connect[%d]: path too long",
670 g->a_ctx->ctx_smfi->xxfi_name,
671 (int) g->a_ctx->ctx_id);
672 return _SMFIS_ABORT;
674 sockaddr.sunix.sun_family = AF_UNIX;
676 else
677 # endif /* NETUNIX */
679 smi_log(SMI_LOG_ERR,
680 "%s: connect[%d]: unknown family %d",
681 g->a_ctx->ctx_smfi->xxfi_name,
682 (int) g->a_ctx->ctx_id, family);
683 return _SMFIS_ABORT;
686 return (*fi_connect)(g->a_ctx, g->a_buf,
687 family != SMFIA_UNKNOWN ? &sockaddr : NULL);
690 ** ST_EOH -- end of headers
692 ** Parameters:
693 ** g -- generic argument structure
695 ** Returns:
696 ** continue or filter-specified value
699 static int
700 st_eoh(g)
701 genarg *g;
703 sfsistat (*fi_eoh) __P((SMFICTX *));
705 if (g == NULL)
706 return _SMFIS_ABORT;
707 if (g->a_ctx->ctx_smfi != NULL &&
708 (fi_eoh = g->a_ctx->ctx_smfi->xxfi_eoh) != NULL)
709 return (*fi_eoh)(g->a_ctx);
710 return SMFIS_CONTINUE;
713 ** ST_HELO -- helo/ehlo command
715 ** Parameters:
716 ** g -- generic argument structure
718 ** Returns:
719 ** continue or filter-specified value
721 static int
722 st_helo(g)
723 genarg *g;
725 sfsistat (*fi_helo) __P((SMFICTX *, char *));
727 if (g == NULL)
728 return _SMFIS_ABORT;
729 mi_clr_macros(g->a_ctx, g->a_idx + 1);
730 if (g->a_ctx->ctx_smfi != NULL &&
731 (fi_helo = g->a_ctx->ctx_smfi->xxfi_helo) != NULL)
732 return (*fi_helo)(g->a_ctx, g->a_buf);
733 return SMFIS_CONTINUE;
736 ** ST_HEADER -- header line
738 ** Parameters:
739 ** g -- generic argument structure
741 ** Returns:
742 ** continue or filter-specified value
745 static int
746 st_header(g)
747 genarg *g;
749 char *hf, *hv;
750 sfsistat (*fi_header) __P((SMFICTX *, char *, char *));
752 if (g == NULL)
753 return _SMFIS_ABORT;
754 if (g->a_ctx->ctx_smfi == NULL ||
755 (fi_header = g->a_ctx->ctx_smfi->xxfi_header) == NULL)
756 return SMFIS_CONTINUE;
757 if (dec_arg2(g->a_buf, g->a_len, &hf, &hv) == MI_SUCCESS)
758 return (*fi_header)(g->a_ctx, hf, hv);
759 else
760 return _SMFIS_ABORT;
763 #define ARGV_FCT(lf, rf, idx) \
764 char **argv; \
765 sfsistat (*lf) __P((SMFICTX *, char **)); \
766 int r; \
768 if (g == NULL) \
769 return _SMFIS_ABORT; \
770 mi_clr_macros(g->a_ctx, g->a_idx + 1); \
771 if (g->a_ctx->ctx_smfi == NULL || \
772 (lf = g->a_ctx->ctx_smfi->rf) == NULL) \
773 return SMFIS_CONTINUE; \
774 if ((argv = dec_argv(g->a_buf, g->a_len)) == NULL) \
775 return _SMFIS_ABORT; \
776 r = (*lf)(g->a_ctx, argv); \
777 free(argv); \
778 return r;
781 ** ST_SENDER -- MAIL FROM command
783 ** Parameters:
784 ** g -- generic argument structure
786 ** Returns:
787 ** continue or filter-specified value
790 static int
791 st_sender(g)
792 genarg *g;
794 ARGV_FCT(fi_envfrom, xxfi_envfrom, CI_MAIL)
797 ** ST_RCPT -- RCPT TO command
799 ** Parameters:
800 ** g -- generic argument structure
802 ** Returns:
803 ** continue or filter-specified value
806 static int
807 st_rcpt(g)
808 genarg *g;
810 ARGV_FCT(fi_envrcpt, xxfi_envrcpt, CI_RCPT)
813 ** ST_MACROS -- deal with macros received from the MTA
815 ** Parameters:
816 ** g -- generic argument structure
818 ** Returns:
819 ** continue/keep
821 ** Side effects:
822 ** set pointer in macro array to current values.
825 static int
826 st_macros(g)
827 genarg *g;
829 int i;
830 char **argv;
832 if (g == NULL || g->a_len < 1)
833 return _SMFIS_FAIL;
834 if ((argv = dec_argv(g->a_buf + 1, g->a_len - 1)) == NULL)
835 return _SMFIS_FAIL;
836 switch (g->a_buf[0])
838 case SMFIC_CONNECT:
839 i = CI_CONN;
840 break;
841 case SMFIC_HELO:
842 i = CI_HELO;
843 break;
844 case SMFIC_MAIL:
845 i = CI_MAIL;
846 break;
847 case SMFIC_RCPT:
848 i = CI_RCPT;
849 break;
850 default:
851 free(argv);
852 return _SMFIS_FAIL;
854 if (g->a_ctx->ctx_mac_ptr[i] != NULL)
855 free(g->a_ctx->ctx_mac_ptr[i]);
856 if (g->a_ctx->ctx_mac_buf[i] != NULL)
857 free(g->a_ctx->ctx_mac_buf[i]);
858 g->a_ctx->ctx_mac_ptr[i] = argv;
859 g->a_ctx->ctx_mac_buf[i] = g->a_buf;
860 return _SMFIS_KEEP;
863 ** ST_QUIT -- quit command
865 ** Parameters:
866 ** g -- generic argument structure
868 ** Returns:
869 ** noreply
872 /* ARGSUSED */
873 static int
874 st_quit(g)
875 genarg *g;
877 return _SMFIS_NOREPLY;
880 ** ST_BODYCHUNK -- deal with a piece of the mail body
882 ** Parameters:
883 ** g -- generic argument structure
885 ** Returns:
886 ** continue or filter-specified value
889 static int
890 st_bodychunk(g)
891 genarg *g;
893 sfsistat (*fi_body) __P((SMFICTX *, unsigned char *, size_t));
895 if (g == NULL)
896 return _SMFIS_ABORT;
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,
900 g->a_len);
901 return SMFIS_CONTINUE;
904 ** ST_BODYEND -- deal with the last piece of the mail body
906 ** Parameters:
907 ** g -- generic argument structure
909 ** Returns:
910 ** continue or filter-specified value
912 ** Side effects:
913 ** sends a reply for the body part (if non-empty).
916 static int
917 st_bodyend(g)
918 genarg *g;
920 sfsistat r;
921 sfsistat (*fi_body) __P((SMFICTX *, unsigned char *, size_t));
922 sfsistat (*fi_eom) __P((SMFICTX *));
924 if (g == NULL)
925 return _SMFIS_ABORT;
926 r = SMFIS_CONTINUE;
927 if (g->a_ctx->ctx_smfi != NULL)
929 if ((fi_body = g->a_ctx->ctx_smfi->xxfi_body) != NULL &&
930 g->a_len > 0)
932 socket_t sd;
933 struct timeval timeout;
935 timeout.tv_sec = g->a_ctx->ctx_timeout;
936 timeout.tv_usec = 0;
937 sd = g->a_ctx->ctx_sd;
938 r = (*fi_body)(g->a_ctx, (unsigned char *)g->a_buf,
939 g->a_len);
940 if (r != SMFIS_CONTINUE &&
941 sendreply(r, sd, &timeout, g->a_ctx) != MI_SUCCESS)
942 return _SMFIS_ABORT;
945 if (r == SMFIS_CONTINUE &&
946 (fi_eom = g->a_ctx->ctx_smfi->xxfi_eom) != NULL)
947 return (*fi_eom)(g->a_ctx);
948 return r;
951 ** ST_ABORTFCT -- deal with aborts
953 ** Parameters:
954 ** g -- generic argument structure
956 ** Returns:
957 ** abort or filter-specified value
960 static int
961 st_abortfct(g)
962 genarg *g;
964 sfsistat (*fi_abort) __P((SMFICTX *));
966 if (g == NULL)
967 return _SMFIS_ABORT;
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?
976 ** Parameters:
977 ** old -- old state
978 ** new -- new state
980 ** Returns:
981 ** state transition ok
984 static bool
985 trans_ok(old, new)
986 int old, new;
988 int s, n;
990 s = old;
993 /* is this state transition allowed? */
994 if ((MI_MASK(new) & next_states[s]) != 0)
995 return true;
998 ** no: try next state;
999 ** this works since the relevant states are ordered
1000 ** strict sequentially
1003 n = s + 1;
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]))
1012 s = n;
1013 else
1014 return false;
1015 } while (s <= ST_LAST);
1016 return false;
1019 ** FIX_STM -- add "skip" bits to the state transition table
1021 ** Parameters:
1022 ** ctx -- context structure
1024 ** Returns:
1025 ** None.
1027 ** Side effects:
1028 ** may change state transition table.
1031 static void
1032 fix_stm(ctx)
1033 SMFICTX_PTR ctx;
1035 unsigned long fl;
1037 if (ctx == NULL || ctx->ctx_smfi == NULL)
1038 return;
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
1058 ** Parameters:
1059 ** buf -- buffer with several strings
1060 ** len -- length of buffer
1062 ** Returns:
1063 ** array of pointers to the individual strings
1066 static char **
1067 dec_argv(buf, len)
1068 char *buf;
1069 size_t len;
1071 char **s;
1072 size_t i;
1073 int elem, nelem;
1075 nelem = 0;
1076 for (i = 0; i < len; i++)
1078 if (buf[i] == '\0')
1079 ++nelem;
1081 if (nelem == 0)
1082 return NULL;
1084 /* last entry is only for the name */
1085 s = (char **)malloc((nelem + 1) * (sizeof *s));
1086 if (s == NULL)
1087 return NULL;
1088 s[0] = buf;
1089 for (i = 0, elem = 0; i < len && elem < nelem; i++)
1091 if (buf[i] == '\0')
1092 s[++elem] = &(buf[i + 1]);
1095 /* overwrite last entry */
1096 s[elem] = NULL;
1097 return s;
1100 ** DEC_ARG2 -- split a buffer into two strings
1102 ** Parameters:
1103 ** buf -- buffer with two strings
1104 ** len -- length of buffer
1105 ** s1,s2 -- pointer to result strings
1107 ** Returns:
1108 ** MI_FAILURE/MI_SUCCESS
1111 static int
1112 dec_arg2(buf, len, s1, s2)
1113 char *buf;
1114 size_t len;
1115 char **s1;
1116 char **s2;
1118 size_t i;
1120 *s1 = buf;
1121 for (i = 1; i < len && buf[i] != '\0'; i++)
1122 continue;
1123 if (i >= len - 1)
1124 return MI_FAILURE;
1125 *s2 = buf + i + 1;
1126 return MI_SUCCESS;
1129 ** SENDOK -- is it ok for the filter to send stuff to the MTA?
1131 ** Parameters:
1132 ** ctx -- context structure
1133 ** flag -- flag to check
1135 ** Returns:
1136 ** sending allowed (in current state)
1139 bool
1140 mi_sendok(ctx, flag)
1141 SMFICTX_PTR ctx;
1142 int flag;
1144 if (ctx == NULL || ctx->ctx_smfi == NULL)
1145 return false;
1147 /* did the milter request this operation? */
1148 if (flag != 0 && !bitset(flag, ctx->ctx_smfi->xxfi_flags))
1149 return false;
1151 /* are we in the correct state? It must be "End of Message". */
1152 return ctx->ctx_state == ST_ENDM;