/* products derived from this software without specific prior written */
/* permission. */
/* */
-/* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND */
-/* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE */
-/* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */
-/* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS */
-/* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR */
-/* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF */
-/* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS */
-/* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN */
-/* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) */
-/* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF */
-/* THE POSSIBILITY OF SUCH DAMAGE. */
+/* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS */
+/* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */
+/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
+/* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY */
+/* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL */
+/* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS */
+/* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) */
+/* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, */
+/* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN */
+/* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE */
+/* POSSIBILITY OF SUCH DAMAGE. */
+/* */
+/* Copyright (c) 2006-2008 the Authors */
+/* see AUTHORS and source files for details */
/******************************************************************************/
/*
#include "file.h"
#include "config.h"
#include "str.h"
+#include "resources.h"
#define config_param_register(Param)
config_param_register("port");
+/* Format of the log message.
+ * The message exact format is $log: "reply"
+ */
+config_param_register("log_format");
+
+
static config_t *global_config = NULL;
static inline config_t *config_new(void)
}
array_deep_wipe(config->filters, filter_wipe);
array_deep_wipe(config->params, filter_params_wipe);
+ p_delete(&config->log_format);
}
void config_delete(config_t **config)
}
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;
char key[BUFSIZ];
char value[BUFSIZ];
- ssize_t key_len, value_len;
+ int key_len, value_len;
if (!file_map_open(&map, config->filename, false)) {
return false;
}
- config_close(config);
filter_init(&filter);
linep = p = map.map;
#define READ_LOG(Lev, Fmt, ...) \
__log(LOG_ ## Lev, "config file %s:%d:%d: " Fmt, config->filename, \
- line + 1, p - linep + 1, ##__VA_ARGS__)
+ line + 1, (int)(p - linep + 1), ##__VA_ARGS__)
#define READ_ERROR(Fmt, ...) \
do { \
READ_LOG(ERR, Fmt, ##__VA_ARGS__); \
}
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;
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);
+ FILTER_PARAM_PARSE_STRING(LOG_FORMAT, config->log_format, true);
+ default: break;
+ }
+ }}
+ array_deep_wipe(config->params, filter_params_wipe);
+
+ if (config->log_format && !query_format_check(config->log_format)) {
+ err("invalid log format: \"%s\"", config->log_format);
+ return false;
+ }
+
+ 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) {
+ config_close(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;
+ }
+
+ resource_garbage_collect();
+ return true;
+}
+
bool config_reload(config_t *config)
{
return config_load(config);
}
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;
+}