/*
* 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: smtpsh.c,v 1.69 2007/10/16 04:20:36 ca Exp $")
#include "sm/assert.h"
#include "sm/error.h"
#include "sm/ctype.h"
#include "sm/memops.h"
#include "sm/io.h"
#include "sm/str.h"
#include "sm/string.h"
#include "sm/time.h"
#include "sm/limits.h"
#include "sm/types.h"
#include "sm/net.h"
#include "statethreads/st.h"
#define MTA_USE_STATETHREADS 1
#include "sm/stsock.h"
#include "sm/tls.h"
#include "sm/tlsbio.h"
#include "sm/sasl.h"
#include "sm/rfc2821.h"
#include "sm/misc.h"
#include "s2q.h"
#include "smtps.h"
#include "s2m.h"
#include "smtpsrv.h"
#include "smtpsh.h"
#include "log.h"
#if MTA_USE_PMILTER
# include "pmilter.h"
#endif
#include "sm/sm-conf-prt.h"
/*
** SSM_MAIL_NEW -- create new mail address
**
** Parameters:
** ss_ta -- SMTP server transaction context
** alloc_pa -- also create sm_str for printable address?
** pmail -- mail (sender) address (output)
**
** Returns:
** usual return code
*/
sm_ret_T
ssm_mail_new(ss_ta_P ss_ta, bool alloc_pa, ss_mail_P *pmail)
{
ss_mail_P mail;
SM_REQUIRE(pmail != NULL);
mail = (ss_mail_P) sm_rpool_zalloc(ss_ta->ssta_rpool, sizeof(*mail));
if (NULL == mail)
return sm_error_temp(SM_EM_SMTPS, ENOMEM);
A2821_INIT_RP(&mail->ssm_a2821, ss_ta->ssta_rpool);
if (alloc_pa) {
mail->ssm_pa = sm_str_new(ss_ta->ssta_rpool, MAXADDRLEN, MAXADDRLEN);
if (NULL == mail->ssm_pa) {
ssm_mail_free(ss_ta, mail);
return sm_error_temp(SM_EM_SMTPS, ENOMEM);
}
}
*pmail = mail;
return SM_SUCCESS;
}
/*
** SSM_MAIL_FREE -- free mail address
**
** Parameters:
** ss_ta -- SMTP server transaction context
** mail -- mail (sender) address
**
** Returns:
** usual return code
*/
sm_ret_T
ssm_mail_free(ss_ta_P ss_ta, ss_mail_P mail)
{
if (NULL == mail)
return SM_SUCCESS;
a2821_free(&mail->ssm_a2821);
SM_STR_FREE(mail->ssm_pa);
sm_rpool_free(ss_ta->ssta_rpool, mail);
return SM_SUCCESS;
}
/*
** SSR_RCPTS_NEW -- add a new recipient to the recipient list
**
** Parameters:
** ss_ta -- SMTP server transaction context
** rcpts -- list of recipients
** prcpt -- new recipient (output)
**
** Returns:
** usual return code
*/
sm_ret_T
ssr_rcpts_new(ss_ta_P ss_ta, ss_rcpts_P rcpts, ss_rcpt_P *prcpt)
{
SM_REQUIRE(rcpts != NULL);
SM_REQUIRE(prcpt != NULL);
*prcpt = (ss_rcpt_P) sm_rpool_zalloc(ss_ta->ssta_rpool, sizeof(**prcpt));
if (*prcpt == NULL)
goto error;
A2821_INIT_RP(&((*prcpt)->ssr_a2821), ss_ta->ssta_rpool);
SS_RCPTS_INSERT_TAIL(rcpts, *prcpt);
(*prcpt)->ssr_idx = ss_ta->ssta_rcpts_tot++;
return SM_SUCCESS;
error:
SM_RPOOL_FREE(ss_ta->ssta_rpool, *prcpt);
return sm_error_temp(SM_EM_SMTPS, ENOMEM);
}
/*
** SSR_RCPT_FREE -- free a single recipient address
**
** Parameters:
** ss_ta -- SMTP server transaction context
** rcpt -- recipient to free
**
** Returns:
** usual return code
*/
sm_ret_T
ssr_rcpt_free(ss_ta_P ss_ta, ss_rcpt_P rcpt)
{
if (NULL == rcpt)
return SM_SUCCESS;
a2821_free(&rcpt->ssr_a2821);
sm_rpool_free(ss_ta->ssta_rpool, rcpt);
/* remove adr from list? it's done by SS_RCPTS_REMOVE_FREE() */
/* XXX adjust some counter? */
return SM_SUCCESS;
}
/*
** SSR_RCPTS_FREE -- free an entire recipient list
**
** Parameters:
** ss_ta -- SMTP server transaction context
** rcpts -- recipient list to free
**
** Returns:
** usual return code
*/
static sm_ret_T
ssr_rcpts_free(ss_ta_P ss_ta, ss_rcpts_P rcpts)
{
ss_rcpt_P ss_rcpt, ss_rcpt_nxt;
if (SS_RCPTS_EMPTY(rcpts))
return SM_SUCCESS;
for (ss_rcpt = SS_RCPTS_FIRST(rcpts); ss_rcpt != SS_RCPTS_END(rcpts);
ss_rcpt = ss_rcpt_nxt)
{
ss_rcpt_nxt = SS_RCPTS_NEXT(ss_rcpt);
/* remove adr from list? use SS_RCPTS_REMOVE_FREE()? */
ssr_rcpt_free(ss_ta, ss_rcpt);
}
SS_RCPTS_INIT(rcpts);
return SM_SUCCESS;
}
#if MTA_USE_PMILTER
/*
** SSR_RCPT_ADD_MOD -- add recipient modification
**
** Parameters:
** ss_sess -- SMTP server session context
** type -- add/delete
** rcpt_idx -- recipient index
**
** Returns:
** usual return code
*/
sm_ret_T
ssr_rcpt_add_mod(ss_sess_P ss_sess, ushort type, rcpt_idx_T rcpt_idx)
{
sm_ret_T ret;
ss_rcpt_P ss_rcpt;
ss_ta_P ss_ta;
ss_rcpt = NULL;
ss_ta = ss_sess->ssse_ta;
if (PM_RCPT_DEL == type) {
ss_rcpts_P ss_rcpt_hd;
/* outside allowed range? */
if (rcpt_idx >= ss_ta->ssta_rcpts_tot_orig) {
sm_log_write(ss_sess->ssse_sctx->ssc_lctx,
SS_LCAT_SERVER, SS_LMOD_SERVER,
SM_LOG_NOTICE, 10,
"sev=NOTICE, func=ssr_rcpt_add_mod, delete_rcpt_idx=%u, max_rcpt_idx=%u"
, rcpt_idx, ss_ta->ssta_rcpts_tot_orig);
return SM_E_NOTFOUND;
}
ss_rcpt_hd = &ss_ta->ssta_rcpts;
for (ss_rcpt = SS_RCPTS_FIRST(ss_rcpt_hd);
ss_rcpt != SS_RCPTS_END(ss_rcpt_hd);
ss_rcpt = SS_RCPTS_NEXT(ss_rcpt))
{
if (ss_rcpt->ssr_idx == rcpt_idx) {
ss_rcpt->ssr_type = type;
ss_rcpt->ssr_rcode = SMTP_R_DISCARD;
--ss_ta->ssta_rcpts_ok; /* ??? */
return SM_SUCCESS;
}
}
sm_log_write(ss_sess->ssse_sctx->ssc_lctx,
SS_LCAT_SERVER, SS_LMOD_SERVER,
SM_LOG_NOTICE, 10,
"sev=NOTICE, func=ssr_rcpt_add_mod, delete_rcpt_idx=%u, status=not_found"
, rcpt_idx);
return SM_E_NOTFOUND;
}
ret = ssr_rcpts_new(ss_ta, &ss_ta->ssta_rcpts, &ss_rcpt);
if (sm_is_err(ret))
goto error;
(void) sm_postmaster_add_domain(ss_sess->ssse_rd,
ss_sess->ssse_sctx->ssc_hostname, 0);
ret = t2821_scan((sm_rdstr_P) ss_sess->ssse_rd, &ss_rcpt->ssr_a2821, 0);
if (sm_is_err(ret))
goto error;
if ((uint)ret < sm_str_getlen(ss_sess->ssse_rd) &&
!ISSPACE(sm_str_rd_elem(ss_sess->ssse_rd, ret)))
goto error;
/* check args: none for now, fixme: misleading error if no address */
if ((uint)ret < sm_str_getlen(ss_sess->ssse_rd))
goto error;
/* checks should be configurable */
ret = t2821_parse(&ss_rcpt->ssr_a2821, R2821_CORRECT);
if (sm_is_err(ret))
goto error;
ss_rcpt->ssr_type = type;
return ret;
error:
if (ss_rcpt != NULL)
SS_RCPTS_REMOVE_FREE(ss_ta, &ss_ta->ssta_rcpts, ss_rcpt);
if (sm_is_success(ret))
ret = sm_err_perm(SM_E_SYNTAX);
return ret;
}
#endif /* MTA_USE_PMILTER */
/*
** SS_TA_CLR -- clear out a transaction context (for reuse)
**
** Parameters:
** ss_ta -- SMTP server transaction context
**
** Returns:
** usual return code
*/
sm_ret_T
ss_ta_clr(ss_ta_P ss_ta)
{
SM_IS_SS_TA(ss_ta);
ssm_mail_free(ss_ta, ss_ta->ssta_mail);
ssr_rcpts_free(ss_ta, &ss_ta->ssta_rcpts);
SM_STR_FREE(ss_ta->ssta_mail_acc.ssa_reply_text);
SM_STR_FREE(ss_ta->ssta_rcpt_acc.ssa_reply_text);
#if MTA_USE_PMILTER
SM_STR_FREE(ss_ta->ssta_msg_acc.ssa_reply_text);
SM_STR_FREE(ss_ta->ssta_mail_new);
sm_hdrmodl_free(&ss_ta->ssta_hdrmodhd);
SM_CSTR_FREE(ss_ta->ssta_cdb_id);
sspm_clrreplies(ss_ta);
#endif
SM_STR_FREE(ss_ta->ssta_msgid);
if (ss_ta->ssta_rpool != NULL) {
sm_rpool_delete(ss_ta->ssta_rpool);
ss_ta->ssta_rpool = NULL;
}
/* clear transaction, also resets counters */
sm_memzero(ss_ta, sizeof(*ss_ta));
SS_RCPTS_INIT(&ss_ta->ssta_rcpts);
#if SS_TA_CHECK
ss_ta->sm_magic = SM_SS_TA_MAGIC;
#endif
return SM_SUCCESS;
}
/*
** SS_TA_ABORT -- abort a transaction
**
** Parameters:
** ss_sess -- SMTP server session context
** ss_ta -- SMTP server transaction context
**
** Returns:
** usual return code
*/
sm_ret_T
ss_ta_abort(ss_sess_P ss_sess, ss_ta_P ss_ta)
{
SM_IS_SS_TA(ss_ta);
/* check existing transaction */
if (ss_ta->ssta_state != SSTA_ST_NONE) {
#if MTA_USE_PMILTER
if (SSTA_IS_FLAG(ss_ta, SSTA_FL_PM_CALLED) &&
SSSE_IS_FLAG(ss_sess, SSSE_FL_PM_USE))
{
sm_ret_T ret;
ss_ctx_P ss_ctx;
ss_ctx = ss_sess->ssse_sctx;
ret = sm_s2m_abort(ss_sess, ss_ctx->ssc_s2m_ctx, ss_sess->ssse_id);
if (sm_is_err(ret)) {
sm_log_write(ss_ctx->ssc_lctx,
SS_LCAT_SERVER, SS_LMOD_SERVER,
SM_LOG_ERROR, 6,
"sev=ERROR, func=ss_ta_abort, ss_sess=%s, sm_s2m_abort=%m"
, ss_sess->ssse_id, ret);
}
}
#endif /* MTA_USE_PMILTER */
/* XXX ... */
/* abort all performed actions */
if (ss_ta->ssta_state >= SSTA_ST_MAIL) {
(void) sm_rcb_close_decn(ss_sess->ssse_rcb);
}
}
ss_ta_clr(ss_ta);
return SM_SUCCESS;
}
/*
** SS_TA_INIT -- initialize transaction context
** ss_ta is NOT allocated, it is a local variable in ss_hdl_session()
**
** Parameters:
** ss_sess -- SMTP server session context
** ss_ta -- SMTP server transaction context
**
** Returns:
** usual return code
*/
sm_ret_T
ss_ta_init(ss_sess_P ss_sess, ss_ta_P ss_ta)
{
sm_rpool_P rp;
sm_ret_T ret;
rp = NULL;
ret = SM_SUCCESS;
sm_memzero(ss_ta, sizeof(*ss_ta));
if (Rpools) {
rp = sm_rpool_new(NULL);
if (NULL == rp) {
ret = sm_error_temp(SM_EM_SMTPS, ENOMEM);
goto error;
}
ss_ta->ssta_rpool = rp;
}
ret = ss_id_next(ss_sess->ssse_sctx->ssc_id, ss_ta->ssta_id);
if (sm_is_err(ret))
goto error;
SS_RCPTS_INIT(&ss_ta->ssta_rcpts);
ss_ta->ssta_state = SSTA_ST_INIT;
/* inherit some flags from session; better (efficient) way?? */
if (SSSE_IS_FLAG(ss_sess, SSSE_FL_DISCARD))
SSTA_SET_FLAG(ss_ta, SSTA_FL_DISCARD);
if (SSSE_IS_CFLAG(ss_sess, SSSE_CFL_DELAY_CHKS))
SSTA_SET_FLAG(ss_ta, SSTA_FL_DELAY_CHKS);
#if MTA_USE_PMILTER
if (SSSE_IS_FLAG(ss_sess, SSSE_FL_PM_USE))
SSTA_SET_FLAG(ss_ta, SSTA_FL_PM_USE);
#endif
#if SS_TA_CHECK
ss_ta->sm_magic = SM_SS_TA_MAGIC;
#endif
return SM_SUCCESS;
error:
if (rp != NULL) {
sm_rpool_delete(rp);
ss_ta->ssta_rpool = NULL;
}
return ret;
}
/*
** SS_SESS_FREE -- free a SMTP server session context
**
** Parameters:
** ss_sess -- SMTP server session context
**
** Returns:
** usual return code
*/
sm_ret_T
ss_sess_free(ss_sess_P ss_sess)
{
ss_ta_P ss_ta;
if (NULL == ss_sess)
return SM_SUCCESS;
/* make sure ss_sess isn't referenced anymore */
if (ss_sess->ssse_sctx != NULL && ss_sess->ssse_sctx->ssc_s2q_ctx != NULL)
(void) ss_clr_sess_rq(ss_sess->ssse_sctx->ssc_s2q_ctx, ss_sess);
/* should this free the ss_ta inside? */
ss_ta = ss_sess->ssse_ta;
if (ss_ta != NULL)
(void) ss_ta_abort(ss_sess, ss_ta);
if (ss_sess->ssse_fp != NULL) {
sm_io_close(ss_sess->ssse_fp, SM_IO_CF_NONE);
ss_sess->ssse_fp = NULL;
#if MTA_USE_TLS
ss_sess->ssse_fptls = NULL;
(void) tlsi_free(ss_sess->ssse_tlsi);
#endif
}
#if MTA_USE_SASL
if (SSSE_IS_FLAG(ss_sess, SSSE_FL_SASL_OK)) {
ss_ctx_P ss_ctx;
ss_ctx = ss_sess->ssse_sctx;
if (ss_ctx != NULL &&
ss_ctx->ssc_sasl_ctx != NULL &&
ss_sess->ssse_sasl_conn != NULL)
{
sasl_dispose(&ss_sess->ssse_sasl_conn);
}
SSSE_CLR_FLAG(ss_sess, SSSE_FL_SASL_OK);
}
#endif /* MTA_USE_SASL */
SM_STR_FREE(ss_sess->ssse_rd);
SM_STR_FREE(ss_sess->ssse_wr);
SM_STR_FREE(ss_sess->ssse_str);
SM_STR_FREE(ss_sess->ssse_helo);
SM_STR_FREE(ss_sess->ssse_acc.ssa_reply_text);
SM_CSTR_FREE(ss_sess->ssse_cltname);
SM_RCB_FREE(ss_sess->ssse_rcb);
#if MTA_USE_PMILTER
/* SM_STR_FREE(ss_sess->ssse_ehlo_acc.ssa_reply_text); */
SM_STR_FREE(ss_sess->ssse_macv);
# if MTA_USE_SASL
SM_STR_FREE(ss_sess->ssse_sasl_mech);
SM_STR_FREE(ss_sess->ssse_sasl_authen);
SM_STR_FREE(ss_sess->ssse_sasl_author);
# endif /* MTA_USE_SASL */
#endif /* MTA_USE_PMILTER */
if (ss_sess->ssse_cond_rd != NULL)
st_cond_destroy(ss_sess->ssse_cond_rd);
#if MTA_USE_TLS
if (ss_sess->ssse_cnf != NULL) {
sm_conf_destroy(ss_sess->ssse_cnf);
ss_sess->ssse_cnf = NULL;
}
#endif
ss_sess->ssse_sctx = NULL;
#if SS_SESS_CHECK
ss_sess->sm_magic = SM_MAGIC_NULL;
#endif
sm_free_size(ss_sess, sizeof(*ss_sess));
return SM_SUCCESS;
}
/*
** SS_SESS_NEW -- create a new SMTP server session context
**
** Parameters:
** ss_ctx -- SMTP server context
** pss_sess -- (pointer to) SMTP server session context (output)
**
** Returns:
** usual return code
*/
sm_ret_T
ss_sess_new(ss_ctx_P ss_ctx, ss_sess_P *pss_sess)
{
sm_str_P str;
sm_ret_T ret;
ss_sess_P ss_sess;
uint u;
extern sm_cstr_P HostnameNone;
SM_REQUIRE(pss_sess != NULL);
ss_sess = (ss_sess_P) sm_zalloc(sizeof(*ss_sess));
if (NULL == ss_sess)
goto errnomem;
str = sm_str_new(NULL, SMTPBUFSIZE, SMTPMAXSIZE);
if (NULL == str)
goto errnomem;
ss_sess->ssse_rd = str;
str = sm_str_new(NULL, SMTPBUFSIZE, SMTPMAXSIZE);
if (NULL == str)
goto errnomem;
ss_sess->ssse_wr = str;
str = sm_str_new(NULL, SMTPBUFSIZE, SMTPMAXSIZE);
if (NULL == str)
goto errnomem;
ss_sess->ssse_str = str;
str = sm_str_new(NULL, 32, SMTPMAXSIZE);
if (NULL == str)
goto errnomem;
ss_sess->ssse_helo = str;
#define NO_EHLONAME "Did_not_use_EHLO/HELO"
sm_str_scat(ss_sess->ssse_helo, NO_EHLONAME);
str = sm_str_new(NULL, 64, SMTPMAXSIZE);
if (NULL == str)
goto errnomem;
ss_sess->ssse_acc.ssa_reply_text = str;
ss_sess->ssse_rcb = sm_rcb_new(NULL, S2Q_RCB_SIZE, QSS_RC_MAXSZ);
if (NULL == ss_sess->ssse_rcb)
goto errnomem;
ss_sess->ssse_cond_rd = st_cond_new();
if (NULL == ss_sess->ssse_cond_rd) {
ret = sm_error_temp(SM_EM_SMTPS, errno);
goto error;
}
ss_sess->ssse_s2q_idx = SSSE_S2Q_IDX_NONE;
#if SS_SESS_CHECK
ss_sess->sm_magic = SM_SS_SESS_MAGIC;
#endif
ss_sess->ssse_cltname = SM_CSTR_DUP(HostnameNone);
#if MTA_USE_TLS
ss_sess->ssse_maprescnf = sm_err_perm(SM_E_NOTFOUND);
ret = tlsi_new(&ss_sess->ssse_tlsi);
#endif
#if MTA_USE_SASL
if (SSC_IS_FLAG(ss_ctx, SSC_FL_SASL_OK))
SSSE_SET_FLAG(ss_sess, SSSE_FL_SASL_OK);
if (SSSE_IS_FLAG(ss_sess, SSSE_FL_SASL_OK)) {
ret = sasl_server_new("smtp",
(const char *)sm_str_getdata(ss_ctx->ssc_hostname),
NULL, NULL, NULL, NULL, 0, &ss_sess->ssse_sasl_conn);
if (ret != SASL_OK) {
SSSE_CLR_FLAG(ss_sess, SSSE_FL_SASL_OK);
sm_log_write(ss_ctx->ssc_lctx,
SS_LCAT_SERVER, SS_LMOD_SERVER,
SM_LOG_WARN, 9,
"sev=WARN, func=ss_sess_new, sasl_server_new=%r",
ret);
}
else {
sm_log_write(ss_ctx->ssc_lctx,
SS_LCAT_SERVER, SS_LMOD_SERVER,
SM_LOG_INFO, 19,
"sev=INFO, func=ss_sess_new, sasl_server_new=%p",
ss_sess->ssse_sasl_conn);
}
}
#if 0
/* security layer not yet implemented */
if (SSSE_IS_FLAG(ss_sess, SSSE_FL_SASL_OK)) {
sasl_security_properties_t ssp;
(void) memset(&ssp, '\0', sizeof ssp);
ssp.max_ssf = 168;
ssp.maxbufsize = MAXOUTLEN;
ssp.security_flags = SASLOpts & SASL_SEC_MASK;
ret = sasl_setprop(conn, SASL_SEC_PROPS, &ssp);
if (ret != SASL_OK) {
SSSE_CLR_FLAG(ss_sess, SSSE_FL_SASL_OK);
sm_log_write(ss_ctx->ssc_lctx,
SS_LCAT_SERVER, SS_LMOD_SERVER,
SM_LOG_WARN, 9,
"sev=WARN, func=ss_sess_new, set_sec=%r",
ret);
}
}
#endif
if (SSSE_IS_FLAG(ss_sess, SSSE_FL_SASL_OK)) {
/*
** SASL set properties for sasl
** set local/remote IP
**
** XXX where exactly are these used/required?
** Kerberos_v4
*/
/* set properties */
sm_memzero(&ss_ctx->ssc_sasl_ctx->sm_sasl_ssp,
sizeof(ss_ctx->ssc_sasl_ctx->sm_sasl_ssp));
ss_ctx->ssc_sasl_ctx->sm_sasl_ssp.security_flags =
ss_ctx->ssc_sasl_ctx->sm_sasl_sec_flags
& SASL_SEC_MAXIMUM;
if (sasl_setprop(ss_sess->ssse_sasl_conn, SASL_SEC_PROPS,
&ss_ctx->ssc_sasl_ctx->sm_sasl_ssp) != SASL_OK)
SSSE_CLR_FLAG(ss_sess, SSSE_FL_SASL_OK);
if (SSSE_IS_FLAG(ss_sess, SSSE_FL_SASL_OK)) {
int ext_ssf;
/*
** external security strength factor;
** currently we have none so zero
*/
ext_ssf = 0;
if (!((sasl_setprop(ss_sess->ssse_sasl_conn,
SASL_SSF_EXTERNAL, &ext_ssf) == SASL_OK) &&
(sasl_setprop(ss_sess->ssse_sasl_conn,
SASL_AUTH_EXTERNAL, NULL) == SASL_OK)))
SSSE_CLR_FLAG(ss_sess, SSSE_FL_SASL_OK);
}
if (SSSE_IS_FLAG(ss_sess, SSSE_FL_SASL_OK)) {
ss_ctx->ssc_sasl_ctx->sm_sasl_n_mechs =
sm_saslmechs(ss_ctx->ssc_sasl_ctx, ss_sess->ssse_sasl_conn,
&ss_sess->ssse_sasl_mech_list);
if (ss_ctx->ssc_sasl_ctx->sm_sasl_n_mechs <= 0)
SSSE_CLR_FLAG(ss_sess, SSSE_FL_SASL_OK);
}
}
sm_log_write(ss_ctx->ssc_lctx,
SS_LCAT_SERVER, SS_LMOD_SERVER,
SM_LOG_INFO, 19,
"sev=INFO, func=ss_sess_new, sasl_conn=%p, flags=%x",
ss_sess->ssse_sasl_conn, ss_sess->ssse_flags);
#endif /* MTA_USE_SASL */
/* inherit some flags from context */
ss_sess->ssse_cnf_flags = ss_ctx->ssc_cnf.ss_cnf_cflags & SSSE_CFL_INHERIT;
if (!SM_IS_FLAG(ss_ctx->ssc_cnf.ss_cnf_cflags, SSC_CFL_PMILTER))
ss_sess->ssse_cnf_flags &= ~SSSE_CFL_RSAD;
#if MTA_USE_TLS
ss_sess->ssse_tlsreq_cnf.tlsreqcnf_viol = ss_ctx->ssc_cnf.ss_cnf_tlsreqfail;
#endif
for (u = 0; u < SS_MAX_COMM_SRVS; u++)
ss_sess->ssse_s2q_id[u] = S2Q_ID_NONE;
ss_sess->ssse_sctx = ss_ctx;
ret = ss_id_next(ss_ctx->ssc_id, ss_sess->ssse_id);
*pss_sess = ss_sess;
return ret;
errnomem:
ret = sm_error_temp(SM_EM_SMTPS, ENOMEM);
error:
if (ss_sess != NULL) {
/* free all allocated data! */
SM_STR_FREE(ss_sess->ssse_rd);
SM_STR_FREE(ss_sess->ssse_wr);
SM_STR_FREE(ss_sess->ssse_str);
SM_STR_FREE(ss_sess->ssse_helo);
SM_STR_FREE(ss_sess->ssse_acc.ssa_reply_text);
SM_CSTR_FREE(ss_sess->ssse_cltname);
SM_RCB_FREE(ss_sess->ssse_rcb);
if (ss_sess->ssse_cond_rd != NULL)
st_cond_destroy(ss_sess->ssse_cond_rd);
#if MTA_USE_TLS
if (ss_sess->ssse_cnf != NULL) {
sm_conf_destroy(ss_sess->ssse_cnf);
ss_sess->ssse_cnf = NULL;
}
#endif
}
/* complain */
sm_log_write(ss_ctx->ssc_lctx,
SS_LCAT_SERVER, SS_LMOD_SERVER,
SM_LOG_ERR, 1,
"sev=ERROR, func=ss_sess_new, status=cannot_create_session_context");
ss_sess_free(ss_sess);
*pss_sess = NULL;
return ret;
}
/*
** SS_SESS_FEAT -- set SMTP server session context features
**
** Parameters:
** ss_sess -- SMTP server session context
**
** Returns:
** usual return code
**
** Side Effects: if a session_feature is found that matches the name
** then its options are copied into the session context.
*/
static sm_ret_T
ss_sess_feat(ss_sess_P ss_sess, const char *feat_name, size_t feat_name_len)
{
uint u;
ss_ctx_P ss_ctx;
SM_IS_SS_SESS(ss_sess);
ss_ctx = ss_sess->ssse_sctx;
SM_IS_SS_CTX(ss_ctx);
if (NULL == feat_name)
return SM_NOMATCH;
if (0 == feat_name_len)
return SM_NOMATCH;
if (NULL == ss_ctx->ssc_cnf.ss_cnf_se_feats.sssfs_feat)
return SM_NOMATCH;
for (u = 0; u < ss_ctx->ssc_cnf.ss_cnf_se_feats.sssfs_n; u++) {
ss_se_feat_T ss_se_feat;
ss_se_feat = ss_ctx->ssc_cnf.ss_cnf_se_feats.sssfs_feat[u];
if (ss_se_feat.sssf_name != NULL
&& strlen(ss_se_feat.sssf_name) == feat_name_len
&& sm_memeq(ss_se_feat.sssf_name, feat_name, feat_name_len))
{
ss_sess->ssse_cnf_flags = ss_se_feat.sssf_flags & SSSE_CFL_INHERIT;
return SM_SUCCESS;
}
}
return SM_NOMATCH;
}
/*
** SS_SESS_CONF -- set SMTP server session context configuration
**
** Parameters:
** ss_sess -- SMTP server session context
**
** Returns:
** usual return code
*/
static sm_conf_definition_T
ssse_tlsreq_defs[] = {
TLSREQ_DEFS(tlsreq_cnf_T, tlsreqcnf),
/* Sentinel */
{ SM_CONF_DEF_MAGIC, NULL, 0, 0, 0, NULL, 0, NULL, NULL, NULL, NULL SM_LC_NO_ISSET SM_LC_SET_MAGIC(0)}
};
static sm_conf_definition_T
ssse_mapcnf_defs[] = {
{ SM_CONF_DEF_MAGIC, "tls_requirements", sm_conf_type_section,
offsetof(ss_sess_T, ssse_tlsreq_cnf), sizeof(tlsreq_cnf_T), NULL,
SM_CONF_FLAG_KEEP_DEFAULT,
ssse_tlsreq_defs,
NULL, NULL, NULL
SM_LC_NO_ISSET SM_LC_SET_MAGIC(0) },
{ SM_CONF_DEF_MAGIC, "session_feature", sm_conf_type_string,
offsetof(ss_sess_T, ssse_feat_name), 0,
NULL,
0, NULL, NULL, NULL,
"name of session feature"
SM_LC_NO_ISSET SM_LC_SET_MAGIC(0) },
/* Sentinel */
{ SM_CONF_DEF_MAGIC, NULL, 0, 0, 0, NULL, 0, NULL, NULL, NULL, NULL SM_LC_NO_ISSET SM_LC_SET_MAGIC(0)}
};
sm_ret_T
ss_sess_conf(ss_sess_P ss_sess)
{
int err;
ss_ctx_P ss_ctx;
#define SS_SESS_CONF "ss_session_conf"
SM_IS_SS_SESS(ss_sess);
ss_ctx = ss_sess->ssse_sctx;
SM_IS_SS_CTX(ss_ctx);
ss_sess->ssse_cnf = sm_conf_new(SS_SESS_CONF);
if (NULL == ss_sess->ssse_cnf) {
err = errno;
sm_log_write(ss_ctx->ssc_lctx,
SS_LCAT_SERVER, SS_LMOD_SERVER,
SM_LOG_ERR, 8,
"sev=ERROR, func=ss_sess_conf, sm_conf_new=NULL, errno=%d\n",
err);
return sm_error_temp(SM_EM_SMTPS, ENOMEM);
}
err = sm_conf_read_data(ss_sess->ssse_cnf,
(char *)sm_str_getdata(ss_sess->ssse_str),
sm_str_getlen(ss_sess->ssse_str), true);
if (err != 0) {
sm_prt_conferr(SS_SESS_CONF, ss_sess->ssse_cnf, err, smioerr);
sm_log_write(ss_ctx->ssc_lctx,
SS_LCAT_SERVER, SS_LMOD_SERVER,
SM_LOG_ERR, 8,
"sev=ERROR, func=ss_sess_conf, sm_conf_read_data=%m\n",
err);
sm_conf_destroy(ss_sess->ssse_cnf);
ss_sess->ssse_cnf = NULL;
return err;
}
err = sm_conf_scan(ss_sess->ssse_cnf, ssse_mapcnf_defs, 0, ss_sess);
if (err != 0) {
sm_log_write(ss_ctx->ssc_lctx,
SS_LCAT_SERVER, SS_LMOD_SERVER,
SM_LOG_ERR, 8,
"sev=ERROR, func=ss_sess_conf, sm_conf_scan=%m\n",
err);
}
if (ss_ctx->ssc_cnf.ss_cnf_se_feats.sssfs_n > 0 &&
ss_sess->ssse_feat_name != NULL) {
sm_ret_T r;
r = ss_sess_feat(ss_sess, ss_sess->ssse_feat_name,
strlen(ss_sess->ssse_feat_name));
sm_log_write(ss_ctx->ssc_lctx,
SS_LCAT_SERVER, SS_LMOD_SERVER,
SM_LOG_DEBUG, 12,
"sev=DBG, func=ss_sess_conf, ss_sess=%s, session_features=%#s, ss_sess_feat=%r"
, ss_sess->ssse_id, ss_sess->ssse_feat_name, r);
}
return err;
}
syntax highlighted by Code2HTML, v. 0.9.1