10Sstevel@tonic-gate /* 22197Sjbeck * Copyright (c) 1999-2004, 2006 Sendmail, Inc. and its suppliers. 30Sstevel@tonic-gate * All rights reserved. 40Sstevel@tonic-gate * 50Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set 60Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of 70Sstevel@tonic-gate * the sendmail distribution. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate */ 100Sstevel@tonic-gate 110Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 120Sstevel@tonic-gate 130Sstevel@tonic-gate #include <sm/gen.h> 14*3966Sjbeck SM_RCSID("@(#)$Id: engine.c,v 8.157 2007/03/26 18:10:04 ca Exp $") 150Sstevel@tonic-gate 160Sstevel@tonic-gate #include "libmilter.h" 170Sstevel@tonic-gate 180Sstevel@tonic-gate #if NETINET || NETINET6 190Sstevel@tonic-gate # include <arpa/inet.h> 200Sstevel@tonic-gate #endif /* NETINET || NETINET6 */ 210Sstevel@tonic-gate 220Sstevel@tonic-gate /* generic argument for functions in the command table */ 230Sstevel@tonic-gate struct arg_struct 240Sstevel@tonic-gate { 250Sstevel@tonic-gate size_t a_len; /* length of buffer */ 260Sstevel@tonic-gate char *a_buf; /* argument string */ 270Sstevel@tonic-gate int a_idx; /* index for macro array */ 280Sstevel@tonic-gate SMFICTX_PTR a_ctx; /* context */ 290Sstevel@tonic-gate }; 300Sstevel@tonic-gate 310Sstevel@tonic-gate typedef struct arg_struct genarg; 320Sstevel@tonic-gate 330Sstevel@tonic-gate /* structure for commands received from MTA */ 340Sstevel@tonic-gate struct cmdfct_t 350Sstevel@tonic-gate { 360Sstevel@tonic-gate char cm_cmd; /* command */ 370Sstevel@tonic-gate int cm_argt; /* type of arguments expected */ 380Sstevel@tonic-gate int cm_next; /* next state */ 390Sstevel@tonic-gate int cm_todo; /* what to do next */ 400Sstevel@tonic-gate int cm_macros; /* index for macros */ 410Sstevel@tonic-gate int (*cm_fct) __P((genarg *)); /* function to execute */ 420Sstevel@tonic-gate }; 430Sstevel@tonic-gate 440Sstevel@tonic-gate typedef struct cmdfct_t cmdfct; 450Sstevel@tonic-gate 460Sstevel@tonic-gate /* possible values for cm_argt */ 470Sstevel@tonic-gate #define CM_ARG0 0 /* no args */ 480Sstevel@tonic-gate #define CM_ARG1 1 /* one arg (string) */ 490Sstevel@tonic-gate #define CM_ARG2 2 /* two args (strings) */ 500Sstevel@tonic-gate #define CM_ARGA 4 /* one string and _SOCK_ADDR */ 510Sstevel@tonic-gate #define CM_ARGO 5 /* two integers */ 520Sstevel@tonic-gate #define CM_ARGV 8 /* \0 separated list of args, NULL-terminated */ 530Sstevel@tonic-gate #define CM_ARGN 9 /* \0 separated list of args (strings) */ 540Sstevel@tonic-gate 550Sstevel@tonic-gate /* possible values for cm_todo */ 560Sstevel@tonic-gate #define CT_CONT 0x0000 /* continue reading commands */ 570Sstevel@tonic-gate #define CT_IGNO 0x0001 /* continue even when error */ 580Sstevel@tonic-gate 590Sstevel@tonic-gate /* not needed right now, done via return code instead */ 600Sstevel@tonic-gate #define CT_KEEP 0x0004 /* keep buffer (contains symbols) */ 613544Sjbeck #define CT_END 0x0008 /* last command of session, stop replying */ 620Sstevel@tonic-gate 630Sstevel@tonic-gate /* index in macro array: macros only for these commands */ 640Sstevel@tonic-gate #define CI_NONE (-1) 650Sstevel@tonic-gate #define CI_CONN 0 660Sstevel@tonic-gate #define CI_HELO 1 670Sstevel@tonic-gate #define CI_MAIL 2 680Sstevel@tonic-gate #define CI_RCPT 3 693544Sjbeck #define CI_DATA 4 703544Sjbeck #define CI_EOM 5 713544Sjbeck #define CI_EOH 6 723544Sjbeck #define CI_LAST CI_EOH 733544Sjbeck #if CI_LAST < CI_DATA 743544Sjbeck ERROR: do not compile with CI_LAST < CI_DATA 753544Sjbeck #endif 763544Sjbeck #if CI_LAST < CI_EOM 773544Sjbeck ERROR: do not compile with CI_LAST < CI_EOM 783544Sjbeck #endif 793544Sjbeck #if CI_LAST < CI_EOH 803544Sjbeck ERROR: do not compile with CI_LAST < CI_EOH 813544Sjbeck #endif 823544Sjbeck #if CI_LAST < CI_ENVRCPT 833544Sjbeck ERROR: do not compile with CI_LAST < CI_ENVRCPT 843544Sjbeck #endif 853544Sjbeck #if CI_LAST < CI_ENVFROM 863544Sjbeck ERROR: do not compile with CI_LAST < CI_ENVFROM 873544Sjbeck #endif 883544Sjbeck #if CI_LAST < CI_HELO 893544Sjbeck ERROR: do not compile with CI_LAST < CI_HELO 903544Sjbeck #endif 913544Sjbeck #if CI_LAST < CI_CONNECT 923544Sjbeck ERROR: do not compile with CI_LAST < CI_CONNECT 933544Sjbeck #endif 943544Sjbeck #if CI_LAST >= MAX_MACROS_ENTRIES 953544Sjbeck ERROR: do not compile with CI_LAST >= MAX_MACROS_ENTRIES 960Sstevel@tonic-gate #endif 970Sstevel@tonic-gate 980Sstevel@tonic-gate /* function prototypes */ 990Sstevel@tonic-gate static int st_abortfct __P((genarg *)); 1000Sstevel@tonic-gate static int st_macros __P((genarg *)); 1010Sstevel@tonic-gate static int st_optionneg __P((genarg *)); 1020Sstevel@tonic-gate static int st_bodychunk __P((genarg *)); 1030Sstevel@tonic-gate static int st_connectinfo __P((genarg *)); 1040Sstevel@tonic-gate static int st_bodyend __P((genarg *)); 1050Sstevel@tonic-gate static int st_helo __P((genarg *)); 1060Sstevel@tonic-gate static int st_header __P((genarg *)); 1070Sstevel@tonic-gate static int st_sender __P((genarg *)); 1080Sstevel@tonic-gate static int st_rcpt __P((genarg *)); 1090Sstevel@tonic-gate static int st_unknown __P((genarg *)); 1100Sstevel@tonic-gate static int st_data __P((genarg *)); 1110Sstevel@tonic-gate static int st_eoh __P((genarg *)); 1120Sstevel@tonic-gate static int st_quit __P((genarg *)); 1130Sstevel@tonic-gate static int sendreply __P((sfsistat, socket_t, struct timeval *, SMFICTX_PTR)); 1140Sstevel@tonic-gate static void fix_stm __P((SMFICTX_PTR)); 1150Sstevel@tonic-gate static bool trans_ok __P((int, int)); 1160Sstevel@tonic-gate static char **dec_argv __P((char *, size_t)); 1170Sstevel@tonic-gate static int dec_arg2 __P((char *, size_t, char **, char **)); 1180Sstevel@tonic-gate 1193544Sjbeck #if _FFR_WORKERS_POOL 1203544Sjbeck static bool mi_rd_socket_ready __P((int)); 1213544Sjbeck #endif /* _FFR_WORKERS_POOL */ 1223544Sjbeck 1230Sstevel@tonic-gate /* states */ 1240Sstevel@tonic-gate #define ST_NONE (-1) 1250Sstevel@tonic-gate #define ST_INIT 0 /* initial state */ 1260Sstevel@tonic-gate #define ST_OPTS 1 /* option negotiation */ 1270Sstevel@tonic-gate #define ST_CONN 2 /* connection info */ 1280Sstevel@tonic-gate #define ST_HELO 3 /* helo */ 1290Sstevel@tonic-gate #define ST_MAIL 4 /* mail from */ 1300Sstevel@tonic-gate #define ST_RCPT 5 /* rcpt to */ 1310Sstevel@tonic-gate #define ST_DATA 6 /* data */ 1320Sstevel@tonic-gate #define ST_HDRS 7 /* headers */ 1330Sstevel@tonic-gate #define ST_EOHS 8 /* end of headers */ 1340Sstevel@tonic-gate #define ST_BODY 9 /* body */ 1350Sstevel@tonic-gate #define ST_ENDM 10 /* end of message */ 1360Sstevel@tonic-gate #define ST_QUIT 11 /* quit */ 1370Sstevel@tonic-gate #define ST_ABRT 12 /* abort */ 1380Sstevel@tonic-gate #define ST_UNKN 13 /* unknown SMTP command */ 1393544Sjbeck #define ST_Q_NC 14 /* quit, new connection follows */ 1403544Sjbeck #define ST_LAST ST_Q_NC /* last valid state */ 1413544Sjbeck #define ST_SKIP 16 /* not a state but required for the state table */ 1420Sstevel@tonic-gate 1430Sstevel@tonic-gate /* in a mail transaction? must be before eom according to spec. */ 1440Sstevel@tonic-gate #define ST_IN_MAIL(st) ((st) >= ST_MAIL && (st) < ST_ENDM) 1450Sstevel@tonic-gate 1460Sstevel@tonic-gate /* 1470Sstevel@tonic-gate ** set of next states 1480Sstevel@tonic-gate ** each state (ST_*) corresponds to bit in an int value (1 << state) 1490Sstevel@tonic-gate ** each state has a set of allowed transitions ('or' of bits of states) 1500Sstevel@tonic-gate ** so a state transition is valid if the mask of the next state 1510Sstevel@tonic-gate ** is set in the NX_* value 1520Sstevel@tonic-gate ** this function is coded in trans_ok(), see below. 1530Sstevel@tonic-gate */ 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate #define MI_MASK(x) (0x0001 << (x)) /* generate a bit "mask" for a state */ 1560Sstevel@tonic-gate #define NX_INIT (MI_MASK(ST_OPTS)) 1570Sstevel@tonic-gate #define NX_OPTS (MI_MASK(ST_CONN) | MI_MASK(ST_UNKN)) 1580Sstevel@tonic-gate #define NX_CONN (MI_MASK(ST_HELO) | MI_MASK(ST_MAIL) | MI_MASK(ST_UNKN)) 1590Sstevel@tonic-gate #define NX_HELO (MI_MASK(ST_HELO) | MI_MASK(ST_MAIL) | MI_MASK(ST_UNKN)) 1600Sstevel@tonic-gate #define NX_MAIL (MI_MASK(ST_RCPT) | MI_MASK(ST_ABRT) | MI_MASK(ST_UNKN)) 1610Sstevel@tonic-gate #define NX_RCPT (MI_MASK(ST_HDRS) | MI_MASK(ST_EOHS) | MI_MASK(ST_DATA) | \ 1620Sstevel@tonic-gate MI_MASK(ST_BODY) | MI_MASK(ST_ENDM) | \ 1630Sstevel@tonic-gate MI_MASK(ST_RCPT) | MI_MASK(ST_ABRT) | MI_MASK(ST_UNKN)) 1640Sstevel@tonic-gate #define NX_DATA (MI_MASK(ST_EOHS) | MI_MASK(ST_HDRS) | MI_MASK(ST_ABRT)) 1650Sstevel@tonic-gate #define NX_HDRS (MI_MASK(ST_EOHS) | MI_MASK(ST_HDRS) | MI_MASK(ST_ABRT)) 1660Sstevel@tonic-gate #define NX_EOHS (MI_MASK(ST_BODY) | MI_MASK(ST_ENDM) | MI_MASK(ST_ABRT)) 1670Sstevel@tonic-gate #define NX_BODY (MI_MASK(ST_ENDM) | MI_MASK(ST_BODY) | MI_MASK(ST_ABRT)) 1683544Sjbeck #define NX_ENDM (MI_MASK(ST_QUIT) | MI_MASK(ST_MAIL) | MI_MASK(ST_UNKN) | \ 1693544Sjbeck MI_MASK(ST_Q_NC)) 1700Sstevel@tonic-gate #define NX_QUIT 0 1710Sstevel@tonic-gate #define NX_ABRT 0 1720Sstevel@tonic-gate #define NX_UNKN (MI_MASK(ST_HELO) | MI_MASK(ST_MAIL) | \ 1730Sstevel@tonic-gate MI_MASK(ST_RCPT) | MI_MASK(ST_ABRT) | \ 1740Sstevel@tonic-gate MI_MASK(ST_DATA) | \ 1750Sstevel@tonic-gate MI_MASK(ST_BODY) | MI_MASK(ST_UNKN) | \ 1763544Sjbeck MI_MASK(ST_ABRT) | MI_MASK(ST_QUIT) | MI_MASK(ST_Q_NC)) 1773544Sjbeck #define NX_Q_NC (MI_MASK(ST_CONN) | MI_MASK(ST_UNKN)) 1780Sstevel@tonic-gate #define NX_SKIP MI_MASK(ST_SKIP) 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate static int next_states[] = 1810Sstevel@tonic-gate { 1823544Sjbeck NX_INIT 1833544Sjbeck , NX_OPTS 1843544Sjbeck , NX_CONN 1853544Sjbeck , NX_HELO 1863544Sjbeck , NX_MAIL 1873544Sjbeck , NX_RCPT 1883544Sjbeck , NX_DATA 1893544Sjbeck , NX_HDRS 1903544Sjbeck , NX_EOHS 1913544Sjbeck , NX_BODY 1923544Sjbeck , NX_ENDM 1933544Sjbeck , NX_QUIT 1943544Sjbeck , NX_ABRT 1953544Sjbeck , NX_UNKN 1963544Sjbeck , NX_Q_NC 1970Sstevel@tonic-gate }; 1980Sstevel@tonic-gate 1992197Sjbeck #define SIZE_NEXT_STATES (sizeof(next_states) / sizeof(next_states[0])) 2002197Sjbeck 2010Sstevel@tonic-gate /* commands received by milter */ 2020Sstevel@tonic-gate static cmdfct cmds[] = 2030Sstevel@tonic-gate { 2043544Sjbeck {SMFIC_ABORT, CM_ARG0, ST_ABRT, CT_CONT, CI_NONE, st_abortfct } 2053544Sjbeck , {SMFIC_MACRO, CM_ARGV, ST_NONE, CT_KEEP, CI_NONE, st_macros } 2063544Sjbeck , {SMFIC_BODY, CM_ARG1, ST_BODY, CT_CONT, CI_NONE, st_bodychunk } 2073544Sjbeck , {SMFIC_CONNECT, CM_ARG2, ST_CONN, CT_CONT, CI_CONN, st_connectinfo } 2083544Sjbeck , {SMFIC_BODYEOB, CM_ARG1, ST_ENDM, CT_CONT, CI_EOM, st_bodyend } 2093544Sjbeck , {SMFIC_HELO, CM_ARG1, ST_HELO, CT_CONT, CI_HELO, st_helo } 2103544Sjbeck , {SMFIC_HEADER, CM_ARG2, ST_HDRS, CT_CONT, CI_NONE, st_header } 2113544Sjbeck , {SMFIC_MAIL, CM_ARGV, ST_MAIL, CT_CONT, CI_MAIL, st_sender } 2123544Sjbeck , {SMFIC_OPTNEG, CM_ARGO, ST_OPTS, CT_CONT, CI_NONE, st_optionneg } 2133544Sjbeck , {SMFIC_EOH, CM_ARG0, ST_EOHS, CT_CONT, CI_EOH, st_eoh } 2143544Sjbeck , {SMFIC_QUIT, CM_ARG0, ST_QUIT, CT_END, CI_NONE, st_quit } 2153544Sjbeck , {SMFIC_DATA, CM_ARG0, ST_DATA, CT_CONT, CI_DATA, st_data } 2163544Sjbeck , {SMFIC_RCPT, CM_ARGV, ST_RCPT, CT_IGNO, CI_RCPT, st_rcpt } 2173544Sjbeck , {SMFIC_UNKNOWN, CM_ARG1, ST_UNKN, CT_IGNO, CI_NONE, st_unknown } 2183544Sjbeck , {SMFIC_QUIT_NC, CM_ARG0, ST_Q_NC, CT_CONT, CI_NONE, st_quit } 2190Sstevel@tonic-gate }; 2200Sstevel@tonic-gate 2213544Sjbeck /* 2223544Sjbeck ** Additional (internal) reply codes; 2233544Sjbeck ** must be coordinated wit libmilter/mfapi.h 2243544Sjbeck */ 2253544Sjbeck 2260Sstevel@tonic-gate #define _SMFIS_KEEP 20 2270Sstevel@tonic-gate #define _SMFIS_ABORT 21 2280Sstevel@tonic-gate #define _SMFIS_OPTIONS 22 2293544Sjbeck #define _SMFIS_NOREPLY SMFIS_NOREPLY 2300Sstevel@tonic-gate #define _SMFIS_FAIL (-1) 2310Sstevel@tonic-gate #define _SMFIS_NONE (-2) 2320Sstevel@tonic-gate 2330Sstevel@tonic-gate /* 2340Sstevel@tonic-gate ** MI_ENGINE -- receive commands and process them 2350Sstevel@tonic-gate ** 2360Sstevel@tonic-gate ** Parameters: 2370Sstevel@tonic-gate ** ctx -- context structure 2380Sstevel@tonic-gate ** 2390Sstevel@tonic-gate ** Returns: 2400Sstevel@tonic-gate ** MI_FAILURE/MI_SUCCESS 2410Sstevel@tonic-gate */ 2423544Sjbeck 2430Sstevel@tonic-gate int 2440Sstevel@tonic-gate mi_engine(ctx) 2450Sstevel@tonic-gate SMFICTX_PTR ctx; 2460Sstevel@tonic-gate { 2470Sstevel@tonic-gate size_t len; 2480Sstevel@tonic-gate int i; 2490Sstevel@tonic-gate socket_t sd; 2500Sstevel@tonic-gate int ret = MI_SUCCESS; 2510Sstevel@tonic-gate int ncmds = sizeof(cmds) / sizeof(cmdfct); 2520Sstevel@tonic-gate int curstate = ST_INIT; 2530Sstevel@tonic-gate int newstate; 2540Sstevel@tonic-gate bool call_abort; 2550Sstevel@tonic-gate sfsistat r; 2560Sstevel@tonic-gate char cmd; 2570Sstevel@tonic-gate char *buf = NULL; 2580Sstevel@tonic-gate genarg arg; 2590Sstevel@tonic-gate struct timeval timeout; 2600Sstevel@tonic-gate int (*f) __P((genarg *)); 2610Sstevel@tonic-gate sfsistat (*fi_abort) __P((SMFICTX *)); 2620Sstevel@tonic-gate sfsistat (*fi_close) __P((SMFICTX *)); 2630Sstevel@tonic-gate 2640Sstevel@tonic-gate arg.a_ctx = ctx; 2650Sstevel@tonic-gate sd = ctx->ctx_sd; 2660Sstevel@tonic-gate fi_abort = ctx->ctx_smfi->xxfi_abort; 2673544Sjbeck #if _FFR_WORKERS_POOL 2683544Sjbeck curstate = ctx->ctx_state; 2693544Sjbeck if (curstate == ST_INIT) 2703544Sjbeck { 2713544Sjbeck mi_clr_macros(ctx, 0); 2723544Sjbeck fix_stm(ctx); 2733544Sjbeck } 2743544Sjbeck #else /* _FFR_WORKERS_POOL */ 2750Sstevel@tonic-gate mi_clr_macros(ctx, 0); 2760Sstevel@tonic-gate fix_stm(ctx); 2773544Sjbeck #endif /* _FFR_WORKERS_POOL */ 2780Sstevel@tonic-gate r = _SMFIS_NONE; 2790Sstevel@tonic-gate do 2800Sstevel@tonic-gate { 2810Sstevel@tonic-gate /* call abort only if in a mail transaction */ 2820Sstevel@tonic-gate call_abort = ST_IN_MAIL(curstate); 2830Sstevel@tonic-gate timeout.tv_sec = ctx->ctx_timeout; 2840Sstevel@tonic-gate timeout.tv_usec = 0; 2850Sstevel@tonic-gate if (mi_stop() == MILTER_ABRT) 2860Sstevel@tonic-gate { 2870Sstevel@tonic-gate if (ctx->ctx_dbg > 3) 2883544Sjbeck sm_dprintf("[%ld] milter_abort\n", 2893544Sjbeck (long) ctx->ctx_id); 2900Sstevel@tonic-gate ret = MI_FAILURE; 2910Sstevel@tonic-gate break; 2920Sstevel@tonic-gate } 2930Sstevel@tonic-gate 2940Sstevel@tonic-gate /* 2950Sstevel@tonic-gate ** Notice: buf is allocated by mi_rd_cmd() and it will 2960Sstevel@tonic-gate ** usually be free()d after it has been used in f(). 2970Sstevel@tonic-gate ** However, if the function returns _SMFIS_KEEP then buf 2980Sstevel@tonic-gate ** contains macros and will not be free()d. 2990Sstevel@tonic-gate ** Hence r must be set to _SMFIS_NONE if a new buf is 3000Sstevel@tonic-gate ** allocated to avoid problem with housekeeping, esp. 3010Sstevel@tonic-gate ** if the code "break"s out of the loop. 3020Sstevel@tonic-gate */ 3030Sstevel@tonic-gate 3043544Sjbeck #if _FFR_WORKERS_POOL 3053544Sjbeck /* Is the socket ready to be read ??? */ 3063544Sjbeck if (!mi_rd_socket_ready(sd)) 3073544Sjbeck { 3083544Sjbeck ret = MI_CONTINUE; 3093544Sjbeck break; 3103544Sjbeck } 3113544Sjbeck #endif /* _FFR_WORKERS_POOL */ 3123544Sjbeck 3130Sstevel@tonic-gate r = _SMFIS_NONE; 3140Sstevel@tonic-gate if ((buf = mi_rd_cmd(sd, &timeout, &cmd, &len, 3150Sstevel@tonic-gate ctx->ctx_smfi->xxfi_name)) == NULL && 3160Sstevel@tonic-gate cmd < SMFIC_VALIDCMD) 3170Sstevel@tonic-gate { 3180Sstevel@tonic-gate if (ctx->ctx_dbg > 5) 3193544Sjbeck sm_dprintf("[%ld] mi_engine: mi_rd_cmd error (%x)\n", 3203544Sjbeck (long) ctx->ctx_id, (int) cmd); 3210Sstevel@tonic-gate 3220Sstevel@tonic-gate /* 3230Sstevel@tonic-gate ** eof is currently treated as failure -> 3240Sstevel@tonic-gate ** abort() instead of close(), otherwise use: 3250Sstevel@tonic-gate ** if (cmd != SMFIC_EOF) 3260Sstevel@tonic-gate */ 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate ret = MI_FAILURE; 3290Sstevel@tonic-gate break; 3300Sstevel@tonic-gate } 3310Sstevel@tonic-gate if (ctx->ctx_dbg > 4) 3323544Sjbeck sm_dprintf("[%ld] got cmd '%c' len %d\n", 3333544Sjbeck (long) ctx->ctx_id, cmd, (int) len); 3340Sstevel@tonic-gate for (i = 0; i < ncmds; i++) 3350Sstevel@tonic-gate { 3360Sstevel@tonic-gate if (cmd == cmds[i].cm_cmd) 3370Sstevel@tonic-gate break; 3380Sstevel@tonic-gate } 3390Sstevel@tonic-gate if (i >= ncmds) 3400Sstevel@tonic-gate { 3410Sstevel@tonic-gate /* unknown command */ 3420Sstevel@tonic-gate if (ctx->ctx_dbg > 1) 3433544Sjbeck sm_dprintf("[%ld] cmd '%c' unknown\n", 3443544Sjbeck (long) ctx->ctx_id, cmd); 3450Sstevel@tonic-gate ret = MI_FAILURE; 3460Sstevel@tonic-gate break; 3470Sstevel@tonic-gate } 3480Sstevel@tonic-gate if ((f = cmds[i].cm_fct) == NULL) 3490Sstevel@tonic-gate { 3500Sstevel@tonic-gate /* stop for now */ 3510Sstevel@tonic-gate if (ctx->ctx_dbg > 1) 3523544Sjbeck sm_dprintf("[%ld] cmd '%c' not impl\n", 3533544Sjbeck (long) ctx->ctx_id, cmd); 3540Sstevel@tonic-gate ret = MI_FAILURE; 3550Sstevel@tonic-gate break; 3560Sstevel@tonic-gate } 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate /* is new state ok? */ 3590Sstevel@tonic-gate newstate = cmds[i].cm_next; 3600Sstevel@tonic-gate if (ctx->ctx_dbg > 5) 3613544Sjbeck sm_dprintf("[%ld] cur %x new %x nextmask %x\n", 3623544Sjbeck (long) ctx->ctx_id, 3630Sstevel@tonic-gate curstate, newstate, next_states[curstate]); 3640Sstevel@tonic-gate 3650Sstevel@tonic-gate if (newstate != ST_NONE && !trans_ok(curstate, newstate)) 3660Sstevel@tonic-gate { 3670Sstevel@tonic-gate if (ctx->ctx_dbg > 1) 3683544Sjbeck sm_dprintf("[%ld] abort: cur %d (%x) new %d (%x) next %x\n", 3693544Sjbeck (long) ctx->ctx_id, 3700Sstevel@tonic-gate curstate, MI_MASK(curstate), 3710Sstevel@tonic-gate newstate, MI_MASK(newstate), 3720Sstevel@tonic-gate next_states[curstate]); 3730Sstevel@tonic-gate 3740Sstevel@tonic-gate /* call abort only if in a mail transaction */ 3750Sstevel@tonic-gate if (fi_abort != NULL && call_abort) 3760Sstevel@tonic-gate (void) (*fi_abort)(ctx); 3770Sstevel@tonic-gate 3780Sstevel@tonic-gate /* 3790Sstevel@tonic-gate ** try to reach the new state from HELO 3800Sstevel@tonic-gate ** if it can't be reached, ignore the command. 3810Sstevel@tonic-gate */ 3820Sstevel@tonic-gate 3830Sstevel@tonic-gate curstate = ST_HELO; 3840Sstevel@tonic-gate if (!trans_ok(curstate, newstate)) 3850Sstevel@tonic-gate { 3860Sstevel@tonic-gate if (buf != NULL) 3870Sstevel@tonic-gate { 3880Sstevel@tonic-gate free(buf); 3890Sstevel@tonic-gate buf = NULL; 3900Sstevel@tonic-gate } 3910Sstevel@tonic-gate continue; 3920Sstevel@tonic-gate } 3930Sstevel@tonic-gate } 3940Sstevel@tonic-gate arg.a_len = len; 3950Sstevel@tonic-gate arg.a_buf = buf; 3960Sstevel@tonic-gate if (newstate != ST_NONE) 3970Sstevel@tonic-gate { 3980Sstevel@tonic-gate curstate = newstate; 3990Sstevel@tonic-gate ctx->ctx_state = curstate; 4000Sstevel@tonic-gate } 4010Sstevel@tonic-gate arg.a_idx = cmds[i].cm_macros; 4020Sstevel@tonic-gate call_abort = ST_IN_MAIL(curstate); 4030Sstevel@tonic-gate 4040Sstevel@tonic-gate /* call function to deal with command */ 4053544Sjbeck MI_MONITOR_BEGIN(ctx, cmd); 4060Sstevel@tonic-gate r = (*f)(&arg); 4073544Sjbeck MI_MONITOR_END(ctx, cmd); 4080Sstevel@tonic-gate if (r != _SMFIS_KEEP && buf != NULL) 4090Sstevel@tonic-gate { 4100Sstevel@tonic-gate free(buf); 4110Sstevel@tonic-gate buf = NULL; 4120Sstevel@tonic-gate } 4130Sstevel@tonic-gate if (sendreply(r, sd, &timeout, ctx) != MI_SUCCESS) 4140Sstevel@tonic-gate { 4150Sstevel@tonic-gate ret = MI_FAILURE; 4160Sstevel@tonic-gate break; 4170Sstevel@tonic-gate } 4180Sstevel@tonic-gate 4190Sstevel@tonic-gate if (r == SMFIS_ACCEPT) 4200Sstevel@tonic-gate { 4210Sstevel@tonic-gate /* accept mail, no further actions taken */ 4220Sstevel@tonic-gate curstate = ST_HELO; 4230Sstevel@tonic-gate } 4240Sstevel@tonic-gate else if (r == SMFIS_REJECT || r == SMFIS_DISCARD || 4250Sstevel@tonic-gate r == SMFIS_TEMPFAIL) 4260Sstevel@tonic-gate { 4270Sstevel@tonic-gate /* 4280Sstevel@tonic-gate ** further actions depend on current state 4290Sstevel@tonic-gate ** if the IGNO bit is set: "ignore" the error, 4300Sstevel@tonic-gate ** i.e., stay in the current state 4310Sstevel@tonic-gate */ 4320Sstevel@tonic-gate if (!bitset(CT_IGNO, cmds[i].cm_todo)) 4330Sstevel@tonic-gate curstate = ST_HELO; 4340Sstevel@tonic-gate } 4350Sstevel@tonic-gate else if (r == _SMFIS_ABORT) 4360Sstevel@tonic-gate { 4370Sstevel@tonic-gate if (ctx->ctx_dbg > 5) 4383544Sjbeck sm_dprintf("[%ld] function returned abort\n", 4393544Sjbeck (long) ctx->ctx_id); 4400Sstevel@tonic-gate ret = MI_FAILURE; 4410Sstevel@tonic-gate break; 4420Sstevel@tonic-gate } 4430Sstevel@tonic-gate } while (!bitset(CT_END, cmds[i].cm_todo)); 4440Sstevel@tonic-gate 4453544Sjbeck ctx->ctx_state = curstate; 4463544Sjbeck 4473544Sjbeck if (ret == MI_FAILURE) 4480Sstevel@tonic-gate { 4490Sstevel@tonic-gate /* call abort only if in a mail transaction */ 4500Sstevel@tonic-gate if (fi_abort != NULL && call_abort) 4510Sstevel@tonic-gate (void) (*fi_abort)(ctx); 4520Sstevel@tonic-gate } 4530Sstevel@tonic-gate 4543544Sjbeck /* has close been called? */ 4553544Sjbeck if (ctx->ctx_state != ST_QUIT 4563544Sjbeck #if _FFR_WORKERS_POOL 4573544Sjbeck && ret != MI_CONTINUE 4583544Sjbeck #endif /* _FFR_WORKERS_POOL */ 4593544Sjbeck ) 4603544Sjbeck { 4613544Sjbeck if ((fi_close = ctx->ctx_smfi->xxfi_close) != NULL) 4623544Sjbeck (void) (*fi_close)(ctx); 4633544Sjbeck } 4640Sstevel@tonic-gate if (r != _SMFIS_KEEP && buf != NULL) 4650Sstevel@tonic-gate free(buf); 4663544Sjbeck #if !_FFR_WORKERS_POOL 4670Sstevel@tonic-gate mi_clr_macros(ctx, 0); 4683544Sjbeck #endif /* _FFR_WORKERS_POOL */ 4690Sstevel@tonic-gate return ret; 4700Sstevel@tonic-gate } 4713544Sjbeck 4723544Sjbeck static size_t milter_addsymlist __P((SMFICTX_PTR, char *, char **)); 4733544Sjbeck 4743544Sjbeck static size_t 4753544Sjbeck milter_addsymlist(ctx, buf, newbuf) 4763544Sjbeck SMFICTX_PTR ctx; 4773544Sjbeck char *buf; 4783544Sjbeck char **newbuf; 4793544Sjbeck { 4803544Sjbeck size_t len; 4813544Sjbeck int i; 4823544Sjbeck mi_int32 v; 4833544Sjbeck char *buffer; 4843544Sjbeck 4853544Sjbeck SM_ASSERT(ctx != NULL); 4863544Sjbeck SM_ASSERT(buf != NULL); 4873544Sjbeck SM_ASSERT(newbuf != NULL); 4883544Sjbeck len = 0; 4893544Sjbeck for (i = 0; i < MAX_MACROS_ENTRIES; i++) 4903544Sjbeck { 4913544Sjbeck if (ctx->ctx_mac_list[i] != NULL) 4923544Sjbeck { 4933544Sjbeck len += strlen(ctx->ctx_mac_list[i]) + 1 + 4943544Sjbeck MILTER_LEN_BYTES; 4953544Sjbeck } 4963544Sjbeck } 4973544Sjbeck if (len > 0) 4983544Sjbeck { 4993544Sjbeck size_t offset; 5003544Sjbeck 5013544Sjbeck SM_ASSERT(len + MILTER_OPTLEN > len); 5023544Sjbeck len += MILTER_OPTLEN; 5033544Sjbeck buffer = malloc(len); 5043544Sjbeck if (buffer != NULL) 5053544Sjbeck { 5063544Sjbeck (void) memcpy(buffer, buf, MILTER_OPTLEN); 5073544Sjbeck offset = MILTER_OPTLEN; 5083544Sjbeck for (i = 0; i < MAX_MACROS_ENTRIES; i++) 5093544Sjbeck { 5103544Sjbeck size_t l; 5113544Sjbeck 5123544Sjbeck if (ctx->ctx_mac_list[i] == NULL) 5133544Sjbeck continue; 5143544Sjbeck 5153544Sjbeck SM_ASSERT(offset + MILTER_LEN_BYTES < len); 5163544Sjbeck v = htonl(i); 5173544Sjbeck (void) memcpy(buffer + offset, (void *) &v, 5183544Sjbeck MILTER_LEN_BYTES); 5193544Sjbeck offset += MILTER_LEN_BYTES; 5203544Sjbeck l = strlen(ctx->ctx_mac_list[i]) + 1; 5213544Sjbeck SM_ASSERT(offset + l <= len); 5223544Sjbeck (void) memcpy(buffer + offset, 5233544Sjbeck ctx->ctx_mac_list[i], l); 5243544Sjbeck offset += l; 5253544Sjbeck } 5263544Sjbeck } 5273544Sjbeck else 5283544Sjbeck { 5293544Sjbeck /* oops ... */ 5303544Sjbeck } 5313544Sjbeck } 5323544Sjbeck else 5333544Sjbeck { 5343544Sjbeck len = MILTER_OPTLEN; 5353544Sjbeck buffer = buf; 5363544Sjbeck } 5373544Sjbeck *newbuf = buffer; 5383544Sjbeck return len; 5393544Sjbeck } 5403544Sjbeck 5413544Sjbeck /* 5423544Sjbeck ** GET_NR_BIT -- get "no reply" bit matching state 5433544Sjbeck ** 5443544Sjbeck ** Parameters: 5453544Sjbeck ** state -- current protocol stage 5463544Sjbeck ** 5473544Sjbeck ** Returns: 5483544Sjbeck ** 0: no matching bit 5493544Sjbeck ** >0: the matching "no reply" bit 5503544Sjbeck */ 5513544Sjbeck 5523544Sjbeck static unsigned long get_nr_bit __P((int)); 5533544Sjbeck 5543544Sjbeck static unsigned long 5553544Sjbeck get_nr_bit(state) 5563544Sjbeck int state; 5573544Sjbeck { 5583544Sjbeck unsigned long bit; 5593544Sjbeck 5603544Sjbeck switch (state) 5613544Sjbeck { 5623544Sjbeck case ST_CONN: 5633544Sjbeck bit = SMFIP_NR_CONN; 5643544Sjbeck break; 5653544Sjbeck case ST_HELO: 5663544Sjbeck bit = SMFIP_NR_HELO; 5673544Sjbeck break; 5683544Sjbeck case ST_MAIL: 5693544Sjbeck bit = SMFIP_NR_MAIL; 5703544Sjbeck break; 5713544Sjbeck case ST_RCPT: 5723544Sjbeck bit = SMFIP_NR_RCPT; 5733544Sjbeck break; 5743544Sjbeck case ST_DATA: 5753544Sjbeck bit = SMFIP_NR_DATA; 5763544Sjbeck break; 5773544Sjbeck case ST_UNKN: 5783544Sjbeck bit = SMFIP_NR_UNKN; 5793544Sjbeck break; 5803544Sjbeck case ST_HDRS: 5813544Sjbeck bit = SMFIP_NR_HDR; 5823544Sjbeck break; 5833544Sjbeck case ST_EOHS: 5843544Sjbeck bit = SMFIP_NR_EOH; 5853544Sjbeck break; 5863544Sjbeck case ST_BODY: 5873544Sjbeck bit = SMFIP_NR_BODY; 5883544Sjbeck break; 5893544Sjbeck default: 5903544Sjbeck bit = 0; 5913544Sjbeck break; 5923544Sjbeck } 5933544Sjbeck return bit; 5943544Sjbeck } 5953544Sjbeck 5960Sstevel@tonic-gate /* 5970Sstevel@tonic-gate ** SENDREPLY -- send a reply to the MTA 5980Sstevel@tonic-gate ** 5990Sstevel@tonic-gate ** Parameters: 6000Sstevel@tonic-gate ** r -- reply code 6010Sstevel@tonic-gate ** sd -- socket descriptor 6020Sstevel@tonic-gate ** timeout_ptr -- (ptr to) timeout to use for sending 6030Sstevel@tonic-gate ** ctx -- context structure 6040Sstevel@tonic-gate ** 6050Sstevel@tonic-gate ** Returns: 6060Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE 6070Sstevel@tonic-gate */ 6080Sstevel@tonic-gate 6090Sstevel@tonic-gate static int 6100Sstevel@tonic-gate sendreply(r, sd, timeout_ptr, ctx) 6110Sstevel@tonic-gate sfsistat r; 6120Sstevel@tonic-gate socket_t sd; 6130Sstevel@tonic-gate struct timeval *timeout_ptr; 6140Sstevel@tonic-gate SMFICTX_PTR ctx; 6150Sstevel@tonic-gate { 6163544Sjbeck int ret; 6173544Sjbeck unsigned long bit; 6183544Sjbeck 6193544Sjbeck ret = MI_SUCCESS; 6203544Sjbeck 6213544Sjbeck bit = get_nr_bit(ctx->ctx_state); 6223544Sjbeck if (bit != 0 && (ctx->ctx_pflags & bit) != 0 && r != SMFIS_NOREPLY) 6233544Sjbeck { 6243544Sjbeck if (r >= SMFIS_CONTINUE && r < _SMFIS_KEEP) 6253544Sjbeck { 6263544Sjbeck /* milter said it wouldn't reply, but it lied... */ 6273544Sjbeck smi_log(SMI_LOG_ERR, 6283544Sjbeck "%s: milter claimed not to reply in state %d but did anyway %d\n", 6293544Sjbeck ctx->ctx_smfi->xxfi_name, 6303544Sjbeck ctx->ctx_state, r); 6313544Sjbeck 6323544Sjbeck } 6333544Sjbeck 6343544Sjbeck /* 6353544Sjbeck ** Force specified behavior, otherwise libmilter 6363544Sjbeck ** and MTA will fail to communicate properly. 6373544Sjbeck */ 6383544Sjbeck 6393544Sjbeck switch (r) 6403544Sjbeck { 6413544Sjbeck case SMFIS_CONTINUE: 6423544Sjbeck case SMFIS_TEMPFAIL: 6433544Sjbeck case SMFIS_REJECT: 6443544Sjbeck case SMFIS_DISCARD: 6453544Sjbeck case SMFIS_ACCEPT: 6463544Sjbeck case SMFIS_SKIP: 6473544Sjbeck case _SMFIS_OPTIONS: 6483544Sjbeck r = SMFIS_NOREPLY; 6493544Sjbeck break; 6503544Sjbeck } 6513544Sjbeck } 6520Sstevel@tonic-gate 6530Sstevel@tonic-gate switch (r) 6540Sstevel@tonic-gate { 6550Sstevel@tonic-gate case SMFIS_CONTINUE: 6560Sstevel@tonic-gate ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_CONTINUE, NULL, 0); 6570Sstevel@tonic-gate break; 6580Sstevel@tonic-gate case SMFIS_TEMPFAIL: 6590Sstevel@tonic-gate case SMFIS_REJECT: 6600Sstevel@tonic-gate if (ctx->ctx_reply != NULL && 6610Sstevel@tonic-gate ((r == SMFIS_TEMPFAIL && *ctx->ctx_reply == '4') || 6620Sstevel@tonic-gate (r == SMFIS_REJECT && *ctx->ctx_reply == '5'))) 6630Sstevel@tonic-gate { 6640Sstevel@tonic-gate ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_REPLYCODE, 6650Sstevel@tonic-gate ctx->ctx_reply, 6660Sstevel@tonic-gate strlen(ctx->ctx_reply) + 1); 6670Sstevel@tonic-gate free(ctx->ctx_reply); 6680Sstevel@tonic-gate ctx->ctx_reply = NULL; 6690Sstevel@tonic-gate } 6700Sstevel@tonic-gate else 6710Sstevel@tonic-gate { 6720Sstevel@tonic-gate ret = mi_wr_cmd(sd, timeout_ptr, r == SMFIS_REJECT ? 6730Sstevel@tonic-gate SMFIR_REJECT : SMFIR_TEMPFAIL, NULL, 0); 6740Sstevel@tonic-gate } 6750Sstevel@tonic-gate break; 6760Sstevel@tonic-gate case SMFIS_DISCARD: 6770Sstevel@tonic-gate ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_DISCARD, NULL, 0); 6780Sstevel@tonic-gate break; 6790Sstevel@tonic-gate case SMFIS_ACCEPT: 6800Sstevel@tonic-gate ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_ACCEPT, NULL, 0); 6810Sstevel@tonic-gate break; 6823544Sjbeck case SMFIS_SKIP: 6833544Sjbeck ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_SKIP, NULL, 0); 6843544Sjbeck break; 6850Sstevel@tonic-gate case _SMFIS_OPTIONS: 6860Sstevel@tonic-gate { 6873544Sjbeck mi_int32 v; 6883544Sjbeck size_t len; 6893544Sjbeck char *buffer; 6900Sstevel@tonic-gate char buf[MILTER_OPTLEN]; 6910Sstevel@tonic-gate 6923544Sjbeck v = htonl(ctx->ctx_prot_vers2mta); 6933544Sjbeck (void) memcpy(&(buf[0]), (void *) &v, 6943544Sjbeck MILTER_LEN_BYTES); 6953544Sjbeck v = htonl(ctx->ctx_aflags); 6960Sstevel@tonic-gate (void) memcpy(&(buf[MILTER_LEN_BYTES]), (void *) &v, 6970Sstevel@tonic-gate MILTER_LEN_BYTES); 6983544Sjbeck v = htonl(ctx->ctx_pflags2mta); 6993544Sjbeck (void) memcpy(&(buf[MILTER_LEN_BYTES * 2]), 7003544Sjbeck (void *) &v, MILTER_LEN_BYTES); 7013544Sjbeck len = milter_addsymlist(ctx, buf, &buffer); 7023544Sjbeck if (buffer != NULL) 7033544Sjbeck ret = mi_wr_cmd(sd, timeout_ptr, SMFIC_OPTNEG, 7043544Sjbeck buffer, len); 7053544Sjbeck else 7063544Sjbeck ret = MI_FAILURE; 7073544Sjbeck } 7083544Sjbeck break; 7093544Sjbeck case SMFIS_NOREPLY: 7103544Sjbeck if (bit != 0 && 7113544Sjbeck (ctx->ctx_pflags & bit) != 0 && 7123544Sjbeck (ctx->ctx_mta_pflags & bit) == 0) 7133544Sjbeck { 7143544Sjbeck /* 7153544Sjbeck ** milter doesn't want to send a reply, 7163544Sjbeck ** but the MTA doesn't have that feature: fake it. 7173544Sjbeck */ 7183544Sjbeck 7193544Sjbeck ret = mi_wr_cmd(sd, timeout_ptr, SMFIR_CONTINUE, NULL, 7203544Sjbeck 0); 7210Sstevel@tonic-gate } 7220Sstevel@tonic-gate break; 7230Sstevel@tonic-gate default: /* don't send a reply */ 7240Sstevel@tonic-gate break; 7250Sstevel@tonic-gate } 7260Sstevel@tonic-gate return ret; 7270Sstevel@tonic-gate } 7280Sstevel@tonic-gate 7290Sstevel@tonic-gate /* 7300Sstevel@tonic-gate ** CLR_MACROS -- clear set of macros starting from a given index 7310Sstevel@tonic-gate ** 7320Sstevel@tonic-gate ** Parameters: 7330Sstevel@tonic-gate ** ctx -- context structure 7340Sstevel@tonic-gate ** m -- index from which to clear all macros 7350Sstevel@tonic-gate ** 7360Sstevel@tonic-gate ** Returns: 7370Sstevel@tonic-gate ** None. 7380Sstevel@tonic-gate */ 739*3966Sjbeck 7400Sstevel@tonic-gate void 7410Sstevel@tonic-gate mi_clr_macros(ctx, m) 7420Sstevel@tonic-gate SMFICTX_PTR ctx; 7430Sstevel@tonic-gate int m; 7440Sstevel@tonic-gate { 7450Sstevel@tonic-gate int i; 7460Sstevel@tonic-gate 7470Sstevel@tonic-gate for (i = m; i < MAX_MACROS_ENTRIES; i++) 7480Sstevel@tonic-gate { 7490Sstevel@tonic-gate if (ctx->ctx_mac_ptr[i] != NULL) 7500Sstevel@tonic-gate { 7510Sstevel@tonic-gate free(ctx->ctx_mac_ptr[i]); 7520Sstevel@tonic-gate ctx->ctx_mac_ptr[i] = NULL; 7530Sstevel@tonic-gate } 7540Sstevel@tonic-gate if (ctx->ctx_mac_buf[i] != NULL) 7550Sstevel@tonic-gate { 7560Sstevel@tonic-gate free(ctx->ctx_mac_buf[i]); 7570Sstevel@tonic-gate ctx->ctx_mac_buf[i] = NULL; 7580Sstevel@tonic-gate } 7590Sstevel@tonic-gate } 7600Sstevel@tonic-gate } 7613544Sjbeck 7620Sstevel@tonic-gate /* 7630Sstevel@tonic-gate ** ST_OPTIONNEG -- negotiate options 7640Sstevel@tonic-gate ** 7650Sstevel@tonic-gate ** Parameters: 7660Sstevel@tonic-gate ** g -- generic argument structure 7670Sstevel@tonic-gate ** 7680Sstevel@tonic-gate ** Returns: 7690Sstevel@tonic-gate ** abort/send options/continue 7700Sstevel@tonic-gate */ 7710Sstevel@tonic-gate 7720Sstevel@tonic-gate static int 7730Sstevel@tonic-gate st_optionneg(g) 7740Sstevel@tonic-gate genarg *g; 7750Sstevel@tonic-gate { 7763544Sjbeck mi_int32 i, v, fake_pflags; 7773544Sjbeck SMFICTX_PTR ctx; 7783544Sjbeck int (*fi_negotiate) __P((SMFICTX *, 7793544Sjbeck unsigned long, unsigned long, 7803544Sjbeck unsigned long, unsigned long, 7813544Sjbeck unsigned long *, unsigned long *, 7823544Sjbeck unsigned long *, unsigned long *)); 7830Sstevel@tonic-gate 7840Sstevel@tonic-gate if (g == NULL || g->a_ctx->ctx_smfi == NULL) 7850Sstevel@tonic-gate return SMFIS_CONTINUE; 7863544Sjbeck ctx = g->a_ctx; 7873544Sjbeck mi_clr_macros(ctx, g->a_idx + 1); 7883544Sjbeck ctx->ctx_prot_vers = SMFI_PROT_VERSION; 7890Sstevel@tonic-gate 7900Sstevel@tonic-gate /* check for minimum length */ 7910Sstevel@tonic-gate if (g->a_len < MILTER_OPTLEN) 7920Sstevel@tonic-gate { 7930Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 7943544Sjbeck "%s: st_optionneg[%ld]: len too short %d < %d", 7953544Sjbeck ctx->ctx_smfi->xxfi_name, 7963544Sjbeck (long) ctx->ctx_id, (int) g->a_len, 7970Sstevel@tonic-gate MILTER_OPTLEN); 7980Sstevel@tonic-gate return _SMFIS_ABORT; 7990Sstevel@tonic-gate } 8000Sstevel@tonic-gate 8013544Sjbeck /* protocol version */ 8023544Sjbeck (void) memcpy((void *) &i, (void *) &(g->a_buf[0]), MILTER_LEN_BYTES); 8030Sstevel@tonic-gate v = ntohl(i); 8043544Sjbeck 8053544Sjbeck #define SMFI_PROT_VERSION_MIN 2 8063544Sjbeck 8073544Sjbeck /* check for minimum version */ 8083544Sjbeck if (v < SMFI_PROT_VERSION_MIN) 8090Sstevel@tonic-gate { 8100Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 8113544Sjbeck "%s: st_optionneg[%ld]: protocol version too old %d < %d", 8123544Sjbeck ctx->ctx_smfi->xxfi_name, 8133544Sjbeck (long) ctx->ctx_id, v, SMFI_PROT_VERSION_MIN); 8140Sstevel@tonic-gate return _SMFIS_ABORT; 8150Sstevel@tonic-gate } 8163544Sjbeck ctx->ctx_mta_prot_vers = v; 8173544Sjbeck if (ctx->ctx_prot_vers < ctx->ctx_mta_prot_vers) 8183544Sjbeck ctx->ctx_prot_vers2mta = ctx->ctx_prot_vers; 8193544Sjbeck else 8203544Sjbeck ctx->ctx_prot_vers2mta = ctx->ctx_mta_prot_vers; 8210Sstevel@tonic-gate 8220Sstevel@tonic-gate (void) memcpy((void *) &i, (void *) &(g->a_buf[MILTER_LEN_BYTES]), 8230Sstevel@tonic-gate MILTER_LEN_BYTES); 8240Sstevel@tonic-gate v = ntohl(i); 8250Sstevel@tonic-gate 8260Sstevel@tonic-gate /* no flags? set to default value for V1 actions */ 8270Sstevel@tonic-gate if (v == 0) 8280Sstevel@tonic-gate v = SMFI_V1_ACTS; 8293544Sjbeck ctx->ctx_mta_aflags = v; /* MTA action flags */ 8300Sstevel@tonic-gate 8310Sstevel@tonic-gate (void) memcpy((void *) &i, (void *) &(g->a_buf[MILTER_LEN_BYTES * 2]), 8320Sstevel@tonic-gate MILTER_LEN_BYTES); 8330Sstevel@tonic-gate v = ntohl(i); 8340Sstevel@tonic-gate 8350Sstevel@tonic-gate /* no flags? set to default value for V1 protocol */ 8360Sstevel@tonic-gate if (v == 0) 8370Sstevel@tonic-gate v = SMFI_V1_PROT; 8383544Sjbeck ctx->ctx_mta_pflags = v; /* MTA protocol flags */ 8393544Sjbeck 8403544Sjbeck /* 8413544Sjbeck ** Copy flags from milter struct into libmilter context; 8423544Sjbeck ** this variable will be used later on to check whether 8433544Sjbeck ** the MTA "actions" can fulfill the milter requirements, 8443544Sjbeck ** but it may be overwritten by the negotiate callback. 8453544Sjbeck */ 8463544Sjbeck 8473544Sjbeck ctx->ctx_aflags = ctx->ctx_smfi->xxfi_flags; 8483544Sjbeck fake_pflags = SMFIP_NR_CONN 8493544Sjbeck |SMFIP_NR_HELO 8503544Sjbeck |SMFIP_NR_MAIL 8513544Sjbeck |SMFIP_NR_RCPT 8523544Sjbeck |SMFIP_NR_DATA 8533544Sjbeck |SMFIP_NR_UNKN 8543544Sjbeck |SMFIP_NR_HDR 8553544Sjbeck |SMFIP_NR_EOH 8563544Sjbeck |SMFIP_NR_BODY 8573544Sjbeck ; 8583544Sjbeck 8593544Sjbeck if (g->a_ctx->ctx_smfi != NULL && 8603544Sjbeck (fi_negotiate = g->a_ctx->ctx_smfi->xxfi_negotiate) != NULL) 8613544Sjbeck { 8623544Sjbeck int r; 8633544Sjbeck unsigned long m_aflags, m_pflags, m_f2, m_f3; 8643544Sjbeck 8653544Sjbeck /* 8663544Sjbeck ** let milter decide whether the features offered by the 8673544Sjbeck ** MTA are "good enough". 8683544Sjbeck ** Notes: 8693544Sjbeck ** - libmilter can "fake" some features (e.g., SMFIP_NR_HDR) 8703544Sjbeck ** - m_f2, m_f3 are for future extensions 8713544Sjbeck */ 8723544Sjbeck 8733544Sjbeck m_f2 = m_f3 = 0; 8743544Sjbeck m_aflags = ctx->ctx_mta_aflags; 8753544Sjbeck m_pflags = ctx->ctx_pflags; 8763544Sjbeck if ((SMFIP_SKIP & ctx->ctx_mta_pflags) != 0) 8773544Sjbeck m_pflags |= SMFIP_SKIP; 8783544Sjbeck r = fi_negotiate(g->a_ctx, 8793544Sjbeck ctx->ctx_mta_aflags, 8803544Sjbeck ctx->ctx_mta_pflags|fake_pflags, 8813544Sjbeck 0, 0, 8823544Sjbeck &m_aflags, &m_pflags, &m_f2, &m_f3); 8833544Sjbeck 8843544Sjbeck /* 8853544Sjbeck ** Types of protocol flags (pflags): 8863544Sjbeck ** 1. do NOT send protocol step X 8873544Sjbeck ** 2. MTA can do/understand something extra (SKIP, 8883544Sjbeck ** send unknown RCPTs) 8893544Sjbeck ** 3. MTA can deal with "no reply" for various protocol steps 8903544Sjbeck ** Note: this mean that it isn't possible to simply set all 8913544Sjbeck ** flags to get "everything": 8923544Sjbeck ** setting a flag of type 1 turns off a step 8933544Sjbeck ** (it should be the other way around: 8943544Sjbeck ** a flag means a protocol step can be sent) 8953544Sjbeck ** setting a flag of type 3 requires that milter 8963544Sjbeck ** never sends a reply for the corresponding step. 8973544Sjbeck ** Summary: the "negation" of protocol flags is causing 8983544Sjbeck ** problems, but at least for type 3 there is no simple 8993544Sjbeck ** solution. 9003544Sjbeck ** 9013544Sjbeck ** What should "all options" mean? 9023544Sjbeck ** send all protocol steps _except_ those for which there is 9033544Sjbeck ** no callback (currently registered in ctx_pflags) 9043544Sjbeck ** expect SKIP as return code? Yes 9053544Sjbeck ** send unknown RCPTs? No, 9063544Sjbeck ** must be explicitly requested? 9073544Sjbeck ** "no reply" for some protocol steps? No, 9083544Sjbeck ** must be explicitly requested. 9093544Sjbeck */ 9103544Sjbeck 9113544Sjbeck if (SMFIS_ALL_OPTS == r) 9123544Sjbeck { 9133544Sjbeck ctx->ctx_aflags = ctx->ctx_mta_aflags; 9143544Sjbeck ctx->ctx_pflags2mta = ctx->ctx_pflags; 9153544Sjbeck if ((SMFIP_SKIP & ctx->ctx_mta_pflags) != 0) 9163544Sjbeck ctx->ctx_pflags2mta |= SMFIP_SKIP; 9173544Sjbeck } 9183544Sjbeck else if (r != SMFIS_CONTINUE) 9193544Sjbeck { 9203544Sjbeck smi_log(SMI_LOG_ERR, 9213544Sjbeck "%s: st_optionneg[%ld]: xxfi_negotiate returned %d (protocol options=0x%lx, actions=0x%lx)", 9223544Sjbeck ctx->ctx_smfi->xxfi_name, 9233544Sjbeck (long) ctx->ctx_id, r, ctx->ctx_mta_pflags, 9243544Sjbeck ctx->ctx_mta_aflags); 9253544Sjbeck return _SMFIS_ABORT; 9263544Sjbeck } 9273544Sjbeck else 9283544Sjbeck { 9293544Sjbeck ctx->ctx_aflags = m_aflags; 9303544Sjbeck ctx->ctx_pflags = m_pflags; 9313544Sjbeck ctx->ctx_pflags2mta = m_pflags; 9323544Sjbeck } 9333544Sjbeck 9343544Sjbeck /* check whether some flags need to be "faked" */ 9353544Sjbeck i = ctx->ctx_pflags2mta; 9363544Sjbeck if ((ctx->ctx_mta_pflags & i) != i) 9373544Sjbeck { 9383544Sjbeck unsigned int idx; 9393544Sjbeck unsigned long b; 9403544Sjbeck 9413544Sjbeck /* 9423544Sjbeck ** If some behavior can be faked (set in fake_pflags), 9433544Sjbeck ** but the MTA doesn't support it, then unset 9443544Sjbeck ** that flag in the value that is sent to the MTA. 9453544Sjbeck */ 9463544Sjbeck 9473544Sjbeck for (idx = 0; idx < 32; idx++) 9483544Sjbeck { 9493544Sjbeck b = 1 << idx; 9503544Sjbeck if ((ctx->ctx_mta_pflags & b) != b && 9513544Sjbeck (fake_pflags & b) == b) 9523544Sjbeck ctx->ctx_pflags2mta &= ~b; 9533544Sjbeck } 9543544Sjbeck } 9553544Sjbeck } 9563544Sjbeck else 9573544Sjbeck { 9583544Sjbeck /* 9593544Sjbeck ** Set the protocol flags based on the values determined 9603544Sjbeck ** in mi_listener() which checked the defined callbacks. 9613544Sjbeck */ 9623544Sjbeck 9633544Sjbeck ctx->ctx_pflags2mta = ctx->ctx_pflags; 9643544Sjbeck } 9653544Sjbeck 9663544Sjbeck /* check whether actions and protocol requirements can be satisfied */ 9673544Sjbeck i = ctx->ctx_aflags; 9683544Sjbeck if ((i & ctx->ctx_mta_aflags) != i) 9690Sstevel@tonic-gate { 9700Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 9713544Sjbeck "%s: st_optionneg[%ld]: 0x%lx does not fulfill action requirements 0x%x", 9723544Sjbeck ctx->ctx_smfi->xxfi_name, 9733544Sjbeck (long) ctx->ctx_id, ctx->ctx_mta_aflags, i); 9740Sstevel@tonic-gate return _SMFIS_ABORT; 9750Sstevel@tonic-gate } 9760Sstevel@tonic-gate 9773544Sjbeck i = ctx->ctx_pflags2mta; 9783544Sjbeck if ((ctx->ctx_mta_pflags & i) != i) 9793544Sjbeck { 9803544Sjbeck /* 9813544Sjbeck ** Older MTAs do not support some protocol steps. 9823544Sjbeck ** As this protocol is a bit "wierd" (it asks for steps 9833544Sjbeck ** NOT to be taken/sent) we have to check whether we 9843544Sjbeck ** should turn off those "negative" requests. 9853544Sjbeck ** Currently these are only SMFIP_NODATA and SMFIP_NOUNKNOWN. 9863544Sjbeck */ 9873544Sjbeck 9883544Sjbeck if (bitset(SMFIP_NODATA, ctx->ctx_pflags2mta) && 9893544Sjbeck !bitset(SMFIP_NODATA, ctx->ctx_mta_pflags)) 9903544Sjbeck ctx->ctx_pflags2mta &= ~SMFIP_NODATA; 9913544Sjbeck if (bitset(SMFIP_NOUNKNOWN, ctx->ctx_pflags2mta) && 9923544Sjbeck !bitset(SMFIP_NOUNKNOWN, ctx->ctx_mta_pflags)) 9933544Sjbeck ctx->ctx_pflags2mta &= ~SMFIP_NOUNKNOWN; 9943544Sjbeck i = ctx->ctx_pflags2mta; 9953544Sjbeck } 9963544Sjbeck 9973544Sjbeck if ((ctx->ctx_mta_pflags & i) != i) 9983544Sjbeck { 9993544Sjbeck smi_log(SMI_LOG_ERR, 10003544Sjbeck "%s: st_optionneg[%ld]: 0x%lx does not fulfill protocol requirements 0x%x", 10013544Sjbeck ctx->ctx_smfi->xxfi_name, 10023544Sjbeck (long) ctx->ctx_id, ctx->ctx_mta_pflags, i); 10033544Sjbeck return _SMFIS_ABORT; 10043544Sjbeck } 10053544Sjbeck 10063544Sjbeck if (ctx->ctx_dbg > 3) 10073544Sjbeck sm_dprintf("[%ld] milter_negotiate:" 10083544Sjbeck " mta_actions=0x%lx, mta_flags=0x%lx" 10093544Sjbeck " actions=0x%lx, flags=0x%lx\n" 10103544Sjbeck , (long) ctx->ctx_id 10113544Sjbeck , ctx->ctx_mta_aflags, ctx->ctx_mta_pflags 10123544Sjbeck , ctx->ctx_aflags, ctx->ctx_pflags); 10133544Sjbeck 10140Sstevel@tonic-gate return _SMFIS_OPTIONS; 10150Sstevel@tonic-gate } 10163544Sjbeck 10170Sstevel@tonic-gate /* 10180Sstevel@tonic-gate ** ST_CONNECTINFO -- receive connection information 10190Sstevel@tonic-gate ** 10200Sstevel@tonic-gate ** Parameters: 10210Sstevel@tonic-gate ** g -- generic argument structure 10220Sstevel@tonic-gate ** 10230Sstevel@tonic-gate ** Returns: 10240Sstevel@tonic-gate ** continue or filter-specified value 10250Sstevel@tonic-gate */ 10260Sstevel@tonic-gate 10270Sstevel@tonic-gate static int 10280Sstevel@tonic-gate st_connectinfo(g) 10290Sstevel@tonic-gate genarg *g; 10300Sstevel@tonic-gate { 10310Sstevel@tonic-gate size_t l; 10320Sstevel@tonic-gate size_t i; 10330Sstevel@tonic-gate char *s, family; 10340Sstevel@tonic-gate unsigned short port = 0; 10350Sstevel@tonic-gate _SOCK_ADDR sockaddr; 10360Sstevel@tonic-gate sfsistat (*fi_connect) __P((SMFICTX *, char *, _SOCK_ADDR *)); 10370Sstevel@tonic-gate 10380Sstevel@tonic-gate if (g == NULL) 10390Sstevel@tonic-gate return _SMFIS_ABORT; 10400Sstevel@tonic-gate mi_clr_macros(g->a_ctx, g->a_idx + 1); 10410Sstevel@tonic-gate if (g->a_ctx->ctx_smfi == NULL || 10420Sstevel@tonic-gate (fi_connect = g->a_ctx->ctx_smfi->xxfi_connect) == NULL) 10430Sstevel@tonic-gate return SMFIS_CONTINUE; 10440Sstevel@tonic-gate 10450Sstevel@tonic-gate s = g->a_buf; 10460Sstevel@tonic-gate i = 0; 10470Sstevel@tonic-gate l = g->a_len; 10480Sstevel@tonic-gate while (s[i] != '\0' && i <= l) 10490Sstevel@tonic-gate ++i; 10500Sstevel@tonic-gate if (i + 1 >= l) 10510Sstevel@tonic-gate return _SMFIS_ABORT; 10520Sstevel@tonic-gate 10530Sstevel@tonic-gate /* Move past trailing \0 in host string */ 10540Sstevel@tonic-gate i++; 10550Sstevel@tonic-gate family = s[i++]; 10560Sstevel@tonic-gate (void) memset(&sockaddr, '\0', sizeof sockaddr); 10570Sstevel@tonic-gate if (family != SMFIA_UNKNOWN) 10580Sstevel@tonic-gate { 10590Sstevel@tonic-gate if (i + sizeof port >= l) 10600Sstevel@tonic-gate { 10610Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 10623544Sjbeck "%s: connect[%ld]: wrong len %d >= %d", 10630Sstevel@tonic-gate g->a_ctx->ctx_smfi->xxfi_name, 10643544Sjbeck (long) g->a_ctx->ctx_id, (int) i, (int) l); 10650Sstevel@tonic-gate return _SMFIS_ABORT; 10660Sstevel@tonic-gate } 10670Sstevel@tonic-gate (void) memcpy((void *) &port, (void *) (s + i), 10680Sstevel@tonic-gate sizeof port); 10690Sstevel@tonic-gate i += sizeof port; 10700Sstevel@tonic-gate 10710Sstevel@tonic-gate /* make sure string is terminated */ 10720Sstevel@tonic-gate if (s[l - 1] != '\0') 10730Sstevel@tonic-gate return _SMFIS_ABORT; 10740Sstevel@tonic-gate # if NETINET 10750Sstevel@tonic-gate if (family == SMFIA_INET) 10760Sstevel@tonic-gate { 10770Sstevel@tonic-gate if (inet_aton(s + i, (struct in_addr *) &sockaddr.sin.sin_addr) 10780Sstevel@tonic-gate != 1) 10790Sstevel@tonic-gate { 10800Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 10813544Sjbeck "%s: connect[%ld]: inet_aton failed", 10820Sstevel@tonic-gate g->a_ctx->ctx_smfi->xxfi_name, 10833544Sjbeck (long) g->a_ctx->ctx_id); 10840Sstevel@tonic-gate return _SMFIS_ABORT; 10850Sstevel@tonic-gate } 10860Sstevel@tonic-gate sockaddr.sa.sa_family = AF_INET; 10870Sstevel@tonic-gate if (port > 0) 10880Sstevel@tonic-gate sockaddr.sin.sin_port = port; 10890Sstevel@tonic-gate } 10900Sstevel@tonic-gate else 10910Sstevel@tonic-gate # endif /* NETINET */ 10920Sstevel@tonic-gate # if NETINET6 10930Sstevel@tonic-gate if (family == SMFIA_INET6) 10940Sstevel@tonic-gate { 10950Sstevel@tonic-gate if (mi_inet_pton(AF_INET6, s + i, 10960Sstevel@tonic-gate &sockaddr.sin6.sin6_addr) != 1) 10970Sstevel@tonic-gate { 10980Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 10993544Sjbeck "%s: connect[%ld]: mi_inet_pton failed", 11000Sstevel@tonic-gate g->a_ctx->ctx_smfi->xxfi_name, 11013544Sjbeck (long) g->a_ctx->ctx_id); 11020Sstevel@tonic-gate return _SMFIS_ABORT; 11030Sstevel@tonic-gate } 11040Sstevel@tonic-gate sockaddr.sa.sa_family = AF_INET6; 11050Sstevel@tonic-gate if (port > 0) 11060Sstevel@tonic-gate sockaddr.sin6.sin6_port = port; 11070Sstevel@tonic-gate } 11080Sstevel@tonic-gate else 11090Sstevel@tonic-gate # endif /* NETINET6 */ 11100Sstevel@tonic-gate # if NETUNIX 11110Sstevel@tonic-gate if (family == SMFIA_UNIX) 11120Sstevel@tonic-gate { 11130Sstevel@tonic-gate if (sm_strlcpy(sockaddr.sunix.sun_path, s + i, 11140Sstevel@tonic-gate sizeof sockaddr.sunix.sun_path) >= 11150Sstevel@tonic-gate sizeof sockaddr.sunix.sun_path) 11160Sstevel@tonic-gate { 11170Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 11183544Sjbeck "%s: connect[%ld]: path too long", 11190Sstevel@tonic-gate g->a_ctx->ctx_smfi->xxfi_name, 11203544Sjbeck (long) g->a_ctx->ctx_id); 11210Sstevel@tonic-gate return _SMFIS_ABORT; 11220Sstevel@tonic-gate } 11230Sstevel@tonic-gate sockaddr.sunix.sun_family = AF_UNIX; 11240Sstevel@tonic-gate } 11250Sstevel@tonic-gate else 11260Sstevel@tonic-gate # endif /* NETUNIX */ 11270Sstevel@tonic-gate { 11280Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 11293544Sjbeck "%s: connect[%ld]: unknown family %d", 11300Sstevel@tonic-gate g->a_ctx->ctx_smfi->xxfi_name, 11313544Sjbeck (long) g->a_ctx->ctx_id, family); 11320Sstevel@tonic-gate return _SMFIS_ABORT; 11330Sstevel@tonic-gate } 11340Sstevel@tonic-gate } 11350Sstevel@tonic-gate return (*fi_connect)(g->a_ctx, g->a_buf, 11360Sstevel@tonic-gate family != SMFIA_UNKNOWN ? &sockaddr : NULL); 11370Sstevel@tonic-gate } 11380Sstevel@tonic-gate 11390Sstevel@tonic-gate /* 11400Sstevel@tonic-gate ** ST_EOH -- end of headers 11410Sstevel@tonic-gate ** 11420Sstevel@tonic-gate ** Parameters: 11430Sstevel@tonic-gate ** g -- generic argument structure 11440Sstevel@tonic-gate ** 11450Sstevel@tonic-gate ** Returns: 11460Sstevel@tonic-gate ** continue or filter-specified value 11470Sstevel@tonic-gate */ 11480Sstevel@tonic-gate 11490Sstevel@tonic-gate static int 11500Sstevel@tonic-gate st_eoh(g) 11510Sstevel@tonic-gate genarg *g; 11520Sstevel@tonic-gate { 11530Sstevel@tonic-gate sfsistat (*fi_eoh) __P((SMFICTX *)); 11540Sstevel@tonic-gate 11550Sstevel@tonic-gate if (g == NULL) 11560Sstevel@tonic-gate return _SMFIS_ABORT; 11570Sstevel@tonic-gate if (g->a_ctx->ctx_smfi != NULL && 11580Sstevel@tonic-gate (fi_eoh = g->a_ctx->ctx_smfi->xxfi_eoh) != NULL) 11590Sstevel@tonic-gate return (*fi_eoh)(g->a_ctx); 11600Sstevel@tonic-gate return SMFIS_CONTINUE; 11610Sstevel@tonic-gate } 11620Sstevel@tonic-gate 11630Sstevel@tonic-gate /* 11640Sstevel@tonic-gate ** ST_DATA -- DATA command 11650Sstevel@tonic-gate ** 11660Sstevel@tonic-gate ** Parameters: 11670Sstevel@tonic-gate ** g -- generic argument structure 11680Sstevel@tonic-gate ** 11690Sstevel@tonic-gate ** Returns: 11700Sstevel@tonic-gate ** continue or filter-specified value 11710Sstevel@tonic-gate */ 11720Sstevel@tonic-gate 11730Sstevel@tonic-gate static int 11740Sstevel@tonic-gate st_data(g) 11750Sstevel@tonic-gate genarg *g; 11760Sstevel@tonic-gate { 11770Sstevel@tonic-gate sfsistat (*fi_data) __P((SMFICTX *)); 11780Sstevel@tonic-gate 11790Sstevel@tonic-gate if (g == NULL) 11800Sstevel@tonic-gate return _SMFIS_ABORT; 11810Sstevel@tonic-gate if (g->a_ctx->ctx_smfi != NULL && 11820Sstevel@tonic-gate (fi_data = g->a_ctx->ctx_smfi->xxfi_data) != NULL) 11830Sstevel@tonic-gate return (*fi_data)(g->a_ctx); 11840Sstevel@tonic-gate return SMFIS_CONTINUE; 11850Sstevel@tonic-gate } 11860Sstevel@tonic-gate 11870Sstevel@tonic-gate /* 11880Sstevel@tonic-gate ** ST_HELO -- helo/ehlo command 11890Sstevel@tonic-gate ** 11900Sstevel@tonic-gate ** Parameters: 11910Sstevel@tonic-gate ** g -- generic argument structure 11920Sstevel@tonic-gate ** 11930Sstevel@tonic-gate ** Returns: 11940Sstevel@tonic-gate ** continue or filter-specified value 11950Sstevel@tonic-gate */ 1196*3966Sjbeck 11970Sstevel@tonic-gate static int 11980Sstevel@tonic-gate st_helo(g) 11990Sstevel@tonic-gate genarg *g; 12000Sstevel@tonic-gate { 12010Sstevel@tonic-gate sfsistat (*fi_helo) __P((SMFICTX *, char *)); 12020Sstevel@tonic-gate 12030Sstevel@tonic-gate if (g == NULL) 12040Sstevel@tonic-gate return _SMFIS_ABORT; 12050Sstevel@tonic-gate mi_clr_macros(g->a_ctx, g->a_idx + 1); 12060Sstevel@tonic-gate if (g->a_ctx->ctx_smfi != NULL && 12070Sstevel@tonic-gate (fi_helo = g->a_ctx->ctx_smfi->xxfi_helo) != NULL) 12080Sstevel@tonic-gate { 12090Sstevel@tonic-gate /* paranoia: check for terminating '\0' */ 12100Sstevel@tonic-gate if (g->a_len == 0 || g->a_buf[g->a_len - 1] != '\0') 12110Sstevel@tonic-gate return MI_FAILURE; 12120Sstevel@tonic-gate return (*fi_helo)(g->a_ctx, g->a_buf); 12130Sstevel@tonic-gate } 12140Sstevel@tonic-gate return SMFIS_CONTINUE; 12150Sstevel@tonic-gate } 1216*3966Sjbeck 12170Sstevel@tonic-gate /* 12180Sstevel@tonic-gate ** ST_HEADER -- header line 12190Sstevel@tonic-gate ** 12200Sstevel@tonic-gate ** Parameters: 12210Sstevel@tonic-gate ** g -- generic argument structure 12220Sstevel@tonic-gate ** 12230Sstevel@tonic-gate ** Returns: 12240Sstevel@tonic-gate ** continue or filter-specified value 12250Sstevel@tonic-gate */ 12260Sstevel@tonic-gate 12270Sstevel@tonic-gate static int 12280Sstevel@tonic-gate st_header(g) 12290Sstevel@tonic-gate genarg *g; 12300Sstevel@tonic-gate { 12310Sstevel@tonic-gate char *hf, *hv; 12320Sstevel@tonic-gate sfsistat (*fi_header) __P((SMFICTX *, char *, char *)); 12330Sstevel@tonic-gate 12340Sstevel@tonic-gate if (g == NULL) 12350Sstevel@tonic-gate return _SMFIS_ABORT; 12360Sstevel@tonic-gate if (g->a_ctx->ctx_smfi == NULL || 12370Sstevel@tonic-gate (fi_header = g->a_ctx->ctx_smfi->xxfi_header) == NULL) 12380Sstevel@tonic-gate return SMFIS_CONTINUE; 12390Sstevel@tonic-gate if (dec_arg2(g->a_buf, g->a_len, &hf, &hv) == MI_SUCCESS) 12400Sstevel@tonic-gate return (*fi_header)(g->a_ctx, hf, hv); 12410Sstevel@tonic-gate else 12420Sstevel@tonic-gate return _SMFIS_ABORT; 12430Sstevel@tonic-gate } 12440Sstevel@tonic-gate 12450Sstevel@tonic-gate #define ARGV_FCT(lf, rf, idx) \ 12460Sstevel@tonic-gate char **argv; \ 12470Sstevel@tonic-gate sfsistat (*lf) __P((SMFICTX *, char **)); \ 12480Sstevel@tonic-gate int r; \ 12490Sstevel@tonic-gate \ 12500Sstevel@tonic-gate if (g == NULL) \ 12510Sstevel@tonic-gate return _SMFIS_ABORT; \ 12520Sstevel@tonic-gate mi_clr_macros(g->a_ctx, g->a_idx + 1); \ 12530Sstevel@tonic-gate if (g->a_ctx->ctx_smfi == NULL || \ 12540Sstevel@tonic-gate (lf = g->a_ctx->ctx_smfi->rf) == NULL) \ 12550Sstevel@tonic-gate return SMFIS_CONTINUE; \ 12560Sstevel@tonic-gate if ((argv = dec_argv(g->a_buf, g->a_len)) == NULL) \ 12570Sstevel@tonic-gate return _SMFIS_ABORT; \ 12580Sstevel@tonic-gate r = (*lf)(g->a_ctx, argv); \ 12590Sstevel@tonic-gate free(argv); \ 12600Sstevel@tonic-gate return r; 12610Sstevel@tonic-gate 12620Sstevel@tonic-gate /* 12630Sstevel@tonic-gate ** ST_SENDER -- MAIL FROM command 12640Sstevel@tonic-gate ** 12650Sstevel@tonic-gate ** Parameters: 12660Sstevel@tonic-gate ** g -- generic argument structure 12670Sstevel@tonic-gate ** 12680Sstevel@tonic-gate ** Returns: 12690Sstevel@tonic-gate ** continue or filter-specified value 12700Sstevel@tonic-gate */ 12710Sstevel@tonic-gate 12720Sstevel@tonic-gate static int 12730Sstevel@tonic-gate st_sender(g) 12740Sstevel@tonic-gate genarg *g; 12750Sstevel@tonic-gate { 12760Sstevel@tonic-gate ARGV_FCT(fi_envfrom, xxfi_envfrom, CI_MAIL) 12770Sstevel@tonic-gate } 12783544Sjbeck 12790Sstevel@tonic-gate /* 12800Sstevel@tonic-gate ** ST_RCPT -- RCPT TO command 12810Sstevel@tonic-gate ** 12820Sstevel@tonic-gate ** Parameters: 12830Sstevel@tonic-gate ** g -- generic argument structure 12840Sstevel@tonic-gate ** 12850Sstevel@tonic-gate ** Returns: 12860Sstevel@tonic-gate ** continue or filter-specified value 12870Sstevel@tonic-gate */ 12880Sstevel@tonic-gate 12890Sstevel@tonic-gate static int 12900Sstevel@tonic-gate st_rcpt(g) 12910Sstevel@tonic-gate genarg *g; 12920Sstevel@tonic-gate { 12930Sstevel@tonic-gate ARGV_FCT(fi_envrcpt, xxfi_envrcpt, CI_RCPT) 12940Sstevel@tonic-gate } 12950Sstevel@tonic-gate 12960Sstevel@tonic-gate /* 12970Sstevel@tonic-gate ** ST_UNKNOWN -- unrecognized or unimplemented command 12980Sstevel@tonic-gate ** 12990Sstevel@tonic-gate ** Parameters: 13000Sstevel@tonic-gate ** g -- generic argument structure 13010Sstevel@tonic-gate ** 13020Sstevel@tonic-gate ** Returns: 13030Sstevel@tonic-gate ** continue or filter-specified value 13040Sstevel@tonic-gate */ 13050Sstevel@tonic-gate 13060Sstevel@tonic-gate static int 13070Sstevel@tonic-gate st_unknown(g) 13080Sstevel@tonic-gate genarg *g; 13090Sstevel@tonic-gate { 13103544Sjbeck sfsistat (*fi_unknown) __P((SMFICTX *, const char *)); 13110Sstevel@tonic-gate 13120Sstevel@tonic-gate if (g == NULL) 13130Sstevel@tonic-gate return _SMFIS_ABORT; 13140Sstevel@tonic-gate if (g->a_ctx->ctx_smfi != NULL && 13150Sstevel@tonic-gate (fi_unknown = g->a_ctx->ctx_smfi->xxfi_unknown) != NULL) 13163544Sjbeck return (*fi_unknown)(g->a_ctx, (const char *) g->a_buf); 13170Sstevel@tonic-gate return SMFIS_CONTINUE; 13180Sstevel@tonic-gate } 13190Sstevel@tonic-gate 13200Sstevel@tonic-gate /* 13210Sstevel@tonic-gate ** ST_MACROS -- deal with macros received from the MTA 13220Sstevel@tonic-gate ** 13230Sstevel@tonic-gate ** Parameters: 13240Sstevel@tonic-gate ** g -- generic argument structure 13250Sstevel@tonic-gate ** 13260Sstevel@tonic-gate ** Returns: 13270Sstevel@tonic-gate ** continue/keep 13280Sstevel@tonic-gate ** 13290Sstevel@tonic-gate ** Side effects: 13300Sstevel@tonic-gate ** set pointer in macro array to current values. 13310Sstevel@tonic-gate */ 13320Sstevel@tonic-gate 13330Sstevel@tonic-gate static int 13340Sstevel@tonic-gate st_macros(g) 13350Sstevel@tonic-gate genarg *g; 13360Sstevel@tonic-gate { 13370Sstevel@tonic-gate int i; 13380Sstevel@tonic-gate char **argv; 13390Sstevel@tonic-gate 13400Sstevel@tonic-gate if (g == NULL || g->a_len < 1) 13410Sstevel@tonic-gate return _SMFIS_FAIL; 13420Sstevel@tonic-gate if ((argv = dec_argv(g->a_buf + 1, g->a_len - 1)) == NULL) 13430Sstevel@tonic-gate return _SMFIS_FAIL; 13440Sstevel@tonic-gate switch (g->a_buf[0]) 13450Sstevel@tonic-gate { 13460Sstevel@tonic-gate case SMFIC_CONNECT: 13470Sstevel@tonic-gate i = CI_CONN; 13480Sstevel@tonic-gate break; 13490Sstevel@tonic-gate case SMFIC_HELO: 13500Sstevel@tonic-gate i = CI_HELO; 13510Sstevel@tonic-gate break; 13520Sstevel@tonic-gate case SMFIC_MAIL: 13530Sstevel@tonic-gate i = CI_MAIL; 13540Sstevel@tonic-gate break; 13550Sstevel@tonic-gate case SMFIC_RCPT: 13560Sstevel@tonic-gate i = CI_RCPT; 13570Sstevel@tonic-gate break; 13583544Sjbeck case SMFIC_DATA: 13593544Sjbeck i = CI_DATA; 13603544Sjbeck break; 13610Sstevel@tonic-gate case SMFIC_BODYEOB: 13620Sstevel@tonic-gate i = CI_EOM; 13630Sstevel@tonic-gate break; 13643544Sjbeck case SMFIC_EOH: 13653544Sjbeck i = CI_EOH; 13663544Sjbeck break; 13670Sstevel@tonic-gate default: 13680Sstevel@tonic-gate free(argv); 13690Sstevel@tonic-gate return _SMFIS_FAIL; 13700Sstevel@tonic-gate } 13710Sstevel@tonic-gate if (g->a_ctx->ctx_mac_ptr[i] != NULL) 13720Sstevel@tonic-gate free(g->a_ctx->ctx_mac_ptr[i]); 13730Sstevel@tonic-gate if (g->a_ctx->ctx_mac_buf[i] != NULL) 13740Sstevel@tonic-gate free(g->a_ctx->ctx_mac_buf[i]); 13750Sstevel@tonic-gate g->a_ctx->ctx_mac_ptr[i] = argv; 13760Sstevel@tonic-gate g->a_ctx->ctx_mac_buf[i] = g->a_buf; 13770Sstevel@tonic-gate return _SMFIS_KEEP; 13780Sstevel@tonic-gate } 1379*3966Sjbeck 13800Sstevel@tonic-gate /* 13810Sstevel@tonic-gate ** ST_QUIT -- quit command 13820Sstevel@tonic-gate ** 13830Sstevel@tonic-gate ** Parameters: 13840Sstevel@tonic-gate ** g -- generic argument structure 13850Sstevel@tonic-gate ** 13860Sstevel@tonic-gate ** Returns: 13870Sstevel@tonic-gate ** noreply 13880Sstevel@tonic-gate */ 13890Sstevel@tonic-gate 13900Sstevel@tonic-gate /* ARGSUSED */ 13910Sstevel@tonic-gate static int 13920Sstevel@tonic-gate st_quit(g) 13930Sstevel@tonic-gate genarg *g; 13940Sstevel@tonic-gate { 13953544Sjbeck sfsistat (*fi_close) __P((SMFICTX *)); 13963544Sjbeck 13973544Sjbeck if (g == NULL) 13983544Sjbeck return _SMFIS_ABORT; 13993544Sjbeck if (g->a_ctx->ctx_smfi != NULL && 14003544Sjbeck (fi_close = g->a_ctx->ctx_smfi->xxfi_close) != NULL) 14013544Sjbeck (void) (*fi_close)(g->a_ctx); 14023544Sjbeck mi_clr_macros(g->a_ctx, 0); 14030Sstevel@tonic-gate return _SMFIS_NOREPLY; 14040Sstevel@tonic-gate } 1405*3966Sjbeck 14060Sstevel@tonic-gate /* 14070Sstevel@tonic-gate ** ST_BODYCHUNK -- deal with a piece of the mail body 14080Sstevel@tonic-gate ** 14090Sstevel@tonic-gate ** Parameters: 14100Sstevel@tonic-gate ** g -- generic argument structure 14110Sstevel@tonic-gate ** 14120Sstevel@tonic-gate ** Returns: 14130Sstevel@tonic-gate ** continue or filter-specified value 14140Sstevel@tonic-gate */ 14150Sstevel@tonic-gate 14160Sstevel@tonic-gate static int 14170Sstevel@tonic-gate st_bodychunk(g) 14180Sstevel@tonic-gate genarg *g; 14190Sstevel@tonic-gate { 14200Sstevel@tonic-gate sfsistat (*fi_body) __P((SMFICTX *, unsigned char *, size_t)); 14210Sstevel@tonic-gate 14220Sstevel@tonic-gate if (g == NULL) 14230Sstevel@tonic-gate return _SMFIS_ABORT; 14240Sstevel@tonic-gate if (g->a_ctx->ctx_smfi != NULL && 14250Sstevel@tonic-gate (fi_body = g->a_ctx->ctx_smfi->xxfi_body) != NULL) 14260Sstevel@tonic-gate return (*fi_body)(g->a_ctx, (unsigned char *)g->a_buf, 14270Sstevel@tonic-gate g->a_len); 14280Sstevel@tonic-gate return SMFIS_CONTINUE; 14290Sstevel@tonic-gate } 1430*3966Sjbeck 14310Sstevel@tonic-gate /* 14320Sstevel@tonic-gate ** ST_BODYEND -- deal with the last piece of the mail body 14330Sstevel@tonic-gate ** 14340Sstevel@tonic-gate ** Parameters: 14350Sstevel@tonic-gate ** g -- generic argument structure 14360Sstevel@tonic-gate ** 14370Sstevel@tonic-gate ** Returns: 14380Sstevel@tonic-gate ** continue or filter-specified value 14390Sstevel@tonic-gate ** 14400Sstevel@tonic-gate ** Side effects: 14410Sstevel@tonic-gate ** sends a reply for the body part (if non-empty). 14420Sstevel@tonic-gate */ 14430Sstevel@tonic-gate 14440Sstevel@tonic-gate static int 14450Sstevel@tonic-gate st_bodyend(g) 14460Sstevel@tonic-gate genarg *g; 14470Sstevel@tonic-gate { 14480Sstevel@tonic-gate sfsistat r; 14490Sstevel@tonic-gate sfsistat (*fi_body) __P((SMFICTX *, unsigned char *, size_t)); 14500Sstevel@tonic-gate sfsistat (*fi_eom) __P((SMFICTX *)); 14510Sstevel@tonic-gate 14520Sstevel@tonic-gate if (g == NULL) 14530Sstevel@tonic-gate return _SMFIS_ABORT; 14540Sstevel@tonic-gate r = SMFIS_CONTINUE; 14550Sstevel@tonic-gate if (g->a_ctx->ctx_smfi != NULL) 14560Sstevel@tonic-gate { 14570Sstevel@tonic-gate if ((fi_body = g->a_ctx->ctx_smfi->xxfi_body) != NULL && 14580Sstevel@tonic-gate g->a_len > 0) 14590Sstevel@tonic-gate { 14600Sstevel@tonic-gate socket_t sd; 14610Sstevel@tonic-gate struct timeval timeout; 14620Sstevel@tonic-gate 14630Sstevel@tonic-gate timeout.tv_sec = g->a_ctx->ctx_timeout; 14640Sstevel@tonic-gate timeout.tv_usec = 0; 14650Sstevel@tonic-gate sd = g->a_ctx->ctx_sd; 14660Sstevel@tonic-gate r = (*fi_body)(g->a_ctx, (unsigned char *)g->a_buf, 14670Sstevel@tonic-gate g->a_len); 14680Sstevel@tonic-gate if (r != SMFIS_CONTINUE && 14690Sstevel@tonic-gate sendreply(r, sd, &timeout, g->a_ctx) != MI_SUCCESS) 14700Sstevel@tonic-gate return _SMFIS_ABORT; 14710Sstevel@tonic-gate } 14720Sstevel@tonic-gate } 14730Sstevel@tonic-gate if (r == SMFIS_CONTINUE && 14740Sstevel@tonic-gate (fi_eom = g->a_ctx->ctx_smfi->xxfi_eom) != NULL) 14750Sstevel@tonic-gate return (*fi_eom)(g->a_ctx); 14760Sstevel@tonic-gate return r; 14770Sstevel@tonic-gate } 1478*3966Sjbeck 14790Sstevel@tonic-gate /* 14800Sstevel@tonic-gate ** ST_ABORTFCT -- deal with aborts 14810Sstevel@tonic-gate ** 14820Sstevel@tonic-gate ** Parameters: 14830Sstevel@tonic-gate ** g -- generic argument structure 14840Sstevel@tonic-gate ** 14850Sstevel@tonic-gate ** Returns: 14860Sstevel@tonic-gate ** abort or filter-specified value 14870Sstevel@tonic-gate */ 14880Sstevel@tonic-gate 14890Sstevel@tonic-gate static int 14900Sstevel@tonic-gate st_abortfct(g) 14910Sstevel@tonic-gate genarg *g; 14920Sstevel@tonic-gate { 14930Sstevel@tonic-gate sfsistat (*fi_abort) __P((SMFICTX *)); 14940Sstevel@tonic-gate 14950Sstevel@tonic-gate if (g == NULL) 14960Sstevel@tonic-gate return _SMFIS_ABORT; 14970Sstevel@tonic-gate if (g != NULL && g->a_ctx->ctx_smfi != NULL && 14980Sstevel@tonic-gate (fi_abort = g->a_ctx->ctx_smfi->xxfi_abort) != NULL) 14990Sstevel@tonic-gate (void) (*fi_abort)(g->a_ctx); 15000Sstevel@tonic-gate return _SMFIS_NOREPLY; 15010Sstevel@tonic-gate } 1502*3966Sjbeck 15030Sstevel@tonic-gate /* 15040Sstevel@tonic-gate ** TRANS_OK -- is the state transition ok? 15050Sstevel@tonic-gate ** 15060Sstevel@tonic-gate ** Parameters: 15070Sstevel@tonic-gate ** old -- old state 15080Sstevel@tonic-gate ** new -- new state 15090Sstevel@tonic-gate ** 15100Sstevel@tonic-gate ** Returns: 15110Sstevel@tonic-gate ** state transition ok 15120Sstevel@tonic-gate */ 15130Sstevel@tonic-gate 15140Sstevel@tonic-gate static bool 15150Sstevel@tonic-gate trans_ok(old, new) 15160Sstevel@tonic-gate int old, new; 15170Sstevel@tonic-gate { 15180Sstevel@tonic-gate int s, n; 15190Sstevel@tonic-gate 15200Sstevel@tonic-gate s = old; 15212197Sjbeck if (s >= SIZE_NEXT_STATES) 15222197Sjbeck return false; 15230Sstevel@tonic-gate do 15240Sstevel@tonic-gate { 15250Sstevel@tonic-gate /* is this state transition allowed? */ 15260Sstevel@tonic-gate if ((MI_MASK(new) & next_states[s]) != 0) 15270Sstevel@tonic-gate return true; 15280Sstevel@tonic-gate 15290Sstevel@tonic-gate /* 15300Sstevel@tonic-gate ** no: try next state; 15310Sstevel@tonic-gate ** this works since the relevant states are ordered 15320Sstevel@tonic-gate ** strict sequentially 15330Sstevel@tonic-gate */ 15340Sstevel@tonic-gate 15350Sstevel@tonic-gate n = s + 1; 15362197Sjbeck if (n >= SIZE_NEXT_STATES) 15372197Sjbeck return false; 15380Sstevel@tonic-gate 15390Sstevel@tonic-gate /* 15400Sstevel@tonic-gate ** can we actually "skip" this state? 15410Sstevel@tonic-gate ** see fix_stm() which sets this bit for those 15420Sstevel@tonic-gate ** states which the filter program is not interested in 15430Sstevel@tonic-gate */ 15440Sstevel@tonic-gate 15450Sstevel@tonic-gate if (bitset(NX_SKIP, next_states[n])) 15460Sstevel@tonic-gate s = n; 15470Sstevel@tonic-gate else 15480Sstevel@tonic-gate return false; 15492197Sjbeck } while (s < SIZE_NEXT_STATES); 15500Sstevel@tonic-gate return false; 15510Sstevel@tonic-gate } 1552*3966Sjbeck 15530Sstevel@tonic-gate /* 15540Sstevel@tonic-gate ** FIX_STM -- add "skip" bits to the state transition table 15550Sstevel@tonic-gate ** 15560Sstevel@tonic-gate ** Parameters: 15570Sstevel@tonic-gate ** ctx -- context structure 15580Sstevel@tonic-gate ** 15590Sstevel@tonic-gate ** Returns: 15600Sstevel@tonic-gate ** None. 15610Sstevel@tonic-gate ** 15620Sstevel@tonic-gate ** Side effects: 15630Sstevel@tonic-gate ** may change state transition table. 15640Sstevel@tonic-gate */ 15650Sstevel@tonic-gate 15660Sstevel@tonic-gate static void 15670Sstevel@tonic-gate fix_stm(ctx) 15680Sstevel@tonic-gate SMFICTX_PTR ctx; 15690Sstevel@tonic-gate { 15700Sstevel@tonic-gate unsigned long fl; 15710Sstevel@tonic-gate 15720Sstevel@tonic-gate if (ctx == NULL || ctx->ctx_smfi == NULL) 15730Sstevel@tonic-gate return; 15740Sstevel@tonic-gate fl = ctx->ctx_pflags; 15750Sstevel@tonic-gate if (bitset(SMFIP_NOCONNECT, fl)) 15760Sstevel@tonic-gate next_states[ST_CONN] |= NX_SKIP; 15770Sstevel@tonic-gate if (bitset(SMFIP_NOHELO, fl)) 15780Sstevel@tonic-gate next_states[ST_HELO] |= NX_SKIP; 15790Sstevel@tonic-gate if (bitset(SMFIP_NOMAIL, fl)) 15800Sstevel@tonic-gate next_states[ST_MAIL] |= NX_SKIP; 15810Sstevel@tonic-gate if (bitset(SMFIP_NORCPT, fl)) 15820Sstevel@tonic-gate next_states[ST_RCPT] |= NX_SKIP; 15830Sstevel@tonic-gate if (bitset(SMFIP_NOHDRS, fl)) 15840Sstevel@tonic-gate next_states[ST_HDRS] |= NX_SKIP; 15850Sstevel@tonic-gate if (bitset(SMFIP_NOEOH, fl)) 15860Sstevel@tonic-gate next_states[ST_EOHS] |= NX_SKIP; 15870Sstevel@tonic-gate if (bitset(SMFIP_NOBODY, fl)) 15880Sstevel@tonic-gate next_states[ST_BODY] |= NX_SKIP; 15893544Sjbeck if (bitset(SMFIP_NODATA, fl)) 15903544Sjbeck next_states[ST_DATA] |= NX_SKIP; 15913544Sjbeck if (bitset(SMFIP_NOUNKNOWN, fl)) 15923544Sjbeck next_states[ST_UNKN] |= NX_SKIP; 15930Sstevel@tonic-gate } 15943544Sjbeck 15950Sstevel@tonic-gate /* 15960Sstevel@tonic-gate ** DEC_ARGV -- split a buffer into a list of strings, NULL terminated 15970Sstevel@tonic-gate ** 15980Sstevel@tonic-gate ** Parameters: 15990Sstevel@tonic-gate ** buf -- buffer with several strings 16000Sstevel@tonic-gate ** len -- length of buffer 16010Sstevel@tonic-gate ** 16020Sstevel@tonic-gate ** Returns: 16030Sstevel@tonic-gate ** array of pointers to the individual strings 16040Sstevel@tonic-gate */ 16050Sstevel@tonic-gate 16060Sstevel@tonic-gate static char ** 16070Sstevel@tonic-gate dec_argv(buf, len) 16080Sstevel@tonic-gate char *buf; 16090Sstevel@tonic-gate size_t len; 16100Sstevel@tonic-gate { 16110Sstevel@tonic-gate char **s; 16120Sstevel@tonic-gate size_t i; 16130Sstevel@tonic-gate int elem, nelem; 16140Sstevel@tonic-gate 16150Sstevel@tonic-gate nelem = 0; 16160Sstevel@tonic-gate for (i = 0; i < len; i++) 16170Sstevel@tonic-gate { 16180Sstevel@tonic-gate if (buf[i] == '\0') 16190Sstevel@tonic-gate ++nelem; 16200Sstevel@tonic-gate } 16210Sstevel@tonic-gate if (nelem == 0) 16220Sstevel@tonic-gate return NULL; 16230Sstevel@tonic-gate 16240Sstevel@tonic-gate /* last entry is only for the name */ 16250Sstevel@tonic-gate s = (char **)malloc((nelem + 1) * (sizeof *s)); 16260Sstevel@tonic-gate if (s == NULL) 16270Sstevel@tonic-gate return NULL; 16280Sstevel@tonic-gate s[0] = buf; 16290Sstevel@tonic-gate for (i = 0, elem = 0; i < len && elem < nelem; i++) 16300Sstevel@tonic-gate { 16310Sstevel@tonic-gate if (buf[i] == '\0') 16320Sstevel@tonic-gate { 16330Sstevel@tonic-gate ++elem; 16340Sstevel@tonic-gate if (i + 1 >= len) 16350Sstevel@tonic-gate s[elem] = NULL; 16360Sstevel@tonic-gate else 16370Sstevel@tonic-gate s[elem] = &(buf[i + 1]); 16380Sstevel@tonic-gate } 16390Sstevel@tonic-gate } 16400Sstevel@tonic-gate 16410Sstevel@tonic-gate /* overwrite last entry (already done above, just paranoia) */ 16420Sstevel@tonic-gate s[elem] = NULL; 16430Sstevel@tonic-gate return s; 16440Sstevel@tonic-gate } 1645*3966Sjbeck 16460Sstevel@tonic-gate /* 16470Sstevel@tonic-gate ** DEC_ARG2 -- split a buffer into two strings 16480Sstevel@tonic-gate ** 16490Sstevel@tonic-gate ** Parameters: 16500Sstevel@tonic-gate ** buf -- buffer with two strings 16510Sstevel@tonic-gate ** len -- length of buffer 16520Sstevel@tonic-gate ** s1,s2 -- pointer to result strings 16530Sstevel@tonic-gate ** 16540Sstevel@tonic-gate ** Returns: 16550Sstevel@tonic-gate ** MI_FAILURE/MI_SUCCESS 16560Sstevel@tonic-gate */ 16570Sstevel@tonic-gate 16580Sstevel@tonic-gate static int 16590Sstevel@tonic-gate dec_arg2(buf, len, s1, s2) 16600Sstevel@tonic-gate char *buf; 16610Sstevel@tonic-gate size_t len; 16620Sstevel@tonic-gate char **s1; 16630Sstevel@tonic-gate char **s2; 16640Sstevel@tonic-gate { 16650Sstevel@tonic-gate size_t i; 16660Sstevel@tonic-gate 16670Sstevel@tonic-gate /* paranoia: check for terminating '\0' */ 16680Sstevel@tonic-gate if (len == 0 || buf[len - 1] != '\0') 16690Sstevel@tonic-gate return MI_FAILURE; 16700Sstevel@tonic-gate *s1 = buf; 16710Sstevel@tonic-gate for (i = 1; i < len && buf[i] != '\0'; i++) 16720Sstevel@tonic-gate continue; 16730Sstevel@tonic-gate if (i >= len - 1) 16740Sstevel@tonic-gate return MI_FAILURE; 16750Sstevel@tonic-gate *s2 = buf + i + 1; 16760Sstevel@tonic-gate return MI_SUCCESS; 16770Sstevel@tonic-gate } 1678*3966Sjbeck 16790Sstevel@tonic-gate /* 16800Sstevel@tonic-gate ** SENDOK -- is it ok for the filter to send stuff to the MTA? 16810Sstevel@tonic-gate ** 16820Sstevel@tonic-gate ** Parameters: 16830Sstevel@tonic-gate ** ctx -- context structure 16840Sstevel@tonic-gate ** flag -- flag to check 16850Sstevel@tonic-gate ** 16860Sstevel@tonic-gate ** Returns: 16870Sstevel@tonic-gate ** sending allowed (in current state) 16880Sstevel@tonic-gate */ 16890Sstevel@tonic-gate 16900Sstevel@tonic-gate bool 16910Sstevel@tonic-gate mi_sendok(ctx, flag) 16920Sstevel@tonic-gate SMFICTX_PTR ctx; 16930Sstevel@tonic-gate int flag; 16940Sstevel@tonic-gate { 16950Sstevel@tonic-gate if (ctx == NULL || ctx->ctx_smfi == NULL) 16960Sstevel@tonic-gate return false; 16970Sstevel@tonic-gate 16980Sstevel@tonic-gate /* did the milter request this operation? */ 16993544Sjbeck if (flag != 0 && !bitset(flag, ctx->ctx_aflags)) 17000Sstevel@tonic-gate return false; 17010Sstevel@tonic-gate 17020Sstevel@tonic-gate /* are we in the correct state? It must be "End of Message". */ 17030Sstevel@tonic-gate return ctx->ctx_state == ST_ENDM; 17040Sstevel@tonic-gate } 17053544Sjbeck 17063544Sjbeck #if _FFR_WORKERS_POOL 17073544Sjbeck /* 17083544Sjbeck ** MI_RD_SOCKET_READY - checks if the socket is ready for read(2) 17093544Sjbeck ** 17103544Sjbeck ** Parameters: 17113544Sjbeck ** sd -- socket_t 17123544Sjbeck ** 17133544Sjbeck ** Returns: 17143544Sjbeck ** true iff socket is ready for read(2) 17153544Sjbeck */ 17163544Sjbeck 17173544Sjbeck #define MI_RD_CMD_TO 1 17183544Sjbeck #define MI_RD_MAX_ERR 16 17193544Sjbeck 17203544Sjbeck static bool 17213544Sjbeck mi_rd_socket_ready (sd) 17223544Sjbeck socket_t sd; 17233544Sjbeck { 17243544Sjbeck int n; 17253544Sjbeck int nerr = 0; 17263544Sjbeck #if SM_CONF_POLL 17273544Sjbeck struct pollfd pfd; 17283544Sjbeck #else /* SM_CONF_POLL */ 17293544Sjbeck fd_set rd_set, exc_set; 17303544Sjbeck #endif /* SM_CONF_POLL */ 17313544Sjbeck 17323544Sjbeck do 17333544Sjbeck { 17343544Sjbeck #if SM_CONF_POLL 17353544Sjbeck pfd.fd = sd; 17363544Sjbeck pfd.events = POLLIN; 17373544Sjbeck pfd.revents = 0; 17383544Sjbeck 17393544Sjbeck n = poll(&pfd, 1, MI_RD_CMD_TO); 17403544Sjbeck #else /* SM_CONF_POLL */ 17413544Sjbeck struct timeval timeout; 17423544Sjbeck 17433544Sjbeck FD_ZERO(&rd_set); 17443544Sjbeck FD_ZERO(&exc_set); 17453544Sjbeck FD_SET(sd, &rd_set); 17463544Sjbeck FD_SET(sd, &exc_set); 17473544Sjbeck 17483544Sjbeck timeout.tv_sec = MI_RD_CMD_TO / 1000; 17493544Sjbeck timeout.tv_usec = 0; 17503544Sjbeck n = select(sd + 1, &rd_set, NULL, &exc_set, &timeout); 17513544Sjbeck #endif /* SM_CONF_POLL */ 17523544Sjbeck 17533544Sjbeck if (n < 0) 17543544Sjbeck { 17553544Sjbeck if (errno == EINTR) 17563544Sjbeck { 17573544Sjbeck nerr++; 17583544Sjbeck continue; 17593544Sjbeck } 17603544Sjbeck return true; 17613544Sjbeck } 17623544Sjbeck 17633544Sjbeck if (n == 0) 17643544Sjbeck return false; 17653544Sjbeck break; 17663544Sjbeck } while (nerr < MI_RD_MAX_ERR); 17673544Sjbeck if (nerr >= MI_RD_MAX_ERR) 17683544Sjbeck return false; 17693544Sjbeck 17703544Sjbeck #if SM_CONF_POLL 17713544Sjbeck return (pfd.revents != 0); 17723544Sjbeck #else /* SM_CONF_POLL */ 17733544Sjbeck return FD_ISSET(sd, &rd_set) || FD_ISSET(sd, &exc_set); 17743544Sjbeck #endif /* SM_CONF_POLL */ 17753544Sjbeck } 17763544Sjbeck #endif /* _FFR_WORKERS_POOL */ 1777