summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Faurot <eric@cvs.openbsd.org>2014-02-04 15:44:07 +0000
committerEric Faurot <eric@cvs.openbsd.org>2014-02-04 15:44:07 +0000
commit5e47a3d0175f739592e7b34ff0c015080411622f (patch)
tree735ab917098eacfabf96ca7885c6be3a5c0e908b
parent031ed87ff6982c47a192337c6ac5fd231f8ea68b (diff)
Add support for DSN and Enhanced Status Code
-rw-r--r--usr.sbin/smtpd/bounce.c51
-rw-r--r--usr.sbin/smtpd/enqueue.c35
-rw-r--r--usr.sbin/smtpd/envelope.c114
-rw-r--r--usr.sbin/smtpd/esc.c137
-rw-r--r--usr.sbin/smtpd/mda.c31
-rw-r--r--usr.sbin/smtpd/mta.c26
-rw-r--r--usr.sbin/smtpd/mta_session.c76
-rw-r--r--usr.sbin/smtpd/queue.c48
-rw-r--r--usr.sbin/smtpd/smtp_session.c260
-rw-r--r--usr.sbin/smtpd/smtpd-api.h81
-rw-r--r--usr.sbin/smtpd/smtpd.h40
-rw-r--r--usr.sbin/smtpd/smtpd/Makefile4
12 files changed, 800 insertions, 103 deletions
diff --git a/usr.sbin/smtpd/bounce.c b/usr.sbin/smtpd/bounce.c
index ded25af80b2..d9decd60734 100644
--- a/usr.sbin/smtpd/bounce.c
+++ b/usr.sbin/smtpd/bounce.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: bounce.c,v 1.61 2014/02/04 14:56:03 eric Exp $ */
+/* $OpenBSD: bounce.c,v 1.62 2014/02/04 15:44:05 eric Exp $ */
/*
* Copyright (c) 2009 Gilles Chehade <gilles@poolp.org>
@@ -95,6 +95,7 @@ static void bounce_status(struct bounce_session *, const char *, ...);
static void bounce_io(struct io *, int);
static void bounce_timeout(int, short, void *);
static void bounce_free(struct bounce_session *);
+static const char *bounce_strtype(enum bounce_type);
static struct tree wait_fd;
static struct bounce_message_tree messages;
@@ -328,6 +329,12 @@ const char *notice_warning2 =
" The message is kept in the queue for up to %s.\n"
" You DO NOT NEED to re-send the message to these recipients.\n\n";
+const char *notice_success =
+ " Your message was successfully delivered to these recipients.\n\n";
+
+const char *notice_relay =
+ " Your message was relayed to these recipients.\n\n";
+
static int
bounce_next_message(struct bounce_session *s)
{
@@ -420,18 +427,29 @@ bounce_next(struct bounce_session *s)
"\n"
NOTICE_INTRO
"\n",
- (s->msg->bounce.type == B_ERROR) ? "error" : "warning",
+ bounce_strtype(s->msg->bounce.type),
s->smtpname,
s->msg->to,
time_to_text(time(NULL)));
- if (s->msg->bounce.type == B_ERROR)
+ switch (s->msg->bounce.type) {
+ case B_ERROR:
iobuf_xfqueue(&s->iobuf, "bounce_next: BODY",
notice_error);
- else
+ break;
+ case B_WARNING:
iobuf_xfqueue(&s->iobuf, "bounce_next: BODY",
notice_warning,
bounce_duration(s->msg->bounce.delay));
+ break;
+ case B_DSN:
+ iobuf_xfqueue(&s->iobuf, "bounce_next: BODY",
+ s->msg->bounce.mta_without_dsn ?
+ notice_relay : notice_success);
+ break;
+ default:
+ log_warn("warn: bounce: unknown bounce_type");
+ }
TAILQ_FOREACH(evp, &s->msg->envelopes, entry) {
iobuf_xfqueue(&s->iobuf,
@@ -463,6 +481,15 @@ bounce_next(struct bounce_session *s)
line = fgetln(s->msgfp, &len);
if (line == NULL)
break;
+ if (len == 1 && line[0] == '\n' && /* end of headers */
+ s->msg->bounce.type == B_DSN &&
+ s->msg->bounce.dsn_ret == DSN_RETHDRS) {
+ fclose(s->msgfp);
+ s->msgfp = NULL;
+ bounce_send(s, ".");
+ s->state = BOUNCE_DATA_END;
+ return (0);
+ }
line[len - 1] = '\0';
iobuf_xfqueue(&s->iobuf,
"bounce_next: DATA_MESSAGE", "%s%s\n",
@@ -693,5 +720,21 @@ bounce_message_cmp(const struct bounce_message *a,
return memcmp(&a->bounce, &b->bounce, sizeof (a->bounce));
}
+static const char *
+bounce_strtype(enum bounce_type t)
+{
+ switch (t) {
+ case B_ERROR:
+ return ("error");
+ case B_WARNING:
+ return ("warning");
+ case B_DSN:
+ return ("dsn");
+ default:
+ log_warn("warn: bounce: unknown bounce_type");
+ return ("");
+ }
+}
+
SPLAY_GENERATE(bounce_message_tree, bounce_message, sp_entry,
bounce_message_cmp);
diff --git a/usr.sbin/smtpd/enqueue.c b/usr.sbin/smtpd/enqueue.c
index fd36b8d161c..7b401bad777 100644
--- a/usr.sbin/smtpd/enqueue.c
+++ b/usr.sbin/smtpd/enqueue.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: enqueue.c,v 1.74 2013/12/26 17:25:32 eric Exp $ */
+/* $OpenBSD: enqueue.c,v 1.75 2014/02/04 15:44:05 eric Exp $ */
/*
* Copyright (c) 2005 Henning Brauer <henning@bulabula.org>
@@ -107,6 +107,9 @@ struct {
char *from;
char *fromname;
char **rcpts;
+ char *dsn_notify;
+ char *dsn_ret;
+ char *dsn_envid;
int rcpt_cnt;
int need_linesplit;
int saw_date;
@@ -163,9 +166,9 @@ enqueue(int argc, char *argv[])
char *fake_from = NULL, *buf;
struct passwd *pw;
FILE *fp, *fout;
+ size_t len, envid_sz = 0;
int fd;
char sfn[] = "/tmp/smtpd.XXXXXXXXXX";
- size_t len;
char *line;
int dotted;
int inheaders = 0;
@@ -179,7 +182,7 @@ enqueue(int argc, char *argv[])
save_argv = argv;
while ((ch = getopt(argc, argv,
- "A:B:b:E::e:F:f:iJ::L:mN:o:p:qR:tvx")) != -1) {
+ "A:B:b:E::e:F:f:iJ::L:mN:o:p:qR:tvV:x")) != -1) {
switch (ch) {
case 'f':
fake_from = optarg;
@@ -187,12 +190,21 @@ enqueue(int argc, char *argv[])
case 'F':
msg.fromname = optarg;
break;
+ case 'N':
+ msg.dsn_notify = optarg;
+ break;
+ case 'R':
+ msg.dsn_ret = optarg;
+ break;
case 't':
tflag = 1;
break;
case 'v':
verbose = 1;
break;
+ case 'V':
+ msg.dsn_envid = optarg;
+ break;
/* all remaining: ignored, sendmail compat */
case 'A':
case 'B':
@@ -202,10 +214,8 @@ enqueue(int argc, char *argv[])
case 'i':
case 'L':
case 'm':
- case 'N': /* XXX: DSN */
case 'o':
case 'p':
- case 'R':
case 'x':
break;
case 'q':
@@ -275,11 +285,22 @@ enqueue(int argc, char *argv[])
send_line(fout, verbose, "EHLO localhost\n");
get_responses(fout, 1);
- send_line(fout, verbose, "MAIL FROM:<%s>\n", msg.from);
+ if (msg.dsn_envid != NULL)
+ envid_sz = strlen(msg.dsn_envid);
+
+ send_line(fout, verbose, "MAIL FROM:<%s> %s%s %s%s\n",
+ msg.from,
+ msg.dsn_ret ? "RET=" : "",
+ msg.dsn_ret ? msg.dsn_ret : "",
+ envid_sz ? "ENVID=" : "",
+ envid_sz ? msg.dsn_envid : "");
get_responses(fout, 1);
for (i = 0; i < msg.rcpt_cnt; i++) {
- send_line(fout, verbose, "RCPT TO:<%s>\n", msg.rcpts[i]);
+ send_line(fout, verbose, "RCPT TO:<%s> %s%s\n",
+ msg.rcpts[i],
+ msg.dsn_notify ? "NOTIFY=" : "",
+ msg.dsn_notify ? msg.dsn_notify : "");
get_responses(fout, 1);
}
diff --git a/usr.sbin/smtpd/envelope.c b/usr.sbin/smtpd/envelope.c
index 4d3e0d071e7..244052bb607 100644
--- a/usr.sbin/smtpd/envelope.c
+++ b/usr.sbin/smtpd/envelope.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: envelope.c,v 1.27 2014/02/04 13:44:41 eric Exp $ */
+/* $OpenBSD: envelope.c,v 1.28 2014/02/04 15:44:05 eric Exp $ */
/*
* Copyright (c) 2013 Eric Faurot <eric@openbsd.org>
@@ -67,6 +67,18 @@ envelope_set_errormsg(struct envelope *e, char *fmt, ...)
strlcpy(e->errorline + (sizeof(e->errorline) - 4), "...", 4);
}
+void
+envelope_set_esc_class(struct envelope *e, enum enhanced_status_class class)
+{
+ e->esc_class = class;
+}
+
+void
+envelope_set_esc_code(struct envelope *e, enum enhanced_status_code code)
+{
+ e->esc_code = code;
+}
+
static int
envelope_buffer_to_dict(struct dict *d, const char *ibuf, size_t buflen)
{
@@ -188,6 +200,12 @@ envelope_dump_buffer(const struct envelope *ep, char *dest, size_t len)
envelope_ascii_dump(ep, &dest, &len, "expire");
envelope_ascii_dump(ep, &dest, &len, "retry");
envelope_ascii_dump(ep, &dest, &len, "flags");
+ envelope_ascii_dump(ep, &dest, &len, "dsn-notify");
+ envelope_ascii_dump(ep, &dest, &len, "dsn-ret");
+ envelope_ascii_dump(ep, &dest, &len, "dsn-envid");
+ envelope_ascii_dump(ep, &dest, &len, "dsn-orcpt");
+ envelope_ascii_dump(ep, &dest, &len, "esc-class");
+ envelope_ascii_dump(ep, &dest, &len, "esc-code");
switch (ep->type) {
case D_MDA:
@@ -221,6 +239,17 @@ envelope_dump_buffer(const struct envelope *ep, char *dest, size_t len)
}
static int
+ascii_load_uint8(uint8_t *dest, char *buf)
+{
+ const char *errstr;
+
+ *dest = strtonum(buf, 0, 0xff, &errstr);
+ if (errstr)
+ return 0;
+ return 1;
+}
+
+static int
ascii_load_uint16(uint16_t *dest, char *buf)
{
const char *errstr;
@@ -382,6 +411,20 @@ ascii_load_bounce_type(enum bounce_type *dest, char *buf)
*dest = B_ERROR;
else if (strcasecmp(buf, "warn") == 0)
*dest = B_WARNING;
+ else if (strcasecmp(buf, "dsn") == 0)
+ *dest = B_DSN;
+ else
+ return 0;
+ return 1;
+}
+
+static int
+ascii_load_dsn_ret(enum dsn_ret *ret, char *buf)
+{
+ if (strcasecmp(buf, "HDRS") == 0)
+ *ret = DSN_RETHDRS;
+ else if (strcasecmp(buf, "FULL") == 0)
+ *ret = DSN_RETFULL;
else
return 0;
return 1;
@@ -500,6 +543,24 @@ ascii_load_field(const char *field, struct envelope *ep, char *buf)
if (strcasecmp("version", field) == 0)
return ascii_load_uint32(&ep->version, buf);
+ if (strcasecmp("dsn-notify", field) == 0)
+ return ascii_load_uint8(&ep->dsn_notify, buf);
+
+ if (strcasecmp("dsn-orcpt", field) == 0)
+ return ascii_load_mailaddr(&ep->dsn_orcpt, buf);
+
+ if (strcasecmp("dsn-ret", field) == 0)
+ return ascii_load_dsn_ret(&ep->dsn_ret, buf);
+
+ if (strcasecmp("dsn-envid", field) == 0)
+ return ascii_load_string(ep->dsn_envid, buf, sizeof(ep->dsn_envid));
+
+ if (strcasecmp("esc-class", field) == 0)
+ return ascii_load_uint8(&ep->esc_class, buf);
+
+ if (strcasecmp("esc-code", field) == 0)
+ return ascii_load_uint8(&ep->esc_code, buf);
+
return (0);
}
@@ -524,6 +585,12 @@ err:
static int
+ascii_dump_uint8(uint8_t src, char *dest, size_t len)
+{
+ return bsnprintf(dest, len, "%d", src);
+}
+
+static int
ascii_dump_uint16(uint16_t src, char *dest, size_t len)
{
return bsnprintf(dest, len, "%d", src);
@@ -667,12 +734,30 @@ ascii_dump_bounce_type(enum bounce_type type, char *dest, size_t len)
case B_WARNING:
p = "warn";
break;
+ case B_DSN:
+ p = "dsn";
+ break;
default:
return 0;
}
return bsnprintf(dest, len, "%s", p);
}
+
+static int
+ascii_dump_dsn_ret(enum dsn_ret flag, char *dest, size_t len)
+{
+ size_t cpylen = 0;
+
+ dest[0] = '\0';
+ if (flag == DSN_RETFULL)
+ cpylen = strlcat(dest, "FULL", len);
+ else if (flag == DSN_RETHDRS)
+ cpylen = strlcat(dest, "HDRS", len);
+
+ return cpylen < len ? 1 : 0;
+}
+
static int
ascii_dump_field(const char *field, const struct envelope *ep,
char *buf, size_t len)
@@ -785,6 +870,33 @@ ascii_dump_field(const char *field, const struct envelope *ep,
if (strcasecmp(field, "version") == 0)
return ascii_dump_uint32(SMTPD_ENVELOPE_VERSION, buf, len);
+ if (strcasecmp(field, "dsn-notify") == 0)
+ return ascii_dump_uint8(ep->dsn_notify, buf, len);
+
+ if (strcasecmp(field, "dsn-ret") == 0)
+ return ascii_dump_dsn_ret(ep->dsn_ret, buf, len);
+
+ if (strcasecmp(field, "dsn-orcpt") == 0) {
+ if (ep->dsn_orcpt.user[0] && ep->dsn_orcpt.domain[0])
+ return ascii_dump_mailaddr(&ep->dsn_orcpt, buf, len);
+ return 1;
+ }
+
+ if (strcasecmp(field, "dsn-envid") == 0)
+ return ascii_dump_string(ep->dsn_envid, buf, len);
+
+ if (strcasecmp(field, "esc-class") == 0) {
+ if (ep->esc_class)
+ return ascii_dump_uint8(ep->esc_class, buf, len);
+ return 1;
+ }
+
+ if (strcasecmp(field, "esc-code") == 0) {
+ if (ep->esc_class)
+ return ascii_dump_uint8(ep->esc_code, buf, len);
+ return 1;
+ }
+
return (0);
}
diff --git a/usr.sbin/smtpd/esc.c b/usr.sbin/smtpd/esc.c
new file mode 100644
index 00000000000..7bccc22d9ab
--- /dev/null
+++ b/usr.sbin/smtpd/esc.c
@@ -0,0 +1,137 @@
+/* $OpenBSD: esc.c,v 1.1 2014/02/04 15:44:05 eric Exp $ */
+
+/*
+ * Copyright (c) 2014 Gilles Chehade <gilles@poolp.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 <stdio.h>
+
+#include "smtpd-defines.h"
+#include "smtpd-api.h"
+
+static struct escode {
+ enum enhanced_status_code code;
+ const char *description;
+} esc[] = {
+ /* 0.0 */
+ { ESC_OTHER_STATUS, "Other/Undefined" },
+
+ /* 1.x */
+ { ESC_OTHER_ADDRESS_STATUS, "Other/Undefined address status" },
+ { ESC_BAD_DESTINATION_MAILBOX_ADDRESS, "Bad destination mailbox address" },
+ { ESC_BAD_DESTINATION_SYSTEM_ADDRESS, "Bad destination system address" },
+ { ESC_BAD_DESTINATION_MAILBOX_ADDRESS_SYNTAX, "Bad destination mailbox address syntax" },
+ { ESC_DESTINATION_MAILBOX_ADDRESS_AMBIGUOUS, "Destination mailbox address ambiguous" },
+ { ESC_DESTINATION_ADDRESS_VALID, "Destination address valid" },
+ { ESC_DESTINATION_MAILBOX_HAS_MOVED, "Destination mailbox has moved, No forwarding address" },
+ { ESC_BAD_SENDER_MAILBOX_ADDRESS_SYNTAX, "Bad sender's mailbox address syntax" },
+ { ESC_BAD_SENDER_SYSTEM_ADDRESS, "Bad sender's system address syntax" },
+
+ /* 2.x */
+ { ESC_OTHER_MAILBOX_STATUS, "Other/Undefined mailbox status" },
+ { ESC_MAILBOX_DISABLED, "Mailbox disabled, not accepting messages" },
+ { ESC_MAILBOX_FULL, "Mailbox full" },
+ { ESC_MESSAGE_LENGTH_TOO_LARGE, "Message length exceeds administrative limit" },
+ { ESC_MAILING_LIST_EXPANSION_PROBLEM, "Mailing list expansion problem" },
+
+ /* 3.x */
+ { ESC_OTHER_MAIL_SYSTEM_STATUS, "Other/Undefined mail system status" },
+ { ESC_MAIL_SYSTEM_FULL, "Mail system full" },
+ { ESC_SYSTEM_NOT_ACCEPTING_MESSAGES, "System not accepting network messages" },
+ { ESC_SYSTEM_NOT_CAPABLE_OF_SELECTED_FEATURES, "System not capable of selected features" },
+ { ESC_MESSAGE_TOO_BIG_FOR_SYSTEM, "Message too big for system" },
+ { ESC_SYSTEM_INCORRECTLY_CONFIGURED, "System incorrectly configured" },
+
+ /* 4.x */
+ { ESC_OTHER_NETWORK_ROUTING_STATUS, "Other/Undefined network or routing status" },
+ { ESC_NO_ANSWER_FROM_HOST, "No answer from host" },
+ { ESC_BAD_CONNECTION, "Bad connection" },
+ { ESC_DIRECTORY_SERVER_FAILURE, "Directory server failure" },
+ { ESC_UNABLE_TO_ROUTE, "Unable to route" },
+ { ESC_MAIL_SYSTEM_CONGESTION, "Mail system congestion" },
+ { ESC_ROUTING_LOOP_DETECTED, "Routing loop detected" },
+ { ESC_DELIVERY_TIME_EXPIRED, "Delivery time expired" },
+
+ /* 5.x */
+ { ESC_OTHER_PROTOCOL_STATUS, "Other/Undefined protocol status" },
+ { ESC_INVALID_COMMAND, "Invalid command" },
+ { ESC_SYNTAX_ERROR, "Syntax error" },
+ { ESC_TOO_MANY_RECIPIENTS, "Too many recipients" },
+ { ESC_INVALID_COMMAND_ARGUMENTS, "Invalid command arguments" },
+ { ESC_WRONG_PROTOCOL_VERSION, "Wrong protocol version" },
+
+ /* 6.x */
+ { ESC_OTHER_MEDIA_ERROR, "Other/Undefined media error" },
+ { ESC_MEDIA_NOT_SUPPORTED, "Media not supported" },
+ { ESC_CONVERSION_REQUIRED_AND_PROHIBITED, "Conversion required and prohibited" },
+ { ESC_CONVERSION_REQUIRED_BUT_NOT_SUPPORTED, "Conversion required but not supported" },
+ { ESC_CONVERSION_WITH_LOSS_PERFORMED, "Conversion with loss performed" },
+ { ESC_CONVERSION_FAILED, "Conversion failed" },
+
+ /* 7.x */
+ { ESC_OTHER_SECURITY_STATUS, "Other/Undefined security status" },
+ { ESC_DELIVERY_NOT_AUTHORIZED_MESSAGE_REFUSED, "Delivery not authorized, message refused" },
+ { ESC_MAILING_LIST_EXPANSION_PROHIBITED, "Mailing list expansion prohibited" },
+ { ESC_SECURITY_CONVERSION_REQUIRED_NOT_POSSIBLE,"Security conversion required but not possible" },
+ { ESC_SECURITY_FEATURES_NOT_SUPPORTED, "Security features not supported" },
+ { ESC_CRYPTOGRAPHIC_FAILURE, "Cryptographic failure" },
+ { ESC_CRYPTOGRAPHIC_ALGORITHM_NOT_SUPPORTED, "Cryptographic algorithm not supported" },
+ { ESC_MESSAGE_TOO_BIG_FOR_SYSTEM, "Message integrity failure" },
+};
+
+#if 0
+struct esc_map {
+ uint8_t code;
+ const char *description;
+};
+
+static struct esc_map esc_class[] = {
+ { 2, "Success" },
+ { 4, "Persistent Transient Failure"},
+ { 5, "Permanent Failure" },
+};
+
+static struct esc_map esc_subclass[] = {
+ { 0, "Other/Undefined" },
+ { 1, "Addressing Status" },
+ { 2, "Mailbox Status" },
+ { 3, "Mail System Status" },
+ { 4, "Network and Routing Status" },
+ { 5, "Mail Delivery Protocol Status" },
+ { 6, "Message Content or Media Status" },
+ { 7, "Security or Policy Status" },
+};
+#endif
+
+const char *
+esc_code(enum enhanced_status_class class, enum enhanced_status_code code)
+{
+ static char buffer[6];
+
+ snprintf(buffer, sizeof buffer, "%d.%d.%d", class, code / 10, code % 10);
+ return buffer;
+
+}
+
+const char *
+esc_description(enum enhanced_status_code code)
+{
+ uint32_t i;
+
+ for (i = 0; i < nitems(esc); ++i)
+ if (code == esc[i].code)
+ return esc[i].description;
+ return "Other/Undefined";
+}
diff --git a/usr.sbin/smtpd/mda.c b/usr.sbin/smtpd/mda.c
index ee5f8c96551..77afab1a5aa 100644
--- a/usr.sbin/smtpd/mda.c
+++ b/usr.sbin/smtpd/mda.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mda.c,v 1.101 2014/02/04 14:56:03 eric Exp $ */
+/* $OpenBSD: mda.c,v 1.102 2014/02/04 15:44:05 eric Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
@@ -90,7 +90,7 @@ static void mda_sig_handler(int, short, 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 *);
+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 struct mda_user *mda_user(const struct envelope *);
@@ -137,10 +137,12 @@ mda_imsg(struct mproc *p, struct imsg *imsg)
if (status == LKA_TEMPFAIL)
mda_fail(u, 0,
- "Temporary failure in user lookup");
+ "Temporary failure in user lookup",
+ ESC_OTHER_ADDRESS_STATUS);
else if (status == LKA_PERMFAIL)
mda_fail(u, 1,
- "Permanent failure in user lookup");
+ "Permanent failure in user lookup",
+ ESC_DESTINATION_MAILBOX_HAS_MOVED);
else {
memmove(&u->userinfo, data, sz);
u->flags &= ~USER_WAITINFO;
@@ -204,7 +206,8 @@ mda_imsg(struct mproc *p, struct imsg *imsg)
if (imsg->fd == -1) {
log_debug("debug: mda: cannot get message fd");
- queue_tempfail(e->id, "Cannot get message fd");
+ 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;
@@ -217,7 +220,8 @@ mda_imsg(struct mproc *p, struct imsg *imsg)
if ((s->datafp = fdopen(imsg->fd, "r")) == NULL) {
log_warn("warn: mda: fdopen");
close(imsg->fd);
- queue_tempfail(e->id, "fdopen failed");
+ queue_tempfail(e->id, "fdopen failed",
+ ESC_OTHER_MAIL_SYSTEM_STATUS);
mda_log(e, "TempFail", "fdopen failed");
mda_done(s);
return;
@@ -245,7 +249,8 @@ mda_imsg(struct mproc *p, struct imsg *imsg)
if (n == -1) {
log_warn("warn: mda: "
"fail to write delivery info");
- queue_tempfail(e->id, "Out of memory");
+ queue_tempfail(e->id, "Out of memory",
+ ESC_OTHER_MAIL_SYSTEM_STATUS);
mda_log(e, "TempFail", "Out of memory");
mda_done(s);
return;
@@ -336,7 +341,8 @@ mda_imsg(struct mproc *p, struct imsg *imsg)
e = s->evp;
if (imsg->fd == -1) {
log_warn("warn: mda: fail to retrieve mda fd");
- queue_tempfail(e->id, "Cannot get mda fd");
+ 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;
@@ -379,7 +385,8 @@ mda_imsg(struct mproc *p, struct imsg *imsg)
/* update queue entry */
if (error) {
- queue_tempfail(e->id, error);
+ queue_tempfail(e->id, error,
+ ESC_OTHER_MAIL_SYSTEM_STATUS);
snprintf(buf, sizeof buf, "Error (%s)", error);
mda_log(e, "TempFail", buf);
}
@@ -662,7 +669,7 @@ mda_getlastline(int fd, char *dst, size_t dstsz)
}
static void
-mda_fail(struct mda_user *user, int permfail, const char *error)
+mda_fail(struct mda_user *user, int permfail, const char *error, enum enhanced_status_code code)
{
struct mda_envelope *e;
@@ -670,11 +677,11 @@ mda_fail(struct mda_user *user, int permfail, const char *error)
TAILQ_REMOVE(&user->envelopes, e, entry);
if (permfail) {
mda_log(e, "PermFail", error);
- queue_permfail(e->id, error);
+ queue_permfail(e->id, error, code);
}
else {
mda_log(e, "TempFail", error);
- queue_tempfail(e->id, error);
+ queue_tempfail(e->id, error, code);
}
mda_envelope_free(e);
}
diff --git a/usr.sbin/smtpd/mta.c b/usr.sbin/smtpd/mta.c
index 7d87d7f1ca8..6740425da7b 100644
--- a/usr.sbin/smtpd/mta.c
+++ b/usr.sbin/smtpd/mta.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mta.c,v 1.181 2014/02/04 15:22:39 eric Exp $ */
+/* $OpenBSD: mta.c,v 1.182 2014/02/04 15:44:05 eric Exp $ */
/*
* Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -266,6 +266,16 @@ mta_imsg(struct mproc *p, struct imsg *imsg)
if (strcmp(buf, e->dest))
e->rcpt = xstrdup(buf, "mta_envelope:rcpt");
e->task = task;
+ if (evp.dsn_orcpt.user[0] && evp.dsn_orcpt.domain[0]) {
+ snprintf(buf, sizeof buf, "%s@%s",
+ evp.dsn_orcpt.user, evp.dsn_orcpt.domain);
+ e->dsn_orcpt = xstrdup(buf,
+ "mta_envelope:dsn_orcpt");
+ }
+ strlcpy(e->dsn_envid, evp.dsn_envid,
+ sizeof e->dsn_envid);
+ e->dsn_notify = evp.dsn_notify;
+ e->dsn_ret = evp.dsn_ret;
TAILQ_INSERT_TAIL(&task->envelopes, e, entry);
log_debug("debug: mta: received evp:%016" PRIx64
@@ -772,12 +782,15 @@ mta_delivery_flush_event(int fd, short event, void *arg)
if (tree_poproot(&flush_evp, NULL, (void**)(&e))) {
- if (e->delivery == IMSG_DELIVERY_OK)
- queue_ok(e->id);
- else if (e->delivery == IMSG_DELIVERY_TEMPFAIL)
- queue_tempfail(e->id, e->status);
+ if (e->delivery == IMSG_DELIVERY_OK) {
+ m_create(p_queue, IMSG_DELIVERY_OK, 0, 0, -1);
+ m_add_evpid(p_queue, e->id);
+ m_add_int(p_queue, e->ext);
+ m_close(p_queue);
+ } else if (e->delivery == IMSG_DELIVERY_TEMPFAIL)
+ queue_tempfail(e->id, e->status, ESC_OTHER_STATUS);
else if (e->delivery == IMSG_DELIVERY_PERMFAIL)
- queue_permfail(e->id, e->status);
+ queue_permfail(e->id, e->status, ESC_OTHER_STATUS);
else if (e->delivery == IMSG_DELIVERY_LOOP)
queue_loop(e->id);
else {
@@ -790,6 +803,7 @@ mta_delivery_flush_event(int fd, short event, void *arg)
free(e->dest);
free(e->rcpt);
+ free(e->dsn_orcpt);
free(e);
tv.tv_sec = 0;
diff --git a/usr.sbin/smtpd/mta_session.c b/usr.sbin/smtpd/mta_session.c
index 3ac18ae822b..3443f49d166 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.53 2014/02/04 14:56:03 eric Exp $ */
+/* $OpenBSD: mta_session.c,v 1.54 2014/02/04 15:44:05 eric Exp $ */
/*
* Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -146,6 +146,8 @@ static int mta_check_loop(FILE *);
static void mta_start_tls(struct mta_session *);
static int mta_verify_certificate(struct mta_session *);
static struct mta_session *mta_tree_pop(struct tree *, uint64_t);
+static const char * dsn_strret(enum dsn_ret);
+static const char * dsn_strnotify(uint8_t);
void mta_hoststat_update(const char *, const char *);
void mta_hoststat_reschedule(const char *);
@@ -576,6 +578,8 @@ mta_connect(struct mta_session *s)
static void
mta_enter_state(struct mta_session *s, int newstate)
{
+ struct mta_envelope *e;
+ size_t envid_sz;
int oldstate;
ssize_t q;
char ibuf[SMTPD_MAXLINESIZE];
@@ -760,15 +764,39 @@ mta_enter_state(struct mta_session *s, int newstate)
break;
case MTA_MAIL:
+ if (s->currevp == NULL)
+ s->currevp = TAILQ_FIRST(&s->task->envelopes);
+
+ e = s->currevp;
s->hangon = 0;
s->msgtried++;
- mta_send(s, "MAIL FROM:<%s>", s->task->sender);
+ envid_sz = strlen(e->dsn_envid);
+ if (s->ext & MTA_EXT_DSN) {
+ mta_send(s, "MAIL FROM:<%s> %s%s %s%s",
+ s->task->sender,
+ e->dsn_ret ? "RET=" : "",
+ e->dsn_ret ? dsn_strret(e->dsn_ret) : "",
+ envid_sz ? "ENVID=" : "",
+ envid_sz ? e->dsn_envid : "");
+ } else
+ mta_send(s, "MAIL FROM:<%s>", s->task->sender);
break;
case MTA_RCPT:
if (s->currevp == NULL)
s->currevp = TAILQ_FIRST(&s->task->envelopes);
- mta_send(s, "RCPT TO:<%s>", s->currevp->dest);
+
+ e = s->currevp;
+ if (s->ext & MTA_EXT_DSN) {
+ mta_send(s, "RCPT TO:<%s> %s%s %s%s",
+ e->dest,
+ e->dsn_notify ? "NOTIFY=" : "",
+ e->dsn_notify ? dsn_strnotify(e->dsn_notify) : "",
+ e->dsn_orcpt ? "ORCPT=" : "",
+ e->dsn_orcpt ? e->dsn_orcpt : "");
+ } else
+ mta_send(s, "RCPT TO:<%s>", e->dest);
+
s->rcptcount++;
break;
@@ -1179,6 +1207,8 @@ mta_io(struct io *io, int evt)
}
else if (strcmp(msg, "PIPELINING") == 0)
s->ext |= MTA_EXT_PIPELINING;
+ else if (strcmp(msg, "DSN") == 0)
+ s->ext |= MTA_EXT_DSN;
}
if (cont)
@@ -1334,6 +1364,7 @@ mta_flush_task(struct mta_session *s, int delivery, const char *error, size_t co
/* we're about to log, associate session to envelope */
e->session = s->id;
+ e->ext = s->ext;
/* XXX */
/*
@@ -1549,6 +1580,45 @@ mta_verify_certificate(struct mta_session *s)
return 1;
}
+static const char *
+dsn_strret(enum dsn_ret ret)
+{
+ if (ret == DSN_RETHDRS)
+ return "HDRS";
+ else if (ret == DSN_RETFULL)
+ return "FULL";
+ else {
+ log_debug("mta: invalid ret %d", ret);
+ return "???";
+ }
+}
+
+static const char *
+dsn_strnotify(uint8_t arg)
+{
+ static char buf[32];
+ size_t sz;
+
+ if (arg & DSN_SUCCESS)
+ strlcat(buf, "SUCCESS,", sizeof(buf));
+
+ if (arg & DSN_FAILURE)
+ strlcat(buf, "FAILURE,", sizeof(buf));
+
+ if (arg & DSN_DELAY)
+ strlcat(buf, "DELAY,", sizeof(buf));
+
+ if (arg & DSN_NEVER)
+ strlcat(buf, "NEVER,", sizeof(buf));
+
+ /* trim trailing comma */
+ sz = strlen(buf);
+ if (sz)
+ buf[sz - 1] = '\0';
+
+ return (buf);
+}
+
#define CASE(x) case x : return #x
static const char *
diff --git a/usr.sbin/smtpd/queue.c b/usr.sbin/smtpd/queue.c
index 48e2c0f0af0..51173e9302d 100644
--- a/usr.sbin/smtpd/queue.c
+++ b/usr.sbin/smtpd/queue.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: queue.c,v 1.158 2014/02/04 14:56:03 eric Exp $ */
+/* $OpenBSD: queue.c,v 1.159 2014/02/04 15:44:05 eric Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
@@ -68,8 +68,9 @@ queue_imsg(struct mproc *p, struct imsg *imsg)
uint64_t reqid, evpid, holdq;
uint32_t msgid;
time_t nexttry;
- int fd, ret, v, flags;
+ int fd, mta_ext, ret, v, flags, code;
+ memset(&bounce, 0, sizeof(struct delivery_bounce));
if (p->proc == PROC_SMTP) {
switch (imsg->hdr.type) {
@@ -213,9 +214,9 @@ queue_imsg(struct mproc *p, struct imsg *imsg)
return;
bounce.type = B_ERROR;
- bounce.delay = 0;
- bounce.expire = 0;
envelope_set_errormsg(&evp, "Envelope expired");
+ envelope_set_esc_class(&evp, ESC_STATUS_TEMPFAIL);
+ envelope_set_esc_code(&evp, ESC_DELIVERY_TIME_EXPIRED);
queue_bounce(&evp, &bounce);
queue_log(&evp, "Expire", "Envelope expired");
queue_envelope_delete(evpid);
@@ -335,7 +336,25 @@ queue_imsg(struct mproc *p, struct imsg *imsg)
case IMSG_DELIVERY_OK:
m_msg(&m, imsg);
m_get_evpid(&m, &evpid);
+ if (p->proc == PROC_MTA)
+ m_get_int(&m, &mta_ext);
m_end(&m);
+ if (queue_envelope_load(evpid, &evp) == 0) {
+ log_warn("queue: dsn: failed to load envelope");
+ return;
+ }
+ if (evp.dsn_notify & DSN_SUCCESS) {
+ bounce.type = B_DSN;
+ bounce.dsn_ret = evp.dsn_ret;
+
+ if (p->proc == PROC_MDA)
+ queue_bounce(&evp, &bounce);
+ else if (p->proc == PROC_MTA &&
+ (mta_ext & MTA_EXT_DSN) == 0) {
+ bounce.mta_without_dsn = 1;
+ queue_bounce(&evp, &bounce);
+ }
+ }
queue_envelope_delete(evpid);
m_create(p_scheduler, IMSG_DELIVERY_OK, 0, 0, -1);
m_add_evpid(p_scheduler, evpid);
@@ -346,6 +365,7 @@ queue_imsg(struct mproc *p, struct imsg *imsg)
m_msg(&m, imsg);
m_get_evpid(&m, &evpid);
m_get_string(&m, &reason);
+ m_get_int(&m, &code);
m_end(&m);
if (queue_envelope_load(evpid, &evp) == 0) {
log_warnx("queue: tempfail: failed to load envelope");
@@ -356,6 +376,8 @@ queue_imsg(struct mproc *p, struct imsg *imsg)
return;
}
envelope_set_errormsg(&evp, "%s", reason);
+ envelope_set_esc_class(&evp, ESC_STATUS_TEMPFAIL);
+ envelope_set_esc_code(&evp, code);
evp.retry++;
if (!queue_envelope_update(&evp))
log_warnx("warn: could not update envelope %016"PRIx64, evpid);
@@ -368,6 +390,7 @@ queue_imsg(struct mproc *p, struct imsg *imsg)
m_msg(&m, imsg);
m_get_evpid(&m, &evpid);
m_get_string(&m, &reason);
+ m_get_int(&m, &code);
m_end(&m);
if (queue_envelope_load(evpid, &evp) == 0) {
log_warnx("queue: permfail: failed to load envelope");
@@ -378,9 +401,9 @@ queue_imsg(struct mproc *p, struct imsg *imsg)
return;
}
bounce.type = B_ERROR;
- bounce.delay = 0;
- bounce.expire = 0;
envelope_set_errormsg(&evp, "%s", reason);
+ envelope_set_esc_class(&evp, ESC_STATUS_PERMFAIL);
+ envelope_set_esc_code(&evp, code);
queue_bounce(&evp, &bounce);
queue_envelope_delete(evpid);
m_create(p_scheduler, IMSG_DELIVERY_PERMFAIL, 0, 0, -1);
@@ -401,9 +424,9 @@ queue_imsg(struct mproc *p, struct imsg *imsg)
return;
}
envelope_set_errormsg(&evp, "%s", "Loop detected");
+ envelope_set_esc_class(&evp, ESC_STATUS_TEMPFAIL);
+ envelope_set_esc_code(&evp, ESC_ROUTING_LOOP_DETECTED);
bounce.type = B_ERROR;
- bounce.delay = 0;
- bounce.expire = 0;
queue_bounce(&evp, &bounce);
queue_envelope_delete(evp.id);
m_create(p_scheduler, IMSG_DELIVERY_LOOP, 0, 0, -1);
@@ -480,6 +503,9 @@ queue_bounce(struct envelope *e, struct delivery_bounce *d)
b.creation = time(NULL);
b.expire = 3600 * 24 * 7;
+ if (e->dsn_notify & DSN_NEVER)
+ return;
+
if (b.id == 0)
log_warnx("warn: queue_bounce: evpid=0");
if (evpid_to_msgid(b.id) == 0)
@@ -657,20 +683,22 @@ queue_ok(uint64_t evpid)
}
void
-queue_tempfail(uint64_t evpid, const char *reason)
+queue_tempfail(uint64_t evpid, const char *reason, enum enhanced_status_code code)
{
m_create(p_queue, IMSG_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);
}
void
-queue_permfail(uint64_t evpid, const char *reason)
+queue_permfail(uint64_t evpid, const char *reason, enum enhanced_status_code code)
{
m_create(p_queue, IMSG_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);
}
diff --git a/usr.sbin/smtpd/smtp_session.c b/usr.sbin/smtpd/smtp_session.c
index 5b6ac71f3fc..513d4a3544a 100644
--- a/usr.sbin/smtpd/smtp_session.c
+++ b/usr.sbin/smtpd/smtp_session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtp_session.c,v 1.194 2014/02/04 13:44:41 eric Exp $ */
+/* $OpenBSD: smtp_session.c,v 1.195 2014/02/04 15:44:05 eric Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
@@ -98,6 +98,7 @@ enum smtp_command {
CMD_RSET,
CMD_QUIT,
CMD_HELP,
+ CMD_WIZ,
CMD_NOOP,
};
@@ -166,6 +167,7 @@ static void smtp_enter_state(struct smtp_session *, int);
static void smtp_reply(struct smtp_session *, char *, ...);
static void smtp_command(struct smtp_session *, char *);
static int smtp_parse_mail_args(struct smtp_session *, char *);
+static int smtp_parse_rcpt_args(struct smtp_session *, char *);
static void smtp_rfc4954_auth_plain(struct smtp_session *, char *);
static void smtp_rfc4954_auth_login(struct smtp_session *, char *);
static void smtp_message_write(struct smtp_session *, const char *);
@@ -175,6 +177,7 @@ static void smtp_wait_mfa(struct smtp_session *s, int);
static void smtp_free(struct smtp_session *, const char *);
static const char *smtp_strstate(int);
static int smtp_verify_certificate(struct smtp_session *);
+static uint8_t dsn_notify_str_to_uint8(const char *);
static void smtp_auth_failure_pause(struct smtp_session *);
static void smtp_auth_failure_resume(int, short, void *);
static int smtp_sni_callback(SSL *, int *, void *);
@@ -190,6 +193,7 @@ static struct { int code; const char *cmd; } commands[] = {
{ CMD_RSET, "RSET" },
{ CMD_QUIT, "QUIT" },
{ CMD_HELP, "HELP" },
+ { CMD_WIZ, "WIZ" },
{ CMD_NOOP, "NOOP" },
{ -1, NULL },
};
@@ -369,9 +373,11 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg)
s->evp.id = msgid_to_evpid(msgid);
s->rcptcount = 0;
s->phase = PHASE_TRANSACTION;
- smtp_reply(s, "250 Ok");
+ smtp_reply(s, "250 %s: Ok",
+ esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
} else {
- smtp_reply(s, "421 Temporary Error");
+ smtp_reply(s, "421 %s: Temporary Error",
+ esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS));
smtp_enter_state(s, STATE_QUIT);
}
m_end(&m);
@@ -389,7 +395,8 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg)
(s->ofile = fdopen(imsg->fd, "w")) == NULL) {
if (imsg->fd != -1)
close(imsg->fd);
- smtp_reply(s, "421 Temporary Error");
+ smtp_reply(s, "421 %s: Temporary Error",
+ esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS));
smtp_enter_state(s, STATE_QUIT);
io_reload(&s->io);
return;
@@ -466,7 +473,8 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg)
* RCPT only so we must cancel the whole transaction
* and close the connection.
*/
- smtp_reply(s, "421 Temporary failure");
+ smtp_reply(s, "421 %s: Temporary failure",
+ esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS));
smtp_enter_state(s, STATE_QUIT);
}
else {
@@ -478,7 +486,9 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg)
s->destcount = 0;
s->rcptcount++;
s->kickcount--;
- smtp_reply(s, "250 Recipient ok");
+ smtp_reply(s, "250 %s %s: Recipient ok",
+ esc_code(ESC_STATUS_OK, ESC_DESTINATION_ADDRESS_VALID),
+ esc_description(ESC_DESTINATION_ADDRESS_VALID));
}
io_reload(&s->io);
return;
@@ -493,7 +503,8 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg)
m_create(p_mfa, IMSG_MFA_EVENT_ROLLBACK, 0, 0, -1);
m_add_id(p_mfa, s->id);
m_close(p_mfa);
- smtp_reply(s, "421 Temporary failure");
+ smtp_reply(s, "421 %s: Temporary failure",
+ esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS));
smtp_enter_state(s, STATE_QUIT);
io_reload(&s->io);
return;
@@ -503,7 +514,8 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg)
m_add_id(p_mfa, s->id);
m_close(p_mfa);
- smtp_reply(s, "250 %08x Message accepted for delivery",
+ smtp_reply(s, "250 %s: %08x Message accepted for delivery",
+ esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS),
evpid_to_msgid(s->evp.id));
TAILQ_FOREACH(rcpt, &s->rcpts, entry) {
@@ -544,7 +556,8 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg)
"on session %016"PRIx64, user, s->id);
s->kickcount = 0;
s->flags |= SF_AUTHENTICATED;
- smtp_reply(s, "235 Authentication succeeded");
+ smtp_reply(s, "235 %s: Authentication succeeded",
+ esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
}
else if (success == LKA_PERMFAIL) {
log_info("smtp-in: Authentication failed for user %s "
@@ -555,7 +568,8 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg)
else if (success == LKA_TEMPFAIL) {
log_info("smtp-in: Authentication temporarily failed "
"for user %s on session %016"PRIx64, user, s->id);
- smtp_reply(s, "421 Temporary failure");
+ smtp_reply(s, "421 %s: Temporary failure",
+ esc_code(ESC_STATUS_TEMPFAIL, ESC_OTHER_MAIL_SYSTEM_STATUS));
}
else
fatalx("bad lka response");
@@ -683,6 +697,7 @@ smtp_mfa_response(struct smtp_session *s, int status, uint32_t code,
smtp_reply(s, "250-8BITMIME");
smtp_reply(s, "250-ENHANCEDSTATUSCODES");
smtp_reply(s, "250-SIZE %zu", env->sc_maxsize);
+ smtp_reply(s, "250-DSN");
if (ADVERTISE_TLS(s))
smtp_reply(s, "250-STARTTLS");
if (ADVERTISE_AUTH(s))
@@ -826,7 +841,8 @@ smtp_io(struct io *io, int evt)
if ((line == NULL && iobuf_len(&s->iobuf) >= SMTPD_MAXLINESIZE) ||
(line && len >= SMTPD_MAXLINESIZE)) {
s->flags |= SF_BADINPUT;
- smtp_reply(s, "500 Line too long");
+ smtp_reply(s, "500 %s: Line too long",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_OTHER_STATUS));
smtp_enter_state(s, STATE_QUIT);
io_set_write(io);
return;
@@ -858,7 +874,9 @@ smtp_io(struct io *io, int evt)
/* Pipelining not supported */
if (iobuf_len(&s->iobuf)) {
s->flags |= SF_BADINPUT;
- smtp_reply(s, "500 Pipelining not supported");
+ smtp_reply(s, "500 %s %s: Pipelining not supported",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+ esc_description(ESC_INVALID_COMMAND));
smtp_enter_state(s, STATE_QUIT);
io_set_write(io);
return;
@@ -933,8 +951,8 @@ smtp_io(struct io *io, int evt)
static void
smtp_command(struct smtp_session *s, char *line)
{
- char *args, *eom, *method;
- int cmd, i;
+ char *args, *eom, *method;
+ int cmd, i;
log_trace(TRACE_SMTP, "smtp: %p: <<< %s", s, line);
@@ -988,18 +1006,25 @@ smtp_command(struct smtp_session *s, char *line)
case CMD_HELO:
case CMD_EHLO:
if (s->phase != PHASE_INIT) {
- smtp_reply(s, "503 Already indentified");
+ smtp_reply(s, "503 %s %s: Already indentified",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+ esc_description(ESC_INVALID_COMMAND));
break;
}
if (args == NULL) {
- smtp_reply(s, "501 %s requires domain name",
+ smtp_reply(s, "501 %s %s: %s requires domain name",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+ esc_description(ESC_INVALID_COMMAND),
(cmd == CMD_HELO) ? "HELO" : "EHLO");
+
break;
}
if (!valid_domainpart(args)) {
- smtp_reply(s, "501 Invalid domain name");
+ smtp_reply(s, "501 %s %s: Invalid domain name",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
+ esc_description(ESC_INVALID_COMMAND_ARGUMENTS));
break;
}
strlcpy(s->helo, args, sizeof(s->helo));
@@ -1023,45 +1048,62 @@ smtp_command(struct smtp_session *s, char *line)
*/
case CMD_STARTTLS:
if (s->phase != PHASE_SETUP) {
- smtp_reply(s, "503 Command not allowed at this point.");
+ smtp_reply(s, "503 %s %s: Command not allowed at this point.",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+ esc_description(ESC_INVALID_COMMAND));
break;
}
if (!(s->listener->flags & F_STARTTLS)) {
- smtp_reply(s, "503 Command not supported");
+ smtp_reply(s, "503 %s %s: Command not supported",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+ esc_description(ESC_INVALID_COMMAND));
break;
}
if (s->flags & SF_SECURE) {
- smtp_reply(s, "503 Channel already secured");
+ smtp_reply(s, "503 %s %s: Channel already secured",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+ esc_description(ESC_INVALID_COMMAND));
break;
}
if (args != NULL) {
- smtp_reply(s, "501 No parameters allowed");
+ smtp_reply(s, "501 %s %s: No parameters allowed",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
+ esc_description(ESC_INVALID_COMMAND_ARGUMENTS));
break;
}
- smtp_reply(s, "220 Ready to start TLS");
+ smtp_reply(s, "220 %s: Ready to start TLS",
+ esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
smtp_enter_state(s, STATE_TLS);
break;
case CMD_AUTH:
if (s->phase != PHASE_SETUP) {
- smtp_reply(s, "503 Command not allowed at this point.");
+ smtp_reply(s, "503 %s %s: Command not allowed at this point.",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+ esc_description(ESC_INVALID_COMMAND));
break;
}
if (s->flags & SF_AUTHENTICATED) {
- smtp_reply(s, "503 Already authenticated");
+ smtp_reply(s, "503 %s %s: Already authenticated",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+ esc_description(ESC_INVALID_COMMAND));
break;
}
if (!ADVERTISE_AUTH(s)) {
- smtp_reply(s, "503 Command not supported");
+ smtp_reply(s, "503 %s %s: Command not supported",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+ esc_description(ESC_INVALID_COMMAND));
break;
}
if (args == NULL) {
- smtp_reply(s, "501 No parameters given");
+ smtp_reply(s, "501 %s %s: No parameters given",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
+ esc_description(ESC_INVALID_COMMAND_ARGUMENTS));
break;
}
@@ -1076,40 +1118,53 @@ smtp_command(struct smtp_session *s, char *line)
else if (strcasecmp(method, "LOGIN") == 0)
smtp_rfc4954_auth_login(s, eom);
else
- smtp_reply(s, "504 AUTH method \"%s\" not supported",
+ smtp_reply(s, "504 %s %s: AUTH method \"%s\" not supported",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_SECURITY_FEATURES_NOT_SUPPORTED),
+ esc_description(ESC_SECURITY_FEATURES_NOT_SUPPORTED),
method);
break;
case CMD_MAIL_FROM:
if (s->phase != PHASE_SETUP) {
- smtp_reply(s, "503 Command not allowed at this point.");
+ smtp_reply(s, "503 %s %s: Command not allowed at this point.",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+ esc_description(ESC_INVALID_COMMAND));
+
break;
}
if (s->listener->flags & F_STARTTLS_REQUIRE &&
!(s->flags & SF_SECURE)) {
smtp_reply(s,
- "530 Must issue a STARTTLS command first");
+ "530 %s %s: Must issue a STARTTLS command first",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+ esc_description(ESC_INVALID_COMMAND));
break;
}
if (s->listener->flags & F_AUTH_REQUIRE &&
!(s->flags & SF_AUTHENTICATED)) {
smtp_reply(s,
- "530 Must issue an AUTH command first");
+ "530 %s %s: Must issue an AUTH command first",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+ esc_description(ESC_INVALID_COMMAND));
break;
}
if (s->mailcount >= SMTP_LIMIT_MAIL) {
- smtp_reply(s, "452 Too many messages sent");
+ /* we can pretend we had too many recipients */
+ smtp_reply(s, "452 %s %s: Too many messages sent",
+ esc_code(ESC_STATUS_TEMPFAIL, ESC_TOO_MANY_RECIPIENTS),
+ esc_description(ESC_TOO_MANY_RECIPIENTS));
break;
}
smtp_message_reset(s, 1);
if (smtp_mailaddr(&s->evp.sender, args, 1, &args,
- s->smtpname) == 0) {
- smtp_reply(s, "553 Sender address syntax error");
+ s->smtpname) == 0) {
+ smtp_reply(s, "553 %s: Sender address syntax error",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_OTHER_ADDRESS_STATUS));
break;
}
if (args && smtp_parse_mail_args(s, args) == -1)
@@ -1126,26 +1181,28 @@ smtp_command(struct smtp_session *s, char *line)
*/
case CMD_RCPT_TO:
if (s->phase != PHASE_TRANSACTION) {
- smtp_reply(s, "503 Command not allowed at this point.");
+ smtp_reply(s, "503 %s %s: Command not allowed at this point.",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+ esc_description(ESC_INVALID_COMMAND));
break;
}
if (s->rcptcount >= SMTP_LIMIT_RCPT) {
- smtp_reply(s, "452 Too many recipients");
+ smtp_reply(s, "451 %s %s: Too many recipients",
+ esc_code(ESC_STATUS_TEMPFAIL, ESC_TOO_MANY_RECIPIENTS),
+ esc_description(ESC_TOO_MANY_RECIPIENTS));
break;
}
if (smtp_mailaddr(&s->evp.rcpt, args, 0, &args,
s->smtpname) == 0) {
smtp_reply(s,
- "553 Recipient address syntax error");
+ "501 %s: Recipient address syntax error",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_BAD_DESTINATION_MAILBOX_ADDRESS_SYNTAX));
break;
}
- if (*args) {
- smtp_reply(s,
- "553 No option supported on RCPT TO");
+ if (args && smtp_parse_rcpt_args(s, args) == -1)
break;
- }
m_create(p_mfa, IMSG_MFA_REQ_RCPT, 0, 0, -1);
m_add_id(p_mfa, s->id);
@@ -1156,7 +1213,9 @@ smtp_command(struct smtp_session *s, char *line)
case CMD_RSET:
if (s->phase != PHASE_TRANSACTION && s->phase != PHASE_SETUP) {
- smtp_reply(s, "503 Command not allowed at this point.");
+ smtp_reply(s, "503 %s %s: Command not allowed at this point.",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+ esc_description(ESC_INVALID_COMMAND));
break;
}
@@ -1172,16 +1231,21 @@ smtp_command(struct smtp_session *s, char *line)
s->phase = PHASE_SETUP;
smtp_message_reset(s, 0);
- smtp_reply(s, "250 2.0.0 Reset state");
+ smtp_reply(s, "250 %s: Reset state",
+ esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
break;
case CMD_DATA:
if (s->phase != PHASE_TRANSACTION) {
- smtp_reply(s, "503 Command not allowed at this point.");
+ smtp_reply(s, "503 %s %s: Command not allowed at this point.",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+ esc_description(ESC_INVALID_COMMAND));
break;
}
if (s->rcptcount == 0) {
- smtp_reply(s, "503 5.5.1 No recipient specified");
+ smtp_reply(s, "503 %s %s: No recipient specified",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
+ esc_description(ESC_INVALID_COMMAND_ARGUMENTS));
break;
}
@@ -1194,12 +1258,14 @@ smtp_command(struct smtp_session *s, char *line)
* ANY
*/
case CMD_QUIT:
- smtp_reply(s, "221 Bye");
+ smtp_reply(s, "221 %s: Bye",
+ esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
smtp_enter_state(s, STATE_QUIT);
break;
case CMD_NOOP:
- smtp_reply(s, "250 Ok");
+ smtp_reply(s, "250 %s: Ok",
+ esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
break;
case CMD_HELP:
@@ -1207,11 +1273,20 @@ smtp_command(struct smtp_session *s, char *line)
smtp_reply(s, "214- To report bugs in the implementation, "
"please contact bugs@openbsd.org");
smtp_reply(s, "214- with full details");
- smtp_reply(s, "214 End of HELP info");
+ smtp_reply(s, "214 %s: End of HELP info",
+ esc_code(ESC_STATUS_OK, ESC_OTHER_STATUS));
+ break;
+
+ case CMD_WIZ:
+ smtp_reply(s, "500 %s %s: this feature is not supported yet ;-)",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+ esc_description(ESC_INVALID_COMMAND));
break;
default:
- smtp_reply(s, "500 Command unrecognized");
+ smtp_reply(s, "500 %s %s: Command unrecognized",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND),
+ esc_description(ESC_INVALID_COMMAND));
break;
}
}
@@ -1270,7 +1345,9 @@ smtp_rfc4954_auth_plain(struct smtp_session *s, char *arg)
}
abort:
- smtp_reply(s, "501 Syntax error");
+ smtp_reply(s, "501 %s %s: Syntax error",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_SYNTAX_ERROR),
+ esc_description(ESC_SYNTAX_ERROR));
smtp_enter_state(s, STATE_HELO);
}
@@ -1315,10 +1392,71 @@ smtp_rfc4954_auth_login(struct smtp_session *s, char *arg)
}
abort:
- smtp_reply(s, "501 Syntax error");
+ smtp_reply(s, "501 %s %s: Syntax error",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_SYNTAX_ERROR),
+ esc_description(ESC_SYNTAX_ERROR));
smtp_enter_state(s, STATE_HELO);
}
+static uint8_t
+dsn_notify_str_to_uint8(const char *arg)
+{
+ if (strcasecmp(arg, "SUCCESS") == 0)
+ return DSN_SUCCESS;
+ else if (strcasecmp(arg, "FAILURE") == 0)
+ return DSN_FAILURE;
+ else if (strcasecmp(arg, "DELAY") == 0)
+ return DSN_DELAY;
+ else if (strcasecmp(arg, "NEVER") == 0)
+ return DSN_NEVER;
+
+ return (0);
+}
+
+static int
+smtp_parse_rcpt_args(struct smtp_session *s, char *args)
+{
+ char *b, *p;
+ uint8_t flag;
+
+ while ((b = strsep(&args, " "))) {
+ if (*b == '\0')
+ continue;
+
+ if (strncasecmp(b, "NOTIFY=", 7) == 0) {
+ b += 7;
+ while ((p = strsep(&b, ","))) {
+ if (*p == '\0')
+ continue;
+
+ if ((flag = dsn_notify_str_to_uint8(p)) == 0)
+ continue;
+
+ s->evp.dsn_notify |= flag;
+ }
+ if (s->evp.dsn_notify & DSN_NEVER &&
+ s->evp.dsn_notify & (DSN_SUCCESS | DSN_FAILURE |
+ DSN_DELAY)) {
+ smtp_reply(s,
+ "553 NOTIFY option NEVER cannot be \
+ combined with other options");
+ return (-1);
+ }
+ } else if (strncasecmp(b, "ORCPT=", 6) == 0) {
+ b += 6;
+ if (!text_to_mailaddr(&s->evp.dsn_orcpt, b)) {
+ smtp_reply(s, "553 ORCPT address syntax error");
+ return (-1);
+ }
+ } else {
+ smtp_reply(s, "503 Unsupported option %s", b);
+ return (-1);
+ }
+ }
+
+ return (0);
+}
+
static int
smtp_parse_mail_args(struct smtp_session *s, char *args)
{
@@ -1332,13 +1470,24 @@ smtp_parse_mail_args(struct smtp_session *s, char *args)
log_debug("debug: smtp: AUTH in MAIL FROM command");
else if (strncasecmp(b, "SIZE=", 5) == 0)
log_debug("debug: smtp: SIZE in MAIL FROM command");
- else if (!strcasecmp(b, "BODY=7BIT"))
+ else if (strcasecmp(b, "BODY=7BIT") == 0)
/* XXX only for this transaction */
s->flags &= ~SF_8BITMIME;
else if (strcasecmp(b, "BODY=8BITMIME") == 0)
;
- else {
- smtp_reply(s, "503 Unsupported option %s", b);
+ else if (strncasecmp(b, "RET=", 4) == 0) {
+ b += 4;
+ if (strcasecmp(b, "HDRS") == 0)
+ s->evp.dsn_ret = DSN_RETHDRS;
+ else if (strcasecmp(b, "FULL") == 0)
+ s->evp.dsn_ret = DSN_RETFULL;
+ } else if (strncasecmp(b, "ENVID=", 6) == 0) {
+ b += 6;
+ strlcpy(s->evp.dsn_envid, b, sizeof(s->evp.dsn_envid));
+ } else {
+ smtp_reply(s, "503 %s %s: Unsupported option %s",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_INVALID_COMMAND_ARGUMENTS),
+ esc_description(ESC_INVALID_COMMAND_ARGUMENTS), b);
return (-1);
}
}
@@ -1459,7 +1608,9 @@ smtp_message_end(struct smtp_session *s)
m_add_msgid(p_queue, evpid_to_msgid(s->evp.id));
m_close(p_queue);
if (s->msgflags & MF_ERROR_SIZE)
- smtp_reply(s, "554 Message too big");
+ smtp_reply(s, "554 %s %s: Transaction failed, message too big",
+ esc_code(ESC_STATUS_PERMFAIL, ESC_MESSAGE_TOO_BIG_FOR_SYSTEM),
+ esc_description(ESC_MESSAGE_TOO_BIG_FOR_SYSTEM));
else
smtp_reply(s, "%d Message rejected", s->msgcode);
smtp_message_reset(s, 0);
@@ -1765,6 +1916,7 @@ smtp_sni_callback(SSL *ssl, int *ad, void *arg)
return SSL_TLSEXT_ERR_OK;
}
+
#define CASE(x) case x : return #x
const char *
diff --git a/usr.sbin/smtpd/smtpd-api.h b/usr.sbin/smtpd/smtpd-api.h
index 45984dd48bd..0570700cca8 100644
--- a/usr.sbin/smtpd/smtpd-api.h
+++ b/usr.sbin/smtpd/smtpd-api.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtpd-api.h,v 1.15 2014/02/04 14:56:03 eric Exp $ */
+/* $OpenBSD: smtpd-api.h,v 1.16 2014/02/04 15:44:06 eric Exp $ */
/*
* Copyright (c) 2013 Eric Faurot <eric@openbsd.org>
@@ -214,6 +214,79 @@ enum {
PROC_TABLE_FETCH,
};
+enum enhanced_status_code {
+ /* 0.0 */
+ ESC_OTHER_STATUS = 00,
+
+ /* 1.x */
+ ESC_OTHER_ADDRESS_STATUS = 10,
+ ESC_BAD_DESTINATION_MAILBOX_ADDRESS = 11,
+ ESC_BAD_DESTINATION_SYSTEM_ADDRESS = 12,
+ ESC_BAD_DESTINATION_MAILBOX_ADDRESS_SYNTAX = 13,
+ ESC_DESTINATION_MAILBOX_ADDRESS_AMBIGUOUS = 14,
+ ESC_DESTINATION_ADDRESS_VALID = 15,
+ ESC_DESTINATION_MAILBOX_HAS_MOVED = 16,
+ ESC_BAD_SENDER_MAILBOX_ADDRESS_SYNTAX = 17,
+ ESC_BAD_SENDER_SYSTEM_ADDRESS = 18,
+
+ /* 2.x */
+ ESC_OTHER_MAILBOX_STATUS = 20,
+ ESC_MAILBOX_DISABLED = 21,
+ ESC_MAILBOX_FULL = 22,
+ ESC_MESSAGE_LENGTH_TOO_LARGE = 23,
+ ESC_MAILING_LIST_EXPANSION_PROBLEM = 24,
+
+ /* 3.x */
+ ESC_OTHER_MAIL_SYSTEM_STATUS = 30,
+ ESC_MAIL_SYSTEM_FULL = 31,
+ ESC_SYSTEM_NOT_ACCEPTING_MESSAGES = 32,
+ ESC_SYSTEM_NOT_CAPABLE_OF_SELECTED_FEATURES = 33,
+ ESC_MESSAGE_TOO_BIG_FOR_SYSTEM = 34,
+ ESC_SYSTEM_INCORRECTLY_CONFIGURED = 35,
+
+ /* 4.x */
+ ESC_OTHER_NETWORK_ROUTING_STATUS = 40,
+ ESC_NO_ANSWER_FROM_HOST = 41,
+ ESC_BAD_CONNECTION = 42,
+ ESC_DIRECTORY_SERVER_FAILURE = 43,
+ ESC_UNABLE_TO_ROUTE = 44,
+ ESC_MAIL_SYSTEM_CONGESTION = 45,
+ ESC_ROUTING_LOOP_DETECTED = 46,
+ ESC_DELIVERY_TIME_EXPIRED = 47,
+
+ /* 5.x */
+ ESC_OTHER_PROTOCOL_STATUS = 50,
+ ESC_INVALID_COMMAND = 51,
+ ESC_SYNTAX_ERROR = 52,
+ ESC_TOO_MANY_RECIPIENTS = 53,
+ ESC_INVALID_COMMAND_ARGUMENTS = 54,
+ ESC_WRONG_PROTOCOL_VERSION = 55,
+
+ /* 6.x */
+ ESC_OTHER_MEDIA_ERROR = 60,
+ ESC_MEDIA_NOT_SUPPORTED = 61,
+ ESC_CONVERSION_REQUIRED_AND_PROHIBITED = 62,
+ ESC_CONVERSION_REQUIRED_BUT_NOT_SUPPORTED = 63,
+ ESC_CONVERSION_WITH_LOSS_PERFORMED = 64,
+ ESC_CONVERSION_FAILED = 65,
+
+ /* 7.x */
+ ESC_OTHER_SECURITY_STATUS = 70,
+ ESC_DELIVERY_NOT_AUTHORIZED_MESSAGE_REFUSED = 71,
+ ESC_MAILING_LIST_EXPANSION_PROHIBITED = 72,
+ ESC_SECURITY_CONVERSION_REQUIRED_NOT_POSSIBLE = 73,
+ ESC_SECURITY_FEATURES_NOT_SUPPORTED = 74,
+ ESC_CRYPTOGRAPHIC_FAILURE = 75,
+ ESC_CRYPTOGRAPHIC_ALGORITHM_NOT_SUPPORTED = 76,
+ ESC_MESSAGE_INTEGRITY_FAILURE = 77,
+};
+
+enum enhanced_status_class {
+ ESC_STATUS_OK = 2,
+ ESC_STATUS_TEMPFAIL = 4,
+ ESC_STATUS_PERMFAIL = 5,
+};
+
static inline uint32_t
evpid_to_msgid(uint64_t evpid)
{
@@ -243,6 +316,12 @@ int dict_iter(struct dict *, void **, const char **, void **);
int dict_iterfrom(struct dict *, void **, const char *, const char **, void **);
void dict_merge(struct dict *, struct dict *);
+
+/* esc.c */
+const char *esc_code(enum enhanced_status_class, enum enhanced_status_code);
+const char *esc_description(enum enhanced_status_code);
+
+
/* filter_api.c */
void filter_api_setugid(uid_t, gid_t);
void filter_api_set_chroot(const char *);
diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h
index 64a62588fc5..70f39a3ff41 100644
--- a/usr.sbin/smtpd/smtpd.h
+++ b/usr.sbin/smtpd/smtpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtpd.h,v 1.447 2014/02/04 15:22:39 eric Exp $ */
+/* $OpenBSD: smtpd.h,v 1.448 2014/02/04 15:44:06 eric Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
@@ -91,6 +91,8 @@
#define RELAY_LMTP 0x80
#define RELAY_TLS_VERIFY 0x200
+#define MTA_EXT_DSN 0x400
+
struct userinfo {
char username[SMTPD_MAXLOGNAME];
char directory[SMTPD_MAXPATHLEN];
@@ -386,12 +388,20 @@ struct delivery_mta {
enum bounce_type {
B_ERROR,
B_WARNING,
+ B_DSN
+};
+
+enum dsn_ret {
+ DSN_RETFULL = 1,
+ DSN_RETHDRS
};
struct delivery_bounce {
enum bounce_type type;
time_t delay;
time_t expire;
+ enum dsn_ret dsn_ret;
+ int mta_without_dsn;
};
enum expand_type {
@@ -435,6 +445,13 @@ struct expand {
struct expandnode *parent;
};
+#define DSN_SUCCESS 0x01
+#define DSN_FAILURE 0x02
+#define DSN_DELAY 0x04
+#define DSN_NEVER 0x08
+
+#define DSN_ENVID_LEN 100
+
#define SMTPD_ENVELOPE_VERSION 2
struct envelope {
TAILQ_ENTRY(envelope) entry;
@@ -468,6 +485,14 @@ struct envelope {
time_t lasttry;
time_t nexttry;
time_t lastbounce;
+
+ struct mailaddr dsn_orcpt;
+ char dsn_envid[DSN_ENVID_LEN+1];
+ uint8_t dsn_notify;
+ enum dsn_ret dsn_ret;
+
+ uint8_t esc_class;
+ uint8_t esc_code;
};
struct listener {
@@ -769,6 +794,13 @@ struct mta_envelope {
char *rcpt;
struct mta_task *task;
int delivery;
+
+ int ext;
+ char *dsn_orcpt;
+ char dsn_envid[DSN_ENVID_LEN+1];
+ uint8_t dsn_notify;
+ enum dsn_ret dsn_ret;
+
char status[SMTPD_MAXLINESIZE];
};
@@ -1082,6 +1114,8 @@ int enqueue(int, char **);
/* envelope.c */
void envelope_set_errormsg(struct envelope *, char *, ...);
+void envelope_set_esc_class(struct envelope *, enum enhanced_status_class);
+void envelope_set_esc_code(struct envelope *, enum enhanced_status_code);
int envelope_load_buffer(struct envelope *, const char *, size_t);
int envelope_dump_buffer(const struct envelope *, char *, size_t);
@@ -1214,8 +1248,8 @@ int cmdline_symset(char *);
/* queue.c */
pid_t queue(void);
void queue_ok(uint64_t);
-void queue_tempfail(uint64_t, const char *);
-void queue_permfail(uint64_t, const char *);
+void queue_tempfail(uint64_t, const char *, enum enhanced_status_code);
+void queue_permfail(uint64_t, const char *, enum enhanced_status_code);
void queue_loop(uint64_t);
void queue_flow_control(void);
diff --git a/usr.sbin/smtpd/smtpd/Makefile b/usr.sbin/smtpd/smtpd/Makefile
index 0336f176b67..34820ea4098 100644
--- a/usr.sbin/smtpd/smtpd/Makefile
+++ b/usr.sbin/smtpd/smtpd/Makefile
@@ -1,11 +1,11 @@
-# $OpenBSD: Makefile,v 1.68 2014/01/18 05:54:51 martynas Exp $
+# $OpenBSD: Makefile,v 1.69 2014/02/04 15:44:06 eric Exp $
.PATH: ${.CURDIR}/..
PROG= smtpd
SRCS= aliases.c bounce.c ca.c compress_backend.c config.c \
- control.c crypto.c delivery.c dict.c dns.c envelope.c \
+ control.c crypto.c delivery.c dict.c dns.c envelope.c esc.c \
expand.c forward.c iobuf.c ioev.c limit.c lka.c lka_session.c \
log.c mda.c mfa.c mfa_session.c mproc.c \
mta.c mta_session.c parse.y queue.c queue_backend.c \