This is a minimal patch to add support for NDR filtering in the
Postfix SMTP client. It should work with Postfix 2.11, 2.12,
and it may even work with Postfix 2.10.
smtp_bounce_defer_filter (default: empty)
Optional filter to rewrite the three-number enhanced status code and
the explanatory text in a Postfix SMTP/LMTP client bounce/defer mes-
sage.
With each bounce or defer request, the user-specified filter is queried
with one line of text that is structured as follows:
enhanced-status-code SPACE explanatory-text
The bounce_defer_filter feature may replace this only with text that
has the same structure. Enhanced status codes must have a first numer-
ical field of 4 (defer) or 5 (bounce), and the free text field must be
non-empty. Other results will result in a warning.
Example:
The following example turns soft TLS errors into hard errors, by over-
riding the first number in the enhanced status code.
/etc/postfix/main.cf:
smtp_bounce_defer_filter = pcre:/etc/postfix/smtp_ndr_filter
/etc/postfix/smtp_ndr_filter:
/^4(\.\d+\.\d+ TLS is required, but host \S+ refused to start TLS: .+)
5$1
/^4(\.\d+\.\d+ TLS is required, but was not offered by host .+)
5$1
# Do not change the following into hard bounces. They may
# result from a local configuration problem.
# 4.\d+.\d+ TLS is required, but our TLS engine is unavailable
# 4.\d+.\d+ TLS is required, but unavailable
# 4.\d+.\d+ Cannot start TLS: handshake failure
Notes:
o This feature modifies error messages that are generated by the
Postfix SMTP client, and that may or may not be derived from
remote SMTP server responses. In contrast, the smtp_reply_fil-
ter feature modifies remote SMTP server responses that may
result in email non-delivery or delivery.
o This feature will NOT override the soft_bounce safety net.
o This feature will apply to all bounce/defer messages from the
Postfix SMTP/LMTP client.
o This feature will change the enhanced status code and text that
is logged to the maillog file, and that is reported tot the
sender.
diff --exclude=.indent.pro --exclude='lmdb*' --exclude='*TLS*' -cr --new-file /var/tmp/postfix-2.12-20140223/html/lmtp.8.html ./html/lmtp.8.html
*** /var/tmp/postfix-2.12-20140223/html/lmtp.8.html Sun Feb 23 17:27:33 2014
--- ./html/lmtp.8.html Sat Mar 15 18:21:46 2014
***************
*** 152,157 ****
--- 152,162 ----
smtp_never_send_ehlo (no)
Never send EHLO at the start of an SMTP session.
+ smtp_bounce_defer_filter (empty)
+ Optional filter to rewrite the three-number enhanced status code
+ and the explanatory text in a Postfix SMTP/LMTP client
+ bounce/defer message.
+
smtp_defer_if_no_mx_address_found (no)
Defer mail delivery when no MX record resolves to an IP address.
diff --exclude=.indent.pro --exclude='lmdb*' --exclude='*TLS*' -cr --new-file /var/tmp/postfix-2.12-20140223/html/postconf.5.html ./html/postconf.5.html
*** /var/tmp/postfix-2.12-20140223/html/postconf.5.html Fri Feb 14 09:48:42 2014
--- ./html/postconf.5.html Sat Mar 15 18:49:49 2014
***************
*** 3854,3859 ****
--- 3854,3870 ----
+
lmtp_bounce_defer_filter
+ (default: empty)
+
+ The LMTP-specific version of the smtp_bounce_defer_filter
+ configuration parameter. See there for details.
+
+ This feature is available in Postfix 2.12 and later.
+
+
+
+
lmtp_cache_connection
(default: yes)
***************
*** 9487,9492 ****
--- 9498,9576 ----
+ smtp_bounce_defer_filter
+ (default: empty)
+
+ Optional filter to rewrite the three-number enhanced status
+ code and the explanatory text in a Postfix SMTP/LMTP client
+ bounce/defer message.
+
+ With each bounce or defer request, the user-specified filter is
+ queried with one line of text that is structured as follows:
+
+
+ enhanced-status-code SPACE explanatory-text
+
+
+ The bounce_defer_filter feature may replace this only with text
+ that has the same structure. Enhanced status codes must have a
+ first numerical field of 4 (defer) or 5 (bounce), and the free text
+ field must be non-empty. Other results will result in a warning.
+
+
+ Example:
+
+ The following example turns soft TLS errors into hard errors,
+ by overriding the first number in the enhanced status code.
+
+
+
+ /etc/postfix/main.cf:
+ smtp_bounce_defer_filter = pcre:/etc/postfix/smtp_ndr_filter
+
+
+
+
+
+ /etc/postfix/smtp_ndr_filter:
+ /^4(\.\d+\.\d+ TLS is required, but host \S+ refused to start TLS: .+)
+ 5$1
+ /^4(\.\d+\.\d+ TLS is required, but was not offered by host .+)
+ 5$1
+ # Do not change the following into hard bounces. They may
+ # result from a local configuration problem.
+ # 4.\d+.\d+ TLS is required, but our TLS engine is unavailable
+ # 4.\d+.\d+ TLS is required, but unavailable
+ # 4.\d+.\d+ Cannot start TLS: handshake failure
+
+
+
+ Notes:
+
+
+
+ -
This feature modifies error messages that are generated
+ by the Postfix SMTP client, and that may or may not be derived from
+ remote SMTP server responses. In contrast, the smtp_reply_filter
+ feature modifies remote SMTP server responses that may result in
+ email non-delivery or delivery.
+
+ -
This feature will NOT override the soft_bounce safety net.
+
+ -
This feature will apply to all bounce/defer messages from
+ the Postfix SMTP/LMTP client.
+
+ -
This feature will change the enhanced status code and text
+ that is logged to the maillog file, and that is reported tot the
+ sender.
+
+
+
+ This feature is available in Postfix 2.12 and later.
+
+
+
+
smtp_cname_overrides_servername
(default: version dependent)
diff --exclude=.indent.pro --exclude='lmdb*' --exclude='*TLS*' -cr --new-file /var/tmp/postfix-2.12-20140223/html/smtp.8.html ./html/smtp.8.html
*** /var/tmp/postfix-2.12-20140223/html/smtp.8.html Sun Feb 23 17:27:33 2014
--- ./html/smtp.8.html Sat Mar 15 18:21:46 2014
***************
*** 152,157 ****
--- 152,162 ----
smtp_never_send_ehlo (no)
Never send EHLO at the start of an SMTP session.
+ smtp_bounce_defer_filter (empty)
+ Optional filter to rewrite the three-number enhanced status code
+ and the explanatory text in a Postfix SMTP/LMTP client
+ bounce/defer message.
+
smtp_defer_if_no_mx_address_found (no)
Defer mail delivery when no MX record resolves to an IP address.
diff --exclude=.indent.pro --exclude='lmdb*' --exclude='*TLS*' -cr --new-file /var/tmp/postfix-2.12-20140223/man/man5/postconf.5 ./man/man5/postconf.5
*** /var/tmp/postfix-2.12-20140223/man/man5/postconf.5 Fri Feb 14 09:48:42 2014
--- ./man/man5/postconf.5 Sat Mar 15 18:49:49 2014
***************
*** 2275,2280 ****
--- 2275,2285 ----
parameter. See there for details.
.PP
This feature is available in Postfix 2.5 and later.
+ .SH lmtp_bounce_defer_filter (default: empty)
+ The LMTP-specific version of the smtp_bounce_defer_filter
+ configuration parameter. See there for details.
+ .PP
+ This feature is available in Postfix 2.12 and later.
.SH lmtp_cache_connection (default: yes)
Keep Postfix LMTP client connections open for up to $max_idle
seconds. When the LMTP client receives a request for the same
***************
*** 5770,5775 ****
--- 5775,5851 ----
that change the delivery time or destination are not available.
.PP
This feature is available in Postfix 2.5 and later.
+ .SH smtp_bounce_defer_filter (default: empty)
+ Optional filter to rewrite the three-number enhanced status
+ code and the explanatory text in a Postfix SMTP/LMTP client
+ bounce/defer message.
+ .PP
+ With each bounce or defer request, the user-specified filter is
+ queried with one line of text that is structured as follows:
+ .sp
+ .in +4
+ enhanced-status-code SPACE explanatory-text
+ .in -4
+ .PP
+ The bounce_defer_filter feature may replace this only with text
+ that has the same structure. Enhanced status codes must have a
+ first numerical field of 4 (defer) or 5 (bounce), and the free text
+ field must be non-empty. Other results will result in a warning.
+ .PP
+ Example:
+ .PP
+ The following example turns soft TLS errors into hard errors,
+ by overriding the first number in the enhanced status code.
+ .sp
+ .in +4
+ .nf
+ .na
+ .ft C
+ /etc/postfix/main.cf:
+ smtp_bounce_defer_filter = pcre:/etc/postfix/smtp_ndr_filter
+ .fi
+ .ad
+ .ft R
+ .in -4
+ .sp
+ .in +4
+ .nf
+ .na
+ .ft C
+ /etc/postfix/smtp_ndr_filter:
+ /^4(\e.\ed+\e.\ed+ TLS is required, but host \eS+ refused to start TLS: .+)
+ 5$1
+ /^4(\e.\ed+\e.\ed+ TLS is required, but was not offered by host .+)
+ 5$1
+ # Do not change the following into hard bounces. They may
+ # result from a local configuration problem.
+ # 4.\ed+.\ed+ TLS is required, but our TLS engine is unavailable
+ # 4.\ed+.\ed+ TLS is required, but unavailable
+ # 4.\ed+.\ed+ Cannot start TLS: handshake failure
+ .fi
+ .ad
+ .ft R
+ .in -4
+ .PP
+ Notes:
+ .IP \(bu
+ This feature modifies error messages that are generated
+ by the Postfix SMTP client, and that may or may not be derived from
+ remote SMTP server responses. In contrast, the smtp_reply_filter
+ feature modifies remote SMTP server responses that may result in
+ email non-delivery or delivery.
+ .IP \(bu
+ This feature will NOT override the soft_bounce safety net.
+ .IP \(bu
+ This feature will apply to all bounce/defer messages from
+ the Postfix SMTP/LMTP client.
+ .IP \(bu
+ This feature will change the enhanced status code and text
+ that is logged to the maillog file, and that is reported tot the
+ sender.
+ .br
+ .PP
+ This feature is available in Postfix 2.12 and later.
.SH smtp_cname_overrides_servername (default: version dependent)
When the remote SMTP servername is a DNS CNAME, replace the
servername with the result from CNAME expansion for the purpose of
diff --exclude=.indent.pro --exclude='lmdb*' --exclude='*TLS*' -cr --new-file /var/tmp/postfix-2.12-20140223/man/man8/smtp.8 ./man/man8/smtp.8
*** /var/tmp/postfix-2.12-20140223/man/man8/smtp.8 Sun Feb 23 17:27:33 2014
--- ./man/man8/smtp.8 Sat Mar 15 18:21:46 2014
***************
*** 163,168 ****
--- 163,172 ----
Always send EHLO at the start of an SMTP session.
.IP "\fBsmtp_never_send_ehlo (no)\fR"
Never send EHLO at the start of an SMTP session.
+ .IP "\fBsmtp_bounce_defer_filter (empty)\fR"
+ Optional filter to rewrite the three-number enhanced status
+ code and the explanatory text in a Postfix SMTP/LMTP client
+ bounce/defer message.
.IP "\fBsmtp_defer_if_no_mx_address_found (no)\fR"
Defer mail delivery when no MX record resolves to an IP address.
.IP "\fBsmtp_line_length_limit (998)\fR"
diff --exclude=.indent.pro --exclude='lmdb*' --exclude='*TLS*' -cr --new-file /var/tmp/postfix-2.12-20140223/mantools/postlink ./mantools/postlink
*** /var/tmp/postfix-2.12-20140223/mantools/postlink Fri Dec 20 17:20:01 2013
--- ./mantools/postlink Sat Mar 15 18:34:17 2014
***************
*** 212,217 ****
--- 212,218 ----
s;\blmtp_address_preference\b;$&;g;
s;\blmtp_body_checks\b;$&;g;
s;\blmtp_cname_overrides_servername\b;$&;g;
+ s;\blmtp_bounce_defer_filter\b;$&;g;
s;\blmtp_dns_resolver_options\b;$&;g;
s;\blmtp_dns_support_level\b;$&;g;
s;\blmtp_header_checks\b;$&;g;
***************
*** 451,456 ****
--- 452,458 ----
s;\bsmtp_connection_cache_time_limit\b;$&;g;
s;\bsmtp_connection_cache_destinations\b;$&;g;
+ s;\bsmtp_bounce_defer_filter\b;$&;g;
s;\bsmtp_data_done_timeout\b;$&;g;
s;\bsmtp_data_init_timeout\b;$&;g;
s;\bsmtp_data_xfer_timeout\b;$&;g;
diff --exclude=.indent.pro --exclude='lmdb*' --exclude='*TLS*' -cr --new-file /var/tmp/postfix-2.12-20140223/proto/postconf.proto ./proto/postconf.proto
*** /var/tmp/postfix-2.12-20140223/proto/postconf.proto Fri Feb 14 09:47:30 2014
--- ./proto/postconf.proto Sat Mar 15 18:49:44 2014
***************
*** 15615,15617 ****
--- 15615,15693 ----
anchor assertion) TLSA records.
This feature is available in Postfix 2.11 and later.
+
+ %PARAM smtp_bounce_defer_filter
+
+ Optional filter to rewrite the three-number enhanced status
+ code and the explanatory text in a Postfix SMTP/LMTP client
+ bounce/defer message.
+
+ With each bounce or defer request, the user-specified filter is
+ queried with one line of text that is structured as follows:
+
+
+ enhanced-status-code SPACE explanatory-text
+
+
+ The bounce_defer_filter feature may replace this only with text
+ that has the same structure. Enhanced status codes must have a
+ first numerical field of 4 (defer) or 5 (bounce), and the free text
+ field must be non-empty. Other results will result in a warning.
+
+
+ Example:
+
+ The following example turns soft TLS errors into hard errors,
+ by overriding the first number in the enhanced status code.
+
+
+
+ /etc/postfix/main.cf:
+ smtp_bounce_defer_filter = pcre:/etc/postfix/smtp_ndr_filter
+
+
+
+
+
+ /etc/postfix/smtp_ndr_filter:
+ /^4(\.\d+\.\d+ TLS is required, but host \S+ refused to start TLS: .+)
+ 5$1
+ /^4(\.\d+\.\d+ TLS is required, but was not offered by host .+)
+ 5$1
+ # Do not change the following into hard bounces. They may
+ # result from a local configuration problem.
+ # 4.\d+.\d+ TLS is required, but our TLS engine is unavailable
+ # 4.\d+.\d+ TLS is required, but unavailable
+ # 4.\d+.\d+ Cannot start TLS: handshake failure
+
+
+
+ Notes:
+
+
+
+ -
This feature modifies error messages that are generated
+ by the Postfix SMTP client, and that may or may not be derived from
+ remote SMTP server responses. In contrast, the smtp_reply_filter
+ feature modifies remote SMTP server responses that may result in
+ email non-delivery or delivery.
+
+ -
This feature will NOT override the soft_bounce safety net.
+
+ -
This feature will apply to all bounce/defer messages from
+ the Postfix SMTP/LMTP client.
+
+ -
This feature will change the enhanced status code and text
+ that is logged to the maillog file, and that is reported tot the
+ sender.
+
+
+
+ This feature is available in Postfix 2.12 and later.
+
+ %PARAM lmtp_bounce_defer_filter
+
+ The LMTP-specific version of the smtp_bounce_defer_filter
+ configuration parameter. See there for details.
+
+ This feature is available in Postfix 2.12 and later.
diff --exclude=.indent.pro --exclude='lmdb*' --exclude='*TLS*' -cr --new-file /var/tmp/postfix-2.12-20140223/src/global/Makefile.in ./src/global/Makefile.in
*** /var/tmp/postfix-2.12-20140223/src/global/Makefile.in Mon Dec 9 15:13:50 2013
--- ./src/global/Makefile.in Sat Mar 15 19:02:42 2014
***************
*** 32,38 ****
match_service.c mail_conf_nint.c addr_match_list.c mail_conf_nbool.c \
smtp_reply_footer.c safe_ultostr.c verify_sender_addr.c \
dict_memcache.c mail_version.c memcache_proto.c server_acl.c \
! mkmap_fail.c haproxy_srvr.c
OBJS = abounce.o anvil_clnt.o been_here.o bounce.o bounce_log.o \
canon_addr.o cfg_parser.o cleanup_strerror.o cleanup_strflags.o \
clnt_stream.o conv_time.o db_common.o debug_peer.o debug_process.o \
--- 32,38 ----
match_service.c mail_conf_nint.c addr_match_list.c mail_conf_nbool.c \
smtp_reply_footer.c safe_ultostr.c verify_sender_addr.c \
dict_memcache.c mail_version.c memcache_proto.c server_acl.c \
! mkmap_fail.c haproxy_srvr.c ndr_filter.c
OBJS = abounce.o anvil_clnt.o been_here.o bounce.o bounce_log.o \
canon_addr.o cfg_parser.o cleanup_strerror.o cleanup_strflags.o \
clnt_stream.o conv_time.o db_common.o debug_peer.o debug_process.o \
***************
*** 66,72 ****
match_service.o mail_conf_nint.o addr_match_list.o mail_conf_nbool.o \
smtp_reply_footer.o safe_ultostr.o verify_sender_addr.o \
dict_memcache.o mail_version.o memcache_proto.o server_acl.o \
! mkmap_fail.o haproxy_srvr.o
HDRS = abounce.h anvil_clnt.h been_here.h bounce.h bounce_log.h \
canon_addr.h cfg_parser.h cleanup_user.h clnt_stream.h config.h \
conv_time.h db_common.h debug_peer.h debug_process.h defer.h \
--- 66,72 ----
match_service.o mail_conf_nint.o addr_match_list.o mail_conf_nbool.o \
smtp_reply_footer.o safe_ultostr.o verify_sender_addr.o \
dict_memcache.o mail_version.o memcache_proto.o server_acl.o \
! mkmap_fail.o haproxy_srvr.o ndr_filter.o
HDRS = abounce.h anvil_clnt.h been_here.h bounce.h bounce_log.h \
canon_addr.h cfg_parser.h cleanup_user.h clnt_stream.h config.h \
conv_time.h db_common.h debug_peer.h debug_process.h defer.h \
***************
*** 93,99 ****
fold_addr.h header_body_checks.h data_redirect.h match_service.h \
addr_match_list.h smtp_reply_footer.h safe_ultostr.h \
verify_sender_addr.h dict_memcache.h memcache_proto.h server_acl.h \
! haproxy_srvr.h
TESTSRC = rec2stream.c stream2rec.c recdump.c
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
CFLAGS = $(DEBUG) $(OPT) $(DEFS)
--- 93,99 ----
fold_addr.h header_body_checks.h data_redirect.h match_service.h \
addr_match_list.h smtp_reply_footer.h safe_ultostr.h \
verify_sender_addr.h dict_memcache.h memcache_proto.h server_acl.h \
! haproxy_srvr.h ndr_filter.h
TESTSRC = rec2stream.c stream2rec.c recdump.c
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
CFLAGS = $(DEBUG) $(OPT) $(DEFS)
***************
*** 666,671 ****
--- 666,672 ----
bounce.o: mail_params.h
bounce.o: mail_proto.h
bounce.o: msg_stats.h
+ bounce.o: ndr_filter.h
bounce.o: rcpt_print.h
bounce.o: recipient_list.h
bounce.o: trace.h
***************
*** 811,816 ****
--- 812,818 ----
defer.o: mail_proto.h
defer.o: mail_queue.h
defer.o: msg_stats.h
+ defer.o: ndr_filter.h
defer.o: rcpt_print.h
defer.o: recipient_list.h
defer.o: trace.h
***************
*** 1768,1773 ****
--- 1806,1825 ----
namadr_list.o: ../../include/sys_defs.h
namadr_list.o: namadr_list.c
namadr_list.o: namadr_list.h
+ ndr_filter.o: ../../include/argv.h
+ ndr_filter.o: ../../include/dict.h
+ ndr_filter.o: ../../include/msg.h
+ ndr_filter.o: ../../include/myflock.h
+ ndr_filter.o: ../../include/mymalloc.h
+ ndr_filter.o: ../../include/sys_defs.h
+ ndr_filter.o: ../../include/vbuf.h
+ ndr_filter.o: ../../include/vstream.h
+ ndr_filter.o: ../../include/vstring.h
+ ndr_filter.o: dsn.h
+ ndr_filter.o: dsn_util.h
+ ndr_filter.o: maps.h
+ ndr_filter.o: ndr_filter.c
+ ndr_filter.o: ndr_filter.h
off_cvt.o: ../../include/msg.h
off_cvt.o: ../../include/sys_defs.h
off_cvt.o: ../../include/vbuf.h
diff --exclude=.indent.pro --exclude='lmdb*' --exclude='*TLS*' -cr --new-file /var/tmp/postfix-2.12-20140223/src/global/bounce.c ./src/global/bounce.c
*** /var/tmp/postfix-2.12-20140223/src/global/bounce.c Tue May 15 16:13:00 2007
--- ./src/global/bounce.c Sat Mar 15 19:46:29 2014
***************
*** 48,53 ****
--- 48,66 ----
/* RECIPIENT *rcpt;
/* const char *relay;
/* DSN *dsn;
+ /*
+ /* void bounce_client_init(title, maps)
+ /* const char *title;
+ /* const char *maps;
+ /* INTERNAL API
+ /* NDR_FILTER *bounce_defer_filter;
+ /*
+ /* int bounce_append_intern(flags, id, stats, recipient, relay, dsn)
+ /* int flags;
+ /* const char *id;
+ /* MSG_STATS *stats;
+ /* RECIPIENT *rcpt;
+ /* const char *relay;
/* DESCRIPTION
/* This module implements the client interface to the message
/* bounce service, which maintains a per-message log of status
***************
*** 75,80 ****
--- 88,96 ----
/* return address in a manner that depends on the recipient
/* address.
/*
+ /* bounce_append_intern() is for use after the DSN filter. DSN
+ /* filtering is not yet supported for bounce_one().
+ /*
/* Arguments:
/* .IP flags
/* The bitwise OR of zero or more of the following (specify
***************
*** 158,163 ****
--- 174,180 ----
/* Global library. */
+ #define BOUNCE_DEFER_INTERN
#include
#include
#include
***************
*** 169,182 ****
#include
#include
! /* bounce_append - append dsn_text to per-message bounce log */
int bounce_append(int flags, const char *id, MSG_STATS *stats,
RECIPIENT *rcpt, const char *relay,
DSN *dsn)
{
DSN my_dsn = *dsn;
! int status;
/*
* Sanity check. If we're really confident, change this into msg_panic
--- 186,203 ----
#include
#include
! /* Shared internally, between bounce and defer clients. */
!
! NDR_FILTER *bounce_defer_filter;
!
! /* bounce_append - append delivery status to per-message bounce log */
int bounce_append(int flags, const char *id, MSG_STATS *stats,
RECIPIENT *rcpt, const char *relay,
DSN *dsn)
{
DSN my_dsn = *dsn;
! DSN *dsn_res;
/*
* Sanity check. If we're really confident, change this into msg_panic
***************
*** 188,193 ****
--- 209,235 ----
}
/*
+ * DSN filter (Postfix 2.12).
+ */
+ if (bounce_defer_filter != 0
+ && (dsn_res = ndr_filter_lookup(bounce_defer_filter, &my_dsn)) != 0) {
+ if (dsn_res->status[0] == '4')
+ return (defer_append_intern(flags, id, stats, rcpt, relay, dsn_res));
+ my_dsn = *dsn_res;
+ }
+ return (bounce_append_intern(flags, id, stats, rcpt, relay, &my_dsn));
+ }
+
+ /* bounce_append_intern - append delivery status to per-message bounce log */
+
+ int bounce_append_intern(int flags, const char *id, MSG_STATS *stats,
+ RECIPIENT *rcpt, const char *relay,
+ DSN *dsn)
+ {
+ DSN my_dsn = *dsn;
+ int status;
+
+ /*
* MTA-requested address verification information is stored in the verify
* service database.
*/
***************
*** 259,265 ****
vstring_sprintf(junk, "%s or %s service failure",
var_bounce_service, var_trace_service);
my_dsn.reason = vstring_str(junk);
! status = defer_append(flags, id, stats, rcpt, relay, &my_dsn);
vstring_free(junk);
} else {
status = -1;
--- 301,307 ----
vstring_sprintf(junk, "%s or %s service failure",
var_bounce_service, var_trace_service);
my_dsn.reason = vstring_str(junk);
! status = defer_append_intern(flags, id, stats, rcpt, relay, &my_dsn);
vstring_free(junk);
} else {
status = -1;
***************
*** 428,430 ****
--- 470,484 ----
return (status);
}
}
+
+ /* bounce_client_init - initialize bounce/defer DSN filter */
+
+ void bounce_client_init(const char *title, const char *maps)
+ {
+ const char myname[] = "bounce_client_init";
+
+ if (bounce_defer_filter != 0)
+ msg_panic("%s: duplicate initialization", myname);
+ if (*maps)
+ bounce_defer_filter = ndr_filter_create(title, maps);
+ }
diff --exclude=.indent.pro --exclude='lmdb*' --exclude='*TLS*' -cr --new-file /var/tmp/postfix-2.12-20140223/src/global/bounce.h ./src/global/bounce.h
*** /var/tmp/postfix-2.12-20140223/src/global/bounce.h Sat Jan 7 15:49:53 2006
--- ./src/global/bounce.h Sat Mar 15 18:28:59 2014
***************
*** 35,40 ****
--- 35,41 ----
const char *, const char *,
int, MSG_STATS *, RECIPIENT *,
const char *, DSN *);
+ extern void bounce_client_init(const char *, const char *);
/*
* Bounce/defer protocol commands.
***************
*** 65,70 ****
--- 66,90 ----
*/
#define BOUNCE_FLAG_KEEP BOUNCE_FLAG_NONE
+ /*
+ * Start of private API.
+ */
+
+ #ifdef BOUNCE_DEFER_INTERN
+
+ #include
+
+ extern NDR_FILTER *bounce_defer_filter;
+
+ extern int bounce_append_intern(int, const char *, MSG_STATS *, RECIPIENT *,
+ const char *, DSN *);
+ extern int bounce_one_intern(int, const char *, const char *, const char *,
+ const char *, const char *,
+ int, MSG_STATS *, RECIPIENT *,
+ const char *, DSN *);
+
+ #endif
+
/* LICENSE
/* .ad
/* .fi
diff --exclude=.indent.pro --exclude='lmdb*' --exclude='*TLS*' -cr --new-file /var/tmp/postfix-2.12-20140223/src/global/defer.c ./src/global/defer.c
*** /var/tmp/postfix-2.12-20140223/src/global/defer.c Tue May 15 16:13:13 2007
--- ./src/global/defer.c Sat Mar 15 19:46:41 2014
***************
*** 31,36 ****
--- 31,43 ----
/* const char *sender;
/* const char *dsn_envid;
/* int dsn_ret;
+ /* INTERNAL API
+ /* int defer_append_intern(flags, id, stats, rcpt, relay, dsn)
+ /* int flags;
+ /* const char *id;
+ /* MSG_STATS *stats;
+ /* RECIPIENT *rcpt;
+ /* const char *relay;
/* DESCRIPTION
/* This module implements a client interface to the defer service,
/* which maintains a per-message logfile with status records for
***************
*** 56,61 ****
--- 63,70 ----
/* question has been deferred. The defer log is not deleted,
/* and no recipients are deleted from the original queue file.
/*
+ /* defer_append_intern() is for use after the DSN filter.
+ /*
/* Arguments:
/* .IP flags
/* The bit-wise OR of zero or more of the following (specify
***************
*** 134,139 ****
--- 143,149 ----
/* Global library. */
+ #define BOUNCE_DEFER_INTERN
#include
#include
#include
***************
*** 154,162 ****
RECIPIENT *rcpt, const char *relay,
DSN *dsn)
{
- const char *rcpt_domain;
DSN my_dsn = *dsn;
! int status;
/*
* Sanity check.
--- 164,171 ----
RECIPIENT *rcpt, const char *relay,
DSN *dsn)
{
DSN my_dsn = *dsn;
! DSN *dsn_res;
/*
* Sanity check.
***************
*** 167,172 ****
--- 176,203 ----
}
/*
+ * DSN filter (Postfix 2.12).
+ */
+ if (bounce_defer_filter != 0
+ && (dsn_res = ndr_filter_lookup(bounce_defer_filter, &my_dsn)) != 0) {
+ if (dsn_res->status[0] == '5')
+ return (bounce_append_intern(flags, id, stats, rcpt, relay, dsn_res));
+ my_dsn = *dsn_res;
+ }
+ return (defer_append_intern(flags, id, stats, rcpt, relay, &my_dsn));
+ }
+
+ /* defer_append_intern - defer message delivery */
+
+ int defer_append_intern(int flags, const char *id, MSG_STATS *stats,
+ RECIPIENT *rcpt, const char *relay,
+ DSN *dsn)
+ {
+ const char *rcpt_domain;
+ DSN my_dsn = *dsn;
+ int status;
+
+ /*
* MTA-requested address verification information is stored in the verify
* service database.
*/
diff --exclude=.indent.pro --exclude='lmdb*' --exclude='*TLS*' -cr --new-file /var/tmp/postfix-2.12-20140223/src/global/defer.h ./src/global/defer.h
*** /var/tmp/postfix-2.12-20140223/src/global/defer.h Tue Nov 1 15:35:05 2005
--- ./src/global/defer.h Sat Mar 15 18:53:06 2014
***************
*** 26,31 ****
--- 26,41 ----
extern int defer_warn(int, const char *, const char *, const char *,
const char *, int);
+ /*
+ * Start of private API.
+ */
+ #ifdef BOUNCE_DEFER_INTERN
+
+ extern int defer_append_intern(int, const char *, MSG_STATS *, RECIPIENT *,
+ const char *, DSN *);
+
+ #endif
+
/* LICENSE
/* .ad
/* .fi
diff --exclude=.indent.pro --exclude='lmdb*' --exclude='*TLS*' -cr --new-file /var/tmp/postfix-2.12-20140223/src/global/mail_params.h ./src/global/mail_params.h
*** /var/tmp/postfix-2.12-20140223/src/global/mail_params.h Sat Dec 28 20:27:16 2013
--- ./src/global/mail_params.h Sat Mar 15 18:30:36 2014
***************
*** 3744,3749 ****
--- 3744,3758 ----
#define DEF_DAEMON_OPEN_FATAL 0
extern bool var_daemon_open_fatal;
+ /*
+ * Optional DSN bounce/defer filter.
+ */
+ #define VAR_SMTP_NDR_FILTER "smtp_bounce_defer_filter"
+ #define DEF_SMTP_NDR_FILTER ""
+ #define VAR_LMTP_NDR_FILTER "lmtp_bounce_defer_filter"
+ #define DEF_LMTP_NDR_FILTER ""
+ extern char *var_ndr_filter;
+
/* LICENSE
/* .ad
/* .fi
diff --exclude=.indent.pro --exclude='lmdb*' --exclude='*TLS*' -cr --new-file /var/tmp/postfix-2.12-20140223/src/global/ndr_filter.c ./src/global/ndr_filter.c
*** /var/tmp/postfix-2.12-20140223/src/global/ndr_filter.c Wed Dec 31 19:00:00 1969
--- ./src/global/ndr_filter.c Sat Mar 15 20:14:11 2014
***************
*** 0 ****
--- 1,178 ----
+ /*++
+ /* NAME
+ /* ndr_filter 3
+ /* SUMMARY
+ /* bounce or defer NDR filter
+ /* SYNOPSIS
+ /* #include
+ /*
+ /* NDR_FILTER *ndr_filter_create(
+ /* const char *title,
+ /* const char *map_names)
+ /*
+ /* DSN *ndr_filter_lookup(
+ /* NDR_FILTER *fp,
+ /* DSN dsn)
+ /*
+ /* void dsn_free(
+ /* NDR_FILTER *fp)
+ /* DESCRIPTION
+ /* This module maps a bounce or defer non-delivery status code
+ /* and text into a bounce or defer non-delivery status code
+ /* and text. The other DSN attributes are passed through without
+ /* modification.
+ /*
+ /* ndr_filter_create() instantiates a bounce or defer NDR filter.
+ /*
+ /* ndr_filter_lookup() queries the specified filter. The DSN
+ /* must be a bounce or defer DSN. If a match is found and the
+ /* result is properly formatted, the result value must specify
+ /* a bounce or defer DSN. The result is in part overwritten
+ /* upon each call, and is in part a shallow copy of the dsn
+ /* argument. The result is a null pointer when no valid match
+ /* is found. This function must not be called with the result
+ /* from a ndr_filter_lookup() call.
+ /*
+ /* dsn_free() destroys the specified NDR filter.
+ /*
+ /* Arguments:
+ /* .IP title
+ /* Origin of the mapnames argument, typically a configuration
+ /* parameter name. This is reported in diagnostics.
+ /* .IP mapnames
+ /* List of lookup tables, separated by whitespace or comma.
+ /* .IP fp
+ /* filter created with ndr_filter_create()
+ /* .IP dsn
+ /* A bounce or defer DSN data structure. The ndr_filter_lookup()
+ /* result value is in part a shallow copy of this argument.
+ /* SEE ALSO
+ /* maps(3) multi-table search
+ /* DIAGNOSTICS
+ /* Panic: invalid dsn argument; recursive call. Fatal error:
+ /* memory allocation problem. Warning: invalid DSN lookup
+ /* result.
+ /* LICENSE
+ /* .ad
+ /* .fi
+ /* The Secure Mailer license must be distributed with this software.
+ /* AUTHOR(S)
+ /* Wietse Venema
+ /* IBM T.J. Watson Research
+ /* P.O. Box 704
+ /* Yorktown Heights, NY 10598, USA
+ /*--*/
+
+ /*
+ * System libraries.
+ */
+ #include
+
+ /*
+ * Utility library.
+ */
+ #include
+ #include
+ #include
+
+ /*
+ * Global library.
+ */
+ #include
+ #include
+ #include
+ #include
+ #include
+
+ /*
+ * Private data structure.
+ */
+ struct NDR_FILTER {
+ MAPS *maps;
+ VSTRING *buffer; /* status code and text */
+ DSN_SPLIT dp;
+ DSN dsn; /* Shallow copy */
+ };
+
+ /*
+ * SLMs.
+ */
+ #define STR(x) vstring_str(x)
+
+ /* ndr_filter_create - create bounce/defer NDR filter */
+
+ NDR_FILTER *ndr_filter_create(const char *title, const char *map_names)
+ {
+ const char myname[] = "ndr_filter_create";
+ NDR_FILTER *fp;
+
+ if (msg_verbose)
+ msg_info("%s: %s %s", myname, title, map_names);
+
+ fp = (NDR_FILTER *) mymalloc(sizeof(*fp));
+ fp->buffer = vstring_alloc(100);
+ fp->maps = maps_create(title, map_names, DICT_FLAG_LOCK);
+ return (fp);
+ }
+
+ /* ndr_filter_lookup - apply bounce/defer NDR filter */
+
+ DSN *ndr_filter_lookup(NDR_FILTER *fp, DSN *dsn)
+ {
+ const char myname[] = "ndr_filter_lookup";
+ const char *result;
+
+ if (msg_verbose)
+ msg_info("%s: %s %s", myname, dsn->status, dsn->reason);
+
+ #define IS_NDR_DSN(s) \
+ (dsn_valid(s) && (s)[1] == '.' && ((s)[0] == '4' || (s)[0] == '5'))
+
+ /*
+ * Sanity check. We filter only bounce/defer DSNs.
+ */
+ if (!IS_NDR_DSN(dsn->status))
+ msg_panic("%s: dsn argument with bad status code: %s",
+ myname, dsn->status);
+
+ /*
+ * Sanity check. An NDR filter must not be invoked with its own result.
+ */
+ if (dsn->reason == fp->dsn.reason)
+ msg_panic("%s: recursive call is not allowed", myname);
+
+ /*
+ * Look up replacement status and text.
+ */
+ vstring_sprintf(fp->buffer, "%s %s", dsn->status, dsn->reason);
+ if ((result = maps_find(fp->maps, STR(fp->buffer), 0)) != 0) {
+ /* Sanity check. We accept only bounce/defer DSNs. */
+ if (!IS_NDR_DSN(result)) {
+ msg_warn("%s: bad status code: %s", fp->maps->title, result);
+ return (0);
+ } else {
+ vstring_strcpy(fp->buffer, result);
+ dsn_split(&fp->dp, "can't happen", STR(fp->buffer));
+ (void) DSN_ASSIGN(&fp->dsn, DSN_STATUS(fp->dp.dsn),
+ (result[0] == '4' ? "delayed" : "failed"),
+ fp->dp.text, dsn->dtype, dsn->dtext,
+ dsn->mtype, dsn->mname);
+ return (&fp->dsn);
+ }
+ }
+ return (0);
+ }
+
+ /* ndr_filter_free - destroy bounce/defer NDR filter */
+
+ void ndr_filter_free(NDR_FILTER *fp)
+ {
+ const char myname[] = "ndr_filter_free";
+
+ if (msg_verbose)
+ msg_info("%s: %s", myname, fp->maps->title);
+
+ maps_free(fp->maps);
+ vstring_free(fp->buffer);
+ myfree((char *) fp);
+ }
diff --exclude=.indent.pro --exclude='lmdb*' --exclude='*TLS*' -cr --new-file /var/tmp/postfix-2.12-20140223/src/global/ndr_filter.h ./src/global/ndr_filter.h
*** /var/tmp/postfix-2.12-20140223/src/global/ndr_filter.h Wed Dec 31 19:00:00 1969
--- ./src/global/ndr_filter.h Sat Mar 15 17:27:29 2014
***************
*** 0 ****
--- 1,34 ----
+ #ifndef _NDR_FILTER_H_INCLUDED_
+ #define _NDR_FILTER_H_INCLUDED_
+
+ /*++
+ /* NAME
+ /* ndr_filter 3h
+ /* SUMMARY
+ /* bounce/defer DSN filter
+ /* SYNOPSIS
+ /* #include
+ /* DESCRIPTION
+ /* .nf
+
+ /*
+ * External interface.
+ */
+ typedef struct NDR_FILTER NDR_FILTER;
+
+ extern NDR_FILTER *ndr_filter_create(const char *, const char *);
+ extern DSN *ndr_filter_lookup(NDR_FILTER *, DSN *);
+ extern void ndr_filter_free(NDR_FILTER *);
+
+ /* LICENSE
+ /* .ad
+ /* .fi
+ /* The Secure Mailer license must be distributed with this software.
+ /* AUTHOR(S)
+ /* Wietse Venema
+ /* IBM T.J. Watson Research
+ /* P.O. Box 704
+ /* Yorktown Heights, NY 10598, USA
+ /*--*/
+
+ #endif
diff --exclude=.indent.pro --exclude='lmdb*' --exclude='*TLS*' -cr --new-file /var/tmp/postfix-2.12-20140223/src/master/mail_server.h ./src/master/mail_server.h
*** /var/tmp/postfix-2.12-20140223/src/master/mail_server.h Thu Jun 14 15:43:35 2012
--- ./src/master/mail_server.h Sat Mar 15 08:38:01 2014
***************
*** 38,43 ****
--- 38,44 ----
#define MAIL_SERVER_IN_FLOW_DELAY 20
#define MAIL_SERVER_SLOW_EXIT 21
+ #define MAIL_SERVER_BOUNCE_INIT 22
typedef void (*MAIL_SERVER_INIT_FN) (char *, char **);
typedef int (*MAIL_SERVER_LOOP_FN) (char *, char **);
diff --exclude=.indent.pro --exclude='lmdb*' --exclude='*TLS*' -cr --new-file /var/tmp/postfix-2.12-20140223/src/master/single_server.c ./src/master/single_server.c
*** /var/tmp/postfix-2.12-20140223/src/master/single_server.c Thu Jun 21 09:15:04 2012
--- ./src/master/single_server.c Sat Mar 15 17:19:04 2014
***************
*** 118,123 ****
--- 118,126 ----
/* This service must be configured with process limit of 0.
/* .IP MAIL_SERVER_PRIVILEGED
/* This service must be configured as privileged.
+ /* .IP "MAIL_SERVER_BOUNCE_INIT (const char *, const char **)"
+ /* Initialize the DSN filter for the bounce/defer service
+ /* clients with the specified map source and map names.
/* .PP
/* The var_use_limit variable limits the number of clients that
/* a server can service before it commits suicide.
***************
*** 194,199 ****
--- 197,203 ----
#include
#include
#include
+ #include
/* Process manager. */
***************
*** 430,435 ****
--- 434,441 ----
char *generation;
int msg_vstream_needed = 0;
int redo_syslog_init = 0;
+ const char *ndr_filter_title;
+ const char **ndr_filter_maps;
/*
* Process environment options as early as we can.
***************
*** 631,636 ****
--- 637,647 ----
msg_fatal("service %s requires privileged operation",
service_name);
break;
+ case MAIL_SERVER_BOUNCE_INIT:
+ ndr_filter_title = va_arg(ap, const char *);
+ ndr_filter_maps = va_arg(ap, const char **);
+ bounce_client_init(ndr_filter_title, *ndr_filter_maps);
+ break;
default:
msg_panic("%s: unknown argument type: %d", myname, key);
}
diff --exclude=.indent.pro --exclude='lmdb*' --exclude='*TLS*' -cr --new-file /var/tmp/postfix-2.12-20140223/src/smtp/lmtp_params.c ./src/smtp/lmtp_params.c
*** /var/tmp/postfix-2.12-20140223/src/smtp/lmtp_params.c Thu Feb 20 19:54:26 2014
--- ./src/smtp/lmtp_params.c Sat Mar 15 18:02:56 2014
***************
*** 57,62 ****
--- 57,63 ----
VAR_LMTP_RESP_FILTER, DEF_LMTP_RESP_FILTER, &var_smtp_resp_filter, 0, 0,
VAR_LMTP_ADDR_PREF, DEF_LMTP_ADDR_PREF, &var_smtp_addr_pref, 1, 0,
VAR_LMTP_DNS_RES_OPT, DEF_LMTP_DNS_RES_OPT, &var_smtp_dns_res_opt, 0, 0,
+ VAR_LMTP_NDR_FILTER, DEF_LMTP_NDR_FILTER, &var_smtp_ndr_filter, 0, 0,
0,
};
static const CONFIG_TIME_TABLE lmtp_time_table[] = {
diff --exclude=.indent.pro --exclude='lmdb*' --exclude='*TLS*' -cr --new-file /var/tmp/postfix-2.12-20140223/src/smtp/smtp.c ./src/smtp/smtp.c
*** /var/tmp/postfix-2.12-20140223/src/smtp/smtp.c Sun Feb 23 17:27:33 2014
--- ./src/smtp/smtp.c Sat Mar 15 18:21:41 2014
***************
*** 141,146 ****
--- 141,150 ----
/* Always send EHLO at the start of an SMTP session.
/* .IP "\fBsmtp_never_send_ehlo (no)\fR"
/* Never send EHLO at the start of an SMTP session.
+ /* .IP "\fBsmtp_bounce_defer_filter (empty)\fR"
+ /* Optional filter to rewrite the three-number enhanced status
+ /* code and the explanatory text in a Postfix SMTP/LMTP client
+ /* bounce/defer message.
/* .IP "\fBsmtp_defer_if_no_mx_address_found (no)\fR"
/* Defer mail delivery when no MX record resolves to an IP address.
/* .IP "\fBsmtp_line_length_limit (998)\fR"
***************
*** 876,881 ****
--- 880,886 ----
char *var_smtp_dns_support;
bool var_smtp_rec_deadline;
bool var_smtp_dummy_mail_auth;
+ char *var_smtp_ndr_filter;
/* Special handling of 535 AUTH errors. */
char *var_smtp_sasl_auth_cache_name;
***************
*** 1271,1275 ****
--- 1276,1282 ----
MAIL_SERVER_PRE_INIT, pre_init,
MAIL_SERVER_POST_INIT, post_init,
MAIL_SERVER_PRE_ACCEPT, pre_accept,
+ MAIL_SERVER_BOUNCE_INIT, VAR_SMTP_NDR_FILTER,
+ &var_smtp_ndr_filter,
0);
}
diff --exclude=.indent.pro --exclude='lmdb*' --exclude='*TLS*' -cr --new-file /var/tmp/postfix-2.12-20140223/src/smtp/smtp_params.c ./src/smtp/smtp_params.c
*** /var/tmp/postfix-2.12-20140223/src/smtp/smtp_params.c Thu Feb 20 19:53:48 2014
--- ./src/smtp/smtp_params.c Sat Mar 15 18:02:46 2014
***************
*** 58,63 ****
--- 58,64 ----
VAR_SMTP_RESP_FILTER, DEF_SMTP_RESP_FILTER, &var_smtp_resp_filter, 0, 0,
VAR_SMTP_ADDR_PREF, DEF_SMTP_ADDR_PREF, &var_smtp_addr_pref, 1, 0,
VAR_SMTP_DNS_RES_OPT, DEF_SMTP_DNS_RES_OPT, &var_smtp_dns_res_opt, 0, 0,
+ VAR_SMTP_NDR_FILTER, DEF_SMTP_NDR_FILTER, &var_smtp_ndr_filter, 0, 0,
0,
};
static const CONFIG_TIME_TABLE smtp_time_table[] = {