rmilter/cfg_file.l
2013-05-29 14:47:11 +01:00

329 lines
9.5 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.
*/
%x incl
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <syslog.h>
#include "cfg_file.h"
#include "cfg_yacc.h"
#define MAX_INCLUDE_DEPTH 10
YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
int line_stack[MAX_INCLUDE_DEPTH];
int include_stack_ptr = 0;
static size_t
parse_limit (const char *limit)
{
size_t result = 0;
char *err_str;
if (!limit || *limit == '\0') return 0;
result = strtoul (limit, &err_str, 10);
if (*err_str != '\0') {
/* Megabytes */
if (*err_str == 'm' || *err_str == 'M') {
result *= 1048576L;
}
/* Kilobytes */
else if (*err_str == 'k' || *err_str == 'K') {
result *= 1024;
}
/* Gigabytes */
else if (*err_str == 'g' || *err_str == 'G') {
result *= 1073741824L;
}
}
return result;
}
static unsigned int
parse_seconds (const char *t)
{
unsigned long int result = 0;
char *err_str;
if (!t || *t == '\0') return 0;
result = strtoul (t, &err_str, 10);
if (*err_str != '\0') {
/* Seconds */
if (*err_str == 's' || *err_str == 'S') {
result *= 1000;
}
/* Minutes */
if (*err_str == 'm' || *err_str == 'M') {
result *= 60 * 1000;
}
/* Hours */
if (*err_str == 'h' || *err_str == 'H') {
result *= 60 * 60 * 1000;
}
/* Days */
if (*err_str == 'd' || *err_str == 'D') {
result *= 24 * 60 * 60 * 1000;
}
}
return result;
}
static char
parse_flag (const char *str)
{
if (!str || !*str) return -1;
if ((*str == 'y' || *str == 'Y') && *(str + 1) == '\0') {
return 1;
}
if ((*str == 'Y' || *str == 'y') &&
(*(str + 1) == 'E' || *(str + 1) == 'e') &&
(*(str + 2) == 'S' || *(str + 2) == 's') &&
*(str + 3) == '\0') {
return 1;
}
if ((*str == 'n' || *str == 'N') && *(str + 1) == '\0') {
return 0;
}
if ((*str == 'N' || *str == 'n') &&
(*(str + 1) == 'O' || *(str + 1) == 'o') &&
*(str + 2) == '\0') {
return 0;
}
return -1;
}
static void
parse_bucket (char *str, bucket_t *bucket)
{
char *cur_tok, *err_str;
bucket->burst = 0;
bucket->rate = 0;
cur_tok = strsep (&str, ":");
if (cur_tok == NULL || *cur_tok == '\0' || str == NULL || *str == '\0') {
yywarn ("parse_bucket: invalid bucket value %s", str);
return;
}
bucket->burst = strtol (cur_tok, &err_str, 10);
if (*err_str != '\0') {
yywarn ("parse_bucket: invalid bucket value %s", err_str);
bucket->burst = 0;
return;
}
bucket->rate = strtod (str, &err_str);
if (*err_str != '\0') {
yywarn ("parse_bucket: invalid bucket value %s", err_str);
bucket->rate = 0;
return;
}
}
%}
%option noyywrap
%option yylineno
%%
^[ \t]*#.* /* ignore comments */;
.include BEGIN(incl);
tempdir return TEMPDIR;
pidfile return PIDFILE;
strict_auth return STRICT_AUTH;
rule return RULE;
clamav return CLAMAV;
spamd return SPAMD;
also_check return ALSO_CHECK;
diff_dir return DIFF_DIR;
check_symbols return CHECK_SYMBOLS;
symbols_dir return SYMBOLS_DIR;
rspamd_metric return RSPAMD_METRIC;
spamd_soft_fail return SPAMD_SOFT_FAIL;
spamd_greylist return SPAMD_GREYLIST;
spam_header return SPAM_HEADER;
extended_spam_headers return EXTENDED_SPAM_HEADERS;
reject_message return REJECT_MESSAGE;
trace_symbol return TRACE_SYMBOL;
trace_addr return TRACE_ADDR;
servers return SERVERS;
servers_limits return SERVERS_LIMITS;
servers_grey return SERVERS_GREY;
servers_white return SERVERS_WHITE;
servers_id return SERVERS_ID;
copy_server return COPY_SERVER;
spam_server return SPAM_SERVER;
error_time return ERROR_TIME;
dead_time return DEAD_TIME;
maxerrors return MAXERRORS;
connect_timeout return CONNECT_TIMEOUT;
port_timeout return PORT_TIMEOUT;
results_timeout return RESULTS_TIMEOUT;
id_prefix return ID_PREFIX;
id_regexp return ID_REGEXP;
lifetime return LIFETIME;
grey_prefix return GREY_PREFIX;
white_prefix return WHITE_PREFIX;
memcached return MEMCACHED;
beanstalk return BEANSTALK;
send_beanstalk_copy return SEND_BEANSTALK_COPY;
send_beanstalk_headers return SEND_BEANSTALK_HEADERS;
send_beanstalk_spam return SEND_BEANSTALK_SPAM;
copy_probability return COPY_PROBABILITY;
dkim return DKIM_SECTION;
key return DKIM_KEY;
domain return DKIM_DOMAIN;
selector return DKIM_SELECTOR;
header_canon return DKIM_HEADER_CANON;
body_canon return DKIM_BODY_CANON;
sign_alg return DKIM_SIGN_ALG;
relaxed return DKIM_RELAXED;
simple return DKIM_SIMPLE;
sha1 return DKIM_SHA1;
sha256 return DKIM_SHA256;
protocol return PROTOCOL;
spf_domains return SPF;
bind_socket return BINDSOCK;
max_size return MAXSIZE;
use_dcc return USEDCC;
greylisting return GREYLISTING;
whitelist return WHITELIST;
timeout return TIMEOUT;
expire_white return EXPIRE_WHITE;
expire return EXPIRE;
greylisted_message return GREYLISTED_MESSAGE;
awl_enable return AWL_ENABLE;
awl_hits return AWL_HITS;
awl_ttl return AWL_TTL;
awl_pool return AWL_POOL;
limits return LIMITS;
limit_to return LIMIT_TO;
limit_to_ip return LIMIT_TO_IP;
limit_to_ip_from return LIMIT_TO_IP_FROM;
limit_whitelist return LIMIT_WHITELIST;
limit_whitelist_rcpt return LIMIT_WHITELIST_RCPT;
limit_bounce_addrs return LIMIT_BOUNCE_ADDRS;
limit_bounce_to return LIMIT_BOUNCE_TO;
limit_bounce_to_ip return LIMIT_BOUNCE_TO_IP;
accept return ACCEPT;
body return BODY;
connect return CONNECT;
discard return DISCARD;
envfrom return ENVFROM;
envrcpt return ENVRCPT;
header return HEADER;
helo return HELO;
not return NOT;
quarantine return QUARANTINE;
reject return REJECTL;
tempfail return TEMPFAIL;
\" return QUOTE;
\{ return OBRACE;
\} return EBRACE;
; return SEMICOLON;
, return COMMA;
= return EQSIGN;
yes|YES|no|NO|[yY]|[nN] yylval.flag=parse_flag(yytext); return FLAG;
\n /* ignore EOL */;
[ \t]+ /* ignore whitespace */;
\".+\" yylval.string=strdup(yytext); return QUOTEDSTRING;
[0-9]+ yylval.number=strtol(yytext, NULL, 10); return NUMBER;
[0-9]+\.[0-9]* yylval.frac=strtod(yytext, NULL); return FLOAT;
[0-9]+[kKmMgG]? yylval.limit=parse_limit(yytext); return SIZELIMIT;
[0-9]+[sShHdD]|[0-9]+[mM][sS] yylval.seconds=parse_seconds(yytext); return SECONDS;
[0-9]+:[0-9]+[.]?[0-9]* parse_bucket(yytext, &yylval.bucket); return BUCKET;
unix:[a-zA-Z0-9\/.-]+ yylval.string=strdup(yytext); return SOCKCRED;
local:[a-zA-Z0-9\/.-]+ yylval.string=strdup(yytext); return SOCKCRED;
inet:[0-9]+@[a-zA-Z0-9.-]+ yylval.string=strdup(yytext); return SOCKCRED;
[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3} yylval.string=strdup(yytext); return IPADDR;
[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\/[0-9]{1,2} yylval.string=strdup(yytext); return IPNETWORK;
\/[^/\n]+\/ yylval.string=strdup(yytext); return REGEXP;
[a-zA-Z<@][.a-zA-Z@+>_-]* yylval.string=strdup(yytext); return STRING;
[a-zA-Z0-9].[a-zA-Z0-9\/.-]+ yylval.string=strdup(yytext); return DOMAIN;
r?:?[a-zA-Z0-9.-]+:[0-9]{1,5} yylval.string=strdup(yytext); return HOSTPORT;
r?:?[a-zA-Z0-9\/.-]+ yylval.string=strdup(yytext); return FILENAME;
<incl>[ \t]* /* eat the whitespace */
<incl>[^ \t\n]+ {
/* got the include file name */
if ( include_stack_ptr >= MAX_INCLUDE_DEPTH ) {
yyerror ("yylex: includes nested too deeply" );
return -1;
}
line_stack[include_stack_ptr] = yylineno;
include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER;
yylineno = 1;
yyin = fopen (yytext, "r");
if (!yyin) {
yyerror ("yylex: cannot open include file");
return -1;
}
yy_switch_to_buffer (yy_create_buffer (yyin, YY_BUF_SIZE));
BEGIN(INITIAL);
}
<<EOF>> {
if ( --include_stack_ptr < 0 ) {
include_stack_ptr = 0;
yylineno = 1;
yyterminate ();
}
else {
yy_delete_buffer (YY_CURRENT_BUFFER);
yy_switch_to_buffer (include_stack[include_stack_ptr] );
yylineno = line_stack[include_stack_ptr];
}
}
%%
/*
* vi:ts=4
*/