summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.sbin/smtpd/mta_session.c222
-rw-r--r--usr.sbin/smtpd/smtpd.h6
2 files changed, 172 insertions, 56 deletions
diff --git a/usr.sbin/smtpd/mta_session.c b/usr.sbin/smtpd/mta_session.c
index 567795d2e02..c641d83b00e 100644
--- a/usr.sbin/smtpd/mta_session.c
+++ b/usr.sbin/smtpd/mta_session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mta_session.c,v 1.1 2012/05/11 12:12:02 eric Exp $ */
+/* $OpenBSD: mta_session.c,v 1.2 2012/05/12 17:41:27 eric Exp $ */
/*
* Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -43,27 +43,49 @@
#include "smtpd.h"
#include "log.h"
+struct mta_task {
+ SPLAY_ENTRY(mta_task) entry;
+ uint64_t id;
+
+ struct mta_session *session;
+ TAILQ_ENTRY(mta_task) list;
+
+ struct mailaddr sender;
+ TAILQ_HEAD(,envelope) envelopes;
+};
+
+SPLAY_HEAD(mta_task_tree, mta_task);
+
static void mta_io(struct io *, int);
static struct mta_session *mta_session_lookup(u_int64_t);
static void mta_enter_state(struct mta_session *, int);
-static void mta_status(struct mta_session *, const char *, ...);
-static void mta_envelope_done(struct mta_session *, struct envelope *,
+static void mta_status(struct mta_session *, int, const char *, ...);
+static int mta_envelope_done(struct mta_task *, struct envelope *,
const char *);
static void mta_send(struct mta_session *, char *, ...);
static ssize_t mta_queue_data(struct mta_session *);
static void mta_response(struct mta_session *, char *);
static int mta_session_cmp(struct mta_session *, struct mta_session *);
+static int mta_task_cmp(struct mta_task *, struct mta_task *);
+static struct mta_task * mta_task_lookup(uint64_t, int);
+static struct mta_task * mta_task_create(uint64_t, struct mta_session *);
+static void mta_task_free(struct mta_task *);
+
SPLAY_PROTOTYPE(mtatree, mta_session, entry, mta_session_cmp);
+SPLAY_PROTOTYPE(mta_task_tree, mta_task, entry, mta_task_cmp);
static const char * mta_strstate(int);
#define MTA_HIWAT 65535
+static struct mta_task_tree mta_tasks = SPLAY_INITIALIZER(&mta_tasks);
+
void
mta_session_imsg(struct imsgev *iev, struct imsg *imsg)
{
struct mta_batch *mta_batch;
+ struct mta_task *task;
struct mta_session *s;
struct mta_relay *relay;
struct envelope *e;
@@ -124,38 +146,43 @@ mta_session_imsg(struct imsgev *iev, struct imsg *imsg)
s->ssl = SPLAY_FIND(ssltree, env->sc_ssl, &key);
}
- TAILQ_INIT(&s->recipients);
TAILQ_INIT(&s->relays);
+ TAILQ_INIT(&s->tasks);
SPLAY_INSERT(mtatree, &env->mta_sessions, s);
+ if (mta_task_create(s->id, s) == NULL)
+ fatalx("mta_session_imsg: mta_task_create");
+
log_debug("mta: %p: new session for batch %llu", s, s->id);
return;
case IMSG_BATCH_APPEND:
e = imsg->data;
- s = mta_session_lookup(e->batch_id);
+ task = mta_task_lookup(e->batch_id, 1);
e = malloc(sizeof *e);
if (e == NULL)
fatal(NULL);
*e = *(struct envelope *)imsg->data;
- envelope_set_errormsg(e, "000 init");
-
+ s = task->session;
if (s->host == NULL) {
s->host = strdup(e->dest.domain);
if (s->host == NULL)
fatal("strdup");
}
+ if (TAILQ_FIRST(&task->envelopes) == NULL)
+ task->sender = e->sender;
log_debug("mta: %p: adding <%s@%s> from envelope %016" PRIx64,
s, e->dest.user, e->dest.domain, e->id);
- TAILQ_INSERT_TAIL(&s->recipients, e, entry);
+ TAILQ_INSERT_TAIL(&task->envelopes, e, entry);
return;
case IMSG_BATCH_CLOSE:
mta_batch = imsg->data;
- s = mta_session_lookup(mta_batch->id);
+ task = mta_task_lookup(mta_batch->id, 1);
+ s = task->session;
if (s->flags & MTA_USE_CERT && s->ssl == NULL) {
- mta_status(s, "190 certificate not found");
+ mta_status(s, 1, "190 certificate not found");
mta_enter_state(s, MTA_DONE);
} else
mta_enter_state(s, MTA_INIT);
@@ -180,7 +207,7 @@ mta_session_imsg(struct imsgev *iev, struct imsg *imsg)
if (s->secret == NULL)
fatal(NULL);
else if (s->secret[0] == '\0') {
- mta_status(s, "190 secrets lookup failed");
+ mta_status(s, 1, "190 secrets lookup failed");
mta_enter_state(s, MTA_DONE);
} else
mta_enter_state(s, MTA_MX);
@@ -202,13 +229,13 @@ mta_session_imsg(struct imsgev *iev, struct imsg *imsg)
s = mta_session_lookup(dns->id);
if (dns->error) {
if (dns->error == DNS_RETRY)
- mta_status(s, "100 MX lookup failed temporarily");
+ mta_status(s, 1, "100 MX lookup failed temporarily");
else if (dns->error == DNS_EINVAL)
- mta_status(s, "600 Invalid domain name");
+ mta_status(s, 1, "600 Invalid domain name");
else if (dns->error == DNS_ENONAME)
- mta_status(s, "600 Domain does not exist");
+ mta_status(s, 1, "600 Domain does not exist");
else if (dns->error == DNS_ENOTFOUND)
- mta_status(s, "600 No MX address found for domain");
+ mta_status(s, 1, "600 No MX address found for domain");
mta_enter_state(s, MTA_DONE);
} else
mta_enter_state(s, MTA_DATA);
@@ -249,6 +276,7 @@ mta_enter_state(struct mta_session *s, int newstate)
int oldstate;
struct secret secret;
struct mta_relay *relay;
+ struct mta_task *task;
struct sockaddr *sa;
struct envelope *e;
int max_reuse;
@@ -256,7 +284,7 @@ mta_enter_state(struct mta_session *s, int newstate)
struct mta_batch batch;
again:
-
+ task = TAILQ_FIRST(&s->tasks);
oldstate = s->state;
log_trace(TRACE_MTA, "mta: %p: %s -> %s", s,
@@ -280,7 +308,7 @@ mta_enter_state(struct mta_session *s, int newstate)
/*
* Obtain message body fd.
*/
- e = TAILQ_FIRST(&s->recipients);
+ e = TAILQ_FIRST(&task->envelopes);
batch.id = s->id;
batch.msgid = evpid_to_msgid(e->id);
imsg_compose_event(env->sc_ievs[PROC_QUEUE],
@@ -365,7 +393,7 @@ mta_enter_state(struct mta_session *s, int newstate)
return;
}
/* tried them all? */
- mta_status(s, "150 Can not connect to MX");
+ mta_status(s, 1, "150 Can not connect to MX");
mta_enter_state(s, MTA_DONE);
break;
@@ -378,8 +406,8 @@ mta_enter_state(struct mta_session *s, int newstate)
io_clear(&s->io);
iobuf_clear(&s->iobuf);
- if ((e = TAILQ_FIRST(&s->recipients)))
- fatalx("all envelopes should have been sent already");
+ if (TAILQ_FIRST(&s->tasks))
+ fatalx("all tasks should have been deleted already");
imsg_compose_event(env->sc_ievs[PROC_QUEUE],
IMSG_BATCH_DONE, 0, 0, -1, NULL, 0);
@@ -438,21 +466,25 @@ mta_enter_state(struct mta_session *s, int newstate)
case MTA_SMTP_READY:
/* ready to send a new mail */
- mta_enter_state(s, MTA_SMTP_MAIL);
+ if (task)
+ mta_enter_state(s, MTA_SMTP_MAIL);
+ else
+ mta_enter_state(s, MTA_SMTP_QUIT);
break;
case MTA_SMTP_MAIL:
- s->currevp = TAILQ_FIRST(&s->recipients);
- if (s->currevp->sender.user[0] &&
- s->currevp->sender.domain[0])
+ if (task->sender.user[0] &&
+ task->sender.domain[0])
mta_send(s, "MAIL FROM: <%s@%s>",
- s->currevp->sender.user,
- s->currevp->sender.domain);
+ task->sender.user,
+ task->sender.domain);
else
mta_send(s, "MAIL FROM: <>");
break;
case MTA_SMTP_RCPT:
+ if (s->currevp == NULL)
+ s->currevp = TAILQ_FIRST(&task->envelopes);
mta_send(s, "RCPT TO: <%s@%s>",
s->currevp->dest.user,
s->currevp->dest.domain);
@@ -486,6 +518,13 @@ mta_enter_state(struct mta_session *s, int newstate)
mta_send(s, "QUIT");
break;
+ case MTA_SMTP_RSET:
+ if (task == NULL)
+ mta_enter_state(s, MTA_SMTP_QUIT);
+ else
+ mta_send(s, "RSET");
+ break;
+
default:
fatal("mta_enter_state: unknown state");
}
@@ -500,6 +539,7 @@ mta_response(struct mta_session *s, char *line)
{
void *ssl;
struct envelope *evp;
+ struct mta_task *task = TAILQ_FIRST(&s->tasks);
switch (s->state) {
@@ -511,7 +551,7 @@ mta_response(struct mta_session *s, char *line)
if (line[0] != '2') {
if ((s->flags & MTA_USE_AUTH) ||
!(s->flags & MTA_ALLOW_PLAIN)) {
- mta_status(s, line);
+ mta_status(s, 1, line);
mta_enter_state(s, MTA_DONE);
return;
}
@@ -523,7 +563,7 @@ mta_response(struct mta_session *s, char *line)
case MTA_SMTP_HELO:
if (line[0] != '2') {
- mta_status(s, line);
+ mta_status(s, 1, line);
mta_enter_state(s, MTA_DONE);
return;
}
@@ -537,7 +577,7 @@ mta_response(struct mta_session *s, char *line)
return;
}
/* stop here if ssl can't be used */
- mta_status(s, line);
+ mta_status(s, 1, line);
mta_enter_state(s, MTA_DONE);
return;
}
@@ -550,7 +590,7 @@ mta_response(struct mta_session *s, char *line)
case MTA_SMTP_AUTH:
if (line[0] != '2') {
- mta_status(s, line);
+ mta_status(s, 1, line);
mta_enter_state(s, MTA_DONE);
return;
}
@@ -559,8 +599,8 @@ mta_response(struct mta_session *s, char *line)
case MTA_SMTP_MAIL:
if (line[0] != '2') {
- mta_status(s, line);
- mta_enter_state(s, MTA_DONE);
+ mta_status(s, 0, line);
+ mta_enter_state(s, MTA_SMTP_RSET);
return;
}
mta_enter_state(s, MTA_SMTP_RCPT);
@@ -570,7 +610,7 @@ mta_response(struct mta_session *s, char *line)
evp = s->currevp;
s->currevp = TAILQ_NEXT(s->currevp, entry);
if (line[0] != '2')
- mta_envelope_done(s, evp, line);
+ mta_envelope_done(task, evp, line);
if (s->currevp == NULL)
mta_enter_state(s, MTA_SMTP_DATA);
else
@@ -579,19 +619,20 @@ mta_response(struct mta_session *s, char *line)
case MTA_SMTP_DATA:
if (line[0] != '2' && line[0] != '3') {
- mta_status(s, line);
- mta_enter_state(s, MTA_DONE);
+ mta_status(s, 0, line);
+ mta_enter_state(s, MTA_SMTP_RSET);
return;
}
mta_enter_state(s, MTA_SMTP_BODY);
break;
case MTA_SMTP_DONE:
- mta_status(s, line);
- if (line[0] != '2')
- mta_enter_state(s, MTA_DONE);
- else
- mta_enter_state(s, MTA_SMTP_QUIT);
+ mta_status(s, 0, line);
+ mta_enter_state(s, MTA_SMTP_READY);
+ break;
+
+ case MTA_SMTP_RSET:
+ mta_enter_state(s, MTA_SMTP_READY);
break;
default:
@@ -634,7 +675,7 @@ mta_io(struct io *io, int evt)
line = iobuf_getline(&s->iobuf, &len);
if (line == NULL) {
if (iobuf_len(&s->iobuf) >= SMTP_LINE_MAX) {
- mta_status(s, "150 Input too long");
+ mta_status(s, 1, "150 Input too long");
mta_enter_state(s, MTA_DONE);
return;
}
@@ -645,7 +686,7 @@ mta_io(struct io *io, int evt)
log_trace(TRACE_MTA, "mta: %p: <<< %s", s, line);
if ((error = parse_smtp_response(line, len, &msg, &cont))) {
- mta_status(s, "150 Bad response: %s", error);
+ mta_status(s, 1, "150 Bad response: %s", error);
mta_enter_state(s, MTA_DONE);
return;
}
@@ -690,7 +731,7 @@ mta_io(struct io *io, int evt)
mta_enter_state(s, MTA_CONNECT);
break;
}
- mta_status(s, "150 connection timeout");
+ mta_status(s, 1, "150 connection timeout");
mta_enter_state(s, MTA_DONE);
break;
@@ -700,7 +741,7 @@ mta_io(struct io *io, int evt)
mta_enter_state(s, MTA_CONNECT);
break;
}
- mta_status(s, "150 IO error");
+ mta_status(s, 1, "150 IO error");
mta_enter_state(s, MTA_DONE);
break;
@@ -710,7 +751,7 @@ mta_io(struct io *io, int evt)
mta_enter_state(s, MTA_CONNECT);
break;
}
- mta_status(s, "150 connection closed unexpectedly");
+ mta_status(s, 1, "150 connection closed unexpectedly");
mta_enter_state(s, MTA_DONE);
break;
@@ -761,7 +802,7 @@ mta_queue_data(struct mta_session *s)
}
if (ferror(s->datafp)) {
- mta_status(s, "460 Error reading content file");
+ mta_status(s, 1, "460 Error reading content file");
return (-1);
}
@@ -774,10 +815,11 @@ mta_queue_data(struct mta_session *s)
}
static void
-mta_status(struct mta_session *s, const char *fmt, ...)
+mta_status(struct mta_session *s, int alltasks, const char *fmt, ...)
{
char *status;
struct envelope *e;
+ struct mta_task *task;
va_list ap;
va_start(ap, fmt);
@@ -785,17 +827,23 @@ mta_status(struct mta_session *s, const char *fmt, ...)
fatal("vasprintf");
va_end(ap);
- log_debug("mta: %p: new status for remaining envelopes: %s", s, status);
-
- while ((e = TAILQ_FIRST(&s->recipients)))
- mta_envelope_done(s, e, status);
+ log_debug("mta: %p: new status for %s: %s", s,
+ alltasks ? "all tasks" : "current task", status);
+ while ((task = TAILQ_FIRST(&s->tasks))) {
+ while((e = TAILQ_FIRST(&task->envelopes)))
+ if (mta_envelope_done(task, e, status))
+ break;
+ if (!alltasks)
+ break;
+ }
free(status);
}
-static void
-mta_envelope_done(struct mta_session *s, struct envelope *e, const char *status)
+static int
+mta_envelope_done(struct mta_task *task, struct envelope *e, const char *status)
{
+ struct mta_session *s = task->session;
struct mta_relay *relay = TAILQ_FIRST(&s->relays);
u_int16_t msg;
@@ -826,8 +874,15 @@ mta_envelope_done(struct mta_session *s, struct envelope *e, const char *status)
}
imsg_compose_event(env->sc_ievs[PROC_QUEUE], msg,
0, 0, -1, e, sizeof(*e));
- TAILQ_REMOVE(&s->recipients, e, entry);
+ TAILQ_REMOVE(&task->envelopes, e, entry);
free(e);
+
+ if (TAILQ_FIRST(&task->envelopes))
+ return (0);
+
+ mta_task_free(task);
+ return (1);
+
}
static int
@@ -849,6 +904,64 @@ mta_session_lookup(u_int64_t id)
SPLAY_GENERATE(mtatree, mta_session, entry, mta_session_cmp);
+static struct mta_task *
+mta_task_create(u_int64_t id, struct mta_session *s)
+{
+ struct mta_task *t;
+
+ if ((t = mta_task_lookup(id, 0)))
+ fatalx("mta_task_create: duplicate task id");
+ if ((t = calloc(1, sizeof(*t))) == NULL)
+ return (NULL);
+
+ t->id = id;
+ t->session = s;
+ SPLAY_INSERT(mta_task_tree, &mta_tasks, t);
+ TAILQ_INIT(&t->envelopes);
+ if (s)
+ TAILQ_INSERT_TAIL(&s->tasks, t, list);
+
+ return (t);
+}
+
+static int
+mta_task_cmp(struct mta_task *a, struct mta_task *b)
+{
+ return (a->id < b->id ? -1 : a->id > b->id);
+}
+
+static struct mta_task *
+mta_task_lookup(u_int64_t id, int strict)
+{
+ struct mta_task key, *res;
+
+ key.id = id;
+ res = SPLAY_FIND(mta_task_tree, &mta_tasks, &key);
+ if (res == NULL && strict)
+ fatalx("mta_task_lookup: task not found");
+ return (res);
+}
+
+static void
+mta_task_free(struct mta_task *t)
+{
+ struct envelope *e;
+
+ if (t->session)
+ TAILQ_REMOVE(&t->session->tasks, t, list);
+
+ SPLAY_REMOVE(mta_task_tree, &mta_tasks, t);
+
+ while ((e = TAILQ_FIRST(&t->envelopes))) {
+ TAILQ_REMOVE(&t->envelopes, e, entry);
+ free(e);
+ }
+
+ free(t);
+}
+
+SPLAY_GENERATE(mta_task_tree, mta_task, entry, mta_task_cmp);
+
#define CASE(x) case x : return #x
static const char *
@@ -873,6 +986,7 @@ mta_strstate(int state)
CASE(MTA_SMTP_QUIT);
CASE(MTA_SMTP_BODY);
CASE(MTA_SMTP_DONE);
+ CASE(MTA_SMTP_RSET);
default:
return "MTA_???";
}
diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h
index 478b73750b4..986b4c93667 100644
--- a/usr.sbin/smtpd/smtpd.h
+++ b/usr.sbin/smtpd/smtpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtpd.h,v 1.289 2012/05/12 15:29:16 gilles Exp $ */
+/* $OpenBSD: smtpd.h,v 1.290 2012/05/12 17:41:27 eric Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -826,6 +826,7 @@ enum mta_state {
MTA_SMTP_QUIT,
MTA_SMTP_BODY,
MTA_SMTP_DONE,
+ MTA_SMTP_RSET,
};
/* mta session flags */
@@ -857,12 +858,13 @@ struct mta_session {
char *host;
int port;
int flags;
- TAILQ_HEAD(,envelope) recipients;
TAILQ_HEAD(,mta_relay) relays;
char *authmap;
char *secret;
FILE *datafp;
+ TAILQ_HEAD(,mta_task) tasks;
+
struct envelope *currevp;
struct iobuf iobuf;
struct io io;