The fixes in this release are back-ports from code that was field tested in Postfix 2.4. - On Redhat Linux, a Postfix daemon could lock up while logging a warning from a signal handler before exiting. This is remedied by a low-cost re-entrancy guard for signal handlers that never return. - Message headers longer than 65535 broke the Milter protocol. To make matters worse the cleanup server would then dereference a null pointer. When Milter support is enabled, the length of each message header is now limited to 60000. - Several fixes to improve worst-case behavior of the (new) queue manager with multi-recipient mail. The queue manager now reads new recipients earlier from the queue file, instead of becoming starved while waiting for the slowest in-memory recipients to complete; and it now reads recipients in smaller chunks to avoid spending too much time not talking to delivery agents. - With remote SMTP server tarpit delays larger than the Postfix SMTP client's smtp_rset_timeout (default: 20s), the client would get out of sync with the server while reusing a connection. The symptoms were "recipient rejected .. in reply to DATA". - On FreeBSD 6.2, Some Postfix daemon processes would complain once with "Error 0" after "postfix reload" and then recover. This warning is now logged only when the problem persists. Prereq: "2.3.4" diff -cr /var/tmp/postfix-2.3.4/src/global/mail_version.h ./src/global/mail_version.h *** /var/tmp/postfix-2.3.4/src/global/mail_version.h Wed Nov 1 14:41:35 2006 --- ./src/global/mail_version.h Mon Dec 11 20:43:55 2006 *************** *** 20,27 **** * Patches change both the patchlevel and the release date. Snapshots have no * patchlevel; they change the release date only. */ ! #define MAIL_RELEASE_DATE "20061101" ! #define MAIL_VERSION_NUMBER "2.3.4" #ifdef SNAPSHOT # define MAIL_VERSION_DATE "-" MAIL_RELEASE_DATE --- 20,27 ---- * Patches change both the patchlevel and the release date. Snapshots have no * patchlevel; they change the release date only. */ ! #define MAIL_RELEASE_DATE "20061211" ! #define MAIL_VERSION_NUMBER "2.3.5" #ifdef SNAPSHOT # define MAIL_VERSION_DATE "-" MAIL_RELEASE_DATE diff -cr /var/tmp/postfix-2.3.4/HISTORY ./HISTORY *** /var/tmp/postfix-2.3.4/HISTORY Thu Oct 19 11:16:11 2006 --- ./HISTORY Sun Dec 10 15:05:41 2006 *************** *** 12769,12771 **** --- 12769,12864 ---- Bugfix: null pointer bug when receiving a non-protocol response on a cached SMTP/LMTP connection. Report by Brian Kantor. Fix by Victor Duchovni. File: smtp/smtp_reuse.c. + + 20061113 + + Bugfix: the Postfix install/upgrade procedure broke with + non-default config_directory. File: conf/post-install. + + 20061115 + + Bugfix: null pointer bug in end-of-header Milter action + when the last header line is too large. Reported by Mark + Martinec. The root of the problem is that the MIME state + engine may execute up to three call-back functions when it + reaches the end of the headers, before it returns to the + caller; as long as call-backs return no result, each call-back + has to check for itself if a previous call-back ran into a + problem. File: milter/milter8.c. + + Workaround: reduce effective header_size_limit to 60000 + when Milter inspection is enabled, to avoid breaking the + Milter protocol request length limit. File: + cleanup/cleanup_message.c. + + 20061123 + + Workaround: more agressive early refill of in-memory + recipients to prevent a worst-case scenario where the queue + manager became starved until after the last batch of slow + in-memory recipients of jumbo multi-recipient mail. Files: + qmgr/qmgr_job.c. + + Safety: don't read more than 5000 recipients at a time, to + avoid spending too much time away from interrupts. File: + qmgr/qmgr_message.c. + + 20061201 + + Workaround: don't complain with "Error 0" in the trivial-rewrite, + verify, proxymap or connection cache client when the server + exits after the client sends its request. We still complain, + however, when the problem persists. Files: global/rewrite_clnt.c, + global/resolve_clnt.c, global/verify_clnt.c, global/scache_clnt.c, + global/dict_proxy.c. + + + Safety: the header_size_limit is now enforced more strictly, + to avoid inter-operability problems with the Milter protocol. + Long headers are truncated at a line boundary if possible, + otherwise they are cut between line boundaries. File: + cleanup/cleanup_out.c. + + 20061203 + + Bugfix (introduced with Postfix 2.2): with SMTP server + tarpit delays of smtp_rset_timeout or larger, the SMTP + client could get out of sync with the server while reusing + a connection. The symptoms were "recipient rejected .. in + reply to DATA". Fix by Victor Duchovni and Wietse. File: + smtp/smtp_proto.c. + + 20061207 + + Compatibility with Postfix < 2.3: undo the change to bounce + instead of defer after pipe-to-command delivery fails with + a signal. File: global/pipe_command.c. + + 20061208 + + Workaround: apparently, some mail software removes or hides + "" in the Postfix bounce text, because it + processes the text as if it were HTML. This confuses users. + The bounce template has been updated to remove the < and + >. File: bounce/bounce_templates.c. + + Cleanup: when smtp_generic_maps is turned on, don't parse + MIME structures in the message body. Victor Duchovni. File: + smtp/smtp_proto.c. + + 20061210 + + Robustness: low-cost re-entrancy guard that allows daemons + to call msg_fatal() etc. from a signal handler, without + risking memory corruption, or deadlock on Redhat Linux. + This works provided that the signal handler never returns. + In that special case we need not guarantee after-the-fact + consistency of the interrupted process. File: util/msg_output.c. + + Robustness: replace exit() calls by _exit(). File: util/msg.c, + bounce/bounce_cleanup.c. + + Cleanup: document under what conditions these protections + work, with REENTRANCY sections in the relevant man pages. + Files: util/vbuf.c. util/msg.c, util/msg_output.c. + diff -cr /var/tmp/postfix-2.3.4/AAAREADME ./AAAREADME *** /var/tmp/postfix-2.3.4/AAAREADME Fri Jul 7 21:00:55 2006 --- ./AAAREADME Fri Nov 10 07:11:19 2006 *************** *** 135,141 **** src/cleanup/ Canonicalize and enqueue mail src/discard/ Trivial discard mailer src/error/ Trivial error mailer - src/lmtp/ LMTP client src/local/ Local delivery src/master/ Postfix resident superserver src/oqmgr/ Old queue manager --- 135,140 ---- *************** *** 144,152 **** src/qmgr/ Queue manager src/qmqpd/ QMQPD server src/showq/ List Postfix queue status ! src/smtp/ SMTP client src/smtpd/ SMTP server src/spawn/ Run non-Postfix server src/trivial-rewrite/ Address rewriting and resolving src/verify/ address verification service src/virtual/ virtual mailbox-only delivery agent --- 143,152 ---- src/qmgr/ Queue manager src/qmqpd/ QMQPD server src/showq/ List Postfix queue status ! src/smtp/ SMTP and LMTP client src/smtpd/ SMTP server src/spawn/ Run non-Postfix server + src/tlsmgr/ TLS session keys and random pool src/trivial-rewrite/ Address rewriting and resolving src/verify/ address verification service src/virtual/ virtual mailbox-only delivery agent diff -cr /var/tmp/postfix-2.3.4/README_FILES/ADDRESS_REWRITING_README ./README_FILES/ADDRESS_REWRITING_README *** /var/tmp/postfix-2.3.4/README_FILES/ADDRESS_REWRITING_README Thu May 18 15:22:14 2006 --- ./README_FILES/ADDRESS_REWRITING_README Sat Dec 2 08:02:45 2006 *************** *** 787,800 **** Content-Description: Notification Content-Type: text/plain ! This is the Postfix program at host spike.porcupine.org. Enclosed is the mail delivery report that you requested. ! The Postfix program : delivery via mail.cloud9.net[168.100.1.4]: 250 ! Ok The second part of the report is in machine-readable form, and includes the following information: --- 787,800 ---- Content-Description: Notification Content-Type: text/plain ! This is the mail system at host spike.porcupine.org. Enclosed is the mail delivery report that you requested. ! The mail system : delivery via mail.cloud9.net[168.100.1.4]: 250 ! 2.1.5 Ok The second part of the report is in machine-readable form, and includes the following information: *************** *** 814,826 **** Reporting-MTA: dns; spike.porcupine.org X-Postfix-Queue-ID: 84863BC0E5 X-Postfix-Sender: rfc822; wietse@porcupine.org ! Arrival-Date: Tue, 13 Apr 2004 19:27:43 -0400 (EDT) Final-Recipient: rfc822; postfix-users@postfix.org Action: deliverable ! Status: 2.0.0 Remote-MTA: dns; mail.cloud9.net ! Diagnostic-Code: smtp; 250 Ok The third part of the report contains the message that Postfix would have delivered, including From: and To: message headers, so that you can see any --- 814,826 ---- Reporting-MTA: dns; spike.porcupine.org X-Postfix-Queue-ID: 84863BC0E5 X-Postfix-Sender: rfc822; wietse@porcupine.org ! Arrival-Date: Sun, 26 Nov 2006 17:01:01 -0500 (EST) Final-Recipient: rfc822; postfix-users@postfix.org Action: deliverable ! Status: 2.1.5 Remote-MTA: dns; mail.cloud9.net ! Diagnostic-Code: smtp; 250 2.1.5 Ok The third part of the report contains the message that Postfix would have delivered, including From: and To: message headers, so that you can see any *************** *** 831,840 **** Content-Type: message/rfc822 Received: by spike.porcupine.org (Postfix, from userid 1001) ! id 84863BC0E5; Tue, 13 Apr 2004 19:27:43 -0400 (EDT) Subject: probe To: postfix-users@postfix.org ! Message-Id: <20040413232743.84863BC0E5@spike.porcupine.org> ! Date: Tue, 13 Apr 2004 19:27:43 -0400 (EDT) From: wietse@porcupine.org (Wietse Venema) --- 831,840 ---- Content-Type: message/rfc822 Received: by spike.porcupine.org (Postfix, from userid 1001) ! id 84863BC0E5; Sun, 26 Nov 2006 17:01:01 -0500 (EST) Subject: probe To: postfix-users@postfix.org ! Message-Id: <20061126220101.84863BC0E5@spike.porcupine.org> ! Date: Sun, 26 Nov 2006 17:01:01 -0500 (EST) From: wietse@porcupine.org (Wietse Venema) diff -cr /var/tmp/postfix-2.3.4/conf/post-install ./conf/post-install *** /var/tmp/postfix-2.3.4/conf/post-install Mon Aug 7 10:48:42 2006 --- ./conf/post-install Mon Nov 13 16:34:32 2006 *************** *** 589,602 **** # This safety net is also documented in LOCAL_RECIPIENT_README. unknown_local=unknown_local_recipient_reject_code ! has_lrm=`$POSTCONF -n local_recipient_maps` ! has_lrjc=`$POSTCONF -n $unknown_local` if [ -z "$has_lrm" -a -z "$has_lrjc" ] then echo SAFETY: editing main.cf, setting $unknown_local=450. echo See the LOCAL_RECIPIENT_README file for details. ! $POSTCONF -e "$unknown_local = 450" || exit 1 fi # Add missing proxymap service to master.cf. --- 589,602 ---- # This safety net is also documented in LOCAL_RECIPIENT_README. unknown_local=unknown_local_recipient_reject_code ! has_lrm=`$POSTCONF -c $config_directory -n local_recipient_maps` ! has_lrjc=`$POSTCONF -c $config_directory -n $unknown_local` if [ -z "$has_lrm" -a -z "$has_lrjc" ] then echo SAFETY: editing main.cf, setting $unknown_local=450. echo See the LOCAL_RECIPIENT_README file for details. ! $POSTCONF -c $config_directory -e "$unknown_local = 450" || exit 1 fi # Add missing proxymap service to master.cf. *************** *** 678,685 **** test -n "$first_install_reminder" && { ! ALIASES=`$POSTCONF -h alias_database | sed 's/^[^:]*://'` ! NEWALIASES_PATH=`$POSTCONF -h newaliases_path` cat < --- 1174,1186 ---- Content-Description: Notification Content-Type: text/plain ! This is the mail system at host spike.porcupine.org. Enclosed is the mail delivery report that you requested. ! The mail system ! <postfix-users@postfix.org>: delivery via mail.cloud9.net[168.100.1.4]: 250 2.1.5 Ok *************** *** 1210,1222 **** Reporting-MTA: dns; spike.porcupine.org X-Postfix-Queue-ID: 84863BC0E5 X-Postfix-Sender: rfc822; wietse@porcupine.org ! Arrival-Date: Tue, 13 Apr 2004 19:27:43 -0400 (EDT) Final-Recipient: rfc822; postfix-users@postfix.org Action: deliverable ! Status: 2.0.0 Remote-MTA: dns; mail.cloud9.net ! Diagnostic-Code: smtp; 250 Ok --- 1210,1222 ---- Reporting-MTA: dns; spike.porcupine.org X-Postfix-Queue-ID: 84863BC0E5 X-Postfix-Sender: rfc822; wietse@porcupine.org ! Arrival-Date: Sun, 26 Nov 2006 17:01:01 -0500 (EST) Final-Recipient: rfc822; postfix-users@postfix.org Action: deliverable ! Status: 2.1.5 Remote-MTA: dns; mail.cloud9.net ! Diagnostic-Code: smtp; 250 2.1.5 Ok *************** *** 1232,1242 **** Content-Type: message/rfc822 Received: by spike.porcupine.org (Postfix, from userid 1001) ! id 84863BC0E5; Tue, 13 Apr 2004 19:27:43 -0400 (EDT) Subject: probe To: postfix-users@postfix.org ! Message-Id: <20040413232743.84863BC0E5@spike.porcupine.org> ! Date: Tue, 13 Apr 2004 19:27:43 -0400 (EDT) From: wietse@porcupine.org (Wietse Venema) --- 1232,1242 ---- Content-Type: message/rfc822 Received: by spike.porcupine.org (Postfix, from userid 1001) ! id 84863BC0E5; Sun, 26 Nov 2006 17:01:01 -0500 (EST) Subject: probe To: postfix-users@postfix.org ! Message-Id: <20061126220101.84863BC0E5@spike.porcupine.org> ! Date: Sun, 26 Nov 2006 17:01:01 -0500 (EST) From: wietse@porcupine.org (Wietse Venema) diff -cr /var/tmp/postfix-2.3.4/html/bounce.5.html ./html/bounce.5.html *** /var/tmp/postfix-2.3.4/html/bounce.5.html Sun Aug 6 10:39:51 2006 --- ./html/bounce.5.html Fri Dec 8 22:02:29 2006 *************** *** 81,87 **** I'm sorry to have to inform you that your message could not be delivered to one or more recipients. It's attached below. ! For further assistance, please send mail to <postmaster> If you do so, please include this problem report. You can delete your own text from the attached returned message. --- 81,87 ---- I'm sorry to have to inform you that your message could not be delivered to one or more recipients. It's attached below. ! For further assistance, please send mail to postmaster. If you do so, please include this problem report. You can delete your own text from the attached returned message. diff -cr /var/tmp/postfix-2.3.4/man/man5/bounce.5 ./man/man5/bounce.5 *** /var/tmp/postfix-2.3.4/man/man5/bounce.5 Sun Aug 6 10:39:51 2006 --- ./man/man5/bounce.5 Fri Dec 8 22:02:28 2006 *************** *** 91,97 **** I'm sorry to have to inform you that your message could not be delivered to one or more recipients. It's attached below. ! For further assistance, please send mail to If you do so, please include this problem report. You can delete your own text from the attached returned message. --- 91,97 ---- I'm sorry to have to inform you that your message could not be delivered to one or more recipients. It's attached below. ! For further assistance, please send mail to postmaster. If you do so, please include this problem report. You can delete your own text from the attached returned message. diff -cr /var/tmp/postfix-2.3.4/proto/ADDRESS_REWRITING_README.html ./proto/ADDRESS_REWRITING_README.html *** /var/tmp/postfix-2.3.4/proto/ADDRESS_REWRITING_README.html Thu May 18 15:21:19 2006 --- ./proto/ADDRESS_REWRITING_README.html Sat Dec 2 08:01:43 2006 *************** *** 1174,1186 **** Content-Description: Notification Content-Type: text/plain ! This is the Postfix program at host spike.porcupine.org. Enclosed is the mail delivery report that you requested. ! The Postfix program ! <postfix-users@postfix.org>: delivery via mail.cloud9.net[168.100.1.4]: 250 Ok --- 1174,1186 ---- Content-Description: Notification Content-Type: text/plain ! This is the mail system at host spike.porcupine.org. Enclosed is the mail delivery report that you requested. ! The mail system ! <postfix-users@postfix.org>: delivery via mail.cloud9.net[168.100.1.4]: 250 2.1.5 Ok *************** *** 1210,1222 **** Reporting-MTA: dns; spike.porcupine.org X-Postfix-Queue-ID: 84863BC0E5 X-Postfix-Sender: rfc822; wietse@porcupine.org ! Arrival-Date: Tue, 13 Apr 2004 19:27:43 -0400 (EDT) Final-Recipient: rfc822; postfix-users@postfix.org Action: deliverable ! Status: 2.0.0 Remote-MTA: dns; mail.cloud9.net ! Diagnostic-Code: smtp; 250 Ok --- 1210,1222 ---- Reporting-MTA: dns; spike.porcupine.org X-Postfix-Queue-ID: 84863BC0E5 X-Postfix-Sender: rfc822; wietse@porcupine.org ! Arrival-Date: Sun, 26 Nov 2006 17:01:01 -0500 (EST) Final-Recipient: rfc822; postfix-users@postfix.org Action: deliverable ! Status: 2.1.5 Remote-MTA: dns; mail.cloud9.net ! Diagnostic-Code: smtp; 250 2.1.5 Ok *************** *** 1232,1242 **** Content-Type: message/rfc822 Received: by spike.porcupine.org (Postfix, from userid 1001) ! id 84863BC0E5; Tue, 13 Apr 2004 19:27:43 -0400 (EDT) Subject: probe To: postfix-users@postfix.org ! Message-Id: <20040413232743.84863BC0E5@spike.porcupine.org> ! Date: Tue, 13 Apr 2004 19:27:43 -0400 (EDT) From: wietse@porcupine.org (Wietse Venema) --- 1232,1242 ---- Content-Type: message/rfc822 Received: by spike.porcupine.org (Postfix, from userid 1001) ! id 84863BC0E5; Sun, 26 Nov 2006 17:01:01 -0500 (EST) Subject: probe To: postfix-users@postfix.org ! Message-Id: <20061126220101.84863BC0E5@spike.porcupine.org> ! Date: Sun, 26 Nov 2006 17:01:01 -0500 (EST) From: wietse@porcupine.org (Wietse Venema) diff -cr /var/tmp/postfix-2.3.4/proto/bounce ./proto/bounce *** /var/tmp/postfix-2.3.4/proto/bounce Sun Aug 6 10:10:55 2006 --- ./proto/bounce Fri Dec 8 22:00:01 2006 *************** *** 81,87 **** # I'm sorry to have to inform you that your message could not # be delivered to one or more recipients. It's attached below. # ! # For further assistance, please send mail to # # If you do so, please include this problem report. You can # delete your own text from the attached returned message. --- 81,87 ---- # I'm sorry to have to inform you that your message could not # be delivered to one or more recipients. It's attached below. # ! # For further assistance, please send mail to postmaster. # # If you do so, please include this problem report. You can # delete your own text from the attached returned message. diff -cr /var/tmp/postfix-2.3.4/src/bounce/bounce_cleanup.c ./src/bounce/bounce_cleanup.c *** /var/tmp/postfix-2.3.4/src/bounce/bounce_cleanup.c Mon Jun 26 08:59:19 2006 --- ./src/bounce/bounce_cleanup.c Fri Dec 8 19:15:39 2006 *************** *** 129,135 **** */ if (bounce_cleanup_path) (void) unlink(vstring_str(bounce_cleanup_path)); ! exit(sig); } /* bounce_cleanup_register - register logfile to clean up */ --- 129,135 ---- */ if (bounce_cleanup_path) (void) unlink(vstring_str(bounce_cleanup_path)); ! _exit(sig); } /* bounce_cleanup_register - register logfile to clean up */ diff -cr /var/tmp/postfix-2.3.4/src/bounce/bounce_templates.c ./src/bounce/bounce_templates.c *** /var/tmp/postfix-2.3.4/src/bounce/bounce_templates.c Sun Aug 6 09:46:35 2006 --- ./src/bounce/bounce_templates.c Fri Dec 8 22:03:52 2006 *************** *** 98,104 **** "I'm sorry to have to inform you that your message could not", "be delivered to one or more recipients. It's attached below.", "", ! "For further assistance, please send mail to <" MAIL_ADDR_POSTMASTER ">", "", "If you do so, please include this problem report. You can", "delete your own text from the attached returned message.", --- 98,104 ---- "I'm sorry to have to inform you that your message could not", "be delivered to one or more recipients. It's attached below.", "", ! "For further assistance, please send mail to " MAIL_ADDR_POSTMASTER ".", "", "If you do so, please include this problem report. You can", "delete your own text from the attached returned message.", *************** *** 134,140 **** , "It will be retried until it is $maximal_queue_lifetime_days day(s) old.", "", ! "For further assistance, please send mail to <" MAIL_ADDR_POSTMASTER ">", "", "If you do so, please include this problem report. You can", "delete your own text from the attached returned message.", --- 134,140 ---- , "It will be retried until it is $maximal_queue_lifetime_days day(s) old.", "", ! "For further assistance, please send mail to " MAIL_ADDR_POSTMASTER ".", "", "If you do so, please include this problem report. You can", "delete your own text from the attached returned message.", diff -cr /var/tmp/postfix-2.3.4/src/cleanup/cleanup_message.c ./src/cleanup/cleanup_message.c *** /var/tmp/postfix-2.3.4/src/cleanup/cleanup_message.c Fri Aug 25 17:30:50 2006 --- ./src/cleanup/cleanup_message.c Fri Dec 1 19:24:40 2006 *************** *** 597,602 **** --- 597,612 ---- time_t tv; /* + * XXX Workaround: when we reach the end of headers, mime_state_update() + * may execute up to three call-backs before returning to the caller: + * head_out(), head_end(), and body_out() or body_end(). As long as + * call-backs don't return a result, each call-back has to check for + * itself if the previous call-back experienced a problem. + */ + if (CLEANUP_OUT_OK(state) == 0) + return; + + /* * Add a missing (Resent-)Message-Id: header. The message ID gives the * time in GMT units, plus the local queue ID. * *************** *** 707,712 **** --- 717,732 ---- CLEANUP_STATE *state = (CLEANUP_STATE *) context; /* + * XXX Workaround: when we reach the end of headers, mime_state_update() + * may execute up to three call-backs before returning to the caller: + * head_out(), head_end(), and body_out() or body_end(). As long as + * call-backs don't return a result, each call-back has to check for + * itself if the previous call-back experienced a problem. + */ + if (CLEANUP_OUT_OK(state) == 0) + return; + + /* * Crude message body content filter for emergencies. This code has * several problems: it sees one line at a time; it looks at long lines * only in chunks of line_length_limit (2048) characters; it is easily *************** *** 891,896 **** --- 911,925 ---- (MIME_STATE_ANY_END) 0, cleanup_mime_error_callback, (void *) state); + + /* + * XXX Workaround: truncate a long message header so that we don't exceed + * the Milter request size limit of 65535. + */ + #define KLUDGE_HEADER_LIMIT 60000 + if ((cleanup_milters || state->milters) + && var_header_limit > KLUDGE_HEADER_LIMIT) + var_header_limit = KLUDGE_HEADER_LIMIT; /* * Pass control to the header processing routine. diff -cr /var/tmp/postfix-2.3.4/src/cleanup/cleanup_milter.c ./src/cleanup/cleanup_milter.c *** /var/tmp/postfix-2.3.4/src/cleanup/cleanup_milter.c Thu Oct 19 11:16:17 2006 --- ./src/cleanup/cleanup_milter.c Fri Dec 1 21:19:42 2006 *************** *** 1697,1702 **** --- 1697,1704 ---- msg_warn(" del_rcpt addr"); } + /* flatten_args - unparse partial command line */ + static void flatten_args(VSTRING *buf, char **argv) { char **cpp; *************** *** 1710,1715 **** --- 1712,1719 ---- VSTRING_TERMINATE(buf); } + /* open_queue_file - open an unedited queue file (all-zero dummy PTRs) */ + static void open_queue_file(CLEANUP_STATE *state, const char *path) { VSTRING *buf = vstring_alloc(100); *************** *** 1720,1725 **** --- 1724,1736 ---- long rcpt_count; long qmgr_opts; + if (state->dst != 0) { + msg_warn("closing %s", cleanup_path); + vstream_fclose(state->dst); + state->dst = 0; + myfree(cleanup_path); + cleanup_path = 0; + } if ((state->dst = vstream_fopen(path, O_RDWR, 0)) == 0) { msg_warn("open %s: %m", path); } else { *************** *** 1794,1799 **** --- 1805,1811 ---- msg_vstream_init(argv[0], VSTREAM_ERR); var_line_limit = DEF_LINE_LIMIT; + var_header_limit = DEF_HEADER_LIMIT; for (;;) { ARGV *argv; diff -cr /var/tmp/postfix-2.3.4/src/cleanup/cleanup_out.c ./src/cleanup/cleanup_out.c *** /var/tmp/postfix-2.3.4/src/cleanup/cleanup_out.c Tue May 16 20:45:13 2006 --- ./src/cleanup/cleanup_out.c Fri Dec 1 21:24:15 2006 *************** *** 175,183 **** --- 175,196 ---- * of such header lines. NB: This code destroys the header. We could try * to avoid clobbering it, but we're not going to use the data any * further. + * + * XXX We prefer to truncate a header at the last line boundary before the + * header size limit. If this would undershoot the limit by more than + * 10%, we truncate between line boundaries to avoid losing too much + * text. This "unkind cut" may result in syntax errors and may trigger + * warnings from down-stream MTAs. */ for (line = start; line; line = next_line) { next_line = split_at(line, '\n'); + if ((next_line ? next_line - 1 : line + strlen(line)) + > start + var_header_limit) { + if (line - start > 0.9 * var_header_limit) /* nice cut */ + break; + start[var_header_limit] = 0; /* unkind cut */ + next_line = 0; + } if (line == start || IS_SPACE_TAB(*line)) { cleanup_out_string(state, REC_TYPE_NORM, line); } else { diff -cr /var/tmp/postfix-2.3.4/src/global/dict_proxy.c ./src/global/dict_proxy.c *** /var/tmp/postfix-2.3.4/src/global/dict_proxy.c Mon Jan 23 10:30:06 2006 --- ./src/global/dict_proxy.c Fri Dec 1 21:03:49 2006 *************** *** 90,95 **** --- 90,96 ---- DICT_PROXY *dict_proxy = (DICT_PROXY *) dict; VSTREAM *stream; int status; + int count = 0; /* * The client and server live in separate processes that may start and *************** *** 103,108 **** --- 104,110 ---- for (;;) { stream = clnt_stream_access(proxy_stream); errno = 0; + count += 1; if (attr_print(stream, ATTR_FLAG_NONE, ATTR_TYPE_STR, MAIL_ATTR_REQ, PROXY_REQ_LOOKUP, ATTR_TYPE_STR, MAIL_ATTR_TABLE, dict->name, *************** *** 114,120 **** ATTR_TYPE_INT, MAIL_ATTR_STATUS, &status, ATTR_TYPE_STR, MAIL_ATTR_VALUE, dict_proxy->result, ATTR_TYPE_END) != 2) { ! if (msg_verbose || (errno != EPIPE && errno != ENOENT)) msg_warn("%s: service %s: %m", myname, VSTREAM_PATH(stream)); } else { if (msg_verbose) --- 116,122 ---- ATTR_TYPE_INT, MAIL_ATTR_STATUS, &status, ATTR_TYPE_STR, MAIL_ATTR_VALUE, dict_proxy->result, ATTR_TYPE_END) != 2) { ! if (msg_verbose || count > 1 || (errno && errno != EPIPE && errno != ENOENT)) msg_warn("%s: service %s: %m", myname, VSTREAM_PATH(stream)); } else { if (msg_verbose) diff -cr /var/tmp/postfix-2.3.4/src/global/pipe_command.c ./src/global/pipe_command.c *** /var/tmp/postfix-2.3.4/src/global/pipe_command.c Thu Jun 15 14:07:15 2006 --- ./src/global/pipe_command.c Thu Dec 7 20:55:33 2006 *************** *** 633,639 **** "Command died with signal %d: \"%s\"%s%s", WTERMSIG(wait_status), args.command, log_len ? ". Command output: " : "", log_buf); ! return (PIPE_STAT_BOUNCE); } /* Use "D.S.N text" command output. XXX What diagnostic code? */ else if (dsn_valid(log_buf) > 0) { --- 633,639 ---- "Command died with signal %d: \"%s\"%s%s", WTERMSIG(wait_status), args.command, log_len ? ". Command output: " : "", log_buf); ! return (PIPE_STAT_DEFER); } /* Use "D.S.N text" command output. XXX What diagnostic code? */ else if (dsn_valid(log_buf) > 0) { diff -cr /var/tmp/postfix-2.3.4/src/global/resolve_clnt.c ./src/global/resolve_clnt.c *** /var/tmp/postfix-2.3.4/src/global/resolve_clnt.c Thu Jun 15 14:07:15 2006 --- ./src/global/resolve_clnt.c Fri Dec 1 21:03:49 2006 *************** *** 164,169 **** --- 164,170 ---- const char *myname = "resolve_clnt"; VSTREAM *stream; int server_flags; + int count = 0; /* * One-entry cache. *************** *** 226,231 **** --- 227,233 ---- for (;;) { stream = clnt_stream_access(rewrite_clnt_stream); errno = 0; + count += 1; if (attr_print(stream, ATTR_FLAG_NONE, ATTR_TYPE_STR, MAIL_ATTR_REQ, class, ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender, *************** *** 239,245 **** ATTR_TYPE_STR, MAIL_ATTR_RECIP, reply->recipient, ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &reply->flags, ATTR_TYPE_END) != 5) { ! if (msg_verbose || (errno != EPIPE && errno != ENOENT)) msg_warn("problem talking to service %s: %m", var_rewrite_service); } else { --- 241,247 ---- ATTR_TYPE_STR, MAIL_ATTR_RECIP, reply->recipient, ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &reply->flags, ATTR_TYPE_END) != 5) { ! if (msg_verbose || count > 1 || (errno && errno != EPIPE && errno != ENOENT)) msg_warn("problem talking to service %s: %m", var_rewrite_service); } else { diff -cr /var/tmp/postfix-2.3.4/src/global/rewrite_clnt.c ./src/global/rewrite_clnt.c *** /var/tmp/postfix-2.3.4/src/global/rewrite_clnt.c Mon Jan 23 10:30:06 2006 --- ./src/global/rewrite_clnt.c Fri Dec 1 21:03:49 2006 *************** *** 82,87 **** --- 82,88 ---- { VSTREAM *stream; int server_flags; + int count = 0; /* * One-entry cache. *************** *** 129,134 **** --- 130,136 ---- for (;;) { stream = clnt_stream_access(rewrite_clnt_stream); errno = 0; + count += 1; if (attr_print(stream, ATTR_FLAG_NONE, ATTR_TYPE_STR, MAIL_ATTR_REQ, REWRITE_ADDR, ATTR_TYPE_STR, MAIL_ATTR_RULE, rule, *************** *** 139,145 **** ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &server_flags, ATTR_TYPE_STR, MAIL_ATTR_ADDR, result, ATTR_TYPE_END) != 2) { ! if (msg_verbose || (errno != EPIPE && errno != ENOENT)) msg_warn("problem talking to service %s: %m", var_rewrite_service); } else { --- 141,147 ---- ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &server_flags, ATTR_TYPE_STR, MAIL_ATTR_ADDR, result, ATTR_TYPE_END) != 2) { ! if (msg_verbose || count > 1 || (errno && errno != EPIPE && errno != ENOENT)) msg_warn("problem talking to service %s: %m", var_rewrite_service); } else { diff -cr /var/tmp/postfix-2.3.4/src/global/scache_clnt.c ./src/global/scache_clnt.c *** /var/tmp/postfix-2.3.4/src/global/scache_clnt.c Mon Jan 23 10:30:06 2006 --- ./src/global/scache_clnt.c Fri Dec 1 21:03:49 2006 *************** *** 91,96 **** --- 91,97 ---- VSTREAM *stream; int status; int tries; + int count = 0; if (msg_verbose) msg_info("%s: endp=%s prop=%s fd=%d", *************** *** 110,115 **** --- 111,117 ---- for (tries = 0; sp->auto_clnt != 0; tries++) { if ((stream = auto_clnt_access(sp->auto_clnt)) != 0) { errno = 0; + count += 1; if (attr_print(stream, ATTR_FLAG_NONE, ATTR_TYPE_STR, MAIL_ATTR_REQ, SCACHE_REQ_SAVE_ENDP, ATTR_TYPE_INT, MAIL_ATTR_TTL, endp_ttl, *************** *** 126,132 **** || attr_scan(stream, ATTR_FLAG_STRICT, ATTR_TYPE_INT, MAIL_ATTR_STATUS, &status, ATTR_TYPE_END) != 1) { ! if (msg_verbose || (errno != EPIPE && errno != ENOENT)) msg_warn("problem talking to service %s: %m", VSTREAM_PATH(stream)); /* Give up or recover. */ --- 128,134 ---- || attr_scan(stream, ATTR_FLAG_STRICT, ATTR_TYPE_INT, MAIL_ATTR_STATUS, &status, ATTR_TYPE_END) != 1) { ! if (msg_verbose || count > 1 || (errno && errno != EPIPE && errno != ENOENT)) msg_warn("problem talking to service %s: %m", VSTREAM_PATH(stream)); /* Give up or recover. */ *************** *** 281,287 **** myname, status); break; } ! } /* Give up or recover. */ if (tries >= SCACHE_MAX_TRIES - 1) { msg_warn("disabling connection caching"); --- 283,289 ---- myname, status); break; } ! } /* Give up or recover. */ if (tries >= SCACHE_MAX_TRIES - 1) { msg_warn("disabling connection caching"); diff -cr /var/tmp/postfix-2.3.4/src/global/verify_clnt.c ./src/global/verify_clnt.c *** /var/tmp/postfix-2.3.4/src/global/verify_clnt.c Mon Jan 23 10:30:06 2006 --- ./src/global/verify_clnt.c Fri Dec 1 21:03:49 2006 *************** *** 96,101 **** --- 96,102 ---- { VSTREAM *stream; int request_status; + int count = 0; /* * Do client-server plumbing. *************** *** 109,114 **** --- 110,116 ---- for (;;) { stream = clnt_stream_access(vrfy_clnt); errno = 0; + count += 1; if (attr_print(stream, ATTR_FLAG_NONE, ATTR_TYPE_STR, MAIL_ATTR_REQ, VRFY_REQ_QUERY, ATTR_TYPE_STR, MAIL_ATTR_ADDR, addr, *************** *** 119,125 **** ATTR_TYPE_INT, MAIL_ATTR_ADDR_STATUS, addr_status, ATTR_TYPE_STR, MAIL_ATTR_WHY, why, ATTR_TYPE_END) != 3) { ! if (msg_verbose || (errno != EPIPE && errno != ENOENT)) msg_warn("problem talking to service %s: %m", var_verify_service); } else { --- 121,127 ---- ATTR_TYPE_INT, MAIL_ATTR_ADDR_STATUS, addr_status, ATTR_TYPE_STR, MAIL_ATTR_WHY, why, ATTR_TYPE_END) != 3) { ! if (msg_verbose || count > 1 || (errno && errno != EPIPE && errno != ENOENT)) msg_warn("problem talking to service %s: %m", var_verify_service); } else { diff -cr /var/tmp/postfix-2.3.4/src/milter/milter8.c ./src/milter/milter8.c *** /var/tmp/postfix-2.3.4/src/milter/milter8.c Thu Jul 27 12:25:00 2006 --- ./src/milter/milter8.c Tue Dec 5 19:20:51 2006 *************** *** 858,863 **** --- 858,864 ---- int skip_reply, ARGV *macros,...) { + const char *myname = "milter8_event"; va_list ap; ssize_t data_len; int err; *************** *** 872,877 **** --- 873,889 ---- #define DONT_SKIP_REPLY 0 /* + * Sanity check. + */ + if (milter->fp == 0 || milter->def_reply != 0) { + msg_warn("%s: attempt to send event %s to milter %s after error", + myname, + (smfic_name = str_name_code(smfic_table, event)) != 0 ? + smfic_name : "(unknown MTA event)", milter->m.name); + return (milter->def_reply); + } + + /* * Skip this event if it doesn't exist in the protocol that I announced. */ #ifndef USE_LIBMILTER_INCLUDES *************** *** 1185,1191 **** (ssize_t) index, STR(milter->buf)); if (edit_resp) ! return (milter8_def_reply(milter, edit_resp)); continue; #endif --- 1197,1203 ---- (ssize_t) index, STR(milter->buf)); if (edit_resp) ! return (edit_resp); continue; #endif *************** *** 1203,1209 **** STR(milter->buf), STR(milter->body)); if (edit_resp) ! return (milter8_def_reply(milter, edit_resp)); continue; /* --- 1215,1221 ---- STR(milter->buf), STR(milter->body)); if (edit_resp) ! return (edit_resp); continue; /* *************** *** 1232,1238 **** STR(milter->buf), STR(milter->body)); if (edit_resp) ! return (milter8_def_reply(milter, edit_resp)); continue; #endif --- 1244,1250 ---- STR(milter->buf), STR(milter->body)); if (edit_resp) ! return (edit_resp); continue; #endif *************** *** 1248,1254 **** edit_resp = parent->add_rcpt(parent->chg_context, STR(milter->buf)); if (edit_resp) ! return (milter8_def_reply(milter, edit_resp)); continue; /* --- 1260,1266 ---- edit_resp = parent->add_rcpt(parent->chg_context, STR(milter->buf)); if (edit_resp) ! return (edit_resp); continue; /* *************** *** 1263,1269 **** edit_resp = parent->del_rcpt(parent->chg_context, STR(milter->buf)); if (edit_resp) ! return (milter8_def_reply(milter, edit_resp)); continue; /* --- 1275,1281 ---- edit_resp = parent->del_rcpt(parent->chg_context, STR(milter->buf)); if (edit_resp) ! return (edit_resp); continue; /* *************** *** 1280,1286 **** edit_resp = parent->repl_body(parent->chg_context, milter->body); if (edit_resp) ! return (milter8_def_reply(milter, edit_resp)); continue; #endif } --- 1292,1298 ---- edit_resp = parent->repl_body(parent->chg_context, milter->body); if (edit_resp) ! return (edit_resp); continue; #endif } *************** *** 1928,1933 **** --- 1940,1955 ---- int skip_reply; /* + * XXX Workaround: mime_state_update() may invoke multiple call-backs + * before returning to the caller. + */ + #define MILTER8_MESSAGE_DONE(milter, msg_ctx) \ + ((milter)->state != MILTER8_STAT_MESSAGE || (msg_ctx)->resp != 0) + + if (MILTER8_MESSAGE_DONE(milter, msg_ctx)) + return; + + /* * XXX Sendmail compatibility. Don't expose our first (received) header * to mail filter applications. See also cleanup_milter.c for code to * ensure that header replace requests are relative to the message *************** *** 1990,1995 **** --- 2012,2019 ---- MILTER_MSG_CONTEXT *msg_ctx = (MILTER_MSG_CONTEXT *) ptr; MILTER8 *milter = msg_ctx->milter; + if (MILTER8_MESSAGE_DONE(milter, msg_ctx)) + return; if (msg_verbose) msg_info("%s: eoh milter %s", myname, milter->m.name); msg_ctx->resp = *************** *** 2012,2017 **** --- 2036,2044 ---- ssize_t space; ssize_t count; + if (MILTER8_MESSAGE_DONE(milter, msg_ctx)) + return; + /* * XXX Sendmail compatibility: don't expose our first body line. */ *************** *** 2079,2084 **** --- 2106,2113 ---- MILTER_MSG_CONTEXT *msg_ctx = (MILTER_MSG_CONTEXT *) ptr; MILTER8 *milter = msg_ctx->milter; + if (MILTER8_MESSAGE_DONE(milter, msg_ctx)) + return; if (msg_verbose) msg_info("%s: eob milter %s", myname, milter->m.name); msg_ctx->resp = *************** *** 2144,2150 **** /* * XXX When the message (not MIME body part) does not end in CRLF ! * (i.e. the last record was REC_TYPE_CONT), do we send CRLF * terminator before triggering the end-of-body condition? */ for (;;) { --- 2173,2179 ---- /* * XXX When the message (not MIME body part) does not end in CRLF ! * (i.e. the last record was REC_TYPE_CONT), do we send a CRLF * terminator before triggering the end-of-body condition? */ for (;;) { *************** *** 2164,2172 **** msg_ctx.resp = "450 4.3.0 Queue file write error"; break; } ! if (msg_ctx.resp != 0) ! break; ! if (milter->state != MILTER8_STAT_MESSAGE) break; if (rec_type != REC_TYPE_NORM && rec_type != REC_TYPE_CONT) break; --- 2193,2199 ---- msg_ctx.resp = "450 4.3.0 Queue file write error"; break; } ! if (MILTER8_MESSAGE_DONE(milter, &msg_ctx)) break; if (rec_type != REC_TYPE_NORM && rec_type != REC_TYPE_CONT) break; diff -cr /var/tmp/postfix-2.3.4/src/oqmgr/qmgr_entry.c ./src/oqmgr/qmgr_entry.c *** /var/tmp/postfix-2.3.4/src/oqmgr/qmgr_entry.c Mon Jun 26 08:59:19 2006 --- ./src/oqmgr/qmgr_entry.c Fri Dec 1 20:24:07 2006 *************** *** 237,243 **** #define FUDGE(x) ((x) * (var_qmgr_fudge / 100.0)) message->refcount--; if (message->rcpt_offset > 0 ! && qmgr_recipient_count < FUDGE(var_qmgr_rcpt_limit)) qmgr_message_realloc(message); if (message->refcount == 0) qmgr_active_done(message); --- 237,243 ---- #define FUDGE(x) ((x) * (var_qmgr_fudge / 100.0)) message->refcount--; if (message->rcpt_offset > 0 ! && qmgr_recipient_count < FUDGE(var_qmgr_rcpt_limit) - 100) qmgr_message_realloc(message); if (message->refcount == 0) qmgr_active_done(message); diff -cr /var/tmp/postfix-2.3.4/src/qmgr/qmgr_job.c ./src/qmgr/qmgr_job.c *** /var/tmp/postfix-2.3.4/src/qmgr/qmgr_job.c Mon Jun 26 08:59:19 2006 --- ./src/qmgr/qmgr_job.c Sun Dec 3 17:14:49 2006 *************** *** 763,768 **** --- 763,778 ---- QMGR_PEER *peer; QMGR_MESSAGE *message = job->message; + /* + * Workaround to prevent queue manager starvation until the last slow + * batch of multi-recipient mail is finished. Postfix 2.4 has a final + * solution, but that involves major changes. + */ + if (message->rcpt_offset != 0 + && message->rcpt_limit > message->rcpt_count + 100 + && message->refcount > 0) { + qmgr_message_realloc(message); + } if (HAS_ENTRIES(job) && (peer = qmgr_peer_select(job)) != 0) return (peer); diff -cr /var/tmp/postfix-2.3.4/src/qmgr/qmgr_message.c ./src/qmgr/qmgr_message.c *** /var/tmp/postfix-2.3.4/src/qmgr/qmgr_message.c Mon Jun 26 08:59:19 2006 --- ./src/qmgr/qmgr_message.c Fri Dec 1 20:22:33 2006 *************** *** 361,366 **** --- 361,369 ---- if (recipient_limit < message->rcpt_limit) recipient_limit = message->rcpt_limit; } + /* Keep interrupt latency in check. */ + if (recipient_limit > 5000) + recipient_limit = 5000; if (recipient_limit <= 0) msg_panic("%s: no recipient slots available", message->queue_id); diff -cr /var/tmp/postfix-2.3.4/src/smtp/smtp_chat.c ./src/smtp/smtp_chat.c *** /var/tmp/postfix-2.3.4/src/smtp/smtp_chat.c Mon Jul 10 16:24:52 2006 --- ./src/smtp/smtp_chat.c Thu Nov 2 13:14:54 2006 *************** *** 305,311 **** */ session->error_mask |= MAIL_ERROR_PROTOCOL; if (session->features & SMTP_FEATURE_PIPELINING) { ! msg_warn("non-%s response from %s: %.100s", (session->state->misc_flags & SMTP_MISC_FLAG_USE_LMTP) ? "LMTP" : "ESMTP", session->namaddrport, STR(session->buffer)); --- 305,312 ---- */ session->error_mask |= MAIL_ERROR_PROTOCOL; if (session->features & SMTP_FEATURE_PIPELINING) { ! msg_warn("%s: non-%s response from %s: %.100s", ! session->state->request->queue_id, (session->state->misc_flags & SMTP_MISC_FLAG_USE_LMTP) ? "LMTP" : "ESMTP", session->namaddrport, STR(session->buffer)); diff -cr /var/tmp/postfix-2.3.4/src/smtp/smtp_connect.c ./src/smtp/smtp_connect.c *** /var/tmp/postfix-2.3.4/src/smtp/smtp_connect.c Sat Sep 2 18:44:51 2006 --- ./src/smtp/smtp_connect.c Sun Dec 3 17:05:40 2006 *************** *** 379,385 **** bad_session = THIS_SESSION_IS_BAD; /* smtp_quit() may fail */ if (THIS_SESSION_IS_EXPIRED) smtp_quit(state); /* also disables caching */ ! if (THIS_SESSION_IS_CACHED) { smtp_save_session(state); } else { smtp_session_free(session); --- 379,389 ---- bad_session = THIS_SESSION_IS_BAD; /* smtp_quit() may fail */ if (THIS_SESSION_IS_EXPIRED) smtp_quit(state); /* also disables caching */ ! if (THIS_SESSION_IS_CACHED ! /* Redundant tests for safety... */ ! && vstream_ferror(session->stream) == 0 ! && vstream_ftimeout(session->stream) == 0 ! && vstream_feof(session->stream) == 0) { smtp_save_session(state); } else { smtp_session_free(session); *************** *** 493,498 **** --- 497,503 ---- && smtp_helo(state) != 0) { if (!THIS_SESSION_IS_DEAD && vstream_ferror(session->stream) == 0 + && vstream_ftimeout(session->stream) == 0 && vstream_feof(session->stream) == 0) smtp_quit(state); } else { *************** *** 871,876 **** --- 876,882 ---- */ if (!THIS_SESSION_IS_DEAD && vstream_ferror(session->stream) == 0 + && vstream_ftimeout(session->stream) == 0 && vstream_feof(session->stream) == 0) smtp_quit(state); } else { diff -cr /var/tmp/postfix-2.3.4/src/smtp/smtp_proto.c ./src/smtp/smtp_proto.c *** /var/tmp/postfix-2.3.4/src/smtp/smtp_proto.c Fri Sep 29 20:37:08 2006 --- ./src/smtp/smtp_proto.c Fri Dec 8 16:31:50 2006 *************** *** 1014,1019 **** --- 1014,1021 ---- } while (0) #define RETURN(x) do { \ + if (recv_state != SMTP_STATE_LAST) \ + DONT_CACHE_THIS_SESSION; \ vstring_free(next_command); \ if (survivors) \ myfree((char *) survivors); \ *************** *** 1632,1638 **** session->mime_state = mime_state_alloc(downgrading ? MIME_OPT_DOWNGRADE | MIME_OPT_REPORT_NESTING : ! MIME_OPT_REPORT_NESTING, smtp_generic_maps ? smtp_header_rewrite : smtp_header_out, --- 1634,1640 ---- session->mime_state = mime_state_alloc(downgrading ? MIME_OPT_DOWNGRADE | MIME_OPT_REPORT_NESTING : ! MIME_OPT_DISABLE_MIME, smtp_generic_maps ? smtp_header_rewrite : smtp_header_out, diff -cr /var/tmp/postfix-2.3.4/src/util/msg.c ./src/util/msg.c *** /var/tmp/postfix-2.3.4/src/util/msg.c Tue Mar 7 15:57:26 2006 --- ./src/util/msg.c Sun Dec 10 12:27:43 2006 *************** *** 39,45 **** /* to the standard error stream, but the disposition can be changed /* by the user. See the hints below in the SEE ALSO section. /* ! /* msg_info(), msg_warn(), msg_error(), msg_fatal() and msg_panic() /* produce a one-line record with the program name, a severity code /* (except for msg_info()), and an informative message. The program /* name must have been set by calling one of the msg_XXX_init() --- 39,45 ---- /* to the standard error stream, but the disposition can be changed /* by the user. See the hints below in the SEE ALSO section. /* ! /* msg_info(), msg_warn(), msg_error(), msg_fatal*() and msg_panic() /* produce a one-line record with the program name, a severity code /* (except for msg_info()), and an informative message. The program /* name must have been set by calling one of the msg_XXX_init() *************** *** 72,77 **** --- 72,111 ---- /* msg_verbose is a global flag that can be set to make software /* more verbose about what it is doing. By default the flag is zero. /* By convention, a larger value means more noise. + /* REENTRANCY + /* .ad + /* .fi + /* The msg_info() etc. output routines are protected against + /* ordinary recursive calls and against re-entry by signal + /* handlers. + /* + /* Protection against re-entry by signal handlers is subject + /* to the following limitations: + /* .IP \(bu + /* The signal handlers must never return. In other words, the + /* signal handlers must do one or more of the following: call + /* _exit(), kill the process with a signal, and permanently block + /* the process. + /* .IP \(bu + /* The signal handlers must invoke msg_info() etc. not until + /* after the msg_XXX_init() functions complete initialization, + /* and not until after the first formatted output to a VSTRING + /* or VSTREAM. + /* .IP \(bu + /* Each msg_cleanup() call-back function, and each Postfix or + /* system function invoked by that call-back function, either + /* protects itself against recursive calls and re-entry by a + /* terminating signal handler, or is called exclusively by the + /* msg(3) module. + /* .PP + /* When re-entrancy is detected, the requested output and + /* optional cleanup operations are skipped. Skipping the output + /* operations prevents memory corruption of VSTREAM_ERR data + /* structures, and prevents deadlock on Linux releases that + /* use mutexes within system library routines such as syslog(). + /* This protection exists under the condition that these + /* specific resources are accessed exclusively via the msg_info() + /* etc. functions. /* SEE ALSO /* msg_output(3) specify diagnostics disposition /* msg_stdio(3) direct diagnostics to standard I/O stream *************** *** 118,131 **** int msg_verbose = 0; /* ! * Private state. The msg_exiting flag prevents us from recursively ! * reporting an error. */ static MSG_CLEANUP_FN msg_cleanup_fn = 0; - static int msg_exiting = 0; static int msg_error_count = 0; static int msg_error_bound = 13; /* msg_info - report informative message */ void msg_info(const char *fmt,...) --- 152,174 ---- int msg_verbose = 0; /* ! * Private state. */ static MSG_CLEANUP_FN msg_cleanup_fn = 0; static int msg_error_count = 0; static int msg_error_bound = 13; + /* + * The msg_exiting flag prevents us from recursively reporting an error with + * msg_fatal*() or msg_panic(), and provides a first-level safety net for + * optional cleanup actions against signal handler re-entry problems. Note + * that msg_vprintf() implements its own guard against re-entry. + * + * XXX We specify global scope, to discourage the compiler from doing smart + * things. + */ + volatile int msg_exiting = 0; + /* msg_info - report informative message */ void msg_info(const char *fmt,...) *************** *** 175,181 **** msg_cleanup_fn(); } sleep(1); ! exit(1); } /* msg_fatal_status - report error and terminate gracefully */ --- 218,225 ---- msg_cleanup_fn(); } sleep(1); ! /* In case we're running as a signal handler. */ ! _exit(1); } /* msg_fatal_status - report error and terminate gracefully */ *************** *** 192,198 **** msg_cleanup_fn(); } sleep(1); ! exit(status); } /* msg_panic - report error and dump core */ --- 236,243 ---- msg_cleanup_fn(); } sleep(1); ! /* In case we're running as a signal handler. */ ! _exit(status); } /* msg_panic - report error and dump core */ *************** *** 208,214 **** } sleep(1); abort(); /* Die! */ ! exit(1); /* DIE!! */ } /* msg_cleanup - specify cleanup routine */ --- 253,260 ---- } sleep(1); abort(); /* Die! */ ! /* In case we're running as a signal handler. */ ! _exit(1); /* DIE!! */ } /* msg_cleanup - specify cleanup routine */ diff -cr /var/tmp/postfix-2.3.4/src/util/msg_output.c ./src/util/msg_output.c *** /var/tmp/postfix-2.3.4/src/util/msg_output.c Mon Nov 20 13:06:33 2000 --- ./src/util/msg_output.c Sun Dec 10 12:27:52 2006 *************** *** 40,45 **** --- 40,75 ---- /* /* msg_text() copies a pre-formatted text, sanitizes the result, and /* calls the output handlers registered with msg_output(). + /* REENTRANCY + /* .ad + /* .fi + /* The above output routines are protected against ordinary + /* recursive calls and against re-entry by signal + /* handlers, with the following limitations: + /* .IP \(bu + /* The signal handlers must never return. In other words, the + /* signal handlers must do one or more of the following: call + /* _exit(), kill the process with a signal, and permanently + /* block the process. + /* .IP \(bu + /* The signal handlers must call the above output routines not + /* until after msg_output() completes initialization, and not + /* until after the first formatted output to a VSTRING or + /* VSTREAM. + /* .IP \(bu + /* Each msg_output() call-back function, and each Postfix or + /* system function called by that call-back function, either + /* must protect itself against recursive calls and re-entry + /* by a terminating signal handler, or it must be called + /* exclusively by functions in the msg_output(3) module. + /* .PP + /* When re-entrancy is detected, the requested output operation + /* is skipped. This prevents memory corruption of VSTREAM_ERR + /* data structures, and prevents deadlock on Linux releases + /* that use mutexes within system library routines such as + /* syslog(). This protection exists under the condition that + /* these specific resources are accessed exclusively via + /* msg_output() call-back functions. /* LICENSE /* .ad /* .fi *************** *** 68,73 **** --- 98,109 ---- #include /* + * Global scope, to discourage the compiler from doing smart things. + */ + volatile int msg_vprintf_lock; + volatile int msg_text_lock; + + /* * Private state. */ static MSG_OUTPUT_FN *msg_output_fn = 0; *************** *** 80,85 **** --- 116,127 ---- { /* + * Allocate all resources during initialization. + */ + if (msg_buffer == 0) + msg_buffer = vstring_alloc(100); + + /* * We're not doing this often, so avoid complexity and allocate memory * for an exact fit. */ *************** *** 106,115 **** void msg_vprintf(int level, const char *format, va_list ap) { ! if (msg_buffer == 0) ! msg_buffer = vstring_alloc(100); ! vstring_vsprintf(msg_buffer, percentm(format, errno), ap); ! msg_text(level, vstring_str(msg_buffer)); } /* msg_text - sanitize and log pre-formatted text */ --- 148,160 ---- void msg_vprintf(int level, const char *format, va_list ap) { ! if (msg_vprintf_lock == 0) { ! msg_vprintf_lock = 1; ! /* OK if terminating signal handler hijacks control before next stmt. */ ! vstring_vsprintf(msg_buffer, percentm(format, errno), ap); ! msg_text(level, vstring_str(msg_buffer)); ! msg_vprintf_lock = 0; ! } } /* msg_text - sanitize and log pre-formatted text */ *************** *** 121,133 **** /* * Sanitize the text. Use a private copy if necessary. */ ! if (msg_buffer == 0) ! msg_buffer = vstring_alloc(100); ! if (text != vstring_str(msg_buffer)) ! vstring_strcpy(msg_buffer, text); ! printable(vstring_str(msg_buffer), '?'); ! if (msg_output_fn_count == 0) ! msg_vstream_init("unknown", VSTREAM_ERR); ! for (i = 0; i < msg_output_fn_count; i++) ! msg_output_fn[i] (level, vstring_str(msg_buffer)); } --- 166,182 ---- /* * Sanitize the text. Use a private copy if necessary. */ ! if (msg_text_lock == 0) { ! msg_text_lock = 1; ! /* OK if terminating signal handler hijacks control before next stmt. */ ! if (text != vstring_str(msg_buffer)) ! vstring_strcpy(msg_buffer, text); ! printable(vstring_str(msg_buffer), '?'); ! /* On-the-fly initialization for debugging test programs only. */ ! if (msg_output_fn_count == 0) ! msg_vstream_init("unknown", VSTREAM_ERR); ! for (i = 0; i < msg_output_fn_count; i++) ! msg_output_fn[i] (level, vstring_str(msg_buffer)); ! msg_text_lock = 0; ! } } diff -cr /var/tmp/postfix-2.3.4/src/util/vbuf_print.c ./src/util/vbuf_print.c *** /var/tmp/postfix-2.3.4/src/util/vbuf_print.c Fri Mar 24 16:00:08 2006 --- ./src/util/vbuf_print.c Sun Dec 10 12:13:07 2006 *************** *** 20,25 **** --- 20,37 ---- /* In addition, vbuf_print() recognizes the %m format specifier /* and expands it to the error message corresponding to the current /* value of the global \fIerrno\fR variable. + /* REENTRANCY + /* .ad + /* .fi + /* vbuf_print() allocates a static buffer. After completion + /* of the first vbuf_print() call, this buffer is safe for + /* reentrant vbuf_print() calls by (asynchronous) terminating + /* signal handlers or by (synchronous) terminating error + /* handlers. vbuf_print() initialization typically happens + /* upon the first formatted output to a VSTRING or VSTREAM. + /* + /* However, it is up to the caller to ensure that the destination + /* VSTREAM or VSTRING buffer is protected against reentrant usage. /* LICENSE /* .ad /* .fi