summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorGilles Chehade <gilles@cvs.openbsd.org>2018-12-21 21:35:30 +0000
committerGilles Chehade <gilles@cvs.openbsd.org>2018-12-21 21:35:30 +0000
commit3e5a496dd5d27664c37c8038bf3ff08b81acda89 (patch)
tree6ed79f2857d7464935d7ed62ccbfc4efc7c81505 /usr.sbin
parent4014ecb37423fedc8d1ee85d5bc2fd411838c67d (diff)
since we already support regex lookups in tables for builtin filters, let's
also support regex lookups in match rule criterias performing table lookups ok millert@
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/smtpd/parse.y132
-rw-r--r--usr.sbin/smtpd/ruleset.c38
-rw-r--r--usr.sbin/smtpd/smtpd.conf.547
-rw-r--r--usr.sbin/smtpd/smtpd.h12
-rw-r--r--usr.sbin/smtpd/table.c10
5 files changed, 225 insertions, 14 deletions
diff --git a/usr.sbin/smtpd/parse.y b/usr.sbin/smtpd/parse.y
index aba2252fc25..d0efed8b828 100644
--- a/usr.sbin/smtpd/parse.y
+++ b/usr.sbin/smtpd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.240 2018/12/21 19:07:47 gilles Exp $ */
+/* $OpenBSD: parse.y,v 1.241 2018/12/21 21:35:29 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
@@ -190,7 +190,7 @@ typedef struct {
%token ON
%token PKI PORT PROC PROC_EXEC
%token QUEUE QUIT
-%token RCPT_TO RECIPIENT RECEIVEDAUTH RELAY REJECT REPORT REWRITE RSET
+%token RCPT_TO RECIPIENT RECEIVEDAUTH REGEX RELAY REJECT REPORT REWRITE RSET
%token SCHEDULER SENDER SENDERS SMTP SMTP_IN SMTP_OUT SMTPS SOCKET SRC SUB_ADDR_DELIM
%token TABLE TAG TAGGED TLS TLS_REQUIRE TTL
%token USER USERBASE
@@ -908,6 +908,25 @@ negation TAG tables {
rule->flag_tag = $1 ? -1 : 1;
rule->table_tag = strdup(t->t_name);
}
+|
+negation TAG REGEX tables {
+ struct table *t = $4;
+
+ if (rule->flag_tag) {
+ yyerror("tag already specified for this rule");
+ YYERROR;
+ }
+
+ if (!table_check_use(t, T_DYNAMIC|T_LIST, K_REGEX)) {
+ yyerror("table \"%s\" may not be used for tag lookups",
+ t->t_name);
+ YYERROR;
+ }
+
+ rule->flag_tag = $1 ? -1 : 1;
+ rule->flag_tag_regex = 1;
+ rule->table_tag = strdup(t->t_name);
+}
| negation HELO tables {
struct table *t = $3;
@@ -925,6 +944,24 @@ negation TAG tables {
rule->flag_smtp_helo = $1 ? -1 : 1;
rule->table_smtp_helo = strdup(t->t_name);
}
+| negation HELO REGEX tables {
+ struct table *t = $4;
+
+ if (rule->flag_smtp_helo) {
+ yyerror("mail-helo already specified for this rule");
+ YYERROR;
+ }
+
+ if (!table_check_use(t, T_DYNAMIC|T_LIST, K_REGEX)) {
+ yyerror("table \"%s\" may not be used for helo lookups",
+ t->t_name);
+ YYERROR;
+ }
+
+ rule->flag_smtp_helo = $1 ? -1 : 1;
+ rule->flag_smtp_helo_regex = 1;
+ rule->table_smtp_helo = strdup(t->t_name);
+}
| negation TLS {
if (rule->flag_smtp_starttls) {
yyerror("tls already specified for this rule");
@@ -956,6 +993,24 @@ negation TAG tables {
rule->flag_smtp_auth = $1 ? -1 : 1;
rule->table_smtp_auth = strdup(t->t_name);
}
+| negation AUTH REGEX tables {
+ struct table *t = $4;
+
+ if (rule->flag_smtp_auth) {
+ yyerror("auth already specified for this rule");
+ YYERROR;
+ }
+
+ if (!table_check_use(t, T_DYNAMIC|T_LIST, K_REGEX)) {
+ yyerror("table \"%s\" may not be used for auth lookups",
+ t->t_name);
+ YYERROR;
+ }
+
+ rule->flag_smtp_auth = $1 ? -1 : 1;
+ rule->flag_smtp_auth_regex = 1;
+ rule->table_smtp_auth = strdup(t->t_name);
+}
| negation MAIL_FROM tables {
struct table *t = $3;
@@ -973,6 +1028,24 @@ negation TAG tables {
rule->flag_smtp_mail_from = $1 ? -1 : 1;
rule->table_smtp_mail_from = strdup(t->t_name);
}
+| negation MAIL_FROM REGEX tables {
+ struct table *t = $4;
+
+ if (rule->flag_smtp_mail_from) {
+ yyerror("mail-from already specified for this rule");
+ YYERROR;
+ }
+
+ if (!table_check_use(t, T_DYNAMIC|T_LIST, K_REGEX)) {
+ yyerror("table \"%s\" may not be used for mail-from lookups",
+ t->t_name);
+ YYERROR;
+ }
+
+ rule->flag_smtp_mail_from = $1 ? -1 : 1;
+ rule->flag_smtp_mail_from_regex = 1;
+ rule->table_smtp_mail_from = strdup(t->t_name);
+}
| negation RCPT_TO tables {
struct table *t = $3;
@@ -990,6 +1063,24 @@ negation TAG tables {
rule->flag_smtp_rcpt_to = $1 ? -1 : 1;
rule->table_smtp_rcpt_to = strdup(t->t_name);
}
+| negation RCPT_TO REGEX tables {
+ struct table *t = $4;
+
+ if (rule->flag_smtp_rcpt_to) {
+ yyerror("rcpt-to already specified for this rule");
+ YYERROR;
+ }
+
+ if (!table_check_use(t, T_DYNAMIC|T_LIST, K_REGEX)) {
+ yyerror("table \"%s\" may not be used for rcpt-to lookups",
+ t->t_name);
+ YYERROR;
+ }
+
+ rule->flag_smtp_rcpt_to = $1 ? -1 : 1;
+ rule->flag_smtp_rcpt_to_regex = 1;
+ rule->table_smtp_rcpt_to = strdup(t->t_name);
+}
| negation FROM SOCKET {
if (rule->flag_from) {
@@ -1036,6 +1127,24 @@ negation TAG tables {
rule->flag_from = $1 ? -1 : 1;
rule->table_from = strdup(t->t_name);
}
+| negation FROM SRC REGEX tables {
+ struct table *t = $5;
+
+ if (rule->flag_from) {
+ yyerror("from already specified for this rule");
+ YYERROR;
+ }
+
+ if (!table_check_use(t, T_DYNAMIC|T_LIST, K_REGEX)) {
+ yyerror("table \"%s\" may not be used for from lookups",
+ t->t_name);
+ YYERROR;
+ }
+
+ rule->flag_from = $1 ? -1 : 1;
+ rule->flag_from_regex = 1;
+ rule->table_from = strdup(t->t_name);
+}
| negation FOR LOCAL {
struct table *t = table_find(conf, "<localnames>", NULL);
@@ -1074,6 +1183,24 @@ negation TAG tables {
rule->flag_for = $1 ? -1 : 1;
rule->table_for = strdup(t->t_name);
}
+| negation FOR DOMAIN REGEX tables {
+ struct table *t = $5;
+
+ if (rule->flag_for) {
+ yyerror("for already specified for this rule");
+ YYERROR;
+ }
+
+ if (!table_check_use(t, T_DYNAMIC|T_LIST, K_REGEX)) {
+ yyerror("table \"%s\" may not be used for 'for' lookups",
+ t->t_name);
+ YYERROR;
+ }
+
+ rule->flag_for = $1 ? -1 : 1;
+ rule->flag_for_regex = 1;
+ rule->table_for = strdup(t->t_name);
+}
;
match_options:
@@ -2039,6 +2166,7 @@ lookup(char *s)
{ "rcpt-to", RCPT_TO },
{ "received-auth", RECEIVEDAUTH },
{ "recipient", RECIPIENT },
+ { "regex", REGEX },
{ "reject", REJECT },
{ "relay", RELAY },
{ "rset", RSET },
diff --git a/usr.sbin/smtpd/ruleset.c b/usr.sbin/smtpd/ruleset.c
index a2617a699a2..0aa9806c828 100644
--- a/usr.sbin/smtpd/ruleset.c
+++ b/usr.sbin/smtpd/ruleset.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ruleset.c,v 1.36 2018/06/16 19:41:26 gilles Exp $ */
+/* $OpenBSD: ruleset.c,v 1.37 2018/12/21 21:35:29 gilles Exp $ */
/*
* Copyright (c) 2009 Gilles Chehade <gilles@poolp.org>
@@ -55,12 +55,16 @@ ruleset_match_tag(struct rule *r, const struct envelope *evp)
{
int ret;
struct table *table;
+ enum table_service service = K_STRING;
if (!r->flag_tag)
return 1;
+ if (r->flag_tag_regex)
+ service = K_REGEX;
+
table = table_find(env, r->table_tag, NULL);
- if ((ret = ruleset_match_table_lookup(table, evp->tag, K_STRING)) < 0)
+ if ((ret = ruleset_match_table_lookup(table, evp->tag, service)) < 0)
return ret;
return r->flag_tag < 0 ? !ret : ret;
@@ -72,6 +76,7 @@ ruleset_match_from(struct rule *r, const struct envelope *evp)
int ret;
const char *key;
struct table *table;
+ enum table_service service = K_NETADDR;
if (!r->flag_from)
return 1;
@@ -87,8 +92,11 @@ ruleset_match_from(struct rule *r, const struct envelope *evp)
else
key = ss_to_text(&evp->ss);
+ if (r->flag_from_regex)
+ service = K_REGEX;
+
table = table_find(env, r->table_from, NULL);
- if ((ret = ruleset_match_table_lookup(table, key, K_NETADDR)) < 0)
+ if ((ret = ruleset_match_table_lookup(table, key, service)) < 0)
return -1;
return r->flag_from < 0 ? !ret : ret;
@@ -99,13 +107,17 @@ ruleset_match_to(struct rule *r, const struct envelope *evp)
{
int ret;
struct table *table;
+ enum table_service service = K_DOMAIN;
if (!r->flag_for)
return 1;
+ if (r->flag_for_regex)
+ service = K_REGEX;
+
table = table_find(env, r->table_for, NULL);
if ((ret = ruleset_match_table_lookup(table, evp->dest.domain,
- K_DOMAIN)) < 0)
+ service)) < 0)
return -1;
return r->flag_for < 0 ? !ret : ret;
@@ -116,12 +128,16 @@ ruleset_match_smtp_helo(struct rule *r, const struct envelope *evp)
{
int ret;
struct table *table;
+ enum table_service service = K_DOMAIN;
if (!r->flag_smtp_helo)
return 1;
+ if (r->flag_smtp_helo_regex)
+ service = K_REGEX;
+
table = table_find(env, r->table_smtp_helo, NULL);
- if ((ret = ruleset_match_table_lookup(table, evp->helo, K_DOMAIN)) < 0)
+ if ((ret = ruleset_match_table_lookup(table, evp->helo, service)) < 0)
return -1;
return r->flag_smtp_helo < 0 ? !ret : ret;
@@ -169,15 +185,19 @@ ruleset_match_smtp_mail_from(struct rule *r, const struct envelope *evp)
int ret;
const char *key;
struct table *table;
+ enum table_service service = K_MAILADDR;
if (!r->flag_smtp_mail_from)
return 1;
+ if (r->flag_smtp_mail_from_regex)
+ service = K_REGEX;
+
if ((key = mailaddr_to_text(&evp->sender)) == NULL)
return -1;
table = table_find(env, r->table_smtp_mail_from, NULL);
- if ((ret = ruleset_match_table_lookup(table, key, K_MAILADDR)) < 0)
+ if ((ret = ruleset_match_table_lookup(table, key, service)) < 0)
return -1;
return r->flag_smtp_mail_from < 0 ? !ret : ret;
@@ -189,15 +209,19 @@ ruleset_match_smtp_rcpt_to(struct rule *r, const struct envelope *evp)
int ret;
const char *key;
struct table *table;
+ enum table_service service = K_MAILADDR;
if (!r->flag_smtp_rcpt_to)
return 1;
+ if (r->flag_smtp_rcpt_to_regex)
+ service = K_REGEX;
+
if ((key = mailaddr_to_text(&evp->dest)) == NULL)
return -1;
table = table_find(env, r->table_smtp_rcpt_to, NULL);
- if ((ret = ruleset_match_table_lookup(table, key, K_MAILADDR)) < 0)
+ if ((ret = ruleset_match_table_lookup(table, key, service)) < 0)
return -1;
return r->flag_smtp_rcpt_to < 0 ? !ret : ret;
diff --git a/usr.sbin/smtpd/smtpd.conf.5 b/usr.sbin/smtpd/smtpd.conf.5
index cb7762249f5..8736d3dbf6b 100644
--- a/usr.sbin/smtpd/smtpd.conf.5
+++ b/usr.sbin/smtpd/smtpd.conf.5
@@ -1,4 +1,4 @@
-.\" $OpenBSD: smtpd.conf.5,v 1.207 2018/12/12 20:21:04 jmc Exp $
+.\" $OpenBSD: smtpd.conf.5,v 1.208 2018/12/21 21:35:29 gilles Exp $
.\"
.\" Copyright (c) 2008 Janne Johansson <jj@openbsd.org>
.\" Copyright (c) 2009 Jacek Masiulaniec <jacekm@dobremiasto.net>
@@ -17,7 +17,7 @@
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.\"
-.Dd $Mdocdate: December 12 2018 $
+.Dd $Mdocdate: December 21 2018 $
.Dt SMTPD.CONF 5
.Os
.Sh NAME
@@ -485,6 +485,13 @@ Specify that session may address the string or list table
.Ar domain .
.It Xo
.Op Ic \&!
+.Cm for domain regex
+.Ar domain | Pf < Ar domain Ns >
+.Xc
+Specify that session may address the regex or regex table
+.Ar domain .
+.It Xo
+.Op Ic \&!
.Cm from any
.Xc
Specify that session may originate from any source.
@@ -508,6 +515,14 @@ Specify that session may only originate from the local enqueuer.
Specify that session may only originate from string or list table
.Ar address
which can be a specific address or a subnet expressed in CIDR-notation.
+.It Xo
+.Op Ic \&!
+.Cm from src regex
+.Ar address | Pf < Ar address Ns >
+.Xc
+Specify that session may only originate from regex or regex table
+.Ar address
+which can be a specific address or a subnet expressed in CIDR-notation.
.El
.Pp
In addition, the following transaction options:
@@ -526,6 +541,13 @@ Specify that session's HELO / EHLO should match the string or list table
.Ar helo-name .
.It Xo
.Op Ic \&!
+.Cm helo regex
+.Ar helo-name | Pf < Ar helo-name Ns >
+.Xc
+Specify that session's HELO / EHLO should match the regex or regex table
+.Ar helo-name .
+.It Xo
+.Op Ic \&!
.Cm mail\-from
.Ar sender | Pf < Ar sender Ns >
.Xc
@@ -533,6 +555,13 @@ Specify that transactions's MAIL FROM should match the string or list table
.Ar sender .
.It Xo
.Op Ic \&!
+.Cm mail\-from regex
+.Ar sender | Pf < Ar sender Ns >
+.Xc
+Specify that transactions's MAIL FROM should match the regex or regex table
+.Ar sender .
+.It Xo
+.Op Ic \&!
.Cm rcpt\-to
.Ar recipient | Pf < Ar recipient Ns >
.Xc
@@ -540,12 +569,26 @@ Specify that transaction's RCPT TO should match the string or list table
.Ar recipient .
.It Xo
.Op Ic \&!
+.Cm rcpt\-to regex
+.Ar recipient | Pf < Ar recipient Ns >
+.Xc
+Specify that transaction's RCPT TO should match the regex or regex table
+.Ar recipient .
+.It Xo
+.Op Ic \&!
.Cm tag Ar tag
.Xc
Matches transactions tagged with the given
.Ar tag .
.It Xo
.Op Ic \&!
+.Cm tag regex Ar tag
+.Xc
+Matches transactions tagged with the given
+.Ar tag
+regex .
+.It Xo
+.Op Ic \&!
.Cm tls
.Xc
Specify that transaction should take place in a TLS channel.
diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h
index 070979a7f23..d3c7b4d9d3b 100644
--- a/usr.sbin/smtpd/smtpd.h
+++ b/usr.sbin/smtpd/smtpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtpd.h,v 1.596 2018/12/21 17:04:46 gilles Exp $ */
+/* $OpenBSD: smtpd.h,v 1.597 2018/12/21 21:35:29 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
@@ -1203,12 +1203,22 @@ struct rule {
int8_t flag_for;
int8_t flag_from_socket;
+ int8_t flag_tag_regex;
+ int8_t flag_for_regex;
+ int8_t flag_from_regex;
+
int8_t flag_smtp_helo;
int8_t flag_smtp_starttls;
int8_t flag_smtp_auth;
int8_t flag_smtp_mail_from;
int8_t flag_smtp_rcpt_to;
+ int8_t flag_smtp_helo_regex;
+ int8_t flag_smtp_starttls_regex;
+ int8_t flag_smtp_auth_regex;
+ int8_t flag_smtp_mail_from_regex;
+ int8_t flag_smtp_rcpt_to_regex;
+
char *table_tag;
char *table_from;
diff --git a/usr.sbin/smtpd/table.c b/usr.sbin/smtpd/table.c
index 7577193d152..187cb0edefb 100644
--- a/usr.sbin/smtpd/table.c
+++ b/usr.sbin/smtpd/table.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: table.c,v 1.32 2018/11/02 13:45:59 gilles Exp $ */
+/* $OpenBSD: table.c,v 1.33 2018/12/21 21:35:29 gilles Exp $ */
/*
* Copyright (c) 2013 Eric Faurot <eric@openbsd.org>
@@ -463,8 +463,14 @@ int
table_regex_match(const char *string, const char *pattern)
{
regex_t preg;
+ int cflags = REG_EXTENDED|REG_NOSUB;
- if (regcomp(&preg, pattern, REG_EXTENDED|REG_NOSUB) != 0)
+ if (strncmp(pattern, "(?i)", 4) == 0) {
+ cflags |= REG_ICASE;
+ pattern += 4;
+ }
+
+ if (regcomp(&preg, pattern, cflags) != 0)
return (0);
if (regexec(&preg, string, 0, NULL, 0) != 0)