1/* $NetBSD$ */ 2 3/*++ 4/* NAME 5/* cleanup_api 3 6/* SUMMARY 7/* cleanup callable interface, message processing 8/* SYNOPSIS 9/* #include "cleanup.h" 10/* 11/* CLEANUP_STATE *cleanup_open(src) 12/* VSTREAM *src; 13/* 14/* void cleanup_control(state, flags) 15/* CLEANUP_STATE *state; 16/* int flags; 17/* 18/* void CLEANUP_RECORD(state, type, buf, len) 19/* CLEANUP_STATE *state; 20/* int type; 21/* char *buf; 22/* int len; 23/* 24/* int cleanup_flush(state) 25/* CLEANUP_STATE *state; 26/* 27/* int cleanup_free(state) 28/* CLEANUP_STATE *state; 29/* DESCRIPTION 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). 33/* 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. 39/* 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 51/* messages. 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 55/* messages. 56/* .IP CLEANUP_FLAG_MAP_OK 57/* Enable canonical and virtual mapping, and address masquerading. 58/* .PP 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 63/* forwarded mail. 64/* 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. 72/* 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. 78/* 79/* cleanup_free() destroys its argument. 80/* DIAGNOSTICS 81/* Problems and transactions are logged to \fBsyslogd\fR(8). 82/* SEE ALSO 83/* cleanup(8) cleanup service description. 84/* cleanup_init(8) cleanup callable interface, initialization 85/* LICENSE 86/* .ad 87/* .fi 88/* The Secure Mailer license must be distributed with this software. 89/* AUTHOR(S) 90/* Wietse Venema 91/* IBM T.J. Watson Research 92/* P.O. Box 704 93/* Yorktown Heights, NY 10598, USA 94/*--*/ 95 96/* System library. */ 97 98#include <sys_defs.h> 99#include <errno.h> 100 101/* Utility library. */ 102 103#include <msg.h> 104#include <vstring.h> 105#include <mymalloc.h> 106 107/* Global library. */ 108 109#include <cleanup_user.h> 110#include <mail_queue.h> 111#include <mail_proto.h> 112#include <bounce.h> 113#include <mail_params.h> 114#include <mail_stream.h> 115#include <mail_flow.h> 116#include <rec_type.h> 117 118/* Milter library. */ 119 120#include <milter.h> 121 122/* Application-specific. */ 123 124#include "cleanup.h" 125 126/* cleanup_open - open queue file and initialize */ 127 128CLEANUP_STATE *cleanup_open(VSTREAM *src) 129{ 130 CLEANUP_STATE *state; 131 static const char *log_queues[] = { 132 MAIL_QUEUE_DEFER, 133 MAIL_QUEUE_BOUNCE, 134 MAIL_QUEUE_TRACE, 135 0, 136 }; 137 const char **cpp; 138 139 /* 140 * Initialize private state. 141 */ 142 state = cleanup_state_alloc(src); 143 144 /* 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. 147 * 148 * XXX For now, a lot of detail is frozen that could be more useful if it 149 * were made configurable. 150 */ 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); 157 if (msg_verbose) 158 msg_info("cleanup_open: open %s", cleanup_path); 159 160 /* 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. 164 * 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 167 * nonsense. 168 */ 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); 174 } 175 return (state); 176} 177 178/* cleanup_control - process client options */ 179 180void cleanup_control(CLEANUP_STATE *state, int flags) 181{ 182 183 /* 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 189 * definition. 190 */ 191 if (msg_verbose) 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; 195 } else { 196 state->err_mask = ~0; 197 } 198} 199 200/* cleanup_flush - finish queue file */ 201 202int cleanup_flush(CLEANUP_STATE *state) 203{ 204 int status; 205 char *junk; 206 VSTRING *trace_junk; 207 208 /* 209 * Raise these errors only if we examined all queue file records. 210 */ 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; 216 } 217 218 /* 219 * Status sanitization. Always report success when the discard flag was 220 * raised by some user-specified access rule. 221 */ 222 if (state->flags & CLEANUP_FLAG_DISCARD) 223 state->errs = 0; 224 225 /* 226 * Apply external mail filter. 227 * 228 * XXX Include test for a built-in action to tempfail this message. 229 */ 230 if (CLEANUP_MILTER_OK(state)) { 231 if (state->milters) 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); 237 } 238 } 239 240 /* 241 * Update the preliminary message size and count fields with the actual 242 * values. 243 */ 244 if (CLEANUP_OUT_OK(state)) 245 cleanup_final(state); 246 247 /* 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. 254 * 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). 260 * 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 267 * not try to do so). 268 */ 269#define CAN_BOUNCE() \ 270 ((state->errs & CLEANUP_STAT_MASK_CANT_BOUNCE) == 0 \ 271 && state->sender != 0 \ 272 && (state->flags & CLEANUP_FLAG_BOUNCE) != 0) 273 274 if (state->errs != 0 && CAN_BOUNCE()) 275 cleanup_bounce(state); 276 277 /* 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. 284 * 285 * XXX Include test for a built-in action to tempfail this message. 286 */ 287 if (state->errs == 0 && (state->flags & CLEANUP_FLAG_DISCARD) == 0) { 288 if ((state->flags & CLEANUP_FLAG_HOLD) != 0 289#ifdef DELAY_ACTION 290 || state->defer_delay > 0 291#endif 292 ) { 293 myfree(state->queue_name); 294#ifdef DELAY_ACTION 295 state->queue_name = mystrdup((state->flags & CLEANUP_FLAG_HOLD) ? 296 MAIL_QUEUE_HOLD : MAIL_QUEUE_DEFERRED); 297#else 298 state->queue_name = mystrdup(MAIL_QUEUE_HOLD); 299#endif 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, 304#ifdef DELAY_ACTION 305 MAIL_STREAM_CTL_DELAY, state->defer_delay, 306#endif 307 MAIL_STREAM_CTL_END); 308 junk = cleanup_path; 309 cleanup_path = mystrdup(VSTREAM_PATH(state->handle->stream)); 310 myfree(junk); 311 312 /* 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). 317 */ 318 (void) mail_flow_put(1); 319 } 320 state->errs = mail_stream_finish(state->handle, (VSTRING *) 0); 321 } else { 322 323 /* 324 * XXX: When discarding mail, should we consume in_flow tokens? See 325 * also the comments above for mail that is placed on hold. 326 */ 327#if 0 328 (void) mail_flow_put(1); 329#endif 330 mail_stream_cleanup(state->handle); 331 } 332 state->handle = 0; 333 state->dst = 0; 334 335 /* 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. 339 */ 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); 345 } 346 347 /* 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. 351 */ 352 trace_junk = cleanup_trace_path; 353 cleanup_trace_path = 0; /* don't delete upon error */ 354 junk = cleanup_path; 355 cleanup_path = 0; /* don't delete upon error */ 356 357 if (trace_junk) 358 vstring_free(trace_junk); 359 myfree(junk); 360 361 /* 362 * Cleanup internal state. This is simply complementary to the 363 * initializations at the beginning of cleanup_open(). 364 */ 365 if (msg_verbose) 366 msg_info("cleanup_flush: status %d", state->errs); 367 status = state->errs; 368 return (status); 369} 370 371/* cleanup_free - pay the last respects */ 372 373void cleanup_free(CLEANUP_STATE *state) 374{ 375 376 /* 377 * Emulate disconnect event. CLEANUP_FLAG_MILTER may be turned off after 378 * we have started. 379 */ 380 if (cleanup_milters != 0 && state->milters == 0) 381 milter_disc_event(cleanup_milters); 382 cleanup_state_free(state); 383} 384