]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.3.8-RC1 v2.3.8-RC1
authorWietse Venema <wietse@porcupine.org>
Sun, 25 Feb 2007 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <postfix-users@dukhovni.org>
Sat, 10 Feb 2018 21:06:55 +0000 (16:06 -0500)
postfix/HISTORY
postfix/RELEASE_NOTES
postfix/src/global/mail_version.h
postfix/src/global/mbox_open.c
postfix/src/smtp/smtp_proto.c
postfix/src/smtpd/smtpd.c
postfix/src/tls/Makefile.in
postfix/src/tls/tls.h
postfix/src/tls/tls_client.c
postfix/src/tls/tls_misc.c
postfix/src/tls/tls_server.c

index 6168ce6ca9638b4ae2d5dc940ccdbd7002d253f9..b223ac05252bbf1d47a3fd5edbb7944a2740230f 100644 (file)
@@ -12928,16 +12928,36 @@ Apologies for any names omitted.
 
        Workaround: don't insert empty-line header/body separator
        into malformed MIME attachments, to avoid breaking digital
-       signatures. This change introduces ambiguity. Postfix still
-       treats the remainder of the attachment as body content;
-       header_checks rules will not detect forbidden MIME types
-       inside a message/rfc822 attachment.  With the empty-line
-       header/body separator no longer inserted by Postfix, other
-       software may process the malformed attachment differently,
-       and thus may become exposed to forbidden MIME types.  This
-       is back-ported from Postfix 2.4. File: global/mime_state.c.
+       signatures. This change introduces ambiguity. As before,
+       Postfix treats the remainder of the attachment as body
+       content, and header_checks rules will not detect forbidden
+       MIME types inside a malformed message/rfc822 attachment.
+       With the empty-line header/body separator no longer inserted
+       by Postfix, other software may process the malformed
+       attachment differently, and thus may now become exposed to
+       forbidden MIME types.  This is back-ported from Postfix
+       2.4. File: global/mime_state.c.
 
 20070118
 
        Bugfix: match lists didn't implement ![ipv6address].  Problem
        reported by Paulo Pacheco. File: util/match_list.c.
+
+20070224
+
+       Workaround: GNU POP3D creates a new mailbox and deletes the
+       old one. Postfix now backs off and retries delivery later,
+       instead of appending mail to a deleted file.  File:
+       global/mbox_open.c.
+
+20070225
+
+       Workaround: Disable SSL/TLS ciphers when the underlying
+       symmetric algorithm is not available in the OpenSSL crypto
+       library at the required bit strength. Problem observed with
+       SunOS 5.10's bundled OpenSSL 0.9.7 and AES 256. Also possible
+       with OpenSSL 0.9.8 and CAMELLIA 256. Root cause fixed in
+       upcoming OpenSSL 0.9.7m, 0.9.8e and 0.9.9 releases. Victor
+       Duchovni, Morgan Stanley. Files: src/smtp/smtp_proto.c,
+       src/smtpd/smtpd.c, src/tls/tls.h, src/tls/tls_client.c,
+       src/tls/tls_misc.c and src/tls/tls_server.c.
index 929e14e5b3fd0e33ffce59184a4c400691932bb3..de425fbcceffe723b2e0aca972e426a54abb7ada 100644 (file)
@@ -17,13 +17,15 @@ Incompatible changes with Postfix 2.3.7
 Postfix no longer inserts an empty-line header/body separator into
 malformed MIME attachments, to avoid breaking digital signatures.
 
-This change introduces ambiguity. Postfix still treats the remainder
-of the attachment as body content; header_checks rules will therefore
-not detect forbidden MIME types inside a message/rfc822 attachment.
+This change introduces ambiguity. As before, Postfix treats the
+remainder of the attachment as body content, and header_checks rules
+will not detect forbidden MIME types inside a malformed message/rfc822
+attachment.
 
 With the empty-line header/body separator no longer inserted by
 Postfix, other software may process the malformed attachment
