]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.5.7 v2.5.7
authorWietse Venema <wietse@porcupine.org>
Tue, 12 May 2009 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <postfix-users@dukhovni.org>
Sat, 10 Feb 2018 19:57:40 +0000 (14:57 -0500)
16 files changed:
postfix/HISTORY
postfix/conf/postfix-files
postfix/html/postconf.5.html
postfix/mantools/postlink
postfix/src/global/mail_params.h
postfix/src/global/mail_version.h
postfix/src/oqmgr/qmgr_transport.c
postfix/src/postdrop/postdrop.c
postfix/src/postsuper/postsuper.c
postfix/src/qmgr/qmgr.h
postfix/src/qmgr/qmgr_entry.c
postfix/src/qmgr/qmgr_job.c
postfix/src/qmgr/qmgr_queue.c
postfix/src/qmgr/qmgr_transport.c
postfix/src/smtp/smtp_proto.c
postfix/src/smtpd/smtpd_proxy.c

index 7d25246647099f7de00528f392045d0a4713f99e..12dd4e802ba36e6d3f288bfae216c95845060b2a 100644 (file)
@@ -14469,3 +14469,48 @@ Apologies for any names omitted.
 
        Documentation: log the "*" pattern as the last transport
        map lookup. File: proto/transport.
+
+20090122
+
+       Bugfix: the data_directory was not automatically created!
+       File: conf/postfix-files.
+
+20090304
+
+       Cleanup: skip over suspended or throttled queues while
+       looking for delivery requests. File: *qmgr/qmgr_transport.c.
+
+20090305
+
+       Bugfix: in the "new queue manager", the _destination_rate_delay
+       code needed to postpone the job scheduler updates after
+       delivery completion, otherwise the scheduler could loop on
+       blocked jobs.  Victor & Wietse.  File: qmgr/qmgr_entry.c,
+       qmgr/qmgr_queue.c, qmgr/qmgr_job.c.
+
+       Cleanup: report a "queue file write error", instead of
+       passing though bogus 2xx replies from proxy filters to SMTP
+       clients.  File: smtpd/smtpd_proxy.c.
+
+20090310
+
+       Bugfix: Postfix used mumble_concurrency_failed_cohort_limit
+       instead of mumble_destination_concurrency_failed_cohort_limit
+       as documented. File: global/mail_params.h.
+
+20090419
+
+       Bugfix: don't re-enable SIGHUP if it is ignored in the
+       parent. This may cause random "Postfix integrity check
+       failed" errors at boot time (POSIX SIGHUP death), causing
+       Postfix not to start. We duplicate code from postdrop and
+       thus avoid past mistakes.  File: postsuper/postsuper.c.
+
+       Robustness: don't re-enable SIGTERM if it is ignored in the
+       parent. Files: postsuper/postsuper.c, postdrop/postdrop.c.
+
+20090428
+
+       Bugfix: don't disable MIME parsing with smtp_header_checks,
+       smtp_mime_header_checks, smtp_nested_header_checks or with
+       smtp_body_checks. Bug reported by Victor. File: smtp/smtp_proto.c.
index 9bd905f8cd16fe9863d94afc0d00a72cd6b3cddc..da938a4ecb92f532fe75672b8036570421af2ded 100644 (file)
@@ -42,7 +42,7 @@
 # permissions, so that running "make install" fixes any glitches.
 #
 $config_directory:d:root:-:755:u
-$data_directory:d:$mail_owner:-:700:u
+$data_directory:d:$mail_owner:-:700:uc
 $daemon_directory:d:root:-:755:u
 $queue_directory:d:root:-:755:uc
 $sample_directory:d:root:-:755:o
index 9166671cecf46ae9f2bcc92b3fe98ae36db634fc..1796c89d838f0a3b2f7b8a6afca73d06828312f6 100644 (file)
@@ -1792,7 +1792,7 @@ is decremented by 1 after each failed pseudo-cohort.  </dd>
 <p> A pseudo-cohort is the number of deliveries equal to a destination's
 delivery concurrency. </p>
 
