1/*++
2/* NAME
3/*	bounce 8
4/* SUMMARY
5/*	Postfix delivery status reports
6/* SYNOPSIS
7/*	\fBbounce\fR [generic Postfix daemon options]
8/* DESCRIPTION
9/*	The \fBbounce\fR(8) daemon maintains per-message log files with
10/*	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
15/*	manager.
16/*
17/*	The \fBbounce\fR(8) daemon processes two types of service requests:
18/* .IP \(bu
19/*	Append a recipient (non-)delivery status record to a per-message
20/*	log file.
21/* .IP \(bu
22/*	Enqueue a delivery status notification message, with a copy
23/*	of a per-message log file and of the corresponding message.
24/*	When the delivery status notification message is
25/*	enqueued successfully, the per-message log file is deleted.
26/* .PP
27/*	The software does a best notification effort. A non-delivery
28/*	notification is sent even when the log file or the original
29/*	message cannot be read.
30/*
31/*	Optionally, a bounce (defer, trace) client can request that the
32/*	per-message log file be deleted when the requested operation fails.
33/*	This is used by clients that cannot retry transactions by
34/*	themselves, and that depend on retry logic in their own client.
35/* STANDARDS
36/*	RFC 822 (ARPA Internet Text Messages)
37/*	RFC 2045 (Format of Internet Message Bodies)
38/*	RFC 2822 (Internet Message Format)
39/*	RFC 3462 (Delivery Status Notifications)
40/*	RFC 3464 (Delivery Status Notifications)
41/*	RFC 3834 (Auto-Submitted: message header)
42/*	RFC 5322 (Internet Message Format)
43/* DIAGNOSTICS
44/*	Problems and transactions are logged to \fBsyslogd\fR(8).
45/* CONFIGURATION PARAMETERS
46/* .ad
47/* .fi
48/*	Changes to \fBmain.cf\fR are picked up automatically, as \fBbounce\fR(8)
49/*	processes run for only a limited amount of time. Use the command
50/*	"\fBpostfix reload\fR" to speed up a change.
51/*
52/*	The text below provides only a parameter summary. See
53/*	\fBpostconf\fR(5) for more details including examples.
54/* .IP "\fB2bounce_notice_recipient (postmaster)\fR"
55/*	The recipient of undeliverable mail that cannot be returned to
56/*	the sender.
57/* .IP "\fBbackwards_bounce_logfile_compatibility (yes)\fR"
58/*	Produce additional \fBbounce\fR(8) logfile records that can be read by
59/*	Postfix versions before 2.0.
60/* .IP "\fBbounce_notice_recipient (postmaster)\fR"
61/*	The recipient of postmaster notifications with the message headers
62/*	of mail that Postfix did not deliver and of SMTP conversation
63/*	transcripts of mail that Postfix did not receive.
64/* .IP "\fBbounce_size_limit (50000)\fR"
65/*	The maximal amount of original message text that is sent in a
66/*	non-delivery notification.
67/* .IP "\fBbounce_template_file (empty)\fR"
68/*	Pathname of a configuration file with bounce message templates.
69/* .IP "\fBconfig_directory (see 'postconf -d' output)\fR"
70/*	The default location of the Postfix main.cf and master.cf
71/*	configuration files.
72/* .IP "\fBdaemon_timeout (18000s)\fR"
73/*	How much time a Postfix daemon process may take to handle a
74/*	request before it is terminated by a built-in watchdog timer.
75/* .IP "\fBdelay_notice_recipient (postmaster)\fR"
76/*	The recipient of postmaster notifications with the message headers
77/*	of mail that cannot be delivered within $delay_warning_time time
78/*	units.
79/* .IP "\fBdeliver_lock_attempts (20)\fR"
80/*	The maximal number of attempts to acquire an exclusive lock on a
81/*	mailbox file or \fBbounce\fR(8) logfile.
82/* .IP "\fBdeliver_lock_delay (1s)\fR"
83/*	The time between attempts to acquire an exclusive lock on a mailbox
84/*	file or \fBbounce\fR(8) logfile.
85/* .IP "\fBipc_timeout (3600s)\fR"
86/*	The time limit for sending or receiving information over an internal
87/*	communication channel.
88/* .IP "\fBinternal_mail_filter_classes (empty)\fR"
89/*	What categories of Postfix-generated mail are subject to
90/*	before-queue content inspection by non_smtpd_milters, header_checks
91/*	and body_checks.
92/* .IP "\fBmail_name (Postfix)\fR"
93/*	The mail system name that is displayed in Received: headers, in
94/*	the SMTP greeting banner, and in bounced mail.
95/* .IP "\fBmax_idle (100s)\fR"
96/*	The maximum amount of time that an idle Postfix daemon process waits
97/*	for an incoming connection before terminating voluntarily.
98/* .IP "\fBmax_use (100)\fR"
99/*	The maximal number of incoming connections that a Postfix daemon
100/*	process will service before terminating voluntarily.
101/* .IP "\fBnotify_classes (resource, software)\fR"
102/*	The list of error classes that are reported to the postmaster.
103/* .IP "\fBprocess_id (read-only)\fR"
104/*	The process ID of a Postfix command or daemon process.
105/* .IP "\fBprocess_name (read-only)\fR"
106/*	The process name of a Postfix command or daemon process.
107/* .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
108/*	The location of the Postfix top-level queue directory.
109/* .IP "\fBsyslog_facility (mail)\fR"
110/*	The syslog facility of Postfix logging.
111/* .IP "\fBsyslog_name (see 'postconf -d' output)\fR"
112/*	The mail system name that is prepended to the process name in syslog
113/*	records, so that "smtpd" becomes, for example, "postfix/smtpd".
114/* FILES
115/*	/var/spool/postfix/bounce/* non-delivery records
116/*	/var/spool/postfix/defer/* non-delivery records
117/*	/var/spool/postfix/trace/* delivery status records
118/* SEE ALSO
119/*	bounce(5), bounce message template format
120/*	qmgr(8), queue manager
121/*	postconf(5), configuration parameters
122/*	master(5), generic daemon options
123/*	master(8), process manager
124/*	syslogd(8), system logging
125/* LICENSE
126/* .ad
127/* .fi
128/*	The Secure Mailer license must be distributed with this software.
129/* AUTHOR(S)
130/*	Wietse Venema
131/*	IBM T.J. Watson Research
132/*	P.O. Box 704
133/*	Yorktown Heights, NY 10598, USA
134/*--*/
135
136/* System library. */
137
138#include <sys_defs.h>
139#include <string.h>
140#include <stdlib.h>
141
142#ifdef STRCASECMP_IN_STRINGS_H
143#include <strings.h>
144#endif
145
146/* Utility library. */
147
148#include <msg.h>
149#include <vstring.h>
150#include <vstream.h>
151#include <stringops.h>
152#include <load_file.h>
153
154/* Global library. */
155
156#include <mail_proto.h>
157#include <mail_queue.h>
158#include <mail_params.h>
159#include <mail_version.h>
160#include <mail_conf.h>
161#include <bounce.h>
162#include <mail_addr.h>
163#include <rcpt_buf.h>
164#include <dsb_scan.h>
165
166/* Single-threaded server skeleton. */
167
168#include <mail_server.h>
169
170/* Application-specific. */
171
172#include <bounce_service.h>
173
174 /*
175  * Tunables.
176  */
177int     var_bounce_limit;
178int     var_max_queue_time;
179int     var_delay_warn_time;
180char   *var_notify_classes;
181char   *var_bounce_rcpt;
182char   *var_2bounce_rcpt;
183char   *var_delay_rcpt;
184char   *var_bounce_tmpl;
185
186 /*
187  * We're single threaded, so we can avoid some memory allocation overhead.
188  */
189static VSTRING *queue_id;
190static VSTRING *queue_name;
191static RCPT_BUF *rcpt_buf;
192static VSTRING *encoding;
193static VSTRING *sender;
194static VSTRING *dsn_envid;
195static VSTRING *verp_delims;
196static DSN_BUF *dsn_buf;
197
198 /*
199  * Templates.
200  */
201BOUNCE_TEMPLATES *bounce_templates;
202
203#define STR vstring_str
204
205#define VS_NEUTER(s) printable(vstring_str(s), '?')
206
207/* bounce_append_proto - bounce_append server protocol */
208
209static int bounce_append_proto(char *service_name, VSTREAM *client)
210{
211    const char *myname = "bounce_append_proto";
212    int     flags;
213
214    /*
215     * Read and validate the client request.
216     */
217    if (mail_command_server(client,
218			    ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &flags,
219			    ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
220			    ATTR_TYPE_FUNC, rcpb_scan, (void *) rcpt_buf,
221			    ATTR_TYPE_FUNC, dsb_scan, (void *) dsn_buf,
222			    ATTR_TYPE_END) != 4) {
223	msg_warn("malformed request");
224	return (-1);
225    }
226
227    /*
228     * Sanitize input.
229     */
230    if (mail_queue_id_ok(STR(queue_id)) == 0) {
231	msg_warn("malformed queue id: %s", printable(STR(queue_id), '?'));
232	return (-1);
233    }
234    VS_NEUTER(rcpt_buf->address);
235    VS_NEUTER(rcpt_buf->orig_addr);
236    VS_NEUTER(rcpt_buf->dsn_orcpt);
237    VS_NEUTER(dsn_buf->status);
238    VS_NEUTER(dsn_buf->action);
239    VS_NEUTER(dsn_buf->reason);
240    VS_NEUTER(dsn_buf->dtype);
241    VS_NEUTER(dsn_buf->dtext);
242    VS_NEUTER(dsn_buf->mtype);
243    VS_NEUTER(dsn_buf->mname);
244    (void) RECIPIENT_FROM_RCPT_BUF(rcpt_buf);
245    (void) DSN_FROM_DSN_BUF(dsn_buf);
246
247    /*
248     * Beware: some DSN or RECIPIENT fields may be null; access dsn_buf and
249     * rcpt_buf buffers instead. See DSN_FROM_DSN_BUF() and
250     * RECIPIENT_FROM_RCPT_BUF().
251     */
252    if (msg_verbose)
253	msg_info("%s: flags=0x%x service=%s id=%s org_to=%s to=%s off=%ld dsn_org=%s, notif=0x%x stat=%s act=%s why=%s",
254		 myname, flags, service_name, STR(queue_id),
255		 STR(rcpt_buf->orig_addr), STR(rcpt_buf->address),
256		 rcpt_buf->offset, STR(rcpt_buf->dsn_orcpt),
257		 rcpt_buf->dsn_notify, STR(dsn_buf->status),
258		 STR(dsn_buf->action), STR(dsn_buf->reason));
259
260    /*
261     * On request by the client, set up a trap to delete the log file in case
262     * of errors.
263     */
264    if (flags & BOUNCE_FLAG_CLEAN)
265	bounce_cleanup_register(service_name, STR(queue_id));
266
267    /*
268     * Execute the request.
269     */
270    return (bounce_append_service(flags, service_name, STR(queue_id),
271				  &rcpt_buf->rcpt, &dsn_buf->dsn));
272}
273
274/* bounce_notify_proto - bounce_notify server protocol */
275
276static int bounce_notify_proto(char *service_name, VSTREAM *client,
277			        int (*service) (int, char *, char *, char *,
278					        char *, char *, char *, int,
279						        BOUNCE_TEMPLATES *))
280{
281    const char *myname = "bounce_notify_proto";
282    int     flags;
283    int     dsn_ret;
284
285    /*
286     * Read and validate the client request.
287     */
288    if (mail_command_server(client,
289			    ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &flags,
290			    ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name,
291			    ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
292			    ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
293			    ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
294			    ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, dsn_envid,
295			    ATTR_TYPE_INT, MAIL_ATTR_DSN_RET, &dsn_ret,
296			    ATTR_TYPE_END) != 7) {
297	msg_warn("malformed request");
298	return (-1);
299    }
300
301    /*
302     * Sanitize input.
303     */
304    if (mail_queue_name_ok(STR(queue_name)) == 0) {
305	msg_warn("malformed queue name: %s", printable(STR(queue_name), '?'));
306	return (-1);
307    }
308    if (mail_queue_id_ok(STR(queue_id)) == 0) {
309	msg_warn("malformed queue id: %s", printable(STR(queue_id), '?'));
310	return (-1);
311    }
312    printable(STR(dsn_envid), '?');
313    if (msg_verbose)
314	msg_info("%s: flags=0x%x service=%s queue=%s id=%s encoding=%s sender=%s envid=%s ret=0x%x",
315		 myname, flags, service_name, STR(queue_name), STR(queue_id),
316		 STR(encoding), STR(sender), STR(dsn_envid), dsn_ret);
317
318    /*
319     * On request by the client, set up a trap to delete the log file in case
320     * of errors.
321     */
322    if (flags & BOUNCE_FLAG_CLEAN)
323	bounce_cleanup_register(service_name, STR(queue_id));
324
325    /*
326     * Execute the request.
327     */
328    return (service(flags, service_name, STR(queue_name),
329		    STR(queue_id), STR(encoding),
330		    STR(sender), STR(dsn_envid), dsn_ret,
331		    bounce_templates));
332}
333
334/* bounce_verp_proto - bounce_notify server protocol, VERP style */
335
336static int bounce_verp_proto(char *service_name, VSTREAM *client)
337{
338    const char *myname = "bounce_verp_proto";
339    int     flags;
340    int     dsn_ret;
341
342    /*
343     * Read and validate the client request.
344     */
345    if (mail_command_server(client,
346			    ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &flags,
347			    ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name,
348			    ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
349			    ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
350			    ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
351			    ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, dsn_envid,
352			    ATTR_TYPE_INT, MAIL_ATTR_DSN_RET, &dsn_ret,
353			    ATTR_TYPE_STR, MAIL_ATTR_VERPDL, verp_delims,
354			    ATTR_TYPE_END) != 8) {
355	msg_warn("malformed request");
356	return (-1);
357    }
358
359    /*
360     * Sanitize input.
361     */
362    if (mail_queue_name_ok(STR(queue_name)) == 0) {
363	msg_warn("malformed queue name: %s", printable(STR(queue_name), '?'));
364	return (-1);
365    }
366    if (mail_queue_id_ok(STR(queue_id)) == 0) {
367	msg_warn("malformed queue id: %s", printable(STR(queue_id), '?'));
368	return (-1);
369    }
370    printable(STR(dsn_envid), '?');
371    if (strlen(STR(verp_delims)) != 2) {
372	msg_warn("malformed verp delimiter string: %s",
373		 printable(STR(verp_delims), '?'));
374	return (-1);
375    }
376    if (msg_verbose)
377	msg_info("%s: flags=0x%x service=%s queue=%s id=%s encoding=%s sender=%s envid=%s ret=0x%x delim=%s",
378		 myname, flags, service_name, STR(queue_name),
379		 STR(queue_id), STR(encoding), STR(sender),
380		 STR(dsn_envid), dsn_ret, STR(verp_delims));
381
382    /*
383     * On request by the client, set up a trap to delete the log file in case
384     * of errors.
385     */
386    if (flags & BOUNCE_FLAG_CLEAN)
387	bounce_cleanup_register(service_name, STR(queue_id));
388
389    /*
390     * Execute the request. Fall back to traditional notification if a bounce
391     * was returned as undeliverable, because we don't want to VERPify those.
392     */
393    if (!*STR(sender) || !strcasecmp(STR(sender), mail_addr_double_bounce())) {
394	msg_warn("request to send VERP-style notification of bounced mail");
395	return (bounce_notify_service(flags, service_name, STR(queue_name),
396				      STR(queue_id), STR(encoding),
397				      STR(sender), STR(dsn_envid), dsn_ret,
398				      bounce_templates));
399    } else
400	return (bounce_notify_verp(flags, service_name, STR(queue_name),
401				   STR(queue_id), STR(encoding),
402				   STR(sender), STR(dsn_envid), dsn_ret,
403				   STR(verp_delims), bounce_templates));
404}
405
406/* bounce_one_proto - bounce_one server protocol */
407
408static int bounce_one_proto(char *service_name, VSTREAM *client)
409{
410    const char *myname = "bounce_one_proto";
411    int     flags;
412    int     dsn_ret;
413
414    /*
415     * Read and validate the client request.
416     */
417    if (mail_command_server(client,
418			    ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &flags,
419			    ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name,
420			    ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
421			    ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
422			    ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
423			    ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, dsn_envid,
424			    ATTR_TYPE_INT, MAIL_ATTR_DSN_RET, &dsn_ret,
425			    ATTR_TYPE_FUNC, rcpb_scan, (void *) rcpt_buf,
426			    ATTR_TYPE_FUNC, dsb_scan, (void *) dsn_buf,
427			    ATTR_TYPE_END) != 9) {
428	msg_warn("malformed request");
429	return (-1);
430    }
431
432    /*
433     * Sanitize input.
434     */
435    if (strcmp(service_name, MAIL_SERVICE_BOUNCE) != 0) {
436	msg_warn("wrong service name \"%s\" for one-recipient bouncing",
437		 service_name);
438	return (-1);
439    }
440    if (mail_queue_name_ok(STR(queue_name)) == 0) {
441	msg_warn("malformed queue name: %s", printable(STR(queue_name), '?'));
442	return (-1);
443    }
444    if (mail_queue_id_ok(STR(queue_id)) == 0) {
445	msg_warn("malformed queue id: %s", printable(STR(queue_id), '?'));
446	return (-1);
447    }
448    printable(STR(dsn_envid), '?');
449    VS_NEUTER(rcpt_buf->address);
450    VS_NEUTER(rcpt_buf->orig_addr);
451    VS_NEUTER(rcpt_buf->dsn_orcpt);
452    VS_NEUTER(dsn_buf->status);
453    VS_NEUTER(dsn_buf->action);
454    VS_NEUTER(dsn_buf->reason);
455    VS_NEUTER(dsn_buf->dtype);
456    VS_NEUTER(dsn_buf->dtext);
457    VS_NEUTER(dsn_buf->mtype);
458    VS_NEUTER(dsn_buf->mname);
459    (void) RECIPIENT_FROM_RCPT_BUF(rcpt_buf);
460    (void) DSN_FROM_DSN_BUF(dsn_buf);
461
462    /*
463     * Beware: some DSN or RECIPIENT fields may be null; access dsn_buf and
464     * rcpt_buf buffers instead. See DSN_FROM_DSN_BUF() and
465     * RECIPIENT_FROM_RCPT_BUF().
466     */
467    if (msg_verbose)
468	msg_info("%s: flags=0x%x queue=%s id=%s encoding=%s sender=%s envid=%s dsn_ret=0x%x orig_to=%s to=%s off=%ld dsn_orig=%s notif=0x%x stat=%s act=%s why=%s",
469		 myname, flags, STR(queue_name), STR(queue_id),
470		 STR(encoding), STR(sender), STR(dsn_envid), dsn_ret,
471		 STR(rcpt_buf->orig_addr), STR(rcpt_buf->address),
472		 rcpt_buf->offset, STR(rcpt_buf->dsn_orcpt),
473		 rcpt_buf->dsn_notify, STR(dsn_buf->status),
474		 STR(dsn_buf->action), STR(dsn_buf->reason));
475
476    /*
477     * Execute the request.
478     */
479    return (bounce_one_service(flags, STR(queue_name), STR(queue_id),
480			       STR(encoding), STR(sender), STR(dsn_envid),
481			     dsn_ret, rcpt_buf, dsn_buf, bounce_templates));
482}
483
484/* bounce_service - parse bounce command type and delegate */
485
486static void bounce_service(VSTREAM *client, char *service_name, char **argv)
487{
488    int     command;
489    int     status;
490
491    /*
492     * Sanity check. This service takes no command-line arguments. The
493     * service name should be usable as a subdirectory name.
494     */
495    if (argv[0])
496	msg_fatal("unexpected command-line argument: %s", argv[0]);
497    if (mail_queue_name_ok(service_name) == 0)
498	msg_fatal("malformed service name: %s", service_name);
499
500    /*
501     * Read and validate the first parameter of the client request. Let the
502     * request-specific protocol routines take care of the remainder.
503     */
504    if (attr_scan(client, ATTR_FLAG_STRICT | ATTR_FLAG_MORE,
505		  ATTR_TYPE_INT, MAIL_ATTR_NREQ, &command, 0) != 1) {
506	msg_warn("malformed request");
507	status = -1;
508    } else if (command == BOUNCE_CMD_VERP) {
509	status = bounce_verp_proto(service_name, client);
510    } else if (command == BOUNCE_CMD_FLUSH) {
511	status = bounce_notify_proto(service_name, client,
512				     bounce_notify_service);
513    } else if (command == BOUNCE_CMD_WARN) {
514	status = bounce_notify_proto(service_name, client,
515				     bounce_warn_service);
516    } else if (command == BOUNCE_CMD_TRACE) {
517	status = bounce_notify_proto(service_name, client,
518				     bounce_trace_service);
519    } else if (command == BOUNCE_CMD_APPEND) {
520	status = bounce_append_proto(service_name, client);
521    } else if (command == BOUNCE_CMD_ONE) {
522	status = bounce_one_proto(service_name, client);
523    } else {
524	msg_warn("unknown command: %d", command);
525	status = -1;
526    }
527
528    /*
529     * When the request has completed, send the completion status to the
530     * client.
531     */
532    attr_print(client, ATTR_FLAG_NONE,
533	       ATTR_TYPE_INT, MAIL_ATTR_STATUS, status,
534	       ATTR_TYPE_END);
535    vstream_fflush(client);
536
537    /*
538     * When a cleanup trap was set, delete the log file in case of error.
539     * This includes errors while sending the completion status to the
540     * client.
541     */
542    if (bounce_cleanup_path) {
543	if (status || vstream_ferror(client))
544	    bounce_cleanup_log();
545	bounce_cleanup_unregister();
546    }
547}
548
549static void load_helper(VSTREAM *stream, void *context)
550{
551    BOUNCE_TEMPLATES *templates = (BOUNCE_TEMPLATES *) context;
552
553    bounce_templates_load(stream, templates);
554}
555
556/* pre_jail_init - pre-jail initialization */
557
558static void pre_jail_init(char *unused_name, char **unused_argv)
559{
560
561    /*
562     * Bundle up a bunch of bounce template information.
563     */
564    bounce_templates = bounce_templates_create();
565
566    /*
567     * Load the alternate message files (if specified) before entering the
568     * chroot jail.
569     */
570    if (*var_bounce_tmpl)
571	load_file(var_bounce_tmpl, load_helper, (char *) bounce_templates);
572}
573
574/* post_jail_init - initialize after entering chroot jail */
575
576static void post_jail_init(char *service_name, char **unused_argv)
577{
578
579    /*
580     * Special case: dump bounce templates. This is not part of the master(5)
581     * public interface. This internal interface is used by the postconf
582     * command. It was implemented before bounce templates were isolated into
583     * modules that could have been called directly.
584     */
585    if (strcmp(service_name, "dump_templates") == 0) {
586	bounce_templates_dump(VSTREAM_OUT, bounce_templates);
587	vstream_fflush(VSTREAM_OUT);
588	exit(0);
589    }
590    if (strcmp(service_name, "expand_templates") == 0) {
591	bounce_templates_expand(VSTREAM_OUT, bounce_templates);
592	vstream_fflush(VSTREAM_OUT);
593	exit(0);
594    }
595
596    /*
597     * Initialize. We're single threaded so we can reuse some memory upon
598     * successive requests.
599     */
600    queue_id = vstring_alloc(10);
601    queue_name = vstring_alloc(10);
602    rcpt_buf = rcpb_create();
603    encoding = vstring_alloc(10);
604    sender = vstring_alloc(10);
605    dsn_envid = vstring_alloc(10);
606    verp_delims = vstring_alloc(10);
607    dsn_buf = dsb_create();
608}
609
610MAIL_VERSION_STAMP_DECLARE;
611
612/* main - the main program */
613
614int     main(int argc, char **argv)
615{
616    static const CONFIG_INT_TABLE int_table[] = {
617	VAR_BOUNCE_LIMIT, DEF_BOUNCE_LIMIT, &var_bounce_limit, 1, 0,
618	0,
619    };
620    static const CONFIG_TIME_TABLE time_table[] = {
621	VAR_MAX_QUEUE_TIME, DEF_MAX_QUEUE_TIME, &var_max_queue_time, 0, 8640000,
622	VAR_DELAY_WARN_TIME, DEF_DELAY_WARN_TIME, &var_delay_warn_time, 0, 0,
623	0,
624    };
625    static const CONFIG_STR_TABLE str_table[] = {
626	VAR_NOTIFY_CLASSES, DEF_NOTIFY_CLASSES, &var_notify_classes, 0, 0,
627	VAR_BOUNCE_RCPT, DEF_BOUNCE_RCPT, &var_bounce_rcpt, 1, 0,
628	VAR_2BOUNCE_RCPT, DEF_2BOUNCE_RCPT, &var_2bounce_rcpt, 1, 0,
629	VAR_DELAY_RCPT, DEF_DELAY_RCPT, &var_delay_rcpt, 1, 0,
630	VAR_BOUNCE_TMPL, DEF_BOUNCE_TMPL, &var_bounce_tmpl, 0, 0,
631	0,
632    };
633
634    /*
635     * Fingerprint executables and core dumps.
636     */
637    MAIL_VERSION_STAMP_ALLOCATE;
638
639    /*
640     * Pass control to the single-threaded service skeleton.
641     */
642    single_server_main(argc, argv, bounce_service,
643		       MAIL_SERVER_INT_TABLE, int_table,
644		       MAIL_SERVER_STR_TABLE, str_table,
645		       MAIL_SERVER_TIME_TABLE, time_table,
646		       MAIL_SERVER_PRE_INIT, pre_jail_init,
647		       MAIL_SERVER_POST_INIT, post_jail_init,
648		       MAIL_SERVER_UNLIMITED,
649		       0);
650}
651