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