engine.c revision 168988
1117610Sdes/* 2117610Sdes * Copyright (c) 1999-2004, 2006 Sendmail, Inc. and its suppliers. 3263421Sdes * All rights reserved. 4117610Sdes * 5263421Sdes * By using this file, you agree to the terms and conditions set 6117610Sdes * forth in the LICENSE file which can be found at the top level of 7117610Sdes * the sendmail distribution. 8117610Sdes * 9263421Sdes */ 10117610Sdes 11117610Sdes#include <sm/gen.h> 12117610SdesSM_RCSID("@(#)$Id: engine.c,v 8.157 2007/03/26 18:10:04 ca Exp $") 13117610Sdes 14117610Sdes#include "libmilter.h" 15117610Sdes 16117610Sdes#if NETINET || NETINET6 17117610Sdes# include <arpa/inet.h> 18263421Sdes#endif /* NETINET || NETINET6 */ 19117610Sdes 20117610Sdes/* generic argument for functions in the command table */ 21117610Sdesstruct arg_struct 22117610Sdes{ 23263421Sdes size_t a_len; /* length of buffer */ 24263421Sdes char *a_buf; /* argument string */ 25263421Sdes int a_idx; /* index for macro array */ 26117610Sdes SMFICTX_PTR a_ctx; /* context */ 27263421Sdes}; 28117610Sdes 29263421Sdestypedef struct arg_struct genarg; 30263421Sdes 31263421Sdes/* structure for commands received from MTA */ 32263421Sdesstruct cmdfct_t 33117610Sdes{ 34263421Sdes char cm_cmd; /* command */ 35117610Sdes int cm_argt; /* type of arguments expected */ 36117610Sdes int cm_next; /* next state */ 37117610Sdes int cm_todo; /* what to do next */ 38117610Sdes int cm_macros; /* index for macros */ 39117610Sdes int (*cm_fct) __P((genarg *)); /* function to execute */ 40117610Sdes}; 41117610Sdes 42117610Sdestypedef struct cmdfct_t cmdfct; 43117610Sdes 44117610Sdes/* possible values for cm_argt */ 45117610Sdes#define CM_ARG0 0 /* no args */ 46117610Sdes#define CM_ARG1 1 /* one arg (string) */ 47117610Sdes#define CM_ARG2 2 /* two args (strings) */ 48117610Sdes#define CM_ARGA 4 /* one string and _SOCK_ADDR */ 49117610Sdes#define CM_ARGO 5 /* two integers */ 50117610Sdes#define CM_ARGV 8 /* \0 separated list of args, NULL-terminated */ 51117610Sdes#define CM_ARGN 9 /* \0 separated list of args (strings) */ 52117610Sdes 53263421Sdes/* possible values for cm_todo */ 54117610Sdes#define CT_CONT 0x0000 /* continue reading commands */ 55117610Sdes#define CT_IGNO 0x0001 /* continue even when error */ 56117610Sdes 57117610Sdes/* not needed right now, done via return code instead */ 58117610Sdes#define CT_KEEP 0x0004 /* keep buffer (contains symbols) */ 59117610Sdes#define CT_END 0x0008 /* last command of session, stop replying */ 60117610Sdes 61117610Sdes/* index in macro array: macros only for these commands */ 62117610Sdes#define CI_NONE (-1) 63117610Sdes#define CI_CONN 0 64117610Sdes#define CI_HELO 1 65263421Sdes#define CI_MAIL 2 66117610Sdes#define CI_RCPT 3 67263421Sdes#define CI_DATA 4 68117610Sdes#define CI_EOM 5 69263421Sdes#define CI_EOH 6 70117610Sdes#define CI_LAST CI_EOH 71117610Sdes#if CI_LAST < CI_DATA 72117610SdesERROR: do not compile with CI_LAST < CI_DATA 73117610Sdes#endif 74117610Sdes#if CI_LAST < CI_EOM 75117610SdesERROR: do not compile with CI_LAST < CI_EOM 76117610Sdes#endif 77117610Sdes#if CI_LAST < CI_EOH 78117610SdesERROR: do not compile with CI_LAST < CI_EOH 79117610Sdes#endif 80117610Sdes#if CI_LAST < CI_ENVRCPT 81117610SdesERROR: do not compile with CI_LAST < CI_ENVRCPT 82117610Sdes#endif 83117610Sdes#if CI_LAST < CI_ENVFROM 84117610SdesERROR: do not compile with CI_LAST < CI_ENVFROM 85117610Sdes#endif 86117610Sdes#if CI_LAST < CI_HELO 87117610SdesERROR: do not compile with CI_LAST < CI_HELO 88117610Sdes#endif 89117610Sdes#if CI_LAST < CI_CONNECT 90117610SdesERROR: do not compile with CI_LAST < CI_CONNECT 91117610Sdes#endif 92117610Sdes#if CI_LAST >= MAX_MACROS_ENTRIES 93117610SdesERROR: do not compile with CI_LAST >= MAX_MACROS_ENTRIES 94117610Sdes#endif 95117610Sdes 96117610Sdes/* function prototypes */ 97117610Sdesstatic int st_abortfct __P((genarg *)); 98117610Sdesstatic int st_macros __P((genarg *)); 99117610Sdesstatic int st_optionneg __P((genarg *)); 100117610Sdesstatic int st_bodychunk __P((genarg *)); 101117610Sdesstatic int st_connectinfo __P((genarg *)); 102117610Sdesstatic int st_bodyend __P((genarg *)); 103263421Sdesstatic int st_helo __P((genarg *)); 104117610Sdesstatic int st_header __P((genarg *)); 105117610Sdesstatic int st_sender __P((genarg *)); 106117610Sdesstatic int st_rcpt __P((genarg *)); 107117610Sdesstatic int st_unknown __P((genarg *)); 108117610Sdesstatic int st_data __P((genarg *)); 109117610Sdesstatic int st_eoh __P((genarg *)); 110117610Sdesstatic int st_quit __P((genarg *)); 111117610Sdesstatic int sendreply __P((sfsistat, socket_t, struct timeval *, SMFICTX_PTR)); 112117610Sdesstatic void fix_stm __P((SMFICTX_PTR)); 113117610Sdesstatic bool trans_ok __P((int, int)); 114117610Sdesstatic char **dec_argv __P((char *, size_t)); 115117610Sdesstatic int dec_arg2 __P((char *, size_t, char **, char **)); 116117610Sdes 117117610Sdes#if _FFR_WORKERS_POOL 118117610Sdesstatic bool mi_rd_socket_ready __P((int)); 119117610Sdes#endif /* _FFR_WORKERS_POOL */ 120117610Sdes 121117610Sdes/* states */ 122263421Sdes#define ST_NONE (-1) 123117610Sdes#define ST_INIT 0 /* initial state */ 124117610Sdes#define ST_OPTS 1 /* option negotiation */ 125117610Sdes#define ST_CONN 2 /* connection info */ 126117610Sdes#define ST_HELO 3 /* helo */ 127117610Sdes#define ST_MAIL 4 /* mail from */ 128117610Sdes#define ST_RCPT 5 /* rcpt to */ 129117610Sdes#define ST_DATA 6 /* data */ 130117610Sdes#define ST_HDRS 7 /* headers */ 131117610Sdes#define ST_EOHS 8 /* end of headers */ 132117610Sdes#define ST_BODY 9 /* body */ 133117610Sdes#define ST_ENDM 10 /* end of message */ 134117610Sdes#define ST_QUIT 11 /* quit */ 135263421Sdes#define ST_ABRT 12 /* abort */ 136263421Sdes#define ST_UNKN 13 /* unknown SMTP command */ 137263421Sdes#define ST_Q_NC 14 /* quit, new connection follows */ 138263421Sdes#define ST_LAST ST_Q_NC /* last valid state */ 139263421Sdes#define ST_SKIP 16 /* not a state but required for the state table */ 140263421Sdes 141263421Sdes/* in a mail transaction? must be before eom according to spec. */ 142263421Sdes#define ST_IN_MAIL(st) ((st) >= ST_MAIL && (st) < ST_ENDM) 143263421Sdes 144263421Sdes/* 145263421Sdes** set of next states 146263421Sdes** each state (ST_*) corresponds to bit in an int value (1 << state) 147263421Sdes** each state has a set of allowed transitions ('or' of bits of states) 148263421Sdes** so a state transition is valid if the mask of the next state 149263421Sdes** is set in the NX_* value 150263421Sdes** this function is coded in trans_ok(), see below. 151263421Sdes*/ 152263421Sdes 153263421Sdes#define MI_MASK(x) (0x0001 << (x)) /* generate a bit "mask" for a state */ 154263421Sdes#define NX_INIT (MI_MASK(ST_OPTS)) 155263421Sdes#define NX_OPTS (MI_MASK(ST_CONN) | MI_MASK(ST_UNKN)) 156117610Sdes#define NX_CONN (MI_MASK(ST_HELO) | MI_MASK(ST_MAIL) | MI_MASK(ST_UNKN)) 157117610Sdes#define NX_HELO (MI_MASK(ST_HELO) | MI_MASK(ST_MAIL) | MI_MASK(ST_UNKN)) 158117610Sdes#define NX_MAIL (MI_MASK(ST_RCPT) | MI_MASK(ST_ABRT) | MI_MASK(ST_UNKN)) 159117610Sdes#define NX_RCPT (MI_MASK(ST_HDRS) | MI_MASK(ST_EOHS) | MI_MASK(ST_DATA) | \ 160117610Sdes MI_MASK(ST_BODY) | MI_MASK(ST_ENDM) | \ 161263421Sdes MI_MASK(ST_RCPT) | MI_MASK(ST_ABRT) | MI_MASK(ST_UNKN)) 162117610Sdes#define NX_DATA (MI_MASK(ST_EOHS) | MI_MASK(ST_HDRS) | MI_MASK(ST_ABRT)) 163117610Sdes#define NX_HDRS (MI_MASK(ST_EOHS) | MI_MASK(ST_HDRS) | MI_MASK(ST_ABRT)) 164117610Sdes#define NX_EOHS (MI_MASK(ST_BODY) | MI_MASK(ST_ENDM) | MI_MASK(ST_ABRT)) 165117610Sdes#define NX_BODY (MI_MASK(ST_ENDM) | MI_MASK(ST_BODY) | MI_MASK(ST_ABRT)) 166117610Sdes#define NX_ENDM (MI_MASK(ST_QUIT) | MI_MASK(ST_MAIL) | MI_MASK(ST_UNKN) | \ 167117610Sdes MI_MASK(ST_Q_NC)) 168117610Sdes#define NX_QUIT 0 169117610Sdes#define NX_ABRT 0 170117610Sdes#define NX_UNKN (MI_MASK(ST_HELO) | MI_MASK(ST_MAIL) | \ 171117610Sdes MI_MASK(ST_RCPT) | MI_MASK(ST_ABRT) | \ 172117610Sdes MI_MASK(ST_DATA) | \ 173117610Sdes MI_MASK(ST_BODY) | MI_MASK(ST_UNKN) | \ 174117610Sdes MI_MASK(ST_ABRT) | MI_MASK(ST_QUIT) | MI_MASK(ST_Q_NC)) 175117610Sdes#define NX_Q_NC (MI_MASK(ST_CONN) | MI_MASK(ST_UNKN)) 176117610Sdes#define NX_SKIP MI_MASK(ST_SKIP) 177117610Sdes 178263421Sdesstatic int next_states[] = 179117610Sdes{ 180117610Sdes NX_INIT 181117610Sdes , NX_OPTS 182117610Sdes , NX_CONN 183117610Sdes , NX_HELO 184117610Sdes , NX_MAIL 185117610Sdes , NX_RCPT 186117610Sdes , NX_DATA 187263421Sdes , NX_HDRS 188117610Sdes , NX_EOHS 189117610Sdes , NX_BODY 190117610Sdes , NX_ENDM 191117610Sdes , NX_QUIT 192117610Sdes , NX_ABRT 193117610Sdes , NX_UNKN 194117610Sdes , NX_Q_NC 195117610Sdes}; 196117610Sdes 197263421Sdes#define SIZE_NEXT_STATES (sizeof(next_states) / sizeof(next_states[0])) 198117610Sdes 199117610Sdes/* commands received by milter */ 200117610Sdesstatic cmdfct cmds[] = 201117610Sdes{ 202117610Sdes {SMFIC_ABORT, CM_ARG0, ST_ABRT, CT_CONT, CI_NONE, st_abortfct } 203117610Sdes, {SMFIC_MACRO, CM_ARGV, ST_NONE, CT_KEEP, CI_NONE, st_macros } 204117610Sdes, {SMFIC_BODY, CM_ARG1, ST_BODY, CT_CONT, CI_NONE, st_bodychunk } 205117610Sdes, {SMFIC_CONNECT, CM_ARG2, ST_CONN, CT_CONT, CI_CONN, st_connectinfo } 206117610Sdes, {SMFIC_BODYEOB, CM_ARG1, ST_ENDM, CT_CONT, CI_EOM, st_bodyend } 207117610Sdes, {SMFIC_HELO, CM_ARG1, ST_HELO, CT_CONT, CI_HELO, st_helo } 208117610Sdes, {SMFIC_HEADER, CM_ARG2, ST_HDRS, CT_CONT, CI_NONE, st_header } 209117610Sdes, {SMFIC_MAIL, CM_ARGV, ST_MAIL, CT_CONT, CI_MAIL, st_sender } 210117610Sdes, {SMFIC_OPTNEG, CM_ARGO, ST_OPTS, CT_CONT, CI_NONE, st_optionneg } 211117610Sdes, {SMFIC_EOH, CM_ARG0, ST_EOHS, CT_CONT, CI_EOH, st_eoh } 212117610Sdes, {SMFIC_QUIT, CM_ARG0, ST_QUIT, CT_END, CI_NONE, st_quit } 213117610Sdes, {SMFIC_DATA, CM_ARG0, ST_DATA, CT_CONT, CI_DATA, st_data } 214117610Sdes, {SMFIC_RCPT, CM_ARGV, ST_RCPT, CT_IGNO, CI_RCPT, st_rcpt } 215117610Sdes, {SMFIC_UNKNOWN, CM_ARG1, ST_UNKN, CT_IGNO, CI_NONE, st_unknown } 216117610Sdes, {SMFIC_QUIT_NC, CM_ARG0, ST_Q_NC, CT_CONT, CI_NONE, st_quit } 217263421Sdes}; 218263421Sdes 219263421Sdes/* 220263421Sdes** Additional (internal) reply codes; 221263421Sdes** must be coordinated wit libmilter/mfapi.h 222117610Sdes*/ 223263421Sdes 224263421Sdes#define _SMFIS_KEEP 20 225263421Sdes#define _SMFIS_ABORT 21 226263421Sdes#define _SMFIS_OPTIONS 22 227263421Sdes#define _SMFIS_NOREPLY SMFIS_NOREPLY 228263421Sdes#define _SMFIS_FAIL (-1) 229263421Sdes#define _SMFIS_NONE (-2) 230263421Sdes 231263421Sdes/* 232263421Sdes** MI_ENGINE -- receive commands and process them 233263421Sdes** 234263421Sdes** Parameters: 235263421Sdes** ctx -- context structure 236263421Sdes** 237263421Sdes** Returns: 238117610Sdes** MI_FAILURE/MI_SUCCESS 239263421Sdes*/ 240263421Sdes 241117610Sdesint 242263421Sdesmi_engine(ctx) 243263421Sdes SMFICTX_PTR ctx; 244263421Sdes{ 245263421Sdes size_t len; 246263421Sdes int i; 247117610Sdes socket_t sd; 248117610Sdes int ret = MI_SUCCESS; 249117610Sdes int ncmds = sizeof(cmds) / sizeof(cmdfct); 250117610Sdes int curstate = ST_INIT; 251117610Sdes int newstate; 252117610Sdes bool call_abort; 253117610Sdes sfsistat r; 254117610Sdes char cmd; 255117610Sdes char *buf = NULL; 256117610Sdes genarg arg; 257117610Sdes struct timeval timeout; 258117610Sdes int (*f) __P((genarg *)); 259117610Sdes sfsistat (*fi_abort) __P((SMFICTX *)); 260117610Sdes sfsistat (*fi_close) __P((SMFICTX *)); 261117610Sdes 262117610Sdes arg.a_ctx = ctx; 263117610Sdes sd = ctx->ctx_sd; 264117610Sdes fi_abort = ctx->ctx_smfi->xxfi_abort; 265117610Sdes#if _FFR_WORKERS_POOL 266117610Sdes curstate = ctx->ctx_state; 267117610Sdes if (curstate == ST_INIT) 268117610Sdes { 269117610Sdes mi_clr_macros(ctx, 0); 270117610Sdes fix_stm(ctx); 271117610Sdes } 272117610Sdes#else /* _FFR_WORKERS_POOL */ 273117610Sdes mi_clr_macros(ctx, 0); 274117610Sdes fix_stm(ctx); 275117610Sdes#endif /* _FFR_WORKERS_POOL */ 276117610Sdes r = _SMFIS_NONE; 277117610Sdes do 278117610Sdes { 279117610Sdes /* call abort only if in a mail transaction */ 280117610Sdes call_abort = ST_IN_MAIL(curstate); 281117610Sdes timeout.tv_sec = ctx->ctx_timeout; 282117610Sdes timeout.tv_usec = 0; 283117610Sdes if (mi_stop() == MILTER_ABRT) 284263421Sdes { 285117610Sdes if (ctx->ctx_dbg > 3) 286117610Sdes sm_dprintf("[%ld] milter_abort\n", 287117610Sdes (long) ctx->ctx_id); 288117610Sdes ret = MI_FAILURE; 289263421Sdes break; 290263421Sdes } 291263421Sdes 292263421Sdes /* 293263421Sdes ** Notice: buf is allocated by mi_rd_cmd() and it will 294117610Sdes ** usually be free()d after it has been used in f(). 295117610Sdes ** However, if the function returns _SMFIS_KEEP then buf 296117610Sdes ** contains macros and will not be free()d. 297117610Sdes ** Hence r must be set to _SMFIS_NONE if a new buf is 298117610Sdes ** allocated to avoid problem with housekeeping, esp. 299263421Sdes ** if the code "break"s out of the loop. 300117610Sdes */ 301117610Sdes 302263421Sdes#if _FFR_WORKERS_POOL 303117610Sdes /* Is the socket ready to be read ??? */ 304117610Sdes if (!mi_rd_socket_ready(sd)) 305263421Sdes { 306117610Sdes ret = MI_CONTINUE; 307117610Sdes break; 308263421Sdes } 309117610Sdes#endif /* _FFR_WORKERS_POOL */ 310117610Sdes 311263421Sdes r = _SMFIS_NONE; 312117610Sdes if ((buf = mi_rd_cmd(sd, &timeout, &cmd, &len, 313117610Sdes ctx->ctx_smfi->xxfi_name)) == NULL && 314263421Sdes cmd < SMFIC_VALIDCMD) 315263421Sdes { 316263421Sdes if (ctx->ctx_dbg > 5) 317263421Sdes sm_dprintf("[%ld] mi_engine: mi_rd_cmd error (%x)\n", 318263421Sdes (long) ctx->ctx_id, (int) cmd); 319263421Sdes 320263421Sdes /* 321117610Sdes ** eof is currently treated as failure -> 322117610Sdes ** abort() instead of close(), otherwise use: 323263421Sdes ** if (cmd != SMFIC_EOF) 324263421Sdes */ 325263421Sdes 326263421Sdes ret = MI_FAILURE; 327117610Sdes break; 328117610Sdes } 329263421Sdes if (ctx->ctx_dbg > 4) 330117610Sdes sm_dprintf("[%ld] got cmd '%c' len %d\n", 331117610Sdes (long) ctx->ctx_id, cmd, (int) len); 332117610Sdes for (i = 0; i < ncmds; i++) 333117610Sdes { 334117610Sdes if (cmd == cmds[i].cm_cmd) 335117610Sdes break; 336117610Sdes } 337263421Sdes if (i >= ncmds) 338117610Sdes { 339117610Sdes /* unknown command */ 340263421Sdes if (ctx->ctx_dbg > 1) 341117610Sdes sm_dprintf("[%ld] cmd '%c' unknown\n", 342117610Sdes (long) ctx->ctx_id, cmd); 343263421Sdes ret = MI_FAILURE; 344263421Sdes break; 345117610Sdes } 346263421Sdes if ((f = cmds[i].cm_fct) == NULL) 347117610Sdes { 348263421Sdes /* stop for now */ 349263421Sdes if (ctx->ctx_dbg > 1) 350263421Sdes sm_dprintf("[%ld] cmd '%c' not impl\n", 351117610Sdes (long) ctx->ctx_id, cmd); 352117610Sdes ret = MI_FAILURE; 353263421Sdes break; 354117610Sdes } 355117610Sdes 356263421Sdes /* is new state ok? */ 357263421Sdes newstate = cmds[i].cm_next; 358263421Sdes if (ctx->ctx_dbg > 5) 359263421Sdes sm_dprintf("[%ld] cur %x new %x nextmask %x\n", 360263421Sdes (long) ctx->ctx_id, 361263421Sdes curstate, newstate, next_states[curstate]); 362263421Sdes 363263421Sdes if (newstate != ST_NONE && !trans_ok(curstate, newstate)) 364263421Sdes { 365263421Sdes if (ctx->ctx_dbg > 1) 366263421Sdes sm_dprintf("[%ld] abort: cur %d (%x) new %d (%x) next %x\n", 367263421Sdes (long) ctx->ctx_id, 368263421Sdes curstate, MI_MASK(curstate), 369263421Sdes newstate, MI_MASK(newstate), 370263421Sdes next_states[curstate]); 371263421Sdes 372263421Sdes /* call abort only if in a mail transaction */ 373263421Sdes if (fi_abort != NULL && call_abort) 374263421Sdes (void) (*fi_abort)(ctx); 375263421Sdes 376117610Sdes /* 377117610Sdes ** try to reach the new state from HELO 378117610Sdes ** if it can't be reached, ignore the command. 379117610Sdes */ 380117610Sdes 381263421Sdes curstate = ST_HELO; 382117610Sdes if (!trans_ok(curstate, newstate)) 383117610Sdes { 384117610Sdes if (buf != NULL) 385117610Sdes { 386117610Sdes free(buf); 387117610Sdes buf = NULL; 388117610Sdes } 389117610Sdes continue; 390263421Sdes } 391117610Sdes } 392117610Sdes arg.a_len = len; 393263421Sdes arg.a_buf = buf; 394117610Sdes if (newstate != ST_NONE) 395117610Sdes { 396117610Sdes curstate = newstate; 397117610Sdes ctx->ctx_state = curstate; 398117610Sdes } 399117610Sdes arg.a_idx = cmds[i].cm_macros; 400117610Sdes call_abort = ST_IN_MAIL(curstate); 401117610Sdes 402117610Sdes /* call function to deal with command */ 403117610Sdes MI_MONITOR_BEGIN(ctx, cmd); 404117610Sdes r = (*f)(&arg); 405263421Sdes MI_MONITOR_END(ctx, cmd); 406117610Sdes if (r != _SMFIS_KEEP && buf != NULL) 407117610Sdes { 408263421Sdes free(buf); 409117610Sdes buf = NULL; 410117610Sdes } 411117610Sdes if (sendreply(r, sd, &timeout, ctx) != MI_SUCCESS) 412117610Sdes { 413117610Sdes ret = MI_FAILURE; 414117610Sdes break; 415117610Sdes } 416117610Sdes 417117610Sdes if (r == SMFIS_ACCEPT) 418263421Sdes { 419263421Sdes /* accept mail, no further actions taken */ 420117610Sdes curstate = ST_HELO; 421117610Sdes } 422263421Sdes else if (r == SMFIS_REJECT || r == SMFIS_DISCARD || 423117610Sdes r == SMFIS_TEMPFAIL) 424263421Sdes { 425263421Sdes /* 426117610Sdes ** further actions depend on current state 427263421Sdes ** if the IGNO bit is set: "ignore" the error, 428263421Sdes ** i.e., stay in the current state 429117610Sdes */ 430263421Sdes if (!bitset(CT_IGNO, cmds[i].cm_todo)) 431263421Sdes curstate = ST_HELO; 432117610Sdes } 433263421Sdes else if (r == _SMFIS_ABORT) 434263421Sdes { 435263421Sdes if (ctx->ctx_dbg > 5) 436263421Sdes sm_dprintf("[%ld] function returned abort\n", 437263421Sdes (long) ctx->ctx_id); 438117610Sdes ret = MI_FAILURE; 439117610Sdes break; 440263421Sdes } 441117610Sdes } while (!bitset(CT_END, cmds[i].cm_todo)); 442117610Sdes 443263421Sdes ctx->ctx_state = curstate; 444117610Sdes 445117610Sdes if (ret == MI_FAILURE) 446263421Sdes { 447117610Sdes /* call abort only if in a mail transaction */ 448117610Sdes if (fi_abort != NULL && call_abort) 449263421Sdes (void) (*fi_abort)(ctx); 450117610Sdes } 451117610Sdes 452263421Sdes /* has close been called? */ 453117610Sdes if (ctx->ctx_state != ST_QUIT 454117610Sdes#if _FFR_WORKERS_POOL 455117610Sdes && ret != MI_CONTINUE 456117610Sdes#endif /* _FFR_WORKERS_POOL */ 457117610Sdes ) 458117610Sdes { 459117610Sdes if ((fi_close = ctx->ctx_smfi->xxfi_close) != NULL) 460117610Sdes (void) (*fi_close)(ctx); 461117610Sdes } 462117610Sdes if (r != _SMFIS_KEEP && buf != NULL) 463117610Sdes free(buf); 464117610Sdes#if !_FFR_WORKERS_POOL 465117610Sdes mi_clr_macros(ctx, 0); 466117610Sdes#endif /* _FFR_WORKERS_POOL */ 467117610Sdes return ret; 468117610Sdes} 469117610Sdes 470117610Sdesstatic size_t milter_addsymlist __P((SMFICTX_PTR, char *, char **)); 471117610Sdes 472117610Sdesstatic size_t 473117610Sdesmilter_addsymlist(ctx, buf, newbuf) 474117610Sdes SMFICTX_PTR ctx; 475117610Sdes char *buf; 476263421Sdes char **newbuf; 477263421Sdes{ 478263421Sdes size_t len; 479263421Sdes int i; 480117610Sdes mi_int32 v; 481263421Sdes char *buffer; 482117610Sdes 483117610Sdes SM_ASSERT(ctx != NULL); 484263421Sdes SM_ASSERT(buf != NULL); 485117610Sdes SM_ASSERT(newbuf != NULL); 486117610Sdes len = 0; 487263421Sdes for (i = 0; i < MAX_MACROS_ENTRIES; i++) 488117610Sdes { 489117610Sdes if (ctx->ctx_mac_list[i] != NULL) 490263421Sdes { 491117610Sdes len += strlen(ctx->ctx_mac_list[i]) + 1 + 492117610Sdes MILTER_LEN_BYTES; 493263421Sdes } 494117610Sdes } 495117610Sdes if (len > 0) 496263421Sdes { 497117610Sdes size_t offset; 498117610Sdes 499263421Sdes SM_ASSERT(len + MILTER_OPTLEN > len); 500117610Sdes len += MILTER_OPTLEN; 501117610Sdes buffer = malloc(len); 502263421Sdes if (buffer != NULL) 503117610Sdes { 504263421Sdes (void) memcpy(buffer, buf, MILTER_OPTLEN); 505263421Sdes offset = MILTER_OPTLEN; 506117610Sdes for (i = 0; i < MAX_MACROS_ENTRIES; i++) 507117610Sdes { 508117610Sdes size_t l; 509117610Sdes 510117610Sdes if (ctx->ctx_mac_list[i] == NULL) 511117610Sdes continue; 512117610Sdes 513117610Sdes SM_ASSERT(offset + MILTER_LEN_BYTES < len); 514117610Sdes v = htonl(i); 515117610Sdes (void) memcpy(buffer + offset, (void *) &v, 516117610Sdes MILTER_LEN_BYTES); 517117610Sdes offset += MILTER_LEN_BYTES; 518263421Sdes l = strlen(ctx->ctx_mac_list[i]) + 1; 519117610Sdes SM_ASSERT(offset + l <= len); 520117610Sdes (void) memcpy(buffer + offset, 521263421Sdes ctx->ctx_mac_list[i], l); 522117610Sdes offset += l; 523117610Sdes } 524117610Sdes } 525263421Sdes else 526117610Sdes { 527117610Sdes /* oops ... */ 528263421Sdes } 529117610Sdes } 530117610Sdes else 531263421Sdes { 532117610Sdes len = MILTER_OPTLEN; 533117610Sdes buffer = buf; 534263421Sdes } 535117610Sdes *newbuf = buffer; 536263421Sdes return len; 537263421Sdes} 538117610Sdes 539117610Sdes/* 540263421Sdes** GET_NR_BIT -- get "no reply" bit matching state 541117610Sdes** 542117610Sdes** Parameters: 543117610Sdes** state -- current protocol stage 544117610Sdes** 545117610Sdes** Returns: 546117610Sdes** 0: no matching bit 547117610Sdes** >0: the matching "no reply" bit 548263421Sdes*/ 549117610Sdes 550117610Sdesstatic unsigned long get_nr_bit __P((int)); 551117610Sdes 552117610Sdesstatic unsigned long 553117610Sdesget_nr_bit(state) 554117610Sdes int state; 555117610Sdes{ 556117610Sdes unsigned long bit; 557117610Sdes 558117610Sdes switch (state) 559117610Sdes { 560117610Sdes case ST_CONN: 561117610Sdes bit = SMFIP_NR_CONN; 562117610Sdes break; 563263421Sdes case ST_HELO: 564263421Sdes bit = SMFIP_NR_HELO; 565263421Sdes break; 566263421Sdes case ST_MAIL: 567263421Sdes bit = SMFIP_NR_MAIL; 568263421Sdes break; 569117610Sdes case ST_RCPT: 570117610Sdes bit = SMFIP_NR_RCPT; 571117610Sdes break; 572117610Sdes case ST_DATA: 573117610Sdes bit = SMFIP_NR_DATA; 574263421Sdes break; 575263421Sdes case ST_UNKN: 576117610Sdes bit = SMFIP_NR_UNKN; 577117610Sdes break; 578117610Sdes case ST_HDRS: 579117610Sdes bit = SMFIP_NR_HDR; 580117610Sdes break; 581117610Sdes case ST_EOHS: 582117610Sdes bit = SMFIP_NR_EOH; 583117610Sdes break; 584117610Sdes case ST_BODY: 585117610Sdes bit = SMFIP_NR_BODY; 586117610Sdes break; 587117610Sdes default: 588263421Sdes bit = 0; 589117610Sdes break; 590117610Sdes } 591263421Sdes return bit; 592117610Sdes} 593117610Sdes 594263421Sdes/* 595117610Sdes** SENDREPLY -- send a reply to the MTA 596117610Sdes** 597263421Sdes** Parameters: 598117610Sdes** r -- reply code 599117610Sdes** sd -- socket descriptor 600263421Sdes** timeout_ptr -- (ptr to) timeout to use for sending 601117610Sdes** ctx -- context structure 602117610Sdes** 603263421Sdes** Returns: 604117610Sdes** MI_SUCCESS/MI_FAILURE 605117610Sdes*/ 606263421Sdes 607117610Sdesstatic int 608117610Sdessendreply(r, sd, timeout_ptr, ctx) 609263421Sdes sfsistat r; 610117610Sdes socket_t sd; 611117610Sdes struct timeval *timeout_ptr; 612117610Sdes SMFICTX_PTR ctx; 613117610Sdes{ 614117610Sdes int ret; 615117610Sdes unsigned long bit; 616117610Sdes 617117610Sdes ret = MI_SUCCESS; 618263421Sdes 619263421Sdes bit = get_nr_bit(ctx->ctx_state); 620263421Sdes if (bit != 0 && (ctx->ctx_pflags & bit) != 0 && r != SMFIS_NOREPLY) 621263421Sdes { 622263421Sdes if (r >= SMFIS_CONTINUE && r < _SMFIS_KEEP) 623263421Sdes { 624263421Sdes /* milter said it wouldn't reply, but it lied... */ 625263421Sdes smi_log(SMI_LOG_ERR, 626117610Sdes "%s: milter claimed not to reply in state %d but did anyway %d\n", 627263421Sdes ctx->ctx_smfi->xxfi_name, 628263421Sdes ctx->ctx_state, r); 629117610Sdes 630117610Sdes } 631117610Sdes 632263421Sdes /* 633117610Sdes ** Force specified behavior, otherwise libmilter 634263421Sdes ** and MTA will fail to communicate properly. 635263421Sdes */ 636263421Sdes 637117610Sdes switch (r) 638263421Sdes { 639263421Sdes case SMFIS_CONTINUE: 640263421Sdes case SMFIS_TEMPFAIL: 641263421Sdes case SMFIS_REJECT: 642263421Sdes case SMFIS_DISCARD: 643263421Sdes case SMFIS_ACCEPT: 644117610Sdes case SMFIS_SKIP: 645263421Sdes case _SMFIS_OPTIONS: 646263421Sdes r = SMFIS_NOREPLY; 647263421Sdes break; 648263421Sdes } 649263421Sdes } 650263421Sdes 651263421Sdes switch (r) 652263421Sdes { 653263421Sdes case SMFIS_CONTINUE: 654263421Sdes ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_CONTINUE, NULL, 0); 655263421Sdes break; 656263421Sdes case SMFIS_TEMPFAIL: 657263421Sdes case SMFIS_REJECT: 658263421Sdes if (ctx->ctx_reply != NULL && 659263421Sdes ((r == SMFIS_TEMPFAIL && *ctx->ctx_reply == '4') || 660263421Sdes (r == SMFIS_REJECT && *ctx->ctx_reply == '5'))) 661263421Sdes { 662263421Sdes ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_REPLYCODE, 663263421Sdes ctx->ctx_reply, 664117610Sdes strlen(ctx->ctx_reply) + 1); 665117610Sdes free(ctx->ctx_reply); 666117610Sdes ctx->ctx_reply = NULL; 667117610Sdes } 668117610Sdes else 669117610Sdes { 670117610Sdes ret = mi_wr_cmd(sd, timeout_ptr, r == SMFIS_REJECT ? 671263421Sdes SMFIR_REJECT : SMFIR_TEMPFAIL, NULL, 0); 672263421Sdes } 673263421Sdes break; 674263421Sdes case SMFIS_DISCARD: 675263421Sdes ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_DISCARD, NULL, 0); 676263421Sdes break; 677263421Sdes case SMFIS_ACCEPT: 678263421Sdes ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_ACCEPT, NULL, 0); 679263421Sdes break; 680263421Sdes case SMFIS_SKIP: 681263421Sdes ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_SKIP, NULL, 0); 682263421Sdes break; 683263421Sdes case _SMFIS_OPTIONS: 684117610Sdes { 685117610Sdes mi_int32 v; 686117610Sdes size_t len; 687117610Sdes char *buffer; 688117610Sdes char buf[MILTER_OPTLEN]; 689117610Sdes 690117610Sdes v = htonl(ctx->ctx_prot_vers2mta); 691263421Sdes (void) memcpy(&(buf[0]), (void *) &v, 692117610Sdes MILTER_LEN_BYTES); 693117610Sdes v = htonl(ctx->ctx_aflags); 694117610Sdes (void) memcpy(&(buf[MILTER_LEN_BYTES]), (void *) &v, 695263421Sdes MILTER_LEN_BYTES); 696117610Sdes v = htonl(ctx->ctx_pflags2mta); 697117610Sdes (void) memcpy(&(buf[MILTER_LEN_BYTES * 2]), 698117610Sdes (void *) &v, MILTER_LEN_BYTES); 699117610Sdes len = milter_addsymlist(ctx, buf, &buffer); 700117610Sdes if (buffer != NULL) 701117610Sdes ret = mi_wr_cmd(sd, timeout_ptr, SMFIC_OPTNEG, 702117610Sdes buffer, len); 703117610Sdes else 704117610Sdes ret = MI_FAILURE; 705117610Sdes } 706117610Sdes break; 707117610Sdes case SMFIS_NOREPLY: 708117610Sdes if (bit != 0 && 709117610Sdes (ctx->ctx_pflags & bit) != 0 && 710117610Sdes (ctx->ctx_mta_pflags & bit) == 0) 711117610Sdes { 712117610Sdes /* 713117610Sdes ** milter doesn't want to send a reply, 714117610Sdes ** but the MTA doesn't have that feature: fake it. 715117610Sdes */ 716117610Sdes 717117610Sdes ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_CONTINUE, NULL, 718117610Sdes 0); 719117610Sdes } 720117610Sdes break; 721117610Sdes default: /* don't send a reply */ 722117610Sdes break; 723263421Sdes } 724263421Sdes return ret; 725117610Sdes} 726263421Sdes 727117610Sdes/* 728117610Sdes** CLR_MACROS -- clear set of macros starting from a given index 729263421Sdes** 730117610Sdes** Parameters: 731117610Sdes** ctx -- context structure 732263421Sdes** m -- index from which to clear all macros 733117610Sdes** 734117610Sdes** Returns: 735263421Sdes** None. 736117610Sdes*/ 737117610Sdes 738263421Sdesvoid 739117610Sdesmi_clr_macros(ctx, m) 740117610Sdes SMFICTX_PTR ctx; 741263421Sdes int m; 742117610Sdes{ 743117610Sdes int i; 744117610Sdes 745117610Sdes for (i = m; i < MAX_MACROS_ENTRIES; i++) 746117610Sdes { 747117610Sdes if (ctx->ctx_mac_ptr[i] != NULL) 748263421Sdes { 749117610Sdes free(ctx->ctx_mac_ptr[i]); 750117610Sdes ctx->ctx_mac_ptr[i] = NULL; 751263421Sdes } 752117610Sdes if (ctx->ctx_mac_buf[i] != NULL) 753117610Sdes { 754263421Sdes free(ctx->ctx_mac_buf[i]); 755117610Sdes ctx->ctx_mac_buf[i] = NULL; 756117610Sdes } 757117610Sdes } 758117610Sdes} 759117610Sdes 760263421Sdes/* 761117610Sdes** ST_OPTIONNEG -- negotiate options 762117610Sdes** 763263421Sdes** Parameters: 764117610Sdes** g -- generic argument structure 765117610Sdes** 766263421Sdes** Returns: 767117610Sdes** abort/send options/continue 768117610Sdes*/ 769263421Sdes 770117610Sdesstatic int 771117610Sdesst_optionneg(g) 772263421Sdes genarg *g; 773117610Sdes{ 774117610Sdes mi_int32 i, v, fake_pflags; 775117610Sdes SMFICTX_PTR ctx; 776117610Sdes int (*fi_negotiate) __P((SMFICTX *, 777117610Sdes unsigned long, unsigned long, 778263421Sdes unsigned long, unsigned long, 779117610Sdes unsigned long *, unsigned long *, 780117610Sdes unsigned long *, unsigned long *)); 781263421Sdes 782117610Sdes if (g == NULL || g->a_ctx->ctx_smfi == NULL) 783117610Sdes return SMFIS_CONTINUE; 784263421Sdes ctx = g->a_ctx; 785117610Sdes mi_clr_macros(ctx, g->a_idx + 1); 786117610Sdes ctx->ctx_prot_vers = SMFI_PROT_VERSION; 787263421Sdes 788117610Sdes /* check for minimum length */ 789263421Sdes if (g->a_len < MILTER_OPTLEN) 790263421Sdes { 791117610Sdes smi_log(SMI_LOG_ERR, 792117610Sdes "%s: st_optionneg[%ld]: len too short %d < %d", 793263421Sdes ctx->ctx_smfi->xxfi_name, 794263421Sdes (long) ctx->ctx_id, (int) g->a_len, 795263421Sdes MILTER_OPTLEN); 796263421Sdes return _SMFIS_ABORT; 797263421Sdes } 798263421Sdes 799263421Sdes /* protocol version */ 800263421Sdes (void) memcpy((void *) &i, (void *) &(g->a_buf[0]), MILTER_LEN_BYTES); 801263421Sdes v = ntohl(i); 802117610Sdes 803117610Sdes#define SMFI_PROT_VERSION_MIN 2 804263421Sdes 805117610Sdes /* check for minimum version */ 806117610Sdes if (v < SMFI_PROT_VERSION_MIN) 807263421Sdes { 808117610Sdes smi_log(SMI_LOG_ERR, 809117610Sdes "%s: st_optionneg[%ld]: protocol version too old %d < %d", 810263421Sdes ctx->ctx_smfi->xxfi_name, 811263421Sdes (long) ctx->ctx_id, v, SMFI_PROT_VERSION_MIN); 812263421Sdes return _SMFIS_ABORT; 813263421Sdes } 814263421Sdes ctx->ctx_mta_prot_vers = v; 815117610Sdes if (ctx->ctx_prot_vers < ctx->ctx_mta_prot_vers) 816117610Sdes ctx->ctx_prot_vers2mta = ctx->ctx_prot_vers; 817263421Sdes else 818263421Sdes ctx->ctx_prot_vers2mta = ctx->ctx_mta_prot_vers; 819263421Sdes 820263421Sdes (void) memcpy((void *) &i, (void *) &(g->a_buf[MILTER_LEN_BYTES]), 821263421Sdes MILTER_LEN_BYTES); 822117610Sdes v = ntohl(i); 823263421Sdes 824263421Sdes /* no flags? set to default value for V1 actions */ 825263421Sdes if (v == 0) 826263421Sdes v = SMFI_V1_ACTS; 827263421Sdes ctx->ctx_mta_aflags = v; /* MTA action flags */ 828263421Sdes 829263421Sdes (void) memcpy((void *) &i, (void *) &(g->a_buf[MILTER_LEN_BYTES * 2]), 830263421Sdes MILTER_LEN_BYTES); 831117610Sdes v = ntohl(i); 832117610Sdes 833263421Sdes /* no flags? set to default value for V1 protocol */ 834263421Sdes if (v == 0) 835263421Sdes v = SMFI_V1_PROT; 836263421Sdes ctx->ctx_mta_pflags = v; /* MTA protocol flags */ 837263421Sdes 838263421Sdes /* 839263421Sdes ** Copy flags from milter struct into libmilter context; 840263421Sdes ** this variable will be used later on to check whether 841263421Sdes ** the MTA "actions" can fulfill the milter requirements, 842263421Sdes ** but it may be overwritten by the negotiate callback. 843263421Sdes */ 844263421Sdes 845263421Sdes ctx->ctx_aflags = ctx->ctx_smfi->xxfi_flags; 846117610Sdes fake_pflags = SMFIP_NR_CONN 847117610Sdes |SMFIP_NR_HELO 848263421Sdes |SMFIP_NR_MAIL 849263421Sdes |SMFIP_NR_RCPT 850263421Sdes |SMFIP_NR_DATA 851263421Sdes |SMFIP_NR_UNKN 852117610Sdes |SMFIP_NR_HDR 853117610Sdes |SMFIP_NR_EOH 854117610Sdes |SMFIP_NR_BODY 855117610Sdes ; 856117610Sdes 857263421Sdes if (g->a_ctx->ctx_smfi != NULL && 858117610Sdes g->a_ctx->ctx_smfi->xxfi_version > 4 && 859117610Sdes (fi_negotiate = g->a_ctx->ctx_smfi->xxfi_negotiate) != NULL) 860263421Sdes { 861263421Sdes int r; 862263421Sdes unsigned long m_aflags, m_pflags, m_f2, m_f3; 863263421Sdes 864117610Sdes /* 865117610Sdes ** let milter decide whether the features offered by the 866263421Sdes ** MTA are "good enough". 867117610Sdes ** Notes: 868117610Sdes ** - libmilter can "fake" some features (e.g., SMFIP_NR_HDR) 869263421Sdes ** - m_f2, m_f3 are for future extensions 870117610Sdes */ 871263421Sdes 872263421Sdes m_f2 = m_f3 = 0; 873263421Sdes m_aflags = ctx->ctx_mta_aflags; 874263421Sdes m_pflags = ctx->ctx_pflags; 875263421Sdes if ((SMFIP_SKIP & ctx->ctx_mta_pflags) != 0) 876263421Sdes m_pflags |= SMFIP_SKIP; 877263421Sdes r = fi_negotiate(g->a_ctx, 878117610Sdes ctx->ctx_mta_aflags, 879117610Sdes ctx->ctx_mta_pflags|fake_pflags, 880263421Sdes 0, 0, 881263421Sdes &m_aflags, &m_pflags, &m_f2, &m_f3); 882263421Sdes 883263421Sdes /* 884263421Sdes ** Types of protocol flags (pflags): 885263421Sdes ** 1. do NOT send protocol step X 886263421Sdes ** 2. MTA can do/understand something extra (SKIP, 887263421Sdes ** send unknown RCPTs) 888263421Sdes ** 3. MTA can deal with "no reply" for various protocol steps 889263421Sdes ** Note: this mean that it isn't possible to simply set all 890263421Sdes ** flags to get "everything": 891263421Sdes ** setting a flag of type 1 turns off a step 892263421Sdes ** (it should be the other way around: 893263421Sdes ** a flag means a protocol step can be sent) 894263421Sdes ** setting a flag of type 3 requires that milter 895263421Sdes ** never sends a reply for the corresponding step. 896263421Sdes ** Summary: the "negation" of protocol flags is causing 897263421Sdes ** problems, but at least for type 3 there is no simple 898263421Sdes ** solution. 899263421Sdes ** 900263421Sdes ** What should "all options" mean? 901263421Sdes ** send all protocol steps _except_ those for which there is 902263421Sdes ** no callback (currently registered in ctx_pflags) 903263421Sdes ** expect SKIP as return code? Yes 904263421Sdes ** send unknown RCPTs? No, 905117610Sdes ** must be explicitly requested? 906263421Sdes ** "no reply" for some protocol steps? No, 907263421Sdes ** must be explicitly requested. 908263421Sdes */ 909263421Sdes 910263421Sdes if (SMFIS_ALL_OPTS == r) 911263421Sdes { 912263421Sdes ctx->ctx_aflags = ctx->ctx_mta_aflags; 913263421Sdes ctx->ctx_pflags2mta = ctx->ctx_pflags; 914263421Sdes if ((SMFIP_SKIP & ctx->ctx_mta_pflags) != 0) 915263421Sdes ctx->ctx_pflags2mta |= SMFIP_SKIP; 916263421Sdes } 917263421Sdes else if (r != SMFIS_CONTINUE) 918263421Sdes { 919263421Sdes smi_log(SMI_LOG_ERR, 920263421Sdes "%s: st_optionneg[%ld]: xxfi_negotiate returned %d (protocol options=0x%lx, actions=0x%lx)", 921263421Sdes ctx->ctx_smfi->xxfi_name, 922263421Sdes (long) ctx->ctx_id, r, ctx->ctx_mta_pflags, 923263421Sdes ctx->ctx_mta_aflags); 924117610Sdes return _SMFIS_ABORT; 925263421Sdes } 926263421Sdes else 927263421Sdes { 928263421Sdes ctx->ctx_aflags = m_aflags; 929263421Sdes ctx->ctx_pflags = m_pflags; 930263421Sdes ctx->ctx_pflags2mta = m_pflags; 931263421Sdes } 932263421Sdes 933263421Sdes /* check whether some flags need to be "faked" */ 934263421Sdes i = ctx->ctx_pflags2mta; 935263421Sdes if ((ctx->ctx_mta_pflags & i) != i) 936263421Sdes { 937263421Sdes unsigned int idx; 938263421Sdes unsigned long b; 939117610Sdes 940263421Sdes /* 941263421Sdes ** If some behavior can be faked (set in fake_pflags), 942263421Sdes ** but the MTA doesn't support it, then unset 943263421Sdes ** that flag in the value that is sent to the MTA. 944263421Sdes */ 945117610Sdes 946263421Sdes for (idx = 0; idx < 32; idx++) 947263421Sdes { 948263421Sdes b = 1 << idx; 949117610Sdes if ((ctx->ctx_mta_pflags & b) != b && 950117610Sdes (fake_pflags & b) == b) 951117610Sdes ctx->ctx_pflags2mta &= ~b; 952263421Sdes } 953263421Sdes } 954117610Sdes } 955263421Sdes else 956117610Sdes { 957117610Sdes /* 958263421Sdes ** Set the protocol flags based on the values determined 959117610Sdes ** in mi_listener() which checked the defined callbacks. 960117610Sdes */ 961117610Sdes 962117610Sdes ctx->ctx_pflags2mta = ctx->ctx_pflags; 963117610Sdes } 964263421Sdes 965263421Sdes /* check whether actions and protocol requirements can be satisfied */ 966117610Sdes i = ctx->ctx_aflags; 967263421Sdes if ((i & ctx->ctx_mta_aflags) != i) 968263421Sdes { 969263421Sdes smi_log(SMI_LOG_ERR, 970263421Sdes "%s: st_optionneg[%ld]: 0x%lx does not fulfill action requirements 0x%x", 971263421Sdes ctx->ctx_smfi->xxfi_name, 972263421Sdes (long) ctx->ctx_id, ctx->ctx_mta_aflags, i); 973263421Sdes return _SMFIS_ABORT; 974263421Sdes } 975263421Sdes 976263421Sdes i = ctx->ctx_pflags2mta; 977263421Sdes if ((ctx->ctx_mta_pflags & i) != i) 978263421Sdes { 979117610Sdes /* 980117610Sdes ** Older MTAs do not support some protocol steps. 981117610Sdes ** As this protocol is a bit "wierd" (it asks for steps 982263421Sdes ** NOT to be taken/sent) we have to check whether we 983263421Sdes ** should turn off those "negative" requests. 984263421Sdes ** Currently these are only SMFIP_NODATA and SMFIP_NOUNKNOWN. 985117610Sdes */ 986263421Sdes 987263421Sdes if (bitset(SMFIP_NODATA, ctx->ctx_pflags2mta) && 988263421Sdes !bitset(SMFIP_NODATA, ctx->ctx_mta_pflags)) 989263421Sdes ctx->ctx_pflags2mta &= ~SMFIP_NODATA; 990263421Sdes if (bitset(SMFIP_NOUNKNOWN, ctx->ctx_pflags2mta) && 991263421Sdes !bitset(SMFIP_NOUNKNOWN, ctx->ctx_mta_pflags)) 992263421Sdes ctx->ctx_pflags2mta &= ~SMFIP_NOUNKNOWN; 993117610Sdes i = ctx->ctx_pflags2mta; 994263421Sdes } 995263421Sdes 996117610Sdes if ((ctx->ctx_mta_pflags & i) != i) 997263421Sdes { 998263421Sdes smi_log(SMI_LOG_ERR, 999117610Sdes "%s: st_optionneg[%ld]: 0x%lx does not fulfill protocol requirements 0x%x", 1000263421Sdes ctx->ctx_smfi->xxfi_name, 1001263421Sdes (long) ctx->ctx_id, ctx->ctx_mta_pflags, i); 1002117610Sdes return _SMFIS_ABORT; 1003263421Sdes } 1004263421Sdes 1005263421Sdes if (ctx->ctx_dbg > 3) 1006263421Sdes sm_dprintf("[%ld] milter_negotiate:" 1007263421Sdes " mta_actions=0x%lx, mta_flags=0x%lx" 1008263421Sdes " actions=0x%lx, flags=0x%lx\n" 1009263421Sdes , (long) ctx->ctx_id 1010263421Sdes , ctx->ctx_mta_aflags, ctx->ctx_mta_pflags 1011117610Sdes , ctx->ctx_aflags, ctx->ctx_pflags); 1012263421Sdes 1013263421Sdes return _SMFIS_OPTIONS; 1014263421Sdes} 1015263421Sdes 1016263421Sdes/* 1017117610Sdes** ST_CONNECTINFO -- receive connection information 1018117610Sdes** 1019117610Sdes** Parameters: 1020117610Sdes** g -- generic argument structure 1021117610Sdes** 1022263421Sdes** Returns: 1023117610Sdes** continue or filter-specified value 1024263421Sdes*/ 1025263421Sdes 1026263421Sdesstatic int 1027117610Sdesst_connectinfo(g) 1028263421Sdes genarg *g; 1029117610Sdes{ 1030263421Sdes size_t l; 1031117610Sdes size_t i; 1032117610Sdes char *s, family; 1033117610Sdes unsigned short port = 0; 1034117610Sdes _SOCK_ADDR sockaddr; 1035263421Sdes sfsistat (*fi_connect) __P((SMFICTX *, char *, _SOCK_ADDR *)); 1036117610Sdes 1037117610Sdes if (g == NULL) 1038263421Sdes return _SMFIS_ABORT; 1039117610Sdes mi_clr_macros(g->a_ctx, g->a_idx + 1); 1040117610Sdes if (g->a_ctx->ctx_smfi == NULL || 1041263421Sdes (fi_connect = g->a_ctx->ctx_smfi->xxfi_connect) == NULL) 1042263421Sdes return SMFIS_CONTINUE; 1043263421Sdes 1044263421Sdes s = g->a_buf; 1045263421Sdes i = 0; 1046117610Sdes l = g->a_len; 1047263421Sdes while (s[i] != '\0' && i <= l) 1048117610Sdes ++i; 1049117610Sdes if (i + 1 >= l) 1050263421Sdes return _SMFIS_ABORT; 1051117610Sdes 1052117610Sdes /* Move past trailing \0 in host string */ 1053117610Sdes i++; 1054117610Sdes family = s[i++]; 1055117610Sdes (void) memset(&sockaddr, '\0', sizeof sockaddr); 1056117610Sdes if (family != SMFIA_UNKNOWN) 1057117610Sdes { 1058263421Sdes if (i + sizeof port >= l) 1059263421Sdes { 1060263421Sdes smi_log(SMI_LOG_ERR, 1061117610Sdes "%s: connect[%ld]: wrong len %d >= %d", 1062117610Sdes g->a_ctx->ctx_smfi->xxfi_name, 1063117610Sdes (long) g->a_ctx->ctx_id, (int) i, (int) l); 1064117610Sdes return _SMFIS_ABORT; 1065117610Sdes } 1066117610Sdes (void) memcpy((void *) &port, (void *) (s + i), 1067263421Sdes sizeof port); 1068117610Sdes i += sizeof port; 1069117610Sdes 1070117610Sdes /* make sure string is terminated */ 1071117610Sdes if (s[l - 1] != '\0') 1072117610Sdes return _SMFIS_ABORT; 1073117610Sdes# if NETINET 1074117610Sdes if (family == SMFIA_INET) 1075117610Sdes { 1076117610Sdes if (inet_aton(s + i, (struct in_addr *) &sockaddr.sin.sin_addr) 1077117610Sdes != 1) 1078117610Sdes { 1079117610Sdes smi_log(SMI_LOG_ERR, 1080117610Sdes "%s: connect[%ld]: inet_aton failed", 1081117610Sdes g->a_ctx->ctx_smfi->xxfi_name, 1082117610Sdes (long) g->a_ctx->ctx_id); 1083117610Sdes return _SMFIS_ABORT; 1084117610Sdes } 1085263421Sdes sockaddr.sa.sa_family = AF_INET; 1086117610Sdes if (port > 0) 1087117610Sdes sockaddr.sin.sin_port = port; 1088263421Sdes } 1089263421Sdes else 1090263421Sdes# endif /* NETINET */ 1091263421Sdes# if NETINET6 1092263421Sdes if (family == SMFIA_INET6) 1093263421Sdes { 1094263421Sdes if (mi_inet_pton(AF_INET6, s + i, 1095117610Sdes &sockaddr.sin6.sin6_addr) != 1) 1096117610Sdes { 1097263421Sdes smi_log(SMI_LOG_ERR, 1098117610Sdes "%s: connect[%ld]: mi_inet_pton failed", 1099117610Sdes g->a_ctx->ctx_smfi->xxfi_name, 1100263421Sdes (long) g->a_ctx->ctx_id); 1101117610Sdes return _SMFIS_ABORT; 1102117610Sdes } 1103117610Sdes sockaddr.sa.sa_family = AF_INET6; 1104117610Sdes if (port > 0) 1105117610Sdes sockaddr.sin6.sin6_port = port; 1106117610Sdes } 1107263421Sdes else 1108117610Sdes# endif /* NETINET6 */ 1109117610Sdes# if NETUNIX 1110117610Sdes if (family == SMFIA_UNIX) 1111263421Sdes { 1112117610Sdes if (sm_strlcpy(sockaddr.sunix.sun_path, s + i, 1113117610Sdes sizeof sockaddr.sunix.sun_path) >= 1114263421Sdes sizeof sockaddr.sunix.sun_path) 1115117610Sdes { 1116117610Sdes smi_log(SMI_LOG_ERR, 1117263421Sdes "%s: connect[%ld]: path too long", 1118263421Sdes g->a_ctx->ctx_smfi->xxfi_name, 1119263421Sdes (long) g->a_ctx->ctx_id); 1120263421Sdes return _SMFIS_ABORT; 1121117610Sdes } 1122117610Sdes sockaddr.sunix.sun_family = AF_UNIX; 1123117610Sdes } 1124117610Sdes else 1125263421Sdes# endif /* NETUNIX */ 1126117610Sdes { 1127263421Sdes smi_log(SMI_LOG_ERR, 1128117610Sdes "%s: connect[%ld]: unknown family %d", 1129263421Sdes g->a_ctx->ctx_smfi->xxfi_name, 1130263421Sdes (long) g->a_ctx->ctx_id, family); 1131263421Sdes return _SMFIS_ABORT; 1132263421Sdes } 1133263421Sdes } 1134263421Sdes return (*fi_connect)(g->a_ctx, g->a_buf, 1135263421Sdes family != SMFIA_UNKNOWN ? &sockaddr : NULL); 1136263421Sdes} 1137263421Sdes 1138263421Sdes/* 1139263421Sdes** ST_EOH -- end of headers 1140263421Sdes** 1141117610Sdes** Parameters: 1142117610Sdes** g -- generic argument structure 1143263421Sdes** 1144117610Sdes** Returns: 1145117610Sdes** continue or filter-specified value 1146263421Sdes*/ 1147117610Sdes 1148117610Sdesstatic int 1149263421Sdesst_eoh(g) 1150117610Sdes genarg *g; 1151117610Sdes{ 1152263421Sdes sfsistat (*fi_eoh) __P((SMFICTX *)); 1153263421Sdes 1154117610Sdes if (g == NULL) 1155263421Sdes return _SMFIS_ABORT; 1156117610Sdes if (g->a_ctx->ctx_smfi != NULL && 1157117610Sdes (fi_eoh = g->a_ctx->ctx_smfi->xxfi_eoh) != NULL) 1158263421Sdes return (*fi_eoh)(g->a_ctx); 1159117610Sdes return SMFIS_CONTINUE; 1160117610Sdes} 1161263421Sdes 1162117610Sdes/* 1163117610Sdes** ST_DATA -- DATA command 1164263421Sdes** 1165117610Sdes** Parameters: 1166117610Sdes** g -- generic argument structure 1167117610Sdes** 1168117610Sdes** Returns: 1169117610Sdes** continue or filter-specified value 1170117610Sdes*/ 1171117610Sdes 1172263421Sdesstatic int 1173263421Sdesst_data(g) 1174263421Sdes genarg *g; 1175263421Sdes{ 1176263421Sdes sfsistat (*fi_data) __P((SMFICTX *)); 1177117610Sdes 1178117610Sdes if (g == NULL) 1179117610Sdes return _SMFIS_ABORT; 1180117610Sdes if (g->a_ctx->ctx_smfi != NULL && 1181263421Sdes g->a_ctx->ctx_smfi->xxfi_version > 3 && 1182117610Sdes (fi_data = g->a_ctx->ctx_smfi->xxfi_data) != NULL) 1183117610Sdes return (*fi_data)(g->a_ctx); 1184117610Sdes return SMFIS_CONTINUE; 1185263421Sdes} 1186263421Sdes 1187263421Sdes/* 1188263421Sdes** ST_HELO -- helo/ehlo command 1189263421Sdes** 1190117610Sdes** Parameters: 1191117610Sdes** g -- generic argument structure 1192117610Sdes** 1193263421Sdes** Returns: 1194117610Sdes** continue or filter-specified value 1195117610Sdes*/ 1196263421Sdes 1197117610Sdesstatic int 1198117610Sdesst_helo(g) 1199263421Sdes genarg *g; 1200117610Sdes{ 1201117610Sdes sfsistat (*fi_helo) __P((SMFICTX *, char *)); 1202263421Sdes 1203117610Sdes if (g == NULL) 1204263421Sdes return _SMFIS_ABORT; 1205117610Sdes mi_clr_macros(g->a_ctx, g->a_idx + 1); 1206263421Sdes if (g->a_ctx->ctx_smfi != NULL && 1207117610Sdes (fi_helo = g->a_ctx->ctx_smfi->xxfi_helo) != NULL) 1208117610Sdes { 1209263421Sdes /* paranoia: check for terminating '\0' */ 1210117610Sdes if (g->a_len == 0 || g->a_buf[g->a_len - 1] != '\0') 1211117610Sdes return MI_FAILURE; 1212263421Sdes return (*fi_helo)(g->a_ctx, g->a_buf); 1213117610Sdes } 1214117610Sdes return SMFIS_CONTINUE; 1215263421Sdes} 1216263421Sdes 1217263421Sdes/* 1218263421Sdes** ST_HEADER -- header line 1219263421Sdes** 1220263421Sdes** Parameters: 1221263421Sdes** g -- generic argument structure 1222117610Sdes** 1223117610Sdes** Returns: 1224263421Sdes** continue or filter-specified value 1225117610Sdes*/ 1226117610Sdes 1227263421Sdesstatic int 1228117610Sdesst_header(g) 1229117610Sdes genarg *g; 1230263421Sdes{ 1231263421Sdes char *hf, *hv; 1232263421Sdes sfsistat (*fi_header) __P((SMFICTX *, char *, char *)); 1233263421Sdes 1234263421Sdes if (g == NULL) 1235263421Sdes return _SMFIS_ABORT; 1236263421Sdes if (g->a_ctx->ctx_smfi == NULL || 1237263421Sdes (fi_header = g->a_ctx->ctx_smfi->xxfi_header) == NULL) 1238263421Sdes return SMFIS_CONTINUE; 1239263421Sdes if (dec_arg2(g->a_buf, g->a_len, &hf, &hv) == MI_SUCCESS) 1240117610Sdes return (*fi_header)(g->a_ctx, hf, hv); 1241117610Sdes else 1242263421Sdes return _SMFIS_ABORT; 1243117610Sdes} 1244117610Sdes 1245263421Sdes#define ARGV_FCT(lf, rf, idx) \ 1246117610Sdes char **argv; \ 1247263421Sdes sfsistat (*lf) __P((SMFICTX *, char **)); \ 1248263421Sdes int r; \ 1249263421Sdes \ 1250263421Sdes if (g == NULL) \ 1251263421Sdes return _SMFIS_ABORT; \ 1252263421Sdes mi_clr_macros(g->a_ctx, g->a_idx + 1); \ 1253263421Sdes if (g->a_ctx->ctx_smfi == NULL || \ 1254263421Sdes (lf = g->a_ctx->ctx_smfi->rf) == NULL) \ 1255263421Sdes return SMFIS_CONTINUE; \ 1256263421Sdes if ((argv = dec_argv(g->a_buf, g->a_len)) == NULL) \ 1257263421Sdes return _SMFIS_ABORT; \ 1258263421Sdes r = (*lf)(g->a_ctx, argv); \ 1259263421Sdes free(argv); \ 1260263421Sdes return r; 1261263421Sdes 1262263421Sdes/* 1263117610Sdes** ST_SENDER -- MAIL FROM command 1264263421Sdes** 1265117610Sdes** Parameters: 1266117610Sdes** g -- generic argument structure 1267117610Sdes** 1268117610Sdes** Returns: 1269117610Sdes** continue or filter-specified value 1270117610Sdes*/ 1271117610Sdes 1272263421Sdesstatic int 1273117610Sdesst_sender(g) 1274117610Sdes genarg *g; 1275263421Sdes{ 1276263421Sdes ARGV_FCT(fi_envfrom, xxfi_envfrom, CI_MAIL) 1277263421Sdes} 1278263421Sdes 1279263421Sdes/* 1280263421Sdes** ST_RCPT -- RCPT TO command 1281263421Sdes** 1282263421Sdes** Parameters: 1283117610Sdes** g -- generic argument structure 1284263421Sdes** 1285117610Sdes** Returns: 1286117610Sdes** continue or filter-specified value 1287263421Sdes*/ 1288117610Sdes 1289117610Sdesstatic int 1290263421Sdesst_rcpt(g) 1291117610Sdes genarg *g; 1292117610Sdes{ 1293263421Sdes ARGV_FCT(fi_envrcpt, xxfi_envrcpt, CI_RCPT) 1294117610Sdes} 1295117610Sdes 1296117610Sdes/* 1297117610Sdes** ST_UNKNOWN -- unrecognized or unimplemented command 1298117610Sdes** 1299117610Sdes** Parameters: 1300117610Sdes** g -- generic argument structure 1301117610Sdes** 1302117610Sdes** Returns: 1303117610Sdes** continue or filter-specified value 1304263421Sdes*/ 1305117610Sdes 1306117610Sdesstatic int 1307263421Sdesst_unknown(g) 1308117610Sdes genarg *g; 1309117610Sdes{ 1310263421Sdes sfsistat (*fi_unknown) __P((SMFICTX *, const char *)); 1311117610Sdes 1312117610Sdes if (g == NULL) 1313263421Sdes return _SMFIS_ABORT; 1314117610Sdes if (g->a_ctx->ctx_smfi != NULL && 1315117610Sdes g->a_ctx->ctx_smfi->xxfi_version > 2 && 1316263421Sdes (fi_unknown = g->a_ctx->ctx_smfi->xxfi_unknown) != NULL) 1317117610Sdes return (*fi_unknown)(g->a_ctx, (const char *) g->a_buf); 1318117610Sdes return SMFIS_CONTINUE; 1319263421Sdes} 1320117610Sdes 1321117610Sdes/* 1322263421Sdes** ST_MACROS -- deal with macros received from the MTA 1323117610Sdes** 1324263421Sdes** Parameters: 1325263421Sdes** g -- generic argument structure 1326263421Sdes** 1327263421Sdes** Returns: 1328263421Sdes** continue/keep 1329263421Sdes** 1330263421Sdes** Side effects: 1331263421Sdes** set pointer in macro array to current values. 1332263421Sdes*/ 1333263421Sdes 1334263421Sdesstatic int 1335263421Sdesst_macros(g) 1336263421Sdes genarg *g; 1337263421Sdes{ 1338263421Sdes int i; 1339263421Sdes char **argv; 1340263421Sdes 1341263421Sdes if (g == NULL || g->a_len < 1) 1342263421Sdes return _SMFIS_FAIL; 1343263421Sdes if ((argv = dec_argv(g->a_buf + 1, g->a_len - 1)) == NULL) 1344263421Sdes return _SMFIS_FAIL; 1345263421Sdes switch (g->a_buf[0]) 1346263421Sdes { 1347263421Sdes case SMFIC_CONNECT: 1348263421Sdes i = CI_CONN; 1349263421Sdes break; 1350263421Sdes case SMFIC_HELO: 1351117610Sdes i = CI_HELO; 1352117610Sdes break; 1353117610Sdes case SMFIC_MAIL: 1354117610Sdes i = CI_MAIL; 1355117610Sdes break; 1356117610Sdes case SMFIC_RCPT: 1357117610Sdes i = CI_RCPT; 1358117610Sdes break; 1359117610Sdes case SMFIC_DATA: 1360117610Sdes i = CI_DATA; 1361117610Sdes break; 1362117610Sdes case SMFIC_BODYEOB: 1363117610Sdes i = CI_EOM; 1364117610Sdes break; 1365117610Sdes case SMFIC_EOH: 1366117610Sdes i = CI_EOH; 1367117610Sdes break; 1368117610Sdes default: 1369117610Sdes free(argv); 1370263421Sdes return _SMFIS_FAIL; 1371117610Sdes } 1372263421Sdes if (g->a_ctx->ctx_mac_ptr[i] != NULL) 1373117610Sdes free(g->a_ctx->ctx_mac_ptr[i]); 1374263421Sdes if (g->a_ctx->ctx_mac_buf[i] != NULL) 1375117610Sdes free(g->a_ctx->ctx_mac_buf[i]); 1376117610Sdes g->a_ctx->ctx_mac_ptr[i] = argv; 1377117610Sdes g->a_ctx->ctx_mac_buf[i] = g->a_buf; 1378117610Sdes return _SMFIS_KEEP; 1379263421Sdes} 1380117610Sdes 1381117610Sdes/* 1382117610Sdes** ST_QUIT -- quit command 1383117610Sdes** 1384117610Sdes** Parameters: 1385117610Sdes** g -- generic argument structure 1386117610Sdes** 1387117610Sdes** Returns: 1388117610Sdes** noreply 1389117610Sdes*/ 1390117610Sdes 1391117610Sdes/* ARGSUSED */ 1392117610Sdesstatic int 1393117610Sdesst_quit(g) 1394117610Sdes genarg *g; 1395117610Sdes{ 1396117610Sdes sfsistat (*fi_close) __P((SMFICTX *)); 1397117610Sdes 1398117610Sdes if (g == NULL) 1399117610Sdes return _SMFIS_ABORT; 1400117610Sdes if (g->a_ctx->ctx_smfi != NULL && 1401117610Sdes (fi_close = g->a_ctx->ctx_smfi->xxfi_close) != NULL) 1402117610Sdes (void) (*fi_close)(g->a_ctx); 1403117610Sdes mi_clr_macros(g->a_ctx, 0); 1404117610Sdes return _SMFIS_NOREPLY; 1405117610Sdes} 1406117610Sdes 1407117610Sdes/* 1408117610Sdes** ST_BODYCHUNK -- deal with a piece of the mail body 1409117610Sdes** 1410117610Sdes** Parameters: 1411117610Sdes** g -- generic argument structure 1412117610Sdes** 1413117610Sdes** Returns: 1414117610Sdes** continue or filter-specified value 1415117610Sdes*/ 1416117610Sdes 1417117610Sdesstatic int 1418117610Sdesst_bodychunk(g) 1419117610Sdes genarg *g; 1420117610Sdes{ 1421117610Sdes sfsistat (*fi_body) __P((SMFICTX *, unsigned char *, size_t)); 1422117610Sdes 1423117610Sdes if (g == NULL) 1424117610Sdes return _SMFIS_ABORT; 1425117610Sdes if (g->a_ctx->ctx_smfi != NULL && 1426117610Sdes (fi_body = g->a_ctx->ctx_smfi->xxfi_body) != NULL) 1427117610Sdes return (*fi_body)(g->a_ctx, (unsigned char *)g->a_buf, 1428117610Sdes g->a_len); 1429117610Sdes return SMFIS_CONTINUE; 1430117610Sdes} 1431117610Sdes 1432117610Sdes/* 1433117610Sdes** ST_BODYEND -- deal with the last piece of the mail body 1434117610Sdes** 1435117610Sdes** Parameters: 1436117610Sdes** g -- generic argument structure 1437117610Sdes** 1438117610Sdes** Returns: 1439117610Sdes** continue or filter-specified value 1440117610Sdes** 1441117610Sdes** Side effects: 1442117610Sdes** sends a reply for the body part (if non-empty). 1443117610Sdes*/ 1444117610Sdes 1445117610Sdesstatic int 1446117610Sdesst_bodyend(g) 1447117610Sdes genarg *g; 1448117610Sdes{ 1449117610Sdes sfsistat r; 1450117610Sdes sfsistat (*fi_body) __P((SMFICTX *, unsigned char *, size_t)); 1451117610Sdes sfsistat (*fi_eom) __P((SMFICTX *)); 1452117610Sdes 1453117610Sdes if (g == NULL) 1454117610Sdes return _SMFIS_ABORT; 1455117610Sdes r = SMFIS_CONTINUE; 1456117610Sdes if (g->a_ctx->ctx_smfi != NULL) 1457117610Sdes { 1458117610Sdes if ((fi_body = g->a_ctx->ctx_smfi->xxfi_body) != NULL && 1459117610Sdes g->a_len > 0) 1460117610Sdes { 1461117610Sdes socket_t sd; 1462117610Sdes struct timeval timeout; 1463117610Sdes 1464117610Sdes timeout.tv_sec = g->a_ctx->ctx_timeout; 1465117610Sdes timeout.tv_usec = 0; 1466117610Sdes sd = g->a_ctx->ctx_sd; 1467117610Sdes r = (*fi_body)(g->a_ctx, (unsigned char *)g->a_buf, 1468263421Sdes g->a_len); 1469263421Sdes if (r != SMFIS_CONTINUE && 1470117610Sdes sendreply(r, sd, &timeout, g->a_ctx) != MI_SUCCESS) 1471117610Sdes return _SMFIS_ABORT; 1472117610Sdes } 1473263421Sdes } 1474117610Sdes if (r == SMFIS_CONTINUE && 1475117610Sdes (fi_eom = g->a_ctx->ctx_smfi->xxfi_eom) != NULL) 1476117610Sdes return (*fi_eom)(g->a_ctx); 1477117610Sdes return r; 1478117610Sdes} 1479117610Sdes 1480117610Sdes/* 1481117610Sdes** ST_ABORTFCT -- deal with aborts 1482263421Sdes** 1483117610Sdes** Parameters: 1484117610Sdes** g -- generic argument structure 1485117610Sdes** 1486117610Sdes** Returns: 1487117610Sdes** abort or filter-specified value 1488263421Sdes*/ 1489117610Sdes 1490117610Sdesstatic int 1491263421Sdesst_abortfct(g) 1492117610Sdes genarg *g; 1493117610Sdes{ 1494263421Sdes sfsistat (*fi_abort) __P((SMFICTX *)); 1495117610Sdes 1496117610Sdes if (g == NULL) 1497263421Sdes return _SMFIS_ABORT; 1498117610Sdes if (g != NULL && g->a_ctx->ctx_smfi != NULL && 1499117610Sdes (fi_abort = g->a_ctx->ctx_smfi->xxfi_abort) != NULL) 1500117610Sdes (void) (*fi_abort)(g->a_ctx); 1501117610Sdes return _SMFIS_NOREPLY; 1502117610Sdes} 1503117610Sdes 1504117610Sdes/* 1505117610Sdes** TRANS_OK -- is the state transition ok? 1506117610Sdes** 1507117610Sdes** Parameters: 1508263421Sdes** old -- old state 1509263421Sdes** new -- new state 1510263421Sdes** 1511117610Sdes** Returns: 1512117610Sdes** state transition ok 1513117610Sdes*/ 1514117610Sdes 1515117610Sdesstatic bool 1516117610Sdestrans_ok(old, new) 1517117610Sdes int old, new; 1518117610Sdes{ 1519117610Sdes int s, n; 1520117610Sdes 1521117610Sdes s = old; 1522117610Sdes if (s >= SIZE_NEXT_STATES) 1523117610Sdes return false; 1524117610Sdes do 1525117610Sdes { 1526117610Sdes /* is this state transition allowed? */ 1527117610Sdes if ((MI_MASK(new) & next_states[s]) != 0) 1528117610Sdes return true; 1529117610Sdes 1530117610Sdes /* 1531117610Sdes ** no: try next state; 1532117610Sdes ** this works since the relevant states are ordered 1533117610Sdes ** strict sequentially 1534117610Sdes */ 1535117610Sdes 1536117610Sdes n = s + 1; 1537117610Sdes if (n >= SIZE_NEXT_STATES) 1538117610Sdes return false; 1539117610Sdes 1540117610Sdes /* 1541117610Sdes ** can we actually "skip" this state? 1542117610Sdes ** see fix_stm() which sets this bit for those 1543117610Sdes ** states which the filter program is not interested in 1544117610Sdes */ 1545117610Sdes 1546117610Sdes if (bitset(NX_SKIP, next_states[n])) 1547117610Sdes s = n; 1548 else 1549 return false; 1550 } while (s < SIZE_NEXT_STATES); 1551 return false; 1552} 1553 1554/* 1555** FIX_STM -- add "skip" bits to the state transition table 1556** 1557** Parameters: 1558** ctx -- context structure 1559** 1560** Returns: 1561** None. 1562** 1563** Side effects: 1564** may change state transition table. 1565*/ 1566 1567static void 1568fix_stm(ctx) 1569 SMFICTX_PTR ctx; 1570{ 1571 unsigned long fl; 1572 1573 if (ctx == NULL || ctx->ctx_smfi == NULL) 1574 return; 1575 fl = ctx->ctx_pflags; 1576 if (bitset(SMFIP_NOCONNECT, fl)) 1577 next_states[ST_CONN] |= NX_SKIP; 1578 if (bitset(SMFIP_NOHELO, fl)) 1579 next_states[ST_HELO] |= NX_SKIP; 1580 if (bitset(SMFIP_NOMAIL, fl)) 1581 next_states[ST_MAIL] |= NX_SKIP; 1582 if (bitset(SMFIP_NORCPT, fl)) 1583 next_states[ST_RCPT] |= NX_SKIP; 1584 if (bitset(SMFIP_NOHDRS, fl)) 1585 next_states[ST_HDRS] |= NX_SKIP; 1586 if (bitset(SMFIP_NOEOH, fl)) 1587 next_states[ST_EOHS] |= NX_SKIP; 1588 if (bitset(SMFIP_NOBODY, fl)) 1589 next_states[ST_BODY] |= NX_SKIP; 1590 if (bitset(SMFIP_NODATA, fl)) 1591 next_states[ST_DATA] |= NX_SKIP; 1592 if (bitset(SMFIP_NOUNKNOWN, fl)) 1593 next_states[ST_UNKN] |= NX_SKIP; 1594} 1595 1596/* 1597** DEC_ARGV -- split a buffer into a list of strings, NULL terminated 1598** 1599** Parameters: 1600** buf -- buffer with several strings 1601** len -- length of buffer 1602** 1603** Returns: 1604** array of pointers to the individual strings 1605*/ 1606 1607static char ** 1608dec_argv(buf, len) 1609 char *buf; 1610 size_t len; 1611{ 1612 char **s; 1613 size_t i; 1614 int elem, nelem; 1615 1616 nelem = 0; 1617 for (i = 0; i < len; i++) 1618 { 1619 if (buf[i] == '\0') 1620 ++nelem; 1621 } 1622 if (nelem == 0) 1623 return NULL; 1624 1625 /* last entry is only for the name */ 1626 s = (char **)malloc((nelem + 1) * (sizeof *s)); 1627 if (s == NULL) 1628 return NULL; 1629 s[0] = buf; 1630 for (i = 0, elem = 0; i < len && elem < nelem; i++) 1631 { 1632 if (buf[i] == '\0') 1633 { 1634 ++elem; 1635 if (i + 1 >= len) 1636 s[elem] = NULL; 1637 else 1638 s[elem] = &(buf[i + 1]); 1639 } 1640 } 1641 1642 /* overwrite last entry (already done above, just paranoia) */ 1643 s[elem] = NULL; 1644 return s; 1645} 1646 1647/* 1648** DEC_ARG2 -- split a buffer into two strings 1649** 1650** Parameters: 1651** buf -- buffer with two strings 1652** len -- length of buffer 1653** s1,s2 -- pointer to result strings 1654** 1655** Returns: 1656** MI_FAILURE/MI_SUCCESS 1657*/ 1658 1659static int 1660dec_arg2(buf, len, s1, s2) 1661 char *buf; 1662 size_t len; 1663 char **s1; 1664 char **s2; 1665{ 1666 size_t i; 1667 1668 /* paranoia: check for terminating '\0' */ 1669 if (len == 0 || buf[len - 1] != '\0') 1670 return MI_FAILURE; 1671 *s1 = buf; 1672 for (i = 1; i < len && buf[i] != '\0'; i++) 1673 continue; 1674 if (i >= len - 1) 1675 return MI_FAILURE; 1676 *s2 = buf + i + 1; 1677 return MI_SUCCESS; 1678} 1679 1680/* 1681** SENDOK -- is it ok for the filter to send stuff to the MTA? 1682** 1683** Parameters: 1684** ctx -- context structure 1685** flag -- flag to check 1686** 1687** Returns: 1688** sending allowed (in current state) 1689*/ 1690 1691bool 1692mi_sendok(ctx, flag) 1693 SMFICTX_PTR ctx; 1694 int flag; 1695{ 1696 if (ctx == NULL || ctx->ctx_smfi == NULL) 1697 return false; 1698 1699 /* did the milter request this operation? */ 1700 if (flag != 0 && !bitset(flag, ctx->ctx_aflags)) 1701 return false; 1702 1703 /* are we in the correct state? It must be "End of Message". */ 1704 return ctx->ctx_state == ST_ENDM; 1705} 1706 1707#if _FFR_WORKERS_POOL 1708/* 1709** MI_RD_SOCKET_READY - checks if the socket is ready for read(2) 1710** 1711** Parameters: 1712** sd -- socket_t 1713** 1714** Returns: 1715** true iff socket is ready for read(2) 1716*/ 1717 1718#define MI_RD_CMD_TO 1 1719#define MI_RD_MAX_ERR 16 1720 1721static bool 1722mi_rd_socket_ready (sd) 1723 socket_t sd; 1724{ 1725 int n; 1726 int nerr = 0; 1727#if SM_CONF_POLL 1728 struct pollfd pfd; 1729#else /* SM_CONF_POLL */ 1730 fd_set rd_set, exc_set; 1731#endif /* SM_CONF_POLL */ 1732 1733 do 1734 { 1735#if SM_CONF_POLL 1736 pfd.fd = sd; 1737 pfd.events = POLLIN; 1738 pfd.revents = 0; 1739 1740 n = poll(&pfd, 1, MI_RD_CMD_TO); 1741#else /* SM_CONF_POLL */ 1742 struct timeval timeout; 1743 1744 FD_ZERO(&rd_set); 1745 FD_ZERO(&exc_set); 1746 FD_SET(sd, &rd_set); 1747 FD_SET(sd, &exc_set); 1748 1749 timeout.tv_sec = MI_RD_CMD_TO / 1000; 1750 timeout.tv_usec = 0; 1751 n = select(sd + 1, &rd_set, NULL, &exc_set, &timeout); 1752#endif /* SM_CONF_POLL */ 1753 1754 if (n < 0) 1755 { 1756 if (errno == EINTR) 1757 { 1758 nerr++; 1759 continue; 1760 } 1761 return true; 1762 } 1763 1764 if (n == 0) 1765 return false; 1766 break; 1767 } while (nerr < MI_RD_MAX_ERR); 1768 if (nerr >= MI_RD_MAX_ERR) 1769 return false; 1770 1771#if SM_CONF_POLL 1772 return (pfd.revents != 0); 1773#else /* SM_CONF_POLL */ 1774 return FD_ISSET(sd, &rd_set) || FD_ISSET(sd, &exc_set); 1775#endif /* SM_CONF_POLL */ 1776} 1777#endif /* _FFR_WORKERS_POOL */ 1778