summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorGilles Chehade <gilles@cvs.openbsd.org>2018-12-22 12:17:17 +0000
committerGilles Chehade <gilles@cvs.openbsd.org>2018-12-22 12:17:17 +0000
commit21ad51598dd25e4c4d0b3d3806bef50e96257b47 (patch)
treedfad4ce3513ab95d71e0de7ac1bfaf0b8e04fc59 /usr.sbin
parenta065f90e49c64de79923cf9c7dedd4d717ff1e2c (diff)
introduce 'helo' builtin filter, can be used on any hook but 'connect'
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/smtpd/lka_filter.c106
-rw-r--r--usr.sbin/smtpd/parse.y31
-rw-r--r--usr.sbin/smtpd/smtpd.h8
3 files changed, 116 insertions, 29 deletions
diff --git a/usr.sbin/smtpd/lka_filter.c b/usr.sbin/smtpd/lka_filter.c
index 5b5623c441d..bdaf4cbcd2c 100644
--- a/usr.sbin/smtpd/lka_filter.c
+++ b/usr.sbin/smtpd/lka_filter.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: lka_filter.c,v 1.25 2018/12/22 11:32:43 gilles Exp $ */
+/* $OpenBSD: lka_filter.c,v 1.26 2018/12/22 12:17:16 gilles Exp $ */
/*
* Copyright (c) 2018 Gilles Chehade <gilles@poolp.org>
@@ -39,12 +39,12 @@
struct filter;
struct filter_session;
-static void filter_protocol_internal(uint64_t *, uint64_t, enum filter_phase, const char *);
+static void filter_protocol_internal(struct filter_session *, uint64_t *, uint64_t, enum filter_phase, const char *);
static void filter_protocol(uint64_t, enum filter_phase, const char *);
static void filter_protocol_next(uint64_t, uint64_t, enum filter_phase, const char *);
static void filter_protocol_query(struct filter *, uint64_t, uint64_t, const char *, const char *);
-static void filter_data_internal(uint64_t, uint64_t, const char *);
+static void filter_data_internal(struct filter_session *, uint64_t, uint64_t, const char *);
static void filter_data(uint64_t, const char *);
static void filter_data_next(uint64_t, uint64_t, const char *);
static void filter_data_query(struct filter *, uint64_t, uint64_t, const char *);
@@ -74,6 +74,8 @@ struct filter_session {
char *rdns;
int fcrdns;
+ char *heloname;
+
enum filter_phase phase;
};
@@ -139,6 +141,7 @@ lka_filter_init(void)
dict_init(&filters);
dict_init(&filter_chains);
+ /* first pass, allocate and init individual filters */
iter = NULL;
while (dict_iter(env->sc_filters_dict, &iter, &name, (void **)&filter_config)) {
switch (filter_config->filter_type) {
@@ -163,6 +166,7 @@ lka_filter_init(void)
}
}
+ /* second pass, allocate and init filter chains but don't build yet */
iter = NULL;
while (dict_iter(env->sc_filters_dict, &iter, &name, (void **)&filter_config)) {
switch (filter_config->filter_type) {
@@ -224,6 +228,7 @@ lka_filter_ready(void)
size_t i;
size_t j;
+ /* all filters are ready, actually build the filter chains */
iter = NULL;
while (dict_iter(&filters, &iter, &filter_name, (void **)&filter)) {
filter_chain = xcalloc(1, sizeof *filter_chain);
@@ -484,19 +489,12 @@ lka_filter_protocol(uint64_t reqid, enum filter_phase phase, const char *param)
}
static void
-filter_protocol_internal(uint64_t *token, uint64_t reqid, enum filter_phase phase, const char *param)
+filter_protocol_internal(struct filter_session *fs, uint64_t *token, uint64_t reqid, enum filter_phase phase, const char *param)
{
- struct filter_session *fs;
struct filter_chain *filter_chain;
struct filter_entry *filter_entry;
struct filter *filter;
- /* session can legitimately disappear on a resume */
- fs = *token ?
- tree_get(&sessions, reqid) :
- tree_xget(&sessions, reqid);
- if (fs == NULL)
- return;
if (!*token)
fs->phase = phase;
@@ -548,25 +546,17 @@ filter_protocol_internal(uint64_t *token, uint64_t reqid, enum filter_phase phas
}
/* filter_entry resulted in proceed, try next filter */
- filter_protocol_internal(token, reqid, phase, param);
+ filter_protocol_internal(fs, token, reqid, phase, param);
return;
}
static void
-filter_data_internal(uint64_t token, uint64_t reqid, const char *line)
+filter_data_internal(struct filter_session *fs, uint64_t token, uint64_t reqid, const char *line)
{
- struct filter_session *fs;
struct filter_chain *filter_chain;
struct filter_entry *filter_entry;
struct filter *filter;
- /* session can legitimately disappear on a resume */
- fs = token ?
- tree_get(&sessions, reqid) :
- tree_xget(&sessions, reqid);
- if (fs == NULL)
- return;
-
if (!token)
fs->phase = FILTER_DATA_LINE;
if (fs->phase != FILTER_DATA_LINE)
@@ -598,27 +588,61 @@ filter_data_internal(uint64_t token, uint64_t reqid, const char *line)
static void
filter_protocol(uint64_t reqid, enum filter_phase phase, const char *param)
{
- uint64_t token = 0;
+ struct filter_session *fs;
+ uint64_t token = 0;
+
+ fs = tree_xget(&sessions, reqid);
- filter_protocol_internal(&token, reqid, phase, param);
+ switch (phase) {
+ case FILTER_HELO:
+ case FILTER_EHLO:
+ if (fs->heloname)
+ free(fs->heloname);
+ fs->heloname = xstrdup(param);
+ break;
+ case FILTER_STARTTLS:
+ case FILTER_AUTH:
+ case FILTER_MAIL_FROM:
+ /* TBD */
+ break;
+ default:
+ break;
+ }
+ filter_protocol_internal(fs, &token, reqid, phase, param);
}
static void
filter_protocol_next(uint64_t token, uint64_t reqid, enum filter_phase phase, const char *param)
{
- filter_protocol_internal(&token, reqid, phase, param);
+ struct filter_session *fs;
+
+ /* session can legitimately disappear on a resume */
+ if ((fs = tree_get(&sessions, reqid)) == NULL)
+ return;
+
+ filter_protocol_internal(fs, &token, reqid, phase, param);
}
static void
filter_data(uint64_t reqid, const char *line)
{
- filter_data_internal(0, reqid, line);
+ struct filter_session *fs;
+
+ fs = tree_xget(&sessions, reqid);
+
+ filter_data_internal(fs, 0, reqid, line);
}
static void
filter_data_next(uint64_t token, uint64_t reqid, const char *line)
{
- filter_data_internal(token, reqid, line);
+ struct filter_session *fs;
+
+ /* session can legitimately disappear on a resume */
+ if ((fs = tree_get(&sessions, reqid)) == NULL)
+ return;
+
+ filter_data_internal(fs, token, reqid, line);
}
static void
@@ -757,6 +781,32 @@ filter_check_src_regex(struct filter *filter, const char *key)
}
static int
+filter_check_helo_table(struct filter *filter, enum table_service kind, const char *key)
+{
+ int ret = 0;
+
+ if (filter->config->helo_table) {
+ if (table_lookup(filter->config->helo_table, NULL, key, kind, NULL) > 0)
+ ret = 1;
+ ret = filter->config->not_helo_table < 0 ? !ret : ret;
+ }
+ return ret;
+}
+
+static int
+filter_check_helo_regex(struct filter *filter, const char *key)
+{
+ int ret = 0;
+
+ if (filter->config->helo_regex) {
+ if (table_lookup(filter->config->helo_regex, NULL, key, K_REGEX, NULL) > 0)
+ ret = 1;
+ ret = filter->config->not_helo_regex < 0 ? !ret : ret;
+ }
+ return ret;
+}
+
+static int
filter_check_fcrdns(struct filter *filter, int fcrdns)
{
int ret = 0;
@@ -798,7 +848,9 @@ filter_builtins_global(struct filter_session *fs, struct filter *filter, uint64_
filter_check_rdns_table(filter, K_DOMAIN, fs->rdns) ||
filter_check_rdns_regex(filter, fs->rdns) ||
filter_check_src_table(filter, K_NETADDR, ss_to_text(&fs->ss_src)) ||
- filter_check_src_regex(filter, ss_to_text(&fs->ss_src)))
+ filter_check_src_regex(filter, ss_to_text(&fs->ss_src)) ||
+ filter_check_helo_table(filter, K_DOMAIN, fs->heloname) ||
+ filter_check_helo_regex(filter, fs->heloname))
return 1;
return 0;
}
diff --git a/usr.sbin/smtpd/parse.y b/usr.sbin/smtpd/parse.y
index e244f5d8fcf..27bab29c928 100644
--- a/usr.sbin/smtpd/parse.y
+++ b/usr.sbin/smtpd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.243 2018/12/22 09:30:19 gilles Exp $ */
+/* $OpenBSD: parse.y,v 1.244 2018/12/22 12:17:16 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
@@ -1330,6 +1330,19 @@ negation SRC REGEX tables {
}
;
+filter_phase_check_helo_table:
+negation HELO tables {
+ filter_config->not_helo_table = $1 ? -1 : 1;
+ filter_config->helo_table = $3;
+}
+;
+filter_phase_check_helo_regex:
+negation HELO REGEX tables {
+ filter_config->not_helo_regex = $1 ? -1 : 1;
+ filter_config->helo_regex = $4;
+}
+;
+
filter_phase_global_options:
filter_phase_check_fcrdns |
filter_phase_check_rdns |
@@ -1342,27 +1355,43 @@ filter_phase_connect_options:
filter_phase_global_options;
filter_phase_helo_options:
+filter_phase_check_helo_table |
+filter_phase_check_helo_regex |
filter_phase_global_options;
filter_phase_mail_from_options:
+filter_phase_check_helo_table |
+filter_phase_check_helo_regex |
filter_phase_global_options;
filter_phase_rcpt_to_options:
+filter_phase_check_helo_table |
+filter_phase_check_helo_regex |
filter_phase_global_options;
filter_phase_data_options:
+filter_phase_check_helo_table |
+filter_phase_check_helo_regex |
filter_phase_global_options;
filter_phase_quit_options:
+filter_phase_check_helo_table |
+filter_phase_check_helo_regex |
filter_phase_global_options;
filter_phase_rset_options:
+filter_phase_check_helo_table |
+filter_phase_check_helo_regex |
filter_phase_global_options;
filter_phase_noop_options:
+filter_phase_check_helo_table |
+filter_phase_check_helo_regex |
filter_phase_global_options;
filter_phase_commit_options:
+filter_phase_check_helo_table |
+filter_phase_check_helo_regex |
filter_phase_global_options;
diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h
index 913c44782c2..1c76438e572 100644
--- a/usr.sbin/smtpd/smtpd.h
+++ b/usr.sbin/smtpd/smtpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtpd.h,v 1.598 2018/12/22 08:54:02 gilles Exp $ */
+/* $OpenBSD: smtpd.h,v 1.599 2018/12/22 12:17:16 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
@@ -1076,6 +1076,12 @@ struct filter_config {
int8_t not_src_regex;
struct table *src_regex;
+ int8_t not_helo_table;
+ struct table *helo_table;
+
+ int8_t not_helo_regex;
+ struct table *helo_regex;
+
};
enum filter_status {