/* * 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: clt2ar.c,v 1.93 2007/06/03 17:03:04 ca Exp $") #include "sm/error.h" #include "sm/assert.h" #include "sm/memops.h" #include "sm/io.h" #include "sm/net.h" #include "sm/rcb.h" #include "sm/mta.h" #include "sm/rfc2821.h" #include "smar.h" #include "reverse.h" #include "log.h" #include "sm/qmgrcomm.h" #include "sm/reccom.h" /* ** SMAR_SET_MAX_THRDS -- set maximum number of threads ** ** Parameters: ** smar_ctx -- SMAR context ** ** Returns: ** usual sm_error code ** ** input: smar_ctx->smar_max_reqs ** Side Effects: may change number of threads in evthr and values ** in smar_ctx ** ** Last code review: ** Last code change: */ static sm_ret_T smar_set_max_threads(smar_ctx_P smar_ctx) { #if SMAR_SET_MAX_THREADS SMAR_LEV_DPRINTF(4, (SMAR_DEBFP, "sev=DBG, func=smar_set_max_threads, max_reqs=%u, max_thrds_s=%u, max_thrds_h=%u\n", smar_ctx->smar_max_reqs, smar_ctx->smar_max_thrds_s, smar_ctx->smar_max_thrds_h)); if (smar_ctx->smar_max_reqs <= smar_ctx->smar_max_thrds_s) return SM_SUCCESS; smar_ctx->smar_max_thrds_s = smar_ctx->smar_max_reqs; if (smar_ctx->smar_max_thrds_s <= smar_ctx->smar_cnf.smar_cnf_maxthr) return SM_SUCCESS; if (smar_ctx->smar_max_thrds_s > smar_ctx->smar_max_thrds_h) { smar_ctx->smar_max_thrds_h = smar_ctx->smar_max_thrds_s * 2; /* overflow? */ if (smar_ctx->smar_max_thrds_s > smar_ctx->smar_max_thrds_h) smar_ctx->smar_max_thrds_h = UINT_MAX; evthr_set_max_h(smar_ctx->smar_ev_ctx, smar_ctx->smar_max_thrds_h); } evthr_set_max_s(smar_ctx->smar_ev_ctx, smar_ctx->smar_max_thrds_s); #endif /* SMAR_SET_MAX_THREADS */ return SM_SUCCESS; } /* ** SMAR_REACT -- Decode data received from client and act accordingly ** ** Parameters: ** smar_clt_ctx -- SMAR client context ** tsk -- evthr task ** ** Returns: ** usual sm_error code ** ** Last code review: ** Last code change: */ static sm_ret_T smar_react(smar_clt_ctx_P smar_clt_ctx, sm_evthr_task_P tsk) { uint32_t v, l, rt, tl; sm_ret_T ret, res; sm_rcb_P rcb; sm_rcbe_P rcbe; bool inwaitq; smar_rcpt_P smar_rcpt; smar_rcpts_P smar_rcpts; smar_ctx_P smar_ctx; SM_IS_SMAR_CLT_CTX(smar_clt_ctx); smar_ctx = smar_clt_ctx->smac_ar_ctx; SM_IS_SMAR_CTX(smar_ctx); ret = res = SM_SUCCESS; inwaitq = false; smar_rcpt = NULL; smar_rcpts = NULL; rcbe = NULL; /* Decode rcb */ rcb = smar_clt_ctx->smac_com_ctx.rcbcom_rdrcb; ret = sm_rcb_open_dec(rcb); if (sm_is_err(ret)) goto error; /* Total length of record */ ret = sm_rcb_getuint32(rcb, &tl); if (sm_is_err(ret) || tl > QM_AR_MAX_REC_LEN || tl > sm_rcb_getlen(rcb)) { res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL); goto err2; } /* protocol header: version */ ret = sm_rcb_get3uint32(rcb, &l, &rt, &v); if (sm_is_err(ret) || l != 4 || rt != RT_PROT_VER || v != PROT_VER_RT) { res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL); goto err2; } /* what's the protocol? */ /* QMGR -> AR: RT_Q2R_RCPT_ID: rcpt_id RT_Q2R_RCPT_PA: rcpt_pa RT_Q2R_FLAGS: flags for resolver SMTPS -> AR: RT_S2A_NID SMTPS id RT_S2A_ID SMTPS id RT_S2A_TAID transaction id RT_S2A_RCPT rcpt to RT_S2A_RCPT_IDX rcpt idx RT_S2A_LTYPE lookup type RT_S2A_LFLAGS lookup flags */ ret = sm_rcb_get2uint32(rcb, &l, &rt); if (sm_is_err(ret)) { res = ret; goto err2; } /* SMTPS -> AR; this is slightly ugly, put it into a different fct? */ if (l == 4 && rt == RT_S2A_NID) { SMAR_LEV_DPRINTF(2, (SMAR_DEBFP, "sev=DBG, func=smar_react, got=RT_S2A_NID\n")); ret = sm_rcb_getuint32(rcb, &v); if (sm_is_err(ret)) { res = ret; goto err2; } ret = sm_rcb_get3uint32(rcb, &l, &rt, &v); if (sm_is_err(ret) || l != 4 || rt != RT_S2A_MAXTHRDS) { SMAR_LEV_DPRINTF(0, (SMAR_DEBFP, "sev=DBG, func=smar_react, l=%d, rt=%X, expected=RT_S2A_MAXTHRDS\n", l, rt)); res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL); goto err2; } /* SM_ASSERT(smar_clt_ctx->smac_idx >= 0); */ SM_ASSERT(smar_clt_ctx->smac_idx < SM_ARRAY_SIZE(smar_ctx->smar_clt_reqs)); smar_ctx->smar_clt_reqs[smar_clt_ctx->smac_idx] = v; smar_ctx->smar_max_reqs += v; (void) smar_set_max_threads(smar_ctx); /* ignore return value... */ ret = sm_rcb_get3uint32(rcb, &l, &rt, &v); if (sm_is_err(ret) || l != 4 || rt != RT_S2A_FLAGS) { res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL); goto err2; } smar_clt_ctx->smac_cl_flags = v; if (SM_IS_FLAG(smar_clt_ctx->smac_cl_flags, SMARCL_FL_ACC) && !SMAR_IS_FLAG(smar_ctx, SMAR_FL_HASACCESS)) { sm_log_write(smar_ctx->smar_lctx, AR_LCAT_COMM, AR_LMOD_FROM_QMGR, SM_LOG_ERROR, 2, "sev=ERROR, func=smar_react, where=startup, status=access map requested but not available"); } /* question: Send a reply?? e.g., "connection accepted"? */ goto done; } else if (l == 4 && rt == RT_S2A_ID) { smar_addr_P smar_addr; /* from SMTPS.... */ /* do something about it */ smar_addr = NULL; ret = smar_addr_new(smar_clt_ctx, &smar_addr); if (sm_is_err(ret)) goto err_a; ret = sm_rcb_getuint32(rcb, &v); if (sm_is_err(ret)) { res = ret; goto err2; } smar_addr->ara_id = v; ret = sm_rcb_get2uint32(rcb, &l, &rt); if (sm_is_err(ret) || l != SMTP_STID_SIZE || (rt != RT_S2A_TAID && rt != RT_S2A_SEID)) { res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL); goto err_a; } ret = sm_rcb_getn(rcb, (uchar *) (smar_addr->ara_taid), l); if (sm_is_err(ret)) goto err_a; ret = sm_rcb_get2uint32(rcb, &l, &rt); if (sm_is_err(ret) || (rt != RT_S2A_RCPT && rt != RT_S2A_MAIL && rt != RT_S2A_CLT_A && rt != RT_S2A_CERTISS && rt != RT_S2A_EHLO ) ) { res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL); goto err_a; /* check also l? too large? */ } ret = sm_rcb_getnstr(rcb, &smar_addr->ara_pa, l); SMAR_LEV_DPRINTF(4, (SMAR_DEBFP, "sev=DBG, func=smar_react, pa=%S, ret=%r\n", smar_addr->ara_pa, ret)); if (sm_is_err(ret)) goto err_a; if (RT_S2A_RCPT == rt) { ret = sm_rcb_get3uint32(rcb, &l, &rt, &v); if (sm_is_err(ret) || l != 4 || rt != RT_S2A_RCPT_IDX) { res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL); goto err_a; } } else v = 0; /* dummy rcpt index... use a different one? */ smar_addr->ara_rcpt_idx = (rcpt_idx_T) v; /* lookup type and flags are transferred in one entry */ ret = sm_rcb_get4uint32(rcb, &l, &rt, &v, &tl); if (sm_is_err(ret) || l != 8 || rt != RT_S2A_LTYPE) { res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL); goto err_a; } smar_addr->ara_ltype = v; smar_addr->ara_lflags = tl; /* don't check DNS BLs if none is configured */ if (SMARA_IS_LFLAG(smar_addr, SMARA_LFL_DNSBL) && !SMAR_IS_FLAG(smar_ctx, SMAR_FL_HASDNSBL)) { SMARA_CLR_LFLAG(smar_addr, SMARA_LFL_DNSBL); #if 0 /* currently SMTPS always requests this */ if (!SMAR_IS_FLAG(smar_ctx, SMAR_FL_DNSBLCOMPL)) { sm_log_write(smar_ctx->smar_lctx, AR_LCAT_COMM, AR_LMOD_FROM_QMGR, SM_LOG_ERROR, 2, "sev=ERROR, func=smar_react, status=dnsbl requested but not available"); /* NOT locked! */ SMAR_SET_FLAG(smar_ctx, SMAR_FL_DNSBLCOMPL); } #endif } /* don't try greylisting if it isn't configured */ if (SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_GREY) && !SMAR_IS_FLAG(smar_ctx, SMAR_FL_HASGREY)) { SM_CLR_FLAG(smar_addr->ara_ltype, SMARA_LT_GREY); if (!SMAR_IS_FLAG(smar_ctx, SMAR_FL_GREYCOMPL)) { sm_log_write(smar_ctx->smar_lctx, AR_LCAT_COMM, AR_LMOD_FROM_QMGR, SM_LOG_ERROR, 2, "sev=ERROR, func=smar_react, status=greylisting requested but not available"); /* NOT locked! */ SMAR_SET_FLAG(smar_ctx, SMAR_FL_GREYCOMPL); } } /* don't try access map if it isn't configured */ if (SM_IS_FLAG(smar_addr->ara_ltype, SMAR_LT_ACCESS) && !SMAR_IS_FLAG(smar_ctx, SMAR_FL_HASACCESS)) { if (!SMAR_IS_FLAG(smar_ctx, SMAR_FL_ACCESSCOMPL)) { sm_log_write(smar_ctx->smar_lctx, AR_LCAT_COMM, AR_LMOD_FROM_QMGR, SM_LOG_ERROR, 2, "sev=ERROR, func=smar_react, status=access map requested but not available"); /* NOT locked! */ SMAR_SET_FLAG(smar_ctx, SMAR_FL_ACCESSCOMPL); } } while (!SM_RCB_ISEOB(rcb)) { ret = sm_rcb_get2uint32(rcb, &l, &rt); if (sm_is_err(ret)) { res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL); goto err_a; } switch (rt) { case RT_S2A_MAIL: /* for protected rcpt */ case RT_S2A_CERTSUB: ret = sm_rcb_getnstr(rcb, &smar_addr->ara_pa2, l); if (sm_is_err(ret)) goto err_a; break; case RT_S2A_IPV4: /* protected rcpt, greylisting */ if (l != 4) { res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL); goto err_a; } ret = sm_rcb_getuint32(rcb, &v); if (sm_is_err(ret)) goto err_a; smar_addr->ara_ipv4 = v; SMARA_SET_FLAG(smar_addr, SMARA_FL_RCVDIPV4); break; case RT_S2A_TIME: /* greylisting */ if (8 == l) { uint64_t ul; ret = sm_rcb_getuint64(rcb, &ul); if (sm_is_err(ret)) goto err_a; smar_addr->ara_conn_time = ul; } else if (4 == l) { ret = sm_rcb_getuint32(rcb, &v); if (sm_is_err(ret)) goto err_a; smar_addr->ara_conn_time = v; } else { res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL); goto err_a; } break; default: res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL); goto err_a; } } ret = sm_rcbcom_prerep(&smar_clt_ctx->smac_com_ctx, tsk, &rcbe); if (sm_is_err(ret)) goto err_a; inwaitq = true; smar_addr->ara_rcbe = rcbe; /* call the correct function based on type! */ if (SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_RCPT_LOCAL)) ret = smar_addr_check(smar_ctx, smar_addr); else ret = smar_access_check(smar_ctx, smar_addr); if (sm_is_err(ret)) goto error; /* need more cleanup here? */ return SMAR_R_ASYNC; err_a: smar_addr_free(smar_addr); goto error; } else if (l == SMTP_STID_SIZE && rt == RT_C2A_SEID) { /* RT_C2A_* is currently only for t-smar-rvrs-0! */ smar_rvrs_P smar_rvrs; /* from SMTPS.... */ /* do something about it */ smar_rvrs = NULL; ret = smar_rvrs_new(smar_ctx, smar_clt_ctx, &smar_rvrs); if (sm_is_err(ret)) goto err_c; ret = sm_rcb_getn(rcb, (uchar *) (smar_rvrs->arv_seid), l); if (sm_is_err(ret)) goto err_c; ret = sm_rcb_get3uint32(rcb, &l, &rt, &v); if (sm_is_err(ret) || l != 4 || rt != RT_C2A_IPV4) { res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL); goto err_c; /* check also l? too large? */ } smar_rvrs->arv_ipv4 = v; /* lookup type and flags are transferred in one entry */ ret = sm_rcb_get4uint32(rcb, &l, &rt, &v, &tl); if (sm_is_err(ret) || l != 8 || rt != RT_C2A_LTYPE) { res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL); goto err_c; } smar_rvrs->arv_ltype = v; smar_rvrs->arv_lflags = tl; smar_rvrs->arv_cbf = smar_rvrs_re; ret = sm_rcbcom_prerep(&smar_clt_ctx->smac_com_ctx, tsk, &rcbe); if (sm_is_err(ret)) goto err_c; inwaitq = true; smar_rvrs->arv_rcbe = rcbe; ret = smar_rvrs_rslv(smar_ctx, smar_rvrs, 0u); if (sm_is_err(ret)) goto err_c; /* need more cleanup here? */ return SMAR_R_ASYNC; err_c: smar_rvrs_free(smar_rvrs); goto error; } if (l != SMTP_RCPTID_SIZE || rt != RT_Q2R_RCPT_ID) goto err2; ret = smar_rcpts_new(smar_ctx, smar_clt_ctx, &smar_rcpts); if (sm_is_err(ret)) goto err2; ret = smar_rcpt_new(&smar_rcpt); if (sm_is_err(ret)) goto err2; smar_rcpts->arrs_rcpt = smar_rcpt; SMARR_SET_FLAG(smar_rcpt, SMARR_FL_ORCPT); ret = sm_rcb_getn(rcb, (uchar *) (smar_rcpt->arr_id), l); if (sm_is_err(ret)) goto err2; RCPT_ID_COPY(smar_rcpts->arrs_rcpt_id, smar_rcpt->arr_id); ret = sm_rcb_get2uint32(rcb, &l, &rt); if (sm_is_err(ret) || rt != RT_Q2R_RCPT_PA) { /* check l? too large? */ res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL); goto err2; } ret = sm_rcb_getnstr(rcb, &smar_rcpt->arr_pa, l); SMAR_LEV_DPRINTF(4, (SMAR_DEBFP, "sev=DBG, func=smar_react, pa=%S, ret=%r\n", smar_rcpt->arr_pa, ret)); if (sm_is_err(ret)) goto err2; ret = sm_rcb_get3uint32(rcb, &l, &rt, &v); if (sm_is_err(ret) || l != 4 || rt != RT_Q2R_FLAGS) { SMAR_LEV_DPRINTF(0, (SMAR_DEBFP, "sev=ERROR, func=smar_react, rt=%#x, v=%d, l=%d, ret=%r, res=%r\n", rt, v, l, ret, res)); res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL); goto err2; } smar_rcpt->arr_rqflags = v; smar_rcpt->arr_cnf_lfl = SMMAP_LFL_ALL|SMMAP_LFL_NOAT; /* default */ if (!SM_RCB_ISEOB(rcb) && sm_is_success(sm_rcb_peek2uint32(rcb, &l, &rt)) && 4 == l && RT_R2Q_RCPT_CNF_LKP_FL == rt) { ret = sm_rcb_get3uint32(rcb, &l, &rt, &v); if (sm_is_err(ret) || l != 4 || rt != RT_R2Q_RCPT_CNF_LKP_FL) { SMAR_LEV_DPRINTF(0, (SMAR_DEBFP, "sev=ERROR, func=smar_react, rt=%#x, v=%d, l=%d, ret=rx, res=rx\n", rt, v, l, ret, res)); res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL); goto err2; } smar_rcpt->arr_cnf_lfl = v; } if (!SM_RCB_ISEOB(rcb)) { ret = sm_rcb_get3uint32(rcb, &l, &rt, &v); if (sm_is_err(ret) || l != 4 || rt != RT_Q2R_TIMEOUT) { SMAR_LEV_DPRINTF(0, (SMAR_DEBFP, "sev=ERROR, func=smar_react, rt=%#x, v=%d, l=%d, ret=rx, res=rx\n", rt, v, l, ret, res)); res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL); goto err2; } smar_rcpt->arr_timeout = v; } ret = sm_rcbcom_prerep(&smar_clt_ctx->smac_com_ctx, tsk, &rcbe); if (sm_is_err(ret)) { SMAR_LEV_DPRINTF(0, (SMAR_DEBFP, "sev=ERROR, func=smar_react, sm_rcbcom_prerep=%r\n", ret)); goto err0; } inwaitq = true; res = SMAR_R_ASYNC; /* XXX Check proper cleanup of data: who free()s what? */ SMARR_SET_FLAG(smar_rcpt, SMARR_FL_A4MT); smar_rcpts->arrs_rcbe = rcbe; ret = smar_rcpt_rslv(smar_ctx, smar_rcpts); smar_rcpt = NULL; /* smar_rcpt_rslv() took over responsibility */ smar_rcpts = NULL; /* smar_rcpt_rslv() took over responsibility */ if (sm_is_err(ret)) { /* in which case is this a fatal error? none? */ SMAR_LEV_DPRINTF(0, (SMAR_DEBFP, "sev=ERROR, func=smar_react, smar_rcpt_rslv=%r\n", ret)); /* need more cleanup here? */ goto errret; } return SMAR_R_ASYNC; done: ret = sm_rcb_close_dec(smar_clt_ctx->smac_com_ctx.rcbcom_rdrcb); (void) sm_rcb_open_rcv(smar_clt_ctx->smac_com_ctx.rcbcom_rdrcb); if (ret == SM_SUCCESS && inwaitq) return SMAR_R_ASYNC; return ret; /* preserve original error code! */ err2: if (!inwaitq) { /* use rcb functions that don't check the state */ (void) sm_rcb_close_decn(smar_clt_ctx->smac_com_ctx.rcbcom_rdrcb); } error: if (!inwaitq) { /* open rcb for receiving next record */ (void) sm_rcb_open_rcvn(smar_clt_ctx->smac_com_ctx.rcbcom_rdrcb); } err0: (void) smar_rcpt_free(smar_rcpt, NULL); (void) smar_rcpts_free(smar_rcpts); errret: sm_log_write(smar_ctx->smar_lctx, AR_LCAT_COMM, AR_LMOD_FROM_QMGR, SM_LOG_ERROR, 0, "sev=ERROR, func=smar_react, status=%#x, rt=%#x, v=%d, l=%d, ret=%m, res=%m", smar_ctx->smar_status, rt, v, l, ret, res); return res; } /* ** SMAR_CLT_CLOSE -- close connection to client ** ** Parameters: ** tsk -- evthr task ** ** Returns: ** usual sm_error code */ static sm_ret_T smar_clt_close(sm_evthr_task_P tsk) { smar_clt_ctx_P smar_clt_ctx; smar_ctx_P smar_ctx; SM_IS_EVTHR_TSK(tsk); smar_clt_ctx = (smar_clt_ctx_P) tsk->evthr_t_actx; SM_IS_SMAR_CLT_CTX(smar_clt_ctx); smar_ctx = smar_clt_ctx->smac_ar_ctx; SM_IS_SMAR_CTX(smar_ctx); close(tsk->evthr_t_fd); /* See comment in qm_fr_ss()!! */ tsk->evthr_t_fd = INVALID_FD; smar_ctx->smar_clt_used &= ~(smar_clt_ctx->smac_bit); smar_clt_ctx->smac_bit = 0; smar_clt_ctx->smac_status = SMAC_ST_NONE; /* "close" client context... put this into a function? */ /* SM_ASSERT(smar_clt_ctx->smac_idx >= 0); */ SM_ASSERT(smar_clt_ctx->smac_idx < SM_ARRAY_SIZE(smar_ctx->smar_clt_reqs)); smar_ctx->smar_max_reqs -= smar_ctx->smar_clt_reqs[smar_clt_ctx->smac_idx]; smar_ctx->smar_clt_reqs[smar_clt_ctx->smac_idx] = 0; smar_clt_ctx->smac_idx = UINT32_MAX; /* more cleanup? */ sm_rcb_close_decn(smar_clt_ctx->smac_com_ctx.rcbcom_rdrcb); smar_clt_ctx->smac_com_ctx.rcbcom_tsk = NULL; return SM_SUCCESS; } /* ** SMAR_CLT2AR -- client - AR interface ** invoked by smar_clt() to deal with RCB receiption ** ** Parameters: ** tsk -- evthr task ** ** Returns: ** usual sm_error code */ static sm_ret_T smar_clt2ar(sm_evthr_task_P tsk) { int fd; sm_ret_T ret; smar_clt_ctx_P smar_clt_ctx; smar_ctx_P smar_ctx; SM_IS_EVTHR_TSK(tsk); smar_clt_ctx = (smar_clt_ctx_P) tsk->evthr_t_actx; SM_IS_SMAR_CLT_CTX(smar_clt_ctx); smar_ctx = smar_clt_ctx->smac_ar_ctx; SM_IS_SMAR_CTX(smar_ctx); fd = tsk->evthr_t_fd; /* checked in caller */ ret = sm_rcb_rcv(fd, smar_clt_ctx->smac_com_ctx.rcbcom_rdrcb, QSS_RC_MINSZ); SMAR_LEV_DPRINTF(5, (SMAR_DEBFP, "sev=DBG, func=smar_clt2ar, fd=%d, ret=%r, buf=%d, len=%d, smar_status=%#x\n", fd, ret, smar_clt_ctx->smac_com_ctx.rcbcom_rdrcb->sm_rcb_base[0], sm_rcb_getlen(smar_clt_ctx->smac_com_ctx.rcbcom_rdrcb), smar_ctx->smar_status)); if (ret > 0) { #if 0 if (buf[0] == 'Q') return EVTHR_TERM|EVTHR_DEL; #endif /* 0 */ return EVTHR_WAITQ; } else if (0 == ret) { ret = sm_rcb_close_rcv(smar_clt_ctx->smac_com_ctx.rcbcom_rdrcb); /* start appropriate function ... */ ret = smar_react(smar_clt_ctx, tsk); SMAR_LEV_DPRINTF(5, (SMAR_DEBFP, "sev=DBG, func=smar_clt2ar, sm_smar_react=%r\n", ret)); if (sm_is_err(ret)) goto termit; /* too harsh? */ else if (SMAR_R_WAITQ == ret) return EVTHR_WAITQ; else if (SMAR_R_ASYNC == ret) return EVTHR_OK; else if (EVTHR_DEL == ret) goto termit; /* terminate this client */ else return ret; } else if (SM_IO_EOF == ret) { ret = sm_rcb_close_rcv(smar_clt_ctx->smac_com_ctx.rcbcom_rdrcb); termit: SMAR_LEV_DPRINTF(1, (SMAR_DEBFP, "sev=DBG, func=smar_clt2ar, task=%p, status=terminate, ret=%r\n", smar_clt_ctx->smac_com_ctx.rcbcom_tsk, ret)); (void) smar_clt_close(tsk); return EVTHR_DEL; } else /* if (ret < 0) */ { sm_log_write(smar_ctx->smar_lctx, AR_LCAT_COMM, AR_LMOD_FROM_QMGR, SM_LOG_ERROR, 0, "sev=ERROR, func=smar_clt2ar, ret=%m, errno=%d" , ret, errno); goto termit; } sm_log_write(smar_ctx->smar_lctx, AR_LCAT_COMM, AR_LMOD_FROM_QMGR, SM_LOG_ERROR, 0, "sev=ERROR, func=smar_clt2ar, fd=%d", fd); #if 0 error: #endif return EVTHR_DEL; } /* ** SMAR_AR2CLT -- SMAR 2 client (QMGR/SMTPS) interface ** ** Parameters: ** tsk -- evthr task ** ** Returns: ** usual sm_error code */ static sm_ret_T smar_ar2clt(sm_evthr_task_P tsk) { smar_clt_ctx_P smar_clt_ctx; SM_IS_EVTHR_TSK(tsk); smar_clt_ctx = (smar_clt_ctx_P) tsk->evthr_t_actx; SM_IS_SMAR_CLT_CTX(smar_clt_ctx); SMAR_LEV_DPRINTF(5, (SMAR_DEBFP, "smar_ar2clt: tsk=%p, fd=%d\n", tsk, tsk->evthr_t_fd)); return sm_rcbcom2mod(tsk, &smar_clt_ctx->smac_com_ctx); } /* ** SMAR_CLT -- SMAR - client interface ** This runs as a task. ** ** Parameters: ** tsk -- evthr task ** ** Returns: ** usual sm_error code */ sm_ret_T smar_clt(sm_evthr_task_P tsk) { sm_ret_T ret; SM_IS_EVTHR_TSK(tsk); if (is_valid_fd(tsk->evthr_t_fd)) { /* ** Note: The first call is not allowed to put the ** task back into the wait queue since then the second ** function acts on a "non-locked" tsk. */ ret = EVTHR_WAITQ; SMAR_LEV_DPRINTF(5, (SMAR_DEBFP, "sev=DBG, func=smar_clt, tsk=%p, flags=%#x, fd=%d\n", tsk, tsk->evthr_t_evocc, tsk->evthr_t_fd)); if (evthr_got_wr(tsk)) { ret = smar_ar2clt(tsk); if (sm_is_err(ret)) goto error; } 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 = smar_clt2ar(tsk); if (sm_is_err(ret)) goto error; } return ret; } return EVTHR_DEL; error: (void) smar_clt_close(tsk); return EVTHR_DEL; }