5
/* postscreen pre-handshake tests
7
/* #include <postscreen.h>
9
/* void psc_early_init(void)
11
/* void psc_early_tests(state)
14
/* psc_early_tests() performs protocol tests before the SMTP
15
/* handshake: the pregreet test and the DNSBL test. Control
16
/* is passed to the psc_smtpd_tests() routine as appropriate.
18
/* psc_early_init() performs one-time initialization.
22
/* The Secure Mailer license must be distributed with this software.
25
/* IBM T.J. Watson Research
27
/* Yorktown Heights, NY 10598, USA
33
#include <sys/socket.h>
35
/* Utility library. */
38
#include <stringops.h>
44
#include <mail_params.h>
46
/* Application-specific. */
48
#include <postscreen.h>
50
static char *psc_teaser_greeting;
51
static VSTRING *psc_escape_buf;
53
/* psc_early_event - handle pre-greet, EOF, and DNSBL results. */
55
static void psc_early_event(int event, char *context)
57
const char *myname = "psc_early_event";
58
PSC_STATE *state = (PSC_STATE *) context;
59
char read_buf[PSC_READ_BUF_SIZE];
63
const char *dnsbl_name;
66
msg_info("%s: sq=%d cq=%d event %d on smtp socket %d from [%s]:%s flags=%s",
67
myname, psc_post_queue_length, psc_check_queue_length,
68
event, vstream_fileno(state->smtp_client_stream),
69
state->smtp_client_addr, state->smtp_client_port,
70
psc_print_state_flags(state->flags, myname));
72
PSC_CLEAR_EVENT_REQUEST(vstream_fileno(state->smtp_client_stream),
73
psc_early_event, context);
76
* XXX Be sure to empty the DNSBL lookup buffer otherwise we have a
79
* XXX We can avoid "forgetting" to do this by keeping a pointer to the
80
* DNSBL lookup buffer in the PSC_STATE structure. This also allows us to
81
* shave off a hash table lookup when retrieving the DNSBL result.
86
* We reached the end of the early tests time limit.
91
* Check if the SMTP client spoke before its turn.
93
if ((state->flags & PSC_STATE_MASK_PREGR_TODO_FAIL)
94
== PSC_STATE_FLAG_PREGR_TODO) {
95
state->pregr_stamp = event_time() + var_psc_pregr_ttl;
96
PSC_PASS_SESSION_STATE(state, "pregreet test",
97
PSC_STATE_FLAG_PREGR_PASS);
99
if ((state->flags & PSC_STATE_FLAG_PREGR_FAIL)
100
&& psc_pregr_action == PSC_ACT_IGNORE) {
101
PSC_UNFAIL_SESSION_STATE(state, PSC_STATE_FLAG_PREGR_FAIL);
102
/* Not: PSC_PASS_SESSION_STATE. Repeat this test the next time. */
106
* If the client is DNS blocklisted, drop the connection, send the
107
* client to a dummy protocol engine, or continue to the next test.
109
#define PSC_DNSBL_FORMAT \
110
"%s 5.7.1 Service unavailable; client [%s] blocked using %s\r\n"
112
if (state->flags & PSC_STATE_FLAG_DNSBL_TODO) {
114
psc_dnsbl_retrieve(state->smtp_client_addr, &dnsbl_name,
116
if (dnsbl_score < var_psc_dnsbl_thresh) {
117
state->dnsbl_stamp = event_time() + var_psc_dnsbl_ttl;
118
PSC_PASS_SESSION_STATE(state, "dnsbl test",
119
PSC_STATE_FLAG_DNSBL_PASS);
121
msg_info("DNSBL rank %d for [%s]:%s",
122
dnsbl_score, PSC_CLIENT_ADDR_PORT(state));
123
PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_DNSBL_FAIL);
124
switch (psc_dnsbl_action) {
126
state->dnsbl_reply = vstring_sprintf(vstring_alloc(100),
127
PSC_DNSBL_FORMAT, "521",
128
state->smtp_client_addr, dnsbl_name);
129
PSC_DROP_SESSION_STATE(state, STR(state->dnsbl_reply));
131
case PSC_ACT_ENFORCE:
132
state->dnsbl_reply = vstring_sprintf(vstring_alloc(100),
133
PSC_DNSBL_FORMAT, "550",
134
state->smtp_client_addr, dnsbl_name);
135
PSC_ENFORCE_SESSION_STATE(state, STR(state->dnsbl_reply));
138
PSC_UNFAIL_SESSION_STATE(state, PSC_STATE_FLAG_DNSBL_FAIL);
139
/* Not: PSC_PASS_SESSION_STATE. Repeat this test. */
142
msg_panic("%s: unknown dnsbl action value %d",
143
myname, psc_dnsbl_action);
150
* Pass the connection to a real SMTP server, or enter the dummy
151
* engine for deep tests.
153
if (state->flags & (PSC_STATE_FLAG_NOFORWARD | PSC_STATE_MASK_SMTPD_TODO))
154
psc_smtpd_tests(state);
160
* EOF, or the client spoke before its turn. We simply drop the
161
* connection, or we continue waiting and allow DNS replies to
165
if ((read_count = recv(vstream_fileno(state->smtp_client_stream),
166
read_buf, sizeof(read_buf) - 1, MSG_PEEK)) <= 0) {
167
/* Avoid memory leak. */
168
if (state->flags & PSC_STATE_FLAG_DNSBL_TODO)
169
(void) psc_dnsbl_retrieve(state->smtp_client_addr, &dnsbl_name,
171
/* XXX Wait for DNS replies to come in. */
172
psc_hangup_event(state);
175
read_buf[read_count] = 0;
176
escape(psc_escape_buf, read_buf, read_count);
177
msg_info("PREGREET %d after %s from [%s]:%s: %.100s", read_count,
178
psc_format_delta_time(psc_temp, state->start_time, &elapsed),
179
PSC_CLIENT_ADDR_PORT(state), STR(psc_escape_buf));
180
PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_PREGR_FAIL);
181
switch (psc_pregr_action) {
183
/* Avoid memory leak. */
184
if (state->flags & PSC_STATE_FLAG_DNSBL_TODO)
185
(void) psc_dnsbl_retrieve(state->smtp_client_addr, &dnsbl_name,
187
PSC_DROP_SESSION_STATE(state, "521 5.5.1 Protocol error\r\n");
189
case PSC_ACT_ENFORCE:
190
/* We call psc_dnsbl_retrieve() when the timer expires. */
191
PSC_ENFORCE_SESSION_STATE(state, "550 5.5.1 Protocol error\r\n");
194
/* We call psc_dnsbl_retrieve() when the timer expires. */
195
/* We must handle this case after the timer expires. */
198
msg_panic("%s: unknown pregreet action value %d",
199
myname, psc_pregr_action);
203
* Terminate the greet delay if we're just waiting for the pregreet
204
* test to complete. It is safe to call psc_early_event directly,
205
* since we are already in that function.
207
* XXX After this code passes all tests, swap around the two blocks in
208
* this switch statement and fall through from EVENT_READ into
209
* EVENT_TIME, instead of calling psc_early_event recursively.
211
state->flags |= PSC_STATE_FLAG_PREGR_DONE;
212
if (elapsed.dt_sec >= PSC_EFF_GREET_WAIT
213
|| ((state->flags & PSC_STATE_MASK_EARLY_DONE)
214
== PSC_STATE_FLAGS_TODO_TO_DONE(state->flags & PSC_STATE_MASK_EARLY_TODO)))
215
psc_early_event(EVENT_TIME, context);
217
event_request_timer(psc_early_event, context,
218
PSC_EFF_GREET_WAIT - elapsed.dt_sec);
223
/* psc_early_dnsbl_event - cancel pregreet timer if waiting for DNS only */
225
static void psc_early_dnsbl_event(int unused_event, char *context)
227
const char *myname = "psc_early_dnsbl_event";
228
PSC_STATE *state = (PSC_STATE *) context;
231
msg_info("%s: notify [%s]:%s", myname, PSC_CLIENT_ADDR_PORT(state));
234
* Terminate the greet delay if we're just waiting for DNSBL lookup to
235
* complete. Don't call psc_early_event directly, that would result in a
238
state->flags |= PSC_STATE_FLAG_DNSBL_DONE;
239
if ((state->flags & PSC_STATE_MASK_EARLY_DONE)
240
== PSC_STATE_FLAGS_TODO_TO_DONE(state->flags & PSC_STATE_MASK_EARLY_TODO))
241
event_request_timer(psc_early_event, context, EVENT_NULL_DELAY);
244
/* psc_early_tests - start the early (before protocol) tests */
246
void psc_early_tests(PSC_STATE *state)
248
const char *myname = "psc_early_tests";
251
* Report errors and progress in the context of this test.
253
PSC_BEGIN_TESTS(state, "tests before SMTP handshake");
256
* Run a PREGREET test. Send half the greeting banner, by way of teaser,
257
* then wait briefly to see if the client speaks before its turn.
259
if ((state->flags & PSC_STATE_FLAG_PREGR_TODO) != 0
260
&& psc_teaser_greeting != 0
261
&& PSC_SEND_REPLY(state, psc_teaser_greeting) != 0) {
262
psc_hangup_event(state);
267
* Run a DNS blocklist query.
269
if ((state->flags & PSC_STATE_FLAG_DNSBL_TODO) != 0)
271
psc_dnsbl_request(state->smtp_client_addr, psc_early_dnsbl_event,
274
state->dnsbl_index = -1;
277
* Wait for the client to respond or for DNS lookup to complete.
279
if ((state->flags & PSC_STATE_FLAG_PREGR_TODO) != 0)
280
PSC_READ_EVENT_REQUEST(vstream_fileno(state->smtp_client_stream),
281
psc_early_event, (char *) state, PSC_EFF_GREET_WAIT);
283
event_request_timer(psc_early_event, (char *) state, PSC_EFF_GREET_WAIT);
286
/* psc_early_init - initialize early tests */
288
void psc_early_init(void)
290
if (*var_psc_pregr_banner) {
291
vstring_sprintf(psc_temp, "220-%s\r\n", var_psc_pregr_banner);
292
psc_teaser_greeting = mystrdup(STR(psc_temp));
293
psc_escape_buf = vstring_alloc(100);