xref: /netbsd-src/external/ibm-public/postfix/dist/src/smtpd/smtpd_dsn_fix.c (revision 41fbaed053f8fbfdf9d2a4ee0a7386a3c83f8505)
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 
smtpd_dsn_fix(const char * status,const char * reply_class)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