164562Sgshapiro/* 2182352Sgshapiro * Copyright (c) 1999-2004, 2006-2008 Sendmail, 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> 12223067SgshapiroSM_RCSID("@(#)$Id: engine.c,v 8.167 2011/03/03 06:09:15 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 */ 4564562Sgshapiro#define CM_ARG0 0 /* no args */ 4664562Sgshapiro#define CM_ARG1 1 /* one arg (string) */ 4764562Sgshapiro#define CM_ARG2 2 /* two args (strings) */ 4864562Sgshapiro#define CM_ARGA 4 /* one string and _SOCK_ADDR */ 4964562Sgshapiro#define CM_ARGO 5 /* two integers */ 5064562Sgshapiro#define CM_ARGV 8 /* \0 separated list of args, NULL-terminated */ 5164562Sgshapiro#define CM_ARGN 9 /* \0 separated list of args (strings) */ 5264562Sgshapiro 5364562Sgshapiro/* possible values for cm_todo */ 5464562Sgshapiro#define CT_CONT 0x0000 /* continue reading commands */ 5564562Sgshapiro#define CT_IGNO 0x0001 /* continue even when error */ 5664562Sgshapiro 5764562Sgshapiro/* not needed right now, done via return code instead */ 5864562Sgshapiro#define CT_KEEP 0x0004 /* keep buffer (contains symbols) */ 59168515Sgshapiro#define CT_END 0x0008 /* last command of session, stop replying */ 6064562Sgshapiro 6164562Sgshapiro/* index in macro array: macros only for these commands */ 62125820Sgshapiro#define CI_NONE (-1) 63125820Sgshapiro#define CI_CONN 0 64125820Sgshapiro#define CI_HELO 1 65125820Sgshapiro#define CI_MAIL 2 66125820Sgshapiro#define CI_RCPT 3 67168515Sgshapiro#define CI_DATA 4 68168515Sgshapiro#define CI_EOM 5 69168515Sgshapiro#define CI_EOH 6 70168515Sgshapiro#define CI_LAST CI_EOH 71168515Sgshapiro#if CI_LAST < CI_DATA 72168515SgshapiroERROR: do not compile with CI_LAST < CI_DATA 73132943Sgshapiro#endif 74168515Sgshapiro#if CI_LAST < CI_EOM 75168515SgshapiroERROR: do not compile with CI_LAST < CI_EOM 76168515Sgshapiro#endif 77168515Sgshapiro#if CI_LAST < CI_EOH 78168515SgshapiroERROR: do not compile with CI_LAST < CI_EOH 79168515Sgshapiro#endif 80168515Sgshapiro#if CI_LAST < CI_ENVRCPT 81168515SgshapiroERROR: do not compile with CI_LAST < CI_ENVRCPT 82168515Sgshapiro#endif 83168515Sgshapiro#if CI_LAST < CI_ENVFROM 84168515SgshapiroERROR: do not compile with CI_LAST < CI_ENVFROM 85168515Sgshapiro#endif 86168515Sgshapiro#if CI_LAST < CI_HELO 87168515SgshapiroERROR: do not compile with CI_LAST < CI_HELO 88168515Sgshapiro#endif 89168515Sgshapiro#if CI_LAST < CI_CONNECT 90168515SgshapiroERROR: do not compile with CI_LAST < CI_CONNECT 91168515Sgshapiro#endif 92168515Sgshapiro#if CI_LAST >= MAX_MACROS_ENTRIES 93168515SgshapiroERROR: do not compile with CI_LAST >= MAX_MACROS_ENTRIES 94168515Sgshapiro#endif 9564562Sgshapiro 9664562Sgshapiro/* function prototypes */ 9764562Sgshapirostatic int st_abortfct __P((genarg *)); 9864562Sgshapirostatic int st_macros __P((genarg *)); 9964562Sgshapirostatic int st_optionneg __P((genarg *)); 10064562Sgshapirostatic int st_bodychunk __P((genarg *)); 10164562Sgshapirostatic int st_connectinfo __P((genarg *)); 10264562Sgshapirostatic int st_bodyend __P((genarg *)); 10364562Sgshapirostatic int st_helo __P((genarg *)); 10464562Sgshapirostatic int st_header __P((genarg *)); 10564562Sgshapirostatic int st_sender __P((genarg *)); 10664562Sgshapirostatic int st_rcpt __P((genarg *)); 107132943Sgshapirostatic int st_unknown __P((genarg *)); 108132943Sgshapirostatic int st_data __P((genarg *)); 10964562Sgshapirostatic int st_eoh __P((genarg *)); 11064562Sgshapirostatic int st_quit __P((genarg *)); 11164562Sgshapirostatic int sendreply __P((sfsistat, socket_t, struct timeval *, SMFICTX_PTR)); 11264562Sgshapirostatic void fix_stm __P((SMFICTX_PTR)); 11364562Sgshapirostatic bool trans_ok __P((int, int)); 11464562Sgshapirostatic char **dec_argv __P((char *, size_t)); 11564562Sgshapirostatic int dec_arg2 __P((char *, size_t, char **, char **)); 116203004Sgshapirostatic void mi_clr_symlist __P((SMFICTX_PTR)); 11764562Sgshapiro 118168515Sgshapiro#if _FFR_WORKERS_POOL 119168515Sgshapirostatic bool mi_rd_socket_ready __P((int)); 120168515Sgshapiro#endif /* _FFR_WORKERS_POOL */ 121168515Sgshapiro 12264562Sgshapiro/* states */ 12364562Sgshapiro#define ST_NONE (-1) 12464562Sgshapiro#define ST_INIT 0 /* initial state */ 12564562Sgshapiro#define ST_OPTS 1 /* option negotiation */ 12664562Sgshapiro#define ST_CONN 2 /* connection info */ 12764562Sgshapiro#define ST_HELO 3 /* helo */ 12864562Sgshapiro#define ST_MAIL 4 /* mail from */ 12964562Sgshapiro#define ST_RCPT 5 /* rcpt to */ 130132943Sgshapiro#define ST_DATA 6 /* data */ 131132943Sgshapiro#define ST_HDRS 7 /* headers */ 132132943Sgshapiro#define ST_EOHS 8 /* end of headers */ 133132943Sgshapiro#define ST_BODY 9 /* body */ 134132943Sgshapiro#define ST_ENDM 10 /* end of message */ 135132943Sgshapiro#define ST_QUIT 11 /* quit */ 136132943Sgshapiro#define ST_ABRT 12 /* abort */ 137132943Sgshapiro#define ST_UNKN 13 /* unknown SMTP command */ 138168515Sgshapiro#define ST_Q_NC 14 /* quit, new connection follows */ 139168515Sgshapiro#define ST_LAST ST_Q_NC /* last valid state */ 140168515Sgshapiro#define ST_SKIP 16 /* not a state but required for the state table */ 14164562Sgshapiro 14264562Sgshapiro/* in a mail transaction? must be before eom according to spec. */ 14364562Sgshapiro#define ST_IN_MAIL(st) ((st) >= ST_MAIL && (st) < ST_ENDM) 14464562Sgshapiro 14564562Sgshapiro/* 14664562Sgshapiro** set of next states 14764562Sgshapiro** each state (ST_*) corresponds to bit in an int value (1 << state) 14864562Sgshapiro** each state has a set of allowed transitions ('or' of bits of states) 14964562Sgshapiro** so a state transition is valid if the mask of the next state 15064562Sgshapiro** is set in the NX_* value 15164562Sgshapiro** this function is coded in trans_ok(), see below. 15264562Sgshapiro*/ 15390792Sgshapiro 154110560Sgshapiro#define MI_MASK(x) (0x0001 << (x)) /* generate a bit "mask" for a state */ 155110560Sgshapiro#define NX_INIT (MI_MASK(ST_OPTS)) 156132943Sgshapiro#define NX_OPTS (MI_MASK(ST_CONN) | MI_MASK(ST_UNKN)) 157132943Sgshapiro#define NX_CONN (MI_MASK(ST_HELO) | MI_MASK(ST_MAIL) | MI_MASK(ST_UNKN)) 158132943Sgshapiro#define NX_HELO (MI_MASK(ST_HELO) | MI_MASK(ST_MAIL) | MI_MASK(ST_UNKN)) 159132943Sgshapiro#define NX_MAIL (MI_MASK(ST_RCPT) | MI_MASK(ST_ABRT) | MI_MASK(ST_UNKN)) 160132943Sgshapiro#define NX_RCPT (MI_MASK(ST_HDRS) | MI_MASK(ST_EOHS) | MI_MASK(ST_DATA) | \ 161110560Sgshapiro MI_MASK(ST_BODY) | MI_MASK(ST_ENDM) | \ 162132943Sgshapiro MI_MASK(ST_RCPT) | MI_MASK(ST_ABRT) | MI_MASK(ST_UNKN)) 163132943Sgshapiro#define NX_DATA (MI_MASK(ST_EOHS) | MI_MASK(ST_HDRS) | MI_MASK(ST_ABRT)) 164110560Sgshapiro#define NX_HDRS (MI_MASK(ST_EOHS) | MI_MASK(ST_HDRS) | MI_MASK(ST_ABRT)) 165110560Sgshapiro#define NX_EOHS (MI_MASK(ST_BODY) | MI_MASK(ST_ENDM) | MI_MASK(ST_ABRT)) 166110560Sgshapiro#define NX_BODY (MI_MASK(ST_ENDM) | MI_MASK(ST_BODY) | MI_MASK(ST_ABRT)) 167168515Sgshapiro#define NX_ENDM (MI_MASK(ST_QUIT) | MI_MASK(ST_MAIL) | MI_MASK(ST_UNKN) | \ 168168515Sgshapiro MI_MASK(ST_Q_NC)) 16964562Sgshapiro#define NX_QUIT 0 17064562Sgshapiro#define NX_ABRT 0 171132943Sgshapiro#define NX_UNKN (MI_MASK(ST_HELO) | MI_MASK(ST_MAIL) | \ 172132943Sgshapiro MI_MASK(ST_RCPT) | MI_MASK(ST_ABRT) | \ 173132943Sgshapiro MI_MASK(ST_DATA) | \ 174132943Sgshapiro MI_MASK(ST_BODY) | MI_MASK(ST_UNKN) | \ 175168515Sgshapiro MI_MASK(ST_ABRT) | MI_MASK(ST_QUIT) | MI_MASK(ST_Q_NC)) 176168515Sgshapiro#define NX_Q_NC (MI_MASK(ST_CONN) | MI_MASK(ST_UNKN)) 177110560Sgshapiro#define NX_SKIP MI_MASK(ST_SKIP) 17864562Sgshapiro 17964562Sgshapirostatic int next_states[] = 18064562Sgshapiro{ 181168515Sgshapiro NX_INIT 182168515Sgshapiro , NX_OPTS 183168515Sgshapiro , NX_CONN 184168515Sgshapiro , NX_HELO 185168515Sgshapiro , NX_MAIL 186168515Sgshapiro , NX_RCPT 187168515Sgshapiro , NX_DATA 188168515Sgshapiro , NX_HDRS 189168515Sgshapiro , NX_EOHS 190168515Sgshapiro , NX_BODY 191168515Sgshapiro , NX_ENDM 192168515Sgshapiro , NX_QUIT 193168515Sgshapiro , NX_ABRT 194168515Sgshapiro , NX_UNKN 195168515Sgshapiro , NX_Q_NC 19664562Sgshapiro}; 19764562Sgshapiro 198159609Sgshapiro#define SIZE_NEXT_STATES (sizeof(next_states) / sizeof(next_states[0])) 199159609Sgshapiro 20064562Sgshapiro/* commands received by milter */ 20164562Sgshapirostatic cmdfct cmds[] = 20264562Sgshapiro{ 203168515Sgshapiro {SMFIC_ABORT, CM_ARG0, ST_ABRT, CT_CONT, CI_NONE, st_abortfct } 204168515Sgshapiro, {SMFIC_MACRO, CM_ARGV, ST_NONE, CT_KEEP, CI_NONE, st_macros } 205168515Sgshapiro, {SMFIC_BODY, CM_ARG1, ST_BODY, CT_CONT, CI_NONE, st_bodychunk } 206168515Sgshapiro, {SMFIC_CONNECT, CM_ARG2, ST_CONN, CT_CONT, CI_CONN, st_connectinfo } 207168515Sgshapiro, {SMFIC_BODYEOB, CM_ARG1, ST_ENDM, CT_CONT, CI_EOM, st_bodyend } 208168515Sgshapiro, {SMFIC_HELO, CM_ARG1, ST_HELO, CT_CONT, CI_HELO, st_helo } 209168515Sgshapiro, {SMFIC_HEADER, CM_ARG2, ST_HDRS, CT_CONT, CI_NONE, st_header } 210168515Sgshapiro, {SMFIC_MAIL, CM_ARGV, ST_MAIL, CT_CONT, CI_MAIL, st_sender } 211168515Sgshapiro, {SMFIC_OPTNEG, CM_ARGO, ST_OPTS, CT_CONT, CI_NONE, st_optionneg } 212168515Sgshapiro, {SMFIC_EOH, CM_ARG0, ST_EOHS, CT_CONT, CI_EOH, st_eoh } 213168515Sgshapiro, {SMFIC_QUIT, CM_ARG0, ST_QUIT, CT_END, CI_NONE, st_quit } 214168515Sgshapiro, {SMFIC_DATA, CM_ARG0, ST_DATA, CT_CONT, CI_DATA, st_data } 215168515Sgshapiro, {SMFIC_RCPT, CM_ARGV, ST_RCPT, CT_IGNO, CI_RCPT, st_rcpt } 216168515Sgshapiro, {SMFIC_UNKNOWN, CM_ARG1, ST_UNKN, CT_IGNO, CI_NONE, st_unknown } 217168515Sgshapiro, {SMFIC_QUIT_NC, CM_ARG0, ST_Q_NC, CT_CONT, CI_NONE, st_quit } 21864562Sgshapiro}; 21964562Sgshapiro 220168515Sgshapiro/* 221168515Sgshapiro** Additional (internal) reply codes; 222168515Sgshapiro** must be coordinated wit libmilter/mfapi.h 223168515Sgshapiro*/ 224168515Sgshapiro 22564562Sgshapiro#define _SMFIS_KEEP 20 22664562Sgshapiro#define _SMFIS_ABORT 21 22764562Sgshapiro#define _SMFIS_OPTIONS 22 228168515Sgshapiro#define _SMFIS_NOREPLY SMFIS_NOREPLY 22964562Sgshapiro#define _SMFIS_FAIL (-1) 23090792Sgshapiro#define _SMFIS_NONE (-2) 23164562Sgshapiro 23290792Sgshapiro/* 23364562Sgshapiro** MI_ENGINE -- receive commands and process them 23464562Sgshapiro** 23564562Sgshapiro** Parameters: 23664562Sgshapiro** ctx -- context structure 23764562Sgshapiro** 23864562Sgshapiro** Returns: 23964562Sgshapiro** MI_FAILURE/MI_SUCCESS 24064562Sgshapiro*/ 241168515Sgshapiro 24264562Sgshapiroint 24364562Sgshapiromi_engine(ctx) 24464562Sgshapiro SMFICTX_PTR ctx; 24564562Sgshapiro{ 24664562Sgshapiro size_t len; 24764562Sgshapiro int i; 24864562Sgshapiro socket_t sd; 24964562Sgshapiro int ret = MI_SUCCESS; 25064562Sgshapiro int ncmds = sizeof(cmds) / sizeof(cmdfct); 25164562Sgshapiro int curstate = ST_INIT; 25264562Sgshapiro int newstate; 25364562Sgshapiro bool call_abort; 25464562Sgshapiro sfsistat r; 25564562Sgshapiro char cmd; 25664562Sgshapiro char *buf = NULL; 25764562Sgshapiro genarg arg; 25864562Sgshapiro struct timeval timeout; 25964562Sgshapiro int (*f) __P((genarg *)); 26064562Sgshapiro sfsistat (*fi_abort) __P((SMFICTX *)); 26164562Sgshapiro sfsistat (*fi_close) __P((SMFICTX *)); 26264562Sgshapiro 26364562Sgshapiro arg.a_ctx = ctx; 26464562Sgshapiro sd = ctx->ctx_sd; 26564562Sgshapiro fi_abort = ctx->ctx_smfi->xxfi_abort; 266168515Sgshapiro#if _FFR_WORKERS_POOL 267168515Sgshapiro curstate = ctx->ctx_state; 268168515Sgshapiro if (curstate == ST_INIT) 269168515Sgshapiro { 270168515Sgshapiro mi_clr_macros(ctx, 0); 271168515Sgshapiro fix_stm(ctx); 272168515Sgshapiro } 273168515Sgshapiro#else /* _FFR_WORKERS_POOL */ 27464562Sgshapiro mi_clr_macros(ctx, 0); 27564562Sgshapiro fix_stm(ctx); 276168515Sgshapiro#endif /* _FFR_WORKERS_POOL */ 27790792Sgshapiro r = _SMFIS_NONE; 27866494Sgshapiro do 27966494Sgshapiro { 28064562Sgshapiro /* call abort only if in a mail transaction */ 28164562Sgshapiro call_abort = ST_IN_MAIL(curstate); 28264562Sgshapiro timeout.tv_sec = ctx->ctx_timeout; 28364562Sgshapiro timeout.tv_usec = 0; 28464562Sgshapiro if (mi_stop() == MILTER_ABRT) 28564562Sgshapiro { 28664562Sgshapiro if (ctx->ctx_dbg > 3) 287223067Sgshapiro sm_dprintf("[%lu] milter_abort\n", 288168515Sgshapiro (long) ctx->ctx_id); 28964562Sgshapiro ret = MI_FAILURE; 29064562Sgshapiro break; 29164562Sgshapiro } 29290792Sgshapiro 29390792Sgshapiro /* 29490792Sgshapiro ** Notice: buf is allocated by mi_rd_cmd() and it will 29590792Sgshapiro ** usually be free()d after it has been used in f(). 29690792Sgshapiro ** However, if the function returns _SMFIS_KEEP then buf 29790792Sgshapiro ** contains macros and will not be free()d. 29890792Sgshapiro ** Hence r must be set to _SMFIS_NONE if a new buf is 29990792Sgshapiro ** allocated to avoid problem with housekeeping, esp. 30090792Sgshapiro ** if the code "break"s out of the loop. 30190792Sgshapiro */ 30290792Sgshapiro 303168515Sgshapiro#if _FFR_WORKERS_POOL 304168515Sgshapiro /* Is the socket ready to be read ??? */ 305168515Sgshapiro if (!mi_rd_socket_ready(sd)) 306168515Sgshapiro { 307168515Sgshapiro ret = MI_CONTINUE; 308168515Sgshapiro break; 309168515Sgshapiro } 310168515Sgshapiro#endif /* _FFR_WORKERS_POOL */ 311168515Sgshapiro 31290792Sgshapiro r = _SMFIS_NONE; 31364562Sgshapiro if ((buf = mi_rd_cmd(sd, &timeout, &cmd, &len, 31464562Sgshapiro ctx->ctx_smfi->xxfi_name)) == NULL && 31564562Sgshapiro cmd < SMFIC_VALIDCMD) 31664562Sgshapiro { 31764562Sgshapiro if (ctx->ctx_dbg > 5) 318223067Sgshapiro sm_dprintf("[%lu] mi_engine: mi_rd_cmd error (%x)\n", 319168515Sgshapiro (long) ctx->ctx_id, (int) cmd); 32064562Sgshapiro 32164562Sgshapiro /* 32264562Sgshapiro ** eof is currently treated as failure -> 32364562Sgshapiro ** abort() instead of close(), otherwise use: 32464562Sgshapiro ** if (cmd != SMFIC_EOF) 32564562Sgshapiro */ 32664562Sgshapiro 32764562Sgshapiro ret = MI_FAILURE; 32864562Sgshapiro break; 32964562Sgshapiro } 33064562Sgshapiro if (ctx->ctx_dbg > 4) 331223067Sgshapiro sm_dprintf("[%lu] got cmd '%c' len %d\n", 332168515Sgshapiro (long) ctx->ctx_id, cmd, (int) len); 33364562Sgshapiro for (i = 0; i < ncmds; i++) 33464562Sgshapiro { 33564562Sgshapiro if (cmd == cmds[i].cm_cmd) 33664562Sgshapiro break; 33764562Sgshapiro } 33864562Sgshapiro if (i >= ncmds) 33964562Sgshapiro { 34064562Sgshapiro /* unknown command */ 34164562Sgshapiro if (ctx->ctx_dbg > 1) 342223067Sgshapiro sm_dprintf("[%lu] cmd '%c' unknown\n", 343168515Sgshapiro (long) ctx->ctx_id, cmd); 34464562Sgshapiro ret = MI_FAILURE; 34564562Sgshapiro break; 34664562Sgshapiro } 34764562Sgshapiro if ((f = cmds[i].cm_fct) == NULL) 34864562Sgshapiro { 34964562Sgshapiro /* stop for now */ 35064562Sgshapiro if (ctx->ctx_dbg > 1) 351223067Sgshapiro sm_dprintf("[%lu] cmd '%c' not impl\n", 352168515Sgshapiro (long) ctx->ctx_id, cmd); 35364562Sgshapiro ret = MI_FAILURE; 35464562Sgshapiro break; 35564562Sgshapiro } 35664562Sgshapiro 35764562Sgshapiro /* is new state ok? */ 35864562Sgshapiro newstate = cmds[i].cm_next; 35964562Sgshapiro if (ctx->ctx_dbg > 5) 360223067Sgshapiro sm_dprintf("[%lu] cur %x new %x nextmask %x\n", 361168515Sgshapiro (long) ctx->ctx_id, 36264562Sgshapiro curstate, newstate, next_states[curstate]); 36364562Sgshapiro 36464562Sgshapiro if (newstate != ST_NONE && !trans_ok(curstate, newstate)) 36564562Sgshapiro { 36664562Sgshapiro if (ctx->ctx_dbg > 1) 367223067Sgshapiro sm_dprintf("[%lu] abort: cur %d (%x) new %d (%x) next %x\n", 368168515Sgshapiro (long) ctx->ctx_id, 369110560Sgshapiro curstate, MI_MASK(curstate), 370110560Sgshapiro newstate, MI_MASK(newstate), 37164562Sgshapiro next_states[curstate]); 37264562Sgshapiro 37364562Sgshapiro /* call abort only if in a mail transaction */ 37464562Sgshapiro if (fi_abort != NULL && call_abort) 37564562Sgshapiro (void) (*fi_abort)(ctx); 37664562Sgshapiro 37764562Sgshapiro /* 37864562Sgshapiro ** try to reach the new state from HELO 37964562Sgshapiro ** if it can't be reached, ignore the command. 38064562Sgshapiro */ 38164562Sgshapiro 38264562Sgshapiro curstate = ST_HELO; 38364562Sgshapiro if (!trans_ok(curstate, newstate)) 38490792Sgshapiro { 385102528Sgshapiro if (buf != NULL) 386102528Sgshapiro { 387102528Sgshapiro free(buf); 388102528Sgshapiro buf = NULL; 389102528Sgshapiro } 39064562Sgshapiro continue; 39190792Sgshapiro } 39264562Sgshapiro } 39364562Sgshapiro arg.a_len = len; 39464562Sgshapiro arg.a_buf = buf; 39564562Sgshapiro if (newstate != ST_NONE) 39664562Sgshapiro { 39764562Sgshapiro curstate = newstate; 39864562Sgshapiro ctx->ctx_state = curstate; 39964562Sgshapiro } 40064562Sgshapiro arg.a_idx = cmds[i].cm_macros; 401141858Sgshapiro call_abort = ST_IN_MAIL(curstate); 40264562Sgshapiro 40364562Sgshapiro /* call function to deal with command */ 404168515Sgshapiro MI_MONITOR_BEGIN(ctx, cmd); 40564562Sgshapiro r = (*f)(&arg); 406168515Sgshapiro MI_MONITOR_END(ctx, cmd); 40764562Sgshapiro if (r != _SMFIS_KEEP && buf != NULL) 40864562Sgshapiro { 40964562Sgshapiro free(buf); 41064562Sgshapiro buf = NULL; 41164562Sgshapiro } 41264562Sgshapiro if (sendreply(r, sd, &timeout, ctx) != MI_SUCCESS) 41364562Sgshapiro { 41464562Sgshapiro ret = MI_FAILURE; 41564562Sgshapiro break; 41664562Sgshapiro } 41764562Sgshapiro 41864562Sgshapiro if (r == SMFIS_ACCEPT) 41964562Sgshapiro { 42064562Sgshapiro /* accept mail, no further actions taken */ 42164562Sgshapiro curstate = ST_HELO; 42264562Sgshapiro } 42364562Sgshapiro else if (r == SMFIS_REJECT || r == SMFIS_DISCARD || 42464562Sgshapiro r == SMFIS_TEMPFAIL) 42564562Sgshapiro { 42664562Sgshapiro /* 42764562Sgshapiro ** further actions depend on current state 42864562Sgshapiro ** if the IGNO bit is set: "ignore" the error, 42964562Sgshapiro ** i.e., stay in the current state 43064562Sgshapiro */ 43164562Sgshapiro if (!bitset(CT_IGNO, cmds[i].cm_todo)) 43264562Sgshapiro curstate = ST_HELO; 43364562Sgshapiro } 43464562Sgshapiro else if (r == _SMFIS_ABORT) 43564562Sgshapiro { 43664562Sgshapiro if (ctx->ctx_dbg > 5) 437223067Sgshapiro sm_dprintf("[%lu] function returned abort\n", 438168515Sgshapiro (long) ctx->ctx_id); 43964562Sgshapiro ret = MI_FAILURE; 44064562Sgshapiro break; 44164562Sgshapiro } 44264562Sgshapiro } while (!bitset(CT_END, cmds[i].cm_todo)); 44364562Sgshapiro 444168515Sgshapiro ctx->ctx_state = curstate; 445168515Sgshapiro 446168515Sgshapiro if (ret == MI_FAILURE) 44764562Sgshapiro { 44864562Sgshapiro /* call abort only if in a mail transaction */ 44964562Sgshapiro if (fi_abort != NULL && call_abort) 45064562Sgshapiro (void) (*fi_abort)(ctx); 45164562Sgshapiro } 45264562Sgshapiro 453168515Sgshapiro /* has close been called? */ 454168515Sgshapiro if (ctx->ctx_state != ST_QUIT 455168515Sgshapiro#if _FFR_WORKERS_POOL 456168515Sgshapiro && ret != MI_CONTINUE 457168515Sgshapiro#endif /* _FFR_WORKERS_POOL */ 458168515Sgshapiro ) 459168515Sgshapiro { 460168515Sgshapiro if ((fi_close = ctx->ctx_smfi->xxfi_close) != NULL) 461168515Sgshapiro (void) (*fi_close)(ctx); 462168515Sgshapiro } 46390792Sgshapiro if (r != _SMFIS_KEEP && buf != NULL) 46464562Sgshapiro free(buf); 465168515Sgshapiro#if !_FFR_WORKERS_POOL 46664562Sgshapiro mi_clr_macros(ctx, 0); 467168515Sgshapiro#endif /* _FFR_WORKERS_POOL */ 46864562Sgshapiro return ret; 46964562Sgshapiro} 470168515Sgshapiro 471168515Sgshapirostatic size_t milter_addsymlist __P((SMFICTX_PTR, char *, char **)); 472168515Sgshapiro 473168515Sgshapirostatic size_t 474168515Sgshapiromilter_addsymlist(ctx, buf, newbuf) 475168515Sgshapiro SMFICTX_PTR ctx; 476168515Sgshapiro char *buf; 477168515Sgshapiro char **newbuf; 478168515Sgshapiro{ 479168515Sgshapiro size_t len; 480168515Sgshapiro int i; 481168515Sgshapiro mi_int32 v; 482168515Sgshapiro char *buffer; 483168515Sgshapiro 484168515Sgshapiro SM_ASSERT(ctx != NULL); 485168515Sgshapiro SM_ASSERT(buf != NULL); 486168515Sgshapiro SM_ASSERT(newbuf != NULL); 487168515Sgshapiro len = 0; 488168515Sgshapiro for (i = 0; i < MAX_MACROS_ENTRIES; i++) 489168515Sgshapiro { 490168515Sgshapiro if (ctx->ctx_mac_list[i] != NULL) 491168515Sgshapiro { 492168515Sgshapiro len += strlen(ctx->ctx_mac_list[i]) + 1 + 493168515Sgshapiro MILTER_LEN_BYTES; 494168515Sgshapiro } 495168515Sgshapiro } 496168515Sgshapiro if (len > 0) 497168515Sgshapiro { 498168515Sgshapiro size_t offset; 499168515Sgshapiro 500168515Sgshapiro SM_ASSERT(len + MILTER_OPTLEN > len); 501168515Sgshapiro len += MILTER_OPTLEN; 502168515Sgshapiro buffer = malloc(len); 503168515Sgshapiro if (buffer != NULL) 504168515Sgshapiro { 505168515Sgshapiro (void) memcpy(buffer, buf, MILTER_OPTLEN); 506168515Sgshapiro offset = MILTER_OPTLEN; 507168515Sgshapiro for (i = 0; i < MAX_MACROS_ENTRIES; i++) 508168515Sgshapiro { 509168515Sgshapiro size_t l; 510168515Sgshapiro 511168515Sgshapiro if (ctx->ctx_mac_list[i] == NULL) 512168515Sgshapiro continue; 513168515Sgshapiro 514168515Sgshapiro SM_ASSERT(offset + MILTER_LEN_BYTES < len); 515168515Sgshapiro v = htonl(i); 516168515Sgshapiro (void) memcpy(buffer + offset, (void *) &v, 517168515Sgshapiro MILTER_LEN_BYTES); 518168515Sgshapiro offset += MILTER_LEN_BYTES; 519168515Sgshapiro l = strlen(ctx->ctx_mac_list[i]) + 1; 520168515Sgshapiro SM_ASSERT(offset + l <= len); 521168515Sgshapiro (void) memcpy(buffer + offset, 522168515Sgshapiro ctx->ctx_mac_list[i], l); 523168515Sgshapiro offset += l; 524168515Sgshapiro } 525168515Sgshapiro } 526168515Sgshapiro else 527168515Sgshapiro { 528168515Sgshapiro /* oops ... */ 529168515Sgshapiro } 530168515Sgshapiro } 531168515Sgshapiro else 532168515Sgshapiro { 533168515Sgshapiro len = MILTER_OPTLEN; 534168515Sgshapiro buffer = buf; 535168515Sgshapiro } 536168515Sgshapiro *newbuf = buffer; 537168515Sgshapiro return len; 538168515Sgshapiro} 539168515Sgshapiro 54090792Sgshapiro/* 541168515Sgshapiro** GET_NR_BIT -- get "no reply" bit matching state 542168515Sgshapiro** 543168515Sgshapiro** Parameters: 544168515Sgshapiro** state -- current protocol stage 545168515Sgshapiro** 546168515Sgshapiro** Returns: 547168515Sgshapiro** 0: no matching bit 548168515Sgshapiro** >0: the matching "no reply" bit 549168515Sgshapiro*/ 550168515Sgshapiro 551168515Sgshapirostatic unsigned long get_nr_bit __P((int)); 552168515Sgshapiro 553168515Sgshapirostatic unsigned long 554168515Sgshapiroget_nr_bit(state) 555168515Sgshapiro int state; 556168515Sgshapiro{ 557168515Sgshapiro unsigned long bit; 558168515Sgshapiro 559168515Sgshapiro switch (state) 560168515Sgshapiro { 561168515Sgshapiro case ST_CONN: 562168515Sgshapiro bit = SMFIP_NR_CONN; 563168515Sgshapiro break; 564168515Sgshapiro case ST_HELO: 565168515Sgshapiro bit = SMFIP_NR_HELO; 566168515Sgshapiro break; 567168515Sgshapiro case ST_MAIL: 568168515Sgshapiro bit = SMFIP_NR_MAIL; 569168515Sgshapiro break; 570168515Sgshapiro case ST_RCPT: 571168515Sgshapiro bit = SMFIP_NR_RCPT; 572168515Sgshapiro break; 573168515Sgshapiro case ST_DATA: 574168515Sgshapiro bit = SMFIP_NR_DATA; 575168515Sgshapiro break; 576168515Sgshapiro case ST_UNKN: 577168515Sgshapiro bit = SMFIP_NR_UNKN; 578168515Sgshapiro break; 579168515Sgshapiro case ST_HDRS: 580168515Sgshapiro bit = SMFIP_NR_HDR; 581168515Sgshapiro break; 582168515Sgshapiro case ST_EOHS: 583168515Sgshapiro bit = SMFIP_NR_EOH; 584168515Sgshapiro break; 585168515Sgshapiro case ST_BODY: 586168515Sgshapiro bit = SMFIP_NR_BODY; 587168515Sgshapiro break; 588168515Sgshapiro default: 589168515Sgshapiro bit = 0; 590168515Sgshapiro break; 591168515Sgshapiro } 592168515Sgshapiro return bit; 593168515Sgshapiro} 594168515Sgshapiro 595168515Sgshapiro/* 59664562Sgshapiro** SENDREPLY -- send a reply to the MTA 59764562Sgshapiro** 59864562Sgshapiro** Parameters: 59964562Sgshapiro** r -- reply code 60064562Sgshapiro** sd -- socket descriptor 60164562Sgshapiro** timeout_ptr -- (ptr to) timeout to use for sending 60264562Sgshapiro** ctx -- context structure 60364562Sgshapiro** 60464562Sgshapiro** Returns: 60564562Sgshapiro** MI_SUCCESS/MI_FAILURE 60664562Sgshapiro*/ 60764562Sgshapiro 60864562Sgshapirostatic int 60964562Sgshapirosendreply(r, sd, timeout_ptr, ctx) 61064562Sgshapiro sfsistat r; 61164562Sgshapiro socket_t sd; 61264562Sgshapiro struct timeval *timeout_ptr; 61364562Sgshapiro SMFICTX_PTR ctx; 61464562Sgshapiro{ 615168515Sgshapiro int ret; 616168515Sgshapiro unsigned long bit; 61764562Sgshapiro 618168515Sgshapiro ret = MI_SUCCESS; 619168515Sgshapiro 620168515Sgshapiro bit = get_nr_bit(ctx->ctx_state); 621168515Sgshapiro if (bit != 0 && (ctx->ctx_pflags & bit) != 0 && r != SMFIS_NOREPLY) 622168515Sgshapiro { 623168515Sgshapiro if (r >= SMFIS_CONTINUE && r < _SMFIS_KEEP) 624168515Sgshapiro { 625168515Sgshapiro /* milter said it wouldn't reply, but it lied... */ 626168515Sgshapiro smi_log(SMI_LOG_ERR, 627168515Sgshapiro "%s: milter claimed not to reply in state %d but did anyway %d\n", 628168515Sgshapiro ctx->ctx_smfi->xxfi_name, 629168515Sgshapiro ctx->ctx_state, r); 630168515Sgshapiro 631168515Sgshapiro } 632168515Sgshapiro 633168515Sgshapiro /* 634168515Sgshapiro ** Force specified behavior, otherwise libmilter 635168515Sgshapiro ** and MTA will fail to communicate properly. 636168515Sgshapiro */ 637168515Sgshapiro 638168515Sgshapiro switch (r) 639168515Sgshapiro { 640168515Sgshapiro case SMFIS_CONTINUE: 641168515Sgshapiro case SMFIS_TEMPFAIL: 642168515Sgshapiro case SMFIS_REJECT: 643168515Sgshapiro case SMFIS_DISCARD: 644168515Sgshapiro case SMFIS_ACCEPT: 645168515Sgshapiro case SMFIS_SKIP: 646168515Sgshapiro case _SMFIS_OPTIONS: 647168515Sgshapiro r = SMFIS_NOREPLY; 648168515Sgshapiro break; 649168515Sgshapiro } 650168515Sgshapiro } 651168515Sgshapiro 65271345Sgshapiro switch (r) 65364562Sgshapiro { 65464562Sgshapiro case SMFIS_CONTINUE: 65564562Sgshapiro ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_CONTINUE, NULL, 0); 65664562Sgshapiro break; 65764562Sgshapiro case SMFIS_TEMPFAIL: 65864562Sgshapiro case SMFIS_REJECT: 65994334Sgshapiro if (ctx->ctx_reply != NULL && 66094334Sgshapiro ((r == SMFIS_TEMPFAIL && *ctx->ctx_reply == '4') || 66194334Sgshapiro (r == SMFIS_REJECT && *ctx->ctx_reply == '5'))) 66264562Sgshapiro { 66364562Sgshapiro ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_REPLYCODE, 66464562Sgshapiro ctx->ctx_reply, 66564562Sgshapiro strlen(ctx->ctx_reply) + 1); 66664562Sgshapiro free(ctx->ctx_reply); 66764562Sgshapiro ctx->ctx_reply = NULL; 66864562Sgshapiro } 66964562Sgshapiro else 67064562Sgshapiro { 67164562Sgshapiro ret = mi_wr_cmd(sd, timeout_ptr, r == SMFIS_REJECT ? 67264562Sgshapiro SMFIR_REJECT : SMFIR_TEMPFAIL, NULL, 0); 67364562Sgshapiro } 67464562Sgshapiro break; 67564562Sgshapiro case SMFIS_DISCARD: 67664562Sgshapiro ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_DISCARD, NULL, 0); 67764562Sgshapiro break; 67864562Sgshapiro case SMFIS_ACCEPT: 67964562Sgshapiro ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_ACCEPT, NULL, 0); 68064562Sgshapiro break; 681168515Sgshapiro case SMFIS_SKIP: 682168515Sgshapiro ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_SKIP, NULL, 0); 683168515Sgshapiro break; 68464562Sgshapiro case _SMFIS_OPTIONS: 68564562Sgshapiro { 686168515Sgshapiro mi_int32 v; 687168515Sgshapiro size_t len; 688168515Sgshapiro char *buffer; 68964562Sgshapiro char buf[MILTER_OPTLEN]; 69064562Sgshapiro 691168515Sgshapiro v = htonl(ctx->ctx_prot_vers2mta); 692168515Sgshapiro (void) memcpy(&(buf[0]), (void *) &v, 693168515Sgshapiro MILTER_LEN_BYTES); 694168515Sgshapiro v = htonl(ctx->ctx_aflags); 69564562Sgshapiro (void) memcpy(&(buf[MILTER_LEN_BYTES]), (void *) &v, 69664562Sgshapiro MILTER_LEN_BYTES); 697168515Sgshapiro v = htonl(ctx->ctx_pflags2mta); 698168515Sgshapiro (void) memcpy(&(buf[MILTER_LEN_BYTES * 2]), 699168515Sgshapiro (void *) &v, MILTER_LEN_BYTES); 700168515Sgshapiro len = milter_addsymlist(ctx, buf, &buffer); 701168515Sgshapiro if (buffer != NULL) 702168515Sgshapiro ret = mi_wr_cmd(sd, timeout_ptr, SMFIC_OPTNEG, 703168515Sgshapiro buffer, len); 704168515Sgshapiro else 705168515Sgshapiro ret = MI_FAILURE; 70664562Sgshapiro } 70764562Sgshapiro break; 708168515Sgshapiro case SMFIS_NOREPLY: 709168515Sgshapiro if (bit != 0 && 710168515Sgshapiro (ctx->ctx_pflags & bit) != 0 && 711168515Sgshapiro (ctx->ctx_mta_pflags & bit) == 0) 712168515Sgshapiro { 713168515Sgshapiro /* 714168515Sgshapiro ** milter doesn't want to send a reply, 715168515Sgshapiro ** but the MTA doesn't have that feature: fake it. 716168515Sgshapiro */ 717168515Sgshapiro 718168515Sgshapiro ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_CONTINUE, NULL, 719168515Sgshapiro 0); 720168515Sgshapiro } 721168515Sgshapiro break; 72264562Sgshapiro default: /* don't send a reply */ 72364562Sgshapiro break; 72464562Sgshapiro } 72564562Sgshapiro return ret; 72664562Sgshapiro} 72764562Sgshapiro 72864562Sgshapiro/* 72964562Sgshapiro** CLR_MACROS -- clear set of macros starting from a given index 73064562Sgshapiro** 73164562Sgshapiro** Parameters: 73264562Sgshapiro** ctx -- context structure 73364562Sgshapiro** m -- index from which to clear all macros 73464562Sgshapiro** 73564562Sgshapiro** Returns: 73664562Sgshapiro** None. 73764562Sgshapiro*/ 738168515Sgshapiro 73964562Sgshapirovoid 74064562Sgshapiromi_clr_macros(ctx, m) 74164562Sgshapiro SMFICTX_PTR ctx; 74264562Sgshapiro int m; 74364562Sgshapiro{ 74464562Sgshapiro int i; 74564562Sgshapiro 74664562Sgshapiro for (i = m; i < MAX_MACROS_ENTRIES; i++) 74764562Sgshapiro { 74864562Sgshapiro if (ctx->ctx_mac_ptr[i] != NULL) 74964562Sgshapiro { 75064562Sgshapiro free(ctx->ctx_mac_ptr[i]); 75164562Sgshapiro ctx->ctx_mac_ptr[i] = NULL; 75264562Sgshapiro } 75364562Sgshapiro if (ctx->ctx_mac_buf[i] != NULL) 75464562Sgshapiro { 75564562Sgshapiro free(ctx->ctx_mac_buf[i]); 75664562Sgshapiro ctx->ctx_mac_buf[i] = NULL; 75764562Sgshapiro } 75864562Sgshapiro } 75964562Sgshapiro} 760168515Sgshapiro 76190792Sgshapiro/* 762203004Sgshapiro** MI_CLR_SYMLIST -- clear list of macros 763203004Sgshapiro** 764203004Sgshapiro** Parameters: 765203004Sgshapiro** ctx -- context structure 766203004Sgshapiro** 767203004Sgshapiro** Returns: 768203004Sgshapiro** None. 769203004Sgshapiro*/ 770203004Sgshapiro 771203004Sgshapirostatic void 772203004Sgshapiromi_clr_symlist(ctx) 773203004Sgshapiro SMFICTX *ctx; 774203004Sgshapiro{ 775203004Sgshapiro int i; 776203004Sgshapiro 777203004Sgshapiro SM_ASSERT(ctx != NULL); 778203004Sgshapiro for (i = SMFIM_FIRST; i <= SMFIM_LAST; i++) 779203004Sgshapiro { 780203004Sgshapiro if (ctx->ctx_mac_list[i] != NULL) 781203004Sgshapiro { 782203004Sgshapiro free(ctx->ctx_mac_list[i]); 783203004Sgshapiro ctx->ctx_mac_list[i] = NULL; 784203004Sgshapiro } 785203004Sgshapiro } 786203004Sgshapiro} 787203004Sgshapiro 788203004Sgshapiro/* 789203004Sgshapiro** MI_CLR_CTX -- clear context 790203004Sgshapiro** 791203004Sgshapiro** Parameters: 792203004Sgshapiro** ctx -- context structure 793203004Sgshapiro** 794203004Sgshapiro** Returns: 795203004Sgshapiro** None. 796203004Sgshapiro*/ 797203004Sgshapiro 798203004Sgshapirovoid 799203004Sgshapiromi_clr_ctx(ctx) 800203004Sgshapiro SMFICTX *ctx; 801203004Sgshapiro{ 802203004Sgshapiro SM_ASSERT(ctx != NULL); 803203004Sgshapiro if (ValidSocket(ctx->ctx_sd)) 804203004Sgshapiro { 805203004Sgshapiro (void) closesocket(ctx->ctx_sd); 806203004Sgshapiro ctx->ctx_sd = INVALID_SOCKET; 807203004Sgshapiro } 808203004Sgshapiro if (ctx->ctx_reply != NULL) 809203004Sgshapiro { 810203004Sgshapiro free(ctx->ctx_reply); 811203004Sgshapiro ctx->ctx_reply = NULL; 812203004Sgshapiro } 813203004Sgshapiro if (ctx->ctx_privdata != NULL) 814203004Sgshapiro { 815203004Sgshapiro smi_log(SMI_LOG_WARN, 816203004Sgshapiro "%s: private data not NULL", 817203004Sgshapiro ctx->ctx_smfi->xxfi_name); 818203004Sgshapiro } 819203004Sgshapiro mi_clr_macros(ctx, 0); 820203004Sgshapiro mi_clr_symlist(ctx); 821203004Sgshapiro free(ctx); 822203004Sgshapiro} 823203004Sgshapiro 824203004Sgshapiro/* 82564562Sgshapiro** ST_OPTIONNEG -- negotiate options 82664562Sgshapiro** 82764562Sgshapiro** Parameters: 82864562Sgshapiro** g -- generic argument structure 82964562Sgshapiro** 83064562Sgshapiro** Returns: 83164562Sgshapiro** abort/send options/continue 83264562Sgshapiro*/ 83364562Sgshapiro 83464562Sgshapirostatic int 83564562Sgshapirost_optionneg(g) 83664562Sgshapiro genarg *g; 83764562Sgshapiro{ 838203004Sgshapiro mi_int32 i, v, fake_pflags, internal_pflags; 839168515Sgshapiro SMFICTX_PTR ctx; 840203004Sgshapiro#if _FFR_MILTER_CHECK 841203004Sgshapiro bool testmode = false; 842203004Sgshapiro#endif /* _FFR_MILTER_CHECK */ 843168515Sgshapiro int (*fi_negotiate) __P((SMFICTX *, 844168515Sgshapiro unsigned long, unsigned long, 845168515Sgshapiro unsigned long, unsigned long, 846168515Sgshapiro unsigned long *, unsigned long *, 847168515Sgshapiro unsigned long *, unsigned long *)); 84864562Sgshapiro 84964562Sgshapiro if (g == NULL || g->a_ctx->ctx_smfi == NULL) 85064562Sgshapiro return SMFIS_CONTINUE; 851168515Sgshapiro ctx = g->a_ctx; 852168515Sgshapiro mi_clr_macros(ctx, g->a_idx + 1); 853168515Sgshapiro ctx->ctx_prot_vers = SMFI_PROT_VERSION; 85464562Sgshapiro 85564562Sgshapiro /* check for minimum length */ 85664562Sgshapiro if (g->a_len < MILTER_OPTLEN) 85764562Sgshapiro { 85864562Sgshapiro smi_log(SMI_LOG_ERR, 859168515Sgshapiro "%s: st_optionneg[%ld]: len too short %d < %d", 860168515Sgshapiro ctx->ctx_smfi->xxfi_name, 861168515Sgshapiro (long) ctx->ctx_id, (int) g->a_len, 86264562Sgshapiro MILTER_OPTLEN); 86364562Sgshapiro return _SMFIS_ABORT; 86464562Sgshapiro } 86564562Sgshapiro 866168515Sgshapiro /* protocol version */ 867168515Sgshapiro (void) memcpy((void *) &i, (void *) &(g->a_buf[0]), MILTER_LEN_BYTES); 86864562Sgshapiro v = ntohl(i); 869168515Sgshapiro 870168515Sgshapiro#define SMFI_PROT_VERSION_MIN 2 871168515Sgshapiro 872168515Sgshapiro /* check for minimum version */ 873168515Sgshapiro if (v < SMFI_PROT_VERSION_MIN) 87464562Sgshapiro { 87564562Sgshapiro smi_log(SMI_LOG_ERR, 876168515Sgshapiro "%s: st_optionneg[%ld]: protocol version too old %d < %d", 877168515Sgshapiro ctx->ctx_smfi->xxfi_name, 878168515Sgshapiro (long) ctx->ctx_id, v, SMFI_PROT_VERSION_MIN); 87964562Sgshapiro return _SMFIS_ABORT; 88064562Sgshapiro } 881168515Sgshapiro ctx->ctx_mta_prot_vers = v; 882168515Sgshapiro if (ctx->ctx_prot_vers < ctx->ctx_mta_prot_vers) 883168515Sgshapiro ctx->ctx_prot_vers2mta = ctx->ctx_prot_vers; 884168515Sgshapiro else 885168515Sgshapiro ctx->ctx_prot_vers2mta = ctx->ctx_mta_prot_vers; 88664562Sgshapiro 88764562Sgshapiro (void) memcpy((void *) &i, (void *) &(g->a_buf[MILTER_LEN_BYTES]), 88864562Sgshapiro MILTER_LEN_BYTES); 88964562Sgshapiro v = ntohl(i); 89064562Sgshapiro 89164562Sgshapiro /* no flags? set to default value for V1 actions */ 89264562Sgshapiro if (v == 0) 89364562Sgshapiro v = SMFI_V1_ACTS; 894168515Sgshapiro ctx->ctx_mta_aflags = v; /* MTA action flags */ 89564562Sgshapiro 896203004Sgshapiro internal_pflags = 0; 89764562Sgshapiro (void) memcpy((void *) &i, (void *) &(g->a_buf[MILTER_LEN_BYTES * 2]), 89864562Sgshapiro MILTER_LEN_BYTES); 89964562Sgshapiro v = ntohl(i); 90064562Sgshapiro 90164562Sgshapiro /* no flags? set to default value for V1 protocol */ 90264562Sgshapiro if (v == 0) 90364562Sgshapiro v = SMFI_V1_PROT; 904203004Sgshapiro#if _FFR_MDS_NEGOTIATE 905203004Sgshapiro else if (ctx->ctx_smfi->xxfi_version >= SMFI_VERSION_MDS) 906203004Sgshapiro { 907203004Sgshapiro /* 908203004Sgshapiro ** Allow changing the size only if milter is compiled 909203004Sgshapiro ** against a version that supports this. 910203004Sgshapiro ** If a milter is dynamically linked against a newer 911203004Sgshapiro ** libmilter version, we don't want to "surprise" 912203004Sgshapiro ** it with a larger buffer as it may rely on it 913203004Sgshapiro ** even though it is not documented as a limit. 914203004Sgshapiro */ 915168515Sgshapiro 916203004Sgshapiro if (bitset(SMFIP_MDS_1M, v)) 917203004Sgshapiro { 918203004Sgshapiro internal_pflags |= SMFIP_MDS_1M; 919203004Sgshapiro (void) smfi_setmaxdatasize(MILTER_MDS_1M); 920203004Sgshapiro } 921203004Sgshapiro else if (bitset(SMFIP_MDS_256K, v)) 922203004Sgshapiro { 923203004Sgshapiro internal_pflags |= SMFIP_MDS_256K; 924203004Sgshapiro (void) smfi_setmaxdatasize(MILTER_MDS_256K); 925203004Sgshapiro } 926203004Sgshapiro } 927203004Sgshapiro# if 0 928203004Sgshapiro /* don't log this for now... */ 929203004Sgshapiro else if (ctx->ctx_smfi->xxfi_version < SMFI_VERSION_MDS && 930203004Sgshapiro bitset(SMFIP_MDS_1M|SMFIP_MDS_256K, v)) 931203004Sgshapiro { 932203004Sgshapiro smi_log(SMI_LOG_WARN, 933203004Sgshapiro "%s: st_optionneg[%ld]: milter version=%X, trying flags=%X", 934203004Sgshapiro ctx->ctx_smfi->xxfi_name, 935203004Sgshapiro (long) ctx->ctx_id, ctx->ctx_smfi->xxfi_version, v); 936203004Sgshapiro } 937203004Sgshapiro# endif /* 0 */ 938203004Sgshapiro#endif /* _FFR_MDS_NEGOTIATE */ 939203004Sgshapiro 940168515Sgshapiro /* 941203004Sgshapiro ** MTA protocol flags. 942203004Sgshapiro ** We pass the internal flags to the milter as "read only", 943203004Sgshapiro ** i.e., a milter can read them so it knows which size 944203004Sgshapiro ** will be used, but any changes by a milter will be ignored 945203004Sgshapiro ** (see below, search for SMFI_INTERNAL). 946203004Sgshapiro */ 947203004Sgshapiro 948203004Sgshapiro ctx->ctx_mta_pflags = (v & ~SMFI_INTERNAL) | internal_pflags; 949203004Sgshapiro 950203004Sgshapiro /* 951168515Sgshapiro ** Copy flags from milter struct into libmilter context; 952168515Sgshapiro ** this variable will be used later on to check whether 953168515Sgshapiro ** the MTA "actions" can fulfill the milter requirements, 954168515Sgshapiro ** but it may be overwritten by the negotiate callback. 955168515Sgshapiro */ 956168515Sgshapiro 957168515Sgshapiro ctx->ctx_aflags = ctx->ctx_smfi->xxfi_flags; 958168515Sgshapiro fake_pflags = SMFIP_NR_CONN 959168515Sgshapiro |SMFIP_NR_HELO 960168515Sgshapiro |SMFIP_NR_MAIL 961168515Sgshapiro |SMFIP_NR_RCPT 962168515Sgshapiro |SMFIP_NR_DATA 963168515Sgshapiro |SMFIP_NR_UNKN 964168515Sgshapiro |SMFIP_NR_HDR 965168515Sgshapiro |SMFIP_NR_EOH 966168515Sgshapiro |SMFIP_NR_BODY 967168515Sgshapiro ; 968168515Sgshapiro 969168515Sgshapiro if (g->a_ctx->ctx_smfi != NULL && 970168988Sgshapiro g->a_ctx->ctx_smfi->xxfi_version > 4 && 971168515Sgshapiro (fi_negotiate = g->a_ctx->ctx_smfi->xxfi_negotiate) != NULL) 97264562Sgshapiro { 973168515Sgshapiro int r; 974168515Sgshapiro unsigned long m_aflags, m_pflags, m_f2, m_f3; 975168515Sgshapiro 976168515Sgshapiro /* 977168515Sgshapiro ** let milter decide whether the features offered by the 978168515Sgshapiro ** MTA are "good enough". 979168515Sgshapiro ** Notes: 980168515Sgshapiro ** - libmilter can "fake" some features (e.g., SMFIP_NR_HDR) 981168515Sgshapiro ** - m_f2, m_f3 are for future extensions 982168515Sgshapiro */ 983168515Sgshapiro 984168515Sgshapiro m_f2 = m_f3 = 0; 985168515Sgshapiro m_aflags = ctx->ctx_mta_aflags; 986168515Sgshapiro m_pflags = ctx->ctx_pflags; 987168515Sgshapiro if ((SMFIP_SKIP & ctx->ctx_mta_pflags) != 0) 988168515Sgshapiro m_pflags |= SMFIP_SKIP; 989168515Sgshapiro r = fi_negotiate(g->a_ctx, 990168515Sgshapiro ctx->ctx_mta_aflags, 991168515Sgshapiro ctx->ctx_mta_pflags|fake_pflags, 992168515Sgshapiro 0, 0, 993168515Sgshapiro &m_aflags, &m_pflags, &m_f2, &m_f3); 994168515Sgshapiro 995203004Sgshapiro#if _FFR_MILTER_CHECK 996203004Sgshapiro testmode = bitset(SMFIP_TEST, m_pflags); 997203004Sgshapiro if (testmode) 998203004Sgshapiro m_pflags &= ~SMFIP_TEST; 999203004Sgshapiro#endif /* _FFR_MILTER_CHECK */ 1000203004Sgshapiro 1001168515Sgshapiro /* 1002168515Sgshapiro ** Types of protocol flags (pflags): 1003168515Sgshapiro ** 1. do NOT send protocol step X 1004168515Sgshapiro ** 2. MTA can do/understand something extra (SKIP, 1005168515Sgshapiro ** send unknown RCPTs) 1006168515Sgshapiro ** 3. MTA can deal with "no reply" for various protocol steps 1007168515Sgshapiro ** Note: this mean that it isn't possible to simply set all 1008168515Sgshapiro ** flags to get "everything": 1009168515Sgshapiro ** setting a flag of type 1 turns off a step 1010168515Sgshapiro ** (it should be the other way around: 1011168515Sgshapiro ** a flag means a protocol step can be sent) 1012168515Sgshapiro ** setting a flag of type 3 requires that milter 1013168515Sgshapiro ** never sends a reply for the corresponding step. 1014168515Sgshapiro ** Summary: the "negation" of protocol flags is causing 1015168515Sgshapiro ** problems, but at least for type 3 there is no simple 1016168515Sgshapiro ** solution. 1017168515Sgshapiro ** 1018168515Sgshapiro ** What should "all options" mean? 1019168515Sgshapiro ** send all protocol steps _except_ those for which there is 1020168515Sgshapiro ** no callback (currently registered in ctx_pflags) 1021168515Sgshapiro ** expect SKIP as return code? Yes 1022168515Sgshapiro ** send unknown RCPTs? No, 1023168515Sgshapiro ** must be explicitly requested? 1024168515Sgshapiro ** "no reply" for some protocol steps? No, 1025168515Sgshapiro ** must be explicitly requested. 1026168515Sgshapiro */ 1027168515Sgshapiro 1028168515Sgshapiro if (SMFIS_ALL_OPTS == r) 1029168515Sgshapiro { 1030168515Sgshapiro ctx->ctx_aflags = ctx->ctx_mta_aflags; 1031168515Sgshapiro ctx->ctx_pflags2mta = ctx->ctx_pflags; 1032168515Sgshapiro if ((SMFIP_SKIP & ctx->ctx_mta_pflags) != 0) 1033168515Sgshapiro ctx->ctx_pflags2mta |= SMFIP_SKIP; 1034168515Sgshapiro } 1035168515Sgshapiro else if (r != SMFIS_CONTINUE) 1036168515Sgshapiro { 1037168515Sgshapiro smi_log(SMI_LOG_ERR, 1038168515Sgshapiro "%s: st_optionneg[%ld]: xxfi_negotiate returned %d (protocol options=0x%lx, actions=0x%lx)", 1039168515Sgshapiro ctx->ctx_smfi->xxfi_name, 1040168515Sgshapiro (long) ctx->ctx_id, r, ctx->ctx_mta_pflags, 1041168515Sgshapiro ctx->ctx_mta_aflags); 1042168515Sgshapiro return _SMFIS_ABORT; 1043168515Sgshapiro } 1044168515Sgshapiro else 1045168515Sgshapiro { 1046168515Sgshapiro ctx->ctx_aflags = m_aflags; 1047168515Sgshapiro ctx->ctx_pflags = m_pflags; 1048168515Sgshapiro ctx->ctx_pflags2mta = m_pflags; 1049168515Sgshapiro } 1050168515Sgshapiro 1051168515Sgshapiro /* check whether some flags need to be "faked" */ 1052168515Sgshapiro i = ctx->ctx_pflags2mta; 1053168515Sgshapiro if ((ctx->ctx_mta_pflags & i) != i) 1054168515Sgshapiro { 1055168515Sgshapiro unsigned int idx; 1056168515Sgshapiro unsigned long b; 1057168515Sgshapiro 1058168515Sgshapiro /* 1059168515Sgshapiro ** If some behavior can be faked (set in fake_pflags), 1060168515Sgshapiro ** but the MTA doesn't support it, then unset 1061168515Sgshapiro ** that flag in the value that is sent to the MTA. 1062168515Sgshapiro */ 1063168515Sgshapiro 1064168515Sgshapiro for (idx = 0; idx < 32; idx++) 1065168515Sgshapiro { 1066168515Sgshapiro b = 1 << idx; 1067168515Sgshapiro if ((ctx->ctx_mta_pflags & b) != b && 1068168515Sgshapiro (fake_pflags & b) == b) 1069168515Sgshapiro ctx->ctx_pflags2mta &= ~b; 1070168515Sgshapiro } 1071168515Sgshapiro } 1072168515Sgshapiro } 1073168515Sgshapiro else 1074168515Sgshapiro { 1075168515Sgshapiro /* 1076168515Sgshapiro ** Set the protocol flags based on the values determined 1077168515Sgshapiro ** in mi_listener() which checked the defined callbacks. 1078168515Sgshapiro */ 1079168515Sgshapiro 1080168515Sgshapiro ctx->ctx_pflags2mta = ctx->ctx_pflags; 1081168515Sgshapiro } 1082168515Sgshapiro 1083168515Sgshapiro /* check whether actions and protocol requirements can be satisfied */ 1084168515Sgshapiro i = ctx->ctx_aflags; 1085168515Sgshapiro if ((i & ctx->ctx_mta_aflags) != i) 1086168515Sgshapiro { 108764562Sgshapiro smi_log(SMI_LOG_ERR, 1088168515Sgshapiro "%s: st_optionneg[%ld]: 0x%lx does not fulfill action requirements 0x%x", 1089168515Sgshapiro ctx->ctx_smfi->xxfi_name, 1090168515Sgshapiro (long) ctx->ctx_id, ctx->ctx_mta_aflags, i); 109164562Sgshapiro return _SMFIS_ABORT; 109264562Sgshapiro } 109364562Sgshapiro 1094168515Sgshapiro i = ctx->ctx_pflags2mta; 1095168515Sgshapiro if ((ctx->ctx_mta_pflags & i) != i) 1096168515Sgshapiro { 1097168515Sgshapiro /* 1098168515Sgshapiro ** Older MTAs do not support some protocol steps. 1099168515Sgshapiro ** As this protocol is a bit "wierd" (it asks for steps 1100168515Sgshapiro ** NOT to be taken/sent) we have to check whether we 1101168515Sgshapiro ** should turn off those "negative" requests. 1102168515Sgshapiro ** Currently these are only SMFIP_NODATA and SMFIP_NOUNKNOWN. 1103168515Sgshapiro */ 1104168515Sgshapiro 1105168515Sgshapiro if (bitset(SMFIP_NODATA, ctx->ctx_pflags2mta) && 1106168515Sgshapiro !bitset(SMFIP_NODATA, ctx->ctx_mta_pflags)) 1107168515Sgshapiro ctx->ctx_pflags2mta &= ~SMFIP_NODATA; 1108168515Sgshapiro if (bitset(SMFIP_NOUNKNOWN, ctx->ctx_pflags2mta) && 1109168515Sgshapiro !bitset(SMFIP_NOUNKNOWN, ctx->ctx_mta_pflags)) 1110168515Sgshapiro ctx->ctx_pflags2mta &= ~SMFIP_NOUNKNOWN; 1111168515Sgshapiro i = ctx->ctx_pflags2mta; 1112168515Sgshapiro } 1113168515Sgshapiro 1114168515Sgshapiro if ((ctx->ctx_mta_pflags & i) != i) 1115168515Sgshapiro { 1116168515Sgshapiro smi_log(SMI_LOG_ERR, 1117168515Sgshapiro "%s: st_optionneg[%ld]: 0x%lx does not fulfill protocol requirements 0x%x", 1118168515Sgshapiro ctx->ctx_smfi->xxfi_name, 1119168515Sgshapiro (long) ctx->ctx_id, ctx->ctx_mta_pflags, i); 1120168515Sgshapiro return _SMFIS_ABORT; 1121168515Sgshapiro } 1122182352Sgshapiro fix_stm(ctx); 1123168515Sgshapiro 1124168515Sgshapiro if (ctx->ctx_dbg > 3) 1125223067Sgshapiro sm_dprintf("[%lu] milter_negotiate:" 1126168515Sgshapiro " mta_actions=0x%lx, mta_flags=0x%lx" 1127168515Sgshapiro " actions=0x%lx, flags=0x%lx\n" 1128168515Sgshapiro , (long) ctx->ctx_id 1129168515Sgshapiro , ctx->ctx_mta_aflags, ctx->ctx_mta_pflags 1130168515Sgshapiro , ctx->ctx_aflags, ctx->ctx_pflags); 1131168515Sgshapiro 1132203004Sgshapiro#if _FFR_MILTER_CHECK 1133203004Sgshapiro if (ctx->ctx_dbg > 3) 1134223067Sgshapiro sm_dprintf("[%lu] milter_negotiate:" 1135203004Sgshapiro " testmode=%d, pflags2mta=%X, internal_pflags=%X\n" 1136203004Sgshapiro , (long) ctx->ctx_id, testmode 1137203004Sgshapiro , ctx->ctx_pflags2mta, internal_pflags); 1138203004Sgshapiro 1139203004Sgshapiro /* in test mode: take flags without further modifications */ 1140203004Sgshapiro if (!testmode) 1141203004Sgshapiro /* Warning: check statement below! */ 1142203004Sgshapiro#endif /* _FFR_MILTER_CHECK */ 1143203004Sgshapiro 1144203004Sgshapiro /* 1145203004Sgshapiro ** Remove the internal flags that might have been set by a milter 1146203004Sgshapiro ** and set only those determined above. 1147203004Sgshapiro */ 1148203004Sgshapiro 1149203004Sgshapiro ctx->ctx_pflags2mta = (ctx->ctx_pflags2mta & ~SMFI_INTERNAL) 1150203004Sgshapiro | internal_pflags; 115164562Sgshapiro return _SMFIS_OPTIONS; 115264562Sgshapiro} 1153168515Sgshapiro 115490792Sgshapiro/* 115564562Sgshapiro** ST_CONNECTINFO -- receive connection information 115664562Sgshapiro** 115764562Sgshapiro** Parameters: 115864562Sgshapiro** g -- generic argument structure 115964562Sgshapiro** 116064562Sgshapiro** Returns: 116164562Sgshapiro** continue or filter-specified value 116264562Sgshapiro*/ 116364562Sgshapiro 116464562Sgshapirostatic int 116564562Sgshapirost_connectinfo(g) 116664562Sgshapiro genarg *g; 116764562Sgshapiro{ 116864562Sgshapiro size_t l; 116964562Sgshapiro size_t i; 117064562Sgshapiro char *s, family; 117190792Sgshapiro unsigned short port = 0; 117264562Sgshapiro _SOCK_ADDR sockaddr; 117364562Sgshapiro sfsistat (*fi_connect) __P((SMFICTX *, char *, _SOCK_ADDR *)); 117464562Sgshapiro 117564562Sgshapiro if (g == NULL) 117664562Sgshapiro return _SMFIS_ABORT; 117764562Sgshapiro mi_clr_macros(g->a_ctx, g->a_idx + 1); 117864562Sgshapiro if (g->a_ctx->ctx_smfi == NULL || 117964562Sgshapiro (fi_connect = g->a_ctx->ctx_smfi->xxfi_connect) == NULL) 118064562Sgshapiro return SMFIS_CONTINUE; 118164562Sgshapiro 118264562Sgshapiro s = g->a_buf; 118364562Sgshapiro i = 0; 118464562Sgshapiro l = g->a_len; 118564562Sgshapiro while (s[i] != '\0' && i <= l) 118664562Sgshapiro ++i; 1187125820Sgshapiro if (i + 1 >= l) 118864562Sgshapiro return _SMFIS_ABORT; 118964562Sgshapiro 119064562Sgshapiro /* Move past trailing \0 in host string */ 119164562Sgshapiro i++; 119264562Sgshapiro family = s[i++]; 1193120256Sgshapiro (void) memset(&sockaddr, '\0', sizeof sockaddr); 119464562Sgshapiro if (family != SMFIA_UNKNOWN) 119564562Sgshapiro { 1196125820Sgshapiro if (i + sizeof port >= l) 119764562Sgshapiro { 119864562Sgshapiro smi_log(SMI_LOG_ERR, 1199168515Sgshapiro "%s: connect[%ld]: wrong len %d >= %d", 120064562Sgshapiro g->a_ctx->ctx_smfi->xxfi_name, 1201168515Sgshapiro (long) g->a_ctx->ctx_id, (int) i, (int) l); 120264562Sgshapiro return _SMFIS_ABORT; 120364562Sgshapiro } 1204125820Sgshapiro (void) memcpy((void *) &port, (void *) (s + i), 1205125820Sgshapiro sizeof port); 1206125820Sgshapiro i += sizeof port; 120794334Sgshapiro 120894334Sgshapiro /* make sure string is terminated */ 120994334Sgshapiro if (s[l - 1] != '\0') 121094334Sgshapiro return _SMFIS_ABORT; 121164562Sgshapiro# if NETINET 121264562Sgshapiro if (family == SMFIA_INET) 121364562Sgshapiro { 121464562Sgshapiro if (inet_aton(s + i, (struct in_addr *) &sockaddr.sin.sin_addr) 121594334Sgshapiro != 1) 121664562Sgshapiro { 121764562Sgshapiro smi_log(SMI_LOG_ERR, 1218168515Sgshapiro "%s: connect[%ld]: inet_aton failed", 121964562Sgshapiro g->a_ctx->ctx_smfi->xxfi_name, 1220168515Sgshapiro (long) g->a_ctx->ctx_id); 122164562Sgshapiro return _SMFIS_ABORT; 122264562Sgshapiro } 122364562Sgshapiro sockaddr.sa.sa_family = AF_INET; 122464562Sgshapiro if (port > 0) 122564562Sgshapiro sockaddr.sin.sin_port = port; 122664562Sgshapiro } 122764562Sgshapiro else 122864562Sgshapiro# endif /* NETINET */ 122964562Sgshapiro# if NETINET6 123064562Sgshapiro if (family == SMFIA_INET6) 123164562Sgshapiro { 123290792Sgshapiro if (mi_inet_pton(AF_INET6, s + i, 123390792Sgshapiro &sockaddr.sin6.sin6_addr) != 1) 123464562Sgshapiro { 123564562Sgshapiro smi_log(SMI_LOG_ERR, 1236168515Sgshapiro "%s: connect[%ld]: mi_inet_pton failed", 123764562Sgshapiro g->a_ctx->ctx_smfi->xxfi_name, 1238168515Sgshapiro (long) g->a_ctx->ctx_id); 123964562Sgshapiro return _SMFIS_ABORT; 124064562Sgshapiro } 124164562Sgshapiro sockaddr.sa.sa_family = AF_INET6; 124264562Sgshapiro if (port > 0) 124364562Sgshapiro sockaddr.sin6.sin6_port = port; 124464562Sgshapiro } 124564562Sgshapiro else 124664562Sgshapiro# endif /* NETINET6 */ 124764562Sgshapiro# if NETUNIX 124864562Sgshapiro if (family == SMFIA_UNIX) 124964562Sgshapiro { 125090792Sgshapiro if (sm_strlcpy(sockaddr.sunix.sun_path, s + i, 125164562Sgshapiro sizeof sockaddr.sunix.sun_path) >= 125264562Sgshapiro sizeof sockaddr.sunix.sun_path) 125364562Sgshapiro { 125464562Sgshapiro smi_log(SMI_LOG_ERR, 1255168515Sgshapiro "%s: connect[%ld]: path too long", 125664562Sgshapiro g->a_ctx->ctx_smfi->xxfi_name, 1257168515Sgshapiro (long) g->a_ctx->ctx_id); 125864562Sgshapiro return _SMFIS_ABORT; 125964562Sgshapiro } 126064562Sgshapiro sockaddr.sunix.sun_family = AF_UNIX; 126164562Sgshapiro } 126264562Sgshapiro else 126364562Sgshapiro# endif /* NETUNIX */ 126464562Sgshapiro { 126564562Sgshapiro smi_log(SMI_LOG_ERR, 1266168515Sgshapiro "%s: connect[%ld]: unknown family %d", 126764562Sgshapiro g->a_ctx->ctx_smfi->xxfi_name, 1268168515Sgshapiro (long) g->a_ctx->ctx_id, family); 126964562Sgshapiro return _SMFIS_ABORT; 127064562Sgshapiro } 127164562Sgshapiro } 127264562Sgshapiro return (*fi_connect)(g->a_ctx, g->a_buf, 127364562Sgshapiro family != SMFIA_UNKNOWN ? &sockaddr : NULL); 127464562Sgshapiro} 1275132943Sgshapiro 127690792Sgshapiro/* 127764562Sgshapiro** ST_EOH -- end of headers 127864562Sgshapiro** 127964562Sgshapiro** Parameters: 128064562Sgshapiro** g -- generic argument structure 128164562Sgshapiro** 128264562Sgshapiro** Returns: 128364562Sgshapiro** continue or filter-specified value 128464562Sgshapiro*/ 128564562Sgshapiro 128664562Sgshapirostatic int 128764562Sgshapirost_eoh(g) 128864562Sgshapiro genarg *g; 128964562Sgshapiro{ 129064562Sgshapiro sfsistat (*fi_eoh) __P((SMFICTX *)); 129164562Sgshapiro 129264562Sgshapiro if (g == NULL) 129364562Sgshapiro return _SMFIS_ABORT; 129464562Sgshapiro if (g->a_ctx->ctx_smfi != NULL && 129564562Sgshapiro (fi_eoh = g->a_ctx->ctx_smfi->xxfi_eoh) != NULL) 129664562Sgshapiro return (*fi_eoh)(g->a_ctx); 129764562Sgshapiro return SMFIS_CONTINUE; 129864562Sgshapiro} 1299132943Sgshapiro 130090792Sgshapiro/* 1301132943Sgshapiro** ST_DATA -- DATA command 1302132943Sgshapiro** 1303132943Sgshapiro** Parameters: 1304132943Sgshapiro** g -- generic argument structure 1305132943Sgshapiro** 1306132943Sgshapiro** Returns: 1307132943Sgshapiro** continue or filter-specified value 1308132943Sgshapiro*/ 1309132943Sgshapiro 1310132943Sgshapirostatic int 1311132943Sgshapirost_data(g) 1312132943Sgshapiro genarg *g; 1313132943Sgshapiro{ 1314132943Sgshapiro sfsistat (*fi_data) __P((SMFICTX *)); 1315132943Sgshapiro 1316132943Sgshapiro if (g == NULL) 1317132943Sgshapiro return _SMFIS_ABORT; 1318132943Sgshapiro if (g->a_ctx->ctx_smfi != NULL && 1319168988Sgshapiro g->a_ctx->ctx_smfi->xxfi_version > 3 && 1320132943Sgshapiro (fi_data = g->a_ctx->ctx_smfi->xxfi_data) != NULL) 1321132943Sgshapiro return (*fi_data)(g->a_ctx); 1322132943Sgshapiro return SMFIS_CONTINUE; 1323132943Sgshapiro} 1324132943Sgshapiro 1325132943Sgshapiro/* 132664562Sgshapiro** ST_HELO -- helo/ehlo command 132764562Sgshapiro** 132864562Sgshapiro** Parameters: 132964562Sgshapiro** g -- generic argument structure 133064562Sgshapiro** 133164562Sgshapiro** Returns: 133264562Sgshapiro** continue or filter-specified value 133364562Sgshapiro*/ 1334168515Sgshapiro 133564562Sgshapirostatic int 133664562Sgshapirost_helo(g) 133764562Sgshapiro genarg *g; 133864562Sgshapiro{ 133964562Sgshapiro sfsistat (*fi_helo) __P((SMFICTX *, char *)); 134064562Sgshapiro 134164562Sgshapiro if (g == NULL) 134264562Sgshapiro return _SMFIS_ABORT; 134364562Sgshapiro mi_clr_macros(g->a_ctx, g->a_idx + 1); 134464562Sgshapiro if (g->a_ctx->ctx_smfi != NULL && 134564562Sgshapiro (fi_helo = g->a_ctx->ctx_smfi->xxfi_helo) != NULL) 1346125820Sgshapiro { 1347125820Sgshapiro /* paranoia: check for terminating '\0' */ 1348125820Sgshapiro if (g->a_len == 0 || g->a_buf[g->a_len - 1] != '\0') 1349125820Sgshapiro return MI_FAILURE; 135064562Sgshapiro return (*fi_helo)(g->a_ctx, g->a_buf); 1351125820Sgshapiro } 135264562Sgshapiro return SMFIS_CONTINUE; 135364562Sgshapiro} 1354168515Sgshapiro 135590792Sgshapiro/* 135664562Sgshapiro** ST_HEADER -- header line 135764562Sgshapiro** 135864562Sgshapiro** Parameters: 135964562Sgshapiro** g -- generic argument structure 136064562Sgshapiro** 136164562Sgshapiro** Returns: 136264562Sgshapiro** continue or filter-specified value 136364562Sgshapiro*/ 136464562Sgshapiro 136564562Sgshapirostatic int 136664562Sgshapirost_header(g) 136764562Sgshapiro genarg *g; 136864562Sgshapiro{ 136964562Sgshapiro char *hf, *hv; 137064562Sgshapiro sfsistat (*fi_header) __P((SMFICTX *, char *, char *)); 137164562Sgshapiro 137264562Sgshapiro if (g == NULL) 137364562Sgshapiro return _SMFIS_ABORT; 137464562Sgshapiro if (g->a_ctx->ctx_smfi == NULL || 137564562Sgshapiro (fi_header = g->a_ctx->ctx_smfi->xxfi_header) == NULL) 137664562Sgshapiro return SMFIS_CONTINUE; 137764562Sgshapiro if (dec_arg2(g->a_buf, g->a_len, &hf, &hv) == MI_SUCCESS) 137864562Sgshapiro return (*fi_header)(g->a_ctx, hf, hv); 137964562Sgshapiro else 138064562Sgshapiro return _SMFIS_ABORT; 138164562Sgshapiro} 138264562Sgshapiro 138390792Sgshapiro#define ARGV_FCT(lf, rf, idx) \ 138490792Sgshapiro char **argv; \ 138590792Sgshapiro sfsistat (*lf) __P((SMFICTX *, char **)); \ 138690792Sgshapiro int r; \ 138790792Sgshapiro \ 138890792Sgshapiro if (g == NULL) \ 138990792Sgshapiro return _SMFIS_ABORT; \ 139090792Sgshapiro mi_clr_macros(g->a_ctx, g->a_idx + 1); \ 139190792Sgshapiro if (g->a_ctx->ctx_smfi == NULL || \ 139290792Sgshapiro (lf = g->a_ctx->ctx_smfi->rf) == NULL) \ 139390792Sgshapiro return SMFIS_CONTINUE; \ 139464562Sgshapiro if ((argv = dec_argv(g->a_buf, g->a_len)) == NULL) \ 139590792Sgshapiro return _SMFIS_ABORT; \ 139690792Sgshapiro r = (*lf)(g->a_ctx, argv); \ 139790792Sgshapiro free(argv); \ 139864562Sgshapiro return r; 139964562Sgshapiro 140090792Sgshapiro/* 140164562Sgshapiro** ST_SENDER -- MAIL FROM command 140264562Sgshapiro** 140364562Sgshapiro** Parameters: 140464562Sgshapiro** g -- generic argument structure 140564562Sgshapiro** 140664562Sgshapiro** Returns: 140764562Sgshapiro** continue or filter-specified value 140864562Sgshapiro*/ 140964562Sgshapiro 141064562Sgshapirostatic int 141164562Sgshapirost_sender(g) 141264562Sgshapiro genarg *g; 141364562Sgshapiro{ 141464562Sgshapiro ARGV_FCT(fi_envfrom, xxfi_envfrom, CI_MAIL) 141564562Sgshapiro} 1416168515Sgshapiro 141790792Sgshapiro/* 141864562Sgshapiro** ST_RCPT -- RCPT TO command 141964562Sgshapiro** 142064562Sgshapiro** Parameters: 142164562Sgshapiro** g -- generic argument structure 142264562Sgshapiro** 142364562Sgshapiro** Returns: 142464562Sgshapiro** continue or filter-specified value 142564562Sgshapiro*/ 142664562Sgshapiro 142764562Sgshapirostatic int 142864562Sgshapirost_rcpt(g) 142964562Sgshapiro genarg *g; 143064562Sgshapiro{ 143164562Sgshapiro ARGV_FCT(fi_envrcpt, xxfi_envrcpt, CI_RCPT) 143264562Sgshapiro} 1433132943Sgshapiro 143490792Sgshapiro/* 1435132943Sgshapiro** ST_UNKNOWN -- unrecognized or unimplemented command 1436132943Sgshapiro** 1437132943Sgshapiro** Parameters: 1438132943Sgshapiro** g -- generic argument structure 1439132943Sgshapiro** 1440132943Sgshapiro** Returns: 1441132943Sgshapiro** continue or filter-specified value 1442132943Sgshapiro*/ 1443132943Sgshapiro 1444132943Sgshapirostatic int 1445132943Sgshapirost_unknown(g) 1446132943Sgshapiro genarg *g; 1447132943Sgshapiro{ 1448168515Sgshapiro sfsistat (*fi_unknown) __P((SMFICTX *, const char *)); 1449132943Sgshapiro 1450132943Sgshapiro if (g == NULL) 1451132943Sgshapiro return _SMFIS_ABORT; 1452132943Sgshapiro if (g->a_ctx->ctx_smfi != NULL && 1453168988Sgshapiro g->a_ctx->ctx_smfi->xxfi_version > 2 && 1454132943Sgshapiro (fi_unknown = g->a_ctx->ctx_smfi->xxfi_unknown) != NULL) 1455168515Sgshapiro return (*fi_unknown)(g->a_ctx, (const char *) g->a_buf); 1456132943Sgshapiro return SMFIS_CONTINUE; 1457132943Sgshapiro} 1458132943Sgshapiro 1459132943Sgshapiro/* 146064562Sgshapiro** ST_MACROS -- deal with macros received from the MTA 146164562Sgshapiro** 146264562Sgshapiro** Parameters: 146364562Sgshapiro** g -- generic argument structure 146464562Sgshapiro** 146564562Sgshapiro** Returns: 146664562Sgshapiro** continue/keep 146764562Sgshapiro** 146864562Sgshapiro** Side effects: 146964562Sgshapiro** set pointer in macro array to current values. 147064562Sgshapiro*/ 147164562Sgshapiro 147264562Sgshapirostatic int 147364562Sgshapirost_macros(g) 147464562Sgshapiro genarg *g; 147564562Sgshapiro{ 147664562Sgshapiro int i; 147764562Sgshapiro char **argv; 147864562Sgshapiro 147964562Sgshapiro if (g == NULL || g->a_len < 1) 148064562Sgshapiro return _SMFIS_FAIL; 148164562Sgshapiro if ((argv = dec_argv(g->a_buf + 1, g->a_len - 1)) == NULL) 148264562Sgshapiro return _SMFIS_FAIL; 148371345Sgshapiro switch (g->a_buf[0]) 148464562Sgshapiro { 148564562Sgshapiro case SMFIC_CONNECT: 148664562Sgshapiro i = CI_CONN; 148764562Sgshapiro break; 148864562Sgshapiro case SMFIC_HELO: 148964562Sgshapiro i = CI_HELO; 149064562Sgshapiro break; 149164562Sgshapiro case SMFIC_MAIL: 149264562Sgshapiro i = CI_MAIL; 149364562Sgshapiro break; 149464562Sgshapiro case SMFIC_RCPT: 149564562Sgshapiro i = CI_RCPT; 149664562Sgshapiro break; 1497168515Sgshapiro case SMFIC_DATA: 1498168515Sgshapiro i = CI_DATA; 1499168515Sgshapiro break; 1500125820Sgshapiro case SMFIC_BODYEOB: 1501125820Sgshapiro i = CI_EOM; 1502125820Sgshapiro break; 1503168515Sgshapiro case SMFIC_EOH: 1504168515Sgshapiro i = CI_EOH; 1505168515Sgshapiro break; 150664562Sgshapiro default: 150764562Sgshapiro free(argv); 150864562Sgshapiro return _SMFIS_FAIL; 150964562Sgshapiro } 151064562Sgshapiro if (g->a_ctx->ctx_mac_ptr[i] != NULL) 151164562Sgshapiro free(g->a_ctx->ctx_mac_ptr[i]); 151264562Sgshapiro if (g->a_ctx->ctx_mac_buf[i] != NULL) 151364562Sgshapiro free(g->a_ctx->ctx_mac_buf[i]); 151464562Sgshapiro g->a_ctx->ctx_mac_ptr[i] = argv; 151564562Sgshapiro g->a_ctx->ctx_mac_buf[i] = g->a_buf; 151664562Sgshapiro return _SMFIS_KEEP; 151764562Sgshapiro} 1518168515Sgshapiro 151990792Sgshapiro/* 152064562Sgshapiro** ST_QUIT -- quit command 152164562Sgshapiro** 152264562Sgshapiro** Parameters: 152364562Sgshapiro** g -- generic argument structure 152464562Sgshapiro** 152564562Sgshapiro** Returns: 152664562Sgshapiro** noreply 152764562Sgshapiro*/ 152864562Sgshapiro 1529120256Sgshapiro/* ARGSUSED */ 153064562Sgshapirostatic int 153164562Sgshapirost_quit(g) 153264562Sgshapiro genarg *g; 153364562Sgshapiro{ 1534168515Sgshapiro sfsistat (*fi_close) __P((SMFICTX *)); 1535168515Sgshapiro 1536168515Sgshapiro if (g == NULL) 1537168515Sgshapiro return _SMFIS_ABORT; 1538168515Sgshapiro if (g->a_ctx->ctx_smfi != NULL && 1539168515Sgshapiro (fi_close = g->a_ctx->ctx_smfi->xxfi_close) != NULL) 1540168515Sgshapiro (void) (*fi_close)(g->a_ctx); 1541168515Sgshapiro mi_clr_macros(g->a_ctx, 0); 154264562Sgshapiro return _SMFIS_NOREPLY; 154364562Sgshapiro} 1544168515Sgshapiro 154590792Sgshapiro/* 154664562Sgshapiro** ST_BODYCHUNK -- deal with a piece of the mail body 154764562Sgshapiro** 154864562Sgshapiro** Parameters: 154964562Sgshapiro** g -- generic argument structure 155064562Sgshapiro** 155164562Sgshapiro** Returns: 155264562Sgshapiro** continue or filter-specified value 155364562Sgshapiro*/ 155464562Sgshapiro 155564562Sgshapirostatic int 155664562Sgshapirost_bodychunk(g) 155764562Sgshapiro genarg *g; 155864562Sgshapiro{ 155990792Sgshapiro sfsistat (*fi_body) __P((SMFICTX *, unsigned char *, size_t)); 156064562Sgshapiro 156164562Sgshapiro if (g == NULL) 156264562Sgshapiro return _SMFIS_ABORT; 156364562Sgshapiro if (g->a_ctx->ctx_smfi != NULL && 156464562Sgshapiro (fi_body = g->a_ctx->ctx_smfi->xxfi_body) != NULL) 156590792Sgshapiro return (*fi_body)(g->a_ctx, (unsigned char *)g->a_buf, 156690792Sgshapiro g->a_len); 156764562Sgshapiro return SMFIS_CONTINUE; 156864562Sgshapiro} 1569168515Sgshapiro 157090792Sgshapiro/* 157164562Sgshapiro** ST_BODYEND -- deal with the last piece of the mail body 157264562Sgshapiro** 157364562Sgshapiro** Parameters: 157464562Sgshapiro** g -- generic argument structure 157564562Sgshapiro** 157664562Sgshapiro** Returns: 157764562Sgshapiro** continue or filter-specified value 157864562Sgshapiro** 157964562Sgshapiro** Side effects: 158064562Sgshapiro** sends a reply for the body part (if non-empty). 158164562Sgshapiro*/ 158264562Sgshapiro 158364562Sgshapirostatic int 158464562Sgshapirost_bodyend(g) 158564562Sgshapiro genarg *g; 158664562Sgshapiro{ 158764562Sgshapiro sfsistat r; 158890792Sgshapiro sfsistat (*fi_body) __P((SMFICTX *, unsigned char *, size_t)); 158964562Sgshapiro sfsistat (*fi_eom) __P((SMFICTX *)); 159064562Sgshapiro 159164562Sgshapiro if (g == NULL) 159264562Sgshapiro return _SMFIS_ABORT; 159364562Sgshapiro r = SMFIS_CONTINUE; 159464562Sgshapiro if (g->a_ctx->ctx_smfi != NULL) 159564562Sgshapiro { 159664562Sgshapiro if ((fi_body = g->a_ctx->ctx_smfi->xxfi_body) != NULL && 159764562Sgshapiro g->a_len > 0) 159864562Sgshapiro { 159964562Sgshapiro socket_t sd; 160064562Sgshapiro struct timeval timeout; 160164562Sgshapiro 160264562Sgshapiro timeout.tv_sec = g->a_ctx->ctx_timeout; 160364562Sgshapiro timeout.tv_usec = 0; 160464562Sgshapiro sd = g->a_ctx->ctx_sd; 160590792Sgshapiro r = (*fi_body)(g->a_ctx, (unsigned char *)g->a_buf, 160690792Sgshapiro g->a_len); 160764562Sgshapiro if (r != SMFIS_CONTINUE && 160864562Sgshapiro sendreply(r, sd, &timeout, g->a_ctx) != MI_SUCCESS) 160964562Sgshapiro return _SMFIS_ABORT; 161064562Sgshapiro } 161164562Sgshapiro } 161264562Sgshapiro if (r == SMFIS_CONTINUE && 161364562Sgshapiro (fi_eom = g->a_ctx->ctx_smfi->xxfi_eom) != NULL) 161464562Sgshapiro return (*fi_eom)(g->a_ctx); 161564562Sgshapiro return r; 161664562Sgshapiro} 1617168515Sgshapiro 161890792Sgshapiro/* 161964562Sgshapiro** ST_ABORTFCT -- deal with aborts 162064562Sgshapiro** 162164562Sgshapiro** Parameters: 162264562Sgshapiro** g -- generic argument structure 162364562Sgshapiro** 162464562Sgshapiro** Returns: 162564562Sgshapiro** abort or filter-specified value 162664562Sgshapiro*/ 162764562Sgshapiro 162864562Sgshapirostatic int 162964562Sgshapirost_abortfct(g) 163064562Sgshapiro genarg *g; 163164562Sgshapiro{ 163264562Sgshapiro sfsistat (*fi_abort) __P((SMFICTX *)); 163364562Sgshapiro 163464562Sgshapiro if (g == NULL) 163564562Sgshapiro return _SMFIS_ABORT; 163664562Sgshapiro if (g != NULL && g->a_ctx->ctx_smfi != NULL && 163764562Sgshapiro (fi_abort = g->a_ctx->ctx_smfi->xxfi_abort) != NULL) 163864562Sgshapiro (void) (*fi_abort)(g->a_ctx); 163964562Sgshapiro return _SMFIS_NOREPLY; 164064562Sgshapiro} 1641168515Sgshapiro 164290792Sgshapiro/* 164364562Sgshapiro** TRANS_OK -- is the state transition ok? 164464562Sgshapiro** 164564562Sgshapiro** Parameters: 164664562Sgshapiro** old -- old state 164764562Sgshapiro** new -- new state 164864562Sgshapiro** 164964562Sgshapiro** Returns: 165064562Sgshapiro** state transition ok 165164562Sgshapiro*/ 165264562Sgshapiro 165364562Sgshapirostatic bool 165464562Sgshapirotrans_ok(old, new) 165564562Sgshapiro int old, new; 165664562Sgshapiro{ 165764562Sgshapiro int s, n; 165864562Sgshapiro 165964562Sgshapiro s = old; 1660159609Sgshapiro if (s >= SIZE_NEXT_STATES) 1661159609Sgshapiro return false; 166266494Sgshapiro do 166366494Sgshapiro { 166464562Sgshapiro /* is this state transition allowed? */ 1665110560Sgshapiro if ((MI_MASK(new) & next_states[s]) != 0) 166690792Sgshapiro return true; 166764562Sgshapiro 166864562Sgshapiro /* 166964562Sgshapiro ** no: try next state; 167064562Sgshapiro ** this works since the relevant states are ordered 167164562Sgshapiro ** strict sequentially 167264562Sgshapiro */ 167390792Sgshapiro 167464562Sgshapiro n = s + 1; 1675159609Sgshapiro if (n >= SIZE_NEXT_STATES) 1676159609Sgshapiro return false; 167764562Sgshapiro 167864562Sgshapiro /* 167964562Sgshapiro ** can we actually "skip" this state? 168064562Sgshapiro ** see fix_stm() which sets this bit for those 168164562Sgshapiro ** states which the filter program is not interested in 168264562Sgshapiro */ 168390792Sgshapiro 168464562Sgshapiro if (bitset(NX_SKIP, next_states[n])) 168564562Sgshapiro s = n; 168664562Sgshapiro else 168790792Sgshapiro return false; 1688159609Sgshapiro } while (s < SIZE_NEXT_STATES); 168990792Sgshapiro return false; 169064562Sgshapiro} 1691168515Sgshapiro 169290792Sgshapiro/* 169364562Sgshapiro** FIX_STM -- add "skip" bits to the state transition table 169464562Sgshapiro** 169564562Sgshapiro** Parameters: 169664562Sgshapiro** ctx -- context structure 169764562Sgshapiro** 169864562Sgshapiro** Returns: 169964562Sgshapiro** None. 170064562Sgshapiro** 170164562Sgshapiro** Side effects: 170264562Sgshapiro** may change state transition table. 170364562Sgshapiro*/ 170464562Sgshapiro 170564562Sgshapirostatic void 170664562Sgshapirofix_stm(ctx) 170764562Sgshapiro SMFICTX_PTR ctx; 170864562Sgshapiro{ 170990792Sgshapiro unsigned long fl; 171064562Sgshapiro 171164562Sgshapiro if (ctx == NULL || ctx->ctx_smfi == NULL) 171264562Sgshapiro return; 171364562Sgshapiro fl = ctx->ctx_pflags; 171464562Sgshapiro if (bitset(SMFIP_NOCONNECT, fl)) 171564562Sgshapiro next_states[ST_CONN] |= NX_SKIP; 171664562Sgshapiro if (bitset(SMFIP_NOHELO, fl)) 171764562Sgshapiro next_states[ST_HELO] |= NX_SKIP; 171864562Sgshapiro if (bitset(SMFIP_NOMAIL, fl)) 171964562Sgshapiro next_states[ST_MAIL] |= NX_SKIP; 172064562Sgshapiro if (bitset(SMFIP_NORCPT, fl)) 172164562Sgshapiro next_states[ST_RCPT] |= NX_SKIP; 172264562Sgshapiro if (bitset(SMFIP_NOHDRS, fl)) 172364562Sgshapiro next_states[ST_HDRS] |= NX_SKIP; 172464562Sgshapiro if (bitset(SMFIP_NOEOH, fl)) 172564562Sgshapiro next_states[ST_EOHS] |= NX_SKIP; 172664562Sgshapiro if (bitset(SMFIP_NOBODY, fl)) 172764562Sgshapiro next_states[ST_BODY] |= NX_SKIP; 1728168515Sgshapiro if (bitset(SMFIP_NODATA, fl)) 1729168515Sgshapiro next_states[ST_DATA] |= NX_SKIP; 1730168515Sgshapiro if (bitset(SMFIP_NOUNKNOWN, fl)) 1731168515Sgshapiro next_states[ST_UNKN] |= NX_SKIP; 173264562Sgshapiro} 1733168515Sgshapiro 173490792Sgshapiro/* 173564562Sgshapiro** DEC_ARGV -- split a buffer into a list of strings, NULL terminated 173664562Sgshapiro** 173764562Sgshapiro** Parameters: 173864562Sgshapiro** buf -- buffer with several strings 173964562Sgshapiro** len -- length of buffer 174064562Sgshapiro** 174164562Sgshapiro** Returns: 174264562Sgshapiro** array of pointers to the individual strings 174364562Sgshapiro*/ 174464562Sgshapiro 174564562Sgshapirostatic char ** 174664562Sgshapirodec_argv(buf, len) 174764562Sgshapiro char *buf; 174864562Sgshapiro size_t len; 174964562Sgshapiro{ 175064562Sgshapiro char **s; 175164562Sgshapiro size_t i; 175264562Sgshapiro int elem, nelem; 175364562Sgshapiro 175464562Sgshapiro nelem = 0; 175564562Sgshapiro for (i = 0; i < len; i++) 175664562Sgshapiro { 175764562Sgshapiro if (buf[i] == '\0') 175864562Sgshapiro ++nelem; 175964562Sgshapiro } 176064562Sgshapiro if (nelem == 0) 176164562Sgshapiro return NULL; 176264562Sgshapiro 176364562Sgshapiro /* last entry is only for the name */ 176464562Sgshapiro s = (char **)malloc((nelem + 1) * (sizeof *s)); 176564562Sgshapiro if (s == NULL) 176664562Sgshapiro return NULL; 176764562Sgshapiro s[0] = buf; 176864562Sgshapiro for (i = 0, elem = 0; i < len && elem < nelem; i++) 176964562Sgshapiro { 177064562Sgshapiro if (buf[i] == '\0') 1771125820Sgshapiro { 1772125820Sgshapiro ++elem; 1773125820Sgshapiro if (i + 1 >= len) 1774125820Sgshapiro s[elem] = NULL; 1775125820Sgshapiro else 1776125820Sgshapiro s[elem] = &(buf[i + 1]); 1777125820Sgshapiro } 177864562Sgshapiro } 177964562Sgshapiro 1780125820Sgshapiro /* overwrite last entry (already done above, just paranoia) */ 178164562Sgshapiro s[elem] = NULL; 178264562Sgshapiro return s; 178364562Sgshapiro} 1784168515Sgshapiro 178590792Sgshapiro/* 178664562Sgshapiro** DEC_ARG2 -- split a buffer into two strings 178764562Sgshapiro** 178864562Sgshapiro** Parameters: 178964562Sgshapiro** buf -- buffer with two strings 179064562Sgshapiro** len -- length of buffer 179164562Sgshapiro** s1,s2 -- pointer to result strings 179264562Sgshapiro** 179364562Sgshapiro** Returns: 179464562Sgshapiro** MI_FAILURE/MI_SUCCESS 179564562Sgshapiro*/ 179664562Sgshapiro 179764562Sgshapirostatic int 179864562Sgshapirodec_arg2(buf, len, s1, s2) 179964562Sgshapiro char *buf; 180064562Sgshapiro size_t len; 180164562Sgshapiro char **s1; 180264562Sgshapiro char **s2; 180364562Sgshapiro{ 180464562Sgshapiro size_t i; 180564562Sgshapiro 1806125820Sgshapiro /* paranoia: check for terminating '\0' */ 1807125820Sgshapiro if (len == 0 || buf[len - 1] != '\0') 1808125820Sgshapiro return MI_FAILURE; 180964562Sgshapiro *s1 = buf; 181064562Sgshapiro for (i = 1; i < len && buf[i] != '\0'; i++) 181164562Sgshapiro continue; 181264562Sgshapiro if (i >= len - 1) 181364562Sgshapiro return MI_FAILURE; 181464562Sgshapiro *s2 = buf + i + 1; 181564562Sgshapiro return MI_SUCCESS; 181664562Sgshapiro} 1817168515Sgshapiro 181890792Sgshapiro/* 181964562Sgshapiro** SENDOK -- is it ok for the filter to send stuff to the MTA? 182064562Sgshapiro** 182164562Sgshapiro** Parameters: 182264562Sgshapiro** ctx -- context structure 182364562Sgshapiro** flag -- flag to check 182464562Sgshapiro** 182564562Sgshapiro** Returns: 182664562Sgshapiro** sending allowed (in current state) 182764562Sgshapiro*/ 182864562Sgshapiro 182964562Sgshapirobool 183064562Sgshapiromi_sendok(ctx, flag) 183164562Sgshapiro SMFICTX_PTR ctx; 183264562Sgshapiro int flag; 183364562Sgshapiro{ 183464562Sgshapiro if (ctx == NULL || ctx->ctx_smfi == NULL) 183590792Sgshapiro return false; 183690792Sgshapiro 183790792Sgshapiro /* did the milter request this operation? */ 1838168515Sgshapiro if (flag != 0 && !bitset(flag, ctx->ctx_aflags)) 183990792Sgshapiro return false; 184090792Sgshapiro 184190792Sgshapiro /* are we in the correct state? It must be "End of Message". */ 184264562Sgshapiro return ctx->ctx_state == ST_ENDM; 184364562Sgshapiro} 1844168515Sgshapiro 1845168515Sgshapiro#if _FFR_WORKERS_POOL 1846168515Sgshapiro/* 1847168515Sgshapiro** MI_RD_SOCKET_READY - checks if the socket is ready for read(2) 1848168515Sgshapiro** 1849168515Sgshapiro** Parameters: 1850168515Sgshapiro** sd -- socket_t 1851168515Sgshapiro** 1852168515Sgshapiro** Returns: 1853168515Sgshapiro** true iff socket is ready for read(2) 1854168515Sgshapiro*/ 1855168515Sgshapiro 1856168515Sgshapiro#define MI_RD_CMD_TO 1 1857168515Sgshapiro#define MI_RD_MAX_ERR 16 1858168515Sgshapiro 1859168515Sgshapirostatic bool 1860168515Sgshapiromi_rd_socket_ready (sd) 1861168515Sgshapiro socket_t sd; 1862168515Sgshapiro{ 1863168515Sgshapiro int n; 1864168515Sgshapiro int nerr = 0; 1865168515Sgshapiro#if SM_CONF_POLL 1866182352Sgshapiro struct pollfd pfd; 1867168515Sgshapiro#else /* SM_CONF_POLL */ 1868182352Sgshapiro fd_set rd_set, exc_set; 1869168515Sgshapiro#endif /* SM_CONF_POLL */ 1870168515Sgshapiro 1871168515Sgshapiro do 1872168515Sgshapiro { 1873168515Sgshapiro#if SM_CONF_POLL 1874168515Sgshapiro pfd.fd = sd; 1875168515Sgshapiro pfd.events = POLLIN; 1876168515Sgshapiro pfd.revents = 0; 1877168515Sgshapiro 1878168515Sgshapiro n = poll(&pfd, 1, MI_RD_CMD_TO); 1879168515Sgshapiro#else /* SM_CONF_POLL */ 1880168515Sgshapiro struct timeval timeout; 1881168515Sgshapiro 1882168515Sgshapiro FD_ZERO(&rd_set); 1883168515Sgshapiro FD_ZERO(&exc_set); 1884168515Sgshapiro FD_SET(sd, &rd_set); 1885168515Sgshapiro FD_SET(sd, &exc_set); 1886168515Sgshapiro 1887168515Sgshapiro timeout.tv_sec = MI_RD_CMD_TO / 1000; 1888168515Sgshapiro timeout.tv_usec = 0; 1889168515Sgshapiro n = select(sd + 1, &rd_set, NULL, &exc_set, &timeout); 1890168515Sgshapiro#endif /* SM_CONF_POLL */ 1891168515Sgshapiro 1892168515Sgshapiro if (n < 0) 1893168515Sgshapiro { 1894168515Sgshapiro if (errno == EINTR) 1895168515Sgshapiro { 1896168515Sgshapiro nerr++; 1897168515Sgshapiro continue; 1898168515Sgshapiro } 1899168515Sgshapiro return true; 1900168515Sgshapiro } 1901168515Sgshapiro 1902168515Sgshapiro if (n == 0) 1903168515Sgshapiro return false; 1904168515Sgshapiro break; 1905168515Sgshapiro } while (nerr < MI_RD_MAX_ERR); 1906168515Sgshapiro if (nerr >= MI_RD_MAX_ERR) 1907168515Sgshapiro return false; 1908168515Sgshapiro 1909168515Sgshapiro#if SM_CONF_POLL 1910168515Sgshapiro return (pfd.revents != 0); 1911168515Sgshapiro#else /* SM_CONF_POLL */ 1912168515Sgshapiro return FD_ISSET(sd, &rd_set) || FD_ISSET(sd, &exc_set); 1913168515Sgshapiro#endif /* SM_CONF_POLL */ 1914168515Sgshapiro} 1915168515Sgshapiro#endif /* _FFR_WORKERS_POOL */ 1916