Postfix3.3.1
smtpd_dsn_fix.c
[詳解]
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 
73 struct 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 
79 static 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 
94 const 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 }
const char * smtpd_dsn_fix(const char *status, const char *reply_class)
Definition: smtpd_dsn_fix.c:94
#define ISDIGIT(c)
Definition: sys_defs.h:1748
#define SMTPD_NAME_SENDER
Definition: smtpd_dsn_fix.h:20
const char * micro_code
Definition: smtpd_dsn_fix.c:74
const char * rcpt_dsn
Definition: smtpd_dsn_fix.c:76
#define SND_DSN
Definition: smtpd_dsn_fix.h:31
#define SMTPD_NAME_RECIPIENT
Definition: smtpd_dsn_fix.h:21
void msg_info(const char *fmt,...)
Definition: msg.c:199
const char * sender_dsn
Definition: smtpd_dsn_fix.c:75