-differently, and thus may become exposed to forbidden MIME types.
+differently, and thus may now become exposed to forbidden MIME types
+that they would not have been exposed to earlier.
 
 Incompatible changes with Postfix 2.3.6
 ---------------------------------------
index 2f4251817bb876bbb5e6efd9e696b31aba0add2c..832b79af30e24a87c086d9be44392372773ca129 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      "20070130"
-#define MAIL_VERSION_NUMBER    "2.3.7"
+#define MAIL_RELEASE_DATE      "20070225"
+#define MAIL_VERSION_NUMBER    "2.3.8-RC1"
 
 #ifdef SNAPSHOT
 # define MAIL_VERSION_DATE     "-" MAIL_RELEASE_DATE
index de3d1551eb2794f38626fbdfbd8a71b2c4595413..97cacdae42c342a4055829aeb5f278d2c8b696b3 100644 (file)
@@ -184,6 +184,26 @@ MBOX   *mbox_open(const char *path, int flags, mode_t mode, struct stat * st,
            return (0);
        }
     }
+
+    /*
+     * Sanity check: reportedly, GNU POP3D creates a new mailbox file and
+     * deletes the old one. This does not play well with software that opens
+     * the mailbox first and then locks it.
+     * 
+     * To detect that GNU POP3D deletes the mailbox file we look at the target
+     * file hard-link count. Note that safe_open() guarantees a hard-link
+     * count of 1, so any change in this count is a sign of trouble.
+     */
+    if (S_ISREG(st->st_mode)
+       && (fstat(vstream_fileno(fp), st) < 0 || st->st_nlink != 1)) {
+       vstring_sprintf(why->reason, "target file status changed unexpectedly");
+       dsb_status(why, mbox_dsn(EAGAIN, def_dsn));
+       msg_warn("%s: file status changed unexpectedly", path);
+       if (locked & MBOX_DOT_LOCK)
+           dot_unlockfile(path);
+       vstream_fclose(fp);
+       return (0);
+    }
     mp = (MBOX *) mymalloc(sizeof(*mp));
     mp->path = mystrdup(path);
     mp->fp = fp;
index 442e3d69536e8c0f029b0f5f2fc8c4e52bc2beb5..1bd4e55cda539cf38ea43dafafc05e526ead1986 100644 (file)
@@ -725,7 +725,7 @@ static int smtp_start_tls(SMTP_STATE *state)
        vstring_sprintf_append(serverid, "&p=%s",
                               tls_protocol_names(VAR_SMTP_TLS_MAND_PROTO,
                                                  session->tls_protocols));
-    if (session->tls_level >= TLS_LEV_ENCRYPT && session->tls_cipherlist)
+    if (session->tls_level >= TLS_LEV_ENCRYPT)
        vstring_sprintf_append(serverid, "&c=%s", session->tls_cipherlist);
 
     tls_props.ctx = smtp_tls_ctx;
index 16f71294bfc7eb9ff4099cf6b6a899ce15358b92..20f462397d0397643c37a9bb3607bc0059beaa0d 100644 (file)
@@ -4293,6 +4293,8 @@ static void pre_jail_init(char *unused_name, char **unused_argv)
                                    enforce_tls ? var_smtpd_tls_mand_excl :
                                    TLS_END_EXCLUDE,
                                    TLS_END_EXCLUDE);
+               if (props.cipherlist == 0)
+                   msg_panic("NULL export cipherlist");
            }
            if (havecert || oknocert)
                smtpd_tls_ctx = tls_server_init(&props);
index 8b8d254bf2853460d4b30a197800a3ee9b381d2c..26037fe720d5d8ab35f5bf2581f893fcdd2fdbe2 100644 (file)
@@ -151,6 +151,7 @@ tls_mgr.o: ../../include/vstream.h
 tls_mgr.o: ../../include/vstring.h
 tls_mgr.o: tls_mgr.c
 tls_mgr.o: tls_mgr.h
