1 /*
2 * Copyright (c) 2002-2014 Balabit
3 * Copyright (c) 1998-2012 Balázs Scheidler
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 * As an additional exemption you are allowed to compile & link against the
20 * OpenSSL libraries as published by the OpenSSL project. See the file
21 * COPYING for details.
22 *
23 */
24
25 #include "cfg.h"
26 #include "cfg-path.h"
27 #include "cfg-grammar.h"
28 #include "module-config.h"
29 #include "cfg-tree.h"
30 #include "messages.h"
31 #include "template/templates.h"
32 #include "userdb.h"
33 #include "logmsg/logmsg.h"
34 #include "dnscache.h"
35 #include "serialize.h"
36 #include "plugin.h"
37 #include "cfg-parser.h"
38 #include "stats/stats-registry.h"
39 #include "logproto/logproto-builtins.h"
40 #include "reloc.h"
41 #include "hostname.h"
42 #include "rcptid.h"
43 #include "resolved-configurable-paths.h"
44 #include "mainloop.h"
45 #include "timeutils/format.h"
46
47 #include <sys/types.h>
48 #include <signal.h>
49 #include <stdio.h>
50 #include <string.h>
51 #include <stdlib.h>
52 #include <iv_work.h>
53
54 /* PersistConfig */
55
56 struct _PersistConfig
57 {
58 GHashTable *keys;
59 };
60
61 typedef struct _PersistConfigEntry
62 {
63 gpointer value;
64 GDestroyNotify destroy;
65 } PersistConfigEntry;
66
67 static void
persist_config_entry_free(PersistConfigEntry * self)68 persist_config_entry_free(PersistConfigEntry *self)
69 {
70 if (self->destroy)
71 {
72 self->destroy(self->value);
73 }
74 g_free(self);
75 }
76
77 PersistConfig *
persist_config_new(void)78 persist_config_new(void)
79 {
80 PersistConfig *self = g_new0(PersistConfig, 1);
81
82 self->keys = g_hash_table_new_full(g_str_hash, g_str_equal, (GDestroyNotify) g_free,
83 (GDestroyNotify) persist_config_entry_free);
84 return self;
85 }
86
87 void
persist_config_free(PersistConfig * self)88 persist_config_free(PersistConfig *self)
89 {
90 g_hash_table_destroy(self->keys);
91 g_free(self);
92 }
93
94 gint
cfg_ts_format_value(gchar * format)95 cfg_ts_format_value(gchar *format)
96 {
97 if (strcmp(format, "rfc3164") == 0 || strcmp(format, "bsd") == 0)
98 return TS_FMT_BSD;
99 else if (strcmp(format, "rfc3339") == 0 || strcmp(format, "iso") == 0)
100 return TS_FMT_ISO;
101 else if (strcmp(format, "full") == 0)
102 return TS_FMT_FULL;
103 else if (strcmp(format, "unix") == 0 || strcmp(format, "utc") == 0)
104 return TS_FMT_UNIX;
105 else
106 {
107 msg_error("Invalid ts_format() value",
108 evt_tag_str("value", format));
109 return TS_FMT_BSD;
110 }
111 }
112
113 void
cfg_bad_hostname_set(GlobalConfig * self,gchar * bad_hostname_re)114 cfg_bad_hostname_set(GlobalConfig *self, gchar *bad_hostname_re)
115 {
116 if (self->bad_hostname_re)
117 g_free(self->bad_hostname_re);
118 self->bad_hostname_re = g_strdup(bad_hostname_re);
119 }
120
121 gint
cfg_lookup_mark_mode(const gchar * mark_mode)122 cfg_lookup_mark_mode(const gchar *mark_mode)
123 {
124 if (!strcmp(mark_mode, "internal"))
125 return MM_INTERNAL;
126 if (!strcmp(mark_mode, "dst_idle") || !strcmp(mark_mode, "dst-idle"))
127 return MM_DST_IDLE;
128 if (!strcmp(mark_mode, "host_idle") || !strcmp(mark_mode, "host-idle"))
129 return MM_HOST_IDLE;
130 if (!strcmp(mark_mode, "periodical"))
131 return MM_PERIODICAL;
132 if (!strcmp(mark_mode, "none"))
133 return MM_NONE;
134 if (!strcmp(mark_mode, "global"))
135 return MM_GLOBAL;
136
137 return -1;
138 }
139
140 void
cfg_set_mark_mode(GlobalConfig * self,const gchar * mark_mode)141 cfg_set_mark_mode(GlobalConfig *self, const gchar *mark_mode)
142 {
143 self->mark_mode = cfg_lookup_mark_mode(mark_mode);
144 }
145
146 static void
_invoke_module_init(gchar * key,ModuleConfig * mc,gpointer * args)147 _invoke_module_init(gchar *key, ModuleConfig *mc, gpointer *args)
148 {
149 GlobalConfig *cfg = (GlobalConfig *) args[0];
150 gboolean *result = (gboolean *) args[1];
151
152 if (!module_config_init(mc, cfg))
153 *result = FALSE;
154 }
155
156 static void
_invoke_module_deinit(gchar * key,ModuleConfig * mc,gpointer user_data)157 _invoke_module_deinit(gchar *key, ModuleConfig *mc, gpointer user_data)
158 {
159 GlobalConfig *cfg = (GlobalConfig *) user_data;
160
161 module_config_deinit(mc, cfg);
162 }
163
164 static gboolean
_sync_plugin_module_path_with_global_define(GlobalConfig * self)165 _sync_plugin_module_path_with_global_define(GlobalConfig *self)
166 {
167 const gchar *module_path;
168
169 /* Sync the @define module-path with the actual module search path as implemented by plugin.
170 *
171 * if @define module-path is not defined, we use whatever there's in
172 * PluginContext by default */
173 if (self->lexer)
174 {
175 module_path = cfg_args_get(self->globals, "module-path");
176 if (module_path && strcmp(module_path, self->plugin_context.module_path) != 0)
177 {
178 plugin_context_set_module_path(&self->plugin_context, module_path);
179 return TRUE;
180 }
181 }
182 return FALSE;
183 }
184
185 gboolean
cfg_load_module_with_args(GlobalConfig * cfg,const gchar * module_name,CfgArgs * args)186 cfg_load_module_with_args(GlobalConfig *cfg, const gchar *module_name, CfgArgs *args)
187 {
188 _sync_plugin_module_path_with_global_define(cfg);
189 return plugin_load_module(&cfg->plugin_context, module_name, args);
190 }
191
192 gboolean
cfg_load_module(GlobalConfig * cfg,const gchar * module_name)193 cfg_load_module(GlobalConfig *cfg, const gchar *module_name)
194 {
195 return cfg_load_module_with_args(cfg, module_name, NULL);
196 }
197
198 void
cfg_load_forced_modules(GlobalConfig * self)199 cfg_load_forced_modules(GlobalConfig *self)
200 {
201 static const gchar *module_list[] =
202 {
203 #if (!SYSLOG_NG_ENABLE_FORCED_SERVER_MODE)
204 "license"
205 #endif
206 };
207
208 if (!self->enable_forced_modules)
209 return;
210
211 int i;
212 for (i=0; i<sizeof(module_list)/sizeof(gchar *); ++i)
213 {
214 const gchar *name = module_list[i];
215
216 if (!cfg_load_module(self, name))
217 {
218 msg_error("Error loading module, forcing exit", evt_tag_str("module", name));
219 exit(1);
220 }
221 }
222 }
223
224 static gboolean
_is_module_autoload_enabled(GlobalConfig * self)225 _is_module_autoload_enabled(GlobalConfig *self)
226 {
227 return atoi(cfg_args_get(self->globals, "autoload-compiled-modules") ? : "1");
228 }
229
230 void
cfg_discover_candidate_modules(GlobalConfig * self)231 cfg_discover_candidate_modules(GlobalConfig *self)
232 {
233 if (self->use_plugin_discovery && _is_module_autoload_enabled(self))
234 {
235 if (_sync_plugin_module_path_with_global_define(self) || !plugin_has_discovery_run(&self->plugin_context))
236 plugin_discover_candidate_modules(&self->plugin_context);
237 }
238 }
239
240 gboolean
cfg_is_module_available(GlobalConfig * self,const gchar * module_name)241 cfg_is_module_available(GlobalConfig *self, const gchar *module_name)
242 {
243 cfg_discover_candidate_modules(self);
244 if (!_is_module_autoload_enabled(self))
245 return cfg_load_module(self, module_name);
246
247 return plugin_is_module_available(&self->plugin_context, module_name);
248 }
249
250 Plugin *
cfg_find_plugin(GlobalConfig * cfg,gint plugin_type,const gchar * plugin_name)251 cfg_find_plugin(GlobalConfig *cfg, gint plugin_type, const gchar *plugin_name)
252 {
253 return plugin_find(&cfg->plugin_context, plugin_type, plugin_name);
254 }
255
256 /* construct a plugin instance by parsing its relevant portion from the
257 * configuration file */
258 gpointer
cfg_parse_plugin(GlobalConfig * cfg,Plugin * plugin,CFG_LTYPE * yylloc,gpointer arg)259 cfg_parse_plugin(GlobalConfig *cfg, Plugin *plugin, CFG_LTYPE *yylloc, gpointer arg)
260 {
261 CfgTokenBlock *block;
262 CFG_STYPE token;
263
264
265 /* we add two tokens to an inserted token-block:
266 * 1) the plugin type (in order to make it possible to support different
267 * plugins from the same grammar)
268 *
269 * 2) the keyword equivalent of the plugin name
270 */
271 block = cfg_token_block_new();
272
273 /* add plugin->type as a token */
274 memset(&token, 0, sizeof(token));
275 token.type = LL_TOKEN;
276 token.token = plugin->type;
277 cfg_token_block_add_and_consume_token(block, &token);
278
279 /* start a new lexer context, so plugin specific keywords are recognized,
280 * we only do this to lookup the parser name. */
281 cfg_lexer_push_context(cfg->lexer, plugin->parser->context, plugin->parser->keywords, plugin->parser->name);
282 cfg_lexer_lookup_keyword(cfg->lexer, &token, yylloc, plugin->name);
283 cfg_lexer_pop_context(cfg->lexer);
284
285 /* add plugin name token */
286 cfg_token_block_add_and_consume_token(block, &token);
287
288 cfg_lexer_inject_token_block(cfg->lexer, block);
289
290 return plugin_construct_from_config(plugin, cfg->lexer, arg);
291 }
292
293 static gboolean
cfg_init_modules(GlobalConfig * cfg)294 cfg_init_modules(GlobalConfig *cfg)
295 {
296 gboolean result = TRUE;
297 gpointer args[] = { cfg, &result };
298 g_hash_table_foreach(cfg->module_config, (GHFunc) _invoke_module_init, args);
299
300 return result;
301 }
302
303 static void
cfg_deinit_modules(GlobalConfig * cfg)304 cfg_deinit_modules(GlobalConfig *cfg)
305 {
306 g_hash_table_foreach(cfg->module_config, (GHFunc) _invoke_module_deinit, cfg);
307 }
308
309 /* Request that this configuration shuts down and terminates. Right now, as
310 * there's only one configuration executed in a syslog-ng process, it will
311 * cause the mainloop to exit. Should there be multiple configs running in
312 * the same process at a future point, this would only terminate one and
313 * continue with the rest.
314 */
315 void
cfg_shutdown(GlobalConfig * cfg)316 cfg_shutdown(GlobalConfig *cfg)
317 {
318 MainLoop *main_loop = main_loop_get_instance();
319 main_loop_exit(main_loop);
320 }
321
322 gboolean
cfg_is_shutting_down(GlobalConfig * cfg)323 cfg_is_shutting_down(GlobalConfig *cfg)
324 {
325 MainLoop *main_loop = main_loop_get_instance();
326 return main_loop_is_terminating(main_loop);
327 }
328
329 gboolean
cfg_init(GlobalConfig * cfg)330 cfg_init(GlobalConfig *cfg)
331 {
332 gint regerr;
333
334 if (cfg->file_template_name && !(cfg->file_template = cfg_tree_lookup_template(&cfg->tree, cfg->file_template_name)))
335 msg_error("Error resolving file template",
336 evt_tag_str("name", cfg->file_template_name));
337 if (cfg->proto_template_name && !(cfg->proto_template = cfg_tree_lookup_template(&cfg->tree, cfg->proto_template_name)))
338 msg_error("Error resolving protocol template",
339 evt_tag_str("name", cfg->proto_template_name));
340
341 if (cfg->bad_hostname_re)
342 {
343 if ((regerr = regcomp(&cfg->bad_hostname, cfg->bad_hostname_re, REG_NOSUB | REG_EXTENDED)) != 0)
344 {
345 gchar buf[256];
346
347 regerror(regerr, &cfg->bad_hostname, buf, sizeof(buf));
348 msg_error("Error compiling bad_hostname regexp",
349 evt_tag_str("error", buf));
350 }
351 else
352 {
353 cfg->bad_hostname_compiled = TRUE;
354 }
355 }
356
357 if (!rcptid_init(cfg->state, cfg->use_uniqid))
358 return FALSE;
359
360 stats_reinit(&cfg->stats_options);
361
362 dns_caching_update_options(&cfg->dns_cache_options);
363 hostname_reinit(cfg->custom_domain);
364 host_resolve_options_init_globals(&cfg->host_resolve_options);
365 log_template_options_init(&cfg->template_options, cfg);
366 if (!cfg_init_modules(cfg))
367 return FALSE;
368 if (!cfg_tree_start(&cfg->tree))
369 return FALSE;
370
371 /*
372 * TLDR: A half-initialized pipeline turned out to be really hard to deinitialize
373 * correctly when dedicated source/destination threads are spawned (because we
374 * would have to wait for workers to stop and guarantee some internal
375 * task/timer/fdwatch ordering in ivykis during this action).
376 * See: https://github.com/syslog-ng/syslog-ng/pull/3176#issuecomment-638849597
377 */
378 g_assert(cfg_tree_on_inited(&cfg->tree));
379 return TRUE;
380 }
381
382 gboolean
cfg_deinit(GlobalConfig * cfg)383 cfg_deinit(GlobalConfig *cfg)
384 {
385 cfg_deinit_modules(cfg);
386 rcptid_deinit();
387 return cfg_tree_stop(&cfg->tree);
388 }
389
390 void
cfg_set_version_without_validation(GlobalConfig * self,gint version)391 cfg_set_version_without_validation(GlobalConfig *self, gint version)
392 {
393 self->user_version = version;
394 }
395
396 gboolean
cfg_set_version(GlobalConfig * self,gint version)397 cfg_set_version(GlobalConfig *self, gint version)
398 {
399 if (self->user_version != 0)
400 {
401 msg_warning("WARNING: you have multiple @version directives in your configuration, only the first one is considered",
402 cfg_format_config_version_tag(self),
403 cfg_format_version_tag("new-version", version));
404 return TRUE;
405 }
406 cfg_set_version_without_validation(self, version);
407 if (cfg_is_config_version_older(self, VERSION_VALUE_3_0))
408 {
409 msg_error("ERROR: compatibility with configurations below 3.0 was dropped in " VERSION_3_13
410 ", please update your configuration accordingly",
411 cfg_format_config_version_tag(self));
412 return FALSE;
413 }
414
415 if (cfg_is_config_version_older(self, VERSION_VALUE_LAST_SEMANTIC_CHANGE))
416 {
417 msg_warning("WARNING: Configuration file format is too old, syslog-ng is running in compatibility mode. "
418 "Please update it to use the " VERSION_PRODUCT_CURRENT " format at your time of convenience. "
419 "To upgrade the configuration, please review the warnings about incompatible changes printed "
420 "by syslog-ng, and once completed change the @version header at the top of the configuration "
421 "file",
422 cfg_format_config_version_tag(self));
423 }
424 else if (version_convert_from_user(self->user_version) > VERSION_VALUE_CURRENT)
425 {
426 msg_warning("WARNING: Configuration file format is newer than the current version, please specify the "
427 "current version number (" VERSION_STR_CURRENT ") in the @version directive. "
428 "syslog-ng will operate at its highest supported version in this mode",
429 cfg_format_config_version_tag(self));
430 self->user_version = VERSION_VALUE_CURRENT;
431 }
432
433 if (cfg_is_config_version_older(self, VERSION_VALUE_3_3))
434 {
435 msg_warning("WARNING: global: the default value of log_fifo_size() has changed to 10000 in " VERSION_3_3
436 " to reflect log_iw_size() changes for tcp()/udp() window size changes",
437 cfg_format_config_version_tag(self));
438 }
439
440 return TRUE;
441 }
442
443 gboolean
cfg_set_current_version(GlobalConfig * self)444 cfg_set_current_version(GlobalConfig *self)
445 {
446 msg_info("Setting current version as config version", evt_tag_str("version", VERSION_STR_CURRENT));
447 return cfg_set_version(self, VERSION_VALUE_CURRENT);
448 }
449
450 gboolean
cfg_allow_config_dups(GlobalConfig * self)451 cfg_allow_config_dups(GlobalConfig *self)
452 {
453 const gchar *s;
454
455 if (cfg_is_config_version_older(self, VERSION_VALUE_3_3))
456 return TRUE;
457
458 s = cfg_args_get(self->globals, "allow-config-dups");
459 if (s && atoi(s))
460 {
461 return TRUE;
462 }
463 else
464 {
465 /* duplicate found, but allow-config-dups is not enabled, hint the user that he might want to use allow-config-dups */
466 msg_warning_once("WARNING: Duplicate configuration objects (sources, destinations, ...) are not allowed by default starting with syslog-ng 3.3, add \"@define allow-config-dups 1\" to your configuration to re-enable");
467 return FALSE;
468 }
469 }
470
471 static void
cfg_register_builtin_plugins(GlobalConfig * self)472 cfg_register_builtin_plugins(GlobalConfig *self)
473 {
474 log_proto_register_builtin_plugins(&self->plugin_context);
475 }
476
477 GlobalConfig *
cfg_new(gint version)478 cfg_new(gint version)
479 {
480 GlobalConfig *self = g_new0(GlobalConfig, 1);
481
482 self->module_config = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify) module_config_free);
483 self->globals = cfg_args_new();
484 self->user_version = version;
485
486 self->flush_lines = 100;
487 self->mark_freq = 1200; /* 20 minutes */
488 self->mark_mode = MM_HOST_IDLE;
489 self->chain_hostnames = 0;
490 self->time_reopen = 60;
491 self->time_reap = 60;
492
493 self->log_fifo_size = 10000;
494 self->log_msg_size = 65536;
495
496 file_perm_options_global_defaults(&self->file_perm_options);
497
498 dns_cache_options_defaults(&self->dns_cache_options);
499 self->threaded = TRUE;
500 self->pass_unix_credentials = -1;
501
502 log_template_options_defaults(&self->template_options);
503 self->template_options.ts_format = TS_FMT_BSD;
504 self->template_options.frac_digits = 0;
505 self->template_options.on_error = ON_ERROR_DROP_MESSAGE;
506
507 host_resolve_options_global_defaults(&self->host_resolve_options);
508
509 self->recv_time_zone = NULL;
510 self->keep_timestamp = TRUE;
511
512 self->use_uniqid = FALSE;
513
514 stats_options_defaults(&self->stats_options);
515
516 self->min_iw_size_per_reader = 100;
517
518 cfg_tree_init_instance(&self->tree, self);
519 plugin_context_init_instance(&self->plugin_context);
520 self->use_plugin_discovery = TRUE;
521 self->enable_forced_modules = TRUE;
522
523 cfg_register_builtin_plugins(self);
524 return self;
525 }
526
527 GlobalConfig *
cfg_new_snippet(void)528 cfg_new_snippet(void)
529 {
530 GlobalConfig *self = cfg_new(VERSION_VALUE_CURRENT);
531
532 self->use_plugin_discovery = FALSE;
533 self->enable_forced_modules = FALSE;
534 return self;
535 }
536
537 /* This function creates a GlobalConfig instance that shares the set of
538 * available plugins as a master one. */
539 GlobalConfig *
cfg_new_subordinate(GlobalConfig * master)540 cfg_new_subordinate(GlobalConfig *master)
541 {
542 GlobalConfig *self = cfg_new_snippet();
543
544 plugin_context_copy_candidates(&self->plugin_context, &master->plugin_context);
545 return self;
546 }
547
548 void
cfg_set_global_paths(GlobalConfig * self)549 cfg_set_global_paths(GlobalConfig *self)
550 {
551 gchar *include_path;
552
553 cfg_args_set(self->globals, "syslog-ng-root", get_installation_path_for(SYSLOG_NG_PATH_PREFIX));
554 cfg_args_set(self->globals, "syslog-ng-data", get_installation_path_for(SYSLOG_NG_PATH_DATADIR));
555 cfg_args_set(self->globals, "syslog-ng-include", get_installation_path_for(SYSLOG_NG_PATH_CONFIG_INCLUDEDIR));
556 cfg_args_set(self->globals, "syslog-ng-sysconfdir", get_installation_path_for(SYSLOG_NG_PATH_SYSCONFDIR));
557 cfg_args_set(self->globals, "scl-root", get_installation_path_for(SYSLOG_NG_PATH_SCLDIR));
558 cfg_args_set(self->globals, "module-path", resolvedConfigurablePaths.initial_module_path);
559 cfg_args_set(self->globals, "module-install-dir", resolvedConfigurablePaths.initial_module_path);
560
561 include_path = g_strdup_printf("%s:%s",
562 get_installation_path_for(SYSLOG_NG_PATH_SYSCONFDIR),
563 get_installation_path_for(SYSLOG_NG_PATH_CONFIG_INCLUDEDIR));
564 cfg_args_set(self->globals, "include-path", include_path);
565 g_free(include_path);
566 }
567
568 gboolean
cfg_run_parser(GlobalConfig * self,CfgLexer * lexer,CfgParser * parser,gpointer * result,gpointer arg)569 cfg_run_parser(GlobalConfig *self, CfgLexer *lexer, CfgParser *parser, gpointer *result, gpointer arg)
570 {
571 gboolean res;
572 GlobalConfig *old_cfg;
573 CfgLexer *old_lexer;
574
575 old_cfg = configuration;
576 configuration = self;
577 old_lexer = self->lexer;
578 self->lexer = lexer;
579
580 cfg_set_global_paths(self);
581
582 res = cfg_parser_parse(parser, lexer, result, arg);
583
584 cfg_lexer_free(lexer);
585 self->lexer = NULL;
586 self->lexer = old_lexer;
587 configuration = old_cfg;
588 return res;
589 }
590
591 gboolean
cfg_run_parser_with_main_context(GlobalConfig * self,CfgLexer * lexer,CfgParser * parser,gpointer * result,gpointer arg,const gchar * desc)592 cfg_run_parser_with_main_context(GlobalConfig *self, CfgLexer *lexer, CfgParser *parser, gpointer *result, gpointer arg,
593 const gchar *desc)
594 {
595 gboolean ret_val;
596
597 cfg_lexer_push_context(lexer, main_parser.context, main_parser.keywords, desc);
598 ret_val = cfg_run_parser(self, lexer, parser, result, arg);
599
600 return ret_val;
601 }
602
603 static void
cfg_dump_processed_config(GString * preprocess_output,gchar * output_filename)604 cfg_dump_processed_config(GString *preprocess_output, gchar *output_filename)
605 {
606 FILE *output_file;
607
608 if (strcmp(output_filename, "-")==0)
609 {
610 fprintf(stdout, "%s", preprocess_output->str);
611 return;
612 }
613
614 output_file = fopen(output_filename, "w+");
615 if (!output_file)
616 {
617 msg_error("Error opening preprocess-into file",
618 evt_tag_str(EVT_TAG_FILENAME, output_filename),
619 evt_tag_error(EVT_TAG_OSERROR));
620 return;
621 }
622 fprintf(output_file, "%s", preprocess_output->str);
623 fclose(output_file);
624 }
625
626 static GString *
_load_file_into_string(const gchar * fname)627 _load_file_into_string(const gchar *fname)
628 {
629 gchar *buff;
630 GString *content = g_string_new("");
631
632 if (g_file_get_contents(fname, &buff, NULL, NULL))
633 {
634 g_string_append(content, buff);
635 g_free(buff);
636 }
637
638 return content;
639 }
640
641 static void
_cfg_file_path_free(gpointer data)642 _cfg_file_path_free(gpointer data)
643 {
644 CfgFilePath *self = (CfgFilePath *)data;
645
646 g_free(self->file_path);
647 g_free(self->path_type);
648 g_free(self);
649 }
650
651 gboolean
cfg_read_config(GlobalConfig * self,const gchar * fname,gchar * preprocess_into)652 cfg_read_config(GlobalConfig *self, const gchar *fname, gchar *preprocess_into)
653 {
654 FILE *cfg_file;
655 gint res;
656
657 self->filename = fname;
658
659 if ((cfg_file = fopen(fname, "r")) != NULL)
660 {
661 CfgLexer *lexer;
662 self->preprocess_config = g_string_sized_new(8192);
663 self->original_config = _load_file_into_string(fname);
664
665 lexer = cfg_lexer_new(self, cfg_file, fname, self->preprocess_config);
666 res = cfg_run_parser(self, lexer, &main_parser, (gpointer *) &self, NULL);
667 fclose(cfg_file);
668 if (preprocess_into)
669 {
670 cfg_dump_processed_config(self->preprocess_config, preprocess_into);
671 }
672
673 if (res)
674 {
675 /* successfully parsed */
676 return TRUE;
677 }
678 }
679 else
680 {
681 msg_error("Error opening configuration file",
682 evt_tag_str(EVT_TAG_FILENAME, fname),
683 evt_tag_error(EVT_TAG_OSERROR));
684 }
685
686 return FALSE;
687 }
688
689 void
cfg_free(GlobalConfig * self)690 cfg_free(GlobalConfig *self)
691 {
692 g_assert(self->persist == NULL);
693
694 g_free(self->file_template_name);
695 g_free(self->proto_template_name);
696 log_template_unref(self->file_template);
697 log_template_unref(self->proto_template);
698 log_template_options_destroy(&self->template_options);
699 host_resolve_options_destroy(&self->host_resolve_options);
700
701 if (self->bad_hostname_compiled)
702 regfree(&self->bad_hostname);
703 g_free(self->recv_time_zone);
704 if (self->source_mangle_callback_list)
705 g_list_free(self->source_mangle_callback_list);
706 g_free(self->bad_hostname_re);
707 dns_cache_options_destroy(&self->dns_cache_options);
708 g_free(self->custom_domain);
709 plugin_context_deinit_instance(&self->plugin_context);
710 cfg_tree_free_instance(&self->tree);
711 g_hash_table_unref(self->module_config);
712 cfg_args_unref(self->globals);
713
714 if (self->state)
715 persist_state_free(self->state);
716
717 if (self->preprocess_config)
718 g_string_free(self->preprocess_config, TRUE);
719 if (self->original_config)
720 g_string_free(self->original_config, TRUE);
721
722 g_list_free_full(self->file_list, _cfg_file_path_free);
723
724 g_free(self);
725 }
726
727 void
cfg_persist_config_move(GlobalConfig * src,GlobalConfig * dest)728 cfg_persist_config_move(GlobalConfig *src, GlobalConfig *dest)
729 {
730 if (dest->persist != NULL)
731 persist_config_free(dest->persist);
732 dest->persist = src->persist;
733 dest->state = src->state;
734 src->persist = NULL;
735 src->state = NULL;
736 }
737
738 void
cfg_persist_config_add(GlobalConfig * cfg,const gchar * name,gpointer value,GDestroyNotify destroy,gboolean force)739 cfg_persist_config_add(GlobalConfig *cfg, const gchar *name, gpointer value, GDestroyNotify destroy,
740 gboolean force)
741 {
742 PersistConfigEntry *p;
743
744 if (cfg->persist && value)
745 {
746 if (g_hash_table_lookup(cfg->persist->keys, name))
747 {
748 if (!force)
749 {
750 msg_error("Internal error, duplicate configuration elements refer to the same persistent config",
751 evt_tag_str("name", name));
752 if (destroy)
753 destroy(value);
754 return;
755 }
756 }
757
758 p = g_new0(PersistConfigEntry, 1);
759
760 p->value = value;
761 p->destroy = destroy;
762 g_hash_table_insert(cfg->persist->keys, g_strdup(name), p);
763 return;
764 }
765 else if (destroy && value)
766 {
767 destroy(value);
768 }
769 return;
770 }
771
772 gpointer
cfg_persist_config_fetch(GlobalConfig * cfg,const gchar * name)773 cfg_persist_config_fetch(GlobalConfig *cfg, const gchar *name)
774 {
775 gpointer res = NULL;
776 gchar *orig_key;
777 PersistConfigEntry *p;
778 gpointer tmp1, tmp2;
779
780 if (cfg->persist && g_hash_table_lookup_extended(cfg->persist->keys, name, &tmp1, &tmp2))
781 {
782 orig_key = (gchar *) tmp1;
783 p = (PersistConfigEntry *) tmp2;
784
785 res = p->value;
786
787 g_hash_table_steal(cfg->persist->keys, name);
788 g_free(orig_key);
789 g_free(p);
790 }
791 return res;
792 }
793
794 gint
cfg_get_user_version(const GlobalConfig * cfg)795 cfg_get_user_version(const GlobalConfig *cfg)
796 {
797 return cfg->user_version;
798 }
799
register_source_mangle_callback(GlobalConfig * src,mangle_callback cb)800 void register_source_mangle_callback(GlobalConfig *src, mangle_callback cb)
801 {
802 src->source_mangle_callback_list = g_list_append(src->source_mangle_callback_list, cb);
803 }
804
uregister_source_mangle_callback(GlobalConfig * src,mangle_callback cb)805 void uregister_source_mangle_callback(GlobalConfig *src, mangle_callback cb)
806 {
807 src->source_mangle_callback_list = g_list_remove(src->source_mangle_callback_list, cb);
808 }
809
810 const gchar *
cfg_get_filename(const GlobalConfig * cfg)811 cfg_get_filename(const GlobalConfig *cfg)
812 {
813 return cfg->filename;
814 }
815
816