1 /*
2  * Copyright (c) 2015 Balabit
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License version 2 as published
6  * by the Free Software Foundation, or (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
16  *
17  * As an additional exemption you are allowed to compile & link against the
18  * OpenSSL libraries as published by the OpenSSL project. See the file
19  * COPYING for details.
20  */
21 
22 %code top {
23 #include "kv-parser-parser.h"
24 
25 }
26 
27 
28 %code {
29 
30 #include "kv-parser.h"
31 #include "kv-parser-parser.h"
32 #include "linux-audit-parser.h"
33 #include "cfg-parser.h"
34 #include "cfg-grammar-internal.h"
35 
36 }
37 
38 %define api.prefix {kv_parser_}
39 
40 /* this parameter is needed in order to instruct bison to use a complete
41  * argument list for yylex/yyerror */
42 
43 %lex-param {CfgLexer *lexer}
44 %parse-param {CfgLexer *lexer}
45 %parse-param {LogParser **instance}
46 %parse-param {gpointer arg}
47 
48 
49 %require "3.7.6"
50 %locations
51 %define api.pure
52 %define api.value.type {CFG_STYPE}
53 %define api.location.type {CFG_LTYPE}
54 %define parse.error verbose
55 
56 %code {
57 
58 # define YYLLOC_DEFAULT(Current, Rhs, N)                                \
59   do {                                                                  \
60     if (N)                                                              \
61       {                                                                 \
62         (Current).level = YYRHSLOC(Rhs, 1).level;                       \
63         (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;          \
64         (Current).first_column = YYRHSLOC (Rhs, 1).first_column;        \
65         (Current).last_line    = YYRHSLOC (Rhs, N).last_line;           \
66         (Current).last_column  = YYRHSLOC (Rhs, N).last_column;         \
67       }                                                                 \
68     else                                                                \
69       {                                                                 \
70         (Current).level = YYRHSLOC(Rhs, 0).level;                       \
71         (Current).first_line   = (Current).last_line   =                \
72           YYRHSLOC (Rhs, 0).last_line;                                  \
73         (Current).first_column = (Current).last_column =                \
74           YYRHSLOC (Rhs, 0).last_column;                                \
75       }                                                                 \
76   } while (0)
77 
78 #define CHECK_ERROR_WITHOUT_MESSAGE(val, token) do {                    \
79     if (!(val))                                                         \
80       {                                                                 \
81         YYERROR;                                                        \
82       }                                                                 \
83   } while (0)
84 
85 #define CHECK_ERROR(val, token, errorfmt, ...) do {                     \
86     if (!(val))                                                         \
87       {                                                                 \
88         if (errorfmt)                                                   \
89           {                                                             \
90             gchar __buf[256];                                           \
91             g_snprintf(__buf, sizeof(__buf), errorfmt, ## __VA_ARGS__); \
92             yyerror(& (token), lexer, NULL, NULL, __buf);               \
93           }                                                             \
94         YYERROR;                                                        \
95       }                                                                 \
96   } while (0)
97 
98 #define CHECK_ERROR_GERROR(val, token, error, errorfmt, ...) do {       \
99     if (!(val))                                                         \
100       {                                                                 \
101         if (errorfmt)                                                   \
102           {                                                             \
103             gchar __buf[256];                                           \
104             g_snprintf(__buf, sizeof(__buf), errorfmt ", error=%s", ## __VA_ARGS__, error->message); \
105             yyerror(& (token), lexer, NULL, NULL, __buf);               \
106           }                                                             \
107         g_clear_error(&error);						\
108         YYERROR;                                                        \
109       }                                                                 \
110   } while (0)
111 
112 #define YYMAXDEPTH 20000
113 
114 
115 }
116 
117 /* plugin types, must be equal to the numerical values of the plugin type in plugin.h */
118 
119 %token LL_CONTEXT_ROOT                1
120 %token LL_CONTEXT_DESTINATION         2
121 %token LL_CONTEXT_SOURCE              3
122 %token LL_CONTEXT_PARSER              4
123 %token LL_CONTEXT_REWRITE             5
124 %token LL_CONTEXT_FILTER              6
125 %token LL_CONTEXT_LOG                 7
126 %token LL_CONTEXT_BLOCK_DEF           8
127 %token LL_CONTEXT_BLOCK_REF           9
128 %token LL_CONTEXT_BLOCK_CONTENT       10
129 %token LL_CONTEXT_BLOCK_ARG           11
130 %token LL_CONTEXT_PRAGMA              12
131 %token LL_CONTEXT_FORMAT              13
132 %token LL_CONTEXT_TEMPLATE_FUNC       14
133 %token LL_CONTEXT_INNER_DEST          15
134 %token LL_CONTEXT_INNER_SRC           16
135 %token LL_CONTEXT_CLIENT_PROTO        17
136 %token LL_CONTEXT_SERVER_PROTO        18
137 %token LL_CONTEXT_OPTIONS             19
138 %token LL_CONTEXT_CONFIG              20
139 
140 /* this is a placeholder for unit tests, must be the latest & largest */
141 %token LL_CONTEXT_MAX                 21
142 
143 
144 /* statements */
145 %token KW_SOURCE                      10000
146 %token KW_FILTER                      10001
147 %token KW_PARSER                      10002
148 %token KW_DESTINATION                 10003
149 %token KW_LOG                         10004
150 %token KW_OPTIONS                     10005
151 %token KW_INCLUDE                     10006
152 %token KW_BLOCK                       10007
153 %token KW_JUNCTION                    10008
154 %token KW_CHANNEL                     10009
155 %token KW_IF                          10010
156 %token KW_ELSE                        10011
157 %token KW_ELIF                        10012
158 
159 /* source & destination items */
160 %token KW_INTERNAL                    10020
161 %token KW_SYSLOG                      10060
162 
163 /* option items */
164 %token KW_MARK_FREQ                   10071
165 %token KW_STATS_FREQ                  10072
166 %token KW_STATS_LEVEL                 10073
167 %token KW_STATS_LIFETIME              10074
168 %token KW_FLUSH_LINES                 10075
169 %token KW_SUPPRESS                    10076
170 %token KW_FLUSH_TIMEOUT               10077
171 %token KW_LOG_MSG_SIZE                10078
172 %token KW_FILE_TEMPLATE               10079
173 %token KW_PROTO_TEMPLATE              10080
174 %token KW_MARK_MODE                   10081
175 %token KW_ENCODING                    10082
176 %token KW_TYPE                        10083
177 %token KW_STATS_MAX_DYNAMIC           10084
178 %token KW_MIN_IW_SIZE_PER_READER      10085
179 %token KW_WORKERS                     10086
180 %token KW_BATCH_LINES                 10087
181 %token KW_BATCH_TIMEOUT               10088
182 %token KW_TRIM_LARGE_MESSAGES         10089
183 
184 %token KW_CHAIN_HOSTNAMES             10090
185 %token KW_NORMALIZE_HOSTNAMES         10091
186 %token KW_KEEP_HOSTNAME               10092
187 %token KW_CHECK_HOSTNAME              10093
188 %token KW_BAD_HOSTNAME                10094
189 
190 %token KW_KEEP_TIMESTAMP              10100
191 
192 %token KW_USE_DNS                     10110
193 %token KW_USE_FQDN                    10111
194 %token KW_CUSTOM_DOMAIN               10112
195 
196 %token KW_DNS_CACHE                   10120
197 %token KW_DNS_CACHE_SIZE              10121
198 
199 %token KW_DNS_CACHE_EXPIRE            10130
200 %token KW_DNS_CACHE_EXPIRE_FAILED     10131
201 %token KW_DNS_CACHE_HOSTS             10132
202 
203 %token KW_PERSIST_ONLY                10140
204 %token KW_USE_RCPTID                  10141
205 %token KW_USE_UNIQID                  10142
206 
207 %token KW_TZ_CONVERT                  10150
208 %token KW_TS_FORMAT                   10151
209 %token KW_FRAC_DIGITS                 10152
210 
211 %token KW_LOG_FIFO_SIZE               10160
212 %token KW_LOG_FETCH_LIMIT             10162
213 %token KW_LOG_IW_SIZE                 10163
214 %token KW_LOG_PREFIX                  10164
215 %token KW_PROGRAM_OVERRIDE            10165
216 %token KW_HOST_OVERRIDE               10166
217 
218 %token KW_THROTTLE                    10170
219 %token KW_THREADED                    10171
220 %token KW_PASS_UNIX_CREDENTIALS       10231
221 
222 %token KW_PERSIST_NAME                10302
223 
224 %token KW_READ_OLD_RECORDS            10304
225 %token KW_USE_SYSLOGNG_PID            10305
226 
227 /* log statement options */
228 %token KW_FLAGS                       10190
229 
230 /* reader options */
231 %token KW_PAD_SIZE                    10200
232 %token KW_TIME_ZONE                   10201
233 %token KW_RECV_TIME_ZONE              10202
234 %token KW_SEND_TIME_ZONE              10203
235 %token KW_LOCAL_TIME_ZONE             10204
236 %token KW_FORMAT                      10205
237 
238 /* destination writer options */
239 %token KW_TRUNCATE_SIZE               10206
240 
241 /* timers */
242 %token KW_TIME_REOPEN                 10210
243 %token KW_TIME_REAP                   10211
244 %token KW_TIME_SLEEP                  10212
245 
246 /* destination options */
247 %token KW_TMPL_ESCAPE                 10220
248 
249 /* driver specific options */
250 %token KW_OPTIONAL                    10230
251 
252 /* file related options */
253 %token KW_CREATE_DIRS                 10240
254 
255 %token KW_OWNER                       10250
256 %token KW_GROUP                       10251
257 %token KW_PERM                        10252
258 
259 %token KW_DIR_OWNER                   10260
260 %token KW_DIR_GROUP                   10261
261 %token KW_DIR_PERM                    10262
262 
263 %token KW_TEMPLATE                    10270
264 %token KW_TEMPLATE_ESCAPE             10271
265 %token KW_TEMPLATE_FUNCTION           10272
266 
267 %token KW_DEFAULT_FACILITY            10300
268 %token KW_DEFAULT_SEVERITY            10301
269 
270 %token KW_PORT                        10323
271 /* misc options */
272 
273 %token KW_USE_TIME_RECVD              10340
274 
275 /* filter items*/
276 %token KW_FACILITY                    10350
277 %token KW_SEVERITY                    10351
278 %token KW_HOST                        10352
279 %token KW_MATCH                       10353
280 %token KW_MESSAGE                     10354
281 %token KW_NETMASK                     10355
282 %token KW_TAGS                        10356
283 %token KW_NETMASK6                    10357
284 
285 /* parser items */
286 
287 /* rewrite items */
288 %token KW_REWRITE                     10370
289 %token KW_CONDITION                   10371
290 %token KW_VALUE                       10372
291 
292 /* yes/no switches */
293 
294 %token KW_YES                         10380
295 %token KW_NO                          10381
296 
297 %token KW_IFDEF                       10410
298 %token KW_ENDIF                       10411
299 
300 %token LL_DOTDOT                      10420
301 %token LL_DOTDOTDOT                   10421
302 %token LL_PRAGMA                      10422
303 %token LL_EOL                         10423
304 %token LL_ERROR                       10424
305 %token LL_ARROW                       10425
306 
307 %token <cptr> LL_IDENTIFIER           10430
308 %token <num>  LL_NUMBER               10431
309 %token <fnum> LL_FLOAT                10432
310 %token <cptr> LL_STRING               10433
311 %token <token> LL_TOKEN               10434
312 %token <cptr> LL_BLOCK                10435
313 
314 %destructor { free($$); } <cptr>
315 
316 /* value pairs */
317 %token KW_VALUE_PAIRS                 10500
318 %token KW_EXCLUDE                     10502
319 %token KW_PAIR                        10503
320 %token KW_KEY                         10504
321 %token KW_SCOPE                       10505
322 %token KW_SHIFT                       10506
323 %token KW_SHIFT_LEVELS                10507
324 %token KW_REKEY                       10508
325 %token KW_ADD_PREFIX                  10509
326 %token KW_REPLACE_PREFIX              10510
327 
328 %token KW_ON_ERROR                    10511
329 
330 %token KW_RETRIES                     10512
331 
332 %token KW_FETCH_NO_DATA_DELAY         10513
333 
334 %type   <ptr> source_content
335 %type	<ptr> source_items
336 %type	<ptr> source_item
337 %type   <ptr> source_afinter
338 %type   <ptr> source_plugin
339 %type   <ptr> source_afinter_params
340 
341 %type   <ptr> dest_content
342 %type	<ptr> dest_items
343 %type	<ptr> dest_item
344 %type   <ptr> dest_plugin
345 
346 %type   <ptr> template_content
347 %type   <ptr> template_content_list
348 
349 %type   <ptr> filter_content
350 
351 %type   <ptr> parser_content
352 
353 %type   <ptr> rewrite_content
354 
355 %type	<ptr> log_items
356 %type	<ptr> log_item
357 
358 %type   <ptr> log_last_junction
359 %type   <ptr> log_junction
360 %type   <ptr> log_content
361 %type   <ptr> log_conditional
362 %type   <ptr> log_if
363 %type   <ptr> log_forks
364 %type   <ptr> log_fork
365 
366 %type	<num> log_flags
367 %type   <num> log_flags_items
368 
369 %type   <ptr> value_pair_option
370 
371 %type	<num> yesno
372 %type   <num> dnsmode
373 %type	<num> dest_writer_options_flags
374 
375 %type	<cptr> string
376 %type	<cptr> string_or_number
377 %type	<cptr> normalized_flag
378 %type   <ptr> string_list
379 %type   <ptr> string_list_build
380 %type   <num> facility_string
381 %type   <num> severity_string
382 
383 %type   <num> positive_integer
384 %type   <num> positive_integer64
385 %type   <num> nonnegative_integer
386 %type   <num> nonnegative_integer64
387 %type   <fnum> positive_float
388 %type   <fnum> nonnegative_float
389 %type	<cptr> path_no_check
390 %type	<cptr> path_secret
391 %type	<cptr> path_check
392 %type	<cptr> path
393 
394 
395 %token KW_KV_PARSER
396 %token KW_LINUX_AUDIT_PARSER
397 %token KW_PREFIX
398 %token KW_VALUE_SEPARATOR
399 %token KW_PAIR_SEPARATOR
400 %token KW_EXTRACT_STRAY_WORDS_INTO
401 %token KW_ALLOW_PAIR_SEPARATOR_OPTION
402 
403 %type	<ptr> parser_expr_kv
404 
405 %%
406 
407 start
408 	: LL_CONTEXT_PARSER parser_expr_kv                  { YYACCEPT; }
409 	;
410 
411 
412 parser_expr_kv
413 	: KW_KV_PARSER '('
414 	  {
415 	    last_parser = *instance = (LogParser *) kv_parser_new(configuration);
416 	  }
417 	  parser_kv_opts
418 	  ')'					{ $$ = last_parser; }
419 	| KW_LINUX_AUDIT_PARSER '('
420 	  {
421 	    last_parser = *instance = (LogParser *) linux_audit_parser_new(configuration);
422 	  }
423 	  parser_kv_opts
424 	  ')'					{ $$ = last_parser; }
425 	;
426 
427 parser_kv_opts
428 	: parser_kv_opt parser_kv_opts
429 	|
430 	;
431 
432 parser_kv_opt
433 	: KW_PREFIX '(' string ')'		{ kv_parser_set_prefix(last_parser, $3); free($3); }
434 	| KW_ALLOW_PAIR_SEPARATOR_OPTION '(' yesno ')'
435 	| KW_VALUE_SEPARATOR '(' string ')'
436 	  {
437 	    CHECK_ERROR((strlen($3) == 1), @3, "kv-parser() only supports single-character values for value-separator()");
438 	    CHECK_ERROR((kv_parser_is_valid_separator_character($3[0])), @3, "kv-parser() unsupported character for value-separator()");
439             kv_parser_set_value_separator(last_parser, $3[0]);
440             free($3);
441 	  }
442 	| KW_PAIR_SEPARATOR '(' string ')'
443           {
444             kv_parser_set_pair_separator(last_parser, $3);
445             free($3);
446           }
447         | KW_EXTRACT_STRAY_WORDS_INTO '(' string ')'
448           {
449             kv_parser_set_stray_words_value_name(last_parser, $3);
450             free($3);
451           }
452 	| parser_opt
453 	;
454 
455 
456 source_content
457         :
458           { cfg_lexer_push_context(lexer, LL_CONTEXT_SOURCE, NULL, "source statement"); }
459           source_items
460           { cfg_lexer_pop_context(lexer); }
461           {
462             $$ = log_expr_node_new_junction($2, &@$);
463           }
464         ;
465 
466 source_items
467         : source_item semicolons source_items	{ $$ = log_expr_node_append_tail(log_expr_node_new_pipe($1, &@1), $3); }
468         | log_fork semicolons source_items      { $$ = log_expr_node_append_tail($1,  $3); }
469 	|					{ $$ = NULL; }
470 	;
471 
472 source_item
473 	: source_afinter			{ $$ = $1; }
474         | source_plugin                         { $$ = $1; }
475 	;
476 
477 source_plugin
478         : LL_IDENTIFIER
479           {
480             Plugin *p;
481             gint context = LL_CONTEXT_SOURCE;
482 
483             p = cfg_find_plugin(configuration, context, $1);
484             CHECK_ERROR(p, @1, "%s plugin %s not found", cfg_lexer_lookup_context_name_by_type(context), $1);
485 
486             last_driver = (LogDriver *) cfg_parse_plugin(configuration, p, &@1, NULL);
487             free($1);
488             if (!last_driver)
489               {
490                 YYERROR;
491               }
492             $$ = last_driver;
493           }
494         ;
495 
496 source_afinter
497 	: KW_INTERNAL '(' source_afinter_params ')'			{ $$ = $3; }
498 	;
499 
500 source_afinter_params
501         : {
502             last_driver = afinter_sd_new(configuration);
503             last_source_options = &((AFInterSourceDriver *) last_driver)->source_options.super;
504           }
505           source_afinter_options { $$ = last_driver; }
506         ;
507 
508 source_afinter_options
509         : source_afinter_option source_afinter_options
510         |
511         ;
512 
513 source_afinter_option
514         : KW_LOG_FIFO_SIZE '(' positive_integer ')'	{ ((AFInterSourceOptions *) last_source_options)->queue_capacity = $3; }
515         | source_option
516         ;
517 
518 
519 filter_content
520         : {
521             FilterExprNode *last_filter_expr = NULL;
522 
523 	    CHECK_ERROR_WITHOUT_MESSAGE(cfg_parser_parse(&filter_expr_parser, lexer, (gpointer *) &last_filter_expr, NULL), @$);
524 
525             $$ = log_expr_node_new_pipe(log_filter_pipe_new(last_filter_expr, configuration), &@$);
526 	  }
527 	;
528 
529 parser_content
530         :
531           {
532             LogExprNode *last_parser_expr = NULL;
533 
534             CHECK_ERROR_WITHOUT_MESSAGE(cfg_parser_parse(&parser_expr_parser, lexer, (gpointer *) &last_parser_expr, NULL), @$);
535             $$ = last_parser_expr;
536           }
537         ;
538 
539 rewrite_content
540         :
541           {
542             LogExprNode *last_rewrite_expr = NULL;
543 
544             CHECK_ERROR_WITHOUT_MESSAGE(cfg_parser_parse(&rewrite_expr_parser, lexer, (gpointer *) &last_rewrite_expr, NULL), @$);
545             $$ = last_rewrite_expr;
546           }
547         ;
548 
549 dest_content
550          : { cfg_lexer_push_context(lexer, LL_CONTEXT_DESTINATION, NULL, "destination statement"); }
551             dest_items
552            { cfg_lexer_pop_context(lexer); }
553            {
554              $$ = log_expr_node_new_junction($2, &@$);
555            }
556          ;
557 
558 
559 dest_items
560         /* all destination drivers are added as an independent branch in a junction*/
561         : dest_item semicolons dest_items	{ $$ = log_expr_node_append_tail(log_expr_node_new_pipe($1, &@1), $3); }
562         | log_fork semicolons dest_items        { $$ = log_expr_node_append_tail($1,  $3); }
563 	|					{ $$ = NULL; }
564 	;
565 
566 dest_item
567         : dest_plugin                           { $$ = $1; }
568 	;
569 
570 dest_plugin
571         : LL_IDENTIFIER
572           {
573             Plugin *p;
574             gint context = LL_CONTEXT_DESTINATION;
575 
576             p = cfg_find_plugin(configuration, context, $1);
577             CHECK_ERROR(p, @1, "%s plugin %s not found", cfg_lexer_lookup_context_name_by_type(context), $1);
578 
579             last_driver = (LogDriver *) cfg_parse_plugin(configuration, p, &@1, NULL);
580             free($1);
581             if (!last_driver)
582               {
583                 YYERROR;
584               }
585             $$ = last_driver;
586           }
587         ;
588 
589 log_items
590 	: log_item semicolons log_items		{ log_expr_node_append_tail($1, $3); $$ = $1; }
591 	|					{ $$ = NULL; }
592 	;
593 
594 log_item
595         : KW_SOURCE '(' string ')'		{ $$ = log_expr_node_new_source_reference($3, &@$); free($3); }
596         | KW_SOURCE '{' source_content '}'      { $$ = log_expr_node_new_source(NULL, $3, &@$); }
597         | KW_FILTER '(' string ')'		{ $$ = log_expr_node_new_filter_reference($3, &@$); free($3); }
598         | KW_FILTER '{' filter_content '}'      { $$ = log_expr_node_new_filter(NULL, $3, &@$); }
599         | KW_PARSER '(' string ')'              { $$ = log_expr_node_new_parser_reference($3, &@$); free($3); }
600         | KW_PARSER '{' parser_content '}'      { $$ = log_expr_node_new_parser(NULL, $3, &@$); }
601         | KW_REWRITE '(' string ')'             { $$ = log_expr_node_new_rewrite_reference($3, &@$); free($3); }
602         | KW_REWRITE '{' rewrite_content '}'    { $$ = log_expr_node_new_rewrite(NULL, $3, &@$); }
603         | KW_DESTINATION '(' string ')'		{ $$ = log_expr_node_new_destination_reference($3, &@$); free($3); }
604         | KW_DESTINATION '{' dest_content '}'   { $$ = log_expr_node_new_destination(NULL, $3, &@$); }
605         | log_conditional			{ $$ = $1; }
606         | log_junction                          { $$ = $1; }
607 	;
608 
609 log_junction
610         : KW_JUNCTION '{' log_forks '}'         { $$ = log_expr_node_new_junction($3, &@$); }
611         ;
612 
613 log_last_junction
614 
615         /* this rule matches the last set of embedded log {}
616          * statements at the end of the log {} block.
617          * It is the final junction and was the only form of creating
618          * a processing tree before syslog-ng 3.4.
619          *
620          * We emulate if the user was writing junction {} explicitly.
621          */
622         : log_forks                             { $$ = $1 ? log_expr_node_new_junction($1, &@1) :  NULL; }
623         ;
624 
625 
626 log_forks
627         : log_fork semicolons log_forks		{ log_expr_node_append_tail($1, $3); $$ = $1; }
628         |                                       { $$ = NULL; }
629         ;
630 
631 log_fork
632         : KW_LOG '{' log_content '}'            { $$ = $3; }
633         | KW_CHANNEL '{' log_content '}'        { $$ = $3; }
634         ;
635 
636 log_conditional
637         : log_if				{ $$ = $1; }
638         | log_if KW_ELSE '{' log_content '}'
639           {
640             log_expr_node_conditional_set_false_branch_of_the_last_if($1, $4);
641             $$ = $1;
642           }
643         ;
644 
645 log_if
646         : KW_IF '(' filter_content ')' '{' log_content '}'
647           {
648             $$ = log_expr_node_new_conditional_with_filter($3, $6, &@$);
649           }
650         | KW_IF '{' log_content '}'
651           {
652             $$ = log_expr_node_new_conditional_with_block($3, &@$);
653           }
654         | log_if KW_ELIF '(' filter_content ')' '{' log_content '}'
655           {
656             LogExprNode *false_branch;
657 
658             false_branch = log_expr_node_new_conditional_with_filter($4, $7, &@$);
659             log_expr_node_conditional_set_false_branch_of_the_last_if($1, false_branch);
660             $$ = $1;
661           }
662         | log_if KW_ELIF '{' log_content '}'
663           {
664             LogExprNode *false_branch;
665 
666             false_branch = log_expr_node_new_conditional_with_block($4, &@$);
667             log_expr_node_conditional_set_false_branch_of_the_last_if($1, false_branch);
668             $$ = $1;
669           }
670         ;
671 
672 log_content
673         : log_items log_last_junction log_flags                { $$ = log_expr_node_new_log(log_expr_node_append_tail($1, $2), $3, &@$); }
674         ;
675 
676 log_flags
677 	: KW_FLAGS '(' log_flags_items ')' semicolons	{ $$ = $3; }
678 	|					{ $$ = 0; }
679 	;
680 
681 log_flags_items
682 	: normalized_flag log_flags_items	{ $$ = log_expr_node_lookup_flag($1) | $2; free($1); }
683 	|					{ $$ = 0; }
684 	;
685 
686 
687 template_content_inner
688         : string
689         {
690           GError *error = NULL;
691 
692           CHECK_ERROR_GERROR(log_template_compile(last_template, $1, &error), @1, error, "Error compiling template");
693           free($1);
694         }
695         | LL_IDENTIFIER '(' string ')'
696         {
697           GError *error = NULL;
698 
699           CHECK_ERROR_GERROR(log_template_compile(last_template, $3, &error), @3, error, "Error compiling template");
700           free($3);
701 
702           CHECK_ERROR_GERROR(log_template_set_type_hint(last_template, $1, &error), @1, error, "Error setting the template type-hint \"%s\"", $1);
703           free($1);
704         }
705         ;
706 
707 template_content
708         : { last_template = log_template_new(configuration, NULL); } template_content_inner	{ $$ = last_template; }
709         ;
710 
711 template_content_list
712 	: template_content template_content_list { $$ = g_list_prepend($2, $1); }
713 	| { $$ = NULL; }
714 	;
715 
716 
717 
718 string
719 	: LL_IDENTIFIER
720 	| LL_STRING
721 	;
722 
723 yesno
724 	: KW_YES				{ $$ = 1; }
725 	| KW_NO					{ $$ = 0; }
726 	| LL_NUMBER				{ $$ = $1; }
727 	;
728 
729 dnsmode
730 	: yesno					{ $$ = $1; }
731 	| KW_PERSIST_ONLY                       { $$ = 2; }
732 	;
733 
734 nonnegative_integer64
735         : LL_NUMBER
736           {
737             CHECK_ERROR(($1 >= 0), @1, "It cannot be negative");
738           }
739         ;
740 
741 nonnegative_integer
742         : nonnegative_integer64
743           {
744             CHECK_ERROR(($1 <= G_MAXINT32), @1, "Must be smaller than 2^31");
745           }
746         ;
747 
748 positive_integer64
749         : LL_NUMBER
750           {
751             CHECK_ERROR(($1 > 0), @1, "Must be positive");
752           }
753         ;
754 
755 positive_integer
756         : positive_integer64
757           {
758             CHECK_ERROR(($1 <= G_MAXINT32), @1, "Must be smaller than 2^31");
759           }
760         ;
761 
762 nonnegative_float
763         : LL_FLOAT
764           {
765             CHECK_ERROR(($1 >= 0), @1, "It cannot be negative");
766           }
767         | nonnegative_integer
768           {
769             $$ = (double) $1;
770           }
771         ;
772 
773 positive_float
774         : LL_FLOAT
775           {
776             CHECK_ERROR(($1 > 0), @1, "Must be positive");
777           }
778         | positive_integer
779           {
780             $$ = (double) $1;
781           }
782         ;
783 
784 string_or_number
785         : string                                { $$ = $1; }
786         | LL_NUMBER                             { $$ = strdup(lexer->token_text->str); }
787         | LL_FLOAT                              { $$ = strdup(lexer->token_text->str); }
788         ;
789 
790 path
791 	: string
792 	  {
793             struct stat buffer;
794             int ret = stat($1, &buffer);
795             CHECK_ERROR((ret == 0), @1, "File \"%s\" not found: %s", $1, strerror(errno));
796             $$ = $1;
797 	  }
798 	;
799 
800 path_check
801     : path { cfg_path_track_file(configuration, $1, "path_check"); }
802     ;
803 
804 path_secret
805     : path { cfg_path_track_file(configuration, $1, "path_secret"); }
806     ;
807 
808 path_no_check
809     : string { cfg_path_track_file(configuration, $1, "path_no_check"); }
810     ;
811 
812 normalized_flag
813         : string                                { $$ = normalize_flag($1); free($1); }
814         ;
815 
816 string_list
817         : string_list_build                     { $$ = $1; }
818         ;
819 
820 string_list_build
821         : string string_list_build		{ $$ = g_list_prepend($2, g_strdup($1)); free($1); }
822         |					{ $$ = NULL; }
823         ;
824 
825 semicolons
826         : ';'
827         | ';' semicolons
828         ;
829 
830 severity_string
831         : string
832 	  {
833 	    /* return the numeric value of the "level" */
834 	    int n = syslog_name_lookup_severity_by_name($1);
835 	    CHECK_ERROR((n != -1), @1, "Unknown priority level\"%s\"", $1);
836 	    free($1);
837             $$ = n;
838 	  }
839         ;
840 
841 facility_string
842         : string
843           {
844             /* return the numeric value of facility */
845 	    int n = syslog_name_lookup_facility_by_name($1);
846 	    CHECK_ERROR((n != -1), @1, "Unknown facility \"%s\"", $1);
847 	    free($1);
848 	    $$ = n;
849 	  }
850         | KW_SYSLOG 				{ $$ = LOG_SYSLOG; }
851         ;
852 
853 parser_opt
854         : KW_TEMPLATE '(' string ')'            {
855                                                   LogTemplate *template;
856                                                   GError *error = NULL;
857 
858                                                   template = cfg_tree_check_inline_template(&configuration->tree, $3, &error);
859                                                   CHECK_ERROR_GERROR(template != NULL, @3, error, "Error compiling template");
860                                                   log_parser_set_template(last_parser, template);
861                                                   free($3);
862                                                 }
863         ;
864 
865 driver_option
866         : KW_PERSIST_NAME '(' string ')' { log_pipe_set_persist_name(&last_driver->super, $3); free($3); }
867         ;
868 
869 inner_source
870         : LL_IDENTIFIER
871           {
872             Plugin *p;
873             gint context = LL_CONTEXT_INNER_SRC;
874             gpointer value;
875 
876             p = cfg_find_plugin(configuration, context, $1);
877             CHECK_ERROR(p, @1, "%s plugin %s not found", cfg_lexer_lookup_context_name_by_type(context), $1);
878 
879             value = cfg_parse_plugin(configuration, p, &@1, last_driver);
880 
881             free($1);
882             if (!value)
883               {
884                 YYERROR;
885               }
886             if (!log_driver_add_plugin(last_driver, (LogDriverPlugin *) value))
887               {
888                 log_driver_plugin_free(value);
889                 CHECK_ERROR(TRUE, @1, "Error while registering the plugin %s in this destination", $1);
890               }
891           }
892         ;
893 
894 /* All source drivers should incorporate this rule, implies driver_option */
895 source_driver_option
896         : inner_source
897         | driver_option
898         ;
899 
900 inner_dest
901         : LL_IDENTIFIER
902           {
903             Plugin *p;
904             gint context = LL_CONTEXT_INNER_DEST;
905             gpointer value;
906 
907             p = cfg_find_plugin(configuration, context, $1);
908             CHECK_ERROR(p, @1, "%s plugin %s not found", cfg_lexer_lookup_context_name_by_type(context), $1);
909 
910             value = cfg_parse_plugin(configuration, p, &@1, last_driver);
911 
912             free($1);
913             if (!value)
914               {
915                 YYERROR;
916               }
917             if (!log_driver_add_plugin(last_driver, (LogDriverPlugin *) value))
918               {
919                 log_driver_plugin_free(value);
920                 CHECK_ERROR(TRUE, @1, "Error while registering the plugin %s in this destination", $1);
921               }
922           }
923         ;
924 
925 /* implies driver_option */
926 dest_driver_option
927         /* NOTE: plugins need to set "last_driver" in order to incorporate this rule in their grammar */
928 
929 	: KW_LOG_FIFO_SIZE '(' positive_integer ')'	{ ((LogDestDriver *) last_driver)->log_fifo_size = $3; }
930 	| KW_THROTTLE '(' nonnegative_integer ')'         { ((LogDestDriver *) last_driver)->throttle = $3; }
931         | inner_dest
932         | driver_option
933         ;
934 
935 threaded_dest_driver_batch_option
936         : KW_BATCH_LINES '(' nonnegative_integer ')' { log_threaded_dest_driver_set_batch_lines(last_driver, $3); }
937         | KW_BATCH_TIMEOUT '(' positive_integer ')' { log_threaded_dest_driver_set_batch_timeout(last_driver, $3); }
938         ;
939 
940 threaded_dest_driver_workers_option
941         : KW_WORKERS '(' positive_integer ')'  { log_threaded_dest_driver_set_num_workers(last_driver, $3); }
942         ;
943 
944 /* implies dest_driver_option */
945 threaded_dest_driver_general_option
946 	: KW_RETRIES '(' positive_integer ')'
947         {
948           log_threaded_dest_driver_set_max_retries_on_error(last_driver, $3);
949         }
950         | KW_TIME_REOPEN '(' positive_integer ')' { log_threaded_dest_driver_set_time_reopen(last_driver, $3); }
951         | dest_driver_option
952         ;
953 
954 /* implies source_driver_option and source_option */
955 threaded_source_driver_option
956 	: KW_FORMAT '(' string ')' { log_threaded_source_driver_get_parse_options(last_driver)->format = g_strdup($3); free($3); }
957         | KW_FLAGS '(' threaded_source_driver_option_flags ')'
958         | { last_msg_format_options = log_threaded_source_driver_get_parse_options(last_driver); } msg_format_option
959         | { last_source_options = log_threaded_source_driver_get_source_options(last_driver); } source_option
960         | source_driver_option
961         ;
962 
963 threaded_fetcher_driver_option
964         : KW_FETCH_NO_DATA_DELAY '(' nonnegative_float ')' { log_threaded_fetcher_driver_set_fetch_no_data_delay(last_driver, $3); }
965         | KW_TIME_REOPEN '(' positive_integer ')' { log_threaded_fetcher_driver_set_time_reopen(last_driver, $3); }
966         ;
967 
968 threaded_source_driver_option_flags
969 	: string threaded_source_driver_option_flags
970         {
971           CHECK_ERROR(msg_format_options_process_flag(log_threaded_source_driver_get_parse_options(last_driver), $1), @1, "Unknown flag \"%s\"", $1);
972           free($1);
973         }
974         |
975         ;
976 
977 /* LogSource related options */
978 source_option
979         /* NOTE: plugins need to set "last_source_options" in order to incorporate this rule in their grammar */
980 	: KW_LOG_IW_SIZE '(' positive_integer ')'	{ last_source_options->init_window_size = $3; }
981 	| KW_CHAIN_HOSTNAMES '(' yesno ')'	{ last_source_options->chain_hostnames = $3; }
982 	| KW_KEEP_HOSTNAME '(' yesno ')'	{ last_source_options->keep_hostname = $3; }
983 	| KW_PROGRAM_OVERRIDE '(' string ')'	{ last_source_options->program_override = g_strdup($3); free($3); }
984 	| KW_HOST_OVERRIDE '(' string ')'	{ last_source_options->host_override = g_strdup($3); free($3); }
985 	| KW_LOG_PREFIX '(' string ')'	        { gchar *p = strrchr($3, ':'); if (p) *p = 0; last_source_options->program_override = g_strdup($3); free($3); }
986 	| KW_KEEP_TIMESTAMP '(' yesno ')'	{ last_source_options->keep_timestamp = $3; }
987 	| KW_READ_OLD_RECORDS '(' yesno ')'	{ last_source_options->read_old_records = $3; }
988 	| KW_USE_SYSLOGNG_PID '(' yesno ')'	{ last_source_options->use_syslogng_pid = $3; }
989         | KW_TAGS '(' string_list ')'		{ log_source_options_set_tags(last_source_options, $3); }
990         | { last_host_resolve_options = &last_source_options->host_resolve_options; } host_resolve_option
991         ;
992 
993 /* LogReader related options, implies source_option */
994 source_reader_option
995         /* NOTE: plugins need to set "last_reader_options" in order to incorporate this rule in their grammar */
996 
997 	: KW_CHECK_HOSTNAME '(' yesno ')'	{ last_reader_options->check_hostname = $3; }
998 	| KW_FLAGS '(' source_reader_option_flags ')'
999 	| KW_LOG_FETCH_LIMIT '(' positive_integer ')'	{ last_reader_options->fetch_limit = $3; }
1000         | KW_FORMAT '(' string ')'              { last_reader_options->parse_options.format = g_strdup($3); free($3); }
1001         | { last_source_options = &last_reader_options->super; } source_option
1002         | { last_proto_server_options = &last_reader_options->proto_options.super; } source_proto_option
1003         | { last_msg_format_options = &last_reader_options->parse_options; } msg_format_option
1004 	;
1005 
1006 source_reader_option_flags
1007         : string source_reader_option_flags     { CHECK_ERROR(log_reader_options_process_flag(last_reader_options, $1), @1, "Unknown flag \"%s\"", $1); free($1); }
1008         | KW_CHECK_HOSTNAME source_reader_option_flags     { log_reader_options_process_flag(last_reader_options, "check-hostname"); }
1009 	|
1010 	;
1011 
1012 /* LogProtoSource related options */
1013 source_proto_option
1014         : KW_ENCODING '(' string ')'
1015           {
1016             CHECK_ERROR(log_proto_server_options_set_encoding(last_proto_server_options, $3),
1017                         @3,
1018                         "unknown encoding \"%s\"", $3);
1019             free($3);
1020           }
1021         | KW_LOG_MSG_SIZE '(' positive_integer ')'      { last_proto_server_options->max_msg_size = $3; }
1022         | KW_TRIM_LARGE_MESSAGES '(' yesno ')'          { last_proto_server_options->trim_large_messages = $3; }
1023         ;
1024 
1025 host_resolve_option
1026         : KW_USE_FQDN '(' yesno ')'             { last_host_resolve_options->use_fqdn = $3; }
1027         | KW_USE_DNS '(' dnsmode ')'            { last_host_resolve_options->use_dns = $3; }
1028 	| KW_DNS_CACHE '(' yesno ')' 		{ last_host_resolve_options->use_dns_cache = $3; }
1029 	| KW_NORMALIZE_HOSTNAMES '(' yesno ')'	{ last_host_resolve_options->normalize_hostnames = $3; }
1030 	;
1031 
1032 msg_format_option
1033 	: KW_TIME_ZONE '(' string ')'		{ last_msg_format_options->recv_time_zone = g_strdup($3); free($3); }
1034 	| KW_DEFAULT_SEVERITY '(' severity_string ')'
1035 	  {
1036 	    if (last_msg_format_options->default_pri == 0xFFFF)
1037 	      last_msg_format_options->default_pri = LOG_USER;
1038 	    last_msg_format_options->default_pri = (last_msg_format_options->default_pri & ~LOG_PRIMASK) | $3;
1039           }
1040 	| KW_DEFAULT_FACILITY '(' facility_string ')'
1041 	  {
1042 	    if (last_msg_format_options->default_pri == 0xFFFF)
1043 	      last_msg_format_options->default_pri = LOG_NOTICE;
1044 	    last_msg_format_options->default_pri = (last_msg_format_options->default_pri & LOG_PRIMASK) | $3;
1045           }
1046         ;
1047 
1048 dest_writer_options
1049 	: dest_writer_option dest_writer_options
1050 	|
1051 	;
1052 
1053 dest_writer_option
1054         /* NOTE: plugins need to set "last_writer_options" in order to incorporate this rule in their grammar */
1055 
1056 	: KW_FLAGS '(' dest_writer_options_flags ')' { last_writer_options->options = $3; }
1057 	| KW_FLUSH_LINES '(' nonnegative_integer ')'		{ last_writer_options->flush_lines = $3; }
1058 	| KW_FLUSH_TIMEOUT '(' positive_integer ')'	{ }
1059         | KW_SUPPRESS '(' nonnegative_integer ')'            { last_writer_options->suppress = $3; }
1060 	| KW_TEMPLATE '(' string ')'       	{
1061                                                   GError *error = NULL;
1062 
1063                                                   last_writer_options->template = cfg_tree_check_inline_template(&configuration->tree, $3, &error);
1064                                                   CHECK_ERROR_GERROR(last_writer_options->template != NULL, @3, error, "Error compiling template");
1065 	                                          free($3);
1066 	                                        }
1067 	| KW_TEMPLATE_ESCAPE '(' yesno ')'	{ log_writer_options_set_template_escape(last_writer_options, $3); }
1068 	| KW_PAD_SIZE '(' nonnegative_integer ')'         { last_writer_options->padding = $3; }
1069 	| KW_TRUNCATE_SIZE '(' nonnegative_integer ')'         { last_writer_options->truncate_size = $3; }
1070 	| KW_MARK_FREQ '(' nonnegative_integer ')'        { last_writer_options->mark_freq = $3; }
1071         | KW_MARK_MODE '(' KW_INTERNAL ')'      { log_writer_options_set_mark_mode(last_writer_options, "internal"); }
1072 	| KW_MARK_MODE '(' string ')'
1073 	  {
1074 	    CHECK_ERROR(cfg_lookup_mark_mode($3) != -1, @3, "illegal mark mode \"%s\"", $3);
1075             log_writer_options_set_mark_mode(last_writer_options, $3);
1076             free($3);
1077           }
1078 	| KW_TIME_REOPEN '(' positive_integer ')' { last_writer_options->time_reopen = $3; }
1079         | { last_template_options = &last_writer_options->template_options; } template_option
1080 	;
1081 
1082 dest_writer_options_flags
1083 	: normalized_flag dest_writer_options_flags   { $$ = log_writer_options_lookup_flag($1) | $2; free($1); }
1084 	|					      { $$ = 0; }
1085 	;
1086 
1087 file_perm_option
1088 	: KW_OWNER '(' string_or_number ')'	{ file_perm_options_set_file_uid(last_file_perm_options, $3); free($3); }
1089 	| KW_OWNER '(' ')'	                { file_perm_options_dont_change_file_uid(last_file_perm_options); }
1090 	| KW_GROUP '(' string_or_number ')'	{ file_perm_options_set_file_gid(last_file_perm_options, $3); free($3); }
1091 	| KW_GROUP '(' ')'	                { file_perm_options_dont_change_file_gid(last_file_perm_options); }
1092 	| KW_PERM '(' LL_NUMBER ')'		{ file_perm_options_set_file_perm(last_file_perm_options, $3); }
1093 	| KW_PERM '(' ')'		        { file_perm_options_dont_change_file_perm(last_file_perm_options); }
1094         | KW_DIR_OWNER '(' string_or_number ')'	{ file_perm_options_set_dir_uid(last_file_perm_options, $3); free($3); }
1095 	| KW_DIR_OWNER '(' ')'	                { file_perm_options_dont_change_dir_uid(last_file_perm_options); }
1096 	| KW_DIR_GROUP '(' string_or_number ')'	{ file_perm_options_set_dir_gid(last_file_perm_options, $3); free($3); }
1097 	| KW_DIR_GROUP '(' ')'	                { file_perm_options_dont_change_dir_gid(last_file_perm_options); }
1098 	| KW_DIR_PERM '(' LL_NUMBER ')'		{ file_perm_options_set_dir_perm(last_file_perm_options, $3); }
1099 	| KW_DIR_PERM '(' ')'		        { file_perm_options_dont_change_dir_perm(last_file_perm_options); }
1100         ;
1101 
1102 template_option
1103 	: KW_TS_FORMAT '(' string ')'		{ last_template_options->ts_format = cfg_ts_format_value($3); free($3); }
1104 	| KW_FRAC_DIGITS '(' nonnegative_integer ')'	{ last_template_options->frac_digits = $3; }
1105 	| KW_TIME_ZONE '(' string ')'		{ last_template_options->time_zone[LTZ_SEND] = g_strdup($3); free($3); }
1106 	| KW_SEND_TIME_ZONE '(' string ')'      { last_template_options->time_zone[LTZ_SEND] = g_strdup($3); free($3); }
1107 	| KW_LOCAL_TIME_ZONE '(' string ')'     { last_template_options->time_zone[LTZ_LOCAL] = g_strdup($3); free($3); }
1108 	| KW_ON_ERROR '(' string ')'
1109         {
1110           gint on_error;
1111 
1112           CHECK_ERROR(log_template_on_error_parse($3, &on_error), @3, "Invalid on-error() setting \"%s\"", $3);
1113           free($3);
1114 
1115           log_template_options_set_on_error(last_template_options, on_error);
1116         }
1117 	;
1118 
1119 matcher_option
1120         : KW_TYPE '(' string ')'		{ CHECK_ERROR(log_matcher_options_set_type(last_matcher_options, $3), @3, "unknown matcher type \"%s\"", $3); free($3); }
1121         | KW_FLAGS '(' matcher_flags ')'
1122         ;
1123 
1124 matcher_flags
1125         : string matcher_flags			{ CHECK_ERROR(log_matcher_options_process_flag(last_matcher_options, $1), @1, "unknown matcher flag \"%s\"", $1); free($1); }
1126         |
1127         ;
1128 
1129 value_pair_option
1130 	: KW_VALUE_PAIRS
1131           {
1132             last_value_pairs = value_pairs_new();
1133           }
1134           '(' vp_options ')'
1135           { $$ = last_value_pairs; }
1136 	;
1137 
1138 vp_options
1139 	: vp_option vp_options
1140 	|
1141 	;
1142 
1143 vp_option
1144         : KW_PAIR '(' string ':' template_content ')'
1145           {
1146             value_pairs_add_pair(last_value_pairs, $3, $5);
1147             free($3);
1148           }
1149         | KW_PAIR '(' string template_content ')'
1150           {
1151             value_pairs_add_pair(last_value_pairs, $3, $4);
1152             free($3);
1153           }
1154         | KW_KEY '(' string KW_REKEY '('
1155           {
1156             last_vp_transset = value_pairs_transform_set_new($3);
1157             value_pairs_add_glob_pattern(last_value_pairs, $3, TRUE);
1158             free($3);
1159           }
1160           vp_rekey_options ')'                           { value_pairs_add_transforms(last_value_pairs, last_vp_transset); } ')'
1161 	| KW_KEY '(' string_list ')'		         { value_pairs_add_glob_patterns(last_value_pairs, $3, TRUE); }
1162         | KW_REKEY '(' string
1163           {
1164             last_vp_transset = value_pairs_transform_set_new($3);
1165             free($3);
1166           }
1167           vp_rekey_options ')'                           { value_pairs_add_transforms(last_value_pairs, last_vp_transset); }
1168         | KW_EXCLUDE '(' string_list ')'                 { value_pairs_add_glob_patterns(last_value_pairs, $3, FALSE); }
1169 	| KW_SCOPE '(' vp_scope_list ')'
1170 	;
1171 
1172 vp_scope_list
1173 	: string vp_scope_list                           { value_pairs_add_scope(last_value_pairs, $1); free($1); }
1174 	|
1175 	;
1176 
1177 vp_rekey_options
1178 	: vp_rekey_option vp_rekey_options
1179         |
1180 	;
1181 
1182 vp_rekey_option
1183 	: KW_SHIFT '(' positive_integer ')' { value_pairs_transform_set_add_func(last_vp_transset, value_pairs_new_transform_shift($3)); }
1184 	| KW_SHIFT_LEVELS '(' positive_integer ')' { value_pairs_transform_set_add_func(last_vp_transset, value_pairs_new_transform_shift_levels($3)); }
1185 	| KW_ADD_PREFIX '(' string ')' { value_pairs_transform_set_add_func(last_vp_transset, value_pairs_new_transform_add_prefix($3)); free($3); }
1186 	| KW_REPLACE_PREFIX '(' string string ')' { value_pairs_transform_set_add_func(last_vp_transset, value_pairs_new_transform_replace_prefix($3, $4)); free($3); free($4); }
1187 	;
1188 
1189 rewrite_expr_opt
1190         : KW_VALUE '(' string ')'
1191           {
1192             const gchar *p = $3;
1193             if (p[0] == '$')
1194               {
1195                 msg_warning("Value references in rewrite rules should not use the '$' prefix, those are only needed in templates",
1196                             evt_tag_str("value", $3),
1197                             cfg_lexer_format_location_tag(lexer, &@3));
1198                 p++;
1199               }
1200             last_rewrite->value_handle = log_msg_get_value_handle(p);
1201             CHECK_ERROR(!log_msg_is_handle_macro(last_rewrite->value_handle), @3, "%s is read-only, it cannot be changed in rewrite rules", p);
1202 	    CHECK_ERROR(log_msg_is_value_name_valid(p), @3, "%s is not a valid name for a name-value pair, perhaps a misspelled .SDATA reference?", p);
1203             free($3);
1204           }
1205         | rewrite_condition_opt
1206         ;
1207 
1208 rewrite_condition_opt
1209         : KW_CONDITION '('
1210           {
1211             FilterExprNode *filter_expr;
1212 
1213             CHECK_ERROR_WITHOUT_MESSAGE(cfg_parser_parse(&filter_expr_parser, lexer, (gpointer *) &filter_expr, NULL), @1);
1214             log_rewrite_set_condition(last_rewrite, filter_expr);
1215           } ')'
1216         ;
1217 
1218 
1219 
1220 %%
1221