mirror of
https://github.com/donl/rmilter.git
synced 2026-06-30 06:12:17 -06:00
Now whitelists are hash tables based. Update documentation. Ip field now may handle IPv6 addresses. Update to 1.5.41.
1635 lines
30 KiB
Text
1635 lines
30 KiB
Text
/*
|
|
* Copyright (c) 2007-2012, Vsevolod Stakhov
|
|
* All rights reserved.
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
* Redistributions of source code must retain the above copyright notice, this
|
|
* list of conditions and the following disclaimer. Redistributions in binary form
|
|
* must reproduce the above copyright notice, this list of conditions and the
|
|
* following disclaimer in the documentation and/or other materials provided with
|
|
* the distribution. Neither the name of the author nor the names of its
|
|
* contributors may be used to endorse or promote products derived from this
|
|
* software without specific prior written permission.
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
%{
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/queue.h>
|
|
#include <syslog.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <sys/mman.h>
|
|
#include <fcntl.h>
|
|
|
|
#include "pcre.h"
|
|
#include "cfg_file.h"
|
|
|
|
#define YYDEBUG 0
|
|
|
|
extern struct config_file *cfg;
|
|
extern int yylineno;
|
|
extern char *yytext;
|
|
|
|
struct condl *cur_conditions;
|
|
struct dkim_domain_entry *cur_domain;
|
|
uint8_t cur_flags = 0;
|
|
|
|
%}
|
|
%union
|
|
{
|
|
char *string;
|
|
struct condition *cond;
|
|
struct action *action;
|
|
size_t limit;
|
|
bucket_t bucket;
|
|
char flag;
|
|
unsigned int seconds;
|
|
unsigned int number;
|
|
double frac;
|
|
}
|
|
|
|
%token ERROR STRING QUOTEDSTRING FLAG FLOAT
|
|
%token ACCEPT REJECTL TEMPFAIL DISCARD QUARANTINE
|
|
%token CONNECT HELO ENVFROM ENVRCPT HEADER MACRO BODY
|
|
%token AND OR NOT
|
|
%token TEMPDIR LOGFILE PIDFILE RULE CLAMAV SERVERS ERROR_TIME DEAD_TIME MAXERRORS CONNECT_TIMEOUT PORT_TIMEOUT RESULTS_TIMEOUT SPF DCC
|
|
%token FILENAME REGEXP QUOTE SEMICOLON OBRACE EBRACE COMMA EQSIGN
|
|
%token BINDSOCK SOCKCRED DOMAIN IPADDR IPNETWORK HOSTPORT NUMBER GREYLISTING WHITELIST TIMEOUT EXPIRE EXPIRE_WHITE
|
|
%token MAXSIZE SIZELIMIT SECONDS BUCKET USEDCC MEMCACHED PROTOCOL AWL_ENABLE AWL_POOL AWL_TTL AWL_HITS SERVERS_WHITE SERVERS_LIMITS SERVERS_GREY
|
|
%token LIMITS LIMIT_TO LIMIT_TO_IP LIMIT_TO_IP_FROM LIMIT_WHITELIST LIMIT_WHITELIST_RCPT LIMIT_BOUNCE_ADDRS LIMIT_BOUNCE_TO LIMIT_BOUNCE_TO_IP
|
|
%token SPAMD REJECT_MESSAGE SERVERS_ID ID_PREFIX GREY_PREFIX WHITE_PREFIX RSPAMD_METRIC ALSO_CHECK DIFF_DIR CHECK_SYMBOLS SYMBOLS_DIR
|
|
%token BEANSTALK ID_REGEXP LIFETIME COPY_SERVER GREYLISTED_MESSAGE SPAMD_SOFT_FAIL
|
|
%token SEND_BEANSTALK_COPY SEND_BEANSTALK_HEADERS SEND_BEANSTALK_SPAM SPAM_SERVER STRICT_AUTH
|
|
%token TRACE_SYMBOL TRACE_ADDR WHITELIST_FROM SPAM_HEADER SPAMD_GREYLIST EXTENDED_SPAM_HEADERS
|
|
%token DKIM_SECTION DKIM_KEY DKIM_DOMAIN DKIM_SELECTOR DKIM_HEADER_CANON DKIM_BODY_CANON
|
|
%token DKIM_SIGN_ALG DKIM_RELAXED DKIM_SIMPLE DKIM_SHA1 DKIM_SHA256 COPY_PROBABILITY
|
|
|
|
%type <string> STRING
|
|
%type <string> QUOTEDSTRING
|
|
%type <string> FILENAME
|
|
%type <string> REGEXP
|
|
%type <string> SOCKCRED
|
|
%type <string> IPADDR IPNETWORK
|
|
%type <string> HOSTPORT
|
|
%type <string> ip_net memcached_hosts beanstalk_hosts clamav_addr spamd_addr
|
|
%type <cond> expr_l expr term
|
|
%type <action> action
|
|
%type <string> DOMAIN
|
|
%type <limit> SIZELIMIT
|
|
%type <flag> FLAG
|
|
%type <bucket> BUCKET;
|
|
%type <seconds> SECONDS;
|
|
%type <number> NUMBER;
|
|
%type <frac> FLOAT;
|
|
%%
|
|
|
|
file : /* empty */
|
|
| file command SEMICOLON { }
|
|
;
|
|
|
|
command :
|
|
tempdir
|
|
| strictauth
|
|
| pidfile
|
|
| rule
|
|
| clamav
|
|
| spamd
|
|
| spf
|
|
| bindsock
|
|
| maxsize
|
|
| usedcc
|
|
| memcached
|
|
| beanstalk
|
|
| limits
|
|
| greylisting
|
|
| whitelist
|
|
| dkim
|
|
;
|
|
|
|
tempdir :
|
|
TEMPDIR EQSIGN FILENAME {
|
|
struct stat st;
|
|
|
|
if (stat ($3, &st) == -1) {
|
|
yyerror ("yyparse: cannot stat directory \"%s\": %s", $3, strerror (errno));
|
|
YYERROR;
|
|
}
|
|
if (!S_ISDIR (st.st_mode)) {
|
|
yyerror ("yyparse: \"%s\" is not a directory", $3);
|
|
YYERROR;
|
|
}
|
|
|
|
cfg->temp_dir = $3;
|
|
}
|
|
;
|
|
|
|
pidfile :
|
|
PIDFILE EQSIGN FILENAME {
|
|
cfg->pid_file = $3;
|
|
}
|
|
;
|
|
|
|
strictauth:
|
|
STRICT_AUTH EQSIGN FLAG {
|
|
cfg->strict_auth = $3;
|
|
}
|
|
;
|
|
|
|
rule :
|
|
RULE OBRACE rulebody EBRACE
|
|
;
|
|
|
|
rulebody :
|
|
action SEMICOLON expr_l {
|
|
struct rule *cur_rule;
|
|
cur_rule = (struct rule *) malloc (sizeof (struct rule));
|
|
if (cur_rule == NULL) {
|
|
yyerror ("yyparse: malloc: %s", strerror (errno));
|
|
YYERROR;
|
|
}
|
|
|
|
cur_rule->act = $1;
|
|
cur_rule->conditions = cur_conditions;
|
|
cur_rule->flags = cur_flags;
|
|
cur_flags = 0;
|
|
LIST_INSERT_HEAD (&cfg->rules, cur_rule, next);
|
|
}
|
|
;
|
|
|
|
action :
|
|
REJECTL QUOTEDSTRING {
|
|
$$ = create_action(ACTION_REJECT, $2);
|
|
if ($$ == NULL) {
|
|
yyerror ("yyparse: create_action");
|
|
YYERROR;
|
|
}
|
|
free($2);
|
|
}
|
|
| TEMPFAIL QUOTEDSTRING {
|
|
$$ = create_action(ACTION_TEMPFAIL, $2);
|
|
if ($$ == NULL) {
|
|
yyerror ("yyparse: create_action");
|
|
YYERROR;
|
|
}
|
|
free($2);
|
|
}
|
|
| QUARANTINE QUOTEDSTRING {
|
|
$$ = create_action(ACTION_QUARANTINE, $2);
|
|
if ($$ == NULL) {
|
|
yyerror ("yyparse: create_action");
|
|
YYERROR;
|
|
}
|
|
free($2);
|
|
}
|
|
| DISCARD {
|
|
$$ = create_action(ACTION_DISCARD, "");
|
|
if ($$ == NULL) {
|
|
yyerror ("yyparse: create_action");
|
|
YYERROR;
|
|
}
|
|
}
|
|
| ACCEPT {
|
|
$$ = create_action(ACTION_ACCEPT, "");
|
|
if ($$ == NULL) {
|
|
yyerror ("yyparse: create_action");
|
|
YYERROR;
|
|
}
|
|
}
|
|
;
|
|
|
|
expr_l :
|
|
expr SEMICOLON {
|
|
cur_conditions = (struct condl *)malloc (sizeof (struct condl));
|
|
if (cur_conditions == NULL) {
|
|
yyerror ("yyparse: malloc: %s", strerror (errno));
|
|
YYERROR;
|
|
}
|
|
LIST_INIT (cur_conditions);
|
|
$$ = $1;
|
|
if ($$ == NULL) {
|
|
yyerror ("yyparse: malloc: %s", strerror(errno));
|
|
YYERROR;
|
|
}
|
|
LIST_INSERT_HEAD (cur_conditions, $$, next);
|
|
}
|
|
| expr_l expr SEMICOLON {
|
|
$$ = $2;
|
|
if ($$ == NULL) {
|
|
yyerror ("yyparse: malloc: %s", strerror(errno));
|
|
YYERROR;
|
|
}
|
|
LIST_INSERT_HEAD (cur_conditions, $$, next);
|
|
}
|
|
;
|
|
|
|
expr :
|
|
term {
|
|
$$ = $1;
|
|
}
|
|
| NOT term {
|
|
struct condition *tmp;
|
|
tmp = $2;
|
|
if (tmp != NULL) {
|
|
tmp->args[0].not = 1;
|
|
tmp->args[1].not = 1;
|
|
}
|
|
$$ = tmp;
|
|
}
|
|
;
|
|
|
|
term :
|
|
CONNECT REGEXP REGEXP {
|
|
$$ = create_cond(COND_CONNECT, $2, $3);
|
|
if ($$ == NULL) {
|
|
yyerror ("yyparse: malloc: %s", strerror(errno));
|
|
YYERROR;
|
|
}
|
|
cur_flags |= COND_CONNECT_FLAG;
|
|
free($2);
|
|
free($3);
|
|
}
|
|
| HELO REGEXP {
|
|
$$ = create_cond(COND_HELO, $2, NULL);
|
|
if ($$ == NULL) {
|
|
yyerror ("yyparse: malloc: %s", strerror(errno));
|
|
YYERROR;
|
|
}
|
|
cur_flags |= COND_HELO_FLAG;
|
|
free($2);
|
|
}
|
|
| ENVFROM REGEXP {
|
|
$$ = create_cond(COND_ENVFROM, $2, NULL);
|
|
if ($$ == NULL) {
|
|
yyerror ("yyparse: malloc: %s", strerror(errno));
|
|
YYERROR;
|
|
}
|
|
cur_flags |= COND_ENVFROM_FLAG;
|
|
free($2);
|
|
}
|
|
| ENVRCPT REGEXP {
|
|
$$ = create_cond(COND_ENVRCPT, $2, NULL);
|
|
if ($$ == NULL) {
|
|
yyerror ("yyparse: malloc: %s", strerror(errno));
|
|
YYERROR;
|
|
}
|
|
cur_flags |= COND_ENVRCPT_FLAG;
|
|
free($2);
|
|
}
|
|
| HEADER REGEXP REGEXP {
|
|
$$ = create_cond(COND_HEADER, $2, $3);
|
|
if ($$ == NULL) {
|
|
yyerror ("yyparse: malloc: %s", strerror(errno));
|
|
YYERROR;
|
|
}
|
|
cur_flags |= COND_HEADER_FLAG;
|
|
free($2);
|
|
free($3);
|
|
}
|
|
| BODY REGEXP {
|
|
$$ = create_cond(COND_BODY, $2, NULL);
|
|
if ($$ == NULL) {
|
|
yyerror ("yyparse: malloc: %s", strerror(errno));
|
|
YYERROR;
|
|
}
|
|
cur_flags |= COND_BODY_FLAG;
|
|
free($2);
|
|
}
|
|
;
|
|
|
|
clamav:
|
|
CLAMAV OBRACE clamavbody EBRACE
|
|
;
|
|
|
|
clamavbody:
|
|
clamavcmd SEMICOLON
|
|
| clamavbody clamavcmd SEMICOLON
|
|
;
|
|
|
|
clamavcmd:
|
|
clamav_servers
|
|
| clamav_connect_timeout
|
|
| clamav_port_timeout
|
|
| clamav_results_timeout
|
|
| clamav_error_time
|
|
| clamav_dead_time
|
|
| clamav_maxerrors
|
|
;
|
|
|
|
clamav_servers:
|
|
SERVERS EQSIGN clamav_server
|
|
;
|
|
|
|
clamav_server:
|
|
clamav_params
|
|
| clamav_server COMMA clamav_params
|
|
;
|
|
|
|
clamav_params:
|
|
clamav_addr {
|
|
if (!add_clamav_server (cfg, $1)) {
|
|
yyerror ("yyparse: add_clamav_server");
|
|
YYERROR;
|
|
}
|
|
free ($1);
|
|
}
|
|
;
|
|
clamav_addr:
|
|
STRING {
|
|
$$ = $1;
|
|
}
|
|
| IPADDR{
|
|
$$ = $1;
|
|
}
|
|
| DOMAIN {
|
|
$$ = $1;
|
|
}
|
|
| HOSTPORT {
|
|
$$ = $1;
|
|
}
|
|
| FILENAME {
|
|
$$ = $1;
|
|
}
|
|
;
|
|
clamav_error_time:
|
|
ERROR_TIME EQSIGN NUMBER {
|
|
cfg->clamav_error_time = $3;
|
|
}
|
|
;
|
|
clamav_dead_time:
|
|
DEAD_TIME EQSIGN NUMBER {
|
|
cfg->clamav_dead_time = $3;
|
|
}
|
|
;
|
|
clamav_maxerrors:
|
|
MAXERRORS EQSIGN NUMBER {
|
|
cfg->clamav_maxerrors = $3;
|
|
}
|
|
;
|
|
clamav_connect_timeout:
|
|
CONNECT_TIMEOUT EQSIGN SECONDS {
|
|
cfg->clamav_connect_timeout = $3;
|
|
}
|
|
;
|
|
clamav_port_timeout:
|
|
PORT_TIMEOUT EQSIGN SECONDS {
|
|
cfg->clamav_port_timeout = $3;
|
|
}
|
|
;
|
|
clamav_results_timeout:
|
|
RESULTS_TIMEOUT EQSIGN SECONDS {
|
|
cfg->clamav_results_timeout = $3;
|
|
}
|
|
;
|
|
|
|
spamd:
|
|
SPAMD OBRACE spamdbody EBRACE
|
|
;
|
|
|
|
spamdbody:
|
|
spamdcmd SEMICOLON
|
|
| spamdbody spamdcmd SEMICOLON
|
|
;
|
|
|
|
spamdcmd:
|
|
spamd_servers
|
|
| spamd_connect_timeout
|
|
| spamd_results_timeout
|
|
| spamd_error_time
|
|
| spamd_dead_time
|
|
| spamd_maxerrors
|
|
| spamd_reject_message
|
|
| spamd_whitelist
|
|
| extra_spamd_servers
|
|
| spamd_rspamd_metric
|
|
| diff_dir
|
|
| symbols_dir
|
|
| check_symbols
|
|
| spamd_soft_fail
|
|
| trace_symbol
|
|
| trace_addr
|
|
| spamd_spam_header
|
|
| spamd_greylist
|
|
| extended_spam_headers
|
|
;
|
|
|
|
diff_dir :
|
|
DIFF_DIR EQSIGN FILENAME {
|
|
struct stat st;
|
|
|
|
if (stat ($3, &st) == -1) {
|
|
yyerror ("yyparse: cannot stat directory \"%s\": %s", $3, strerror (errno));
|
|
YYERROR;
|
|
}
|
|
if (!S_ISDIR (st.st_mode)) {
|
|
yyerror ("yyparse: \"%s\" is not a directory", $3);
|
|
YYERROR;
|
|
}
|
|
|
|
cfg->diff_dir = $3;
|
|
}
|
|
;
|
|
symbols_dir:
|
|
SYMBOLS_DIR EQSIGN FILENAME {
|
|
struct stat st;
|
|
|
|
if (stat ($3, &st) == -1) {
|
|
yyerror ("yyparse: cannot stat directory \"%s\": %s", $3, strerror (errno));
|
|
YYERROR;
|
|
}
|
|
if (!S_ISDIR (st.st_mode)) {
|
|
yyerror ("yyparse: \"%s\" is not a directory", $3);
|
|
YYERROR;
|
|
}
|
|
|
|
cfg->symbols_dir = $3;
|
|
}
|
|
;
|
|
|
|
check_symbols:
|
|
CHECK_SYMBOLS EQSIGN QUOTEDSTRING {
|
|
size_t len = strlen ($3);
|
|
char *c = $3;
|
|
|
|
/* Trim quotes */
|
|
if (*c == '"') {
|
|
c++;
|
|
len--;
|
|
}
|
|
if (c[len - 1] == '"') {
|
|
len--;
|
|
}
|
|
|
|
if (cfg->check_symbols) {
|
|
free (cfg->check_symbols);
|
|
}
|
|
cfg->check_symbols = (char *)malloc (len + 1);
|
|
if (!cfg->check_symbols) {
|
|
yyerror ("yyparse: malloc failed");
|
|
YYERROR;
|
|
}
|
|
strlcpy (cfg->check_symbols, c, len + 1);
|
|
|
|
free ($3);
|
|
}
|
|
;
|
|
|
|
|
|
spamd_servers:
|
|
SERVERS EQSIGN spamd_server
|
|
;
|
|
|
|
spamd_server:
|
|
spamd_params
|
|
| spamd_server COMMA spamd_params
|
|
;
|
|
|
|
spamd_params:
|
|
spamd_addr {
|
|
if (!add_spamd_server (cfg, $1, 0)) {
|
|
yyerror ("yyparse: add_spamd_server");
|
|
YYERROR;
|
|
}
|
|
free ($1);
|
|
}
|
|
;
|
|
|
|
extra_spamd_servers:
|
|
ALSO_CHECK EQSIGN extra_spamd_server
|
|
;
|
|
|
|
extra_spamd_server:
|
|
extra_spamd_params
|
|
| extra_spamd_server COMMA extra_spamd_params
|
|
;
|
|
|
|
extra_spamd_params:
|
|
spamd_addr {
|
|
if (!add_spamd_server (cfg, $1, 1)) {
|
|
yyerror ("yyparse: add_spamd_server");
|
|
YYERROR;
|
|
}
|
|
free ($1);
|
|
}
|
|
;
|
|
|
|
spamd_addr:
|
|
STRING {
|
|
$$ = $1;
|
|
}
|
|
| IPADDR{
|
|
$$ = $1;
|
|
}
|
|
| DOMAIN {
|
|
$$ = $1;
|
|
}
|
|
| HOSTPORT {
|
|
$$ = $1;
|
|
}
|
|
| FILENAME {
|
|
$$ = $1;
|
|
}
|
|
;
|
|
spamd_error_time:
|
|
ERROR_TIME EQSIGN NUMBER {
|
|
cfg->spamd_error_time = $3;
|
|
}
|
|
;
|
|
spamd_dead_time:
|
|
DEAD_TIME EQSIGN NUMBER {
|
|
cfg->spamd_dead_time = $3;
|
|
}
|
|
;
|
|
spamd_maxerrors:
|
|
MAXERRORS EQSIGN NUMBER {
|
|
cfg->spamd_maxerrors = $3;
|
|
}
|
|
;
|
|
spamd_connect_timeout:
|
|
CONNECT_TIMEOUT EQSIGN SECONDS {
|
|
cfg->spamd_connect_timeout = $3;
|
|
}
|
|
;
|
|
spamd_results_timeout:
|
|
RESULTS_TIMEOUT EQSIGN SECONDS {
|
|
cfg->spamd_results_timeout = $3;
|
|
}
|
|
;
|
|
spamd_reject_message:
|
|
REJECT_MESSAGE EQSIGN QUOTEDSTRING {
|
|
size_t len = strlen ($3);
|
|
char *c = $3;
|
|
|
|
/* Trim quotes */
|
|
if (*c == '"') {
|
|
c++;
|
|
len--;
|
|
}
|
|
if (c[len - 1] == '"') {
|
|
len--;
|
|
}
|
|
|
|
if (cfg->spamd_reject_message) {
|
|
free (cfg->spamd_reject_message);
|
|
}
|
|
cfg->spamd_reject_message = (char *)malloc (len + 1);
|
|
if (!cfg->spamd_reject_message) {
|
|
yyerror ("yyparse: malloc failed");
|
|
YYERROR;
|
|
}
|
|
strlcpy (cfg->spamd_reject_message, c, len + 1);
|
|
|
|
free ($3);
|
|
}
|
|
;
|
|
spamd_whitelist:
|
|
WHITELIST EQSIGN spamd_ip_list
|
|
;
|
|
|
|
spamd_ip_list:
|
|
spamd_ip
|
|
| spamd_ip_list COMMA spamd_ip
|
|
;
|
|
|
|
spamd_ip:
|
|
ip_net {
|
|
if (add_ip_radix (cfg->spamd_whitelist, $1) == 0) {
|
|
YYERROR;
|
|
}
|
|
}
|
|
;
|
|
|
|
spamd_rspamd_metric:
|
|
RSPAMD_METRIC EQSIGN QUOTEDSTRING {
|
|
size_t len = strlen ($3);
|
|
char *c = $3;
|
|
|
|
/* Trim quotes */
|
|
if (*c == '"') {
|
|
c++;
|
|
len--;
|
|
}
|
|
if (c[len - 1] == '"') {
|
|
len--;
|
|
}
|
|
|
|
if (cfg->rspamd_metric) {
|
|
free (cfg->rspamd_metric);
|
|
}
|
|
cfg->rspamd_metric = (char *)malloc (len + 1);
|
|
if (!cfg->rspamd_metric) {
|
|
yyerror ("yyparse: malloc failed");
|
|
YYERROR;
|
|
}
|
|
strlcpy (cfg->rspamd_metric, c, len + 1);
|
|
|
|
free ($3);
|
|
}
|
|
;
|
|
|
|
spamd_soft_fail:
|
|
SPAMD_SOFT_FAIL EQSIGN FLAG {
|
|
if ($3) {
|
|
cfg->spamd_soft_fail = 1;
|
|
}
|
|
}
|
|
;
|
|
|
|
extended_spam_headers:
|
|
EXTENDED_SPAM_HEADERS EQSIGN FLAG {
|
|
if ($3) {
|
|
cfg->extended_spam_headers = 1;
|
|
}
|
|
}
|
|
;
|
|
|
|
spamd_greylist:
|
|
SPAMD_GREYLIST EQSIGN FLAG {
|
|
if ($3) {
|
|
cfg->spamd_greylist = 1;
|
|
}
|
|
}
|
|
;
|
|
|
|
spamd_spam_header:
|
|
SPAM_HEADER EQSIGN QUOTEDSTRING {
|
|
if ($3) {
|
|
size_t len = strlen ($3);
|
|
char *c = $3;
|
|
|
|
/* Trim quotes */
|
|
if (*c == '"') {
|
|
c++;
|
|
len--;
|
|
}
|
|
if (c[len - 1] == '"') {
|
|
len--;
|
|
}
|
|
|
|
if (cfg->spam_header) {
|
|
free (cfg->spam_header);
|
|
}
|
|
cfg->spam_header = (char *)malloc (len + 1);
|
|
if (!cfg->spam_header) {
|
|
yyerror ("yyparse: malloc failed");
|
|
YYERROR;
|
|
}
|
|
strlcpy (cfg->spam_header, c, len + 1);
|
|
|
|
free ($3);
|
|
}
|
|
}
|
|
;
|
|
|
|
trace_symbol:
|
|
TRACE_SYMBOL EQSIGN QUOTEDSTRING {
|
|
size_t len = strlen ($3);
|
|
char *c = $3;
|
|
|
|
/* Trim quotes */
|
|
if (*c == '"') {
|
|
c++;
|
|
len--;
|
|
}
|
|
if (c[len - 1] == '"') {
|
|
len--;
|
|
}
|
|
|
|
if (cfg->trace_symbol) {
|
|
free (cfg->trace_symbol);
|
|
}
|
|
cfg->trace_symbol = (char *)malloc (len + 1);
|
|
if (!cfg->trace_symbol) {
|
|
yyerror ("yyparse: malloc failed");
|
|
YYERROR;
|
|
}
|
|
strlcpy (cfg->trace_symbol, c, len + 1);
|
|
|
|
free ($3);
|
|
|
|
}
|
|
;
|
|
|
|
trace_addr:
|
|
TRACE_ADDR EQSIGN QUOTEDSTRING {
|
|
size_t len = strlen ($3);
|
|
char *c = $3;
|
|
|
|
/* Trim quotes */
|
|
if (*c == '"') {
|
|
c++;
|
|
len--;
|
|
}
|
|
if (c[len - 1] == '"') {
|
|
len--;
|
|
}
|
|
|
|
if (cfg->trace_addr) {
|
|
free (cfg->trace_addr);
|
|
}
|
|
cfg->trace_addr = (char *)malloc (len + 1);
|
|
if (!cfg->trace_addr) {
|
|
yyerror ("yyparse: malloc failed");
|
|
YYERROR;
|
|
}
|
|
strlcpy (cfg->trace_addr, c, len + 1);
|
|
|
|
free ($3);
|
|
|
|
}
|
|
;
|
|
|
|
|
|
spf:
|
|
SPF EQSIGN spf_params
|
|
;
|
|
spf_params:
|
|
spf_domain
|
|
| spf_params COMMA spf_domain
|
|
;
|
|
|
|
spf_domain:
|
|
DOMAIN {
|
|
if (!add_spf_domain (cfg, $1)) {
|
|
yyerror ("yyparse: add_spf_domain");
|
|
YYERROR;
|
|
}
|
|
}
|
|
| STRING {
|
|
if (!add_spf_domain (cfg, $1)) {
|
|
yyerror ("yyparse: add_spf_domain");
|
|
YYERROR;
|
|
}
|
|
}
|
|
;
|
|
|
|
bindsock:
|
|
BINDSOCK EQSIGN SOCKCRED {
|
|
cfg->sock_cred = $3;
|
|
}
|
|
;
|
|
|
|
maxsize:
|
|
MAXSIZE EQSIGN SIZELIMIT {
|
|
cfg->sizelimit = $3;
|
|
}
|
|
| MAXSIZE EQSIGN NUMBER {
|
|
cfg->sizelimit = $3;
|
|
}
|
|
;
|
|
usedcc:
|
|
USEDCC EQSIGN FLAG {
|
|
if ($3 == -1) {
|
|
yyerror ("yyparse: parse flag");
|
|
YYERROR;
|
|
}
|
|
cfg->use_dcc = $3;
|
|
}
|
|
;
|
|
|
|
greylisting:
|
|
GREYLISTING OBRACE greylistingbody EBRACE
|
|
;
|
|
|
|
greylistingbody:
|
|
greylistingcmd SEMICOLON
|
|
| greylistingbody greylistingcmd SEMICOLON
|
|
;
|
|
|
|
greylistingcmd:
|
|
greylisting_whitelist
|
|
| greylisting_timeout
|
|
| greylisting_expire
|
|
| greylisting_whitelist_expire
|
|
| greylisted_message
|
|
| awl_enable
|
|
| awl_hits
|
|
| awl_pool
|
|
| awl_ttl
|
|
;
|
|
|
|
greylisting_timeout:
|
|
TIMEOUT EQSIGN SECONDS {
|
|
/* This value is in seconds, not in milliseconds */
|
|
cfg->greylisting_timeout = $3 / 1000;
|
|
}
|
|
;
|
|
|
|
greylisting_expire:
|
|
EXPIRE EQSIGN SECONDS {
|
|
/* This value is in seconds, not in milliseconds */
|
|
cfg->greylisting_expire = $3 / 1000;
|
|
}
|
|
;
|
|
|
|
greylisting_whitelist_expire:
|
|
EXPIRE_WHITE EQSIGN SECONDS {
|
|
/* This value is in seconds, not in milliseconds */
|
|
cfg->whitelisting_expire = $3 / 1000;
|
|
}
|
|
;
|
|
|
|
greylisting_whitelist:
|
|
WHITELIST EQSIGN greylisting_ip_list
|
|
;
|
|
|
|
greylisting_ip_list:
|
|
greylisting_ip
|
|
| greylisting_ip_list COMMA greylisting_ip
|
|
;
|
|
|
|
greylisting_ip:
|
|
ip_net {
|
|
if (add_ip_radix (cfg->grey_whitelist_tree, $1) == 0) {
|
|
YYERROR;
|
|
}
|
|
}
|
|
;
|
|
|
|
awl_enable:
|
|
AWL_ENABLE EQSIGN FLAG {
|
|
if ($3 == -1) {
|
|
yyerror ("yyparse: cannot parse flag");
|
|
YYERROR;
|
|
}
|
|
cfg->awl_enable = $3;
|
|
}
|
|
;
|
|
awl_hits:
|
|
AWL_HITS EQSIGN NUMBER {
|
|
cfg->awl_max_hits = $3;
|
|
}
|
|
;
|
|
|
|
awl_pool:
|
|
AWL_POOL EQSIGN SIZELIMIT {
|
|
cfg->awl_pool_size = $3;
|
|
}
|
|
;
|
|
|
|
awl_ttl:
|
|
AWL_TTL EQSIGN SECONDS {
|
|
/* Time is in seconds */
|
|
cfg->awl_ttl = $3 / 1000;
|
|
}
|
|
;
|
|
|
|
greylisted_message:
|
|
GREYLISTED_MESSAGE EQSIGN QUOTEDSTRING {
|
|
size_t len = strlen ($3);
|
|
char *c = $3;
|
|
|
|
/* Trim quotes */
|
|
if (*c == '"') {
|
|
c++;
|
|
len--;
|
|
}
|
|
if (c[len - 1] == '"') {
|
|
len--;
|
|
}
|
|
|
|
if (cfg->greylisted_message) {
|
|
free (cfg->greylisted_message);
|
|
}
|
|
cfg->greylisted_message = (char *)malloc (len + 1);
|
|
if (!cfg->greylisted_message) {
|
|
yyerror ("yyparse: malloc failed");
|
|
YYERROR;
|
|
}
|
|
strlcpy (cfg->greylisted_message, c, len + 1);
|
|
|
|
free ($3);
|
|
}
|
|
;
|
|
|
|
ip_net:
|
|
IPADDR
|
|
| IPNETWORK
|
|
;
|
|
|
|
memcached:
|
|
MEMCACHED OBRACE memcachedbody EBRACE
|
|
;
|
|
|
|
memcachedbody:
|
|
memcachedcmd SEMICOLON
|
|
| memcachedbody memcachedcmd SEMICOLON
|
|
;
|
|
|
|
memcachedcmd:
|
|
memcached_grey_servers
|
|
| memcached_white_servers
|
|
| memcached_limits_servers
|
|
| memcached_id_servers
|
|
| memcached_connect_timeout
|
|
| memcached_error_time
|
|
| memcached_dead_time
|
|
| memcached_maxerrors
|
|
| memcached_protocol
|
|
| memcached_id_prefix
|
|
| memcached_grey_prefix
|
|
| memcached_white_prefix
|
|
;
|
|
|
|
memcached_grey_servers:
|
|
SERVERS_GREY EQSIGN memcached_grey_server
|
|
;
|
|
|
|
memcached_grey_server:
|
|
memcached_grey_params
|
|
| memcached_grey_server COMMA memcached_grey_params
|
|
;
|
|
|
|
memcached_grey_params:
|
|
OBRACE memcached_hosts COMMA memcached_hosts EBRACE {
|
|
if (!add_memcached_server (cfg, $2, $4, MEMCACHED_SERVER_GREY)) {
|
|
yyerror ("yyparse: add_memcached_server");
|
|
YYERROR;
|
|
}
|
|
free ($2);
|
|
free ($4);
|
|
}
|
|
| memcached_hosts {
|
|
if (!add_memcached_server (cfg, $1, NULL, MEMCACHED_SERVER_GREY)) {
|
|
yyerror ("yyparse: add_memcached_server");
|
|
YYERROR;
|
|
}
|
|
free ($1);
|
|
}
|
|
;
|
|
|
|
memcached_white_servers:
|
|
SERVERS_WHITE EQSIGN memcached_white_server
|
|
;
|
|
|
|
memcached_white_server:
|
|
memcached_white_params
|
|
| memcached_white_server COMMA memcached_white_params
|
|
;
|
|
|
|
memcached_white_params:
|
|
OBRACE memcached_hosts COMMA memcached_hosts EBRACE {
|
|
if (!add_memcached_server (cfg, $2, $4, MEMCACHED_SERVER_WHITE)) {
|
|
yyerror ("yyparse: add_memcached_server");
|
|
YYERROR;
|
|
}
|
|
free ($2);
|
|
free ($4);
|
|
}
|
|
| memcached_hosts {
|
|
if (!add_memcached_server (cfg, $1, NULL, MEMCACHED_SERVER_WHITE)) {
|
|
yyerror ("yyparse: add_memcached_server");
|
|
YYERROR;
|
|
}
|
|
free ($1);
|
|
}
|
|
;
|
|
|
|
memcached_limits_servers:
|
|
SERVERS_LIMITS EQSIGN memcached_limits_server
|
|
;
|
|
|
|
memcached_limits_server:
|
|
memcached_limits_params
|
|
| memcached_limits_server COMMA memcached_limits_params
|
|
;
|
|
|
|
memcached_limits_params:
|
|
memcached_hosts {
|
|
if (!add_memcached_server (cfg, $1, NULL, MEMCACHED_SERVER_LIMITS)) {
|
|
yyerror ("yyparse: add_memcached_server");
|
|
YYERROR;
|
|
}
|
|
free ($1);
|
|
}
|
|
;
|
|
|
|
memcached_id_servers:
|
|
SERVERS_ID EQSIGN memcached_id_server
|
|
;
|
|
|
|
memcached_id_server:
|
|
memcached_id_params
|
|
| memcached_id_server COMMA memcached_id_params
|
|
;
|
|
|
|
memcached_id_params:
|
|
memcached_hosts {
|
|
if (!add_memcached_server (cfg, $1, NULL, MEMCACHED_SERVER_ID)) {
|
|
yyerror ("yyparse: add_memcached_server");
|
|
YYERROR;
|
|
}
|
|
free ($1);
|
|
}
|
|
;
|
|
|
|
memcached_hosts:
|
|
STRING
|
|
| IPADDR
|
|
| DOMAIN
|
|
| HOSTPORT
|
|
;
|
|
memcached_error_time:
|
|
ERROR_TIME EQSIGN NUMBER {
|
|
cfg->memcached_error_time = $3;
|
|
}
|
|
;
|
|
memcached_dead_time:
|
|
DEAD_TIME EQSIGN NUMBER {
|
|
cfg->memcached_dead_time = $3;
|
|
}
|
|
;
|
|
memcached_maxerrors:
|
|
MAXERRORS EQSIGN NUMBER {
|
|
cfg->memcached_maxerrors = $3;
|
|
}
|
|
;
|
|
memcached_connect_timeout:
|
|
CONNECT_TIMEOUT EQSIGN SECONDS {
|
|
cfg->memcached_connect_timeout = $3;
|
|
}
|
|
;
|
|
|
|
memcached_protocol:
|
|
PROTOCOL EQSIGN STRING {
|
|
if (strncasecmp ($3, "udp", sizeof ("udp") - 1) == 0) {
|
|
cfg->memcached_protocol = UDP_TEXT;
|
|
}
|
|
else if (strncasecmp ($3, "tcp", sizeof ("tcp") - 1) == 0) {
|
|
cfg->memcached_protocol = TCP_TEXT;
|
|
}
|
|
else {
|
|
yyerror ("yyparse: cannot recognize protocol: %s", $3);
|
|
YYERROR;
|
|
}
|
|
}
|
|
;
|
|
memcached_id_prefix:
|
|
ID_PREFIX EQSIGN QUOTEDSTRING {
|
|
size_t len = strlen ($3);
|
|
char *c = $3;
|
|
|
|
/* Trim quotes */
|
|
if (*c == '"') {
|
|
c++;
|
|
len--;
|
|
}
|
|
if (c[len - 1] == '"') {
|
|
len--;
|
|
}
|
|
|
|
if (cfg->id_prefix) {
|
|
free (cfg->id_prefix);
|
|
}
|
|
cfg->id_prefix = (char *)malloc (len + 1);
|
|
if (!cfg->id_prefix) {
|
|
yyerror ("yyparse: malloc failed");
|
|
YYERROR;
|
|
}
|
|
strlcpy (cfg->id_prefix, c, len + 1);
|
|
|
|
free ($3);
|
|
}
|
|
;
|
|
|
|
memcached_grey_prefix:
|
|
GREY_PREFIX EQSIGN QUOTEDSTRING {
|
|
size_t len = strlen ($3);
|
|
char *c = $3;
|
|
|
|
/* Trim quotes */
|
|
if (*c == '"') {
|
|
c++;
|
|
len--;
|
|
}
|
|
if (c[len - 1] == '"') {
|
|
len--;
|
|
}
|
|
|
|
if (cfg->grey_prefix) {
|
|
free (cfg->grey_prefix);
|
|
}
|
|
cfg->grey_prefix = (char *)malloc (len + 1);
|
|
if (!cfg->grey_prefix) {
|
|
yyerror ("yyparse: malloc failed");
|
|
YYERROR;
|
|
}
|
|
strlcpy (cfg->grey_prefix, c, len + 1);
|
|
|
|
free ($3);
|
|
}
|
|
;
|
|
|
|
memcached_white_prefix:
|
|
WHITE_PREFIX EQSIGN QUOTEDSTRING {
|
|
size_t len = strlen ($3);
|
|
char *c = $3;
|
|
|
|
/* Trim quotes */
|
|
if (*c == '"') {
|
|
c++;
|
|
len--;
|
|
}
|
|
if (c[len - 1] == '"') {
|
|
len--;
|
|
}
|
|
|
|
if (cfg->white_prefix) {
|
|
free (cfg->white_prefix);
|
|
}
|
|
cfg->white_prefix = (char *)malloc (len + 1);
|
|
if (!cfg->white_prefix) {
|
|
yyerror ("yyparse: malloc failed");
|
|
YYERROR;
|
|
}
|
|
strlcpy (cfg->white_prefix, c, len + 1);
|
|
|
|
free ($3);
|
|
}
|
|
;
|
|
|
|
beanstalk:
|
|
BEANSTALK OBRACE beanstalkbody EBRACE
|
|
;
|
|
|
|
beanstalkbody:
|
|
beanstalkcmd SEMICOLON
|
|
| beanstalkbody beanstalkcmd SEMICOLON
|
|
;
|
|
|
|
beanstalkcmd:
|
|
beanstalk_servers
|
|
| beanstalk_copy_server
|
|
| beanstalk_spam_server
|
|
| beanstalk_connect_timeout
|
|
| beanstalk_error_time
|
|
| beanstalk_dead_time
|
|
| beanstalk_maxerrors
|
|
| beanstalk_protocol
|
|
| beanstalk_id_regexp
|
|
| beanstalk_lifetime
|
|
| send_beanstalk_headers
|
|
| send_beanstalk_spam
|
|
| send_beanstalk_copy
|
|
| beanstalk_copy_prob
|
|
;
|
|
|
|
beanstalk_servers:
|
|
SERVERS EQSIGN beanstalk_server
|
|
;
|
|
|
|
beanstalk_server:
|
|
beanstalk_params
|
|
| beanstalk_server COMMA beanstalk_params
|
|
;
|
|
|
|
beanstalk_params:
|
|
beanstalk_hosts {
|
|
if (!add_beanstalk_server (cfg, $1, 0)) {
|
|
yyerror ("yyparse: add_beanstalk_server");
|
|
YYERROR;
|
|
}
|
|
free ($1);
|
|
}
|
|
;
|
|
|
|
beanstalk_copy_server:
|
|
COPY_SERVER EQSIGN beanstalk_hosts {
|
|
if (!add_beanstalk_server (cfg, $3, 1)) {
|
|
yyerror ("yyparse: add_beanstalk_server");
|
|
YYERROR;
|
|
}
|
|
free ($3);
|
|
}
|
|
;
|
|
beanstalk_spam_server:
|
|
SPAM_SERVER EQSIGN beanstalk_hosts {
|
|
if (!add_beanstalk_server (cfg, $3, 2)) {
|
|
yyerror ("yyparse: add_beanstalk_server");
|
|
YYERROR;
|
|
}
|
|
free ($3);
|
|
}
|
|
;
|
|
|
|
beanstalk_hosts:
|
|
STRING
|
|
| IPADDR
|
|
| DOMAIN
|
|
| HOSTPORT
|
|
;
|
|
|
|
beanstalk_error_time:
|
|
ERROR_TIME EQSIGN NUMBER {
|
|
cfg->beanstalk_error_time = $3;
|
|
}
|
|
;
|
|
beanstalk_dead_time:
|
|
DEAD_TIME EQSIGN NUMBER {
|
|
cfg->beanstalk_dead_time = $3;
|
|
}
|
|
;
|
|
beanstalk_maxerrors:
|
|
MAXERRORS EQSIGN NUMBER {
|
|
cfg->beanstalk_maxerrors = $3;
|
|
}
|
|
;
|
|
beanstalk_connect_timeout:
|
|
CONNECT_TIMEOUT EQSIGN SECONDS {
|
|
cfg->beanstalk_connect_timeout = $3;
|
|
}
|
|
;
|
|
|
|
beanstalk_protocol:
|
|
PROTOCOL EQSIGN STRING {
|
|
if (strncasecmp ($3, "udp", sizeof ("udp") - 1) == 0) {
|
|
cfg->beanstalk_protocol = BEANSTALK_UDP_TEXT;
|
|
}
|
|
else if (strncasecmp ($3, "tcp", sizeof ("tcp") - 1) == 0) {
|
|
cfg->beanstalk_protocol = BEANSTALK_TCP_TEXT;
|
|
}
|
|
else {
|
|
yyerror ("yyparse: cannot recognize protocol: %s", $3);
|
|
YYERROR;
|
|
}
|
|
}
|
|
;
|
|
beanstalk_id_regexp:
|
|
ID_REGEXP EQSIGN QUOTEDSTRING {
|
|
size_t len = strlen ($3);
|
|
char *c = $3;
|
|
int offset;
|
|
const char *read_err;
|
|
|
|
/* Trim quotes */
|
|
if (*c == '"') {
|
|
c++;
|
|
len--;
|
|
}
|
|
if (*c == '/') {
|
|
c ++;
|
|
len --;
|
|
}
|
|
if (c[len - 1] == '"') {
|
|
c[len - 1] = '\0';
|
|
len --;
|
|
}
|
|
if (c[len - 1] == '/') {
|
|
c[len - 1] = '\0';
|
|
len --;
|
|
}
|
|
|
|
if (cfg->special_mid_re) {
|
|
pcre_free (cfg->special_mid_re);
|
|
}
|
|
cfg->special_mid_re = pcre_compile (c, 0, &read_err, &offset, NULL);
|
|
if (cfg->special_mid_re == NULL) {
|
|
yyerror ("yyparse: pcre_compile failed: %s", read_err);
|
|
YYERROR;
|
|
}
|
|
|
|
free ($3);
|
|
}
|
|
;
|
|
beanstalk_lifetime:
|
|
LIFETIME EQSIGN NUMBER {
|
|
cfg->beanstalk_lifetime = $3;
|
|
}
|
|
;
|
|
|
|
send_beanstalk_headers:
|
|
SEND_BEANSTALK_HEADERS EQSIGN FLAG {
|
|
if ($3) {
|
|
cfg->send_beanstalk_headers = 1;
|
|
}
|
|
else {
|
|
cfg->send_beanstalk_headers = 0;
|
|
}
|
|
}
|
|
;
|
|
send_beanstalk_copy:
|
|
SEND_BEANSTALK_COPY EQSIGN FLAG {
|
|
if ($3) {
|
|
cfg->send_beanstalk_copy = 1;
|
|
}
|
|
else {
|
|
cfg->send_beanstalk_copy = 0;
|
|
}
|
|
}
|
|
;
|
|
send_beanstalk_spam:
|
|
SEND_BEANSTALK_SPAM EQSIGN FLAG {
|
|
if ($3) {
|
|
cfg->send_beanstalk_spam = 1;
|
|
}
|
|
else {
|
|
cfg->send_beanstalk_spam = 0;
|
|
}
|
|
}
|
|
;
|
|
|
|
beanstalk_copy_prob:
|
|
COPY_PROBABILITY EQSIGN NUMBER {
|
|
cfg->beanstalk_copy_prob = $3;
|
|
}
|
|
| COPY_PROBABILITY EQSIGN FLOAT {
|
|
cfg->beanstalk_copy_prob = $3;
|
|
}
|
|
;
|
|
|
|
limits:
|
|
LIMITS OBRACE limitsbody EBRACE
|
|
;
|
|
|
|
limitsbody:
|
|
limitcmd SEMICOLON
|
|
| limitsbody limitcmd SEMICOLON
|
|
;
|
|
limitcmd:
|
|
limit_to
|
|
| limit_to_ip
|
|
| limit_to_ip_from
|
|
| limit_whitelist
|
|
| limit_whitelist_rcpt
|
|
| limit_bounce_addrs
|
|
| limit_bounce_to
|
|
| limit_bounce_to_ip
|
|
;
|
|
|
|
limit_to:
|
|
LIMIT_TO EQSIGN BUCKET {
|
|
cfg->limit_to.burst = $3.burst;
|
|
cfg->limit_to.rate = $3.rate;
|
|
}
|
|
;
|
|
limit_to_ip:
|
|
LIMIT_TO_IP EQSIGN BUCKET {
|
|
cfg->limit_to_ip.burst = $3.burst;
|
|
cfg->limit_to_ip.rate = $3.rate;
|
|
}
|
|
;
|
|
limit_to_ip_from:
|
|
LIMIT_TO_IP_FROM EQSIGN BUCKET {
|
|
cfg->limit_to_ip_from.burst = $3.burst;
|
|
cfg->limit_to_ip_from.rate = $3.rate;
|
|
}
|
|
;
|
|
limit_whitelist:
|
|
LIMIT_WHITELIST EQSIGN whitelist_ip_list
|
|
;
|
|
whitelist_ip_list:
|
|
ip_net {
|
|
if (add_ip_radix (cfg->limit_whitelist_tree, $1) == 0) {
|
|
YYERROR;
|
|
}
|
|
}
|
|
| whitelist_ip_list COMMA ip_net {
|
|
if (add_ip_radix (cfg->limit_whitelist_tree, $3) == 0) {
|
|
YYERROR;
|
|
}
|
|
}
|
|
;
|
|
|
|
limit_whitelist_rcpt:
|
|
LIMIT_WHITELIST_RCPT EQSIGN whitelist_rcpt_list
|
|
;
|
|
whitelist_rcpt_list:
|
|
STRING {
|
|
add_rcpt_whitelist (cfg, $1, 0);
|
|
}
|
|
| whitelist_rcpt_list COMMA STRING {
|
|
add_rcpt_whitelist (cfg, $3, 0);
|
|
}
|
|
;
|
|
|
|
limit_bounce_addrs:
|
|
LIMIT_BOUNCE_ADDRS EQSIGN bounce_addr_list
|
|
;
|
|
bounce_addr_list:
|
|
STRING {
|
|
struct addr_list_entry *t;
|
|
t = (struct addr_list_entry *)malloc (sizeof (struct addr_list_entry));
|
|
t->addr = strdup ($1);
|
|
t->len = strlen (t->addr);
|
|
LIST_INSERT_HEAD (&cfg->bounce_addrs, t, next);
|
|
}
|
|
| bounce_addr_list COMMA STRING {
|
|
struct addr_list_entry *t;
|
|
t = (struct addr_list_entry *)malloc (sizeof (struct addr_list_entry));
|
|
t->addr = strdup ($3);
|
|
t->len = strlen (t->addr);
|
|
LIST_INSERT_HEAD (&cfg->bounce_addrs, t, next);
|
|
}
|
|
;
|
|
|
|
|
|
limit_bounce_to:
|
|
LIMIT_BOUNCE_TO EQSIGN BUCKET {
|
|
cfg->limit_bounce_to.burst = $3.burst;
|
|
cfg->limit_bounce_to.rate = $3.rate;
|
|
}
|
|
;
|
|
|
|
limit_bounce_to_ip:
|
|
LIMIT_BOUNCE_TO_IP EQSIGN BUCKET {
|
|
cfg->limit_bounce_to_ip.burst = $3.burst;
|
|
cfg->limit_bounce_to_ip.rate = $3.rate;
|
|
}
|
|
;
|
|
|
|
|
|
whitelist:
|
|
WHITELIST EQSIGN whitelist_list
|
|
;
|
|
whitelist_list:
|
|
STRING {
|
|
add_rcpt_whitelist (cfg, $1, 1);
|
|
}
|
|
| whitelist_list COMMA STRING {
|
|
add_rcpt_whitelist (cfg, $3, 1);
|
|
}
|
|
;
|
|
|
|
|
|
dkim:
|
|
DKIM_SECTION OBRACE dkimbody EBRACE
|
|
;
|
|
|
|
dkimbody:
|
|
dkimcmd SEMICOLON
|
|
| dkimbody dkimcmd SEMICOLON
|
|
;
|
|
|
|
dkimcmd:
|
|
dkim_key
|
|
| dkim_domain
|
|
| dkim_header_canon
|
|
| dkim_body_canon
|
|
| dkim_sign_alg
|
|
;
|
|
|
|
dkim_domain:
|
|
DKIM_DOMAIN OBRACE dkim_domain_body EBRACE {
|
|
if (cur_domain == NULL || cur_domain->domain == NULL || cur_domain->selector == NULL) {
|
|
yyerror ("yyparse: incomplete dkim definition");
|
|
YYERROR;
|
|
}
|
|
if (!cur_domain->is_loaded) {
|
|
/* Assume it as wildcard domain */
|
|
cur_domain->is_wildcard = 1;
|
|
}
|
|
HASH_ADD_KEYPTR (hh, cfg->dkim_domains, cur_domain->domain, strlen (cur_domain->domain), cur_domain);
|
|
cur_domain = NULL;
|
|
}
|
|
;
|
|
|
|
dkim_domain_body:
|
|
dkim_domain_cmd SEMICOLON
|
|
| dkim_domain_body dkim_domain_cmd SEMICOLON
|
|
;
|
|
|
|
dkim_domain_cmd:
|
|
dkim_key
|
|
| dkim_domain
|
|
| dkim_selector
|
|
;
|
|
|
|
dkim_key:
|
|
DKIM_KEY EQSIGN FILENAME {
|
|
struct stat st;
|
|
int fd;
|
|
if (cur_domain == NULL) {
|
|
cur_domain = malloc (sizeof (struct dkim_domain_entry));
|
|
memset (cur_domain, 0, sizeof (struct dkim_domain_entry));
|
|
}
|
|
if (stat ($3, &st) != -1 && S_ISREG (st.st_mode)) {
|
|
cur_domain->keylen = st.st_size;
|
|
if ((fd = open ($3, O_RDONLY)) != -1) {
|
|
if ((cur_domain->key = mmap (NULL, cur_domain->keylen, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
|
|
yyerror ("yyparse: cannot mmap: %s, %s", $3, strerror (errno));
|
|
close (fd);
|
|
YYERROR;
|
|
}
|
|
else {
|
|
cur_domain->is_loaded = 1;
|
|
}
|
|
close (fd);
|
|
}
|
|
}
|
|
cur_domain->keyfile = strdup ($3);
|
|
}
|
|
;
|
|
|
|
dkim_domain:
|
|
DKIM_DOMAIN EQSIGN QUOTEDSTRING {
|
|
size_t len = strlen ($3);
|
|
char *c = $3;
|
|
|
|
if (cur_domain == NULL) {
|
|
cur_domain = malloc (sizeof (struct dkim_domain_entry));
|
|
memset (cur_domain, 0, sizeof (struct dkim_domain_entry));
|
|
}
|
|
/* Trim quotes */
|
|
if (*c == '"') {
|
|
c++;
|
|
len--;
|
|
}
|
|
if (*c == '/') {
|
|
c ++;
|
|
len --;
|
|
}
|
|
if (c[len - 1] == '"') {
|
|
c[len - 1] = '\0';
|
|
len --;
|
|
}
|
|
if (c[len - 1] == '/') {
|
|
c[len - 1] = '\0';
|
|
len --;
|
|
}
|
|
cur_domain->domain = strdup (c);
|
|
free ($3);
|
|
}
|
|
;
|
|
|
|
dkim_selector:
|
|
DKIM_SELECTOR EQSIGN QUOTEDSTRING {
|
|
size_t len = strlen ($3);
|
|
char *c = $3;
|
|
|
|
if (cur_domain == NULL) {
|
|
cur_domain = malloc (sizeof (struct dkim_domain_entry));
|
|
memset (cur_domain, 0, sizeof (struct dkim_domain_entry));
|
|
}
|
|
/* Trim quotes */
|
|
if (*c == '"') {
|
|
c++;
|
|
len--;
|
|
}
|
|
if (*c == '/') {
|
|
c ++;
|
|
len --;
|
|
}
|
|
if (c[len - 1] == '"') {
|
|
c[len - 1] = '\0';
|
|
len --;
|
|
}
|
|
if (c[len - 1] == '/') {
|
|
c[len - 1] = '\0';
|
|
len --;
|
|
}
|
|
cur_domain->selector = strdup (c);
|
|
free ($3);
|
|
}
|
|
;
|
|
|
|
dkim_header_canon:
|
|
DKIM_HEADER_CANON EQSIGN DKIM_SIMPLE {
|
|
cfg->dkim_relaxed_header = 0;
|
|
}
|
|
| DKIM_HEADER_CANON EQSIGN DKIM_RELAXED {
|
|
cfg->dkim_relaxed_header = 1;
|
|
}
|
|
;
|
|
|
|
dkim_body_canon:
|
|
DKIM_BODY_CANON EQSIGN DKIM_SIMPLE {
|
|
cfg->dkim_relaxed_body = 0;
|
|
}
|
|
| DKIM_BODY_CANON EQSIGN DKIM_RELAXED {
|
|
cfg->dkim_relaxed_body = 1;
|
|
}
|
|
;
|
|
|
|
dkim_sign_alg:
|
|
DKIM_SIGN_ALG EQSIGN DKIM_SHA1 {
|
|
cfg->dkim_sign_sha256 = 0;
|
|
}
|
|
| DKIM_SIGN_ALG EQSIGN DKIM_SHA256 {
|
|
cfg->dkim_sign_sha256 = 1;
|
|
}
|
|
;
|
|
|
|
%%
|
|
/*
|
|
* vi:ts=4
|
|
*/
|