aboutsummaryrefslogtreecommitdiffstats
path: root/mda.c
diff options
context:
space:
mode:
Diffstat (limited to 'mda.c')
-rw-r--r--mda.c912
1 files changed, 0 insertions, 912 deletions
diff --git a/mda.c b/mda.c
deleted file mode 100644
index 765acda9..00000000
--- a/mda.c
+++ /dev/null
@@ -1,912 +0,0 @@
-/* $OpenBSD: mda.c,v 1.141 2019/10/03 08:50:08 gilles Exp $ */
-
-/*
- * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
- * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
- * Copyright (c) 2009 Jacek Masiulaniec <jacekm@dobremiasto.net>
- * 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 <ctype.h>
-#include <err.h>
-#include <errno.h>
-#include <event.h>
-#include <imsg.h>
-#include <inttypes.h>
-#include <pwd.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sysexits.h>
-#include <time.h>
-#include <unistd.h>
-#include <limits.h>
-#include <vis.h>
-
-#include "smtpd.h"
-#include "log.h"
-
-#define MDA_HIWAT 65536
-
-struct mda_envelope {
- TAILQ_ENTRY(mda_envelope) entry;
- uint64_t session_id;
- uint64_t id;
- time_t creation;
- char *sender;
- char *rcpt;
- char *dest;
- char *user;
- char *dispatcher;
- char *mda_subaddress;
- char *mda_exec;
-};
-
-#define USER_WAITINFO 0x01
-#define USER_RUNNABLE 0x02
-#define USER_ONHOLD 0x04
-#define USER_HOLDQ 0x08
-
-struct mda_user {
- uint64_t id;
- TAILQ_ENTRY(mda_user) entry;
- TAILQ_ENTRY(mda_user) entry_runnable;
- char name[LOGIN_NAME_MAX];
- char usertable[PATH_MAX];
- size_t evpcount;
- TAILQ_HEAD(, mda_envelope) envelopes;
- int flags;
- size_t running;
- struct userinfo userinfo;
-};
-
-struct mda_session {
- uint64_t id;
- struct mda_user *user;
- struct mda_envelope *evp;
- struct io *io;
- FILE *datafp;
-};
-
-static void mda_io(struct io *, int, void *);
-static int mda_check_loop(FILE *, struct mda_envelope *);
-static int mda_getlastline(int, char *, size_t);
-static void mda_done(struct mda_session *);
-static void mda_fail(struct mda_user *, int, const char *,
- enum enhanced_status_code);
-static void mda_drain(void);
-static void mda_log(const struct mda_envelope *, const char *, const char *);
-static void mda_queue_ok(uint64_t);
-static void mda_queue_tempfail(uint64_t, const char *,
- enum enhanced_status_code);
-static void mda_queue_permfail(uint64_t, const char *, enum enhanced_status_code);
-static void mda_queue_loop(uint64_t);
-static struct mda_user *mda_user(const struct envelope *);
-static void mda_user_free(struct mda_user *);
-static const char *mda_user_to_text(const struct mda_user *);
-static struct mda_envelope *mda_envelope(uint64_t, const struct envelope *);
-static void mda_envelope_free(struct mda_envelope *);
-static struct mda_session * mda_session(struct mda_user *);
-static const char *mda_sysexit_to_str(int);
-
-static struct tree sessions;
-static struct tree users;
-
-static TAILQ_HEAD(, mda_user) runnable;
-
-void
-mda_imsg(struct mproc *p, struct imsg *imsg)
-{
- struct mda_session *s;
- struct mda_user *u;
- struct mda_envelope *e;
- struct envelope evp;
- struct deliver deliver;
- struct msg m;
- const void *data;
- const char *error, *parent_error, *syserror;
- uint64_t reqid;
- size_t sz;
- char out[256], buf[LINE_MAX];
- int n;
- enum lka_resp_status status;
- enum mda_resp_status mda_status;
- int mda_sysexit;
-
- switch (imsg->hdr.type) {
- case IMSG_MDA_LOOKUP_USERINFO:
- m_msg(&m, imsg);
- m_get_id(&m, &reqid);
- m_get_int(&m, (int *)&status);
- if (status == LKA_OK)
- m_get_data(&m, &data, &sz);
- m_end(&m);
-
- u = tree_xget(&users, reqid);
-
- if (status == LKA_TEMPFAIL)
- mda_fail(u, 0,
- "Temporary failure in user lookup",
- ESC_OTHER_ADDRESS_STATUS);
- else if (status == LKA_PERMFAIL)
- mda_fail(u, 1,
- "Permanent failure in user lookup",
- ESC_DESTINATION_MAILBOX_HAS_MOVED);
- else {
- if (sz != sizeof(u->userinfo))
- fatalx("mda: userinfo size mismatch");
- memmove(&u->userinfo, data, sz);
- u->flags &= ~USER_WAITINFO;
- u->flags |= USER_RUNNABLE;
- TAILQ_INSERT_TAIL(&runnable, u, entry_runnable);
- mda_drain();
- }
- return;
-
- case IMSG_QUEUE_DELIVER:
- m_msg(&m, imsg);
- m_get_envelope(&m, &evp);
- m_end(&m);
-
- u = mda_user(&evp);
-
- if (u->evpcount >= env->sc_mda_task_hiwat) {
- if (!(u->flags & USER_ONHOLD)) {
- log_debug("debug: mda: hiwat reached for "
- "user \"%s\": holding envelopes",
- mda_user_to_text(u));
- u->flags |= USER_ONHOLD;
- }
- }
-
- if (u->flags & USER_ONHOLD) {
- u->flags |= USER_HOLDQ;
- m_create(p_queue, IMSG_MDA_DELIVERY_HOLD,
- 0, 0, -1);
- m_add_evpid(p_queue, evp.id);
- m_add_id(p_queue, u->id);
- m_close(p_queue);
- return;
- }
-
- e = mda_envelope(u->id, &evp);
- TAILQ_INSERT_TAIL(&u->envelopes, e, entry);
- u->evpcount += 1;
- stat_increment("mda.pending", 1);
-
- if (!(u->flags & USER_RUNNABLE) &&
- !(u->flags & USER_WAITINFO)) {
- u->flags |= USER_RUNNABLE;
- TAILQ_INSERT_TAIL(&runnable, u, entry_runnable);
- }
-
- mda_drain();
- return;
-
- case IMSG_MDA_OPEN_MESSAGE:
- m_msg(&m, imsg);
- m_get_id(&m, &reqid);
- m_end(&m);
-
- s = tree_xget(&sessions, reqid);
- e = s->evp;
-
- if (imsg->fd == -1) {
- log_debug("debug: mda: cannot get message fd");
- mda_queue_tempfail(e->id,
- "Cannot get message fd",
- ESC_OTHER_MAIL_SYSTEM_STATUS);
- mda_log(e, "TempFail", "Cannot get message fd");
- mda_done(s);
- return;
- }
-
- log_debug("debug: mda: got message fd %d "
- "for session %016"PRIx64 " evpid %016"PRIx64,
- imsg->fd, s->id, e->id);
-
- if ((s->datafp = fdopen(imsg->fd, "r")) == NULL) {
- log_warn("warn: mda: fdopen");
- close(imsg->fd);
- mda_queue_tempfail(e->id, "fdopen failed",
- ESC_OTHER_MAIL_SYSTEM_STATUS);
- mda_log(e, "TempFail", "fdopen failed");
- mda_done(s);
- return;
- }
-
- /* check delivery loop */
- if (mda_check_loop(s->datafp, e)) {
- log_debug("debug: mda: loop detected");
- mda_queue_loop(e->id);
- mda_log(e, "PermFail", "Loop detected");
- mda_done(s);
- return;
- }
-
- /* start queueing delivery headers */
- if (e->sender[0])
- /*
- * XXX: remove existing Return-Path,
- * if any
- */
- n = io_printf(s->io,
- "Return-Path: <%s>\n"
- "Delivered-To: %s\n",
- e->sender,
- e->rcpt ? e->rcpt : e->dest);
- else
- n = io_printf(s->io,
- "Delivered-To: %s\n",
- e->rcpt ? e->rcpt : e->dest);
- if (n == -1) {
- log_warn("warn: mda: "
- "fail to write delivery info");
- mda_queue_tempfail(e->id, "Out of memory",
- ESC_OTHER_MAIL_SYSTEM_STATUS);
- mda_log(e, "TempFail", "Out of memory");
- mda_done(s);
- return;
- }
-
- /* request parent to fork a helper process */
- memset(&deliver, 0, sizeof deliver);
- (void)text_to_mailaddr(&deliver.sender, s->evp->sender);
- (void)text_to_mailaddr(&deliver.rcpt, s->evp->rcpt);
- (void)text_to_mailaddr(&deliver.dest, s->evp->dest);
- if (s->evp->mda_exec)
- (void)strlcpy(deliver.mda_exec, s->evp->mda_exec, sizeof deliver.mda_exec);
- if (s->evp->mda_subaddress)
- (void)strlcpy(deliver.mda_subaddress, s->evp->mda_subaddress, sizeof deliver.mda_subaddress);
- (void)strlcpy(deliver.dispatcher, s->evp->dispatcher, sizeof deliver.dispatcher);
- deliver.userinfo = s->user->userinfo;
-
- log_debug("debug: mda: querying mda fd "
- "for session %016"PRIx64 " evpid %016"PRIx64,
- s->id, s->evp->id);
-
- m_create(p_parent, IMSG_MDA_FORK, 0, 0, -1);
- m_add_id(p_parent, reqid);
- m_add_data(p_parent, &deliver, sizeof(deliver));
- m_close(p_parent);
- return;
-
- case IMSG_MDA_FORK:
- m_msg(&m, imsg);
- m_get_id(&m, &reqid);
- m_end(&m);
-
- s = tree_xget(&sessions, reqid);
- e = s->evp;
- if (imsg->fd == -1) {
- log_warn("warn: mda: fail to retrieve mda fd");
- mda_queue_tempfail(e->id, "Cannot get mda fd",
- ESC_OTHER_MAIL_SYSTEM_STATUS);
- mda_log(e, "TempFail", "Cannot get mda fd");
- mda_done(s);
- return;
- }
-
- log_debug("debug: mda: got mda fd %d "
- "for session %016"PRIx64 " evpid %016"PRIx64,
- imsg->fd, s->id, s->evp->id);
-
- io_set_nonblocking(imsg->fd);
- io_set_fd(s->io, imsg->fd);
- io_set_write(s->io);
- return;
-
- case IMSG_MDA_DONE:
- m_msg(&m, imsg);
- m_get_id(&m, &reqid);
- m_get_int(&m, (int *)&mda_status);
- m_get_int(&m, (int *)&mda_sysexit);
- m_get_string(&m, &parent_error);
- m_end(&m);
-
- s = tree_xget(&sessions, reqid);
- e = s->evp;
- /*
- * Grab last line of mda stdout/stderr if available.
- */
- out[0] = '\0';
- if (imsg->fd != -1)
- mda_getlastline(imsg->fd, out, sizeof(out));
-
- /*
- * Choose between parent's description of error and
- * child's output, the latter having preference over
- * the former.
- */
- error = NULL;
- if (mda_status == MDA_OK) {
- if (s->datafp || (s->io && io_queued(s->io))) {
- error = "mda exited prematurely";
- mda_status = MDA_TEMPFAIL;
- }
- } else
- error = out[0] ? out : parent_error;
-
- syserror = NULL;
- if (mda_sysexit)
- syserror = mda_sysexit_to_str(mda_sysexit);
-
- /* update queue entry */
- switch (mda_status) {
- case MDA_TEMPFAIL:
- mda_queue_tempfail(e->id, error,
- ESC_OTHER_MAIL_SYSTEM_STATUS);
- (void)snprintf(buf, sizeof buf,
- "Error (%s%s%s)",
- syserror ? syserror : "",
- syserror ? ": " : "",
- error);
- mda_log(e, "TempFail", buf);
- break;
- case MDA_PERMFAIL:
- mda_queue_permfail(e->id, error,
- ESC_OTHER_MAIL_SYSTEM_STATUS);
- (void)snprintf(buf, sizeof buf,
- "Error (%s%s%s)",
- syserror ? syserror : "",
- syserror ? ": " : "",
- error);
- mda_log(e, "PermFail", buf);
- break;
- case MDA_OK:
- mda_queue_ok(e->id);
- mda_log(e, "Ok", "Delivered");
- break;
- }
- mda_done(s);
- return;
- }
-
- errx(1, "mda_imsg: unexpected %s imsg", imsg_to_str(imsg->hdr.type));
-}
-
-void
-mda_postfork()
-{
-}
-
-void
-mda_postprivdrop()
-{
- tree_init(&sessions);
- tree_init(&users);
- TAILQ_INIT(&runnable);
-}
-
-static void
-mda_io(struct io *io, int evt, void *arg)
-{
- struct mda_session *s = arg;
- char *ln = NULL;
- size_t sz = 0;
- ssize_t len;
-
- log_trace(TRACE_IO, "mda: %p: %s %s", s, io_strevent(evt),
- io_strio(io));
-
- switch (evt) {
- case IO_LOWAT:
-
- /* done */
- done:
- if (s->datafp == NULL) {
- log_debug("debug: mda: all data sent for session"
- " %016"PRIx64 " evpid %016"PRIx64,
- s->id, s->evp->id);
- io_free(io);
- s->io = NULL;
- return;
- }
-
- while (io_queued(s->io) < MDA_HIWAT) {
- if ((len = getline(&ln, &sz, s->datafp)) == -1)
- break;
- if (io_write(s->io, ln, len) == -1) {
- m_create(p_parent, IMSG_MDA_KILL,
- 0, 0, -1);
- m_add_id(p_parent, s->id);
- m_add_string(p_parent, "Out of memory");
- m_close(p_parent);
- io_pause(io, IO_OUT);
- free(ln);
- return;
- }
- }
-
- free(ln);
- ln = NULL;
- if (ferror(s->datafp)) {
- log_debug("debug: mda: ferror on session %016"PRIx64,
- s->id);
- m_create(p_parent, IMSG_MDA_KILL, 0, 0, -1);
- m_add_id(p_parent, s->id);
- m_add_string(p_parent, "Error reading body");
- m_close(p_parent);
- io_pause(io, IO_OUT);
- return;
- }
-
- if (feof(s->datafp)) {
- log_debug("debug: mda: end-of-file for session"
- " %016"PRIx64 " evpid %016"PRIx64,
- s->id, s->evp->id);
- fclose(s->datafp);
- s->datafp = NULL;
- if (io_queued(s->io) == 0)
- goto done;
- }
- return;
-
- case IO_TIMEOUT:
- log_debug("debug: mda: timeout on session %016"PRIx64, s->id);
- io_pause(io, IO_OUT);
- return;
-
- case IO_ERROR:
- log_debug("debug: mda: io error on session %016"PRIx64": %s",
- s->id, io_error(io));
- io_pause(io, IO_OUT);
- return;
-
- case IO_DISCONNECTED:
- log_debug("debug: mda: io disconnected on session %016"PRIx64,
- s->id);
- io_pause(io, IO_OUT);
- return;
-
- default:
- log_debug("debug: mda: unexpected event on session %016"PRIx64,
- s->id);
- io_pause(io, IO_OUT);
- return;
- }
-}
-
-static int
-mda_check_loop(FILE *fp, struct mda_envelope *e)
-{
- char *buf = NULL;
- size_t sz = 0;
- ssize_t len;
- int ret = 0;
-
- while ((len = getline(&buf, &sz, fp)) != -1) {
- if (buf[len - 1] == '\n')
- buf[len - 1] = '\0';
-
- if (strchr(buf, ':') == NULL && !isspace((unsigned char)*buf))
- break;
-
- if (strncasecmp("Delivered-To: ", buf, 14) == 0) {
- if (strcasecmp(buf + 14, e->dest) == 0) {
- ret = 1;
- break;
- }
- }
- }
-
- free(buf);
- fseek(fp, SEEK_SET, 0);
- return (ret);
-}
-
-static int
-mda_getlastline(int fd, char *dst, size_t dstsz)
-{
- FILE *fp;
- char *ln = NULL;
- size_t sz = 0;
- ssize_t len;
- int out = 0;
-
- if (lseek(fd, 0, SEEK_SET) == -1) {
- log_warn("warn: mda: lseek");
- close(fd);
- return (-1);
- }
- fp = fdopen(fd, "r");
- if (fp == NULL) {
- log_warn("warn: mda: fdopen");
- close(fd);
- return (-1);
- }
- while ((len = getline(&ln, &sz, fp)) != -1) {
- if (ln[len - 1] == '\n')
- ln[len - 1] = '\0';
- out = 1;
- }
- fclose(fp);
-
- if (out) {
- (void)strlcpy(dst, "\"", dstsz);
- (void)strnvis(dst + 1, ln, dstsz - 2, VIS_SAFE | VIS_CSTYLE | VIS_NL);
- (void)strlcat(dst, "\"", dstsz);
- }
-
- free(ln);
- return (0);
-}
-
-static void
-mda_fail(struct mda_user *user, int permfail, const char *error,
- enum enhanced_status_code code)
-{
- struct mda_envelope *e;
-
- while ((e = TAILQ_FIRST(&user->envelopes))) {
- TAILQ_REMOVE(&user->envelopes, e, entry);
- if (permfail) {
- mda_log(e, "PermFail", error);
- mda_queue_permfail(e->id, error, code);
- }
- else {
- mda_log(e, "TempFail", error);
- mda_queue_tempfail(e->id, error, code);
- }
- mda_envelope_free(e);
- }
-
- mda_user_free(user);
-}
-
-static void
-mda_drain(void)
-{
- struct mda_user *u;
-
- while ((u = (TAILQ_FIRST(&runnable)))) {
-
- TAILQ_REMOVE(&runnable, u, entry_runnable);
-
- if (u->evpcount == 0 && u->running == 0) {
- log_debug("debug: mda: all done for user \"%s\"",
- mda_user_to_text(u));
- mda_user_free(u);
- continue;
- }
-
- if (u->evpcount == 0) {
- log_debug("debug: mda: no more envelope for \"%s\"",
- mda_user_to_text(u));
- u->flags &= ~USER_RUNNABLE;
- continue;
- }
-
- if (u->running >= env->sc_mda_max_user_session) {
- log_debug("debug: mda: "
- "maximum number of session reached for user \"%s\"",
- mda_user_to_text(u));
- u->flags &= ~USER_RUNNABLE;
- continue;
- }
-
- if (tree_count(&sessions) >= env->sc_mda_max_session) {
- log_debug("debug: mda: "
- "maximum number of session reached");
- TAILQ_INSERT_HEAD(&runnable, u, entry_runnable);
- return;
- }
-
- mda_session(u);
-
- if (u->evpcount == env->sc_mda_task_lowat) {
- if (u->flags & USER_ONHOLD) {
- log_debug("debug: mda: down to lowat for user "
- "\"%s\": releasing",
- mda_user_to_text(u));
- u->flags &= ~USER_ONHOLD;
- }
- if (u->flags & USER_HOLDQ) {
- m_create(p_queue, IMSG_MDA_HOLDQ_RELEASE,
- 0, 0, -1);
- m_add_id(p_queue, u->id);
- m_add_int(p_queue, env->sc_mda_task_release);
- m_close(p_queue);
- }
- }
-
- /* re-add the user at the tail of the queue */
- TAILQ_INSERT_TAIL(&runnable, u, entry_runnable);
- }
-}
-
-static void
-mda_done(struct mda_session *s)
-{
- log_debug("debug: mda: session %016" PRIx64 " done", s->id);
-
- tree_xpop(&sessions, s->id);
-
- mda_envelope_free(s->evp);
-
- s->user->running--;
- if (!(s->user->flags & USER_RUNNABLE)) {
- log_debug("debug: mda: user \"%s\" becomes runnable",
- s->user->name);
- TAILQ_INSERT_TAIL(&runnable, s->user, entry_runnable);
- s->user->flags |= USER_RUNNABLE;
- }
-
- if (s->datafp)
- fclose(s->datafp);
- if (s->io)
- io_free(s->io);
-
- free(s);
-
- stat_decrement("mda.running", 1);
-
- mda_drain();
-}
-
-static void
-mda_log(const struct mda_envelope *evp, const char *prefix, const char *status)
-{
- char rcpt[LINE_MAX];
-
- rcpt[0] = '\0';
- if (evp->rcpt)
- (void)snprintf(rcpt, sizeof rcpt, "rcpt=<%s> ", evp->rcpt);
-
- log_info("%016"PRIx64" mda delivery evpid=%016" PRIx64 " from=<%s> to=<%s> "
- "%suser=%s delay=%s result=%s stat=%s",
- evp->session_id,
- evp->id,
- evp->sender ? evp->sender : "",
- evp->dest,
- rcpt,
- evp->user,
- duration_to_text(time(NULL) - evp->creation),
- prefix,
- status);
-}
-
-static void
-mda_queue_ok(uint64_t evpid)
-{
- m_create(p_queue, IMSG_MDA_DELIVERY_OK, 0, 0, -1);
- m_add_evpid(p_queue, evpid);
- m_close(p_queue);
-}
-
-static void
-mda_queue_tempfail(uint64_t evpid, const char *reason,
- enum enhanced_status_code code)
-{
- m_create(p_queue, IMSG_MDA_DELIVERY_TEMPFAIL, 0, 0, -1);
- m_add_evpid(p_queue, evpid);
- m_add_string(p_queue, reason);
- m_add_int(p_queue, (int)code);
- m_close(p_queue);
-}
-
-static void
-mda_queue_permfail(uint64_t evpid, const char *reason,
- enum enhanced_status_code code)
-{
- m_create(p_queue, IMSG_MDA_DELIVERY_PERMFAIL, 0, 0, -1);
- m_add_evpid(p_queue, evpid);
- m_add_string(p_queue, reason);
- m_add_int(p_queue, (int)code);
- m_close(p_queue);
-}
-
-static void
-mda_queue_loop(uint64_t evpid)
-{
- m_create(p_queue, IMSG_MDA_DELIVERY_LOOP, 0, 0, -1);
- m_add_evpid(p_queue, evpid);
- m_close(p_queue);
-}
-
-static struct mda_user *
-mda_user(const struct envelope *evp)
-{
- struct dispatcher *dsp;
- struct mda_user *u;
- void *i;
-
- i = NULL;
- dsp = dict_xget(env->sc_dispatchers, evp->dispatcher);
- while (tree_iter(&users, &i, NULL, (void**)(&u))) {
- if (!strcmp(evp->mda_user, u->name) &&
- !strcmp(dsp->u.local.table_userbase, u->usertable))
- return (u);
- }
-
- u = xcalloc(1, sizeof *u);
- u->id = generate_uid();
- TAILQ_INIT(&u->envelopes);
- (void)strlcpy(u->name, evp->mda_user, sizeof(u->name));
- (void)strlcpy(u->usertable, dsp->u.local.table_userbase,
- sizeof(u->usertable));
-
- tree_xset(&users, u->id, u);
-
- m_create(p_lka, IMSG_MDA_LOOKUP_USERINFO, 0, 0, -1);
- m_add_id(p_lka, u->id);
- m_add_string(p_lka, dsp->u.local.table_userbase);
- m_add_string(p_lka, evp->mda_user);
- m_close(p_lka);
- u->flags |= USER_WAITINFO;
-
- stat_increment("mda.user", 1);
-
- if (dsp->u.local.user)
- log_debug("mda: new user %016" PRIx64
- " for \"%s\" delivering as \"%s\"",
- u->id, mda_user_to_text(u), dsp->u.local.user);
- else
- log_debug("mda: new user %016" PRIx64
- " for \"%s\"", u->id, mda_user_to_text(u));
-
- return (u);
-}
-
-static void
-mda_user_free(struct mda_user *u)
-{
- tree_xpop(&users, u->id);
-
- if (u->flags & USER_HOLDQ) {
- m_create(p_queue, IMSG_MDA_HOLDQ_RELEASE, 0, 0, -1);
- m_add_id(p_queue, u->id);
- m_add_int(p_queue, 0);
- m_close(p_queue);
- }
-
- free(u);
- stat_decrement("mda.user", 1);
-}
-
-static const char *
-mda_user_to_text(const struct mda_user *u)
-{
- static char buf[1024];
-
- (void)snprintf(buf, sizeof(buf), "%s:%s", u->usertable, u->name);
-
- return (buf);
-}
-
-static struct mda_envelope *
-mda_envelope(uint64_t session_id, const struct envelope *evp)
-{
- struct mda_envelope *e;
- char buf[LINE_MAX];
-
- e = xcalloc(1, sizeof *e);
- e->session_id = session_id;
- e->id = evp->id;
- e->creation = evp->creation;
- buf[0] = '\0';
- if (evp->sender.user[0] && evp->sender.domain[0])
- (void)snprintf(buf, sizeof buf, "%s@%s",
- evp->sender.user, evp->sender.domain);
- e->sender = xstrdup(buf);
- (void)snprintf(buf, sizeof buf, "%s@%s", evp->dest.user,
- evp->dest.domain);
- e->dest = xstrdup(buf);
- (void)snprintf(buf, sizeof buf, "%s@%s", evp->rcpt.user,
- evp->rcpt.domain);
- e->rcpt = xstrdup(buf);
- e->user = evp->mda_user[0] ?
- xstrdup(evp->mda_user) : xstrdup(evp->dest.user);
- e->dispatcher = xstrdup(evp->dispatcher);
- if (evp->mda_exec[0])
- e->mda_exec = xstrdup(evp->mda_exec);
- if (evp->mda_subaddress[0])
- e->mda_subaddress = xstrdup(evp->mda_subaddress);
- stat_increment("mda.envelope", 1);
- return (e);
-}
-
-static void
-mda_envelope_free(struct mda_envelope *e)
-{
- free(e->sender);
- free(e->dest);
- free(e->rcpt);
- free(e->user);
- free(e->mda_exec);
- free(e);
-
- stat_decrement("mda.envelope", 1);
-}
-
-static struct mda_session *
-mda_session(struct mda_user * u)
-{
- struct mda_session *s;
-
- s = xcalloc(1, sizeof *s);
- s->id = generate_uid();
- s->user = u;
- s->io = io_new();
- io_set_callback(s->io, mda_io, s);
-
- tree_xset(&sessions, s->id, s);
-
- s->evp = TAILQ_FIRST(&u->envelopes);
- TAILQ_REMOVE(&u->envelopes, s->evp, entry);
- u->evpcount--;
- u->running++;
-
- stat_decrement("mda.pending", 1);
- stat_increment("mda.running", 1);
-
- log_debug("debug: mda: new session %016" PRIx64
- " for user \"%s\" evpid %016" PRIx64, s->id,
- mda_user_to_text(u), s->evp->id);
-
- m_create(p_queue, IMSG_MDA_OPEN_MESSAGE, 0, 0, -1);
- m_add_id(p_queue, s->id);
- m_add_msgid(p_queue, evpid_to_msgid(s->evp->id));
- m_close(p_queue);
-
- return (s);
-}
-
-static const char *
-mda_sysexit_to_str(int sysexit)
-{
- switch (sysexit) {
- case EX_USAGE:
- return "command line usage error";
- case EX_DATAERR:
- return "data format error";
- case EX_NOINPUT:
- return "cannot open input";
- case EX_NOUSER:
- return "user unknown";
- case EX_NOHOST:
- return "host name unknown";
- case EX_UNAVAILABLE:
- return "service unavailable";
- case EX_SOFTWARE:
- return "internal software error";
- case EX_OSERR:
- return "system resource problem";
- case EX_OSFILE:
- return "critical OS file missing";
- case EX_CANTCREAT:
- return "can't create user output file";
- case EX_IOERR:
- return "input/output error";
- case EX_TEMPFAIL:
- return "temporary failure";
- case EX_PROTOCOL:
- return "remote error in protocol";
- case EX_NOPERM:
- return "permission denied";
- case EX_CONFIG:
- return "local configuration error";
- default:
- break;
- }
- return NULL;
-}
-