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 
psc_format_delta_time(VSTRING * buf,struct timeval tv,DELTA_TIME * delta)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 
psc_conclude(PSC_STATE * state)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 
psc_hangup_event(PSC_STATE * state)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