X-Git-Url: http://git.madism.org/?a=blobdiff_plain;f=postlicyd%2Fconfig.c;h=d964aaa5b7b094679b1a0bf027090b759b75d79b;hb=3d18b18de2e63eadc6a8dd2c375e16f7c7abadc8;hp=d4fbce3f73b9683a93d68855f1b20ef391e6ce8b;hpb=8a641b3dc8b4e2ede5961f95249640c83d3267a6;p=apps%2Fpfixtools.git diff --git a/postlicyd/config.c b/postlicyd/config.c index d4fbce3..d964aaa 100644 --- a/postlicyd/config.c +++ b/postlicyd/config.c @@ -34,38 +34,119 @@ */ #include "file.h" -#include "filter.h" #include "config.h" +#include "str.h" -struct config_t { - filter_t *filters; - int filters_len; - int filters_size; +#define config_param_register(Param) - int entry_point; -}; +/* Filter to execute on "CONNECT" + */ +config_param_register("client_filter"); + +/* Filter to execute on "MAIL FROM" + */ +config_param_register("sender_filter"); + +/* Filter to execute on "RCPT TO" + */ +config_param_register("recipient_filter"); + +/* Filter to execute on "DATA" + */ +config_param_register("data_filter"); + +/* Filter to execute on "END-OF-DATA" + */ +config_param_register("end_of_data_filter"); + +/* Filter to execute on "ETRN" + */ +config_param_register("etrn_filter"); + +/* Filter to execute on "HELO" + */ +config_param_register("helo_filter"); +config_param_register("ehlo_filter"); + +/* Filter to execute on "VRFY" + */ +config_param_register("verify_filter"); static inline config_t *config_new(void) { config_t *config = p_new(config_t, 1); - config->entry_point = -1; + for (int i = 0 ; i < SMTP_count ; ++i) { + config->entry_points[i] = -1; + } return config; } void config_delete(config_t **config) { if (*config) { - for (int i = 0 ; i < (*config)->filters_len ; ++i) { - filter_wipe((*config)->filters + i); + array_deep_wipe((*config)->filters, filter_wipe); + array_deep_wipe((*config)->params, filter_params_wipe); + p_delete(config); + } +} + + +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; + } + + ok = 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); \ + 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 + default: break; } - p_delete(&(*config)->filters); + }} + array_deep_wipe(config->params, filter_params_wipe); + + if (!ok) { + syslog(LOG_ERR, "no entry point defined"); } + + return ok; } config_t *config_read(const char *file) { config_t *config; - //filter_t *filter = NULL; + filter_t filter; file_map_t map; const char *p; int line = 0; @@ -80,28 +161,33 @@ config_t *config_read(const char *file) } config = config_new(); + filter_init(&filter); linep = p = map.map; #define READ_ERROR(Fmt, ...) \ - syslog(LOG_ERR, "config file %s:%d:%d: " Fmt, file, line + 1, \ - p - linep + 1, ##__VA_ARGS__) -#define ADD_IN_BUFFER(Buffer, Len, Char) \ - if ((Len) >= BUFSIZ - 1) { \ - READ_ERROR("unreasonnable long line"); \ + do { \ + syslog(LOG_ERR, "config file %s:%d:%d: " Fmt, file, line + 1, \ + p - linep + 1, ##__VA_ARGS__); \ goto error; \ - } \ - (Buffer)[(Len)++] = (Char); \ - (Buffer)[(Len)] = '\0'; - + } while (0) +#define ADD_IN_BUFFER(Buffer, Len, Char) \ + do { \ + if ((Len) >= BUFSIZ - 1) { \ + READ_ERROR("unreasonnable long line"); \ + } \ + (Buffer)[(Len)++] = (Char); \ + (Buffer)[(Len)] = '\0'; \ + } while (0) #define READ_NEXT(OnEOF) \ - if (*p == '\n') { \ - ++line; \ - linep = p + 1; \ - } \ - if (++p >= map.end) { \ - OnEOF; \ - } \ - syslog(LOG_ERR, "Read char '%c' at %d", *p, __LINE__); + do { \ + if (*p == '\n') { \ + ++line; \ + linep = p + 1; \ + } \ + if (++p >= map.end) { \ + OnEOF; \ + } \ + } while (0) #define READ_BLANK(OnEOF) \ do { \ bool in_comment = false; \ @@ -120,11 +206,10 @@ config_t *config_read(const char *file) (Buffer)[0] = '\0'; \ if (!isalpha(*p)) { \ READ_ERROR("invalid %s, unexpected character '%c'", Name, *p); \ - goto error; \ } \ do { \ ADD_IN_BUFFER(Buffer, Len, *p); \ - READ_NEXT(goto badeof) \ + READ_NEXT(goto badeof); \ } while (isalnum(*p) || *p == '_'); \ } while (0) #define READ_STRING(Name, Buffer, Len, OnEOF) \ @@ -138,7 +223,6 @@ config_t *config_read(const char *file) while (true) { \ if (*p == '\n') { \ READ_ERROR("string must not contain EOL"); \ - goto error; \ } else if (escaped) { \ ADD_IN_BUFFER(Buffer, Len, *p); \ escaped = false; \ @@ -156,7 +240,6 @@ config_t *config_read(const char *file) } \ if (*p != ';') { \ READ_ERROR("%s must end with a ';'", Name); \ - goto error; \ } \ } else { \ bool escaped = false; \ @@ -181,14 +264,15 @@ config_t *config_read(const char *file) if (escaped) { \ ADD_IN_BUFFER(Buffer, Len, '\\'); \ } \ + while ((Len) > 0 && isspace((Buffer)[(Len) - 1])) { \ + (Buffer)[--(Len)] = '\0'; \ + } \ } \ - READ_NEXT(OnEOF) \ - syslog(LOG_ERR, "string read: %s", Buffer); \ + READ_NEXT(OnEOF); \ } while(0) read_section: - syslog(LOG_ERR, "read_section"); if (p >= map.end) { goto ok; } @@ -201,56 +285,82 @@ read_section: READ_BLANK(goto badeof); switch (*p) { case '=': - READ_NEXT(goto badeof) + READ_NEXT(goto badeof); goto read_param_value; case '{': - READ_NEXT(goto badeof) + READ_NEXT(goto badeof); goto read_filter; default: READ_ERROR("invalid character '%c', expected '=' or '{'", *p); - goto error; } read_param_value: - syslog(LOG_ERR, "read_param_value: key=%s", key); READ_BLANK(goto badeof); READ_STRING("parameter value", value, value_len, ;); - /* TODO: Insert parameter in the configuration. - */ + { + filter_param_t param; + param.type = param_tokenize(key, key_len); + if (param.type != ATK_UNKNOWN) { + param.value = m_strdup(value); + array_add(config->params, param); + } + } goto read_section; read_filter: - syslog(LOG_ERR, "read_filter: key=%s", key); - /* TODO: Create a filter with the given name. - */ + filter_set_name(&filter, key, key_len); READ_BLANK(goto badeof); while (*p != '}') { READ_TOKEN("filter parameter name", key, key_len); - syslog(LOG_ERR, "read parameter: key=%s", key); READ_BLANK(goto badeof); if (*p != '=') { READ_ERROR("invalid character '%c', expected '='", *p); - goto error; } READ_NEXT(goto badeof); READ_BLANK(goto badeof); READ_STRING("filter parameter value", value, value_len, goto badeof); READ_BLANK(goto badeof); - /* TODO: Insert parameter in the filter. - */ + if (strcmp(key, "type") == 0) { + if (!filter_set_type(&filter, value, value_len)) { + READ_ERROR("unknow filter type (%s) for filter %s", + value, filter.name); + } + } else if (key_len > 3 && strncmp(key, "on_", 3) == 0) { + if (!filter_add_hook(&filter, key + 3, key_len - 3, + value, value_len)) { + READ_ERROR("hook %s not supported by filter %s", + key + 3, filter.name); + } + } else { + /* filter_add_param failure mean unknown type or unsupported type. + * this are non-fatal errors. + */ + (void)filter_add_param(&filter, key, key_len, value, value_len); + } + } + READ_NEXT(;); + if (!filter_build(&filter)) { + READ_ERROR("invalid filter %s", filter.name); } - READ_NEXT(;) - /* TODO: Check the filter. - */ + array_add(config->filters, filter); + filter_init(&filter); goto read_section; ok: + if (!config_second_pass(config)) { + goto error; + } + file_map_close(&map); return config; badeof: syslog(LOG_ERR, "Unexpected end of file"); error: + if (filter.name) { + filter_wipe(&filter); + } config_delete(&config); + file_map_close(&map); return NULL; }