1/*	$NetBSD$	*/
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
50/* System library. */
51
52#include <sys_defs.h>
53
54/* Utility library. */
55
56#include <msg.h>
57#include <vstring.h>
58#include <iostuff.h>
59#include <format_tv.h>
60
61/* Global library. */
62
63#include <mail_params.h>
64
65/* Application-specific. */
66
67#include <postscreen.h>
68
69/* psc_format_delta_time - pretty-formatted delta time */
70
71char   *psc_format_delta_time(VSTRING *buf, struct timeval tv,
72			              DELTA_TIME *delta)
73{
74    DELTA_TIME pdelay;
75    struct timeval now;
76
77    GETTIMEOFDAY(&now);
78    PSC_CALC_DELTA(pdelay, now, tv);
79    VSTRING_RESET(buf);
80    format_tv(buf, pdelay.dt_sec, pdelay.dt_usec, SIG_DIGS, var_delay_max_res);
81    *delta = pdelay;
82    return (STR(buf));
83}
84
85/* psc_conclude - bring this session to a conclusion */
86
87void    psc_conclude(PSC_STATE *state)
88{
89    const char *myname = "psc_conclude";
90
91    if (msg_verbose)
92	msg_info("flags for %s: %s",
93		 myname, psc_print_state_flags(state->flags, myname));
94
95    /*
96     * Handle clients that passed at least one test other than permanent
97     * whitelisting, and that didn't fail any test including permanent
98     * blacklisting. There may still be unfinished tests; those tests will
99     * need to be completed when the client returns in a later session.
100     */
101    if (state->flags & PSC_STATE_MASK_ANY_FAIL)
102	state->flags &= ~PSC_STATE_MASK_ANY_PASS;
103
104    /*
105     * Log our final blessing when all unfinished tests were completed.
106     */
107    if ((state->flags & PSC_STATE_MASK_ANY_PASS) != 0
108	&& (state->flags & PSC_STATE_MASK_ANY_PASS) ==
109	PSC_STATE_FLAGS_TODO_TO_PASS(state->flags & PSC_STATE_MASK_ANY_TODO))
110	msg_info("PASS %s [%s]:%s", (state->flags & PSC_STATE_FLAG_NEW) == 0 ?
111		 "OLD" : "NEW", PSC_CLIENT_ADDR_PORT(state));
112
113    /*
114     * Update the postscreen cache. This still supports a scenario where a
115     * client gets whitelisted in the course of multiple sessions, as long as
116     * that client does not "fail" any test.
117     */
118    if ((state->flags & PSC_STATE_MASK_ANY_UPDATE) != 0
119	&& psc_cache_map != 0) {
120	psc_print_tests(psc_temp, state);
121	psc_cache_update(psc_cache_map, state->smtp_client_addr, STR(psc_temp));
122    }
123
124    /*
125     * Either hand off the socket to a real SMTP engine, or say bye-bye.
126     */
127    if ((state->flags & PSC_STATE_FLAG_NOFORWARD) == 0) {
128	psc_send_socket(state);
129    } else {
130	if ((state->flags & PSC_STATE_FLAG_HANGUP) == 0)
131	    (void) PSC_SEND_REPLY(state, state->final_reply);
132	msg_info("DISCONNECT [%s]:%s", PSC_CLIENT_ADDR_PORT(state));
133	psc_free_session_state(state);
134    }
135}
136
137/* psc_hangup_event - handle unexpected disconnect */
138
139void    psc_hangup_event(PSC_STATE *state)
140{
141    DELTA_TIME elapsed;
142
143    /*
144     * Sessions can break at any time, even after the client passes all tests
145     * (some MTAs including Postfix don't send QUIT when connection reuse is
146     * enabled). This must not be treated as a protocol test failure.
147     *
148     * Log the current test phase, and the elapsed time after the start of that
149     * phase.
150     */
151    state->flags |= PSC_STATE_FLAG_HANGUP;
152    msg_info("HANGUP after %s from [%s]:%s in %s",
153	     psc_format_delta_time(psc_temp, state->start_time, &elapsed),
154	     PSC_CLIENT_ADDR_PORT(state), state->test_name);
155    state->flags |= PSC_STATE_FLAG_NOFORWARD;
156    psc_conclude(state);
157}
158