summaryrefslogtreecommitdiffstats
path: root/src/postscreen/postscreen.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/postscreen/postscreen.h')
-rw-r--r--src/postscreen/postscreen.h599
1 files changed, 599 insertions, 0 deletions
diff --git a/src/postscreen/postscreen.h b/src/postscreen/postscreen.h
new file mode 100644
index 0000000..69a5e17
--- /dev/null
+++ b/src/postscreen/postscreen.h
@@ -0,0 +1,599 @@
+/*++
+/* NAME
+/* postscreen 3h
+/* SUMMARY
+/* postscreen internal interfaces
+/* SYNOPSIS
+/* #include <postscreen.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * System library.
+ */
+
+ /*
+ * Utility library.
+ */
+#include <dict_cache.h>
+#include <vstream.h>
+#include <vstring.h>
+#include <events.h>
+#include <htable.h>
+#include <myaddrinfo.h>
+
+ /*
+ * Global library.
+ */
+#include <addr_match_list.h>
+#include <string_list.h>
+#include <maps.h>
+#include <server_acl.h>
+
+ /*
+ * Preliminary stuff, to be fixed.
+ */
+#define PSC_READ_BUF_SIZE 1024
+
+ /*
+ * Numeric indices and symbolic names for tests whose time stamps and status
+ * flags can be accessed by numeric index.
+ */
+#define PSC_TINDX_PREGR 0 /* pregreet */
+#define PSC_TINDX_DNSBL 1 /* dnsbl */
+#define PSC_TINDX_PIPEL 2 /* pipelining */
+#define PSC_TINDX_NSMTP 3 /* non-smtp command */
+#define PSC_TINDX_BARLF 4 /* bare newline */
+#define PSC_TINDX_COUNT 5 /* number of tests */
+
+#define PSC_TNAME_PREGR "pregreet"
+#define PSC_TNAME_DNSBL "dnsbl"
+#define PSC_TNAME_PIPEL "pipelining"
+#define PSC_TNAME_NSMTP "non-smtp command"
+#define PSC_TNAME_BARLF "bare newline"
+
+#define PSC_TINDX_BYTNAME(tname) (PSC_TINDX_ ## tname)
+
+ /*
+ * Per-client shared state.
+ */
+typedef struct {
+ int concurrency; /* per-client */
+ int pass_new_count; /* per-client */
+ time_t expire_time[PSC_TINDX_COUNT]; /* per-test expiration */
+} PSC_CLIENT_INFO;
+
+ /*
+ * Per-session state.
+ */
+typedef struct {
+ int flags; /* see below */
+ /* Socket state. */
+ VSTREAM *smtp_client_stream; /* remote SMTP client */
+ int smtp_server_fd; /* real SMTP server */
+ char *smtp_client_addr; /* client address */
+ char *smtp_client_port; /* client port */
+ char *smtp_server_addr; /* server address */
+ char *smtp_server_port; /* server port */
+ const char *final_reply; /* cause for hanging up */
+ VSTRING *send_buf; /* pending output */
+ /* Test context. */
+ struct timeval start_time; /* start of current test */
+ const char *test_name; /* name of current test */
+ PSC_CLIENT_INFO *client_info; /* shared client state */
+ VSTRING *dnsbl_reply; /* dnsbl reject text */
+ int dnsbl_score; /* saved DNSBL score */
+ int dnsbl_ttl; /* saved DNSBL TTL */
+ const char *dnsbl_name; /* DNSBL name with largest weight */
+ int dnsbl_index; /* dnsbl request index */
+ const char *rcpt_reply; /* how to reject recipients */
+ int command_count; /* error + junk command count */
+ const char *protocol; /* SMTP or ESMTP */
+ char *helo_name; /* SMTP helo/ehlo */
+ char *sender; /* MAIL FROM */
+ VSTRING *cmd_buffer; /* command read buffer */
+ int read_state; /* command read state machine */
+ /* smtpd(8) compatibility */
+ int ehlo_discard_mask; /* EHLO filter */
+ VSTRING *expand_buf; /* macro expansion */
+ const char *where; /* SMTP protocol state */
+} PSC_STATE;
+
+ /*
+ * Special expiration time values.
+ */
+#define PSC_TIME_STAMP_NEW (0) /* test was never passed */
+#define PSC_TIME_STAMP_DISABLED (1) /* never passed but disabled */
+#define PSC_TIME_STAMP_INVALID (-1) /* must not be cached */
+
+ /*
+ * Status flags.
+ */
+#define PSC_STATE_FLAG_NOFORWARD (1<<0) /* don't forward this session */
+#define PSC_STATE_FLAG_USING_TLS (1<<1) /* using the TLS proxy */
+#define PSC_STATE_FLAG_UNUSED2 (1<<2) /* use me! */
+#define PSC_STATE_FLAG_NEW (1<<3) /* some test was never passed */
+#define PSC_STATE_FLAG_DNLIST_FAIL (1<<4) /* denylisted */
+#define PSC_STATE_FLAG_HANGUP (1<<5) /* NOT a test failure */
+#define PSC_STATE_FLAG_SMTPD_X21 (1<<6) /* hang up after command */
+#define PSC_STATE_FLAG_ALLIST_FAIL (1<<7) /* do not allowlist */
+#define PSC_STATE_FLAG_TEST_BASE (8) /* start of indexable flags */
+
+ /*
+ * Tests whose flags and expiration time can be accessed by numerical index.
+ *
+ * Important: every MUMBLE_TODO flag must have a MUMBLE_PASS flag, such that
+ * MUMBLE_PASS == PSC_STATE_FLAGS_TODO_TO_PASS(MUMBLE_TODO).
+ *
+ * MUMBLE_TODO flags must not be cleared once raised. The _TODO_TO_PASS and
+ * _TODO_TO_DONE macros depend on this to decide that a group of tests is
+ * passed or completed.
+ *
+ * MUMBLE_DONE flags are used for "early" tests that have final results.
+ *
+ * MUMBLE_SKIP flags are used for "deep" tests where the client messed up.
+ * These flags look like MUMBLE_DONE but they are different. Deep tests can
+ * tentatively pass, but can still fail later in a session. The "ignore"
+ * action introduces an additional complication. MUMBLE_PASS indicates
+ * either that a deep test passed tentatively, or that the test failed but
+ * the result was ignored. MUMBLE_FAIL, on the other hand, is always final.
+ * We use MUMBLE_SKIP to indicate that a decision was either "fail" or
+ * forced "pass".
+ *
+ * The difference between DONE and SKIP is in the beholder's eye. These flags
+ * share the same bit.
+ */
+#define PSC_STATE_FLAGS_TODO_TO_PASS(todo_flags) ((todo_flags) >> 1)
+#define PSC_STATE_FLAGS_TODO_TO_DONE(todo_flags) ((todo_flags) << 1)
+
+#define PSC_STATE_FLAG_SHIFT_FAIL (0) /* failed test */
+#define PSC_STATE_FLAG_SHIFT_PASS (1) /* passed test */
+#define PSC_STATE_FLAG_SHIFT_TODO (2) /* expired test */
+#define PSC_STATE_FLAG_SHIFT_DONE (3) /* decision is final */
+#define PSC_STATE_FLAG_SHIFT_SKIP (3) /* action is already logged */
+#define PSC_STATE_FLAG_SHIFT_STRIDE (4) /* nr of flags per test */
+
+#define PSC_STATE_FLAG_SHIFT_BYFNAME(fname) (PSC_STATE_FLAG_SHIFT_ ## fname)
+
+ /*
+ * Indexable per-test flags. These are used for DNS allowlisting multiple
+ * tests, without needing per-test ad-hoc code.
+ */
+#define PSC_STATE_FLAG_BYTINDX_FNAME(tindx, fname) \
+ (1U << (PSC_STATE_FLAG_TEST_BASE \
+ + PSC_STATE_FLAG_SHIFT_STRIDE * (tindx) \
+ + PSC_STATE_FLAG_SHIFT_BYFNAME(fname)))
+
+#define PSC_STATE_FLAG_BYTINDX_FAIL(tindx) \
+ PSC_STATE_FLAG_BYTINDX_FNAME((tindx), FAIL)
+#define PSC_STATE_FLAG_BYTINDX_PASS(tindx) \
+ PSC_STATE_FLAG_BYTINDX_FNAME((tindx), PASS)
+#define PSC_STATE_FLAG_BYTINDX_TODO(tindx) \
+ PSC_STATE_FLAG_BYTINDX_FNAME((tindx), TODO)
+#define PSC_STATE_FLAG_BYTINDX_DONE(tindx) \
+ PSC_STATE_FLAG_BYTINDX_FNAME((tindx), DONE)
+#define PSC_STATE_FLAG_BYTINDX_SKIP(tindx) \
+ PSC_STATE_FLAG_BYTINDX_FNAME((tindx), SKIP)
+
+ /*
+ * Flags with distinct names. These are used in the per-test ad-hoc code.
+ */
+#define PSC_STATE_FLAG_BYTNAME_FNAME(tname, fname) \
+ (1U << (PSC_STATE_FLAG_TEST_BASE \
+ + PSC_STATE_FLAG_SHIFT_STRIDE * PSC_TINDX_BYTNAME(tname) \
+ + PSC_STATE_FLAG_SHIFT_BYFNAME(fname)))
+
+#define PSC_STATE_FLAG_PREGR_FAIL PSC_STATE_FLAG_BYTNAME_FNAME(PREGR, FAIL)
+#define PSC_STATE_FLAG_PREGR_PASS PSC_STATE_FLAG_BYTNAME_FNAME(PREGR, PASS)
+#define PSC_STATE_FLAG_PREGR_TODO PSC_STATE_FLAG_BYTNAME_FNAME(PREGR, TODO)
+#define PSC_STATE_FLAG_PREGR_DONE PSC_STATE_FLAG_BYTNAME_FNAME(PREGR, DONE)
+
+#define PSC_STATE_FLAG_DNSBL_FAIL PSC_STATE_FLAG_BYTNAME_FNAME(DNSBL, FAIL)
+#define PSC_STATE_FLAG_DNSBL_PASS PSC_STATE_FLAG_BYTNAME_FNAME(DNSBL, PASS)
+#define PSC_STATE_FLAG_DNSBL_TODO PSC_STATE_FLAG_BYTNAME_FNAME(DNSBL, TODO)
+#define PSC_STATE_FLAG_DNSBL_DONE PSC_STATE_FLAG_BYTNAME_FNAME(DNSBL, DONE)
+
+#define PSC_STATE_FLAG_PIPEL_FAIL PSC_STATE_FLAG_BYTNAME_FNAME(PIPEL, FAIL)
+#define PSC_STATE_FLAG_PIPEL_PASS PSC_STATE_FLAG_BYTNAME_FNAME(PIPEL, PASS)
+#define PSC_STATE_FLAG_PIPEL_TODO PSC_STATE_FLAG_BYTNAME_FNAME(PIPEL, TODO)
+#define PSC_STATE_FLAG_PIPEL_SKIP PSC_STATE_FLAG_BYTNAME_FNAME(PIPEL, SKIP)
+
+#define PSC_STATE_FLAG_NSMTP_FAIL PSC_STATE_FLAG_BYTNAME_FNAME(NSMTP, FAIL)
+#define PSC_STATE_FLAG_NSMTP_PASS PSC_STATE_FLAG_BYTNAME_FNAME(NSMTP, PASS)
+#define PSC_STATE_FLAG_NSMTP_TODO PSC_STATE_FLAG_BYTNAME_FNAME(NSMTP, TODO)
+#define PSC_STATE_FLAG_NSMTP_SKIP PSC_STATE_FLAG_BYTNAME_FNAME(NSMTP, SKIP)
+
+#define PSC_STATE_FLAG_BARLF_FAIL PSC_STATE_FLAG_BYTNAME_FNAME(BARLF, FAIL)
+#define PSC_STATE_FLAG_BARLF_PASS PSC_STATE_FLAG_BYTNAME_FNAME(BARLF, PASS)
+#define PSC_STATE_FLAG_BARLF_TODO PSC_STATE_FLAG_BYTNAME_FNAME(BARLF, TODO)
+#define PSC_STATE_FLAG_BARLF_SKIP PSC_STATE_FLAG_BYTNAME_FNAME(BARLF, SKIP)
+
+ /*
+ * Aggregates for individual tests.
+ */
+#define PSC_STATE_MASK_PREGR_TODO_FAIL \
+ (PSC_STATE_FLAG_PREGR_TODO | PSC_STATE_FLAG_PREGR_FAIL)
+#define PSC_STATE_MASK_DNSBL_TODO_FAIL \
+ (PSC_STATE_FLAG_DNSBL_TODO | PSC_STATE_FLAG_DNSBL_FAIL)
+#define PSC_STATE_MASK_PIPEL_TODO_FAIL \
+ (PSC_STATE_FLAG_PIPEL_TODO | PSC_STATE_FLAG_PIPEL_FAIL)
+#define PSC_STATE_MASK_NSMTP_TODO_FAIL \
+ (PSC_STATE_FLAG_NSMTP_TODO | PSC_STATE_FLAG_NSMTP_FAIL)
+#define PSC_STATE_MASK_BARLF_TODO_FAIL \
+ (PSC_STATE_FLAG_BARLF_TODO | PSC_STATE_FLAG_BARLF_FAIL)
+
+#define PSC_STATE_MASK_PREGR_TODO_DONE \
+ (PSC_STATE_FLAG_PREGR_TODO | PSC_STATE_FLAG_PREGR_DONE)
+#define PSC_STATE_MASK_PIPEL_TODO_SKIP \
+ (PSC_STATE_FLAG_PIPEL_TODO | PSC_STATE_FLAG_PIPEL_SKIP)
+#define PSC_STATE_MASK_NSMTP_TODO_SKIP \
+ (PSC_STATE_FLAG_NSMTP_TODO | PSC_STATE_FLAG_NSMTP_SKIP)
+#define PSC_STATE_MASK_BARLF_TODO_SKIP \
+ (PSC_STATE_FLAG_BARLF_TODO | PSC_STATE_FLAG_BARLF_SKIP)
+
+#define PSC_STATE_MASK_PREGR_FAIL_DONE \
+ (PSC_STATE_FLAG_PREGR_FAIL | PSC_STATE_FLAG_PREGR_DONE)
+
+#define PSC_STATE_MASK_PIPEL_TODO_PASS_FAIL \
+ (PSC_STATE_MASK_PIPEL_TODO_FAIL | PSC_STATE_FLAG_PIPEL_PASS)
+#define PSC_STATE_MASK_NSMTP_TODO_PASS_FAIL \
+ (PSC_STATE_MASK_NSMTP_TODO_FAIL | PSC_STATE_FLAG_NSMTP_PASS)
+#define PSC_STATE_MASK_BARLF_TODO_PASS_FAIL \
+ (PSC_STATE_MASK_BARLF_TODO_FAIL | PSC_STATE_FLAG_BARLF_PASS)
+
+ /*
+ * Separate aggregates for early tests and deep tests.
+ */
+#define PSC_STATE_MASK_EARLY_DONE \
+ (PSC_STATE_FLAG_PREGR_DONE | PSC_STATE_FLAG_DNSBL_DONE)
+#define PSC_STATE_MASK_EARLY_TODO \
+ (PSC_STATE_FLAG_PREGR_TODO | PSC_STATE_FLAG_DNSBL_TODO)
+#define PSC_STATE_MASK_EARLY_PASS \
+ (PSC_STATE_FLAG_PREGR_PASS | PSC_STATE_FLAG_DNSBL_PASS)
+#define PSC_STATE_MASK_EARLY_FAIL \
+ (PSC_STATE_FLAG_PREGR_FAIL | PSC_STATE_FLAG_DNSBL_FAIL)
+
+#define PSC_STATE_MASK_SMTPD_TODO \
+ (PSC_STATE_FLAG_PIPEL_TODO | PSC_STATE_FLAG_NSMTP_TODO | \
+ PSC_STATE_FLAG_BARLF_TODO)
+#define PSC_STATE_MASK_SMTPD_PASS \
+ (PSC_STATE_FLAG_PIPEL_PASS | PSC_STATE_FLAG_NSMTP_PASS | \
+ PSC_STATE_FLAG_BARLF_PASS)
+#define PSC_STATE_MASK_SMTPD_FAIL \
+ (PSC_STATE_FLAG_PIPEL_FAIL | PSC_STATE_FLAG_NSMTP_FAIL | \
+ PSC_STATE_FLAG_BARLF_FAIL)
+
+ /*
+ * Super-aggregates for all tests combined.
+ */
+#define PSC_STATE_MASK_ANY_FAIL \
+ (PSC_STATE_FLAG_DNLIST_FAIL | \
+ PSC_STATE_MASK_EARLY_FAIL | PSC_STATE_MASK_SMTPD_FAIL | \
+ PSC_STATE_FLAG_ALLIST_FAIL)
+
+#define PSC_STATE_MASK_ANY_PASS \
+ (PSC_STATE_MASK_EARLY_PASS | PSC_STATE_MASK_SMTPD_PASS)
+
+#define PSC_STATE_MASK_ANY_TODO \
+ (PSC_STATE_MASK_EARLY_TODO | PSC_STATE_MASK_SMTPD_TODO)
+
+#define PSC_STATE_MASK_ANY_TODO_FAIL \
+ (PSC_STATE_MASK_ANY_TODO | PSC_STATE_MASK_ANY_FAIL)
+
+#define PSC_STATE_MASK_ANY_UPDATE \
+ (PSC_STATE_MASK_ANY_PASS)
+
+ /*
+ * Meta-commands for state->where that reflect the initial command processor
+ * state and commands that aren't implemented.
+ */
+#define PSC_SMTPD_CMD_CONNECT "CONNECT"
+#define PSC_SMTPD_CMD_UNIMPL "UNIMPLEMENTED"
+
+ /*
+ * See log_adhoc.c for discussion.
+ */
+typedef struct {
+ int dt_sec; /* make sure it's signed */
+ int dt_usec; /* make sure it's signed */
+} DELTA_TIME;
+
+#define PSC_CALC_DELTA(x, y, z) \
+ do { \
+ (x).dt_sec = (y).tv_sec - (z).tv_sec; \
+ (x).dt_usec = (y).tv_usec - (z).tv_usec; \
+ while ((x).dt_usec < 0) { \
+ (x).dt_usec += 1000000; \
+ (x).dt_sec -= 1; \
+ } \
+ while ((x).dt_usec >= 1000000) { \
+ (x).dt_usec -= 1000000; \
+ (x).dt_sec += 1; \
+ } \
+ if ((x).dt_sec < 0) \
+ (x).dt_sec = (x).dt_usec = 0; \
+ } while (0)
+
+#define SIG_DIGS 2
+
+ /*
+ * Event management.
+ */
+
+/* PSC_READ_EVENT_REQUEST - prepare for transition to next state */
+
+#define PSC_READ_EVENT_REQUEST(fd, action, context, timeout) do { \
+ if (msg_verbose > 1) \
+ msg_info("%s: read-request fd=%d", myname, (fd)); \
+ event_enable_read((fd), (action), (context)); \
+ event_request_timer((action), (context), (timeout)); \
+ } while (0)
+
+#define PSC_READ_EVENT_REQUEST2(fd, read_act, time_act, context, timeout) do { \
+ if (msg_verbose > 1) \
+ msg_info("%s: read-request fd=%d", myname, (fd)); \
+ event_enable_read((fd), (read_act), (context)); \
+ event_request_timer((time_act), (context), (timeout)); \
+ } while (0)
+
+/* PSC_CLEAR_EVENT_REQUEST - complete state transition */
+
+#define PSC_CLEAR_EVENT_REQUEST(fd, time_act, context) do { \
+ if (msg_verbose > 1) \
+ msg_info("%s: clear-request fd=%d", myname, (fd)); \
+ event_disable_readwrite(fd); \
+ event_cancel_timer((time_act), (context)); \
+ } while (0)
+
+ /*
+ * Failure enforcement policies.
+ */
+#define PSC_NAME_ACT_DROP "drop"
+#define PSC_NAME_ACT_ENFORCE "enforce"
+#define PSC_NAME_ACT_IGNORE "ignore"
+#define PSC_NAME_ACT_CONT "continue"
+
+#define PSC_ACT_DROP 1
+#define PSC_ACT_ENFORCE 2
+#define PSC_ACT_IGNORE 3
+
+ /*
+ * Global variables.
+ */
+extern int psc_check_queue_length; /* connections being checked */
+extern int psc_post_queue_length; /* being sent to real SMTPD */
+extern DICT_CACHE *psc_cache_map; /* cache table handle */
+extern VSTRING *psc_temp; /* scratchpad */
+extern char *psc_smtpd_service_name; /* path to real SMTPD */
+extern int psc_pregr_action; /* PSC_ACT_DROP etc. */
+extern int psc_dnsbl_action; /* PSC_ACT_DROP etc. */
+extern int psc_pipel_action; /* PSC_ACT_DROP etc. */
+extern int psc_nsmtp_action; /* PSC_ACT_DROP etc. */
+extern int psc_barlf_action; /* PSC_ACT_DROP etc. */
+extern int psc_min_ttl; /* Update with new tests! */
+extern STRING_LIST *psc_forbid_cmds; /* CONNECT GET POST */
+extern int psc_stress_greet_wait; /* stressed greet wait */
+extern int psc_normal_greet_wait; /* stressed greet wait */
+extern int psc_stress_cmd_time_limit; /* stressed command limit */
+extern int psc_normal_cmd_time_limit; /* normal command time limit */
+extern int psc_stress; /* stress level */
+extern int psc_lowat_check_queue_length;/* stress low-water mark */
+extern int psc_hiwat_check_queue_length;/* stress high-water mark */
+extern DICT *psc_dnsbl_reply; /* DNSBL name mapper */
+extern HTABLE *psc_client_concurrency; /* per-client concurrency */
+
+#define PSC_EFF_GREET_WAIT \
+ (psc_stress ? psc_stress_greet_wait : psc_normal_greet_wait)
+#define PSC_EFF_CMD_TIME_LIMIT \
+ (psc_stress ? psc_stress_cmd_time_limit : psc_normal_cmd_time_limit)
+
+ /*
+ * String plumbing macros.
+ */
+#define PSC_STRING_UPDATE(str, text) do { \
+ if (str) myfree(str); \
+ (str) = ((text) ? mystrdup(text) : 0); \
+ } while (0)
+
+#define PSC_STRING_RESET(str) do { \
+ if (str) { \
+ myfree(str); \
+ (str) = 0; \
+ } \
+ } while (0)
+
+ /*
+ * SLMs.
+ */
+#define STR(x) vstring_str(x)
+#define LEN(x) VSTRING_LEN(x)
+
+ /*
+ * postscreen_state.c
+ */
+#define PSC_CLIENT_ADDR_PORT(state) \
+ (state)->smtp_client_addr, (state)->smtp_client_port
+
+#define PSC_PASS_SESSION_STATE(state, what, bits) do { \
+ if (msg_verbose) \
+ msg_info("PASS %s [%s]:%s", (what), PSC_CLIENT_ADDR_PORT(state)); \
+ (state)->flags |= (bits); \
+ } while (0)
+#define PSC_FAIL_SESSION_STATE(state, bits) do { \
+ if (msg_verbose) \
+ msg_info("FAIL [%s]:%s", PSC_CLIENT_ADDR_PORT(state)); \
+ (state)->flags |= (bits); \
+ } while (0)
+#define PSC_SKIP_SESSION_STATE(state, what, bits) do { \
+ if (msg_verbose) \
+ msg_info("SKIP %s [%s]:%s", (what), PSC_CLIENT_ADDR_PORT(state)); \
+ (state)->flags |= (bits); \
+ } while (0)
+#define PSC_DROP_SESSION_STATE(state, reply) do { \
+ if (msg_verbose) \
+ msg_info("DROP [%s]:%s", PSC_CLIENT_ADDR_PORT(state)); \
+ (state)->flags |= PSC_STATE_FLAG_NOFORWARD; \
+ (state)->final_reply = (reply); \
+ psc_conclude(state); \
+ } while (0)
+#define PSC_ENFORCE_SESSION_STATE(state, reply) do { \
+ if (msg_verbose) \
+ msg_info("ENFORCE [%s]:%s", PSC_CLIENT_ADDR_PORT(state)); \
+ (state)->rcpt_reply = (reply); \
+ (state)->flags |= PSC_STATE_FLAG_NOFORWARD; \
+ } while (0)
+#define PSC_UNPASS_SESSION_STATE(state, bits) do { \
+ if (msg_verbose) \
+ msg_info("UNPASS [%s]:%s", PSC_CLIENT_ADDR_PORT(state)); \
+ (state)->flags &= ~(bits); \
+ } while (0)
+#define PSC_UNFAIL_SESSION_STATE(state, bits) do { \
+ if (msg_verbose) \
+ msg_info("UNFAIL [%s]:%s", PSC_CLIENT_ADDR_PORT(state)); \
+ (state)->flags &= ~(bits); \
+ } while (0)
+#define PSC_ADD_SERVER_STATE(state, fd) do { \
+ (state)->smtp_server_fd = (fd); \
+ psc_post_queue_length++; \
+ } while (0)
+#define PSC_DEL_SERVER_STATE(state) do { \
+ close((state)->smtp_server_fd); \
+ (state)->smtp_server_fd = (-1); \
+ psc_post_queue_length--; \
+ } while (0)
+#define PSC_DEL_CLIENT_STATE(state) do { \
+ event_server_disconnect((state)->smtp_client_stream); \
+ (state)->smtp_client_stream = 0; \
+ psc_check_queue_length--; \
+ } while (0)
+extern PSC_STATE *psc_new_session_state(VSTREAM *, const char *, const char *, const char *, const char *);
+extern void psc_free_session_state(PSC_STATE *);
+extern const char *psc_print_state_flags(int, const char *);
+
+ /*
+ * postscreen_dict.c
+ */
+extern int psc_addr_match_list_match(ADDR_MATCH_LIST *, const char *);
+extern const char *psc_cache_lookup(DICT_CACHE *, const char *);
+extern void psc_cache_update(DICT_CACHE *, const char *, const char *);
+const char *psc_dict_get(DICT *, const char *);
+const char *psc_maps_find(MAPS *, const char *, int);
+
+ /*
+ * postscreen_dnsbl.c
+ */
+extern void psc_dnsbl_init(void);
+extern int psc_dnsbl_retrieve(const char *, const char **, int, int *);
+extern int psc_dnsbl_request(const char *, void (*) (int, void *), void *);
+
+ /*
+ * postscreen_tests.c
+ */
+#define PSC_INIT_TESTS(dst) do { \
+ time_t *_it_stamp_p; \
+ (dst)->flags = 0; \
+ for (_it_stamp_p = (dst)->client_info->expire_time; \
+ _it_stamp_p < (dst)->client_info->expire_time + PSC_TINDX_COUNT; \
+ _it_stamp_p++) \
+ *_it_stamp_p = PSC_TIME_STAMP_INVALID; \
+ } while (0)
+#define PSC_INIT_TEST_FLAGS_ONLY(dst) do { \
+ (dst)->flags = 0; \
+ } while (0)
+#define PSC_BEGIN_TESTS(state, name) do { \
+ (state)->test_name = (name); \
+ GETTIMEOFDAY(&(state)->start_time); \
+ } while (0)
+extern void psc_new_tests(PSC_STATE *);
+extern void psc_parse_tests(PSC_STATE *, const char *, time_t);
+extern void psc_todo_tests(PSC_STATE *, time_t);
+extern char *psc_print_tests(VSTRING *, PSC_STATE *);
+extern char *psc_print_grey_key(VSTRING *, const char *, const char *,
+ const char *, const char *);
+extern const char *psc_test_name(int);
+
+#define PSC_MIN(x, y) ((x) < (y) ? (x) : (y))
+#define PSC_MAX(x, y) ((x) > (y) ? (x) : (y))
+
+ /*
+ * postscreen_early.c
+ */
+extern void psc_early_tests(PSC_STATE *);
+extern void psc_early_init(void);
+
+ /*
+ * postscreen_smtpd.c
+ */
+extern void psc_smtpd_tests(PSC_STATE *);
+extern void psc_smtpd_init(void);
+extern void psc_smtpd_pre_jail_init(void);
+
+#define PSC_SMTPD_X21(state, reply) do { \
+ (state)->flags |= PSC_STATE_FLAG_SMTPD_X21; \
+ (state)->final_reply = (reply); \
+ psc_smtpd_tests(state); \
+ } while (0)
+
+ /*
+ * postscreen_misc.c
+ */
+extern char *psc_format_delta_time(VSTRING *, struct timeval, DELTA_TIME *);
+extern void psc_conclude(PSC_STATE *);
+extern void psc_hangup_event(PSC_STATE *);
+
+ /*
+ * postscreen_send.c
+ */
+#define PSC_SEND_REPLY psc_send_reply /* legacy macro */
+extern void pcs_send_pre_jail_init(void);
+extern int psc_send_reply(PSC_STATE *, const char *);
+extern void psc_send_socket(PSC_STATE *);
+
+ /*
+ * postscreen_starttls.c
+ */
+extern void psc_starttls_open(PSC_STATE *, EVENT_NOTIFY_FN);
+
+ /*
+ * postscreen_expand.c
+ */
+extern VSTRING *psc_expand_filter;
+extern void psc_expand_init(void);
+extern const char *psc_expand_lookup(const char *, int, void *);
+
+ /*
+ * postscreen_endpt.c
+ */
+typedef void (*PSC_ENDPT_LOOKUP_FN) (int, VSTREAM *,
+ MAI_HOSTADDR_STR *, MAI_SERVPORT_STR *,
+ MAI_HOSTADDR_STR *, MAI_SERVPORT_STR *);
+extern void psc_endpt_lookup(VSTREAM *, PSC_ENDPT_LOOKUP_FN);
+extern void psc_endpt_local_lookup(VSTREAM *, PSC_ENDPT_LOOKUP_FN);
+
+ /*
+ * postscreen_access emulation.
+ */
+#define PSC_ACL_ACT_ALLOWLIST SERVER_ACL_ACT_PERMIT
+#define PSC_ACL_ACT_DUNNO SERVER_ACL_ACT_DUNNO
+#define PSC_ACL_ACT_DENYLIST SERVER_ACL_ACT_REJECT
+#define PSC_ACL_ACT_ERROR SERVER_ACL_ACT_ERROR
+
+#define psc_acl_pre_jail_init server_acl_pre_jail_init
+#define psc_acl_parse server_acl_parse
+#define psc_acl_eval(s,a,p) server_acl_eval((s)->smtp_client_addr, (a), (p))
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/