+tls_misc.o: ../../include/argv.h
 tls_misc.o: ../../include/msg.h
 tls_misc.o: ../../include/mymalloc.h
 tls_misc.o: ../../include/name_code.h
index f1370232703ffd56621b6386ab6e538387c7574e..78b40421af1b6d5ab6b81d990d6978894efa355c 100644 (file)
@@ -130,6 +130,7 @@ extern NAME_CODE tls_cipher_level_table[];
 
 #define TLS_END_EXCLUDE ((char *)0)
 extern const char *tls_cipher_list(int,...);
+extern const char *tls_set_cipher_list(SSL_CTX *, const char *);
 
  /*
   * tls_client.c
index 0680ee0cd14bdd5f034560456dbb03caa810f96c..0c77c8c4a672d5fae05e41c3e60ddf2713785a01 100644 (file)
@@ -626,6 +626,15 @@ TLScontext_t *tls_client_start(const tls_client_start_props *props)
     if (props->log_level >= 1)
        msg_info("setting up TLS connection to %s", props->host);
 
+    /*
+     * Before we create an SSL, update the SSL_CTX cipherlist if necessary.
+     */
+    if (tls_set_cipher_list(props->ctx, props->cipherlist) == 0) {
+       msg_warn("Invalid cipherlist \"%s\": aborting TLS session",
+                props->cipherlist);
+       return (0);
+    }
+
     /*
      * Allocate a new TLScontext for the new connection and get an SSL
      * structure. Add the location of TLScontext to the SSL to later retrieve
@@ -710,24 +719,13 @@ TLScontext_t *tls_client_start(const tls_client_start_props *props)
     }
 
     /*
-     * Per session cipher selection for sessions with mandatory encryption
+     * Try to load an existing session from the TLS session cache.
      * 
      * By the time a TLS client is negotiating ciphers it has already offered to
      * re-use a session, it is too late to renege on the offer. So we must
      * not attempt to re-use sessions whose ciphers are too weak. We expect
      * the caller to salt the session lookup key with the cipher list, so
      * that sessions found in the cache are always acceptable.
-     */
-    if (props->cipherlist != 0)
-       if (SSL_set_cipher_list(TLScontext->con, props->cipherlist) == 0) {
-           msg_warn("Could not set cipherlist: %s", props->cipherlist);
-           tls_print_errors();
-           tls_free_context(TLScontext);
-           return (0);
-       }
-
-    /*
-     * Try to load an existing session from the TLS session cache.
      * 
      * XXX To avoid memory leaks we must always call SSL_SESSION_free() after
      * calling SSL_set_session(), regardless of whether or not the session
index f8738981946fae268facfa17a3bfe351b3d571f6..2d05b0ba82baeac04500eb585765f2c6b8681912 100644 (file)
 /*
 /*     long    tls_bug_bits()
 /*
+/*     const char *tls_set_cipher_list(ssl_ctx, cipher_list)
+/*     SSL_CTX *ssl_ctx;
+/*     char    *cipher_list;
+/*
 /*     const char *tls_cipher_list(cipher_level, ...)
 /*     int     cipher_level;
 /*
 /*     for the run-time library. Some of the bug work-arounds are
 /*     not appropriate for some library versions.
 /*
+/*     tls_set_cipher_list() updates the cipher list of the specified SSL
+/*     context. Returns the new cipherlist on success, otherwise logs a
+/*     suitable warning and returns 0. The storage for the return value
+/*     is overwritted with each call.
+/*
 /*     tls_cipher_list() generates a cipher list from the specified
 /*     grade, minus any ciphers specified via a null-terminated
 /*     list of string-valued exclusions. The result is overwritten
 #include <mymalloc.h>
 #include <vstring.h>
 #include <stringops.h>
+#include <argv.h>
 
 /* TLS library. */
 
