/* * Copyright (c) 2004, 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: pmilter_smtps.c,v 1.12 2006/10/05 04:27:38 ca Exp $") #include "sm/error.h" #include "sm/assert.h" #include "sm/io.h" #include "sm/rcb.h" #include "pmilter.h" #if MTA_USE_PMILTER /* ** SM_PMILT2SMTPS -- PMILTER - SMTPS interface ** Called if socket is writable. ** ** Parameters: ** tsk -- evthr task ** ** Returns: ** usual sm_error code ** ** Last code review: */ static sm_ret_T sm_pmilt2smtps(sm_evthr_task_P tsk) { sm_ret_T ret; pmss_ctx_P pmss_ctx; SM_IS_EVTHR_TSK(tsk); pmss_ctx = (pmss_ctx_P) tsk->evthr_t_actx; SM_IS_PMSS_CTX(pmss_ctx); ret = sm_rcbcom2mod(tsk, &pmss_ctx->pmss_com); return ret; } /* ** SM_PMILT_SMTPS -- PMILTER - SMTPS interface ** This runs as a task. ** ** Parameters: ** tsk -- evthr task ** ** Returns: ** usual sm_error code */ static sm_ret_T sm_pmilt_smtps(sm_evthr_task_P tsk) { sm_ret_T ret; SM_IS_EVTHR_TSK(tsk); PM_LEV_DPRINTF(3, (PM_DEBFP, "sev=DBG, func=sm_pmilt_smtps, fd=%d, ev_rq=%x, ev_occ=%x\n", tsk->evthr_t_fd, evthr_rqevents(tsk), tsk->evthr_t_evocc)); if (is_valid_fd(tsk->evthr_t_fd)) { ret = EVTHR_WAITQ; if (evthr_got_slp(tsk)) { #if 0 sm_ret_T res; /* don't set ret here, it's the wrong return value */ res = sm_smtps_wakeup(tsk); if (sm_is_err(res)) { PM_LEV_DPRINTF(3, (PM_DEBFP, "sev=DBG, func=sm_pmilt_smtps, sm_smtps_wakeup=%x\n", res)); } #endif /* 0 */ } if (evthr_got_wr(tsk)) { ret = sm_pmilt2smtps(tsk); if (sm_is_err(ret)) { sm_io_fprintf(smioerr, "sev=DBG, func=sm_pmilt_smtps, sm_pmilt2smtps=%x\n", ret); /* really return here? */ return ret; } } if (evthr_got_rd(tsk)) { /* ** This routine could set EVTHR_EV_WR ** to cause data to be written back to the SMTPS. ** However, most of the routines may work ** asynchronously and hence they should return the ** correct value themselves. */ ret = sm_smtps2pmilt(tsk); if (sm_is_err(ret)) { sm_io_fprintf(smioerr, "sev=DBG, func=sm_pmilt_smtps, sm_smtps2pmilt=%x\n", ret); return ret; } } PM_LEV_DPRINTF(3, (PM_DEBFP, "sev=DBG, func=sm_pmilt_smtps, ret=%x\n", ret)); return ret; } return EVTHR_DEL; } /* ** SM_PMILT_SMTPSLI -- Handle new connections from SMTPS ** This runs as a (listen) task. ** ** Parameters: ** tsk -- evthr task ** ** Returns: ** usual sm_error code ** ** Last code review: */ sm_ret_T sm_pmilt_smtpsli(sm_evthr_task_P tsk) { int fd, r; uint u; uint32_t j; sm_ret_T ret; sm_evthr_task_P task; pmg_ctx_P pmg_ctx; pmss_ctx_P pmss_ctx; SM_IS_EVTHR_TSK(tsk); SM_REQUIRE(tsk->evthr_t_nc != NULL); fd = INVALID_FD; pmg_ctx = (pmg_ctx_P) tsk->evthr_t_actx; SM_IS_PMG_CTX(pmg_ctx); #if 0 PM_LEV_DPRINTF(3, (PM_DEBFP, "func=sm_pmilt_smtpsli, status=new_connection\n")); #endif /* 0 */ /* add the new connection */ if (tsk->evthr_t_nc != NULL && is_valid_fd(fd = tsk->evthr_t_nc->evthr_a_fd)) { r = pthread_mutex_lock(&pmg_ctx->pmg_mutex); SM_LOCK_OK(r); if (r != 0) { /* LOG */ sm_io_fprintf(smioerr, "sev=ERROR, func=sm_pmilt_smtpsli, cannot get lock=%d\n", r); goto error; } if (pmg_ctx->pmg_ssnfd >= SM_ARRAY_SIZE(pmg_ctx->pmg_sctx)) { /* LOG */ /* too many: don't accept it */ /* XXX maybe turn off accept job if max is reached? */ sm_io_fprintf(smioerr, "sev=ERROR, func=sm_pmilt_smtpsli, too many connections\n"); goto err2; } pmss_ctx = NULL; /* search for free sss ctx */ for (j = 1, u = 0; u < SM_ARRAY_SIZE(pmg_ctx->pmg_sctx); u++, j *= 2) { if ((pmg_ctx->pmg_sused & j) == 0) { pmg_ctx->pmg_sused |= j; pmss_ctx = pmg_ctx->pmg_sctx[u]; #if 0 pmss_ctx->pmss_status = PMSS_ST_NONE; #endif /* 0 */ pmss_ctx->pmss_id = PMSS_ID_NONE; pmss_ctx->pmss_bit = j; break; } } if (u >= SM_ARRAY_SIZE(pmg_ctx->pmg_sctx)) { /* see above */ sm_io_fprintf(smioerr, "sev=ERROR, func=sm_pmilt_smtpsli, no free connection\n"); goto err2; } ret = sm_rcb_open_rcv(pmss_ctx->pmss_com.rcbcom_rdrcb); if (sm_is_err(ret)) { sm_io_fprintf(smioerr, "sev=ERROR, func=sm_pmilt_smtpsli, sm_rcb_open_rcv failed=%x\n", ret); goto err3; } ret = sm_fd_nonblock(fd, true); if (sm_is_err(ret)) { sm_io_fprintf(smioerr, "sev=ERROR, func=sm_pmilt_smtpsli, sm_fd_nonblock=%x\n", ret); goto err3; } pmg_ctx->pmg_ssnfd++; /* start a task for the new SMTPS */ ret = evthr_task_new(pmg_ctx->pmg_ev_ctx, &task, EVTHR_EV_RD, fd, NULL, sm_pmilt_smtps, pmss_ctx); if (sm_is_err(ret)) { sm_io_fprintf(smioerr, "sev=ERROR, func=sm_pmilt_smtpsli, evthr_task_new failed=%x\n", ret); goto err3; } else { PM_LEV_DPRINTF(3, (PM_DEBFP, "sev=DBG, func=sm_pmilt_smtpsli, fd=%d, task=%p\n" , fd, task)); } SM_IS_EVTHR_TSK(task); pmss_ctx->pmss_com.rcbcom_tsk = task; } r = pthread_mutex_unlock(&pmg_ctx->pmg_mutex); SM_ASSERT(r == 0); /* r isn't checked further; will fail on next iteration */ return EVTHR_WAITQ; err3: pmg_ctx->pmg_sused &= ~j; err2: r = pthread_mutex_unlock(&pmg_ctx->pmg_mutex); SM_ASSERT(r == 0); /* r isn't checked further; will fail on next iteration */ error: if (is_valid_fd(fd)) close(fd); return EVTHR_WAITQ; } #endif /* MTA_USE_PMILTER */