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