1/*++ 2/* NAME 3/* smtpd_dsn_fix 3 4/* SUMMARY 5/* fix DSN status 6/* SYNOPSIS 7/* #include <smtpd_dsn_fix.h> 8/* 9/* const char *smtpd_dsn_fix(status, reply_class) 10/* const char *status; 11/* const char *reply_class; 12/* DESCRIPTION 13/* smtpd_dsn_fix() transforms DSN status codes according to the 14/* status information that is actually being reported. The 15/* following transformations are implemented: 16/* .IP \(bu 17/* Transform a recipient address DSN into a sender address DSN 18/* when reporting sender address status information, and vice 19/* versa. This transformation may be needed because some Postfix 20/* access control features don't know whether the address being 21/* rejected is a sender or recipient. Examples are smtpd access 22/* tables, rbl reply templates, and the error mailer. 23/* .IP \(bu 24/* Transform a sender or recipient address DSN into a non-address 25/* DSN when reporting non-address status information. For 26/* example, if something rejects HELO with DSN status 4.1.1 27/* (unknown recipient address), then we send the more neutral 28/* 4.0.0 DSN instead. This transformation is needed when the 29/* same smtpd access map entry or rbl reply template is used 30/* for both address and non-address information. 31/* .PP 32/* A non-address DSN is not transformed 33/* when reporting sender or recipient address status information, 34/* as there are many legitimate instances of such usage. 35/* 36/* It is left up to the caller to update the initial DSN digit 37/* appropriately; in Postfix this is done as late as possible, 38/* because hard rejects may be changed into soft rejects for 39/* all kinds of reasons. 40/* 41/* Arguments: 42/* .IP status 43/* A DSN status as per RFC 3463. 44/* .IP reply_class 45/* SMTPD_NAME_SENDER, SMTPD_NAME_RECIPIENT or some other 46/* null-terminated string. 47/* LICENSE 48/* .ad 49/* .fi 50/* The Secure Mailer license must be distributed with this software. 51/* AUTHOR(S) 52/* Wietse Venema 53/* IBM T.J. Watson Research 54/* P.O. Box 704 55/* Yorktown Heights, NY 10598, USA 56/*--*/ 57/* System library. */ 58 59#include <sys_defs.h> 60#include <ctype.h> 61#include <string.h> 62 63/* Utility library. */ 64 65#include <msg.h> 66 67/* Global library. */ 68 69/* Application-specific. */ 70 71#include <smtpd_dsn_fix.h> 72 73struct dsn_map { 74 const char *micro_code; /* Final digits in mailbox D.S.N. */ 75 const char *sender_dsn; /* Replacement sender D.S.N. */ 76 const char *rcpt_dsn; /* Replacement recipient D.S.N. */ 77}; 78 79static struct dsn_map dsn_map[] = { 80 /* - Sender - Recipient */ 81 "1", SND_DSN, "4.1.1", /* 4.1.1: Bad dest mbox addr */ 82 "2", "4.1.8", "4.1.2", /* 4.1.2: Bad dest system addr */ 83 "3", "4.1.7", "4.1.3", /* 4.1.3: Bad dest mbox addr syntax */ 84 "4", SND_DSN, "4.1.4", /* 4.1.4: Dest mbox addr ambiguous */ 85 "5", "4.1.0", "4.1.5", /* 4.1.5: Dest mbox addr valid */ 86 "6", SND_DSN, "4.1.6", /* 4.1.6: Mailbox has moved */ 87 "7", "4.1.7", "4.1.3", /* 4.1.7: Bad sender mbox addr syntax */ 88 "8", "4.1.8", "4.1.2", /* 4.1.8: Bad sender system addr */ 89 0, "4.1.0", "4.1.0", /* Default mapping */ 90}; 91 92/* smtpd_dsn_fix - fix DSN status */ 93 94const char *smtpd_dsn_fix(const char *status, const char *reply_class) 95{ 96 struct dsn_map *dp; 97 const char *result = status; 98 99 /* 100 * Update an address-specific DSN according to what is being rejected. 101 */ 102 if (ISDIGIT(status[0]) && strncmp(status + 1, ".1.", 3) == 0) { 103 104 /* 105 * Fix recipient address DSN while rejecting a sender address. Don't 106 * let future recipient-specific DSN codes slip past us. 107 */ 108 if (strcmp(reply_class, SMTPD_NAME_SENDER) == 0) { 109 for (dp = dsn_map; dp->micro_code != 0; dp++) 110 if (strcmp(status + 4, dp->micro_code) == 0) 111 break; 112 result = dp->sender_dsn; 113 } 114 115 /* 116 * Fix sender address DSN while rejecting a recipient address. Don't 117 * let future sender-specific DSN codes slip past us. 118 */ 119 else if (strcmp(reply_class, SMTPD_NAME_RECIPIENT) == 0) { 120 for (dp = dsn_map; dp->micro_code != 0; dp++) 121 if (strcmp(status + 4, dp->micro_code) == 0) 122 break; 123 result = dp->rcpt_dsn; 124 } 125 126 /* 127 * Fix address-specific DSN while rejecting a non-address. 128 */ 129 else { 130 result = "4.0.0"; 131 } 132 133 /* 134 * Give them a clue of what is going on. 135 */ 136 if (strcmp(status + 2, result + 2) != 0) 137 msg_info("mapping DSN status %s into %s status %c%s", 138 status, reply_class, status[0], result + 1); 139 return (result); 140 } 141 142 /* 143 * Don't update a non-address DSN. There are many legitimate uses for 144 * these while rejecting address or non-address information. 145 */ 146 else { 147 return (status); 148 } 149} 150