@@ -162,6 +172,134 @@ typedef struct {
     int     status;
 } TLS_VINFO;
 
+ /*
+  * OpenSSL adopted the cipher selection patch, so we don't expect any more
+  * broken ciphers other than AES and CAMELLIA.
+  */
+typedef struct {
+    char   *ssl_name;
+    int     alg_bits;
+    char   *evp_name;
+}       cipher_probe_t;
+
+static cipher_probe_t cipher_probes[] = {
+    "AES", 256, "AES-256-CBC",
+    "CAMELLIA", 256, "CAMELLIA-256-CBC",
+    0, 0, 0,
+};
+
+/* tls_exclude_missing - Append exclusions for missing ciphers */
+
+static void tls_exclude_missing(SSL_CTX *ctx, VSTRING *buf)
+{
+    const char *myname = "tls_exclude_missing";
+    static ARGV *exclude;              /* Cached */
+    SSL    *s = 0;
+
+    STACK_OF(SSL_CIPHER) * ciphers;
+    SSL_CIPHER *c;
+    cipher_probe_t *probe;
+    int     alg_bits;
+    int     num;
+    int     i;
+
+    /*
+     * Process a list of probes which specify:
+     * 
+     * An SSL cipher-suite name for a family of ciphers that use the same
+     * symmetric algorithm at two or more key sizes, typically 128/256 bits.
+     * 
+     * The key size (typically 256) that OpenSSL fails check, and assumes is
+     * available when another key size (typically 128) is usable.
+     * 
+     * The OpenSSL name of the symmetric algorithm associated with the SSL
+     * cipher-suite. Typically, this is MUMBLE-256-CBC, where "MUMBLE" is the
+     * name of the SSL cipher-suite that use the MUMBLE symmetric algorithm.
+     * On systems that support the required encryption algorithm, the name is
+     * listed in the output of "openssl list-cipher-algorithms".
+     * 
+     * When an encryption algorithm is not available at the given key size but
+     * the corresponding OpenSSL cipher-suite contains ciphers that have have
+     * this key size, the problem ciphers are explicitly disabled in Postfix.
+     * The list is cached in the static "exclude" array.
+     */
+    if (exclude == 0) {
+       exclude = argv_alloc(1);
+
+       /*
+        * Iterate over the probe list
+        */
+       for (probe = cipher_probes; probe->ssl_name; ++probe) {
+           /* No exclusions if evp_name is a valid algorithm */
+           if (EVP_get_cipherbyname(probe->evp_name))
+               continue;
+
+           /*
+            * Sadly there is no SSL_CTX_get_ciphers() interface, so we are
+            * forced to allocate and free an SSL object. Fatal error if we
+            * can't allocate the SSL object.
+            */
+           ERR_clear_error();
+           if (s == 0 && (s = SSL_new(ctx)) == 0) {
+               tls_print_errors();
+               msg_fatal("%s: error allocating SSL object", myname);
+           }
+
+           /*
+            * Cipher is not supported by libcrypto, nothing to do if also
+            * not supported by libssl. Flush the OpenSSL error stack.
+            * 
+            * XXX: There may be additional places in pre-existing code where
+            * SSL errors are generated and ignored, that require a similar
+            * "flush". Better yet, is to always flush before calls that run
+            * tls_print_errors() on failure.
+            * 
+            * Contrary to documentation, on SunOS 5.10 SSL_set_cipher_list()
+            * returns success with no ciphers selected, when this happens
+            * SSL_get_ciphers() produces a stack with 0 elements!
+            */
+           if (SSL_set_cipher_list(s, probe->ssl_name) == 0
+               || (ciphers = SSL_get_ciphers(s)) == 0
+               || (num = sk_SSL_CIPHER_num(ciphers)) == 0) {
+               ERR_clear_error();              /* flush any generated errors */
+               continue;
+           }
+           for (i = 0; i < num; ++i) {
+               c = sk_SSL_CIPHER_value(ciphers, i);
+               (void) SSL_CIPHER_get_bits(c, &alg_bits);
+               if (alg_bits == probe->alg_bits)
+                   argv_add(exclude, SSL_CIPHER_get_name(c), ARGV_END);
+           }
+       }
+       if (s != 0)
+           SSL_free(s);
+    }
+    for (i = 0; i < exclude->argc; ++i)
+       vstring_sprintf_append(buf, ":!%s", exclude->argv[i]);
+}
+
+/* tls_set_cipher_list - Set SSL_CTX cipher list */
+
+const char *tls_set_cipher_list(SSL_CTX *ssl_ctx, const char *spec)
+{
+    static VSTRING *buf;
+    const char *ex_spec;
+
+    if (buf == 0)
+       buf = vstring_alloc(10);
+
+    vstring_strcpy(buf, spec);
+    tls_exclude_missing(ssl_ctx, buf);
+    ex_spec = vstring_str(buf);
+
+    ERR_clear_error();
+    if (SSL_CTX_set_cipher_list(ssl_ctx, ex_spec) != 0)
+       return (ex_spec);
+
+    tls_print_errors();
+    return (0);
+}
+
 /* tls_cipher_list - Cipherlist for given grade, less exclusions */
 
 const char *tls_cipher_list(int cipher_level,...)