-<p> Use <a href="postconf.5.html#transport_destination_concurrency_positive_feedback"><i>transport</i>_destination_concurrency_negative_feedback</a>
+<p> Use <a href="postconf.5.html#transport_destination_concurrency_negative_feedback"><i>transport</i>_destination_concurrency_negative_feedback</a>
 to specify a transport-specific override, where <i>transport</i>
 is the <a href="master.5.html">master.cf</a>
 name of the message delivery transport. </p>
@@ -3718,7 +3718,7 @@ client, for example:
 <blockquote>
 <pre>
 /etc/postfix/<a href="master.5.html">master.cf</a>:
-    mylmtp ... lmtp -o <a href="postconf.5.html#lmtp_lhloname">lmtp_lhlo_name</a>=foo.bar.com
+    mylmtp ... lmtp -o <a href="postconf.5.html#lmtp_lhlo_name">lmtp_lhlo_name</a>=foo.bar.com
 </pre>
 </blockquote>
 
index be98d67e78d4ed75c082534d91dc0ed79a21ddaf..5e76394a6a7752a98bccce9bb09bd360dbb4d473 100755 (executable)
@@ -254,7 +254,7 @@ while (<>) {
     s;\blmtp_tls_note_starttls_offer\b;<a href="postconf.5.html#lmtp_tls_note_starttls_offer">$&</a>;g;
     s;\blmtp_sender_dependent_authentication\b;<a href="postconf.5.html#lmtp_sender_dependent_authentication">$&</a>;g;
     s;\blmtp_sasl_path\b;<a href="postconf.5.html#lmtp_sasl_path">$&</a>;g;
-    s;\blmtp_lhlo_name\b;<a href="postconf.5.html#lmtp_lhloname">$&</a>;g;
+    s;\blmtp_lhlo_name\b;<a href="postconf.5.html#lmtp_lhlo_name">$&</a>;g;
     s;\blmtp_connect_timeout\b;<a href="postconf.5.html#lmtp_connect_timeout">$&</a>;g;
     s;\blmtp_data_done_timeout\b;<a href="postconf.5.html#lmtp_data_done_timeout">$&</a>;g;
     s;\blmtp_data_init_timeout\b;<a href="postconf.5.html#lmtp_data_init_timeout">$&</a>;g;
@@ -636,7 +636,7 @@ while (<>) {
     # Transport-dependent magical parameters.
 
     s;(<i>transport</i>)(<b>)?(_destination_concurrency_failed_cohort_limit)\b;$2<a href="postconf.5.html#transport_destination_concurrency_failed_cohort_limit">$1$3</a>;g;
-    s;(<i>transport</i>)(<b>)?(_destination_concurrency_negative_feedback)\b;$2<a href="postconf.5.html#transport_destination_concurrency_positive_feedback">$1$3</a>;g;
+    s;(<i>transport</i>)(<b>)?(_destination_concurrency_negative_feedback)\b;$2<a href="postconf.5.html#transport_destination_concurrency_negative_feedback">$1$3</a>;g;
     s;(<i>transport</i>)(<b>)?(_destination_concurrency_positive_feedback)\b;$2<a href="postconf.5.html#transport_destination_concurrency_positive_feedback">$1$3</a>;g;
     s;(<i>transport</i>)(<b>)?(_delivery_slot_cost)\b;$2<a href="postconf.5.html#transport_delivery_slot_cost">$1$3</a>;g;
     s;(<i>transport</i>)(<b>)?(_delivery_slot_discount)\b;$2<a href="postconf.5.html#transport_delivery_slot_discount">$1$3</a>;g;
index ca9d1cf48f4b3826413d34d36f262826ea37092f..0702df170fff0e63879796ae5cc990df8a41e2f0 100644 (file)
@@ -2899,12 +2899,12 @@ extern char *var_smtp_body_chks;
   * Scheduler concurrency feedback algorithms.
   */
 #define VAR_CONC_POS_FDBACK    "default_destination_concurrency_positive_feedback"
-#define _CONC_POS_FDBACK       "_concurrency_positive_feedback"
+#define _CONC_POS_FDBACK       "_destination_concurrency_positive_feedback"
 #define DEF_CONC_POS_FDBACK    "1"
 extern char *var_conc_pos_feedback;
 
 #define VAR_CONC_NEG_FDBACK    "default_destination_concurrency_negative_feedback"
-#define _CONC_NEG_FDBACK       "_concurrency_negative_feedback"
+#define _CONC_NEG_FDBACK       "_destination_concurrency_negative_feedback"
 #define DEF_CONC_NEG_FDBACK    "1"
 extern char *var_conc_neg_feedback;
 
@@ -2912,7 +2912,7 @@ extern char *var_conc_neg_feedback;
 #define CONC_FDBACK_NAME_SQRT_WIN "sqrt_concurrency"
 
 #define VAR_CONC_COHORT_LIM    "default_destination_concurrency_failed_cohort_limit"
-#define _CONC_COHORT_LIM       "_concurrency_failed_cohort_limit"
+#define _CONC_COHORT_LIM       "_destination_concurrency_failed_cohort_limit"
 #define DEF_CONC_COHORT_LIM    1
 extern int var_conc_cohort_limit;
 
index 251fb751b9b315bd3e449a0cf6bad0fc2a653afa..e7b69aef73d80353015070e3c76a39d285d385fb 100644 (file)
@@ -20,8 +20,8 @@
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
-#define MAIL_RELEASE_DATE      "20090103"
-#define MAIL_VERSION_NUMBER    "2.5.6"
+#define MAIL_RELEASE_DATE      "20090512"
+#define MAIL_VERSION_NUMBER    "2.5.7"
 
 #ifdef SNAPSHOT
 # define MAIL_VERSION_DATE     "-" MAIL_RELEASE_DATE
index aac9dc35c611450e8fbb516c4c6cf976ba84e60f..09149f2d25b7674abd6dea73dfa2b93a56a5e851 100644 (file)
@@ -286,6 +286,8 @@ QMGR_TRANSPORT *qmgr_transport_select(void)
            continue;
        need = xport->pending + 1;
        for (queue = xport->queue_list.next; queue; queue = queue->peers.next) {
+           if (QMGR_QUEUE_READY(queue) == 0)
+               continue;
            if ((need -= MIN5af51743e4eef(queue->window - queue->busy_refcount,
                                          queue->todo_refcount)) <= 0) {
                QMGR_LIST_ROTATE(qmgr_transport_list, xport);
index 630bdb300ce440ac987ba8faebc0a9fd9c90bd70..e2196a057ad5aa7c0c711d99df05fc80d031807a 100644 (file)
@@ -340,7 +340,8 @@ int     main(int argc, char **argv)
 
     signal(SIGINT, postdrop_sig);
     signal(SIGQUIT, postdrop_sig);
-    signal(SIGTERM, postdrop_sig);
+    if (signal(SIGTERM, SIG_IGN) == SIG_DFL)
+       signal(SIGTERM, postdrop_sig);
     if (signal(SIGHUP, SIG_IGN) == SIG_DFL)
        signal(SIGHUP, postdrop_sig);
     msg_cleanup(postdrop_cleanup);
index 48f390909ade23b3131ebb9dd41670d109a287c8..c9d980030d0019f2a1f8bee1907ca92d1dbe5bde 100644 (file)
@@ -974,11 +974,17 @@ static void interrupted(int sig)
     /*
      * This commands requires root privileges. We therefore do not worry
      * about hostile signals, and report problems via msg_warn().
+     * 
+     * We use the in-kernel SIGINT handler address as an atomic variable to
+     * prevent nested interrupted() calls. For this reason, main() must
+     * configure interrupted() as SIGINT handler before other signal handlers
+     * are allowed to invoke interrupted(). See also similar code in
+     * postdrop.
      */
-    if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
-       (void) signal(SIGINT, SIG_IGN);
+    if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
        (void) signal(SIGQUIT, SIG_IGN);
        (void) signal(SIGTERM, SIG_IGN);
+       (void) signal(SIGHUP, SIG_IGN);
        if (inode_mismatch > 0 || inode_fixed > 0 || position_mismatch > 0)
            msg_warn("OPERATION INCOMPLETE -- RERUN COMMAND TO FIX THE QUEUE FIRST");
        if (sig)
@@ -1175,11 +1181,20 @@ int     main(int argc, char **argv)
      * 
      * Set up signal handlers after permanently dropping super-user privileges,
      * so that signal handlers will always run with the correct privileges.
+     * 
+     * XXX Don't enable SIGHUP or SIGTERM if it was ignored by the parent.
+     * 
+     * interrupted() uses the in-kernel SIGINT handler address as an atomic
+     * variable to prevent nested interrupted() calls. For this reason, the
+     * SIGINT handler must be configured before other signal handlers are
+     * allowed to invoke interrupted(). See also similar code in postdrop.
      */
-    signal(SIGHUP, interrupted);
     signal(SIGINT, interrupted);
     signal(SIGQUIT, interrupted);
-    signal(SIGTERM, interrupted);
+    if (signal(SIGTERM, SIG_IGN) == SIG_DFL)
+       signal(SIGTERM, interrupted);
+    if (signal(SIGHUP, SIG_IGN) == SIG_DFL)
+       signal(SIGHUP, interrupted);
     msg_cleanup(fatal_warning);
 
     /*
index df8b980adc6b3b1ecc4ba02966c62a0a64db16e6..52f0327e3a58cd8c7bc26dec07d5d5ed8c92fbe2 100644 (file)
@@ -436,6 +436,7 @@ struct QMGR_PEER {
 
 extern QMGR_ENTRY *qmgr_job_entry_select(QMGR_TRANSPORT *);
 extern QMGR_PEER *qmgr_peer_select(QMGR_JOB *);
+extern void qmgr_job_blocker_update(QMGR_QUEUE *);
 
 extern QMGR_JOB *qmgr_job_obtain(QMGR_MESSAGE *, QMGR_TRANSPORT *);
 extern void qmgr_job_free(QMGR_JOB *);
index 9f89e0a7335dfb7aeddebffaa937204a38d1af20..71eba9f0ad23184d51b288ffe673ac467b2aec17 100644 (file)
@@ -299,29 +299,25 @@ void    qmgr_entry_done(QMGR_ENTRY *entry, int which)
     }
 
     /*
-     * If the queue was blocking some of the jobs on the job list, check if
-     * the concurrency limit has lifted. If there are still some pending
-     * deliveries, give it a try and unmark all transport blockers at once.
-     * The qmgr_job_entry_select() will do the rest. In either case make sure
-     * the queue is not marked as a blocker anymore, with extra handling of
-     * queues which were declared dead.
+     * We implement a rate-limited queue by emulating a slow delivery
+     * channel. We insert the artificial delays with qmgr_queue_suspend().
      * 
-     * Note that changing the blocker status also affects the candidate cache.
-     * Most of the cases would be automatically recognized by the current job
-     * change, but we play safe and reset the cache explicitly below.
-     * 
-     * Keeping the transport blocker tag odd is an easy way to make sure the tag
-     * never matches jobs that are not explicitly marked as blockers.
+     * When a queue is suspended, we must postpone any job scheduling decisions
+     * until the queue is resumed. Otherwise, we make those decisions now.
+     * The job scheduling decisions are made by qmgr_job_blocker_update().
      */
-    if (queue->blocker_tag == transport->blocker_tag) {
-       if (queue->window > queue->busy_refcount && queue->todo.next != 0) {
-           transport->blocker_tag += 2;
-           transport->job_current = transport->job_list.next;
-           transport->candidate_cache_current = 0;
-       }
-       if (queue->window > queue->busy_refcount || QMGR_QUEUE_THROTTLED(queue))
-           queue->blocker_tag = 0;
+    if (which == QMGR_QUEUE_BUSY && transport->rate_delay > 0) {
+       if (queue->window > 1)
+           msg_panic("%s: queue %s/%s: window %d > 1 on rate-limited service",
+                     myname, transport->name, queue->name, queue->window);
+       if (QMGR_QUEUE_THROTTLED(queue))        /* XXX */
+           qmgr_queue_unthrottle(queue);
+       if (QMGR_QUEUE_READY(queue))
+           qmgr_queue_suspend(queue, transport->rate_delay);
     }
+    if (!QMGR_QUEUE_SUSPENDED(queue)
+       && queue->blocker_tag == transport->blocker_tag)
+       qmgr_job_blocker_update(queue);
 
     /*
      * When there are no more entries for this peer, discard the peer
@@ -337,19 +333,6 @@ void    qmgr_entry_done(QMGR_ENTRY *entry, int which)
     if (which == QMGR_QUEUE_BUSY)
        queue->last_done = event_time();
 
-    /*
-     * Suspend a rate-limited queue, so that mail trickles out.
-     */
-    if (which == QMGR_QUEUE_BUSY && transport->rate_delay > 0) {
-       if (queue->window > 1)
-           msg_panic("%s: queue %s/%s: window %d > 1 on rate-limited service",
-                     myname, transport->name, queue->name, queue->window);
-       if (QMGR_QUEUE_THROTTLED(queue))        /* XXX */
-           qmgr_queue_unthrottle(queue);
-       if (QMGR_QUEUE_READY(queue))
-           qmgr_queue_suspend(queue, transport->rate_delay);
-    }
-
     /*
      * When the in-core queue for this site is empty and when this site is
      * not dead or suspended, discard the in-core queue. When this site is
index ad727f43a6da538d07e06bf0c5adce97b79b56e5..7de70f25c3f1b7115c35780f152fefc68aa16ffe 100644 (file)
@@ -18,6 +18,9 @@
 /*
 /*     QMGR_ENTRY *qmgr_job_entry_select(transport)
 /*     QMGR_TRANSPORT *transport;
+/*
+/*     void    qmgr_job_blocker_update(queue)
+/*     QMGR_QUEUE *queue;
 /* DESCRIPTION
 /*     These routines add/delete/manipulate per-transport jobs.
 /*     Each job corresponds to a specific transport and message.
 /*     If necessary, an attempt to read more recipients into core is made.
 /*     This can result in creation of more job, queue and entry structures.
 /*
+/*     qmgr_job_blocker_update() updates the status of blocked
+/*     jobs after a decrease in the queue's concurrency level,
+/*     after the queue is throttled, or after the queue is resumed
+/*     from suspension.
+/*
 /*     qmgr_job_move_limits() takes care of proper distribution of the
 /*     per-transport recipients limit among the per-transport jobs.
 /*     Should be called whenever a job's recipient slot becomes available.
@@ -937,3 +945,36 @@ QMGR_ENTRY *qmgr_job_entry_select(QMGR_TRANSPORT *transport)
     transport->job_current = 0;
     return (0);
 }
+
+/* qmgr_job_blocker_update - update "blocked job" status */
+
+void     qmgr_job_blocker_update(QMGR_QUEUE *queue)
+{
+    QMGR_TRANSPORT *transport = queue->transport;
+
+    /*
+     * If the queue was blocking some of the jobs on the job list, check if
+     * the concurrency limit has lifted. If there are still some pending
+     * deliveries, give it a try and unmark all transport blockers at once.
+     * The qmgr_job_entry_select() will do the rest. In either case make sure
+     * the queue is not marked as a blocker anymore, with extra handling of
+     * queues which were declared dead.
+     * 
+     * Note that changing the blocker status also affects the candidate cache.
+     * Most of the cases would be automatically recognized by the current job
+     * change, but we play safe and reset the cache explicitly below.
+     * 
+     * Keeping the transport blocker tag odd is an easy way to make sure the tag
+     * never matches jobs that are not explicitly marked as blockers.
+     */
+    if (queue->blocker_tag == transport->blocker_tag) {
+       if (queue->window > queue->busy_refcount && queue->todo.next != 0) {
+           transport->blocker_tag += 2;
+           transport->job_current = transport->job_list.next;
+           transport->candidate_cache_current = 0;
+       }
+       if (queue->window > queue->busy_refcount || QMGR_QUEUE_THROTTLED(queue))
+           queue->blocker_tag = 0;
+    }
+}
+
index 3bc6782b2f73efbd51694edda28c5928627bf860..d35b7db0cb9249733bd93b3fb3d54e8d21459595 100644 (file)
 /*     "slow open" mode, and eliminates the "thundering herd" problem.
 /*
 /*     qmgr_queue_suspend() suspends delivery for this destination
-/*     briefly.
+/*     briefly. This function invalidates any scheduling decisions
+/*     that are based on the present queue's concurrency window.
+/*     To compensate for work skipped by qmgr_entry_done(), the
+/*     status of blocker jobs is re-evaluated after the queue is
+/*     resumed.
 /* DIAGNOSTICS
 /*     Panic: consistency check failure.
 /* LICENSE
@@ -152,9 +156,20 @@ static void qmgr_queue_resume(int event, char *context)
     /*
      * Every event handler that leaves a queue in the "ready" state should
      * remove the queue when it is empty.
+     * 
+     * XXX Do not omit the redundant test below. It is here to simplify code
+     * consistency checks. The check is trivially eliminated by the compiler
+     * optimizer. There is no need to sacrifice code clarity for the sake of
+     * performance.
+     * 
+     * XXX Do not expose the blocker job logic here. Rate-limited queues are not
+     * a performance-critical feature. Here, too, there is no need to sacrifice
+     * code clarity for the sake of performance.
      */
     if (QMGR_QUEUE_READY(queue) && queue->todo.next == 0 && queue->busy.next == 0)
        qmgr_queue_done(queue);
+    else
+       qmgr_job_blocker_update(queue);
 }
 
 /* qmgr_queue_suspend - briefly suspend a destination */
index 1265c6f0ccf162d345286405d5038a01d3c3df5b..04bd0b06b20c9be3f3cab12da7df24a578a1b64e 100644 (file)
@@ -291,6 +291,8 @@ QMGR_TRANSPORT *qmgr_transport_select(void)
            continue;
        need = xport->pending + 1;
        for (queue = xport->queue_list.next; queue; queue = queue->peers.next) {
+           if (QMGR_QUEUE_READY(queue) == 0)
+               continue;
            if ((need -= MIN5af51743e4eef(queue->window - queue->busy_refcount,
                                          queue->todo_refcount)) <= 0) {
                QMGR_LIST_ROTATE(qmgr_transport_list, xport, peers);
index ed40eff5b25863dec88f8217889ab0c8dc26c8a1..886f4016b47679abe6311f09a9b48e56625e5ef4 100644 (file)
@@ -1771,12 +1771,15 @@ static int smtp_loop(SMTP_STATE *state, NOCLOBBER int send_state,
                 * XXX Don't downgrade just because generic_maps is turned
                 * on.
                 */
-               if (downgrading || smtp_generic_maps || smtp_header_checks
-                   || smtp_body_checks)
+#define SMTP_ANY_CHECKS (smtp_header_checks || smtp_body_checks)
+
+               if (downgrading || smtp_generic_maps || SMTP_ANY_CHECKS)
                    session->mime_state = mime_state_alloc(downgrading ?
                                                           MIME_OPT_DOWNGRADE
                                                 | MIME_OPT_REPORT_NESTING :
-                                                     MIME_OPT_DISABLE_MIME,
+                                                     SMTP_ANY_CHECKS == 0 ?
+                                                    MIME_OPT_DISABLE_MIME :
+                                                          0,
                                                           smtp_generic_maps
                                                     || smtp_header_checks ?
                                                       smtp_header_rewrite :
index c2fa84102bde04b3563d82b95030685b41924182..cfefe7e3dde80307c66b7f02d4b420ca87accad0 100644 (file)
@@ -564,11 +564,23 @@ int     smtpd_proxy_cmd(SMTPD_STATE *state, int expect, const char *fmt,...)
     /*
      * Log a warning in case the proxy does not send the expected response.
      * Silently accept any response when the client expressed no expectation.
+     * 
+     * Don't pass through misleading 2xx replies. it confuses naive users and
+     * SMTP clients, and creates support problems.
      */
     if (expect != SMTPD_PROX_WANT_ANY && expect != *STR(state->proxy_buffer)) {
        va_start(ap, fmt);
        smtpd_proxy_cmd_error(state, fmt, ap);
        va_end(ap);
+       if (*STR(state->proxy_buffer) == SMTPD_PROX_WANT_OK
+           || *STR(state->proxy_buffer) == SMTPD_PROX_WANT_MORE) {
+           state->error_mask |= MAIL_ERROR_SOFTWARE;
+           state->err |= CLEANUP_STAT_PROXY;
+           detail = cleanup_stat_detail(CLEANUP_STAT_PROXY);
+           vstring_sprintf(state->proxy_buffer,
+                           "%d %s Error: %s",
+                           detail->smtp, detail->dsn, detail->text);
+       }
        return (-1);
     } else {
        return (0);