-/* $OpenBSD: mda.c,v 1.133 2018/07/08 13:06:37 gilles Exp $ */
+/* $OpenBSD: mda.c,v 1.134 2018/09/04 13:04:42 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sysexits.h>
#include <time.h>
#include <unistd.h>
#include <limits.h>
static struct mda_envelope *mda_envelope(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;
struct deliver deliver;
struct msg m;
const void *data;
- const char *error, *parent_error;
+ 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:
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);
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 (strcmp(parent_error, "exited okay") == 0) {
- if (s->datafp || (s->io && io_queued(s->io)))
+ 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);
+ if (syserror)
+ error = syserror;
+ }
+
/* update queue entry */
- if (error) {
+ switch (mda_status) {
+ case MDA_TEMPFAIL:
mda_queue_tempfail(e->id, error,
ESC_OTHER_MAIL_SYSTEM_STATUS);
(void)snprintf(buf, sizeof buf,
"Error (%s)", error);
mda_log(e, "TempFail", buf);
- }
- else {
+ break;
+ case MDA_PERMFAIL:
+ mda_queue_permfail(e->id, error,
+ ESC_OTHER_MAIL_SYSTEM_STATUS);
+ (void)snprintf(buf, sizeof buf,
+ "Error (%s)", 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;
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;
+}
+
-/* $OpenBSD: smtpd.c,v 1.302 2018/07/25 16:00:48 eric Exp $ */
+/* $OpenBSD: smtpd.c,v 1.303 2018/09/04 13:04:42 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
+#include <sysexits.h>
#include <time.h>
#include <unistd.h>
case SIGCHLD:
do {
int len;
-
+ enum mda_resp_status mda_status;
+ int mda_sysexit;
+
pid = waitpid(-1, &status, WNOHANG);
if (pid <= 0)
continue;
fail = 1;
len = asprintf(&cause, "terminated; signal %d",
WTERMSIG(status));
+ mda_status = MDA_TEMPFAIL;
+ mda_sysexit = 0;
} else if (WIFEXITED(status)) {
if (WEXITSTATUS(status) != 0) {
fail = 1;
len = asprintf(&cause,
"exited abnormally");
- } else
+ mda_sysexit = WEXITSTATUS(status);
+ if (mda_sysexit == EX_OSERR ||
+ mda_sysexit == EX_TEMPFAIL)
+ mda_status = MDA_TEMPFAIL;
+ else
+ mda_status = MDA_PERMFAIL;
+ } else {
len = asprintf(&cause, "exited okay");
+ mda_status = MDA_OK;
+ mda_sysexit = 0;
+ }
} else
/* WIFSTOPPED or WIFCONTINUED */
continue;
log_debug("debug: smtpd: mda process done "
"for session %016"PRIx64 ": %s",
child->mda_id, cause);
+
m_create(p_pony, IMSG_MDA_DONE, 0, 0,
child->mda_out);
m_add_id(p_pony, child->mda_id);
+ m_add_int(p_pony, mda_status);
+ m_add_int(p_pony, mda_sysexit);
m_add_string(p_pony, cause);
m_close(p_pony);
- /* free(cause); */
+
break;
case CHILD_ENQUEUE_OFFLINE:
dsp->u.local.user);
m_create(p_pony, IMSG_MDA_DONE, 0, 0, -1);
m_add_id(p_pony, id);
+ m_add_int(p_pony, MDA_PERMFAIL);
+ m_add_int(p_pony, EX_NOUSER);
m_add_string(p_pony, ebuf);
m_close(p_pony);
return;
deliver->userinfo.username);
m_create(p_pony, IMSG_MDA_DONE, 0, 0, -1);
m_add_id(p_pony, id);
+ m_add_int(p_pony, MDA_PERMFAIL);
+ m_add_int(p_pony, EX_NOPERM);
m_add_string(p_pony, ebuf);
m_close(p_pony);
return;
(void)snprintf(ebuf, sizeof ebuf, "pipe: %s", strerror(errno));
m_create(p_pony, IMSG_MDA_DONE, 0, 0, -1);
m_add_id(p_pony, id);
+ m_add_int(p_pony, MDA_TEMPFAIL);
+ m_add_int(p_pony, EX_OSERR);
m_add_string(p_pony, ebuf);
m_close(p_pony);
return;
(void)snprintf(ebuf, sizeof ebuf, "mkstemp: %s", strerror(errno));
m_create(p_pony, IMSG_MDA_DONE, 0, 0, -1);
m_add_id(p_pony, id);
+ m_add_int(p_pony, MDA_TEMPFAIL);
+ m_add_int(p_pony, EX_OSERR);
m_add_string(p_pony, ebuf);
m_close(p_pony);
close(pipefd[0]);
(void)snprintf(ebuf, sizeof ebuf, "fork: %s", strerror(errno));
m_create(p_pony, IMSG_MDA_DONE, 0, 0, -1);
m_add_id(p_pony, id);
+ m_add_int(p_pony, MDA_TEMPFAIL);
+ m_add_int(p_pony, EX_OSERR);
m_add_string(p_pony, ebuf);
m_close(p_pony);
close(pipefd[0]);