@@ -196,9 +334,16 @@ const char *tls_cipher_list(int cipher_level,...)
     case TLS_CIPHER_NONE:
        return 0;
     default:
+
+       /*
+        * The caller MUST provide a valid cipher grade
+        */
        msg_panic("%s: invalid cipher grade: %d", myname, cipher_level);
     }
 
+    /*
+     * The base lists for each grade can't be empty.
+     */
     if (VSTRING_LEN(buf) == 0)
        msg_panic("%s: empty cipherlist", myname);
 
@@ -207,22 +352,16 @@ const char *tls_cipher_list(int cipher_level,...)
        if (*exclude == '\0')
            continue;
        save = cp = mystrdup(exclude);
-       while ((tok = mystrtok(&cp, "\t\n\r ,")) != 0) {
+       while ((tok = mystrtok(&cp, "\t\n\r ,:")) != 0) {
 
            /*
-            * Can't exclude ciphers that start with modifiers, or
-            * multi-element (":" separated) ciphers.
+            * Can't exclude ciphers that start with modifiers.
             */
            if (strchr("!+-@", *tok)) {
                msg_warn("%s: can't exclude '!+-@' modifiers, '%s' ignored",
                         myname, tok);
                continue;
            }
-           if (strchr(tok, ':')) {
-               msg_warn("%s: can't exclude compound ciphers, '%s' ignored",
-                        myname, tok);
-               continue;
-           }
            vstring_sprintf_append(buf, ":!%s", tok);
        }
        myfree(save);
index 3c6dac341a458b4766574c342bcb7d45c9be31de..85b1a656de5649de745b38a19aafe8a1f44108b1 100644 (file)
@@ -328,12 +328,12 @@ SSL_CTX *tls_server_init(const tls_server_props *props)
     /*
      * Override the default cipher list with our own list.
      */
-    if (*props->cipherlist != 0)
-       if (SSL_CTX_set_cipher_list(server_ctx, props->cipherlist) == 0) {
-           tls_print_errors();
-           SSL_CTX_free(server_ctx);           /* 200411 */
-           return (0);
-       }
+    if (tls_set_cipher_list(server_ctx, props->cipherlist) == 0) {
+       SSL_CTX_free(server_ctx);
+       msg_warn("Invalid cipherlist \"%s\": disabling TLS support",
+                props->cipherlist);
+       return (0);                             /* Already logged */
+    }
 
     /*
      * Load the CA public key certificates for both the server cert and for