diff options
Diffstat (limited to 'src/postscreen/postscreen_misc.c')
-rw-r--r-- | src/postscreen/postscreen_misc.c | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/src/postscreen/postscreen_misc.c b/src/postscreen/postscreen_misc.c new file mode 100644 index 0000000..f07c9ac --- /dev/null +++ b/src/postscreen/postscreen_misc.c @@ -0,0 +1,164 @@ +/*++ +/* NAME +/* postscreen_misc 3 +/* SUMMARY +/* postscreen misc routines +/* SYNOPSIS +/* #include <postscreen.h> +/* +/* char *psc_format_delta_time(buf, tv, delta) +/* VSTRING *buf; +/* struct timeval tv; +/* DELTA_TIME *delta; +/* +/* void psc_conclude(state) +/* PSC_STATE *state; +/* +/* void psc_hangup_event(state) +/* PSC_STATE *state; +/* DESCRIPTION +/* psc_format_delta_time() computes the time difference between +/* tv (past) and the present, formats the time difference with +/* sub-second resolution in a human-readable way, and returns +/* the integer time difference in seconds through the delta +/* argument. +/* +/* psc_conclude() logs when a client passes all necessary tests, +/* updates the postscreen cache for any testes that were passed, +/* and either forwards the connection to a real SMTP server or +/* replies with the text in state->error_reply and hangs up the +/* connection (by default, state->error_reply is set to a +/* default 421 reply). +/* +/* psc_hangup_event() cleans up after a client connection breaks +/* unexpectedly. If logs the test where the break happened, +/* and how much time as spent in that test before the connection +/* broke. +/* 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 +/*--*/ + +/* System library. */ + +#include <sys_defs.h> + +/* Utility library. */ + +#include <msg.h> +#include <vstring.h> +#include <iostuff.h> +#include <format_tv.h> + +/* Global library. */ + +#include <mail_params.h> + +/* Application-specific. */ + +#include <postscreen.h> + +/* psc_format_delta_time - pretty-formatted delta time */ + +char *psc_format_delta_time(VSTRING *buf, struct timeval tv, + DELTA_TIME *delta) +{ + DELTA_TIME pdelay; + struct timeval now; + + GETTIMEOFDAY(&now); + PSC_CALC_DELTA(pdelay, now, tv); + VSTRING_RESET(buf); + format_tv(buf, pdelay.dt_sec, pdelay.dt_usec, SIG_DIGS, var_delay_max_res); + *delta = pdelay; + return (STR(buf)); +} + +/* psc_conclude - bring this session to a conclusion */ + +void psc_conclude(PSC_STATE *state) +{ + const char *myname = "psc_conclude"; + + if (msg_verbose) + msg_info("flags for %s: %s", + myname, psc_print_state_flags(state->flags, myname)); + + /* + * Handle clients that passed at least one test other than permanent + * allowlisting, and that didn't fail any test including permanent + * denylisting. There may still be unfinished tests; those tests will + * need to be completed when the client returns in a later session. + */ + if (state->flags & PSC_STATE_MASK_ANY_FAIL) + state->flags &= ~PSC_STATE_MASK_ANY_PASS; + + /* + * Log our final blessing when all unfinished tests were completed. + */ + if ((state->flags & PSC_STATE_MASK_ANY_PASS) != 0 + && (state->flags & PSC_STATE_MASK_ANY_PASS) == + PSC_STATE_FLAGS_TODO_TO_PASS(state->flags & PSC_STATE_MASK_ANY_TODO)) + msg_info("PASS %s [%s]:%s", (state->flags & PSC_STATE_FLAG_NEW) == 0 + || state->client_info->pass_new_count++ > 0 ? + "OLD" : "NEW", PSC_CLIENT_ADDR_PORT(state)); + + /* + * Update the postscreen cache. This still supports a scenario where a + * client gets allowlisted in the course of multiple sessions, as long as + * that client does not "fail" any test. Don't try to optimize away cache + * updates; we want cached information to be up-to-date even if a test + * result is renewed during overlapping SMTP sessions, and even if + * 'postfix reload' happens in the middle of that. + */ + if ((state->flags & PSC_STATE_MASK_ANY_UPDATE) != 0 + && psc_cache_map != 0) { + psc_print_tests(psc_temp, state); + psc_cache_update(psc_cache_map, state->smtp_client_addr, STR(psc_temp)); + } + + /* + * Either hand off the socket to a real SMTP engine, or say bye-bye. + */ + if ((state->flags & PSC_STATE_FLAG_NOFORWARD) == 0) { + psc_send_socket(state); + } else { + if ((state->flags & PSC_STATE_FLAG_HANGUP) == 0) + (void) PSC_SEND_REPLY(state, state->final_reply); + msg_info("DISCONNECT [%s]:%s", PSC_CLIENT_ADDR_PORT(state)); + psc_free_session_state(state); + } +} + +/* psc_hangup_event - handle unexpected disconnect */ + +void psc_hangup_event(PSC_STATE *state) +{ + DELTA_TIME elapsed; + + /* + * Sessions can break at any time, even after the client passes all tests + * (some MTAs including Postfix don't send QUIT when connection reuse is + * enabled). This must not be treated as a protocol test failure. + * + * Log the current test phase, and the elapsed time after the start of that + * phase. + */ + state->flags |= PSC_STATE_FLAG_HANGUP; + msg_info("HANGUP after %s from [%s]:%s in %s", + psc_format_delta_time(psc_temp, state->start_time, &elapsed), + PSC_CLIENT_ADDR_PORT(state), state->test_name); + state->flags |= PSC_STATE_FLAG_NOFORWARD; + psc_conclude(state); +} |