/* * 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. * * $Id: smar.h,v 1.112 2007/11/14 06:03:09 ca Exp $ */ #ifndef SMAR_H #define SMAR_H 1 #include "sm/generic.h" #include "sm/net.h" #include "sm/evthr.h" #include "sm/rpool.h" #include "sm/rcb.h" #include "sm/rcbl.h" #include "sm/rcbcomm.h" #include "sm/queue.h" #include "sm/bhtable.h" #include "sm/pthread.h" #include "sm/mta.h" #include "sm/map.h" #include "sm/log.h" #include "sm/smar.h" #include "smarstr.h" #include "sm/sm-conf.h" #include "sm/smarcnf.h" #include "sm/rfc2821.h" #include "sm/greyctl.h" /* access map required? */ #define SMAR_LT_ACCESS (SMARA_LT_CERT_RELAY|\ SMARA_LT_CLT_A_ACC|SMARA_LT_CLT_N_ACC|\ SMARA_LT_RVRS_N_ACC|\ SMARA_LT_EHLO_ACC|\ SMARA_LT_MAIL_ACC|\ SMARA_LT_RCPT_ACC|SMARA_LT_RCPT_PROT) #ifndef SMAR_USE_DNS # define SMAR_USE_DNS 1 #endif /* ** Limits for (currently compile time only) ** number of MX records per domain ** number of A records per MX record */ #ifndef SM_DNS_MX_MAX # define SM_DNS_MX_MAX 50 #endif #ifndef SM_DNS_A_PER_MX_MAX # define SM_DNS_A_PER_MX_MAX 50 #endif #ifndef SMAR_TEST # define SMAR_TEST 1 #endif #ifndef SM_ALIASES_LARGE # define SM_ALIASES_LARGE 1 #endif #if SMAR_USE_DNS # include "sm/dns.h" # include "sm/dns-int.h" # include "sm/dnstsk.h" #endif /* SMAR_USE_DNS */ #if SM_ALIASES_LARGE # define DNS_MGR_HTSIZE 4993u # define DNS_MGR_HTMAX 29989u #else /* SM_ALIASES_LARGE */ # define DNS_MGR_HTSIZE 0u # define DNS_MGR_HTMAX 0u #endif /* SM_ALIASES_LARGE */ #ifndef SMAR_DEBUG # define SMAR_DEBUG 1 #endif #if SMAR_DEBUG # include "sm/io.h" uint smar_debug; # define SMAR_DEBFP smioerr # define SMAR_LEV_DPRINTF(lev, x) do \ { \ if ((lev) < smar_debug) \ { \ sm_io_fprintf x; \ sm_io_flush(SMAR_DEBFP); \ } \ } while (0) # define SMAR_DPRINTF(x) sm_io_fprintf x #else /* SMAR_DEBUG */ # define SMAR_DPRINTF(x) # define SMAR_LEV_DPRINTF(lev, x) #endif /* SMAR_DEBUG */ #if SM_HEAP_CHECK extern SM_DEBUG_T SmHeapCheck; # define HEAP_CHECK (SmHeapCheck > 0) #else # define HEAP_CHECK 0 #endif #define SMAR_RHS_SEP_C ' ' /* seperate entries in the host list */ #define SMAR_RHS_PORT_C '^' /* separate port from protocol */ #define SMAR_RHS_PROT_C ':' /* separate protocol from host list */ #define SMAR_DEFAULT_TTL 3600 #ifndef SMAR_MAXRHS # define SMAR_MAXRHS 1024 #endif #define RHS_ERROR "error:" #define RHS_ERROR_LEN 6 #define RHS_ERROR_4 "error:4" #define RHS_ERROR_4_LEN 7 #define RHS_QUICK "quick:" #define RHS_QUICK_LEN 6 #define RHS_DELAY "delay:" #define RHS_DELAY_LEN 6 /* XXX use LEN(x) (sizeof(x) - 1) ??? */ /* ** Maximum number of SMAR clients; this should be dynamic! ** However, the value must not exceed the number of bits in smar_clt_used. */ #define SMAR_MAX_CLTS 32 /* Client context type for SMAR */ struct smar_clt_ctx_S { sm_magic_T sm_magic; #if 0 pthread_mutex_t smac_mutex; #endif int smac_status; /* see below, SMAR_ST_* */ /* info about connections? */ uint32_t smac_bit; /* bit for smar_clt_used */ uint32_t smac_idx; /* index (MUST be unsigned) */ uint32_t smac_cl_flags; /* client flags */ smar_ctx_P smac_ar_ctx; /* pointer back to main ctx */ rcbcom_ctx_T smac_com_ctx; /* communication context */ }; /* SMAC status */ #define SMAC_ST_NONE 0x00 /* not yet OK */ #define SMAC_ST_INIT 0x01 /* initialized */ /* Main context type for SMAR */ struct smar_ctx_S { sm_magic_T sm_magic; pthread_mutex_t smar_mutex; smar_cnf_T smar_cnf; sm_str_P smar_hostname; uint smar_status; /* see below, SMAR_ST_* */ uint smar_flags; /* see below, SMAR_FL_* */ /* info about connections? */ sm_evthr_ctx_P smar_ev_ctx; /* event thread context */ #if SMAR_MAX_CLTS > 32 ERROR: _SMAR_MAX_CLTS > 32 value must not exceed number of bits in smar_clt_used #endif uint32_t smar_clt_used; /* bitmask for used elements */ smar_clt_ctx_P smar_clt_ctx[SMAR_MAX_CLTS]; /* communication tasks */ /* max number of concurrent requests from a client */ uint32_t smar_clt_reqs[SMAR_MAX_CLTS]; uint32_t smar_max_reqs; uint32_t smar_max_thrds_s; uint32_t smar_max_thrds_h; sm_log_ctx_P smar_lctx; #if SMAR_USE_DNS uint smar_dns_ntsks; ipv4_T smar_nameserveripv4s[SM_DNS_MAX_TSKS]; dns_mgr_ctx_P smar_dns_mgr_ctx; #endif sm_map_P smar_mt_map; /* "mailertable" (HACK) */ sm_maps_P smar_maps; /* map system context */ sm_map_P smar_aliases; /* alias map */ sm_map_P smar_access; /* access map */ sm_map_P smar_lum; /* map of local users */ sm_cstr_P smar_strmaptype; uint smar_alias_lfl; /* alias lookup flags */ uint smar_lum_lfl; /* local user map lookup flags */ uint smar_mt_lfl; /* mailertable map lookup flags */ greyctx_P smar_greyctx; #if SMAR_TEST long smar_rand_err; #endif }; /* SMAR status */ #define SMAR_ST_NONE 0x00 /* not yet OK */ #define SMAR_ST_INIT 0x01 /* initialized */ #define SMAR_ST_CONF 0x02 /* configured */ #define SMAR_ST_START 0x04 /* started */ #define SMAR_ST_OK 0x10 /* initialized, running normal */ #define SMAR_ST_SLOW 0x20 /* slow down */ /* Notice: this must be ordered, see smar_is_stop() below */ #define SMAR_ST_SH_DOWN 0x80 /* shutting down */ #define SMAR_ST_STOPPED 0x81 /* stopped: almost terminated */ #define smar_is_stop(smar_ctx) ((smar_ctx)->smar_status >= SMAR_ST_SH_DOWN) /* SMAR flags */ #define SMAR_FL_NONE 0x0000 #define SMAR_FL_HASACCESS 0x0001 #define SMAR_FL_HASDNSBL 0x0002 #define SMAR_FL_HASGREY 0x0004 #define SMAR_FL_HASALIAS 0x0008 #define SMAR_FL_ACCESSCOMPL 0x0010 /* complained about access */ #define SMAR_FL_DNSBLCOMPL 0x0020 /* complained about dnsbl */ #define SMAR_FL_GREYCOMPL 0x0040 /* complained about greylisting */ #define SMAR_FL_ALIASCOMPL 0x0080 /* complained about aliases */ #define SMAR_FL_REQACCESS 0x0100 /* requires access map */ #define SMAR_FL_REQALIAS 0x0800 /* requires aliases map */ /* complained about protected_rcpts misconfiguration for client_ip */ #define SMAR_FL_PROTIPCOMPL 0x1000 /* complained about protected_rcpts misconfiguration for sender */ #define SMAR_FL_PROTMAILCOMPL 0x2000 #define SMAR_SET_FLAG(smar_ctx, fl) (smar_ctx)->smar_flags |= (fl) #define SMAR_CLR_FLAG(smar_ctx, fl) (smar_ctx)->smar_flags &= ~(fl) #define SMAR_IS_FLAG(smar_ctx, fl) (((smar_ctx)->smar_flags & (fl)) != 0) struct smar_dns_S { uint ardns_ttl; /* TTL from DNS */ ushort ardns_pref; /* preference from DNS */ sm_cstr_P ardns_name; /* name from DNS (RHS of MX RR) */ int ardns_n_A; /* number of A records */ /* XXX missing TTL for individual A records */ /* pointer to list of A records [0 to ardns_n_A-1] */ ipv4_T *ardns_A_rrs; }; struct smar_rcpt_S { sm_magic_T sm_magic; sm_str_P arr_pa; /* printable addr */ rcpt_id_T arr_id; /* rcpt id */ rcpt_idx_T arr_idx; /* (local) rcpt idx */ sm_str_P arr_owner_pa; /* owner: printable addr */ rcpt_idx_T arr_owner_idx; /* (local) owner idx */ short arr_port; /* port for all addresses, 0: use default */ sm_str_P arr_domain_pa; sm_str_P arr_user_pa; /* user without +detail */ sm_str_P arr_detail_pa; /* detail */ uchar arr_delim; /* used delimiter */ uint32_t arr_flags; /* status of address resolving */ sm_ret_T arr_ret; /* result of address resolving */ uint arr_timeout; /* timeout */ uint32_t arr_rqflags; /* request flags */ uint32_t arr_da; /* DA */ /* ** Number of A queries sent (= Number of MX records). ** For each MX record one query for the A records is sent. */ int arr_A_qsent; /* Number of responses received for A queries */ int arr_A_rrcvd; /* ** Total number of A records (each A record query can return multiple ** A records). */ int arr_n_A; /* ** array of results [0 to arr_A_qsent-1]; the array can be bigger, ** but only arr_A_qsent entries are used. */ smar_dns_T *arr_res; /* array of results */ ipv4_T arr_ipv4; /* single A record */ uint32_t arr_cnf_lfl; sm_ret_T arr_maprescnf; sm_str_P arr_rhs_conf; smar_rcpts_P arr_rcpts; /* pointer back to recipient list */ TAILQ_ENTRY(smar_rcpt_S) arr_next; }; /* SMAR RCPT flags (A4: asked for) */ #define SMARR_FL_NONE 0x00000000 /* not yet OK */ #define SMARR_FL_INIT 0x00000001 /* initialized */ #define SMARR_FL_A4MT 0x00000002 /* check in mailertable */ /* XXX this needs more states if RHS in mailertable can be a hostname... */ #define SMARR_FL_GOTMT 0x00000004 /* got mailertable IP */ #define SMARR_FL_NOMT 0x00000008 /* no mailertable entry */ #define SMARR_FL_A4MX 0x00000010 /* asked for MX records */ #define SMARR_FL_GOTMX 0x00000020 /* got MX records */ #define SMARR_FL_A4A 0x00000040 /* asked for A records */ #define SMARR_FL_GOTA 0x00000080 /* got A records */ #define SMARR_FL_TEMP 0x00000100 /* temporary error */ #define SMARR_FL_EXPD 0x00000200 /* alias expansion performed */ #define SMARR_FL_ALIAS 0x00000400 /* 1-1 alias expansion performed */ #define SMARR_FL_LU 0x00000800 /* is local user */ #define SMARR_FL_FREEIT 0x00001000 /* something failed, free smar_rcpt */ #define SMARR_FL_INRLST 0x00002000 /* smar_rcpt is in smar_rcpts rcpt list */ #define SMARR_FL_INHT 0x00004000 /* smar_rcpt is in smar_rcpts hash table */ #define SMARR_FL_ORCPT 0x00008000 /* smar_rcpt is smar_rcpts->arrs_rcpt */ /* smar_rcpt_expand() to take responsibility (add to list or free it) */ #define SMARR_FL_TAKEIT 0x00010000 #define SMARR_FL_ISALIAS 0x00020000 /* found in alias map */ #define SMARR_FL_C_MX 0x00100000 /* got a CNAME record for MX */ #define SMARR_FL_C_A 0x00200000 /* got a CNAME record for A */ /* XXX maybe use counters instead of flags? */ #define SMARR_FL_C_MX_L 0x00400000 /* CNAME loop for MX */ #define SMARR_FL_C_A_L 0x00800000 /* CNAME loop for A */ #define SMARR_FL_ISOWN 0x01000000 /* address is owner- alias */ #define SMARR_FL_INOWNLST 0x02000000 /* smar_rcpt is in smar_rcpts owner list */ #define SMARR_FL_ISVERP 0x04000000 /* address is verp- alias */ #define SMARR_FL_HASVERP 0x08000000 /* address has verp- alias */ #define SMARR_FL_HASDET 0x10000000 /* address has +detail */ #define SMARR_SET_FLAG(smar_rcpt, fl) (smar_rcpt)->arr_flags |= (fl) #define SMARR_CLR_FLAG(smar_rcpt, fl) (smar_rcpt)->arr_flags &= ~(fl) #define SMARR_IS_FLAG(smar_rcpt, fl) (((smar_rcpt)->arr_flags & (fl)) != 0) #define SMARRQ_SET_FLAG(smar_rcpt, fl) (smar_rcpt)->arr_rqflags |= (fl) #define SMARRQ_CLR_FLAG(smar_rcpt, fl) (smar_rcpt)->arr_rqflags &= ~(fl) #define SMARRQ_IS_FLAG(smar_rcpt, fl) (((smar_rcpt)->arr_rqflags & (fl)) != 0) /* return codes from SMAR modules that decode/handle requests */ #define SMAR_R_WAITQ SM_SUCCESS /* default: put back in waitq */ #define SMAR_R_ASYNC 1 /* do nothing, task has been put in waitq */ typedef TAILQ_HEAD(smar_rcptshd_S, smar_rcpt_S) smar_rcptshd_T, *smar_rcptshd_P; /* callback function to return result */ typedef sm_ret_T (smar_rcpts_cb_F)(smar_rcpts_P, void *); struct smar_rcpts_S { sm_magic_T sm_magic; #if 0 /* ** It seems this mutex isn't needed because the callback function ** (which can be called asynchronously) is protected using ** smar_ctx->smar_mutex */ pthread_mutex_t arrs_mutex; #endif /* 0 */ smar_rcpt_P arrs_rcpt; /* original recipient */ rcpt_id_T arrs_rcpt_id; /* original rcpt id */ uint32_t arrs_flags; /* status of address resolving */ sm_ret_T arrs_ret; /* result of address resolving */ rcpt_idx_T arrs_idx; /* running counter for recipients */ bht_P arrs_rcpts; /* hash table of recipients */ smar_rcptshd_T arrs_rcpthd; /* list of recipients */ smar_rcptshd_T arrs_ownerhd; /* list of owner addresses */ uint arrs_ht_n; /* number of entries (in hash table) */ uint arrs_lst_n; /* number of entries (in list) */ rcpt_idx_T arrs_owners_n; /* number of owner aliases */ uint arrs_resolved; /* resolved entries */ sm_rcbe_P arrs_rcbe; /* RCB to write back result */ smar_ctx_P arrs_smar_ctx; /* pointer back to SMAR context */ smar_clt_ctx_P arrs_smar_clt_ctx; /* pointer back to client context */ sm_str_P arrs_pa; /* address to check against elements */ smar_addr_P arrs_addr; smar_rcpts_cb_F *arrs_cbf; /* callback fct to invoke to return result */ void *arrs_cb_ctx; /* context for callback function */ }; #define SMARRS_FL_NONE 0x0000 /* not yet OK */ #define SMARRS_FL_ERCB 0x0001 /* writing to RCB failed, return an error */ #define SMARRS_FL_TEMP 0x0002 /* temporary error (ENOMEM), return error */ #define SMARRS_FL_FAIL 0x0004 /* last attempt to write result failed */ #define SMARRS_FL_INITRE 0x0008 /* initialized reply (RCB) */ #define SMARRS_FL_NOSEND 0x0010 /* do not send data */ #define SMARRS_FL_NOFREE 0x0020 /* do not free context */ #define SMARRS_FL_NOREC 0x0100 /* no recursion */ #define SMARRS_FL_NOADD 0x0200 /* do not add elements to hash table */ #define SMARRS_FL_COMP 0x0400 /* compare elements against address arrs_addr */ #define SMARRS_FL_FOUND 0x1000 /* found arrs_pa */ #define SMARRS_SET_FLAG(smar_rcpts, fl) (smar_rcpts)->arrs_flags |= (fl) #define SMARRS_CLR_FLAG(smar_rcpts, fl) (smar_rcpts)->arrs_flags &= ~(fl) #define SMARRS_IS_FLAG(smar_rcpts, fl) (((smar_rcpts)->arrs_flags & (fl)) != 0) /* prototypes */ sm_ret_T smar_rcpts_new(smar_ctx_P _smar_ctx, smar_clt_ctx_P _smar_clt_ctx, smar_rcpts_P *_psmar_rcpts); sm_ret_T smar_rcpts_free(smar_rcpts_P _smar_rcpts); sm_ret_T smar_rcpt_expand(smar_rcpts_P _smar_rcpts, smar_rcpt_P _smar_rcpt, rcpt_idx_T _owner_idx, uint _flags, uint _level); sm_ret_T smar_rcpts_t2l(smar_rcpts_P _smar_rcpts); #define SM_IS_SMAR_RCPTS(smar_rcpts) SM_REQUIRE_ISA((smar_rcpts), SM_SMAR_RCPTS_MAGIC) #define RCPTS_INIT(smar_rcpts) TAILQ_INIT(&((smar_rcpts)->arrs_rcpthd)) #define RCPTS_FIRST(smar_rcpts) TAILQ_FIRST(&((smar_rcpts)->arrs_rcpthd)) #define RCPTS_END(smar_rcpts) TAILQ_END(&((smar_rcpts)->arrs_rcpthd)) #define RCPTS_EMPTY(smar_rcpts) TAILQ_EMPTY(&((smar_rcpts)->arrs_rcpthd)) #define RCPTS_NEXT(smar_rcpt) TAILQ_NEXT(smar_rcpt, arr_next) #define RCPTS_APP(smar_rcpts, smar_rcpt) TAILQ_INSERT_TAIL(&((smar_rcpts)->arrs_rcpthd), smar_rcpt, arr_next) #define RCPTS_REMOVE(smar_rcpts, smar_rcpt) TAILQ_REMOVE(&((smar_rcpts)->arrs_rcpthd), smar_rcpt, arr_next) #define OWNER_INIT(smar_rcpts) TAILQ_INIT(&((smar_rcpts)->arrs_ownerhd)) #define OWNER_FIRST(smar_rcpts) TAILQ_FIRST(&((smar_rcpts)->arrs_ownerhd)) #define OWNER_END(smar_rcpts) TAILQ_END(&((smar_rcpts)->arrs_ownerhd)) #define OWNER_EMPTY(smar_rcpts) TAILQ_EMPTY(&((smar_rcpts)->arrs_ownerhd)) #define OWNER_NEXT(smar_rcpt) TAILQ_NEXT(smar_rcpt, arr_next) #define OWNER_APP(smar_rcpts, smar_rcpt) TAILQ_INSERT_TAIL(&((smar_rcpts)->arrs_ownerhd), smar_rcpt, arr_next) #define OWNER_REMOVE(smar_rcpts, smar_rcpt) TAILQ_REMOVE(&((smar_rcpts)->arrs_ownerhd), smar_rcpt, arr_next) /* DNS BL result */ struct smar_dnsblres_S { ipv4_T sdbr_ipv4; /* IPv4 address returned */ sm_ret_T sbdr_res; /* result of lookup */ ipv4_T *sdbr_ipv4s; /* IPv4 addresses returned */ uint sdbr_n; /* size of array */ }; /* result values (+ usual error code) */ #define SM_DNSBL_RES_INIT 0 /* initialized */ #define SM_DNSBL_RES_WAIT 1 /* waiting for result */ #define SM_DNSBL_RES_OK 2 /* result is OK (found A record) */ /* ** Recipient/Sender address context for map lookups or other checks. ** ** Should this allow for multiple tests per invocation? ** If yes, it would be necessary to send back multiple results. ** For now, it can be multiple tests, but there is only one result, i.e., ** some order is fixed in the algorithm. */ struct smar_addr_S { sm_magic_T sm_magic; sessta_id_T ara_taid; /* transaction id */ int ara_id; /* SMTPS id */ smar_clt_ctx_P ara_smar_clt_ctx; /* pointer back to client context */ sm_str_P ara_pa; /* printable addr */ sm_str_P ara_pa2; /* another printable addr */ sm_str_P ara_rhs; /* rewritten address/result of lookup */ sm_str_P ara_str; /* various purposes */ sm_str_P ara_tag; /* tag */ sm_str_P ara_detail; sm_str_P ara_domain_pa; /* domain part */ uchar ara_delim; /* used delimiter */ rcpt_idx_T ara_rcpt_idx; /* only valid for recipients */ ipv4_T ara_ipv4; /* IPv4 address */ sm_str_P ara_ipv4_str; /* IPv4 address in ASCII */ sm_map_P ara_str_map; /* str map */ time_t ara_conn_time; /* connection time (greylisting) */ /* ** Parts of ara_pa2 (if necessary). ** Note: ara_rhs2 is used for protected_rcpts ** and in smar_rcpt_expand() */ sm_str_P ara_user2; sm_str_P ara_detail2; sm_str_P ara_domain_pa2; sm_str_P ara_rhs2; uchar ara_delim2; /* used delimiter */ /* ** Note: it might be useful to have a "cache" of these instead of ** of opening and closing them all the time. */ sm_a2821_T ara_a_rcpt; /* ** What is the relation between lookup flags and lookup types? ** E.g., RCPT_LOCAL and RCPT_ACC: should that really be two ** lookup types? Why not RCPT with lookup flags: LOCAL, ACC? ** Should it be: ** type: This is an MAIL/RCPT address, a hostname, an IP address ** flags: perform the following tests: ** access map (tag determined by type) ** with "subflags": lookup exactly, lookup subdomains, ... ** check whether RCPT is local ** check whether MAIL is deliverable ** Note: the last two apply to exactly one type, so it doesn't ** seem to make much sense to have them as generic flags. */ uint32_t ara_lflags; /* lookup flags */ uint32_t ara_ltype; /* lookup type */ uint32_t ara_flags; /* various flags */ /* return value of map lookup function */ sm_ret_T ara_mapres; /* status of lookup, e.g., (interpreted) RHS if lookup succeeded */ uint32_t ara_status; uint32_t ara_rflags; /* result flags */ /* these values will be combined into one return value */ /* record type for status return, i.e., what does ara_status refer to */ uint32_t ara_which_status; uint ara_rhstagoff; /* offset in RHS to return text */ /* 2nd return value of map lookup function, result in ara_rhs2 */ sm_ret_T ara_mapres2; int ara_c_MX; int ara_c_A; int ara_c_dnsbl; smar_rcpt_P ara_rcpt; smar_rcpts_P ara_rcpts; /* result of dns (reverse/recipient) lookup */ sm_ret_T ara_dns_ret; sm_cstr_P ara_rvrs_hostname; /* name from DNS (reverse lookup) */ int ara_res_cnt; /* result counter */ smar_rvrs_P ara_rvrs; smar_dnsblres_T ara_dnsblres[SM_MAX_DNSBL]; /* ** ara_mutex protects access to ara_dns_ret, ara_rvrs_hostname, ** ara_dnsblres, and ara_res_cnt. Currently it does not protect ** ara_flags even though some are modified in the callback/notify ** functions (see algorithm descriptions; it might be better to ** use "inline" signaling via the result variables because those ** are protected by the mutex). ** ara_cond is used to signal that those variables have valid content. */ pthread_mutex_t ara_mutex; pthread_cond_t ara_cond; sm_rcbe_P ara_rcbe; /* RCB to write back result */ sm_rpool_P ara_rpool; /* for this context? */ sm_ret_T ara_maprescnf; sm_str_P ara_rhs_conf; }; #define SM_IS_SMAR_ADDR(smar_addr) SM_REQUIRE_ISA((smar_addr), SM_SMAR_ADDR_MAGIC) /* ** values for ara_dns_ret to signal between caller and callee ** Algorithm: ** Caller: ** status = init; * initialize status * ** ... * do something * ** lock * acquire mutex for v etc * ** if (status == init) { * is it still the initial value? * ** status = wait; * indicate that caller is waiting * ** while (status == wait) ** cond_wait ** } ** unlock ** ** Callee: ** lock * acquire mutex * ** notify = (status == wait); * is caller waiting? * ** v = v_new * set new value * ** status = sent; * result is available * ** if (notify) ** cond_signal * notify caller if it is waiting * ** unlock * done * ** ** Explanation: see docs */ /* SMAR addr flags */ #define SMARA_FL_NONE 0x00000000 #define SMARA_FL_HASMUT 0x00000001 /* mutex is initialized */ #define SMARA_FL_HASCOND 0x00000002 /* condition is initialized */ #define SMARA_FL_A4RVRS 0x00000004 /* asked for reverse lookup */ #define SMARA_FL_A4RCPT 0x00000008 /* asked for recipient lookup */ #define SMARA_FL_A4DNSBL 0x00000010 /* asked for DNS BL lookup */ #define SMARA_FL_GOTRVRS 0x00000020 /* got reverse DNS lookup result */ #define SMARA_FL_GOTDNSBL 0x00000040 /* got DNS BL result */ #define SMARA_FL_FAILDNS 0x00000080 /* failed to get DNS result */ #define SMARA_FL_GOTRCPT 0x00000100 /* got recipient DNS lookup result */ #define SMARA_FL_2ND 0x00000200 /* second lookup result is valid */ #define SMARA_FL_STOP 0x00000400 /* don't perform more lookups */ #define SMARA_FL_DIDLOOKUP 0x00000800 /* did lookup: check result */ #define SMARA_FL_RFC2821 0x00001000 /* RFC 2821 address */ #define SMARA_FL_GOTCERTISS 0x00002000 /* checked cert issuer */ #define SMARA_FL_GOTCERTSUB 0x00004000 /* checked cert subject */ #define SMARA_FL_GOTRCPTPROT 0x00008000 /* checked protected rcpt */ #define SMARA_FL_RP_ANALYSE 0x00010000 /* need to "analyse" protected rcpt lookup result */ #define SMARA_FL_INIT 0x00020000 /* all data initialized */ #define SMARA_FL_GOTGREY 0x00040000 /* greylisting check done */ #define SMARA_FL_GOTRVRSA 0x00080000 /* got reverse lookup result */ #define SMARA_FL_GOTRVRSN 0x00100000 /* resolved hostname checked */ #define SMARA_FL_RCVDIPV4 0x00200000 /* ara_ipv4 is valid */ #define SMARA_FL_PA2EMPTY 0x00400000 /* ara_pa2 is <> */ #define SMARA_FL_GOT2821ACC 0x00800000 /*did RFC2821 address access map lookup*/ #define SMARA_FL_GOTIPV4ACC 0x01000000 /* did IPv4 access map lookup */ /* flags for algorithm described above (AF: Asynchronous Function) */ #define SMARA_FL_AFWAIT 0x02000000 /* status==wait */ #define SMARA_FL_GOTSSSECONF 0x08000000 /* got smtps session conf */ #define SMARA_SET_FLAG(smar_addr, fl) (smar_addr)->ara_flags |= (fl) #define SMARA_CLR_FLAG(smar_addr, fl) (smar_addr)->ara_flags &= ~(fl) #define SMARA_IS_FLAG(smar_addr, fl) (((smar_addr)->ara_flags & (fl)) != 0) #define SMARA_SET_LFLAG(smar_addr, fl) (smar_addr)->ara_lflags |= (fl) #define SMARA_CLR_LFLAG(smar_addr, fl) (smar_addr)->ara_lflags &= ~(fl) #define SMARA_IS_LFLAG(smar_addr, fl) (((smar_addr)->ara_lflags & (fl)) != 0) /* see sm/smar.h: SMAR_R_* */ #define SMAR_SET_RFL(smar_addr, flags) (smar_addr)->ara_rflags |= (flags) #define SMAR_CLR_RFL(smar_addr, flags) (smar_addr)->ara_rflags &= ~(flags) #define SMAR_IS_RFL(smar_addr, flags) (((smar_addr)->ara_rflags & (flags)) != 0) /* assertions */ #define SM_IS_SMAR_CTX(smar_ctx) SM_REQUIRE_ISA((smar_ctx), SM_SMAR_CTX_MAGIC) #define SM_IS_SMAR_CLT_CTX(smac_ctx) SM_REQUIRE_ISA((smac_ctx), SM_SMAC_CTX_MAGIC) #define SM_IS_SMAR_RCPT(smar_rcpt) SM_REQUIRE_ISA((smar_rcpt), SM_SMAR_RCPT_MAGIC) /* prototypes */ sm_ret_T smar_init0(smar_ctx_P _smar_ctx); sm_ret_T smar_init1(smar_ctx_P _smar_ctx); sm_ret_T smar_init_map_lfl(smar_ctx_P _smar_ctx, uint _lfl_conf, uint *_plflags); sm_ret_T smar_rdcf(smar_ctx_P _smar_ctx, int _argc, char *_argv[]); sm_ret_T smar_read_cnf(smar_ctx_P _smar_ctx, const char *_fn, sm_conf_T **_psmc); sm_ret_T smar_mt_init(smar_ctx_P _smar_ctx); sm_ret_T smar_start(smar_ctx_P _smar_ctx); sm_ret_T smar_stop(smar_ctx_P _smar_ctx); sm_ret_T smar_clt_new(smar_ctx_P _smar_ctx, smar_clt_ctx_P *_psmar_clt_ctx); sm_ret_T smar_clt_free(smar_clt_ctx_P _smar_clt_ctx); sm_ret_T smar_li(sm_evthr_task_P _tsk); sm_ret_T smar_clt(sm_evthr_task_P _tsk); sm_ret_T smar_rcpt_rslv(smar_ctx_P _smar_ctx, smar_rcpts_P _smar_rcpts); sm_ret_T smar_rcpt_new(smar_rcpt_P *_psmar_rcpt); sm_ret_T smar_rcpt_free(smar_rcpt_P _smar_rcpt, smar_rcpts_P _smar_rcpts); sm_ret_T smar_addr_new(smar_clt_ctx_P _smar_clt_ctx, smar_addr_P *_psmar_addr); sm_ret_T smar_addr_free(smar_addr_P _smar_addr); sm_ret_T smar_addr_check(smar_ctx_P _smar_ctx, smar_addr_P _smar_addr); sm_ret_T smar_addr_chk(smar_ctx_P _smar_ctx, smar_addr_P _smar_addr); sm_ret_T smar_addr_lu(smar_ctx_P _smar_ctx, sm_str_P _user, uchar _delim, sm_str_P _detail, sm_str_P _domain, sm_str_P _rhs, uint32_t *_pstatus); sm_ret_T smar_addr_re(smar_addr_P _smar_addr, uint _offset); #define SM_CONST_LEN(str) (sizeof(str) - 1) #define CLT_A_TAG "cltaddr:" #define CLT_A_TAG_LEN SM_CONST_LEN(CLT_A_TAG) #define CLT_N_TAG "cltname:" #define CLT_N_TAG_LEN SM_CONST_LEN(CLT_N_TAG) #define MAIL_TAG "from:" #define MAIL_TAG_LEN SM_CONST_LEN(MAIL_TAG) #define RCPT_TAG "to:" #define RCPT_TAG_LEN SM_CONST_LEN(RCPT_TAG) #define CERT_ISSUER_TAG "certissuer:" #define CERT_ISSUER_TAG_LEN SM_CONST_LEN(CERT_ISSUER_TAG) #define CERT_SUBJECT_TAG "certsubject:" #define CERT_SUBJECT_TAG_LEN SM_CONST_LEN(CERT_SUBJECT_TAG) #define PROT_RCPT_TAG "protectedrcpt:" #define PROT_RCPT_TAG_LEN SM_CONST_LEN(PROT_RCPT_TAG) #define RHS_LIST_TAG "list:" #define RHS_LIST_TAG_LEN SM_CONST_LEN(RHS_LIST_TAG) #define EHLO_TAG "ehlo:" #define SS_SE_CONF_A_TAG "smtps_session_conf:" #define SC_SE_CONF_TAG "smtpc_session_conf:" #define SC_RCPT_CONF_TAG "smtpc_rcpt_conf:" sm_ret_T smar_map2acc(sm_ret_T _rv); sm_ret_T smar_access_re(smar_addr_P _smar_addr, uint32_t _which_status, uint _off); sm_ret_T smar_access_check(smar_ctx_P _smar_ctx, smar_addr_P _smar_addr); sm_ret_T smar_access_chk(smar_ctx_P _smar_ctx, smar_addr_P _smar_addr); sm_ret_T smar_prot_chk(smar_ctx_P _smar_ctx, smar_addr_P _smar_addr); sm_ret_T smar_prot_rhs(smar_ctx_P _smar_ctx, smar_addr_P _smar_addr); /* should mailertable use the "full" address for lookups? */ #define SMAR_MT_FULL_LOOKUP(smar_ctx) (SMMAP_LFL_MT != (smar_ctx)->smar_mt_lfl) #endif /* SMAR_H */