diff options
author | Gilles Chehade <gilles@cvs.openbsd.org> | 2018-12-21 21:35:30 +0000 |
---|---|---|
committer | Gilles Chehade <gilles@cvs.openbsd.org> | 2018-12-21 21:35:30 +0000 |
commit | 3e5a496dd5d27664c37c8038bf3ff08b81acda89 (patch) | |
tree | 6ed79f2857d7464935d7ed62ccbfc4efc7c81505 /usr.sbin | |
parent | 4014ecb37423fedc8d1ee85d5bc2fd411838c67d (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.y | 132 | ||||
-rw-r--r-- | usr.sbin/smtpd/ruleset.c | 38 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtpd.conf.5 | 47 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtpd.h | 12 | ||||
-rw-r--r-- | usr.sbin/smtpd/table.c | 10 |
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) |