/*
* Copyright (c) 2005 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: ssreplacemsg.c,v 1.13 2007/08/18 15:58:24 ca Exp $")
#include "sm/assert.h"
#include "sm/error.h"
#include "sm/memops.h"
#include "sm/reccom.h"
#include "sm/rcbst.h"
#include "smtps-str.h"
#include "s2q.h"
#include "smtps.h"
#if MTA_USE_PMILTER
#include "s2m.h"
#include "sm/pmilter.h"
#include "log.h"
/*
** SS_REPLACEMSG -- read message chunk and write it to cdb
**
** Parameters:
** ss_sess -- session context
** l -- length of buffer to read from rcb
**
** Returns:
** usual sm_error code
**
** Called by: sm_w4q2s_reply()
*/
sm_ret_T
ss_replacemsg(ss_sess_P ss_sess, uint32_t l)
{
sm_ret_T ret;
int c;
uint u;
ssize_t byteswritten;
ss_ta_P ss_ta;
cdb_ctx_P cdb_ctx;
const uchar *buf;
static SM_DECL_EOT;
SM_IS_SS_SESS(ss_sess);
ss_ta = ss_sess->ssse_ta;
cdb_ctx = ss_sess->ssse_sctx->ssc_cdb_ctx;
sm_log_write(ss_sess->ssse_sctx->ssc_lctx,
SS_LCAT_PMILTER, SS_LMOD_PMILTER, SM_LOG_INFO, 12,
"sev=INFO, func=ss_replacemsg, ss_sess=%s, ss_ta=%s, status=%d"
, ss_sess->ssse_id, ss_ta->ssta_id, ss_ta->ssta_msg_st);
if (ss_ta->ssta_msg_st != SSTA_ST_MR_CDB_OK)
{
ret = sm_rcb_skip(ss_sess->ssse_rcb, l);
return SM_SUCCESS;
}
ret = sm_rcb_getdata(ss_sess->ssse_rcb, &buf, l);
if (sm_is_err(ret))
{
sm_log_write(ss_sess->ssse_sctx->ssc_lctx,
SS_LCAT_PMILTER, SS_LMOD_PMILTER,
SM_LOG_ERROR, 8,
"sev=ERROR, func=ss_replacemsg, ss_sess=%s, ss_ta=%s, sm_rcb_getdata=%m, l=%d"
, ss_sess->ssse_id, ss_ta->ssta_id, ret, l);
ss_ta->ssta_msg_st = SSTA_ST_MR_CDB_FAIL;
return ret;
}
for (u = 0; u < l; u++)
{
c = buf[u];
if (c == eot[ss_ta->ssta_eot_state])
{
if (++ss_ta->ssta_eot_state >= SM_EOT_LEN)
break;
}
else
{
ss_ta->ssta_eot_state = 0;
if (c == eot[ss_ta->ssta_eot_state])
++ss_ta->ssta_eot_state;
}
}
/*
** Increment u as it is the index in buf[] not the length
** of the buffer to write.
*/
if (ss_ta->ssta_eot_state >= SM_EOT_LEN && ++u < l)
{
sm_log_write(ss_sess->ssse_sctx->ssc_lctx,
SS_LCAT_PMILTER, SS_LMOD_PMILTER,
SM_LOG_ERROR, 8,
"sev=ERROR, func=ss_replacemsg, found_eot_at=%d, buf_len=%d"
, u, l);
l = u;
ss_ta->ssta_msg_st = SSTA_ST_MR_CDB_FAIL;
}
ret = cdb_write(cdb_ctx, ss_ta->ssta_msg_fp, buf, l, &byteswritten);
if (sm_is_err(ret) || byteswritten < 0 || l != (uint32_t) byteswritten)
{
sm_log_write(ss_sess->ssse_sctx->ssc_lctx,
SS_LCAT_PMILTER, SS_LMOD_PMILTER,
SM_LOG_ERROR, 8,
"sev=ERROR, func=ss_replacemsg, ss_sess=%s, ss_ta=%s, cdb_write=%m, len=%u, byteswritten=%d"
, ss_sess->ssse_id, ss_ta->ssta_id, ret, l
, (int) byteswritten);
ss_ta->ssta_msg_st = SSTA_ST_MR_CDB_FAIL;
}
else
ss_ta->ssta_rmsg_sz_b += byteswritten;
return SM_SUCCESS;
}
/*
** SS_CLOSEMSG -- close (replacement) cdb
**
** Parameters:
** ss_sess -- session context
**
** Returns:
** usual sm_error code
**
** Side Effects: removes original cdb if everything goes well here
*/
static sm_ret_T
ss_closemsg(ss_sess_P ss_sess)
{
sm_ret_T ret;
ss_ta_P ss_ta;
cdb_ctx_P cdb_ctx;
ss_ctx_P ss_ctx;
SM_IS_SS_SESS(ss_sess);
ss_ta = ss_sess->ssse_ta;
SM_IS_SS_TA(ss_ta);
ss_ctx = ss_sess->ssse_sctx;
ret = SM_SUCCESS;
sm_log_write(ss_sess->ssse_sctx->ssc_lctx,
SS_LCAT_PMILTER, SS_LMOD_PMILTER, SM_LOG_INFO, 12,
"sev=INFO, func=ss_closemsg, ss_sess=%s, ss_ta=%s, status=%d"
, ss_sess->ssse_id, ss_ta->ssta_id, ss_ta->ssta_msg_st);
/* no message has been written? */
if (SSTA_ST_MR_NONE == ss_ta->ssta_msg_st)
return SM_SUCCESS;
cdb_ctx = ss_sess->ssse_sctx->ssc_cdb_ctx;
if (NULL == ss_ta->ssta_cdb_id)
{
sm_log_write(ss_sess->ssse_sctx->ssc_lctx,
SS_LCAT_PMILTER, SS_LMOD_PMILTER, SM_LOG_ERR, 2,
"sev=ERR, func=ss_closemsg, ss_sess=%s, ss_ta=%s, status=missing cdb id"
, ss_sess->ssse_id, ss_ta->ssta_id);
ss_ta->ssta_msg_st = SSTA_ST_MR_CDB_FAIL;
ret = sm_error_perm(SM_EM_PMILTER, SM_E_UNEXPECTED);
goto error;
}
if (SM_GOT_CRLF == ss_ta->ssta_eot_state)
{
const char buf[] = ".\r\n";
size_t l;
ssize_t byteswritten;
l = sizeof(buf) - 1;
ret = cdb_write(cdb_ctx, ss_ta->ssta_msg_fp,
(const uchar *) buf, l, &byteswritten);
if (sm_is_err(ret) || byteswritten < 0 ||
l != (size_t) byteswritten)
{
sm_log_write(ss_sess->ssse_sctx->ssc_lctx,
SS_LCAT_PMILTER, SS_LMOD_PMILTER, SM_LOG_ERR, 2,
"sev=ERR, func=ss_closemsg, ss_sess=%s, ss_ta=%s, cdb_write=%m, len=%y, byteswritten=%d, status=fail"
, ss_sess->ssse_id, ss_ta->ssta_id
, ret, l, byteswritten);
ss_ta->ssta_msg_st = SSTA_ST_MR_CDB_FAIL;
}
else
ss_ta->ssta_rmsg_sz_b += byteswritten;
}
else if (ss_ta->ssta_eot_state < SM_EOT_LEN)
{
sm_log_write(ss_sess->ssse_sctx->ssc_lctx,
SS_LCAT_PMILTER, SS_LMOD_PMILTER, SM_LOG_ERR, 2,
"sev=ERR, func=ss_closemsg, ss_sess=%s, ss_ta=%s, eot_state=%d, status=invalid end of message"
, ss_sess->ssse_id, ss_ta->ssta_id
, ss_ta->ssta_eot_state);
ss_ta->ssta_msg_st = SSTA_ST_MR_CDB_FAIL;
ret = sm_error_perm(SM_EM_PMILTER, SM_E_PR_ERR);
}
if (SSTA_ST_MR_CDB_OK != ss_ta->ssta_msg_st)
goto error;
ret = cdb_close(cdb_ctx, ss_ta->ssta_msg_fp, SM_IO_CF_SYNC);
if (sm_is_err(ret))
{
sm_log_write(ss_sess->ssse_sctx->ssc_lctx,
SS_LCAT_PMILTER, SS_LMOD_PMILTER, SM_LOG_ERR, 8,
"sev=ERR, func=ss_closemsg, ss_sess=%s, ss_ta=%s, cdb_close=%m"
, ss_sess->ssse_id, ss_ta->ssta_id, ret);
goto error;
}
ss_ta->ssta_msg_fp = NULL;
ss_ta->ssta_msg_st = SSTA_ST_MR_CDB_CLSD;
ret = sm_s2m_msg_rplc_stat(ss_sess, ss_ctx->ssc_s2m_ctx,
ss_sess->ssse_id, SM_SUCCESS);
if (sm_is_err(ret))
sm_log_write(ss_sess->ssse_sctx->ssc_lctx,
SS_LCAT_PMILTER, SS_LMOD_PMILTER, SM_LOG_WARN, 9,
"sev=WARN, func=ss_closemsg, ss_sess=%s, ss_ta=%s, sm_s2m_msg_rplc_stat=%#x"
, ss_sess->ssse_id, ss_ta->ssta_id, ret);
/* remove original file, new file is safely stored */
(void) cdb_abort(cdb_ctx, ss_ta->ssta_dfp);
ss_ta->ssta_dfp = NULL;
SSTA_CLR_FLAG(ss_ta, SSTA_FL_CDB_EXISTS);
ss_ta->ssta_msg_sz_b = ss_ta->ssta_rmsg_sz_b;
sm_log_write(ss_sess->ssse_sctx->ssc_lctx,
SS_LCAT_PMILTER, SS_LMOD_PMILTER, SM_LOG_INFO, 9,
"sev=INFO, func=ss_closemsg, ss_sess=%s, ss_ta=%s, status=message_replaced, size=%lu"
, ss_sess->ssse_id, ss_ta->ssta_id
, (ulong) ss_ta->ssta_msg_sz_b);
return SM_SUCCESS;
error:
if (cdb_ctx != NULL)
{
if (ss_ta->ssta_msg_fp != NULL)
{
(void) cdb_abort(cdb_ctx, ss_ta->ssta_msg_fp);
ss_ta->ssta_msg_fp = NULL;
/* abort also removes the file */
SM_CSTR_FREE(ss_ta->ssta_cdb_id);
}
if (ss_ta->ssta_cdb_id != NULL)
{
(void) cdb_unlink(cdb_ctx,
(const char *)
sm_cstr_data(ss_ta->ssta_cdb_id));
SM_CSTR_FREE(ss_ta->ssta_cdb_id);
}
}
if (!sm_is_err(ret))
ret = sm_err_perm(EIO);
(void) sm_s2m_msg_rplc_stat(ss_sess, ss_ctx->ssc_s2m_ctx,
ss_sess->ssse_id, ret);
return ret;
}
/*
** SS_RPLCMSG -- read message chunks and write them to cdb
**
** Parameters:
** ss_sess -- session context
**
** Returns:
** usual sm_error code
*/
sm_ret_T
ss_rplcmsg(ss_sess_P ss_sess)
{
sm_ret_T ret;
ss_ta_P ss_ta;
ss_ctx_P ss_ctx;
cdb_ctx_P cdb_ctx;
ss_ta = ss_sess->ssse_ta;
SM_IS_SS_TA(ss_ta);
ss_ctx = ss_sess->ssse_sctx;
cdb_ctx = ss_sess->ssse_sctx->ssc_cdb_ctx;
ret = cdb_open_write(cdb_ctx, ss_ta->ssta_id, ss_ta->ssta_msg_fp,
SM_IO_WREXCL, 1, &ss_ta->ssta_cdb_id);
if (sm_is_err(ret))
{
sm_log_write(ss_sess->ssse_sctx->ssc_lctx,
SS_LCAT_PMILTER, SS_LMOD_PMILTER, SM_LOG_ERROR, 8,
"sev=ERROR, func=ss_rplcmsg, ss_sess=%s, ss_ta=%s, cdb_open=%m"
, ss_sess->ssse_id, ss_ta->ssta_id, ret);
ss_ta->ssta_msg_st = SSTA_ST_MR_CDB_NONE;
}
else
ss_ta->ssta_msg_st = SSTA_ST_MR_CDB_OK;
ss_ta->ssta_eot_state = SM_GOT_CRLF;
do
{
ret = ss_add_rq(ss_sess, ss_sess->ssse_id,
ss_ctx->ssc_s2m_ctx, NULL);
if (sm_is_err(ret))
{
sm_log_write(ss_ctx->ssc_lctx,
SS_LCAT_PMILTER, SS_LMOD_PMILTER, SM_LOG_ERR, 4,
"sev=ERR, func=ss_rplcmsg, ss_sess=%s, ss_ta=%s, ss_add_rq=%m"
, ss_sess->ssse_id, ss_ta->ssta_id
, ret);
ss_ta->ssta_msg_st = SSTA_ST_MR_CDB_FAIL;
break;
}
ret = sm_w4q2s_reply(ss_sess,
ss_ctx->ssc_cnf.ss_cnf_w4m2s,
ss_ctx->ssc_s2m_ctx);
if (sm_is_err(ret))
{
/* don't use milter anymore in this session */
SSSE_CLR_FLAG(ss_sess, SSSE_FL_PM_USE);
sm_log_write(ss_ctx->ssc_lctx,
SS_LCAT_PMILTER, SS_LMOD_PMILTER, SM_LOG_ERR, 4,
"sev=ERR, func=ss_rplcmsg, ss_sess=%s, ss_ta=%s, sm_w4q2s_reply=%m"
, ss_sess->ssse_id, ss_ta->ssta_id
, ret);
ss_ta->ssta_msg_st = SSTA_ST_MR_CDB_FAIL;
break;
}
} while (SMTP_R_CONT == ret);
ret = ss_closemsg(ss_sess);
if (sm_is_err(ret))
{
sm_log_write(ss_ctx->ssc_lctx,
SS_LCAT_PMILTER, SS_LMOD_PMILTER, SM_LOG_ERROR, 6,
"sev=ERROR, func=ss_rplcmsg, ss_sess=%s, ss_ta=%s, ss_closemsg=%m"
, ss_sess->ssse_id, ss_ta->ssta_id, ret);
if (SSC_IS_MFLAG(ss_ctx, SSC_MFL_PM_421))
ret = SMTP_R_SSD;
else /* ignore error */
ret = SM_SUCCESS;
}
return ret;
}
#endif /* MTA_USE_PMILTER */
syntax highlighted by Code2HTML, v. 0.9.1