#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_STATE {
int misc_flags;
VSTREAM *src;
const char *service;
DELIVER_REQUEST *request;
struct SMTP_SESSION *session;
int status;
ssize_t space_left;
HTABLE *cache_used;
VSTRING *dest_label;
VSTRING *dest_prop;
VSTRING *endp_label;
VSTRING *endp_prop;
int nexthop_lookup_mx;
char *nexthop_domain;
unsigned nexthop_port;
int rcpt_left;
int rcpt_drop;
int rcpt_keep;
DSN_BUF *why;
} SMTP_STATE;
#define SET_NEXTHOP_STATE(state, lookup_mx, domain, port) { \
(state)->nexthop_lookup_mx = lookup_mx; \
(state)->nexthop_domain = mystrdup(domain); \
(state)->nexthop_port = port; \
}
#define FREE_NEXTHOP_STATE(state) { \
myfree((state)->nexthop_domain); \
(state)->nexthop_domain = 0; \
}
#define HAVE_NEXTHOP_STATE(state) ((state)->nexthop_domain != 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_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_USE_LMTP (1<<2)
#define SMTP_MISC_FLAG_FIRST_NEXTHOP (1<<3)
#define SMTP_MISC_FLAG_FINAL_NEXTHOP (1<<4)
#define SMTP_MISC_FLAG_FINAL_SERVER (1<<5)
#define SMTP_MISC_FLAG_CONN_LOAD (1<<6)
#define SMTP_MISC_FLAG_CONN_STORE (1<<7)
#define SMTP_MISC_FLAG_COMPLETE_SESSION (1<<8)
#define SMTP_MISC_FLAG_PREF_IPV6 (1<<9)
#define SMTP_MISC_FLAG_PREF_IPV4 (1<<10)
#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 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;
#endif
extern HBC_CHECKS *smtp_header_checks;
extern HBC_CHECKS *smtp_body_checks;
typedef struct SMTP_SESSION {
VSTREAM *stream;
char *dest;
char *host;
char *addr;
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 dead;
#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_level;
int tls_retry_plain;
char *tls_protocols;
char *tls_grade;
VSTRING *tls_exclusions;
ARGV *tls_matchargv;
#endif
SMTP_STATE *state;
} SMTP_SESSION;
extern SMTP_SESSION *smtp_session_alloc(VSTREAM *, const char *, const char *,
const char *, unsigned, time_t, int);
extern void smtp_session_free(SMTP_SESSION *);
extern int smtp_session_passivate(SMTP_SESSION *, VSTRING *, VSTRING *);
extern SMTP_SESSION *smtp_session_activate(int, VSTRING *, VSTRING *);
#ifdef USE_TLS
extern void smtp_tls_list_init(void);
#endif
#define SMTP_HNAME(rr) (var_smtp_cname_overr ? (rr)->rname : (rr)->qname)
extern int smtp_connect(SMTP_STATE *);
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_DEAD && session->expire_time > 0)
#define THIS_SESSION_IS_EXPIRED \
(THIS_SESSION_IS_CACHED \
&& session->expire_time < vstream_ftime(session->stream))
#define THIS_SESSION_IS_BAD \
(!THIS_SESSION_IS_DEAD && session->expire_time < 0)
#define THIS_SESSION_IS_DEAD \
(session->dead != 0)
#define DONT_CACHE_THIS_SESSION \
(session->expire_time = 0)
#define DONT_CACHE_BAD_SESSION \
(session->expire_time = -1)
#define DONT_USE_DEAD_SESSION \
(session->dead = 1)
#define USE_NEWBORN_SESSION \
(session->dead = 0)
#define CACHE_THIS_SESSION_UNTIL(when) \
(session->expire_time = (when))
#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_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
extern void smtp_rcpt_cleanup(SMTP_STATE *);
extern void smtp_rcpt_done(SMTP_STATE *, SMTP_RESP *, RECIPIENT *);
extern int smtp_sess_fail(SMTP_STATE *);
extern int PRINTFLIKE(4, 5) smtp_site_fail(SMTP_STATE *, const char *,
SMTP_RESP *, const char *,...);
extern int PRINTFLIKE(4, 5) smtp_mesg_fail(SMTP_STATE *, 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 *);
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);
#define STR(s) vstring_str(s)
#define LEN(s) VSTRING_LEN(s)