5
/* Postfix message bounce or defer daemon
7
/* \fBbounce\fR [generic Postfix daemon options]
9
/* The \fBbounce\fR daemon maintains per-message log files with
10
/* non-delivery status information. Each log file is named after the
11
/* queue file that it corresponds to, and is kept in a queue subdirectory
12
/* named after the service name in the \fBmaster.cf\fR file (either
13
/* \fBbounce\fR, \fBdefer\fR or \fBtrace\fR).
14
/* This program expects to be run from the \fBmaster\fR(8) process
17
/* The \fBbounce\fR daemon processes two types of service requests:
19
/* Append a recipient (non-)delivery status record to a per-message
22
/* Enqueue a bounce message, with a copy of a per-message log file
23
/* and of the corresponding message. When the bounce message is
24
/* enqueued successfully, the per-message log file is deleted.
26
/* The software does a best notification effort. A non-delivery
27
/* notification is sent even when the log file or the original
28
/* message cannot be read.
30
/* Optionally, a bounce (defer, trace) client can request that the
31
/* per-message log file be deleted when the requested operation fails.
32
/* This is used by clients that cannot retry transactions by
33
/* themselves, and that depend on retry logic in their own client.
35
/* RFC 822 (ARPA Internet Text Messages)
36
/* RFC 1894 (Delivery Status Notifications)
37
/* RFC 2045 (Format of Internet Message Bodies)
39
/* Problems and transactions are logged to \fBsyslogd\fR(8).
40
/* CONFIGURATION PARAMETERS
43
/* Changes to \fBmain.cf\fR are picked up automatically, as bounce(8)
44
/* processes run for only a limited amount of time. Use the command
45
/* "\fBpostfix reload\fR" to speed up a change.
47
/* The text below provides only a parameter summary. See
48
/* postconf(5) for more details including examples.
49
/* .IP "\fB2bounce_notice_recipient (postmaster)\fR"
50
/* The recipient of undeliverable mail that cannot be returned to
52
/* .IP "\fBbackwards_bounce_logfile_compatibility (yes)\fR"
53
/* Produce additional bounce(8) logfile records that can be read by
54
/* older Postfix versions.
55
/* .IP "\fBbounce_notice_recipient (postmaster)\fR"
56
/* The recipient of postmaster notifications with the message headers
57
/* of mail that Postfix did not deliver and of SMTP conversation
58
/* transcripts of mail that Postfix did not receive.
59
/* .IP "\fBbounce_size_limit (50000)\fR"
60
/* The maximal amount of original message text that is sent in a
61
/* non-delivery notification.
62
/* .IP "\fBconfig_directory (see 'postconf -d' output)\fR"
63
/* The default location of the Postfix main.cf and master.cf
64
/* configuration files.
65
/* .IP "\fBdaemon_timeout (18000s)\fR"
66
/* How much time a Postfix daemon process may take to handle a
67
/* request before it is terminated by a built-in watchdog timer.
68
/* .IP "\fBdelay_notice_recipient (postmaster)\fR"
69
/* The recipient of postmaster notifications with the message headers
70
/* of mail that cannot be delivered within $delay_warning_time time
72
/* .IP "\fBdeliver_lock_attempts (20)\fR"
73
/* The maximal number of attempts to acquire an exclusive lock on a
74
/* mailbox file or bounce(8) logfile.
75
/* .IP "\fBdeliver_lock_delay (1s)\fR"
76
/* The time between attempts to acquire an exclusive lock on a mailbox
77
/* file or bounce(8) logfile.
78
/* .IP "\fBipc_timeout (3600s)\fR"
79
/* The time limit for sending or receiving information over an internal
80
/* communication channel.
81
/* .IP "\fBmail_name (Postfix)\fR"
82
/* The mail system name that is displayed in Received: headers, in
83
/* the SMTP greeting banner, and in bounced mail.
84
/* .IP "\fBmax_idle (100s)\fR"
85
/* The maximum amount of time that an idle Postfix daemon process
86
/* waits for the next service request before exiting.
87
/* .IP "\fBmax_use (100)\fR"
88
/* The maximal number of connection requests before a Postfix daemon
89
/* process terminates.
90
/* .IP "\fBnotify_classes (resource, software)\fR"
91
/* The list of error classes that are reported to the postmaster.
92
/* .IP "\fBprocess_id (read-only)\fR"
93
/* The process ID of a Postfix command or daemon process.
94
/* .IP "\fBprocess_name (read-only)\fR"
95
/* The process name of a Postfix command or daemon process.
96
/* .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
97
/* The location of the Postfix top-level queue directory.
98
/* .IP "\fBsyslog_facility (mail)\fR"
99
/* The syslog facility of Postfix logging.
100
/* .IP "\fBsyslog_name (postfix)\fR"
101
/* The mail system name that is prepended to the process name in syslog
102
/* records, so that "smtpd" becomes, for example, "postfix/smtpd".
104
/* /var/spool/postfix/bounce/* non-delivery records
105
/* /var/spool/postfix/defer/* non-delivery records
106
/* /var/spool/postfix/trace/* delivery status records
108
/* qmgr(8), queue manager
109
/* postconf(5), configuration parameters
110
/* master(8), process manager
111
/* syslogd(8), system logging
115
/* The Secure Mailer license must be distributed with this software.
118
/* IBM T.J. Watson Research
120
/* Yorktown Heights, NY 10598, USA
123
/* System library. */
125
#include <sys_defs.h>
128
#ifdef STRCASECMP_IN_STRINGS_H
132
/* Utility library. */
137
#include <stringops.h>
139
/* Global library. */
141
#include <mail_proto.h>
142
#include <mail_queue.h>
143
#include <mail_params.h>
144
#include <mail_conf.h>
146
#include <mail_addr.h>
148
/* Single-threaded server skeleton. */
150
#include <mail_server.h>
152
/* Application-specific. */
154
#include "bounce_service.h"
159
int var_bounce_limit;
160
int var_max_queue_time;
161
int var_delay_warn_time;
162
char *var_notify_classes;
163
char *var_bounce_rcpt;
164
char *var_2bounce_rcpt;
165
char *var_delay_rcpt;
168
* We're single threaded, so we can avoid some memory allocation overhead.
170
static VSTRING *queue_id;
171
static VSTRING *queue_name;
172
static VSTRING *orig_rcpt;
173
static VSTRING *recipient;
174
static VSTRING *encoding;
175
static VSTRING *sender;
176
static VSTRING *verp_delims;
177
static VSTRING *dsn_status;
178
static VSTRING *dsn_action;
181
#define STR vstring_str
183
/* bounce_append_proto - bounce_append server protocol */
185
static int bounce_append_proto(char *service_name, VSTREAM *client)
187
char *myname = "bounce_append_proto";
192
* Read the and validate the client request.
194
if (mail_command_server(client,
195
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &flags,
196
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
197
ATTR_TYPE_STR, MAIL_ATTR_ORCPT, orig_rcpt,
198
ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient,
199
ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, &offset,
200
ATTR_TYPE_STR, MAIL_ATTR_STATUS, dsn_status,
201
ATTR_TYPE_STR, MAIL_ATTR_ACTION, dsn_action,
202
ATTR_TYPE_STR, MAIL_ATTR_WHY, why,
203
ATTR_TYPE_END) != 8) {
204
msg_warn("malformed request");
207
if (mail_queue_id_ok(STR(queue_id)) == 0) {
208
msg_warn("malformed queue id: %s", printable(STR(queue_id), '?'));
212
msg_info("%s: flags=0x%x service=%s id=%s org_to=%s to=%s off=%ld stat=%s act=%s why=%s",
213
myname, flags, service_name, STR(queue_id), STR(orig_rcpt),
214
STR(recipient), offset, STR(dsn_status),
215
STR(dsn_action), STR(why));
218
* On request by the client, set up a trap to delete the log file in case
221
if (flags & BOUNCE_FLAG_CLEAN)
222
bounce_cleanup_register(service_name, STR(queue_id));
225
* Execute the request.
227
return (bounce_append_service(flags, service_name, STR(queue_id),
228
STR(orig_rcpt), STR(recipient), offset,
229
STR(dsn_status), STR(dsn_action),
233
/* bounce_notify_proto - bounce_notify server protocol */
235
static int bounce_notify_proto(char *service_name, VSTREAM *client,
236
int (*service) (int, char *, char *, char *, char *, char *))
238
char *myname = "bounce_notify_proto";
242
* Read and validate the client request.
244
if (mail_command_server(client,
245
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &flags,
246
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name,
247
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
248
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
249
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
250
ATTR_TYPE_END) != 5) {
251
msg_warn("malformed request");
254
if (mail_queue_name_ok(STR(queue_name)) == 0) {
255
msg_warn("malformed queue name: %s", printable(STR(queue_name), '?'));
258
if (mail_queue_id_ok(STR(queue_id)) == 0) {
259
msg_warn("malformed queue id: %s", printable(STR(queue_id), '?'));
263
msg_info("%s: flags=0x%x service=%s queue=%s id=%s encoding=%s sender=%s",
264
myname, flags, service_name, STR(queue_name), STR(queue_id),
265
STR(encoding), STR(sender));
268
* On request by the client, set up a trap to delete the log file in case
271
if (flags & BOUNCE_FLAG_CLEAN)
272
bounce_cleanup_register(service_name, STR(queue_id));
275
* Execute the request.
277
return (service(flags, service_name, STR(queue_name),
278
STR(queue_id), STR(encoding),
282
/* bounce_verp_proto - bounce_notify server protocol, VERP style */
284
static int bounce_verp_proto(char *service_name, VSTREAM *client)
286
char *myname = "bounce_verp_proto";
290
* Read and validate the client request.
292
if (mail_command_server(client,
293
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &flags,
294
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name,
295
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
296
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
297
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
298
ATTR_TYPE_STR, MAIL_ATTR_VERPDL, verp_delims,
299
ATTR_TYPE_END) != 6) {
300
msg_warn("malformed request");
303
if (mail_queue_name_ok(STR(queue_name)) == 0) {
304
msg_warn("malformed queue name: %s", printable(STR(queue_name), '?'));
307
if (mail_queue_id_ok(STR(queue_id)) == 0) {
308
msg_warn("malformed queue id: %s", printable(STR(queue_id), '?'));
311
if (strlen(STR(verp_delims)) != 2) {
312
msg_warn("malformed verp delimiter string: %s",
313
printable(STR(verp_delims), '?'));
317
msg_info("%s: flags=0x%x service=%s queue=%s id=%s encoding=%s sender=%s delim=%s",
318
myname, flags, service_name, STR(queue_name), STR(queue_id),
319
STR(encoding), STR(sender), STR(verp_delims));
322
* On request by the client, set up a trap to delete the log file in case
325
if (flags & BOUNCE_FLAG_CLEAN)
326
bounce_cleanup_register(service_name, STR(queue_id));
329
* Execute the request. Fall back to traditional notification if a bounce
330
* was returned as undeliverable, because we don't want to VERPify those.
332
if (!*STR(sender) || !strcasecmp(STR(sender), mail_addr_double_bounce())) {
333
msg_warn("request to send VERP-style notification of bounced mail");
334
return (bounce_notify_service(flags, service_name, STR(queue_name),
335
STR(queue_id), STR(encoding),
338
return (bounce_notify_verp(flags, service_name, STR(queue_name),
339
STR(queue_id), STR(encoding),
340
STR(sender), STR(verp_delims)));
343
/* bounce_one_proto - bounce_one server protocol */
345
static int bounce_one_proto(char *service_name, VSTREAM *client)
347
char *myname = "bounce_one_proto";
352
* Read and validate the client request.
354
if (mail_command_server(client,
355
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &flags,
356
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name,
357
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
358
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
359
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
360
ATTR_TYPE_STR, MAIL_ATTR_ORCPT, orig_rcpt,
361
ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient,
362
ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, &offset,
363
ATTR_TYPE_STR, MAIL_ATTR_STATUS, dsn_status,
364
ATTR_TYPE_STR, MAIL_ATTR_ACTION, dsn_action,
365
ATTR_TYPE_STR, MAIL_ATTR_WHY, why,
366
ATTR_TYPE_END) != 11) {
367
msg_warn("malformed request");
370
if (strcmp(service_name, MAIL_SERVICE_BOUNCE) != 0) {
371
msg_warn("wrong service name \"%s\" for one-recipient bouncing",
375
if (mail_queue_name_ok(STR(queue_name)) == 0) {
376
msg_warn("malformed queue name: %s", printable(STR(queue_name), '?'));
379
if (mail_queue_id_ok(STR(queue_id)) == 0) {
380
msg_warn("malformed queue id: %s", printable(STR(queue_id), '?'));
384
msg_info("%s: flags=0x%x queue=%s id=%s encoding=%s sender=%s orig_to=%s to=%s off=%ld stat=%s act=%s why=%s",
385
myname, flags, STR(queue_name), STR(queue_id), STR(encoding),
386
STR(sender), STR(orig_rcpt), STR(recipient), offset,
387
STR(dsn_status), STR(dsn_action), STR(why));
390
* Execute the request.
392
return (bounce_one_service(flags, STR(queue_name), STR(queue_id),
393
STR(encoding), STR(sender), STR(orig_rcpt),
394
STR(recipient), offset, STR(dsn_status),
395
STR(dsn_action), STR(why)));
398
/* bounce_service - parse bounce command type and delegate */
400
static void bounce_service(VSTREAM *client, char *service_name, char **argv)
406
* Sanity check. This service takes no command-line arguments. The
407
* service name should be usable as a subdirectory name.
410
msg_fatal("unexpected command-line argument: %s", argv[0]);
411
if (mail_queue_name_ok(service_name) == 0)
412
msg_fatal("malformed service name: %s", service_name);
415
* Read and validate the first parameter of the client request. Let the
416
* request-specific protocol routines take care of the remainder.
418
if (attr_scan(client, ATTR_FLAG_STRICT | ATTR_FLAG_MORE,
419
ATTR_TYPE_NUM, MAIL_ATTR_NREQ, &command, 0) != 1) {
420
msg_warn("malformed request");
422
} else if (command == BOUNCE_CMD_VERP) {
423
status = bounce_verp_proto(service_name, client);
424
} else if (command == BOUNCE_CMD_FLUSH) {
425
status = bounce_notify_proto(service_name, client,
426
bounce_notify_service);
427
} else if (command == BOUNCE_CMD_WARN) {
428
status = bounce_notify_proto(service_name, client,
429
bounce_warn_service);
430
} else if (command == BOUNCE_CMD_TRACE) {
431
status = bounce_notify_proto(service_name, client,
432
bounce_trace_service);
433
} else if (command == BOUNCE_CMD_APPEND) {
434
status = bounce_append_proto(service_name, client);
435
} else if (command == BOUNCE_CMD_ONE) {
436
status = bounce_one_proto(service_name, client);
438
msg_warn("unknown command: %d", command);
443
* When the request has completed, send the completion status to the
446
attr_print(client, ATTR_FLAG_NONE,
447
ATTR_TYPE_NUM, MAIL_ATTR_STATUS, status,
449
vstream_fflush(client);
452
* When a cleanup trap was set, delete the log file in case of error.
453
* This includes errors while sending the completion status to the
456
if (bounce_cleanup_path) {
457
if (status || vstream_ferror(client))
458
bounce_cleanup_log();
459
bounce_cleanup_unregister();
463
/* post_jail_init - initialize after entering chroot jail */
465
static void post_jail_init(char *unused_name, char **unused_argv)
469
* Initialize. We're single threaded so we can reuse some memory upon
470
* successive requests.
472
queue_id = vstring_alloc(10);
473
queue_name = vstring_alloc(10);
474
orig_rcpt = vstring_alloc(10);
475
recipient = vstring_alloc(10);
476
encoding = vstring_alloc(10);
477
sender = vstring_alloc(10);
478
verp_delims = vstring_alloc(10);
479
dsn_status = vstring_alloc(10);
480
dsn_action = vstring_alloc(10);
481
why = vstring_alloc(10);
484
/* main - the main program */
486
int main(int argc, char **argv)
488
static CONFIG_INT_TABLE int_table[] = {
489
VAR_BOUNCE_LIMIT, DEF_BOUNCE_LIMIT, &var_bounce_limit, 1, 0,
492
static CONFIG_TIME_TABLE time_table[] = {
493
VAR_MAX_QUEUE_TIME, DEF_MAX_QUEUE_TIME, &var_max_queue_time, 0, 8640000,
494
VAR_DELAY_WARN_TIME, DEF_DELAY_WARN_TIME, &var_delay_warn_time, 0, 0,
497
static CONFIG_STR_TABLE str_table[] = {
498
VAR_NOTIFY_CLASSES, DEF_NOTIFY_CLASSES, &var_notify_classes, 0, 0,
499
VAR_BOUNCE_RCPT, DEF_BOUNCE_RCPT, &var_bounce_rcpt, 1, 0,
500
VAR_2BOUNCE_RCPT, DEF_2BOUNCE_RCPT, &var_2bounce_rcpt, 1, 0,
501
VAR_DELAY_RCPT, DEF_DELAY_RCPT, &var_delay_rcpt, 1, 0,
506
* Pass control to the single-threaded service skeleton.
508
single_server_main(argc, argv, bounce_service,
509
MAIL_SERVER_INT_TABLE, int_table,
510
MAIL_SERVER_STR_TABLE, str_table,
511
MAIL_SERVER_TIME_TABLE, time_table,
512
MAIL_SERVER_POST_INIT, post_jail_init,
513
MAIL_SERVER_UNLIMITED,