/*
* Copyright (c) 2004-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: t-pmilter-0.c,v 1.35 2006/10/05 04:27:38 ca Exp $")
#include "sm/error.h"
#include "sm/assert.h"
#include "sm/types.h"
#include "sm/sysexits.h"
#include "sm/fcntl.h"
#include "sm/io.h"
#include "sm/ctype.h"
#include "sm/reccom.h"
#include "sm/mta.h"
#define PMILTER_DEBUG_DEFINE 1
#include "pmilter.h"
#include "sm/pmfdef.h"
#include "sm/pmfapi.h"
#include "sm/pmilter.h"
#include "util.h"
#include "t-pmilter.h"
#if MTA_USE_PMILTER
/*
** pmilter test program; uses direct access, not any "published" API.
*/
static pmt_ctx_T pmt_ctx;
static pmilter_T pmilter;
sm_ret_T
sm_pmilt_nseid(pmss_ctx_P pmss_ctx, pmse_ctx_P pmse_ctx, sm_rcbe_P rcbe)
{
sm_ret_T ret;
if (PMT_EXIT(pmt_ctx.pmt_rcode[SM_STAGE_NSEID]))
exit(0);
ret = sm_rcb_putv(&rcbe->rcbe_rcb, RCB_PUTV_FIRST,
SM_RCBV_INT, RT_PROT_VER, PROT_VER_RT,
SM_RCBV_INT, RT_M2S_ID, pmss_ctx->pmss_id,
SM_RCBV_BUF, RT_M2S_SEID, pmse_ctx->pmse_se_id, SMTP_STID_SIZE,
SM_RCBV_INT, RT_M2S_RCODE, pmt_ctx.pmt_rcode[SM_STAGE_NSEID],
SM_RCBV_END);
sm_io_fprintf(smioerr, "sev=DBG, seid=%s, host=%S, ret=%X\n",
pmse_ctx->pmse_se_id, pmse_ctx->pmse_arg1, ret);
return ret;
}
sm_ret_T
sm_pmilt_cseid(pmss_ctx_P pmss_ctx, pmse_ctx_P pmse_ctx)
{
sm_io_fprintf(smioerr, "sev=DBG, seid=%s, where=close\n",
pmse_ctx->pmse_se_id);
return SM_SUCCESS;
}
sm_ret_T
sm_pmilt_helo(pmss_ctx_P pmss_ctx, pmse_ctx_P pmse_ctx, sm_rcbe_P rcbe, bool ehlo)
{
sm_ret_T ret;
sm_io_fprintf(smioerr, "sev=DBG, seid=%s, helo=%S\n",
pmse_ctx->pmse_se_id, pmse_ctx->pmse_arg1);
if (PMT_EXIT(pmt_ctx.pmt_rcode[SM_STAGE_HELO]))
exit(0);
ret = sm_rcb_putv(&rcbe->rcbe_rcb, RCB_PUTV_FIRST,
SM_RCBV_INT, RT_PROT_VER, PROT_VER_RT,
SM_RCBV_INT, RT_M2S_ID, pmss_ctx->pmss_id,
SM_RCBV_BUF, RT_M2S_SEID, pmse_ctx->pmse_se_id, SMTP_STID_SIZE,
SM_RCBV_INT, RT_M2S_RCODE, pmt_ctx.pmt_rcode[SM_STAGE_HELO],
SM_RCBV_END);
return ret;
}
sm_ret_T
sm_pmilt_mail(pmss_ctx_P pmss_ctx, pmse_ctx_P pmse_ctx, sm_rcbe_P rcbe)
{
sm_ret_T ret;
unsigned int nelem;
char **argv;
ret = args2argv(pmse_ctx->pmse_arg2, &nelem, &argv);
sm_io_fprintf(smioerr,
"sev=DBG, seid=%s, mail=%@S, args=%S, nelem=%u, args2argv=%r, argv[0]=%s\n",
pmse_ctx->pmse_se_id, pmse_ctx->pmse_arg1,
pmse_ctx->pmse_arg2, nelem, ret,
(argv != NULL && argv[0] != NULL) ? argv[0] : "NULL");
if (PMT_EXIT(pmt_ctx.pmt_rcode[SM_STAGE_MAIL]))
exit(0);
ret = sm_rcb_putv(&rcbe->rcbe_rcb, RCB_PUTV_FIRST,
SM_RCBV_INT, RT_PROT_VER, PROT_VER_RT,
SM_RCBV_INT, RT_M2S_ID, pmss_ctx->pmss_id,
SM_RCBV_BUF, RT_M2S_SEID, pmse_ctx->pmse_se_id, SMTP_STID_SIZE,
SM_RCBV_INT, RT_M2S_RCODE, pmt_ctx.pmt_rcode[SM_STAGE_MAIL],
SM_RCBV_END);
if (argv != NULL)
sm_free(argv);
return ret;
}
sm_ret_T
sm_pmilt_rcpt(pmss_ctx_P pmss_ctx, pmse_ctx_P pmse_ctx, sm_rcbe_P rcbe)
{
sm_ret_T ret;
sm_io_fprintf(smioerr, "sev=DBG, seid=%s, rcpt=%@S, idx=%d\n",
pmse_ctx->pmse_se_id, pmse_ctx->pmse_arg1,
pmse_ctx->pmse_rcpt_idx);
if (PMT_EXIT(pmt_ctx.pmt_rcode[SM_STAGE_RCPT]))
exit(0);
ret = sm_rcb_putv(&rcbe->rcbe_rcb, RCB_PUTV_FIRST,
SM_RCBV_INT, RT_PROT_VER, PROT_VER_RT,
SM_RCBV_INT, RT_M2S_ID, pmss_ctx->pmss_id,
SM_RCBV_BUF, RT_M2S_SEID, pmse_ctx->pmse_se_id, SMTP_STID_SIZE,
SM_RCBV_INT, RT_M2S_RCODE, pmt_ctx.pmt_rcode[SM_STAGE_RCPT],
SM_RCBV_END);
return ret;
}
sm_ret_T
sm_pmilt_data(pmss_ctx_P pmss_ctx, pmse_ctx_P pmse_ctx, sm_rcbe_P rcbe)
{
sm_ret_T ret;
sm_io_fprintf(smioerr, "sev=DBG, seid=%s, where=data\n",
pmse_ctx->pmse_se_id);
if (PMT_EXIT(pmt_ctx.pmt_rcode[SM_STAGE_DATA]))
exit(0);
ret = sm_rcb_putv(&rcbe->rcbe_rcb, RCB_PUTV_FIRST,
SM_RCBV_INT, RT_PROT_VER, PROT_VER_RT,
SM_RCBV_INT, RT_M2S_ID, pmss_ctx->pmss_id,
SM_RCBV_BUF, RT_M2S_SEID, pmse_ctx->pmse_se_id, SMTP_STID_SIZE,
SM_RCBV_INT, RT_M2S_RCODE, pmt_ctx.pmt_rcode[SM_STAGE_DATA],
SM_RCBV_END);
return ret;
}
static void
pm_open(pmse_ctx_P pmse_ctx)
{
if (PMT_IS_FLAG(&pmt_ctx, PMT_FL_W2F) &&
!PMT_IS_FLAG(&pmt_ctx, PMT_FL_FD_OPEN) &&
!PMT_IS_FLAG(&pmt_ctx, PMT_FL_FD_FAIL))
{
pmt_ctx.pmt_fd = open(pmt_ctx.pmt_fname,
O_WRONLY|O_APPEND|O_CREAT,
0660);
if (pmt_ctx.pmt_fd >= 0)
PMT_SET_FLAG(&pmt_ctx, PMT_FL_FD_OPEN);
else
PMT_SET_FLAG(&pmt_ctx, PMT_FL_FD_FAIL);
sm_io_fprintf(smioerr,
"sev=DBG, seid=%s, where=pm_open, open=%d\n",
pmse_ctx->pmse_se_id, pmt_ctx.pmt_fd);
}
}
sfsistat_T
sm_pmilt_msg(pmss_ctx_P pmss_ctx, pmse_ctx_P pmse_ctx, uchar *buf, size_t len, sm_rcbe_P rcbe)
{
pm_open(pmse_ctx);
if (PMT_IS_FLAG(&pmt_ctx, PMT_FL_W2F) &&
PMT_IS_FLAG(&pmt_ctx, PMT_FL_FD_OPEN) &&
!PMT_IS_FLAG(&pmt_ctx, PMT_FL_WR_FAIL) &&
buf != NULL && len > 0
)
{
ssize_t written;
written = write(pmt_ctx.pmt_fd, buf, len);
if (written == -1)
{
sm_io_fprintf(smioerr,
"sev=ERROR, seid=%s, where=msg, write=%d\n",
pmse_ctx->pmse_se_id, (int) written);
PMT_SET_FLAG(&pmt_ctx, PMT_FL_WR_FAIL);
close(pmt_ctx.pmt_fd);
pmt_ctx.pmt_fd = INVALID_FD;
PMT_CLR_FLAG(&pmt_ctx, PMT_FL_FD_OPEN);
}
}
sm_io_fprintf(smioerr, "sev=DBG, seid=%s, where=msg, len=%d\n",
pmse_ctx->pmse_se_id, (int) len);
return SM_SUCCESS;
}
sm_ret_T
sm_pmilt_dot(pmss_ctx_P pmss_ctx, pmse_ctx_P pmse_ctx, uchar *buf, size_t len, sm_rcbe_P rcbe)
{
sm_ret_T ret;
bool writefailed;
int rcode;
pm_open(pmse_ctx);
if (PMT_IS_FLAG(&pmt_ctx, PMT_FL_W2F) &&
PMT_IS_FLAG(&pmt_ctx, PMT_FL_FD_OPEN) &&
!PMT_IS_FLAG(&pmt_ctx, PMT_FL_WR_FAIL) &&
buf != NULL && len > 0
)
{
ssize_t written;
written = write(pmt_ctx.pmt_fd, buf, len);
if (written == -1)
{
sm_io_fprintf(smioerr,
"sev=ERROR, seid=%s, where=dot, write=%d\n",
pmse_ctx->pmse_se_id, (int) written);
PMT_SET_FLAG(&pmt_ctx, PMT_FL_WR_FAIL);
close(pmt_ctx.pmt_fd);
pmt_ctx.pmt_fd = INVALID_FD;
PMT_CLR_FLAG(&pmt_ctx, PMT_FL_FD_OPEN);
}
}
writefailed = PMT_IS_FLAG(&pmt_ctx, PMT_FL_W2F) &&
PMT_IS_FLAG(&pmt_ctx, PMT_FL_WR_FAIL);
if (PMT_IS_FLAG(&pmt_ctx, PMT_FL_W2F) &&
PMT_IS_FLAG(&pmt_ctx, PMT_FL_FD_OPEN) &&
!PMT_IS_FLAG(&pmt_ctx, PMT_FL_WR_FAIL))
{
int r;
r = close(pmt_ctx.pmt_fd);
sm_io_fprintf(smioerr,
"sev=DBG, seid=%s, where=dot, write=%d\n",
pmse_ctx->pmse_se_id, r);
pmt_ctx.pmt_fd = INVALID_FD;
PMT_CLR_FLAG(&pmt_ctx, PMT_FL_FD_OPEN);
}
rcode = pmt_ctx.pmt_rcode[SM_STAGE_DOT];
if (rcode == SMTP_R_OK && writefailed)
rcode = SMTP_R_TEMP;
sm_io_fprintf(smioerr, "sev=DBG, seid=%s, where=dot, len=%d\n",
pmse_ctx->pmse_se_id, (int) len);
if (PMT_EXIT(pmt_ctx.pmt_rcode[SM_STAGE_DOT]))
exit(0);
ret = sm_rcb_putv(&rcbe->rcbe_rcb, RCB_PUTV_FIRST,
SM_RCBV_INT, RT_PROT_VER, PROT_VER_RT,
SM_RCBV_INT, RT_M2S_ID, pmss_ctx->pmss_id,
SM_RCBV_BUF, RT_M2S_SEID, pmse_ctx->pmse_se_id, SMTP_STID_SIZE,
SM_RCBV_INT, RT_M2S_RCODE, pmt_ctx.pmt_rcode[SM_STAGE_DOT],
SM_RCBV_END);
return ret;
}
sm_ret_T
sm_pmilt_abort_ta(pmss_ctx_P pmss_ctx, pmse_ctx_P pmse_ctx)
{
sm_io_fprintf(smioerr, "sev=DBG, seid=%s, where=abort_ta\n",
pmse_ctx->pmse_se_id);
return SM_SUCCESS;
}
sm_ret_T
sm_pmilt_msg_rplc_stat(pmss_ctx_P pmss_ctx, pmse_ctx_P pmse_ctx, sm_ret_T status)
{
return SM_SUCCESS;
}
/*
** USAGE -- Print usage message to smioerr
**
** Parameters:
** prg -- program name
**
** Returns:
** exits
*/
static void
usage(const char *prg)
{
sm_io_fprintf(smioerr, "usage: %s [options]\n"
#if PMILTER_DEBUG
"-d n set debug level\n"
#endif
"-f name write msg to file\n"
"-r stage=rcode set SMTP reply code for stage to rcode\n"
" stage:\n"
" c: new session (connect)\n"
" h: HELO\n"
" m: MAIL\n"
" r: RCPT\n"
" d: DATA\n"
" B: Body\n"
" rcode=%d will invoke exit() to simulate a fatal error\n"
, prg
, PMT_EXIT_CODE
);
exit(EX_USAGE);
}
/*
** MAIN -- PMILTER test server
**
** Parameters:
** argc -- number of arguments
** argv -- vector of arguments
**
** Returns:
** exit code
*/
int
main(int argc, char *argv[])
{
sm_ret_T ret;
int c, stage;
unsigned int u, off;
pmg_ctx_P pmg_ctx;
char *prg;
prg = argv[0];
pmg_ctx = NULL;
if (getuid() == 0 || geteuid() == 0)
{
sm_io_fprintf(smioerr,
"%s: ERROR: do not run this as super-user!\n",
prg);
exit(EX_USAGE);
}
/* initialize test context */
sm_memzero(&pmt_ctx, sizeof(pmt_ctx));
for (c = 0; c < SM_STAGES; c++)
pmt_ctx.pmt_rcode[c] = SMTP_R_CONT;
pmt_ctx.pmt_fname[0] = '\0';
pmt_ctx.pmt_fd = INVALID_FD;
sm_memzero(&pmilter, sizeof(pmilter));
pmilter.pmfi_name = "t-pmilter-0";
pmilter.pmfi_version = LPMILTER_VERSION;
pmilter.pmfi_dfl_cap = SM_SCAP_PM_BASIC;
pmilter.pmfi_dfl_fct = 0;
pmilter.pmfi_dfl_feat = 0;
pmilter.pmfi_dfl_misc = 0;
/* basic initialization */
ret = sm_pmilt_init0(&pmg_ctx);
if (sm_is_err(ret))
goto error0;
#if SM_HEAP_CHECK
SmHeapCheck = 1;
if (HEAP_CHECK)
sm_heap_report(smioerr, 3);
#endif
while ((c = getopt(argc, argv, "d:f:r:")) != -1)
{
switch (c)
{
case 'd':
#if PMILTER_DEBUG
pm_debug = atoi(optarg);
#endif
break;
case 'f':
strlcpy(pmt_ctx.pmt_fname, optarg,
sizeof(pmt_ctx.pmt_fname));
PMT_SET_FLAG(&pmt_ctx, PMT_FL_W2F);
break;
case 'r':
if (optarg != NULL && ISALPHA(optarg[0])
&& optarg[1] == '=')
off = 2;
else
{
usage(prg);
break;
}
u = (unsigned int) atoi(optarg + off);
stage = sm_getstage(optarg[0]);
if (stage < 0 || stage > SM_STAGES)
{
usage(prg);
/* NOTREACHED */
SM_ASSERT(false);
}
pmt_ctx.pmt_rcode[stage] = u;
break;
default:
usage(prg);
/* NOTREACHED */
SM_ASSERT(false);
break;
}
}
argc -= optind;
argv += optind;
/* XXX HACK */
if (argc > 0)
pmg_ctx->pmg_sockname = argv[0];
else
pmg_ctx->pmg_sockname = "pmilter.sock";
pmg_ctx->pmg_pmilter = &pmilter;
#if 0
/* read config */
ret = sm_pmilt_rdcf(pmg_ctx, argc, argv);
if (sm_is_err(ret))
goto error0;
#endif
/* initialize system */
ret = sm_pmilt_init1(pmg_ctx);
if (sm_is_err(ret))
{
sm_io_fprintf(smioerr, "sev=ERROR, sm_pmilt_init=%x\n", ret);
goto error;
}
/* startup pmilt */
ret = sm_pmilt_start(pmg_ctx);
if (sm_is_err(ret))
{
sm_io_fprintf(smioerr, "sev=ERROR, sm_pmilt_start=%x\n", ret);
goto error;
}
/* wait for events, schedule tasks */
ret = evthr_loop(pmg_ctx->pmg_ev_ctx);
ret = sm_pmilt_stop(pmg_ctx);
#if SM_HEAP_CHECK
if (HEAP_CHECK)
sm_heap_report(smioerr, 3);
#endif
return 0;
error:
/* ignore shutdown errors... */
(void) sm_pmilt_stop(pmg_ctx);
error0:
/* select an appropriate error here... */
return sm_error_value(ret);
}
#else /* MTA_USE_PMILTER */
int
main(int argc, char *argv[])
{
return 0;
}
#endif /* MTA_USE_PMILTER */
syntax highlighted by Code2HTML, v. 0.9.1