164562Sgshapiro/* 2261363Sgshapiro * Copyright (c) 1999-2004, 2006-2008 Proofpoint, Inc. and its suppliers. 364562Sgshapiro * All rights reserved. 464562Sgshapiro * 564562Sgshapiro * By using this file, you agree to the terms and conditions set 664562Sgshapiro * forth in the LICENSE file which can be found at the top level of 764562Sgshapiro * the sendmail distribution. 864562Sgshapiro * 964562Sgshapiro */ 1064562Sgshapiro 1190792Sgshapiro#include <sm/gen.h> 12266692SgshapiroSM_RCSID("@(#)$Id: engine.c,v 8.168 2013-11-22 20:51:36 ca Exp $") 1364562Sgshapiro 1464562Sgshapiro#include "libmilter.h" 1564562Sgshapiro 1664562Sgshapiro#if NETINET || NETINET6 1764562Sgshapiro# include <arpa/inet.h> 1864562Sgshapiro#endif /* NETINET || NETINET6 */ 1964562Sgshapiro 2064562Sgshapiro/* generic argument for functions in the command table */ 2164562Sgshapirostruct arg_struct 2264562Sgshapiro{ 2364562Sgshapiro size_t a_len; /* length of buffer */ 2464562Sgshapiro char *a_buf; /* argument string */ 2564562Sgshapiro int a_idx; /* index for macro array */ 2664562Sgshapiro SMFICTX_PTR a_ctx; /* context */ 2764562Sgshapiro}; 2864562Sgshapiro 2964562Sgshapirotypedef struct arg_struct genarg; 3064562Sgshapiro 3164562Sgshapiro/* structure for commands received from MTA */ 3264562Sgshapirostruct cmdfct_t 3364562Sgshapiro{ 3464562Sgshapiro char cm_cmd; /* command */ 3564562Sgshapiro int cm_argt; /* type of arguments expected */ 3664562Sgshapiro int cm_next; /* next state */ 3764562Sgshapiro int cm_todo; /* what to do next */ 3864562Sgshapiro int cm_macros; /* index for macros */ 3964562Sgshapiro int (*cm_fct) __P((genarg *)); /* function to execute */ 4064562Sgshapiro}; 4164562Sgshapiro 4264562Sgshapirotypedef struct cmdfct_t cmdfct; 4364562Sgshapiro 4464562Sgshapiro/* possible values for cm_argt */ 45285303Sgshapiro#define CM_BUF 0 46285303Sgshapiro#define CM_NULLOK 1 4764562Sgshapiro 4864562Sgshapiro/* possible values for cm_todo */ 4964562Sgshapiro#define CT_CONT 0x0000 /* continue reading commands */ 5064562Sgshapiro#define CT_IGNO 0x0001 /* continue even when error */ 5164562Sgshapiro 5264562Sgshapiro/* not needed right now, done via return code instead */ 5364562Sgshapiro#define CT_KEEP 0x0004 /* keep buffer (contains symbols) */ 54168515Sgshapiro#define CT_END 0x0008 /* last command of session, stop replying */ 5564562Sgshapiro 5664562Sgshapiro/* index in macro array: macros only for these commands */ 57125820Sgshapiro#define CI_NONE (-1) 58125820Sgshapiro#define CI_CONN 0 59125820Sgshapiro#define CI_HELO 1 60125820Sgshapiro#define CI_MAIL 2 61125820Sgshapiro#define CI_RCPT 3 62168515Sgshapiro#define CI_DATA 4 63168515Sgshapiro#define CI_EOM 5 64168515Sgshapiro#define CI_EOH 6 65168515Sgshapiro#define CI_LAST CI_EOH 66168515Sgshapiro#if CI_LAST < CI_DATA 67168515SgshapiroERROR: do not compile with CI_LAST < CI_DATA 68132943Sgshapiro#endif 69168515Sgshapiro#if CI_LAST < CI_EOM 70168515SgshapiroERROR: do not compile with CI_LAST < CI_EOM 71168515Sgshapiro#endif 72168515Sgshapiro#if CI_LAST < CI_EOH 73168515SgshapiroERROR: do not compile with CI_LAST < CI_EOH 74168515Sgshapiro#endif 75168515Sgshapiro#if CI_LAST < CI_ENVRCPT 76168515SgshapiroERROR: do not compile with CI_LAST < CI_ENVRCPT 77168515Sgshapiro#endif 78168515Sgshapiro#if CI_LAST < CI_ENVFROM 79168515SgshapiroERROR: do not compile with CI_LAST < CI_ENVFROM 80168515Sgshapiro#endif 81168515Sgshapiro#if CI_LAST < CI_HELO 82168515SgshapiroERROR: do not compile with CI_LAST < CI_HELO 83168515Sgshapiro#endif 84168515Sgshapiro#if CI_LAST < CI_CONNECT 85168515SgshapiroERROR: do not compile with CI_LAST < CI_CONNECT 86168515Sgshapiro#endif 87168515Sgshapiro#if CI_LAST >= MAX_MACROS_ENTRIES 88168515SgshapiroERROR: do not compile with CI_LAST >= MAX_MACROS_ENTRIES 89168515Sgshapiro#endif 9064562Sgshapiro 9164562Sgshapiro/* function prototypes */ 9264562Sgshapirostatic int st_abortfct __P((genarg *)); 9364562Sgshapirostatic int st_macros __P((genarg *)); 9464562Sgshapirostatic int st_optionneg __P((genarg *)); 9564562Sgshapirostatic int st_bodychunk __P((genarg *)); 9664562Sgshapirostatic int st_connectinfo __P((genarg *)); 9764562Sgshapirostatic int st_bodyend __P((genarg *)); 9864562Sgshapirostatic int st_helo __P((genarg *)); 9964562Sgshapirostatic int st_header __P((genarg *)); 10064562Sgshapirostatic int st_sender __P((genarg *)); 10164562Sgshapirostatic int st_rcpt __P((genarg *)); 102132943Sgshapirostatic int st_unknown __P((genarg *)); 103132943Sgshapirostatic int st_data __P((genarg *)); 10464562Sgshapirostatic int st_eoh __P((genarg *)); 10564562Sgshapirostatic int st_quit __P((genarg *)); 10664562Sgshapirostatic int sendreply __P((sfsistat, socket_t, struct timeval *, SMFICTX_PTR)); 10764562Sgshapirostatic void fix_stm __P((SMFICTX_PTR)); 10864562Sgshapirostatic bool trans_ok __P((int, int)); 10964562Sgshapirostatic char **dec_argv __P((char *, size_t)); 11064562Sgshapirostatic int dec_arg2 __P((char *, size_t, char **, char **)); 111203004Sgshapirostatic void mi_clr_symlist __P((SMFICTX_PTR)); 11264562Sgshapiro 113168515Sgshapiro#if _FFR_WORKERS_POOL 114168515Sgshapirostatic bool mi_rd_socket_ready __P((int)); 115168515Sgshapiro#endif /* _FFR_WORKERS_POOL */ 116168515Sgshapiro 11764562Sgshapiro/* states */ 11864562Sgshapiro#define ST_NONE (-1) 11964562Sgshapiro#define ST_INIT 0 /* initial state */ 12064562Sgshapiro#define ST_OPTS 1 /* option negotiation */ 12164562Sgshapiro#define ST_CONN 2 /* connection info */ 12264562Sgshapiro#define ST_HELO 3 /* helo */ 12364562Sgshapiro#define ST_MAIL 4 /* mail from */ 12464562Sgshapiro#define ST_RCPT 5 /* rcpt to */ 125132943Sgshapiro#define ST_DATA 6 /* data */ 126132943Sgshapiro#define ST_HDRS 7 /* headers */ 127132943Sgshapiro#define ST_EOHS 8 /* end of headers */ 128132943Sgshapiro#define ST_BODY 9 /* body */ 129132943Sgshapiro#define ST_ENDM 10 /* end of message */ 130132943Sgshapiro#define ST_QUIT 11 /* quit */ 131132943Sgshapiro#define ST_ABRT 12 /* abort */ 132132943Sgshapiro#define ST_UNKN 13 /* unknown SMTP command */ 133168515Sgshapiro#define ST_Q_NC 14 /* quit, new connection follows */ 134168515Sgshapiro#define ST_LAST ST_Q_NC /* last valid state */ 135168515Sgshapiro#define ST_SKIP 16 /* not a state but required for the state table */ 13664562Sgshapiro 13764562Sgshapiro/* in a mail transaction? must be before eom according to spec. */ 13864562Sgshapiro#define ST_IN_MAIL(st) ((st) >= ST_MAIL && (st) < ST_ENDM) 13964562Sgshapiro 14064562Sgshapiro/* 14164562Sgshapiro** set of next states 14264562Sgshapiro** each state (ST_*) corresponds to bit in an int value (1 << state) 14364562Sgshapiro** each state has a set of allowed transitions ('or' of bits of states) 14464562Sgshapiro** so a state transition is valid if the mask of the next state 14564562Sgshapiro** is set in the NX_* value 14664562Sgshapiro** this function is coded in trans_ok(), see below. 14764562Sgshapiro*/ 14890792Sgshapiro 149110560Sgshapiro#define MI_MASK(x) (0x0001 << (x)) /* generate a bit "mask" for a state */ 150110560Sgshapiro#define NX_INIT (MI_MASK(ST_OPTS)) 151132943Sgshapiro#define NX_OPTS (MI_MASK(ST_CONN) | MI_MASK(ST_UNKN)) 152132943Sgshapiro#define NX_CONN (MI_MASK(ST_HELO) | MI_MASK(ST_MAIL) | MI_MASK(ST_UNKN)) 153132943Sgshapiro#define NX_HELO (MI_MASK(ST_HELO) | MI_MASK(ST_MAIL) | MI_MASK(ST_UNKN)) 154132943Sgshapiro#define NX_MAIL (MI_MASK(ST_RCPT) | MI_MASK(ST_ABRT) | MI_MASK(ST_UNKN)) 155132943Sgshapiro#define NX_RCPT (MI_MASK(ST_HDRS) | MI_MASK(ST_EOHS) | MI_MASK(ST_DATA) | \ 156110560Sgshapiro MI_MASK(ST_BODY) | MI_MASK(ST_ENDM) | \ 157132943Sgshapiro MI_MASK(ST_RCPT) | MI_MASK(ST_ABRT) | MI_MASK(ST_UNKN)) 158132943Sgshapiro#define NX_DATA (MI_MASK(ST_EOHS) | MI_MASK(ST_HDRS) | MI_MASK(ST_ABRT)) 159110560Sgshapiro#define NX_HDRS (MI_MASK(ST_EOHS) | MI_MASK(ST_HDRS) | MI_MASK(ST_ABRT)) 160110560Sgshapiro#define NX_EOHS (MI_MASK(ST_BODY) | MI_MASK(ST_ENDM) | MI_MASK(ST_ABRT)) 161110560Sgshapiro#define NX_BODY (MI_MASK(ST_ENDM) | MI_MASK(ST_BODY) | MI_MASK(ST_ABRT)) 162168515Sgshapiro#define NX_ENDM (MI_MASK(ST_QUIT) | MI_MASK(ST_MAIL) | MI_MASK(ST_UNKN) | \ 163168515Sgshapiro MI_MASK(ST_Q_NC)) 16464562Sgshapiro#define NX_QUIT 0 16564562Sgshapiro#define NX_ABRT 0 166132943Sgshapiro#define NX_UNKN (MI_MASK(ST_HELO) | MI_MASK(ST_MAIL) | \ 167132943Sgshapiro MI_MASK(ST_RCPT) | MI_MASK(ST_ABRT) | \ 168132943Sgshapiro MI_MASK(ST_DATA) | \ 169132943Sgshapiro MI_MASK(ST_BODY) | MI_MASK(ST_UNKN) | \ 170168515Sgshapiro MI_MASK(ST_ABRT) | MI_MASK(ST_QUIT) | MI_MASK(ST_Q_NC)) 171168515Sgshapiro#define NX_Q_NC (MI_MASK(ST_CONN) | MI_MASK(ST_UNKN)) 172110560Sgshapiro#define NX_SKIP MI_MASK(ST_SKIP) 17364562Sgshapiro 17464562Sgshapirostatic int next_states[] = 17564562Sgshapiro{ 176168515Sgshapiro NX_INIT 177168515Sgshapiro , NX_OPTS 178168515Sgshapiro , NX_CONN 179168515Sgshapiro , NX_HELO 180168515Sgshapiro , NX_MAIL 181168515Sgshapiro , NX_RCPT 182168515Sgshapiro , NX_DATA 183168515Sgshapiro , NX_HDRS 184168515Sgshapiro , NX_EOHS 185168515Sgshapiro , NX_BODY 186168515Sgshapiro , NX_ENDM 187168515Sgshapiro , NX_QUIT 188168515Sgshapiro , NX_ABRT 189168515Sgshapiro , NX_UNKN 190168515Sgshapiro , NX_Q_NC 19164562Sgshapiro}; 19264562Sgshapiro 193159609Sgshapiro#define SIZE_NEXT_STATES (sizeof(next_states) / sizeof(next_states[0])) 194159609Sgshapiro 19564562Sgshapiro/* commands received by milter */ 19664562Sgshapirostatic cmdfct cmds[] = 19764562Sgshapiro{ 198285303Sgshapiro {SMFIC_ABORT, CM_NULLOK, ST_ABRT, CT_CONT, CI_NONE, st_abortfct} 199285303Sgshapiro, {SMFIC_MACRO, CM_BUF, ST_NONE, CT_KEEP, CI_NONE, st_macros } 200285303Sgshapiro, {SMFIC_BODY, CM_BUF, ST_BODY, CT_CONT, CI_NONE, st_bodychunk} 201285303Sgshapiro, {SMFIC_CONNECT, CM_BUF, ST_CONN, CT_CONT, CI_CONN, st_connectinfo} 202285303Sgshapiro, {SMFIC_BODYEOB, CM_NULLOK, ST_ENDM, CT_CONT, CI_EOM, st_bodyend } 203285303Sgshapiro, {SMFIC_HELO, CM_BUF, ST_HELO, CT_CONT, CI_HELO, st_helo } 204285303Sgshapiro, {SMFIC_HEADER, CM_BUF, ST_HDRS, CT_CONT, CI_NONE, st_header } 205285303Sgshapiro, {SMFIC_MAIL, CM_BUF, ST_MAIL, CT_CONT, CI_MAIL, st_sender } 206285303Sgshapiro, {SMFIC_OPTNEG, CM_BUF, ST_OPTS, CT_CONT, CI_NONE, st_optionneg} 207285303Sgshapiro, {SMFIC_EOH, CM_NULLOK, ST_EOHS, CT_CONT, CI_EOH, st_eoh } 208285303Sgshapiro, {SMFIC_QUIT, CM_NULLOK, ST_QUIT, CT_END, CI_NONE, st_quit } 209285303Sgshapiro, {SMFIC_DATA, CM_NULLOK, ST_DATA, CT_CONT, CI_DATA, st_data } 210285303Sgshapiro, {SMFIC_RCPT, CM_BUF, ST_RCPT, CT_IGNO, CI_RCPT, st_rcpt } 211285303Sgshapiro, {SMFIC_UNKNOWN, CM_BUF, ST_UNKN, CT_IGNO, CI_NONE, st_unknown } 212285303Sgshapiro, {SMFIC_QUIT_NC, CM_NULLOK, ST_Q_NC, CT_CONT, CI_NONE, st_quit } 21364562Sgshapiro}; 21464562Sgshapiro 215168515Sgshapiro/* 216168515Sgshapiro** Additional (internal) reply codes; 217168515Sgshapiro** must be coordinated wit libmilter/mfapi.h 218168515Sgshapiro*/ 219168515Sgshapiro 22064562Sgshapiro#define _SMFIS_KEEP 20 22164562Sgshapiro#define _SMFIS_ABORT 21 22264562Sgshapiro#define _SMFIS_OPTIONS 22 223168515Sgshapiro#define _SMFIS_NOREPLY SMFIS_NOREPLY 22464562Sgshapiro#define _SMFIS_FAIL (-1) 22590792Sgshapiro#define _SMFIS_NONE (-2) 22664562Sgshapiro 22790792Sgshapiro/* 22864562Sgshapiro** MI_ENGINE -- receive commands and process them 22964562Sgshapiro** 23064562Sgshapiro** Parameters: 23164562Sgshapiro** ctx -- context structure 23264562Sgshapiro** 23364562Sgshapiro** Returns: 23464562Sgshapiro** MI_FAILURE/MI_SUCCESS 23564562Sgshapiro*/ 236168515Sgshapiro 23764562Sgshapiroint 23864562Sgshapiromi_engine(ctx) 23964562Sgshapiro SMFICTX_PTR ctx; 24064562Sgshapiro{ 24164562Sgshapiro size_t len; 24264562Sgshapiro int i; 24364562Sgshapiro socket_t sd; 24464562Sgshapiro int ret = MI_SUCCESS; 24564562Sgshapiro int ncmds = sizeof(cmds) / sizeof(cmdfct); 24664562Sgshapiro int curstate = ST_INIT; 24764562Sgshapiro int newstate; 24864562Sgshapiro bool call_abort; 24964562Sgshapiro sfsistat r; 25064562Sgshapiro char cmd; 25164562Sgshapiro char *buf = NULL; 25264562Sgshapiro genarg arg; 25364562Sgshapiro struct timeval timeout; 25464562Sgshapiro int (*f) __P((genarg *)); 25564562Sgshapiro sfsistat (*fi_abort) __P((SMFICTX *)); 25664562Sgshapiro sfsistat (*fi_close) __P((SMFICTX *)); 25764562Sgshapiro 25864562Sgshapiro arg.a_ctx = ctx; 25964562Sgshapiro sd = ctx->ctx_sd; 26064562Sgshapiro fi_abort = ctx->ctx_smfi->xxfi_abort; 261168515Sgshapiro#if _FFR_WORKERS_POOL 262168515Sgshapiro curstate = ctx->ctx_state; 263168515Sgshapiro if (curstate == ST_INIT) 264168515Sgshapiro { 265168515Sgshapiro mi_clr_macros(ctx, 0); 266168515Sgshapiro fix_stm(ctx); 267168515Sgshapiro } 268168515Sgshapiro#else /* _FFR_WORKERS_POOL */ 26964562Sgshapiro mi_clr_macros(ctx, 0); 27064562Sgshapiro fix_stm(ctx); 271168515Sgshapiro#endif /* _FFR_WORKERS_POOL */ 27290792Sgshapiro r = _SMFIS_NONE; 27366494Sgshapiro do 27466494Sgshapiro { 27564562Sgshapiro /* call abort only if in a mail transaction */ 27664562Sgshapiro call_abort = ST_IN_MAIL(curstate); 27764562Sgshapiro timeout.tv_sec = ctx->ctx_timeout; 27864562Sgshapiro timeout.tv_usec = 0; 27964562Sgshapiro if (mi_stop() == MILTER_ABRT) 28064562Sgshapiro { 28164562Sgshapiro if (ctx->ctx_dbg > 3) 282223067Sgshapiro sm_dprintf("[%lu] milter_abort\n", 283168515Sgshapiro (long) ctx->ctx_id); 28464562Sgshapiro ret = MI_FAILURE; 28564562Sgshapiro break; 28664562Sgshapiro } 28790792Sgshapiro 28890792Sgshapiro /* 28990792Sgshapiro ** Notice: buf is allocated by mi_rd_cmd() and it will 29090792Sgshapiro ** usually be free()d after it has been used in f(). 29190792Sgshapiro ** However, if the function returns _SMFIS_KEEP then buf 29290792Sgshapiro ** contains macros and will not be free()d. 29390792Sgshapiro ** Hence r must be set to _SMFIS_NONE if a new buf is 29490792Sgshapiro ** allocated to avoid problem with housekeeping, esp. 29590792Sgshapiro ** if the code "break"s out of the loop. 29690792Sgshapiro */ 29790792Sgshapiro 298168515Sgshapiro#if _FFR_WORKERS_POOL 299168515Sgshapiro /* Is the socket ready to be read ??? */ 300168515Sgshapiro if (!mi_rd_socket_ready(sd)) 301168515Sgshapiro { 302168515Sgshapiro ret = MI_CONTINUE; 303168515Sgshapiro break; 304168515Sgshapiro } 305168515Sgshapiro#endif /* _FFR_WORKERS_POOL */ 306168515Sgshapiro 30790792Sgshapiro r = _SMFIS_NONE; 30864562Sgshapiro if ((buf = mi_rd_cmd(sd, &timeout, &cmd, &len, 30964562Sgshapiro ctx->ctx_smfi->xxfi_name)) == NULL && 31064562Sgshapiro cmd < SMFIC_VALIDCMD) 31164562Sgshapiro { 31264562Sgshapiro if (ctx->ctx_dbg > 5) 313223067Sgshapiro sm_dprintf("[%lu] mi_engine: mi_rd_cmd error (%x)\n", 314168515Sgshapiro (long) ctx->ctx_id, (int) cmd); 31564562Sgshapiro 31664562Sgshapiro /* 31764562Sgshapiro ** eof is currently treated as failure -> 31864562Sgshapiro ** abort() instead of close(), otherwise use: 31964562Sgshapiro ** if (cmd != SMFIC_EOF) 32064562Sgshapiro */ 32164562Sgshapiro 32264562Sgshapiro ret = MI_FAILURE; 32364562Sgshapiro break; 32464562Sgshapiro } 32564562Sgshapiro if (ctx->ctx_dbg > 4) 326223067Sgshapiro sm_dprintf("[%lu] got cmd '%c' len %d\n", 327168515Sgshapiro (long) ctx->ctx_id, cmd, (int) len); 32864562Sgshapiro for (i = 0; i < ncmds; i++) 32964562Sgshapiro { 33064562Sgshapiro if (cmd == cmds[i].cm_cmd) 33164562Sgshapiro break; 33264562Sgshapiro } 33364562Sgshapiro if (i >= ncmds) 33464562Sgshapiro { 33564562Sgshapiro /* unknown command */ 33664562Sgshapiro if (ctx->ctx_dbg > 1) 337223067Sgshapiro sm_dprintf("[%lu] cmd '%c' unknown\n", 338168515Sgshapiro (long) ctx->ctx_id, cmd); 33964562Sgshapiro ret = MI_FAILURE; 34064562Sgshapiro break; 34164562Sgshapiro } 34264562Sgshapiro if ((f = cmds[i].cm_fct) == NULL) 34364562Sgshapiro { 34464562Sgshapiro /* stop for now */ 34564562Sgshapiro if (ctx->ctx_dbg > 1) 346223067Sgshapiro sm_dprintf("[%lu] cmd '%c' not impl\n", 347168515Sgshapiro (long) ctx->ctx_id, cmd); 34864562Sgshapiro ret = MI_FAILURE; 34964562Sgshapiro break; 35064562Sgshapiro } 35164562Sgshapiro 35264562Sgshapiro /* is new state ok? */ 35364562Sgshapiro newstate = cmds[i].cm_next; 35464562Sgshapiro if (ctx->ctx_dbg > 5) 355223067Sgshapiro sm_dprintf("[%lu] cur %x new %x nextmask %x\n", 356168515Sgshapiro (long) ctx->ctx_id, 35764562Sgshapiro curstate, newstate, next_states[curstate]); 35864562Sgshapiro 35964562Sgshapiro if (newstate != ST_NONE && !trans_ok(curstate, newstate)) 36064562Sgshapiro { 36164562Sgshapiro if (ctx->ctx_dbg > 1) 362223067Sgshapiro sm_dprintf("[%lu] abort: cur %d (%x) new %d (%x) next %x\n", 363168515Sgshapiro (long) ctx->ctx_id, 364110560Sgshapiro curstate, MI_MASK(curstate), 365110560Sgshapiro newstate, MI_MASK(newstate), 36664562Sgshapiro next_states[curstate]); 36764562Sgshapiro 36864562Sgshapiro /* call abort only if in a mail transaction */ 36964562Sgshapiro if (fi_abort != NULL && call_abort) 37064562Sgshapiro (void) (*fi_abort)(ctx); 37164562Sgshapiro 37264562Sgshapiro /* 37364562Sgshapiro ** try to reach the new state from HELO 37464562Sgshapiro ** if it can't be reached, ignore the command. 37564562Sgshapiro */ 37664562Sgshapiro 37764562Sgshapiro curstate = ST_HELO; 37864562Sgshapiro if (!trans_ok(curstate, newstate)) 37990792Sgshapiro { 380102528Sgshapiro if (buf != NULL) 381102528Sgshapiro { 382102528Sgshapiro free(buf); 383102528Sgshapiro buf = NULL; 384102528Sgshapiro } 38564562Sgshapiro continue; 38690792Sgshapiro } 38764562Sgshapiro } 388285303Sgshapiro if (cmds[i].cm_argt != CM_NULLOK && buf == NULL) 389285303Sgshapiro { 390285303Sgshapiro /* stop for now */ 391285303Sgshapiro if (ctx->ctx_dbg > 1) 392285303Sgshapiro sm_dprintf("[%lu] cmd='%c', buf=NULL\n", 393285303Sgshapiro (long) ctx->ctx_id, cmd); 394285303Sgshapiro ret = MI_FAILURE; 395285303Sgshapiro break; 396285303Sgshapiro } 39764562Sgshapiro arg.a_len = len; 39864562Sgshapiro arg.a_buf = buf; 39964562Sgshapiro if (newstate != ST_NONE) 40064562Sgshapiro { 40164562Sgshapiro curstate = newstate; 40264562Sgshapiro ctx->ctx_state = curstate; 40364562Sgshapiro } 40464562Sgshapiro arg.a_idx = cmds[i].cm_macros; 405141858Sgshapiro call_abort = ST_IN_MAIL(curstate); 40664562Sgshapiro 40764562Sgshapiro /* call function to deal with command */ 408168515Sgshapiro MI_MONITOR_BEGIN(ctx, cmd); 40964562Sgshapiro r = (*f)(&arg); 410168515Sgshapiro MI_MONITOR_END(ctx, cmd); 41164562Sgshapiro if (r != _SMFIS_KEEP && buf != NULL) 41264562Sgshapiro { 41364562Sgshapiro free(buf); 41464562Sgshapiro buf = NULL; 41564562Sgshapiro } 41664562Sgshapiro if (sendreply(r, sd, &timeout, ctx) != MI_SUCCESS) 41764562Sgshapiro { 41864562Sgshapiro ret = MI_FAILURE; 41964562Sgshapiro break; 42064562Sgshapiro } 42164562Sgshapiro 42264562Sgshapiro if (r == SMFIS_ACCEPT) 42364562Sgshapiro { 42464562Sgshapiro /* accept mail, no further actions taken */ 42564562Sgshapiro curstate = ST_HELO; 42664562Sgshapiro } 42764562Sgshapiro else if (r == SMFIS_REJECT || r == SMFIS_DISCARD || 42864562Sgshapiro r == SMFIS_TEMPFAIL) 42964562Sgshapiro { 43064562Sgshapiro /* 43164562Sgshapiro ** further actions depend on current state 43264562Sgshapiro ** if the IGNO bit is set: "ignore" the error, 43364562Sgshapiro ** i.e., stay in the current state 43464562Sgshapiro */ 43564562Sgshapiro if (!bitset(CT_IGNO, cmds[i].cm_todo)) 43664562Sgshapiro curstate = ST_HELO; 43764562Sgshapiro } 43864562Sgshapiro else if (r == _SMFIS_ABORT) 43964562Sgshapiro { 44064562Sgshapiro if (ctx->ctx_dbg > 5) 441223067Sgshapiro sm_dprintf("[%lu] function returned abort\n", 442168515Sgshapiro (long) ctx->ctx_id); 44364562Sgshapiro ret = MI_FAILURE; 44464562Sgshapiro break; 44564562Sgshapiro } 44664562Sgshapiro } while (!bitset(CT_END, cmds[i].cm_todo)); 44764562Sgshapiro 448168515Sgshapiro ctx->ctx_state = curstate; 449168515Sgshapiro 450168515Sgshapiro if (ret == MI_FAILURE) 45164562Sgshapiro { 45264562Sgshapiro /* call abort only if in a mail transaction */ 45364562Sgshapiro if (fi_abort != NULL && call_abort) 45464562Sgshapiro (void) (*fi_abort)(ctx); 45564562Sgshapiro } 45664562Sgshapiro 457168515Sgshapiro /* has close been called? */ 458168515Sgshapiro if (ctx->ctx_state != ST_QUIT 459168515Sgshapiro#if _FFR_WORKERS_POOL 460168515Sgshapiro && ret != MI_CONTINUE 461168515Sgshapiro#endif /* _FFR_WORKERS_POOL */ 462168515Sgshapiro ) 463168515Sgshapiro { 464168515Sgshapiro if ((fi_close = ctx->ctx_smfi->xxfi_close) != NULL) 465168515Sgshapiro (void) (*fi_close)(ctx); 466168515Sgshapiro } 46790792Sgshapiro if (r != _SMFIS_KEEP && buf != NULL) 46864562Sgshapiro free(buf); 469168515Sgshapiro#if !_FFR_WORKERS_POOL 47064562Sgshapiro mi_clr_macros(ctx, 0); 471168515Sgshapiro#endif /* _FFR_WORKERS_POOL */ 47264562Sgshapiro return ret; 47364562Sgshapiro} 474168515Sgshapiro 475168515Sgshapirostatic size_t milter_addsymlist __P((SMFICTX_PTR, char *, char **)); 476168515Sgshapiro 477168515Sgshapirostatic size_t 478168515Sgshapiromilter_addsymlist(ctx, buf, newbuf) 479168515Sgshapiro SMFICTX_PTR ctx; 480168515Sgshapiro char *buf; 481168515Sgshapiro char **newbuf; 482168515Sgshapiro{ 483168515Sgshapiro size_t len; 484168515Sgshapiro int i; 485168515Sgshapiro mi_int32 v; 486168515Sgshapiro char *buffer; 487168515Sgshapiro 488168515Sgshapiro SM_ASSERT(ctx != NULL); 489168515Sgshapiro SM_ASSERT(buf != NULL); 490168515Sgshapiro SM_ASSERT(newbuf != NULL); 491168515Sgshapiro len = 0; 492168515Sgshapiro for (i = 0; i < MAX_MACROS_ENTRIES; i++) 493168515Sgshapiro { 494168515Sgshapiro if (ctx->ctx_mac_list[i] != NULL) 495168515Sgshapiro { 496168515Sgshapiro len += strlen(ctx->ctx_mac_list[i]) + 1 + 497168515Sgshapiro MILTER_LEN_BYTES; 498168515Sgshapiro } 499168515Sgshapiro } 500168515Sgshapiro if (len > 0) 501168515Sgshapiro { 502168515Sgshapiro size_t offset; 503168515Sgshapiro 504168515Sgshapiro SM_ASSERT(len + MILTER_OPTLEN > len); 505168515Sgshapiro len += MILTER_OPTLEN; 506168515Sgshapiro buffer = malloc(len); 507168515Sgshapiro if (buffer != NULL) 508168515Sgshapiro { 509168515Sgshapiro (void) memcpy(buffer, buf, MILTER_OPTLEN); 510168515Sgshapiro offset = MILTER_OPTLEN; 511168515Sgshapiro for (i = 0; i < MAX_MACROS_ENTRIES; i++) 512168515Sgshapiro { 513168515Sgshapiro size_t l; 514168515Sgshapiro 515168515Sgshapiro if (ctx->ctx_mac_list[i] == NULL) 516168515Sgshapiro continue; 517168515Sgshapiro 518168515Sgshapiro SM_ASSERT(offset + MILTER_LEN_BYTES < len); 519168515Sgshapiro v = htonl(i); 520168515Sgshapiro (void) memcpy(buffer + offset, (void *) &v, 521168515Sgshapiro MILTER_LEN_BYTES); 522168515Sgshapiro offset += MILTER_LEN_BYTES; 523168515Sgshapiro l = strlen(ctx->ctx_mac_list[i]) + 1; 524168515Sgshapiro SM_ASSERT(offset + l <= len); 525168515Sgshapiro (void) memcpy(buffer + offset, 526168515Sgshapiro ctx->ctx_mac_list[i], l); 527168515Sgshapiro offset += l; 528168515Sgshapiro } 529168515Sgshapiro } 530168515Sgshapiro else 531168515Sgshapiro { 532168515Sgshapiro /* oops ... */ 533168515Sgshapiro } 534168515Sgshapiro } 535168515Sgshapiro else 536168515Sgshapiro { 537168515Sgshapiro len = MILTER_OPTLEN; 538168515Sgshapiro buffer = buf; 539168515Sgshapiro } 540168515Sgshapiro *newbuf = buffer; 541168515Sgshapiro return len; 542168515Sgshapiro} 543168515Sgshapiro 54490792Sgshapiro/* 545168515Sgshapiro** GET_NR_BIT -- get "no reply" bit matching state 546168515Sgshapiro** 547168515Sgshapiro** Parameters: 548168515Sgshapiro** state -- current protocol stage 549168515Sgshapiro** 550168515Sgshapiro** Returns: 551168515Sgshapiro** 0: no matching bit 552168515Sgshapiro** >0: the matching "no reply" bit 553168515Sgshapiro*/ 554168515Sgshapiro 555168515Sgshapirostatic unsigned long get_nr_bit __P((int)); 556168515Sgshapiro 557168515Sgshapirostatic unsigned long 558168515Sgshapiroget_nr_bit(state) 559168515Sgshapiro int state; 560168515Sgshapiro{ 561168515Sgshapiro unsigned long bit; 562168515Sgshapiro 563168515Sgshapiro switch (state) 564168515Sgshapiro { 565168515Sgshapiro case ST_CONN: 566168515Sgshapiro bit = SMFIP_NR_CONN; 567168515Sgshapiro break; 568168515Sgshapiro case ST_HELO: 569168515Sgshapiro bit = SMFIP_NR_HELO; 570168515Sgshapiro break; 571168515Sgshapiro case ST_MAIL: 572168515Sgshapiro bit = SMFIP_NR_MAIL; 573168515Sgshapiro break; 574168515Sgshapiro case ST_RCPT: 575168515Sgshapiro bit = SMFIP_NR_RCPT; 576168515Sgshapiro break; 577168515Sgshapiro case ST_DATA: 578168515Sgshapiro bit = SMFIP_NR_DATA; 579168515Sgshapiro break; 580168515Sgshapiro case ST_UNKN: 581168515Sgshapiro bit = SMFIP_NR_UNKN; 582168515Sgshapiro break; 583168515Sgshapiro case ST_HDRS: 584168515Sgshapiro bit = SMFIP_NR_HDR; 585168515Sgshapiro break; 586168515Sgshapiro case ST_EOHS: 587168515Sgshapiro bit = SMFIP_NR_EOH; 588168515Sgshapiro break; 589168515Sgshapiro case ST_BODY: 590168515Sgshapiro bit = SMFIP_NR_BODY; 591168515Sgshapiro break; 592168515Sgshapiro default: 593168515Sgshapiro bit = 0; 594168515Sgshapiro break; 595168515Sgshapiro } 596168515Sgshapiro return bit; 597168515Sgshapiro} 598168515Sgshapiro 599168515Sgshapiro/* 60064562Sgshapiro** SENDREPLY -- send a reply to the MTA 60164562Sgshapiro** 60264562Sgshapiro** Parameters: 60364562Sgshapiro** r -- reply code 60464562Sgshapiro** sd -- socket descriptor 60564562Sgshapiro** timeout_ptr -- (ptr to) timeout to use for sending 60664562Sgshapiro** ctx -- context structure 60764562Sgshapiro** 60864562Sgshapiro** Returns: 60964562Sgshapiro** MI_SUCCESS/MI_FAILURE 61064562Sgshapiro*/ 61164562Sgshapiro 61264562Sgshapirostatic int 61364562Sgshapirosendreply(r, sd, timeout_ptr, ctx) 61464562Sgshapiro sfsistat r; 61564562Sgshapiro socket_t sd; 61664562Sgshapiro struct timeval *timeout_ptr; 61764562Sgshapiro SMFICTX_PTR ctx; 61864562Sgshapiro{ 619168515Sgshapiro int ret; 620168515Sgshapiro unsigned long bit; 62164562Sgshapiro 622168515Sgshapiro ret = MI_SUCCESS; 623168515Sgshapiro 624168515Sgshapiro bit = get_nr_bit(ctx->ctx_state); 625168515Sgshapiro if (bit != 0 && (ctx->ctx_pflags & bit) != 0 && r != SMFIS_NOREPLY) 626168515Sgshapiro { 627168515Sgshapiro if (r >= SMFIS_CONTINUE && r < _SMFIS_KEEP) 628168515Sgshapiro { 629168515Sgshapiro /* milter said it wouldn't reply, but it lied... */ 630168515Sgshapiro smi_log(SMI_LOG_ERR, 631168515Sgshapiro "%s: milter claimed not to reply in state %d but did anyway %d\n", 632168515Sgshapiro ctx->ctx_smfi->xxfi_name, 633168515Sgshapiro ctx->ctx_state, r); 634168515Sgshapiro 635168515Sgshapiro } 636168515Sgshapiro 637168515Sgshapiro /* 638168515Sgshapiro ** Force specified behavior, otherwise libmilter 639168515Sgshapiro ** and MTA will fail to communicate properly. 640168515Sgshapiro */ 641168515Sgshapiro 642168515Sgshapiro switch (r) 643168515Sgshapiro { 644168515Sgshapiro case SMFIS_CONTINUE: 645168515Sgshapiro case SMFIS_TEMPFAIL: 646168515Sgshapiro case SMFIS_REJECT: 647168515Sgshapiro case SMFIS_DISCARD: 648168515Sgshapiro case SMFIS_ACCEPT: 649168515Sgshapiro case SMFIS_SKIP: 650168515Sgshapiro case _SMFIS_OPTIONS: 651168515Sgshapiro r = SMFIS_NOREPLY; 652168515Sgshapiro break; 653168515Sgshapiro } 654168515Sgshapiro } 655168515Sgshapiro 65671345Sgshapiro switch (r) 65764562Sgshapiro { 65864562Sgshapiro case SMFIS_CONTINUE: 65964562Sgshapiro ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_CONTINUE, NULL, 0); 66064562Sgshapiro break; 66164562Sgshapiro case SMFIS_TEMPFAIL: 66264562Sgshapiro case SMFIS_REJECT: 66394334Sgshapiro if (ctx->ctx_reply != NULL && 66494334Sgshapiro ((r == SMFIS_TEMPFAIL && *ctx->ctx_reply == '4') || 66594334Sgshapiro (r == SMFIS_REJECT && *ctx->ctx_reply == '5'))) 66664562Sgshapiro { 66764562Sgshapiro ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_REPLYCODE, 66864562Sgshapiro ctx->ctx_reply, 66964562Sgshapiro strlen(ctx->ctx_reply) + 1); 67064562Sgshapiro free(ctx->ctx_reply); 67164562Sgshapiro ctx->ctx_reply = NULL; 67264562Sgshapiro } 67364562Sgshapiro else 67464562Sgshapiro { 67564562Sgshapiro ret = mi_wr_cmd(sd, timeout_ptr, r == SMFIS_REJECT ? 67664562Sgshapiro SMFIR_REJECT : SMFIR_TEMPFAIL, NULL, 0); 67764562Sgshapiro } 67864562Sgshapiro break; 67964562Sgshapiro case SMFIS_DISCARD: 68064562Sgshapiro ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_DISCARD, NULL, 0); 68164562Sgshapiro break; 68264562Sgshapiro case SMFIS_ACCEPT: 68364562Sgshapiro ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_ACCEPT, NULL, 0); 68464562Sgshapiro break; 685168515Sgshapiro case SMFIS_SKIP: 686168515Sgshapiro ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_SKIP, NULL, 0); 687168515Sgshapiro break; 68864562Sgshapiro case _SMFIS_OPTIONS: 68964562Sgshapiro { 690168515Sgshapiro mi_int32 v; 691168515Sgshapiro size_t len; 692168515Sgshapiro char *buffer; 69364562Sgshapiro char buf[MILTER_OPTLEN]; 69464562Sgshapiro 695168515Sgshapiro v = htonl(ctx->ctx_prot_vers2mta); 696168515Sgshapiro (void) memcpy(&(buf[0]), (void *) &v, 697168515Sgshapiro MILTER_LEN_BYTES); 698168515Sgshapiro v = htonl(ctx->ctx_aflags); 69964562Sgshapiro (void) memcpy(&(buf[MILTER_LEN_BYTES]), (void *) &v, 70064562Sgshapiro MILTER_LEN_BYTES); 701168515Sgshapiro v = htonl(ctx->ctx_pflags2mta); 702168515Sgshapiro (void) memcpy(&(buf[MILTER_LEN_BYTES * 2]), 703168515Sgshapiro (void *) &v, MILTER_LEN_BYTES); 704168515Sgshapiro len = milter_addsymlist(ctx, buf, &buffer); 705168515Sgshapiro if (buffer != NULL) 706168515Sgshapiro ret = mi_wr_cmd(sd, timeout_ptr, SMFIC_OPTNEG, 707168515Sgshapiro buffer, len); 708168515Sgshapiro else 709168515Sgshapiro ret = MI_FAILURE; 71064562Sgshapiro } 71164562Sgshapiro break; 712168515Sgshapiro case SMFIS_NOREPLY: 713168515Sgshapiro if (bit != 0 && 714168515Sgshapiro (ctx->ctx_pflags & bit) != 0 && 715168515Sgshapiro (ctx->ctx_mta_pflags & bit) == 0) 716168515Sgshapiro { 717168515Sgshapiro /* 718168515Sgshapiro ** milter doesn't want to send a reply, 719168515Sgshapiro ** but the MTA doesn't have that feature: fake it. 720168515Sgshapiro */ 721168515Sgshapiro 722168515Sgshapiro ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_CONTINUE, NULL, 723168515Sgshapiro 0); 724168515Sgshapiro } 725168515Sgshapiro break; 72664562Sgshapiro default: /* don't send a reply */ 72764562Sgshapiro break; 72864562Sgshapiro } 72964562Sgshapiro return ret; 73064562Sgshapiro} 73164562Sgshapiro 73264562Sgshapiro/* 733285303Sgshapiro** MI_CLR_MACROS -- clear set of macros starting from a given index 73464562Sgshapiro** 73564562Sgshapiro** Parameters: 73664562Sgshapiro** ctx -- context structure 73764562Sgshapiro** m -- index from which to clear all macros 73864562Sgshapiro** 73964562Sgshapiro** Returns: 74064562Sgshapiro** None. 74164562Sgshapiro*/ 742168515Sgshapiro 74364562Sgshapirovoid 74464562Sgshapiromi_clr_macros(ctx, m) 74564562Sgshapiro SMFICTX_PTR ctx; 74664562Sgshapiro int m; 74764562Sgshapiro{ 74864562Sgshapiro int i; 74964562Sgshapiro 75064562Sgshapiro for (i = m; i < MAX_MACROS_ENTRIES; i++) 75164562Sgshapiro { 75264562Sgshapiro if (ctx->ctx_mac_ptr[i] != NULL) 75364562Sgshapiro { 75464562Sgshapiro free(ctx->ctx_mac_ptr[i]); 75564562Sgshapiro ctx->ctx_mac_ptr[i] = NULL; 75664562Sgshapiro } 75764562Sgshapiro if (ctx->ctx_mac_buf[i] != NULL) 75864562Sgshapiro { 75964562Sgshapiro free(ctx->ctx_mac_buf[i]); 76064562Sgshapiro ctx->ctx_mac_buf[i] = NULL; 76164562Sgshapiro } 76264562Sgshapiro } 76364562Sgshapiro} 764168515Sgshapiro 76590792Sgshapiro/* 766203004Sgshapiro** MI_CLR_SYMLIST -- clear list of macros 767203004Sgshapiro** 768203004Sgshapiro** Parameters: 769203004Sgshapiro** ctx -- context structure 770203004Sgshapiro** 771203004Sgshapiro** Returns: 772203004Sgshapiro** None. 773203004Sgshapiro*/ 774203004Sgshapiro 775203004Sgshapirostatic void 776203004Sgshapiromi_clr_symlist(ctx) 777203004Sgshapiro SMFICTX *ctx; 778203004Sgshapiro{ 779203004Sgshapiro int i; 780203004Sgshapiro 781203004Sgshapiro SM_ASSERT(ctx != NULL); 782203004Sgshapiro for (i = SMFIM_FIRST; i <= SMFIM_LAST; i++) 783203004Sgshapiro { 784203004Sgshapiro if (ctx->ctx_mac_list[i] != NULL) 785203004Sgshapiro { 786203004Sgshapiro free(ctx->ctx_mac_list[i]); 787203004Sgshapiro ctx->ctx_mac_list[i] = NULL; 788203004Sgshapiro } 789203004Sgshapiro } 790203004Sgshapiro} 791203004Sgshapiro 792203004Sgshapiro/* 793203004Sgshapiro** MI_CLR_CTX -- clear context 794203004Sgshapiro** 795203004Sgshapiro** Parameters: 796203004Sgshapiro** ctx -- context structure 797203004Sgshapiro** 798203004Sgshapiro** Returns: 799203004Sgshapiro** None. 800203004Sgshapiro*/ 801203004Sgshapiro 802203004Sgshapirovoid 803203004Sgshapiromi_clr_ctx(ctx) 804203004Sgshapiro SMFICTX *ctx; 805203004Sgshapiro{ 806203004Sgshapiro SM_ASSERT(ctx != NULL); 807203004Sgshapiro if (ValidSocket(ctx->ctx_sd)) 808203004Sgshapiro { 809203004Sgshapiro (void) closesocket(ctx->ctx_sd); 810203004Sgshapiro ctx->ctx_sd = INVALID_SOCKET; 811203004Sgshapiro } 812203004Sgshapiro if (ctx->ctx_reply != NULL) 813203004Sgshapiro { 814203004Sgshapiro free(ctx->ctx_reply); 815203004Sgshapiro ctx->ctx_reply = NULL; 816203004Sgshapiro } 817203004Sgshapiro if (ctx->ctx_privdata != NULL) 818203004Sgshapiro { 819203004Sgshapiro smi_log(SMI_LOG_WARN, 820203004Sgshapiro "%s: private data not NULL", 821203004Sgshapiro ctx->ctx_smfi->xxfi_name); 822203004Sgshapiro } 823203004Sgshapiro mi_clr_macros(ctx, 0); 824203004Sgshapiro mi_clr_symlist(ctx); 825203004Sgshapiro free(ctx); 826203004Sgshapiro} 827203004Sgshapiro 828203004Sgshapiro/* 82964562Sgshapiro** ST_OPTIONNEG -- negotiate options 83064562Sgshapiro** 83164562Sgshapiro** Parameters: 83264562Sgshapiro** g -- generic argument structure 83364562Sgshapiro** 83464562Sgshapiro** Returns: 83564562Sgshapiro** abort/send options/continue 83664562Sgshapiro*/ 83764562Sgshapiro 83864562Sgshapirostatic int 83964562Sgshapirost_optionneg(g) 84064562Sgshapiro genarg *g; 84164562Sgshapiro{ 842203004Sgshapiro mi_int32 i, v, fake_pflags, internal_pflags; 843168515Sgshapiro SMFICTX_PTR ctx; 844203004Sgshapiro#if _FFR_MILTER_CHECK 845203004Sgshapiro bool testmode = false; 846203004Sgshapiro#endif /* _FFR_MILTER_CHECK */ 847168515Sgshapiro int (*fi_negotiate) __P((SMFICTX *, 848168515Sgshapiro unsigned long, unsigned long, 849168515Sgshapiro unsigned long, unsigned long, 850168515Sgshapiro unsigned long *, unsigned long *, 851168515Sgshapiro unsigned long *, unsigned long *)); 85264562Sgshapiro 85364562Sgshapiro if (g == NULL || g->a_ctx->ctx_smfi == NULL) 85464562Sgshapiro return SMFIS_CONTINUE; 855168515Sgshapiro ctx = g->a_ctx; 856168515Sgshapiro mi_clr_macros(ctx, g->a_idx + 1); 857168515Sgshapiro ctx->ctx_prot_vers = SMFI_PROT_VERSION; 85864562Sgshapiro 85964562Sgshapiro /* check for minimum length */ 86064562Sgshapiro if (g->a_len < MILTER_OPTLEN) 86164562Sgshapiro { 86264562Sgshapiro smi_log(SMI_LOG_ERR, 863168515Sgshapiro "%s: st_optionneg[%ld]: len too short %d < %d", 864168515Sgshapiro ctx->ctx_smfi->xxfi_name, 865168515Sgshapiro (long) ctx->ctx_id, (int) g->a_len, 86664562Sgshapiro MILTER_OPTLEN); 86764562Sgshapiro return _SMFIS_ABORT; 86864562Sgshapiro } 86964562Sgshapiro 870168515Sgshapiro /* protocol version */ 871168515Sgshapiro (void) memcpy((void *) &i, (void *) &(g->a_buf[0]), MILTER_LEN_BYTES); 87264562Sgshapiro v = ntohl(i); 873168515Sgshapiro 874168515Sgshapiro#define SMFI_PROT_VERSION_MIN 2 875168515Sgshapiro 876168515Sgshapiro /* check for minimum version */ 877168515Sgshapiro if (v < SMFI_PROT_VERSION_MIN) 87864562Sgshapiro { 87964562Sgshapiro smi_log(SMI_LOG_ERR, 880168515Sgshapiro "%s: st_optionneg[%ld]: protocol version too old %d < %d", 881168515Sgshapiro ctx->ctx_smfi->xxfi_name, 882168515Sgshapiro (long) ctx->ctx_id, v, SMFI_PROT_VERSION_MIN); 88364562Sgshapiro return _SMFIS_ABORT; 88464562Sgshapiro } 885168515Sgshapiro ctx->ctx_mta_prot_vers = v; 886168515Sgshapiro if (ctx->ctx_prot_vers < ctx->ctx_mta_prot_vers) 887168515Sgshapiro ctx->ctx_prot_vers2mta = ctx->ctx_prot_vers; 888168515Sgshapiro else 889168515Sgshapiro ctx->ctx_prot_vers2mta = ctx->ctx_mta_prot_vers; 89064562Sgshapiro 89164562Sgshapiro (void) memcpy((void *) &i, (void *) &(g->a_buf[MILTER_LEN_BYTES]), 89264562Sgshapiro MILTER_LEN_BYTES); 89364562Sgshapiro v = ntohl(i); 89464562Sgshapiro 89564562Sgshapiro /* no flags? set to default value for V1 actions */ 89664562Sgshapiro if (v == 0) 89764562Sgshapiro v = SMFI_V1_ACTS; 898168515Sgshapiro ctx->ctx_mta_aflags = v; /* MTA action flags */ 89964562Sgshapiro 900203004Sgshapiro internal_pflags = 0; 90164562Sgshapiro (void) memcpy((void *) &i, (void *) &(g->a_buf[MILTER_LEN_BYTES * 2]), 90264562Sgshapiro MILTER_LEN_BYTES); 90364562Sgshapiro v = ntohl(i); 90464562Sgshapiro 90564562Sgshapiro /* no flags? set to default value for V1 protocol */ 90664562Sgshapiro if (v == 0) 90764562Sgshapiro v = SMFI_V1_PROT; 908203004Sgshapiro#if _FFR_MDS_NEGOTIATE 909203004Sgshapiro else if (ctx->ctx_smfi->xxfi_version >= SMFI_VERSION_MDS) 910203004Sgshapiro { 911203004Sgshapiro /* 912203004Sgshapiro ** Allow changing the size only if milter is compiled 913203004Sgshapiro ** against a version that supports this. 914203004Sgshapiro ** If a milter is dynamically linked against a newer 915203004Sgshapiro ** libmilter version, we don't want to "surprise" 916203004Sgshapiro ** it with a larger buffer as it may rely on it 917203004Sgshapiro ** even though it is not documented as a limit. 918203004Sgshapiro */ 919168515Sgshapiro 920203004Sgshapiro if (bitset(SMFIP_MDS_1M, v)) 921203004Sgshapiro { 922203004Sgshapiro internal_pflags |= SMFIP_MDS_1M; 923203004Sgshapiro (void) smfi_setmaxdatasize(MILTER_MDS_1M); 924203004Sgshapiro } 925203004Sgshapiro else if (bitset(SMFIP_MDS_256K, v)) 926203004Sgshapiro { 927203004Sgshapiro internal_pflags |= SMFIP_MDS_256K; 928203004Sgshapiro (void) smfi_setmaxdatasize(MILTER_MDS_256K); 929203004Sgshapiro } 930203004Sgshapiro } 931203004Sgshapiro# if 0 932203004Sgshapiro /* don't log this for now... */ 933203004Sgshapiro else if (ctx->ctx_smfi->xxfi_version < SMFI_VERSION_MDS && 934203004Sgshapiro bitset(SMFIP_MDS_1M|SMFIP_MDS_256K, v)) 935203004Sgshapiro { 936203004Sgshapiro smi_log(SMI_LOG_WARN, 937203004Sgshapiro "%s: st_optionneg[%ld]: milter version=%X, trying flags=%X", 938203004Sgshapiro ctx->ctx_smfi->xxfi_name, 939203004Sgshapiro (long) ctx->ctx_id, ctx->ctx_smfi->xxfi_version, v); 940203004Sgshapiro } 941203004Sgshapiro# endif /* 0 */ 942203004Sgshapiro#endif /* _FFR_MDS_NEGOTIATE */ 943203004Sgshapiro 944168515Sgshapiro /* 945203004Sgshapiro ** MTA protocol flags. 946203004Sgshapiro ** We pass the internal flags to the milter as "read only", 947203004Sgshapiro ** i.e., a milter can read them so it knows which size 948203004Sgshapiro ** will be used, but any changes by a milter will be ignored 949203004Sgshapiro ** (see below, search for SMFI_INTERNAL). 950203004Sgshapiro */ 951203004Sgshapiro 952203004Sgshapiro ctx->ctx_mta_pflags = (v & ~SMFI_INTERNAL) | internal_pflags; 953203004Sgshapiro 954203004Sgshapiro /* 955168515Sgshapiro ** Copy flags from milter struct into libmilter context; 956168515Sgshapiro ** this variable will be used later on to check whether 957168515Sgshapiro ** the MTA "actions" can fulfill the milter requirements, 958168515Sgshapiro ** but it may be overwritten by the negotiate callback. 959168515Sgshapiro */ 960168515Sgshapiro 961168515Sgshapiro ctx->ctx_aflags = ctx->ctx_smfi->xxfi_flags; 962168515Sgshapiro fake_pflags = SMFIP_NR_CONN 963168515Sgshapiro |SMFIP_NR_HELO 964168515Sgshapiro |SMFIP_NR_MAIL 965168515Sgshapiro |SMFIP_NR_RCPT 966168515Sgshapiro |SMFIP_NR_DATA 967168515Sgshapiro |SMFIP_NR_UNKN 968168515Sgshapiro |SMFIP_NR_HDR 969168515Sgshapiro |SMFIP_NR_EOH 970168515Sgshapiro |SMFIP_NR_BODY 971168515Sgshapiro ; 972168515Sgshapiro 973168515Sgshapiro if (g->a_ctx->ctx_smfi != NULL && 974168988Sgshapiro g->a_ctx->ctx_smfi->xxfi_version > 4 && 975168515Sgshapiro (fi_negotiate = g->a_ctx->ctx_smfi->xxfi_negotiate) != NULL) 97664562Sgshapiro { 977168515Sgshapiro int r; 978168515Sgshapiro unsigned long m_aflags, m_pflags, m_f2, m_f3; 979168515Sgshapiro 980168515Sgshapiro /* 981168515Sgshapiro ** let milter decide whether the features offered by the 982168515Sgshapiro ** MTA are "good enough". 983168515Sgshapiro ** Notes: 984168515Sgshapiro ** - libmilter can "fake" some features (e.g., SMFIP_NR_HDR) 985168515Sgshapiro ** - m_f2, m_f3 are for future extensions 986168515Sgshapiro */ 987168515Sgshapiro 988168515Sgshapiro m_f2 = m_f3 = 0; 989168515Sgshapiro m_aflags = ctx->ctx_mta_aflags; 990168515Sgshapiro m_pflags = ctx->ctx_pflags; 991168515Sgshapiro if ((SMFIP_SKIP & ctx->ctx_mta_pflags) != 0) 992168515Sgshapiro m_pflags |= SMFIP_SKIP; 993168515Sgshapiro r = fi_negotiate(g->a_ctx, 994168515Sgshapiro ctx->ctx_mta_aflags, 995168515Sgshapiro ctx->ctx_mta_pflags|fake_pflags, 996168515Sgshapiro 0, 0, 997168515Sgshapiro &m_aflags, &m_pflags, &m_f2, &m_f3); 998168515Sgshapiro 999203004Sgshapiro#if _FFR_MILTER_CHECK 1000203004Sgshapiro testmode = bitset(SMFIP_TEST, m_pflags); 1001203004Sgshapiro if (testmode) 1002203004Sgshapiro m_pflags &= ~SMFIP_TEST; 1003203004Sgshapiro#endif /* _FFR_MILTER_CHECK */ 1004203004Sgshapiro 1005168515Sgshapiro /* 1006168515Sgshapiro ** Types of protocol flags (pflags): 1007168515Sgshapiro ** 1. do NOT send protocol step X 1008168515Sgshapiro ** 2. MTA can do/understand something extra (SKIP, 1009168515Sgshapiro ** send unknown RCPTs) 1010168515Sgshapiro ** 3. MTA can deal with "no reply" for various protocol steps 1011168515Sgshapiro ** Note: this mean that it isn't possible to simply set all 1012168515Sgshapiro ** flags to get "everything": 1013168515Sgshapiro ** setting a flag of type 1 turns off a step 1014168515Sgshapiro ** (it should be the other way around: 1015168515Sgshapiro ** a flag means a protocol step can be sent) 1016168515Sgshapiro ** setting a flag of type 3 requires that milter 1017168515Sgshapiro ** never sends a reply for the corresponding step. 1018168515Sgshapiro ** Summary: the "negation" of protocol flags is causing 1019168515Sgshapiro ** problems, but at least for type 3 there is no simple 1020168515Sgshapiro ** solution. 1021168515Sgshapiro ** 1022168515Sgshapiro ** What should "all options" mean? 1023168515Sgshapiro ** send all protocol steps _except_ those for which there is 1024168515Sgshapiro ** no callback (currently registered in ctx_pflags) 1025168515Sgshapiro ** expect SKIP as return code? Yes 1026168515Sgshapiro ** send unknown RCPTs? No, 1027168515Sgshapiro ** must be explicitly requested? 1028168515Sgshapiro ** "no reply" for some protocol steps? No, 1029168515Sgshapiro ** must be explicitly requested. 1030168515Sgshapiro */ 1031168515Sgshapiro 1032168515Sgshapiro if (SMFIS_ALL_OPTS == r) 1033168515Sgshapiro { 1034168515Sgshapiro ctx->ctx_aflags = ctx->ctx_mta_aflags; 1035168515Sgshapiro ctx->ctx_pflags2mta = ctx->ctx_pflags; 1036168515Sgshapiro if ((SMFIP_SKIP & ctx->ctx_mta_pflags) != 0) 1037168515Sgshapiro ctx->ctx_pflags2mta |= SMFIP_SKIP; 1038168515Sgshapiro } 1039168515Sgshapiro else if (r != SMFIS_CONTINUE) 1040168515Sgshapiro { 1041168515Sgshapiro smi_log(SMI_LOG_ERR, 1042168515Sgshapiro "%s: st_optionneg[%ld]: xxfi_negotiate returned %d (protocol options=0x%lx, actions=0x%lx)", 1043168515Sgshapiro ctx->ctx_smfi->xxfi_name, 1044168515Sgshapiro (long) ctx->ctx_id, r, ctx->ctx_mta_pflags, 1045168515Sgshapiro ctx->ctx_mta_aflags); 1046168515Sgshapiro return _SMFIS_ABORT; 1047168515Sgshapiro } 1048168515Sgshapiro else 1049168515Sgshapiro { 1050168515Sgshapiro ctx->ctx_aflags = m_aflags; 1051168515Sgshapiro ctx->ctx_pflags = m_pflags; 1052168515Sgshapiro ctx->ctx_pflags2mta = m_pflags; 1053168515Sgshapiro } 1054168515Sgshapiro 1055168515Sgshapiro /* check whether some flags need to be "faked" */ 1056168515Sgshapiro i = ctx->ctx_pflags2mta; 1057168515Sgshapiro if ((ctx->ctx_mta_pflags & i) != i) 1058168515Sgshapiro { 1059168515Sgshapiro unsigned int idx; 1060168515Sgshapiro unsigned long b; 1061168515Sgshapiro 1062168515Sgshapiro /* 1063168515Sgshapiro ** If some behavior can be faked (set in fake_pflags), 1064168515Sgshapiro ** but the MTA doesn't support it, then unset 1065168515Sgshapiro ** that flag in the value that is sent to the MTA. 1066168515Sgshapiro */ 1067168515Sgshapiro 1068168515Sgshapiro for (idx = 0; idx < 32; idx++) 1069168515Sgshapiro { 1070168515Sgshapiro b = 1 << idx; 1071168515Sgshapiro if ((ctx->ctx_mta_pflags & b) != b && 1072168515Sgshapiro (fake_pflags & b) == b) 1073168515Sgshapiro ctx->ctx_pflags2mta &= ~b; 1074168515Sgshapiro } 1075168515Sgshapiro } 1076168515Sgshapiro } 1077168515Sgshapiro else 1078168515Sgshapiro { 1079168515Sgshapiro /* 1080168515Sgshapiro ** Set the protocol flags based on the values determined 1081168515Sgshapiro ** in mi_listener() which checked the defined callbacks. 1082168515Sgshapiro */ 1083168515Sgshapiro 1084168515Sgshapiro ctx->ctx_pflags2mta = ctx->ctx_pflags; 1085168515Sgshapiro } 1086168515Sgshapiro 1087168515Sgshapiro /* check whether actions and protocol requirements can be satisfied */ 1088168515Sgshapiro i = ctx->ctx_aflags; 1089168515Sgshapiro if ((i & ctx->ctx_mta_aflags) != i) 1090168515Sgshapiro { 109164562Sgshapiro smi_log(SMI_LOG_ERR, 1092168515Sgshapiro "%s: st_optionneg[%ld]: 0x%lx does not fulfill action requirements 0x%x", 1093168515Sgshapiro ctx->ctx_smfi->xxfi_name, 1094168515Sgshapiro (long) ctx->ctx_id, ctx->ctx_mta_aflags, i); 109564562Sgshapiro return _SMFIS_ABORT; 109664562Sgshapiro } 109764562Sgshapiro 1098168515Sgshapiro i = ctx->ctx_pflags2mta; 1099168515Sgshapiro if ((ctx->ctx_mta_pflags & i) != i) 1100168515Sgshapiro { 1101168515Sgshapiro /* 1102168515Sgshapiro ** Older MTAs do not support some protocol steps. 1103168515Sgshapiro ** As this protocol is a bit "wierd" (it asks for steps 1104168515Sgshapiro ** NOT to be taken/sent) we have to check whether we 1105168515Sgshapiro ** should turn off those "negative" requests. 1106168515Sgshapiro ** Currently these are only SMFIP_NODATA and SMFIP_NOUNKNOWN. 1107168515Sgshapiro */ 1108168515Sgshapiro 1109168515Sgshapiro if (bitset(SMFIP_NODATA, ctx->ctx_pflags2mta) && 1110168515Sgshapiro !bitset(SMFIP_NODATA, ctx->ctx_mta_pflags)) 1111168515Sgshapiro ctx->ctx_pflags2mta &= ~SMFIP_NODATA; 1112168515Sgshapiro if (bitset(SMFIP_NOUNKNOWN, ctx->ctx_pflags2mta) && 1113168515Sgshapiro !bitset(SMFIP_NOUNKNOWN, ctx->ctx_mta_pflags)) 1114168515Sgshapiro ctx->ctx_pflags2mta &= ~SMFIP_NOUNKNOWN; 1115168515Sgshapiro i = ctx->ctx_pflags2mta; 1116168515Sgshapiro } 1117168515Sgshapiro 1118168515Sgshapiro if ((ctx->ctx_mta_pflags & i) != i) 1119168515Sgshapiro { 1120168515Sgshapiro smi_log(SMI_LOG_ERR, 1121168515Sgshapiro "%s: st_optionneg[%ld]: 0x%lx does not fulfill protocol requirements 0x%x", 1122168515Sgshapiro ctx->ctx_smfi->xxfi_name, 1123168515Sgshapiro (long) ctx->ctx_id, ctx->ctx_mta_pflags, i); 1124168515Sgshapiro return _SMFIS_ABORT; 1125168515Sgshapiro } 1126182352Sgshapiro fix_stm(ctx); 1127168515Sgshapiro 1128168515Sgshapiro if (ctx->ctx_dbg > 3) 1129223067Sgshapiro sm_dprintf("[%lu] milter_negotiate:" 1130168515Sgshapiro " mta_actions=0x%lx, mta_flags=0x%lx" 1131168515Sgshapiro " actions=0x%lx, flags=0x%lx\n" 1132168515Sgshapiro , (long) ctx->ctx_id 1133168515Sgshapiro , ctx->ctx_mta_aflags, ctx->ctx_mta_pflags 1134168515Sgshapiro , ctx->ctx_aflags, ctx->ctx_pflags); 1135168515Sgshapiro 1136203004Sgshapiro#if _FFR_MILTER_CHECK 1137203004Sgshapiro if (ctx->ctx_dbg > 3) 1138223067Sgshapiro sm_dprintf("[%lu] milter_negotiate:" 1139203004Sgshapiro " testmode=%d, pflags2mta=%X, internal_pflags=%X\n" 1140203004Sgshapiro , (long) ctx->ctx_id, testmode 1141203004Sgshapiro , ctx->ctx_pflags2mta, internal_pflags); 1142203004Sgshapiro 1143203004Sgshapiro /* in test mode: take flags without further modifications */ 1144203004Sgshapiro if (!testmode) 1145203004Sgshapiro /* Warning: check statement below! */ 1146203004Sgshapiro#endif /* _FFR_MILTER_CHECK */ 1147203004Sgshapiro 1148203004Sgshapiro /* 1149203004Sgshapiro ** Remove the internal flags that might have been set by a milter 1150203004Sgshapiro ** and set only those determined above. 1151203004Sgshapiro */ 1152203004Sgshapiro 1153203004Sgshapiro ctx->ctx_pflags2mta = (ctx->ctx_pflags2mta & ~SMFI_INTERNAL) 1154203004Sgshapiro | internal_pflags; 115564562Sgshapiro return _SMFIS_OPTIONS; 115664562Sgshapiro} 1157168515Sgshapiro 115890792Sgshapiro/* 115964562Sgshapiro** ST_CONNECTINFO -- receive connection information 116064562Sgshapiro** 116164562Sgshapiro** Parameters: 116264562Sgshapiro** g -- generic argument structure 116364562Sgshapiro** 116464562Sgshapiro** Returns: 116564562Sgshapiro** continue or filter-specified value 116664562Sgshapiro*/ 116764562Sgshapiro 116864562Sgshapirostatic int 116964562Sgshapirost_connectinfo(g) 117064562Sgshapiro genarg *g; 117164562Sgshapiro{ 117264562Sgshapiro size_t l; 117364562Sgshapiro size_t i; 117464562Sgshapiro char *s, family; 117590792Sgshapiro unsigned short port = 0; 117664562Sgshapiro _SOCK_ADDR sockaddr; 117764562Sgshapiro sfsistat (*fi_connect) __P((SMFICTX *, char *, _SOCK_ADDR *)); 117864562Sgshapiro 117964562Sgshapiro if (g == NULL) 118064562Sgshapiro return _SMFIS_ABORT; 118164562Sgshapiro mi_clr_macros(g->a_ctx, g->a_idx + 1); 118264562Sgshapiro if (g->a_ctx->ctx_smfi == NULL || 118364562Sgshapiro (fi_connect = g->a_ctx->ctx_smfi->xxfi_connect) == NULL) 118464562Sgshapiro return SMFIS_CONTINUE; 118564562Sgshapiro 118664562Sgshapiro s = g->a_buf; 118764562Sgshapiro i = 0; 118864562Sgshapiro l = g->a_len; 118964562Sgshapiro while (s[i] != '\0' && i <= l) 119064562Sgshapiro ++i; 1191125820Sgshapiro if (i + 1 >= l) 119264562Sgshapiro return _SMFIS_ABORT; 119364562Sgshapiro 119464562Sgshapiro /* Move past trailing \0 in host string */ 119564562Sgshapiro i++; 119664562Sgshapiro family = s[i++]; 1197120256Sgshapiro (void) memset(&sockaddr, '\0', sizeof sockaddr); 119864562Sgshapiro if (family != SMFIA_UNKNOWN) 119964562Sgshapiro { 1200125820Sgshapiro if (i + sizeof port >= l) 120164562Sgshapiro { 120264562Sgshapiro smi_log(SMI_LOG_ERR, 1203168515Sgshapiro "%s: connect[%ld]: wrong len %d >= %d", 120464562Sgshapiro g->a_ctx->ctx_smfi->xxfi_name, 1205168515Sgshapiro (long) g->a_ctx->ctx_id, (int) i, (int) l); 120664562Sgshapiro return _SMFIS_ABORT; 120764562Sgshapiro } 1208125820Sgshapiro (void) memcpy((void *) &port, (void *) (s + i), 1209125820Sgshapiro sizeof port); 1210125820Sgshapiro i += sizeof port; 121194334Sgshapiro 121294334Sgshapiro /* make sure string is terminated */ 121394334Sgshapiro if (s[l - 1] != '\0') 121494334Sgshapiro return _SMFIS_ABORT; 121564562Sgshapiro# if NETINET 121664562Sgshapiro if (family == SMFIA_INET) 121764562Sgshapiro { 121864562Sgshapiro if (inet_aton(s + i, (struct in_addr *) &sockaddr.sin.sin_addr) 121994334Sgshapiro != 1) 122064562Sgshapiro { 122164562Sgshapiro smi_log(SMI_LOG_ERR, 1222168515Sgshapiro "%s: connect[%ld]: inet_aton failed", 122364562Sgshapiro g->a_ctx->ctx_smfi->xxfi_name, 1224168515Sgshapiro (long) g->a_ctx->ctx_id); 122564562Sgshapiro return _SMFIS_ABORT; 122664562Sgshapiro } 122764562Sgshapiro sockaddr.sa.sa_family = AF_INET; 122864562Sgshapiro if (port > 0) 122964562Sgshapiro sockaddr.sin.sin_port = port; 123064562Sgshapiro } 123164562Sgshapiro else 123264562Sgshapiro# endif /* NETINET */ 123364562Sgshapiro# if NETINET6 123464562Sgshapiro if (family == SMFIA_INET6) 123564562Sgshapiro { 123690792Sgshapiro if (mi_inet_pton(AF_INET6, s + i, 123790792Sgshapiro &sockaddr.sin6.sin6_addr) != 1) 123864562Sgshapiro { 123964562Sgshapiro smi_log(SMI_LOG_ERR, 1240168515Sgshapiro "%s: connect[%ld]: mi_inet_pton failed", 124164562Sgshapiro g->a_ctx->ctx_smfi->xxfi_name, 1242168515Sgshapiro (long) g->a_ctx->ctx_id); 124364562Sgshapiro return _SMFIS_ABORT; 124464562Sgshapiro } 124564562Sgshapiro sockaddr.sa.sa_family = AF_INET6; 124664562Sgshapiro if (port > 0) 124764562Sgshapiro sockaddr.sin6.sin6_port = port; 124864562Sgshapiro } 124964562Sgshapiro else 125064562Sgshapiro# endif /* NETINET6 */ 125164562Sgshapiro# if NETUNIX 125264562Sgshapiro if (family == SMFIA_UNIX) 125364562Sgshapiro { 125490792Sgshapiro if (sm_strlcpy(sockaddr.sunix.sun_path, s + i, 125564562Sgshapiro sizeof sockaddr.sunix.sun_path) >= 125664562Sgshapiro sizeof sockaddr.sunix.sun_path) 125764562Sgshapiro { 125864562Sgshapiro smi_log(SMI_LOG_ERR, 1259168515Sgshapiro "%s: connect[%ld]: path too long", 126064562Sgshapiro g->a_ctx->ctx_smfi->xxfi_name, 1261168515Sgshapiro (long) g->a_ctx->ctx_id); 126264562Sgshapiro return _SMFIS_ABORT; 126364562Sgshapiro } 126464562Sgshapiro sockaddr.sunix.sun_family = AF_UNIX; 126564562Sgshapiro } 126664562Sgshapiro else 126764562Sgshapiro# endif /* NETUNIX */ 126864562Sgshapiro { 126964562Sgshapiro smi_log(SMI_LOG_ERR, 1270168515Sgshapiro "%s: connect[%ld]: unknown family %d", 127164562Sgshapiro g->a_ctx->ctx_smfi->xxfi_name, 1272168515Sgshapiro (long) g->a_ctx->ctx_id, family); 127364562Sgshapiro return _SMFIS_ABORT; 127464562Sgshapiro } 127564562Sgshapiro } 127664562Sgshapiro return (*fi_connect)(g->a_ctx, g->a_buf, 127764562Sgshapiro family != SMFIA_UNKNOWN ? &sockaddr : NULL); 127864562Sgshapiro} 1279132943Sgshapiro 128090792Sgshapiro/* 128164562Sgshapiro** ST_EOH -- end of headers 128264562Sgshapiro** 128364562Sgshapiro** Parameters: 128464562Sgshapiro** g -- generic argument structure 128564562Sgshapiro** 128664562Sgshapiro** Returns: 128764562Sgshapiro** continue or filter-specified value 128864562Sgshapiro*/ 128964562Sgshapiro 129064562Sgshapirostatic int 129164562Sgshapirost_eoh(g) 129264562Sgshapiro genarg *g; 129364562Sgshapiro{ 129464562Sgshapiro sfsistat (*fi_eoh) __P((SMFICTX *)); 129564562Sgshapiro 129664562Sgshapiro if (g == NULL) 129764562Sgshapiro return _SMFIS_ABORT; 129864562Sgshapiro if (g->a_ctx->ctx_smfi != NULL && 129964562Sgshapiro (fi_eoh = g->a_ctx->ctx_smfi->xxfi_eoh) != NULL) 130064562Sgshapiro return (*fi_eoh)(g->a_ctx); 130164562Sgshapiro return SMFIS_CONTINUE; 130264562Sgshapiro} 1303132943Sgshapiro 130490792Sgshapiro/* 1305132943Sgshapiro** ST_DATA -- DATA command 1306132943Sgshapiro** 1307132943Sgshapiro** Parameters: 1308132943Sgshapiro** g -- generic argument structure 1309132943Sgshapiro** 1310132943Sgshapiro** Returns: 1311132943Sgshapiro** continue or filter-specified value 1312132943Sgshapiro*/ 1313132943Sgshapiro 1314132943Sgshapirostatic int 1315132943Sgshapirost_data(g) 1316132943Sgshapiro genarg *g; 1317132943Sgshapiro{ 1318132943Sgshapiro sfsistat (*fi_data) __P((SMFICTX *)); 1319132943Sgshapiro 1320132943Sgshapiro if (g == NULL) 1321132943Sgshapiro return _SMFIS_ABORT; 1322132943Sgshapiro if (g->a_ctx->ctx_smfi != NULL && 1323168988Sgshapiro g->a_ctx->ctx_smfi->xxfi_version > 3 && 1324132943Sgshapiro (fi_data = g->a_ctx->ctx_smfi->xxfi_data) != NULL) 1325132943Sgshapiro return (*fi_data)(g->a_ctx); 1326132943Sgshapiro return SMFIS_CONTINUE; 1327132943Sgshapiro} 1328132943Sgshapiro 1329132943Sgshapiro/* 133064562Sgshapiro** ST_HELO -- helo/ehlo command 133164562Sgshapiro** 133264562Sgshapiro** Parameters: 133364562Sgshapiro** g -- generic argument structure 133464562Sgshapiro** 133564562Sgshapiro** Returns: 133664562Sgshapiro** continue or filter-specified value 133764562Sgshapiro*/ 1338168515Sgshapiro 133964562Sgshapirostatic int 134064562Sgshapirost_helo(g) 134164562Sgshapiro genarg *g; 134264562Sgshapiro{ 134364562Sgshapiro sfsistat (*fi_helo) __P((SMFICTX *, char *)); 134464562Sgshapiro 134564562Sgshapiro if (g == NULL) 134664562Sgshapiro return _SMFIS_ABORT; 134764562Sgshapiro mi_clr_macros(g->a_ctx, g->a_idx + 1); 134864562Sgshapiro if (g->a_ctx->ctx_smfi != NULL && 134964562Sgshapiro (fi_helo = g->a_ctx->ctx_smfi->xxfi_helo) != NULL) 1350125820Sgshapiro { 1351125820Sgshapiro /* paranoia: check for terminating '\0' */ 1352125820Sgshapiro if (g->a_len == 0 || g->a_buf[g->a_len - 1] != '\0') 1353125820Sgshapiro return MI_FAILURE; 135464562Sgshapiro return (*fi_helo)(g->a_ctx, g->a_buf); 1355125820Sgshapiro } 135664562Sgshapiro return SMFIS_CONTINUE; 135764562Sgshapiro} 1358168515Sgshapiro 135990792Sgshapiro/* 136064562Sgshapiro** ST_HEADER -- header line 136164562Sgshapiro** 136264562Sgshapiro** Parameters: 136364562Sgshapiro** g -- generic argument structure 136464562Sgshapiro** 136564562Sgshapiro** Returns: 136664562Sgshapiro** continue or filter-specified value 136764562Sgshapiro*/ 136864562Sgshapiro 136964562Sgshapirostatic int 137064562Sgshapirost_header(g) 137164562Sgshapiro genarg *g; 137264562Sgshapiro{ 137364562Sgshapiro char *hf, *hv; 137464562Sgshapiro sfsistat (*fi_header) __P((SMFICTX *, char *, char *)); 137564562Sgshapiro 137664562Sgshapiro if (g == NULL) 137764562Sgshapiro return _SMFIS_ABORT; 137864562Sgshapiro if (g->a_ctx->ctx_smfi == NULL || 137964562Sgshapiro (fi_header = g->a_ctx->ctx_smfi->xxfi_header) == NULL) 138064562Sgshapiro return SMFIS_CONTINUE; 138164562Sgshapiro if (dec_arg2(g->a_buf, g->a_len, &hf, &hv) == MI_SUCCESS) 138264562Sgshapiro return (*fi_header)(g->a_ctx, hf, hv); 138364562Sgshapiro else 138464562Sgshapiro return _SMFIS_ABORT; 138564562Sgshapiro} 138664562Sgshapiro 138790792Sgshapiro#define ARGV_FCT(lf, rf, idx) \ 138890792Sgshapiro char **argv; \ 138990792Sgshapiro sfsistat (*lf) __P((SMFICTX *, char **)); \ 139090792Sgshapiro int r; \ 139190792Sgshapiro \ 139290792Sgshapiro if (g == NULL) \ 139390792Sgshapiro return _SMFIS_ABORT; \ 139490792Sgshapiro mi_clr_macros(g->a_ctx, g->a_idx + 1); \ 139590792Sgshapiro if (g->a_ctx->ctx_smfi == NULL || \ 139690792Sgshapiro (lf = g->a_ctx->ctx_smfi->rf) == NULL) \ 139790792Sgshapiro return SMFIS_CONTINUE; \ 139864562Sgshapiro if ((argv = dec_argv(g->a_buf, g->a_len)) == NULL) \ 139990792Sgshapiro return _SMFIS_ABORT; \ 140090792Sgshapiro r = (*lf)(g->a_ctx, argv); \ 140190792Sgshapiro free(argv); \ 140264562Sgshapiro return r; 140364562Sgshapiro 140490792Sgshapiro/* 140564562Sgshapiro** ST_SENDER -- MAIL FROM command 140664562Sgshapiro** 140764562Sgshapiro** Parameters: 140864562Sgshapiro** g -- generic argument structure 140964562Sgshapiro** 141064562Sgshapiro** Returns: 141164562Sgshapiro** continue or filter-specified value 141264562Sgshapiro*/ 141364562Sgshapiro 141464562Sgshapirostatic int 141564562Sgshapirost_sender(g) 141664562Sgshapiro genarg *g; 141764562Sgshapiro{ 141864562Sgshapiro ARGV_FCT(fi_envfrom, xxfi_envfrom, CI_MAIL) 141964562Sgshapiro} 1420168515Sgshapiro 142190792Sgshapiro/* 142264562Sgshapiro** ST_RCPT -- RCPT TO command 142364562Sgshapiro** 142464562Sgshapiro** Parameters: 142564562Sgshapiro** g -- generic argument structure 142664562Sgshapiro** 142764562Sgshapiro** Returns: 142864562Sgshapiro** continue or filter-specified value 142964562Sgshapiro*/ 143064562Sgshapiro 143164562Sgshapirostatic int 143264562Sgshapirost_rcpt(g) 143364562Sgshapiro genarg *g; 143464562Sgshapiro{ 143564562Sgshapiro ARGV_FCT(fi_envrcpt, xxfi_envrcpt, CI_RCPT) 143664562Sgshapiro} 1437132943Sgshapiro 143890792Sgshapiro/* 1439132943Sgshapiro** ST_UNKNOWN -- unrecognized or unimplemented command 1440132943Sgshapiro** 1441132943Sgshapiro** Parameters: 1442132943Sgshapiro** g -- generic argument structure 1443132943Sgshapiro** 1444132943Sgshapiro** Returns: 1445132943Sgshapiro** continue or filter-specified value 1446132943Sgshapiro*/ 1447132943Sgshapiro 1448132943Sgshapirostatic int 1449132943Sgshapirost_unknown(g) 1450132943Sgshapiro genarg *g; 1451132943Sgshapiro{ 1452168515Sgshapiro sfsistat (*fi_unknown) __P((SMFICTX *, const char *)); 1453132943Sgshapiro 1454132943Sgshapiro if (g == NULL) 1455132943Sgshapiro return _SMFIS_ABORT; 1456132943Sgshapiro if (g->a_ctx->ctx_smfi != NULL && 1457168988Sgshapiro g->a_ctx->ctx_smfi->xxfi_version > 2 && 1458132943Sgshapiro (fi_unknown = g->a_ctx->ctx_smfi->xxfi_unknown) != NULL) 1459168515Sgshapiro return (*fi_unknown)(g->a_ctx, (const char *) g->a_buf); 1460132943Sgshapiro return SMFIS_CONTINUE; 1461132943Sgshapiro} 1462132943Sgshapiro 1463132943Sgshapiro/* 146464562Sgshapiro** ST_MACROS -- deal with macros received from the MTA 146564562Sgshapiro** 146664562Sgshapiro** Parameters: 146764562Sgshapiro** g -- generic argument structure 146864562Sgshapiro** 146964562Sgshapiro** Returns: 147064562Sgshapiro** continue/keep 147164562Sgshapiro** 147264562Sgshapiro** Side effects: 147364562Sgshapiro** set pointer in macro array to current values. 147464562Sgshapiro*/ 147564562Sgshapiro 147664562Sgshapirostatic int 147764562Sgshapirost_macros(g) 147864562Sgshapiro genarg *g; 147964562Sgshapiro{ 148064562Sgshapiro int i; 148164562Sgshapiro char **argv; 148264562Sgshapiro 148364562Sgshapiro if (g == NULL || g->a_len < 1) 148464562Sgshapiro return _SMFIS_FAIL; 148564562Sgshapiro if ((argv = dec_argv(g->a_buf + 1, g->a_len - 1)) == NULL) 148664562Sgshapiro return _SMFIS_FAIL; 148771345Sgshapiro switch (g->a_buf[0]) 148864562Sgshapiro { 148964562Sgshapiro case SMFIC_CONNECT: 149064562Sgshapiro i = CI_CONN; 149164562Sgshapiro break; 149264562Sgshapiro case SMFIC_HELO: 149364562Sgshapiro i = CI_HELO; 149464562Sgshapiro break; 149564562Sgshapiro case SMFIC_MAIL: 149664562Sgshapiro i = CI_MAIL; 149764562Sgshapiro break; 149864562Sgshapiro case SMFIC_RCPT: 149964562Sgshapiro i = CI_RCPT; 150064562Sgshapiro break; 1501168515Sgshapiro case SMFIC_DATA: 1502168515Sgshapiro i = CI_DATA; 1503168515Sgshapiro break; 1504125820Sgshapiro case SMFIC_BODYEOB: 1505125820Sgshapiro i = CI_EOM; 1506125820Sgshapiro break; 1507168515Sgshapiro case SMFIC_EOH: 1508168515Sgshapiro i = CI_EOH; 1509168515Sgshapiro break; 151064562Sgshapiro default: 151164562Sgshapiro free(argv); 151264562Sgshapiro return _SMFIS_FAIL; 151364562Sgshapiro } 151464562Sgshapiro if (g->a_ctx->ctx_mac_ptr[i] != NULL) 151564562Sgshapiro free(g->a_ctx->ctx_mac_ptr[i]); 151664562Sgshapiro if (g->a_ctx->ctx_mac_buf[i] != NULL) 151764562Sgshapiro free(g->a_ctx->ctx_mac_buf[i]); 151864562Sgshapiro g->a_ctx->ctx_mac_ptr[i] = argv; 151964562Sgshapiro g->a_ctx->ctx_mac_buf[i] = g->a_buf; 152064562Sgshapiro return _SMFIS_KEEP; 152164562Sgshapiro} 1522168515Sgshapiro 152390792Sgshapiro/* 152464562Sgshapiro** ST_QUIT -- quit command 152564562Sgshapiro** 152664562Sgshapiro** Parameters: 152764562Sgshapiro** g -- generic argument structure 152864562Sgshapiro** 152964562Sgshapiro** Returns: 153064562Sgshapiro** noreply 153164562Sgshapiro*/ 153264562Sgshapiro 1533120256Sgshapiro/* ARGSUSED */ 153464562Sgshapirostatic int 153564562Sgshapirost_quit(g) 153664562Sgshapiro genarg *g; 153764562Sgshapiro{ 1538168515Sgshapiro sfsistat (*fi_close) __P((SMFICTX *)); 1539168515Sgshapiro 1540168515Sgshapiro if (g == NULL) 1541168515Sgshapiro return _SMFIS_ABORT; 1542168515Sgshapiro if (g->a_ctx->ctx_smfi != NULL && 1543168515Sgshapiro (fi_close = g->a_ctx->ctx_smfi->xxfi_close) != NULL) 1544168515Sgshapiro (void) (*fi_close)(g->a_ctx); 1545168515Sgshapiro mi_clr_macros(g->a_ctx, 0); 154664562Sgshapiro return _SMFIS_NOREPLY; 154764562Sgshapiro} 1548168515Sgshapiro 154990792Sgshapiro/* 155064562Sgshapiro** ST_BODYCHUNK -- deal with a piece of the mail body 155164562Sgshapiro** 155264562Sgshapiro** Parameters: 155364562Sgshapiro** g -- generic argument structure 155464562Sgshapiro** 155564562Sgshapiro** Returns: 155664562Sgshapiro** continue or filter-specified value 155764562Sgshapiro*/ 155864562Sgshapiro 155964562Sgshapirostatic int 156064562Sgshapirost_bodychunk(g) 156164562Sgshapiro genarg *g; 156264562Sgshapiro{ 156390792Sgshapiro sfsistat (*fi_body) __P((SMFICTX *, unsigned char *, size_t)); 156464562Sgshapiro 156564562Sgshapiro if (g == NULL) 156664562Sgshapiro return _SMFIS_ABORT; 156764562Sgshapiro if (g->a_ctx->ctx_smfi != NULL && 156864562Sgshapiro (fi_body = g->a_ctx->ctx_smfi->xxfi_body) != NULL) 156990792Sgshapiro return (*fi_body)(g->a_ctx, (unsigned char *)g->a_buf, 157090792Sgshapiro g->a_len); 157164562Sgshapiro return SMFIS_CONTINUE; 157264562Sgshapiro} 1573168515Sgshapiro 157490792Sgshapiro/* 157564562Sgshapiro** ST_BODYEND -- deal with the last piece of the mail body 157664562Sgshapiro** 157764562Sgshapiro** Parameters: 157864562Sgshapiro** g -- generic argument structure 157964562Sgshapiro** 158064562Sgshapiro** Returns: 158164562Sgshapiro** continue or filter-specified value 158264562Sgshapiro** 158364562Sgshapiro** Side effects: 158464562Sgshapiro** sends a reply for the body part (if non-empty). 158564562Sgshapiro*/ 158664562Sgshapiro 158764562Sgshapirostatic int 158864562Sgshapirost_bodyend(g) 158964562Sgshapiro genarg *g; 159064562Sgshapiro{ 159164562Sgshapiro sfsistat r; 159290792Sgshapiro sfsistat (*fi_body) __P((SMFICTX *, unsigned char *, size_t)); 159364562Sgshapiro sfsistat (*fi_eom) __P((SMFICTX *)); 159464562Sgshapiro 159564562Sgshapiro if (g == NULL) 159664562Sgshapiro return _SMFIS_ABORT; 159764562Sgshapiro r = SMFIS_CONTINUE; 159864562Sgshapiro if (g->a_ctx->ctx_smfi != NULL) 159964562Sgshapiro { 160064562Sgshapiro if ((fi_body = g->a_ctx->ctx_smfi->xxfi_body) != NULL && 160164562Sgshapiro g->a_len > 0) 160264562Sgshapiro { 160364562Sgshapiro socket_t sd; 160464562Sgshapiro struct timeval timeout; 160564562Sgshapiro 160664562Sgshapiro timeout.tv_sec = g->a_ctx->ctx_timeout; 160764562Sgshapiro timeout.tv_usec = 0; 160864562Sgshapiro sd = g->a_ctx->ctx_sd; 160990792Sgshapiro r = (*fi_body)(g->a_ctx, (unsigned char *)g->a_buf, 161090792Sgshapiro g->a_len); 161164562Sgshapiro if (r != SMFIS_CONTINUE && 161264562Sgshapiro sendreply(r, sd, &timeout, g->a_ctx) != MI_SUCCESS) 161364562Sgshapiro return _SMFIS_ABORT; 161464562Sgshapiro } 161564562Sgshapiro } 161664562Sgshapiro if (r == SMFIS_CONTINUE && 161764562Sgshapiro (fi_eom = g->a_ctx->ctx_smfi->xxfi_eom) != NULL) 161864562Sgshapiro return (*fi_eom)(g->a_ctx); 161964562Sgshapiro return r; 162064562Sgshapiro} 1621168515Sgshapiro 162290792Sgshapiro/* 162364562Sgshapiro** ST_ABORTFCT -- deal with aborts 162464562Sgshapiro** 162564562Sgshapiro** Parameters: 162664562Sgshapiro** g -- generic argument structure 162764562Sgshapiro** 162864562Sgshapiro** Returns: 162964562Sgshapiro** abort or filter-specified value 163064562Sgshapiro*/ 163164562Sgshapiro 163264562Sgshapirostatic int 163364562Sgshapirost_abortfct(g) 163464562Sgshapiro genarg *g; 163564562Sgshapiro{ 163664562Sgshapiro sfsistat (*fi_abort) __P((SMFICTX *)); 163764562Sgshapiro 163864562Sgshapiro if (g == NULL) 163964562Sgshapiro return _SMFIS_ABORT; 164064562Sgshapiro if (g != NULL && g->a_ctx->ctx_smfi != NULL && 164164562Sgshapiro (fi_abort = g->a_ctx->ctx_smfi->xxfi_abort) != NULL) 164264562Sgshapiro (void) (*fi_abort)(g->a_ctx); 164364562Sgshapiro return _SMFIS_NOREPLY; 164464562Sgshapiro} 1645168515Sgshapiro 164690792Sgshapiro/* 164764562Sgshapiro** TRANS_OK -- is the state transition ok? 164864562Sgshapiro** 164964562Sgshapiro** Parameters: 165064562Sgshapiro** old -- old state 165164562Sgshapiro** new -- new state 165264562Sgshapiro** 165364562Sgshapiro** Returns: 165464562Sgshapiro** state transition ok 165564562Sgshapiro*/ 165664562Sgshapiro 165764562Sgshapirostatic bool 165864562Sgshapirotrans_ok(old, new) 165964562Sgshapiro int old, new; 166064562Sgshapiro{ 166164562Sgshapiro int s, n; 166264562Sgshapiro 166364562Sgshapiro s = old; 1664159609Sgshapiro if (s >= SIZE_NEXT_STATES) 1665159609Sgshapiro return false; 166666494Sgshapiro do 166766494Sgshapiro { 166864562Sgshapiro /* is this state transition allowed? */ 1669110560Sgshapiro if ((MI_MASK(new) & next_states[s]) != 0) 167090792Sgshapiro return true; 167164562Sgshapiro 167264562Sgshapiro /* 167364562Sgshapiro ** no: try next state; 167464562Sgshapiro ** this works since the relevant states are ordered 167564562Sgshapiro ** strict sequentially 167664562Sgshapiro */ 167790792Sgshapiro 167864562Sgshapiro n = s + 1; 1679159609Sgshapiro if (n >= SIZE_NEXT_STATES) 1680159609Sgshapiro return false; 168164562Sgshapiro 168264562Sgshapiro /* 168364562Sgshapiro ** can we actually "skip" this state? 168464562Sgshapiro ** see fix_stm() which sets this bit for those 168564562Sgshapiro ** states which the filter program is not interested in 168664562Sgshapiro */ 168790792Sgshapiro 168864562Sgshapiro if (bitset(NX_SKIP, next_states[n])) 168964562Sgshapiro s = n; 169064562Sgshapiro else 169190792Sgshapiro return false; 1692159609Sgshapiro } while (s < SIZE_NEXT_STATES); 169390792Sgshapiro return false; 169464562Sgshapiro} 1695168515Sgshapiro 169690792Sgshapiro/* 169764562Sgshapiro** FIX_STM -- add "skip" bits to the state transition table 169864562Sgshapiro** 169964562Sgshapiro** Parameters: 170064562Sgshapiro** ctx -- context structure 170164562Sgshapiro** 170264562Sgshapiro** Returns: 170364562Sgshapiro** None. 170464562Sgshapiro** 170564562Sgshapiro** Side effects: 170664562Sgshapiro** may change state transition table. 170764562Sgshapiro*/ 170864562Sgshapiro 170964562Sgshapirostatic void 171064562Sgshapirofix_stm(ctx) 171164562Sgshapiro SMFICTX_PTR ctx; 171264562Sgshapiro{ 171390792Sgshapiro unsigned long fl; 171464562Sgshapiro 171564562Sgshapiro if (ctx == NULL || ctx->ctx_smfi == NULL) 171664562Sgshapiro return; 171764562Sgshapiro fl = ctx->ctx_pflags; 171864562Sgshapiro if (bitset(SMFIP_NOCONNECT, fl)) 171964562Sgshapiro next_states[ST_CONN] |= NX_SKIP; 172064562Sgshapiro if (bitset(SMFIP_NOHELO, fl)) 172164562Sgshapiro next_states[ST_HELO] |= NX_SKIP; 172264562Sgshapiro if (bitset(SMFIP_NOMAIL, fl)) 172364562Sgshapiro next_states[ST_MAIL] |= NX_SKIP; 172464562Sgshapiro if (bitset(SMFIP_NORCPT, fl)) 172564562Sgshapiro next_states[ST_RCPT] |= NX_SKIP; 172664562Sgshapiro if (bitset(SMFIP_NOHDRS, fl)) 172764562Sgshapiro next_states[ST_HDRS] |= NX_SKIP; 172864562Sgshapiro if (bitset(SMFIP_NOEOH, fl)) 172964562Sgshapiro next_states[ST_EOHS] |= NX_SKIP; 173064562Sgshapiro if (bitset(SMFIP_NOBODY, fl)) 173164562Sgshapiro next_states[ST_BODY] |= NX_SKIP; 1732168515Sgshapiro if (bitset(SMFIP_NODATA, fl)) 1733168515Sgshapiro next_states[ST_DATA] |= NX_SKIP; 1734168515Sgshapiro if (bitset(SMFIP_NOUNKNOWN, fl)) 1735168515Sgshapiro next_states[ST_UNKN] |= NX_SKIP; 173664562Sgshapiro} 1737168515Sgshapiro 173890792Sgshapiro/* 173964562Sgshapiro** DEC_ARGV -- split a buffer into a list of strings, NULL terminated 174064562Sgshapiro** 174164562Sgshapiro** Parameters: 174264562Sgshapiro** buf -- buffer with several strings 174364562Sgshapiro** len -- length of buffer 174464562Sgshapiro** 174564562Sgshapiro** Returns: 174664562Sgshapiro** array of pointers to the individual strings 174764562Sgshapiro*/ 174864562Sgshapiro 174964562Sgshapirostatic char ** 175064562Sgshapirodec_argv(buf, len) 175164562Sgshapiro char *buf; 175264562Sgshapiro size_t len; 175364562Sgshapiro{ 175464562Sgshapiro char **s; 175564562Sgshapiro size_t i; 175664562Sgshapiro int elem, nelem; 175764562Sgshapiro 175864562Sgshapiro nelem = 0; 175964562Sgshapiro for (i = 0; i < len; i++) 176064562Sgshapiro { 176164562Sgshapiro if (buf[i] == '\0') 176264562Sgshapiro ++nelem; 176364562Sgshapiro } 176464562Sgshapiro if (nelem == 0) 176564562Sgshapiro return NULL; 176664562Sgshapiro 176764562Sgshapiro /* last entry is only for the name */ 176864562Sgshapiro s = (char **)malloc((nelem + 1) * (sizeof *s)); 176964562Sgshapiro if (s == NULL) 177064562Sgshapiro return NULL; 177164562Sgshapiro s[0] = buf; 177264562Sgshapiro for (i = 0, elem = 0; i < len && elem < nelem; i++) 177364562Sgshapiro { 177464562Sgshapiro if (buf[i] == '\0') 1775125820Sgshapiro { 1776125820Sgshapiro ++elem; 1777125820Sgshapiro if (i + 1 >= len) 1778125820Sgshapiro s[elem] = NULL; 1779125820Sgshapiro else 1780125820Sgshapiro s[elem] = &(buf[i + 1]); 1781125820Sgshapiro } 178264562Sgshapiro } 178364562Sgshapiro 1784125820Sgshapiro /* overwrite last entry (already done above, just paranoia) */ 178564562Sgshapiro s[elem] = NULL; 178664562Sgshapiro return s; 178764562Sgshapiro} 1788168515Sgshapiro 178990792Sgshapiro/* 179064562Sgshapiro** DEC_ARG2 -- split a buffer into two strings 179164562Sgshapiro** 179264562Sgshapiro** Parameters: 179364562Sgshapiro** buf -- buffer with two strings 179464562Sgshapiro** len -- length of buffer 179564562Sgshapiro** s1,s2 -- pointer to result strings 179664562Sgshapiro** 179764562Sgshapiro** Returns: 179864562Sgshapiro** MI_FAILURE/MI_SUCCESS 179964562Sgshapiro*/ 180064562Sgshapiro 180164562Sgshapirostatic int 180264562Sgshapirodec_arg2(buf, len, s1, s2) 180364562Sgshapiro char *buf; 180464562Sgshapiro size_t len; 180564562Sgshapiro char **s1; 180664562Sgshapiro char **s2; 180764562Sgshapiro{ 180864562Sgshapiro size_t i; 180964562Sgshapiro 1810125820Sgshapiro /* paranoia: check for terminating '\0' */ 1811125820Sgshapiro if (len == 0 || buf[len - 1] != '\0') 1812125820Sgshapiro return MI_FAILURE; 181364562Sgshapiro *s1 = buf; 181464562Sgshapiro for (i = 1; i < len && buf[i] != '\0'; i++) 181564562Sgshapiro continue; 181664562Sgshapiro if (i >= len - 1) 181764562Sgshapiro return MI_FAILURE; 181864562Sgshapiro *s2 = buf + i + 1; 181964562Sgshapiro return MI_SUCCESS; 182064562Sgshapiro} 1821168515Sgshapiro 182290792Sgshapiro/* 1823285303Sgshapiro** MI_SENDOK -- is it ok for the filter to send stuff to the MTA? 182464562Sgshapiro** 182564562Sgshapiro** Parameters: 182664562Sgshapiro** ctx -- context structure 182764562Sgshapiro** flag -- flag to check 182864562Sgshapiro** 182964562Sgshapiro** Returns: 183064562Sgshapiro** sending allowed (in current state) 183164562Sgshapiro*/ 183264562Sgshapiro 183364562Sgshapirobool 183464562Sgshapiromi_sendok(ctx, flag) 183564562Sgshapiro SMFICTX_PTR ctx; 183664562Sgshapiro int flag; 183764562Sgshapiro{ 183864562Sgshapiro if (ctx == NULL || ctx->ctx_smfi == NULL) 183990792Sgshapiro return false; 184090792Sgshapiro 184190792Sgshapiro /* did the milter request this operation? */ 1842168515Sgshapiro if (flag != 0 && !bitset(flag, ctx->ctx_aflags)) 184390792Sgshapiro return false; 184490792Sgshapiro 184590792Sgshapiro /* are we in the correct state? It must be "End of Message". */ 184664562Sgshapiro return ctx->ctx_state == ST_ENDM; 184764562Sgshapiro} 1848168515Sgshapiro 1849168515Sgshapiro#if _FFR_WORKERS_POOL 1850168515Sgshapiro/* 1851168515Sgshapiro** MI_RD_SOCKET_READY - checks if the socket is ready for read(2) 1852168515Sgshapiro** 1853168515Sgshapiro** Parameters: 1854168515Sgshapiro** sd -- socket_t 1855168515Sgshapiro** 1856168515Sgshapiro** Returns: 1857168515Sgshapiro** true iff socket is ready for read(2) 1858168515Sgshapiro*/ 1859168515Sgshapiro 1860168515Sgshapiro#define MI_RD_CMD_TO 1 1861168515Sgshapiro#define MI_RD_MAX_ERR 16 1862168515Sgshapiro 1863168515Sgshapirostatic bool 1864168515Sgshapiromi_rd_socket_ready (sd) 1865168515Sgshapiro socket_t sd; 1866168515Sgshapiro{ 1867168515Sgshapiro int n; 1868168515Sgshapiro int nerr = 0; 1869168515Sgshapiro#if SM_CONF_POLL 1870182352Sgshapiro struct pollfd pfd; 1871168515Sgshapiro#else /* SM_CONF_POLL */ 1872182352Sgshapiro fd_set rd_set, exc_set; 1873168515Sgshapiro#endif /* SM_CONF_POLL */ 1874168515Sgshapiro 1875168515Sgshapiro do 1876168515Sgshapiro { 1877168515Sgshapiro#if SM_CONF_POLL 1878168515Sgshapiro pfd.fd = sd; 1879168515Sgshapiro pfd.events = POLLIN; 1880168515Sgshapiro pfd.revents = 0; 1881168515Sgshapiro 1882168515Sgshapiro n = poll(&pfd, 1, MI_RD_CMD_TO); 1883168515Sgshapiro#else /* SM_CONF_POLL */ 1884168515Sgshapiro struct timeval timeout; 1885168515Sgshapiro 1886168515Sgshapiro FD_ZERO(&rd_set); 1887168515Sgshapiro FD_ZERO(&exc_set); 1888168515Sgshapiro FD_SET(sd, &rd_set); 1889168515Sgshapiro FD_SET(sd, &exc_set); 1890168515Sgshapiro 1891168515Sgshapiro timeout.tv_sec = MI_RD_CMD_TO / 1000; 1892168515Sgshapiro timeout.tv_usec = 0; 1893168515Sgshapiro n = select(sd + 1, &rd_set, NULL, &exc_set, &timeout); 1894168515Sgshapiro#endif /* SM_CONF_POLL */ 1895168515Sgshapiro 1896168515Sgshapiro if (n < 0) 1897168515Sgshapiro { 1898168515Sgshapiro if (errno == EINTR) 1899168515Sgshapiro { 1900168515Sgshapiro nerr++; 1901168515Sgshapiro continue; 1902168515Sgshapiro } 1903168515Sgshapiro return true; 1904168515Sgshapiro } 1905168515Sgshapiro 1906168515Sgshapiro if (n == 0) 1907168515Sgshapiro return false; 1908168515Sgshapiro break; 1909168515Sgshapiro } while (nerr < MI_RD_MAX_ERR); 1910168515Sgshapiro if (nerr >= MI_RD_MAX_ERR) 1911168515Sgshapiro return false; 1912168515Sgshapiro 1913168515Sgshapiro#if SM_CONF_POLL 1914168515Sgshapiro return (pfd.revents != 0); 1915168515Sgshapiro#else /* SM_CONF_POLL */ 1916168515Sgshapiro return FD_ISSET(sd, &rd_set) || FD_ISSET(sd, &exc_set); 1917168515Sgshapiro#endif /* SM_CONF_POLL */ 1918168515Sgshapiro} 1919168515Sgshapiro#endif /* _FFR_WORKERS_POOL */ 1920