7 /* cleanup callable interface, message processing
9 /* #include "cleanup.h"
11 /* CLEANUP_STATE *cleanup_open(src)
14 /* void cleanup_control(state, flags)
15 /* CLEANUP_STATE *state;
18 /* void CLEANUP_RECORD(state, type, buf, len)
19 /* CLEANUP_STATE *state;
24 /* int cleanup_flush(state)
25 /* CLEANUP_STATE *state;
27 /* int cleanup_free(state)
28 /* CLEANUP_STATE *state;
30 /* This module implements a callable interface to the cleanup service
31 /* for processing one message and for writing it to queue file.
32 /* For a description of the cleanup service, see cleanup(8).
34 /* cleanup_open() creates a new queue file and performs other
35 /* per-message initialization. The result is a handle that should be
36 /* given to the cleanup_control(), cleanup_record(), cleanup_flush()
37 /* and cleanup_free() routines. The name of the queue file is in the
38 /* queue_id result structure member.
40 /* cleanup_control() processes per-message flags specified by the caller.
41 /* These flags control the handling of data errors, and must be set
42 /* before processing the first message record.
43 /* .IP CLEANUP_FLAG_BOUNCE
44 /* The cleanup server is responsible for returning undeliverable
45 /* mail (too many hops, message too large) to the sender.
46 /* .IP CLEANUP_FLAG_BCC_OK
47 /* It is OK to add automatic BCC recipient addresses.
48 /* .IP CLEANUP_FLAG_FILTER
49 /* Enable header/body filtering. This should be enabled only with mail
50 /* that enters Postfix, not with locally forwarded mail or with bounce
52 /* .IP CLEANUP_FLAG_MILTER
53 /* Enable Milter applications. This should be enabled only with mail
54 /* that enters Postfix, not with locally forwarded mail or with bounce
56 /* .IP CLEANUP_FLAG_MAP_OK
57 /* Enable canonical and virtual mapping, and address masquerading.
59 /* For convenience the CLEANUP_FLAG_MASK_EXTERNAL macro specifies
60 /* the options that are normally needed for mail that enters
61 /* Postfix from outside, and CLEANUP_FLAG_MASK_INTERNAL specifies
62 /* the options that are normally needed for internally generated or
65 /* CLEANUP_RECORD() is a macro that processes one message record,
66 /* that copies the result to the queue file, and that maintains a
67 /* little state machine. The last record in a valid message has type
68 /* REC_TYPE_END. In order to find out if a message is corrupted,
69 /* the caller is encouraged to test the CLEANUP_OUT_OK(state) macro.
70 /* The result is false when further message processing is futile.
71 /* In that case, it is safe to call cleanup_flush() immediately.
73 /* cleanup_flush() closes a queue file. In case of any errors,
74 /* the file is removed. The result value is non-zero in case of
75 /* problems. In some cases a human-readable text can be found in
76 /* the state->reason member. In all other cases, use cleanup_strerror()
77 /* to translate the result into human-readable text.
79 /* cleanup_free() destroys its argument.
81 /* Problems and transactions are logged to \fBsyslogd\fR(8).
83 /* cleanup(8) cleanup service description.
84 /* cleanup_init(8) cleanup callable interface, initialization
88 /* The Secure Mailer license must be distributed with this software.
91 /* IBM T.J. Watson Research
93 /* Yorktown Heights, NY 10598, USA
101 /* Utility library. */
105 #include <mymalloc.h>
107 /* Global library. */
109 #include <cleanup_user.h>
110 #include <mail_queue.h>
111 #include <mail_proto.h>
113 #include <mail_params.h>
114 #include <mail_stream.h>
115 #include <mail_flow.h>
116 #include <rec_type.h>
118 /* Milter library. */
122 /* Application-specific. */
126 /* cleanup_open - open queue file and initialize */
128 CLEANUP_STATE
*cleanup_open(VSTREAM
*src
)
130 CLEANUP_STATE
*state
;
131 static const char *log_queues
[] = {
140 * Initialize private state.
142 state
= cleanup_state_alloc(src
);
145 * Open the queue file. Save the queue file name in a global variable, so
146 * that the runtime error handler can clean up in case of problems.
148 * XXX For now, a lot of detail is frozen that could be more useful if it
149 * were made configurable.
151 state
->queue_name
= mystrdup(MAIL_QUEUE_INCOMING
);
152 state
->handle
= mail_stream_file(state
->queue_name
,
153 MAIL_CLASS_PUBLIC
, var_queue_service
, 0);
154 state
->dst
= state
->handle
->stream
;
155 cleanup_path
= mystrdup(VSTREAM_PATH(state
->dst
));
156 state
->queue_id
= mystrdup(state
->handle
->id
);
158 msg_info("cleanup_open: open %s", cleanup_path
);
161 * If there is a time to get rid of spurious log files, this is it. The
162 * down side is that this costs performance for every message, while the
163 * probability of spurious log files is quite low.
165 * XXX The defer logfile is deleted when the message is moved into the
166 * active queue. We must also remove it now, otherwise mailq produces
169 for (cpp
= log_queues
; *cpp
; cpp
++) {
170 if (mail_queue_remove(*cpp
, state
->queue_id
) == 0)
171 msg_warn("%s: removed spurious %s log", *cpp
, state
->queue_id
);
172 else if (errno
!= ENOENT
)
173 msg_fatal("%s: remove %s log: %m", *cpp
, state
->queue_id
);
178 /* cleanup_control - process client options */
180 void cleanup_control(CLEANUP_STATE
*state
, int flags
)
184 * If the client requests us to do the bouncing in case of problems,
185 * throw away the input only in case of real show-stopper errors, such as
186 * unrecognizable data (which should never happen) or insufficient space
187 * for the queue file (which will happen occasionally). Otherwise,
188 * discard input after any lethal error. See the CLEANUP_OUT_OK() macro
192 msg_info("cleanup flags = %s", cleanup_strflags(flags
));
193 if ((state
->flags
= flags
) & CLEANUP_FLAG_BOUNCE
) {
194 state
->err_mask
= CLEANUP_STAT_MASK_INCOMPLETE
;
196 state
->err_mask
= ~0;
200 /* cleanup_flush - finish queue file */
202 int cleanup_flush(CLEANUP_STATE
*state
)
209 * Raise these errors only if we examined all queue file records.
211 if (CLEANUP_OUT_OK(state
)) {
212 if (state
->recip
== 0)
213 state
->errs
|= CLEANUP_STAT_RCPT
;
214 if ((state
->flags
& CLEANUP_FLAG_END_SEEN
) == 0)
215 state
->errs
|= CLEANUP_STAT_BAD
;
219 * Status sanitization. Always report success when the discard flag was
220 * raised by some user-specified access rule.
222 if (state
->flags
& CLEANUP_FLAG_DISCARD
)
226 * Apply external mail filter.
228 * XXX Include test for a built-in action to tempfail this message.
230 if (CLEANUP_MILTER_OK(state
)) {
232 cleanup_milter_inspect(state
, state
->milters
);
233 else if (cleanup_milters
) {
234 cleanup_milter_emul_data(state
, cleanup_milters
);
235 if (CLEANUP_MILTER_OK(state
))
236 cleanup_milter_inspect(state
, cleanup_milters
);
241 * Update the preliminary message size and count fields with the actual
244 if (CLEANUP_OUT_OK(state
))
245 cleanup_final(state
);
248 * If there was an error that requires us to generate a bounce message
249 * (mail submitted with the Postfix sendmail command, mail forwarded by
250 * the local(8) delivery agent, or mail re-queued with "postsuper -r"),
251 * send a bounce notification, reset the error flags in case of success,
252 * and request deletion of the the incoming queue file and of the
253 * optional DSN SUCCESS records from virtual alias expansion.
255 * XXX It would make no sense to knowingly report success after we already
256 * have bounced all recipients, especially because the information in the
257 * DSN SUCCESS notice is completely redundant compared to the information
258 * in the bounce notice (however, both may be incomplete when the queue
259 * file size would exceed the safety limit).
261 * An alternative is to keep the DSN SUCCESS records and to delegate bounce
262 * notification to the queue manager, just like we already delegate
263 * success notification. This requires that we leave the undeliverable
264 * message in the incoming queue; versions up to 20050726 did exactly
265 * that. Unfortunately, this broke with over-size queue files, because
266 * the queue manager cannot handle incomplete queue files (and it should
269 #define CAN_BOUNCE() \
270 ((state->errs & CLEANUP_STAT_MASK_CANT_BOUNCE) == 0 \
271 && state->sender != 0 \
272 && (state->flags & CLEANUP_FLAG_BOUNCE) != 0)
274 if (state
->errs
!= 0 && CAN_BOUNCE())
275 cleanup_bounce(state
);
278 * Optionally, place the message on hold, but only if the message was
279 * received successfully and only if it's not being discarded for other
280 * reasons. This involves renaming the queue file before "finishing" it
281 * (or else the queue manager would grab it too early) and updating our
282 * own idea of the queue file name for error recovery and for error
283 * reporting purposes.
285 * XXX Include test for a built-in action to tempfail this message.
287 if (state
->errs
== 0 && (state
->flags
& CLEANUP_FLAG_DISCARD
) == 0) {
288 if ((state
->flags
& CLEANUP_FLAG_HOLD
) != 0
290 || state
->defer_delay
> 0
293 myfree(state
->queue_name
);
295 state
->queue_name
= mystrdup((state
->flags
& CLEANUP_FLAG_HOLD
) ?
296 MAIL_QUEUE_HOLD
: MAIL_QUEUE_DEFERRED
);
298 state
->queue_name
= mystrdup(MAIL_QUEUE_HOLD
);
300 mail_stream_ctl(state
->handle
,
301 MAIL_STREAM_CTL_QUEUE
, state
->queue_name
,
302 MAIL_STREAM_CTL_CLASS
, (char *) 0,
303 MAIL_STREAM_CTL_SERVICE
, (char *) 0,
305 MAIL_STREAM_CTL_DELAY
, state
->defer_delay
,
307 MAIL_STREAM_CTL_END
);
309 cleanup_path
= mystrdup(VSTREAM_PATH(state
->handle
->stream
));
313 * XXX: When delivering to a non-incoming queue, do not consume
314 * in_flow tokens. Unfortunately we can't move the code that
315 * consumes tokens until after the mail is received, because that
316 * would increase the risk of duplicate deliveries (RFC 1047).
318 (void) mail_flow_put(1);
320 state
->errs
= mail_stream_finish(state
->handle
, (VSTRING
*) 0);
324 * XXX: When discarding mail, should we consume in_flow tokens? See
325 * also the comments above for mail that is placed on hold.
328 (void) mail_flow_put(1);
330 mail_stream_cleanup(state
->handle
);
336 * If there was an error, or if the message must be discarded for other
337 * reasons, remove the queue file and the optional trace file with DSN
338 * SUCCESS records from virtual alias expansion.
340 if (state
->errs
!= 0 || (state
->flags
& CLEANUP_FLAG_DISCARD
) != 0) {
341 if (cleanup_trace_path
)
342 (void) REMOVE(vstring_str(cleanup_trace_path
));
343 if (REMOVE(cleanup_path
))
344 msg_warn("remove %s: %m", cleanup_path
);
348 * Make sure that our queue file will not be deleted by the error handler
349 * AFTER we have taken responsibility for delivery. Better to deliver
350 * twice than to lose mail.
352 trace_junk
= cleanup_trace_path
;
353 cleanup_trace_path
= 0; /* don't delete upon error */
355 cleanup_path
= 0; /* don't delete upon error */
358 vstring_free(trace_junk
);
362 * Cleanup internal state. This is simply complementary to the
363 * initializations at the beginning of cleanup_open().
366 msg_info("cleanup_flush: status %d", state
->errs
);
367 status
= state
->errs
;
371 /* cleanup_free - pay the last respects */
373 void cleanup_free(CLEANUP_STATE
*state
)
377 * Emulate disconnect event. CLEANUP_FLAG_MILTER may be turned off after
380 if (cleanup_milters
!= 0 && state
->milters
== 0)
381 milter_disc_event(cleanup_milters
);
382 cleanup_state_free(state
);