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