/* * Copyright (c) 2002-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: qss_rcptid.c,v 1.79 2007/03/26 03:20:24 ca Exp $") #include "sm/error.h" #include "sm/assert.h" #include "sm/io.h" #include "sm/rcb.h" #include "sm/qmgr.h" #include "sm/qmgr-int.h" #include "sm/reccom.h" #include "sm/rfc2821.h" #include "qmgr.h" #include "log.h" /* ** QM_SS_RCPTID -- check recipient, add to IQDB, write rcpt IBDB record ** ** Parameters: ** qss_ctx -- QMGR/SMTPS context ** qss_ta -- transaction ** tsk -- evthr task ** qss_rcpt -- recipient ("consumed" by this function, caller ** must not access it afterwards) ** ** Returns: ** <0: usual sm_error code ** >=0: acceptance/rejection code */ sm_ret_T qm_ss_rcptid(qss_ctx_P qss_ctx, qss_ta_P qss_ta, sm_evthr_task_P tsk, qss_rcpt_P qss_rcpt) { int flags; ibdb_rcpt_T ibdb_rcpt; sm_a2821_T addr; qss_rcpt_P *rrcpt; sm_ret_T ret, rv; SM_IS_QS_RCPT(qss_rcpt); ret = SM_SUCCESS; rrcpt = NULL; rv = SMTP_R_REJECT; /* do some checks here: is it ok to accept this rcpt?? */ /* check recipient address */ A2821_INIT_RP(&addr, NULL); ret = t2821_scan((sm_rdstr_P) qss_rcpt->qsr_pa, &addr, 0); QM_LEV_DPRINTFC(QDC_S2Q, 5, (QM_DEBFP, "func=qm_ss_rcptid, rcpt=%@S, t2821_scan=%r\n", qss_rcpt->qsr_pa, ret)); if (sm_is_err(ret)) goto errortemp; flags = R2821_CORRECT & ~R2821_AT; ret = t2821_parse(&addr, flags); QM_LEV_DPRINTFC(QDC_S2Q, 5, (QM_DEBFP, "func=qm_ss_rcptid, rcpt=%@S, t2821_parse=%r\n", qss_rcpt->qsr_pa, ret)); /* addr isn't used anymore... */ (void) a2821_free(&addr); if (sm_is_err(ret)) goto errortemp; /* add rcpt to iqdb */ ret = iqdb_rcpt_add(qss_ctx->qss_qmgr_ctx->qmgr_iqdb, qss_rcpt->qsr_id, SMTP_RCPTID_SIZE, qss_rcpt, (void **) &rrcpt, THR_LOCK_UNLOCK); if (sm_is_err(ret)) goto errortemp; QSRCPT_SET_FLAG(qss_rcpt, QSRCPT_FL_IQDB); /* ** XXX call address resolver ** XXX anti-spam/relay checks? (done in SMTPS) ** split here: this function can be "asynchronous" ** hence we need to store the "state" in rcpt and ** add it to some worklist; we can use rcpt_id as id. ** the state is: ** qss_ta (-> qss_ctx -> tsk) ** some state about the rcpt (what is currently happening to it, ** e.g., processed by AR, anti-spam, ...) so it "knows" what to ** do next (-> qsr_flags) ** should we store this in qss_rcpt_T itself or put some struct ** "around" it? The former is simpler, but it "enlarges" qss_rcpt_T ** a bit. */ /* write rcpt to ibd if everything is ok so far */ ibdb_rcpt.ibr_ta_id = qss_ta->qssta_id; ibdb_rcpt.ibr_pa = qss_rcpt->qsr_pa; ibdb_rcpt.ibr_idx = qss_rcpt->qsr_idx; ret = ibdb_rcpt_status(qss_ctx->qss_qmgr_ctx->qmgr_ibdb, &ibdb_rcpt, IBDB_RCPT_NEW, IBDB_FL_NONE, THR_LOCK_UNLOCK); if (sm_is_err(ret)) goto tempfail; QSRCPT_SET_FLAG(qss_rcpt, QSRCPT_FL_IBDB); /* ok so far */ rv = SMTP_R_OK; errortemp: if (sm_is_err(ret)) { if (sm_is_temp_err(ret)) { tempfail: rv = SMTP_R_TEMP; } /* XXX Other errors that trigger this? */ if (sm_error_value(ret) == SM_E_FULL || sm_error_value(ret) == ENOMEM) (void) qss_control(qss_ctx, QMGR_THROTTLE, 100, QMGR_RFL_IQD_I, THR_LOCK_UNLOCK); /* else necessary? */ } #if 0 sm_log_write(qss_ctx->qss_qmgr_ctx->qmgr_lctx, QM_LCAT_SMTPS, QM_LMOD_FROM_SMTPS, SM_LOG_INFO, 12, "func=qm_ss_rcptid, rcpt=%@S, ret=%d", qss_rcpt->qsr_pa, rv); #endif /* 0 */ /* did we accept the recipient? */ if (rv != SMTP_R_OK) { qss_rcpt_free(qss_ta, qss_rcpt, (QSRCPT_IS_FLAG(qss_rcpt, QSRCPT_FL_IQDB) ? QSS_RMFIQDB : 0)|QSS_DECR_RCPTS_TOT); } /* ** This might have been freed already, but it's ok to call the ** function again. Alternatively we could use a pointer and set ** it to NULL after freeing the address. */ (void) a2821_free(&addr); return rv; }