#include <string.h>
#include <vstream.h>
#include <vstring.h>
#include <argv.h>
#include <htable.h>
#include <dict.h>
#include <deliver_request.h>
#include <scache.h>
#include <string_list.h>
#include <maps.h>
#include <tok822.h>
#include <dsn_buf.h>
#include <header_body_checks.h>
#include <tls.h>
typedef struct SMTP_ITERATOR {
VSTRING *request_nexthop;
VSTRING *dest;
VSTRING *host;
VSTRING *addr;
unsigned port;
struct DNS_RR *rr;
struct DNS_RR *mx;
VSTRING *saved_dest;
struct SMTP_STATE *parent;
} SMTP_ITERATOR;
#define SMTP_ITER_INIT(iter, _dest, _host, _addr, _port, state) do { \
vstring_strcpy((iter)->dest, (_dest)); \
vstring_strcpy((iter)->host, (_host)); \
vstring_strcpy((iter)->addr, (_addr)); \
(iter)->port = (_port); \
(iter)->mx = (iter)->rr = 0; \
vstring_strcpy((iter)->saved_dest, ""); \
(iter)->parent = (state); \
} while (0)
#define SMTP_ITER_CLOBBER(iter, _dest, _host, _addr) do { \
vstring_strcpy((iter)->dest, (_dest)); \
vstring_strcpy((iter)->host, (_host)); \
vstring_strcpy((iter)->addr, (_addr)); \
} while (0)
#define SMTP_ITER_SAVE_DEST(iter) do { \
vstring_strcpy((iter)->saved_dest, STR((iter)->dest)); \
} while (0)
#define SMTP_ITER_RESTORE_DEST(iter) do { \
vstring_strcpy((iter)->dest, STR((iter)->saved_dest)); \
} while (0)
#ifdef USE_TLS
typedef struct SMTP_TLS_POLICY {
int level;
char *protocols;
char *grade;
VSTRING *exclusions;
ARGV *matchargv;
DSN_BUF *why;
TLS_DANE *dane;
} SMTP_TLS_POLICY;
extern void smtp_tls_list_init(void);
extern int smtp_tls_policy_cache_query(DSN_BUF *, SMTP_TLS_POLICY *, SMTP_ITERATOR *);
extern void smtp_tls_policy_cache_flush(void);
#define smtp_tls_policy_dummy(t) do { \
SMTP_TLS_POLICY *_tls_policy_dummy_tmp = (t); \
smtp_tls_policy_init(_tls_policy_dummy_tmp, (DSN_BUF *) 0); \
_tls_policy_dummy_tmp->level = TLS_LEV_NONE; \
} while (0)
#define smtp_tls_policy_init(t, w) do { \
SMTP_TLS_POLICY *_tls_policy_init_tmp = (t); \
_tls_policy_init_tmp->protocols = 0; \
_tls_policy_init_tmp->grade = 0; \
_tls_policy_init_tmp->exclusions = 0; \
_tls_policy_init_tmp->matchargv = 0; \
_tls_policy_init_tmp->why = (w); \
_tls_policy_init_tmp->dane = 0; \
} while (0)
#endif
typedef struct SMTP_STATE {
int misc_flags;
VSTREAM *src;
const char *service;
DELIVER_REQUEST *request;
struct SMTP_SESSION *session;
int status;
ssize_t space_left;
SMTP_ITERATOR iterator[1];
#ifdef USE_TLS
SMTP_TLS_POLICY tls[1];
#endif
HTABLE *cache_used;
VSTRING *dest_label;
VSTRING *dest_prop;
VSTRING *endp_label;
VSTRING *endp_prop;
int rcpt_left;
int rcpt_drop;
int rcpt_keep;
DSN_BUF *why;
} SMTP_STATE;
#define SET_NEXTHOP_STATE(state, nexthop) { \
vstring_strcpy((state)->iterator->request_nexthop, nexthop); \
}
#define FREE_NEXTHOP_STATE(state) { \
STR((state)->iterator->request_nexthop)[0] = 0; \
}
#define HAVE_NEXTHOP_STATE(state) (STR((state)->iterator->request_nexthop)[0] != 0)
#define SMTP_FEATURE_ESMTP (1<<0)
#define SMTP_FEATURE_8BITMIME (1<<1)
#define SMTP_FEATURE_PIPELINING (1<<2)
#define SMTP_FEATURE_SIZE (1<<3)
#define SMTP_FEATURE_STARTTLS (1<<4)
#define SMTP_FEATURE_AUTH (1<<5)
#define SMTP_FEATURE_XFORWARD_NAME (1<<7)
#define SMTP_FEATURE_XFORWARD_ADDR (1<<8)
#define SMTP_FEATURE_XFORWARD_PROTO (1<<9)
#define SMTP_FEATURE_XFORWARD_HELO (1<<10)
#define SMTP_FEATURE_XFORWARD_DOMAIN (1<<11)
#define SMTP_FEATURE_BEST_MX (1<<12)
#define SMTP_FEATURE_RSET_REJECTED (1<<13)
#define SMTP_FEATURE_FROM_CACHE (1<<14)
#define SMTP_FEATURE_DSN (1<<15)
#define SMTP_FEATURE_PIX_NO_ESMTP (1<<16)
#define SMTP_FEATURE_PIX_DELAY_DOTCRLF (1<<17)
#define SMTP_FEATURE_XFORWARD_PORT (1<<18)
#define SMTP_FEATURE_EARLY_TLS_MAIL_REPLY (1<<19)
#define SMTP_FEATURE_XFORWARD_IDENT (1<<20)
#define SMTP_FEATURE_SMTPUTF8 (1<<21)
#define SMTP_FEATURE_ENDPOINT_MASK \
(~(SMTP_FEATURE_BEST_MX | SMTP_FEATURE_RSET_REJECTED \
| SMTP_FEATURE_FROM_CACHE))
#define SMTP_FEATURE_DESTINATION_MASK (SMTP_FEATURE_BEST_MX)
#define SMTP_MISC_FLAG_LOOP_DETECT (1<<0)
#define SMTP_MISC_FLAG_IN_STARTTLS (1<<1)
#define SMTP_MISC_FLAG_FIRST_NEXTHOP (1<<2)
#define SMTP_MISC_FLAG_FINAL_NEXTHOP (1<<3)
#define SMTP_MISC_FLAG_FINAL_SERVER (1<<4)
#define SMTP_MISC_FLAG_CONN_LOAD (1<<5)
#define SMTP_MISC_FLAG_CONN_STORE (1<<6)
#define SMTP_MISC_FLAG_COMPLETE_SESSION (1<<7)
#define SMTP_MISC_FLAG_PREF_IPV6 (1<<8)
#define SMTP_MISC_FLAG_PREF_IPV4 (1<<9)
#define SMTP_MISC_FLAG_CONN_CACHE_MASK \
(SMTP_MISC_FLAG_CONN_LOAD | SMTP_MISC_FLAG_CONN_STORE)
#define SMTP_HAS_DSN(why) (STR((why)->status)[0] != 0)
#define SMTP_HAS_SOFT_DSN(why) (STR((why)->status)[0] == '4')
#define SMTP_HAS_HARD_DSN(why) (STR((why)->status)[0] == '5')
#define SMTP_HAS_LOOP_DSN(why) \
(SMTP_HAS_DSN(why) && strcmp(STR((why)->status) + 1, ".4.6") == 0)
#define SMTP_SET_SOFT_DSN(why) (STR((why)->status)[0] = '4')
#define SMTP_SET_HARD_DSN(why) (STR((why)->status)[0] = '5')
extern int smtp_host_lookup_mask;
#define SMTP_HOST_FLAG_DNS (1<<0)
#define SMTP_HOST_FLAG_NATIVE (1<<1)
extern int smtp_dns_support;
#define SMTP_DNS_INVALID (-1)
#define SMTP_DNS_DISABLED 0
#define SMTP_DNS_ENABLED 1
#define SMTP_DNS_DNSSEC 2
extern SCACHE *smtp_scache;
extern STRING_LIST *smtp_cache_dest;
extern MAPS *smtp_ehlo_dis_maps;
extern MAPS *smtp_pix_bug_maps;
extern MAPS *smtp_generic_maps;
extern int smtp_ext_prop_mask;
extern unsigned smtp_dns_res_opt;
#ifdef USE_TLS
extern TLS_APPL_STATE *smtp_tls_ctx;
extern int smtp_tls_insecure_mx_policy;
#endif
extern HBC_CHECKS *smtp_header_checks;
extern HBC_CHECKS *smtp_body_checks;
typedef struct SMTP_SESSION {
VSTREAM *stream;
SMTP_ITERATOR *iterator;
char *namaddr;
char *helo;
unsigned port;
char *namaddrport;
VSTRING *buffer;
VSTRING *scratch;
VSTRING *scratch2;
int features;
off_t size_limit;
ARGV *history;
int error_mask;
struct MIME_STATE *mime_state;
int send_proto_helo;
time_t expire_time;
int reuse_count;
int forbidden;
#ifdef USE_SASL_AUTH
char *sasl_mechanism_list;
char *sasl_username;
char *sasl_passwd;
struct XSASL_CLIENT *sasl_client;
VSTRING *sasl_reply;
#endif
#ifdef USE_TLS
TLS_SESS_STATE *tls_context;
char *tls_nexthop;
int tls_retry_plain;
#endif
SMTP_STATE *state;
} SMTP_SESSION;
extern SMTP_SESSION *smtp_session_alloc(VSTREAM *, SMTP_ITERATOR *, time_t, int);
extern void smtp_session_new_stream(SMTP_SESSION *, VSTREAM *, time_t, int);
extern int smtp_sess_plaintext_ok(SMTP_ITERATOR *, int);
extern void smtp_session_free(SMTP_SESSION *);
extern int smtp_session_passivate(SMTP_SESSION *, VSTRING *, VSTRING *);
extern SMTP_SESSION *smtp_session_activate(int, SMTP_ITERATOR *, VSTRING *, VSTRING *);
#define SMTP_HNAME(rr) (var_smtp_cname_overr ? (rr)->rname : (rr)->qname)
extern int smtp_connect(SMTP_STATE *);
extern void smtp_vrfy_init(void);
extern int smtp_helo(SMTP_STATE *);
extern int smtp_xfer(SMTP_STATE *);
extern int smtp_rset(SMTP_STATE *);
extern int smtp_quit(SMTP_STATE *);
extern HBC_CALL_BACKS smtp_hbc_callbacks[];
#define THIS_SESSION_IS_CACHED \
(!THIS_SESSION_IS_FORBIDDEN && session->expire_time > 0)
#define THIS_SESSION_IS_EXPIRED \
(THIS_SESSION_IS_CACHED \
&& (session->expire_time < vstream_ftime(session->stream) \
|| (var_smtp_reuse_count > 0 \
&& session->reuse_count >= var_smtp_reuse_count)))
#define THIS_SESSION_IS_THROTTLED \
(!THIS_SESSION_IS_FORBIDDEN && session->expire_time < 0)
#define THIS_SESSION_IS_FORBIDDEN \
(session->forbidden != 0)
#define DONT_CACHE_THIS_SESSION \
(session->expire_time = 0)
#define DONT_CACHE_THROTTLED_SESSION \
(session->expire_time = -1)
#define DONT_USE_FORBIDDEN_SESSION \
(session->forbidden = 1)
#define USE_NEWBORN_SESSION \
(session->forbidden = 0)
#define CACHE_THIS_SESSION_UNTIL(when) \
(session->expire_time = (when))
#ifdef USE_SASL_AUTH
#define HAVE_SASL_CREDENTIALS \
(var_smtp_sasl_enable \
&& *var_smtp_sasl_passwd \
&& smtp_sasl_passwd_lookup(session))
#else
#define HAVE_SASL_CREDENTIALS (0)
#endif
#define PREACTIVE_DELAY \
(session->state->request->msg_stats.active_arrival.tv_sec - \
session->state->request->msg_stats.incoming_arrival.tv_sec)
#define PLAINTEXT_FALLBACK_OK_AFTER_STARTTLS_FAILURE \
(session->tls_context == 0 \
&& state->tls->level == TLS_LEV_MAY \
&& PREACTIVE_DELAY >= var_min_backoff_time \
&& !HAVE_SASL_CREDENTIALS)
#define PLAINTEXT_FALLBACK_OK_AFTER_TLS_SESSION_FAILURE \
(session->tls_context != 0 \
&& SMTP_RCPT_LEFT(state) > SMTP_RCPT_MARK_COUNT(state) \
&& state->tls->level == TLS_LEV_MAY \
&& PREACTIVE_DELAY >= var_min_backoff_time \
&& !HAVE_SASL_CREDENTIALS)
#define RETRY_AS_PLAINTEXT do { \
session->tls_retry_plain = 1; \
state->misc_flags &= ~SMTP_MISC_FLAG_FINAL_SERVER; \
} while (0)
typedef struct SMTP_RESP {
int code;
const char *dsn;
char *str;
VSTRING *dsn_buf;
VSTRING *str_buf;
} SMTP_RESP;
extern void PRINTFLIKE(2, 3) smtp_chat_cmd(SMTP_SESSION *, const char *,...);
extern DICT *smtp_chat_resp_filter;
extern SMTP_RESP *smtp_chat_resp(SMTP_SESSION *);
extern void smtp_chat_init(SMTP_SESSION *);
extern void smtp_chat_reset(SMTP_SESSION *);
extern void smtp_chat_notify(SMTP_SESSION *);
#define SMTP_RESP_FAKE(resp, _dsn) \
((resp)->code = 0, \
(resp)->dsn = (_dsn), \
(resp)->str = DSN_BY_LOCAL_MTA, \
(resp))
#define DSN_BY_LOCAL_MTA ((char *) 0)
#define SMTP_RESP_SET_DSN(resp, _dsn) do { \
vstring_strcpy((resp)->dsn_buf, (_dsn)); \
(resp)->dsn = STR((resp)->dsn_buf); \
} while (0)
#define SMTP_RCPT_STATE_KEEP 1
#define SMTP_RCPT_STATE_DROP 2
#define SMTP_RCPT_INIT(state) do { \
(state)->rcpt_drop = (state)->rcpt_keep = 0; \
(state)->rcpt_left = state->request->rcpt_list.len; \
} while (0)
#define SMTP_RCPT_DROP(state, rcpt) do { \
(rcpt)->u.status = SMTP_RCPT_STATE_DROP; (state)->rcpt_drop++; \
} while (0)
#define SMTP_RCPT_KEEP(state, rcpt) do { \
(rcpt)->u.status = SMTP_RCPT_STATE_KEEP; (state)->rcpt_keep++; \
} while (0)
#define SMTP_RCPT_ISMARKED(rcpt) ((rcpt)->u.status != 0)
#define SMTP_RCPT_LEFT(state) (state)->rcpt_left
#define SMTP_RCPT_MARK_COUNT(state) ((state)->rcpt_drop + (state)->rcpt_keep)
extern void smtp_rcpt_cleanup(SMTP_STATE *);
extern void smtp_rcpt_done(SMTP_STATE *, SMTP_RESP *, RECIPIENT *);
#define SMTP_THROTTLE 1
#define SMTP_NOTHROTTLE 0
extern int smtp_sess_fail(SMTP_STATE *);
extern int PRINTFLIKE(5, 6) smtp_misc_fail(SMTP_STATE *, int, const char *,
SMTP_RESP *, const char *,...);
extern void PRINTFLIKE(5, 6) smtp_rcpt_fail(SMTP_STATE *, RECIPIENT *,
const char *, SMTP_RESP *,
const char *,...);
extern int smtp_stream_except(SMTP_STATE *, int, const char *);
#define smtp_site_fail(state, mta, resp, ...) \
smtp_misc_fail((state), SMTP_THROTTLE, (mta), (resp), __VA_ARGS__)
#define smtp_mesg_fail(state, mta, resp, ...) \
smtp_misc_fail((state), SMTP_NOTHROTTLE, (mta), (resp), __VA_ARGS__)
extern const char *smtp_unalias_name(const char *);
extern VSTRING *smtp_unalias_addr(VSTRING *, const char *);
extern SMTP_STATE *smtp_state_alloc(void);
extern void smtp_state_free(SMTP_STATE *);
extern int smtp_map11_external(VSTRING *, MAPS *, int);
extern int smtp_map11_tree(TOK822 *, MAPS *, int);
extern int smtp_map11_internal(VSTRING *, MAPS *, int);
char *smtp_key_prefix(VSTRING *, const char *, SMTP_ITERATOR *, int);
#define SMTP_KEY_FLAG_SERVICE (1<<0)
#define SMTP_KEY_FLAG_SENDER (1<<1)
#define SMTP_KEY_FLAG_REQ_NEXTHOP (1<<2)
#define SMTP_KEY_FLAG_NEXTHOP (1<<3)
#define SMTP_KEY_FLAG_HOSTNAME (1<<4)
#define SMTP_KEY_FLAG_ADDR (1<<5)
#define SMTP_KEY_FLAG_PORT (1<<6)
#define SMTP_KEY_MASK_ALL \
(SMTP_KEY_FLAG_SERVICE | SMTP_KEY_FLAG_SENDER | \
SMTP_KEY_FLAG_REQ_NEXTHOP | \
SMTP_KEY_FLAG_NEXTHOP | SMTP_KEY_FLAG_HOSTNAME | \
SMTP_KEY_FLAG_ADDR | SMTP_KEY_FLAG_PORT)
#define COND_SASL_SMTP_KEY_FLAG_SENDER \
((var_smtp_sender_auth && *var_smtp_sasl_passwd) ? \
SMTP_KEY_FLAG_SENDER : 0)
#define COND_SASL_SMTP_KEY_FLAG_NEXTHOP \
(*var_smtp_sasl_passwd ? SMTP_KEY_FLAG_NEXTHOP : 0)
#define COND_SASL_SMTP_KEY_FLAG_HOSTNAME \
(*var_smtp_sasl_passwd ? SMTP_KEY_FLAG_HOSTNAME : 0)
#define SMTP_KEY_MASK_SCACHE_DEST_LABEL \
(SMTP_KEY_FLAG_SERVICE | COND_SASL_SMTP_KEY_FLAG_SENDER \
| SMTP_KEY_FLAG_REQ_NEXTHOP)
#define SMTP_KEY_MASK_SCACHE_ENDP_LABEL \
(SMTP_KEY_FLAG_SERVICE | COND_SASL_SMTP_KEY_FLAG_SENDER \
| COND_SASL_SMTP_KEY_FLAG_NEXTHOP | COND_SASL_SMTP_KEY_FLAG_HOSTNAME \
| SMTP_KEY_FLAG_ADDR | SMTP_KEY_FLAG_PORT)
#define STR(s) vstring_str(s)
#define LEN(s) VSTRING_LEN(s)
extern int smtp_mode;
#define VAR_LMTP_SMTP(x) (smtp_mode ? VAR_SMTP_##x : VAR_LMTP_##x)
#define LMTP_SMTP_SUFFIX(x) (smtp_mode ? x##_SMTP : x##_LMTP)