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/* DIAGNOSTICS
79/*	Problems and transactions are logged to \fBsyslogd\fR(8).
80/* SEE ALSO
81/*	cleanup(8) cleanup service description.
82/*	cleanup_init(8) cleanup callable interface, initialization
83/* LICENSE
84/* .ad
85/* .fi
86/*	The Secure Mailer license must be distributed with this software.
87/* AUTHOR(S)
88/*	Wietse Venema
89/*	IBM T.J. Watson Research
90/*	P.O. Box 704
91/*	Yorktown Heights, NY 10598, USA
92/*--*/
93
94/* System library. */
95
96#include <sys_defs.h>
97#include <errno.h>
98
99/* Utility library. */
100
101#include <msg.h>
102#include <vstring.h>
103#include <mymalloc.h>
104
105/* Global library. */
106
107#include <cleanup_user.h>
108#include <mail_queue.h>
109#include <mail_proto.h>
110#include <bounce.h>
111#include <mail_params.h>
112#include <mail_stream.h>
113#include <mail_flow.h>
114#include <rec_type.h>
115
116/* Milter library. */
117
118#include <milter.h>
119
120/* Application-specific. */
121
122#include "cleanup.h"
123
124/* cleanup_open - open queue file and initialize */
125
126CLEANUP_STATE *cleanup_open(VSTREAM *src)
127{
128    CLEANUP_STATE *state;
129    static const char *log_queues[] = {
130	MAIL_QUEUE_DEFER,
131	MAIL_QUEUE_BOUNCE,
132	MAIL_QUEUE_TRACE,
133	0,
134    };
135    const char **cpp;
136
137    /*
138     * Initialize private state.
139     */
140    state = cleanup_state_alloc(src);
141
142    /*
143     * Open the queue file. Save the queue file name in a global variable, so
144     * that the runtime error handler can clean up in case of problems.
145     *
146     * XXX For now, a lot of detail is frozen that could be more useful if it
147     * were made configurable.
148     */
149    state->queue_name = mystrdup(MAIL_QUEUE_INCOMING);
150    state->handle = mail_stream_file(state->queue_name,
151				   MAIL_CLASS_PUBLIC, var_queue_service, 0);
152    state->dst = state->handle->stream;
153    cleanup_path = mystrdup(VSTREAM_PATH(state->dst));
154    state->queue_id = mystrdup(state->handle->id);
155    if (msg_verbose)
156	msg_info("cleanup_open: open %s", cleanup_path);
157
158    /*
159     * If there is a time to get rid of spurious log files, this is it. The
160     * down side is that this costs performance for every message, while the
161     * probability of spurious log files is quite low.
162     *
163     * XXX The defer logfile is deleted when the message is moved into the
164     * active queue. We must also remove it now, otherwise mailq produces
165     * nonsense.
166     */
167    for (cpp = log_queues; *cpp; cpp++) {
168	if (mail_queue_remove(*cpp, state->queue_id) == 0)
169	    msg_warn("%s: removed spurious %s log", *cpp, state->queue_id);
170	else if (errno != ENOENT)
171	    msg_fatal("%s: remove %s log: %m", *cpp, state->queue_id);
172    }
173    return (state);
174}
175
176/* cleanup_control - process client options */
177
178void    cleanup_control(CLEANUP_STATE *state, int flags)
179{
180
181    /*
182     * If the client requests us to do the bouncing in case of problems,
183     * throw away the input only in case of real show-stopper errors, such as
184     * unrecognizable data (which should never happen) or insufficient space
185     * for the queue file (which will happen occasionally). Otherwise,
186     * discard input after any lethal error. See the CLEANUP_OUT_OK() macro
187     * definition.
188     */
189    if (msg_verbose)
190	msg_info("cleanup flags = %s", cleanup_strflags(flags));
191    if ((state->flags = flags) & CLEANUP_FLAG_BOUNCE) {
192	state->err_mask = CLEANUP_STAT_MASK_INCOMPLETE;
193    } else {
194	state->err_mask = ~0;
195    }
196}
197
198/* cleanup_flush - finish queue file */
199
200int     cleanup_flush(CLEANUP_STATE *state)
201{
202    int     status;
203    char   *junk;
204    VSTRING *trace_junk;
205
206    /*
207     * Raise these errors only if we examined all queue file records.
208     */
209    if (CLEANUP_OUT_OK(state)) {
210	if (state->recip == 0)
211	    state->errs |= CLEANUP_STAT_RCPT;
212	if ((state->flags & CLEANUP_FLAG_END_SEEN) == 0)
213	    state->errs |= CLEANUP_STAT_BAD;
214    }
215
216    /*
217     * Status sanitization. Always report success when the discard flag was
218     * raised by some user-specified access rule.
219     */
220    if (state->flags & CLEANUP_FLAG_DISCARD)
221	state->errs = 0;
222
223    /*
224     * Apply external mail filter.
225     *
226     * XXX Include test for a built-in action to tempfail this message.
227     */
228    if (CLEANUP_MILTER_OK(state)) {
229	if (state->milters)
230	    cleanup_milter_inspect(state, state->milters);
231	else if (cleanup_milters) {
232	    cleanup_milter_emul_data(state, cleanup_milters);
233	    if (CLEANUP_MILTER_OK(state))
234		cleanup_milter_inspect(state, cleanup_milters);
235	}
236    }
237
238    /*
239     * Update the preliminary message size and count fields with the actual
240     * values.
241     */
242    if (CLEANUP_OUT_OK(state))
243	cleanup_final(state);
244
245    /*
246     * If there was an error that requires us to generate a bounce message
247     * (mail submitted with the Postfix sendmail command, mail forwarded by
248     * the local(8) delivery agent, or mail re-queued with "postsuper -r"),
249     * send a bounce notification, reset the error flags in case of success,
250     * and request deletion of the the incoming queue file and of the
251     * optional DSN SUCCESS records from virtual alias expansion.
252     *
253     * XXX It would make no sense to knowingly report success after we already
254     * have bounced all recipients, especially because the information in the
255     * DSN SUCCESS notice is completely redundant compared to the information
256     * in the bounce notice (however, both may be incomplete when the queue
257     * file size would exceed the safety limit).
258     *
259     * An alternative is to keep the DSN SUCCESS records and to delegate bounce
260     * notification to the queue manager, just like we already delegate
261     * success notification. This requires that we leave the undeliverable
262     * message in the incoming queue; versions up to 20050726 did exactly
263     * that. Unfortunately, this broke with over-size queue files, because
264     * the queue manager cannot handle incomplete queue files (and it should
265     * not try to do so).
266     */
267#define CAN_BOUNCE() \
268	((state->errs & CLEANUP_STAT_MASK_CANT_BOUNCE) == 0 \
269	    && state->sender != 0 \
270	    && (state->flags & CLEANUP_FLAG_BOUNCE) != 0)
271
272    if (state->errs != 0 && CAN_BOUNCE())
273	cleanup_bounce(state);
274
275    /*
276     * Optionally, place the message on hold, but only if the message was
277     * received successfully and only if it's not being discarded for other
278     * reasons. This involves renaming the queue file before "finishing" it
279     * (or else the queue manager would grab it too early) and updating our
280     * own idea of the queue file name for error recovery and for error
281     * reporting purposes.
282     *
283     * XXX Include test for a built-in action to tempfail this message.
284     */
285    if (state->errs == 0 && (state->flags & CLEANUP_FLAG_DISCARD) == 0) {
286	if ((state->flags & CLEANUP_FLAG_HOLD) != 0
287#ifdef DELAY_ACTION
288	    || state->defer_delay > 0
289#endif
290	    ) {
291	    myfree(state->queue_name);
292#ifdef DELAY_ACTION
293	    state->queue_name = mystrdup((state->flags & CLEANUP_FLAG_HOLD) ?
294				     MAIL_QUEUE_HOLD : MAIL_QUEUE_DEFERRED);
295#else
296	    state->queue_name = mystrdup(MAIL_QUEUE_HOLD);
297#endif
298	    mail_stream_ctl(state->handle,
299			    MAIL_STREAM_CTL_QUEUE, state->queue_name,
300			    MAIL_STREAM_CTL_CLASS, (char *) 0,
301			    MAIL_STREAM_CTL_SERVICE, (char *) 0,
302#ifdef DELAY_ACTION
303			    MAIL_STREAM_CTL_DELAY, state->defer_delay,
304#endif
305			    MAIL_STREAM_CTL_END);
306	    junk = cleanup_path;
307	    cleanup_path = mystrdup(VSTREAM_PATH(state->handle->stream));
308	    myfree(junk);
309
310	    /*
311	     * XXX: When delivering to a non-incoming queue, do not consume
312	     * in_flow tokens. Unfortunately we can't move the code that
313	     * consumes tokens until after the mail is received, because that
314	     * would increase the risk of duplicate deliveries (RFC 1047).
315	     */
316	    (void) mail_flow_put(1);
317	}
318	state->errs = mail_stream_finish(state->handle, (VSTRING *) 0);
319    } else {
320
321	/*
322	 * XXX: When discarding mail, should we consume in_flow tokens? See
323	 * also the comments above for mail that is placed on hold.
324	 */
325#if 0
326	(void) mail_flow_put(1);
327#endif
328	mail_stream_cleanup(state->handle);
329    }
330    state->handle = 0;
331    state->dst = 0;
332
333    /*
334     * If there was an error, or if the message must be discarded for other
335     * reasons, remove the queue file and the optional trace file with DSN
336     * SUCCESS records from virtual alias expansion.
337     */
338    if (state->errs != 0 || (state->flags & CLEANUP_FLAG_DISCARD) != 0) {
339	if (cleanup_trace_path)
340	    (void) REMOVE(vstring_str(cleanup_trace_path));
341	if (REMOVE(cleanup_path))
342	    msg_warn("remove %s: %m", cleanup_path);
343    }
344
345    /*
346     * Make sure that our queue file will not be deleted by the error handler
347     * AFTER we have taken responsibility for delivery. Better to deliver
348     * twice than to lose mail.
349     */
350    trace_junk = cleanup_trace_path;
351    cleanup_trace_path = 0;			/* don't delete upon error */
352    junk = cleanup_path;
353    cleanup_path = 0;				/* don't delete upon error */
354
355    if (trace_junk)
356	vstring_free(trace_junk);
357    myfree(junk);
358
359    /*
360     * Cleanup internal state. This is simply complementary to the
361     * initializations at the beginning of cleanup_open().
362     */
363    if (msg_verbose)
364	msg_info("cleanup_flush: status %d", state->errs);
365    status = state->errs;
366    return (status);
367}
368
369/* cleanup_free - pay the last respects */
370
371void    cleanup_free(CLEANUP_STATE *state)
372{
373
374    /*
375     * Emulate disconnect event. CLEANUP_FLAG_MILTER may be turned off after
376     * we have started.
377     */
378    if (cleanup_milters != 0 && state->milters == 0)
379	milter_disc_event(cleanup_milters);
380    cleanup_state_free(state);
381}
382