From c78538ac1dd1f22e4b6384b6e85a153646cb90d9 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Sat, 1 Dec 2007 14:14:02 +0100 Subject: [PATCH] Plug the postfix policy query parsing again. Signed-off-by: Pierre Habouzit --- common.h | 1 + policy.c | 187 ++++++++++++++++++++++++++++--------------------------- policy.h | 67 -------------------- 3 files changed, 97 insertions(+), 158 deletions(-) diff --git a/common.h b/common.h index daf7d03..e6050ac 100644 --- a/common.h +++ b/common.h @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include diff --git a/policy.c b/policy.c index 30bc588..0949dd2 100644 --- a/policy.c +++ b/policy.c @@ -38,31 +38,74 @@ #include "buffer.h" #include "tokens.h" -#if 0 - -#define ishspace(c) ((c) == ' ' || (c) == '\t') - -typedef struct jpriv_t { - buffer_t ibuf; - buffer_t obuf; - query_t query; -} jpriv_t; - -static jpriv_t *postfix_jpriv_init(jpriv_t *jp) -{ - buffer_init(&jp->ibuf); - buffer_init(&jp->obuf); - query_init(&jp->query); - return jp; +enum smtp_state { + SMTP_UNKNOWN, + SMTP_CONNECT, + SMTP_EHLO, + SMTP_HELO = SMTP_EHLO, + SMTP_MAIL, + SMTP_RCPT, + SMTP_DATA, + SMTP_END_OF_MESSAGE, + SMTP_VRFY, + SMTP_ETRN, +}; + +/* \see http://www.postfix.org/SMTPD_POLICY_README.html */ +typedef struct query_t { + unsigned state : 4; + unsigned esmtp : 1; + + const char *helo_name; + const char *queue_id; + const char *sender; + const char *recipient; + const char *recipient_count; + const char *client_address; + const char *client_name; + const char *rclient_name; + const char *instance; + + /* postfix 2.2+ */ + const char *sasl_method; + const char *sasl_username; + const char *sasl_sender; + const char *size; + const char *ccert_subject; + const char *ccert_issuer; + const char *ccsert_fingerprint; + + /* postfix 2.3+ */ + const char *encryption_protocol; + const char *encryption_cipher; + const char *encryption_keysize; + const char *etrn_domain; + + buffer_t data; +} query_t; + +static query_t *query_init(query_t *rq) { + memset(rq, 0, offsetof(query_t, data)); + buffer_init(&rq->data); + return rq; } -static void postfix_jpriv_wipe(jpriv_t *jp) +static void query_wipe(query_t *rq) { + buffer_wipe(&rq->data); +} + +static int xwrite(int fd, const char *s, size_t l) { - query_wipe(&jp->query); - buffer_wipe(&jp->ibuf); - buffer_wipe(&jp->obuf); + while (l > 0) { + int nb = write(fd, s, l); + if (nb < 0) { + if (errno == EINTR || errno == EAGAIN) + continue; + return -1; + } + l -= nb; + } + return 0; } -DO_NEW(jpriv_t, postfix_jpriv); -DO_DELETE(jpriv_t, postfix_jpriv); static int postfix_parsejob(query_t *query) { @@ -76,22 +119,23 @@ static int postfix_parsejob(query_t *query) char *p = vskipspaces(query->data.data); - while (*p) { + memset(query, 0, offsetof(query_t, data)); + while (p[0] != '\r' || p[1] != '\n') { char *k, *v; int klen, vlen, vtk; - while (ishspace(*p)) + while (isblank(*p)) p++; p = strchr(k = p, '='); PARSE_CHECK(p, "could not find '=' in line"); - for (klen = p - k; klen && ishspace(k[klen]); klen--); + for (klen = p - k; klen && isblank(k[klen]); klen--); p += 1; /* skip = */ - while (ishspace(*p)) + while (isblank(*p)) p++; p = strstr(v = p, "\r\n"); PARSE_CHECK(p, "could not find final \\r\\n in line"); - for (vlen = p - v; vlen && ishspace(v[vlen]); vlen--); + for (vlen = p - v; vlen && isblank(v[vlen]); vlen--); p += 2; /* skip \r\n */ vtk = tokenize(v, vlen); @@ -150,90 +194,51 @@ static int postfix_parsejob(query_t *query) break; default: - return -1; + syslog(LOG_WARNING, "unexpected key, skipped: %.*s", klen, k); + break; } } return query->state == SMTP_UNKNOWN ? -1 : 0; - #undef PARSE_CHECK } -static void postfix_process(job_t *job) +void *policy_run(int fd, void *data) { - int nb; - const char *p; - - switch (job->mode) { - case JOB_LISTEN: - if ((job = job_accept(job, JOB_READ))) { - job->jdata = postfix_jpriv_new(); - job->process = &postfix_process; - job->stop = &postfix_stop; - } - return; - - case JOB_WRITE: - nb = write(job->fd, job->jdata->obuf.data, job->jdata->obuf.len); - if (nb < 0) { - if ((job->error = errno != EINTR && errno != EAGAIN)) { - syslog(LOG_ERR, "unexpected problem on the socket: %m"); - } - return; - } - - buffer_consume(&job->jdata->obuf, nb); - if (job->jdata->obuf.len) - return; + query_t q; + query_init(&q); - /* fall through */ + for (;;) { + int nb = buffer_read(&q.data, fd, -1); + const char *eoq; - case JOB_READ: - nb = buffer_read(&job->jdata->ibuf, job->fd, -1); if (nb < 0) { - if ((job->error = errno != EINTR && errno != EAGAIN)) { - syslog(LOG_ERR, "unexpected problem on the socket: %m"); - } - return; + if (errno == EAGAIN || errno == EINTR) + continue; + UNIXERR("read"); + break; } if (nb == 0) { - syslog(LOG_ERR, "unexpected eof"); - job->error = true; - return; + if (q.data.len) + syslog(LOG_ERR, "unexpected end of data"); + break; } - p = strstr(skipspaces(job->jdata->ibuf.data), "\r\n\r\n"); - if (!p) { - if (job->jdata->ibuf.len > SHRT_MAX) { - syslog(LOG_ERR, "too much data without CRLFCRLF"); - job->error = true; - } - return; - } - p += 4; + eoq = strstr(q.data.data + MAX(0, q.data.len - 3), "\r\n\r\n"); + if (!eoq) + continue; - query_reset(&job->jdata->query); - buffer_add(&job->jdata->query.data, job->jdata->ibuf.data, - p - 2 - job->jdata->ibuf.data); - buffer_consume(&job->jdata->query.data, p - job->jdata->ibuf.data); + if (postfix_parsejob(&q) < 0) + break; - if (postfix_parsejob(&job->jdata->query) < 0) { - job->error = true; - return; + buffer_consume(&q.data, eoq + strlen("\r\n\r\n") - q.data.data); + if (xwrite(fd, "DUNNO\r\n", strlen("DUNNO\r\n"))) { + UNIXERR("write"); + break; } - - /* TODO: run the scenario */ - return; - - default: - job->error = true; - return; } -} -#endif -void *policy_run(int fd, void *data) -{ + query_wipe(&q); close(fd); return NULL; } diff --git a/policy.h b/policy.h index 077b045..632baf8 100644 --- a/policy.h +++ b/policy.h @@ -36,73 +36,6 @@ #ifndef PFIXTOOLS_POLICY_H #define PFIXTOOLS_POLICY_H -#include - -#include "buffer.h" - -enum smtp_state { - SMTP_UNKNOWN, - SMTP_CONNECT, - SMTP_EHLO, - SMTP_HELO = SMTP_EHLO, - SMTP_MAIL, - SMTP_RCPT, - SMTP_DATA, - SMTP_END_OF_MESSAGE, - SMTP_VRFY, - SMTP_ETRN, -}; - -/* \see http://www.postfix.org/SMTPD_POLICY_README.html */ -typedef struct query_t { - unsigned state : 4; - unsigned esmtp : 1; - - const char *helo_name; - const char *queue_id; - const char *sender; - const char *recipient; - const char *recipient_count; - const char *client_address; - const char *client_name; - const char *rclient_name; - const char *instance; - - /* postfix 2.2+ */ - const char *sasl_method; - const char *sasl_username; - const char *sasl_sender; - const char *size; - const char *ccert_subject; - const char *ccert_issuer; - const char *ccsert_fingerprint; - - /* postfix 2.3+ */ - const char *encryption_protocol; - const char *encryption_cipher; - const char *encryption_keysize; - const char *etrn_domain; - - buffer_t data; -} query_t; - -static inline query_t *query_init(query_t *rq) { - memset(rq, 0, offsetof(query_t, data)); - buffer_init(&rq->data); - return rq; -} -static inline query_t *query_reset(query_t *rq) { - memset(rq, 0, offsetof(query_t, data)); - buffer_reset(&rq->data); - return rq; -} -static inline void query_wipe(query_t *rq) { - buffer_wipe(&rq->data); -} -DO_NEW(query_t, query); -DO_DELETE(query_t, query); - - void *policy_run(int fd, void *); #endif -- 2.20.1