summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacek Masiulaniec <jacekm@cvs.openbsd.org>2010-04-19 08:14:08 +0000
committerJacek Masiulaniec <jacekm@cvs.openbsd.org>2010-04-19 08:14:08 +0000
commitdc3a57651fdfd7cf25e9e9c162861d4cfaa814a9 (patch)
treed69846fa2000fe4cc83e3ac91c99f3662b074889
parent66d77e83d0378b266e8187aa2c6dcbb493d97846 (diff)
Simplify local delivery codepath:
- replace uses of struct batch in the parent with simpler struct delivery. - replace IMSG_BATCH_* dance with single IMSG_MDA_SESS_NEW. - make mda assume it delivers to external program over a pipe. - fork helper process when delivering to maildir or a file. New feature: upon external mda failure use last line of its output as an error message. With input and tests from nicm@. OK nicm@ gilles@
-rw-r--r--usr.sbin/smtpd/mda.c479
-rw-r--r--usr.sbin/smtpd/runner.c123
-rw-r--r--usr.sbin/smtpd/smtpd.c576
-rw-r--r--usr.sbin/smtpd/smtpd.h42
4 files changed, 482 insertions, 738 deletions
diff --git a/usr.sbin/smtpd/mda.c b/usr.sbin/smtpd/mda.c
index ed4cbf8e665..b3c66065197 100644
--- a/usr.sbin/smtpd/mda.c
+++ b/usr.sbin/smtpd/mda.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mda.c,v 1.37 2010/03/03 10:52:31 jacekm Exp $ */
+/* $OpenBSD: mda.c,v 1.38 2010/04/19 08:14:07 jacekm Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -33,20 +33,22 @@
#include <string.h>
#include <time.h>
#include <unistd.h>
+#include <vis.h>
#include "smtpd.h"
-__dead void mda_shutdown(void);
-void mda_sig_handler(int, short, void *);
-void mda_dispatch_parent(int, short, void *);
-void mda_dispatch_queue(int, short, void *);
-void mda_dispatch_runner(int, short, void *);
-void mda_setup_events(struct smtpd *);
-void mda_disable_events(struct smtpd *);
-void mda_store(struct batch *);
-void mda_event(int, short, void *);
-void mda_store_done(struct batch *);
-void mda_done(struct smtpd *, struct batch *);
+__dead void mda_shutdown(void);
+void mda_sig_handler(int, short, void *);
+void mda_dispatch_parent(int, short, void *);
+void mda_dispatch_queue(int, short, void *);
+void mda_dispatch_runner(int, short, void *);
+void mda_setup_events(struct smtpd *);
+void mda_disable_events(struct smtpd *);
+void mda_store(struct mda_session *);
+void mda_store_event(int, short, void *);
+struct mda_session *mda_lookup(struct smtpd *, u_int32_t);
+
+int mda_id;
void
mda_sig_handler(int sig, short event, void *p)
@@ -96,74 +98,126 @@ mda_dispatch_parent(int sig, short event, void *p)
break;
switch (imsg.hdr.type) {
- case IMSG_PARENT_MAILBOX_OPEN: {
- struct batch *b = imsg.data;
-
- IMSG_SIZE_CHECK(b);
-
- if ((b = batch_by_id(env, b->id)) == NULL)
- fatalx("mda: internal inconsistency");
-
- /* parent ensures mboxfd is valid */
- if (imsg.fd == -1)
- fatalx("mda: mboxfd pass failure");
+ case IMSG_PARENT_FORK_MDA: {
+ struct mda_session *s;
- /* got user's mbox fd */
- if ((b->mboxfp = fdopen(imsg.fd, "w")) == NULL) {
- log_warn("mda: fdopen");
- mda_done(env, b);
- break;
- }
+ s = mda_lookup(env, imsg.hdr.peerid);
- /*
- * From now on, delivery session must be deinited in
- * the parent process as well as in mda.
- */
- b->cleanup_parent = 1;
+ if (imsg.fd < 0)
+ fatalx("mda: fd pass fail");
+ s->w.fd = imsg.fd;
- /* get message content fd */
- imsg_compose_event(env->sc_ievs[PROC_PARENT],
- IMSG_PARENT_MESSAGE_OPEN, 0, 0, -1, b,
- sizeof(*b));
+ /* send message content to the helper process */
+ mda_store(s);
break;
}
- case IMSG_PARENT_MESSAGE_OPEN: {
- struct batch *b = imsg.data;
+ case IMSG_MDA_DONE: {
+ char output[64];
+ struct mda_session *s;
+ struct path *path;
+ char *error, *parent_error;
- IMSG_SIZE_CHECK(b);
+ s = mda_lookup(env, imsg.hdr.peerid);
- if ((b = batch_by_id(env, b->id)) == NULL)
- fatalx("mda: internal inconsistency");
-
- if (imsg.fd == -1) {
- mda_done(env, b);
- break;
+ /*
+ * Grab last line of mda stdout/stderr if available.
+ */
+ output[0] = '\0';
+ if (imsg.fd != -1) {
+ char *ln, *buf;
+ FILE *fp;
+ size_t len;
+
+ buf = NULL;
+ if (lseek(imsg.fd, 0, SEEK_SET) < 0)
+ fatalx("lseek");
+ fp = fdopen(imsg.fd, "r");
+ if (fp == NULL)
+ fatal("mda: fdopen");
+ while ((ln = fgetln(fp, &len))) {
+ if (ln[len - 1] == '\n')
+ ln[len - 1] = '\0';
+ else {
+ buf = malloc(len + 1);
+ if (buf == NULL)
+ fatal(NULL);
+ memcpy(buf, ln, len);
+ buf[len] = '\0';
+ ln = buf;
+ }
+ strlcpy(output, "\"", sizeof output);
+ strnvis(output + 1, ln,
+ sizeof(output) - 2,
+ VIS_SAFE | VIS_CSTYLE);
+ strlcat(output, "\"", sizeof output);
+ log_debug("mda_out: %s", output);
+ }
+ free(buf);
+ fclose(fp);
}
- if ((b->datafp = fdopen(imsg.fd, "r")) == NULL) {
- log_warn("mda: fdopen");
- mda_done(env, b);
- break;
+ /*
+ * Choose between parent's description of error and
+ * child's output, the latter having preference over
+ * the former.
+ */
+ error = NULL;
+ parent_error = imsg.data;
+ if (strcmp(parent_error, "exited okay") == 0) {
+ if (!feof(s->datafp) || s->w.queued)
+ error = "mda exited prematurely";
+ } else {
+ if (output[0])
+ error = output;
+ else
+ error = parent_error;
}
- /* got message content, copy it to mbox */
- mda_store(b);
- break;
- }
-
- case IMSG_MDA_FINALIZE: {
- struct batch *b = imsg.data;
- enum message_status status;
-
- IMSG_SIZE_CHECK(b);
+ /* update queue entry */
+ if (error == NULL)
+ s->msg.status = S_MESSAGE_ACCEPTED;
+ else
+ strlcpy(s->msg.session_errorline, error,
+ sizeof s->msg.session_errorline);
+ imsg_compose_event(env->sc_ievs[PROC_QUEUE],
+ IMSG_QUEUE_MESSAGE_UPDATE, 0, 0, -1, &s->msg,
+ sizeof s->msg);
- status = b->message.status;
- if ((b = batch_by_id(env, b->id)) == NULL)
- fatalx("mda: internal inconsistency");
- b->message.status = status;
-
- mda_done(env, b);
+ /*
+ * XXX: which struct path gets used for logging depends
+ * on whether lka did aliases or .forward processing;
+ * lka may need to be changed to present data in more
+ * unified way.
+ */
+ if (s->msg.recipient.rule.r_action == A_MAILDIR ||
+ s->msg.recipient.rule.r_action == A_MBOX)
+ path = &s->msg.recipient;
+ else
+ path = &s->msg.session_rcpt;
+
+ /* log status */
+ if (error && asprintf(&error, "Error (%s)", error) < 0)
+ fatal("mda: asprintf");
+ log_info("%s: to=<%s@%s>, delay=%d, stat=%s",
+ s->msg.message_id, path->user, path->domain,
+ time(NULL) - s->msg.creation,
+ error ? error : "Sent");
+ free(error);
+
+ /* destroy session */
+ LIST_REMOVE(s, entry);
+ if (s->w.fd != -1)
+ close(s->w.fd);
+ if (s->datafp)
+ fclose(s->datafp);
+ msgbuf_clear(&s->w);
+ event_del(&s->ev);
+ free(s);
+
+ /* update runner's session count */
+ imsg_compose_event(env->sc_ievs[PROC_RUNNER],
+ IMSG_MDA_SESS_NEW, 0, 0, -1, NULL, 0);
break;
}
@@ -176,6 +230,7 @@ mda_dispatch_parent(int sig, short event, void *p)
log_verbose(verbose);
break;
}
+
default:
log_warnx("mda_dispatch_parent: got imsg %d",
imsg.hdr.type);
@@ -266,54 +321,69 @@ mda_dispatch_runner(int sig, short event, void *p)
break;
switch (imsg.hdr.type) {
- case IMSG_BATCH_CREATE: {
- struct batch *req = imsg.data;
- struct batch *b;
-
- IMSG_SIZE_CHECK(req);
-
- /* runner opens delivery session */
- if ((b = malloc(sizeof(*b))) == NULL)
+ case IMSG_MDA_SESS_NEW: {
+ struct deliver deliver;
+ struct mda_session *s;
+ struct path *path;
+
+ /* make new session based on provided args */
+ s = calloc(1, sizeof *s);
+ if (s == NULL)
fatal(NULL);
- *b = *req;
- msgbuf_init(&b->w);
- b->env = env;
- b->mboxfp = NULL;
- b->datafp = NULL;
- SPLAY_INSERT(batchtree, &env->batch_queue, b);
- break;
- }
-
- case IMSG_BATCH_APPEND: {
- struct message *append = imsg.data;
- struct batch *b;
-
- IMSG_SIZE_CHECK(append);
+ msgbuf_init(&s->w);
+ s->msg = *(struct message *)imsg.data;
+ s->msg.status = S_MESSAGE_TEMPFAILURE;
+ s->id = mda_id++;
+ s->datafp = fdopen(imsg.fd, "r");
+ if (s->datafp == NULL)
+ fatalx("mda: fdopen");
+ LIST_INSERT_HEAD(&env->mda_sessions, s, entry);
+
+ /* request parent to fork a helper process */
+ path = &s->msg.recipient;
+ switch (path->rule.r_action) {
+ case A_EXT:
+ deliver.mode = A_EXT;
+ strlcpy(deliver.user, path->pw_name,
+ sizeof deliver.user);
+ strlcpy(deliver.to, path->rule.r_value.path,
+ sizeof deliver.to);
+ break;
- /* runner submits the message to deliver */
- if ((b = batch_by_id(env, append->batch_id)) == NULL)
- fatalx("mda: internal inconsistency");
- if (b->message.message_id[0])
- fatal("mda: runner submitted extra msg");
- b->message = *append;
+ case A_MBOX:
+ deliver.mode = A_EXT;
+ strlcpy(deliver.user, "root",
+ sizeof deliver.user);
+ snprintf(deliver.to, sizeof deliver.to,
+ "%s -f %s@%s %s", PATH_MAILLOCAL,
+ s->msg.sender.user, s->msg.sender.domain,
+ path->pw_name);
+ break;
- /* safe default */
- b->message.status = S_MESSAGE_TEMPFAILURE;
- break;
- }
+ case A_MAILDIR:
+ deliver.mode = A_MAILDIR;
+ strlcpy(deliver.user, path->pw_name,
+ sizeof deliver.user);
+ strlcpy(deliver.to, path->rule.r_value.path,
+ sizeof deliver.to);
+ break;
- case IMSG_BATCH_CLOSE: {
- struct batch *b = imsg.data;
+ case A_FILENAME:
+ deliver.mode = A_FILENAME;
+ /* XXX: unconditional SMTPD_USER is wrong. */
+ strlcpy(deliver.user, SMTPD_USER,
+ sizeof deliver.user);
+ strlcpy(deliver.to, path->u.filename,
+ sizeof deliver.to);
+ break;
- IMSG_SIZE_CHECK(b);
+ default:
+ fatalx("unknown rule action");
+ }
- /* runner finished opening delivery session;
- * request user's mbox fd */
- if ((b = batch_by_id(env, b->id)) == NULL)
- fatalx("mda: internal inconsistency");
imsg_compose_event(env->sc_ievs[PROC_PARENT],
- IMSG_PARENT_MAILBOX_OPEN, 0, 0, -1, b,
- sizeof(*b));
+ IMSG_PARENT_FORK_MDA, s->id, 0, -1, &deliver,
+ sizeof deliver);
break;
}
default:
@@ -391,7 +461,7 @@ mda(struct smtpd *env)
fatal("mda: cannot drop privileges");
#endif
- SPLAY_INIT(&env->batch_queue);
+ LIST_INIT(&env->mda_sessions);
event_init();
@@ -413,187 +483,80 @@ mda(struct smtpd *env)
}
void
-mda_store(struct batch *b)
+mda_store(struct mda_session *s)
{
char *p;
struct buf *buf;
- int ch, len;
+ int len;
- if (b->message.sender.user[0] && b->message.sender.domain[0])
+ if (s->msg.sender.user[0] && s->msg.sender.domain[0])
/* XXX: remove user provided Return-Path, if any */
len = asprintf(&p, "Return-Path: %s@%s\nDelivered-To: %s@%s\n",
- b->message.sender.user,
- b->message.sender.domain,
- b->message.session_rcpt.user,
- b->message.session_rcpt.domain);
+ s->msg.sender.user, s->msg.sender.domain,
+ s->msg.session_rcpt.user, s->msg.session_rcpt.domain);
else
len = asprintf(&p, "Delivered-To: %s@%s\n",
- b->message.session_rcpt.user,
- b->message.session_rcpt.domain);
+ s->msg.session_rcpt.user, s->msg.session_rcpt.domain);
if (len == -1)
fatal("mda_store: asprintf");
- if (b->message.recipient.rule.r_action == A_MAILDIR) {
- fprintf(b->mboxfp, "%s", p);
- while ((ch = fgetc(b->datafp)) != EOF)
- if (fputc(ch, b->mboxfp) == EOF)
- break;
- if (ferror(b->datafp))
- fatal("mda_store: cannot read message in queue");
- if (fflush(b->mboxfp) || ferror(b->mboxfp))
- fatal("mda_store: cannot write to file");
- mda_store_done(b);
- } else {
- b->w.fd = fileno(b->mboxfp);
- session_socket_blockmode(b->w.fd, BM_NONBLOCK);
- if ((buf = buf_open(len)) == NULL)
- fatal(NULL);
- if (buf_add(buf, p, len) < 0)
- fatal(NULL);
- buf_close(&b->w, buf);
- event_set(&b->ev, b->w.fd, EV_WRITE, mda_event, b);
- event_add(&b->ev, NULL);
- }
-
+ session_socket_blockmode(s->w.fd, BM_NONBLOCK);
+ if ((buf = buf_open(len)) == NULL)
+ fatal(NULL);
+ if (buf_add(buf, p, len) < 0)
+ fatal(NULL);
+ buf_close(&s->w, buf);
+ event_set(&s->ev, s->w.fd, EV_WRITE, mda_store_event, s);
+ event_add(&s->ev, NULL);
free(p);
}
void
-mda_event(int fd, short event, void *p)
+mda_store_event(int fd, short event, void *p)
{
- char tmp[16384];
- struct batch *b = p;
- struct buf *buf;
- size_t len;
+ char tmp[16384];
+ struct mda_session *s = p;
+ struct buf *buf;
+ size_t len;
- if (b->w.queued == 0) {
- if ((buf = buf_dynamic(0, sizeof(tmp))) == NULL)
+ if (s->w.queued == 0) {
+ if ((buf = buf_dynamic(0, sizeof tmp)) == NULL)
fatal(NULL);
- len = fread(tmp, 1, sizeof(tmp), b->datafp);
- if (ferror(b->datafp))
- fatal("mda_event: fread failed");
- if (feof(b->datafp) && len == 0) {
- mda_store_done(b);
+ len = fread(tmp, 1, sizeof tmp, s->datafp);
+ if (ferror(s->datafp))
+ fatal("mda_store_event: fread failed");
+ if (feof(s->datafp) && len == 0) {
+ close(s->w.fd);
+ s->w.fd = -1;
return;
}
if (buf_add(buf, tmp, len) < 0)
fatal(NULL);
- buf_close(&b->w, buf);
+ buf_close(&s->w, buf);
}
- if (buf_write(&b->w) < 0) {
- /* XXX: if $? is zero, message is considered delivered despite
- * write error. */
- log_warn("mda_event: write failed");
- mda_store_done(b);
+ if (buf_write(&s->w) < 0) {
+ close(s->w.fd);
+ s->w.fd = -1;
return;
}
- event_set(&b->ev, fd, EV_WRITE, mda_event, b);
- event_add(&b->ev, NULL);
+ event_set(&s->ev, fd, EV_WRITE, mda_store_event, s);
+ event_add(&s->ev, NULL);
}
-void
-mda_store_done(struct batch *b)
+struct mda_session *
+mda_lookup(struct smtpd *env, u_int32_t id)
{
- fclose(b->datafp);
- b->datafp = NULL;
-
- /* closing mboxfd will trigger EOF in forked mda */
- fsync(fileno(b->mboxfp));
- fclose(b->mboxfp);
- b->mboxfp = NULL;
-
- /* ... unless it is maildir, in which case we need to
- * "trigger EOF" differently */
- if (b->message.recipient.rule.r_action == A_MAILDIR)
- imsg_compose_event(b->env->sc_ievs[PROC_PARENT],
- IMSG_PARENT_MAILDIR_RENAME, 0, 0, -1, b,
- sizeof(*b));
-
- /* Waiting for IMSG_MDA_FINALIZE... */
- b->cleanup_parent = 0;
-}
+ struct mda_session *s;
-void
-mda_done(struct smtpd *env, struct batch *b)
-{
- if (b->cleanup_parent) {
- /*
- * Error has occured while both parent and mda maintain some
- * state for this delivery session. Need to deinit both.
- * Deinit parent first.
- */
-
- if (b->message.recipient.rule.r_action == A_MAILDIR) {
- /*
- * In case of maildir, deiniting parent's state consists
- * of removing the file in tmp.
- */
- imsg_compose_event(env->sc_ievs[PROC_PARENT],
- IMSG_PARENT_MAILDIR_FAIL, 0, 0, -1, b,
- sizeof(*b));
- } else {
- /*
- * In all other cases, ie. mbox and external, deiniting
- * parent's state consists of killing its child, and
- * freeing associated struct child.
- *
- * Requesting that parent does this cleanup involves
- * racing issues. The race-free way is to simply wait.
- * Eventually, child timeout in parent will be hit.
- */
- }
+ LIST_FOREACH(s, &env->mda_sessions, entry)
+ if (s->id == id)
+ break;
- /*
- * Either way, parent will eventually send IMSG_MDA_FINALIZE.
- * Then, the mda deinit will happen.
- */
- b->cleanup_parent = 0;
- } else {
- /*
- * Deinit mda.
- */
-
- /* update runner (currently: via queue) */
- imsg_compose_event(env->sc_ievs[PROC_QUEUE],
- IMSG_QUEUE_MESSAGE_UPDATE, 0, 0, -1,
- &b->message, sizeof(b->message));
-
- imsg_compose_event(env->sc_ievs[PROC_RUNNER],
- IMSG_BATCH_DONE, 0, 0, -1, NULL, 0);
-
- /* log status */
- if (b->message.recipient.rule.r_action != A_MAILDIR &&
- b->message.recipient.rule.r_action != A_MBOX) {
- log_info("%s: to=<%s@%s>, delay=%d, stat=%s",
- b->message.message_id,
- b->message.session_rcpt.user,
- b->message.session_rcpt.domain,
- time(NULL) - b->message.creation,
- b->message.status & S_MESSAGE_PERMFAILURE ? "MdaPermError" :
- b->message.status & S_MESSAGE_TEMPFAILURE ? "MdaTempError" :
- "Sent");
- }
- else {
- log_info("%s: to=<%s@%s>, delay=%d, stat=%s",
- b->message.message_id,
- b->message.recipient.user,
- b->message.recipient.domain,
- time(NULL) - b->message.creation,
- b->message.status & S_MESSAGE_PERMFAILURE ? "MdaPermError" :
- b->message.status & S_MESSAGE_TEMPFAILURE ? "MdaTempError" :
- "Sent");
- }
+ if (s == NULL)
+ fatalx("mda: bogus session id");
- /* deallocate resources */
- SPLAY_REMOVE(batchtree, &env->batch_queue, b);
- if (b->mboxfp)
- fclose(b->mboxfp);
- if (b->datafp)
- fclose(b->datafp);
- msgbuf_clear(&b->w);
- free(b);
- }
+ return s;
}
diff --git a/usr.sbin/smtpd/runner.c b/usr.sbin/smtpd/runner.c
index a2f9b1ac808..acbf095a648 100644
--- a/usr.sbin/smtpd/runner.c
+++ b/usr.sbin/smtpd/runner.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: runner.c,v 1.78 2010/01/10 16:42:35 gilles Exp $ */
+/* $OpenBSD: runner.c,v 1.79 2010/04/19 08:14:07 jacekm Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -68,8 +68,6 @@ void runner_process_queue(struct smtpd *);
void runner_process_runqueue(struct smtpd *);
void runner_process_batchqueue(struct smtpd *);
-void runner_batch_dispatch(struct smtpd *, struct batch *, time_t);
-
int runner_message_schedule(struct message *, time_t);
void runner_purge_run(void);
@@ -330,7 +328,7 @@ runner_dispatch_mda(int sig, short event, void *p)
break;
switch (imsg.hdr.type) {
- case IMSG_BATCH_DONE:
+ case IMSG_MDA_SESS_NEW:
env->stats->mda.sessions_active--;
break;
@@ -781,68 +779,56 @@ runner_process_runqueue(struct smtpd *env)
void
runner_process_batchqueue(struct smtpd *env)
{
- time_t curtime;
- struct batch *batchp, *nxt;
-
- curtime = time(NULL);
- for (batchp = SPLAY_MIN(batchtree, &env->batch_queue);
- batchp != NULL;
- batchp = nxt) {
- nxt = SPLAY_NEXT(batchtree, &env->batch_queue, batchp);
+ struct batch *batchp;
+ struct message *m;
+ int fd;
+
+ while ((batchp = SPLAY_MIN(batchtree, &env->batch_queue)) != NULL) {
+ switch (batchp->type) {
+ case T_BOUNCE_BATCH:
+ while ((m = TAILQ_FIRST(&batchp->messages))) {
+ bounce_process(env, m);
+ TAILQ_REMOVE(&batchp->messages, m, entry);
+ free(m);
+ }
+ env->stats->runner.bounces_active++;
+ env->stats->runner.bounces++;
+ break;
- runner_batch_dispatch(env, batchp, curtime);
+ case T_MDA_BATCH:
+ m = TAILQ_FIRST(&batchp->messages);
+ fd = queue_open_message_file(m->message_id);
+ imsg_compose_event(env->sc_ievs[PROC_MDA],
+ IMSG_MDA_SESS_NEW, 0, 0, fd, m, sizeof *m);
+ TAILQ_REMOVE(&batchp->messages, m, entry);
+ free(m);
+ env->stats->mda.sessions_active++;
+ env->stats->mda.sessions++;
+ break;
- SPLAY_REMOVE(batchtree, &env->batch_queue, batchp);
- bzero(batchp, sizeof(struct batch));
- free(batchp);
- }
-}
+ case T_MTA_BATCH:
+ imsg_compose_event(env->sc_ievs[PROC_MTA],
+ IMSG_BATCH_CREATE, 0, 0, -1, batchp,
+ sizeof *batchp);
+ while ((m = TAILQ_FIRST(&batchp->messages))) {
+ imsg_compose_event(env->sc_ievs[PROC_MTA],
+ IMSG_BATCH_APPEND, 0, 0, -1, m, sizeof *m);
+ TAILQ_REMOVE(&batchp->messages, m, entry);
+ free(m);
+ }
+ imsg_compose_event(env->sc_ievs[PROC_MTA],
+ IMSG_BATCH_CLOSE, 0, 0, -1, batchp, sizeof *batchp);
+ env->stats->mta.sessions_active++;
+ env->stats->mta.sessions++;
+ break;
-void
-runner_batch_dispatch(struct smtpd *env, struct batch *batchp, time_t curtime)
-{
- u_int8_t proctype;
- struct message *messagep;
-
- if ((batchp->type & (T_BOUNCE_BATCH|T_MDA_BATCH|T_MTA_BATCH)) == 0)
- fatal("runner_batch_dispatch: unknown batch type");
-
- log_debug("in batch dispatch");
- if (batchp->type == T_BOUNCE_BATCH) {
- while ((messagep = TAILQ_FIRST(&batchp->messages))) {
- bounce_process(env, messagep);
- TAILQ_REMOVE(&batchp->messages, messagep, entry);
- bzero(messagep, sizeof(*messagep));
- free(messagep);
+ default:
+ fatalx("runner_process_batchqueue: unknown type");
}
- env->stats->runner.bounces_active++;
- env->stats->runner.bounces++;
- return;
- }
- if (batchp->type & T_MDA_BATCH) {
- proctype = PROC_MDA;
- env->stats->mda.sessions_active++;
- env->stats->mda.sessions++;
- } else if (batchp->type & T_MTA_BATCH) {
- proctype = PROC_MTA;
- env->stats->mta.sessions_active++;
- env->stats->mta.sessions++;
- }
-
- imsg_compose_event(env->sc_ievs[proctype], IMSG_BATCH_CREATE, 0, 0, -1,
- batchp, sizeof (struct batch));
-
- while ((messagep = TAILQ_FIRST(&batchp->messages))) {
- imsg_compose_event(env->sc_ievs[proctype], IMSG_BATCH_APPEND, 0, 0,
- -1, messagep, sizeof (struct message));
- TAILQ_REMOVE(&batchp->messages, messagep, entry);
- bzero(messagep, sizeof(struct message));
- free(messagep);
+ SPLAY_REMOVE(batchtree, &env->batch_queue, batchp);
+ free(batchp);
}
-
- imsg_compose_event(env->sc_ievs[proctype], IMSG_BATCH_CLOSE, 0, 0, -1,
- batchp, sizeof(struct batch));
}
int
@@ -873,19 +859,12 @@ runner_message_schedule(struct message *messagep, time_t tm)
// recompute path
if (messagep->type == T_MDA_MESSAGE ||
- messagep->type == T_BOUNCE_MESSAGE) {
- if (messagep->status & S_MESSAGE_LOCKFAILURE) {
- if (messagep->retry < 128)
- return 1;
- delay = (messagep->retry * 60) + arc4random_uniform(60);
- }
- else {
- if (messagep->retry < 5)
- return 1;
+ messagep->type == T_BOUNCE_MESSAGE) {
+ if (messagep->retry < 5)
+ return 1;
- if (messagep->retry < 15)
- delay = (messagep->retry * 60) + arc4random_uniform(60);
- }
+ if (messagep->retry < 15)
+ delay = (messagep->retry * 60) + arc4random_uniform(60);
}
if (messagep->type == T_MTA_MESSAGE) {
diff --git a/usr.sbin/smtpd/smtpd.c b/usr.sbin/smtpd/smtpd.c
index ffd185692f8..85ab80a664e 100644
--- a/usr.sbin/smtpd/smtpd.c
+++ b/usr.sbin/smtpd/smtpd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtpd.c,v 1.96 2010/03/01 13:04:03 gilles Exp $ */
+/* $OpenBSD: smtpd.c,v 1.97 2010/04/19 08:14:07 jacekm Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -61,12 +61,9 @@ void parent_dispatch_runner(int, short, void *);
void parent_dispatch_queue(int, short, void *);
void parent_dispatch_control(int, short, void *);
void parent_sig_handler(int, short, void *);
-int parent_open_message_file(struct batch *);
-int parent_mailbox_open(char *, struct passwd *, struct batch *);
-int parent_filename_open(char *, struct passwd *, struct batch *);
-int parent_maildir_open(char *, struct passwd *, struct batch *);
-int parent_maildir_init(struct passwd *, char *);
-int parent_external_mda(char *, struct passwd *, struct batch *);
+
+void forkmda(struct smtpd *, struct imsgev *, u_int32_t,
+ struct deliver *);
int parent_enqueue_offline(struct smtpd *, char *);
int parent_forward_open(char *);
int setup_spool(uid_t, gid_t);
@@ -78,10 +75,6 @@ struct child *child_add(struct smtpd *, pid_t, int, int);
void child_del(struct smtpd *, pid_t);
struct child *child_lookup(struct smtpd *, pid_t);
-void parent_mda_permfail(struct smtpd *, struct batch *);
-void parent_mda_tempfail(struct smtpd *, struct batch *);
-void parent_mda_success(struct smtpd *, struct batch *);
-
extern char **environ;
int __b64_pton(char const *, unsigned char *, size_t);
@@ -420,162 +413,10 @@ parent_dispatch_mda(int imsgfd, short event, void *p)
break;
switch (imsg.hdr.type) {
- case IMSG_PARENT_MAILBOX_OPEN: {
- struct batch *batchp = imsg.data;
- struct path *path;
- struct passwd *pw;
- char *pw_name;
- char *file;
- u_int8_t i;
- int fd;
- struct action_handler {
- enum action_type action;
- int (*handler)(char *, struct passwd *, struct batch *);
- } action_hdl_table[] = {
- { A_MBOX, parent_mailbox_open },
- { A_MAILDIR, parent_maildir_open },
- { A_EXT, parent_external_mda },
- { A_FILENAME, parent_filename_open }
- };
-
- IMSG_SIZE_CHECK(batchp);
-
- batchp->env = env;
- path = &batchp->message.recipient;
- if (batchp->type & T_BOUNCE_BATCH) {
- path = &batchp->message.sender;
- }
-
- for (i = 0; i < nitems(action_hdl_table); ++i)
- if (action_hdl_table[i].action == path->rule.r_action)
- break;
- if (i == nitems(action_hdl_table))
- fatalx("parent_dispatch_mda: unknown action");
-
- file = path->rule.r_value.path;
-
- if (path->rule.r_action == A_FILENAME) {
- file = path->u.filename;
- pw_name = SMTPD_USER;
- }
- else if (path->rule.r_user != NULL)
- pw_name = path->rule.r_user;
- else
- pw_name = path->pw_name;
-
- errno = 0;
- pw = getpwnam(pw_name);
- if (pw == NULL) {
- if (errno) {
- log_warn("%s: getpwnam: %s",
- batchp->message.message_id,
- pw_name);
- parent_mda_tempfail(env, batchp);
- } else {
- log_warnx("%s: getpwnam: %s: user does not exist",
- batchp->message.message_id,
- pw_name);
- parent_mda_permfail(env, batchp);
- }
- break;
- }
-
- if (setegid(pw->pw_gid) || seteuid(pw->pw_uid))
- fatal("privdrop failed");
-
- fd = action_hdl_table[i].handler(file, pw, batchp);
-
- if (setegid(0) || seteuid(0))
- fatal("privraise failed");
-
- if (fd == -1) {
- log_warnx("%s: could not init delivery for %s",
- batchp->message.message_id, pw_name);
- parent_mda_tempfail(env, batchp);
- } else
- imsg_compose_event(iev,
- IMSG_PARENT_MAILBOX_OPEN, 0, 0, fd, batchp,
- sizeof(*batchp));
- break;
- }
- case IMSG_PARENT_MESSAGE_OPEN: {
- struct batch *batchp = imsg.data;
- int fd;
-
- IMSG_SIZE_CHECK(batchp);
-
- fd = parent_open_message_file(batchp);
- imsg_compose_event(iev, IMSG_PARENT_MESSAGE_OPEN,
- 0, 0, fd, batchp, sizeof(struct batch));
-
+ case IMSG_PARENT_FORK_MDA:
+ forkmda(env, iev, imsg.hdr.peerid, imsg.data);
break;
- }
- case IMSG_PARENT_MAILDIR_FAIL:
- case IMSG_PARENT_MAILDIR_RENAME: {
- char tmp[MAXPATHLEN], new[MAXPATHLEN];
- struct batch *batchp = imsg.data;
- struct path *path;
- struct passwd *pw;
- int ret;
- char *pw_name;
-
- IMSG_SIZE_CHECK(batchp);
-
- path = &batchp->message.recipient;
- if (batchp->type & T_BOUNCE_BATCH) {
- path = &batchp->message.sender;
- }
-
- if (path->rule.r_user != NULL)
- pw_name = path->rule.r_user;
- else
- pw_name = path->pw_name;
-
- errno = 0;
- pw = getpwnam(pw_name);
- if (pw == NULL) {
- if (errno) {
- log_warn("%s: getpwnam: %s",
- batchp->message.message_id,
- pw_name);
- parent_mda_tempfail(env, batchp);
- } else {
- log_warnx("%s: getpwnam: %s: user does not exist",
- batchp->message.message_id,
- pw_name);
- parent_mda_permfail(env, batchp);
- }
- break;
- }
-
- if (! bsnprintf(tmp, sizeof(tmp), "%s/tmp/%s",
- path->rule.r_value.path, batchp->message.message_uid))
- fatal("parent_dispatch_mda: snprintf");
- if (! bsnprintf(new, sizeof(new), "%s/new/%s",
- path->rule.r_value.path, batchp->message.message_uid))
- fatal("parent_dispatch_mda: snprintf");
- if (seteuid(pw->pw_uid) == -1)
- fatal("privdrop failed");
-
- if (imsg.hdr.type == IMSG_PARENT_MAILDIR_FAIL) {
- unlink(tmp);
- ret = 0;
- } else
- ret = rename(tmp, new);
-
- if (seteuid(0) == -1)
- fatal("privraise failed");
-
- if (ret < 0) {
- log_warn("%s: %s: cannot rename to the 'new' directory",
- batchp->message.message_id, tmp);
- parent_mda_tempfail(env, batchp);
- unlink(tmp);
- } else
- parent_mda_success(env, batchp);
- break;
- }
default:
log_warnx("parent_dispatch_mda: got imsg %d",
imsg.hdr.type);
@@ -888,13 +729,9 @@ parent_sig_handler(int sig, short event, void *p)
free(cause);
asprintf(&cause, "terminated; timeout");
}
- if (fail) {
- log_warnx("external mda %s", cause);
- parent_mda_tempfail(env, &child->mda_batch);
- } else {
- log_debug("external mda %s", cause);
- parent_mda_success(env, &child->mda_batch);
- }
+ imsg_compose_event(env->sc_ievs[PROC_MDA],
+ IMSG_MDA_DONE, child->mda_id, 0,
+ child->mda_out, cause, strlen(cause) + 1);
break;
case CHILD_ENQUEUE_OFFLINE:
@@ -1302,192 +1139,207 @@ imsg_compose_event(struct imsgev *iev, u_int16_t type, u_int32_t peerid,
return (ret);
}
-int
-parent_open_message_file(struct batch *batchp)
+void
+forkmda(struct smtpd *env, struct imsgev *iev, u_int32_t id,
+ struct deliver *deliver)
{
- int fd;
- char pathname[MAXPATHLEN];
- u_int16_t hval;
- struct message *messagep;
+ char ebuf[128], sfn[32];
+ struct passwd *pw;
+ struct child *child;
+ pid_t pid;
+ int n, allout, pipefd[2];
- messagep = &batchp->message;
- hval = queue_hash(messagep->message_id);
+ log_debug("forkmda: to %s as %s", deliver->to, deliver->user);
- if (! bsnprintf(pathname, sizeof(pathname), "%s%s/%d/%s/message",
- PATH_SPOOL, PATH_QUEUE, hval, batchp->message_id))
- fatal("parent_open_message_file: snprintf");
+ errno = 0;
+ pw = getpwnam(deliver->user);
+ if (pw == NULL) {
+ n = snprintf(ebuf, sizeof ebuf, "getpwnam: %s",
+ errno ? strerror(errno) : "no such user");
+ imsg_compose_event(iev, IMSG_MDA_DONE, id, 0, -1, ebuf, n + 1);
+ return;
+ }
- fd = open(pathname, O_RDONLY);
- return fd;
-}
+ /* lower privs early to allow fork fail due to ulimit */
+ if (seteuid(pw->pw_uid) < 0)
+ fatal("cannot lower privileges");
-int
-parent_mailbox_open(char *path, struct passwd *pw, struct batch *batchp)
-{
- pid_t pid;
- int pipefd[2];
- struct child *child;
- char sender[MAX_PATH_SIZE];
-
- /* This can never happen, but better safe than sorry. */
- if (! bsnprintf(sender, MAX_PATH_SIZE, "%s@%s",
- batchp->message.sender.user,
- batchp->message.sender.domain))
- fatal("parent_mailbox_open: bogus email length");
-
- log_debug("executing mail.local");
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipefd) == -1)
- return -1;
+ if (pipe(pipefd) < 0) {
+ n = snprintf(ebuf, sizeof ebuf, "pipe: %s", strerror(errno));
+ if (seteuid(0) < 0)
+ fatal("forkmda: cannot restore privileges");
+ imsg_compose_event(iev, IMSG_MDA_DONE, id, 0, -1, ebuf, n + 1);
+ return;
+ }
- /* raise privileges because mail.local needs root to
- * deliver to user mailboxes.
- */
- if (seteuid(0) == -1)
- fatal("privraise failed");
+ /* prepare file which captures stdout and stderr */
+ strlcpy(sfn, "/tmp/smtpd.out.XXXXXXXXXXX", sizeof(sfn));
+ allout = mkstemp(sfn);
+ if (allout < 0) {
+ n = snprintf(ebuf, sizeof ebuf, "mkstemp: %s", strerror(errno));
+ if (seteuid(0) < 0)
+ fatal("forkmda: cannot restore privileges");
+ imsg_compose_event(iev, IMSG_MDA_DONE, id, 0, -1, ebuf, n + 1);
+ close(pipefd[0]);
+ close(pipefd[1]);
+ return;
+ }
+ unlink(sfn);
pid = fork();
- if (pid == -1) {
+ if (pid < 0) {
+ n = snprintf(ebuf, sizeof ebuf, "fork: %s", strerror(errno));
+ if (seteuid(0) < 0)
+ fatal("forkmda: cannot restore privileges");
+ imsg_compose_event(iev, IMSG_MDA_DONE, id, 0, -1, ebuf, n + 1);
close(pipefd[0]);
close(pipefd[1]);
- return -1;
+ close(allout);
+ return;
}
- if (pid == 0) {
+ /* parent passes the child fd over to mda */
+ if (pid > 0) {
+ if (seteuid(0) < 0)
+ fatal("forkmda: cannot restore privileges");
+ child = child_add(env, pid, CHILD_MDA, -1);
+ child->mda_out = allout;
+ child->mda_id = id;
close(pipefd[0]);
- close(STDOUT_FILENO);
- close(STDERR_FILENO);
- dup2(pipefd[1], 0);
-
- /* avoid hangs by setting a 5m timeout */
- alarm(300);
-
- execlp(PATH_MAILLOCAL, "mail.local", "-f", sender, pw->pw_name,
- (void *)NULL);
- _exit(1);
+ imsg_compose_event(iev, IMSG_PARENT_FORK_MDA, id, 0, pipefd[1],
+ NULL, 0);
+ return;
}
- if (seteuid(pw->pw_uid) == -1)
- fatal("privdrop failed");
-
- child = child_add(batchp->env, pid, CHILD_MDA, -1);
-
- /* Each child relates to a batch; record this relationship. */
- child->mda_batch = *batchp;
-
- close(pipefd[1]);
- return pipefd[0];
-}
-
-int
-parent_maildir_init(struct passwd *pw, char *root)
-{
- u_int8_t i;
- char pathname[MAXPATHLEN];
- char *subdir[] = { "/", "/tmp", "/cur", "/new" };
-
- for (i = 0; i < nitems(subdir); ++i) {
- if (! bsnprintf(pathname, sizeof(pathname), "%s%s", root,
- subdir[i]))
- return 0;
- if (mkdir(pathname, 0700) == -1)
- if (errno != EEXIST)
- return 0;
+#define error(m) { printf("%s: %s\n", m, strerror(errno)); exit(1); }
+ if (seteuid(0) < 0)
+ fatal("forkmda: cannot restore privileges");
+ if (setgroups(1, &pw->pw_gid) ||
+ setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
+ setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
+ fatal("forkmda: cannot drop privileges");
+ if (dup2(pipefd[0], STDIN_FILENO) < 0 ||
+ dup2(allout, STDOUT_FILENO) < 0 ||
+ dup2(allout, STDERR_FILENO) < 0)
+ fatal("forkmda: dup2");
+ if (setsid() < 0)
+ error("setsid");
+ if (signal(SIGPIPE, SIG_DFL) == SIG_ERR ||
+ signal(SIGINT, SIG_DFL) == SIG_ERR ||
+ signal(SIGTERM, SIG_DFL) == SIG_ERR ||
+ signal(SIGCHLD, SIG_DFL) == SIG_ERR ||
+ signal(SIGHUP, SIG_DFL) == SIG_ERR)
+ error("signal");
+ if (chdir(pw->pw_dir) < 0 && chdir("/") < 0)
+ error("chdir");
+ if (closefrom(STDERR_FILENO + 1) < 0)
+ error("closefrom");
+
+ /* avoid hangs by setting 5m timeout */
+ alarm(300);
+
+ if (deliver->mode == A_EXT) {
+ char *environ_new[2];
+
+ environ_new[0] = "PATH=" _PATH_DEFPATH;
+ environ_new[1] = (char *)NULL;
+ environ = environ_new;
+ execle("/bin/sh", "/bin/sh", "-c", deliver->to, (char *)NULL,
+ environ_new);
+ error("execle");
}
- return 1;
-}
-
-int
-parent_maildir_open(char *path, struct passwd *pw, struct batch *batchp)
-{
- char tmp[MAXPATHLEN];
- int mode = O_CREAT|O_RDWR|O_TRUNC|O_SYNC;
-
- if (! parent_maildir_init(pw, path))
- return -1;
-
- if (! bsnprintf(tmp, sizeof(tmp), "%s/tmp/%s", path,
- batchp->message.message_uid))
- return -1;
-
- return open(tmp, mode, 0600);
-}
-
-int
-parent_external_mda(char *path, struct passwd *pw, struct batch *batchp)
-{
- struct child *child;
- pid_t pid;
- int pipefd[2];
- arglist args;
- char *word;
- char *envp[2];
-
- log_debug("executing filter as user: %s", pw->pw_name);
-
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipefd) == -1) {
- if (errno == ENFILE) {
- log_warn("parent_external_mda: socketpair");
- return -1;
- }
- fatal("parent_external_mda: socketpair");
- }
+ if (deliver->mode == A_MAILDIR) {
+ char tmp[PATH_MAX], new[PATH_MAX];
+ int ch, fd;
+ FILE *fp;
- pid = fork();
- if (pid == -1) {
- log_warn("parent_external_mda: fork");
- close(pipefd[0]);
- close(pipefd[1]);
- return -1;
+#define error2(m) { n = errno; unlink(tmp); errno = n; error(m); }
+ setproctitle("maildir delivery");
+ if (mkdir(deliver->to, 0700) < 0 && errno != EEXIST)
+ error("cannot mkdir maildir");
+ if (chdir(deliver->to) < 0)
+ error("cannot cd to maildir");
+ if (mkdir("cur", 0700) < 0 && errno != EEXIST)
+ error("mkdir cur failed");
+ if (mkdir("tmp", 0700) < 0 && errno != EEXIST)
+ error("mkdir tmp failed");
+ if (mkdir("new", 0700) < 0 && errno != EEXIST)
+ error("mkdir new failed");
+ snprintf(tmp, sizeof tmp, "tmp/%d.%d.%s", time(NULL),
+ getpid(), env->sc_hostname);
+ fd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0600);
+ if (fd < 0)
+ error("cannot open tmp file");
+ fp = fdopen(fd, "w");
+ if (fp == NULL)
+ error2("fdopen");
+ while ((ch = getc(stdin)) != EOF)
+ if (putc(ch, fp) == EOF)
+ break;
+ if (ferror(stdin))
+ error2("read error");
+ if (fflush(fp) == EOF || ferror(fp))
+ error2("write error");
+ if (fsync(fd) < 0)
+ error2("fsync");
+ if (fclose(fp) == EOF)
+ error2("fclose");
+ snprintf(new, sizeof new, "new/%s", tmp + 4);
+ if (rename(tmp, new) < 0)
+ error2("cannot rename tmp->new");
+ exit(0);
}
-
- if (pid == 0) {
- if (seteuid(0) == -1)
- fatal("privraise failed");
- if (setgroups(1, &pw->pw_gid) ||
- setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
- setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
- fatal("cannot drop privileges");
-
- bzero(&args, sizeof(args));
- while ((word = strsep(&path, " \t")) != NULL)
- if (*word != '\0')
- addargs(&args, "%s", word);
-
- if (setsid() == -1)
- fatal("setsid");
-
- if (signal(SIGPIPE, SIG_DFL) == SIG_ERR)
- fatal("signal");
-
- if (dup2(pipefd[0], STDIN_FILENO) == -1)
- fatal("dup2");
-
- if (chdir(pw->pw_dir) == -1 && chdir("/") == -1)
- fatal("chdir");
-
- if (closefrom(STDERR_FILENO + 1) == -1)
- fatal("closefrom");
-
- /* avoid hangs by setting a 5m timeout */
- alarm(300);
-
- envp[0] = "PATH=" _PATH_DEFPATH;
- envp[1] = (char *)NULL;
- environ = envp;
-
- execvp(args.list[0], args.list);
- _exit(1);
+#undef error2
+
+ if (deliver->mode == A_FILENAME) {
+ struct stat sb;
+ time_t now;
+ size_t len;
+ int fd;
+ FILE *fp;
+ char *ln;
+
+#define error2(m) { n = errno; ftruncate(fd, sb.st_size); errno = n; error(m); }
+ setproctitle("file delivery");
+ fd = open(deliver->to, O_CREAT | O_APPEND | O_WRONLY, 0600);
+ if (fd < 0)
+ error("open");
+ if (fstat(fd, &sb) < 0)
+ error("fstat");
+ if (S_ISREG(sb.st_flags) && flock(fd, LOCK_EX) < 0)
+ error("flock");
+ fp = fdopen(fd, "a");
+ if (fp == NULL)
+ error("fdopen");
+ time(&now);
+ fprintf(fp, "From %s@%s %s", SMTPD_USER, env->sc_hostname,
+ ctime(&now));
+ while ((ln = fgetln(stdin, &len)) != NULL) {
+ if (ln[len - 1] == '\n')
+ len--;
+ if (len >= 5 && memcmp(ln, "From ", 5) == 0)
+ putc('>', fp);
+ fprintf(fp, "%.*s\n", (int)len, ln);
+ if (ferror(fp))
+ break;
+ }
+ if (ferror(stdin))
+ error2("read error");
+ putc('\n', fp);
+ if (fflush(fp) == EOF || ferror(fp))
+ error2("write error");
+ if (fsync(fd) < 0)
+ error2("fsync");
+ if (fclose(fp) == EOF)
+ error2("fclose");
+ exit(0);
}
- child = child_add(batchp->env, pid, CHILD_MDA, -1);
-
- /* Each child relates to a batch; record this relationship. */
- child->mda_batch = *batchp;
-
- close(pipefd[0]);
- return pipefd[1];
+ fatalx("forkmda: unknown mode");
}
+#undef error
+#undef error2
int
parent_enqueue_offline(struct smtpd *env, char *runner_path)
@@ -1600,35 +1452,6 @@ parent_enqueue_offline(struct smtpd *env, char *runner_path)
}
int
-parent_filename_open(char *path, struct passwd *pw, struct batch *batchp)
-{
- int fd;
- int mode = O_CREAT|O_APPEND|O_RDWR|O_SYNC|O_NONBLOCK;
-
- fd = open(path, mode, 0600);
- if (fd == -1) {
- if (errno == EWOULDBLOCK)
- goto lockfail;
- return -1;
- }
-
- if (flock(fd, LOCK_EX|LOCK_NB) == -1) {
- if (errno == EWOULDBLOCK)
- goto lockfail;
- fatal("flock");
- }
-
- return fd;
-
-lockfail:
- if (fd != -1)
- close(fd);
-
- batchp->message.status |= S_MESSAGE_LOCKFAILURE;
- return -1;
-}
-
-int
parent_forward_open(char *username)
{
struct passwd *pw;
@@ -1683,27 +1506,4 @@ child_cmp(struct child *c1, struct child *c2)
return (0);
}
-void
-parent_mda_permfail(struct smtpd *env, struct batch *b)
-{
- b->message.status |= S_MESSAGE_PERMFAILURE;
- imsg_compose_event(env->sc_ievs[PROC_MDA], IMSG_MDA_FINALIZE,
- 0, 0, -1, b, sizeof(*b));
-}
-
-void
-parent_mda_tempfail(struct smtpd *env, struct batch *b)
-{
- imsg_compose_event(env->sc_ievs[PROC_MDA], IMSG_MDA_FINALIZE,
- 0, 0, -1, b, sizeof(*b));
-}
-
-void
-parent_mda_success(struct smtpd *env, struct batch *b)
-{
- b->message.status &= ~S_MESSAGE_TEMPFAILURE;
- imsg_compose_event(env->sc_ievs[PROC_MDA], IMSG_MDA_FINALIZE,
- 0, 0, -1, b, sizeof(*b));
-}
-
SPLAY_GENERATE(childtree, child, entry, child_cmp);
diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h
index 339a26d733f..1ad585d78ac 100644
--- a/usr.sbin/smtpd/smtpd.h
+++ b/usr.sbin/smtpd/smtpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtpd.h,v 1.171 2010/04/11 22:46:28 jacekm Exp $ */
+/* $OpenBSD: smtpd.h,v 1.172 2010/04/19 08:14:07 jacekm Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -137,7 +137,8 @@ enum imsg_type {
IMSG_LKA_RCPT,
IMSG_LKA_SECRET,
IMSG_LKA_RULEMATCH,
- IMSG_MDA_FINALIZE,
+ IMSG_MDA_SESS_NEW,
+ IMSG_MDA_DONE,
IMSG_MFA_RCPT,
IMSG_MFA_MAIL,
@@ -166,10 +167,7 @@ enum imsg_type {
IMSG_PARENT_ENQUEUE_OFFLINE,
IMSG_PARENT_FORWARD_OPEN,
- IMSG_PARENT_MAILBOX_OPEN,
- IMSG_PARENT_MESSAGE_OPEN,
- IMSG_PARENT_MAILDIR_RENAME,
- IMSG_PARENT_MAILDIR_FAIL,
+ IMSG_PARENT_FORK_MDA,
IMSG_PARENT_STATS,
IMSG_PARENT_AUTHENTICATE,
@@ -409,7 +407,6 @@ enum message_type {
};
enum message_status {
- S_MESSAGE_LOCKFAILURE = 0x1,
S_MESSAGE_PERMFAILURE = 0x2,
S_MESSAGE_TEMPFAILURE = 0x4,
S_MESSAGE_REJECTED = 0x8,
@@ -467,24 +464,13 @@ enum batch_type {
struct batch {
SPLAY_ENTRY(batch) b_nodes;
-
u_int64_t id;
enum batch_type type;
struct rule rule;
-
struct smtpd *env;
-
char message_id[MAX_ID_SIZE];
char hostname[MAXHOSTNAMELEN];
-
- struct message message;
TAILQ_HEAD(, message) messages;
-
- FILE *mboxfp;
- FILE *datafp;
- struct msgbuf w;
- int cleanup_parent;
- struct event ev;
};
enum child_type {
@@ -496,11 +482,11 @@ enum child_type {
struct child {
SPLAY_ENTRY(child) entry;
-
pid_t pid;
enum child_type type;
enum smtp_proc_type title;
- struct batch mda_batch;
+ int mda_out;
+ u_int32_t mda_id;
};
enum session_state {
@@ -633,6 +619,7 @@ struct smtpd {
SPLAY_HEAD(childtree, child) children;
SPLAY_HEAD(lkatree, lkasession) lka_sessions;
SPLAY_HEAD(mtatree, mta_session) mta_sessions;
+ LIST_HEAD(mdalist, mda_session) mda_sessions;
struct stats *stats;
};
@@ -746,6 +733,21 @@ struct secret {
char secret[MAX_LINE_SIZE];
};
+struct mda_session {
+ LIST_ENTRY(mda_session) entry;
+ struct message msg;
+ struct msgbuf w;
+ struct event ev;
+ u_int32_t id;
+ FILE *datafp;
+};
+
+struct deliver {
+ char to[PATH_MAX];
+ char user[MAXLOGNAME];
+ short mode;
+};
+
struct rulematch {
u_int64_t id;
struct submit_status ss;