/*
* Copyright (c) 2002-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: qm_ssh.c,v 1.74 2007/03/27 03:04:41 ca Exp $")
#include "sm/error.h"
#include "sm/assert.h"
#include "sm/memops.h"
#include "sm/hdrmod.h"
#include "sm/qmgr.h"
#include "sm/qmgr-int.h"
#include "qmgr.h"
/*
** This module contains (de)allocation functions for QMGR/SMTPS related data.
*/
/*
** QSS_MAIL_NEW -- create new QMGR/SMTPS mail entry
**
** Parameters:
** qss_ta -- QMGR/SMTPS transaction
**
** Returns:
** usual sm_error code
**
** Last code review:
** Last code change:
*/
sm_ret_T
qss_mail_new(qss_ta_P qss_ta)
{
qss_mail_P qss_mail;
SM_IS_QS_TA(qss_ta);
qss_mail = (qss_mail_P) sm_rpool_zalloc(qss_ta->qssta_rpool,
sizeof(*qss_mail));
if (NULL == qss_mail)
return sm_error_temp(SM_EM_Q_Q2SS, ENOMEM);
qss_ta->qssta_mail = qss_mail;
return SM_SUCCESS;
}
/*
** QSS_MAIL_FREE -- free QMGR/SMTPS mail entry
**
** Parameters:
** qss_ta -- QMGR/SMTPS transaction
**
** Returns:
** SM_SUCCESS
**
** Last code review: 2005-04-01 18:09:25
** Last code change:
*/
sm_ret_T
qss_mail_free(qss_ta_P qss_ta)
{
SM_IS_QS_TA(qss_ta);
if (NULL == qss_ta->qssta_mail)
return SM_SUCCESS;
SM_STR_FREE(qss_ta->qssta_mail->qsm_pa);
SM_RPOOL_FREE(qss_ta->qssta_rpool, qss_ta->qssta_mail);
return SM_SUCCESS;
}
/*
** QSS_RCPTS_NEW -- create new QMGR/SMTPS recipient and add it to rcpt list
**
** Parameters:
** qss_ta -- QMGR/SMTPS transaction
** prcpt_pa -- (pointer to) recipient printable address
** rcpt_idx -- recipient index
** prcpt -- (pointer to) recipient (output)
**
** Returns:
** usual sm_error code
**
** Last code review:
** Last code change:
*/
sm_ret_T
qss_rcpts_new(qss_ta_P qss_ta, sm_str_P *prcpt_pa, rcpt_idx_T rcpt_idx, qss_rcpt_P *prcpt)
{
qss_rcpt_P qss_rcpt;
SM_IS_QS_TA(qss_ta);
SM_REQUIRE(prcpt_pa != NULL && *prcpt_pa != NULL);
SM_REQUIRE(prcpt != NULL);
if (qss_ta->qssta_rcpts_tot >= SMTP_RCPTIDX_MAX)
return sm_error_temp(SM_EM_Q_Q2SS, SM_E_FULL);
qss_rcpt = (qss_rcpt_P) sm_rpool_zalloc(qss_ta->qssta_rpool,
sizeof(*qss_rcpt));
if (NULL == qss_rcpt)
goto error;
qss_rcpt->qsr_pa = *prcpt_pa;
*prcpt_pa = NULL;
qss_rcpt->qsr_idx = rcpt_idx;
sm_snprintf(qss_rcpt->qsr_id, sizeof(qss_rcpt->qsr_id),
SMTP_RCPTID_FORMAT, qss_ta->qssta_id, rcpt_idx);
QSRCPTS_INSERT_TAIL(&qss_ta->qssta_rcpts, qss_rcpt);
++qss_ta->qssta_rcpts_tot;
*prcpt = qss_rcpt;
return SM_SUCCESS;
error:
SM_RPOOL_FREE(qss_ta->qssta_rpool, qss_rcpt);
return sm_error_temp(SM_EM_Q_Q2SS, ENOMEM);
}
/*
** QSS_RCPT_FREE -- free a single QMGR/SMTPS recipient address
**
** Parameters:
** qss_ta -- QMGR/SMTPS transaction
** qss_rcpt -- QMGR/SMTPS recipient
** rmflags -- various flags (qmgr/qmgr.h: QSS_)
**
** Returns:
** SM_SUCCESS
**
** Last code review: 2005-04-01 18:12:03
** Last code change: 2005-04-01 18:10:42
*/
sm_ret_T
qss_rcpt_free(qss_ta_P qss_ta, qss_rcpt_P qss_rcpt, uint rmflags)
{
if (NULL == qss_rcpt)
return SM_SUCCESS;
SM_IS_QS_TA(qss_ta);
sm_str_free(qss_rcpt->qsr_pa);
QSRCPTS_REMOVE(&qss_ta->qssta_rcpts, qss_rcpt);
if (SM_IS_FLAG(rmflags, QSS_RMFIQDB)) {
qmgr_ctx_P qmgr_ctx;
qmgr_ctx = qss_ta->qssta_ssctx->qss_qmgr_ctx;
iqdb_rcpt_rm(qmgr_ctx->qmgr_iqdb,
qss_rcpt->qsr_id, SMTP_RCPTID_SIZE,
SM_IS_FLAG(rmflags, QSS_IQDB_NOLOCK)
? THR_NO_LOCK : THR_LOCK_UNLOCK);
if (QMGR_IS_RFLAG_I(qmgr_ctx, QMGR_RFL_IQD)) {
(void) qm_resource(qmgr_ctx, QMGR_UN_THROTTLE,
iqdb_usage(qmgr_ctx->qmgr_iqdb),
QMGR_RFL_IQD);
}
}
sm_rpool_free(qss_ta->qssta_rpool, qss_rcpt);
if (SM_IS_FLAG(rmflags, QSS_DECR_RCPTS_TOT)) {
SM_ASSERT(qss_ta->qssta_rcpts_tot > 0);
--qss_ta->qssta_rcpts_tot;
}
return SM_SUCCESS;
}
/*
** QSS_RCPTS_FREE -- free an entire QMGR/SMTPS recipient list
**
** Parameters:
** qss_ta -- QMGR/SMTPS transaction
** rmflags -- various flags (for qss_rcpt_free())
** prcpt_idx_high -- (pointer to) highest rcpt idx (output)
**
** Returns:
** SM_SUCCESS (or SM_NOTDONE)
**
** Last code review: 2005-04-01 18:12:30
** Last code change: 2006-08-05 04:02:31
*/
sm_ret_T
qss_rcpts_free(qss_ta_P qss_ta, uint rmflags, rcpt_idx_T *prcpt_idx_high)
{
qss_rcpts_P qss_rcpts;
qss_rcpt_P qss_rcpt, qss_nxt_rcpt;
rcpt_idx_T rcpt_idx_high;
SM_IS_QS_TA(qss_ta);
qss_rcpts = &qss_ta->qssta_rcpts;
if (QSRCPTS_EMPTY(qss_rcpts))
return SM_NOTDONE;
rcpt_idx_high = 0;
for (qss_rcpt = QSRCPTS_FIRST(qss_rcpts);
qss_rcpt != QSRCPTS_END(qss_rcpts);
qss_rcpt = qss_nxt_rcpt)
{
qss_nxt_rcpt = QSRCPTS_NEXT(qss_rcpt);
if (rcpt_idx_high < qss_rcpt->qsr_idx)
rcpt_idx_high = qss_rcpt->qsr_idx;
qss_rcpt_free(qss_ta, qss_rcpt, rmflags);
}
QSRCPTS_INIT(&qss_ta->qssta_rcpts);
if (prcpt_idx_high != NULL)
*prcpt_idx_high = rcpt_idx_high;
return SM_SUCCESS;
}
/*
** QSS_TA_CLR -- clear out a QMGR/SMTPS transaction
**
** Parameters:
** qss_ta -- QMGR/SMTPS transaction
** rmflags -- various flags (for qss_rcpt_free())
**
** Returns:
** SM_SUCCESS
**
** Last code review: 2005-04-01 18:12:44
** Last code change:
*/
static sm_ret_T
qss_ta_clr(qss_ta_P qss_ta, uint rmflags)
{
SM_IS_QS_TA(qss_ta);
/*
** If all data inside qss_ta is allocated via rpool,
** we could simply free the rpool.
** Cleanup functions (resources) could be registered with
** the rpool... future enhancement??
*/
qss_mail_free(qss_ta);
qss_rcpts_free(qss_ta, rmflags, NULL);
if (qss_ta->qssta_rpool != NULL) {
sm_rpool_delete(qss_ta->qssta_rpool);
qss_ta->qssta_rpool = NULL;
}
SM_CSTR_FREE(qss_ta->qssta_cdb_id);
sm_hdrmodl_free(&qss_ta->qssta_hdrmodhd);
/* clear transaction */
sm_memzero(qss_ta, sizeof(*qss_ta));
QSRCPTS_INIT(&qss_ta->qssta_rcpts);
return SM_SUCCESS;
}
#if 0
///*
//** QSS_TA_ABORT -- abort a QMGR/SMTPS transaction
//**
//** Parameters:
//** qss_ta -- QMGR/SMTPS transaction
//**
//** Returns:
//** usual sm_error code
//**
//** Comments:
//** this is currently not really used.
//*/
//
//sm_ret_T
//qss_ta_abort(qss_ta_P qss_ta)
//{
// SM_IS_QS_TA(qss_ta);
//
//#if 0
// /* check existing transaction */
// if (qss_ta->qssta_state != STA_NONE)
// {
// /* XXX ... */
// /* abort all performed actions */
//
// }
//#endif
//
// /* XXX should this be dependent on the state? */
// qss_ta_clr(qss_ta, QSS_RMFIQDB);
// return SM_SUCCESS;
//}
#endif /* 0 */
/*
** QSS_TA_FREE -- free a QMGR/SMTPS transaction
**
** Parameters:
** qss_ta -- QMGR/SMTPS transaction
** unlock -- transaction is locked: unlock it before freeing
** flag -- from where is qss_ta removed?
** rmflags -- various flags (qmgr/qmgr.h: QSS_)
**
** Returns:
** SM_SUCCESS except for (un)lock errors
**
** Last code review: 2005-04-01 18:17:03
** Last code change: 2005-04-01 18:06:05
*/
sm_ret_T
qss_ta_free(qss_ta_P qss_ta, bool unlock, uint flag, uint rmflags)
{
int r;
uint flags;
if (NULL == qss_ta) {
if (unlock)
QM_LEV_DPRINTFC(QDC_Q2S, 0, (QM_DEBFP,
"sev=ERROR, func=qss_ta_free, status=qss_ta_is_NULL_but_unlock_is_set\n"));
SM_ASSERT(!unlock);
return SM_SUCCESS;
}
SM_IS_QS_TA(qss_ta);
/*
** Get a copy of flags before unlocking qss_ta.
** Alternatively unlock qss_ta after the check down below.
*/
flags = qss_ta->qssta_flags;
QM_LEV_DPRINTFC(QDC_Q2S, 1, (QM_DEBFP, "sev=DBG, func=qss_ta_free, qss_ta=%p, flags=%#x, flag=%#x, unlock=%d, free=%d\n", qss_ta, flags, flag, unlock, QSS_TA_OK_FREE(flags)
));
if (unlock) {
r = pthread_mutex_unlock(&qss_ta->qssta_mutex);
if (r != 0) {
QM_LEV_DPRINTFC(QDC_Q2S, 0, (QM_DEBFP, "sev=ERROR, func=qss_ta_free, unlock=%d\n", r));
SM_ASSERT(r == 0);
return sm_error_perm(SM_EM_Q_Q2SS, r);
}
}
/* more conditions when to remove qss_ta? */
if (SM_IS_FLAG(flag, QSS_TA_FREE_ALWAYS) || QSS_TA_OK_FREE(flags)) {
(void) pthread_mutex_destroy(&qss_ta->qssta_mutex);
(void) qss_ta_clr(qss_ta, rmflags);
#if QS_TA_CHECK
qss_ta->sm_magic = SM_MAGIC_NULL;
#endif
sm_free_size(qss_ta, sizeof(*qss_ta));
}
return SM_SUCCESS;
}
/*
** QSS_TA_NEW -- create new QMGR/SMTPS transaction
** Note: qssta_cdb_id is not allocated here, it's done when an RCB is read
**
** Parameters:
** pqss_ta -- QMGR/SMTPS transaction (output)
** qss_ctx -- QMGR/SMTPS context
** rpool -- rpool: only for data in qss_ta, not for qss_ta itself
**
** Returns:
** usual sm_error code
**
** Last code review:
** Last code change:
*/
sm_ret_T
qss_ta_new(qss_ta_P *pqss_ta, qss_ctx_P qss_ctx, sm_rpool_P rpool)
{
int r;
sm_ret_T ret;
qss_ta_P qss_ta;
SM_REQUIRE(pqss_ta != NULL);
SM_IS_QSS_CTX(qss_ctx);
qss_ta = (qss_ta_P) sm_zalloc(sizeof(*qss_ta));
if (NULL == qss_ta)
return sm_error_temp(SM_EM_Q_Q2SS, ENOMEM);
r = pthread_mutex_init(&qss_ta->qssta_mutex, SM_PTHREAD_MUTEXATTR);
if (r != 0) {
ret = sm_error_perm(SM_EM_Q_Q2SS, r);
goto error;
}
qss_ta->qssta_rpool = rpool;
qss_ta->qssta_ssctx = qss_ctx;
QSRCPTS_INIT(&qss_ta->qssta_rcpts);
#if 0
qss_ta->qssta_sess = sess;
#endif
#if QS_TA_CHECK
qss_ta->sm_magic = SM_QSS_TA_MAGIC;
#endif
*pqss_ta = qss_ta;
return SM_SUCCESS;
error:
if (*pqss_ta != NULL)
sm_free_size(*pqss_ta, sizeof(**pqss_ta));
*pqss_ta = NULL;
return ret;
}
/*
** QSS_SESS_FREE -- free QMGR/SMTPS session
**
** Parameters:
** qss_sess -- QMGR/SMTPS session
**
** Returns:
** usual sm_error code
**
** Last code review: 2005-04-10 05:28:30
** Last code change: 2005-04-10 05:28:26
*/
sm_ret_T
qss_sess_free(qss_sess_P qss_sess)
{
if (NULL == qss_sess)
return SM_SUCCESS;
SM_IS_QS_SE(qss_sess);
#if 0
/* should this free the ta inside? we don't know the current ta! */
qss_ta = qss_sess->sss_ta;
if (qss_ta != NULL)
qss_ta_abort(qss_ta);
#endif
#if QS_SE_CHECK
qss_sess->sm_magic = SM_MAGIC_NULL;
#endif
sm_free_size(qss_sess, sizeof(*qss_sess));
return SM_SUCCESS;
}
/*
** QSS_SESS_NEW -- create new QMGR/SMTPS session
**
** Parameters:
** pqss_sess -- (pointer to) QMGR/SMTPS session (output)
** rpool -- rpool: for data in qss_sess, not for qss_sess itself
**
** Returns:
** usual sm_error code
**
** Last code review:
** Last code change:
*/
/* pass it an rpool or let it create one?? */
sm_ret_T
qss_sess_new(qss_sess_P *pqss_sess, sm_rpool_P rpool)
{
SM_REQUIRE(pqss_sess != NULL);
*pqss_sess = (qss_sess_P) sm_zalloc(sizeof(**pqss_sess));
if (*pqss_sess == NULL)
goto error;
(*pqss_sess)->qsess_rpool = rpool;
#if QS_SE_CHECK
(*pqss_sess)->sm_magic = SM_QSS_SE_MAGIC;
#endif
return SM_SUCCESS;
error:
/* complain?? */
/* qss_sess_free(*pqss_sess); not needed now */
return sm_error_temp(SM_EM_Q_Q2SS, ENOMEM);
}
syntax highlighted by Code2HTML, v. 0.9.1