]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.5.12 v2.5.12
authorWietse Venema <wietse@porcupine.org>
Thu, 3 Mar 2011 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <postfix-users@dukhovni.org>
Sat, 10 Feb 2018 19:57:40 +0000 (14:57 -0500)
12 files changed:
postfix/HISTORY
postfix/makedefs
postfix/src/cleanup/cleanup_map1n.c
postfix/src/global/mail_version.h
postfix/src/local/recipient.c
postfix/src/master/master_sig.c
postfix/src/smtp/smtp_proto.c
postfix/src/smtpd/smtpd.c
postfix/src/util/host_port.c
postfix/src/util/make_dirs.c
postfix/src/util/sys_defs.h
postfix/src/util/watchdog.c

index 6ded39d8ebafbf711b08d4a98acfc58776a57ac2..a78420e39b41dfb1d2336c32575c437d0c276223 100644 (file)
@@ -14571,6 +14571,18 @@ Apologies for any names omitted.
        2821 (and 5321) is vague about the VRFY request format, but
        spends lots of text on the reply format.  File: smtpd/smtpd.c.
 
+20100422
+
+       Workaround (introduced: postfix-19990906 a.k.a. Postfix
+       0.8.0).  The Postfix local delivery agent did not properly
+       distinguish between "address has no extension" and "address
+       has an extension, but the extension is invalid". In both
+       cases it would run only the full recipient local-part through
+       the alias maps.  Instead, it now drops the faulty extension
+       from the recipient address local-part (it would be too
+       error-prone to replace all tests for "no extension" by tests
+       for "no valid extension".  File: local/recipient.c.
+
 20100610
 
        Bugfix (introduced Postfix 2.2): Postfix no longer appends
@@ -14610,3 +14622,59 @@ Apologies for any names omitted.
        compliance. We now make an exception for "final" replies,
        as permitted by RFC. Solution by Victor Duchovni. File:
        smtpd/smtpd.c.
+
+20101201
+
+       Workaround: BSD-ish mkdir() ignores the effective GID and
+       copies group ownership from the parent directory.  File:
+       util/make_dirs.c.
+
+20101202
+
+       Cleanup: the cleanup server now reports a temporary delivery
+       error when it reaches the virtual_alias_expansion_limit or
+       virtual_alias_recursion_limit. Previously, it would silently
+       ignore the excess recipients and deliver the message.  File:
+       cleanup/cleanup_map1n.c.
+
+20110105
+
+       Bugfix (introduced with the Postfix TLS patch): discard
+       plaintext following the STARTTLS command or response. This
+       matters only for the minority of SMTP clients that actually
+       verify server certificates.  Files: smtpd/smtpd.c,
+       smtp/smtp_proto.c.
+
+       This vulnerability is also known as CVE-2011-0411.
+
+20110109
+
+       Bugfix (introduced Postfix 2.4): on Solaris the Postfix
+       event engine was deaf for SIGHUP and SIGALRM signals after
+       the switch to /dev/poll. Symptoms were delayed "postfix
+       reload" response, and killed processes when the watchdog
+       timeout was less than max_idle.  The fix is to set up SIGHUP
+       and SIGALRM handlers that write to a pipe, and to monitor
+       that pipe for read events via the Postfix event engine.
+       Files: master/master_sig.c, util/watchdog.c, util/sys_defs.h.
+
+20110117
+
+       Bugfix (introduced Postfix alpha, or thereabouts): on HP-UX
+       the Postfix event engine was deaf for SIGALRM signals.
+       Symptoms were killed processes when the watchdog timeout
+       was less than max_idle.  The fix is the same as Solaris fix
+       20110109. Since we can't know what other systems need this,
+       the workaround is enabled by default.  Files: util/sys_defs.h.
+
+20110225
+
+       Workaround (problem introduced with IPv6 support in Postfix
+       2.2): the SMTP client did not support mail to [ipv6:ipv6addr].
+       Fix based on a patch by Gurusamy Sarathy (Sophos).  File:
+       util/host_port.c and regression test files.
+
+20110227
+
+       Portability: FreeBSD closefrom() support time window.  Sahil
+       Tandon. File: util/sys_defs.h.
index af60d58d0efd5c01ae5f0035b7ba4d7052b3b4f7..51e094d3d3a9269605089ba4f1ce7c39094f7787 100644 (file)
@@ -214,6 +214,12 @@ case "$SYSTEM.$RELEASE" in
                done
                ;;
        AIX.*)  case "`uname -v`" in
