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