From 1ee374e93e0d195185731be49d60c193e4182f08 Mon Sep 17 00:00:00 2001 From: Florent Bruneau Date: Sun, 9 Nov 2008 22:32:30 +0100 Subject: [PATCH] Cleanup configuration parser, add 'check-conf' option. Signed-off-by: Florent Bruneau --- postlicyd/config.c | 170 ++++++++++++++++++++++--------------- postlicyd/config.h | 3 + postlicyd/main-postlicyd.c | 12 ++- 3 files changed, 115 insertions(+), 70 deletions(-) diff --git a/postlicyd/config.c b/postlicyd/config.c index 672faca..0111b7a 100644 --- a/postlicyd/config.c +++ b/postlicyd/config.c @@ -113,70 +113,8 @@ static void config_exit() } module_exit(config_exit); -static bool config_second_pass(config_t *config) -{ - bool ok = true; - if (config->filters.len > 0) { -# define QSORT_TYPE filter_t -# define QSORT_BASE config->filters.data -# define QSORT_NELT config->filters.len -# define QSORT_LT(a,b) strcmp(a->name, b->name) < 0 -# include "qsort.c" - } - - foreach (filter_t *filter, config->filters) { - if (!filter_update_references(filter, &config->filters)) { - ok = false; - break; - } - }} - if (!ok) { - return false; - } - if (!filter_check_safety(&config->filters)) { - return false; - } - - ok = false; -#define PARSE_CHECK(Expr, Fmt, ...) \ - if (!(Expr)) { \ - err(Fmt, ##__VA_ARGS__); \ - return false; \ - } - foreach (filter_param_t *param, config->params) { - switch (param->type) { -#define CASE(Param, State) \ - case ATK_ ## Param ## _FILTER: \ - ok = true; \ - config->entry_points[SMTP_ ## State] \ - = filter_find_with_name(&config->filters, param->value); \ - PARSE_CHECK(config->entry_points[SMTP_ ## State] >= 0, \ - "invalid filter name %s", param->value); \ - break; - CASE(CLIENT, CONNECT) - CASE(EHLO, EHLO) - CASE(HELO, HELO) - CASE(SENDER, MAIL) - CASE(RECIPIENT, RCPT) - CASE(DATA, DATA) - CASE(END_OF_DATA, END_OF_MESSAGE) - CASE(VERIFY, VRFY) - CASE(ETRN, ETRN) -#undef CASE - FILTER_PARAM_PARSE_INT(PORT, config->port); - default: break; - } - }} - array_deep_wipe(config->params, filter_params_wipe); - if (!ok) { - err("no entry point defined"); - } - - return ok; -} - -static bool config_load(config_t *config) +static bool config_parse(config_t *config) { filter_t filter; file_map_t map; @@ -388,17 +326,11 @@ read_filter: } end_of_section = true; READ_NEXT; - if (!filter_build(&filter)) { - READ_ERROR("invalid filter %s", filter.name); - } array_add(config->filters, filter); filter_init(&filter); goto read_section; ok: - if (!config_second_pass(config)) { - goto error; - } file_map_close(&map); return true; @@ -413,6 +345,95 @@ error: return false; } +static bool config_build_structure(config_t *config) +{ + bool ok = true; + if (config->filters.len > 0) { +# define QSORT_TYPE filter_t +# define QSORT_BASE config->filters.data +# define QSORT_NELT config->filters.len +# define QSORT_LT(a,b) strcmp(a->name, b->name) < 0 +# include "qsort.c" + } + + foreach (filter_t *filter, config->filters) { + if (!filter_update_references(filter, &config->filters)) { + ok = false; + break; + } + }} + if (!ok) { + return false; + } + if (!filter_check_safety(&config->filters)) { + return false; + } + + ok = false; +#define PARSE_CHECK(Expr, Fmt, ...) \ + if (!(Expr)) { \ + err(Fmt, ##__VA_ARGS__); \ + return false; \ + } + foreach (filter_param_t *param, config->params) { + switch (param->type) { +#define CASE(Param, State) \ + case ATK_ ## Param ## _FILTER: \ + ok = true; \ + config->entry_points[SMTP_ ## State] \ + = filter_find_with_name(&config->filters, param->value); \ + PARSE_CHECK(config->entry_points[SMTP_ ## State] >= 0, \ + "invalid filter name %s", param->value); \ + break; + CASE(CLIENT, CONNECT) + CASE(EHLO, EHLO) + CASE(HELO, HELO) + CASE(SENDER, MAIL) + CASE(RECIPIENT, RCPT) + CASE(DATA, DATA) + CASE(END_OF_DATA, END_OF_MESSAGE) + CASE(VERIFY, VRFY) + CASE(ETRN, ETRN) +#undef CASE + FILTER_PARAM_PARSE_INT(PORT, config->port); + default: break; + } + }} + array_deep_wipe(config->params, filter_params_wipe); + + if (!ok) { + err("no entry point defined"); + } + return ok; +} + +static bool config_build_filters(config_t *config) +{ + foreach (filter_t *filter, config->filters) { + if (!filter_build(filter)) { + return false; + } + }} + + return true; +} + +static bool config_load(config_t *config) { + if (!config_parse(config)) { + err("Invalid configuration: cannot parse configuration file \"%s\"", config->filename); + return false; + } + if (!config_build_structure(config)) { + err("Invalid configuration: inconsistent filter structure"); + return false; + } + if (!config_build_filters(config)) { + err("Invalid configuration: invalid filter"); + return false; + } + return true; +} + bool config_reload(config_t *config) { return config_load(config); @@ -428,3 +449,14 @@ config_t *config_read(const char *file) } return config; } + +bool config_check(const char *file) +{ + config_t *config = config_new(); + config->filename = file; + + bool ret = config_parse(config) && config_build_structure(config); + + config_delete(&config); + return ret; +} diff --git a/postlicyd/config.h b/postlicyd/config.h index 6584919..26fb619 100644 --- a/postlicyd/config.h +++ b/postlicyd/config.h @@ -70,6 +70,9 @@ struct config_t { __attribute__((nonnull(1))) config_t *config_read(const char *file); +__attribute__((nonnull(1))) +bool config_check(const char *file); + __attribute__((nonnull(1))) bool config_reload(config_t *config); diff --git a/postlicyd/main-postlicyd.c b/postlicyd/main-postlicyd.c index 08c6a2b..87920be 100644 --- a/postlicyd/main-postlicyd.c +++ b/postlicyd/main-postlicyd.c @@ -283,6 +283,7 @@ void usage(void) " -f stay in foreground\n" " -d grow logging level\n" " -u unsafe mode (don't drop privileges)\n" + " -c check-conf\n" , stderr); } @@ -295,8 +296,9 @@ int main(int argc, char *argv[]) bool daemonize = true; int port = DEFAULT_PORT; bool port_from_cli = false; + bool check_conf = false; - for (int c = 0; (c = getopt(argc, argv, "ufd" "l:p:")) >= 0; ) { + for (int c = 0; (c = getopt(argc, argv, "ufdc" "l:p:")) >= 0; ) { switch (c) { case 'p': pidfile = optarg; @@ -314,6 +316,11 @@ int main(int argc, char *argv[]) case 'd': ++log_level; break; + case 'c': + check_conf = true; + daemonize = false; + unsafe = true; + break; default: usage(); return EXIT_FAILURE; @@ -330,6 +337,9 @@ int main(int argc, char *argv[]) } info("%s v%s...", DAEMON_NAME, DAEMON_VERSION); + if (check_conf) { + return config_check(argv[optind]) ? EXIT_SUCCESS : EXIT_FAILURE; + } if (pidfile_open(pidfile) < 0) { crit("unable to write pidfile %s", pidfile); -- 2.20.1