+               6)      SYSTYPE=AIX6
+                       case "$CC" in
+                       cc|*/cc|xlc|*/xlc) CCARGS="$CCARGS -w -blibpath:/usr/lib:/lib:/usr/local/lib";;
+                       esac
+                       CCARGS="$CCARGS -D_ALL_SOURCE -DHAS_POSIX_REGEXP"
+                       ;;
                5)      SYSTYPE=AIX5
                        case "$CC" in
                        cc|*/cc|xlc|*/xlc) CCARGS="$CCARGS -w -blibpath:/usr/lib:/lib:/usr/local/lib";;
index e69ec190f0825156babe518aca5f2032196c6a67..b806a6017a99928a819a694dcf770840db8cd10c 100644 (file)
 /*     This module implements one-to-many table mapping via table lookup.
 /*     Table lookups are done with quoted (externalized) address forms.
 /*     The process is recursive. The recursion terminates when the
-/*     left-hand side appears in its own expansion, or when a maximal
-/*     nesting level is reached.
+/*     left-hand side appears in its own expansion.
 /*
 /*     cleanup_map1n_internal() is the interface for addresses in
 /*     internal (unquoted) form.
 /* DIAGNOSTICS
-/*     Recoverable errors: the global \fIcleanup_errs\fR flag is updated.
+/*     When the maximal expansion or recursion limit is reached,
+/*     the alias is not expanded and the CLEANUP_STAT_DEFER error
+/*     is raised with reason "4.6.0 Alias expansion error".
+/*
+/*     When table lookup fails, the alias is not expanded and the
+/*     CLEANUP_STAT_WRITE error is raised with reason "4.6.0 Alias
+/*     expansion error".
 /* SEE ALSO
 /*     mail_addr_map(3) address mappings
 /*     mail_addr_find(3) address lookups
@@ -93,15 +98,26 @@ ARGV   *cleanup_map1n_internal(CLEANUP_STATE *state, const char *addr,
      * must index the array explicitly, instead of running along it with a
      * pointer.
      */
-#define UPDATE(ptr,new)        { myfree(ptr); ptr = mystrdup(new); }
+#define UPDATE(ptr,new)        do { \
+       if (ptr) myfree(ptr); ptr = mystrdup(new); \
+    } while (0)
 #define STR    vstring_str
