/* * Copyright (c) 2005, 2006 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set * forth in the LICENSE file which can be found at the top level of * the sendmail distribution. */ #include "sm/generic.h" SM_RCSID("@(#)$Id: pmilter.c,v 1.34 2007/08/18 15:58:24 ca Exp $") #include "sm/assert.h" #include "sm/error.h" #include "sm/io.h" #include "sm/str.h" #include "sm/types.h" #include "sm/ctype.h" #include "sm/smar.h" #include "s2q.h" #include "smtps.h" #include "s2m.h" #include "log.h" #include "pmilter.h" #if MTA_USE_PMILTER # if MTA_USE_RSAD /* ** SSPM_CLRREPLIES -- Clear replies in transaction context ** ** Parameters: ** ss_ta -- SMTP server transaction context ** ** Returns: ** usual sm_error code */ sm_ret_T sspm_clrreplies(ss_ta_P ss_ta) { SM_IS_SS_TA(ss_ta); if (0 == ss_ta->ssta_nreplies) return SM_SUCCESS; if (ss_ta->ssta_rcodes != NULL) SM_FREE(ss_ta->ssta_rcodes); if (ss_ta->ssta_replies != NULL) { uint u; sm_str_P reply; for (u = 0; u < ss_ta->ssta_nreplies; u++) { reply = ss_ta->ssta_replies[u]; SM_STR_FREE(reply); } SM_FREE(ss_ta->ssta_replies); } ss_ta->ssta_nreplies = 0; return SM_SUCCESS; } # endif /* MTA_USE_RSAD */ /* ** SSPM_CHK_REPLY -- check whether SMTP reply text is "OK" and fix it if not ** ** Parameters: ** replystr -- str for SMTP reply text (in/out) ** replycode -- error code to transform ** phase -- SMTP phase ** ** Returns: ** usual return code */ static sm_ret_T sspm_chk_reply(sm_str_P replystr, sm_ret_T replycode, int phase) { uint len; if (replystr == NULL) return SM_SUCCESS; len = sm_str_getlen(replystr); if (len < 5) { (void) ss_crt_reply(replystr, replycode, phase, true); return sm_err_temp(EINVAL); } /* check for \r\n */ if (sm_str_rd_elem(replystr, len - 1) != '\n' || sm_str_rd_elem(replystr, len - 2) != '\r') { sm_str_scat(replystr, "\r\n"); return sm_err_temp(EINVAL); } return SM_SUCCESS; } /* ** SSPM_HELO -- Inform libpmilter about EHLO/HELO command ** ** Parameters: ** ss_sess -- SMTPS session ** ehlo -- was EHLO used? ** ** Returns: ** >0: reply code to use for EHLO ** <=0: usual sm_error code: SM_SUCCESS */ sm_ret_T sspm_helo(ss_sess_P ss_sess, bool ehlo) { sm_ret_T ret; ss_ta_P ss_ta; SM_IS_SS_SESS(ss_sess); ss_ta = ss_sess->ssse_ta; SM_IS_SS_TA(ss_ta); if (!(SSSE_IS_FLAG(ss_sess, SSSE_FL_PM_USE) && SSC_IS_PMCAP(ss_sess->ssse_sctx, SM_SCAP_PM_EHLO))) return SM_SUCCESS; sm_str_clr(ss_sess->ssse_wr); ret = sm_s2m_helo(ss_sess, ss_sess->ssse_sctx->ssc_s2m_ctx, ss_sess->ssse_id, ehlo); if (sm_is_err(ret)) { sm_log_write(ss_sess->ssse_sctx->ssc_lctx, SS_LCAT_SERVER, SS_LMOD_SERVER, SM_LOG_ERROR, 7, "sev=ERROR, func=sspm_ehlo, ss_sess=%s, sm_s2m_ehlo=%m" , ss_sess->ssse_id, ret); } else { SSTA_SET_FLAG(ss_ta, SSTA_FL_PM_CALLED); SSSE_SET_FLAG(ss_sess, SSSE_FL_PM_CALLED); ret = sm_w4q2s_reply(ss_sess, ss_sess->ssse_sctx->ssc_cnf.ss_cnf_w4m2s, ss_sess->ssse_sctx->ssc_s2m_ctx); } if (sm_is_err(ret)) { SSPM_TRY_AGAIN(ss_sess->ssse_sctx, ss_sess); SSSE_CLR_FLAG(ss_sess, SSSE_FL_PM_USE); if (SSC_IS_MFLAG(ss_sess->ssse_sctx, SSC_MFL_PM_421)) ret = SMTP_R_SSD; else ret = SM_SUCCESS; } #if 0 /* ??? this can't happen, ret is reset above */ if (sm_is_err(ret)) { sm_log_write(ss_sess->ssse_sctx->ssc_lctx, SS_LCAT_SERVER, SS_LMOD_SERVER, SM_LOG_ERROR, 6, "sev=ERROR, func=sspm_ehlo, ss_sess=%s, sm_w4q2s_reply=%m" , ss_sess->ssse_id, ret); /* XXX properly deal with error... */ /* write a macro? */ goto error; } else #endif if (SMAR_RISQUICK(ret)) { if (SMTP_R_ACCEPT == ret) SSSE_CLR_FLAG(ss_sess, SSSE_FL_PM_USE); #if 0 SSTA_SET_FLAG(ss_ta, SSTA_FL_EHLO_QCK); #endif SMAR_RCLRQUICK(ret); } else if (SSSE_IS_CFLAG(ss_sess, SSSE_CFL_DELAY_CHKS) && IS_SMTP_REPLY(ret) && SMTP_IS_REPLY_ERROR(ret)) { sm_str_P str; sm_log_write(ss_sess->ssse_sctx->ssc_lctx, SS_LCAT_SERVER, SS_LMOD_SERVER, SM_LOG_DEBUG, 12, "sev=DBG, func=sspm_ehlo, ss_sess=%s, reply=%d, text=%@T" , ss_sess->ssse_id, ret, ss_sess->ssse_wr); if (sm_str_getlen(ss_sess->ssse_wr) != 0) { str = sm_str_dup(NULL, ss_sess->ssse_wr); (void) sspm_chk_reply(str, ret, SS_PHASE_EHLO); } else str = NULL; if (str != NULL || sm_str_getlen(ss_sess->ssse_wr) == 0) { if (!IS_SMTP_REPLY(ss_sess->ssse_acc.ssa_reply_code)) { ss_sess->ssse_acc.ssa_map_result = SM_ACC_FOUND; ss_sess->ssse_acc.ssa_reply_text = str; ss_sess->ssse_acc.ssa_reply_code = ret; } /* ss_sess->ssse_ehlo_acc.ssa_reply_text = str; */ sm_str_clr(ss_sess->ssse_wr); ret = SMTP_R_OK; } else { /* can't accept session: ENOMEM */ ret = SMTP_R_SSD; (void) ss_crt_reply(ss_sess->ssse_wr, ret, SS_PHASE_EHLO, true); sm_log_write(ss_sess->ssse_sctx->ssc_lctx, SS_LCAT_SERVER, SS_LMOD_SERVER, SM_LOG_ERROR, 4, "sev=ERROR, func=sspm_ehlo, ss_sess=%s, sm_str_dup=ENOMEM" , ss_sess->ssse_id); } SSSE_CLR_FLAG(ss_sess, SSSE_FL_PM_USE); } if (IS_SMTP_REPLY(ret) && SMTP_IS_REPLY_ERROR(ret)) { int temprc; sm_log_write(ss_sess->ssse_sctx->ssc_lctx, SS_LCAT_SERVER, SS_LMOD_SERVER, SM_LOG_INFO, 10, "sev=INFO, func=sspm_ehlo, ss_sess=%s, ehlo=%N, stat=%r, text=%@T" , ss_sess->ssse_id, ss_sess->ssse_str , ret, ss_sess->ssse_wr); if (!SMTP_REPLY_MATCHES_RCODE(ss_sess->ssse_wr, ret, 0, temprc)) { /* overwrite non-matching text */ (void) ss_crt_reply(ss_sess->ssse_wr, ret, SS_PHASE_EHLO, true); } else (void) sspm_chk_reply(ss_sess->ssse_wr, ret, SS_PHASE_EHLO); } else { sm_log_write(ss_sess->ssse_sctx->ssc_lctx, SS_LCAT_SERVER, SS_LMOD_SERVER, SM_LOG_INFO, 13, "sev=INFO, func=sspm_ehlo, ss_sess=%s, ss_ta=%s, sm_w4q2s_reply_ar=%m" , ss_sess->ssse_id, ss_ta->ssta_id, ret); if (SMTP_R_CONT == ret) ret = SM_SUCCESS; /* "normalize" */ } return ret; } /* ** SSPM_MAIL -- Inform libpmilter about MAIL command ** ** Parameters: ** ss_sess -- SMTPS session ** cur_status -- current status while dealing with MAIL ** argoffset -- where do arguments start? ** ** Returns: ** >0: reply code to use for MAIL ** <=0: usual sm_error code: SM_SUCCESS */ sm_ret_T sspm_mail(ss_sess_P ss_sess, sm_ret_T cur_status, uint argoffset) { sm_ret_T ret; ss_ta_P ss_ta; ss_ctx_P ss_ctx; char *which; SM_IS_SS_SESS(ss_sess); ss_ta = ss_sess->ssse_ta; SM_IS_SS_TA(ss_ta); ss_ctx = ss_sess->ssse_sctx; /* when to call milter? */ if (!(cur_status == SM_SUCCESS && SSSE_IS_FLAG(ss_sess, SSSE_FL_PM_USE) && SSC_IS_PMCAP(ss_ctx, SM_SCAP_PM_MAIL) && SSTA_IS_FLAG(ss_ta, SSTA_FL_PM_USE))) return SM_SUCCESS; which = "sm_s2m_mail"; ret = sm_s2m_mail(ss_sess, ss_ctx->ssc_s2m_ctx, ss_sess->ssse_id, ss_ta->ssta_id, ss_sess->ssse_str, argoffset); if (sm_is_success(ret)) { SSTA_SET_FLAG(ss_ta, SSTA_FL_PM_CALLED); SSSE_SET_FLAG(ss_sess, SSSE_FL_PM_CALLED); ret = sm_w4q2s_reply(ss_sess, ss_ctx->ssc_cnf.ss_cnf_w4m2s, ss_ctx->ssc_s2m_ctx); which = "sm_w4q2s_reply"; } if (sm_is_err(ret)) { SSPM_TRY_AGAIN(ss_ctx, ss_sess); sm_log_write(ss_ctx->ssc_lctx, SS_LCAT_SERVER, SS_LMOD_SERVER, SM_LOG_ERROR, 6, "sev=ERROR, func=sspm_mail, ss_sess=%s, ss_ta=%s, %s=%m" , ss_sess->ssse_id, ss_ta->ssta_id, which, ret); /* don't use milter anymore in this session */ SSSE_CLR_FLAG(ss_sess, SSSE_FL_PM_USE); if (SSC_IS_MFLAG(ss_ctx, SSC_MFL_PM_421)) ret = SMTP_R_SSD; else /* ignore error */ ret = SM_SUCCESS; } else if (SMAR_RISQUICK(ret)) { if (SMTP_R_ACCEPT == ret) SSTA_CLR_FLAG(ss_ta, SSTA_FL_PM_USE); /* SSTA_SET_FLAG(ss_ta, SSTA_FL_MAIL_QCK); */ SMAR_RCLRQUICK(ret); } else if (SSTA_IS_FLAG(ss_ta, SSTA_FL_DELAY_CHKS) && IS_SMTP_REPLY(ret) && SMTP_IS_REPLY_ERROR(ret)) { sm_str_P str; sm_log_write(ss_ctx->ssc_lctx, SS_LCAT_SERVER, SS_LMOD_SERVER, SM_LOG_DEBUG, 12, "sev=DBG, func=sspm_mail, ss_sess=%s, ss_ta=%s, %s=%m, reply=%r, text=%@T" , ss_sess->ssse_id, ss_ta->ssta_id, which, ret , ss_ta->ssta_mail_acc.ssa_reply_code , ss_sess->ssse_wr); /* delay rejection */ str = sm_str_dup(NULL, ss_sess->ssse_wr); if (str != NULL) { (void) sspm_chk_reply(str, ret, SS_PHASE_MAIL); ss_ta->ssta_mail_acc.ssa_reply_text = str; sm_str_clr(ss_sess->ssse_wr); ret = SMTP_R_OK; } else { /* can't accept session: ENOMEM */ ret = SMTP_R_SSD; (void) ss_crt_reply(ss_sess->ssse_wr, ret, SS_PHASE_MAIL, true); sm_log_write(ss_ctx->ssc_lctx, SS_LCAT_SERVER, SS_LMOD_SERVER, SM_LOG_ERROR, 4, "sev=ERROR, func=sspm_mail, ss_sess=%s, ss_ta=%s, sm_str_dup=ENOMEM" , ss_sess->ssse_id, ss_ta->ssta_id); } } if (IS_SMTP_REPLY(ret) && SMTP_IS_REPLY_ERROR(ret)) { int temprc; sm_log_write(ss_ctx->ssc_lctx, SS_LCAT_SERVER, SS_LMOD_SERVER, SM_LOG_INFO, 10, "sev=INFO, func=sspm_mail, ss_sess=%s, ss_ta=%s, mail=%@N, stat=%r, text=%@T" , ss_sess->ssse_id, ss_ta->ssta_id , ss_sess->ssse_str , ret, ss_sess->ssse_wr); if (!SMTP_REPLY_MATCHES_RCODE(ss_sess->ssse_wr, ret, 0, temprc)) (void) ss_crt_reply(ss_sess->ssse_wr, ret, SS_PHASE_MAIL, true); else (void) sspm_chk_reply(ss_sess->ssse_wr, ret, SS_PHASE_MAIL); } else { sm_log_write(ss_ctx->ssc_lctx, SS_LCAT_SERVER, SS_LMOD_SERVER, SM_LOG_INFO, 13, "sev=INFO, func=sspm_mail, ss_sess=%s, ss_ta=%s, sm_w4q2s_reply_ar=%m" , ss_sess->ssse_id, ss_ta->ssta_id, ret); if (SMTP_R_DISCARD == ret) { SSTA_SET_FLAG(ss_ta, SSTA_FL_DISCARD); ret = SM_SUCCESS; /* "normalize" */ } else if (SMTP_R_CONT == ret) ret = SM_SUCCESS; /* "normalize" */ } return ret; } /* ** SSPM_RCPT -- Inform libpmilter about RCPT command ** ** Parameters: ** ss_sess -- SMTPS session ** ss_rcpt -- recipient ** cur_status -- current status while dealing with RCPT ** ** Returns: ** reply code to use for MAIL */ sm_ret_T sspm_rcpt(ss_sess_P ss_sess, ss_rcpt_P ss_rcpt, sm_ret_T cur_status) { sm_ret_T ret; ss_ta_P ss_ta; ss_ctx_P ss_ctx; char *which; SM_IS_SS_SESS(ss_sess); ss_ta = ss_sess->ssse_ta; SM_IS_SS_TA(ss_ta); ss_ctx = ss_sess->ssse_sctx; /* when to call milter? */ if (!((cur_status == SM_SUCCESS || SSC_IS_PMCAP(ss_ctx, SM_SCAP_PM_RCPT_ST)) && SSSE_IS_FLAG(ss_sess, SSSE_FL_PM_USE) && SSC_IS_PMCAP(ss_ctx, SM_SCAP_PM_RCPT) && SSTA_IS_FLAG(ss_ta, SSTA_FL_PM_USE))) return SM_SUCCESS; which = "sm_s2m_rcpt"; ret = sm_s2m_rcpt(ss_sess, ss_ctx->ssc_s2m_ctx, ss_sess->ssse_id, ss_rcpt->ssr_idx, ss_sess->ssse_str, cur_status); if (sm_is_success(ret)) { SSTA_SET_FLAG(ss_ta, SSTA_FL_PM_CALLED); SSSE_SET_FLAG(ss_sess, SSSE_FL_PM_CALLED); ret = sm_w4q2s_reply(ss_sess, ss_ctx->ssc_cnf.ss_cnf_w4m2s, ss_ctx->ssc_s2m_ctx); which = "sm_w4q2s_reply"; } if (sm_is_err(ret)) { SSPM_TRY_AGAIN(ss_ctx, ss_sess); sm_log_write(ss_ctx->ssc_lctx, SS_LCAT_SERVER, SS_LMOD_SERVER, SM_LOG_ERROR, 6, "sev=ERROR, func=sspm_rcpt, ss_sess=%s, ss_ta=%s, %s=%m" , ss_sess->ssse_id, ss_ta->ssta_id, which, ret); /* don't use milter anymore in this session */ SSSE_CLR_FLAG(ss_sess, SSSE_FL_PM_USE); if (SSC_IS_MFLAG(ss_ctx, SSC_MFL_PM_421)) ret = SMTP_R_SSD; else /* ignore error */ ret = SM_SUCCESS; } else if (SMAR_RISQUICK(ret)) { if (SMTP_R_ACCEPT == ret) SSTA_CLR_FLAG(ss_ta, SSTA_FL_PM_USE); /* SSTA_SET_FLAG(ss_ta, SSTA_FL_RCPT_QCK); */ SMAR_RCLRQUICK(ret); /* quick:discard -> discard entire transaction */ if (SMTP_R_DISCARD == ret) SSTA_SET_FLAG(ss_ta, SSTA_FL_DISCARD); } if (IS_SMTP_REPLY(ret) && SMTP_IS_REPLY_ERROR(ret)) { int temprc; if (!SMTP_REPLY_MATCHES_RCODE(ss_sess->ssse_wr, ret, 0, temprc)) sm_str_clr(ss_sess->ssse_wr); /* new error text will be generated later */ else (void) sspm_chk_reply(ss_sess->ssse_wr, ret, SS_PHASE_RCPT); } else if (SMTP_R_CONT == ret) ret = SM_SUCCESS; /* "normalize" */ return ret; } /* ** SSPM_DATA -- Inform libpmilter about DATA command ** ** Parameters: ** ss_sess -- SMTPS session ** pskip -- skip msg (input and output) ** ** Returns: ** reply code to use for DATA */ sm_ret_T sspm_data(ss_sess_P ss_sess, bool *pskip) { sm_ret_T ret; ss_ta_P ss_ta; ss_ctx_P ss_ctx; char *which; SM_IS_SS_SESS(ss_sess); ss_ta = ss_sess->ssse_ta; SM_IS_SS_TA(ss_ta); ss_ctx = ss_sess->ssse_sctx; /* send DATA commant to milter unless DISCARD (skip) is set */ if (!(!*pskip && SSSE_IS_FLAG(ss_sess, SSSE_FL_PM_USE) && SSC_IS_PMCAP(ss_ctx, SM_SCAP_PM_DATA) && SSTA_IS_FLAG(ss_ta, SSTA_FL_PM_USE))) return SM_SUCCESS; which = "sm_s2m_data"; ret = sm_s2m_data(ss_sess, ss_ctx->ssc_s2m_ctx, ss_sess->ssse_id); if (sm_is_success(ret)) { SSTA_SET_FLAG(ss_ta, SSTA_FL_PM_CALLED); SSSE_SET_FLAG(ss_sess, SSSE_FL_PM_CALLED); ret = sm_w4q2s_reply(ss_sess, ss_ctx->ssc_cnf.ss_cnf_w4m2s, ss_ctx->ssc_s2m_ctx); which = "sm_w4q2s_reply"; } if (sm_is_err(ret)) { SSPM_TRY_AGAIN(ss_ctx, ss_sess); sm_log_write(ss_ctx->ssc_lctx, SS_LCAT_SERVER, SS_LMOD_SERVER, SM_LOG_ERROR, 6, "sev=ERROR, func=sspm_data, ss_sess=%s, ss_ta=%s, %s=%m" , ss_sess->ssse_id, ss_ta->ssta_id, which, ret); /* don't use milter anymore in this session */ SSSE_CLR_FLAG(ss_sess, SSSE_FL_PM_USE); if (SSC_IS_MFLAG(ss_ctx, SSC_MFL_PM_421)) ret = SMTP_R_SSD; else /* ignore error */ ret = SM_SUCCESS; } else if (SMAR_RISQUICK(ret)) { if (SMTP_R_ACCEPT == ret) SSTA_CLR_FLAG(ss_ta, SSTA_FL_PM_USE); SMAR_RCLRQUICK(ret); } if (IS_SMTP_REPLY(ret) && SMTP_IS_REPLY_ERROR(ret)) { int temprc; sm_log_write(ss_ctx->ssc_lctx, SS_LCAT_SERVER, SS_LMOD_SERVER, SM_LOG_INFO, 10, "sev=INFO, func=sspm_data, ss_sess=%s, ss_ta=%s, stat=%r, text=%@T" , ss_sess->ssse_id, ss_ta->ssta_id , ret, ss_sess->ssse_wr); if (!SMTP_REPLY_MATCHES_RCODE(ss_sess->ssse_wr, ret, 0, temprc)) (void) ss_crt_reply(ss_sess->ssse_wr, ret, SS_PHASE_DATA, true); else (void) sspm_chk_reply(ss_sess->ssse_wr, ret, SS_PHASE_DATA); } else if (SMTP_R_DISCARD == ret) { SSTA_SET_FLAG(ss_ta, SSTA_FL_DISCARD); *pskip = true; ret = SM_SUCCESS; /* "normalize" */ } else if (SMTP_R_CONT == ret) ret = SM_SUCCESS; /* "normalize" */ return ret; } /* ** SSPM_MSG -- Inform libpmilter about msg chunk ** ** Parameters: ** ss_sess -- SMTPS session ** bufp -- pointer to buffer to transmit ** bytes2write -- size of buffer ** isrcvd -- is this the generated Received: header? ** pskip -- skip msg (input and output) ** ** Returns: ** reply code to use for final dot ** ** Side Effects: ** on fatal error a reply text is written to ssse_wr ** on SMTP rejections, ss_ta->ssta_msg_acc is set. */ sm_ret_T sspm_msg(ss_sess_P ss_sess, uchar *bufp, size_t bytes2write, bool isrcvd, bool *pskip) { sm_ret_T ret; ss_ta_P ss_ta; ss_ctx_P ss_ctx; char *which; SM_IS_SS_SESS(ss_sess); ss_ta = ss_sess->ssse_ta; SM_IS_SS_TA(ss_ta); ss_ctx = ss_sess->ssse_sctx; /* call milter even if skip is set? */ if (!(!*pskip && SSSE_IS_FLAG(ss_sess, SSSE_FL_PM_USE) && ((SSC_IS_PMCAP(ss_ctx, SM_SCAP_PM_MSG) && !isrcvd) || (SSC_IS_PMCAP(ss_ctx, SM_SCAP_PM_SND_RCVD) && isrcvd)) && SSTA_IS_FLAG(ss_ta, SSTA_FL_PM_USE) && !SSTA_IS_FLAG(ss_ta, SSTA_FL_PM_SKIP_MSG))) return SM_SUCCESS; sm_log_write(ss_ctx->ssc_lctx, SS_LCAT_SERVER, SS_LMOD_SERVER, SM_LOG_DEBUG, 15, "sev=DBG, func=sspm_msg, ss_sess=%s, ss_ta=%s, bytes2write=%u, bfsize=%d, blksize=%d" , ss_sess->ssse_id, ss_ta->ssta_id, (uint) bytes2write , (int) f_bfsize(*ss_sess->ssse_fp) , (int) ss_sess->ssse_fp->f_blksize ); which = "sm_s2m_msg"; ret = sm_s2m_msg(ss_sess, ss_ctx->ssc_s2m_ctx, ss_sess->ssse_id, bufp, bytes2write, SSC_IS_PMCAP(ss_ctx, SM_SCAP_PM_MSG_RC) ? SM_S2M_MSG_REPLY : SM_S2M_MSG_NONE); if (sm_is_success(ret)) { SSTA_SET_FLAG(ss_ta, SSTA_FL_PM_CALLED); SSSE_SET_FLAG(ss_sess, SSSE_FL_PM_CALLED); if (SSC_IS_PMCAP(ss_ctx, SM_SCAP_PM_MSG_RC)) { ret = sm_w4q2s_reply(ss_sess, ss_ctx->ssc_cnf.ss_cnf_w4m2s, ss_ctx->ssc_s2m_ctx); which = "sm_w4q2s_reply"; } } if (sm_is_err(ret)) { SSPM_TRY_AGAIN(ss_ctx, ss_sess); sm_log_write(ss_ctx->ssc_lctx, SS_LCAT_SERVER, SS_LMOD_SERVER, SM_LOG_ERROR, 7, "sev=ERROR, func=sspm_msg, ss_sess=%s, ss_ta=%s, %s=%m, bytes2write=%d" , ss_sess->ssse_id, ss_ta->ssta_id, which, ret , (int) bytes2write); /* don't use milter anymore in this session */ SSSE_CLR_FLAG(ss_sess, SSSE_FL_PM_USE); if (SSC_IS_MFLAG(ss_ctx, SSC_MFL_PM_421)) { ret = SMTP_R_SSD; sm_str_scopy(ss_sess->ssse_wr, "421 4.3.0 Cannot contact milter.\r\n"); *pskip = true; } else /* ignore error */ ret = SM_SUCCESS; } else if (SSC_IS_PMCAP(ss_ctx, SM_SCAP_PM_MSG_RC)) { if (SMAR_RISQUICK(ret)) { if (SMTP_R_ACCEPT == ret) SSTA_CLR_FLAG(ss_ta, SSTA_FL_PM_USE); SMAR_RCLRQUICK(ret); } if (IS_SMTP_REPLY(ret) && SMTP_IS_REPLY_ERROR(ret)) { int temprc; sm_str_P str; str = NULL; sm_log_write(ss_ctx->ssc_lctx, SS_LCAT_SERVER, SS_LMOD_SERVER, SM_LOG_INFO, 10, "sev=INFO, func=sspm_msg, ss_sess=%s, ss_ta=%s, stat=%r, text=%@T" , ss_sess->ssse_id, ss_ta->ssta_id , ret, ss_sess->ssse_wr); if (!SMTP_REPLY_MATCHES_RCODE(ss_sess->ssse_wr, ret, 0, temprc)) (void) ss_crt_reply(ss_sess->ssse_wr, ret, SS_PHASE_DOT, true); else (void) sspm_chk_reply(ss_sess->ssse_wr, ret, SS_PHASE_DOT); ss_ta->ssta_msg_acc.ssa_map_result = SM_ACC_FOUND; ss_ta->ssta_msg_acc.ssa_reply_code = ret; str = sm_str_dup(NULL, ss_sess->ssse_wr); if (str != NULL) { ss_ta->ssta_msg_acc.ssa_reply_text = str; sm_str_clr(ss_sess->ssse_wr); } SSTA_CLR_FLAG(ss_ta, SSTA_FL_PM_USE); } else if (SMTP_R_DISCARD == ret) { SSTA_SET_FLAG(ss_ta, SSTA_FL_DISCARD); *pskip = true; ret = SM_SUCCESS; /* "normalize" */ } else if (SMTP_R_SKIP == ret) { SSTA_SET_FLAG(ss_ta, SSTA_FL_PM_SKIP_MSG); ret = SM_SUCCESS; /* "normalize" */ } else if (SMTP_R_CONT == ret) ret = SM_SUCCESS; /* "normalize" */ } return ret; } /* ** SSPM_EOB -- Inform libpmilter about last msg chunk ** ** Parameters: ** ss_sess -- SMTPS session ** pskip -- skip msg (input and output) ** ** Returns: ** reply code to use for dot */ sm_ret_T sspm_eob(ss_sess_P ss_sess, uchar *bufp, size_t bytes2write, bool *pskip) { sm_ret_T ret; ss_ta_P ss_ta; ss_ctx_P ss_ctx; char *which; SM_IS_SS_SESS(ss_sess); ss_ta = ss_sess->ssse_ta; SM_IS_SS_TA(ss_ta); ss_ctx = ss_sess->ssse_sctx; /* NOTE: pmilter isn't called for any of the errors above! */ if (!(SSSE_IS_FLAG(ss_sess, SSSE_FL_PM_USE) && SSC_IS_PMCAP(ss_ctx, SM_SCAP_PM_MSG) && SSTA_IS_FLAG(ss_ta, SSTA_FL_PM_USE))) return SM_SUCCESS; which = "sm_s2m_msg"; ret = sm_s2m_msg(ss_sess, ss_ctx->ssc_s2m_ctx, ss_sess->ssse_id, bufp, bytes2write, SM_S2M_MSG_LAST|SM_S2M_MSG_REPLY); if (sm_is_success(ret)) { SSTA_SET_FLAG(ss_ta, SSTA_FL_PM_CALLED); SSSE_SET_FLAG(ss_sess, SSSE_FL_PM_CALLED); ret = sm_w4q2s_reply(ss_sess, ss_ctx->ssc_cnf.ss_cnf_w4m2s, ss_ctx->ssc_s2m_ctx); which = "sm_w4q2s_reply"; sm_log_write(ss_ctx->ssc_lctx, SS_LCAT_SERVER, SS_LMOD_SERVER, SM_LOG_INFO, 19, "sev=INFO, func=sspm_eob, ss_sess=%s, ss_ta=%s, stat=%m, text=%@T" , ss_sess->ssse_id, ss_ta->ssta_id , ret, ss_sess->ssse_wr); } if (sm_is_err(ret)) { SSPM_TRY_AGAIN(ss_ctx, ss_sess); sm_log_write(ss_ctx->ssc_lctx, SS_LCAT_SERVER, SS_LMOD_SERVER, SM_LOG_ERROR, 6, "sev=ERROR, func=sspm_eob, ss_sess=%s, ss_ta=%s, %s=%m" , ss_sess->ssse_id, ss_ta->ssta_id, which, ret); /* don't use milter anymore in this session */ SSSE_CLR_FLAG(ss_sess, SSSE_FL_PM_USE); if (SSC_IS_MFLAG(ss_ctx, SSC_MFL_PM_421)) ret = SMTP_R_SSD; else /* ignore error */ ret = SM_SUCCESS; } else if (SMAR_RISQUICK(ret)) { if (SMTP_R_ACCEPT == ret) SSTA_CLR_FLAG(ss_ta, SSTA_FL_PM_USE); SMAR_RCLRQUICK(ret); } if (IS_SMTP_REPLY(ret) && SMTP_IS_REPLY_ERROR(ret)) { int temprc; sm_log_write(ss_ctx->ssc_lctx, SS_LCAT_SERVER, SS_LMOD_SERVER, SM_LOG_INFO, 10, "sev=INFO, func=sspm_eob, ss_sess=%s, ss_ta=%s, stat=%r, text=%@T" , ss_sess->ssse_id, ss_ta->ssta_id , ret, ss_sess->ssse_wr); if (!SMTP_REPLY_MATCHES_RCODE(ss_sess->ssse_wr, ret, 0, temprc)) (void) ss_crt_reply(ss_sess->ssse_wr, ret, SS_PHASE_DOT, true); else (void) sspm_chk_reply(ss_sess->ssse_wr, ret, SS_PHASE_DOT); } else if (SMTP_R_DISCARD == ret) { SSTA_SET_FLAG(ss_ta, SSTA_FL_DISCARD); *pskip = true; ret = SM_SUCCESS; /* "normalize" */ } else if (SMTP_R_CONT == ret) ret = SM_SUCCESS; /* "normalize" */ if (SMTP_R_RPLCMSG == ret) ret = ss_rplcmsg(ss_sess); return ret; } #endif /* MTA_USE_PMILTER */