From c80eebe296e2ca5adc482bc447f824b34a890452 Mon Sep 17 00:00:00 2001 From: Gilles Chehade Date: Tue, 19 Sep 2017 10:20:13 +0200 Subject: sync with openbsd --- smtpd/filter.c | 866 ------------------------------------------- smtpd/mail.file.c | 5 +- smtpd/mail.lmtp.c | 3 + smtpd/mail.maildir.c | 5 +- smtpd/mail.mda.8 | 35 ++ smtpd/mail.mda.c | 55 +++ smtpd/mail/Makefile | 3 +- smtpd/mail/mail.mda/Makefile | 21 ++ smtpd/mta.c | 187 +++++----- smtpd/parse.y | 6 +- smtpd/pony.c | 5 +- smtpd/smtp_session.c | 566 +++++++--------------------- smtpd/smtpctl/CVS/Entries | 2 +- smtpd/smtpd-api.h | 88 +---- smtpd/smtpd.c | 4 +- smtpd/smtpd.h | 34 +- smtpd/smtpd/CVS/Entries | 2 +- smtpd/smtpd/Makefile | 3 +- smtpd/table_static.c | 92 +++-- 19 files changed, 423 insertions(+), 1559 deletions(-) delete mode 100644 smtpd/filter.c create mode 100644 smtpd/mail.mda.8 create mode 100644 smtpd/mail.mda.c create mode 100644 smtpd/mail/mail.mda/Makefile (limited to 'smtpd') diff --git a/smtpd/filter.c b/smtpd/filter.c deleted file mode 100644 index fcbdaec7..00000000 --- a/smtpd/filter.c +++ /dev/null @@ -1,866 +0,0 @@ -/* $OpenBSD: filter.c,v 1.25 2017/01/09 09:53:23 reyk Exp $ */ - -/* - * Copyright (c) 2011 Gilles Chehade - * Copyright (c) 2012 Eric Faurot - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "smtpd.h" -#include "log.h" - -enum { - QUERY_READY, - QUERY_RUNNING, - QUERY_DONE -}; - - -struct filter_proc { - TAILQ_ENTRY(filter_proc) entry; - struct mproc mproc; - int hooks; - int flags; - int ready; -}; - -struct filter { - TAILQ_ENTRY(filter) entry; - struct filter_proc *proc; -}; -TAILQ_HEAD(filter_lst, filter); - -TAILQ_HEAD(filter_query_lst, filter_query); -struct filter_session { - uint64_t id; - int terminate; - struct filter_lst *filters; - struct filter *fcurr; - - int error; - struct io *iev; - size_t idatalen; - FILE *ofile; - - struct filter_query *eom; -}; - -struct filter_query { - uint64_t qid; - int type; - struct filter_session *session; - - int state; - struct filter *current; - - /* current data */ - union { - struct { - struct sockaddr_storage local; - struct sockaddr_storage remote; - char hostname[HOST_NAME_MAX+1]; - } connect; - char line[LINE_MAX]; - struct mailaddr maddr; - size_t datalen; - } u; - - /* current response */ - struct { - int status; - int code; - char *response; - } smtp; -}; - -static void filter_imsg(struct mproc *, struct imsg *); -static void filter_post_event(uint64_t, int, struct filter *, struct filter *); -static struct filter_query *filter_query(struct filter_session *, int); -static void filter_drain_query(struct filter_query *); -static void filter_run_query(struct filter *, struct filter_query *); -static void filter_end_query(struct filter_query *); -static void filter_set_sink(struct filter_session *, int); -static int filter_tx(struct filter_session *, int); -static void filter_tx_io(struct io *, int, void *); - -static TAILQ_HEAD(, filter_proc) procs; -struct dict chains; - -static const char * filter_session_to_text(struct filter_session *); -static const char * filter_query_to_text(struct filter_query *); -static const char * filter_to_text(struct filter *); -static const char * filter_proc_to_text(struct filter_proc *); -static const char * query_to_str(int); -static const char * event_to_str(int); -static const char * status_to_str(int); -static const char * filterimsg_to_str(int); - -struct tree sessions; -struct tree queries; - -static void -filter_add_arg(struct filter_conf *filter, char *arg) -{ - if (filter->argc == MAX_FILTER_ARGS) { - log_warnx("warn: filter \"%s\" is full", filter->name); - fatalx("exiting"); - } - filter->argv[filter->argc++] = arg; -} - -static void -filter_extend_chain(struct filter_lst *chain, const char *name) -{ - struct filter *n; - struct filter_lst *fchain; - struct filter_conf *fconf; - int i; - - fconf = dict_xget(&env->sc_filters, name); - if (fconf->chain) { - log_debug("filter: extending with \"%s\"", name); - for (i = 0; i < fconf->argc; i++) - filter_extend_chain(chain, fconf->argv[i]); - } - else { - log_debug("filter: adding filter \"%s\"", name); - n = xcalloc(1, sizeof(*n), "filter_extend_chain"); - fchain = dict_get(&chains, name); - n->proc = TAILQ_FIRST(fchain)->proc; - TAILQ_INSERT_TAIL(chain, n, entry); - } -} - -void -filter_postfork(void) -{ - static int prepare = 0; - struct filter_conf *filter; - void *iter; - struct filter_proc *proc; - struct filter_lst *fchain; - struct filter *f; - struct mproc *p; - int done, i; - - if (prepare) - return; - prepare = 1; - - TAILQ_INIT(&procs); - dict_init(&chains); - - log_debug("filter: building simple chains..."); - - /* create all filter proc and associated chains */ - iter = NULL; - while (dict_iter(&env->sc_filters, &iter, NULL, (void **)&filter)) { - if (filter->chain) - continue; - - log_debug("filter: building simple chain \"%s\"", filter->name); - proc = xcalloc(1, sizeof(*proc), "filter_postfork"); - p = &proc->mproc; - p->handler = filter_imsg; - p->proc = PROC_FILTER; - p->name = xstrdup(filter->name, "filter_postfork"); - p->data = proc; - if (tracing & TRACE_DEBUG) - filter_add_arg(filter, "-v"); - if (foreground_log) - filter_add_arg(filter, "-d"); - if (mproc_fork(p, filter->path, filter->argv) < 0) - fatalx("filter_postfork"); - - log_debug("filter: registering proc \"%s\"", filter->name); - f = xcalloc(1, sizeof(*f), "filter_postfork"); - f->proc = proc; - - TAILQ_INSERT_TAIL(&procs, proc, entry); - fchain = xcalloc(1, sizeof(*fchain), "filter_postfork"); - TAILQ_INIT(fchain); - TAILQ_INSERT_TAIL(fchain, f, entry); - dict_xset(&chains, filter->name, fchain); - filter->done = 1; - } - - log_debug("filter: building complex chains..."); - - /* resolve all chains */ - done = 0; - while (!done) { - done = 1; - iter = NULL; - while (dict_iter(&env->sc_filters, &iter, NULL, - (void **)&filter)) { - if (filter->done) - continue; - done = 0; - filter->done = 1; - for (i = 0; i < filter->argc; i++) { - if (!dict_get(&chains, filter->argv[i])) { - filter->done = 0; - break; - } - } - if (filter->done == 0) - continue; - fchain = xcalloc(1, sizeof(*fchain), "filter_postfork"); - TAILQ_INIT(fchain); - log_debug("filter: building chain \"%s\"...", - filter->name); - for (i = 0; i < filter->argc; i++) - filter_extend_chain(fchain, filter->argv[i]); - log_debug("filter: done building chain \"%s\"", - filter->name); - dict_xset(&chains, filter->name, fchain); - } - } - log_debug("filter: done building complex chains"); - - fchain = xcalloc(1, sizeof(*fchain), "filter_postfork"); - TAILQ_INIT(fchain); - dict_xset(&chains, "", fchain); -} - -void -filter_configure(void) -{ - static int init = 0; - struct filter_proc *p; - - if (init) - return; - init = 1; - - tree_init(&sessions); - tree_init(&queries); - - TAILQ_FOREACH(p, &procs, entry) { - m_create(&p->mproc, IMSG_FILTER_REGISTER, 0, 0, -1); - m_add_u32(&p->mproc, FILTER_API_VERSION); - m_add_string(&p->mproc, p->mproc.name); - m_close(&p->mproc); - mproc_enable(&p->mproc); - } - - if (TAILQ_FIRST(&procs) == NULL) - smtp_configure(); -} - -void -filter_event(uint64_t id, int event) -{ - struct filter_session *s; - - if (event == EVENT_DISCONNECT) - /* On disconnect, the session is virtualy dead */ - s = tree_xpop(&sessions, id); - else - s = tree_xget(&sessions, id); - - filter_post_event(id, event, TAILQ_FIRST(s->filters), NULL); - - if (event == EVENT_DISCONNECT) { - if (s->iev) - io_free(s->iev); - if (s->ofile) - fclose(s->ofile); - free(s); - } -} - -void -filter_connect(uint64_t id, const struct sockaddr *local, - const struct sockaddr *remote, const char *host, const char *filter) -{ - struct filter_session *s; - struct filter_query *q; - - s = xcalloc(1, sizeof(*s), "filter_event"); - s->id = id; - if (filter == NULL) - filter = ""; - s->filters = dict_xget(&chains, filter); - tree_xset(&sessions, s->id, s); - - filter_event(id, EVENT_CONNECT); - q = filter_query(s, QUERY_CONNECT); - - memmove(&q->u.connect.local, local, local->sa_len); - memmove(&q->u.connect.remote, remote, remote->sa_len); - strlcpy(q->u.connect.hostname, host, sizeof(q->u.connect.hostname)); - - q->smtp.status = FILTER_OK; - q->smtp.code = 0; - q->smtp.response = NULL; - - filter_drain_query(q); -} - -void -filter_mailaddr(uint64_t id, int type, const struct mailaddr *maddr) -{ - struct filter_session *s; - struct filter_query *q; - - s = tree_xget(&sessions, id); - q = filter_query(s, type); - - strlcpy(q->u.maddr.user, maddr->user, sizeof(q->u.maddr.user)); - strlcpy(q->u.maddr.domain, maddr->domain, sizeof(q->u.maddr.domain)); - - filter_drain_query(q); -} - -void -filter_line(uint64_t id, int type, const char *line) -{ - struct filter_session *s; - struct filter_query *q; - - s = tree_xget(&sessions, id); - q = filter_query(s, type); - - if (line) - strlcpy(q->u.line, line, sizeof(q->u.line)); - - filter_drain_query(q); -} - -void -filter_eom(uint64_t id, int type, size_t datalen) -{ - struct filter_session *s; - struct filter_query *q; - - s = tree_xget(&sessions, id); - q = filter_query(s, type); - q->u.datalen = datalen; - - filter_drain_query(q); -} - -static void -filter_set_sink(struct filter_session *s, int sink) -{ - struct mproc *p; - - while (s->fcurr) { - if (s->fcurr->proc->hooks & HOOK_DATALINE) { - log_trace(TRACE_FILTERS, "filter: sending fd %d to %s", - sink, filter_to_text(s->fcurr)); - p = &s->fcurr->proc->mproc; - m_create(p, IMSG_FILTER_PIPE, 0, 0, sink); - m_add_id(p, s->id); - m_close(p); - return; - } - s->fcurr = TAILQ_PREV(s->fcurr, filter_lst, entry); - } - - log_trace(TRACE_FILTERS, "filter: chain input is %d", sink); - smtp_filter_fd(s->id, sink); -} - -void -filter_build_fd_chain(uint64_t id, int sink) -{ - struct filter_session *s; - int fd; - - s = tree_xget(&sessions, id); - s->fcurr = TAILQ_LAST(s->filters, filter_lst); - - fd = filter_tx(s, sink); - filter_set_sink(s, fd); -} - -void -filter_post_event(uint64_t id, int event, struct filter *f, struct filter *end) -{ - for(; f && f != end; f = TAILQ_NEXT(f, entry)) { - log_trace(TRACE_FILTERS, "filter: post-event event=%s filter=%s", - event_to_str(event), f->proc->mproc.name); - - m_create(&f->proc->mproc, IMSG_FILTER_EVENT, 0, 0, -1); - m_add_id(&f->proc->mproc, id); - m_add_int(&f->proc->mproc, event); - m_close(&f->proc->mproc); - } -} - -static struct filter_query * -filter_query(struct filter_session *s, int type) -{ - struct filter_query *q; - - q = xcalloc(1, sizeof(*q), "filter_query"); - q->qid = generate_uid(); - q->session = s; - q->type = type; - - q->state = QUERY_READY; - q->current = TAILQ_FIRST(s->filters); - - log_trace(TRACE_FILTERS, "filter: new query %s", query_to_str(type)); - - return (q); -} - -static void -filter_drain_query(struct filter_query *q) -{ - log_trace(TRACE_FILTERS, "filter: filter_drain_query %s", - filter_query_to_text(q)); - - /* - * The query must be passed through all filters that registered - * a hook, until one rejects it. - */ - while (q->state != QUERY_DONE) { - /* Walk over all filters */ - while (q->current) { - filter_run_query(q->current, q); - if (q->state == QUERY_RUNNING) { - log_trace(TRACE_FILTERS, - "filter: waiting for running query %s", - filter_query_to_text(q)); - return; - } - } - q->state = QUERY_DONE; - } - - /* Defer the response if the file is not closed yet. */ - if (q->type == QUERY_EOM && q->session->ofile && q->smtp.status == FILTER_OK) { - log_debug("filter: deferring eom query..."); - q->session->eom = q; - return; - } - - filter_end_query(q); -} - -static void -filter_run_query(struct filter *f, struct filter_query *q) -{ - log_trace(TRACE_FILTERS, - "filter: running filter %s for query %s", - filter_to_text(f), filter_query_to_text(q)); - - m_create(&f->proc->mproc, IMSG_FILTER_QUERY, 0, 0, -1); - m_add_id(&f->proc->mproc, q->session->id); - m_add_id(&f->proc->mproc, q->qid); - m_add_int(&f->proc->mproc, q->type); - - switch (q->type) { - case QUERY_CONNECT: - m_add_sockaddr(&f->proc->mproc, - (struct sockaddr *)&q->u.connect.local); - m_add_sockaddr(&f->proc->mproc, - (struct sockaddr *)&q->u.connect.remote); - m_add_string(&f->proc->mproc, q->u.connect.hostname); - break; - case QUERY_HELO: - m_add_string(&f->proc->mproc, q->u.line); - break; - case QUERY_MAIL: - case QUERY_RCPT: - m_add_mailaddr(&f->proc->mproc, &q->u.maddr); - break; - case QUERY_EOM: - m_add_u32(&f->proc->mproc, q->u.datalen); - break; - default: - break; - } - m_close(&f->proc->mproc); - - tree_xset(&queries, q->qid, q); - q->state = QUERY_RUNNING; -} - -static void -filter_end_query(struct filter_query *q) -{ - struct filter_session *s = q->session; - const char *response = q->smtp.response; - - log_trace(TRACE_FILTERS, "filter: filter_end_query %s", - filter_query_to_text(q)); - - if (q->type == QUERY_EOM && q->smtp.status == FILTER_OK) { - if (s->error || q->u.datalen != s->idatalen) { - response = "Internal error"; - q->smtp.code = 451; - q->smtp.status = FILTER_FAIL; - if (!s->error) - log_warnx("filter: datalen mismatch on session %" PRIx64 - ": %zu/%zu", s->id, s->idatalen, q->u.datalen); - } - } - - log_trace(TRACE_FILTERS, - "filter: query %016"PRIx64" done: " - "status=%s code=%d response=\"%s\"", - q->qid, - status_to_str(q->smtp.status), - q->smtp.code, - response); - - smtp_filter_response(s->id, q->type, q->smtp.status, q->smtp.code, - response); - free(q->smtp.response); - free(q); -} - -static void -filter_imsg(struct mproc *p, struct imsg *imsg) -{ - struct filter_proc *proc = p->data; - struct filter_session *s; - struct filter_query *q; - struct msg m; - const char *line; - uint64_t qid; - uint32_t datalen; - int type, status, code; - - if (imsg == NULL) { - log_warnx("warn: filter \"%s\" closed unexpectedly", p->name); - fatalx("exiting"); - } - - log_trace(TRACE_FILTERS, "filter: imsg %s from procfilter %s", - filterimsg_to_str(imsg->hdr.type), - filter_proc_to_text(proc)); - - switch (imsg->hdr.type) { - - case IMSG_FILTER_REGISTER: - if (proc->ready) { - log_warnx("warn: filter \"%s\" already registered", - proc->mproc.name); - exit(1); - } - - m_msg(&m, imsg); - m_get_int(&m, &proc->hooks); - m_get_int(&m, &proc->flags); - m_end(&m); - proc->ready = 1; - - log_debug("debug: filter \"%s\": hooks 0x%08x flags 0x%04x", - proc->mproc.name, proc->hooks, proc->flags); - - TAILQ_FOREACH(proc, &procs, entry) - if (!proc->ready) - return; - - smtp_configure(); - break; - - case IMSG_FILTER_RESPONSE: - m_msg(&m, imsg); - m_get_id(&m, &qid); - m_get_int(&m, &type); - if (type == QUERY_EOM) - m_get_u32(&m, &datalen); - m_get_int(&m, &status); - m_get_int(&m, &code); - if (m_is_eom(&m)) - line = NULL; - else - m_get_string(&m, &line); - m_end(&m); - - q = tree_xpop(&queries, qid); - if (q->type != type) { - log_warnx("warn: filter: type mismatch %d != %d", - q->type, type); - fatalx("exiting"); - } - q->smtp.status = status; - if (code) - q->smtp.code = code; - if (line) { - free(q->smtp.response); - q->smtp.response = xstrdup(line, "filter_imsg"); - } - q->state = (status == FILTER_OK) ? QUERY_READY : QUERY_DONE; - if (type == QUERY_EOM) - q->u.datalen = datalen; - - q->current = TAILQ_NEXT(q->current, entry); - filter_drain_query(q); - break; - - case IMSG_FILTER_PIPE: - m_msg(&m, imsg); - m_get_id(&m, &qid); - m_end(&m); - - s = tree_xget(&sessions, qid); - s->fcurr = TAILQ_PREV(s->fcurr, filter_lst, entry); - filter_set_sink(s, imsg->fd); - break; - - default: - log_warnx("warn: bad imsg from filter %s", p->name); - exit(1); - } -} - -static int -filter_tx(struct filter_session *s, int sink) -{ - int sp[2]; - - s->idatalen = 0; - s->eom = NULL; - s->error = 0; - - if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sp) == -1) { - log_warn("warn: filter: socketpair"); - return (-1); - } - - if ((s->ofile = fdopen(sink, "w")) == NULL) { - log_warn("warn: filter: fdopen"); - close(sp[0]); - close(sp[1]); - return (-1); - } - - io_set_nonblocking(sp[0]); - io_set_nonblocking(sp[1]); - - s->iev = io_new(); - io_set_callback(s->iev, filter_tx_io, s); - io_set_fd(s->iev, sp[0]); - io_set_read(s->iev); - - return (sp[1]); -} - -static void -filter_tx_io(struct io *io, int evt, void *arg) -{ - struct filter_session *s = arg; - size_t len, n; - char *data; - - log_trace(TRACE_FILTERS, "filter: filter_tx_io(%p, %s)", - s, io_strevent(evt)); - - switch (evt) { - case IO_DATAIN: - data = io_data(s->iev); - len = io_datalen(s->iev); - - log_trace(TRACE_FILTERS, - "filter: filter_tx_io: datain (%zu) for req %016"PRIx64"", - len, s->id); - - n = fwrite(data, 1, len, s->ofile); - if (n != len) { - log_warnx("warn: filter_tx_io: fwrite %zu/%zu", n, len); - s->error = 1; - break; - } - s->idatalen += n; - io_drop(s->iev, n); - return; - - case IO_DISCONNECTED: - log_trace(TRACE_FILTERS, - "debug: filter: tx done (%zu) for req %016"PRIx64, - s->idatalen, s->id); - break; - - default: - log_warn("warn: filter_tx_io: bad evt (%d) for req %016"PRIx64, - evt, s->id); - s->error = 1; - break; - } - - io_free(s->iev); - s->iev = NULL; - fclose(s->ofile); - s->ofile = NULL; - - /* deferred eom request */ - if (s->eom) { - log_debug("filter: running eom query..."); - filter_end_query(s->eom); - } else { - log_debug("filter: eom not received yet"); - } -} - -static const char * -filter_query_to_text(struct filter_query *q) -{ - static char buf[1024]; - char tmp[1024]; - - tmp[0] = '\0'; - - switch (q->type) { - case QUERY_CONNECT: - strlcat(tmp, "=", sizeof tmp); - strlcat(tmp, ss_to_text(&q->u.connect.local), - sizeof tmp); - strlcat(tmp, " <-> ", sizeof tmp); - strlcat(tmp, ss_to_text(&q->u.connect.remote), - sizeof tmp); - strlcat(tmp, "(", sizeof tmp); - strlcat(tmp, q->u.connect.hostname, sizeof tmp); - strlcat(tmp, ")", sizeof tmp); - break; - case QUERY_MAIL: - case QUERY_RCPT: - snprintf(tmp, sizeof tmp, "=%s@%s", - q->u.maddr.user, q->u.maddr.domain); - break; - case QUERY_HELO: - snprintf(tmp, sizeof tmp, "=%s", q->u.line); - break; - default: - break; - } - snprintf(buf, sizeof buf, "%016"PRIx64"[%s%s,%s]", - q->qid, query_to_str(q->type), tmp, - filter_session_to_text(q->session)); - - return (buf); -} - -static const char * -filter_session_to_text(struct filter_session *s) -{ - static char buf[1024]; - - if (s == NULL) - return "filter_session@NULL"; - - snprintf(buf, sizeof(buf), - "filter_session@%p[datalen=%zu,eom=%p,ofile=%p]", - s, s->idatalen, s->eom, s->ofile); - - return buf; -} - -static const char * -filter_to_text(struct filter *f) -{ - static char buf[1024]; - - snprintf(buf, sizeof buf, "filter:%s", filter_proc_to_text(f->proc)); - - return (buf); -} - -static const char * -filter_proc_to_text(struct filter_proc *proc) -{ - static char buf[1024]; - - snprintf(buf, sizeof buf, "%s[hooks=0x%08x,flags=0x%04x]", - proc->mproc.name, proc->hooks, proc->flags); - - return (buf); -} - -#define CASE(x) case x : return #x - -static const char * -filterimsg_to_str(int imsg) -{ - switch (imsg) { - CASE(IMSG_FILTER_REGISTER); - CASE(IMSG_FILTER_EVENT); - CASE(IMSG_FILTER_QUERY); - CASE(IMSG_FILTER_PIPE); - CASE(IMSG_FILTER_RESPONSE); - default: - return "IMSG_FILTER_???"; - } -} - -static const char * -query_to_str(int query) -{ - switch (query) { - CASE(QUERY_CONNECT); - CASE(QUERY_HELO); - CASE(QUERY_MAIL); - CASE(QUERY_RCPT); - CASE(QUERY_DATA); - CASE(QUERY_EOM); - CASE(QUERY_DATALINE); - default: - return "QUERY_???"; - } -} - -static const char * -event_to_str(int event) -{ - switch (event) { - CASE(EVENT_CONNECT); - CASE(EVENT_RESET); - CASE(EVENT_DISCONNECT); - CASE(EVENT_TX_BEGIN); - CASE(EVENT_TX_COMMIT); - CASE(EVENT_TX_ROLLBACK); - default: - return "EVENT_???"; - } -} - -static const char * -status_to_str(int status) -{ - switch (status) { - CASE(FILTER_OK); - CASE(FILTER_FAIL); - CASE(FILTER_CLOSE); - default: - return "FILTER_???"; - } -} diff --git a/smtpd/mail.file.c b/smtpd/mail.file.c index cd9fd88f..94888cea 100644 --- a/smtpd/mail.file.c +++ b/smtpd/mail.file.c @@ -34,7 +34,10 @@ int main(int argc, char *argv[]) { int ch; - + + if (! geteuid()) + errx(1, "mail.file: may not be executed as root"); + while ((ch = getopt(argc, argv, "")) != -1) { switch (ch) { default: diff --git a/smtpd/mail.lmtp.c b/smtpd/mail.lmtp.c index 55faa331..93154446 100644 --- a/smtpd/mail.lmtp.c +++ b/smtpd/mail.lmtp.c @@ -57,6 +57,9 @@ main(int argc, char *argv[]) const char *destination = "inet:localhost"; struct session session; + if (! geteuid()) + errx(1, "mail.lmtp: may not be executed as root"); + session.lhlo = "localhost"; session.mailfrom = NULL; diff --git a/smtpd/mail.maildir.c b/smtpd/mail.maildir.c index effbc49a..a209764d 100644 --- a/smtpd/mail.maildir.c +++ b/smtpd/mail.maildir.c @@ -37,7 +37,10 @@ main(int argc, char *argv[]) { int ch; char *dirname = NULL; - + + if (! geteuid()) + errx(1, "mail.maildir: may not be executed as root"); + while ((ch = getopt(argc, argv, "d:")) != -1) { switch (ch) { case 'd': diff --git a/smtpd/mail.mda.8 b/smtpd/mail.mda.8 new file mode 100644 index 00000000..61fed733 --- /dev/null +++ b/smtpd/mail.mda.8 @@ -0,0 +1,35 @@ +.\" $OpenBSD: mail.mda.8,v 1.1 2017/08/09 07:56:10 gilles Exp $ +.\" +.\" Copyright (c) 2017 Gilles Chehade +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: August 9 2017 $ +.Dt MAIL.MDA 8 +.Os +.Sh NAME +.Nm mail.mda +.Nd deliver mail to a program +.Sh SYNOPSIS +.Nm mail.mda +.Ar program +.Sh DESCRIPTION +.Nm +executes the program and its parameters. +The program must read from the standard input up to an end-of-file +and acknowledge delivery success or failure with its exit status. +.Sh EXIT STATUS +.Ex -std mail.mda +.Sh SEE ALSO +.Xr mail 1 , +.Xr smtpd 8 diff --git a/smtpd/mail.mda.c b/smtpd/mail.mda.c new file mode 100644 index 00000000..6853b040 --- /dev/null +++ b/smtpd/mail.mda.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2017 Gilles Chehade + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern char **environ; + +int +main(int argc, char *argv[]) +{ + int ch; + + if (! geteuid()) + errx(1, "mail.mda: may not be executed as root"); + + while ((ch = getopt(argc, argv, "")) != -1) { + switch (ch) { + default: + break; + } + } + argc -= optind; + argv += optind; + + if (argc == 0) + errx(1, "mail.mda: command required"); + + execve(argv[0], argv, environ); + err(1, NULL); +} diff --git a/smtpd/mail/Makefile b/smtpd/mail/Makefile index e83da451..78e46ff4 100644 --- a/smtpd/mail/Makefile +++ b/smtpd/mail/Makefile @@ -1,9 +1,10 @@ -# $OpenBSD: Makefile,v 1.3 2017/02/14 16:48:30 gilles Exp $ +# $OpenBSD: Makefile,v 1.4 2017/08/09 07:56:10 gilles Exp $ .include SUBDIR = mail.lmtp SUBDIR+= mail.file SUBDIR+= mail.maildir +SUBDIR+= mail.mda .include diff --git a/smtpd/mail/mail.mda/Makefile b/smtpd/mail/mail.mda/Makefile new file mode 100644 index 00000000..5f28c430 --- /dev/null +++ b/smtpd/mail/mail.mda/Makefile @@ -0,0 +1,21 @@ +.PATH: ${.CURDIR}/../.. + +PROG= mail.mda +BINOWN= root +BINGRP= wheel + +BINMODE?=0555 + +BINDIR= /usr/libexec +MAN= mail.mda.8 + +CFLAGS+= -fstack-protector-all +CFLAGS+= -Wall -Wstrict-prototypes -Wmissing-prototypes +CFLAGS+= -Wmissing-declarations +CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual +CFLAGS+= -Wsign-compare +CFLAGS+= -Werror-implicit-function-declaration + +SRCS= mail.mda.c + +.include diff --git a/smtpd/mta.c b/smtpd/mta.c index 08630cc6..d15f86c3 100644 --- a/smtpd/mta.c +++ b/smtpd/mta.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mta.c,v 1.203 2017/01/09 09:53:23 reyk Exp $ */ +/* $OpenBSD: mta.c,v 1.205 2017/09/15 11:50:39 eric Exp $ */ /* * Copyright (c) 2008 Pierre-Yves Ritschard @@ -57,6 +57,7 @@ #define RELAY_ONHOLD 0x01 #define RELAY_HOLDQ 0x02 +static void mta_handle_envelope(struct envelope *); static void mta_query_mx(struct mta_relay *); static void mta_query_secret(struct mta_relay *); static void mta_query_preference(struct mta_relay *); @@ -177,7 +178,6 @@ void mta_imsg(struct mproc *p, struct imsg *imsg) { struct mta_relay *relay; - struct mta_task *task; struct mta_domain *domain; struct mta_host *host; struct mta_route *route; @@ -185,7 +185,6 @@ mta_imsg(struct mproc *p, struct imsg *imsg) struct mta_mx *mx, *imx; struct mta_source *source; struct hoststat *hs; - struct mta_envelope *e; struct sockaddr_storage ss; struct envelope evp; struct msg m; @@ -206,83 +205,7 @@ mta_imsg(struct mproc *p, struct imsg *imsg) m_msg(&m, imsg); m_get_envelope(&m, &evp); m_end(&m); - - relay = mta_relay(&evp); - /* ignore if we don't know the limits yet */ - if (relay->limits && - relay->ntask >= (size_t)relay->limits->task_hiwat) { - if (!(relay->state & RELAY_ONHOLD)) { - log_info("smtp-out: hiwat reached on %s: holding envelopes", - mta_relay_to_text(relay)); - relay->state |= RELAY_ONHOLD; - } - } - - /* - * If the relay has too many pending tasks, tell the - * scheduler to hold it until further notice - */ - if (relay->state & RELAY_ONHOLD) { - relay->state |= RELAY_HOLDQ; - m_create(p_queue, IMSG_MTA_DELIVERY_HOLD, 0, 0, -1); - m_add_evpid(p_queue, evp.id); - m_add_id(p_queue, relay->id); - m_close(p_queue); - mta_relay_unref(relay); /* from here */ - return; - } - - task = NULL; - TAILQ_FOREACH(task, &relay->tasks, entry) - if (task->msgid == evpid_to_msgid(evp.id)) - break; - - if (task == NULL) { - task = xmalloc(sizeof *task, "mta_task"); - TAILQ_INIT(&task->envelopes); - task->relay = relay; - relay->ntask += 1; - TAILQ_INSERT_TAIL(&relay->tasks, task, entry); - task->msgid = evpid_to_msgid(evp.id); - if (evp.sender.user[0] || evp.sender.domain[0]) - (void)snprintf(buf, sizeof buf, "%s@%s", - evp.sender.user, evp.sender.domain); - else - buf[0] = '\0'; - task->sender = xstrdup(buf, "mta_task:sender"); - stat_increment("mta.task", 1); - } - - e = xcalloc(1, sizeof *e, "mta_envelope"); - e->id = evp.id; - e->creation = evp.creation; - (void)snprintf(buf, sizeof buf, "%s@%s", - evp.dest.user, evp.dest.domain); - e->dest = xstrdup(buf, "mta_envelope:dest"); - (void)snprintf(buf, sizeof buf, "%s@%s", - evp.rcpt.user, evp.rcpt.domain); - if (strcmp(buf, e->dest)) - e->rcpt = xstrdup(buf, "mta_envelope:rcpt"); - e->task = task; - if (evp.dsn_orcpt.user[0] && evp.dsn_orcpt.domain[0]) { - (void)snprintf(buf, sizeof buf, "%s@%s", - evp.dsn_orcpt.user, evp.dsn_orcpt.domain); - e->dsn_orcpt = xstrdup(buf, - "mta_envelope:dsn_orcpt"); - } - (void)strlcpy(e->dsn_envid, evp.dsn_envid, - sizeof e->dsn_envid); - e->dsn_notify = evp.dsn_notify; - e->dsn_ret = evp.dsn_ret; - - TAILQ_INSERT_TAIL(&task->envelopes, e, entry); - log_debug("debug: mta: received evp:%016" PRIx64 - " for <%s>", e->id, e->dest); - - stat_increment("mta.envelope", 1); - - mta_drain(relay); - mta_relay_unref(relay); /* from here */ + mta_handle_envelope(&evp); return; case IMSG_MTA_OPEN_MESSAGE: @@ -394,24 +317,6 @@ mta_imsg(struct mproc *p, struct imsg *imsg) } } - if (p->proc == PROC_PARENT) { - switch (imsg->hdr.type) { - case IMSG_CTL_VERBOSE: - m_msg(&m, imsg); - m_get_int(&m, &v); - m_end(&m); - log_trace_verbose(v); - return; - - case IMSG_CTL_PROFILE: - m_msg(&m, imsg); - m_get_int(&m, &v); - m_end(&m); - profiling = v; - return; - } - } - if (p->proc == PROC_CONTROL) { switch (imsg->hdr.type) { @@ -712,6 +617,92 @@ mta_route_next_task(struct mta_relay *relay, struct mta_route *route) return (task); } +static void +mta_handle_envelope(struct envelope *evp) +{ + struct mta_relay *relay; + struct mta_task *task; + struct mta_envelope *e; + char buf[LINE_MAX]; + + relay = mta_relay(evp); + /* ignore if we don't know the limits yet */ + if (relay->limits && + relay->ntask >= (size_t)relay->limits->task_hiwat) { + if (!(relay->state & RELAY_ONHOLD)) { + log_info("smtp-out: hiwat reached on %s: holding envelopes", + mta_relay_to_text(relay)); + relay->state |= RELAY_ONHOLD; + } + } + + /* + * If the relay has too many pending tasks, tell the + * scheduler to hold it until further notice + */ + if (relay->state & RELAY_ONHOLD) { + relay->state |= RELAY_HOLDQ; + m_create(p_queue, IMSG_MTA_DELIVERY_HOLD, 0, 0, -1); + m_add_evpid(p_queue, evp->id); + m_add_id(p_queue, relay->id); + m_close(p_queue); + mta_relay_unref(relay); /* from here */ + return; + } + + task = NULL; + TAILQ_FOREACH(task, &relay->tasks, entry) + if (task->msgid == evpid_to_msgid(evp->id)) + break; + + if (task == NULL) { + task = xmalloc(sizeof *task, "mta_task"); + TAILQ_INIT(&task->envelopes); + task->relay = relay; + relay->ntask += 1; + TAILQ_INSERT_TAIL(&relay->tasks, task, entry); + task->msgid = evpid_to_msgid(evp->id); + if (evp->sender.user[0] || evp->sender.domain[0]) + (void)snprintf(buf, sizeof buf, "%s@%s", + evp->sender.user, evp->sender.domain); + else + buf[0] = '\0'; + task->sender = xstrdup(buf, "mta_task:sender"); + stat_increment("mta.task", 1); + } + + e = xcalloc(1, sizeof *e, "mta_envelope"); + e->id = evp->id; + e->creation = evp->creation; + (void)snprintf(buf, sizeof buf, "%s@%s", + evp->dest.user, evp->dest.domain); + e->dest = xstrdup(buf, "mta_envelope:dest"); + (void)snprintf(buf, sizeof buf, "%s@%s", + evp->rcpt.user, evp->rcpt.domain); + if (strcmp(buf, e->dest)) + e->rcpt = xstrdup(buf, "mta_envelope:rcpt"); + e->task = task; + if (evp->dsn_orcpt.user[0] && evp->dsn_orcpt.domain[0]) { + (void)snprintf(buf, sizeof buf, "%s@%s", + evp->dsn_orcpt.user, evp->dsn_orcpt.domain); + e->dsn_orcpt = xstrdup(buf, + "mta_envelope:dsn_orcpt"); + } + (void)strlcpy(e->dsn_envid, evp->dsn_envid, + sizeof e->dsn_envid); + e->dsn_notify = evp->dsn_notify; + e->dsn_ret = evp->dsn_ret; + + TAILQ_INSERT_TAIL(&task->envelopes, e, entry); + log_debug("debug: mta: received evp:%016" PRIx64 + " for <%s>", e->id, e->dest); + + stat_increment("mta.envelope", 1); + + mta_drain(relay); + mta_relay_unref(relay); /* from here */ +} + static void mta_delivery_flush_event(int fd, short event, void *arg) { diff --git a/smtpd/parse.y b/smtpd/parse.y index b522d402..5cf4a24b 100644 --- a/smtpd/parse.y +++ b/smtpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.197 2017/07/11 06:08:40 natano Exp $ */ +/* $OpenBSD: parse.y,v 1.199 2017/09/08 16:51:21 eric Exp $ */ /* * Copyright (c) 2008 Gilles Chehade @@ -480,7 +480,7 @@ opt_if_listen : INET4 { } listen_opts.options |= LO_PORT; - if ($2 <= 0 || $2 >= (int)USHRT_MAX) { + if ($2 <= 0 || $2 > (int)USHRT_MAX) { yyerror("invalid port: %" PRId64, $2); YYERROR; } @@ -1901,8 +1901,6 @@ parse_config(struct smtpd *x_conf, const char *filename, int opts) table = NULL; rule = NULL; - dict_init(&conf->sc_filters); - dict_init(conf->sc_ca_dict); dict_init(conf->sc_pki_dict); dict_init(conf->sc_ssl_dict); diff --git a/smtpd/pony.c b/smtpd/pony.c index c057a6df..fb0ec8bb 100644 --- a/smtpd/pony.c +++ b/smtpd/pony.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pony.c,v 1.17 2017/01/09 09:53:23 reyk Exp $ */ +/* $OpenBSD: pony.c,v 1.18 2017/08/13 11:10:30 eric Exp $ */ /* * Copyright (c) 2014 Gilles Chehade @@ -60,7 +60,7 @@ pony_imsg(struct mproc *p, struct imsg *imsg) case IMSG_CONF_START: return; case IMSG_CONF_END: - filter_configure(); + smtp_configure(); return; case IMSG_CTL_VERBOSE: m_msg(&m, imsg); @@ -148,7 +148,6 @@ pony(void) mda_postfork(); mta_postfork(); smtp_postfork(); - filter_postfork(); /* do not purge listeners and pki, they are purged * in smtp_configure() diff --git a/smtpd/smtp_session.c b/smtpd/smtp_session.c index 7060b80b..7d83b9b9 100644 --- a/smtpd/smtp_session.c +++ b/smtpd/smtp_session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: smtp_session.c,v 1.304 2017/06/19 08:35:56 gilles Exp $ */ +/* $OpenBSD: smtp_session.c,v 1.312 2017/09/08 16:51:22 eric Exp $ */ /* * Copyright (c) 2008 Gilles Chehade @@ -69,20 +69,17 @@ enum session_flags { SF_BOUNCE = 0x0010, SF_VERIFIED = 0x0020, SF_BADINPUT = 0x0080, - SF_FILTERCONN = 0x0100, - SF_FILTERDATA = 0x0200, - SF_FILTERTX = 0x0400, }; -enum message_flags { - MF_QUEUE_ENVELOPE_FAIL = 0x00001, - MF_ERROR_SIZE = 0x01000, - MF_ERROR_IO = 0x02000, - MF_ERROR_LOOP = 0x04000, - MF_ERROR_MALFORMED = 0x08000, - MF_ERROR_RESOURCES = 0x10000, +enum { + TX_OK = 0, + TX_ERROR_ENVELOPE, + TX_ERROR_SIZE, + TX_ERROR_IO, + TX_ERROR_LOOP, + TX_ERROR_MALFORMED, + TX_ERROR_RESOURCES }; -#define MF_ERROR (MF_ERROR_SIZE | MF_ERROR_IO | MF_ERROR_LOOP | MF_ERROR_MALFORMED | MF_ERROR_RESOURCES) enum smtp_command { CMD_HELO = 0, @@ -114,16 +111,12 @@ struct smtp_tx { size_t destcount; TAILQ_HEAD(, smtp_rcpt) rcpts; + int error; size_t datain; size_t odatalen; - struct io *oev; + FILE *ofile; int hdrdone; int rcvcount; - int dataeom; - - int msgflags; - int msgcode; - int skiphdr; struct rfc2822_parser rfc2822_parser; }; @@ -167,8 +160,6 @@ static void smtp_connected(struct smtp_session *); static void smtp_send_banner(struct smtp_session *); static void smtp_tls_verified(struct smtp_session *); static void smtp_io(struct io *, int, void *); -static void smtp_data_io(struct io *, int, void *); -static void smtp_data_io_done(struct smtp_session *); static void smtp_enter_state(struct smtp_session *, int); static void smtp_reply(struct smtp_session *, char *, ...); static void smtp_command(struct smtp_session *, char *); @@ -176,6 +167,7 @@ static int smtp_parse_mail_args(struct smtp_session *, char *); static int smtp_parse_rcpt_args(struct smtp_session *, char *); static void smtp_rfc4954_auth_plain(struct smtp_session *, char *); static void smtp_rfc4954_auth_login(struct smtp_session *, char *); +static void smtp_message_fd(struct smtp_session *, int); static void smtp_message_end(struct smtp_session *); static int smtp_message_printf(struct smtp_session *, const char *, ...); static void smtp_free(struct smtp_session *, const char *); @@ -193,18 +185,7 @@ static void smtp_queue_open_message(struct smtp_session *); static void smtp_queue_commit(struct smtp_session *); static void smtp_queue_rollback(struct smtp_session *); -static void smtp_filter_connect(struct smtp_session *, struct sockaddr *); -static void smtp_filter_rset(struct smtp_session *); -static void smtp_filter_disconnect(struct smtp_session *); -static void smtp_filter_tx_begin(struct smtp_session *); -static void smtp_filter_tx_commit(struct smtp_session *); -static void smtp_filter_tx_rollback(struct smtp_session *); -static void smtp_filter_eom(struct smtp_session *); -static void smtp_filter_helo(struct smtp_session *); -static void smtp_filter_mail(struct smtp_session *); -static void smtp_filter_rcpt(struct smtp_session *); -static void smtp_filter_data(struct smtp_session *); -static void smtp_filter_dataline(struct smtp_session *, const char *); +static void smtp_dataline(struct smtp_session *, const char *); static struct { int code; const char *cmd; } commands[] = { { CMD_HELO, "HELO" }, @@ -226,8 +207,6 @@ static struct tree wait_lka_ptr; static struct tree wait_lka_helo; static struct tree wait_lka_mail; static struct tree wait_lka_rcpt; -static struct tree wait_filter; -static struct tree wait_filter_data; static struct tree wait_parent_auth; static struct tree wait_queue_msg; static struct tree wait_queue_fd; @@ -615,8 +594,6 @@ smtp_session_init(void) tree_init(&wait_lka_helo); tree_init(&wait_lka_mail); tree_init(&wait_lka_rcpt); - tree_init(&wait_filter); - tree_init(&wait_filter_data); tree_init(&wait_parent_auth); tree_init(&wait_queue_msg); tree_init(&wait_queue_fd); @@ -728,12 +705,10 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg) break; case LKA_PERMFAIL: - smtp_filter_tx_rollback(s); smtp_tx_free(s->tx); smtp_reply(s, "%d %s", 530, "Sender rejected"); break; case LKA_TEMPFAIL: - smtp_filter_tx_rollback(s); smtp_tx_free(s->tx); smtp_reply(s, "421 %s: Temporary Error", esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS)); @@ -785,7 +760,6 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg) smtp_reply(s, "250 %s: Ok", esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS)); } else { - smtp_filter_tx_rollback(s); smtp_tx_free(s->tx); smtp_reply(s, "421 %s: Temporary Error", esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS)); @@ -812,8 +786,7 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg) log_debug("smtp: %p: fd %d from queue", s, imsg->fd); - tree_xset(&wait_filter, s->id, s); - filter_build_fd_chain(s->id, imsg->fd); + smtp_message_fd(s, imsg->fd); return; case IMSG_QUEUE_ENVELOPE_SUBMIT: @@ -826,7 +799,7 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg) s->tx->destcount++; } else - s->tx->msgflags |= MF_QUEUE_ENVELOPE_FAIL; + s->tx->error = TX_ERROR_ENVELOPE; m_end(&m); return; @@ -838,7 +811,7 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg) if (!success) fatalx("commit evp failed: not supposed to happen"); s = tree_xpop(&wait_lka_rcpt, reqid); - if (s->tx->msgflags & MF_QUEUE_ENVELOPE_FAIL) { + if (s->tx->error) { /* * If an envelope failed, we can't cancel the last * RCPT only so we must cancel the whole transaction @@ -869,7 +842,6 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg) m_end(&m); s = tree_xpop(&wait_queue_commit, reqid); if (!success) { - smtp_filter_tx_rollback(s); smtp_tx_free(s->tx); smtp_reply(s, "421 %s: Temporary failure", esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS)); @@ -877,7 +849,6 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg) return; } - smtp_filter_tx_commit(s); smtp_reply(s, "250 %s: %08x Message accepted for delivery", esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS), s->tx->msgid); @@ -1015,181 +986,30 @@ smtp_tls_verified(struct smtp_session *s) } void -smtp_filter_response(uint64_t id, int query, int status, uint32_t code, - const char *line) -{ - struct smtp_session *s; - struct ca_cert_req_msg req_ca_cert; - - s = tree_xpop(&wait_filter, id); - - if (status == FILTER_CLOSE) { - code = code ? code : 421; - line = line ? line : "Temporary failure"; - smtp_reply(s, "%d %s", code, line); - smtp_enter_state(s, STATE_QUIT); - return; - } - - switch (query) { - - case QUERY_CONNECT: - if (status != FILTER_OK) { - log_info("%016"PRIx64" smtp " - "event=closed address=%s host=%s reason=filter-reject", - s->id, ss_to_text(&s->ss), s->hostname); - smtp_free(s, "rejected by filter"); - return; - } - - if (s->listener->flags & F_SMTPS) { - req_ca_cert.reqid = s->id; - if (s->listener->pki_name[0]) { - (void)strlcpy(req_ca_cert.name, s->listener->pki_name, - sizeof req_ca_cert.name); - req_ca_cert.fallback = 0; - } - else { - (void)strlcpy(req_ca_cert.name, s->smtpname, - sizeof req_ca_cert.name); - req_ca_cert.fallback = 1; - } - m_compose(p_lka, IMSG_SMTP_TLS_INIT, 0, 0, -1, - &req_ca_cert, sizeof(req_ca_cert)); - tree_xset(&wait_ssl_init, s->id, s); - return; - } - smtp_send_banner(s); - return; - - case QUERY_HELO: - if (status != FILTER_OK) { - code = code ? code : 530; - line = line ? line : "Hello rejected"; - smtp_reply(s, "%d %s", code, line); - return; - } - - smtp_enter_state(s, STATE_HELO); - smtp_reply(s, "250%c%s Hello %s [%s], pleased to meet you", - (s->flags & SF_EHLO) ? '-' : ' ', - s->smtpname, - s->helo, - ss_to_text(&s->ss)); - - if (s->flags & SF_EHLO) { - smtp_reply(s, "250-8BITMIME"); - smtp_reply(s, "250-ENHANCEDSTATUSCODES"); - smtp_reply(s, "250-SIZE %zu", env->sc_maxsize); - if (ADVERTISE_EXT_DSN(s)) - smtp_reply(s, "250-DSN"); - if (ADVERTISE_TLS(s)) - smtp_reply(s, "250-STARTTLS"); - if (ADVERTISE_AUTH(s)) - smtp_reply(s, "250-AUTH PLAIN LOGIN"); - smtp_reply(s, "250 HELP"); - } - return; - - case QUERY_MAIL: - if (status != FILTER_OK) { - smtp_filter_tx_rollback(s); - smtp_tx_free(s->tx); - code = code ? code : 530; - line = line ? line : "Sender rejected"; - smtp_reply(s, "%d %s", code, line); - return; - } - - /* only check sendertable if defined and user has authenticated */ - if (s->flags & SF_AUTHENTICATED && s->listener->sendertable[0]) { - m_create(p_lka, IMSG_SMTP_CHECK_SENDER, 0, 0, -1); - m_add_id(p_lka, s->id); - m_add_string(p_lka, s->listener->sendertable); - m_add_string(p_lka, s->username); - m_add_mailaddr(p_lka, &s->tx->evp.sender); - m_close(p_lka); - tree_xset(&wait_lka_mail, s->id, s); - } - else - smtp_queue_create_message(s); - return; - - case QUERY_RCPT: - if (status != FILTER_OK) { - code = code ? code : 530; - line = line ? line : "Recipient rejected"; - smtp_reply(s, "%d %s", code, line); - return; - } - - m_create(p_lka, IMSG_SMTP_EXPAND_RCPT, 0, 0, -1); - m_add_id(p_lka, s->id); - m_add_envelope(p_lka, &s->tx->evp); - m_close(p_lka); - tree_xset(&wait_lka_rcpt, s->id, s); - return; - - case QUERY_DATA: - if (status != FILTER_OK) { - code = code ? code : 530; - line = line ? line : "Message rejected"; - smtp_reply(s, "%d %s", code, line); - return; - } - smtp_queue_open_message(s); - return; - - case QUERY_EOM: - if (status != FILTER_OK) { - tree_pop(&wait_filter_data, s->id); - smtp_filter_tx_rollback(s); - smtp_queue_rollback(s); - smtp_tx_free(s->tx); - code = code ? code : 530; - line = line ? line : "Message rejected"; - smtp_reply(s, "%d %s", code, line); - smtp_enter_state(s, STATE_HELO); - return; - } - smtp_message_end(s); - return; - - default: - log_warn("smtp: bad mfa query type %d", query); - } -} - -void -smtp_filter_fd(uint64_t id, int fd) +smtp_message_fd(struct smtp_session *s, int fd) { - struct smtp_session *s; - X509 *x; - - s = tree_xpop(&wait_filter, id); + X509 *x; - log_debug("smtp: %p: fd %d from filter", s, fd); + log_debug("smtp: %p: message fd %d", s, fd); - if (fd == -1) { + if ((s->tx->ofile = fdopen(fd, "w")) == NULL) { + close(fd); smtp_reply(s, "421 %s: Temporary Error", esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS)); smtp_enter_state(s, STATE_QUIT); return; } - io_set_nonblocking(fd); - s->tx->oev = io_new(); - io_set_callback(s->tx->oev, smtp_data_io, s); - io_set_fd(s->tx->oev, fd); + s->tx->odatalen = 0; - io_print(s->tx->oev, "Received: "); + smtp_message_printf(s, "Received: "); if (!(s->listener->flags & F_MASK_SOURCE)) { - io_printf(s->tx->oev, "from %s (%s [%s])", + smtp_message_printf(s, "from %s (%s [%s])", s->helo, s->hostname, ss_to_text(&s->ss)); } - io_printf(s->tx->oev, "\n\tby %s (%s) with %sSMTP%s%s id %08x", + smtp_message_printf(s, "\n\tby %s (%s) with %sSMTP%s%s id %08x", s->smtpname, SMTPD_NAME, s->flags & SF_EHLO ? "E" : "", @@ -1199,7 +1019,7 @@ smtp_filter_fd(uint64_t id, int fd) if (s->flags & SF_SECURE) { x = SSL_get_peer_certificate(io_ssl(s->io)); - io_printf(s->tx->oev, " (%s:%s:%d:%s)", + smtp_message_printf(s, " (%s:%s:%d:%s)", SSL_get_version(io_ssl(s->io)), SSL_get_cipher_name(io_ssl(s->io)), SSL_get_cipher_bits(io_ssl(s->io), NULL), @@ -1207,29 +1027,24 @@ smtp_filter_fd(uint64_t id, int fd) X509_free(x); if (s->listener->flags & F_RECEIVEDAUTH) { - io_printf(s->tx->oev, " auth=%s", s->username[0] ? "yes" : "no"); + smtp_message_printf(s, " auth=%s", + s->username[0] ? "yes" : "no"); if (s->username[0]) - io_printf(s->tx->oev, " user=%s", s->username); + smtp_message_printf(s, " user=%s", s->username); } } if (s->tx->rcptcount == 1) { - io_printf(s->tx->oev, "\n\tfor <%s@%s>", + smtp_message_printf(s, "\n\tfor <%s@%s>", s->tx->evp.rcpt.user, s->tx->evp.rcpt.domain); } - io_printf(s->tx->oev, ";\n\t%s\n", time_to_text(time(NULL))); - - s->tx->odatalen = io_queued(s->tx->oev); - - io_set_write(s->tx->oev); + smtp_message_printf(s, ";\n\t%s\n", time_to_text(time(NULL))); smtp_enter_state(s, STATE_BODY); smtp_reply(s, "354 Enter mail, end with \".\"" " on a line by itself"); - - tree_xset(&wait_filter_data, s->id, s); } static void @@ -1287,7 +1102,7 @@ smtp_io(struct io *io, int evt, void *arg) /* Message body */ if (s->state == STATE_BODY && strcmp(line, ".")) { - smtp_filter_dataline(s, line); + smtp_dataline(s, line); goto nextline; } @@ -1310,9 +1125,7 @@ smtp_io(struct io *io, int evt, void *arg) io_set_write(io); - s->tx->dataeom = 1; - if (io_queued(s->tx->oev) == 0) - smtp_data_io_done(s); + smtp_message_end(s); return; } @@ -1443,91 +1256,14 @@ smtp_tx_free(struct smtp_tx *tx) free(rcpt); } - if (tx->oev) - io_free(tx->oev); + if (tx->ofile) + fclose(tx->ofile); tx->session->tx = NULL; free(tx); } -static void -smtp_data_io(struct io *io, int evt, void *arg) -{ - struct smtp_session *s = arg; - - log_trace(TRACE_IO, "smtp: %p (data): %s %s", s, io_strevent(evt), - io_strio(io)); - - switch (evt) { - case IO_TIMEOUT: - case IO_DISCONNECTED: - case IO_ERROR: - log_debug("debug: smtp: %p: io error on mfa", s); - io_free(s->tx->oev); - s->tx->oev = NULL; - s->tx->msgflags |= MF_ERROR_IO; - if (io_paused(s->io, IO_IN)) { - log_debug("debug: smtp: %p: resuming session after mfa error", s); - io_resume(s->io, IO_IN); - } - break; - - case IO_LOWAT: - if (io_paused(s->io, IO_IN)) { - log_debug("debug: smtp: %p: filter congestion over: resuming session", s); - io_resume(s->io, IO_IN); - } - if (s->tx->dataeom && io_queued(s->tx->oev) == 0) - smtp_data_io_done(s); - break; - - default: - fatalx("smtp_data_io()"); - } -} - -static void -smtp_data_io_done(struct smtp_session *s) -{ - log_debug("debug: smtp: %p: data io done (%zu bytes)", s, s->tx->odatalen); - - if (s->tx->oev) { - io_free(s->tx->oev); - s->tx->oev = NULL; - } - - if (s->tx->msgflags & MF_ERROR) { - - tree_pop(&wait_filter_data, s->id); - - smtp_filter_tx_rollback(s); - smtp_queue_rollback(s); - - if (s->tx->msgflags & MF_ERROR_SIZE) - smtp_reply(s, "554 Message too big"); - else if (s->tx->msgflags & MF_ERROR_LOOP) - smtp_reply(s, "500 %s %s: Loop detected", - esc_code(ESC_STATUS_PERMFAIL, ESC_ROUTING_LOOP_DETECTED), - esc_description(ESC_ROUTING_LOOP_DETECTED)); - else if (s->tx->msgflags & MF_ERROR_RESOURCES) - smtp_reply(s, "421 %s: Temporary Error", - esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS)); - else if (s->tx->msgflags & MF_ERROR_MALFORMED) - smtp_reply(s, "550 %s %s: Message is not RFC 2822 compliant", - esc_code(ESC_STATUS_PERMFAIL, - ESC_DELIVERY_NOT_AUTHORIZED_MESSAGE_REFUSED), - esc_description(ESC_DELIVERY_NOT_AUTHORIZED_MESSAGE_REFUSED)); - else if (s->tx->msgflags) - smtp_reply(s, "421 Internal server error"); - smtp_tx_free(s->tx); - smtp_enter_state(s, STATE_HELO); - } - else { - smtp_filter_eom(s); - } -} - static void smtp_command(struct smtp_session *s, char *line) { @@ -1600,13 +1336,31 @@ smtp_command(struct smtp_session *s, char *line) break; } (void)strlcpy(s->helo, args, sizeof(s->helo)); - s->flags &= SF_SECURE | SF_AUTHENTICATED | SF_VERIFIED | SF_FILTERCONN; + s->flags &= SF_SECURE | SF_AUTHENTICATED | SF_VERIFIED; if (cmd == CMD_EHLO) { s->flags |= SF_EHLO; s->flags |= SF_8BITMIME; } - smtp_filter_helo(s); + smtp_enter_state(s, STATE_HELO); + smtp_reply(s, "250%c%s Hello %s [%s], pleased to meet you", + (s->flags & SF_EHLO) ? '-' : ' ', + s->smtpname, + s->helo, + ss_to_text(&s->ss)); + + if (s->flags & SF_EHLO) { + smtp_reply(s, "250-8BITMIME"); + smtp_reply(s, "250-ENHANCEDSTATUSCODES"); + smtp_reply(s, "250-SIZE %zu", env->sc_maxsize); + if (ADVERTISE_EXT_DSN(s)) + smtp_reply(s, "250-DSN"); + if (ADVERTISE_TLS(s)) + smtp_reply(s, "250-STARTTLS"); + if (ADVERTISE_AUTH(s)) + smtp_reply(s, "250-AUTH PLAIN LOGIN"); + smtp_reply(s, "250 HELP"); + } break; /* * SETUP @@ -1743,8 +1497,18 @@ smtp_command(struct smtp_session *s, char *line) break; } - smtp_filter_tx_begin(s); - smtp_filter_mail(s); + /* only check sendertable if defined and user has authenticated */ + if (s->flags & SF_AUTHENTICATED && s->listener->sendertable[0]) { + m_create(p_lka, IMSG_SMTP_CHECK_SENDER, 0, 0, -1); + m_add_id(p_lka, s->id); + m_add_string(p_lka, s->listener->sendertable); + m_add_string(p_lka, s->username); + m_add_mailaddr(p_lka, &s->tx->evp.sender); + m_close(p_lka); + tree_xset(&wait_lka_mail, s->id, s); + } + else + smtp_queue_create_message(s); break; /* * TRANSACTION @@ -1774,7 +1538,11 @@ smtp_command(struct smtp_session *s, char *line) if (args && smtp_parse_rcpt_args(s, args) == -1) break; - smtp_filter_rcpt(s); + m_create(p_lka, IMSG_SMTP_EXPAND_RCPT, 0, 0, -1); + m_add_id(p_lka, s->id); + m_add_envelope(p_lka, &s->tx->evp); + m_close(p_lka); + tree_xset(&wait_lka_rcpt, s->id, s); break; case CMD_RSET: @@ -1786,13 +1554,11 @@ smtp_command(struct smtp_session *s, char *line) } if (s->tx) { - smtp_filter_tx_rollback(s); if (s->tx->msgid) smtp_queue_rollback(s); smtp_tx_free(s->tx); } - smtp_filter_rset(s); smtp_reply(s, "250 %s: Reset state", esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS)); break; @@ -1811,7 +1577,7 @@ smtp_command(struct smtp_session *s, char *line) break; } - smtp_filter_data(s); + smtp_queue_open_message(s); break; /* * ANY @@ -2089,6 +1855,7 @@ smtp_lookup_servername(struct smtp_session *s) static void smtp_connected(struct smtp_session *s) { + struct ca_cert_req_msg req_ca_cert; struct sockaddr_storage ss; socklen_t sl; @@ -2103,8 +1870,25 @@ smtp_connected(struct smtp_session *s) return; } - s->flags |= SF_FILTERCONN; - smtp_filter_connect(s, (struct sockaddr *)&ss); + if (s->listener->flags & F_SMTPS) { + req_ca_cert.reqid = s->id; + if (s->listener->pki_name[0]) { + (void)strlcpy(req_ca_cert.name, s->listener->pki_name, + sizeof req_ca_cert.name); + req_ca_cert.fallback = 0; + } + else { + (void)strlcpy(req_ca_cert.name, s->smtpname, + sizeof req_ca_cert.name); + req_ca_cert.fallback = 1; + } + m_compose(p_lka, IMSG_SMTP_TLS_INIT, 0, 0, -1, + &req_ca_cert, sizeof(req_ca_cert)); + tree_xset(&wait_ssl_init, s->id, s); + return; + } + + smtp_send_banner(s); } static void @@ -2126,25 +1910,48 @@ smtp_enter_state(struct smtp_session *s, int newstate) static void smtp_message_end(struct smtp_session *s) { - log_debug("debug: %p: end of message, msgflags=0x%04x", s, s->tx->msgflags); + log_debug("debug: %p: end of message, error=%d", s, s->tx->error); - tree_xpop(&wait_filter_data, s->id); + fclose(s->tx->ofile); + s->tx->ofile = NULL; - if (s->tx->msgflags & MF_ERROR) { - smtp_filter_tx_rollback(s); - smtp_queue_rollback(s); - if (s->tx->msgflags & MF_ERROR_SIZE) - smtp_reply(s, "554 %s %s: Transaction failed, message too big", - esc_code(ESC_STATUS_PERMFAIL, ESC_MESSAGE_TOO_BIG_FOR_SYSTEM), - esc_description(ESC_MESSAGE_TOO_BIG_FOR_SYSTEM)); - else - smtp_reply(s, "%d Message rejected", s->tx->msgcode); - smtp_tx_free(s->tx); - smtp_enter_state(s, STATE_HELO); - return; + switch(s->tx->error) { + case TX_OK: + smtp_queue_commit(s); + return; + + case TX_ERROR_SIZE: + smtp_reply(s, "554 %s %s: Transaction failed, message too big", + esc_code(ESC_STATUS_PERMFAIL, ESC_MESSAGE_TOO_BIG_FOR_SYSTEM), + esc_description(ESC_MESSAGE_TOO_BIG_FOR_SYSTEM)); + break; + + case TX_ERROR_LOOP: + smtp_reply(s, "500 %s %s: Loop detected", + esc_code(ESC_STATUS_PERMFAIL, ESC_ROUTING_LOOP_DETECTED), + esc_description(ESC_ROUTING_LOOP_DETECTED)); + break; + + case TX_ERROR_MALFORMED: + smtp_reply(s, "550 %s %s: Message is not RFC 2822 compliant", + esc_code(ESC_STATUS_PERMFAIL, ESC_DELIVERY_NOT_AUTHORIZED_MESSAGE_REFUSED), + esc_description(ESC_DELIVERY_NOT_AUTHORIZED_MESSAGE_REFUSED)); + break; + + case TX_ERROR_IO: + case TX_ERROR_RESOURCES: + smtp_reply(s, "421 %s: Temporary Error", + esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS)); + break; + + default: + /* fatal? */ + smtp_reply(s, "421 Internal server error"); } - smtp_queue_commit(s); + smtp_queue_rollback(s); + smtp_tx_free(s->tx); + smtp_enter_state(s, STATE_HELO); } static int @@ -2153,16 +1960,16 @@ smtp_message_printf(struct smtp_session *s, const char *fmt, ...) va_list ap; int len; - if (s->tx->msgflags & MF_ERROR) + if (s->tx->error) return -1; va_start(ap, fmt); - len = io_vprintf(s->tx->oev, fmt, ap); + len = vfprintf(s->tx->ofile, fmt, ap); va_end(ap); if (len < 0) { log_warn("smtp-in: session %016"PRIx64": vfprintf", s->id); - s->tx->msgflags |= MF_ERROR_IO; + s->tx->error = TX_ERROR_IO; } else s->tx->odatalen += len; @@ -2231,18 +2038,12 @@ smtp_free(struct smtp_session *s, const char * reason) { log_debug("debug: smtp: %p: deleting session: %s", s, reason); - tree_pop(&wait_filter_data, s->id); - if (s->tx) { if (s->tx->msgid) smtp_queue_rollback(s); - smtp_filter_tx_rollback(s); smtp_tx_free(s->tx); } - if (s->flags & SF_FILTERCONN) - smtp_filter_disconnect(s); - if (s->flags & SF_SECURE && s->listener->flags & F_SMTPS) stat_decrement("smtp.smtps", 1); if (s->flags & SF_SECURE && s->listener->flags & F_STARTTLS) @@ -2488,94 +2289,14 @@ smtp_queue_rollback(struct smtp_session *s) } static void -smtp_filter_rset(struct smtp_session *s) -{ - filter_event(s->id, EVENT_RESET); -} - -static void -smtp_filter_tx_begin(struct smtp_session *s) -{ - s->flags |= SF_FILTERTX; - filter_event(s->id, EVENT_TX_BEGIN); -} - -static void -smtp_filter_tx_commit(struct smtp_session *s) -{ - s->flags &= ~SF_FILTERTX; - filter_event(s->id, EVENT_TX_COMMIT); -} - -static void -smtp_filter_tx_rollback(struct smtp_session *s) -{ - s->flags &= ~SF_FILTERTX; - filter_event(s->id, EVENT_TX_ROLLBACK); -} - -static void -smtp_filter_disconnect(struct smtp_session *s) -{ - filter_event(s->id, EVENT_DISCONNECT); -} - -static void -smtp_filter_connect(struct smtp_session *s, struct sockaddr *sa) -{ - char *filter; - - tree_xset(&wait_filter, s->id, s); - - filter = s->listener->filter[0] ? s->listener->filter : NULL; - - filter_connect(s->id, sa, (struct sockaddr *)&s->ss, s->hostname, filter); -} - -static void -smtp_filter_eom(struct smtp_session *s) -{ - tree_xset(&wait_filter, s->id, s); - filter_eom(s->id, QUERY_EOM, s->tx->odatalen); -} - -static void -smtp_filter_helo(struct smtp_session *s) -{ - tree_xset(&wait_filter, s->id, s); - filter_line(s->id, QUERY_HELO, s->helo); -} - -static void -smtp_filter_mail(struct smtp_session *s) -{ - tree_xset(&wait_filter, s->id, s); - filter_mailaddr(s->id, QUERY_MAIL, &s->tx->evp.sender); -} - -static void -smtp_filter_rcpt(struct smtp_session *s) -{ - tree_xset(&wait_filter, s->id, s); - filter_mailaddr(s->id, QUERY_RCPT, &s->tx->evp.rcpt); -} - -static void -smtp_filter_data(struct smtp_session *s) -{ - tree_xset(&wait_filter, s->id, s); - filter_line(s->id, QUERY_DATA, NULL); -} - -static void -smtp_filter_dataline(struct smtp_session *s, const char *line) +smtp_dataline(struct smtp_session *s, const char *line) { int ret; log_trace(TRACE_SMTP, "<<< [MSG] %s", line); - /* ignore data line if an error flag is set */ - if (s->tx->msgflags & MF_ERROR) + /* ignore data line if an error is set */ + if (s->tx->error) return; /* escape lines starting with a '.' */ @@ -2585,7 +2306,7 @@ smtp_filter_dataline(struct smtp_session *s, const char *line) /* account for newline */ s->tx->datain += strlen(line) + 1; if (s->tx->datain > env->sc_maxsize) { - s->tx->msgflags |= MF_ERROR_SIZE; + s->tx->error = TX_ERROR_SIZE; return; } @@ -2606,7 +2327,7 @@ smtp_filter_dataline(struct smtp_session *s, const char *line) if (strncasecmp("Received: ", line, 10) == 0) s->tx->rcvcount++; if (s->tx->rcvcount == MAX_HOPS_COUNT) { - s->tx->msgflags |= MF_ERROR_LOOP; + s->tx->error = TX_ERROR_LOOP; log_warnx("warn: loop detected"); return; } @@ -2617,19 +2338,14 @@ smtp_filter_dataline(struct smtp_session *s, const char *line) ret = rfc2822_parser_feed(&s->tx->rfc2822_parser, line); if (ret == -1) { - s->tx->msgflags |= MF_ERROR_RESOURCES; + s->tx->error = TX_ERROR_RESOURCES; return; } if (ret == 0) { - s->tx->msgflags |= MF_ERROR_MALFORMED; + s->tx->error = TX_ERROR_MALFORMED; return; } - - if (io_queued(s->tx->oev) > DATA_HIWAT && !io_paused(s->io, IO_IN)) { - log_debug("debug: smtp: %p: filter congestion: pausing session", s); - io_pause(s->io, IO_IN); - } } #define CASE(x) case x : return #x diff --git a/smtpd/smtpctl/CVS/Entries b/smtpd/smtpctl/CVS/Entries index 02ff43ca..4f5f5e29 100644 --- a/smtpd/smtpctl/CVS/Entries +++ b/smtpd/smtpctl/CVS/Entries @@ -1,2 +1,2 @@ -/Makefile/1.45/Tue Aug 1 21:13:51 2017// +/Makefile/1.45/Mon Jul 3 22:21:47 2017// D diff --git a/smtpd/smtpd-api.h b/smtpd/smtpd-api.h index ce18063f..18f61bcd 100644 --- a/smtpd/smtpd-api.h +++ b/smtpd/smtpd-api.h @@ -1,4 +1,4 @@ -/* $OpenBSD: smtpd-api.h,v 1.31 2016/09/03 16:06:26 eric Exp $ */ +/* $OpenBSD: smtpd-api.h,v 1.32 2017/09/08 16:51:22 eric Exp $ */ /* * Copyright (c) 2013 Eric Faurot @@ -20,8 +20,6 @@ #ifndef _SMTPD_API_H_ #define _SMTPD_API_H_ -#define FILTER_API_VERSION 52 - struct mailaddr { char user[SMTPD_MAXLOCALPARTSIZE]; char domain[SMTPD_MAXDOMAINPARTSIZE]; @@ -40,62 +38,6 @@ struct dict { size_t count; }; -enum filter_status { - FILTER_OK, - FILTER_FAIL, - FILTER_CLOSE, -}; - -enum filter_imsg { - IMSG_FILTER_REGISTER, - IMSG_FILTER_EVENT, - IMSG_FILTER_QUERY, - IMSG_FILTER_PIPE, - IMSG_FILTER_RESPONSE -}; - -/* XXX - server side requires mfa_session.c update on filter_event */ -enum filter_event_type { - EVENT_CONNECT, - EVENT_RESET, - EVENT_DISCONNECT, - EVENT_TX_BEGIN, - EVENT_TX_COMMIT, - EVENT_TX_ROLLBACK, -}; - -/* XXX - server side requires mfa_session.c update on filter_hook changes */ -enum filter_query_type { - QUERY_CONNECT, - QUERY_HELO, - QUERY_MAIL, - QUERY_RCPT, - QUERY_DATA, - QUERY_EOM, - QUERY_DATALINE, -}; - -/* XXX - server side requires mfa_session.c update on filter_hook changes */ -enum filter_hook_type { - HOOK_CONNECT = 1 << 0, - HOOK_HELO = 1 << 1, - HOOK_MAIL = 1 << 2, - HOOK_RCPT = 1 << 3, - HOOK_DATA = 1 << 4, - HOOK_EOM = 1 << 5, - HOOK_RESET = 1 << 6, - HOOK_DISCONNECT = 1 << 7, - HOOK_COMMIT = 1 << 8, - HOOK_ROLLBACK = 1 << 9, - HOOK_DATALINE = 1 << 10, -}; - -struct filter_connect { - struct sockaddr_storage local; - struct sockaddr_storage remote; - const char *hostname; -}; - #define PROC_QUEUE_API_VERSION 2 enum { @@ -324,34 +266,6 @@ const char *esc_code(enum enhanced_status_class, enum enhanced_status_code); const char *esc_description(enum enhanced_status_code); -/* filter_api.c */ -void filter_api_setugid(uid_t, gid_t); -void filter_api_set_chroot(const char *); -void filter_api_no_chroot(void); -void filter_api_set_udata(uint64_t, void *); -void *filter_api_get_udata(uint64_t); - -void filter_api_loop(void); -int filter_api_accept(uint64_t); -int filter_api_reject(uint64_t, enum filter_status); -int filter_api_reject_code(uint64_t, enum filter_status, uint32_t, - const char *); -void filter_api_writeln(uint64_t, const char *); -const char *filter_api_sockaddr_to_text(const struct sockaddr *); -const char *filter_api_mailaddr_to_text(const struct mailaddr *); - -void filter_api_on_connect(int(*)(uint64_t, struct filter_connect *)); -void filter_api_on_helo(int(*)(uint64_t, const char *)); -void filter_api_on_mail(int(*)(uint64_t, struct mailaddr *)); -void filter_api_on_rcpt(int(*)(uint64_t, struct mailaddr *)); -void filter_api_on_data(int(*)(uint64_t)); -void filter_api_on_dataline(void(*)(uint64_t, const char *)); -void filter_api_on_eom(int(*)(uint64_t, size_t)); -void filter_api_on_reset(void(*)(uint64_t)); -void filter_api_on_disconnect(void(*)(uint64_t)); -void filter_api_on_commit(void(*)(uint64_t)); -void filter_api_on_rollback(void(*)(uint64_t)); - /* queue */ void queue_api_on_close(int(*)(void)); void queue_api_on_message_create(int(*)(uint32_t *)); diff --git a/smtpd/smtpd.c b/smtpd/smtpd.c index d4182d57..5433711f 100644 --- a/smtpd/smtpd.c +++ b/smtpd/smtpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: smtpd.c,v 1.289 2017/05/12 20:15:52 gilles Exp $ */ +/* $OpenBSD: smtpd.c,v 1.290 2017/09/08 16:51:22 eric Exp $ */ /* * Copyright (c) 2008 Gilles Chehade @@ -1696,8 +1696,6 @@ proc_name(enum smtp_proc_type proc) return "pony"; case PROC_CA: return "ca"; - case PROC_FILTER: - return "filter-proc"; case PROC_CLIENT: return "client-proc"; default: diff --git a/smtpd/smtpd.h b/smtpd/smtpd.h index 39f9e136..1456a5fc 100644 --- a/smtpd/smtpd.h +++ b/smtpd/smtpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: smtpd.h,v 1.534 2017/08/04 14:38:49 gilles Exp $ */ +/* $OpenBSD: smtpd.h,v 1.536 2017/09/08 16:51:22 eric Exp $ */ /* * Copyright (c) 2008 Gilles Chehade @@ -46,8 +46,6 @@ #define MAX_HOPS_COUNT 100 #define DEFAULT_MAX_BODY_SIZE (35*1024*1024) -#define MAX_FILTER_NAME 32 -#define MAX_FILTER_ARGS 255 #define EXPAND_BUFFER 1024 @@ -325,7 +323,6 @@ enum smtp_proc_type { PROC_PONY, PROC_CA, - PROC_FILTER, PROC_CLIENT, }; @@ -635,11 +632,6 @@ struct smtpd { struct dict *sc_limits_dict; - struct dict sc_filters; - uint32_t filtermask; - - char sc_enqueue_filter[PATH_MAX]; - char *sc_tls_ciphers; char *sc_subaddressing_delim; @@ -685,16 +677,6 @@ struct deliver { struct userinfo userinfo; }; -#define MAX_FILTER_PER_CHAIN 16 -struct filter_conf { - int chain; - int done; - int argc; - char *name; - char *argv[MAX_FILTER_ARGS + 1]; - char *path; -}; - struct mta_host { SPLAY_ENTRY(mta_host) entry; struct sockaddr *sa; @@ -1200,18 +1182,6 @@ int expand_to_text(struct expand *, char *, size_t); RB_PROTOTYPE(expandtree, expandnode, nodes, expand_cmp); -/* filter.c */ -void filter_postfork(void); -void filter_configure(void); -void filter_connect(uint64_t, const struct sockaddr *, - const struct sockaddr *, const char *, const char *); -void filter_mailaddr(uint64_t, int, const struct mailaddr *); -void filter_line(uint64_t, int, const char *); -void filter_eom(uint64_t, int, size_t); -void filter_event(uint64_t, int); -void filter_build_fd_chain(uint64_t, int); - - /* forward.c */ int forwards_get(int, struct expand *); @@ -1395,8 +1365,6 @@ void smtp_collect(void); int smtp_session(struct listener *, int, const struct sockaddr_storage *, const char *); void smtp_session_imsg(struct mproc *, struct imsg *); -void smtp_filter_response(uint64_t, int, int, uint32_t, const char *); -void smtp_filter_fd(uint64_t, int); /* smtpf_session.c */ diff --git a/smtpd/smtpd/CVS/Entries b/smtpd/smtpd/CVS/Entries index 8a84585e..09e8b8f9 100644 --- a/smtpd/smtpd/CVS/Entries +++ b/smtpd/smtpd/CVS/Entries @@ -1,2 +1,2 @@ -/Makefile/1.87/Tue Aug 1 21:16:01 2017// +/Makefile/1.88/Sun Aug 13 11:10:31 2017// D diff --git a/smtpd/smtpd/Makefile b/smtpd/smtpd/Makefile index a1d1f1d7..a7621419 100644 --- a/smtpd/smtpd/Makefile +++ b/smtpd/smtpd/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.87 2017/05/26 21:30:00 gilles Exp $ +# $OpenBSD: Makefile,v 1.88 2017/08/13 11:10:31 eric Exp $ .PATH: ${.CURDIR}/.. @@ -17,7 +17,6 @@ SRCS+= dns.c SRCS+= envelope.c SRCS+= esc.c SRCS+= expand.c -SRCS+= filter.c SRCS+= forward.c SRCS+= iobuf.c SRCS+= ioev.c diff --git a/smtpd/table_static.c b/smtpd/table_static.c index a2031849..facb0e4a 100644 --- a/smtpd/table_static.c +++ b/smtpd/table_static.c @@ -1,4 +1,4 @@ -/* $OpenBSD: table_static.c,v 1.15 2016/01/22 13:08:44 gilles Exp $ */ +/* $OpenBSD: table_static.c,v 1.17 2017/08/29 07:37:11 eric Exp $ */ /* * Copyright (c) 2013 Eric Faurot @@ -47,7 +47,6 @@ static int table_static_lookup(void *, struct dict *, const char *, static int table_static_fetch(void *, struct dict *, enum table_service, union lookup *); static void table_static_close(void *); -static int table_static_parse(struct table *, const char *, enum table_type); struct table_backend table_backend_static = { K_ALIAS|K_CREDENTIALS|K_DOMAIN|K_NETADDR|K_USERINFO| @@ -71,40 +70,68 @@ static struct keycmp { static int -table_static_config(struct table *table) -{ - /* no config ? ok */ - if (*table->t_config == '\0') - return 1; - - return table_static_parse(table, table->t_config, T_LIST|T_HASH); -} - -static int -table_static_parse(struct table *t, const char *config, enum table_type type) +table_static_config(struct table *t) { FILE *fp; - char *buf = NULL; + char *buf = NULL, *p; + int lineno = 0; size_t sz = 0; ssize_t flen; char *keyp; char *valp; size_t ret = 0; - if ((fp = fopen(config, "r")) == NULL) { - log_warn("warn: Table \"%s\"", config); - return 0; - } + /* no config ? ok */ + if (*t->t_config == '\0') + return 1; + + if ((fp = fopen(t->t_config, "r")) == NULL) { + log_warn("warn: Table \"%s\"", t->t_config); + return 0; + } while ((flen = getline(&buf, &sz, fp)) != -1) { + lineno++; if (buf[flen - 1] == '\n') - buf[flen - 1] = '\0'; + buf[--flen] = '\0'; keyp = buf; - while (isspace((unsigned char)*keyp)) + while (isspace((unsigned char)*keyp)) { ++keyp; - if (*keyp == '\0' || *keyp == '#') + --flen; + } + if (*keyp == '\0') continue; + while (isspace((unsigned char)keyp[flen - 1])) + keyp[--flen] = '\0'; + if (*keyp == '#') { + if (t->t_type == T_NONE) { + keyp++; + while (isspace((unsigned char)*keyp)) + ++keyp; + if (!strcmp(keyp, "@list")) + t->t_type = T_LIST; + } + continue; + } + + if (t->t_type == T_NONE) { + for (p = keyp; *p; p++) { + if (*p == ' ' || *p == '\t' || *p == ':') { + t->t_type = T_HASH; + break; + } + } + if (t->t_type == T_NONE) + t->t_type = T_LIST; + } + + if (t->t_type == T_LIST) { + table_add(t, keyp, NULL); + continue; + } + + /* T_HASH */ valp = keyp; strsep(&valp, " \t:"); if (valp) { @@ -118,21 +145,20 @@ table_static_parse(struct table *t, const char *config, enum table_type type) if (*valp == '\0') valp = NULL; } - - if (t->t_type == 0) - t->t_type = (valp == keyp || valp == NULL) ? T_LIST : - T_HASH; - - if (!(t->t_type & type)) + if (valp == NULL) { + log_warnx("%s: invalid map entry line %d", t->t_config, + lineno); goto end; + } - if ((valp == keyp || valp == NULL) && t->t_type == T_LIST) - table_add(t, keyp, NULL); - else if ((valp != keyp && valp != NULL) && t->t_type == T_HASH) - table_add(t, keyp, valp); - else - goto end; + table_add(t, keyp, valp); + } + + if (ferror(fp)) { + log_warn("%s: getline", t->t_config); + goto end; } + /* Accept empty alias files; treat them as hashes */ if (t->t_type == T_NONE && t->t_backend->services & K_ALIAS) t->t_type = T_HASH; -- cgit v1.2.3-59-g8ed1b