postscreen_early.c [plain text]
#include <sys_defs.h>
#include <sys/socket.h>
#include <msg.h>
#include <stringops.h>
#include <mymalloc.h>
#include <vstring.h>
#include <mail_params.h>
#include <postscreen.h>
static char *psc_teaser_greeting;
static VSTRING *psc_escape_buf;
static void psc_early_event(int event, char *context)
{
const char *myname = "psc_early_event";
PSC_STATE *state = (PSC_STATE *) context;
char read_buf[PSC_READ_BUF_SIZE];
int read_count;
int dnsbl_score;
DELTA_TIME elapsed;
const char *dnsbl_name;
if (msg_verbose > 1)
msg_info("%s: sq=%d cq=%d event %d on smtp socket %d from [%s]:%s flags=%s",
myname, psc_post_queue_length, psc_check_queue_length,
event, vstream_fileno(state->smtp_client_stream),
state->smtp_client_addr, state->smtp_client_port,
psc_print_state_flags(state->flags, myname));
PSC_CLEAR_EVENT_REQUEST(vstream_fileno(state->smtp_client_stream),
psc_early_event, context);
switch (event) {
case EVENT_TIME:
if ((state->flags & PSC_STATE_MASK_PREGR_TODO_FAIL)
== PSC_STATE_FLAG_PREGR_TODO) {
state->pregr_stamp = event_time() + var_psc_pregr_ttl;
PSC_PASS_SESSION_STATE(state, "pregreet test",
PSC_STATE_FLAG_PREGR_PASS);
}
if ((state->flags & PSC_STATE_FLAG_PREGR_FAIL)
&& psc_pregr_action == PSC_ACT_IGNORE) {
PSC_UNFAIL_SESSION_STATE(state, PSC_STATE_FLAG_PREGR_FAIL);
}
#define PSC_DNSBL_FORMAT \
"%s 5.7.1 Service unavailable; client [%s] blocked using %s\r\n"
if (state->flags & PSC_STATE_FLAG_DNSBL_TODO) {
dnsbl_score =
psc_dnsbl_retrieve(state->smtp_client_addr, &dnsbl_name,
state->dnsbl_index);
if (dnsbl_score < var_psc_dnsbl_thresh) {
state->dnsbl_stamp = event_time() + var_psc_dnsbl_ttl;
PSC_PASS_SESSION_STATE(state, "dnsbl test",
PSC_STATE_FLAG_DNSBL_PASS);
} else {
msg_info("DNSBL rank %d for [%s]:%s",
dnsbl_score, PSC_CLIENT_ADDR_PORT(state));
PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_DNSBL_FAIL);
switch (psc_dnsbl_action) {
case PSC_ACT_DROP:
state->dnsbl_reply = vstring_sprintf(vstring_alloc(100),
PSC_DNSBL_FORMAT, "521",
state->smtp_client_addr, dnsbl_name);
PSC_DROP_SESSION_STATE(state, STR(state->dnsbl_reply));
return;
case PSC_ACT_ENFORCE:
state->dnsbl_reply = vstring_sprintf(vstring_alloc(100),
PSC_DNSBL_FORMAT, "550",
state->smtp_client_addr, dnsbl_name);
PSC_ENFORCE_SESSION_STATE(state, STR(state->dnsbl_reply));
break;
case PSC_ACT_IGNORE:
PSC_UNFAIL_SESSION_STATE(state, PSC_STATE_FLAG_DNSBL_FAIL);
break;
default:
msg_panic("%s: unknown dnsbl action value %d",
myname, psc_dnsbl_action);
}
}
}
if (state->flags & (PSC_STATE_FLAG_NOFORWARD | PSC_STATE_MASK_SMTPD_TODO))
psc_smtpd_tests(state);
else
psc_conclude(state);
return;
default:
if ((read_count = recv(vstream_fileno(state->smtp_client_stream),
read_buf, sizeof(read_buf) - 1, MSG_PEEK)) <= 0) {
if (state->flags & PSC_STATE_FLAG_DNSBL_TODO)
(void) psc_dnsbl_retrieve(state->smtp_client_addr, &dnsbl_name,
state->dnsbl_index);
psc_hangup_event(state);
return;
}
read_buf[read_count] = 0;
escape(psc_escape_buf, read_buf, read_count);
msg_info("PREGREET %d after %s from [%s]:%s: %.100s", read_count,
psc_format_delta_time(psc_temp, state->start_time, &elapsed),
PSC_CLIENT_ADDR_PORT(state), STR(psc_escape_buf));
PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_PREGR_FAIL);
switch (psc_pregr_action) {
case PSC_ACT_DROP:
if (state->flags & PSC_STATE_FLAG_DNSBL_TODO)
(void) psc_dnsbl_retrieve(state->smtp_client_addr, &dnsbl_name,
state->dnsbl_index);
PSC_DROP_SESSION_STATE(state, "521 5.5.1 Protocol error\r\n");
return;
case PSC_ACT_ENFORCE:
PSC_ENFORCE_SESSION_STATE(state, "550 5.5.1 Protocol error\r\n");
break;
case PSC_ACT_IGNORE:
break;
default:
msg_panic("%s: unknown pregreet action value %d",
myname, psc_pregr_action);
}
state->flags |= PSC_STATE_FLAG_PREGR_DONE;
if (elapsed.dt_sec >= PSC_EFF_GREET_WAIT
|| ((state->flags & PSC_STATE_MASK_EARLY_DONE)
== PSC_STATE_FLAGS_TODO_TO_DONE(state->flags & PSC_STATE_MASK_EARLY_TODO)))
psc_early_event(EVENT_TIME, context);
else
event_request_timer(psc_early_event, context,
PSC_EFF_GREET_WAIT - elapsed.dt_sec);
return;
}
}
static void psc_early_dnsbl_event(int unused_event, char *context)
{
const char *myname = "psc_early_dnsbl_event";
PSC_STATE *state = (PSC_STATE *) context;
if (msg_verbose)
msg_info("%s: notify [%s]:%s", myname, PSC_CLIENT_ADDR_PORT(state));
state->flags |= PSC_STATE_FLAG_DNSBL_DONE;
if ((state->flags & PSC_STATE_MASK_EARLY_DONE)
== PSC_STATE_FLAGS_TODO_TO_DONE(state->flags & PSC_STATE_MASK_EARLY_TODO))
event_request_timer(psc_early_event, context, EVENT_NULL_DELAY);
}
void psc_early_tests(PSC_STATE *state)
{
const char *myname = "psc_early_tests";
PSC_BEGIN_TESTS(state, "tests before SMTP handshake");
if ((state->flags & PSC_STATE_FLAG_PREGR_TODO) != 0
&& psc_teaser_greeting != 0
&& PSC_SEND_REPLY(state, psc_teaser_greeting) != 0) {
psc_hangup_event(state);
return;
}
if ((state->flags & PSC_STATE_FLAG_DNSBL_TODO) != 0)
state->dnsbl_index =
psc_dnsbl_request(state->smtp_client_addr, psc_early_dnsbl_event,
(char *) state);
else
state->dnsbl_index = -1;
if ((state->flags & PSC_STATE_FLAG_PREGR_TODO) != 0)
PSC_READ_EVENT_REQUEST(vstream_fileno(state->smtp_client_stream),
psc_early_event, (char *) state, PSC_EFF_GREET_WAIT);
else
event_request_timer(psc_early_event, (char *) state, PSC_EFF_GREET_WAIT);
}
void psc_early_init(void)
{
if (*var_psc_pregr_banner) {
vstring_sprintf(psc_temp, "220-%s\r\n", var_psc_pregr_banner);
psc_teaser_greeting = mystrdup(STR(psc_temp));
psc_escape_buf = vstring_alloc(100);
}
}