/* * 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 */