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