-#define RETURN(x) { been_here_free(been_here); return (x); }
+#define RETURN(x) do { \
+       been_here_free(been_here); return (x); \
+    } while (0)
+#define UNEXPAND(argv, addr) do { \
+       argv_truncate((argv), 0); argv_add((argv), (addr), (char *) 0); \
+    } while (0)
 
     for (arg = 0; arg < argv->argc; arg++) {
        if (argv->argc > var_virt_expan_limit) {
-           msg_warn("%s: unreasonable %s map expansion size for %s",
+           msg_warn("%s: unreasonable %s map expansion size for %s -- "
+                    "deferring delivery",
                     state->queue_id, maps->title, addr);
-           break;
+           state->errs |= CLEANUP_STAT_DEFER;
+           UPDATE(state->reason, "4.6.0 Alias expansion error");
+           UNEXPAND(argv, addr);
+           RETURN(argv);
        }
        for (count = 0; /* void */ ; count++) {
 
@@ -111,9 +127,13 @@ ARGV   *cleanup_map1n_internal(CLEANUP_STATE *state, const char *addr,
            if (been_here_check_fixed(been_here, argv->argv[arg]) != 0)
                break;
            if (count >= var_virt_recur_limit) {
-               msg_warn("%s: unreasonable %s map nesting for %s",
+               msg_warn("%s: unreasonable %s map nesting for %s -- "
+                        "deferring delivery",
                         state->queue_id, maps->title, addr);
-               break;
+               state->errs |= CLEANUP_STAT_DEFER;
+               UPDATE(state->reason, "4.6.0 Alias expansion error");
+               UNEXPAND(argv, addr);
+               RETURN(argv);
            }
            quote_822_local(state->temp1, argv->argv[arg]);
            if ((lookup = mail_addr_map(maps, STR(state->temp1), propagate)) != 0) {
@@ -136,9 +156,12 @@ ARGV   *cleanup_map1n_internal(CLEANUP_STATE *state, const char *addr,
                myfree(saved_lhs);
                argv_free(lookup);
            } else if (dict_errno != 0) {
-               msg_warn("%s: %s map lookup problem for %s",
+               msg_warn("%s: %s map lookup problem for %s -- "
+                        "deferring delivery",
                         state->queue_id, maps->title, addr);
                state->errs |= CLEANUP_STAT_WRITE;
+               UPDATE(state->reason, "4.6.0 Alias expansion error");
+               UNEXPAND(argv, addr);
                RETURN(argv);
            } else {
                break;
index ca3776258ef077febb055c616c156d36eab47f67..bac353695dd5c83d4a46b75595c5d570cc6f68ed 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      "20101123"
-#define MAIL_VERSION_NUMBER    "2.5.11"
+#define MAIL_RELEASE_DATE      "20110303"
+#define MAIL_VERSION_NUMBER    "2.5.12"
 
 #ifdef SNAPSHOT
 # define MAIL_VERSION_DATE     "-" MAIL_RELEASE_DATE
index e279eef0e2b8ec43d6d8dd9798f911cea0ca6949..8432e3fdc1d866dd47c4850d3f22c4f4db381c87 100644 (file)
@@ -287,6 +287,10 @@ int     deliver_recipient(LOCAL_STATE state, USER_ATTR usr_attr)
 
     /*
      * Address extension management.
+     * 
+     * XXX Fix 20100422, finalized 20100529: it is too error-prone to
+     * distinguish between "no extension" and "no valid extension", so we
+     * drop an invalid extension from the recipient address local-part.
      */
     state.msg_attr.user = mystrdup(state.msg_attr.local);
     if (*var_rcpt_delim) {
@@ -296,6 +300,9 @@ int     deliver_recipient(LOCAL_STATE state, USER_ATTR usr_attr)
            msg_warn("%s: address with illegal extension: %s",
                     state.msg_attr.queue_id, state.msg_attr.local);
            state.msg_attr.extension = 0;
+           /* XXX Can't myfree + mystrdup, must truncate instead. */
+           state.msg_attr.local[strlen(state.msg_attr.user)] = 0;
+           /* Truncating is safe. The code below rejects null usernames. */
        }
     } else
        state.msg_attr.extension = 0;
index 0f7d2e6e1d37dbef2f2fb5e866c1c9204bb9e0c4..925144725605adaa7782699a1e6204ec578308af 100644 (file)
@@ -53,9 +53,8 @@
 
 #ifdef USE_SIG_RETURN
 #include <sys/syscall.h>
-#endif
-
-#ifndef USE_SIG_RETURN
+#undef USE_SIG_PIPE
+#else
 #define USE_SIG_PIPE
 #endif
 
@@ -76,6 +75,8 @@ int     master_sig_pipe[2];
 int     master_gotsigchld;
 int     master_gotsighup;
 
+#ifdef USE_SIG_RETURN
+
 /* master_sighup - register arrival of hangup signal */
 
 static void master_sighup(int sig)
@@ -92,8 +93,6 @@ static void master_sighup(int sig)
 
 /* master_sigchld - register arrival of child death signal */
 
-#ifdef USE_SIG_RETURN
-
 static void master_sigchld(int sig, int code, struct sigcontext * scp)
 {
 
@@ -116,7 +115,25 @@ static void master_sigchld(int sig, int code, struct sigcontext * scp)
 
 #else
 
-#ifdef USE_SIG_PIPE
+/* master_sighup - register arrival of hangup signal */
+
+static void master_sighup(int sig)
+{
+    int     saved_errno = errno;
+
+    /*
+     * WARNING WARNING WARNING.
+     * 
+     * This code runs at unpredictable moments, as a signal handler. Don't put
+     * any code here other than for setting a global flag, or code that is
+     * intended to be run within a signal handler. Restore errno in case we
+     * are interrupting the epilog of a failed system call.
+     */
+    master_gotsighup = sig;
+    if (write(SIG_PIPE_WRITE_FD, "", 1) != 1)
+       msg_warn("write to SIG_PIPE_WRITE_FD failed: %m");
+    errno = saved_errno;
+}
 
 /* master_sigchld - force wakeup from select() */
 
@@ -132,6 +149,7 @@ static void master_sigchld(int unused_sig)
      * intended to be run within a signal handler. Restore errno in case we
      * are interrupting the epilog of a failed system call.
      */
+    master_gotsigchld = 1;
     if (write(SIG_PIPE_WRITE_FD, "", 1) != 1)
        msg_warn("write to SIG_PIPE_WRITE_FD failed: %m");
     errno = saved_errno;
@@ -145,24 +163,8 @@ static void master_sig_event(int unused_event, char *unused_context)
 
     while (read(SIG_PIPE_READ_FD, c, 1) > 0)
         /* void */ ;
-    master_gotsigchld = 1;
 }
 
-#else
-
-static void master_sigchld(int sig)
-{
-
-    /*
-     * WARNING WARNING WARNING.
-     * 
-     * This code runs at unpredictable moments, as a signal handler. Don't put
-     * any code here other than for setting a global flag.
-     */
-    master_gotsigchld = sig;
-}
-
-#endif
 #endif
 
 /* master_sigdeath - die, women and children first */
index 886f4016b47679abe6311f09a9b48e56625e5ef4..2573d81aacda7f544548229c2ef32e0b1fee4445 100644 (file)
@@ -811,6 +811,9 @@ static int smtp_start_tls(SMTP_STATE *state)
                                   SMTP_RESP_FAKE(&fake, "4.7.5"),
                                   "Server certificate not verified"));
 
+    /* At this point there must not be any pending plaintext. */
+    vstream_fpurge(session->stream, VSTREAM_PURGE_BOTH);
+
     /*
      * At this point we have to re-negotiate the "EHLO" to reget the
      * feature-list.
index a376e06a5839c4403051d8217e20241d6e460046..f13ad7011470050cb8ea2f3f7cf2fe3e010191da 100644 (file)
@@ -3911,6 +3911,8 @@ static int starttls_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
     smtpd_chat_reply(state, "220 2.0.0 Ready to start TLS");
     /* Flush before we switch the stream's read/write routines. */
     smtp_flush(state->client);
+    /* At this point there must not be any pending plaintext. */
+    vstream_fpurge(state->client, VSTREAM_PURGE_BOTH);
 
     /*
      * Reset all inputs to the initial state.
index bfcad8c09a37c0d9c3977a34222f3b4f1e5bf001..7cc932479307ac4554b397b360b2b3c76c6368b2 100644 (file)
 
 #include <host_port.h>
 
+ /*
+  * Point-fix workaround. The libutil library should be email agnostic, but
+  * we can't rip up the library APIs in the stable releases.
+  */
+#include <string.h>
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+#define IPV6_COL           "IPv6:"     /* RFC 2821 */
+#define IPV6_COL_LEN       (sizeof(IPV6_COL) - 1)
+#define HAS_IPV6_COL(str)  (strncasecmp((str), IPV6_COL, IPV6_COL_LEN) == 0)
+
 /* host_port - parse string into host and port, destroy string */
 
 const char *host_port(char *buf, char **host, char *def_host,
                              char **port, char *def_service)
 {
     char   *cp = buf;
+    int     ipv6 = 0;
 
     /*
      * [host]:port, [host]:, [host].
+     * [ipv6:ipv6addr]:port, [ipv6:ipv6addr]:, [ipv6:ipv6addr].
      */
     if (*cp == '[') {
-       *host = ++cp;
+       ++cp;
+       if ((ipv6 = HAS_IPV6_COL(cp)) != 0)
+           cp += IPV6_COL_LEN;
+       *host = cp;
        if ((cp = split_at(cp, ']')) == 0)
            return ("missing \"]\"");
        if (*cp && *cp++ != ':')
            return ("garbage after \"]\"");
+       if (ipv6 && !valid_ipv6_hostaddr(*host, DONT_GRIPE))
+           return ("malformed IPv6 address");
        *port = *cp ? cp : def_service;
     }
 
index cf50aae2575cb12897991471ed4f614308d319e2..fef1c6fcc7d6f9c0ad41b995fd41d5a13044ea39 100644 (file)
@@ -37,6 +37,7 @@
 #include <sys/stat.h>
 #include <errno.h>
 #include <string.h>
+#include <unistd.h>
 
 /* Utility library. */
 
 
 int     make_dirs(const char *path, int perms)
 {
+    const char *myname = "make_dirs";
     char   *saved_path;
     unsigned char *cp;
     int     saved_ch;
     struct stat st;
     int     ret;
     mode_t  saved_mode = 0;
+    gid_t   egid = -1;
 
     /*
      * Initialize. Make a copy of the path that we can safely clobber.
@@ -117,6 +120,21 @@ int     make_dirs(const char *path, int perms)
                    break;
                }
            }
+
+           /*
+            * Fix directory ownership when mkdir() ignores the effective
+            * GID. Don't change the effective UID for doing this.
+            */
+           if ((ret = stat(saved_path, &st)) < 0) {
+               msg_warn("%s: stat %s: %m", myname, saved_path);
+               break;
+           }
+           if (egid == -1)
+               egid = getegid();
+           if (st.st_gid != egid && (ret = chown(saved_path, -1, egid)) < 0) {
+               msg_warn("%s: chgrp %s: %m", myname, saved_path);
+               break;
+           }
        }
        if (saved_ch != 0)
            *cp = saved_ch;
index d0411d77587a353c272d5692c0b59c511dc10b48..e1ab6b701b06db4bf8938e8e2bca9cbb5cc09d52 100644 (file)
 #define HAS_DUPLEX_PIPE                        /* 4.1 breaks with kqueue(2) */
 #endif
 
-#if __FreeBSD_version >= 800098                /* commit: r194262 */
+#if (__FreeBSD_version >= 702104 && __FreeBSD_version <= 800000) \
+    || __FreeBSD_version >= 800100
 #define HAS_CLOSEFROM
 #endif
 
@@ -506,7 +507,7 @@ extern int opterr;
   * AIX: a SYSV-flavored hybrid. NB: fcntl() and flock() access the same
   * underlying locking primitives.
   */
-#ifdef AIX5
+#if defined(AIX5) || defined(AIX6)
 #define SUPPORTED
 #include <sys/types.h>
 #define UINT32_TYPE    unsigned int
@@ -1261,6 +1262,17 @@ extern int dup2_pass_on_exec(int oldd, int newd);
 extern const char *inet_ntop(int, const void *, char *, size_t);
 extern int inet_pton(int, const char *, void *);
 
+#endif
+
+ /*
+  * Workaround: after a watchdog alarm signal, wake up from select/poll/etc.
+  * by writing to a pipe. Solaris needs this, and HP-UX apparently, too. The
+  * run-time cost is negligible so we just turn it on for all systems. As a
+  * side benefit, making this code system-independent will simplify the
+  * detection of bit-rot problems.
+  */
+#ifndef NO_WATCHDOG_PIPE
+#define USE_WATCHDOG_PIPE
 #endif
 
  /*
index a1ab0cf1edaff62254de7607ecffbed99158e880..71b483fbe42762f1e30b80aeb1c4b08725debdbb 100644 (file)
@@ -119,6 +119,31 @@ struct WATCHDOG {
   */
 static WATCHDOG *watchdog_curr;
 
+ /*
+  * Workaround for systems where the alarm signal does not wakeup the event
+  * machinery, and therefore does not restart the watchdog timer in the
+  * single_server etc. skeletons. The symptom is that programs abort when the
+  * watchdog timeout is less than the max_idle time.
+  */
+#ifdef USE_WATCHDOG_PIPE
+#include <errno.h>
+#include <iostuff.h>
+#include <events.h>
+
+static int watchdog_pipe[2];
+
+/* watchdog_read - read event pipe */
+
+static void watchdog_read(int unused_event, char *unused_context)
+{
+    char    ch;
+
+    while (read(watchdog_pipe[0], &ch, 1) > 0)
+        /* void */ ;
+}
+
+#endif                                 /* USE_WATCHDOG_PIPE */
+
 /* watchdog_event - handle timeout event */
 
 static void watchdog_event(int unused_sig)
@@ -137,6 +162,14 @@ static void watchdog_event(int unused_sig)
     if (msg_verbose > 1)
        msg_info("%s: %p %d", myname, (void *) wp, wp->trip_run);
     if (++(wp->trip_run) < WATCHDOG_STEPS) {
+#ifdef USE_WATCHDOG_PIPE
+       int     saved_errno = errno;
+
+       /* Wake up the events(3) engine. */
+       if (write(watchdog_pipe[1], "", 1) != 1)
+           msg_warn("%s: write watchdog_pipe: %m", myname);
+       errno = saved_errno;
+#endif
        alarm(wp->timeout);
     } else {
        if (wp->action)
@@ -177,6 +210,15 @@ WATCHDOG *watchdog_create(unsigned timeout, WATCHDOG_FN action, char *context)
        msg_fatal("%s: sigaction(SIGALRM): %m", myname);
     if (msg_verbose > 1)
        msg_info("%s: %p %d", myname, (void *) wp, timeout);
+#ifdef USE_WATCHDOG_PIPE
+    if (watchdog_curr == 0) {
+       if (pipe(watchdog_pipe) < 0)
+           msg_fatal("%s: pipe: %m", myname);
+       non_blocking(watchdog_pipe[0], NON_BLOCKING);
+       non_blocking(watchdog_pipe[1], NON_BLOCKING);
+       event_enable_read(watchdog_pipe[0], watchdog_read, (char *) 0);
+    }
+#endif
     return (watchdog_curr = wp);
 }
 
@@ -193,6 +235,13 @@ void    watchdog_destroy(WATCHDOG *wp)
     if (wp->saved_time)
        alarm(wp->saved_time);
     myfree((char *) wp);
+#ifdef USE_WATCHDOG_PIPE
+    if (watchdog_curr == 0) {
+       event_disable_readwrite(watchdog_pipe[0]);
+       (void) close(watchdog_pipe[0]);
+       (void) close(watchdog_pipe[1]);
+    }
+#endif
     if (msg_verbose > 1)
        msg_info("%s: %p", myname, (void *) wp);
 }