aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGilles Chehade <gilles@poolp.org>2017-09-19 10:20:13 +0200
committerGilles Chehade <gilles@poolp.org>2017-09-19 10:20:13 +0200
commitc80eebe296e2ca5adc482bc447f824b34a890452 (patch)
treed566cec02c64a2dd44386debc07310d88285c21a
parentfix flags masking for PURGE and remove envelope upgrade code (diff)
downloadOpenSMTPD-c80eebe296e2ca5adc482bc447f824b34a890452.tar.xz
OpenSMTPD-c80eebe296e2ca5adc482bc447f824b34a890452.zip
sync with openbsd
-rw-r--r--smtpd/filter.c866
-rw-r--r--smtpd/mail.file.c5
-rw-r--r--smtpd/mail.lmtp.c3
-rw-r--r--smtpd/mail.maildir.c5
-rw-r--r--smtpd/mail.mda.835
-rw-r--r--smtpd/mail.mda.c55
-rw-r--r--smtpd/mail/Makefile3
-rw-r--r--smtpd/mail/mail.mda/Makefile21
-rw-r--r--smtpd/mta.c187
-rw-r--r--smtpd/parse.y6
-rw-r--r--smtpd/pony.c5
-rw-r--r--smtpd/smtp_session.c566
-rw-r--r--smtpd/smtpctl/CVS/Entries2
-rw-r--r--smtpd/smtpd-api.h88
-rw-r--r--smtpd/smtpd.c4
-rw-r--r--smtpd/smtpd.h34
-rw-r--r--smtpd/smtpd/CVS/Entries2
-rw-r--r--smtpd/smtpd/Makefile3
-rw-r--r--smtpd/table_static.c92
19 files changed, 423 insertions, 1559 deletions
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 <gilles@poolp.org>
- * Copyright (c) 2012 Eric Faurot <eric@openbsd.org>
- *
- * 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 <sys/types.h>
-#include <sys/queue.h>
-#include <sys/tree.h>
-#include <sys/socket.h>
-#include <sys/wait.h>
-
-#include <netinet/in.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <event.h>
-#include <imsg.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <resolv.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#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, "<no-filter>", 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 = "<no-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 <gilles@poolp.org>
+.\"
+.\" 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 <gilles@poolp.org>
+ *
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+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 <bsd.own.mk>
SUBDIR = mail.lmtp
SUBDIR+= mail.file
SUBDIR+= mail.maildir
+SUBDIR+= mail.mda
.include <bsd.subdir.mk>
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 <bsd.prog.mk>
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 <pyr@openbsd.org>
@@ -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) {
@@ -713,6 +618,92 @@ mta_route_next_task(struct mta_relay *relay, struct mta_route *route)
}
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)
{
struct mta_envelope *e;
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 <gilles@poolp.org>
@@ -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 <gilles@poolp.org>
@@ -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 <gilles@poolp.org>
@@ -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,8 +1256,8 @@ 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;
@@ -1452,83 +1265,6 @@ smtp_tx_free(struct smtp_tx *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)
{
char *args, *eom, *method;
@@ -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 <eric@openbsd.org>
@@ -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 <gilles@poolp.org>
@@ -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 <gilles@poolp.org>
@@ -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 <eric@openbsd.org>
@@ -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;