diff options
Diffstat (limited to 'usr.sbin/smtpd/mda.c')
-rw-r--r-- | usr.sbin/smtpd/mda.c | 176 |
1 files changed, 78 insertions, 98 deletions
diff --git a/usr.sbin/smtpd/mda.c b/usr.sbin/smtpd/mda.c index a91e540295c..31e4197df55 100644 --- a/usr.sbin/smtpd/mda.c +++ b/usr.sbin/smtpd/mda.c @@ -1,9 +1,9 @@ -/* $OpenBSD: mda.c,v 1.44 2010/05/26 13:56:08 nicm Exp $ */ +/* $OpenBSD: mda.c,v 1.45 2010/05/31 23:38:56 jacekm Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org> * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> - * Copyright (c) 2009 Jacek Masiulaniec <jacekm@dobremiasto.net> + * Copyright (c) 2009-2010 Jacek Masiulaniec <jacekm@dobremiasto.net> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -36,6 +36,7 @@ #include <vis.h> #include "smtpd.h" +#include "queue_backend.h" void mda_imsg(struct smtpd *, struct imsgev *, struct imsg *); __dead void mda_shutdown(void); @@ -46,74 +47,65 @@ void mda_store(struct mda_session *); void mda_store_event(int, short, void *); struct mda_session *mda_lookup(struct smtpd *, u_int32_t); -u_int32_t mda_id; - void mda_imsg(struct smtpd *env, struct imsgev *iev, struct imsg *imsg) { char output[128], *error, *parent_error; struct deliver deliver; struct mda_session *s; - struct path *path; + struct action *action; + size_t action_sz; if (iev->proc == PROC_QUEUE) { switch (imsg->hdr.type) { - case IMSG_MDA_SESS_NEW: - /* make new session based on provided args */ - s = calloc(1, sizeof *s); + case IMSG_BATCH_CREATE: + s = malloc(sizeof *s); if (s == NULL) fatal(NULL); msgbuf_init(&s->w); - s->msg = *(struct message *)imsg->data; - s->msg.status = S_MESSAGE_TEMPFAILURE; - s->id = mda_id++; + bzero(&s->ev, sizeof s->ev); + s->id = imsg->hdr.peerid; + s->content_id = *(u_int64_t *)imsg->data; s->datafp = fdopen(imsg->fd, "r"); if (s->datafp == NULL) fatalx("mda: fdopen"); LIST_INSERT_HEAD(&env->mda_sessions, s, entry); + return; + + case IMSG_BATCH_APPEND: + LIST_FOREACH(s, &env->mda_sessions, entry) + if (s->id == imsg->hdr.peerid) + break; + if (s == NULL) + fatalx("mda: bogus append"); + action = imsg->data; + s->action_id = action->id; + s->auxraw = strdup(action->arg); + if (s->auxraw == NULL) + fatal(NULL); + auxsplit(&s->aux, s->auxraw); + return; - /* 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; - - case A_MBOX: - deliver.mode = A_EXT; - strlcpy(deliver.user, "root", - sizeof deliver.user); + case IMSG_BATCH_CLOSE: + LIST_FOREACH(s, &env->mda_sessions, entry) + if (s->id == imsg->hdr.peerid) + break; + if (s == NULL) + fatalx("mda: bogus close"); + memcpy(&s->birth, imsg->data, sizeof s->birth); + + /* request helper process from parent */ + if (s->aux.mode[0] == 'M') { + deliver.mode = 'P'; + 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; - - 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 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; - - default: - fatalx("mda: unknown rule action"); + "exec /usr/libexec/mail.local %s", + s->aux.user_to); + } else { + deliver.mode = s->aux.mode[0]; + strlcpy(deliver.user, s->aux.user_to, sizeof deliver.user); + strlcpy(deliver.to, s->aux.path, sizeof deliver.to); } - imsg_compose_event(env->sc_ievs[PROC_PARENT], IMSG_PARENT_FORK_MDA, s->id, 0, -1, &deliver, sizeof deliver); @@ -136,6 +128,10 @@ mda_imsg(struct smtpd *env, struct imsgev *iev, struct imsg *imsg) case IMSG_MDA_DONE: s = mda_lookup(env, imsg->hdr.peerid); + /* all parent errors are temporary */ + if (asprintf(&parent_error, "100 %s", (char *)imsg->data) < 0) + fatal("mda: asprintf"); + /* * Grab last line of mda stdout/stderr if available. */ @@ -162,12 +158,11 @@ mda_imsg(struct smtpd *env, struct imsgev *iev, struct imsg *imsg) buf[len] = '\0'; ln = buf; } - strlcpy(output, "\"", sizeof output); - strnvis(output + 1, ln, - sizeof(output) - 2, + strlcpy(output, "100 \"", sizeof output); + strnvis(output + 5, ln, + sizeof(output) - 6, VIS_SAFE | VIS_CSTYLE); strlcat(output, "\"", sizeof output); - log_debug("mda_out: %s", output); } free(buf); fclose(fp); @@ -178,11 +173,11 @@ mda_imsg(struct smtpd *env, struct imsgev *iev, struct imsg *imsg) * child's output, the latter having preference over * the former. */ - error = NULL; - parent_error = imsg->data; - if (strcmp(parent_error, "exited okay") == 0) { + if (strcmp(parent_error + 4, "exited okay") == 0) { if (!feof(s->datafp) || s->w.queued) - error = "mda exited prematurely"; + error = "100 mda exited prematurely"; + else + error = "200 ok"; } else { if (output[0]) error = output; @@ -191,35 +186,24 @@ mda_imsg(struct smtpd *env, struct imsgev *iev, struct imsg *imsg) } /* update queue entry */ - if (error == NULL) - s->msg.status = S_MESSAGE_ACCEPTED; - else - strlcpy(s->msg.session_errorline, error, - sizeof s->msg.session_errorline); + action_sz = sizeof *action + strlen(error) + 1; + action = malloc(action_sz); + if (action == NULL) + fatal(NULL); + action->id = s->action_id; + strlcpy(action->arg, error, action_sz - sizeof *action); imsg_compose_event(env->sc_ievs[PROC_QUEUE], - IMSG_QUEUE_MESSAGE_UPDATE, 0, 0, -1, &s->msg, - sizeof s->msg); - - /* - * 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; + IMSG_BATCH_UPDATE, s->id, 0, -1, action, action_sz); + imsg_compose_event(env->sc_ievs[PROC_QUEUE], + IMSG_BATCH_DONE, s->id, 0, -1, NULL, 0); /* 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); + log_info("%s: to=%s, delay=%d, stat=%s%s%s", + queue_be_decode(s->content_id), rcpt_pretty(&s->aux), + time(NULL) - s->birth, + *error == '2' ? "Sent" : "Error (", + *error == '2' ? "" : error + 4, + *error == '2' ? "" : ")"); /* destroy session */ LIST_REMOVE(s, entry); @@ -229,11 +213,9 @@ mda_imsg(struct smtpd *env, struct imsgev *iev, struct imsg *imsg) fclose(s->datafp); msgbuf_clear(&s->w); event_del(&s->ev); + free(s->auxraw); free(s); - - /* update queue's session count */ - imsg_compose_event(env->sc_ievs[PROC_QUEUE], - IMSG_MDA_SESS_NEW, 0, 0, -1, NULL, 0); + free(parent_error); return; case IMSG_CTL_VERBOSE: @@ -325,13 +307,13 @@ mda(struct smtpd *env) signal_add(&ev_sigint, NULL); signal_add(&ev_sigterm, NULL); signal(SIGPIPE, SIG_IGN); - signal(SIGHUP, SIG_IGN); config_pipes(env, peers, nitems(peers)); config_peers(env, peers, nitems(peers)); mda_setup_events(env); - event_dispatch(); + if (event_dispatch() < 0) + log_warn("event_dispatch"); mda_shutdown(); return (0); @@ -344,14 +326,12 @@ mda_store(struct mda_session *s) struct ibuf *buf; int len; - 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", - s->msg.sender.user, s->msg.sender.domain, - s->msg.session_rcpt.user, s->msg.session_rcpt.domain); + /* XXX: remove user provided Return-Path, if any */ + if (s->aux.mail_from[0]) + len = asprintf(&p, "Return-Path: %s\nDelivered-To: %s\n", + s->aux.mail_from, s->aux.rcpt_to); else - len = asprintf(&p, "Delivered-To: %s@%s\n", - s->msg.session_rcpt.user, s->msg.session_rcpt.domain); + len = asprintf(&p, "Delivered-To: %s\n", s->aux.rcpt_to); if (len == -1) fatal("mda_store: asprintf"); |