Prereq: "2.3.7" diff -cr /var/tmp/postfix-2.3.7/src/global/mail_version.h ./src/global/mail_version.h *** /var/tmp/postfix-2.3.7/src/global/mail_version.h Tue Jan 30 19:57:27 2007 --- ./src/global/mail_version.h Fri Mar 2 12:36:10 2007 *************** *** 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 "20070130" ! #define MAIL_VERSION_NUMBER "2.3.7" #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 "20070301" ! #define MAIL_VERSION_NUMBER "2.3.8" #ifdef SNAPSHOT # define MAIL_VERSION_DATE "-" MAIL_RELEASE_DATE diff -cr /var/tmp/postfix-2.3.7/HISTORY ./HISTORY *** /var/tmp/postfix-2.3.7/HISTORY Tue Jan 30 20:11:21 2007 --- ./HISTORY Sun Feb 25 09:47:30 2007 *************** *** 12928,12943 **** 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. 20070118 Bugfix: match lists didn't implement ![ipv6address]. Problem reported by Paulo Pacheco. File: util/match_list.c. --- 12928,12963 ---- Workaround: don't insert empty-line header/body separator into malformed MIME attachments, to avoid breaking digital ! 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. diff -cr /var/tmp/postfix-2.3.7/RELEASE_NOTES ./RELEASE_NOTES *** /var/tmp/postfix-2.3.7/RELEASE_NOTES Tue Jan 30 20:11:49 2007 --- ./RELEASE_NOTES Fri Feb 2 11:11:07 2007 *************** *** 17,29 **** 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. 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. Incompatible changes with Postfix 2.3.6 --------------------------------------- --- 17,31 ---- Postfix no longer inserts an empty-line header/body separator into malformed MIME attachments, to avoid breaking digital 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 ! that they would not have been exposed to earlier. Incompatible changes with Postfix 2.3.6 --------------------------------------- diff -cr /var/tmp/postfix-2.3.7/src/global/mbox_open.c ./src/global/mbox_open.c *** /var/tmp/postfix-2.3.7/src/global/mbox_open.c Wed Jan 18 11:06:03 2006 --- ./src/global/mbox_open.c Sat Feb 24 20:04:03 2007 *************** *** 184,189 **** --- 184,209 ---- 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; diff -cr /var/tmp/postfix-2.3.7/src/smtp/smtp_proto.c ./src/smtp/smtp_proto.c *** /var/tmp/postfix-2.3.7/src/smtp/smtp_proto.c Fri Dec 8 16:31:50 2006 --- ./src/smtp/smtp_proto.c Sun Feb 25 09:26:59 2007 *************** *** 725,731 **** 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) vstring_sprintf_append(serverid, "&c=%s", session->tls_cipherlist); tls_props.ctx = smtp_tls_ctx; --- 725,731 ---- vstring_sprintf_append(serverid, "&p=%s", tls_protocol_names(VAR_SMTP_TLS_MAND_PROTO, session->tls_protocols)); ! if (session->tls_level >= TLS_LEV_ENCRYPT) vstring_sprintf_append(serverid, "&c=%s", session->tls_cipherlist); tls_props.ctx = smtp_tls_ctx; diff -cr /var/tmp/postfix-2.3.7/src/smtpd/smtpd.c ./src/smtpd/smtpd.c *** /var/tmp/postfix-2.3.7/src/smtpd/smtpd.c Mon Oct 2 15:48:02 2006 --- ./src/smtpd/smtpd.c Sun Feb 25 09:26:59 2007 *************** *** 4293,4298 **** --- 4293,4300 ---- 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); diff -cr /var/tmp/postfix-2.3.7/src/tls/Makefile.in ./src/tls/Makefile.in *** /var/tmp/postfix-2.3.7/src/tls/Makefile.in Sun Jul 9 13:45:28 2006 --- ./src/tls/Makefile.in Sun Feb 25 09:42:44 2007 *************** *** 151,156 **** --- 151,157 ---- 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 diff -cr /var/tmp/postfix-2.3.7/src/tls/tls.h ./src/tls/tls.h *** /var/tmp/postfix-2.3.7/src/tls/tls.h Wed Jul 19 11:33:01 2006 --- ./src/tls/tls.h Sun Feb 25 09:26:59 2007 *************** *** 130,135 **** --- 130,136 ---- #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 diff -cr /var/tmp/postfix-2.3.7/src/tls/tls_client.c ./src/tls/tls_client.c *** /var/tmp/postfix-2.3.7/src/tls/tls_client.c Fri Sep 29 19:26:04 2006 --- ./src/tls/tls_client.c Sun Feb 25 09:26:59 2007 *************** *** 627,632 **** --- 627,641 ---- 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 * the information inside the tls_verify_certificate_callback(). *************** *** 710,733 **** } /* ! * Per session cipher selection for sessions with mandatory encryption * * 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 --- 719,731 ---- } /* ! * 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. * * XXX To avoid memory leaks we must always call SSL_SESSION_free() after * calling SSL_set_session(), regardless of whether or not the session diff -cr /var/tmp/postfix-2.3.7/src/tls/tls_misc.c ./src/tls/tls_misc.c *** /var/tmp/postfix-2.3.7/src/tls/tls_misc.c Sun Jul 9 11:20:12 2006 --- ./src/tls/tls_misc.c Sun Feb 25 09:28:29 2007 *************** *** 18,23 **** --- 18,27 ---- /* /* 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; /* *************** *** 53,58 **** --- 57,67 ---- /* 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 *************** *** 104,109 **** --- 113,119 ---- #include #include #include + #include /* TLS library. */ *************** *** 162,167 **** --- 172,305 ---- 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,204 **** --- 334,349 ---- 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,225 **** if (*exclude == '\0') continue; save = cp = mystrdup(exclude); ! while ((tok = mystrtok(&cp, "\t\n\r ,")) != 0) { /* ! * Can't exclude ciphers that start with modifiers, or ! * multi-element (":" separated) ciphers. */ 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; } --- 352,364 ---- if (*exclude == '\0') continue; save = cp = mystrdup(exclude); ! while ((tok = mystrtok(&cp, "\t\n\r ,:")) != 0) { /* ! * Can't exclude ciphers that start with modifiers. */ if (strchr("!+-@", *tok)) { msg_warn("%s: can't exclude '!+-@' modifiers, '%s' ignored", myname, tok); continue; } diff -cr /var/tmp/postfix-2.3.7/src/tls/tls_server.c ./src/tls/tls_server.c *** /var/tmp/postfix-2.3.7/src/tls/tls_server.c Tue Jul 18 21:11:49 2006 --- ./src/tls/tls_server.c Sun Feb 25 09:26:59 2007 *************** *** 328,339 **** /* * 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); ! } /* * Load the CA public key certificates for both the server cert and for --- 328,339 ---- /* * Override the default cipher list with our own list. */ ! 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