diff options
Diffstat (limited to 'src/smtpd/smtpd_dsn_fix.c')
-rw-r--r-- | src/smtpd/smtpd_dsn_fix.c | 149 |
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); + } +} |