X-Git-Url: http://git.madism.org/?a=blobdiff_plain;ds=sidebyside;f=postfix.c;h=0b5f84aa7c3679a799f00722805240bcb4f295b5;hb=f9a1a5c0041df31fa26f159764703f92d9bfa840;hp=83d7c4d58e5684d60c0ba29ced109828e09ba83e;hpb=8f6739048c2593e196aceb654b4b96e1426e57d5;p=apps%2Fpfixtools.git diff --git a/postfix.c b/postfix.c index 83d7c4d..0b5f84a 100644 --- a/postfix.c +++ b/postfix.c @@ -1,5 +1,5 @@ /******************************************************************************/ -/* postlicyd: a postfix policy daemon with a lot of features */ +/* pfixtools: a collection of postfix related tools */ /* ~~~~~~~~~ */ /* ________________________________________________________________________ */ /* */ @@ -33,63 +33,201 @@ * Copyright © 2006-2007 Pierre Habouzit */ -#include -#include -#include - -#include "job.h" +#include "common.h" #include "postfix.h" +#include "buffer.h" +#include "tokens.h" + +#if 0 -struct jpriv_t { +#define ishspace(c) ((c) == ' ' || (c) == '\t') + +typedef struct jpriv_t { buffer_t ibuf; buffer_t obuf; -}; + query_t query; +} jpriv_t; -void postfix_start(job_t *job, query_t *query) +static jpriv_t *postfix_jpriv_init(jpriv_t *jp) { + buffer_init(&jp->ibuf); + buffer_init(&jp->obuf); + query_init(&jp->query); + return jp; } - -void postfix_stop(job_t *job) +static void postfix_jpriv_wipe(jpriv_t *jp) { + query_wipe(&jp->query); + buffer_wipe(&jp->ibuf); + buffer_wipe(&jp->obuf); } +DO_NEW(jpriv_t, postfix_jpriv); +DO_DELETE(jpriv_t, postfix_jpriv); -void postfix_process(job_t *job) +static int postfix_parsejob(query_t *query) { - if (job->state & JOB_LISTEN) { - /* TODO check return code */ - job_accept(job, JOB_READ); +#define PARSE_CHECK(expr, error, ...) \ + do { \ + if (!(expr)) { \ + syslog(LOG_ERR, error, ##__VA_ARGS__); \ + return -1; \ + } \ + } while (0) + + char *p = vskipspaces(query->data.data); + + while (*p) { + char *k, *v; + int klen, vlen, vtk; + + while (ishspace(*p)) + p++; + p = strchr(k = p, '='); + PARSE_CHECK(p, "could not find '=' in line"); + for (klen = p - k; klen && ishspace(k[klen]); klen--); + p += 1; /* skip = */ + + while (ishspace(*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--); + p += 2; /* skip \r\n */ + + vtk = tokenize(v, vlen); + switch (tokenize(k, klen)) { +#define CASE(up, low) case PTK_##up: query->low = v; v[vlen] = '\0'; 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(RCLIENT_NAME, rclient_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(CCSERT_FINGERPRINT, ccsert_fingerprint); + CASE(ENCRYPTION_PROTOCOL, encryption_protocol); + CASE(ENCRYPTION_CIPHER, encryption_cipher); + CASE(ENCRYPTION_KEYSIZE, encryption_keysize); + CASE(ETRN_DOMAIN, etrn_domain); +#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: + return -1; + } } - if (job->state & JOB_WRITE) { - int nbwritten; + return query->state == SMTP_UNKNOWN ? -1 : 0; - nbwritten = write(job->fd, job->jdata->obuf.data, job->jdata->obuf.len); - if (nbwritten < 0) { - job->error = errno != EINTR && errno != EAGAIN; +#undef PARSE_CHECK +} + +static void postfix_process(job_t *job) +{ + 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, nbwritten); - } + buffer_consume(&job->jdata->obuf, nb); + if (job->jdata->obuf.len) + return; - if (job->state & JOB_READ) { - int nbread; + /* fall through */ - nbread = buffer_read(&job->jdata->ibuf, job->fd, -1); - if (nbread < 0) { - job->error = errno != EINTR && errno != EAGAIN; + 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 (nbread == 0) { + if (nb == 0) { + syslog(LOG_ERR, "unexpected eof"); job->error = true; return; } - if (!strstr(job->jdata->ibuf.data, "\r\n\r\n")) + 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; + + 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(&job->jdata->query) < 0) { + job->error = true; + return; + } - job->state &= ~JOB_READ; + /* TODO: run the scenario */ + return; - /* TODO: do the parse */ + default: + job->error = true; + return; } } +#endif