Home | History | Annotate | Line # | Download | only in postscreen
      1 /*	$NetBSD: postscreen_misc.c,v 1.4 2022/10/08 16:12:48 christos Exp $	*/
      2 
      3 /*++
      4 /* NAME
      5 /*	postscreen_misc 3
      6 /* SUMMARY
      7 /*	postscreen misc routines
      8 /* SYNOPSIS
      9 /*	#include <postscreen.h>
     10 /*
     11 /*	char	*psc_format_delta_time(buf, tv, delta)
     12 /*	VSTRING	*buf;
     13 /*	struct timeval tv;
     14 /*	DELTA_TIME *delta;
     15 /*
     16 /*	void	psc_conclude(state)
     17 /*	PSC_STATE *state;
     18 /*
     19 /*	void	psc_hangup_event(state)
     20 /*	PSC_STATE *state;
     21 /* DESCRIPTION
     22 /*	psc_format_delta_time() computes the time difference between
     23 /*	tv (past) and the present, formats the time difference with
     24 /*	sub-second resolution in a human-readable way, and returns
     25 /*	the integer time difference in seconds through the delta
     26 /*	argument.
     27 /*
     28 /*	psc_conclude() logs when a client passes all necessary tests,
     29 /*	updates the postscreen cache for any testes that were passed,
     30 /*	and either forwards the connection to a real SMTP server or
     31 /*	replies with the text in state->error_reply and hangs up the
     32 /*	connection (by default, state->error_reply is set to a
     33 /*	default 421 reply).
     34 /*
     35 /*	psc_hangup_event() cleans up after a client connection breaks
     36 /*	unexpectedly. If logs the test where the break happened,
     37 /*	and how much time as spent in that test before the connection
     38 /*	broke.
     39 /* LICENSE
     40 /* .ad
     41 /* .fi
     42 /*	The Secure Mailer license must be distributed with this software.
     43 /* AUTHOR(S)
     44 /*	Wietse Venema
     45 /*	IBM T.J. Watson Research
     46 /*	P.O. Box 704
     47 /*	Yorktown Heights, NY 10598, USA
     48 /*
     49 /*	Wietse Venema
     50 /*	Google, Inc.
     51 /*	111 8th Avenue
     52 /*	New York, NY 10011, USA
     53 /*--*/
     54 
     55 /* System library. */
     56 
     57 #include <sys_defs.h>
     58 
     59 /* Utility library. */
     60 
     61 #include <msg.h>
     62 #include <vstring.h>
     63 #include <iostuff.h>
     64 #include <format_tv.h>
     65 
     66 /* Global library. */
     67 
     68 #include <mail_params.h>
     69 
     70 /* Application-specific. */
     71 
     72 #include <postscreen.h>
     73 
     74 /* psc_format_delta_time - pretty-formatted delta time */
     75 
     76 char   *psc_format_delta_time(VSTRING *buf, struct timeval tv,
     77 			              DELTA_TIME *delta)
     78 {
     79     DELTA_TIME pdelay;
     80     struct timeval now;
     81 
     82     GETTIMEOFDAY(&now);
     83     PSC_CALC_DELTA(pdelay, now, tv);
     84     VSTRING_RESET(buf);
     85     format_tv(buf, pdelay.dt_sec, pdelay.dt_usec, SIG_DIGS, var_delay_max_res);
     86     *delta = pdelay;
     87     return (STR(buf));
     88 }
     89 
     90 /* psc_conclude - bring this session to a conclusion */
     91 
     92 void    psc_conclude(PSC_STATE *state)
     93 {
     94     const char *myname = "psc_conclude";
     95 
     96     if (msg_verbose)
     97 	msg_info("flags for %s: %s",
     98 		 myname, psc_print_state_flags(state->flags, myname));
     99 
    100     /*
    101      * Handle clients that passed at least one test other than permanent
    102      * allowlisting, and that didn't fail any test including permanent
    103      * denylisting. There may still be unfinished tests; those tests will
    104      * need to be completed when the client returns in a later session.
    105      */
    106     if (state->flags & PSC_STATE_MASK_ANY_FAIL)
    107 	state->flags &= ~PSC_STATE_MASK_ANY_PASS;
    108 
    109     /*
    110      * Log our final blessing when all unfinished tests were completed.
    111      */
    112     if ((state->flags & PSC_STATE_MASK_ANY_PASS) != 0
    113 	&& (state->flags & PSC_STATE_MASK_ANY_PASS) ==
    114 	PSC_STATE_FLAGS_TODO_TO_PASS(state->flags & PSC_STATE_MASK_ANY_TODO))
    115 	msg_info("PASS %s [%s]:%s", (state->flags & PSC_STATE_FLAG_NEW) == 0
    116 		 || state->client_info->pass_new_count++ > 0 ?
    117 		 "OLD" : "NEW", PSC_CLIENT_ADDR_PORT(state));
    118 
    119     /*
    120      * Update the postscreen cache. This still supports a scenario where a
    121      * client gets allowlisted in the course of multiple sessions, as long as
    122      * that client does not "fail" any test. Don't try to optimize away cache
    123      * updates; we want cached information to be up-to-date even if a test
    124      * result is renewed during overlapping SMTP sessions, and even if
    125      * 'postfix reload' happens in the middle of that.
    126      */
    127     if ((state->flags & PSC_STATE_MASK_ANY_UPDATE) != 0
    128 	&& psc_cache_map != 0) {
    129 	psc_print_tests(psc_temp, state);
    130 	psc_cache_update(psc_cache_map, state->smtp_client_addr, STR(psc_temp));
    131     }
    132 
    133     /*
    134      * Either hand off the socket to a real SMTP engine, or say bye-bye.
    135      */
    136     if ((state->flags & PSC_STATE_FLAG_NOFORWARD) == 0) {
    137 	psc_send_socket(state);
    138     } else {
    139 	if ((state->flags & PSC_STATE_FLAG_HANGUP) == 0)
    140 	    (void) PSC_SEND_REPLY(state, state->final_reply);
    141 	msg_info("DISCONNECT [%s]:%s", PSC_CLIENT_ADDR_PORT(state));
    142 	psc_free_session_state(state);
    143     }
    144 }
    145 
    146 /* psc_hangup_event - handle unexpected disconnect */
    147 
    148 void    psc_hangup_event(PSC_STATE *state)
    149 {
    150     DELTA_TIME elapsed;
    151 
    152     /*
    153      * Sessions can break at any time, even after the client passes all tests
    154      * (some MTAs including Postfix don't send QUIT when connection reuse is
    155      * enabled). This must not be treated as a protocol test failure.
    156      *
    157      * Log the current test phase, and the elapsed time after the start of that
    158      * phase.
    159      */
    160     state->flags |= PSC_STATE_FLAG_HANGUP;
    161     msg_info("HANGUP after %s from [%s]:%s in %s",
    162 	     psc_format_delta_time(psc_temp, state->start_time, &elapsed),
    163 	     PSC_CLIENT_ADDR_PORT(state), state->test_name);
    164     state->flags |= PSC_STATE_FLAG_NOFORWARD;
    165     psc_conclude(state);
    166 }
    167