Postfix3.3.1
cleanup_api.c
[詳解]
1 /*++
2 /* NAME
3 /* cleanup_api 3
4 /* SUMMARY
5 /* cleanup callable interface, message processing
6 /* SYNOPSIS
7 /* #include "cleanup.h"
8 /*
9 /* CLEANUP_STATE *cleanup_open(src)
10 /* VSTREAM *src;
11 /*
12 /* void cleanup_control(state, flags)
13 /* CLEANUP_STATE *state;
14 /* int flags;
15 /*
16 /* void CLEANUP_RECORD(state, type, buf, len)
17 /* CLEANUP_STATE *state;
18 /* int type;
19 /* char *buf;
20 /* int len;
21 /*
22 /* int cleanup_flush(state)
23 /* CLEANUP_STATE *state;
24 /*
25 /* int cleanup_free(state)
26 /* CLEANUP_STATE *state;
27 /* DESCRIPTION
28 /* This module implements a callable interface to the cleanup service
29 /* for processing one message and for writing it to queue file.
30 /* For a description of the cleanup service, see cleanup(8).
31 /*
32 /* cleanup_open() creates a new queue file and performs other
33 /* per-message initialization. The result is a handle that should be
34 /* given to the cleanup_control(), cleanup_record(), cleanup_flush()
35 /* and cleanup_free() routines. The name of the queue file is in the
36 /* queue_id result structure member.
37 /*
38 /* cleanup_control() processes per-message flags specified by the caller.
39 /* These flags control the handling of data errors, and must be set
40 /* before processing the first message record.
41 /* .IP CLEANUP_FLAG_BOUNCE
42 /* The cleanup server is responsible for returning undeliverable
43 /* mail (too many hops, message too large) to the sender.
44 /* .IP CLEANUP_FLAG_BCC_OK
45 /* It is OK to add automatic BCC recipient addresses.
46 /* .IP CLEANUP_FLAG_FILTER
47 /* Enable header/body filtering. This should be enabled only with mail
48 /* that enters Postfix, not with locally forwarded mail or with bounce
49 /* messages.
50 /* .IP CLEANUP_FLAG_MILTER
51 /* Enable Milter applications. This should be enabled only with mail
52 /* that enters Postfix, not with locally forwarded mail or with bounce
53 /* messages.
54 /* .IP CLEANUP_FLAG_MAP_OK
55 /* Enable canonical and virtual mapping, and address masquerading.
56 /* .PP
57 /* For convenience the CLEANUP_FLAG_MASK_EXTERNAL macro specifies
58 /* the options that are normally needed for mail that enters
59 /* Postfix from outside, and CLEANUP_FLAG_MASK_INTERNAL specifies
60 /* the options that are normally needed for internally generated or
61 /* forwarded mail.
62 /*
63 /* CLEANUP_RECORD() is a macro that processes one message record,
64 /* that copies the result to the queue file, and that maintains a
65 /* little state machine. The last record in a valid message has type
66 /* REC_TYPE_END. In order to find out if a message is corrupted,
67 /* the caller is encouraged to test the CLEANUP_OUT_OK(state) macro.
68 /* The result is false when further message processing is futile.
69 /* In that case, it is safe to call cleanup_flush() immediately.
70 /*
71 /* cleanup_flush() closes a queue file. In case of any errors,
72 /* the file is removed. The result value is non-zero in case of
73 /* problems. In some cases a human-readable text can be found in
74 /* the state->reason member. In all other cases, use cleanup_strerror()
75 /* to translate the result into human-readable text.
76 /*
77 /* cleanup_free() destroys its argument.
78 /* .IP CLEANUP_FLAG_SMTPUTF8
79 /* Request SMTPUTF8 support when delivering mail.
80 /* .IP CLEANUP_FLAG_AUTOUTF8
81 /* Autodetection: request SMTPUTF8 support if the message
82 /* contains an UTF8 message header, sender, or recipient.
83 /* DIAGNOSTICS
84 /* Problems and transactions are logged to \fBsyslogd\fR(8).
85 /* SEE ALSO
86 /* cleanup(8) cleanup service description.
87 /* cleanup_init(8) cleanup callable interface, initialization
88 /* LICENSE
89 /* .ad
90 /* .fi
91 /* The Secure Mailer license must be distributed with this software.
92 /* AUTHOR(S)
93 /* Wietse Venema
94 /* IBM T.J. Watson Research
95 /* P.O. Box 704
96 /* Yorktown Heights, NY 10598, USA
97 /*--*/
98 
99 /* System library. */
100 
101 #include <sys_defs.h>
102 #include <errno.h>
103 
104 /* Utility library. */
105 
106 #include <msg.h>
107 #include <vstring.h>
108 #include <mymalloc.h>
109 
110 /* Global library. */
111 
112 #include <cleanup_user.h>
113 #include <mail_queue.h>
114 #include <mail_proto.h>
115 #include <bounce.h>
116 #include <mail_params.h>
117 #include <mail_stream.h>
118 #include <mail_flow.h>
119 #include <rec_type.h>
120 #include <smtputf8.h>
121 
122 /* Milter library. */
123 
124 #include <milter.h>
125 
126 /* Application-specific. */
127 
128 #include "cleanup.h"
129 
130 /* cleanup_open - open queue file and initialize */
131 
133 {
134  CLEANUP_STATE *state;
135  static const char *log_queues[] = {
139  0,
140  };
141  const char **cpp;
142 
143  /*
144  * Initialize private state.
145  */
146  state = cleanup_state_alloc(src);
147 
148  /*
149  * Open the queue file. Save the queue file name in a global variable, so
150  * that the runtime error handler can clean up in case of problems.
151  *
152  * XXX For now, a lot of detail is frozen that could be more useful if it
153  * were made configurable.
154  */
156  state->handle = mail_stream_file(state->queue_name,
158  state->dst = state->handle->stream;
160  state->queue_id = mystrdup(state->handle->id);
161  if (msg_verbose)
162  msg_info("cleanup_open: open %s", cleanup_path);
163 
164  /*
165  * If there is a time to get rid of spurious log files, this is it. The
166  * down side is that this costs performance for every message, while the
167  * probability of spurious log files is quite low.
168  *
169  * XXX The defer logfile is deleted when the message is moved into the
170  * active queue. We must also remove it now, otherwise mailq produces
171  * nonsense.
172  */
173  for (cpp = log_queues; *cpp; cpp++) {
174  if (mail_queue_remove(*cpp, state->queue_id) == 0)
175  msg_warn("%s: removed spurious %s log", *cpp, state->queue_id);
176  else if (errno != ENOENT)
177  msg_fatal("%s: remove %s log: %m", *cpp, state->queue_id);
178  }
179  return (state);
180 }
181 
182 /* cleanup_control - process client options */
183 
184 void cleanup_control(CLEANUP_STATE *state, int flags)
185 {
186 
187  /*
188  * If the client requests us to do the bouncing in case of problems,
189  * throw away the input only in case of real show-stopper errors, such as
190  * unrecognizable data (which should never happen) or insufficient space
191  * for the queue file (which will happen occasionally). Otherwise,
192  * discard input after any lethal error. See the CLEANUP_OUT_OK() macro
193  * definition.
194  */
195  if (msg_verbose)
196  msg_info("cleanup flags = %s", cleanup_strflags(flags));
197  if ((state->flags = flags) & CLEANUP_FLAG_BOUNCE) {
199  } else {
200  state->err_mask = ~0;
201  }
202  if (state->flags & CLEANUP_FLAG_SMTPUTF8)
204 }
205 
206 /* cleanup_flush - finish queue file */
207 
209 {
210  int status;
211  char *junk;
212  VSTRING *trace_junk;
213 
214  /*
215  * Raise these errors only if we examined all queue file records.
216  */
217  if (CLEANUP_OUT_OK(state)) {
218  if (state->recip == 0)
219  state->errs |= CLEANUP_STAT_RCPT;
220  if ((state->flags & CLEANUP_FLAG_END_SEEN) == 0)
221  state->errs |= CLEANUP_STAT_BAD;
222  }
223 
224  /*
225  * Status sanitization. Always report success when the discard flag was
226  * raised by some user-specified access rule.
227  */
228  if (state->flags & CLEANUP_FLAG_DISCARD)
229  state->errs = 0;
230 
231  /*
232  * Apply external mail filter.
233  *
234  * XXX Include test for a built-in action to tempfail this message.
235  */
236  if (CLEANUP_MILTER_OK(state)) {
237  if (state->milters)
238  cleanup_milter_inspect(state, state->milters);
239  else if (cleanup_milters) {
241  if (CLEANUP_MILTER_OK(state))
243  }
244  }
245 
246  /*
247  * Update the preliminary message size and count fields with the actual
248  * values.
249  */
250  if (CLEANUP_OUT_OK(state))
251  cleanup_final(state);
252 
253  /*
254  * If there was an error that requires us to generate a bounce message
255  * (mail submitted with the Postfix sendmail command, mail forwarded by
256  * the local(8) delivery agent, or mail re-queued with "postsuper -r"),
257  * send a bounce notification, reset the error flags in case of success,
258  * and request deletion of the the incoming queue file and of the
259  * optional DSN SUCCESS records from virtual alias expansion.
260  *
261  * XXX It would make no sense to knowingly report success after we already
262  * have bounced all recipients, especially because the information in the
263  * DSN SUCCESS notice is completely redundant compared to the information
264  * in the bounce notice (however, both may be incomplete when the queue
265  * file size would exceed the safety limit).
266  *
267  * An alternative is to keep the DSN SUCCESS records and to delegate bounce
268  * notification to the queue manager, just like we already delegate
269  * success notification. This requires that we leave the undeliverable
270  * message in the incoming queue; versions up to 20050726 did exactly
271  * that. Unfortunately, this broke with over-size queue files, because
272  * the queue manager cannot handle incomplete queue files (and it should
273  * not try to do so).
274  */
275 #define CAN_BOUNCE() \
276  ((state->errs & CLEANUP_STAT_MASK_CANT_BOUNCE) == 0 \
277  && state->sender != 0 \
278  && (state->flags & CLEANUP_FLAG_BOUNCE) != 0)
279 
280  if (state->errs != 0 && CAN_BOUNCE())
281  cleanup_bounce(state);
282 
283  /*
284  * Optionally, place the message on hold, but only if the message was
285  * received successfully and only if it's not being discarded for other
286  * reasons. This involves renaming the queue file before "finishing" it
287  * (or else the queue manager would grab it too early) and updating our
288  * own idea of the queue file name for error recovery and for error
289  * reporting purposes.
290  *
291  * XXX Include test for a built-in action to tempfail this message.
292  */
293  if (state->errs == 0 && (state->flags & CLEANUP_FLAG_DISCARD) == 0) {
294  if ((state->flags & CLEANUP_FLAG_HOLD) != 0
295 #ifdef DELAY_ACTION
296  || state->defer_delay > 0
297 #endif
298  ) {
299  myfree(state->queue_name);
300 #ifdef DELAY_ACTION
301  state->queue_name = mystrdup((state->flags & CLEANUP_FLAG_HOLD) ?
303 #else
305 #endif
306  mail_stream_ctl(state->handle,
308  CA_MAIL_STREAM_CTL_CLASS((char *) 0),
309  CA_MAIL_STREAM_CTL_SERVICE((char *) 0),
310 #ifdef DELAY_ACTION
311  CA_MAIL_STREAM_CTL_DELAY(state->defer_delay),
312 #endif
314  junk = cleanup_path;
316  myfree(junk);
317 
318  /*
319  * XXX: When delivering to a non-incoming queue, do not consume
320  * in_flow tokens. Unfortunately we can't move the code that
321  * consumes tokens until after the mail is received, because that
322  * would increase the risk of duplicate deliveries (RFC 1047).
323  */
324  (void) mail_flow_put(1);
325  }
326  state->errs = mail_stream_finish(state->handle, (VSTRING *) 0);
327  } else {
328 
329  /*
330  * XXX: When discarding mail, should we consume in_flow tokens? See
331  * also the comments above for mail that is placed on hold.
332  */
333 #if 0
334  (void) mail_flow_put(1);
335 #endif
336  mail_stream_cleanup(state->handle);
337  }
338  state->handle = 0;
339  state->dst = 0;
340 
341  /*
342  * If there was an error, or if the message must be discarded for other
343  * reasons, remove the queue file and the optional trace file with DSN
344  * SUCCESS records from virtual alias expansion.
345  */
346  if (state->errs != 0 || (state->flags & CLEANUP_FLAG_DISCARD) != 0) {
347  if (cleanup_trace_path)
349  if (REMOVE(cleanup_path))
350  msg_warn("remove %s: %m", cleanup_path);
351  }
352 
353  /*
354  * Make sure that our queue file will not be deleted by the error handler
355  * AFTER we have taken responsibility for delivery. Better to deliver
356  * twice than to lose mail.
357  */
358  trace_junk = cleanup_trace_path;
359  cleanup_trace_path = 0; /* don't delete upon error */
360  junk = cleanup_path;
361  cleanup_path = 0; /* don't delete upon error */
362 
363  if (trace_junk)
364  vstring_free(trace_junk);
365  myfree(junk);
366 
367  /*
368  * Cleanup internal state. This is simply complementary to the
369  * initializations at the beginning of cleanup_open().
370  */
371  if (msg_verbose)
372  msg_info("cleanup_flush: status %d", state->errs);
373  status = state->errs;
374  return (status);
375 }
376 
377 /* cleanup_free - pay the last respects */
378 
380 {
381 
382  /*
383  * Emulate disconnect event. CLEANUP_FLAG_MILTER may be turned off after
384  * we have started.
385  */
386  if (cleanup_milters != 0 && state->milters == 0)
388  cleanup_state_free(state);
389 }
#define CA_MAIL_STREAM_CTL_SERVICE(v)
Definition: mail_stream.h:63
int mail_stream_finish(MAIL_STREAM *info, VSTRING *why)
Definition: mail_stream.c:398
int msg_verbose
Definition: msg.c:177
void cleanup_milter_inspect(CLEANUP_STATE *, MILTERS *)
void myfree(void *ptr)
Definition: mymalloc.c:207
void mail_stream_ctl(MAIL_STREAM *info, int op,...)
Definition: mail_stream.c:515
char * id
Definition: mail_stream.h:37
int smtputf8
Definition: cleanup.h:134
#define MAIL_QUEUE_BOUNCE
Definition: mail_queue.h:35
MAIL_STREAM * mail_stream_file(const char *queue, const char *class, const char *service, int mode)
Definition: mail_stream.c:405
char * mystrdup(const char *str)
Definition: mymalloc.c:225
#define CLEANUP_FLAG_SMTPUTF8
Definition: cleanup_user.h:26
char * recip
Definition: cleanup.h:60
char * queue_name
Definition: cleanup.h:55
void mail_stream_cleanup(MAIL_STREAM *info)
Definition: mail_stream.c:151
VSTRING * cleanup_trace_path
Definition: cleanup_init.c:117
void cleanup_free(CLEANUP_STATE *state)
Definition: cleanup_api.c:379
#define vstring_str(vp)
Definition: vstring.h:71
#define CA_MAIL_STREAM_CTL_QUEUE(v)
Definition: mail_stream.h:61
int REMOVE(const char *path)
Definition: remove.c:52
void cleanup_state_free(CLEANUP_STATE *)
#define CLEANUP_FLAG_BOUNCE
Definition: cleanup_user.h:18
MILTERS * milters
Definition: cleanup.h:109
CLEANUP_STATE * cleanup_open(VSTREAM *src)
Definition: cleanup_api.c:132
#define CLEANUP_FLAG_DISCARD
Definition: cleanup_user.h:21
#define VSTREAM_PATH(vp)
Definition: vstream.h:126
#define CA_MAIL_STREAM_CTL_CLASS(v)
Definition: mail_stream.h:62
#define CLEANUP_MILTER_OK(s)
Definition: cleanup.h:327
char * cleanup_path
Definition: cleanup_init.c:111
#define MAIL_QUEUE_HOLD
Definition: mail_queue.h:29
#define CLEANUP_FLAG_HOLD
Definition: cleanup_user.h:20
int err_mask
Definition: cleanup.h:70
ssize_t mail_flow_put(ssize_t len)
Definition: mail_flow.c:105
void cleanup_control(CLEANUP_STATE *state, int flags)
Definition: cleanup_api.c:184
#define SMTPUTF8_FLAG_REQUESTED
Definition: smtputf8.h:97
#define CLEANUP_STAT_MASK_INCOMPLETE
Definition: cleanup_user.h:76
#define MAIL_CLASS_PUBLIC
Definition: mail_proto.h:95
#define MAIL_QUEUE_INCOMING
Definition: mail_queue.h:30
void msg_warn(const char *fmt,...)
Definition: msg.c:215
void milter_disc_event(MILTERS *milters)
Definition: milter.c:605
int cleanup_bounce(CLEANUP_STATE *)
void cleanup_final(CLEANUP_STATE *)
Definition: cleanup_final.c:45
CLEANUP_STATE * cleanup_state_alloc(VSTREAM *)
Definition: cleanup_state.c:65
char * queue_id
Definition: cleanup.h:56
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
VSTREAM * stream
Definition: mail_stream.h:35
VSTREAM * dst
Definition: cleanup.h:53
#define CLEANUP_STAT_BAD
Definition: cleanup_user.h:57
#define MAIL_QUEUE_DEFERRED
Definition: mail_queue.h:32
int mail_queue_remove(const char *queue_name, const char *queue_id)
Definition: mail_queue.c:274
#define CLEANUP_OUT_OK(s)
Definition: cleanup.h:239
#define CLEANUP_FLAG_END_SEEN
Definition: cleanup.h:142
#define MAIL_QUEUE_DEFER
Definition: mail_queue.h:34
#define CLEANUP_STAT_RCPT
Definition: cleanup_user.h:62
int cleanup_flush(CLEANUP_STATE *state)
Definition: cleanup_api.c:208
#define MAIL_QUEUE_TRACE
Definition: mail_queue.h:33
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
char * var_queue_service
Definition: mail_params.c:305
#define CAN_BOUNCE()
#define CA_MAIL_STREAM_CTL_END
Definition: mail_stream.h:60
MAIL_STREAM * handle
Definition: cleanup.h:54
const char * cleanup_strflags(unsigned flags)
void cleanup_milter_emul_data(CLEANUP_STATE *, MILTERS *)
MILTERS * cleanup_milters
Definition: cleanup_init.c:279
void msg_info(const char *fmt,...)
Definition: msg.c:199