/* * Copyright (c) 2003-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: access.c,v 1.145 2007/11/14 06:03:08 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/map.h" #include "sm/mta.h" #include "sm/ctype.h" #include "sm/rfc2821.h" #include "sm/greyctl.h" #include "smar.h" #include "reverse.h" #include "dnsbl.h" #include "log.h" #include "sm/reccom.h" /* see sm/error.h! */ #define SM_DONE 3 /* caller should use "goto done;" */ #define SM_BREAK 4 /* caller should use "break;" */ #define SM_AGAIN 5 /* caller should invoke this function again */ #if SM_NOTDONE >= SM_DONE ERROR: _SM_NOTDONE MUST BE LESS THAN _SM_DONE: SM_NOTDONE >= SM_DONE #endif typedef sm_ret_T (smar_chk_F)(smar_ctx_P, smar_addr_P, sm_ret_T *); struct smar_chk_ctx_S { const char *arcc_name; smar_chk_F *arcc_fct; /* anything else? preconditions? flags? */ }; typedef struct smar_chk_ctx_S smar_chk_ctx_T, *smar_chk_ctx_P; /* ** SMAR_DNS_GETRET -- get result of dns resolution query (wait for it) ** ** Parameters: ** smar_addr -- address context ** ** Returns: ** usual sm_error code ** ** Locking: locks smar_addr ** ** Last code review: 2004-03-11 17:10:43; see below ** Last code change: 2004-04-18 23:28:23 */ #if SMAR_DEBUG /* HACK: count number of waiting tasks; doesn't use locking... */ static int waits = 0; #endif static sm_ret_T smar_dns_getret(smar_addr_P smar_addr) { int r; sm_evthr_ctx_P evthr_ctx; SM_IS_SMAR_ADDR(smar_addr); r = pthread_mutex_lock(&smar_addr->ara_mutex); SM_LOCK_OK(r); if (r != 0) { sm_log_write(smar_addr->ara_smar_clt_ctx->smac_ar_ctx->smar_lctx, AR_LCAT_RESOLVER, AR_LMOD_RESOLVER, SM_LOG_CRIT, 4, "sev=CRIT, func=smar_dns_getret, lock=%d", r); return sm_error_perm(SM_EM_AR_WAIT, r); } if (smar_addr->ara_res_cnt > 0) { SMARA_SET_FLAG(smar_addr, SMARA_FL_AFWAIT); while (smar_addr->ara_res_cnt > 0) { evthr_ctx = smar_addr->ara_smar_clt_ctx->smac_ar_ctx->smar_ev_ctx; # if SMAR_DEBUG ++waits; SMAR_LEV_DPRINTF(4, (SMAR_DEBFP, "sev=DBG, func=smar_dns_getret, smar_addr=%p, taid=%s, where=before-cond_wait, waits=%d, act=%u, cur=%u, max_s=%u, max_h=%u\n", smar_addr, smar_addr->ara_taid, waits , evthr_ctx->evthr_c_act , evthr_ctx->evthr_c_cur , evthr_ctx->evthr_c_max_s , evthr_ctx->evthr_c_max_h )); # endif (void) evthr_before_block(evthr_ctx); r = pthread_cond_wait(&smar_addr->ara_cond, &smar_addr->ara_mutex); # if SMAR_DEBUG --waits; SMAR_LEV_DPRINTF(4, (SMAR_DEBFP, "sev=DBG, func=smar_dns_getret, smar_addr=%p, taid=%s, where=after-cond_wait, r=%d, waits=%d, act=%u, cur=%u, max_s=%u, max_h=%u\n", smar_addr, smar_addr->ara_taid, r, waits , evthr_ctx->evthr_c_act , evthr_ctx->evthr_c_cur , evthr_ctx->evthr_c_max_s , evthr_ctx->evthr_c_max_h )); # endif (void) evthr_after_block(evthr_ctx); if (EINVAL == r) { sm_log_write(smar_addr->ara_smar_clt_ctx->smac_ar_ctx->smar_lctx, AR_LCAT_RESOLVER, AR_LMOD_RESOLVER, SM_LOG_ERR, 4, "sev=ERROR, func=smar_dns_getret, cond_wait=%m", sm_err_perm(r)); break; } } if (0 == r) { r = pthread_mutex_unlock(&smar_addr->ara_mutex); SM_ASSERT(0 == r); } } else { r = pthread_mutex_unlock(&smar_addr->ara_mutex); SM_ASSERT(0 == r); } if (0 == r) { if (SMARA_IS_FLAG(smar_addr, SMARA_FL_A4RVRS)) SMARA_SET_FLAG(smar_addr, SMARA_FL_GOTRVRS); if (SMARA_IS_FLAG(smar_addr, SMARA_FL_A4RCPT)) SMARA_SET_FLAG(smar_addr, SMARA_FL_GOTRCPT); if (SMARA_IS_FLAG(smar_addr, SMARA_FL_A4DNSBL)) SMARA_SET_FLAG(smar_addr, SMARA_FL_GOTDNSBL); return SM_SUCCESS; } SMARA_SET_FLAG(smar_addr, SMARA_FL_FAILDNS); return sm_error_perm(SM_EM_AR_WAIT, r); /* error value/type */ } /* ** SMAR_RVRS_NOTIFY -- callback for a reverse resolution query ** This function will be called when the reverse resolution is done ** (to "send back" the result to the caller, i.e., usually it would be ** a RCB routine). ** ** Parameters: ** smar_rvrs -- reverse resolution context ** ctx -- smar_addr ** ** Returns: ** usual sm_error code ** ** Locking: locks smar_addr ** ** Last code review: 2004-03-11 17:14:30; see below ** Last code change: */ static sm_ret_T smar_rvrs_notify(smar_rvrs_P smar_rvrs, void *ctx) { sm_ret_T ret; int r; smar_addr_P smar_addr; SM_REQUIRE(smar_rvrs != NULL); SM_REQUIRE(ctx != NULL); smar_addr = ctx; ret = SM_SUCCESS; r = pthread_mutex_lock(&smar_addr->ara_mutex); SM_LOCK_OK(r); if (r != 0) { sm_log_write(smar_addr->ara_smar_clt_ctx->smac_ar_ctx->smar_lctx, AR_LCAT_RESOLVER, AR_LMOD_RESOLVER, SM_LOG_CRIT, 4, "sev=CRIT, func=smar_rvrs_notify, lock=%d", r); return sm_error_perm(SM_EM_AR, r); } if (smar_rvrs->arv_hostname != NULL) smar_addr->ara_rvrs_hostname = SM_CSTR_DUP(smar_rvrs->arv_hostname); SM_REQUIRE(smar_rvrs->arv_ret != 0); smar_addr->ara_dns_ret = smar_rvrs->arv_ret; SM_ASSERT(smar_addr->ara_res_cnt > 0); --smar_addr->ara_res_cnt; /* ** Notify original thread that the data is now there. ** How? Can this be done via evthreads? ** Otherwise: ** pipe() + select() ** pthread_cond_timedwait() ** Write a generic function? ** Blocking here isn't a good idea because it's not under ** control of evthreads, i.e., it will consume a task; ** in the worst case this could lead to a deadlock, however, ** libevthr solves this by allowing more "potentially blocking" ** threads. */ if (smar_addr->ara_res_cnt == 0 && SMARA_IS_FLAG(smar_addr, SMARA_FL_AFWAIT)) { r = pthread_cond_signal(&smar_addr->ara_cond); if (r != 0) { sm_log_write(smar_addr->ara_smar_clt_ctx->smac_ar_ctx->smar_lctx, AR_LCAT_RESOLVER, AR_LMOD_RESOLVER, SM_LOG_ERR, 1, "sev=ERROR, func=smar_rvrs_notify, cond_signal=%m", sm_err_perm(r)); } else SMARA_CLR_FLAG(smar_addr, SMARA_FL_AFWAIT); } r = pthread_mutex_unlock(&smar_addr->ara_mutex); SM_ASSERT(0 == r); if (r != 0 && sm_is_success(ret)) ret = sm_error_perm(SM_EM_AR, r); SMAR_LEV_DPRINTF(8, (SMAR_DEBFP, "func=smar_rvrs_notify, ret=%m\n", smar_addr->ara_dns_ret)); return ret; } /* ** SMAR_RCPT_NOTIFY -- callback for a recipient resolution query ** This function will be called when the recipient resolution is done ** (to "send back" the result to the caller, i.e., usually it would be ** a RCB routine). ** ** Parameters: ** smar_rcpts -- recipient list context ** ctx -- smar_addr ** ** Returns: ** usual sm_error code ** ** Locking: locks smar_addr ** ** Last code review: ** Last code change: ** ** Note: this is almost the same as smar_rvrs_notify(), except ** for the assignment of smar_addr->ara_rvrs_hostname */ static sm_ret_T smar_rcpt_notify(smar_rcpts_P smar_rcpts, void *ctx) { sm_ret_T ret; int r; smar_addr_P smar_addr; SM_IS_SMAR_RCPTS(smar_rcpts); SM_REQUIRE(ctx != NULL); smar_addr = ctx; ret = SM_SUCCESS; r = pthread_mutex_lock(&smar_addr->ara_mutex); SM_LOCK_OK(r); if (r != 0) { sm_log_write(smar_addr->ara_smar_clt_ctx->smac_ar_ctx->smar_lctx, AR_LCAT_RESOLVER, AR_LMOD_RESOLVER, SM_LOG_CRIT, 4, "sev=CRIT, func=smar_rcpt_notify, lock=%d", r); return sm_error_perm(SM_EM_AR, r); } smar_addr->ara_dns_ret = smar_rcpts->arrs_ret; SM_ASSERT(smar_addr->ara_res_cnt > 0); --smar_addr->ara_res_cnt; /* ** Notify original thread that the data is now there. (see above) */ if (smar_addr->ara_res_cnt == 0 && SMARA_IS_FLAG(smar_addr, SMARA_FL_AFWAIT)) { r = pthread_cond_signal(&smar_addr->ara_cond); if (r != 0) { sm_log_write(smar_addr->ara_smar_clt_ctx->smac_ar_ctx->smar_lctx, AR_LCAT_RESOLVER, AR_LMOD_RESOLVER, SM_LOG_ERR, 4, "sev=ERROR, func=smar_rcpt_notify, cond_signal=%m", sm_err_perm(r)); } else SMARA_CLR_FLAG(smar_addr, SMARA_FL_AFWAIT); } r = pthread_mutex_unlock(&smar_addr->ara_mutex); SM_ASSERT(0 == r); if (r != 0 && sm_is_success(ret)) ret = sm_error_perm(SM_EM_AR, r); SMAR_LEV_DPRINTF(8, (SMAR_DEBFP, "func=smar_rcpt_notify, ret=%m\n", smar_addr->ara_dns_ret)); return ret; } /* ** SMAR_DNSBL_NOTIFY -- callback for a DNS BL query ** ** Parameters: ** smar_dnsbl -- DNS BL context ** ctx -- smar_addr ** ** Returns: ** usual sm_error code ** ** Locking: locks smar_addr ** ** Last code review: ** Last code change: */ static sm_ret_T smar_dnsbl_notify(smar_dnsbl_P smar_dnsbl, void *ctx) { sm_ret_T ret; int r; smar_addr_P smar_addr; SM_REQUIRE(smar_dnsbl != NULL); SM_REQUIRE(ctx != NULL); smar_addr = ctx; SM_IS_SMAR_ADDR(smar_addr); ret = SM_SUCCESS; r = pthread_mutex_lock(&smar_addr->ara_mutex); SM_LOCK_OK(r); if (r != 0) { sm_log_write(smar_addr->ara_smar_clt_ctx->smac_ar_ctx->smar_lctx, AR_LCAT_RESOLVER, AR_LMOD_RESOLVER, SM_LOG_CRIT, 4, "sev=CRIT, func=smar_dnsbl_notify, lock=%d", r); return sm_error_perm(SM_EM_AR, r); } SM_ASSERT(smar_addr->ara_res_cnt > 0); --smar_addr->ara_res_cnt; /* ** Notify original thread that the data is now there. (see above) */ if (smar_addr->ara_res_cnt == 0 && SMARA_IS_FLAG(smar_addr, SMARA_FL_AFWAIT)) { r = pthread_cond_signal(&smar_addr->ara_cond); if (r != 0) { /* XXX Complain/Log */ sm_log_write(smar_addr->ara_smar_clt_ctx->smac_ar_ctx->smar_lctx, AR_LCAT_RESOLVER, AR_LMOD_RESOLVER, SM_LOG_ERR, 4, "sev=ERROR, func=smar_dnsbl_notify, cond_signal=%m", sm_err_perm(r)); } else SMARA_CLR_FLAG(smar_addr, SMARA_FL_AFWAIT); } r = pthread_mutex_unlock(&smar_addr->ara_mutex); SM_ASSERT(0 == r); if (r != 0 && sm_is_success(ret)) ret = sm_error_perm(SM_EM_AR, r); SMAR_LEV_DPRINTF(8, (SMAR_DEBFP, "func=smar_dnsbl_notify, ret=%m\n", smar_addr->ara_dns_ret)); return ret; } /* ** SMAR_ACCESS_RE -- Send reply for an address check ** The status is stored in smar_addr: smar_addr->ara_status; ** if smar_addr->ara_rhs isn't NULL it is sent as error text ** (no real checking is done here). ** NOTE: ara_status is only sent iff ** (SM_SUCCESS == ret && SM_ACC_FOUND == ara_mapres) ** ** Parameters: ** smar_addr -- address context ** which_status -- which status record type is returned ** off -- possible offset in return string ** ** Returns: ** usual sm_error code ** ** Side Effects: ** reply is stored in smar_addr->ara_rcbe->rcbe_rcb ** which must be taken care of (sent) by the caller. ** ** Locking: smar_addr must be under control of the caller ("locked") ** ** Last code review: 2004-03-11 ** Last code change: */ sm_ret_T smar_access_re(smar_addr_P smar_addr, uint32_t which_status, uint off) { sm_rcb_P rcb; sm_ret_T ret; SM_IS_SMAR_ADDR(smar_addr); rcb = &smar_addr->ara_rcbe->rcbe_rcb; ret = sm_rcb_putv(rcb, RCB_PUTV_FIRST, SM_RCBV_INT, RT_PROT_VER, PROT_VER_RT, SM_RCBV_INT, RT_A2S_ID, smar_addr->ara_id, SM_RCBV_BUF, RT_A2S_TAID, smar_addr->ara_taid, SMTP_STID_SIZE, SM_RCBV_INT, RT_A2S_MAP_RES, smar_addr->ara_mapres, SM_RCBV_END); if (SM_SUCCESS == ret && SM_ACC_FOUND == smar_addr->ara_mapres) { ret = sm_rcb_putv(rcb, RCB_PUTV_NONE, SM_RCBV_INT, which_status, smar_addr->ara_status|smar_addr->ara_rflags, SM_RCBV_END); } if (SM_SUCCESS == ret && smar_addr->ara_rhs != NULL && sm_str_getlen(smar_addr->ara_rhs) > 3) { if (off > 0) { SM_ASSERT(sm_str_getlen(smar_addr->ara_rhs) > off); ret = sm_rcb_putv(rcb, RCB_PUTV_NONE, SM_RCBV_BUF, RT_A2S_STATT, sm_str_getdata(smar_addr->ara_rhs) + off, sm_str_getlen(smar_addr->ara_rhs) - off, SM_RCBV_END); } else { ret = sm_rcb_putv(rcb, RCB_PUTV_NONE, SM_RCBV_STR, RT_A2S_STATT, smar_addr->ara_rhs, SM_RCBV_END); } } if (SM_SUCCESS == ret && SMARA_IS_LFLAG(smar_addr, SMARA_LFL_RVRS4)) { ret = sm_rcb_putv(rcb, RCB_PUTV_NONE, SM_RCBV_INT, RT_A2S_RVRS_ST, smar_addr->ara_dns_ret, SM_RCBV_END); SMAR_LEV_DPRINTF(7, (SMAR_DEBFP, "func=smar_access_re, rvrs_ret=%r, putv=%r, hostname=%C\n", smar_addr->ara_dns_ret, ret, smar_addr->ara_rvrs_hostname)); if (SM_SUCCESS == ret && smar_addr->ara_rvrs_hostname != NULL) { ret = sm_rcb_putv(rcb, RCB_PUTV_NONE, SM_RCBV_CSTR, RT_A2S_RVRS_NAME, smar_addr->ara_rvrs_hostname, SM_RCBV_END); } } if (SM_SUCCESS == ret && SMARA_IS_FLAG(smar_addr, SMARA_FL_GOTSSSECONF)) { ret = sm_rcb_putv(rcb, RCB_PUTV_NONE, SM_RCBV_INT, RT_A2S_MAP_RES_CNF, smar_addr->ara_maprescnf, SM_RCBV_STR, RT_A2S_RHS_CNF, smar_addr->ara_rhs_conf, SM_RCBV_END); } return ret; } /* ** SMAR_DNS2RET -- Convert DNS status code to address status ** ** Parameters: ** smar_ctx -- SMAR context ** smar_addr -- address context ** ** Returns: ** usual sm_error code ** ** Side Effects: ** creates error string in ara_rhs ** ** Locking: smar_addr must be under control of the caller. ** ** Last code review: ** Last code change: ** ** Note: enh.status code X.1.8 is only for sender, which is currently ** correct. However, it might be useful to check the lookup type, e.g., ** SMARA_LT_MAIL_ROUTE. */ static sm_ret_T smar_dns2ret(smar_ctx_P smar_ctx, smar_addr_P smar_addr) { sm_ret_T ret; #define SM_ARA_RHS_LEN 64 ret = SM_SUCCESS; switch (smar_addr->ara_dns_ret) { case 0: break; case DNSR_TEMP: case DNSR_TIMEOUT: smar_addr->ara_status = SMTP_R_TEMP; smar_addr->ara_rhs = sm_str_scpy(NULL, "451 4.1.8 Sender address does not resolve", SM_ARA_RHS_LEN); break; case DNSR_REFUSED: sm_log_write(smar_ctx->smar_lctx, AR_LCAT_RESOLVER, AR_LMOD_RVRS_CB, SM_LOG_CRIT, 6, "sev=CRIT, func=smar_dns2ret, pa=%#S, error=%m", smar_addr->ara_pa, smar_addr->ara_dns_ret); case DNSR_NOTFOUND: case DNSR_PERM: case DNSR_NO_DATA: smar_addr->ara_status = SMTP_R_REJECT; smar_addr->ara_rhs = sm_str_scpy(NULL, "553 5.1.8 Sender address does not exist", SM_ARA_RHS_LEN); break; case sm_error_perm(SM_EM_AR, SM_E_ALIAS_REC): smar_addr->ara_status = SMTP_R_TEMP; smar_addr->ara_rhs = sm_str_scpy(NULL, "451 4.1.8 Alias loop", SM_ARA_RHS_LEN); break; case sm_error_perm(SM_EM_AR, ELOOP): smar_addr->ara_status = SMTP_R_TEMP; smar_addr->ara_rhs = sm_str_scpy(NULL, "451 4.1.8 CNAME loop", SM_ARA_RHS_LEN); break; case sm_error_perm(SM_EM_DNS, EINVAL): smar_addr->ara_status = SMTP_R_REJECT; smar_addr->ara_rhs = sm_str_scpy(NULL, "551 5.1.8 Invalid DNS entry", SM_ARA_RHS_LEN); break; case DNSR_MXINVALID: smar_addr->ara_status = SMTP_R_REJECT; smar_addr->ara_rhs = sm_str_scpy(NULL, "551 5.1.8 Invalid MX entry", SM_ARA_RHS_LEN); break; case DNSR_PTRINVALID: smar_addr->ara_status = SMTP_R_REJECT; smar_addr->ara_rhs = sm_str_scpy(NULL, "551 5.1.8 Invalid PTR entry", SM_ARA_RHS_LEN); break; case DNSR_CNINVALID: smar_addr->ara_status = SMTP_R_REJECT; smar_addr->ara_rhs = sm_str_scpy(NULL, "551 5.1.8 Invalid CNAME entry", SM_ARA_RHS_LEN); break; default: smar_addr->ara_status = SMTP_R_TEMP; smar_addr->ara_rhs = sm_str_scpy(NULL, "451 4.1.8 oops", SM_ARA_RHS_LEN); /* don't return an error to caller? */ ret = smar_addr->ara_dns_ret; } return ret; } #if 0 ///* //** SMAR_IP2STR -- app //** //** Parameters: //** smar_rcpt -- SMAR RCPT context //** //** Returns: //** usual sm_error code //** //** Locking: //** //** Last code review: //** Last code change: //*/ // //static sm_ret_T //smar_ip2str(smar_rcpt_P smar_rcpt, uint i, uint j, sm_str_P str) //{ // sm_ret_T ret; // smar_dns_P smar_dns; // // SM_IS_SMAR_RCPT(smar_rcpt); // for (i = 0; i < smar_rcpt->arr_A_qsent; i++) // { // smar_dns = &(smar_rcpt->arr_res[i]); //SMAR_LEV_DPRINTF(4, (SMAR_DEBFP, "i=%d, smar_dns=%p\n", i, smar_dns)); // // /* and send all A records with the MX data */ // for (j = 0; j < smar_dns->ardns_n_A; j++) // { //SMAR_LEV_DPRINTF(4, (SMAR_DEBFP, "i=%d, j=%d, a=%A\n", i, j, smar_dns->ardns_A_rrs[j])); // /* HACK: ignore addresses with value 0 */ // if (smar_dns->ardns_A_rrs[j] == 0) // continue; // // smar_dns->ardns_A_rrs[j], // } // } //} #endif /* 0 */ /* ** SMAR_MAP2ACC -- convert map result code to access lookup code ** ** Parameters: ** rv -- result of map lookup ** ** Returns: ** access lookup code */ sm_ret_T smar_map2acc(sm_ret_T rv) { if (SM_MAP_TEMPMAP == rv) return SM_ACC_TEMPFAIL; else if (SM_MAP_PERMMAP == rv) return SM_ACC_PERMFAIL; else if (SM_MAP_NOTFOUND == rv) return SM_ACC_NOTFOUND; else return sm_error_perm(SM_EM_AR, EINVAL); } /* ** SMAR_DNSBL -- start DNS BL queries ** ** Parameters: ** smar_ctx -- SMAR context ** smar_addr -- address context ** ** Returns: ** usual sm_error code ** ** Locking: should smar_addr be locked? ** ** Side Effects: ** sets SMARA_FL_A4DNSBL if successful */ static sm_ret_T smar_startdnsbl(smar_ctx_P smar_ctx, smar_addr_P smar_addr) { sm_ret_T ret; int r; ipv4_T ipv4; uint u; smar_dnsbl_P smar_dnsbl; SM_IS_SMAR_ADDR(smar_addr); SM_IS_SMAR_CTX(smar_ctx); r = pthread_mutex_lock(&smar_addr->ara_mutex); SM_LOCK_OK(r); if (r != 0) { sm_log_write(smar_addr->ara_smar_clt_ctx->smac_ar_ctx->smar_lctx, AR_LCAT_RESOLVER, AR_LMOD_RESOLVER, SM_LOG_CRIT, 4, "sev=CRIT, func=smar_startdnsbl, lock=%d", r); return sm_error_perm(SM_EM_AR, r); } ret = SM_SUCCESS; for (u = 0; u < SM_MAX_DNSBL && smar_ctx->smar_cnf.smar_cnf_dnsbl[u].scdb_name != NULL; u++) { ret = smar_dnsbl_new(smar_addr, &(smar_addr->ara_dnsblres[u]), &(smar_ctx->smar_cnf.smar_cnf_dnsbl[u]), smar_dnsbl_notify, smar_addr, &smar_dnsbl); if (sm_is_err(ret)) goto unlock; /* XXX set some error code, log? */ ++smar_addr->ara_res_cnt; ret = sm_inet_a2ipv4((const char *)sm_str_getdata(smar_addr->ara_pa), NULL, &ipv4); /* ** This is an asynchronous function! ** Note: smar_dnsbl is now under control of smar_dnsbl_rslv(). */ ret = smar_dnsbl_rslv(smar_ctx, smar_dnsbl, ipv4, 0u); if (sm_is_success(ret)) SMARA_SET_FLAG(smar_addr, SMARA_FL_A4DNSBL); else { --smar_addr->ara_res_cnt; ret = SM_SUCCESS; /* don't return error to caller */ } SMAR_LEV_DPRINTF(7, (SMAR_DEBFP, "sev=DBG, func=smar_startdnsbl, smar_dnsbl_rslv=%r, ipv4=%A, scdb_name=%s\n", ret, ipv4, smar_ctx->smar_cnf.smar_cnf_dnsbl[u].scdb_name)); } /* ignore error, ara_status is initialized */ unlock: r = pthread_mutex_unlock(&smar_addr->ara_mutex); SM_ASSERT(0 == r); if (r != 0 && sm_is_success(ret)) ret = sm_error_perm(SM_EM_AR, r); return ret; } /* ** SMAR_INIT_PA2 -- Initialize address data structure *2 components ** ** Parameters: ** smar_ctx -- SMAR context ** smar_addr -- address context ** ** Returns: ** usual sm_error code ** ** Locking: smar_addr must be under control of the caller. */ static sm_ret_T smar_init_pa2(smar_ctx_P smar_ctx, smar_addr_P smar_addr) { sm_ret_T ret; sm_a2821_T a_addr; sm_a2821_P paddr; SM_REQUIRE(smar_ctx != NULL); SM_REQUIRE(smar_addr != NULL); if (NULL == smar_addr->ara_pa2) return SM_SUCCESS; paddr = &a_addr; /* paddr is just pointer to a_addr */ A2821_INIT_RP(paddr, smar_addr->ara_rpool); ret = t2821_scan((sm_rdstr_P) smar_addr->ara_pa2, paddr, 0); if (sm_is_success(ret)) { ret = t2821_parse(paddr, (R2821_CORRECT|R2821_EMPTY) & ~R2821_AT); if (sm_is_err(ret)) goto done; if (sm_str_getlen(smar_addr->ara_pa2) == 2 && sm_str_rd_elem(smar_addr->ara_pa2, 0) == '<' && sm_str_rd_elem(smar_addr->ara_pa2, 1) == '>') { SMARA_SET_FLAG(smar_addr, SMARA_FL_PA2EMPTY); } } smar_addr->ara_rhs2 = sm_str_new(smar_addr->ara_rpool, MAXADDRLEN, SMAR_MAXRHS); if (NULL == smar_addr->ara_rhs2) { ret = sm_err_temp(ENOMEM); goto done; } if (!SMARA_IS_FLAG(smar_addr, SMARA_FL_PA2EMPTY)) { smar_addr->ara_user2 = sm_str_new(smar_addr->ara_rpool, MAXADDRLEN >> 1, MAXADDRLEN); smar_addr->ara_detail2 = sm_str_new(smar_addr->ara_rpool, MAXADDRLEN >> 1, MAXADDRLEN); smar_addr->ara_domain_pa2 = sm_str_new(smar_addr->ara_rpool, MAXADDRLEN >> 1, MAXADDRLEN); if (smar_addr->ara_user2 == NULL || smar_addr->ara_detail2 == NULL || NULL == smar_addr->ara_domain_pa2) { ret = sm_err_temp(ENOMEM); goto done; } ret = t2821_parts(paddr, smar_ctx->smar_cnf.smar_cnf_addr_delim, true, smar_addr->ara_user2, smar_addr->ara_detail2, smar_addr->ara_domain_pa2, &smar_addr->ara_delim2); if (0 == ret) { /* no delimiter: detail must be set to NULL! */ SM_STR_FREE(smar_addr->ara_detail2); } } a2821_free(paddr); paddr = NULL; if (sm_is_err(ret)) goto done; return ret; done: if (paddr != NULL) { a2821_free(paddr); paddr = NULL; } return ret; } /* ** SMAR_ADDR_INIT -- Initialize address data structure for further operations ** ** Parameters: ** smar_ctx -- SMAR context ** smar_addr -- address context ** rv -- return value (output) ** this is used by the caller to decide how to continue ** ** Returns: ** usual sm_error code ** ** Locking: smar_addr must be under control of the caller. ** ** Last code review: ** Last code change: ** ** Called by: smar_access_chk() ** ** XXX switch ret and rv? */ static sm_ret_T smar_addr_init(smar_ctx_P smar_ctx, smar_addr_P smar_addr, sm_ret_T *rv) { sm_ret_T ret; smar_clt_ctx_P smar_clt_ctx; SM_IS_SMAR_ADDR(smar_addr); SM_IS_SMAR_CTX(smar_ctx); SM_REQUIRE(rv != NULL); smar_clt_ctx = smar_addr->ara_smar_clt_ctx; ret = SM_SUCCESS; *rv = SM_SUCCESS; if (SMARA_IS_FLAG(smar_addr, SMARA_FL_INIT)) return SM_SUCCESS; /* SM_IS_SMAR_CLT_CTX(smar_clt_ctx); not really necessary here */ smar_addr->ara_c_MX = smar_addr->ara_c_A = 0; smar_addr->ara_c_dnsbl = 0; /* default status: "continue" aka "don't know" */ smar_addr->ara_status = SMTP_R_CONT; smar_addr->ara_mapres = SM_ACC_NOTFOUND; smar_addr->ara_str = smar_addr->ara_tag = smar_addr->ara_detail = NULL; smar_addr->ara_domain_pa = NULL; smar_addr->ara_rvrs = NULL; smar_addr->ara_rcpt = NULL; smar_addr->ara_rcpts = NULL; smar_addr->ara_rhstagoff = 0; /* which lookup types use RFC2821 addresses? */ if (SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_MAIL_ACC|SMARA_LT_MAIL_ROUTE| SMARA_LT_RCPT_ACC|SMARA_LT_RCPT_PROT)) SMARA_SET_FLAG(smar_addr, SMARA_FL_RFC2821); /* XXX is this needed? it can be done by smar_access_re() */ if (SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_CLT_A_ACC)) smar_addr->ara_which_status = RT_A2S_CLT_A_ST; else if (SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_CLT_N_ACC)) smar_addr->ara_which_status = RT_A2S_CLT_N_ST; else if (SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_MAIL_ACC| SMARA_LT_MAIL_ROUTE|SMARA_LT_MAIL_LOCAL)) smar_addr->ara_which_status = RT_A2S_MAIL_ST; else if (SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_RCPT_ACC| SMARA_LT_RCPT_PROT)) smar_addr->ara_which_status = RT_A2S_RCPT_ST; else if (SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_CERT_RELAY)) smar_addr->ara_which_status = RT_A2S_CERT_ST; else if (SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_EHLO_ACC)) smar_addr->ara_which_status = RT_A2S_EHLO_ST; else { /* XXX BOGUS */ smar_addr->ara_which_status = RT_A2S_CLT_N_ST; goto done; } if (SMARA_IS_FLAG(smar_addr, SMARA_FL_RFC2821)) { int flags; A2821_INIT_RP(&smar_addr->ara_a_rcpt, smar_addr->ara_rpool); ret = t2821_scan((sm_rdstr_P) smar_addr->ara_pa, &smar_addr->ara_a_rcpt, 0); if (sm_is_err(ret)) goto done; flags = R2821_CORRECT & ~R2821_AT; if (SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_MAIL_ACC|SMARA_LT_MAIL_ROUTE)) flags |= R2821_EMPTY; ret = t2821_parse(&smar_addr->ara_a_rcpt, flags); if (sm_is_err(ret)) goto done; smar_addr->ara_detail = sm_str_new(smar_addr->ara_rpool, MAXADDRLEN >> 1, MAXADDRLEN); if (NULL == smar_addr->ara_detail) goto done; smar_addr->ara_domain_pa = sm_str_new(smar_addr->ara_rpool, MAXADDRLEN >> 1, MAXADDRLEN); if (NULL == smar_addr->ara_domain_pa) goto done; } smar_addr->ara_str = sm_str_new(smar_addr->ara_rpool, MAXADDRLEN, MAXADDRLEN + 2); if (NULL == smar_addr->ara_str) goto done; smar_addr->ara_rhs = sm_str_new(smar_addr->ara_rpool, MAXADDRLEN, SMAR_MAXRHS); if (NULL == smar_addr->ara_rhs) goto done; smar_addr->ara_tag = sm_str_new(smar_addr->ara_rpool, MAXADDRLEN, MAXADDRLEN + 2); if (NULL == smar_addr->ara_tag) goto done; /* setup mutex+cond for asynchronous calls */ if (SMARA_IS_LFLAG(smar_addr, SMARA_LFL_RVRS4) || SMARA_IS_LFLAG(smar_addr, SMARA_LFL_DNSBL) || SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_MAIL_ROUTE)) { int r; r = pthread_mutex_init(&smar_addr->ara_mutex, SM_PTHREAD_MUTEXATTR); if (r != 0) goto done; /* XXX set some error code, log? */ SMARA_SET_FLAG(smar_addr, SMARA_FL_HASMUT); r = pthread_cond_init(&smar_addr->ara_cond, NULL); if (r != 0) goto done; /* XXX set some error code, log? */ SMARA_SET_FLAG(smar_addr, SMARA_FL_HASCOND); } if (SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_MAIL_ROUTE)) { smar_addr->ara_which_status = RT_A2S_MAIL_ST; if (sm_is_err(smar_rcpts_new(smar_ctx, smar_clt_ctx, &smar_addr->ara_rcpts)) || sm_is_err(smar_rcpt_new(&smar_addr->ara_rcpt))) goto done; /* create rcpt id, idx = 0 (bogus, but irrelevant) */ smar_addr->ara_rcpt_idx = 0; sm_snprintf(smar_addr->ara_rcpt->arr_id, sizeof(smar_addr->ara_rcpt->arr_id), SMTP_RCPTID_FORMAT, smar_addr->ara_taid, 0); RCPT_ID_COPY(smar_addr->ara_rcpts->arrs_rcpt_id, smar_addr->ara_rcpt->arr_id); smar_addr->ara_rcpt->arr_pa = sm_str_dup(NULL, smar_addr->ara_pa); if (NULL == smar_addr->ara_rcpt->arr_pa) goto done; smar_addr->ara_rcpts->arrs_rcpt = smar_addr->ara_rcpt; SMARR_SET_FLAG(smar_addr->ara_rcpt, SMARR_FL_ORCPT); SMARRS_SET_FLAG(smar_addr->ara_rcpts, SMARRS_FL_NOSEND|SMARRS_FL_NOFREE); /* XXX setup more data? */ smar_addr->ara_rcpt->arr_rqflags = SMARRQ_FL_NOEXP|SMARRQ_FL_NOMXCUT; smar_addr->ara_rcpt->arr_timeout = DNS_TIMEOUT; smar_addr->ara_rcpts->arrs_cbf = smar_rcpt_notify; smar_addr->ara_rcpts->arrs_cb_ctx = smar_addr; ++smar_addr->ara_res_cnt; /* This is an asynchronous function! */ ret = smar_rcpt_rslv(smar_ctx, smar_addr->ara_rcpts); if (sm_is_success(ret)) SMARA_SET_FLAG(smar_addr, SMARA_FL_A4RCPT); else --smar_addr->ara_res_cnt; /* ignore error, ara_status is initialized */ ret = SM_SUCCESS; /* better safe than sorry */ } if (SMARA_IS_LFLAG(smar_addr, SMARA_LFL_RVRS4)) { ret = smar_rvrs_new(smar_ctx, smar_clt_ctx, &smar_addr->ara_rvrs); if (sm_is_err(ret)) goto done; /* XXX set some error code, log? */ SMARV_SET_FLAG(smar_addr->ara_rvrs, SMARV_FL_NOSEND|SMARV_FL_NOFREE); SESSTA_COPY(smar_addr->ara_rvrs->arv_seid, smar_addr->ara_taid); smar_addr->ara_rvrs->arv_ltype = smar_addr->ara_ltype; smar_addr->ara_rvrs->arv_lflags = smar_addr->ara_lflags; sm_str_cat(smar_addr->ara_str, smar_addr->ara_pa); ret = sm_inet_a2ipv4((const char *)sm_str_getdata(smar_addr->ara_str), NULL, &smar_addr->ara_rvrs->arv_ipv4); smar_addr->ara_rvrs->arv_cbf = smar_rvrs_notify; smar_addr->ara_rvrs->arv_cb_ctx = smar_addr; sm_str_clr(smar_addr->ara_str); ++smar_addr->ara_res_cnt; /* This is an asynchronous function! */ ret = smar_rvrs_rslv(smar_ctx, smar_addr->ara_rvrs, 0u); SMAR_LEV_DPRINTF(5, (SMAR_DEBFP, "sev=DBG, func=smar_addr_init, smar_rvrs_rslv=%r\n", ret)); if (sm_is_success(ret)) SMARA_SET_FLAG(smar_addr, SMARA_FL_A4RVRS); else --smar_addr->ara_res_cnt; /* ignore error, ara_status is initialized */ ret = SM_SUCCESS; /* better safe than sorry */ } /* ** don't do this here if clt access is checked because it may ** make this superfluous? */ if (SMARA_IS_LFLAG(smar_addr, SMARA_LFL_DNSBL) && !SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_CLT_A_ACC)) { ret = smar_startdnsbl(smar_ctx, smar_addr); if (sm_is_err(ret)) goto done; /* XXX set some error code, log? */ } /* check flags for what to do... */ if (SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_CLT_A_ACC)) ret = sm_str_scat(smar_addr->ara_tag, CLT_A_TAG); else if (SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_CLT_N_ACC)) ret = sm_str_scat(smar_addr->ara_tag, CLT_N_TAG); else if (SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_MAIL_ACC|SMARA_LT_MAIL_ROUTE)) ret = sm_str_scat(smar_addr->ara_tag, MAIL_TAG); else if (SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_RCPT_ACC)) ret = sm_str_scat(smar_addr->ara_tag, RCPT_TAG); else if (SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_RCPT_PROT)) { ret = sm_str_scat(smar_addr->ara_tag, PROT_RCPT_TAG); SMARA_SET_FLAG(smar_addr, SMARA_FL_GOTRCPTPROT|SMARA_FL_RP_ANALYSE); /* note: this is too early, but the check is done "real soon" */ } else if (SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_EHLO_ACC)) ret = sm_str_scat(smar_addr->ara_tag, EHLO_TAG); else if (!SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_CERT_RELAY)) goto done; if (sm_is_err(ret)) goto done; if (SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_RCPT_PROT) && SMARA_IS_LFLAG(smar_addr, SMARA_LFL_PROTMAP) && smar_addr->ara_pa2 != NULL) { ret = smar_init_pa2(smar_ctx, smar_addr); if (sm_is_err(ret)) goto done; } else if (SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_RCPT_PROT) && SMARA_IS_LFLAG(smar_addr, SMARA_LFL_PROTMAP)) { smar_addr->ara_rhs2 = sm_str_new(smar_addr->ara_rpool, MAXADDRLEN, SMAR_MAXRHS); if (NULL == smar_addr->ara_rhs2) goto done; } if (SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_SS_SE_CONF)) { smar_addr->ara_rhs_conf = sm_str_new(smar_addr->ara_rpool, MAXADDRLEN, SMAR_MAXRHS); if (NULL == smar_addr->ara_rhs_conf) goto done; } if (SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_RCPT_PROT) && SMARA_IS_LFLAG(smar_addr, SMARA_LFL_PROTMAP)) { ret = sm_map_open(smar_ctx->smar_maps, smar_ctx->smar_strmaptype /* HACK!!! should be NAME */, smar_ctx->smar_strmaptype, 0, "", SMAP_MODE_RDONLY, &smar_addr->ara_str_map, SMPO_END); if (sm_is_err(ret)) { SMAR_LEV_DPRINTF(5, (SMAR_DEBFP, "sev=ERROR, func=smar_addr_init, map=%C, sm_map_open=%r\n", ret, smar_ctx->smar_strmaptype)); goto done; } } if (SMARA_IS_LFLAG(smar_addr, SMARA_LFL_2821)) { SM_ASSERT(SMARA_IS_FLAG(smar_addr, SMARA_FL_RFC2821)); sm_str_clr(smar_addr->ara_str); ret = t2821_parts(&smar_addr->ara_a_rcpt, smar_ctx->smar_cnf.smar_cnf_addr_delim, true, smar_addr->ara_str, smar_addr->ara_detail, smar_addr->ara_domain_pa, &smar_addr->ara_delim); if (sm_is_err(ret)) { SMAR_LEV_DPRINTF(5, (SMAR_DEBFP, "sev=ERROR, func=smar_addr_init, t2821_parts=%r\n", ret)); goto done; } if (0 == ret) { /* no delimiter: detail must be set to NULL! */ SM_STR_FREE(smar_addr->ara_detail); } } else if (SMARA_IS_LFLAG(smar_addr, SMARA_LFL_IPV4|SMARA_LFL_STR)) { sm_str_clr(smar_addr->ara_str); ret = sm_str_cat(smar_addr->ara_str, smar_addr->ara_pa); if (sm_is_err(ret)) goto done; } /* ... other cases?? ... */ SMARA_SET_FLAG(smar_addr, SMARA_FL_INIT); return ret; done: SMARA_SET_FLAG(smar_addr, SMARA_FL_INIT); *rv = SM_DONE; return ret; } /* ** SMAR_ACC_ANALYSE -- Analyse result of current check/map lookup ** ** Parameters: ** smar_ctx -- SMAR context ** smar_addr -- address context ** ret -- return value of map lookup ** ** Returns: ** usual sm_error code ** if ok: smar_addr->ara_status should have result of lookup(s) ** ** Locking: smar_addr must be under control of the caller. ** ** Last code review: ** Last code change: 2005-08-24 05:24:02 */ static sm_ret_T smar_acc_analyse(smar_ctx_P smar_ctx, smar_addr_P smar_addr, sm_ret_T ret) { sm_ret_T res; /* note: ara_str is not necessarily the item that was looked up! */ sm_log_write(smar_ctx->smar_lctx, AR_LCAT_RESOLVER, AR_LMOD_RESOLVER, SM_LOG_INFO, 14, "sev=INFO, func=smar_acc_analyse, tag=%S, str=%S, ret=%r, rhs=%.256S", smar_addr->ara_tag, smar_addr->ara_str, ret, smar_addr->ara_rhs); if (ret != SM_SUCCESS) { /* XXX check for other temporary errors? */ res = smar_map2acc(ret); if (res == sm_error_perm(SM_EM_AR, EINVAL)) { sm_log_write(smar_ctx->smar_lctx, AR_LCAT_RESOLVER, AR_LMOD_RESOLVER, SM_LOG_ERR, 4, "sev=ERROR, func=smar_acc_analyse, str=%S, ret=%m, rhs=%.256S", smar_addr->ara_str, ret, smar_addr->ara_rhs); } smar_addr->ara_mapres = res; smar_addr->ara_status = SMTP_R_CONT; sm_str_clr(smar_addr->ara_rhs); } else if (sm_str_getlen(smar_addr->ara_rhs) > 0 && SMARA_IS_FLAG(smar_addr, SMARA_FL_RP_ANALYSE) && SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_RCPT_PROT)) { res = smar_prot_rhs(smar_ctx, smar_addr); } else if (sm_str_getlen(smar_addr->ara_rhs) > 0) { char *rhsc; uint mod_len; mod_len = 0; rhsc = (char *) sm_str_getdata(smar_addr->ara_rhs); if (NULL == rhsc) { /* tempfail... */ ret = sm_error_temp(SM_EM_AR, ENOMEM); goto error; } if (sm_str_getlen(smar_addr->ara_rhs) > RHS_QUICK_LEN && strncasecmp(rhsc, RHS_QUICK, RHS_QUICK_LEN) == 0) { mod_len = RHS_QUICK_LEN; rhsc += RHS_QUICK_LEN; SMAR_SET_RFL(smar_addr, SMAR_R_QUICK); } else if (sm_str_getlen(smar_addr->ara_rhs) > RHS_DELAY_LEN && strncasecmp(rhsc, RHS_DELAY, RHS_DELAY_LEN) == 0) { mod_len = RHS_DELAY_LEN; rhsc += RHS_DELAY_LEN; SMAR_SET_RFL(smar_addr, SMAR_R_DELAY); } if (sm_strcaseeq(rhsc, "OK")) { sm_str_clr(smar_addr->ara_rhs); smar_addr->ara_mapres = SM_ACC_FOUND; smar_addr->ara_status = SMTP_R_OK; /* stop further lookups?? */ /* see design docs about sequence of lookups! */ SMARA_SET_FLAG(smar_addr, SMARA_FL_STOP); } else if (sm_strcaseeq(rhsc, "RELAY")) { sm_str_clr(smar_addr->ara_rhs); smar_addr->ara_mapres = SM_ACC_FOUND; smar_addr->ara_status = SMTP_R_RELAY; /* stop further lookups?? */ /* see design docs about sequence of lookups! */ SMARA_SET_FLAG(smar_addr, SMARA_FL_STOP); } else if (sm_strcaseeq(rhsc, "CONT") /* || sm_strcaseeq(rhsc, "DUNNO") */ ) { sm_str_clr(smar_addr->ara_rhs); smar_addr->ara_mapres = SM_ACC_FOUND; smar_addr->ara_status = SMTP_R_CONT; } else if (sm_strcaseeq(rhsc, "REJECT")) { sm_str_clr(smar_addr->ara_rhs); smar_addr->ara_mapres = SM_ACC_FOUND; smar_addr->ara_status = SMTP_R_REJECT; } else if (sm_strcaseeq(rhsc, "DISCARD")) { sm_str_clr(smar_addr->ara_rhs); smar_addr->ara_mapres = SM_ACC_FOUND; smar_addr->ara_status = SMTP_R_DISCARD; /* stop further lookups?? */ /* see design docs about sequence of lookups! */ SMARA_SET_FLAG(smar_addr, SMARA_FL_STOP); } else if (strncasecmp(rhsc, RHS_ERROR, RHS_ERROR_LEN) == 0) { smar_addr->ara_rhstagoff = RHS_ERROR_LEN + mod_len; smar_addr->ara_mapres = SM_ACC_FOUND; if (IS_SMTP_REPLY_STR(smar_addr->ara_rhs, smar_addr->ara_rhstagoff)) { smar_addr->ara_status = SMTP_REPLY_STR2VAL(smar_addr->ara_rhs, smar_addr->ara_rhstagoff); } } } return SM_SUCCESS; error: return ret; } /* ** SMAR_GREY -- Perform greylisting check ** ** Parameters: ** smar_ctx -- SMAR context ** smar_addr -- address context ** perr -- (pointer to) error code (output) ** ** Returns: ** usual sm_error code ** if ok: smar_addr->ara_rhs has result, smar_acc_analyse() ** should be called to "analyse" it. ** ** Locking: smar_addr must be under control of the caller. ** ** Last code review: ** Last code change: */ static sm_ret_T smar_grey(smar_ctx_P smar_ctx, smar_addr_P smar_addr, sm_ret_T *perr) { sm_ret_T ret; ipv4_T ipv4; SM_IS_SMAR_CTX(smar_ctx); SM_IS_SMAR_ADDR(smar_addr); SM_REQUIRE(perr != NULL); *perr = SM_SUCCESS; if (!SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_GREY) || SMARA_IS_FLAG(smar_addr, SMARA_FL_GOTGREY) || !SMAR_IS_FLAG(smar_ctx, SMAR_FL_HASGREY)) return SM_NOTDONE; SMARA_SET_FLAG(smar_addr, SMARA_FL_GOTGREY); if (SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_RCPT_ACC)) { ipv4 = smar_addr->ara_ipv4; ret = SM_SUCCESS; } else { ret = sm_inet_a2ipv4((const char *)sm_str_getdata(smar_addr->ara_pa), NULL, &ipv4); } if (sm_is_success(ret) && ipv4 != INADDR_ANY && smar_addr->ara_conn_time != 0) { ret = sm_greyctl(smar_ctx->smar_greyctx, (uchar *)&ipv4, sizeof(ipv4), smar_addr->ara_conn_time); SMAR_LEV_DPRINTF(1, (SMAR_DEBFP, "sev=DBG, func=smar_grey, grey=%r, ip=%A, now=%ld\n", ret, ipv4, (long) smar_addr->ara_conn_time)); /* ** "convert" ret into "map lookup result" ** suitable for smar_acc_analyse() */ if (SM_GREY_AGAIN == ret || SM_GREY_FIRST == ret || SM_GREY_WAIT == ret) { ret = SM_SUCCESS; sm_str_clr(smar_addr->ara_rhs); (void) sm_str_scat(smar_addr->ara_rhs, "error:421 4.7.0 Come back later."); smar_addr->ara_mapres = SM_ACC_FOUND; SMAR_SET_RFL(smar_addr, SMAR_R_GREY); } else ret = SM_MAP_NOTFOUND; SMARA_SET_FLAG(smar_addr, SMARA_FL_DIDLOOKUP); SMAR_SET_RFL(smar_addr, SMAR_R_GREYCHKD); } SMARA_SET_FLAG(smar_addr, SMARA_FL_GOTGREY); return ret; } /* ** SMAR_CLTRESOLVE -- Perform cltresolve check ** ** Parameters: ** smar_ctx -- SMAR context ** smar_addr -- address context ** perr -- (pointer to) error code (output) ** ** Returns: ** usual sm_error code ** ** Locking: smar_addr must be under control of the caller. ** ** Last code review: ** Last code change: */ static sm_ret_T smar_cltresolve(smar_ctx_P smar_ctx, smar_addr_P smar_addr, sm_ret_T *perr) { sm_ret_T ret; #define CLT_RVRS_TAG "cltresolve:" SM_REQUIRE(perr != NULL); *perr = SM_SUCCESS; if (SMARA_IS_FLAG(smar_addr, SMARA_FL_GOTRVRSA) || !SMARA_IS_LFLAG(smar_addr, SMARA_LFL_RVACC)) return SM_NOTDONE; ret = SM_SUCCESS; sm_str_clr(smar_addr->ara_str); /* XXX can block */ if (smar_dns_getret(smar_addr) == SM_SUCCESS && sm_str_scat(smar_addr->ara_str, CLT_RVRS_TAG) == SM_SUCCESS && sm_str_scat(smar_addr->ara_str, sm_rslv2txt(smar_addr->ara_rvrs->arv_ret)) == SM_SUCCESS) { sm_str_clr(smar_addr->ara_rhs); ret = sm_map_lookup(smar_ctx->smar_access, SMMAP_FL_LWR_KEY, smar_addr->ara_str, smar_addr->ara_rhs); SMARA_SET_FLAG(smar_addr, SMARA_FL_DIDLOOKUP); } SMARA_SET_FLAG(smar_addr, SMARA_FL_GOTRVRSA); return ret; } /* ** SMAR_CLTNAME -- Perform clientname check ** ** Parameters: ** smar_ctx -- SMAR context ** smar_addr -- address context ** perr -- (pointer to) error code (output) ** ** Returns: ** usual sm_error code ** ** Locking: smar_addr must be under control of the caller. ** ** Last code review: ** Last code change: */ static sm_ret_T smar_cltname(smar_ctx_P smar_ctx, smar_addr_P smar_addr, sm_ret_T *perr) { sm_ret_T ret; SM_REQUIRE(perr != NULL); *perr = SM_SUCCESS; /* Note: SMARA_LT_RVRS_N_ACC requires SMARA_LFL_RVACC! */ if (SMARA_IS_FLAG(smar_addr, SMARA_FL_GOTRVRSN) || !SMARA_IS_FLAG(smar_addr, SMARA_FL_GOTRVRSA) || !SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_RVRS_N_ACC) || NULL == smar_addr->ara_rvrs_hostname) return SM_NOTDONE; ret = SM_SUCCESS; sm_str_clr(smar_addr->ara_tag); ret = sm_str_scat(smar_addr->ara_tag, CLT_N_TAG); ret = sm_map_lookup_domain(smar_ctx->smar_access, (sm_rdstr_P) smar_addr->ara_rvrs_hostname, smar_addr->ara_tag, 0, smar_addr->ara_rhs); SMARA_SET_FLAG(smar_addr, SMARA_FL_DIDLOOKUP|SMARA_FL_GOTRVRSN); return ret; } /* ** SMAR_DNSBL -- check DNSBL results (look up in access map) ** ** Parameters: ** smar_ctx -- SMAR context ** smar_addr -- address context ** perr -- (pointer to) error code (output) ** ** Returns: ** usual sm_error code ** ** Locking: smar_addr must be under control of the caller. ** ** Last code review: ** Last code change: 2007-06-21 05:07:49 */ static sm_ret_T smar_chk_dnsbl(smar_ctx_P smar_ctx, smar_addr_P smar_addr, sm_ret_T *perr) { sm_ret_T ret; char *dnsbltag; SM_REQUIRE(perr != NULL); *perr = SM_SUCCESS; if (SMARA_IS_LFLAG(smar_addr, SMARA_LFL_DNSBL) && !SMARA_IS_FLAG(smar_addr, SMARA_FL_A4DNSBL)) { /* This is an asynchronous function! */ ret = smar_startdnsbl(smar_ctx, smar_addr); if (sm_is_err(ret)) { *perr = ret; return ret; } } /* get DNS BL results? */ if (SMARA_IS_LFLAG(smar_addr, SMARA_LFL_DNSBL) && !SMARA_IS_FLAG(smar_addr, SMARA_FL_GOTDNSBL) && !SMARA_IS_FLAG(smar_addr, SMARA_FL_FAILDNS)) { /* XXX can block */ if (smar_dns_getret(smar_addr) != SM_SUCCESS) SMARA_SET_FLAG(smar_addr, SMARA_FL_FAILDNS); } if (!SMARA_IS_LFLAG(smar_addr, SMARA_LFL_DNSBL) || !SMARA_IS_FLAG(smar_addr, SMARA_FL_GOTDNSBL) || smar_addr->ara_c_dnsbl >= SM_MAX_DNSBL || smar_ctx->smar_cnf.smar_cnf_dnsbl[smar_addr->ara_c_dnsbl].scdb_name == NULL) return SM_NOTDONE; ret = SM_SUCCESS; sm_str_clr(smar_addr->ara_str); dnsbltag = smar_ctx->smar_cnf.smar_cnf_dnsbl[smar_addr->ara_c_dnsbl].scdb_tag; if (NULL == dnsbltag) dnsbltag = "dnsbl"; if (smar_addr->ara_dnsblres[smar_addr->ara_c_dnsbl].sbdr_res == SM_DNSBL_RES_OK && sm_strprintf(smar_addr->ara_str, "%s:%A", dnsbltag, smar_addr->ara_dnsblres[smar_addr->ara_c_dnsbl].sdbr_ipv4) > 0) { /* should this use _lookup_ip? */ sm_str_clr(smar_addr->ara_rhs); ret = sm_map_lookup(smar_ctx->smar_access, SMMAP_FL_LWR_KEY, smar_addr->ara_str, smar_addr->ara_rhs); SMARA_SET_FLAG(smar_addr, SMARA_FL_DIDLOOKUP); *perr = SM_AGAIN; SMAR_LEV_DPRINTF(5, (SMAR_DEBFP, "dnsbl=%S, ret=%r\n", smar_addr->ara_str, ret)); /* * check the rest... but how to get the result back? * add a counter: * smar_addr->ara_dnsblres[smar_addr->ara_c_dnsbl].sbdr_i * and check it against the limit in the statement above similar to * smar_addr->ara_c_dnsbl >= SM_MAX_DNSBL * * however, then we still have the problem of selecting the "right" * result, e.g., perm over temp error. * * call something like "analyze" to extract result? */ /* hack for now: try to find the first match, this is random! */ if (smar_addr->ara_dnsblres[smar_addr->ara_c_dnsbl].sdbr_n > 0 && smar_addr->ara_dnsblres[smar_addr->ara_c_dnsbl].sdbr_ipv4s != NULL && ret != SM_SUCCESS ) { uint ui; ipv4_T *ipv4s; for (ui = 0, ipv4s = smar_addr->ara_dnsblres[smar_addr->ara_c_dnsbl].sdbr_ipv4s; ui < smar_addr->ara_dnsblres[smar_addr->ara_c_dnsbl].sdbr_n && ret != SM_SUCCESS; ++ui) { sm_str_clr(smar_addr->ara_str); if (sm_strprintf(smar_addr->ara_str, "%s:%A", dnsbltag, ipv4s[ui]) > 0) { sm_str_clr(smar_addr->ara_rhs); ret = sm_map_lookup(smar_ctx->smar_access, SMMAP_FL_LWR_KEY, smar_addr->ara_str, smar_addr->ara_rhs); SMAR_LEV_DPRINTF(5, (SMAR_DEBFP, "dnsbl=%S, ret=%r\n", smar_addr->ara_str, ret)); } } } } else if (smar_addr->ara_dnsblres[smar_addr->ara_c_dnsbl].sbdr_res == DNSR_TEMP && sm_str_scatv(smar_addr->ara_str, 2, dnsbltag, ":temp") == SM_SUCCESS) { sm_str_clr(smar_addr->ara_rhs); ret = sm_map_lookup(smar_ctx->smar_access, SMMAP_FL_LWR_KEY, smar_addr->ara_str, smar_addr->ara_rhs); SMARA_SET_FLAG(smar_addr, SMARA_FL_DIDLOOKUP); *perr = SM_AGAIN; SMAR_LEV_DPRINTF(5, (SMAR_DEBFP, "dnsbl=%S, ret=%r\n", smar_addr->ara_str, ret)); } else if (smar_addr->ara_dnsblres[smar_addr->ara_c_dnsbl].sbdr_res == DNSR_PERM && sm_str_scatv(smar_addr->ara_str, 2, dnsbltag, ":perm") == SM_SUCCESS) { sm_str_clr(smar_addr->ara_rhs); ret = sm_map_lookup(smar_ctx->smar_access, SMMAP_FL_LWR_KEY, smar_addr->ara_str, smar_addr->ara_rhs); SMARA_SET_FLAG(smar_addr, SMARA_FL_DIDLOOKUP); *perr = SM_AGAIN; SMAR_LEV_DPRINTF(5, (SMAR_DEBFP, "dnsbl=%S, ret=%r\n", smar_addr->ara_str, ret)); } ++smar_addr->ara_c_dnsbl; return ret; } /* ** SMAR_MXBADIP -- Perform MXBADIP check ** ** Parameters: ** smar_ctx -- SMAR context ** smar_addr -- address context ** perr -- (pointer to) error code (output) ** ** Returns: ** usual sm_error code ** ** Locking: smar_addr must be under control of the caller. ** ** Last code review: ** Last code change: */ static sm_ret_T smar_mxbadip(smar_ctx_P smar_ctx, smar_addr_P smar_addr, sm_ret_T *perr) { sm_ret_T ret; smar_dns_P smar_dns; SM_REQUIRE(perr != NULL); *perr = SM_SUCCESS; /* ** XXX Need consistency check! ** ara_rcpts is only initialized of ** SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_MAIL_ROUTE) ** but this test is supposed to be done ** SMARA_IS_LFLAG(smar_addr, SMARA_LFL_MXACC) ** -> confusion with lookup type and flags! */ if (smar_addr->ara_mapres != SM_ACC_NOTFOUND || !SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_MAIL_ROUTE) || !SMARA_IS_LFLAG(smar_addr, SMARA_LFL_MXACC)) return SM_NOTDONE; ret = SM_SUCCESS; SMAR_LEV_DPRINTF(5, (SMAR_DEBFP, "func=smar_mxbadip, call=smar_dns_getret, where=mxbadip\n")); if (!SMARA_IS_FLAG(smar_addr, SMARA_FL_GOTRCPT)) { /* XXX can block */ ret = smar_dns_getret(smar_addr); if (sm_is_err(ret)) goto error; } SMAR_LEV_DPRINTF(5, (SMAR_DEBFP, "func=smar_mxbadip, ara_dns_ret=%r\n", smar_addr->ara_dns_ret)); if (smar_addr->ara_dns_ret != SM_SUCCESS) { ret = smar_dns2ret(smar_ctx, smar_addr); SMAR_LEV_DPRINTF(5, (SMAR_DEBFP, "func=smar_mxbadip, ara_dns_ret=%r, ret=%r\n", smar_addr->ara_dns_ret, ret)); if (sm_is_err(ret)) goto error; /* required for smar_access_re() */ smar_addr->ara_mapres = SM_ACC_FOUND; SMARA_CLR_FLAG(smar_addr, SMARA_FL_DIDLOOKUP); *perr = SM_BREAK; return SM_SUCCESS; } #define MAIL_MX_TAG "mxbadip:" sm_str_clr(smar_addr->ara_str); SM_IS_SMAR_RCPTS(smar_addr->ara_rcpts); SM_IS_SMAR_RCPT(smar_addr->ara_rcpt); SMAR_LEV_DPRINTF(4, (SMAR_DEBFP, "n_mx=%d, ipv4=%A\n", smar_addr->ara_rcpt->arr_A_qsent, smar_addr->ara_rcpt->arr_ipv4)); sm_str_scat(smar_addr->ara_str, MAIL_MX_TAG); /* ** This would be a nested loop: ** ** for (c_MX = 0; c_MX < smar_addr->ara_rcpt->arr_A_qsent; c_MX++) ** smar_dns = &(smar_addr->ara_rcpt->arr_res[c_MX]); ** for (c_A = 0; c_A < smar_dns->ardns_n_Al c_A++) ** do lookup ** ** except that we are in a do { } while () loop already ** which we want to reuse for checking ** the results of each lookup. ** hence we "wrap" the loop "inside out": ** ** c_MX = c_A = 0; ** do { ** next_MX: ** if (c_MX < smar_addr->ara_rcpt->arr_A_qsent) { ** smar_dns = &(smar_addr->ara_rcpt->arr_res[c_MX]); ** * check whether c_A is OK * ** if (c_A >= smar_dns->ardns_n_A) { ** * try next c_MX * ** ++c_MX; c_A = 0; ** goto next_MX; ** } ** do lookup ** } ** } while (); ** ** let's remove the goto: ** ** c_MX = c_A = 0; ** do { ** if (c_MX < smar_addr->ara_rcpt->arr_A_qsent) { ** smar_dns = &(smar_addr->ara_rcpt->arr_res[c_MX]); ** * check whether c_A is OK * ** while (c_A >= smar_dns->ardns_n_A) { ** c_A = 0; ++c_MX; ** if (c_MX < smar_addr->ara_rcpt->arr_A_qsent) ** smar_dns = &(smar_addr->ara_rcpt->arr_res[c_MX]); ** else ** break; ** } ** * check whether end has not been reached * ** if (c_MX < smar_addr->ara_rcpt->arr_A_qsent && ** c_A < smar_dns->ardns_n_A) { ** do lookup ** } ** } ** } while (); ** */ if (0 == smar_addr->ara_rcpt->arr_A_qsent) { sm_inet_ipv4str(smar_addr->ara_rcpt->arr_ipv4, smar_addr->ara_str); SMARA_SET_FLAG(smar_addr, SMARA_FL_DIDLOOKUP); SMARA_CLR_LFLAG(smar_addr, SMARA_LFL_MXACC); } else if (smar_addr->ara_c_MX < smar_addr->ara_rcpt->arr_A_qsent) { smar_dns = &(smar_addr->ara_rcpt->arr_res[smar_addr->ara_c_MX]); SMAR_LEV_DPRINTF(4, (SMAR_DEBFP, "smar_addr->ara_c_MX=%d, smar_dns=%p\n", smar_addr->ara_c_MX, smar_dns)); while (smar_addr->ara_c_A >= smar_dns->ardns_n_A) { smar_addr->ara_c_A = 0; ++smar_addr->ara_c_MX; if (smar_addr->ara_c_MX < smar_addr->ara_rcpt->arr_A_qsent) smar_dns = &(smar_addr->ara_rcpt->arr_res[smar_addr->ara_c_MX]); else break; } if (smar_addr->ara_c_MX < smar_addr->ara_rcpt->arr_A_qsent && smar_addr->ara_c_A < smar_dns->ardns_n_A) { /* XXX HACK: ignore addresses with value 0 */ if (smar_dns->ardns_A_rrs[smar_addr->ara_c_A] != 0) sm_inet_ipv4str(smar_dns->ardns_A_rrs[smar_addr->ara_c_A], smar_addr->ara_str); SMAR_LEV_DPRINTF(4, (SMAR_DEBFP, "smar_addr->ara_c_MX=%d, smar_addr->ara_c_A=%d, a=%A, str=%S\n", smar_addr->ara_c_MX, smar_addr->ara_c_A, smar_dns->ardns_A_rrs[smar_addr->ara_c_A], smar_addr->ara_str)); ++smar_addr->ara_c_A; SMARA_SET_FLAG(smar_addr, SMARA_FL_DIDLOOKUP); } } else SMARA_CLR_LFLAG(smar_addr, SMARA_LFL_MXACC); if (SMARA_IS_FLAG(smar_addr, SMARA_FL_DIDLOOKUP)) { sm_str_clr(smar_addr->ara_rhs); ret = sm_map_lookup(smar_ctx->smar_access, SMMAP_FL_LWR_KEY, smar_addr->ara_str, smar_addr->ara_rhs); } /* XXX use a different flag to indicate that the test has been done? */ return ret; error: *perr = ret; return ret; } /* ** SMAR_CERTSUB -- Perform CERT subject check ** ** Parameters: ** smar_ctx -- SMAR context ** smar_addr -- address context ** perr -- (pointer to) error code (output) ** ** Returns: ** usual sm_error code ** ** Locking: smar_addr must be under control of the caller. ** ** Last code review: ** Last code change: */ static sm_ret_T smar_certsub(smar_ctx_P smar_ctx, smar_addr_P smar_addr, sm_ret_T *perr) { sm_ret_T ret; SM_REQUIRE(perr != NULL); *perr = SM_SUCCESS; if (!SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_CERT_RELAY) || !SMARA_IS_FLAG(smar_addr, SMARA_FL_GOTCERTISS) || SMARA_IS_FLAG(smar_addr, SMARA_FL_GOTCERTSUB)) return SM_NOTDONE; ret = SM_SUCCESS; SMARA_SET_FLAG(smar_addr, SMARA_FL_GOTCERTSUB); sm_str_clr(smar_addr->ara_str); if (sm_str_scat(smar_addr->ara_str, CERT_SUBJECT_TAG) == SM_SUCCESS && sm_str_cat(smar_addr->ara_str, smar_addr->ara_pa2) == SM_SUCCESS) { sm_str_clr(smar_addr->ara_rhs); ret = sm_map_lookup(smar_ctx->smar_access, SMMAP_FL_LWR_KEY, smar_addr->ara_str, smar_addr->ara_rhs); SMARA_SET_FLAG(smar_addr, SMARA_FL_DIDLOOKUP); } return ret; } /* ** SMAR_PROTRCPT -- Perform PROTRCPT check ** ** Parameters: ** smar_ctx -- SMAR context ** smar_addr -- address context ** perr -- (pointer to) error code (output) ** ** Returns: ** usual sm_error code ** ** Locking: smar_addr must be under control of the caller. ** ** Last code review: ** Last code change: */ static sm_ret_T smar_protrcpt(smar_ctx_P smar_ctx, smar_addr_P smar_addr, sm_ret_T *perr) { sm_ret_T ret; SM_REQUIRE(perr != NULL); *perr = SM_SUCCESS; if (!SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_RCPT_PROT) || SMARA_IS_FLAG(smar_addr, SMARA_FL_GOTRCPTPROT)) return SM_NOTDONE; ret = SM_SUCCESS; sm_str_clr(smar_addr->ara_tag); ret = sm_str_scat(smar_addr->ara_tag, PROT_RCPT_TAG); SMARA_SET_FLAG(smar_addr, SMARA_FL_GOTRCPTPROT|SMARA_FL_RP_ANALYSE); /* flags (SMMAP_LFL_*) to be set by caller of smar?? */ ret = sm_map_lookup_addr(smar_ctx->smar_access, smar_addr->ara_str, smar_addr->ara_detail, smar_addr->ara_domain_pa, smar_addr->ara_tag, smar_addr->ara_delim, SMMAP_LFL_ALL|SMMAP_LFL_NOAT| (SMARA_IS_LFLAG(smar_addr, SMARA_LFL_ACCIMPLDET) ? SMMAP_LFL_IMPLDET : 0), smar_addr->ara_rhs); SMARA_SET_FLAG(smar_addr, SMARA_FL_DIDLOOKUP); return ret; } /* ** SMAR_CHK_IPV4 -- perform IPv4 access map lookup. ** ** Parameters: ** smar_ctx -- SMAR context ** smar_addr -- address context ** perr -- (pointer to) error code (output) ** ** Returns: ** usual sm_error code ** ** Locking: smar_addr must be under control of the caller. ** ** Last code review: ** Last code change: */ static sm_ret_T smar_chk_ipv4(smar_ctx_P smar_ctx, smar_addr_P smar_addr, sm_ret_T *perr) { sm_ret_T ret; SM_IS_SMAR_ADDR(smar_addr); SM_IS_SMAR_CTX(smar_ctx); SM_REQUIRE(perr != NULL); *perr = SM_SUCCESS; if (!SMARA_IS_LFLAG(smar_addr, SMARA_LFL_IPV4) || !SMARA_IS_LFLAG(smar_addr, SMARA_LFL_SUB) || SMARA_IS_FLAG(smar_addr, SMARA_FL_GOTIPV4ACC)) return SM_NOTDONE; sm_str_clr(smar_addr->ara_tag); ret = sm_str_scat(smar_addr->ara_tag, CLT_A_TAG); ret = sm_map_lookup_ip(smar_ctx->smar_access, smar_addr->ara_str, smar_addr->ara_tag, SMMAP_LFL_SUBNETS|SMMAP_LFL_TAG, smar_addr->ara_rhs); SMARA_SET_FLAG(smar_addr, SMARA_FL_DIDLOOKUP|SMARA_FL_GOTIPV4ACC); SMAR_LEV_DPRINTF(3, (SMAR_DEBFP, "sev=DBG, func=smar_chk_ipv4, ip=%S, tag=%S, ret=%r\n", smar_addr->ara_str, smar_addr->ara_tag, ret)); return ret; } /* ** SMAR_CHK_2821 -- perform RFC 2821 address access map lookup. ** ** Parameters: ** smar_ctx -- SMAR context ** smar_addr -- address context ** perr -- (pointer to) error code (output) ** ** Returns: ** usual sm_error code ** ** Locking: smar_addr must be under control of the caller. ** ** Last code review: ** Last code change: */ static sm_ret_T smar_chk_2821(smar_ctx_P smar_ctx, smar_addr_P smar_addr, sm_ret_T *perr) { sm_ret_T ret; SM_IS_SMAR_ADDR(smar_addr); SM_IS_SMAR_CTX(smar_ctx); SM_REQUIRE(perr != NULL); *perr = SM_SUCCESS; if (!SMARA_IS_LFLAG(smar_addr, SMARA_LFL_2821) || SMARA_IS_FLAG(smar_addr, SMARA_FL_GOT2821ACC)) return SM_NOTDONE; /* fixme: flags (SMMAP_LFL_*) to be set by caller of smar?? */ ret = sm_map_lookup_addr(smar_ctx->smar_access, smar_addr->ara_str, smar_addr->ara_detail, smar_addr->ara_domain_pa, smar_addr->ara_tag, smar_addr->ara_delim, SMMAP_LFL_ALL|SMMAP_LFL_NOAT| (SMARA_IS_LFLAG(smar_addr, SMARA_LFL_ACCIMPLDET) ? SMMAP_LFL_IMPLDET : 0), smar_addr->ara_rhs); SMARA_SET_FLAG(smar_addr, SMARA_FL_DIDLOOKUP|SMARA_FL_GOT2821ACC); SMAR_LEV_DPRINTF(3, (SMAR_DEBFP, "sev=DBG, func=smar_chk_2821, str=%S, detail=%S, domain=%S, tag=%S, ltype=%#x, lflags=%#x, flags=%#x, ret=%r\n", smar_addr->ara_str, smar_addr->ara_detail, smar_addr->ara_domain_pa, smar_addr->ara_tag, smar_addr->ara_ltype, smar_addr->ara_lflags, smar_addr->ara_flags, ret)); return ret; } /* ** SMAR_CHK_CERTISS -- perform CERT issuer access map lookup. ** ** Parameters: ** smar_ctx -- SMAR context ** smar_addr -- address context ** perr -- (pointer to) error code (output) ** ** Returns: ** usual sm_error code ** ** Locking: smar_addr must be under control of the caller. ** ** Last code review: ** Last code change: */ static sm_ret_T smar_chk_certiss(smar_ctx_P smar_ctx, smar_addr_P smar_addr, sm_ret_T *perr) { sm_ret_T ret; SM_IS_SMAR_ADDR(smar_addr); SM_IS_SMAR_CTX(smar_ctx); SM_REQUIRE(perr != NULL); *perr = SM_SUCCESS; if (!SMARA_IS_LFLAG(smar_addr, SMARA_LFL_CERT) || SMARA_IS_FLAG(smar_addr, SMARA_FL_GOTCERTISS)) return SM_NOTDONE; ret = SM_SUCCESS; SMARA_SET_FLAG(smar_addr, SMARA_FL_GOTCERTISS); sm_str_clr(smar_addr->ara_str); if (sm_str_scat(smar_addr->ara_str, CERT_ISSUER_TAG) == SM_SUCCESS && sm_str_cat(smar_addr->ara_str, smar_addr->ara_pa) == SM_SUCCESS) { sm_str_clr(smar_addr->ara_rhs); ret = sm_map_lookup(smar_ctx->smar_access, SMMAP_FL_LWR_KEY|SMMAP_LFL_TAG, smar_addr->ara_str, smar_addr->ara_rhs); SMARA_SET_FLAG(smar_addr, SMARA_FL_DIDLOOKUP); } return ret; } /* ** SMAR_CHK_GEN -- perform "generic" access map lookup. ** ** Parameters: ** smar_ctx -- SMAR context ** smar_addr -- address context ** perr -- (pointer to) error code (output) ** ** Returns: ** usual sm_error code ** ** Locking: smar_addr must be under control of the caller. ** ** Last code review: ** Last code change: */ static sm_ret_T smar_chk_gen(smar_ctx_P smar_ctx, smar_addr_P smar_addr, sm_ret_T *perr) { sm_ret_T ret; sm_str_P exchg; SM_IS_SMAR_ADDR(smar_addr); SM_IS_SMAR_CTX(smar_ctx); SM_REQUIRE(perr != NULL); *perr = SM_SUCCESS; /* Which flag to check here for SM_NOTDONE??? */ if (!SM_IS_FLAG(smar_addr->ara_ltype, SMAR_LT_ACCESS) || (SMARA_IS_LFLAG(smar_addr, SMARA_LFL_IPV4) && SMARA_IS_LFLAG(smar_addr, SMARA_LFL_SUB)) || SMARA_IS_LFLAG(smar_addr, SMARA_LFL_2821) || SMARA_IS_LFLAG(smar_addr, SMARA_LFL_CERT) ) return SM_NOTDONE; /* ** HACK: sm_map_lookup() doesn't support tags, hence: ** append ara_str to ara_tag and use that as key (by exchanging ** ara_tag and ara_str). */ ret = sm_str_cat(smar_addr->ara_tag, smar_addr->ara_str); if (sm_is_err(ret)) { /* tempfail? */ *perr = SM_DONE; } else { exchg = smar_addr->ara_str; smar_addr->ara_str = smar_addr->ara_tag; smar_addr->ara_tag = exchg; ret = sm_map_lookup(smar_ctx->smar_access, SMMAP_FL_LWR_KEY|SMMAP_FL_HAS_TAG, smar_addr->ara_str, smar_addr->ara_rhs); SMARA_SET_FLAG(smar_addr, SMARA_FL_DIDLOOKUP); SMAR_LEV_DPRINTF(3, (SMAR_DEBFP, "sev=DBG, func=smar_chk_gen, str=%S, ltype=%#x, lflags=%#x, flags=%#x, ret=%r\n", smar_addr->ara_str, smar_addr->ara_ltype, smar_addr->ara_lflags, smar_addr->ara_flags, ret)); } return ret; } /* ** SMAR_SS_SE_CONF -- look up smtps session configuration in access map ** ** Parameters: ** smar_ctx -- SMAR context ** smar_addr -- address context ** perr -- (pointer to) error code (output) ** ** Returns: ** usual sm_error code ** ** Locking: smar_addr must be under control of the caller. ** ** Last code review: ** Last code change: */ static sm_ret_T smar_ss_se_conf(smar_ctx_P smar_ctx, smar_addr_P smar_addr, sm_ret_T *perr) { SM_IS_SMAR_ADDR(smar_addr); SM_IS_SMAR_CTX(smar_ctx); SM_REQUIRE(perr != NULL); *perr = SM_SUCCESS; /* Which flag to check here for SM_NOTDONE??? */ if (!SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_SS_SE_CONF) || SMARA_IS_FLAG(smar_addr, SMARA_FL_GOTSSSECONF)) return SM_NOTDONE; sm_str_clr(smar_addr->ara_tag); sm_str_clr(smar_addr->ara_rhs_conf); (void) sm_str_scat(smar_addr->ara_tag, SS_SE_CONF_A_TAG); smar_addr->ara_maprescnf = sm_map_lookup_ip(smar_ctx->smar_access, smar_addr->ara_str, smar_addr->ara_tag, SMMAP_LFL_SUBNETS|SMMAP_LFL_TAG, smar_addr->ara_rhs_conf); /* do not set SMARA_FL_DIDLOOKUP: there is nothing to analyze */ SMARA_SET_FLAG(smar_addr, SMARA_FL_GOTSSSECONF); SMAR_LEV_DPRINTF(3, (SMAR_DEBFP, "sev=DBG, func=smar_ss_se_conf, ip=%S, tag=%S, ret=%r, rhs=%S\n", smar_addr->ara_str, smar_addr->ara_tag, smar_addr->ara_maprescnf, smar_addr->ara_rhs_conf)); return SM_SUCCESS; } /* ** SMAR_ACCESS_CHK -- Check address against access map and perform other ** checks as requested (e.g., DNS) ** ** Parameters: ** smar_ctx -- SMAR context ** smar_addr -- address context ** ** Returns: ** usual sm_error code ** if ok: smar_addr->ara_status should have result of lookup(s) ** ** Locking: smar_addr must be under control of the caller. ** ** Last code review: ** Last code change: ** ** split this into smaller functions that can be called individually? */ const smar_chk_ctx_T ar_chks[] = { { "smar_ss_se_conf", smar_ss_se_conf }, { "smar_chk_ipv4", smar_chk_ipv4 }, { "smar_chk_2821", smar_chk_2821 }, { "smar_chk_certiss", smar_chk_certiss }, { "smar_chk_gen", smar_chk_gen }, /* { "smar_access_first", smar_access_first }, */ { "smar_cltresolve", smar_cltresolve }, { "smar_cltname", smar_cltname }, { "smar_chk_dnsbl", smar_chk_dnsbl }, { "smar_mxbadip", smar_mxbadip }, { "smar_certsub", smar_certsub }, { "smar_protrcpt", smar_protrcpt }, { "smar_grey", smar_grey }, { NULL, (smar_chk_F*)NULL}, }; sm_ret_T smar_access_chk(smar_ctx_P smar_ctx, smar_addr_P smar_addr) { sm_ret_T ret, res; uint fct_idx; smar_chk_F *smar_cc_fct; SM_IS_SMAR_ADDR(smar_addr); SM_IS_SMAR_CTX(smar_ctx); /* move to smar_access_check()??? only if the cleanup code is moved too */ ret = smar_addr_init(smar_ctx, smar_addr, &res); if (sm_is_err(res)) goto error; if (SM_DONE == res) goto done; /* ** lookup loop; note: ret is the result of the last lookup, it is ** "analyzed" at the begin of the loop. */ fct_idx = 0; smar_cc_fct = ar_chks[fct_idx].arcc_fct; for (;;) { /* ** Perform lookups as long as requested. */ SMAR_LEV_DPRINTF(6, (SMAR_DEBFP, "func=smar_access_chk, where=before_while, ara_status=%d, flags=%#x\n", smar_addr->ara_status, smar_addr->ara_rflags)); while (smar_addr->ara_status == SMTP_R_CONT && !SMARA_IS_FLAG(smar_addr, SMARA_FL_STOP) && !SMARA_IS_FLAG(smar_addr, SMARA_FL_DIDLOOKUP) && fct_idx < SM_ARRAY_SIZE(ar_chks) && (smar_cc_fct = ar_chks[fct_idx].arcc_fct) != NULL) { /* ** ret is used by smar_acc_analyse() ** res is used "locally" to make decision about the control flow, ** e.g., whether to "error out", break, etc. */ ret = (*smar_cc_fct)(smar_ctx, smar_addr, &res); SMAR_LEV_DPRINTF(5, (SMAR_DEBFP, "func=smar_access_chk, chk_fct=%s, ret=%r, res=%r\n", ar_chks[fct_idx].arcc_name, ret, res)); if (sm_is_err(res)) goto error; if (SM_BREAK == res) break; if (SM_DONE == res) goto done; /* hack... how should this be done properly? */ if (res != SM_AGAIN) ++fct_idx; } if (!SMARA_IS_FLAG(smar_addr, SMARA_FL_DIDLOOKUP)) break; ret = smar_acc_analyse(smar_ctx, smar_addr, ret); if (SMARA_IS_FLAG(smar_addr, SMARA_FL_RP_ANALYSE)) SMARA_CLR_FLAG(smar_addr, SMARA_FL_RP_ANALYSE); if (sm_is_err(ret)) goto error; SMARA_CLR_FLAG(smar_addr, SMARA_FL_DIDLOOKUP); } done: SMAR_LEV_DPRINTF(3, (SMAR_DEBFP, "func=smar_access_chk, where=done, ara_status=%d\n", smar_addr->ara_status)); if (smar_addr->ara_status == SMTP_R_CONT && SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_MAIL_ROUTE) && !SMARA_IS_FLAG(smar_addr, SMARA_FL_GOTRCPT)) { SMAR_LEV_DPRINTF(3, (SMAR_DEBFP, "func=smar_access_chk, calling=smar_dns_getret\n")); /* XXX can block */ ret = smar_dns_getret(smar_addr); if (SM_SUCCESS == ret) { ret = smar_dns2ret(smar_ctx, smar_addr); if (sm_is_err(ret)) goto error; /* required for smar_access_re() */ smar_addr->ara_mapres = SM_ACC_FOUND; /* XXX more? e.g., error text */ SMAR_LEV_DPRINTF(3, (SMAR_DEBFP, "func=smar_access_chk, smar_addr->ara_dns_ret=%d\n", smar_addr->ara_dns_ret)); } else { SMAR_LEV_DPRINTF(0, (SMAR_DEBFP, "sev=ERROR, func=smar_access_chk, smar_dns_getret=%r\n", ret)); } } /* when to perform greylisting??? */ if (SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_RCPT_ACC) && SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_GREY) && !SMARA_IS_FLAG(smar_addr, SMARA_FL_GOTGREY) && SMAR_IS_FLAG(smar_ctx, SMAR_FL_HASGREY) && (SMTP_R_OK == smar_addr->ara_status || SMTP_R_RELAY == smar_addr->ara_status) && !SMAR_IS_RFL(smar_addr, SMAR_R_QUICK) ) { ret = smar_grey(smar_ctx, smar_addr, &res); if (SMAR_IS_RFL(smar_addr, SMAR_R_GREY)) { ret = smar_acc_analyse(smar_ctx, smar_addr, ret); if (SMARA_IS_FLAG(smar_addr, SMARA_FL_RP_ANALYSE)) SMARA_CLR_FLAG(smar_addr, SMARA_FL_RP_ANALYSE); } SMARA_CLR_FLAG(smar_addr, SMARA_FL_DIDLOOKUP); } /* claim that everything is ok */ ret = SM_SUCCESS; /* fallthrough for cleanup */ error: if (smar_addr->ara_rhs != NULL && sm_str_getlen(smar_addr->ara_rhs) > 0) { ret = sm_str_scat(smar_addr->ara_rhs, "\r\n"); SM_ASSERT(SM_SUCCESS == ret); } if (SMARA_IS_FLAG(smar_addr, SMARA_FL_RFC2821)) a2821_free(&smar_addr->ara_a_rcpt); SM_STR_FREE(smar_addr->ara_str); SM_STR_FREE(smar_addr->ara_tag); SM_STR_FREE(smar_addr->ara_detail); SM_STR_FREE(smar_addr->ara_domain_pa); /* XXX should we wait for result here? smar_addr->ara_rvrs needs to be free()d */ if ((SMARA_IS_FLAG(smar_addr, SMARA_FL_A4RVRS) && !SMARA_IS_FLAG(smar_addr, SMARA_FL_GOTRVRS)) || (SMARA_IS_FLAG(smar_addr, SMARA_FL_A4RCPT) && !SMARA_IS_FLAG(smar_addr, SMARA_FL_GOTRCPT)) || (SMARA_IS_FLAG(smar_addr, SMARA_FL_A4DNSBL) && !SMARA_IS_FLAG(smar_addr, SMARA_FL_GOTDNSBL))) { /* ** XXX really overwrite ret? ** what if ret already contains an error? */ /* XXX can block */ ret = smar_dns_getret(smar_addr); } if (smar_addr->ara_rvrs != NULL) { (void) smar_rvrs_free(smar_addr->ara_rvrs); smar_addr->ara_rvrs = NULL; } (void) smar_rcpts_free(smar_addr->ara_rcpts); return ret; } /* ** SMAR_ACCESS_CHECK -- Check address against access map and perform other ** tests as requested; send answer ** ** Parameters: ** smar_ctx -- SMAR context ** smar_addr -- address context ** ** Returns: ** usual sm_error code ** ** Called by: smar_react() ** ** Locking: smar_addr has been created by smar_react(), ** this is the only function that has been given access ** (locking is only required for reverse resolution) ** ** Last code review: 2004-03-11 17:57:57; see comments below ** Last code change: 2004-04-11 18:20:34 */ sm_ret_T smar_access_check(smar_ctx_P smar_ctx, smar_addr_P smar_addr) { sm_ret_T ret; smar_clt_ctx_P smar_clt_ctx; SM_IS_SMAR_ADDR(smar_addr); SM_IS_SMAR_CTX(smar_ctx); smar_clt_ctx = smar_addr->ara_smar_clt_ctx; SM_IS_SMAR_CLT_CTX(smar_clt_ctx); ret = smar_access_chk(smar_ctx, smar_addr); if (sm_is_err(ret)) { sm_log_write(smar_ctx->smar_lctx, AR_LCAT_RESOLVER, AR_LMOD_RESOLVER, SM_LOG_ERROR, 1, "sev=ERROR, func=smar_access_check, smar_access_chk=%m" , ret); goto error; } SMAR_LEV_DPRINTF(5, (SMAR_DEBFP, "sev=DBG, func=smar_access_check, map_res=%r, status=%r, ltype=%#x\n", smar_addr->ara_mapres, smar_addr->ara_status, smar_addr->ara_ltype)); if (SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_MAIL_LOCAL) && (SM_ACC_NOTFOUND == smar_addr->ara_mapres || (SM_ACC_FOUND == smar_addr->ara_mapres && SMTP_R_CONT == smar_addr->ara_status)) ) { ret = smar_addr_chk(smar_ctx, smar_addr); SMAR_LEV_DPRINTF(3, (SMAR_DEBFP, "sev=DBG, func=smar_access_check, map_res=%r, ltype=%#x, smar_addr_chk=%r, status=%r\n", smar_addr->ara_mapres, smar_addr->ara_ltype, ret, smar_addr->ara_status)); if (sm_is_err(ret)) { sm_log_write(smar_ctx->smar_lctx, AR_LCAT_RESOLVER, AR_LMOD_RESOLVER, SM_LOG_ERROR, 1, "sev=ERROR, func=smar_access_check, smar_addr_chk=%m" , ret); goto error; } /* this is necessary to send back the result */ if (smar_addr->ara_status != SMTP_R_CONT) { smar_addr->ara_mapres = SM_ACC_FOUND; sm_str_clr(smar_addr->ara_rhs); (void) sm_str_scat(smar_addr->ara_rhs, "550 5.1.8 Bogus sender\r\n"); SMAR_SET_RFL(smar_addr, SMAR_R_QUICK); } } ret = smar_access_re(smar_addr, smar_addr->ara_which_status, smar_addr->ara_rhstagoff); if (sm_is_err(ret)) { sm_log_write(smar_ctx->smar_lctx, AR_LCAT_RESOLVER, AR_LMOD_RESOLVER, SM_LOG_ERROR, 1, "sev=ERROR, func=smar_access_check, smar_access_re=%m" , ret); goto error; } ret = sm_rcbcom_endrep(&smar_clt_ctx->smac_com_ctx, smar_clt_ctx->smac_com_ctx.rcbcom_tsk, false, &smar_addr->ara_rcbe); if (sm_is_err(ret)) { sm_log_write(smar_ctx->smar_lctx, AR_LCAT_RESOLVER, AR_LMOD_RESOLVER, SM_LOG_ERROR, 1, "sev=ERROR, func=smar_access_check, sm_rcbcom_endrep=%m" , ret); goto error; } (void) smar_addr_free(smar_addr); return ret; error: (void) smar_addr_free(smar_addr); sm_log_write(smar_ctx->smar_lctx, AR_LCAT_RESOLVER, AR_LMOD_RESOLVER, SM_LOG_ERROR, 0, "sev=ERROR, func=smar_access_check, ret=%m", ret); return ret; }