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