diff options
author | Gilles Chehade <gilles@cvs.openbsd.org> | 2018-12-21 14:33:53 +0000 |
---|---|---|
committer | Gilles Chehade <gilles@cvs.openbsd.org> | 2018-12-21 14:33:53 +0000 |
commit | 094f3a27e7039a788aa328ab2800d14d8d0ba591 (patch) | |
tree | fbb0ba82b3e60515aa4ecf5265944d0c9502c704 /usr.sbin/smtpd/parse.y | |
parent | 1b811f60c0e491dd91800a159c62f7337d9b13b3 (diff) |
bring in new grammar for filters, allowing filter chains and plugging of
different filters & chains on different interfaces.
in this diff, proc filters are still disabled as they're missing on very
important piece of logic.
ok eric@
Diffstat (limited to 'usr.sbin/smtpd/parse.y')
-rw-r--r-- | usr.sbin/smtpd/parse.y | 207 |
1 files changed, 166 insertions, 41 deletions
diff --git a/usr.sbin/smtpd/parse.y b/usr.sbin/smtpd/parse.y index dbf8c21b634..bb437d34f15 100644 --- a/usr.sbin/smtpd/parse.y +++ b/usr.sbin/smtpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.237 2018/12/13 14:43:31 gilles Exp $ */ +/* $OpenBSD: parse.y,v 1.238 2018/12/21 14:33:52 gilles Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> @@ -106,7 +106,8 @@ static struct ca *sca; struct dispatcher *dispatcher; struct rule *rule; struct processor *processor; -struct filter_rule *filter_rule; +struct filter_config *filter_config; +/*static uint64_t last_dynproc_id = 1;*/ enum listen_options { LO_FAMILY = 0x000001, @@ -172,8 +173,8 @@ typedef struct { %} %token ACTION ALIAS ANY ARROW AUTH AUTH_OPTIONAL -%token BACKUP BOUNCE -%token CA CERT CHROOT CIPHERS COMMIT COMPRESSION CONNECT +%token BACKUP BOUNCE BUILTIN +%token CA CERT CHAIN CHROOT CIPHERS COMMIT COMPRESSION CONNECT %token CHECK_FCRDNS CHECK_RDNS CHECK_REGEX CHECK_TABLE %token DATA DATA_LINE DHE DISCONNECT DOMAIN %token EHLO ENABLE ENCRYPTION ERROR EXPAND_ONLY @@ -187,7 +188,7 @@ typedef struct { %token MAIL_FROM MAILDIR MASK_SRC MASQUERADE MATCH MAX_MESSAGE_SIZE MAX_DEFERRED MBOX MDA MTA MX %token NO_DSN NO_VERIFY NOOP %token ON -%token PKI PORT PROC +%token PKI PORT PROC PROC_EXEC %token QUEUE QUIT %token RCPT_TO RECIPIENT RECEIVEDAUTH RELAY REJECT REPORT REWRITE RSET %token SCHEDULER SENDER SENDERS SMTP SMTP_IN SMTP_OUT SMTPS SOCKET SRC SUB_ADDR_DELIM @@ -1116,38 +1117,38 @@ MATCH { filter_action_builtin: REJECT STRING { - filter_rule->reject = $2; + filter_config->reject = $2; } | DISCONNECT STRING { - filter_rule->disconnect = $2; + filter_config->disconnect = $2; } ; filter_phase_check_table: negation CHECK_TABLE tables { - filter_rule->not_table = $1 ? -1 : 1; - filter_rule->table = $3; + filter_config->not_table = $1 ? -1 : 1; + filter_config->table = $3; } ; filter_phase_check_regex: negation CHECK_REGEX tables { - filter_rule->not_regex = $1 ? -1 : 1; - filter_rule->regex = $3; + filter_config->not_regex = $1 ? -1 : 1; + filter_config->regex = $3; } ; filter_phase_check_fcrdns: negation CHECK_FCRDNS { - filter_rule->not_fcrdns = $1 ? -1 : 1; - filter_rule->fcrdns = 1; + filter_config->not_fcrdns = $1 ? -1 : 1; + filter_config->fcrdns = 1; } ; filter_phase_check_rdns: negation CHECK_RDNS { - filter_rule->not_rdns = $1 ? -1 : 1; - filter_rule->rdns = 1; + filter_config->not_rdns = $1 ? -1 : 1; + filter_config->rdns = 1; } ; @@ -1156,7 +1157,7 @@ filter_phase_check_table | filter_phase_check_regex | filter_phase_check_fcrdns filter_phase_connect: CONNECT { - filter_rule->phase = FILTER_CONNECTED; + filter_config->phase = FILTER_CONNECT; } filter_phase_connect_options filter_action_builtin ; @@ -1165,13 +1166,13 @@ filter_phase_check_table | filter_phase_check_regex | filter_phase_check_fcrdns filter_phase_helo: HELO { - filter_rule->phase = FILTER_HELO; + filter_config->phase = FILTER_HELO; } filter_phase_helo_options filter_action_builtin ; filter_phase_ehlo: EHLO { - filter_rule->phase = FILTER_EHLO; + filter_config->phase = FILTER_EHLO; } filter_phase_helo_options filter_action_builtin ; @@ -1180,7 +1181,7 @@ filter_phase_check_table | filter_phase_check_regex | filter_phase_check_fcrdns filter_phase_mail_from: MAIL_FROM { - filter_rule->phase = FILTER_MAIL_FROM; + filter_config->phase = FILTER_MAIL_FROM; } filter_phase_mail_from_options filter_action_builtin ; @@ -1189,47 +1190,48 @@ filter_phase_check_table | filter_phase_check_regex | filter_phase_check_fcrdns filter_phase_rcpt_to: RCPT_TO { - filter_rule->phase = FILTER_RCPT_TO; + filter_config->phase = FILTER_RCPT_TO; } filter_phase_rcpt_to_options filter_action_builtin ; filter_phase_data: DATA { - filter_rule->phase = FILTER_DATA; + filter_config->phase = FILTER_DATA; } filter_action_builtin ; filter_phase_data_line: DATA_LINE { - filter_rule->phase = FILTER_DATA_LINE; + filter_config->phase = FILTER_DATA_LINE; } filter_action_builtin ; filter_phase_quit: QUIT { - filter_rule->phase = FILTER_QUIT; + filter_config->phase = FILTER_QUIT; } filter_action_builtin ; filter_phase_rset: RSET { - filter_rule->phase = FILTER_RSET; + filter_config->phase = FILTER_RSET; } filter_action_builtin ; filter_phase_noop: NOOP { - filter_rule->phase = FILTER_NOOP; + filter_config->phase = FILTER_NOOP; } filter_action_builtin ; filter_phase_commit: COMMIT { - filter_rule->phase = FILTER_COMMIT; + filter_config->phase = FILTER_COMMIT; } filter_action_builtin ; + filter_phase: filter_phase_connect | filter_phase_helo @@ -1244,28 +1246,131 @@ filter_phase_connect | filter_phase_commit ; -filter: -FILTER SMTP_IN { - filter_rule = xcalloc(1, sizeof *filter_rule); -} filter_phase { - TAILQ_INSERT_TAIL(&conf->sc_filter_rules[filter_rule->phase], filter_rule, entry); - filter_rule = NULL; + +filterel: +STRING { + struct filter_config *fr; + size_t i; + + if ((fr = dict_get(conf->sc_filters_dict, $1)) == NULL) { + yyerror("no filter exist with that name: %s", $1); + free($1); + YYERROR; + } + if (fr->filter_type == FILTER_TYPE_CHAIN) { + yyerror("no filter chain allowed within a filter chain: %s", $1); + free($1); + YYERROR; + } + + for (i = 0; i < filter_config->chain_size; i++) { + if (strcmp(filter_config->chain[i], $1) == 0) { + yyerror("no filter allowed twice within a filter chain: %s", $1); + free($1); + YYERROR; + } + } + + if (fr->proc) { + if (dict_check(&filter_config->chain_procs, fr->proc)) { + yyerror("no proc allowed twice within a filter chain: %s", fr->proc); + free($1); + YYERROR; + } + dict_set(&filter_config->chain_procs, fr->proc, NULL); + } + + filter_config->chain_size += 1; + filter_config->chain = reallocarray(filter_config->chain, filter_config->chain_size, sizeof(char *)); + if (filter_config->chain == NULL) + err(1, NULL); + filter_config->chain[filter_config->chain_size - 1] = $1; } -| FILTER SMTP_IN ON STRING { +; + +filter_list: +filterel +| filterel comma filter_list +; + +filter: +/* +FILTER STRING PROC STRING { + if (dict_get(conf->sc_filters_dict, $2)) { + yyerror("filter already exists with that name: %s", $2); + free($2); + free($4); + YYERROR; + } if (! dict_get(conf->sc_processors_dict, $4)) { yyerror("no processor exist with that name: %s", $4); free($4); YYERROR; } - dict_set(conf->sc_smtp_reporters_dict, $4, (void *)~0); + + filter_config = xcalloc(1, sizeof *filter_config); + filter_config->filter_type = FILTER_TYPE_PROC; + filter_config->name = $2; + filter_config->proc = $4; + dict_set(conf->sc_filters_dict, $2, filter_config); + filter_config = NULL; } -| FILTER SMTP_OUT ON STRING { - if (! dict_get(conf->sc_processors_dict, $4)) { - yyerror("no processor exist with that name: %s", $4); +| +FILTER STRING PROC_EXEC STRING { + char buffer[128]; + + do { + (void)snprintf(buffer, sizeof buffer, "<dynproc:%016"PRIx64">", last_dynproc_id++); + } while (dict_check(conf->sc_processors_dict, buffer)); + + if (dict_get(conf->sc_filters_dict, $2)) { + yyerror("filter already exists with that name: %s", $2); + free($2); free($4); YYERROR; } - dict_set(conf->sc_mta_reporters_dict, $4, (void *)~0); + + processor = xcalloc(1, sizeof *processor); + processor->command = $4; + + filter_config = xcalloc(1, sizeof *filter_config); + filter_config->filter_type = FILTER_TYPE_PROC; + filter_config->name = $2; + filter_config->proc = xstrdup(buffer); + dict_set(conf->sc_filters_dict, $2, filter_config); +} proc_params { + dict_set(conf->sc_processors_dict, filter_config->proc, processor); + processor = NULL; + filter_config = NULL; +} +| +*/ +FILTER STRING BUILTIN { + if (dict_get(conf->sc_filters_dict, $2)) { + yyerror("filter already exists with that name: %s", $2); + free($2); + YYERROR; + } + filter_config = xcalloc(1, sizeof *filter_config); + filter_config->name = $2; + filter_config->filter_type = FILTER_TYPE_BUILTIN; + dict_set(conf->sc_filters_dict, $2, filter_config); +} filter_phase { + filter_config = NULL; +} +| +FILTER STRING CHAIN { + if (dict_get(conf->sc_filters_dict, $2)) { + yyerror("filter already exists with that name: %s", $2); + free($2); + YYERROR; + } + filter_config = xcalloc(1, sizeof *filter_config); + filter_config->filter_type = FILTER_TYPE_CHAIN; + dict_init(&filter_config->chain_procs); +} '{' filter_list '}' { + dict_set(conf->sc_filters_dict, $2, filter_config); + filter_config = NULL; } ; @@ -1409,12 +1514,19 @@ limits_scheduler: opt_limit_scheduler limits_scheduler ; -opt_sock_listen : FILTER { +opt_sock_listen : FILTER STRING { if (listen_opts.options & LO_FILTER) { yyerror("filter already specified"); + free($2); + YYERROR; + } + if (dict_get(conf->sc_filters_dict, $2) == NULL) { + yyerror("no filter exist with that name: %s", $2); + free($2); YYERROR; } listen_opts.options |= LO_FILTER; + listen_opts.filtername = $2; } | MASK_SRC { if (config_lo_mask_source(&listen_opts)) { @@ -1470,12 +1582,18 @@ opt_if_listen : INET4 { } listen_opts.port = $2; } - | FILTER { + | FILTER STRING { if (listen_opts.options & LO_FILTER) { yyerror("filter already specified"); YYERROR; } + if (dict_get(conf->sc_filters_dict, $2) == NULL) { + yyerror("no filter exist with that name: %s", $2); + free($2); + YYERROR; + } listen_opts.options |= LO_FILTER; + listen_opts.filtername = $2; } | SMTPS { if (listen_opts.options & LO_SSL) { @@ -1818,8 +1936,10 @@ lookup(char *s) { "auth-optional", AUTH_OPTIONAL }, { "backup", BACKUP }, { "bounce", BOUNCE }, + { "builtin", BUILTIN }, { "ca", CA }, { "cert", CERT }, + { "chain", CHAIN }, { "check-fcrdns", CHECK_FCRDNS }, { "check-rdns", CHECK_RDNS }, { "check-regex", CHECK_REGEX }, @@ -1874,6 +1994,7 @@ lookup(char *s) { "pki", PKI }, { "port", PORT }, { "proc", PROC }, + { "proc-exec", PROC_EXEC }, { "queue", QUEUE }, { "quit", QUIT }, { "rcpt-to", RCPT_TO }, @@ -2454,8 +2575,12 @@ config_listener(struct listener *h, struct listen_opts *lo) if (lo->hostname == NULL) lo->hostname = conf->sc_hostname; - if (lo->options & LO_FILTER) + if (lo->options & LO_FILTER) { h->flags |= F_FILTERED; + (void)strlcpy(h->filter_name, + lo->filtername, + sizeof(h->filter_name)); + } h->pki_name[0] = '\0'; |