17c478bd9Sstevel@tonic-gate /* 2d4660949Sjbeck * Copyright (c) 1999-2004, 2006-2008 Sendmail, Inc. and its suppliers. 37c478bd9Sstevel@tonic-gate * All rights reserved. 47c478bd9Sstevel@tonic-gate * 57c478bd9Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set 67c478bd9Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of 77c478bd9Sstevel@tonic-gate * the sendmail distribution. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate */ 107c478bd9Sstevel@tonic-gate 117c478bd9Sstevel@tonic-gate #include <sm/gen.h> 12*e9af4bc0SJohn Beck SM_RCSID("@(#)$Id: engine.c,v 8.166 2009/11/06 00:57:07 ca Exp $") 137c478bd9Sstevel@tonic-gate 147c478bd9Sstevel@tonic-gate #include "libmilter.h" 157c478bd9Sstevel@tonic-gate 167c478bd9Sstevel@tonic-gate #if NETINET || NETINET6 177c478bd9Sstevel@tonic-gate # include <arpa/inet.h> 187c478bd9Sstevel@tonic-gate #endif /* NETINET || NETINET6 */ 197c478bd9Sstevel@tonic-gate 207c478bd9Sstevel@tonic-gate /* generic argument for functions in the command table */ 217c478bd9Sstevel@tonic-gate struct arg_struct 227c478bd9Sstevel@tonic-gate { 237c478bd9Sstevel@tonic-gate size_t a_len; /* length of buffer */ 247c478bd9Sstevel@tonic-gate char *a_buf; /* argument string */ 257c478bd9Sstevel@tonic-gate int a_idx; /* index for macro array */ 267c478bd9Sstevel@tonic-gate SMFICTX_PTR a_ctx; /* context */ 277c478bd9Sstevel@tonic-gate }; 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate typedef struct arg_struct genarg; 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate /* structure for commands received from MTA */ 327c478bd9Sstevel@tonic-gate struct cmdfct_t 337c478bd9Sstevel@tonic-gate { 347c478bd9Sstevel@tonic-gate char cm_cmd; /* command */ 357c478bd9Sstevel@tonic-gate int cm_argt; /* type of arguments expected */ 367c478bd9Sstevel@tonic-gate int cm_next; /* next state */ 377c478bd9Sstevel@tonic-gate int cm_todo; /* what to do next */ 387c478bd9Sstevel@tonic-gate int cm_macros; /* index for macros */ 397c478bd9Sstevel@tonic-gate int (*cm_fct) __P((genarg *)); /* function to execute */ 407c478bd9Sstevel@tonic-gate }; 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate typedef struct cmdfct_t cmdfct; 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate /* possible values for cm_argt */ 457c478bd9Sstevel@tonic-gate #define CM_ARG0 0 /* no args */ 467c478bd9Sstevel@tonic-gate #define CM_ARG1 1 /* one arg (string) */ 477c478bd9Sstevel@tonic-gate #define CM_ARG2 2 /* two args (strings) */ 487c478bd9Sstevel@tonic-gate #define CM_ARGA 4 /* one string and _SOCK_ADDR */ 497c478bd9Sstevel@tonic-gate #define CM_ARGO 5 /* two integers */ 507c478bd9Sstevel@tonic-gate #define CM_ARGV 8 /* \0 separated list of args, NULL-terminated */ 517c478bd9Sstevel@tonic-gate #define CM_ARGN 9 /* \0 separated list of args (strings) */ 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate /* possible values for cm_todo */ 547c478bd9Sstevel@tonic-gate #define CT_CONT 0x0000 /* continue reading commands */ 557c478bd9Sstevel@tonic-gate #define CT_IGNO 0x0001 /* continue even when error */ 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate /* not needed right now, done via return code instead */ 587c478bd9Sstevel@tonic-gate #define CT_KEEP 0x0004 /* keep buffer (contains symbols) */ 59058561cbSjbeck #define CT_END 0x0008 /* last command of session, stop replying */ 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate /* index in macro array: macros only for these commands */ 627c478bd9Sstevel@tonic-gate #define CI_NONE (-1) 637c478bd9Sstevel@tonic-gate #define CI_CONN 0 647c478bd9Sstevel@tonic-gate #define CI_HELO 1 657c478bd9Sstevel@tonic-gate #define CI_MAIL 2 667c478bd9Sstevel@tonic-gate #define CI_RCPT 3 67058561cbSjbeck #define CI_DATA 4 68058561cbSjbeck #define CI_EOM 5 69058561cbSjbeck #define CI_EOH 6 70058561cbSjbeck #define CI_LAST CI_EOH 71058561cbSjbeck #if CI_LAST < CI_DATA 72058561cbSjbeck ERROR: do not compile with CI_LAST < CI_DATA 73058561cbSjbeck #endif 74058561cbSjbeck #if CI_LAST < CI_EOM 75058561cbSjbeck ERROR: do not compile with CI_LAST < CI_EOM 76058561cbSjbeck #endif 77058561cbSjbeck #if CI_LAST < CI_EOH 78058561cbSjbeck ERROR: do not compile with CI_LAST < CI_EOH 79058561cbSjbeck #endif 80058561cbSjbeck #if CI_LAST < CI_ENVRCPT 81058561cbSjbeck ERROR: do not compile with CI_LAST < CI_ENVRCPT 82058561cbSjbeck #endif 83058561cbSjbeck #if CI_LAST < CI_ENVFROM 84058561cbSjbeck ERROR: do not compile with CI_LAST < CI_ENVFROM 85058561cbSjbeck #endif 86058561cbSjbeck #if CI_LAST < CI_HELO 87058561cbSjbeck ERROR: do not compile with CI_LAST < CI_HELO 88058561cbSjbeck #endif 89058561cbSjbeck #if CI_LAST < CI_CONNECT 90058561cbSjbeck ERROR: do not compile with CI_LAST < CI_CONNECT 91058561cbSjbeck #endif 92058561cbSjbeck #if CI_LAST >= MAX_MACROS_ENTRIES 93058561cbSjbeck ERROR: do not compile with CI_LAST >= MAX_MACROS_ENTRIES 947c478bd9Sstevel@tonic-gate #endif 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate /* function prototypes */ 977c478bd9Sstevel@tonic-gate static int st_abortfct __P((genarg *)); 987c478bd9Sstevel@tonic-gate static int st_macros __P((genarg *)); 997c478bd9Sstevel@tonic-gate static int st_optionneg __P((genarg *)); 1007c478bd9Sstevel@tonic-gate static int st_bodychunk __P((genarg *)); 1017c478bd9Sstevel@tonic-gate static int st_connectinfo __P((genarg *)); 1027c478bd9Sstevel@tonic-gate static int st_bodyend __P((genarg *)); 1037c478bd9Sstevel@tonic-gate static int st_helo __P((genarg *)); 1047c478bd9Sstevel@tonic-gate static int st_header __P((genarg *)); 1057c478bd9Sstevel@tonic-gate static int st_sender __P((genarg *)); 1067c478bd9Sstevel@tonic-gate static int st_rcpt __P((genarg *)); 1077c478bd9Sstevel@tonic-gate static int st_unknown __P((genarg *)); 1087c478bd9Sstevel@tonic-gate static int st_data __P((genarg *)); 1097c478bd9Sstevel@tonic-gate static int st_eoh __P((genarg *)); 1107c478bd9Sstevel@tonic-gate static int st_quit __P((genarg *)); 1117c478bd9Sstevel@tonic-gate static int sendreply __P((sfsistat, socket_t, struct timeval *, SMFICTX_PTR)); 1127c478bd9Sstevel@tonic-gate static void fix_stm __P((SMFICTX_PTR)); 1137c478bd9Sstevel@tonic-gate static bool trans_ok __P((int, int)); 1147c478bd9Sstevel@tonic-gate static char **dec_argv __P((char *, size_t)); 1157c478bd9Sstevel@tonic-gate static int dec_arg2 __P((char *, size_t, char **, char **)); 116*e9af4bc0SJohn Beck static void mi_clr_symlist __P((SMFICTX_PTR)); 1177c478bd9Sstevel@tonic-gate 118058561cbSjbeck #if _FFR_WORKERS_POOL 119058561cbSjbeck static bool mi_rd_socket_ready __P((int)); 120058561cbSjbeck #endif /* _FFR_WORKERS_POOL */ 121058561cbSjbeck 1227c478bd9Sstevel@tonic-gate /* states */ 1237c478bd9Sstevel@tonic-gate #define ST_NONE (-1) 1247c478bd9Sstevel@tonic-gate #define ST_INIT 0 /* initial state */ 1257c478bd9Sstevel@tonic-gate #define ST_OPTS 1 /* option negotiation */ 1267c478bd9Sstevel@tonic-gate #define ST_CONN 2 /* connection info */ 1277c478bd9Sstevel@tonic-gate #define ST_HELO 3 /* helo */ 1287c478bd9Sstevel@tonic-gate #define ST_MAIL 4 /* mail from */ 1297c478bd9Sstevel@tonic-gate #define ST_RCPT 5 /* rcpt to */ 1307c478bd9Sstevel@tonic-gate #define ST_DATA 6 /* data */ 1317c478bd9Sstevel@tonic-gate #define ST_HDRS 7 /* headers */ 1327c478bd9Sstevel@tonic-gate #define ST_EOHS 8 /* end of headers */ 1337c478bd9Sstevel@tonic-gate #define ST_BODY 9 /* body */ 1347c478bd9Sstevel@tonic-gate #define ST_ENDM 10 /* end of message */ 1357c478bd9Sstevel@tonic-gate #define ST_QUIT 11 /* quit */ 1367c478bd9Sstevel@tonic-gate #define ST_ABRT 12 /* abort */ 1377c478bd9Sstevel@tonic-gate #define ST_UNKN 13 /* unknown SMTP command */ 138058561cbSjbeck #define ST_Q_NC 14 /* quit, new connection follows */ 139058561cbSjbeck #define ST_LAST ST_Q_NC /* last valid state */ 140058561cbSjbeck #define ST_SKIP 16 /* not a state but required for the state table */ 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate /* in a mail transaction? must be before eom according to spec. */ 1437c478bd9Sstevel@tonic-gate #define ST_IN_MAIL(st) ((st) >= ST_MAIL && (st) < ST_ENDM) 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate /* 1467c478bd9Sstevel@tonic-gate ** set of next states 1477c478bd9Sstevel@tonic-gate ** each state (ST_*) corresponds to bit in an int value (1 << state) 1487c478bd9Sstevel@tonic-gate ** each state has a set of allowed transitions ('or' of bits of states) 1497c478bd9Sstevel@tonic-gate ** so a state transition is valid if the mask of the next state 1507c478bd9Sstevel@tonic-gate ** is set in the NX_* value 1517c478bd9Sstevel@tonic-gate ** this function is coded in trans_ok(), see below. 1527c478bd9Sstevel@tonic-gate */ 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate #define MI_MASK(x) (0x0001 << (x)) /* generate a bit "mask" for a state */ 1557c478bd9Sstevel@tonic-gate #define NX_INIT (MI_MASK(ST_OPTS)) 1567c478bd9Sstevel@tonic-gate #define NX_OPTS (MI_MASK(ST_CONN) | MI_MASK(ST_UNKN)) 1577c478bd9Sstevel@tonic-gate #define NX_CONN (MI_MASK(ST_HELO) | MI_MASK(ST_MAIL) | MI_MASK(ST_UNKN)) 1587c478bd9Sstevel@tonic-gate #define NX_HELO (MI_MASK(ST_HELO) | MI_MASK(ST_MAIL) | MI_MASK(ST_UNKN)) 1597c478bd9Sstevel@tonic-gate #define NX_MAIL (MI_MASK(ST_RCPT) | MI_MASK(ST_ABRT) | MI_MASK(ST_UNKN)) 1607c478bd9Sstevel@tonic-gate #define NX_RCPT (MI_MASK(ST_HDRS) | MI_MASK(ST_EOHS) | MI_MASK(ST_DATA) | \ 1617c478bd9Sstevel@tonic-gate MI_MASK(ST_BODY) | MI_MASK(ST_ENDM) | \ 1627c478bd9Sstevel@tonic-gate MI_MASK(ST_RCPT) | MI_MASK(ST_ABRT) | MI_MASK(ST_UNKN)) 1637c478bd9Sstevel@tonic-gate #define NX_DATA (MI_MASK(ST_EOHS) | MI_MASK(ST_HDRS) | MI_MASK(ST_ABRT)) 1647c478bd9Sstevel@tonic-gate #define NX_HDRS (MI_MASK(ST_EOHS) | MI_MASK(ST_HDRS) | MI_MASK(ST_ABRT)) 1657c478bd9Sstevel@tonic-gate #define NX_EOHS (MI_MASK(ST_BODY) | MI_MASK(ST_ENDM) | MI_MASK(ST_ABRT)) 1667c478bd9Sstevel@tonic-gate #define NX_BODY (MI_MASK(ST_ENDM) | MI_MASK(ST_BODY) | MI_MASK(ST_ABRT)) 167058561cbSjbeck #define NX_ENDM (MI_MASK(ST_QUIT) | MI_MASK(ST_MAIL) | MI_MASK(ST_UNKN) | \ 168058561cbSjbeck MI_MASK(ST_Q_NC)) 1697c478bd9Sstevel@tonic-gate #define NX_QUIT 0 1707c478bd9Sstevel@tonic-gate #define NX_ABRT 0 1717c478bd9Sstevel@tonic-gate #define NX_UNKN (MI_MASK(ST_HELO) | MI_MASK(ST_MAIL) | \ 1727c478bd9Sstevel@tonic-gate MI_MASK(ST_RCPT) | MI_MASK(ST_ABRT) | \ 1737c478bd9Sstevel@tonic-gate MI_MASK(ST_DATA) | \ 1747c478bd9Sstevel@tonic-gate MI_MASK(ST_BODY) | MI_MASK(ST_UNKN) | \ 175058561cbSjbeck MI_MASK(ST_ABRT) | MI_MASK(ST_QUIT) | MI_MASK(ST_Q_NC)) 176058561cbSjbeck #define NX_Q_NC (MI_MASK(ST_CONN) | MI_MASK(ST_UNKN)) 1777c478bd9Sstevel@tonic-gate #define NX_SKIP MI_MASK(ST_SKIP) 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate static int next_states[] = 1807c478bd9Sstevel@tonic-gate { 181058561cbSjbeck NX_INIT 182058561cbSjbeck , NX_OPTS 183058561cbSjbeck , NX_CONN 184058561cbSjbeck , NX_HELO 185058561cbSjbeck , NX_MAIL 186058561cbSjbeck , NX_RCPT 187058561cbSjbeck , NX_DATA 188058561cbSjbeck , NX_HDRS 189058561cbSjbeck , NX_EOHS 190058561cbSjbeck , NX_BODY 191058561cbSjbeck , NX_ENDM 192058561cbSjbeck , NX_QUIT 193058561cbSjbeck , NX_ABRT 194058561cbSjbeck , NX_UNKN 195058561cbSjbeck , NX_Q_NC 1967c478bd9Sstevel@tonic-gate }; 1977c478bd9Sstevel@tonic-gate 1983ee0e492Sjbeck #define SIZE_NEXT_STATES (sizeof(next_states) / sizeof(next_states[0])) 1993ee0e492Sjbeck 2007c478bd9Sstevel@tonic-gate /* commands received by milter */ 2017c478bd9Sstevel@tonic-gate static cmdfct cmds[] = 2027c478bd9Sstevel@tonic-gate { 203058561cbSjbeck {SMFIC_ABORT, CM_ARG0, ST_ABRT, CT_CONT, CI_NONE, st_abortfct } 204058561cbSjbeck , {SMFIC_MACRO, CM_ARGV, ST_NONE, CT_KEEP, CI_NONE, st_macros } 205058561cbSjbeck , {SMFIC_BODY, CM_ARG1, ST_BODY, CT_CONT, CI_NONE, st_bodychunk } 206058561cbSjbeck , {SMFIC_CONNECT, CM_ARG2, ST_CONN, CT_CONT, CI_CONN, st_connectinfo } 207058561cbSjbeck , {SMFIC_BODYEOB, CM_ARG1, ST_ENDM, CT_CONT, CI_EOM, st_bodyend } 208058561cbSjbeck , {SMFIC_HELO, CM_ARG1, ST_HELO, CT_CONT, CI_HELO, st_helo } 209058561cbSjbeck , {SMFIC_HEADER, CM_ARG2, ST_HDRS, CT_CONT, CI_NONE, st_header } 210058561cbSjbeck , {SMFIC_MAIL, CM_ARGV, ST_MAIL, CT_CONT, CI_MAIL, st_sender } 211058561cbSjbeck , {SMFIC_OPTNEG, CM_ARGO, ST_OPTS, CT_CONT, CI_NONE, st_optionneg } 212058561cbSjbeck , {SMFIC_EOH, CM_ARG0, ST_EOHS, CT_CONT, CI_EOH, st_eoh } 213058561cbSjbeck , {SMFIC_QUIT, CM_ARG0, ST_QUIT, CT_END, CI_NONE, st_quit } 214058561cbSjbeck , {SMFIC_DATA, CM_ARG0, ST_DATA, CT_CONT, CI_DATA, st_data } 215058561cbSjbeck , {SMFIC_RCPT, CM_ARGV, ST_RCPT, CT_IGNO, CI_RCPT, st_rcpt } 2167c478bd9Sstevel@tonic-gate , {SMFIC_UNKNOWN, CM_ARG1, ST_UNKN, CT_IGNO, CI_NONE, st_unknown } 217058561cbSjbeck , {SMFIC_QUIT_NC, CM_ARG0, ST_Q_NC, CT_CONT, CI_NONE, st_quit } 2187c478bd9Sstevel@tonic-gate }; 2197c478bd9Sstevel@tonic-gate 220058561cbSjbeck /* 221058561cbSjbeck ** Additional (internal) reply codes; 222058561cbSjbeck ** must be coordinated wit libmilter/mfapi.h 223058561cbSjbeck */ 224058561cbSjbeck 2257c478bd9Sstevel@tonic-gate #define _SMFIS_KEEP 20 2267c478bd9Sstevel@tonic-gate #define _SMFIS_ABORT 21 2277c478bd9Sstevel@tonic-gate #define _SMFIS_OPTIONS 22 228058561cbSjbeck #define _SMFIS_NOREPLY SMFIS_NOREPLY 2297c478bd9Sstevel@tonic-gate #define _SMFIS_FAIL (-1) 2307c478bd9Sstevel@tonic-gate #define _SMFIS_NONE (-2) 2317c478bd9Sstevel@tonic-gate 2327c478bd9Sstevel@tonic-gate /* 2337c478bd9Sstevel@tonic-gate ** MI_ENGINE -- receive commands and process them 2347c478bd9Sstevel@tonic-gate ** 2357c478bd9Sstevel@tonic-gate ** Parameters: 2367c478bd9Sstevel@tonic-gate ** ctx -- context structure 2377c478bd9Sstevel@tonic-gate ** 2387c478bd9Sstevel@tonic-gate ** Returns: 2397c478bd9Sstevel@tonic-gate ** MI_FAILURE/MI_SUCCESS 2407c478bd9Sstevel@tonic-gate */ 241058561cbSjbeck 2427c478bd9Sstevel@tonic-gate int 2437c478bd9Sstevel@tonic-gate mi_engine(ctx) 2447c478bd9Sstevel@tonic-gate SMFICTX_PTR ctx; 2457c478bd9Sstevel@tonic-gate { 2467c478bd9Sstevel@tonic-gate size_t len; 2477c478bd9Sstevel@tonic-gate int i; 2487c478bd9Sstevel@tonic-gate socket_t sd; 2497c478bd9Sstevel@tonic-gate int ret = MI_SUCCESS; 2507c478bd9Sstevel@tonic-gate int ncmds = sizeof(cmds) / sizeof(cmdfct); 2517c478bd9Sstevel@tonic-gate int curstate = ST_INIT; 2527c478bd9Sstevel@tonic-gate int newstate; 2537c478bd9Sstevel@tonic-gate bool call_abort; 2547c478bd9Sstevel@tonic-gate sfsistat r; 2557c478bd9Sstevel@tonic-gate char cmd; 2567c478bd9Sstevel@tonic-gate char *buf = NULL; 2577c478bd9Sstevel@tonic-gate genarg arg; 2587c478bd9Sstevel@tonic-gate struct timeval timeout; 2597c478bd9Sstevel@tonic-gate int (*f) __P((genarg *)); 2607c478bd9Sstevel@tonic-gate sfsistat (*fi_abort) __P((SMFICTX *)); 2617c478bd9Sstevel@tonic-gate sfsistat (*fi_close) __P((SMFICTX *)); 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate arg.a_ctx = ctx; 2647c478bd9Sstevel@tonic-gate sd = ctx->ctx_sd; 2657c478bd9Sstevel@tonic-gate fi_abort = ctx->ctx_smfi->xxfi_abort; 266058561cbSjbeck #if _FFR_WORKERS_POOL 267058561cbSjbeck curstate = ctx->ctx_state; 268058561cbSjbeck if (curstate == ST_INIT) 269058561cbSjbeck { 2707c478bd9Sstevel@tonic-gate mi_clr_macros(ctx, 0); 2717c478bd9Sstevel@tonic-gate fix_stm(ctx); 272058561cbSjbeck } 273058561cbSjbeck #else /* _FFR_WORKERS_POOL */ 274058561cbSjbeck mi_clr_macros(ctx, 0); 275058561cbSjbeck fix_stm(ctx); 276058561cbSjbeck #endif /* _FFR_WORKERS_POOL */ 2777c478bd9Sstevel@tonic-gate r = _SMFIS_NONE; 2787c478bd9Sstevel@tonic-gate do 2797c478bd9Sstevel@tonic-gate { 2807c478bd9Sstevel@tonic-gate /* call abort only if in a mail transaction */ 2817c478bd9Sstevel@tonic-gate call_abort = ST_IN_MAIL(curstate); 2827c478bd9Sstevel@tonic-gate timeout.tv_sec = ctx->ctx_timeout; 2837c478bd9Sstevel@tonic-gate timeout.tv_usec = 0; 2847c478bd9Sstevel@tonic-gate if (mi_stop() == MILTER_ABRT) 2857c478bd9Sstevel@tonic-gate { 2867c478bd9Sstevel@tonic-gate if (ctx->ctx_dbg > 3) 287058561cbSjbeck sm_dprintf("[%ld] milter_abort\n", 288058561cbSjbeck (long) ctx->ctx_id); 2897c478bd9Sstevel@tonic-gate ret = MI_FAILURE; 2907c478bd9Sstevel@tonic-gate break; 2917c478bd9Sstevel@tonic-gate } 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate /* 2947c478bd9Sstevel@tonic-gate ** Notice: buf is allocated by mi_rd_cmd() and it will 2957c478bd9Sstevel@tonic-gate ** usually be free()d after it has been used in f(). 2967c478bd9Sstevel@tonic-gate ** However, if the function returns _SMFIS_KEEP then buf 2977c478bd9Sstevel@tonic-gate ** contains macros and will not be free()d. 2987c478bd9Sstevel@tonic-gate ** Hence r must be set to _SMFIS_NONE if a new buf is 2997c478bd9Sstevel@tonic-gate ** allocated to avoid problem with housekeeping, esp. 3007c478bd9Sstevel@tonic-gate ** if the code "break"s out of the loop. 3017c478bd9Sstevel@tonic-gate */ 3027c478bd9Sstevel@tonic-gate 303058561cbSjbeck #if _FFR_WORKERS_POOL 304058561cbSjbeck /* Is the socket ready to be read ??? */ 305058561cbSjbeck if (!mi_rd_socket_ready(sd)) 306058561cbSjbeck { 307058561cbSjbeck ret = MI_CONTINUE; 308058561cbSjbeck break; 309058561cbSjbeck } 310058561cbSjbeck #endif /* _FFR_WORKERS_POOL */ 311058561cbSjbeck 3127c478bd9Sstevel@tonic-gate r = _SMFIS_NONE; 3137c478bd9Sstevel@tonic-gate if ((buf = mi_rd_cmd(sd, &timeout, &cmd, &len, 3147c478bd9Sstevel@tonic-gate ctx->ctx_smfi->xxfi_name)) == NULL && 3157c478bd9Sstevel@tonic-gate cmd < SMFIC_VALIDCMD) 3167c478bd9Sstevel@tonic-gate { 3177c478bd9Sstevel@tonic-gate if (ctx->ctx_dbg > 5) 318058561cbSjbeck sm_dprintf("[%ld] mi_engine: mi_rd_cmd error (%x)\n", 319058561cbSjbeck (long) ctx->ctx_id, (int) cmd); 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate /* 3227c478bd9Sstevel@tonic-gate ** eof is currently treated as failure -> 3237c478bd9Sstevel@tonic-gate ** abort() instead of close(), otherwise use: 3247c478bd9Sstevel@tonic-gate ** if (cmd != SMFIC_EOF) 3257c478bd9Sstevel@tonic-gate */ 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate ret = MI_FAILURE; 3287c478bd9Sstevel@tonic-gate break; 3297c478bd9Sstevel@tonic-gate } 3307c478bd9Sstevel@tonic-gate if (ctx->ctx_dbg > 4) 331058561cbSjbeck sm_dprintf("[%ld] got cmd '%c' len %d\n", 332058561cbSjbeck (long) ctx->ctx_id, cmd, (int) len); 3337c478bd9Sstevel@tonic-gate for (i = 0; i < ncmds; i++) 3347c478bd9Sstevel@tonic-gate { 3357c478bd9Sstevel@tonic-gate if (cmd == cmds[i].cm_cmd) 3367c478bd9Sstevel@tonic-gate break; 3377c478bd9Sstevel@tonic-gate } 3387c478bd9Sstevel@tonic-gate if (i >= ncmds) 3397c478bd9Sstevel@tonic-gate { 3407c478bd9Sstevel@tonic-gate /* unknown command */ 3417c478bd9Sstevel@tonic-gate if (ctx->ctx_dbg > 1) 342058561cbSjbeck sm_dprintf("[%ld] cmd '%c' unknown\n", 343058561cbSjbeck (long) ctx->ctx_id, cmd); 3447c478bd9Sstevel@tonic-gate ret = MI_FAILURE; 3457c478bd9Sstevel@tonic-gate break; 3467c478bd9Sstevel@tonic-gate } 3477c478bd9Sstevel@tonic-gate if ((f = cmds[i].cm_fct) == NULL) 3487c478bd9Sstevel@tonic-gate { 3497c478bd9Sstevel@tonic-gate /* stop for now */ 3507c478bd9Sstevel@tonic-gate if (ctx->ctx_dbg > 1) 351058561cbSjbeck sm_dprintf("[%ld] cmd '%c' not impl\n", 352058561cbSjbeck (long) ctx->ctx_id, cmd); 3537c478bd9Sstevel@tonic-gate ret = MI_FAILURE; 3547c478bd9Sstevel@tonic-gate break; 3557c478bd9Sstevel@tonic-gate } 3567c478bd9Sstevel@tonic-gate 3577c478bd9Sstevel@tonic-gate /* is new state ok? */ 3587c478bd9Sstevel@tonic-gate newstate = cmds[i].cm_next; 3597c478bd9Sstevel@tonic-gate if (ctx->ctx_dbg > 5) 360058561cbSjbeck sm_dprintf("[%ld] cur %x new %x nextmask %x\n", 361058561cbSjbeck (long) ctx->ctx_id, 3627c478bd9Sstevel@tonic-gate curstate, newstate, next_states[curstate]); 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate if (newstate != ST_NONE && !trans_ok(curstate, newstate)) 3657c478bd9Sstevel@tonic-gate { 3667c478bd9Sstevel@tonic-gate if (ctx->ctx_dbg > 1) 367058561cbSjbeck sm_dprintf("[%ld] abort: cur %d (%x) new %d (%x) next %x\n", 368058561cbSjbeck (long) ctx->ctx_id, 3697c478bd9Sstevel@tonic-gate curstate, MI_MASK(curstate), 3707c478bd9Sstevel@tonic-gate newstate, MI_MASK(newstate), 3717c478bd9Sstevel@tonic-gate next_states[curstate]); 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate /* call abort only if in a mail transaction */ 3747c478bd9Sstevel@tonic-gate if (fi_abort != NULL && call_abort) 3757c478bd9Sstevel@tonic-gate (void) (*fi_abort)(ctx); 3767c478bd9Sstevel@tonic-gate 3777c478bd9Sstevel@tonic-gate /* 3787c478bd9Sstevel@tonic-gate ** try to reach the new state from HELO 3797c478bd9Sstevel@tonic-gate ** if it can't be reached, ignore the command. 3807c478bd9Sstevel@tonic-gate */ 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate curstate = ST_HELO; 3837c478bd9Sstevel@tonic-gate if (!trans_ok(curstate, newstate)) 3847c478bd9Sstevel@tonic-gate { 3857c478bd9Sstevel@tonic-gate if (buf != NULL) 3867c478bd9Sstevel@tonic-gate { 3877c478bd9Sstevel@tonic-gate free(buf); 3887c478bd9Sstevel@tonic-gate buf = NULL; 3897c478bd9Sstevel@tonic-gate } 3907c478bd9Sstevel@tonic-gate continue; 3917c478bd9Sstevel@tonic-gate } 3927c478bd9Sstevel@tonic-gate } 3937c478bd9Sstevel@tonic-gate arg.a_len = len; 3947c478bd9Sstevel@tonic-gate arg.a_buf = buf; 3957c478bd9Sstevel@tonic-gate if (newstate != ST_NONE) 3967c478bd9Sstevel@tonic-gate { 3977c478bd9Sstevel@tonic-gate curstate = newstate; 3987c478bd9Sstevel@tonic-gate ctx->ctx_state = curstate; 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate arg.a_idx = cmds[i].cm_macros; 4017c478bd9Sstevel@tonic-gate call_abort = ST_IN_MAIL(curstate); 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate /* call function to deal with command */ 404058561cbSjbeck MI_MONITOR_BEGIN(ctx, cmd); 4057c478bd9Sstevel@tonic-gate r = (*f)(&arg); 406058561cbSjbeck MI_MONITOR_END(ctx, cmd); 4077c478bd9Sstevel@tonic-gate if (r != _SMFIS_KEEP && buf != NULL) 4087c478bd9Sstevel@tonic-gate { 4097c478bd9Sstevel@tonic-gate free(buf); 4107c478bd9Sstevel@tonic-gate buf = NULL; 4117c478bd9Sstevel@tonic-gate } 4127c478bd9Sstevel@tonic-gate if (sendreply(r, sd, &timeout, ctx) != MI_SUCCESS) 4137c478bd9Sstevel@tonic-gate { 4147c478bd9Sstevel@tonic-gate ret = MI_FAILURE; 4157c478bd9Sstevel@tonic-gate break; 4167c478bd9Sstevel@tonic-gate } 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate if (r == SMFIS_ACCEPT) 4197c478bd9Sstevel@tonic-gate { 4207c478bd9Sstevel@tonic-gate /* accept mail, no further actions taken */ 4217c478bd9Sstevel@tonic-gate curstate = ST_HELO; 4227c478bd9Sstevel@tonic-gate } 4237c478bd9Sstevel@tonic-gate else if (r == SMFIS_REJECT || r == SMFIS_DISCARD || 4247c478bd9Sstevel@tonic-gate r == SMFIS_TEMPFAIL) 4257c478bd9Sstevel@tonic-gate { 4267c478bd9Sstevel@tonic-gate /* 4277c478bd9Sstevel@tonic-gate ** further actions depend on current state 4287c478bd9Sstevel@tonic-gate ** if the IGNO bit is set: "ignore" the error, 4297c478bd9Sstevel@tonic-gate ** i.e., stay in the current state 4307c478bd9Sstevel@tonic-gate */ 4317c478bd9Sstevel@tonic-gate if (!bitset(CT_IGNO, cmds[i].cm_todo)) 4327c478bd9Sstevel@tonic-gate curstate = ST_HELO; 4337c478bd9Sstevel@tonic-gate } 4347c478bd9Sstevel@tonic-gate else if (r == _SMFIS_ABORT) 4357c478bd9Sstevel@tonic-gate { 4367c478bd9Sstevel@tonic-gate if (ctx->ctx_dbg > 5) 437058561cbSjbeck sm_dprintf("[%ld] function returned abort\n", 438058561cbSjbeck (long) ctx->ctx_id); 4397c478bd9Sstevel@tonic-gate ret = MI_FAILURE; 4407c478bd9Sstevel@tonic-gate break; 4417c478bd9Sstevel@tonic-gate } 4427c478bd9Sstevel@tonic-gate } while (!bitset(CT_END, cmds[i].cm_todo)); 4437c478bd9Sstevel@tonic-gate 444058561cbSjbeck ctx->ctx_state = curstate; 445058561cbSjbeck 446058561cbSjbeck if (ret == MI_FAILURE) 4477c478bd9Sstevel@tonic-gate { 4487c478bd9Sstevel@tonic-gate /* call abort only if in a mail transaction */ 4497c478bd9Sstevel@tonic-gate if (fi_abort != NULL && call_abort) 4507c478bd9Sstevel@tonic-gate (void) (*fi_abort)(ctx); 4517c478bd9Sstevel@tonic-gate } 4527c478bd9Sstevel@tonic-gate 453058561cbSjbeck /* has close been called? */ 454058561cbSjbeck if (ctx->ctx_state != ST_QUIT 455058561cbSjbeck #if _FFR_WORKERS_POOL 456058561cbSjbeck && ret != MI_CONTINUE 457058561cbSjbeck #endif /* _FFR_WORKERS_POOL */ 458058561cbSjbeck ) 459058561cbSjbeck { 4607c478bd9Sstevel@tonic-gate if ((fi_close = ctx->ctx_smfi->xxfi_close) != NULL) 4617c478bd9Sstevel@tonic-gate (void) (*fi_close)(ctx); 462058561cbSjbeck } 4637c478bd9Sstevel@tonic-gate if (r != _SMFIS_KEEP && buf != NULL) 4647c478bd9Sstevel@tonic-gate free(buf); 465058561cbSjbeck #if !_FFR_WORKERS_POOL 4667c478bd9Sstevel@tonic-gate mi_clr_macros(ctx, 0); 467058561cbSjbeck #endif /* _FFR_WORKERS_POOL */ 4687c478bd9Sstevel@tonic-gate return ret; 4697c478bd9Sstevel@tonic-gate } 470058561cbSjbeck 471058561cbSjbeck static size_t milter_addsymlist __P((SMFICTX_PTR, char *, char **)); 472058561cbSjbeck 473058561cbSjbeck static size_t 474058561cbSjbeck milter_addsymlist(ctx, buf, newbuf) 475058561cbSjbeck SMFICTX_PTR ctx; 476058561cbSjbeck char *buf; 477058561cbSjbeck char **newbuf; 478058561cbSjbeck { 479058561cbSjbeck size_t len; 480058561cbSjbeck int i; 481058561cbSjbeck mi_int32 v; 482058561cbSjbeck char *buffer; 483058561cbSjbeck 484058561cbSjbeck SM_ASSERT(ctx != NULL); 485058561cbSjbeck SM_ASSERT(buf != NULL); 486058561cbSjbeck SM_ASSERT(newbuf != NULL); 487058561cbSjbeck len = 0; 488058561cbSjbeck for (i = 0; i < MAX_MACROS_ENTRIES; i++) 489058561cbSjbeck { 490058561cbSjbeck if (ctx->ctx_mac_list[i] != NULL) 491058561cbSjbeck { 492058561cbSjbeck len += strlen(ctx->ctx_mac_list[i]) + 1 + 493058561cbSjbeck MILTER_LEN_BYTES; 494058561cbSjbeck } 495058561cbSjbeck } 496058561cbSjbeck if (len > 0) 497058561cbSjbeck { 498058561cbSjbeck size_t offset; 499058561cbSjbeck 500058561cbSjbeck SM_ASSERT(len + MILTER_OPTLEN > len); 501058561cbSjbeck len += MILTER_OPTLEN; 502058561cbSjbeck buffer = malloc(len); 503058561cbSjbeck if (buffer != NULL) 504058561cbSjbeck { 505058561cbSjbeck (void) memcpy(buffer, buf, MILTER_OPTLEN); 506058561cbSjbeck offset = MILTER_OPTLEN; 507058561cbSjbeck for (i = 0; i < MAX_MACROS_ENTRIES; i++) 508058561cbSjbeck { 509058561cbSjbeck size_t l; 510058561cbSjbeck 511058561cbSjbeck if (ctx->ctx_mac_list[i] == NULL) 512058561cbSjbeck continue; 513058561cbSjbeck 514058561cbSjbeck SM_ASSERT(offset + MILTER_LEN_BYTES < len); 515058561cbSjbeck v = htonl(i); 516058561cbSjbeck (void) memcpy(buffer + offset, (void *) &v, 517058561cbSjbeck MILTER_LEN_BYTES); 518058561cbSjbeck offset += MILTER_LEN_BYTES; 519058561cbSjbeck l = strlen(ctx->ctx_mac_list[i]) + 1; 520058561cbSjbeck SM_ASSERT(offset + l <= len); 521058561cbSjbeck (void) memcpy(buffer + offset, 522058561cbSjbeck ctx->ctx_mac_list[i], l); 523058561cbSjbeck offset += l; 524058561cbSjbeck } 525058561cbSjbeck } 526058561cbSjbeck else 527058561cbSjbeck { 528058561cbSjbeck /* oops ... */ 529058561cbSjbeck } 530058561cbSjbeck } 531058561cbSjbeck else 532058561cbSjbeck { 533058561cbSjbeck len = MILTER_OPTLEN; 534058561cbSjbeck buffer = buf; 535058561cbSjbeck } 536058561cbSjbeck *newbuf = buffer; 537058561cbSjbeck return len; 538058561cbSjbeck } 539058561cbSjbeck 540058561cbSjbeck /* 541058561cbSjbeck ** GET_NR_BIT -- get "no reply" bit matching state 542058561cbSjbeck ** 543058561cbSjbeck ** Parameters: 544058561cbSjbeck ** state -- current protocol stage 545058561cbSjbeck ** 546058561cbSjbeck ** Returns: 547058561cbSjbeck ** 0: no matching bit 548058561cbSjbeck ** >0: the matching "no reply" bit 549058561cbSjbeck */ 550058561cbSjbeck 551058561cbSjbeck static unsigned long get_nr_bit __P((int)); 552058561cbSjbeck 553058561cbSjbeck static unsigned long 554058561cbSjbeck get_nr_bit(state) 555058561cbSjbeck int state; 556058561cbSjbeck { 557058561cbSjbeck unsigned long bit; 558058561cbSjbeck 559058561cbSjbeck switch (state) 560058561cbSjbeck { 561058561cbSjbeck case ST_CONN: 562058561cbSjbeck bit = SMFIP_NR_CONN; 563058561cbSjbeck break; 564058561cbSjbeck case ST_HELO: 565058561cbSjbeck bit = SMFIP_NR_HELO; 566058561cbSjbeck break; 567058561cbSjbeck case ST_MAIL: 568058561cbSjbeck bit = SMFIP_NR_MAIL; 569058561cbSjbeck break; 570058561cbSjbeck case ST_RCPT: 571058561cbSjbeck bit = SMFIP_NR_RCPT; 572058561cbSjbeck break; 573058561cbSjbeck case ST_DATA: 574058561cbSjbeck bit = SMFIP_NR_DATA; 575058561cbSjbeck break; 576058561cbSjbeck case ST_UNKN: 577058561cbSjbeck bit = SMFIP_NR_UNKN; 578058561cbSjbeck break; 579058561cbSjbeck case ST_HDRS: 580058561cbSjbeck bit = SMFIP_NR_HDR; 581058561cbSjbeck break; 582058561cbSjbeck case ST_EOHS: 583058561cbSjbeck bit = SMFIP_NR_EOH; 584058561cbSjbeck break; 585058561cbSjbeck case ST_BODY: 586058561cbSjbeck bit = SMFIP_NR_BODY; 587058561cbSjbeck break; 588058561cbSjbeck default: 589058561cbSjbeck bit = 0; 590058561cbSjbeck break; 591058561cbSjbeck } 592058561cbSjbeck return bit; 593058561cbSjbeck } 594058561cbSjbeck 5957c478bd9Sstevel@tonic-gate /* 5967c478bd9Sstevel@tonic-gate ** SENDREPLY -- send a reply to the MTA 5977c478bd9Sstevel@tonic-gate ** 5987c478bd9Sstevel@tonic-gate ** Parameters: 5997c478bd9Sstevel@tonic-gate ** r -- reply code 6007c478bd9Sstevel@tonic-gate ** sd -- socket descriptor 6017c478bd9Sstevel@tonic-gate ** timeout_ptr -- (ptr to) timeout to use for sending 6027c478bd9Sstevel@tonic-gate ** ctx -- context structure 6037c478bd9Sstevel@tonic-gate ** 6047c478bd9Sstevel@tonic-gate ** Returns: 6057c478bd9Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE 6067c478bd9Sstevel@tonic-gate */ 6077c478bd9Sstevel@tonic-gate 6087c478bd9Sstevel@tonic-gate static int 6097c478bd9Sstevel@tonic-gate sendreply(r, sd, timeout_ptr, ctx) 6107c478bd9Sstevel@tonic-gate sfsistat r; 6117c478bd9Sstevel@tonic-gate socket_t sd; 6127c478bd9Sstevel@tonic-gate struct timeval *timeout_ptr; 6137c478bd9Sstevel@tonic-gate SMFICTX_PTR ctx; 6147c478bd9Sstevel@tonic-gate { 615058561cbSjbeck int ret; 616058561cbSjbeck unsigned long bit; 617058561cbSjbeck 618058561cbSjbeck ret = MI_SUCCESS; 619058561cbSjbeck 620058561cbSjbeck bit = get_nr_bit(ctx->ctx_state); 621058561cbSjbeck if (bit != 0 && (ctx->ctx_pflags & bit) != 0 && r != SMFIS_NOREPLY) 622058561cbSjbeck { 623058561cbSjbeck if (r >= SMFIS_CONTINUE && r < _SMFIS_KEEP) 624058561cbSjbeck { 625058561cbSjbeck /* milter said it wouldn't reply, but it lied... */ 626058561cbSjbeck smi_log(SMI_LOG_ERR, 627058561cbSjbeck "%s: milter claimed not to reply in state %d but did anyway %d\n", 628058561cbSjbeck ctx->ctx_smfi->xxfi_name, 629058561cbSjbeck ctx->ctx_state, r); 630058561cbSjbeck 631058561cbSjbeck } 632058561cbSjbeck 633058561cbSjbeck /* 634058561cbSjbeck ** Force specified behavior, otherwise libmilter 635058561cbSjbeck ** and MTA will fail to communicate properly. 636058561cbSjbeck */ 637058561cbSjbeck 638058561cbSjbeck switch (r) 639058561cbSjbeck { 640058561cbSjbeck case SMFIS_CONTINUE: 641058561cbSjbeck case SMFIS_TEMPFAIL: 642058561cbSjbeck case SMFIS_REJECT: 643058561cbSjbeck case SMFIS_DISCARD: 644058561cbSjbeck case SMFIS_ACCEPT: 645058561cbSjbeck case SMFIS_SKIP: 646058561cbSjbeck case _SMFIS_OPTIONS: 647058561cbSjbeck r = SMFIS_NOREPLY; 648058561cbSjbeck break; 649058561cbSjbeck } 650058561cbSjbeck } 6517c478bd9Sstevel@tonic-gate 6527c478bd9Sstevel@tonic-gate switch (r) 6537c478bd9Sstevel@tonic-gate { 6547c478bd9Sstevel@tonic-gate case SMFIS_CONTINUE: 6557c478bd9Sstevel@tonic-gate ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_CONTINUE, NULL, 0); 6567c478bd9Sstevel@tonic-gate break; 6577c478bd9Sstevel@tonic-gate case SMFIS_TEMPFAIL: 6587c478bd9Sstevel@tonic-gate case SMFIS_REJECT: 6597c478bd9Sstevel@tonic-gate if (ctx->ctx_reply != NULL && 6607c478bd9Sstevel@tonic-gate ((r == SMFIS_TEMPFAIL && *ctx->ctx_reply == '4') || 6617c478bd9Sstevel@tonic-gate (r == SMFIS_REJECT && *ctx->ctx_reply == '5'))) 6627c478bd9Sstevel@tonic-gate { 6637c478bd9Sstevel@tonic-gate ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_REPLYCODE, 6647c478bd9Sstevel@tonic-gate ctx->ctx_reply, 6657c478bd9Sstevel@tonic-gate strlen(ctx->ctx_reply) + 1); 6667c478bd9Sstevel@tonic-gate free(ctx->ctx_reply); 6677c478bd9Sstevel@tonic-gate ctx->ctx_reply = NULL; 6687c478bd9Sstevel@tonic-gate } 6697c478bd9Sstevel@tonic-gate else 6707c478bd9Sstevel@tonic-gate { 6717c478bd9Sstevel@tonic-gate ret = mi_wr_cmd(sd, timeout_ptr, r == SMFIS_REJECT ? 6727c478bd9Sstevel@tonic-gate SMFIR_REJECT : SMFIR_TEMPFAIL, NULL, 0); 6737c478bd9Sstevel@tonic-gate } 6747c478bd9Sstevel@tonic-gate break; 6757c478bd9Sstevel@tonic-gate case SMFIS_DISCARD: 6767c478bd9Sstevel@tonic-gate ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_DISCARD, NULL, 0); 6777c478bd9Sstevel@tonic-gate break; 6787c478bd9Sstevel@tonic-gate case SMFIS_ACCEPT: 6797c478bd9Sstevel@tonic-gate ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_ACCEPT, NULL, 0); 6807c478bd9Sstevel@tonic-gate break; 681058561cbSjbeck case SMFIS_SKIP: 682058561cbSjbeck ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_SKIP, NULL, 0); 683058561cbSjbeck break; 6847c478bd9Sstevel@tonic-gate case _SMFIS_OPTIONS: 6857c478bd9Sstevel@tonic-gate { 6867c478bd9Sstevel@tonic-gate mi_int32 v; 687058561cbSjbeck size_t len; 688058561cbSjbeck char *buffer; 689058561cbSjbeck char buf[MILTER_OPTLEN]; 6907c478bd9Sstevel@tonic-gate 691058561cbSjbeck v = htonl(ctx->ctx_prot_vers2mta); 692058561cbSjbeck (void) memcpy(&(buf[0]), (void *) &v, 693058561cbSjbeck MILTER_LEN_BYTES); 694058561cbSjbeck v = htonl(ctx->ctx_aflags); 6957c478bd9Sstevel@tonic-gate (void) memcpy(&(buf[MILTER_LEN_BYTES]), (void *) &v, 6967c478bd9Sstevel@tonic-gate MILTER_LEN_BYTES); 697058561cbSjbeck v = htonl(ctx->ctx_pflags2mta); 698058561cbSjbeck (void) memcpy(&(buf[MILTER_LEN_BYTES * 2]), 699058561cbSjbeck (void *) &v, MILTER_LEN_BYTES); 700058561cbSjbeck len = milter_addsymlist(ctx, buf, &buffer); 701058561cbSjbeck if (buffer != NULL) 702058561cbSjbeck ret = mi_wr_cmd(sd, timeout_ptr, SMFIC_OPTNEG, 703058561cbSjbeck buffer, len); 704058561cbSjbeck else 705058561cbSjbeck ret = MI_FAILURE; 706058561cbSjbeck } 707058561cbSjbeck break; 708058561cbSjbeck case SMFIS_NOREPLY: 709058561cbSjbeck if (bit != 0 && 710058561cbSjbeck (ctx->ctx_pflags & bit) != 0 && 711058561cbSjbeck (ctx->ctx_mta_pflags & bit) == 0) 712058561cbSjbeck { 713058561cbSjbeck /* 714058561cbSjbeck ** milter doesn't want to send a reply, 715058561cbSjbeck ** but the MTA doesn't have that feature: fake it. 716058561cbSjbeck */ 717058561cbSjbeck 718058561cbSjbeck ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_CONTINUE, NULL, 719058561cbSjbeck 0); 7207c478bd9Sstevel@tonic-gate } 7217c478bd9Sstevel@tonic-gate break; 7227c478bd9Sstevel@tonic-gate default: /* don't send a reply */ 7237c478bd9Sstevel@tonic-gate break; 7247c478bd9Sstevel@tonic-gate } 7257c478bd9Sstevel@tonic-gate return ret; 7267c478bd9Sstevel@tonic-gate } 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate /* 7297c478bd9Sstevel@tonic-gate ** CLR_MACROS -- clear set of macros starting from a given index 7307c478bd9Sstevel@tonic-gate ** 7317c478bd9Sstevel@tonic-gate ** Parameters: 7327c478bd9Sstevel@tonic-gate ** ctx -- context structure 7337c478bd9Sstevel@tonic-gate ** m -- index from which to clear all macros 7347c478bd9Sstevel@tonic-gate ** 7357c478bd9Sstevel@tonic-gate ** Returns: 7367c478bd9Sstevel@tonic-gate ** None. 7377c478bd9Sstevel@tonic-gate */ 7384aac33d3Sjbeck 7397c478bd9Sstevel@tonic-gate void 7407c478bd9Sstevel@tonic-gate mi_clr_macros(ctx, m) 7417c478bd9Sstevel@tonic-gate SMFICTX_PTR ctx; 7427c478bd9Sstevel@tonic-gate int m; 7437c478bd9Sstevel@tonic-gate { 7447c478bd9Sstevel@tonic-gate int i; 7457c478bd9Sstevel@tonic-gate 7467c478bd9Sstevel@tonic-gate for (i = m; i < MAX_MACROS_ENTRIES; i++) 7477c478bd9Sstevel@tonic-gate { 7487c478bd9Sstevel@tonic-gate if (ctx->ctx_mac_ptr[i] != NULL) 7497c478bd9Sstevel@tonic-gate { 7507c478bd9Sstevel@tonic-gate free(ctx->ctx_mac_ptr[i]); 7517c478bd9Sstevel@tonic-gate ctx->ctx_mac_ptr[i] = NULL; 7527c478bd9Sstevel@tonic-gate } 7537c478bd9Sstevel@tonic-gate if (ctx->ctx_mac_buf[i] != NULL) 7547c478bd9Sstevel@tonic-gate { 7557c478bd9Sstevel@tonic-gate free(ctx->ctx_mac_buf[i]); 7567c478bd9Sstevel@tonic-gate ctx->ctx_mac_buf[i] = NULL; 7577c478bd9Sstevel@tonic-gate } 7587c478bd9Sstevel@tonic-gate } 7597c478bd9Sstevel@tonic-gate } 760058561cbSjbeck 7617c478bd9Sstevel@tonic-gate /* 762*e9af4bc0SJohn Beck ** MI_CLR_SYMLIST -- clear list of macros 763*e9af4bc0SJohn Beck ** 764*e9af4bc0SJohn Beck ** Parameters: 765*e9af4bc0SJohn Beck ** ctx -- context structure 766*e9af4bc0SJohn Beck ** 767*e9af4bc0SJohn Beck ** Returns: 768*e9af4bc0SJohn Beck ** None. 769*e9af4bc0SJohn Beck */ 770*e9af4bc0SJohn Beck 771*e9af4bc0SJohn Beck static void 772*e9af4bc0SJohn Beck mi_clr_symlist(ctx) 773*e9af4bc0SJohn Beck SMFICTX *ctx; 774*e9af4bc0SJohn Beck { 775*e9af4bc0SJohn Beck int i; 776*e9af4bc0SJohn Beck 777*e9af4bc0SJohn Beck SM_ASSERT(ctx != NULL); 778*e9af4bc0SJohn Beck for (i = SMFIM_FIRST; i <= SMFIM_LAST; i++) 779*e9af4bc0SJohn Beck { 780*e9af4bc0SJohn Beck if (ctx->ctx_mac_list[i] != NULL) 781*e9af4bc0SJohn Beck { 782*e9af4bc0SJohn Beck free(ctx->ctx_mac_list[i]); 783*e9af4bc0SJohn Beck ctx->ctx_mac_list[i] = NULL; 784*e9af4bc0SJohn Beck } 785*e9af4bc0SJohn Beck } 786*e9af4bc0SJohn Beck } 787*e9af4bc0SJohn Beck 788*e9af4bc0SJohn Beck /* 789*e9af4bc0SJohn Beck ** MI_CLR_CTX -- clear context 790*e9af4bc0SJohn Beck ** 791*e9af4bc0SJohn Beck ** Parameters: 792*e9af4bc0SJohn Beck ** ctx -- context structure 793*e9af4bc0SJohn Beck ** 794*e9af4bc0SJohn Beck ** Returns: 795*e9af4bc0SJohn Beck ** None. 796*e9af4bc0SJohn Beck */ 797*e9af4bc0SJohn Beck 798*e9af4bc0SJohn Beck void 799*e9af4bc0SJohn Beck mi_clr_ctx(ctx) 800*e9af4bc0SJohn Beck SMFICTX *ctx; 801*e9af4bc0SJohn Beck { 802*e9af4bc0SJohn Beck SM_ASSERT(ctx != NULL); 803*e9af4bc0SJohn Beck if (ValidSocket(ctx->ctx_sd)) 804*e9af4bc0SJohn Beck { 805*e9af4bc0SJohn Beck (void) closesocket(ctx->ctx_sd); 806*e9af4bc0SJohn Beck ctx->ctx_sd = INVALID_SOCKET; 807*e9af4bc0SJohn Beck } 808*e9af4bc0SJohn Beck if (ctx->ctx_reply != NULL) 809*e9af4bc0SJohn Beck { 810*e9af4bc0SJohn Beck free(ctx->ctx_reply); 811*e9af4bc0SJohn Beck ctx->ctx_reply = NULL; 812*e9af4bc0SJohn Beck } 813*e9af4bc0SJohn Beck if (ctx->ctx_privdata != NULL) 814*e9af4bc0SJohn Beck { 815*e9af4bc0SJohn Beck smi_log(SMI_LOG_WARN, 816*e9af4bc0SJohn Beck "%s: private data not NULL", 817*e9af4bc0SJohn Beck ctx->ctx_smfi->xxfi_name); 818*e9af4bc0SJohn Beck } 819*e9af4bc0SJohn Beck mi_clr_macros(ctx, 0); 820*e9af4bc0SJohn Beck mi_clr_symlist(ctx); 821*e9af4bc0SJohn Beck free(ctx); 822*e9af4bc0SJohn Beck } 823*e9af4bc0SJohn Beck 824*e9af4bc0SJohn Beck /* 8257c478bd9Sstevel@tonic-gate ** ST_OPTIONNEG -- negotiate options 8267c478bd9Sstevel@tonic-gate ** 8277c478bd9Sstevel@tonic-gate ** Parameters: 8287c478bd9Sstevel@tonic-gate ** g -- generic argument structure 8297c478bd9Sstevel@tonic-gate ** 8307c478bd9Sstevel@tonic-gate ** Returns: 8317c478bd9Sstevel@tonic-gate ** abort/send options/continue 8327c478bd9Sstevel@tonic-gate */ 8337c478bd9Sstevel@tonic-gate 8347c478bd9Sstevel@tonic-gate static int 8357c478bd9Sstevel@tonic-gate st_optionneg(g) 8367c478bd9Sstevel@tonic-gate genarg *g; 8377c478bd9Sstevel@tonic-gate { 838*e9af4bc0SJohn Beck mi_int32 i, v, fake_pflags, internal_pflags; 839058561cbSjbeck SMFICTX_PTR ctx; 840*e9af4bc0SJohn Beck #if _FFR_MILTER_CHECK 841*e9af4bc0SJohn Beck bool testmode = false; 842*e9af4bc0SJohn Beck #endif /* _FFR_MILTER_CHECK */ 843058561cbSjbeck int (*fi_negotiate) __P((SMFICTX *, 844058561cbSjbeck unsigned long, unsigned long, 845058561cbSjbeck unsigned long, unsigned long, 846058561cbSjbeck unsigned long *, unsigned long *, 847058561cbSjbeck unsigned long *, unsigned long *)); 8487c478bd9Sstevel@tonic-gate 8497c478bd9Sstevel@tonic-gate if (g == NULL || g->a_ctx->ctx_smfi == NULL) 8507c478bd9Sstevel@tonic-gate return SMFIS_CONTINUE; 851058561cbSjbeck ctx = g->a_ctx; 852058561cbSjbeck mi_clr_macros(ctx, g->a_idx + 1); 853058561cbSjbeck ctx->ctx_prot_vers = SMFI_PROT_VERSION; 8547c478bd9Sstevel@tonic-gate 8557c478bd9Sstevel@tonic-gate /* check for minimum length */ 8567c478bd9Sstevel@tonic-gate if (g->a_len < MILTER_OPTLEN) 8577c478bd9Sstevel@tonic-gate { 8587c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 859058561cbSjbeck "%s: st_optionneg[%ld]: len too short %d < %d", 860058561cbSjbeck ctx->ctx_smfi->xxfi_name, 861058561cbSjbeck (long) ctx->ctx_id, (int) g->a_len, 8627c478bd9Sstevel@tonic-gate MILTER_OPTLEN); 8637c478bd9Sstevel@tonic-gate return _SMFIS_ABORT; 8647c478bd9Sstevel@tonic-gate } 8657c478bd9Sstevel@tonic-gate 866058561cbSjbeck /* protocol version */ 867058561cbSjbeck (void) memcpy((void *) &i, (void *) &(g->a_buf[0]), MILTER_LEN_BYTES); 8687c478bd9Sstevel@tonic-gate v = ntohl(i); 869058561cbSjbeck 870058561cbSjbeck #define SMFI_PROT_VERSION_MIN 2 871058561cbSjbeck 872058561cbSjbeck /* check for minimum version */ 873058561cbSjbeck if (v < SMFI_PROT_VERSION_MIN) 8747c478bd9Sstevel@tonic-gate { 8757c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 876058561cbSjbeck "%s: st_optionneg[%ld]: protocol version too old %d < %d", 877058561cbSjbeck ctx->ctx_smfi->xxfi_name, 878058561cbSjbeck (long) ctx->ctx_id, v, SMFI_PROT_VERSION_MIN); 8797c478bd9Sstevel@tonic-gate return _SMFIS_ABORT; 8807c478bd9Sstevel@tonic-gate } 881058561cbSjbeck ctx->ctx_mta_prot_vers = v; 882058561cbSjbeck if (ctx->ctx_prot_vers < ctx->ctx_mta_prot_vers) 883058561cbSjbeck ctx->ctx_prot_vers2mta = ctx->ctx_prot_vers; 884058561cbSjbeck else 885058561cbSjbeck ctx->ctx_prot_vers2mta = ctx->ctx_mta_prot_vers; 8867c478bd9Sstevel@tonic-gate 8877c478bd9Sstevel@tonic-gate (void) memcpy((void *) &i, (void *) &(g->a_buf[MILTER_LEN_BYTES]), 8887c478bd9Sstevel@tonic-gate MILTER_LEN_BYTES); 8897c478bd9Sstevel@tonic-gate v = ntohl(i); 8907c478bd9Sstevel@tonic-gate 8917c478bd9Sstevel@tonic-gate /* no flags? set to default value for V1 actions */ 8927c478bd9Sstevel@tonic-gate if (v == 0) 8937c478bd9Sstevel@tonic-gate v = SMFI_V1_ACTS; 894058561cbSjbeck ctx->ctx_mta_aflags = v; /* MTA action flags */ 8957c478bd9Sstevel@tonic-gate 896*e9af4bc0SJohn Beck internal_pflags = 0; 8977c478bd9Sstevel@tonic-gate (void) memcpy((void *) &i, (void *) &(g->a_buf[MILTER_LEN_BYTES * 2]), 8987c478bd9Sstevel@tonic-gate MILTER_LEN_BYTES); 8997c478bd9Sstevel@tonic-gate v = ntohl(i); 9007c478bd9Sstevel@tonic-gate 9017c478bd9Sstevel@tonic-gate /* no flags? set to default value for V1 protocol */ 9027c478bd9Sstevel@tonic-gate if (v == 0) 9037c478bd9Sstevel@tonic-gate v = SMFI_V1_PROT; 904*e9af4bc0SJohn Beck #if _FFR_MDS_NEGOTIATE 905*e9af4bc0SJohn Beck else if (ctx->ctx_smfi->xxfi_version >= SMFI_VERSION_MDS) 906*e9af4bc0SJohn Beck { 907*e9af4bc0SJohn Beck /* 908*e9af4bc0SJohn Beck ** Allow changing the size only if milter is compiled 909*e9af4bc0SJohn Beck ** against a version that supports this. 910*e9af4bc0SJohn Beck ** If a milter is dynamically linked against a newer 911*e9af4bc0SJohn Beck ** libmilter version, we don't want to "surprise" 912*e9af4bc0SJohn Beck ** it with a larger buffer as it may rely on it 913*e9af4bc0SJohn Beck ** even though it is not documented as a limit. 914*e9af4bc0SJohn Beck */ 915*e9af4bc0SJohn Beck 916*e9af4bc0SJohn Beck if (bitset(SMFIP_MDS_1M, v)) 917*e9af4bc0SJohn Beck { 918*e9af4bc0SJohn Beck internal_pflags |= SMFIP_MDS_1M; 919*e9af4bc0SJohn Beck (void) smfi_setmaxdatasize(MILTER_MDS_1M); 920*e9af4bc0SJohn Beck } 921*e9af4bc0SJohn Beck else if (bitset(SMFIP_MDS_256K, v)) 922*e9af4bc0SJohn Beck { 923*e9af4bc0SJohn Beck internal_pflags |= SMFIP_MDS_256K; 924*e9af4bc0SJohn Beck (void) smfi_setmaxdatasize(MILTER_MDS_256K); 925*e9af4bc0SJohn Beck } 926*e9af4bc0SJohn Beck } 927*e9af4bc0SJohn Beck # if 0 928*e9af4bc0SJohn Beck /* don't log this for now... */ 929*e9af4bc0SJohn Beck else if (ctx->ctx_smfi->xxfi_version < SMFI_VERSION_MDS && 930*e9af4bc0SJohn Beck bitset(SMFIP_MDS_1M|SMFIP_MDS_256K, v)) 931*e9af4bc0SJohn Beck { 932*e9af4bc0SJohn Beck smi_log(SMI_LOG_WARN, 933*e9af4bc0SJohn Beck "%s: st_optionneg[%ld]: milter version=%X, trying flags=%X", 934*e9af4bc0SJohn Beck ctx->ctx_smfi->xxfi_name, 935*e9af4bc0SJohn Beck (long) ctx->ctx_id, ctx->ctx_smfi->xxfi_version, v); 936*e9af4bc0SJohn Beck } 937*e9af4bc0SJohn Beck # endif /* 0 */ 938*e9af4bc0SJohn Beck #endif /* _FFR_MDS_NEGOTIATE */ 939*e9af4bc0SJohn Beck 940*e9af4bc0SJohn Beck /* 941*e9af4bc0SJohn Beck ** MTA protocol flags. 942*e9af4bc0SJohn Beck ** We pass the internal flags to the milter as "read only", 943*e9af4bc0SJohn Beck ** i.e., a milter can read them so it knows which size 944*e9af4bc0SJohn Beck ** will be used, but any changes by a milter will be ignored 945*e9af4bc0SJohn Beck ** (see below, search for SMFI_INTERNAL). 946*e9af4bc0SJohn Beck */ 947*e9af4bc0SJohn Beck 948*e9af4bc0SJohn Beck ctx->ctx_mta_pflags = (v & ~SMFI_INTERNAL) | internal_pflags; 949058561cbSjbeck 950058561cbSjbeck /* 951058561cbSjbeck ** Copy flags from milter struct into libmilter context; 952058561cbSjbeck ** this variable will be used later on to check whether 953058561cbSjbeck ** the MTA "actions" can fulfill the milter requirements, 954058561cbSjbeck ** but it may be overwritten by the negotiate callback. 955058561cbSjbeck */ 956058561cbSjbeck 957058561cbSjbeck ctx->ctx_aflags = ctx->ctx_smfi->xxfi_flags; 958058561cbSjbeck fake_pflags = SMFIP_NR_CONN 959058561cbSjbeck |SMFIP_NR_HELO 960058561cbSjbeck |SMFIP_NR_MAIL 961058561cbSjbeck |SMFIP_NR_RCPT 962058561cbSjbeck |SMFIP_NR_DATA 963058561cbSjbeck |SMFIP_NR_UNKN 964058561cbSjbeck |SMFIP_NR_HDR 965058561cbSjbeck |SMFIP_NR_EOH 966058561cbSjbeck |SMFIP_NR_BODY 967058561cbSjbeck ; 968058561cbSjbeck 969058561cbSjbeck if (g->a_ctx->ctx_smfi != NULL && 97024472db6Sjbeck g->a_ctx->ctx_smfi->xxfi_version > 4 && 971058561cbSjbeck (fi_negotiate = g->a_ctx->ctx_smfi->xxfi_negotiate) != NULL) 972058561cbSjbeck { 973058561cbSjbeck int r; 974058561cbSjbeck unsigned long m_aflags, m_pflags, m_f2, m_f3; 975058561cbSjbeck 976058561cbSjbeck /* 977058561cbSjbeck ** let milter decide whether the features offered by the 978058561cbSjbeck ** MTA are "good enough". 979058561cbSjbeck ** Notes: 980058561cbSjbeck ** - libmilter can "fake" some features (e.g., SMFIP_NR_HDR) 981058561cbSjbeck ** - m_f2, m_f3 are for future extensions 982058561cbSjbeck */ 983058561cbSjbeck 984058561cbSjbeck m_f2 = m_f3 = 0; 985058561cbSjbeck m_aflags = ctx->ctx_mta_aflags; 986058561cbSjbeck m_pflags = ctx->ctx_pflags; 987058561cbSjbeck if ((SMFIP_SKIP & ctx->ctx_mta_pflags) != 0) 988058561cbSjbeck m_pflags |= SMFIP_SKIP; 989058561cbSjbeck r = fi_negotiate(g->a_ctx, 990058561cbSjbeck ctx->ctx_mta_aflags, 991058561cbSjbeck ctx->ctx_mta_pflags|fake_pflags, 992058561cbSjbeck 0, 0, 993058561cbSjbeck &m_aflags, &m_pflags, &m_f2, &m_f3); 994058561cbSjbeck 995*e9af4bc0SJohn Beck #if _FFR_MILTER_CHECK 996*e9af4bc0SJohn Beck testmode = bitset(SMFIP_TEST, m_pflags); 997*e9af4bc0SJohn Beck if (testmode) 998*e9af4bc0SJohn Beck m_pflags &= ~SMFIP_TEST; 999*e9af4bc0SJohn Beck #endif /* _FFR_MILTER_CHECK */ 1000*e9af4bc0SJohn Beck 1001058561cbSjbeck /* 1002058561cbSjbeck ** Types of protocol flags (pflags): 1003058561cbSjbeck ** 1. do NOT send protocol step X 1004058561cbSjbeck ** 2. MTA can do/understand something extra (SKIP, 1005058561cbSjbeck ** send unknown RCPTs) 1006058561cbSjbeck ** 3. MTA can deal with "no reply" for various protocol steps 1007058561cbSjbeck ** Note: this mean that it isn't possible to simply set all 1008058561cbSjbeck ** flags to get "everything": 1009058561cbSjbeck ** setting a flag of type 1 turns off a step 1010058561cbSjbeck ** (it should be the other way around: 1011058561cbSjbeck ** a flag means a protocol step can be sent) 1012058561cbSjbeck ** setting a flag of type 3 requires that milter 1013058561cbSjbeck ** never sends a reply for the corresponding step. 1014058561cbSjbeck ** Summary: the "negation" of protocol flags is causing 1015058561cbSjbeck ** problems, but at least for type 3 there is no simple 1016058561cbSjbeck ** solution. 1017058561cbSjbeck ** 1018058561cbSjbeck ** What should "all options" mean? 1019058561cbSjbeck ** send all protocol steps _except_ those for which there is 1020058561cbSjbeck ** no callback (currently registered in ctx_pflags) 1021058561cbSjbeck ** expect SKIP as return code? Yes 1022058561cbSjbeck ** send unknown RCPTs? No, 1023058561cbSjbeck ** must be explicitly requested? 1024058561cbSjbeck ** "no reply" for some protocol steps? No, 1025058561cbSjbeck ** must be explicitly requested. 1026058561cbSjbeck */ 1027058561cbSjbeck 1028058561cbSjbeck if (SMFIS_ALL_OPTS == r) 1029058561cbSjbeck { 1030058561cbSjbeck ctx->ctx_aflags = ctx->ctx_mta_aflags; 1031058561cbSjbeck ctx->ctx_pflags2mta = ctx->ctx_pflags; 1032058561cbSjbeck if ((SMFIP_SKIP & ctx->ctx_mta_pflags) != 0) 1033058561cbSjbeck ctx->ctx_pflags2mta |= SMFIP_SKIP; 1034058561cbSjbeck } 1035058561cbSjbeck else if (r != SMFIS_CONTINUE) 10367c478bd9Sstevel@tonic-gate { 10377c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 1038058561cbSjbeck "%s: st_optionneg[%ld]: xxfi_negotiate returned %d (protocol options=0x%lx, actions=0x%lx)", 1039058561cbSjbeck ctx->ctx_smfi->xxfi_name, 1040058561cbSjbeck (long) ctx->ctx_id, r, ctx->ctx_mta_pflags, 1041058561cbSjbeck ctx->ctx_mta_aflags); 1042058561cbSjbeck return _SMFIS_ABORT; 1043058561cbSjbeck } 1044058561cbSjbeck else 1045058561cbSjbeck { 1046058561cbSjbeck ctx->ctx_aflags = m_aflags; 1047058561cbSjbeck ctx->ctx_pflags = m_pflags; 1048058561cbSjbeck ctx->ctx_pflags2mta = m_pflags; 1049058561cbSjbeck } 1050058561cbSjbeck 1051058561cbSjbeck /* check whether some flags need to be "faked" */ 1052058561cbSjbeck i = ctx->ctx_pflags2mta; 1053058561cbSjbeck if ((ctx->ctx_mta_pflags & i) != i) 1054058561cbSjbeck { 1055058561cbSjbeck unsigned int idx; 1056058561cbSjbeck unsigned long b; 1057058561cbSjbeck 1058058561cbSjbeck /* 1059058561cbSjbeck ** If some behavior can be faked (set in fake_pflags), 1060058561cbSjbeck ** but the MTA doesn't support it, then unset 1061058561cbSjbeck ** that flag in the value that is sent to the MTA. 1062058561cbSjbeck */ 1063058561cbSjbeck 1064058561cbSjbeck for (idx = 0; idx < 32; idx++) 1065058561cbSjbeck { 1066058561cbSjbeck b = 1 << idx; 1067058561cbSjbeck if ((ctx->ctx_mta_pflags & b) != b && 1068058561cbSjbeck (fake_pflags & b) == b) 1069058561cbSjbeck ctx->ctx_pflags2mta &= ~b; 1070058561cbSjbeck } 1071058561cbSjbeck } 1072058561cbSjbeck } 1073058561cbSjbeck else 1074058561cbSjbeck { 1075058561cbSjbeck /* 1076058561cbSjbeck ** Set the protocol flags based on the values determined 1077058561cbSjbeck ** in mi_listener() which checked the defined callbacks. 1078058561cbSjbeck */ 1079058561cbSjbeck 1080058561cbSjbeck ctx->ctx_pflags2mta = ctx->ctx_pflags; 1081058561cbSjbeck } 1082058561cbSjbeck 1083058561cbSjbeck /* check whether actions and protocol requirements can be satisfied */ 1084058561cbSjbeck i = ctx->ctx_aflags; 1085058561cbSjbeck if ((i & ctx->ctx_mta_aflags) != i) 1086058561cbSjbeck { 1087058561cbSjbeck smi_log(SMI_LOG_ERR, 1088058561cbSjbeck "%s: st_optionneg[%ld]: 0x%lx does not fulfill action requirements 0x%x", 1089058561cbSjbeck ctx->ctx_smfi->xxfi_name, 1090058561cbSjbeck (long) ctx->ctx_id, ctx->ctx_mta_aflags, i); 10917c478bd9Sstevel@tonic-gate return _SMFIS_ABORT; 10927c478bd9Sstevel@tonic-gate } 10937c478bd9Sstevel@tonic-gate 1094058561cbSjbeck i = ctx->ctx_pflags2mta; 1095058561cbSjbeck if ((ctx->ctx_mta_pflags & i) != i) 1096058561cbSjbeck { 1097058561cbSjbeck /* 1098058561cbSjbeck ** Older MTAs do not support some protocol steps. 1099058561cbSjbeck ** As this protocol is a bit "wierd" (it asks for steps 1100058561cbSjbeck ** NOT to be taken/sent) we have to check whether we 1101058561cbSjbeck ** should turn off those "negative" requests. 1102058561cbSjbeck ** Currently these are only SMFIP_NODATA and SMFIP_NOUNKNOWN. 1103058561cbSjbeck */ 1104058561cbSjbeck 1105058561cbSjbeck if (bitset(SMFIP_NODATA, ctx->ctx_pflags2mta) && 1106058561cbSjbeck !bitset(SMFIP_NODATA, ctx->ctx_mta_pflags)) 1107058561cbSjbeck ctx->ctx_pflags2mta &= ~SMFIP_NODATA; 1108058561cbSjbeck if (bitset(SMFIP_NOUNKNOWN, ctx->ctx_pflags2mta) && 1109058561cbSjbeck !bitset(SMFIP_NOUNKNOWN, ctx->ctx_mta_pflags)) 1110058561cbSjbeck ctx->ctx_pflags2mta &= ~SMFIP_NOUNKNOWN; 1111058561cbSjbeck i = ctx->ctx_pflags2mta; 1112058561cbSjbeck } 1113058561cbSjbeck 1114058561cbSjbeck if ((ctx->ctx_mta_pflags & i) != i) 1115058561cbSjbeck { 1116058561cbSjbeck smi_log(SMI_LOG_ERR, 1117058561cbSjbeck "%s: st_optionneg[%ld]: 0x%lx does not fulfill protocol requirements 0x%x", 1118058561cbSjbeck ctx->ctx_smfi->xxfi_name, 1119058561cbSjbeck (long) ctx->ctx_id, ctx->ctx_mta_pflags, i); 1120058561cbSjbeck return _SMFIS_ABORT; 1121058561cbSjbeck } 1122d4660949Sjbeck fix_stm(ctx); 1123058561cbSjbeck 1124058561cbSjbeck if (ctx->ctx_dbg > 3) 1125058561cbSjbeck sm_dprintf("[%ld] milter_negotiate:" 1126058561cbSjbeck " mta_actions=0x%lx, mta_flags=0x%lx" 1127058561cbSjbeck " actions=0x%lx, flags=0x%lx\n" 1128058561cbSjbeck , (long) ctx->ctx_id 1129058561cbSjbeck , ctx->ctx_mta_aflags, ctx->ctx_mta_pflags 1130058561cbSjbeck , ctx->ctx_aflags, ctx->ctx_pflags); 1131058561cbSjbeck 1132*e9af4bc0SJohn Beck #if _FFR_MILTER_CHECK 1133*e9af4bc0SJohn Beck if (ctx->ctx_dbg > 3) 1134*e9af4bc0SJohn Beck sm_dprintf("[%ld] milter_negotiate:" 1135*e9af4bc0SJohn Beck " testmode=%d, pflags2mta=%X, internal_pflags=%X\n" 1136*e9af4bc0SJohn Beck , (long) ctx->ctx_id, testmode 1137*e9af4bc0SJohn Beck , ctx->ctx_pflags2mta, internal_pflags); 1138*e9af4bc0SJohn Beck 1139*e9af4bc0SJohn Beck /* in test mode: take flags without further modifications */ 1140*e9af4bc0SJohn Beck if (!testmode) 1141*e9af4bc0SJohn Beck /* Warning: check statement below! */ 1142*e9af4bc0SJohn Beck #endif /* _FFR_MILTER_CHECK */ 1143*e9af4bc0SJohn Beck 1144*e9af4bc0SJohn Beck /* 1145*e9af4bc0SJohn Beck ** Remove the internal flags that might have been set by a milter 1146*e9af4bc0SJohn Beck ** and set only those determined above. 1147*e9af4bc0SJohn Beck */ 1148*e9af4bc0SJohn Beck 1149*e9af4bc0SJohn Beck ctx->ctx_pflags2mta = (ctx->ctx_pflags2mta & ~SMFI_INTERNAL) 1150*e9af4bc0SJohn Beck | internal_pflags; 11517c478bd9Sstevel@tonic-gate return _SMFIS_OPTIONS; 11527c478bd9Sstevel@tonic-gate } 1153058561cbSjbeck 11547c478bd9Sstevel@tonic-gate /* 11557c478bd9Sstevel@tonic-gate ** ST_CONNECTINFO -- receive connection information 11567c478bd9Sstevel@tonic-gate ** 11577c478bd9Sstevel@tonic-gate ** Parameters: 11587c478bd9Sstevel@tonic-gate ** g -- generic argument structure 11597c478bd9Sstevel@tonic-gate ** 11607c478bd9Sstevel@tonic-gate ** Returns: 11617c478bd9Sstevel@tonic-gate ** continue or filter-specified value 11627c478bd9Sstevel@tonic-gate */ 11637c478bd9Sstevel@tonic-gate 11647c478bd9Sstevel@tonic-gate static int 11657c478bd9Sstevel@tonic-gate st_connectinfo(g) 11667c478bd9Sstevel@tonic-gate genarg *g; 11677c478bd9Sstevel@tonic-gate { 11687c478bd9Sstevel@tonic-gate size_t l; 11697c478bd9Sstevel@tonic-gate size_t i; 11707c478bd9Sstevel@tonic-gate char *s, family; 11717c478bd9Sstevel@tonic-gate unsigned short port = 0; 11727c478bd9Sstevel@tonic-gate _SOCK_ADDR sockaddr; 11737c478bd9Sstevel@tonic-gate sfsistat (*fi_connect) __P((SMFICTX *, char *, _SOCK_ADDR *)); 11747c478bd9Sstevel@tonic-gate 11757c478bd9Sstevel@tonic-gate if (g == NULL) 11767c478bd9Sstevel@tonic-gate return _SMFIS_ABORT; 11777c478bd9Sstevel@tonic-gate mi_clr_macros(g->a_ctx, g->a_idx + 1); 11787c478bd9Sstevel@tonic-gate if (g->a_ctx->ctx_smfi == NULL || 11797c478bd9Sstevel@tonic-gate (fi_connect = g->a_ctx->ctx_smfi->xxfi_connect) == NULL) 11807c478bd9Sstevel@tonic-gate return SMFIS_CONTINUE; 11817c478bd9Sstevel@tonic-gate 11827c478bd9Sstevel@tonic-gate s = g->a_buf; 11837c478bd9Sstevel@tonic-gate i = 0; 11847c478bd9Sstevel@tonic-gate l = g->a_len; 11857c478bd9Sstevel@tonic-gate while (s[i] != '\0' && i <= l) 11867c478bd9Sstevel@tonic-gate ++i; 11877c478bd9Sstevel@tonic-gate if (i + 1 >= l) 11887c478bd9Sstevel@tonic-gate return _SMFIS_ABORT; 11897c478bd9Sstevel@tonic-gate 11907c478bd9Sstevel@tonic-gate /* Move past trailing \0 in host string */ 11917c478bd9Sstevel@tonic-gate i++; 11927c478bd9Sstevel@tonic-gate family = s[i++]; 11937c478bd9Sstevel@tonic-gate (void) memset(&sockaddr, '\0', sizeof sockaddr); 11947c478bd9Sstevel@tonic-gate if (family != SMFIA_UNKNOWN) 11957c478bd9Sstevel@tonic-gate { 11967c478bd9Sstevel@tonic-gate if (i + sizeof port >= l) 11977c478bd9Sstevel@tonic-gate { 11987c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 1199058561cbSjbeck "%s: connect[%ld]: wrong len %d >= %d", 12007c478bd9Sstevel@tonic-gate g->a_ctx->ctx_smfi->xxfi_name, 1201058561cbSjbeck (long) g->a_ctx->ctx_id, (int) i, (int) l); 12027c478bd9Sstevel@tonic-gate return _SMFIS_ABORT; 12037c478bd9Sstevel@tonic-gate } 12047c478bd9Sstevel@tonic-gate (void) memcpy((void *) &port, (void *) (s + i), 12057c478bd9Sstevel@tonic-gate sizeof port); 12067c478bd9Sstevel@tonic-gate i += sizeof port; 12077c478bd9Sstevel@tonic-gate 12087c478bd9Sstevel@tonic-gate /* make sure string is terminated */ 12097c478bd9Sstevel@tonic-gate if (s[l - 1] != '\0') 12107c478bd9Sstevel@tonic-gate return _SMFIS_ABORT; 12117c478bd9Sstevel@tonic-gate # if NETINET 12127c478bd9Sstevel@tonic-gate if (family == SMFIA_INET) 12137c478bd9Sstevel@tonic-gate { 12147c478bd9Sstevel@tonic-gate if (inet_aton(s + i, (struct in_addr *) &sockaddr.sin.sin_addr) 12157c478bd9Sstevel@tonic-gate != 1) 12167c478bd9Sstevel@tonic-gate { 12177c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 1218058561cbSjbeck "%s: connect[%ld]: inet_aton failed", 12197c478bd9Sstevel@tonic-gate g->a_ctx->ctx_smfi->xxfi_name, 1220058561cbSjbeck (long) g->a_ctx->ctx_id); 12217c478bd9Sstevel@tonic-gate return _SMFIS_ABORT; 12227c478bd9Sstevel@tonic-gate } 12237c478bd9Sstevel@tonic-gate sockaddr.sa.sa_family = AF_INET; 12247c478bd9Sstevel@tonic-gate if (port > 0) 12257c478bd9Sstevel@tonic-gate sockaddr.sin.sin_port = port; 12267c478bd9Sstevel@tonic-gate } 12277c478bd9Sstevel@tonic-gate else 12287c478bd9Sstevel@tonic-gate # endif /* NETINET */ 12297c478bd9Sstevel@tonic-gate # if NETINET6 12307c478bd9Sstevel@tonic-gate if (family == SMFIA_INET6) 12317c478bd9Sstevel@tonic-gate { 12327c478bd9Sstevel@tonic-gate if (mi_inet_pton(AF_INET6, s + i, 12337c478bd9Sstevel@tonic-gate &sockaddr.sin6.sin6_addr) != 1) 12347c478bd9Sstevel@tonic-gate { 12357c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 1236058561cbSjbeck "%s: connect[%ld]: mi_inet_pton failed", 12377c478bd9Sstevel@tonic-gate g->a_ctx->ctx_smfi->xxfi_name, 1238058561cbSjbeck (long) g->a_ctx->ctx_id); 12397c478bd9Sstevel@tonic-gate return _SMFIS_ABORT; 12407c478bd9Sstevel@tonic-gate } 12417c478bd9Sstevel@tonic-gate sockaddr.sa.sa_family = AF_INET6; 12427c478bd9Sstevel@tonic-gate if (port > 0) 12437c478bd9Sstevel@tonic-gate sockaddr.sin6.sin6_port = port; 12447c478bd9Sstevel@tonic-gate } 12457c478bd9Sstevel@tonic-gate else 12467c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 12477c478bd9Sstevel@tonic-gate # if NETUNIX 12487c478bd9Sstevel@tonic-gate if (family == SMFIA_UNIX) 12497c478bd9Sstevel@tonic-gate { 12507c478bd9Sstevel@tonic-gate if (sm_strlcpy(sockaddr.sunix.sun_path, s + i, 12517c478bd9Sstevel@tonic-gate sizeof sockaddr.sunix.sun_path) >= 12527c478bd9Sstevel@tonic-gate sizeof sockaddr.sunix.sun_path) 12537c478bd9Sstevel@tonic-gate { 12547c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 1255058561cbSjbeck "%s: connect[%ld]: path too long", 12567c478bd9Sstevel@tonic-gate g->a_ctx->ctx_smfi->xxfi_name, 1257058561cbSjbeck (long) g->a_ctx->ctx_id); 12587c478bd9Sstevel@tonic-gate return _SMFIS_ABORT; 12597c478bd9Sstevel@tonic-gate } 12607c478bd9Sstevel@tonic-gate sockaddr.sunix.sun_family = AF_UNIX; 12617c478bd9Sstevel@tonic-gate } 12627c478bd9Sstevel@tonic-gate else 12637c478bd9Sstevel@tonic-gate # endif /* NETUNIX */ 12647c478bd9Sstevel@tonic-gate { 12657c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 1266058561cbSjbeck "%s: connect[%ld]: unknown family %d", 12677c478bd9Sstevel@tonic-gate g->a_ctx->ctx_smfi->xxfi_name, 1268058561cbSjbeck (long) g->a_ctx->ctx_id, family); 12697c478bd9Sstevel@tonic-gate return _SMFIS_ABORT; 12707c478bd9Sstevel@tonic-gate } 12717c478bd9Sstevel@tonic-gate } 12727c478bd9Sstevel@tonic-gate return (*fi_connect)(g->a_ctx, g->a_buf, 12737c478bd9Sstevel@tonic-gate family != SMFIA_UNKNOWN ? &sockaddr : NULL); 12747c478bd9Sstevel@tonic-gate } 12757c478bd9Sstevel@tonic-gate 12767c478bd9Sstevel@tonic-gate /* 12777c478bd9Sstevel@tonic-gate ** ST_EOH -- end of headers 12787c478bd9Sstevel@tonic-gate ** 12797c478bd9Sstevel@tonic-gate ** Parameters: 12807c478bd9Sstevel@tonic-gate ** g -- generic argument structure 12817c478bd9Sstevel@tonic-gate ** 12827c478bd9Sstevel@tonic-gate ** Returns: 12837c478bd9Sstevel@tonic-gate ** continue or filter-specified value 12847c478bd9Sstevel@tonic-gate */ 12857c478bd9Sstevel@tonic-gate 12867c478bd9Sstevel@tonic-gate static int 12877c478bd9Sstevel@tonic-gate st_eoh(g) 12887c478bd9Sstevel@tonic-gate genarg *g; 12897c478bd9Sstevel@tonic-gate { 12907c478bd9Sstevel@tonic-gate sfsistat (*fi_eoh) __P((SMFICTX *)); 12917c478bd9Sstevel@tonic-gate 12927c478bd9Sstevel@tonic-gate if (g == NULL) 12937c478bd9Sstevel@tonic-gate return _SMFIS_ABORT; 12947c478bd9Sstevel@tonic-gate if (g->a_ctx->ctx_smfi != NULL && 12957c478bd9Sstevel@tonic-gate (fi_eoh = g->a_ctx->ctx_smfi->xxfi_eoh) != NULL) 12967c478bd9Sstevel@tonic-gate return (*fi_eoh)(g->a_ctx); 12977c478bd9Sstevel@tonic-gate return SMFIS_CONTINUE; 12987c478bd9Sstevel@tonic-gate } 12997c478bd9Sstevel@tonic-gate 13007c478bd9Sstevel@tonic-gate /* 13017c478bd9Sstevel@tonic-gate ** ST_DATA -- DATA command 13027c478bd9Sstevel@tonic-gate ** 13037c478bd9Sstevel@tonic-gate ** Parameters: 13047c478bd9Sstevel@tonic-gate ** g -- generic argument structure 13057c478bd9Sstevel@tonic-gate ** 13067c478bd9Sstevel@tonic-gate ** Returns: 13077c478bd9Sstevel@tonic-gate ** continue or filter-specified value 13087c478bd9Sstevel@tonic-gate */ 13097c478bd9Sstevel@tonic-gate 13107c478bd9Sstevel@tonic-gate static int 13117c478bd9Sstevel@tonic-gate st_data(g) 13127c478bd9Sstevel@tonic-gate genarg *g; 13137c478bd9Sstevel@tonic-gate { 13147c478bd9Sstevel@tonic-gate sfsistat (*fi_data) __P((SMFICTX *)); 13157c478bd9Sstevel@tonic-gate 13167c478bd9Sstevel@tonic-gate if (g == NULL) 13177c478bd9Sstevel@tonic-gate return _SMFIS_ABORT; 13187c478bd9Sstevel@tonic-gate if (g->a_ctx->ctx_smfi != NULL && 131924472db6Sjbeck g->a_ctx->ctx_smfi->xxfi_version > 3 && 13207c478bd9Sstevel@tonic-gate (fi_data = g->a_ctx->ctx_smfi->xxfi_data) != NULL) 13217c478bd9Sstevel@tonic-gate return (*fi_data)(g->a_ctx); 13227c478bd9Sstevel@tonic-gate return SMFIS_CONTINUE; 13237c478bd9Sstevel@tonic-gate } 13247c478bd9Sstevel@tonic-gate 13257c478bd9Sstevel@tonic-gate /* 13267c478bd9Sstevel@tonic-gate ** ST_HELO -- helo/ehlo command 13277c478bd9Sstevel@tonic-gate ** 13287c478bd9Sstevel@tonic-gate ** Parameters: 13297c478bd9Sstevel@tonic-gate ** g -- generic argument structure 13307c478bd9Sstevel@tonic-gate ** 13317c478bd9Sstevel@tonic-gate ** Returns: 13327c478bd9Sstevel@tonic-gate ** continue or filter-specified value 13337c478bd9Sstevel@tonic-gate */ 13344aac33d3Sjbeck 13357c478bd9Sstevel@tonic-gate static int 13367c478bd9Sstevel@tonic-gate st_helo(g) 13377c478bd9Sstevel@tonic-gate genarg *g; 13387c478bd9Sstevel@tonic-gate { 13397c478bd9Sstevel@tonic-gate sfsistat (*fi_helo) __P((SMFICTX *, char *)); 13407c478bd9Sstevel@tonic-gate 13417c478bd9Sstevel@tonic-gate if (g == NULL) 13427c478bd9Sstevel@tonic-gate return _SMFIS_ABORT; 13437c478bd9Sstevel@tonic-gate mi_clr_macros(g->a_ctx, g->a_idx + 1); 13447c478bd9Sstevel@tonic-gate if (g->a_ctx->ctx_smfi != NULL && 13457c478bd9Sstevel@tonic-gate (fi_helo = g->a_ctx->ctx_smfi->xxfi_helo) != NULL) 13467c478bd9Sstevel@tonic-gate { 13477c478bd9Sstevel@tonic-gate /* paranoia: check for terminating '\0' */ 13487c478bd9Sstevel@tonic-gate if (g->a_len == 0 || g->a_buf[g->a_len - 1] != '\0') 13497c478bd9Sstevel@tonic-gate return MI_FAILURE; 13507c478bd9Sstevel@tonic-gate return (*fi_helo)(g->a_ctx, g->a_buf); 13517c478bd9Sstevel@tonic-gate } 13527c478bd9Sstevel@tonic-gate return SMFIS_CONTINUE; 13537c478bd9Sstevel@tonic-gate } 13544aac33d3Sjbeck 13557c478bd9Sstevel@tonic-gate /* 13567c478bd9Sstevel@tonic-gate ** ST_HEADER -- header line 13577c478bd9Sstevel@tonic-gate ** 13587c478bd9Sstevel@tonic-gate ** Parameters: 13597c478bd9Sstevel@tonic-gate ** g -- generic argument structure 13607c478bd9Sstevel@tonic-gate ** 13617c478bd9Sstevel@tonic-gate ** Returns: 13627c478bd9Sstevel@tonic-gate ** continue or filter-specified value 13637c478bd9Sstevel@tonic-gate */ 13647c478bd9Sstevel@tonic-gate 13657c478bd9Sstevel@tonic-gate static int 13667c478bd9Sstevel@tonic-gate st_header(g) 13677c478bd9Sstevel@tonic-gate genarg *g; 13687c478bd9Sstevel@tonic-gate { 13697c478bd9Sstevel@tonic-gate char *hf, *hv; 13707c478bd9Sstevel@tonic-gate sfsistat (*fi_header) __P((SMFICTX *, char *, char *)); 13717c478bd9Sstevel@tonic-gate 13727c478bd9Sstevel@tonic-gate if (g == NULL) 13737c478bd9Sstevel@tonic-gate return _SMFIS_ABORT; 13747c478bd9Sstevel@tonic-gate if (g->a_ctx->ctx_smfi == NULL || 13757c478bd9Sstevel@tonic-gate (fi_header = g->a_ctx->ctx_smfi->xxfi_header) == NULL) 13767c478bd9Sstevel@tonic-gate return SMFIS_CONTINUE; 13777c478bd9Sstevel@tonic-gate if (dec_arg2(g->a_buf, g->a_len, &hf, &hv) == MI_SUCCESS) 13787c478bd9Sstevel@tonic-gate return (*fi_header)(g->a_ctx, hf, hv); 13797c478bd9Sstevel@tonic-gate else 13807c478bd9Sstevel@tonic-gate return _SMFIS_ABORT; 13817c478bd9Sstevel@tonic-gate } 13827c478bd9Sstevel@tonic-gate 13837c478bd9Sstevel@tonic-gate #define ARGV_FCT(lf, rf, idx) \ 13847c478bd9Sstevel@tonic-gate char **argv; \ 13857c478bd9Sstevel@tonic-gate sfsistat (*lf) __P((SMFICTX *, char **)); \ 13867c478bd9Sstevel@tonic-gate int r; \ 13877c478bd9Sstevel@tonic-gate \ 13887c478bd9Sstevel@tonic-gate if (g == NULL) \ 13897c478bd9Sstevel@tonic-gate return _SMFIS_ABORT; \ 13907c478bd9Sstevel@tonic-gate mi_clr_macros(g->a_ctx, g->a_idx + 1); \ 13917c478bd9Sstevel@tonic-gate if (g->a_ctx->ctx_smfi == NULL || \ 13927c478bd9Sstevel@tonic-gate (lf = g->a_ctx->ctx_smfi->rf) == NULL) \ 13937c478bd9Sstevel@tonic-gate return SMFIS_CONTINUE; \ 13947c478bd9Sstevel@tonic-gate if ((argv = dec_argv(g->a_buf, g->a_len)) == NULL) \ 13957c478bd9Sstevel@tonic-gate return _SMFIS_ABORT; \ 13967c478bd9Sstevel@tonic-gate r = (*lf)(g->a_ctx, argv); \ 13977c478bd9Sstevel@tonic-gate free(argv); \ 13987c478bd9Sstevel@tonic-gate return r; 13997c478bd9Sstevel@tonic-gate 14007c478bd9Sstevel@tonic-gate /* 14017c478bd9Sstevel@tonic-gate ** ST_SENDER -- MAIL FROM command 14027c478bd9Sstevel@tonic-gate ** 14037c478bd9Sstevel@tonic-gate ** Parameters: 14047c478bd9Sstevel@tonic-gate ** g -- generic argument structure 14057c478bd9Sstevel@tonic-gate ** 14067c478bd9Sstevel@tonic-gate ** Returns: 14077c478bd9Sstevel@tonic-gate ** continue or filter-specified value 14087c478bd9Sstevel@tonic-gate */ 14097c478bd9Sstevel@tonic-gate 14107c478bd9Sstevel@tonic-gate static int 14117c478bd9Sstevel@tonic-gate st_sender(g) 14127c478bd9Sstevel@tonic-gate genarg *g; 14137c478bd9Sstevel@tonic-gate { 14147c478bd9Sstevel@tonic-gate ARGV_FCT(fi_envfrom, xxfi_envfrom, CI_MAIL) 14157c478bd9Sstevel@tonic-gate } 1416058561cbSjbeck 14177c478bd9Sstevel@tonic-gate /* 14187c478bd9Sstevel@tonic-gate ** ST_RCPT -- RCPT TO command 14197c478bd9Sstevel@tonic-gate ** 14207c478bd9Sstevel@tonic-gate ** Parameters: 14217c478bd9Sstevel@tonic-gate ** g -- generic argument structure 14227c478bd9Sstevel@tonic-gate ** 14237c478bd9Sstevel@tonic-gate ** Returns: 14247c478bd9Sstevel@tonic-gate ** continue or filter-specified value 14257c478bd9Sstevel@tonic-gate */ 14267c478bd9Sstevel@tonic-gate 14277c478bd9Sstevel@tonic-gate static int 14287c478bd9Sstevel@tonic-gate st_rcpt(g) 14297c478bd9Sstevel@tonic-gate genarg *g; 14307c478bd9Sstevel@tonic-gate { 14317c478bd9Sstevel@tonic-gate ARGV_FCT(fi_envrcpt, xxfi_envrcpt, CI_RCPT) 14327c478bd9Sstevel@tonic-gate } 14337c478bd9Sstevel@tonic-gate 14347c478bd9Sstevel@tonic-gate /* 14357c478bd9Sstevel@tonic-gate ** ST_UNKNOWN -- unrecognized or unimplemented command 14367c478bd9Sstevel@tonic-gate ** 14377c478bd9Sstevel@tonic-gate ** Parameters: 14387c478bd9Sstevel@tonic-gate ** g -- generic argument structure 14397c478bd9Sstevel@tonic-gate ** 14407c478bd9Sstevel@tonic-gate ** Returns: 14417c478bd9Sstevel@tonic-gate ** continue or filter-specified value 14427c478bd9Sstevel@tonic-gate */ 14437c478bd9Sstevel@tonic-gate 14447c478bd9Sstevel@tonic-gate static int 14457c478bd9Sstevel@tonic-gate st_unknown(g) 14467c478bd9Sstevel@tonic-gate genarg *g; 14477c478bd9Sstevel@tonic-gate { 1448058561cbSjbeck sfsistat (*fi_unknown) __P((SMFICTX *, const char *)); 14497c478bd9Sstevel@tonic-gate 14507c478bd9Sstevel@tonic-gate if (g == NULL) 14517c478bd9Sstevel@tonic-gate return _SMFIS_ABORT; 14527c478bd9Sstevel@tonic-gate if (g->a_ctx->ctx_smfi != NULL && 145324472db6Sjbeck g->a_ctx->ctx_smfi->xxfi_version > 2 && 14547c478bd9Sstevel@tonic-gate (fi_unknown = g->a_ctx->ctx_smfi->xxfi_unknown) != NULL) 1455058561cbSjbeck return (*fi_unknown)(g->a_ctx, (const char *) g->a_buf); 14567c478bd9Sstevel@tonic-gate return SMFIS_CONTINUE; 14577c478bd9Sstevel@tonic-gate } 14587c478bd9Sstevel@tonic-gate 14597c478bd9Sstevel@tonic-gate /* 14607c478bd9Sstevel@tonic-gate ** ST_MACROS -- deal with macros received from the MTA 14617c478bd9Sstevel@tonic-gate ** 14627c478bd9Sstevel@tonic-gate ** Parameters: 14637c478bd9Sstevel@tonic-gate ** g -- generic argument structure 14647c478bd9Sstevel@tonic-gate ** 14657c478bd9Sstevel@tonic-gate ** Returns: 14667c478bd9Sstevel@tonic-gate ** continue/keep 14677c478bd9Sstevel@tonic-gate ** 14687c478bd9Sstevel@tonic-gate ** Side effects: 14697c478bd9Sstevel@tonic-gate ** set pointer in macro array to current values. 14707c478bd9Sstevel@tonic-gate */ 14717c478bd9Sstevel@tonic-gate 14727c478bd9Sstevel@tonic-gate static int 14737c478bd9Sstevel@tonic-gate st_macros(g) 14747c478bd9Sstevel@tonic-gate genarg *g; 14757c478bd9Sstevel@tonic-gate { 14767c478bd9Sstevel@tonic-gate int i; 14777c478bd9Sstevel@tonic-gate char **argv; 14787c478bd9Sstevel@tonic-gate 14797c478bd9Sstevel@tonic-gate if (g == NULL || g->a_len < 1) 14807c478bd9Sstevel@tonic-gate return _SMFIS_FAIL; 14817c478bd9Sstevel@tonic-gate if ((argv = dec_argv(g->a_buf + 1, g->a_len - 1)) == NULL) 14827c478bd9Sstevel@tonic-gate return _SMFIS_FAIL; 14837c478bd9Sstevel@tonic-gate switch (g->a_buf[0]) 14847c478bd9Sstevel@tonic-gate { 14857c478bd9Sstevel@tonic-gate case SMFIC_CONNECT: 14867c478bd9Sstevel@tonic-gate i = CI_CONN; 14877c478bd9Sstevel@tonic-gate break; 14887c478bd9Sstevel@tonic-gate case SMFIC_HELO: 14897c478bd9Sstevel@tonic-gate i = CI_HELO; 14907c478bd9Sstevel@tonic-gate break; 14917c478bd9Sstevel@tonic-gate case SMFIC_MAIL: 14927c478bd9Sstevel@tonic-gate i = CI_MAIL; 14937c478bd9Sstevel@tonic-gate break; 14947c478bd9Sstevel@tonic-gate case SMFIC_RCPT: 14957c478bd9Sstevel@tonic-gate i = CI_RCPT; 14967c478bd9Sstevel@tonic-gate break; 1497058561cbSjbeck case SMFIC_DATA: 1498058561cbSjbeck i = CI_DATA; 1499058561cbSjbeck break; 15007c478bd9Sstevel@tonic-gate case SMFIC_BODYEOB: 15017c478bd9Sstevel@tonic-gate i = CI_EOM; 15027c478bd9Sstevel@tonic-gate break; 1503058561cbSjbeck case SMFIC_EOH: 1504058561cbSjbeck i = CI_EOH; 1505058561cbSjbeck break; 15067c478bd9Sstevel@tonic-gate default: 15077c478bd9Sstevel@tonic-gate free(argv); 15087c478bd9Sstevel@tonic-gate return _SMFIS_FAIL; 15097c478bd9Sstevel@tonic-gate } 15107c478bd9Sstevel@tonic-gate if (g->a_ctx->ctx_mac_ptr[i] != NULL) 15117c478bd9Sstevel@tonic-gate free(g->a_ctx->ctx_mac_ptr[i]); 15127c478bd9Sstevel@tonic-gate if (g->a_ctx->ctx_mac_buf[i] != NULL) 15137c478bd9Sstevel@tonic-gate free(g->a_ctx->ctx_mac_buf[i]); 15147c478bd9Sstevel@tonic-gate g->a_ctx->ctx_mac_ptr[i] = argv; 15157c478bd9Sstevel@tonic-gate g->a_ctx->ctx_mac_buf[i] = g->a_buf; 15167c478bd9Sstevel@tonic-gate return _SMFIS_KEEP; 15177c478bd9Sstevel@tonic-gate } 15184aac33d3Sjbeck 15197c478bd9Sstevel@tonic-gate /* 15207c478bd9Sstevel@tonic-gate ** ST_QUIT -- quit command 15217c478bd9Sstevel@tonic-gate ** 15227c478bd9Sstevel@tonic-gate ** Parameters: 15237c478bd9Sstevel@tonic-gate ** g -- generic argument structure 15247c478bd9Sstevel@tonic-gate ** 15257c478bd9Sstevel@tonic-gate ** Returns: 15267c478bd9Sstevel@tonic-gate ** noreply 15277c478bd9Sstevel@tonic-gate */ 15287c478bd9Sstevel@tonic-gate 15297c478bd9Sstevel@tonic-gate /* ARGSUSED */ 15307c478bd9Sstevel@tonic-gate static int 15317c478bd9Sstevel@tonic-gate st_quit(g) 15327c478bd9Sstevel@tonic-gate genarg *g; 15337c478bd9Sstevel@tonic-gate { 1534058561cbSjbeck sfsistat (*fi_close) __P((SMFICTX *)); 1535058561cbSjbeck 1536058561cbSjbeck if (g == NULL) 1537058561cbSjbeck return _SMFIS_ABORT; 1538058561cbSjbeck if (g->a_ctx->ctx_smfi != NULL && 1539058561cbSjbeck (fi_close = g->a_ctx->ctx_smfi->xxfi_close) != NULL) 1540058561cbSjbeck (void) (*fi_close)(g->a_ctx); 1541058561cbSjbeck mi_clr_macros(g->a_ctx, 0); 15427c478bd9Sstevel@tonic-gate return _SMFIS_NOREPLY; 15437c478bd9Sstevel@tonic-gate } 15444aac33d3Sjbeck 15457c478bd9Sstevel@tonic-gate /* 15467c478bd9Sstevel@tonic-gate ** ST_BODYCHUNK -- deal with a piece of the mail body 15477c478bd9Sstevel@tonic-gate ** 15487c478bd9Sstevel@tonic-gate ** Parameters: 15497c478bd9Sstevel@tonic-gate ** g -- generic argument structure 15507c478bd9Sstevel@tonic-gate ** 15517c478bd9Sstevel@tonic-gate ** Returns: 15527c478bd9Sstevel@tonic-gate ** continue or filter-specified value 15537c478bd9Sstevel@tonic-gate */ 15547c478bd9Sstevel@tonic-gate 15557c478bd9Sstevel@tonic-gate static int 15567c478bd9Sstevel@tonic-gate st_bodychunk(g) 15577c478bd9Sstevel@tonic-gate genarg *g; 15587c478bd9Sstevel@tonic-gate { 15597c478bd9Sstevel@tonic-gate sfsistat (*fi_body) __P((SMFICTX *, unsigned char *, size_t)); 15607c478bd9Sstevel@tonic-gate 15617c478bd9Sstevel@tonic-gate if (g == NULL) 15627c478bd9Sstevel@tonic-gate return _SMFIS_ABORT; 15637c478bd9Sstevel@tonic-gate if (g->a_ctx->ctx_smfi != NULL && 15647c478bd9Sstevel@tonic-gate (fi_body = g->a_ctx->ctx_smfi->xxfi_body) != NULL) 15657c478bd9Sstevel@tonic-gate return (*fi_body)(g->a_ctx, (unsigned char *)g->a_buf, 15667c478bd9Sstevel@tonic-gate g->a_len); 15677c478bd9Sstevel@tonic-gate return SMFIS_CONTINUE; 15687c478bd9Sstevel@tonic-gate } 15694aac33d3Sjbeck 15707c478bd9Sstevel@tonic-gate /* 15717c478bd9Sstevel@tonic-gate ** ST_BODYEND -- deal with the last piece of the mail body 15727c478bd9Sstevel@tonic-gate ** 15737c478bd9Sstevel@tonic-gate ** Parameters: 15747c478bd9Sstevel@tonic-gate ** g -- generic argument structure 15757c478bd9Sstevel@tonic-gate ** 15767c478bd9Sstevel@tonic-gate ** Returns: 15777c478bd9Sstevel@tonic-gate ** continue or filter-specified value 15787c478bd9Sstevel@tonic-gate ** 15797c478bd9Sstevel@tonic-gate ** Side effects: 15807c478bd9Sstevel@tonic-gate ** sends a reply for the body part (if non-empty). 15817c478bd9Sstevel@tonic-gate */ 15827c478bd9Sstevel@tonic-gate 15837c478bd9Sstevel@tonic-gate static int 15847c478bd9Sstevel@tonic-gate st_bodyend(g) 15857c478bd9Sstevel@tonic-gate genarg *g; 15867c478bd9Sstevel@tonic-gate { 15877c478bd9Sstevel@tonic-gate sfsistat r; 15887c478bd9Sstevel@tonic-gate sfsistat (*fi_body) __P((SMFICTX *, unsigned char *, size_t)); 15897c478bd9Sstevel@tonic-gate sfsistat (*fi_eom) __P((SMFICTX *)); 15907c478bd9Sstevel@tonic-gate 15917c478bd9Sstevel@tonic-gate if (g == NULL) 15927c478bd9Sstevel@tonic-gate return _SMFIS_ABORT; 15937c478bd9Sstevel@tonic-gate r = SMFIS_CONTINUE; 15947c478bd9Sstevel@tonic-gate if (g->a_ctx->ctx_smfi != NULL) 15957c478bd9Sstevel@tonic-gate { 15967c478bd9Sstevel@tonic-gate if ((fi_body = g->a_ctx->ctx_smfi->xxfi_body) != NULL && 15977c478bd9Sstevel@tonic-gate g->a_len > 0) 15987c478bd9Sstevel@tonic-gate { 15997c478bd9Sstevel@tonic-gate socket_t sd; 16007c478bd9Sstevel@tonic-gate struct timeval timeout; 16017c478bd9Sstevel@tonic-gate 16027c478bd9Sstevel@tonic-gate timeout.tv_sec = g->a_ctx->ctx_timeout; 16037c478bd9Sstevel@tonic-gate timeout.tv_usec = 0; 16047c478bd9Sstevel@tonic-gate sd = g->a_ctx->ctx_sd; 16057c478bd9Sstevel@tonic-gate r = (*fi_body)(g->a_ctx, (unsigned char *)g->a_buf, 16067c478bd9Sstevel@tonic-gate g->a_len); 16077c478bd9Sstevel@tonic-gate if (r != SMFIS_CONTINUE && 16087c478bd9Sstevel@tonic-gate sendreply(r, sd, &timeout, g->a_ctx) != MI_SUCCESS) 16097c478bd9Sstevel@tonic-gate return _SMFIS_ABORT; 16107c478bd9Sstevel@tonic-gate } 16117c478bd9Sstevel@tonic-gate } 16127c478bd9Sstevel@tonic-gate if (r == SMFIS_CONTINUE && 16137c478bd9Sstevel@tonic-gate (fi_eom = g->a_ctx->ctx_smfi->xxfi_eom) != NULL) 16147c478bd9Sstevel@tonic-gate return (*fi_eom)(g->a_ctx); 16157c478bd9Sstevel@tonic-gate return r; 16167c478bd9Sstevel@tonic-gate } 16174aac33d3Sjbeck 16187c478bd9Sstevel@tonic-gate /* 16197c478bd9Sstevel@tonic-gate ** ST_ABORTFCT -- deal with aborts 16207c478bd9Sstevel@tonic-gate ** 16217c478bd9Sstevel@tonic-gate ** Parameters: 16227c478bd9Sstevel@tonic-gate ** g -- generic argument structure 16237c478bd9Sstevel@tonic-gate ** 16247c478bd9Sstevel@tonic-gate ** Returns: 16257c478bd9Sstevel@tonic-gate ** abort or filter-specified value 16267c478bd9Sstevel@tonic-gate */ 16277c478bd9Sstevel@tonic-gate 16287c478bd9Sstevel@tonic-gate static int 16297c478bd9Sstevel@tonic-gate st_abortfct(g) 16307c478bd9Sstevel@tonic-gate genarg *g; 16317c478bd9Sstevel@tonic-gate { 16327c478bd9Sstevel@tonic-gate sfsistat (*fi_abort) __P((SMFICTX *)); 16337c478bd9Sstevel@tonic-gate 16347c478bd9Sstevel@tonic-gate if (g == NULL) 16357c478bd9Sstevel@tonic-gate return _SMFIS_ABORT; 16367c478bd9Sstevel@tonic-gate if (g != NULL && g->a_ctx->ctx_smfi != NULL && 16377c478bd9Sstevel@tonic-gate (fi_abort = g->a_ctx->ctx_smfi->xxfi_abort) != NULL) 16387c478bd9Sstevel@tonic-gate (void) (*fi_abort)(g->a_ctx); 16397c478bd9Sstevel@tonic-gate return _SMFIS_NOREPLY; 16407c478bd9Sstevel@tonic-gate } 16414aac33d3Sjbeck 16427c478bd9Sstevel@tonic-gate /* 16437c478bd9Sstevel@tonic-gate ** TRANS_OK -- is the state transition ok? 16447c478bd9Sstevel@tonic-gate ** 16457c478bd9Sstevel@tonic-gate ** Parameters: 16467c478bd9Sstevel@tonic-gate ** old -- old state 16477c478bd9Sstevel@tonic-gate ** new -- new state 16487c478bd9Sstevel@tonic-gate ** 16497c478bd9Sstevel@tonic-gate ** Returns: 16507c478bd9Sstevel@tonic-gate ** state transition ok 16517c478bd9Sstevel@tonic-gate */ 16527c478bd9Sstevel@tonic-gate 16537c478bd9Sstevel@tonic-gate static bool 16547c478bd9Sstevel@tonic-gate trans_ok(old, new) 16557c478bd9Sstevel@tonic-gate int old, new; 16567c478bd9Sstevel@tonic-gate { 16577c478bd9Sstevel@tonic-gate int s, n; 16587c478bd9Sstevel@tonic-gate 16597c478bd9Sstevel@tonic-gate s = old; 16603ee0e492Sjbeck if (s >= SIZE_NEXT_STATES) 16613ee0e492Sjbeck return false; 16627c478bd9Sstevel@tonic-gate do 16637c478bd9Sstevel@tonic-gate { 16647c478bd9Sstevel@tonic-gate /* is this state transition allowed? */ 16657c478bd9Sstevel@tonic-gate if ((MI_MASK(new) & next_states[s]) != 0) 16667c478bd9Sstevel@tonic-gate return true; 16677c478bd9Sstevel@tonic-gate 16687c478bd9Sstevel@tonic-gate /* 16697c478bd9Sstevel@tonic-gate ** no: try next state; 16707c478bd9Sstevel@tonic-gate ** this works since the relevant states are ordered 16717c478bd9Sstevel@tonic-gate ** strict sequentially 16727c478bd9Sstevel@tonic-gate */ 16737c478bd9Sstevel@tonic-gate 16747c478bd9Sstevel@tonic-gate n = s + 1; 16753ee0e492Sjbeck if (n >= SIZE_NEXT_STATES) 16763ee0e492Sjbeck return false; 16777c478bd9Sstevel@tonic-gate 16787c478bd9Sstevel@tonic-gate /* 16797c478bd9Sstevel@tonic-gate ** can we actually "skip" this state? 16807c478bd9Sstevel@tonic-gate ** see fix_stm() which sets this bit for those 16817c478bd9Sstevel@tonic-gate ** states which the filter program is not interested in 16827c478bd9Sstevel@tonic-gate */ 16837c478bd9Sstevel@tonic-gate 16847c478bd9Sstevel@tonic-gate if (bitset(NX_SKIP, next_states[n])) 16857c478bd9Sstevel@tonic-gate s = n; 16867c478bd9Sstevel@tonic-gate else 16877c478bd9Sstevel@tonic-gate return false; 16883ee0e492Sjbeck } while (s < SIZE_NEXT_STATES); 16897c478bd9Sstevel@tonic-gate return false; 16907c478bd9Sstevel@tonic-gate } 16914aac33d3Sjbeck 16927c478bd9Sstevel@tonic-gate /* 16937c478bd9Sstevel@tonic-gate ** FIX_STM -- add "skip" bits to the state transition table 16947c478bd9Sstevel@tonic-gate ** 16957c478bd9Sstevel@tonic-gate ** Parameters: 16967c478bd9Sstevel@tonic-gate ** ctx -- context structure 16977c478bd9Sstevel@tonic-gate ** 16987c478bd9Sstevel@tonic-gate ** Returns: 16997c478bd9Sstevel@tonic-gate ** None. 17007c478bd9Sstevel@tonic-gate ** 17017c478bd9Sstevel@tonic-gate ** Side effects: 17027c478bd9Sstevel@tonic-gate ** may change state transition table. 17037c478bd9Sstevel@tonic-gate */ 17047c478bd9Sstevel@tonic-gate 17057c478bd9Sstevel@tonic-gate static void 17067c478bd9Sstevel@tonic-gate fix_stm(ctx) 17077c478bd9Sstevel@tonic-gate SMFICTX_PTR ctx; 17087c478bd9Sstevel@tonic-gate { 17097c478bd9Sstevel@tonic-gate unsigned long fl; 17107c478bd9Sstevel@tonic-gate 17117c478bd9Sstevel@tonic-gate if (ctx == NULL || ctx->ctx_smfi == NULL) 17127c478bd9Sstevel@tonic-gate return; 17137c478bd9Sstevel@tonic-gate fl = ctx->ctx_pflags; 17147c478bd9Sstevel@tonic-gate if (bitset(SMFIP_NOCONNECT, fl)) 17157c478bd9Sstevel@tonic-gate next_states[ST_CONN] |= NX_SKIP; 17167c478bd9Sstevel@tonic-gate if (bitset(SMFIP_NOHELO, fl)) 17177c478bd9Sstevel@tonic-gate next_states[ST_HELO] |= NX_SKIP; 17187c478bd9Sstevel@tonic-gate if (bitset(SMFIP_NOMAIL, fl)) 17197c478bd9Sstevel@tonic-gate next_states[ST_MAIL] |= NX_SKIP; 17207c478bd9Sstevel@tonic-gate if (bitset(SMFIP_NORCPT, fl)) 17217c478bd9Sstevel@tonic-gate next_states[ST_RCPT] |= NX_SKIP; 17227c478bd9Sstevel@tonic-gate if (bitset(SMFIP_NOHDRS, fl)) 17237c478bd9Sstevel@tonic-gate next_states[ST_HDRS] |= NX_SKIP; 17247c478bd9Sstevel@tonic-gate if (bitset(SMFIP_NOEOH, fl)) 17257c478bd9Sstevel@tonic-gate next_states[ST_EOHS] |= NX_SKIP; 17267c478bd9Sstevel@tonic-gate if (bitset(SMFIP_NOBODY, fl)) 17277c478bd9Sstevel@tonic-gate next_states[ST_BODY] |= NX_SKIP; 1728058561cbSjbeck if (bitset(SMFIP_NODATA, fl)) 1729058561cbSjbeck next_states[ST_DATA] |= NX_SKIP; 1730058561cbSjbeck if (bitset(SMFIP_NOUNKNOWN, fl)) 1731058561cbSjbeck next_states[ST_UNKN] |= NX_SKIP; 17327c478bd9Sstevel@tonic-gate } 1733058561cbSjbeck 17347c478bd9Sstevel@tonic-gate /* 17357c478bd9Sstevel@tonic-gate ** DEC_ARGV -- split a buffer into a list of strings, NULL terminated 17367c478bd9Sstevel@tonic-gate ** 17377c478bd9Sstevel@tonic-gate ** Parameters: 17387c478bd9Sstevel@tonic-gate ** buf -- buffer with several strings 17397c478bd9Sstevel@tonic-gate ** len -- length of buffer 17407c478bd9Sstevel@tonic-gate ** 17417c478bd9Sstevel@tonic-gate ** Returns: 17427c478bd9Sstevel@tonic-gate ** array of pointers to the individual strings 17437c478bd9Sstevel@tonic-gate */ 17447c478bd9Sstevel@tonic-gate 17457c478bd9Sstevel@tonic-gate static char ** 17467c478bd9Sstevel@tonic-gate dec_argv(buf, len) 17477c478bd9Sstevel@tonic-gate char *buf; 17487c478bd9Sstevel@tonic-gate size_t len; 17497c478bd9Sstevel@tonic-gate { 17507c478bd9Sstevel@tonic-gate char **s; 17517c478bd9Sstevel@tonic-gate size_t i; 17527c478bd9Sstevel@tonic-gate int elem, nelem; 17537c478bd9Sstevel@tonic-gate 17547c478bd9Sstevel@tonic-gate nelem = 0; 17557c478bd9Sstevel@tonic-gate for (i = 0; i < len; i++) 17567c478bd9Sstevel@tonic-gate { 17577c478bd9Sstevel@tonic-gate if (buf[i] == '\0') 17587c478bd9Sstevel@tonic-gate ++nelem; 17597c478bd9Sstevel@tonic-gate } 17607c478bd9Sstevel@tonic-gate if (nelem == 0) 17617c478bd9Sstevel@tonic-gate return NULL; 17627c478bd9Sstevel@tonic-gate 17637c478bd9Sstevel@tonic-gate /* last entry is only for the name */ 17647c478bd9Sstevel@tonic-gate s = (char **)malloc((nelem + 1) * (sizeof *s)); 17657c478bd9Sstevel@tonic-gate if (s == NULL) 17667c478bd9Sstevel@tonic-gate return NULL; 17677c478bd9Sstevel@tonic-gate s[0] = buf; 17687c478bd9Sstevel@tonic-gate for (i = 0, elem = 0; i < len && elem < nelem; i++) 17697c478bd9Sstevel@tonic-gate { 17707c478bd9Sstevel@tonic-gate if (buf[i] == '\0') 17717c478bd9Sstevel@tonic-gate { 17727c478bd9Sstevel@tonic-gate ++elem; 17737c478bd9Sstevel@tonic-gate if (i + 1 >= len) 17747c478bd9Sstevel@tonic-gate s[elem] = NULL; 17757c478bd9Sstevel@tonic-gate else 17767c478bd9Sstevel@tonic-gate s[elem] = &(buf[i + 1]); 17777c478bd9Sstevel@tonic-gate } 17787c478bd9Sstevel@tonic-gate } 17797c478bd9Sstevel@tonic-gate 17807c478bd9Sstevel@tonic-gate /* overwrite last entry (already done above, just paranoia) */ 17817c478bd9Sstevel@tonic-gate s[elem] = NULL; 17827c478bd9Sstevel@tonic-gate return s; 17837c478bd9Sstevel@tonic-gate } 17844aac33d3Sjbeck 17857c478bd9Sstevel@tonic-gate /* 17867c478bd9Sstevel@tonic-gate ** DEC_ARG2 -- split a buffer into two strings 17877c478bd9Sstevel@tonic-gate ** 17887c478bd9Sstevel@tonic-gate ** Parameters: 17897c478bd9Sstevel@tonic-gate ** buf -- buffer with two strings 17907c478bd9Sstevel@tonic-gate ** len -- length of buffer 17917c478bd9Sstevel@tonic-gate ** s1,s2 -- pointer to result strings 17927c478bd9Sstevel@tonic-gate ** 17937c478bd9Sstevel@tonic-gate ** Returns: 17947c478bd9Sstevel@tonic-gate ** MI_FAILURE/MI_SUCCESS 17957c478bd9Sstevel@tonic-gate */ 17967c478bd9Sstevel@tonic-gate 17977c478bd9Sstevel@tonic-gate static int 17987c478bd9Sstevel@tonic-gate dec_arg2(buf, len, s1, s2) 17997c478bd9Sstevel@tonic-gate char *buf; 18007c478bd9Sstevel@tonic-gate size_t len; 18017c478bd9Sstevel@tonic-gate char **s1; 18027c478bd9Sstevel@tonic-gate char **s2; 18037c478bd9Sstevel@tonic-gate { 18047c478bd9Sstevel@tonic-gate size_t i; 18057c478bd9Sstevel@tonic-gate 18067c478bd9Sstevel@tonic-gate /* paranoia: check for terminating '\0' */ 18077c478bd9Sstevel@tonic-gate if (len == 0 || buf[len - 1] != '\0') 18087c478bd9Sstevel@tonic-gate return MI_FAILURE; 18097c478bd9Sstevel@tonic-gate *s1 = buf; 18107c478bd9Sstevel@tonic-gate for (i = 1; i < len && buf[i] != '\0'; i++) 18117c478bd9Sstevel@tonic-gate continue; 18127c478bd9Sstevel@tonic-gate if (i >= len - 1) 18137c478bd9Sstevel@tonic-gate return MI_FAILURE; 18147c478bd9Sstevel@tonic-gate *s2 = buf + i + 1; 18157c478bd9Sstevel@tonic-gate return MI_SUCCESS; 18167c478bd9Sstevel@tonic-gate } 18174aac33d3Sjbeck 18187c478bd9Sstevel@tonic-gate /* 18197c478bd9Sstevel@tonic-gate ** SENDOK -- is it ok for the filter to send stuff to the MTA? 18207c478bd9Sstevel@tonic-gate ** 18217c478bd9Sstevel@tonic-gate ** Parameters: 18227c478bd9Sstevel@tonic-gate ** ctx -- context structure 18237c478bd9Sstevel@tonic-gate ** flag -- flag to check 18247c478bd9Sstevel@tonic-gate ** 18257c478bd9Sstevel@tonic-gate ** Returns: 18267c478bd9Sstevel@tonic-gate ** sending allowed (in current state) 18277c478bd9Sstevel@tonic-gate */ 18287c478bd9Sstevel@tonic-gate 18297c478bd9Sstevel@tonic-gate bool 18307c478bd9Sstevel@tonic-gate mi_sendok(ctx, flag) 18317c478bd9Sstevel@tonic-gate SMFICTX_PTR ctx; 18327c478bd9Sstevel@tonic-gate int flag; 18337c478bd9Sstevel@tonic-gate { 18347c478bd9Sstevel@tonic-gate if (ctx == NULL || ctx->ctx_smfi == NULL) 18357c478bd9Sstevel@tonic-gate return false; 18367c478bd9Sstevel@tonic-gate 18377c478bd9Sstevel@tonic-gate /* did the milter request this operation? */ 1838058561cbSjbeck if (flag != 0 && !bitset(flag, ctx->ctx_aflags)) 18397c478bd9Sstevel@tonic-gate return false; 18407c478bd9Sstevel@tonic-gate 18417c478bd9Sstevel@tonic-gate /* are we in the correct state? It must be "End of Message". */ 18427c478bd9Sstevel@tonic-gate return ctx->ctx_state == ST_ENDM; 18437c478bd9Sstevel@tonic-gate } 1844058561cbSjbeck 1845058561cbSjbeck #if _FFR_WORKERS_POOL 1846058561cbSjbeck /* 1847058561cbSjbeck ** MI_RD_SOCKET_READY - checks if the socket is ready for read(2) 1848058561cbSjbeck ** 1849058561cbSjbeck ** Parameters: 1850058561cbSjbeck ** sd -- socket_t 1851058561cbSjbeck ** 1852058561cbSjbeck ** Returns: 1853058561cbSjbeck ** true iff socket is ready for read(2) 1854058561cbSjbeck */ 1855058561cbSjbeck 1856058561cbSjbeck #define MI_RD_CMD_TO 1 1857058561cbSjbeck #define MI_RD_MAX_ERR 16 1858058561cbSjbeck 1859058561cbSjbeck static bool 1860058561cbSjbeck mi_rd_socket_ready (sd) 1861058561cbSjbeck socket_t sd; 1862058561cbSjbeck { 1863058561cbSjbeck int n; 1864058561cbSjbeck int nerr = 0; 1865058561cbSjbeck #if SM_CONF_POLL 1866058561cbSjbeck struct pollfd pfd; 1867058561cbSjbeck #else /* SM_CONF_POLL */ 1868058561cbSjbeck fd_set rd_set, exc_set; 1869058561cbSjbeck #endif /* SM_CONF_POLL */ 1870058561cbSjbeck 1871058561cbSjbeck do 1872058561cbSjbeck { 1873058561cbSjbeck #if SM_CONF_POLL 1874058561cbSjbeck pfd.fd = sd; 1875058561cbSjbeck pfd.events = POLLIN; 1876058561cbSjbeck pfd.revents = 0; 1877058561cbSjbeck 1878058561cbSjbeck n = poll(&pfd, 1, MI_RD_CMD_TO); 1879058561cbSjbeck #else /* SM_CONF_POLL */ 1880058561cbSjbeck struct timeval timeout; 1881058561cbSjbeck 1882058561cbSjbeck FD_ZERO(&rd_set); 1883058561cbSjbeck FD_ZERO(&exc_set); 1884058561cbSjbeck FD_SET(sd, &rd_set); 1885058561cbSjbeck FD_SET(sd, &exc_set); 1886058561cbSjbeck 1887058561cbSjbeck timeout.tv_sec = MI_RD_CMD_TO / 1000; 1888058561cbSjbeck timeout.tv_usec = 0; 1889058561cbSjbeck n = select(sd + 1, &rd_set, NULL, &exc_set, &timeout); 1890058561cbSjbeck #endif /* SM_CONF_POLL */ 1891058561cbSjbeck 1892058561cbSjbeck if (n < 0) 1893058561cbSjbeck { 1894058561cbSjbeck if (errno == EINTR) 1895058561cbSjbeck { 1896058561cbSjbeck nerr++; 1897058561cbSjbeck continue; 1898058561cbSjbeck } 1899058561cbSjbeck return true; 1900058561cbSjbeck } 1901058561cbSjbeck 1902058561cbSjbeck if (n == 0) 1903058561cbSjbeck return false; 1904058561cbSjbeck break; 1905058561cbSjbeck } while (nerr < MI_RD_MAX_ERR); 1906058561cbSjbeck if (nerr >= MI_RD_MAX_ERR) 1907058561cbSjbeck return false; 1908058561cbSjbeck 1909058561cbSjbeck #if SM_CONF_POLL 1910058561cbSjbeck return (pfd.revents != 0); 1911058561cbSjbeck #else /* SM_CONF_POLL */ 1912058561cbSjbeck return FD_ISSET(sd, &rd_set) || FD_ISSET(sd, &exc_set); 1913058561cbSjbeck #endif /* SM_CONF_POLL */ 1914058561cbSjbeck } 1915058561cbSjbeck #endif /* _FFR_WORKERS_POOL */ 1916