/*
* 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 */
syntax highlighted by Code2HTML, v. 0.9.1