summaryrefslogtreecommitdiffstats
path: root/src/smtpd/smtpd_dsn_fix.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/smtpd/smtpd_dsn_fix.c')
-rw-r--r--src/smtpd/smtpd_dsn_fix.c149
1 files changed, 149 insertions, 0 deletions
diff --git a/src/smtpd/smtpd_dsn_fix.c b/src/smtpd/smtpd_dsn_fix.c
new file mode 100644
index 0000000..d436967
--- /dev/null
+++ b/src/smtpd/smtpd_dsn_fix.c
@@ -0,0 +1,149 @@
+/*++
+/* NAME
+/* smtpd_dsn_fix 3
+/* SUMMARY
+/* fix DSN status
+/* SYNOPSIS
+/* #include <smtpd_dsn_fix.h>
+/*
+/* const char *smtpd_dsn_fix(status, reply_class)
+/* const char *status;
+/* const char *reply_class;
+/* DESCRIPTION
+/* smtpd_dsn_fix() transforms DSN status codes according to the
+/* status information that is actually being reported. The
+/* following transformations are implemented:
+/* .IP \(bu
+/* Transform a recipient address DSN into a sender address DSN
+/* when reporting sender address status information, and vice
+/* versa. This transformation may be needed because some Postfix
+/* access control features don't know whether the address being
+/* rejected is a sender or recipient. Examples are smtpd access
+/* tables, rbl reply templates, and the error mailer.
+/* .IP \(bu
+/* Transform a sender or recipient address DSN into a non-address
+/* DSN when reporting non-address status information. For
+/* example, if something rejects HELO with DSN status 4.1.1
+/* (unknown recipient address), then we send the more neutral
+/* 4.0.0 DSN instead. This transformation is needed when the
+/* same smtpd access map entry or rbl reply template is used
+/* for both address and non-address information.
+/* .PP
+/* A non-address DSN is not transformed
+/* when reporting sender or recipient address status information,
+/* as there are many legitimate instances of such usage.
+/*
+/* It is left up to the caller to update the initial DSN digit
+/* appropriately; in Postfix this is done as late as possible,
+/* because hard rejects may be changed into soft rejects for
+/* all kinds of reasons.
+/*
+/* Arguments:
+/* .IP status
+/* A DSN status as per RFC 3463.
+/* .IP reply_class
+/* SMTPD_NAME_SENDER, SMTPD_NAME_RECIPIENT or some other
+/* null-terminated string.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+/* System library. */
+
+#include <sys_defs.h>
+#include <ctype.h>
+#include <string.h>
+
+/* Utility library. */
+
+#include <msg.h>
+
+/* Global library. */
+
+/* Application-specific. */
+
+#include <smtpd_dsn_fix.h>
+
+struct dsn_map {
+ const char *micro_code; /* Final digits in mailbox D.S.N. */
+ const char *sender_dsn; /* Replacement sender D.S.N. */
+ const char *rcpt_dsn; /* Replacement recipient D.S.N. */
+};
+
+static struct dsn_map dsn_map[] = {
+ /* - Sender - Recipient */
+ "1", SND_DSN, "4.1.1", /* 4.1.1: Bad dest mbox addr */
+ "2", "4.1.8", "4.1.2", /* 4.1.2: Bad dest system addr */
+ "3", "4.1.7", "4.1.3", /* 4.1.3: Bad dest mbox addr syntax */
+ "4", SND_DSN, "4.1.4", /* 4.1.4: Dest mbox addr ambiguous */
+ "5", "4.1.0", "4.1.5", /* 4.1.5: Dest mbox addr valid */
+ "6", SND_DSN, "4.1.6", /* 4.1.6: Mailbox has moved */
+ "7", "4.1.7", "4.1.3", /* 4.1.7: Bad sender mbox addr syntax */
+ "8", "4.1.8", "4.1.2", /* 4.1.8: Bad sender system addr */
+ 0, "4.1.0", "4.1.0", /* Default mapping */
+};
+
+/* smtpd_dsn_fix - fix DSN status */
+
+const char *smtpd_dsn_fix(const char *status, const char *reply_class)
+{
+ struct dsn_map *dp;
+ const char *result = status;
+
+ /*
+ * Update an address-specific DSN according to what is being rejected.
+ */
+ if (ISDIGIT(status[0]) && strncmp(status + 1, ".1.", 3) == 0) {
+
+ /*
+ * Fix recipient address DSN while rejecting a sender address. Don't
+ * let future recipient-specific DSN codes slip past us.
+ */
+ if (strcmp(reply_class, SMTPD_NAME_SENDER) == 0) {
+ for (dp = dsn_map; dp->micro_code != 0; dp++)
+ if (strcmp(status + 4, dp->micro_code) == 0)
+ break;
+ result = dp->sender_dsn;
+ }
+
+ /*
+ * Fix sender address DSN while rejecting a recipient address. Don't
+ * let future sender-specific DSN codes slip past us.
+ */
+ else if (strcmp(reply_class, SMTPD_NAME_RECIPIENT) == 0) {
+ for (dp = dsn_map; dp->micro_code != 0; dp++)
+ if (strcmp(status + 4, dp->micro_code) == 0)
+ break;
+ result = dp->rcpt_dsn;
+ }
+
+ /*
+ * Fix address-specific DSN while rejecting a non-address.
+ */
+ else {
+ result = "4.0.0";
+ }
+
+ /*
+ * Give them a clue of what is going on.
+ */
+ if (strcmp(status + 2, result + 2) != 0)
+ msg_info("mapping DSN status %s into %s status %c%s",
+ status, reply_class, status[0], result + 1);
+ return (result);
+ }
+
+ /*
+ * Don't update a non-address DSN. There are many legitimate uses for
+ * these while rejecting address or non-address information.
+ */
+ else {
+ return (status);
+ }
+}