Postfix3.3.1
cleanup_out_recipient.c
[詳解]
1 /*++
2 /* NAME
3 /* cleanup_out_recipient 3
4 /* SUMMARY
5 /* envelope recipient output filter
6 /* SYNOPSIS
7 /* #include "cleanup.h"
8 /*
9 /* void cleanup_out_recipient(state, dsn_orig_recipient,
10 /* dsn_notify, orig_recipient,
11 /* recipient)
12 /* CLEANUP_STATE *state;
13 /* const char *dsn_orig_recipient;
14 /* const char *dsn_notify;
15 /* const char *orig_recipient;
16 /* const char *recipient;
17 /* DESCRIPTION
18 /* This module implements an envelope recipient output filter.
19 /*
20 /* cleanup_out_recipient() performs virtual table expansion
21 /* and recipient duplicate filtering, and appends the
22 /* resulting recipients to the output stream. It also
23 /* generates DSN SUCCESS notifications.
24 /*
25 /* Arguments:
26 /* .IP state
27 /* Cleanup server state.
28 /* .IP dsn_orig_recipient
29 /* DSN original recipient information.
30 /* .IP dsn_notify
31 /* DSN notify flags.
32 /* .IP orig_recipient
33 /* Envelope recipient as received by Postfix.
34 /* .IP recipient
35 /* Envelope recipient as rewritten by Postfix.
36 /* CONFIGURATION
37 /* .ad
38 /* .fi
39 /* .IP enable_original_recipient
40 /* Enable orig_recipient support.
41 /* .IP local_duplicate_filter_limit
42 /* Upper bound to the size of the recipient duplicate filter.
43 /* Zero means no limit; this may cause the mail system to
44 /* become stuck.
45 /* .IP virtual_alias_maps
46 /* list of virtual address lookup tables.
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 /* Wietse Venema
58 /* Google, Inc.
59 /* 111 8th Avenue
60 /* New York, NY 10011, USA
61 /*--*/
62 
63 /* System library. */
64 
65 #include <sys_defs.h>
66 #include <string.h>
67 
68 /* Utility library. */
69 
70 #include <argv.h>
71 #include <msg.h>
72 
73 /* Global library. */
74 
75 #include <been_here.h>
76 #include <mail_params.h>
77 #include <rec_type.h>
78 #include <ext_prop.h>
79 #include <cleanup_user.h>
80 #include <dsn_mask.h>
81 #include <recipient_list.h>
82 #include <dsn.h>
83 #include <trace.h>
84 #include <verify.h>
85 #include <mail_queue.h> /* cleanup_trace_path */
86 #include <mail_proto.h>
87 #include <msg_stats.h>
88 
89 /* Application-specific. */
90 
91 #include "cleanup.h"
92 
93 /* cleanup_trace_append - update trace logfile */
94 
95 static void cleanup_trace_append(CLEANUP_STATE *state, RECIPIENT *rcpt,
96  DSN *dsn)
97 {
98  MSG_STATS stats;
99 
100  if (cleanup_trace_path == 0) {
103  state->queue_id);
104  }
106  CLEANUP_MSG_STATS(&stats, state),
107  rcpt, "none", dsn) != 0) {
108  msg_warn("%s: trace logfile update error", state->queue_id);
109  state->errs |= CLEANUP_STAT_WRITE;
110  }
111 }
112 
113 /* cleanup_verify_append - update verify daemon */
114 
115 static void cleanup_verify_append(CLEANUP_STATE *state, RECIPIENT *rcpt,
116  DSN *dsn, int verify_status)
117 {
118  MSG_STATS stats;
119 
120  if (verify_append(state->queue_id, CLEANUP_MSG_STATS(&stats, state),
121  rcpt, "none", dsn, verify_status) != 0) {
122  msg_warn("%s: verify service update error", state->queue_id);
123  state->errs |= CLEANUP_STAT_WRITE;
124  }
125 }
126 
127 /* cleanup_out_recipient - envelope recipient output filter */
128 
130  const char *dsn_orcpt,
131  int dsn_notify,
132  const char *orcpt,
133  const char *recip)
134 {
135  ARGV *argv;
136  char **cpp;
137 
138  /*
139  * XXX Not elegant, but eliminates complexity in the record reading loop.
140  */
141  if (dsn_orcpt == 0)
142  dsn_orcpt = "";
143 
144  /*
145  * Distinguish between different original recipient addresses that map
146  * onto the same mailbox. The recipient will use our original recipient
147  * message header to figure things out.
148  *
149  * Postfix 2.2 compatibility: when ignoring differences in Postfix original
150  * recipient information, also ignore differences in DSN attributes. We
151  * do, however, keep the DSN attributes of the recipient that survives
152  * duplicate elimination.
153  */
154 #define STREQ(x, y) (strcmp((x), (y)) == 0)
155 
156  if ((state->flags & CLEANUP_FLAG_MAP_OK) == 0
157  || cleanup_virt_alias_maps == 0) {
158  if ((var_enable_orcpt ?
159  been_here(state->dups, "%s\n%d\n%s\n%s",
160  dsn_orcpt, dsn_notify, orcpt, recip) :
161  been_here_fixed(state->dups, recip)) == 0) {
162  if (dsn_notify)
163  cleanup_out_format(state, REC_TYPE_ATTR, "%s=%d",
164  MAIL_ATTR_DSN_NOTIFY, dsn_notify);
165  if (*dsn_orcpt)
166  cleanup_out_format(state, REC_TYPE_ATTR, "%s=%s",
167  MAIL_ATTR_DSN_ORCPT, dsn_orcpt);
168  cleanup_out_string(state, REC_TYPE_ORCP, orcpt);
169  cleanup_out_string(state, REC_TYPE_RCPT, recip);
170  state->rcpt_count++;
171  }
172  }
173 
174  /*
175  * XXX DSN. RFC 3461 gives us three options for multi-recipient aliases
176  * (we're treating single recipient aliases as a special case of
177  * multi-recipient aliases, one argument being that it is none of the
178  * sender's business).
179  *
180  * (a) Don't propagate ENVID, NOTIFY, RET, or ORCPT. If NOTIFY specified
181  * SUCCESS, send a "relayed" DSN.
182  *
183  * (b) Propagate ENVID, (NOTIFY minus SUCCESS), RET, and ORCPT. If NOTIFY
184  * specified SUCCESS, send an "expanded" DSN.
185  *
186  * (c) Propagate ENVID, NOTIFY, RET, and ORCPT to one recipient only. Send
187  * no DSN.
188  *
189  * In all three cases we are modifying at least one NOTIFY value. Either we
190  * have to record explicit dsn_notify records, or we must not allow the
191  * use of a per-message non-default NOTIFY value that applies to all
192  * recipient records.
193  *
194  * Alternatives (a) and (c) require that we store explicit per-recipient RET
195  * and ENVID records, at least for the recipients that are excluded from
196  * RET and ENVID propagation. This means storing explicit ENVID records
197  * to indicate that the information does not exist. All this makes
198  * alternative (b) more and more attractive. It is no surprise that we
199  * use (b) here and in the local delivery agent.
200  *
201  * In order to generate a SUCCESS notification from the cleanup server we
202  * have to write the trace logfile record now. We're NOT going to flush
203  * the trace file from the cleanup server; if we need to write bounce
204  * logfile records, and the bounce service fails, we must be able to
205  * cancel the entire cleanup request including any success or failure
206  * notifications. The queue manager will flush the trace (and bounce)
207  * logfile, possibly after it has generated its own success or failure
208  * notification records.
209  *
210  * Postfix 2.2 compatibility: when ignoring differences in Postfix original
211  * recipient information, also ignore differences in DSN attributes. We
212  * do, however, keep the DSN attributes of the recipient that survives
213  * duplicate elimination.
214  *
215  * In the case of a verify(8) request for a one-to-many alias, declare the
216  * alias address as "deliverable". Do not verify the individual addresses
217  * in the expansion because that results in multiple verify(8) updates
218  * for one verify(8) request.
219  *
220  * Multiple verify(8) updates for one verify(8) request would overwrite
221  * each other's status, and if the last status update is "undeliverable",
222  * then the whole alias is flagged as undeliverable.
223  */
224  else {
225  RECIPIENT rcpt;
226  DSN dsn;
227 
228  argv = cleanup_map1n_internal(state, recip, cleanup_virt_alias_maps,
230  if (argv->argc > 1 && (state->tflags & DEL_REQ_FLAG_MTA_VRFY)) {
231  (void) DSN_SIMPLE(&dsn, "2.0.0", "aliased to multiple recipients");
232  dsn.action = "deliverable";
233  RECIPIENT_ASSIGN(&rcpt, 0, dsn_orcpt, dsn_notify, orcpt, recip);
234  cleanup_verify_append(state, &rcpt, &dsn, DEL_RCPT_STAT_OK);
235  argv_free(argv);
236  return;
237  }
238  if ((dsn_notify & DSN_NOTIFY_SUCCESS)
239  && (argv->argc > 1 || strcmp(recip, argv->argv[0]) != 0)) {
240  (void) DSN_SIMPLE(&dsn, "2.0.0", "alias expanded");
241  dsn.action = "expanded";
242  RECIPIENT_ASSIGN(&rcpt, 0, dsn_orcpt, dsn_notify, orcpt, recip);
243  cleanup_trace_append(state, &rcpt, &dsn);
244  dsn_notify = (dsn_notify == DSN_NOTIFY_SUCCESS ? DSN_NOTIFY_NEVER :
245  dsn_notify & ~DSN_NOTIFY_SUCCESS);
246  }
247  for (cpp = argv->argv; *cpp; cpp++) {
248  if ((var_enable_orcpt ?
249  been_here(state->dups, "%s\n%d\n%s\n%s",
250  dsn_orcpt, dsn_notify, orcpt, *cpp) :
251  been_here_fixed(state->dups, *cpp)) == 0) {
252  if (dsn_notify)
253  cleanup_out_format(state, REC_TYPE_ATTR, "%s=%d",
254  MAIL_ATTR_DSN_NOTIFY, dsn_notify);
255  if (*dsn_orcpt)
256  cleanup_out_format(state, REC_TYPE_ATTR, "%s=%s",
257  MAIL_ATTR_DSN_ORCPT, dsn_orcpt);
258  cleanup_out_string(state, REC_TYPE_ORCP, orcpt);
259  cleanup_out_string(state, REC_TYPE_RCPT, *cpp);
260  state->rcpt_count++;
261  }
262  }
263  argv_free(argv);
264  }
265 }
#define MAIL_ATTR_DSN_NOTIFY
Definition: mail_proto.h:275
void cleanup_out_format(CLEANUP_STATE *state, int type, const char *fmt,...)
Definition: cleanup_out.c:155
VSTRING * cleanup_trace_path
Definition: cleanup_init.c:117
MAPS * cleanup_virt_alias_maps
Definition: cleanup_init.c:258
ARGV * argv_free(ARGV *argvp)
Definition: argv.c:136
#define DSN_SIMPLE(dsn, _status, _reason)
Definition: dsn.h:41
#define CLEANUP_FLAG_MAP_OK
Definition: cleanup_user.h:23
ARGV * cleanup_map1n_internal(CLEANUP_STATE *, const char *, MAPS *, int)
Definition: cleanup_map1n.c:77
Definition: argv.h:17
const char * action
Definition: dsn.h:19
int trace_append(int flags, const char *id, MSG_STATS *stats, RECIPIENT *rcpt, const char *relay, DSN *dsn)
Definition: trace.c:106
int tflags
Definition: cleanup.h:67
char ** argv
Definition: argv.h:20
#define DSN_NOTIFY_NEVER
Definition: dsn_mask.h:43
#define RECIPIENT_ASSIGN(rcpt, offs, orcpt, notify, orig, addr)
#define BOUNCE_FLAG_CLEAN
Definition: bounce.h:61
int cleanup_ext_prop_mask
Definition: cleanup_init.c:274
const char * mail_queue_path(VSTRING *buf, const char *queue_name, const char *queue_id)
Definition: mail_queue.c:204
#define MAIL_ATTR_DSN_ORCPT
Definition: mail_proto.h:276
int verify_append(const char *queue_id, MSG_STATS *stats, RECIPIENT *recipient, const char *relay, DSN *dsn, int vrfy_stat)
Definition: verify.c:92
int been_here(BH_TABLE *dup_filter, const char *fmt,...)
Definition: been_here.c:124
#define EXT_PROP_VIRTUAL
Definition: ext_prop.h:18
BH_TABLE * dups
Definition: cleanup.h:74
#define REC_TYPE_RCPT
Definition: rec_type.h:45
void msg_warn(const char *fmt,...)
Definition: msg.c:215
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
bool var_enable_orcpt
Definition: mail_params.c:349
char * queue_id
Definition: cleanup.h:56
void cleanup_out_recipient(CLEANUP_STATE *state, const char *dsn_orcpt, int dsn_notify, const char *orcpt, const char *recip)
#define CLEANUP_MSG_STATS(stats, state)
Definition: cleanup.h:315
#define DSN_NOTIFY_SUCCESS
Definition: dsn_mask.h:44
int been_here_fixed(BH_TABLE *dup_filter, const char *string)
Definition: been_here.c:151
Definition: dsn.h:17
#define MAIL_QUEUE_TRACE
Definition: mail_queue.h:33
#define REC_TYPE_ATTR
Definition: rec_type.h:49
ssize_t rcpt_count
Definition: cleanup.h:88
#define CLEANUP_STAT_WRITE
Definition: cleanup_user.h:58
ssize_t argc
Definition: argv.h:19
void cleanup_out_string(CLEANUP_STATE *, int, const char *)
Definition: cleanup_out.c:148
#define DEL_RCPT_STAT_OK
#define REC_TYPE_ORCP
Definition: rec_type.h:46
#define DEL_REQ_FLAG_MTA_VRFY