Merge from vendor branch NCURSES:
[dragonfly.git] / contrib / sendmail-8.13.4 / libmilter / engine.c
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 }