From e6d0c7ab6103af206f95c1291b29c3f151a41484 Mon Sep 17 00:00:00 2001 From: Florent Bruneau Date: Sun, 28 Sep 2008 15:14:29 +0200 Subject: [PATCH] Add filter_test and move query parser in its own file. Signed-off-by: Florent Bruneau --- postlicyd/Makefile | 2 +- postlicyd/filter.c | 5 ++ postlicyd/filter.h | 3 + postlicyd/main-postlicyd.c | 98 +-------------------------- postlicyd/query.c | 135 +++++++++++++++++++++++++++++++++++++ postlicyd/query.h | 9 +++ 6 files changed, 154 insertions(+), 98 deletions(-) create mode 100644 postlicyd/query.c diff --git a/postlicyd/Makefile b/postlicyd/Makefile index bdfd89b..7901504 100644 --- a/postlicyd/Makefile +++ b/postlicyd/Makefile @@ -40,7 +40,7 @@ TESTS = test-rbl FILTERS = rbl.c greylist.c strlist.c match.c -postlicyd_SOURCES = main-postlicyd.c ../common/lib.a filter.c config.c $(FILTERS) $(GENERATED) +postlicyd_SOURCES = main-postlicyd.c ../common/lib.a filter.c config.c query.c $(FILTERS) $(GENERATED) postlicyd_LIBADD = $(TC_LIBS) tst-rbl_SOURCES = tst-rbl.c diff --git a/postlicyd/filter.c b/postlicyd/filter.c index de6ba03..3f9991b 100644 --- a/postlicyd/filter.c +++ b/postlicyd/filter.c @@ -194,6 +194,11 @@ const filter_hook_t *filter_run(const filter_t *filter, const query_t *query) return &default_hook; } +bool filter_test(const filter_t *filter, const query_t *query, filter_result_t result) +{ + return !!(runners[filter->type](filter, query) == result); +} + void filter_set_name(filter_t *filter, const char *name, ssize_t len) { filter->name = p_dupstr(name, len); diff --git a/postlicyd/filter.h b/postlicyd/filter.h index c950402..0aca7e9 100644 --- a/postlicyd/filter.h +++ b/postlicyd/filter.h @@ -173,6 +173,9 @@ void filter_wipe(filter_t *filter); __attribute__((nonnull(1,2))) const filter_hook_t *filter_run(const filter_t *filter, const query_t *query); +__attribute__((nonnull(1,2))) +bool filter_test(const filter_t *filter, const query_t *query, filter_result_t expt); + /* Helpers */ diff --git a/postlicyd/main-postlicyd.c b/postlicyd/main-postlicyd.c index 5f46e76..cae2d23 100644 --- a/postlicyd/main-postlicyd.c +++ b/postlicyd/main-postlicyd.c @@ -61,102 +61,6 @@ static bool config_refresh(void *config) return config_reload(config); } -static int postfix_parsejob(query_t *query, char *p) -{ -#define PARSE_CHECK(expr, error, ...) \ - do { \ - if (!(expr)) { \ - syslog(LOG_ERR, error, ##__VA_ARGS__); \ - return -1; \ - } \ - } while (0) - - p_clear(query, 1); - query->state = SMTP_UNKNOWN; - while (*p != '\n') { - char *k, *v; - int klen, vlen, vtk; - - while (isblank(*p)) - p++; - p = strchr(k = p, '='); - PARSE_CHECK(p, "could not find '=' in line"); - for (klen = p - k; klen && isblank(k[klen]); klen--); - p += 1; /* skip = */ - - while (isblank(*p)) - p++; - p = strchr(v = p, '\n'); - PARSE_CHECK(p, "could not find final \\n in line"); - for (vlen = p - v; vlen && isblank(v[vlen]); vlen--); - p += 1; /* skip \n */ - - vtk = policy_tokenize(v, vlen); - switch (policy_tokenize(k, klen)) { -#define CASE(up, low) case PTK_##up: query->low = v; v[vlen] = '\0'; syslog(LOG_DEBUG, "%s = %s", ptokens[PTK_##up], query->low); break; - CASE(HELO_NAME, helo_name); - CASE(QUEUE_ID, queue_id); - CASE(SENDER, sender); - CASE(RECIPIENT, recipient); - CASE(RECIPIENT_COUNT, recipient_count); - CASE(CLIENT_ADDRESS, client_address); - CASE(CLIENT_NAME, client_name); - CASE(REVERSE_CLIENT_NAME, reverse_client_name); - CASE(INSTANCE, instance); - CASE(SASL_METHOD, sasl_method); - CASE(SASL_USERNAME, sasl_username); - CASE(SASL_SENDER, sasl_sender); - CASE(SIZE, size); - CASE(CCERT_SUBJECT, ccert_subject); - CASE(CCERT_ISSUER, ccert_issuer); - CASE(CCERT_FINGERPRINT, ccert_fingerprint); - CASE(ENCRYPTION_PROTOCOL, encryption_protocol); - CASE(ENCRYPTION_CIPHER, encryption_cipher); - CASE(ENCRYPTION_KEYSIZE, encryption_keysize); - CASE(ETRN_DOMAIN, etrn_domain); - CASE(STRESS, stress); -#undef CASE - - case PTK_REQUEST: - PARSE_CHECK(vtk == PTK_SMTPD_ACCESS_POLICY, - "unexpected `request' value: %.*s", vlen, v); - break; - - case PTK_PROTOCOL_NAME: - PARSE_CHECK(vtk == PTK_SMTP || vtk == PTK_ESMTP, - "unexpected `protocol_name' value: %.*s", vlen, v); - query->esmtp = vtk == PTK_ESMTP; - break; - - case PTK_PROTOCOL_STATE: - switch (vtk) { -#define CASE(name) case PTK_##name: query->state = SMTP_##name; break; - CASE(CONNECT); - CASE(EHLO); - CASE(HELO); - CASE(MAIL); - CASE(RCPT); - CASE(DATA); - CASE(END_OF_MESSAGE); - CASE(VRFY); - CASE(ETRN); - default: - PARSE_CHECK(false, "unexpected `protocol_state` value: %.*s", - vlen, v); -#undef CASE - } - break; - - default: - syslog(LOG_WARNING, "unexpected key, skipped: %.*s", klen, k); - continue; - } - } - - return query->state == SMTP_UNKNOWN ? -1 : 0; -#undef PARSE_CHECK -} - __attribute__((format(printf,2,0))) static void policy_answer(server_t *pcy, const char *fmt, ...) { @@ -218,7 +122,7 @@ static int policy_run(server_t *pcy, void* vconfig) if (!(eoq = strstr(pcy->ibuf.data + search_offs, "\n\n"))) return 0; - if (postfix_parsejob(pcy->data, pcy->ibuf.data) < 0) + if (!query_parse(pcy->data, pcy->ibuf.data)) return -1; query->eoq = eoq + strlen("\n\n"); epoll_modify(pcy->fd, 0, pcy); diff --git a/postlicyd/query.c b/postlicyd/query.c new file mode 100644 index 0000000..1dc8e6f --- /dev/null +++ b/postlicyd/query.c @@ -0,0 +1,135 @@ +/******************************************************************************/ +/* pfixtools: a collection of postfix related tools */ +/* ~~~~~~~~~ */ +/* ________________________________________________________________________ */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions */ +/* are met: */ +/* */ +/* 1. Redistributions of source code must retain the above copyright */ +/* notice, this list of conditions and the following disclaimer. */ +/* 2. Redistributions in binary form must reproduce the above copyright */ +/* notice, this list of conditions and the following disclaimer in the */ +/* documentation and/or other materials provided with the distribution. */ +/* 3. The names of its contributors may not be used to endorse or promote */ +/* 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. */ +/******************************************************************************/ + +/* + * Copyright © 2007 Pierre Habouzit + * Copyright © 2008 Florent Bruneau + */ + +#include "query.h" +#include "policy_tokens.h" + +bool query_parse(query_t *query, char *p) +{ +#define PARSE_CHECK(expr, error, ...) \ + do { \ + if (!(expr)) { \ + syslog(LOG_ERR, error, ##__VA_ARGS__); \ + return false; \ + } \ + } while (0) + + p_clear(query, 1); + query->state = SMTP_UNKNOWN; + while (*p != '\n') { + char *k, *v; + int klen, vlen, vtk; + + while (isblank(*p)) + p++; + p = strchr(k = p, '='); + PARSE_CHECK(p, "could not find '=' in line"); + for (klen = p - k; klen && isblank(k[klen]); klen--); + p += 1; /* skip = */ + + while (isblank(*p)) + p++; + p = strchr(v = p, '\n'); + PARSE_CHECK(p, "could not find final \\n in line"); + for (vlen = p - v; vlen && isblank(v[vlen]); vlen--); + p += 1; /* skip \n */ + + vtk = policy_tokenize(v, vlen); + switch (policy_tokenize(k, klen)) { +#define CASE(up, low) case PTK_##up: query->low = v; v[vlen] = '\0'; syslog(LOG_DEBUG, "%s = %s", ptokens[PTK_##up], query->low); break; + CASE(HELO_NAME, helo_name); + CASE(QUEUE_ID, queue_id); + CASE(SENDER, sender); + CASE(RECIPIENT, recipient); + CASE(RECIPIENT_COUNT, recipient_count); + CASE(CLIENT_ADDRESS, client_address); + CASE(CLIENT_NAME, client_name); + CASE(REVERSE_CLIENT_NAME, reverse_client_name); + CASE(INSTANCE, instance); + CASE(SASL_METHOD, sasl_method); + CASE(SASL_USERNAME, sasl_username); + CASE(SASL_SENDER, sasl_sender); + CASE(SIZE, size); + CASE(CCERT_SUBJECT, ccert_subject); + CASE(CCERT_ISSUER, ccert_issuer); + CASE(CCERT_FINGERPRINT, ccert_fingerprint); + CASE(ENCRYPTION_PROTOCOL, encryption_protocol); + CASE(ENCRYPTION_CIPHER, encryption_cipher); + CASE(ENCRYPTION_KEYSIZE, encryption_keysize); + CASE(ETRN_DOMAIN, etrn_domain); + CASE(STRESS, stress); +#undef CASE + + case PTK_REQUEST: + PARSE_CHECK(vtk == PTK_SMTPD_ACCESS_POLICY, + "unexpected `request' value: %.*s", vlen, v); + break; + + case PTK_PROTOCOL_NAME: + PARSE_CHECK(vtk == PTK_SMTP || vtk == PTK_ESMTP, + "unexpected `protocol_name' value: %.*s", vlen, v); + query->esmtp = vtk == PTK_ESMTP; + break; + + case PTK_PROTOCOL_STATE: + switch (vtk) { +#define CASE(name) case PTK_##name: query->state = SMTP_##name; break; + CASE(CONNECT); + CASE(EHLO); + CASE(HELO); + CASE(MAIL); + CASE(RCPT); + CASE(DATA); + CASE(END_OF_MESSAGE); + CASE(VRFY); + CASE(ETRN); + default: + PARSE_CHECK(false, "unexpected `protocol_state` value: %.*s", + vlen, v); +#undef CASE + } + break; + + default: + syslog(LOG_WARNING, "unexpected key, skipped: %.*s", klen, k); + continue; + } + } + + return query->state != SMTP_UNKNOWN; +#undef PARSE_CHECK +} + diff --git a/postlicyd/query.h b/postlicyd/query.h index d4d9596..f9cd0b6 100644 --- a/postlicyd/query.h +++ b/postlicyd/query.h @@ -38,6 +38,7 @@ #define PFIXTOOLS_QUERY_H #include "mem.h" +#include "common.h" enum smtp_state { SMTP_CONNECT, @@ -101,4 +102,12 @@ static inline void query_delete(query_t **query) } } +/** Parse the content of the text to fill the query. + * The text pointed by \p p is segmented (and modified to add + * a \0 at the end of each segment) and used to fill the query + * object. + */ +__attribute__((nonnull(1,2))) +bool query_parse(query_t *query, char *p); + #endif -- 2.20.1