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