Compare commits

..

No commits in common. 'c9' and 'i8c-beta' have entirely different histories.
c9 ... i8c-beta

@ -1,7 +1,7 @@
diff -up dovecot-2.3.16/doc/example-config/conf.d/10-mail.conf.default-settings dovecot-2.3.16/doc/example-config/conf.d/10-mail.conf
--- dovecot-2.3.16/doc/example-config/conf.d/10-mail.conf.default-settings 2021-08-06 11:25:51.000000000 +0200
+++ dovecot-2.3.16/doc/example-config/conf.d/10-mail.conf 2021-10-27 11:13:45.666956339 +0200
@@ -175,7 +175,7 @@ namespace inbox {
diff -up dovecot-2.3.0.1/doc/example-config/conf.d/10-mail.conf.default-settings dovecot-2.3.0.1/doc/example-config/conf.d/10-mail.conf
--- dovecot-2.3.0.1/doc/example-config/conf.d/10-mail.conf.default-settings 2018-02-28 15:28:57.000000000 +0100
+++ dovecot-2.3.0.1/doc/example-config/conf.d/10-mail.conf 2018-03-01 10:29:38.208368555 +0100
@@ -165,7 +165,7 @@ namespace inbox {
# to make sure that users can't log in as daemons or other system users.
# Note that denying root logins is hardcoded to dovecot binary and can't
# be done even if first_valid_uid is set to 0.
@ -18,9 +18,9 @@ diff -up dovecot-2.3.16/doc/example-config/conf.d/10-mail.conf.default-settings
# Maximum time to wait for lock (all of them) before aborting.
#mbox_lock_timeout = 5 mins
diff -up dovecot-2.3.16/doc/example-config/conf.d/10-ssl.conf.default-settings dovecot-2.3.16/doc/example-config/conf.d/10-ssl.conf
--- dovecot-2.3.16/doc/example-config/conf.d/10-ssl.conf.default-settings 2021-08-06 11:25:51.000000000 +0200
+++ dovecot-2.3.16/doc/example-config/conf.d/10-ssl.conf 2021-10-27 11:13:02.834533975 +0200
diff -up dovecot-2.3.0.1/doc/example-config/conf.d/10-ssl.conf.default-settings dovecot-2.3.0.1/doc/example-config/conf.d/10-ssl.conf
--- dovecot-2.3.0.1/doc/example-config/conf.d/10-ssl.conf.default-settings 2018-02-28 15:28:57.000000000 +0100
+++ dovecot-2.3.0.1/doc/example-config/conf.d/10-ssl.conf 2018-03-01 10:33:54.779499044 +0100
@@ -3,7 +3,9 @@
##
@ -32,7 +32,7 @@ diff -up dovecot-2.3.16/doc/example-config/conf.d/10-ssl.conf.default-settings d
# PEM encoded X.509 SSL/TLS certificate and private key. They're opened before
# dropping root privileges, so keep the key file unreadable by anyone but
@@ -64,6 +66,7 @@ ssl_key = </etc/ssl/private/dovecot.pem
@@ -57,6 +59,7 @@ ssl_key = </etc/ssl/private/dovecot.pem
#ssl_cipher_list = ALL:!kRSA:!SRP:!kDHd:!DSS:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK:!RC4:!ADH:!LOW@STRENGTH
# To disable non-EC DH, use:
#ssl_cipher_list = ALL:!DH:!kRSA:!SRP:!kDHd:!DSS:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK:!RC4:!ADH:!LOW@STRENGTH

@ -0,0 +1,13 @@
diff -up dovecot-2.2.36/src/plugins/acl/acl-backend-vfile.c.aclfix dovecot-2.2.36/src/plugins/acl/acl-backend-vfile.c
--- dovecot-2.2.36/src/plugins/acl/acl-backend-vfile.c.aclfix 2018-09-18 15:00:08.778823903 +0200
+++ dovecot-2.2.36/src/plugins/acl/acl-backend-vfile.c 2018-09-18 15:00:08.814823737 +0200
@@ -161,8 +161,7 @@ acl_backend_vfile_object_init(struct acl
T_BEGIN {
if (*name == '\0' ||
mailbox_list_is_valid_name(_backend->list, name, &error)) {
- vname = *name == '\0' ? "" :
- mailbox_list_get_vname(_backend->list, name);
+ vname = mailbox_list_get_vname(_backend->list, name);
dir = acl_backend_vfile_get_local_dir(_backend, name, vname);
aclobj->local_path = dir == NULL ? NULL :

@ -1,34 +0,0 @@
diff -up dovecot-2.3.14/src/lib-dcrypt/dcrypt-openssl.c.opensslv3 dovecot-2.3.14/src/lib-dcrypt/dcrypt-openssl.c
--- dovecot-2.3.14/src/lib-dcrypt/dcrypt-openssl.c.opensslv3 2021-06-03 18:56:52.573174433 +0200
+++ dovecot-2.3.14/src/lib-dcrypt/dcrypt-openssl.c 2021-06-03 18:56:52.585174274 +0200
@@ -73,10 +73,30 @@
2<tab>key algo oid<tab>1<tab>symmetric algo name<tab>salt<tab>hash algo<tab>rounds<tab>E(RSA = i2d_PrivateKey, EC=Private Point)<tab>key id
**/
+#if OPENSSL_VERSION_MAJOR == 3
+static EC_KEY *EVP_PKEY_get0_EC_KEYv3(EVP_PKEY *key)
+{
+ EC_KEY *eck = EVP_PKEY_get1_EC_KEY(key);
+ EVP_PKEY_set1_EC_KEY(key, eck);
+ EC_KEY_free(eck);
+ return eck;
+}
+
+static EC_KEY *EVP_PKEY_get1_EC_KEYv3(EVP_PKEY *key)
+{
+ EC_KEY *eck = EVP_PKEY_get1_EC_KEY(key);
+ EVP_PKEY_set1_EC_KEY(key, eck);
+ return eck;
+}
+
+#define EVP_PKEY_get0_EC_KEY EVP_PKEY_get0_EC_KEYv3
+#define EVP_PKEY_get1_EC_KEY EVP_PKEY_get1_EC_KEYv3
+#else
#ifndef HAVE_EVP_PKEY_get0
#define EVP_PKEY_get0_EC_KEY(x) x->pkey.ec
#define EVP_PKEY_get0_RSA(x) x->pkey.rsa
#endif
+#endif
#ifndef HAVE_OBJ_LENGTH
#define OBJ_length(o) ((o)->length)

@ -1,24 +0,0 @@
diff -up dovecot-2.3.15/dovecot-2.3-pigeonhole-0.5.15/src/lib-sieve/storage/dict/sieve-dict-script.c.fixvalcond dovecot-2.3.15/dovecot-2.3-pigeonhole-0.5.15/src/lib-sieve/storage/dict/sieve-dict-script.c
--- dovecot-2.3.15/dovecot-2.3-pigeonhole-0.5.16/src/lib-sieve/storage/dict/sieve-dict-script.c.fixvalcond 2021-06-21 23:07:55.269814896 +0200
+++ dovecot-2.3.15/dovecot-2.3-pigeonhole-0.5.16/src/lib-sieve/storage/dict/sieve-dict-script.c 2021-06-21 23:07:55.298814544 +0200
@@ -109,7 +109,7 @@ static int sieve_dict_script_get_stream
{
struct sieve_dict_script *dscript =
(struct sieve_dict_script *)script;
- const char *path, *name = script->name, *data, *error;
+ const char *path, *name = script->name, *data, *error = NULL;
int ret;
dscript->data_pool =
diff -up dovecot-2.3.15/src/lib-storage/index/index-attribute.c.fixvalcond dovecot-2.3.15/src/lib-storage/index/index-attribute.c
--- dovecot-2.3.15/src/lib-storage/index/index-attribute.c.fixvalcond 2021-06-14 15:40:37.000000000 +0200
+++ dovecot-2.3.15/src/lib-storage/index/index-attribute.c 2021-06-21 21:52:22.963171229 +0200
@@ -249,7 +249,7 @@ int index_storage_attribute_get(struct m
struct mail_attribute_value *value_r)
{
struct dict *dict;
- const char *mailbox_prefix, *error;
+ const char *mailbox_prefix, *error = NULL;
int ret;
i_zero(value_r);

@ -1,20 +0,0 @@
diff -up dovecot-2.3.15/run-test-valgrind.supp.valbasherr dovecot-2.3.15/run-test-valgrind.supp
--- dovecot-2.3.15/run-test-valgrind.supp.valbasherr 2021-06-21 22:52:53.272707239 +0200
+++ dovecot-2.3.15/run-test-valgrind.supp 2021-06-21 22:54:19.786668430 +0200
@@ -1,4 +1,16 @@
{
+ <bashagin>
+ Memcheck:Leak
+ match-leak-kinds: definite
+ fun:malloc
+ fun:make_if_command
+ fun:yyparse
+ fun:parse_command
+ fun:read_command
+ fun:reader_loop
+ fun:main
+}
+{
<bash>
Memcheck:Leak
fun:malloc

@ -0,0 +1,353 @@
diff -up dovecot-2.3.16/configure.ac.keeplzma dovecot-2.3.16/configure.ac
--- dovecot-2.3.16/configure.ac.keeplzma 2021-08-06 11:25:51.000000000 +0200
+++ dovecot-2.3.16/configure.ac 2022-02-28 13:58:02.337149927 +0100
@@ -173,7 +173,7 @@ AS_HELP_STRING([--with-bzlib], [Build wi
want_bzlib=auto)
AC_ARG_WITH(lzma,
-AS_HELP_STRING([--with-lzma], [Build with LZMA decompression support (auto)]),
+AS_HELP_STRING([--with-lzma], [Build with LZMA compression support (auto)]),
TEST_WITH(lzma, $withval),
want_lzma=auto)
diff -up dovecot-2.3.16/run-test-valgrind.supp.keeplzma dovecot-2.3.16/run-test-valgrind.supp
--- dovecot-2.3.16/run-test-valgrind.supp.keeplzma 2021-08-06 11:25:51.000000000 +0200
+++ dovecot-2.3.16/run-test-valgrind.supp 2022-02-28 13:58:02.337149927 +0100
@@ -5,6 +5,17 @@
obj:*/bash
}
{
+ <liblzma>
+ Memcheck:Cond
+ obj:/lib/x86_64-linux-gnu/liblzma.so.5.*
+ obj:/lib/x86_64-linux-gnu/liblzma.so.5.*
+ obj:/lib/x86_64-linux-gnu/liblzma.so.5.*
+ obj:/lib/x86_64-linux-gnu/liblzma.so.5.*
+ obj:/lib/x86_64-linux-gnu/liblzma.so.5.*
+ fun:lzma_stream_encoder
+ fun:lzma_easy_encoder
+}
+{
<openssl_centos6_i386_v1_0_1_compression_methods>
Memcheck:Leak
fun:malloc
diff -up dovecot-2.3.16/src/lib-compression/compression.c.keeplzma dovecot-2.3.16/src/lib-compression/compression.c
--- dovecot-2.3.16/src/lib-compression/compression.c.keeplzma 2021-08-06 11:25:51.000000000 +0200
+++ dovecot-2.3.16/src/lib-compression/compression.c 2022-02-28 14:22:32.467944396 +0100
@@ -25,6 +25,7 @@
#endif
#ifndef HAVE_LZMA
# define i_stream_create_lzma NULL
+# define o_stream_create_lzma NULL
#endif
#ifndef HAVE_LZ4
# define i_stream_create_lz4 NULL
@@ -216,7 +217,7 @@ const struct compression_handler compres
.ext = ".xz",
.is_compressed = is_compressed_xz,
.create_istream = i_stream_create_lzma,
- .create_ostream = NULL,
+ .create_ostream = o_stream_create_lzma,
.get_min_level = compression_get_min_level_unsupported,
.get_default_level = compression_get_default_level_unsupported,
.get_max_level = compression_get_max_level_unsupported,
diff -up dovecot-2.3.16/src/lib-compression/Makefile.am.keeplzma dovecot-2.3.16/src/lib-compression/Makefile.am
--- dovecot-2.3.16/src/lib-compression/Makefile.am.keeplzma 2021-08-06 11:25:51.000000000 +0200
+++ dovecot-2.3.16/src/lib-compression/Makefile.am 2022-02-28 13:58:02.337149927 +0100
@@ -13,6 +13,7 @@ libcompression_la_SOURCES = \
istream-zlib.c \
istream-bzlib.c \
istream-zstd.c \
+ ostream-lzma.c \
ostream-lz4.c \
ostream-zlib.c \
ostream-bzlib.c \
diff -up dovecot-2.3.16/src/lib-compression/ostream-lzma.c.keeplzma dovecot-2.3.16/src/lib-compression/ostream-lzma.c
--- dovecot-2.3.16/src/lib-compression/ostream-lzma.c.keeplzma 2022-02-28 13:58:02.338149934 +0100
+++ dovecot-2.3.16/src/lib-compression/ostream-lzma.c 2022-02-28 13:58:02.338149934 +0100
@@ -0,0 +1,263 @@
+/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+
+#ifdef HAVE_LZMA
+
+#include "ostream-private.h"
+#include "ostream-zlib.h"
+#include <lzma.h>
+
+#define CHUNK_SIZE (1024*64)
+
+struct lzma_ostream {
+ struct ostream_private ostream;
+ lzma_stream strm;
+
+ unsigned char outbuf[CHUNK_SIZE];
+ unsigned int outbuf_offset, outbuf_used;
+
+ bool flushed:1;
+};
+
+static void o_stream_lzma_close(struct iostream_private *stream,
+ bool close_parent)
+{
+ struct lzma_ostream *zstream = (struct lzma_ostream *)stream;
+ i_assert(zstream->ostream.finished ||
+ zstream->ostream.ostream.stream_errno != 0 ||
+ zstream->ostream.error_handling_disabled);
+ lzma_end(&zstream->strm);
+ if (close_parent)
+ o_stream_close(zstream->ostream.parent);
+}
+
+static int o_stream_zlib_send_outbuf(struct lzma_ostream *zstream)
+{
+ ssize_t ret;
+ size_t size;
+
+ if (zstream->outbuf_used == 0)
+ return 1;
+
+ size = zstream->outbuf_used - zstream->outbuf_offset;
+ i_assert(size > 0);
+ ret = o_stream_send(zstream->ostream.parent,
+ zstream->outbuf + zstream->outbuf_offset, size);
+ if (ret < 0) {
+ o_stream_copy_error_from_parent(&zstream->ostream);
+ return -1;
+ }
+ if ((size_t)ret != size) {
+ zstream->outbuf_offset += ret;
+ return 0;
+ }
+ zstream->outbuf_offset = 0;
+ zstream->outbuf_used = 0;
+ return 1;
+}
+
+static ssize_t
+o_stream_lzma_send_chunk(struct lzma_ostream *zstream,
+ const void *data, size_t size)
+{
+ lzma_stream *zs = &zstream->strm;
+ int ret;
+
+ i_assert(zstream->outbuf_used == 0);
+
+ zs->next_in = (void *)data;
+ zs->avail_in = size;
+ while (zs->avail_in > 0) {
+ if (zs->avail_out == 0) {
+ /* previous block was compressed. send it and start
+ compression for a new block. */
+ zs->next_out = zstream->outbuf;
+ zs->avail_out = sizeof(zstream->outbuf);
+
+ zstream->outbuf_used = sizeof(zstream->outbuf);
+ if ((ret = o_stream_zlib_send_outbuf(zstream)) < 0)
+ return -1;
+ if (ret == 0) {
+ /* parent stream's buffer full */
+ break;
+ }
+ }
+
+ ret = lzma_code(zs, LZMA_RUN);
+ switch (ret) {
+ case LZMA_OK:
+ break;
+ case LZMA_MEM_ERROR:
+ i_fatal_status(FATAL_OUTOFMEM,
+ "lzma.write(%s): Out of memory",
+ o_stream_get_name(&zstream->ostream.ostream));
+ default:
+ i_panic("lzma.write(%s) failed with unexpected code %d",
+ o_stream_get_name(&zstream->ostream.ostream), ret);
+ }
+ }
+ size -= zs->avail_in;
+
+ return size;
+}
+
+static int o_stream_lzma_send_flush(struct lzma_ostream *zstream, bool final)
+{
+ lzma_stream *zs = &zstream->strm;
+ size_t len;
+ bool done = FALSE;
+ int ret;
+
+ i_assert(zs->avail_in == 0);
+
+ if (zstream->flushed) {
+ i_assert(zstream->outbuf_used == 0);
+ return 1;
+ }
+
+ if ((ret = o_stream_flush_parent_if_needed(&zstream->ostream)) <= 0)
+ return ret;
+ if ((ret = o_stream_zlib_send_outbuf(zstream)) <= 0)
+ return ret;
+
+ if (!final)
+ return 1;
+
+ i_assert(zstream->outbuf_used == 0);
+ do {
+ len = sizeof(zstream->outbuf) - zs->avail_out;
+ if (len != 0) {
+ zs->next_out = zstream->outbuf;
+ zs->avail_out = sizeof(zstream->outbuf);
+
+ zstream->outbuf_used = len;
+ if ((ret = o_stream_zlib_send_outbuf(zstream)) <= 0)
+ return ret;
+ if (done)
+ break;
+ }
+ ret = lzma_code(zs, LZMA_FINISH);
+ switch (ret) {
+ case LZMA_OK:
+ /* still unfinished - need to call lzma_code() again */
+ break;
+ case LZMA_STREAM_END:
+ /* output is fully finished */
+ done = TRUE;
+ break;
+ case LZMA_MEM_ERROR:
+ i_fatal_status(FATAL_OUTOFMEM,
+ "lzma.write(%s): Out of memory",
+ o_stream_get_name(&zstream->ostream.ostream));
+ default:
+ i_panic("lzma.write(%s) flush failed with unexpected code %d",
+ o_stream_get_name(&zstream->ostream.ostream), ret);
+ }
+ } while (zs->avail_out != sizeof(zstream->outbuf));
+
+ if (final)
+ zstream->flushed = TRUE;
+ i_assert(zstream->outbuf_used == 0);
+ return 1;
+}
+
+static int o_stream_lzma_flush(struct ostream_private *stream)
+{
+ struct lzma_ostream *zstream = (struct lzma_ostream *)stream;
+ int ret;
+
+ if ((ret = o_stream_lzma_send_flush(zstream, stream->finished)) < 0)
+ return -1;
+ else if (ret > 0)
+ return o_stream_flush_parent(stream);
+ return ret;
+}
+
+static size_t
+o_stream_lzma_get_buffer_used_size(const struct ostream_private *stream)
+{
+ const struct lzma_ostream *zstream =
+ (const struct lzma_ostream *)stream;
+
+ /* outbuf has already compressed data that we're trying to send to the
+ parent stream. We're not including lzma's internal compression
+ buffer size. */
+ return (zstream->outbuf_used - zstream->outbuf_offset) +
+ o_stream_get_buffer_used_size(stream->parent);
+}
+
+static size_t
+o_stream_lzma_get_buffer_avail_size(const struct ostream_private *stream)
+{
+ /* FIXME: not correct - this is counting compressed size, which may be
+ too larger than uncompressed size in some situations. Fixing would
+ require some kind of additional buffering. */
+ return o_stream_get_buffer_avail_size(stream->parent);
+}
+
+static ssize_t
+o_stream_lzma_sendv(struct ostream_private *stream,
+ const struct const_iovec *iov, unsigned int iov_count)
+{
+ struct lzma_ostream *zstream = (struct lzma_ostream *)stream;
+ ssize_t ret, bytes = 0;
+ unsigned int i;
+
+ if ((ret = o_stream_zlib_send_outbuf(zstream)) <= 0) {
+ /* error / we still couldn't flush existing data to
+ parent stream. */
+ return ret;
+ }
+
+ for (i = 0; i < iov_count; i++) {
+ ret = o_stream_lzma_send_chunk(zstream, iov[i].iov_base,
+ iov[i].iov_len);
+ if (ret < 0)
+ return -1;
+ bytes += ret;
+ if ((size_t)ret != iov[i].iov_len)
+ break;
+ }
+ stream->ostream.offset += bytes;
+
+ /* avail_in!=0 check is used to detect errors. if it's non-zero here
+ it simply means we didn't send all the data */
+ zstream->strm.avail_in = 0;
+ return bytes;
+}
+
+struct ostream *o_stream_create_lzma(struct ostream *output, int level)
+{
+ struct lzma_ostream *zstream;
+ lzma_ret ret;
+
+ i_assert(level >= 1 && level <= 9);
+
+ zstream = i_new(struct lzma_ostream, 1);
+ zstream->ostream.sendv = o_stream_lzma_sendv;
+ zstream->ostream.flush = o_stream_lzma_flush;
+ zstream->ostream.get_buffer_used_size =
+ o_stream_lzma_get_buffer_used_size;
+ zstream->ostream.get_buffer_avail_size =
+ o_stream_lzma_get_buffer_avail_size;
+ zstream->ostream.iostream.close = o_stream_lzma_close;
+
+ ret = lzma_easy_encoder(&zstream->strm, level, LZMA_CHECK_CRC64);
+ switch (ret) {
+ case LZMA_OK:
+ break;
+ case LZMA_MEM_ERROR:
+ i_fatal_status(FATAL_OUTOFMEM, "lzma: Out of memory");
+ case LZMA_OPTIONS_ERROR:
+ i_fatal("lzma: Invalid level");
+ default:
+ i_fatal("lzma_easy_encoder() failed with %d", ret);
+ }
+
+ zstream->strm.next_out = zstream->outbuf;
+ zstream->strm.avail_out = sizeof(zstream->outbuf);
+ return o_stream_create(&zstream->ostream, output,
+ o_stream_get_fd(output));
+}
+#endif
diff -up dovecot-2.3.16/src/lib-compression/ostream-zlib.h.keeplzma dovecot-2.3.16/src/lib-compression/ostream-zlib.h
--- dovecot-2.3.16/src/lib-compression/ostream-zlib.h.keeplzma 2021-08-06 11:25:51.000000000 +0200
+++ dovecot-2.3.16/src/lib-compression/ostream-zlib.h 2022-02-28 13:58:02.338149934 +0100
@@ -4,6 +4,7 @@
struct ostream *o_stream_create_gz(struct ostream *output, int level);
struct ostream *o_stream_create_deflate(struct ostream *output, int level);
struct ostream *o_stream_create_bz2(struct ostream *output, int level);
+struct ostream *o_stream_create_lzma(struct ostream *output, int level);
struct ostream *o_stream_create_lz4(struct ostream *output, int level);
struct ostream *o_stream_create_zstd(struct ostream *output, int level);
diff -up dovecot-2.3.16/src/lib-compression/test-compression.c.keeplzma dovecot-2.3.16/src/lib-compression/test-compression.c
--- dovecot-2.3.16/src/lib-compression/test-compression.c.keeplzma 2021-08-06 11:25:51.000000000 +0200
+++ dovecot-2.3.16/src/lib-compression/test-compression.c 2022-02-28 13:58:02.338149934 +0100
@@ -730,7 +730,6 @@ static void test_compression_int(bool au
for (i = 0; compression_handlers[i].name != NULL; i++) {
if (compression_handlers[i].create_istream != NULL &&
- compression_handlers[i].create_ostream != NULL &&
(!autodetect ||
compression_handlers[i].is_compressed != NULL)) T_BEGIN {
if (compression_handlers[i].is_compressed != NULL &&

@ -1,22 +0,0 @@
From 9a3e0d099044d3a7478c3a24ccb8990181767f7c Mon Sep 17 00:00:00 2001
From: Duncan Bellamy <dunk@denkimushi.com>
Date: Sat, 6 Mar 2021 14:25:29 +0000
Subject: [PATCH] imap: Shorten test-imap-client-hibernate socket path length
---
src/imap/test-imap-client-hibernate.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/imap/test-imap-client-hibernate.c b/src/imap/test-imap-client-hibernate.c
index 9b90e1bd9a..c5392fa3fc 100644
--- a/src/imap/test-imap-client-hibernate.c
+++ b/src/imap/test-imap-client-hibernate.c
@@ -19,7 +19,7 @@
#include <sys/stat.h>
-#define TEMP_DIRNAME ".test-imap-client-hibernate"
+#define TEMP_DIRNAME ".test-ich"
#define EVILSTR "\t\r\n\001"

@ -1,976 +0,0 @@
From 8e4c42dbb3c770fcdbc396f2abcf1bc228ec548d Mon Sep 17 00:00:00 2001
From: Timo Sirainen <timo.sirainen@open-xchange.com>
Date: Fri, 9 Feb 2024 00:32:39 +0200
Subject: [PATCH 1/6] lib: test-llist - Fix dllist2 test name
---
src/lib/test-llist.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/lib/test-llist.c b/src/lib/test-llist.c
index d57006ce2aa..ed584318fa3 100644
--- a/src/lib/test-llist.c
+++ b/src/lib/test-llist.c
@@ -71,7 +71,7 @@ static void test_dllist2(void)
l2 = t_new(struct dllist, 1);
l1 = t_new(struct dllist, 1);
- test_begin("dllist");
+ test_begin("dllist2");
/* prepend to empty */
DLLIST2_PREPEND(&head, &tail, l3);
test_assert(head == l3 && tail == l3);
From cee08202c759a3bdf185d998dcf888ebd1bc6e36 Mon Sep 17 00:00:00 2001
From: Timo Sirainen <timo.sirainen@open-xchange.com>
Date: Fri, 9 Feb 2024 00:33:00 +0200
Subject: [PATCH 2/6] lib: Add DLLIST2_JOIN()
---
src/lib/llist.h | 14 ++++++++++++++
src/lib/test-llist.c | 39 +++++++++++++++++++++++++++++++++++++++
2 files changed, 53 insertions(+)
diff --git a/src/lib/llist.h b/src/lib/llist.h
index 8a52e873352..5ad5d75c0df 100644
--- a/src/lib/llist.h
+++ b/src/lib/llist.h
@@ -78,4 +78,18 @@
#define DLLIST2_REMOVE(head, tail, item) \
DLLIST2_REMOVE_FULL(head, tail, item, prev, next)
+#define DLLIST2_JOIN_FULL(head1, tail1, head2, tail2, prev, next) STMT_START { \
+ if (*(head1) == NULL) { \
+ *(head1) = *(head2); \
+ *(tail1) = *(tail2); \
+ } else if (*(head2) != NULL) { \
+ (*(tail1))->next = *(head2); \
+ (*(head2))->prev = *(tail1); \
+ (*tail1) = (*tail2); \
+ } \
+ } STMT_END
+
+#define DLLIST2_JOIN(head1, tail1, head2, tail2) \
+ DLLIST2_JOIN_FULL(head1, tail1, head2, tail2, prev, next)
+
#endif
diff --git a/src/lib/test-llist.c b/src/lib/test-llist.c
index ed584318fa3..e293eb6a603 100644
--- a/src/lib/test-llist.c
+++ b/src/lib/test-llist.c
@@ -131,8 +131,47 @@ static void test_dllist2(void)
test_end();
}
+static void test_dllist2_join(void)
+{
+ struct dllist *head, *tail, *elem[4];
+ struct dllist *head2, *tail2, *elem2[N_ELEMENTS(elem)];
+
+ test_begin("dllist2 join");
+ for (unsigned int i = 0; i < N_ELEMENTS(elem); i++) {
+ elem[i] = t_new(struct dllist, 1);
+ elem2[i] = t_new(struct dllist, 1);
+ }
+ for (unsigned int i = 0; i < N_ELEMENTS(elem); i++) {
+ for (unsigned int j = 0; j < N_ELEMENTS(elem2); j++) {
+ head = tail = head2 = tail2 = NULL;
+ for (unsigned int n = 0; n < i; n++)
+ DLLIST2_APPEND(&head, &tail, elem[n]);
+ for (unsigned int n = 0; n < j; n++)
+ DLLIST2_APPEND(&head2, &tail2, elem2[n]);
+ DLLIST2_JOIN(&head, &tail, &head2, &tail2);
+
+ /* verify */
+ struct dllist *tmp = head, *last = NULL;
+ for (unsigned int n = 0; n < i; n++) {
+ test_assert(tmp == elem[n]);
+ last = tmp;
+ tmp = tmp->next;
+ }
+ for (unsigned int n = 0; n < j; n++) {
+ test_assert(tmp == elem2[n]);
+ last = tmp;
+ tmp = tmp->next;
+ }
+ test_assert(tmp == NULL);
+ test_assert(tail == last);
+ }
+ }
+ test_end();
+}
+
void test_llist(void)
{
test_dllist();
test_dllist2();
+ test_dllist2_join();
}
From 0bae091859c905dc335f21eed01347e6b8338672 Mon Sep 17 00:00:00 2001
From: Timo Sirainen <timo.sirainen@open-xchange.com>
Date: Tue, 30 Jan 2024 22:42:50 +0200
Subject: [PATCH 3/6] lib-mail: test-imap-envelope - Use test_assert_idx()
where possible
---
src/lib-imap/test-imap-envelope.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/lib-imap/test-imap-envelope.c b/src/lib-imap/test-imap-envelope.c
index 1f295e58bab..c9b92b4be2b 100644
--- a/src/lib-imap/test-imap-envelope.c
+++ b/src/lib-imap/test-imap-envelope.c
@@ -157,7 +157,7 @@ static void test_imap_envelope_write(void)
envlp = msg_parse(pool, test->message);
imap_envelope_write(envlp, str);
- test_assert(strcmp(str_c(str), test->envelope) == 0);
+ test_assert_idx(strcmp(str_c(str), test->envelope) == 0, i);
pool_unref(&pool);
test_end();
@@ -179,12 +179,12 @@ static void test_imap_envelope_parse(void)
test_begin(t_strdup_printf("imap envelope parser [%u]", i));
ret = imap_envelope_parse(test->envelope, pool, &envlp, &error);
- test_assert(ret);
+ test_assert_idx(ret, i);
if (ret) {
str_truncate(str, 0);
imap_envelope_write(envlp, str);
- test_assert(strcmp(str_c(str), test->envelope) == 0);
+ test_assert_idx(strcmp(str_c(str), test->envelope) == 0, i);
} else {
i_error("Invalid envelope: %s", error);
}
From a1c9b0409454e45937bf7e9c3685f5e91d6a5a43 Mon Sep 17 00:00:00 2001
From: Timo Sirainen <timo.sirainen@open-xchange.com>
Date: Sun, 4 Feb 2024 00:26:57 +0200
Subject: [PATCH 4/6] lib-mail: Change message_address to be doubly linked list
---
src/lib-imap/imap-envelope.c | 11 +-
src/lib-mail/message-address.c | 8 +-
src/lib-mail/message-address.h | 2 +-
src/lib-mail/test-message-address.c | 226 ++++++++++++++--------------
4 files changed, 121 insertions(+), 126 deletions(-)
diff --git a/src/lib-imap/imap-envelope.c b/src/lib-imap/imap-envelope.c
index 87297f4f691..1312eae2ff3 100644
--- a/src/lib-imap/imap-envelope.c
+++ b/src/lib-imap/imap-envelope.c
@@ -1,6 +1,7 @@
/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
+#include "llist.h"
#include "istream.h"
#include "str.h"
#include "message-address.h"
@@ -127,7 +128,7 @@ static bool
imap_envelope_parse_addresses(const struct imap_arg *arg,
pool_t pool, struct message_address **addrs_r)
{
- struct message_address *first, *addr, *prev;
+ struct message_address *first, *last, *addr;
const struct imap_arg *list_args;
if (arg->type == IMAP_ARG_NIL) {
@@ -138,16 +139,12 @@ imap_envelope_parse_addresses(const struct imap_arg *arg,
if (!imap_arg_get_list(arg, &list_args))
return FALSE;
- first = addr = prev = NULL;
+ first = last = addr = NULL;
for (; !IMAP_ARG_IS_EOL(list_args); list_args++) {
if (!imap_envelope_parse_address
(list_args, pool, &addr))
return FALSE;
- if (first == NULL)
- first = addr;
- if (prev != NULL)
- prev->next = addr;
- prev = addr;
+ DLLIST2_APPEND(&first, &last, addr);
}
*addrs_r = first;
diff --git a/src/lib-mail/message-address.c b/src/lib-mail/message-address.c
index fb06afae7b7..9d192799468 100644
--- a/src/lib-mail/message-address.c
+++ b/src/lib-mail/message-address.c
@@ -1,6 +1,7 @@
/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
+#include "llist.h"
#include "str.h"
#include "strescape.h"
#include "smtp-address.h"
@@ -27,11 +28,7 @@ static void add_address(struct message_address_parser_context *ctx)
memcpy(addr, &ctx->addr, sizeof(ctx->addr));
i_zero(&ctx->addr);
- if (ctx->first_addr == NULL)
- ctx->first_addr = addr;
- else
- ctx->last_addr->next = addr;
- ctx->last_addr = addr;
+ DLLIST2_APPEND(&ctx->first_addr, &ctx->last_addr, addr);
}
/* quote with "" and escape all '\', '"' and "'" characters if need */
@@ -631,6 +628,7 @@ const char *message_address_first_to_string(const struct message_address *addr)
struct message_address first_addr;
first_addr = *addr;
+ first_addr.prev = NULL;
first_addr.next = NULL;
first_addr.route = NULL;
return message_address_to_string(&first_addr);
diff --git a/src/lib-mail/message-address.h b/src/lib-mail/message-address.h
index 8370397741c..85cff3dcc6f 100644
--- a/src/lib-mail/message-address.h
+++ b/src/lib-mail/message-address.h
@@ -18,7 +18,7 @@ enum message_address_parse_flags {
{name = NULL, NULL, "group", NULL}, ..., {NULL, NULL, NULL, NULL}
*/
struct message_address {
- struct message_address *next;
+ struct message_address *prev, *next;
/* display-name */
const char *name;
diff --git a/src/lib-mail/test-message-address.c b/src/lib-mail/test-message-address.c
index e6204bb0588..261cbfba70a 100644
--- a/src/lib-mail/test-message-address.c
+++ b/src/lib-mail/test-message-address.c
@@ -47,174 +47,174 @@ static void test_message_address(void)
} tests[] = {
/* user@domain -> <user@domain> */
{ "user@domain", "<user@domain>", NULL,
- { NULL, NULL, NULL, "user", "domain", FALSE },
- { NULL, NULL, NULL, "user", "domain", FALSE }, 0 },
+ { NULL, NULL, NULL, NULL, "user", "domain", FALSE },
+ { NULL, NULL, NULL, NULL, "user", "domain", FALSE }, 0 },
{ "\"user\"@domain", "<user@domain>", NULL,
- { NULL, NULL, NULL, "user", "domain", FALSE },
- { NULL, NULL, NULL, "user", "domain", FALSE }, 0 },
+ { NULL, NULL, NULL, NULL, "user", "domain", FALSE },
+ { NULL, NULL, NULL, NULL, "user", "domain", FALSE }, 0 },
{ "\"user name\"@domain", "<\"user name\"@domain>", NULL,
- { NULL, NULL, NULL, "user name", "domain", FALSE },
- { NULL, NULL, NULL, "user name", "domain", FALSE }, 0 },
+ { NULL, NULL, NULL, NULL, "user name", "domain", FALSE },
+ { NULL, NULL, NULL, NULL, "user name", "domain", FALSE }, 0 },
{ "\"user@na\\\\me\"@domain", "<\"user@na\\\\me\"@domain>", NULL,
- { NULL, NULL, NULL, "user@na\\me", "domain", FALSE },
- { NULL, NULL, NULL, "user@na\\me", "domain", FALSE }, 0 },
+ { NULL, NULL, NULL, NULL, "user@na\\me", "domain", FALSE },
+ { NULL, NULL, NULL, NULL, "user@na\\me", "domain", FALSE }, 0 },
{ "\"user\\\"name\"@domain", "<\"user\\\"name\"@domain>", NULL,
- { NULL, NULL, NULL, "user\"name", "domain", FALSE },
- { NULL, NULL, NULL, "user\"name", "domain", FALSE }, 0 },
+ { NULL, NULL, NULL, NULL, "user\"name", "domain", FALSE },
+ { NULL, NULL, NULL, NULL, "user\"name", "domain", FALSE }, 0 },
{ "\"\"@domain", "<\"\"@domain>", NULL,
- { NULL, NULL, NULL, "", "domain", FALSE },
- { NULL, NULL, NULL, "", "domain", FALSE }, 0 },
+ { NULL, NULL, NULL, NULL, "", "domain", FALSE },
+ { NULL, NULL, NULL, NULL, "", "domain", FALSE }, 0 },
{ "user", "<user>", "<user@MISSING_DOMAIN>",
- { NULL, NULL, NULL, "user", "", TRUE },
- { NULL, NULL, NULL, "user", "MISSING_DOMAIN", TRUE }, 0 },
+ { NULL, NULL, NULL, NULL, "user", "", TRUE },
+ { NULL, NULL, NULL, NULL, "user", "MISSING_DOMAIN", TRUE }, 0 },
{ "@domain", "<\"\"@domain>", "<MISSING_MAILBOX@domain>",
- { NULL, NULL, NULL, "", "domain", TRUE },
- { NULL, NULL, NULL, "MISSING_MAILBOX", "domain", TRUE }, 0 },
+ { NULL, NULL, NULL, NULL, "", "domain", TRUE },
+ { NULL, NULL, NULL, NULL, "MISSING_MAILBOX", "domain", TRUE }, 0 },
/* Display Name -> Display Name */
{ "Display Name", "\"Display Name\"", "\"Display Name\" <MISSING_MAILBOX@MISSING_DOMAIN>",
- { NULL, "Display Name", NULL, "", "", TRUE },
- { NULL, "Display Name", NULL, "MISSING_MAILBOX", "MISSING_DOMAIN", TRUE }, 0 },
+ { NULL, NULL, "Display Name", NULL, "", "", TRUE },
+ { NULL, NULL, "Display Name", NULL, "MISSING_MAILBOX", "MISSING_DOMAIN", TRUE }, 0 },
{ "\"Display Name\"", "\"Display Name\"", "\"Display Name\" <MISSING_MAILBOX@MISSING_DOMAIN>",
- { NULL, "Display Name", NULL, "", "", TRUE },
- { NULL, "Display Name", NULL, "MISSING_MAILBOX", "MISSING_DOMAIN", TRUE }, 0 },
+ { NULL, NULL, "Display Name", NULL, "", "", TRUE },
+ { NULL, NULL, "Display Name", NULL, "MISSING_MAILBOX", "MISSING_DOMAIN", TRUE }, 0 },
{ "Display \"Name\"", "\"Display Name\"", "\"Display Name\" <MISSING_MAILBOX@MISSING_DOMAIN>",
- { NULL, "Display Name", NULL, "", "", TRUE },
- { NULL, "Display Name", NULL, "MISSING_MAILBOX", "MISSING_DOMAIN", TRUE }, 0 },
+ { NULL, NULL, "Display Name", NULL, "", "", TRUE },
+ { NULL, NULL, "Display Name", NULL, "MISSING_MAILBOX", "MISSING_DOMAIN", TRUE }, 0 },
{ "\"Display\" \"Name\"", "\"Display Name\"", "\"Display Name\" <MISSING_MAILBOX@MISSING_DOMAIN>",
- { NULL, "Display Name", NULL, "", "", TRUE },
- { NULL, "Display Name", NULL, "MISSING_MAILBOX", "MISSING_DOMAIN", TRUE }, 0 },
+ { NULL, NULL, "Display Name", NULL, "", "", TRUE },
+ { NULL, NULL, "Display Name", NULL, "MISSING_MAILBOX", "MISSING_DOMAIN", TRUE }, 0 },
{ "\"\"", "", "<MISSING_MAILBOX@MISSING_DOMAIN>",
- { NULL, "", NULL, "", "", TRUE },
- { NULL, "", NULL, "MISSING_MAILBOX", "MISSING_DOMAIN", TRUE }, 0 },
+ { NULL, NULL, "", NULL, "", "", TRUE },
+ { NULL, NULL, "", NULL, "MISSING_MAILBOX", "MISSING_DOMAIN", TRUE }, 0 },
/* <user@domain> -> <user@domain> */
{ "<user@domain>", NULL, NULL,
- { NULL, NULL, NULL, "user", "domain", FALSE },
- { NULL, NULL, NULL, "user", "domain", FALSE }, 0 },
+ { NULL, NULL, NULL, NULL, "user", "domain", FALSE },
+ { NULL, NULL, NULL, NULL, "user", "domain", FALSE }, 0 },
{ "<\"user\"@domain>", "<user@domain>", NULL,
- { NULL, NULL, NULL, "user", "domain", FALSE },
- { NULL, NULL, NULL, "user", "domain", FALSE }, 0 },
+ { NULL, NULL, NULL, NULL, "user", "domain", FALSE },
+ { NULL, NULL, NULL, NULL, "user", "domain", FALSE }, 0 },
{ "<\"user name\"@domain>", NULL, NULL,
- { NULL, NULL, NULL, "user name", "domain", FALSE },
- { NULL, NULL, NULL, "user name", "domain", FALSE }, 0 },
+ { NULL, NULL, NULL, NULL, "user name", "domain", FALSE },
+ { NULL, NULL, NULL, NULL, "user name", "domain", FALSE }, 0 },
{ "<\"user@na\\\\me\"@domain>", NULL, NULL,
- { NULL, NULL, NULL, "user@na\\me", "domain", FALSE },
- { NULL, NULL, NULL, "user@na\\me", "domain", FALSE }, 0 },
+ { NULL, NULL, NULL, NULL, "user@na\\me", "domain", FALSE },
+ { NULL, NULL, NULL, NULL, "user@na\\me", "domain", FALSE }, 0 },
{ "<\"user\\\"name\"@domain>", NULL, NULL,
- { NULL, NULL, NULL, "user\"name", "domain", FALSE },
- { NULL, NULL, NULL, "user\"name", "domain", FALSE }, 0 },
+ { NULL, NULL, NULL, NULL, "user\"name", "domain", FALSE },
+ { NULL, NULL, NULL, NULL, "user\"name", "domain", FALSE }, 0 },
{ "<\"\"@domain>", NULL, NULL,
- { NULL, NULL, NULL, "", "domain", FALSE },
- { NULL, NULL, NULL, "", "domain", FALSE }, 0 },
+ { NULL, NULL, NULL, NULL, "", "domain", FALSE },
+ { NULL, NULL, NULL, NULL, "", "domain", FALSE }, 0 },
{ "<user>", NULL, "<user@MISSING_DOMAIN>",
- { NULL, NULL, NULL, "user", "", TRUE },
- { NULL, NULL, NULL, "user", "MISSING_DOMAIN", TRUE }, 0 },
+ { NULL, NULL, NULL, NULL, "user", "", TRUE },
+ { NULL, NULL, NULL, NULL, "user", "MISSING_DOMAIN", TRUE }, 0 },
{ "<@route>", "<@route:\"\">", "<INVALID_ROUTE:MISSING_MAILBOX@MISSING_DOMAIN>",
- { NULL, NULL, "@route", "", "", TRUE },
- { NULL, NULL, "INVALID_ROUTE", "MISSING_MAILBOX", "MISSING_DOMAIN", TRUE }, 0 },
+ { NULL, NULL, NULL, "@route", "", "", TRUE },
+ { NULL, NULL, NULL, "INVALID_ROUTE", "MISSING_MAILBOX", "MISSING_DOMAIN", TRUE }, 0 },
/* user@domain (Display Name) -> "Display Name" <user@domain> */
{ "user@domain (DisplayName)", "DisplayName <user@domain>", NULL,
- { NULL, "DisplayName", NULL, "user", "domain", FALSE },
- { NULL, "DisplayName", NULL, "user", "domain", FALSE }, 0 },
+ { NULL, NULL, "DisplayName", NULL, "user", "domain", FALSE },
+ { NULL, NULL, "DisplayName", NULL, "user", "domain", FALSE }, 0 },
{ "user@domain (Display Name)", "\"Display Name\" <user@domain>", NULL,
- { NULL, "Display Name", NULL, "user", "domain", FALSE },
- { NULL, "Display Name", NULL, "user", "domain", FALSE }, 0 },
+ { NULL, NULL, "Display Name", NULL, "user", "domain", FALSE },
+ { NULL, NULL, "Display Name", NULL, "user", "domain", FALSE }, 0 },
{ "user@domain (Display\"Name)", "\"Display\\\"Name\" <user@domain>", NULL,
- { NULL, "Display\"Name", NULL, "user", "domain", FALSE },
- { NULL, "Display\"Name", NULL, "user", "domain", FALSE }, 0 },
+ { NULL, NULL, "Display\"Name", NULL, "user", "domain", FALSE },
+ { NULL, NULL, "Display\"Name", NULL, "user", "domain", FALSE }, 0 },
{ "user (Display Name)", "\"Display Name\" <user>", "\"Display Name\" <user@MISSING_DOMAIN>",
- { NULL, "Display Name", NULL, "user", "", TRUE },
- { NULL, "Display Name", NULL, "user", "MISSING_DOMAIN", TRUE }, 0 },
+ { NULL, NULL, "Display Name", NULL, "user", "", TRUE },
+ { NULL, NULL, "Display Name", NULL, "user", "MISSING_DOMAIN", TRUE }, 0 },
{ "@domain (Display Name)", "\"Display Name\" <\"\"@domain>", "\"Display Name\" <MISSING_MAILBOX@domain>",
- { NULL, "Display Name", NULL, "", "domain", TRUE },
- { NULL, "Display Name", NULL, "MISSING_MAILBOX", "domain", TRUE }, 0 },
+ { NULL, NULL, "Display Name", NULL, "", "domain", TRUE },
+ { NULL, NULL, "Display Name", NULL, "MISSING_MAILBOX", "domain", TRUE }, 0 },
{ "user@domain ()", "<user@domain>", NULL,
- { NULL, NULL, NULL, "user", "domain", FALSE },
- { NULL, NULL, NULL, "user", "domain", FALSE }, 0 },
+ { NULL, NULL, NULL, NULL, "user", "domain", FALSE },
+ { NULL, NULL, NULL, NULL, "user", "domain", FALSE }, 0 },
/* Display Name <user@domain> -> "Display Name" <user@domain> */
{ "DisplayName <user@domain>", NULL, NULL,
- { NULL, "DisplayName", NULL, "user", "domain", FALSE },
- { NULL, "DisplayName", NULL, "user", "domain", FALSE }, 0 },
+ { NULL, NULL, "DisplayName", NULL, "user", "domain", FALSE },
+ { NULL, NULL, "DisplayName", NULL, "user", "domain", FALSE }, 0 },
{ "Display Name <user@domain>", "\"Display Name\" <user@domain>", NULL,
- { NULL, "Display Name", NULL, "user", "domain", FALSE },
- { NULL, "Display Name", NULL, "user", "domain", FALSE }, 0 },
+ { NULL, NULL, "Display Name", NULL, "user", "domain", FALSE },
+ { NULL, NULL, "Display Name", NULL, "user", "domain", FALSE }, 0 },
{ "\"Display Name\" <user@domain>", NULL, NULL,
- { NULL, "Display Name", NULL, "user", "domain", FALSE },
- { NULL, "Display Name", NULL, "user", "domain", FALSE }, 0 },
+ { NULL, NULL, "Display Name", NULL, "user", "domain", FALSE },
+ { NULL, NULL, "Display Name", NULL, "user", "domain", FALSE }, 0 },
{ "\"Display\\\"Name\" <user@domain>", NULL, NULL,
- { NULL, "Display\"Name", NULL, "user", "domain", FALSE },
- { NULL, "Display\"Name", NULL, "user", "domain", FALSE }, 0 },
+ { NULL, NULL, "Display\"Name", NULL, "user", "domain", FALSE },
+ { NULL, NULL, "Display\"Name", NULL, "user", "domain", FALSE }, 0 },
{ "Display Name <user>", "\"Display Name\" <user>", "\"Display Name\" <user@MISSING_DOMAIN>",
- { NULL, "Display Name", NULL, "user", "", TRUE },
- { NULL, "Display Name", NULL, "user", "MISSING_DOMAIN", TRUE }, 0 },
+ { NULL, NULL, "Display Name", NULL, "user", "", TRUE },
+ { NULL, NULL, "Display Name", NULL, "user", "MISSING_DOMAIN", TRUE }, 0 },
{ "\"\" <user@domain>", "<user@domain>", NULL,
- { NULL, NULL, NULL, "user", "domain", FALSE },
- { NULL, NULL, NULL, "user", "domain", FALSE }, 0 },
+ { NULL, NULL, NULL, NULL, "user", "domain", FALSE },
+ { NULL, NULL, NULL, NULL, "user", "domain", FALSE }, 0 },
/* <@route:user@domain> -> <@route:user@domain> */
{ "<@route:user@domain>", NULL, NULL,
- { NULL, NULL, "@route", "user", "domain", FALSE },
- { NULL, NULL, "@route", "user", "domain", FALSE }, 0 },
+ { NULL, NULL, NULL, "@route", "user", "domain", FALSE },
+ { NULL, NULL, NULL, "@route", "user", "domain", FALSE }, 0 },
{ "<@route,@route2:user@domain>", NULL, NULL,
- { NULL, NULL, "@route,@route2", "user", "domain", FALSE },
- { NULL, NULL, "@route,@route2", "user", "domain", FALSE }, 0 },
+ { NULL, NULL, NULL, "@route,@route2", "user", "domain", FALSE },
+ { NULL, NULL, NULL, "@route,@route2", "user", "domain", FALSE }, 0 },
{ "<@route@route2:user@domain>", "<@route,@route2:user@domain>", NULL,
- { NULL, NULL, "@route,@route2", "user", "domain", FALSE },
- { NULL, NULL, "@route,@route2", "user", "domain", FALSE }, 0 },
+ { NULL, NULL, NULL, "@route,@route2", "user", "domain", FALSE },
+ { NULL, NULL, NULL, "@route,@route2", "user", "domain", FALSE }, 0 },
{ "<@route@route2:user>", "<@route,@route2:user>", "<@route,@route2:user@MISSING_DOMAIN>",
- { NULL, NULL, "@route,@route2", "user", "", TRUE },
- { NULL, NULL, "@route,@route2", "user", "MISSING_DOMAIN", TRUE }, 0 },
+ { NULL, NULL, NULL, "@route,@route2", "user", "", TRUE },
+ { NULL, NULL, NULL, "@route,@route2", "user", "MISSING_DOMAIN", TRUE }, 0 },
{ "<@route@route2:\"\"@domain>", "<@route,@route2:\"\"@domain>", NULL,
- { NULL, NULL, "@route,@route2", "", "domain", FALSE },
- { NULL, NULL, "@route,@route2", "", "domain", FALSE }, 0 },
+ { NULL, NULL, NULL, "@route,@route2", "", "domain", FALSE },
+ { NULL, NULL, NULL, "@route,@route2", "", "domain", FALSE }, 0 },
/* Display Name <@route:user@domain> ->
"Display Name" <@route:user@domain> */
{ "Display Name <@route:user@domain>", "\"Display Name\" <@route:user@domain>", NULL,
- { NULL, "Display Name", "@route", "user", "domain", FALSE },
- { NULL, "Display Name", "@route", "user", "domain", FALSE }, 0 },
+ { NULL, NULL, "Display Name", "@route", "user", "domain", FALSE },
+ { NULL, NULL, "Display Name", "@route", "user", "domain", FALSE }, 0 },
{ "Display Name <@route,@route2:user@domain>", "\"Display Name\" <@route,@route2:user@domain>", NULL,
- { NULL, "Display Name", "@route,@route2", "user", "domain", FALSE },
- { NULL, "Display Name", "@route,@route2", "user", "domain", FALSE }, 0 },
+ { NULL, NULL, "Display Name", "@route,@route2", "user", "domain", FALSE },
+ { NULL, NULL, "Display Name", "@route,@route2", "user", "domain", FALSE }, 0 },
{ "Display Name <@route@route2:user@domain>", "\"Display Name\" <@route,@route2:user@domain>", NULL,
- { NULL, "Display Name", "@route,@route2", "user", "domain", FALSE },
- { NULL, "Display Name", "@route,@route2", "user", "domain", FALSE }, 0 },
+ { NULL, NULL, "Display Name", "@route,@route2", "user", "domain", FALSE },
+ { NULL, NULL, "Display Name", "@route,@route2", "user", "domain", FALSE }, 0 },
{ "Display Name <@route@route2:user>", "\"Display Name\" <@route,@route2:user>", "\"Display Name\" <@route,@route2:user@MISSING_DOMAIN>",
- { NULL, "Display Name", "@route,@route2", "user", "", TRUE },
- { NULL, "Display Name", "@route,@route2", "user", "MISSING_DOMAIN", TRUE }, 0 },
+ { NULL, NULL, "Display Name", "@route,@route2", "user", "", TRUE },
+ { NULL, NULL, "Display Name", "@route,@route2", "user", "MISSING_DOMAIN", TRUE }, 0 },
{ "Display Name <@route@route2:\"\"@domain>", "\"Display Name\" <@route,@route2:\"\"@domain>", NULL,
- { NULL, "Display Name", "@route,@route2", "", "domain", FALSE },
- { NULL, "Display Name", "@route,@route2", "", "domain", FALSE }, 0 },
+ { NULL, NULL, "Display Name", "@route,@route2", "", "domain", FALSE },
+ { NULL, NULL, "Display Name", "@route,@route2", "", "domain", FALSE }, 0 },
/* other tests: */
{ "\"foo: <a@b>;,\" <user@domain>", NULL, NULL,
- { NULL, "foo: <a@b>;,", NULL, "user", "domain", FALSE },
- { NULL, "foo: <a@b>;,", NULL, "user", "domain", FALSE }, 0 },
+ { NULL, NULL, "foo: <a@b>;,", NULL, "user", "domain", FALSE },
+ { NULL, NULL, "foo: <a@b>;,", NULL, "user", "domain", FALSE }, 0 },
{ "<>", "", "<MISSING_MAILBOX@MISSING_DOMAIN>",
- { NULL, NULL, NULL, "", "", TRUE },
- { NULL, NULL, NULL, "MISSING_MAILBOX", "MISSING_DOMAIN", TRUE }, 0 },
+ { NULL, NULL, NULL, NULL, "", "", TRUE },
+ { NULL, NULL, NULL, NULL, "MISSING_MAILBOX", "MISSING_DOMAIN", TRUE }, 0 },
{ "<@>", "", "<INVALID_ROUTE:MISSING_MAILBOX@MISSING_DOMAIN>",
- { NULL, NULL, NULL, "", "", TRUE },
- { NULL, NULL, "INVALID_ROUTE", "MISSING_MAILBOX", "MISSING_DOMAIN", TRUE }, 0 },
+ { NULL, NULL, NULL, NULL, "", "", TRUE },
+ { NULL, NULL, NULL, "INVALID_ROUTE", "MISSING_MAILBOX", "MISSING_DOMAIN", TRUE }, 0 },
/* Test against a out-of-bounds read bug - keep these two tests
together in this same order: */
{ "aaaa@", "<aaaa>", "<aaaa@MISSING_DOMAIN>",
- { NULL, NULL, NULL, "aaaa", "", TRUE },
- { NULL, NULL, NULL, "aaaa", "MISSING_DOMAIN", TRUE }, 0 },
+ { NULL, NULL, NULL, NULL, "aaaa", "", TRUE },
+ { NULL, NULL, NULL, NULL, "aaaa", "MISSING_DOMAIN", TRUE }, 0 },
{ "a(aa", "", "<MISSING_MAILBOX@MISSING_DOMAIN>",
- { NULL, NULL, NULL, "", "", TRUE },
- { NULL, NULL, NULL, "MISSING_MAILBOX", "MISSING_DOMAIN", TRUE },
+ { NULL, NULL, NULL, NULL, "", "", TRUE },
+ { NULL, NULL, NULL, NULL, "MISSING_MAILBOX", "MISSING_DOMAIN", TRUE },
TEST_MESSAGE_ADDRESS_FLAG_SKIP_LIST },
};
static struct message_address group_prefix = {
- NULL, NULL, NULL, "group", NULL, FALSE
+ NULL, NULL, NULL, NULL, "group", NULL, FALSE
};
static struct message_address group_suffix = {
- NULL, NULL, NULL, NULL, NULL, FALSE
+ NULL, NULL, NULL, NULL, NULL, NULL, FALSE
};
const struct message_address *addr;
string_t *str, *group;
@@ -327,7 +327,7 @@ static void test_message_address_nuls(void)
const unsigned char input[] =
"\"user\0nuls\\\0-esc\"@[domain\0nuls\\\0-esc] (comment\0nuls\\\0-esc)";
const struct message_address output = {
- NULL, "comment\xEF\xBF\xBDnuls\\\xEF\xBF\xBD-esc", NULL,
+ NULL, NULL, "comment\xEF\xBF\xBDnuls\\\xEF\xBF\xBD-esc", NULL,
"user\xEF\xBF\xBDnuls\\\xEF\xBF\xBD-esc",
"[domain\xEF\xBF\xBDnuls\\\xEF\xBF\xBD-esc]", FALSE
};
@@ -345,7 +345,7 @@ static void test_message_address_nuls_display_name(void)
const unsigned char input[] =
"\"displayname\0nuls\\\0-esc\" <\"user\0nuls\\\0-esc\"@[domain\0nuls\\\0-esc]>";
const struct message_address output = {
- NULL, "displayname\xEF\xBF\xBDnuls\\\xEF\xBF\xBD-esc", NULL,
+ NULL, NULL, "displayname\xEF\xBF\xBDnuls\\\xEF\xBF\xBD-esc", NULL,
"user\xEF\xBF\xBDnuls\\\xEF\xBF\xBD-esc",
"[domain\xEF\xBF\xBDnuls\\\xEF\xBF\xBD-esc]", FALSE
};
@@ -369,7 +369,7 @@ static void test_message_address_non_strict_dots(void)
};
const struct message_address *addr;
struct message_address output = {
- NULL, NULL, NULL, "local-part",
+ NULL, NULL, NULL, NULL, "local-part",
"example.com", FALSE
};
@@ -421,29 +421,29 @@ static void test_message_address_path(void)
struct message_address addr;
} tests[] = {
{ "<>", NULL,
- { NULL, NULL, NULL, NULL, NULL, FALSE } },
+ { NULL, NULL, NULL, NULL, NULL, NULL, FALSE } },
{ " < > ", "<>",
- { NULL, NULL, NULL, NULL, NULL, FALSE } },
+ { NULL, NULL, NULL, NULL, NULL, NULL, FALSE } },
{ "<user@domain>", NULL,
- { NULL, NULL, NULL, "user", "domain", FALSE } },
+ { NULL, NULL, NULL, NULL, "user", "domain", FALSE } },
{ " <user@domain> ", "<user@domain>",
- { NULL, NULL, NULL, "user", "domain", FALSE } },
+ { NULL, NULL, NULL, NULL, "user", "domain", FALSE } },
{ "user@domain", "<user@domain>",
- { NULL, NULL, NULL, "user", "domain", FALSE } },
+ { NULL, NULL, NULL, NULL, "user", "domain", FALSE } },
{ " user@domain ", "<user@domain>",
- { NULL, NULL, NULL, "user", "domain", FALSE } },
+ { NULL, NULL, NULL, NULL, "user", "domain", FALSE } },
{ "<\"user\"@domain>", "<user@domain>",
- { NULL, NULL, NULL, "user", "domain", FALSE } },
+ { NULL, NULL, NULL, NULL, "user", "domain", FALSE } },
{ "<\"user name\"@domain>", NULL,
- { NULL, NULL, NULL, "user name", "domain", FALSE } },
+ { NULL, NULL, NULL, NULL, "user name", "domain", FALSE } },
{ "<\"user@na\\\\me\"@domain>", NULL,
- { NULL, NULL, NULL, "user@na\\me", "domain", FALSE } },
+ { NULL, NULL, NULL, NULL, "user@na\\me", "domain", FALSE } },
{ "<\"user\\\"name\"@domain>", NULL,
- { NULL, NULL, NULL, "user\"name", "domain", FALSE } },
+ { NULL, NULL, NULL, NULL, "user\"name", "domain", FALSE } },
{ "<\"\"@domain>", NULL,
- { NULL, NULL, NULL, "", "domain", FALSE } },
+ { NULL, NULL, NULL, NULL, "", "domain", FALSE } },
{ "<@source", "<>",
- { NULL, NULL, NULL, NULL, NULL, TRUE } },
+ { NULL, NULL, NULL, NULL, NULL, NULL, TRUE } },
};
const struct message_address *addr;
string_t *str;
From da61d20311da34f22944c6111a0b97ea2a1f8a47 Mon Sep 17 00:00:00 2001
From: Timo Sirainen <timo.sirainen@open-xchange.com>
Date: Tue, 30 Jan 2024 22:17:38 +0200
Subject: [PATCH 5/6] lib-mail: Add message_address_parse_full() and struct
message_address_list
---
src/lib-mail/message-address.c | 37 +++++++++++++---------
src/lib-mail/message-address.h | 10 ++++++
src/lib-mail/test-message-address.c | 48 +++++++++++++++++++++++++----
3 files changed, 75 insertions(+), 20 deletions(-)
diff --git a/src/lib-mail/message-address.c b/src/lib-mail/message-address.c
index 9d192799468..ae37014079a 100644
--- a/src/lib-mail/message-address.c
+++ b/src/lib-mail/message-address.c
@@ -13,7 +13,8 @@ struct message_address_parser_context {
pool_t pool;
struct rfc822_parser_context parser;
- struct message_address *first_addr, *last_addr, addr;
+ struct message_address addr;
+ struct message_address_list addr_list;
string_t *str;
bool fill_missing, non_strict_dots;
@@ -28,7 +29,7 @@ static void add_address(struct message_address_parser_context *ctx)
memcpy(addr, &ctx->addr, sizeof(ctx->addr));
i_zero(&ctx->addr);
- DLLIST2_APPEND(&ctx->first_addr, &ctx->last_addr, addr);
+ DLLIST2_APPEND(&ctx->addr_list.head, &ctx->addr_list.tail, addr);
}
/* quote with "" and escape all '\', '"' and "'" characters if need */
@@ -439,10 +440,11 @@ static int parse_path(struct message_address_parser_context *ctx)
return ret;
}
-static struct message_address *
+static void
message_address_parse_real(pool_t pool, const unsigned char *data, size_t size,
unsigned int max_addresses,
- enum message_address_parse_flags flags)
+ enum message_address_parse_flags flags,
+ struct message_address_list *list_r)
{
struct message_address_parser_context ctx;
@@ -461,7 +463,7 @@ message_address_parse_real(pool_t pool, const unsigned char *data, size_t size,
(void)parse_address_list(&ctx, max_addresses);
}
rfc822_parser_deinit(&ctx.parser);
- return ctx.first_addr;
+ *list_r = ctx.addr_list;
}
static int
@@ -481,7 +483,7 @@ message_address_parse_path_real(pool_t pool, const unsigned char *data,
ret = parse_path(&ctx);
rfc822_parser_deinit(&ctx.parser);
- *addr_r = ctx.first_addr;
+ *addr_r = ctx.addr_list.head;
return (ret < 0 ? -1 : 0);
}
@@ -490,17 +492,24 @@ message_address_parse(pool_t pool, const unsigned char *data, size_t size,
unsigned int max_addresses,
enum message_address_parse_flags flags)
{
- struct message_address *addr;
+ struct message_address_list list;
+ message_address_parse_full(pool, data, size, max_addresses, flags,
+ &list);
+ return list.head;
+}
+void message_address_parse_full(pool_t pool, const unsigned char *data,
+ size_t size, unsigned int max_addresses,
+ enum message_address_parse_flags flags,
+ struct message_address_list *list_r)
+{
if (pool->datastack_pool) {
- return message_address_parse_real(pool, data, size,
- max_addresses, flags);
- }
- T_BEGIN {
- addr = message_address_parse_real(pool, data, size,
- max_addresses, flags);
+ message_address_parse_real(pool, data, size,
+ max_addresses, flags, list_r);
+ } else T_BEGIN {
+ message_address_parse_real(pool, data, size,
+ max_addresses, flags, list_r);
} T_END;
- return addr;
}
int message_address_parse_path(pool_t pool, const unsigned char *data,
diff --git a/src/lib-mail/message-address.h b/src/lib-mail/message-address.h
index 85cff3dcc6f..224f7a75605 100644
--- a/src/lib-mail/message-address.h
+++ b/src/lib-mail/message-address.h
@@ -31,12 +31,22 @@ struct message_address {
bool invalid_syntax;
};
+struct message_address_list {
+ struct message_address *head, *tail;
+};
+
/* Parse message addresses from given data. Note that giving an empty string
will return NULL since there are no addresses. */
struct message_address *
message_address_parse(pool_t pool, const unsigned char *data, size_t size,
unsigned int max_addresses,
enum message_address_parse_flags flags);
+/* Same as message_address_parse(), but return message_address_list containing
+ both the first and the last address in the linked list. */
+void message_address_parse_full(pool_t pool, const unsigned char *data,
+ size_t size, unsigned int max_addresses,
+ enum message_address_parse_flags flags,
+ struct message_address_list *list_r);
/* Parse RFC 5322 "path" (Return-Path header) from given data. Returns -1 if
the path is invalid and 0 otherwise.
diff --git a/src/lib-mail/test-message-address.c b/src/lib-mail/test-message-address.c
index 261cbfba70a..54aa9a83101 100644
--- a/src/lib-mail/test-message-address.c
+++ b/src/lib-mail/test-message-address.c
@@ -19,8 +19,9 @@ static bool cmp_addr(const struct message_address *a1,
a1->invalid_syntax == a2->invalid_syntax;
}
-static const struct message_address *
-test_parse_address(const char *input, bool fill_missing)
+static void
+test_parse_address_full(const char *input, bool fill_missing,
+ struct message_address_list *list_r)
{
const enum message_address_parse_flags flags =
fill_missing ? MESSAGE_ADDRESS_PARSE_FLAG_FILL_MISSING : 0;
@@ -28,11 +29,18 @@ test_parse_address(const char *input, bool fill_missing)
if there's any out-of-bounds access */
size_t input_len = strlen(input);
unsigned char *input_dup = i_memdup(input, input_len);
- const struct message_address *addr =
- message_address_parse(pool_datastack_create(),
- input_dup, input_len, UINT_MAX, flags);
+ message_address_parse_full(pool_datastack_create(),
+ input_dup, input_len, UINT_MAX, flags,
+ list_r);
i_free(input_dup);
- return addr;
+}
+
+static const struct message_address *
+test_parse_address(const char *input, bool fill_missing)
+{
+ struct message_address_list list;
+ test_parse_address_full(input, fill_missing, &list);
+ return list.head;
}
static void test_message_address(void)
@@ -322,6 +330,33 @@ static void test_message_address(void)
test_end();
}
+static void test_message_address_list(void)
+{
+ test_begin("message address list");
+
+ const char *test_input =
+ "user1@example1.com, user2@example2.com, user3@example3.com";
+ const struct message_address wanted_addrs[] = {
+ { NULL, NULL, NULL, NULL, "user1", "example1.com", FALSE },
+ { NULL, NULL, NULL, NULL, "user2", "example2.com", FALSE },
+ { NULL, NULL, NULL, NULL, "user3", "example3.com", FALSE },
+ };
+
+ struct message_address_list list;
+ struct message_address *addr, *scanned_last_addr;
+ test_parse_address_full(test_input, FALSE, &list);
+ addr = list.head;
+ for (unsigned int i = 0; i < N_ELEMENTS(wanted_addrs); i++) {
+ test_assert_idx(cmp_addr(addr, &wanted_addrs[i]), i);
+ scanned_last_addr = addr;
+ addr = addr->next;
+ }
+ test_assert(list.tail == scanned_last_addr);
+ test_assert(addr == NULL);
+
+ test_end();
+}
+
static void test_message_address_nuls(void)
{
const unsigned char input[] =
@@ -521,6 +556,7 @@ int main(void)
{
static void (*const test_functions[])(void) = {
test_message_address,
+ test_message_address_list,
test_message_address_nuls,
test_message_address_nuls_display_name,
test_message_address_non_strict_dots,
From 1481c04f02df7647f520df65d63df7626bf0ee32 Mon Sep 17 00:00:00 2001
From: Timo Sirainen <timo.sirainen@open-xchange.com>
Date: Fri, 9 Feb 2024 00:57:12 +0200
Subject: [PATCH 6/6] lib-mail, lib-imap: Optimize parsing large number of
address headers
Every header was appended to a linked list by walking through the whole
list, causing excessive CPU usage when the list became large enough.
Fixed by changing struct message_part_envelope to use struct
message_address_list, which stores also linked list tail pointers. This
allows quickly appending to the end of the linked list.
---
src/lib-imap/imap-envelope.c | 27 ++++++++++-------------
src/lib-mail/message-part-data.c | 17 +++++++-------
src/lib-mail/message-part-data.h | 6 +++--
src/lib-storage/index/index-search-mime.c | 4 ++--
4 files changed, 27 insertions(+), 27 deletions(-)
diff --git a/src/lib-imap/imap-envelope.c b/src/lib-imap/imap-envelope.c
index 1312eae2ff3..da3177025a5 100644
--- a/src/lib-imap/imap-envelope.c
+++ b/src/lib-imap/imap-envelope.c
@@ -67,17 +67,17 @@ void imap_envelope_write(struct message_part_envelope *data,
}
str_append_c(str, ' ');
- imap_write_address(str, data->from);
+ imap_write_address(str, data->from.head);
str_append_c(str, ' ');
- imap_write_address(str, NVL(data->sender, data->from));
+ imap_write_address(str, NVL(data->sender.head, data->from.head));
str_append_c(str, ' ');
- imap_write_address(str, NVL(data->reply_to, data->from));
+ imap_write_address(str, NVL(data->reply_to.head, data->from.head));
str_append_c(str, ' ');
- imap_write_address(str, data->to);
+ imap_write_address(str, data->to.head);
str_append_c(str, ' ');
- imap_write_address(str, data->cc);
+ imap_write_address(str, data->cc.head);
str_append_c(str, ' ');
- imap_write_address(str, data->bcc);
+ imap_write_address(str, data->bcc.head);
str_append_c(str, ' ');
imap_append_nstring_nolf(str, data->in_reply_to);
@@ -126,28 +126,25 @@ imap_envelope_parse_address(const struct imap_arg *arg,
static bool
imap_envelope_parse_addresses(const struct imap_arg *arg,
- pool_t pool, struct message_address **addrs_r)
+ pool_t pool, struct message_address_list *addrs_r)
{
- struct message_address *first, *last, *addr;
+ struct message_address *addr;
const struct imap_arg *list_args;
- if (arg->type == IMAP_ARG_NIL) {
- *addrs_r = NULL;
+ i_zero(addrs_r);
+ if (arg->type == IMAP_ARG_NIL)
return TRUE;
- }
if (!imap_arg_get_list(arg, &list_args))
return FALSE;
- first = last = addr = NULL;
+ addr = NULL;
for (; !IMAP_ARG_IS_EOL(list_args); list_args++) {
if (!imap_envelope_parse_address
(list_args, pool, &addr))
return FALSE;
- DLLIST2_APPEND(&first, &last, addr);
+ DLLIST2_APPEND(&addrs_r->head, &addrs_r->tail, addr);
}
-
- *addrs_r = first;
return TRUE;
}
diff --git a/src/lib-mail/message-part-data.c b/src/lib-mail/message-part-data.c
index a5771f87e2e..25019ab432d 100644
--- a/src/lib-mail/message-part-data.c
+++ b/src/lib-mail/message-part-data.c
@@ -4,6 +4,7 @@
#include "str.h"
#include "wildcard-match.h"
#include "array.h"
+#include "llist.h"
#include "rfc822-parser.h"
#include "rfc2231-parser.h"
#include "message-address.h"
@@ -176,7 +177,7 @@ void message_part_envelope_parse_from_header(pool_t pool,
{
struct message_part_envelope *d;
enum envelope_field field;
- struct message_address **addr_p, *addr;
+ struct message_address_list *addr_p, new_addr;
const char **str_p;
if (*data == NULL) {
@@ -234,18 +235,18 @@ void message_part_envelope_parse_from_header(pool_t pool,
}
if (addr_p != NULL) {
- addr = message_address_parse(pool, hdr->full_value,
- hdr->full_value_len,
- UINT_MAX,
- MESSAGE_ADDRESS_PARSE_FLAG_FILL_MISSING);
+ message_address_parse_full(pool, hdr->full_value,
+ hdr->full_value_len,
+ UINT_MAX,
+ MESSAGE_ADDRESS_PARSE_FLAG_FILL_MISSING,
+ &new_addr);
/* Merge multiple headers the same as if they were comma
separated in a single line. This is better from security
point of view, because attacker could intentionally write
addresses in a way that e.g. the first From header is
validated while MUA only shows the second From header. */
- while (*addr_p != NULL)
- addr_p = &(*addr_p)->next;
- *addr_p = addr;
+ DLLIST2_JOIN(&addr_p->head, &addr_p->tail,
+ &new_addr.head, &new_addr.tail);
} else if (str_p != NULL) {
*str_p = message_header_strdup(pool, hdr->full_value,
hdr->full_value_len);
diff --git a/src/lib-mail/message-part-data.h b/src/lib-mail/message-part-data.h
index 5ff9ffe1bc6..7ec878de68e 100644
--- a/src/lib-mail/message-part-data.h
+++ b/src/lib-mail/message-part-data.h
@@ -2,6 +2,7 @@
#define MESSAGE_PART_DATA_H
#include "message-part.h"
+#include "message-address.h"
#define MESSAGE_PART_DEFAULT_CHARSET "us-ascii"
@@ -14,8 +15,9 @@ struct message_part_param {
struct message_part_envelope {
const char *date, *subject;
- struct message_address *from, *sender, *reply_to;
- struct message_address *to, *cc, *bcc;
+
+ struct message_address_list from, sender, reply_to;
+ struct message_address_list to, cc, bcc;
const char *in_reply_to, *message_id;
};
diff --git a/src/lib-storage/index/index-search-mime.c b/src/lib-storage/index/index-search-mime.c
index da7e5e17092..3328ce98af1 100644
--- a/src/lib-storage/index/index-search-mime.c
+++ b/src/lib-storage/index/index-search-mime.c
@@ -205,7 +205,7 @@ seach_arg_mime_envelope_address_match(
enum mail_search_mime_arg_type type, const char *key,
const struct message_part_envelope *envelope)
{
- const struct message_address *addrs;
+ struct message_address_list addrs;
string_t *addrs_enc;
if (envelope == NULL)
@@ -239,7 +239,7 @@ seach_arg_mime_envelope_address_match(
probably be normalized directly in the struct message_address. */
addrs_enc = t_str_new(128);
- message_address_write(addrs_enc, addrs);
+ message_address_write(addrs_enc, addrs.head);
return (strstr(str_c(addrs_enc), key) != NULL ? 1 : 0);
}

@ -1,459 +0,0 @@
diff -up dovecot-2.3.16/src/lib-mail/message-header-parser.c.CVE-2024-23185 dovecot-2.3.16/src/lib-mail/message-header-parser.c
--- dovecot-2.3.16/src/lib-mail/message-header-parser.c.CVE-2024-23185 2021-08-06 11:25:51.000000000 +0200
+++ dovecot-2.3.16/src/lib-mail/message-header-parser.c 2024-08-20 23:29:25.214183880 +0200
@@ -17,6 +17,9 @@ struct message_header_parser_ctx {
string_t *name;
buffer_t *value_buf;
+ size_t header_block_max_size;
+ size_t header_block_total_size;
+
enum message_header_parser_flags flags;
bool skip_line:1;
bool has_nuls:1;
@@ -34,6 +37,7 @@ message_parse_header_init(struct istream
ctx->name = str_new(default_pool, 128);
ctx->flags = flags;
ctx->value_buf = buffer_create_dynamic(default_pool, 4096);
+ ctx->header_block_max_size = MESSAGE_HEADER_BLOCK_DEFAULT_MAX_SIZE;
i_stream_ref(input);
if (hdr_size != NULL)
@@ -41,6 +45,21 @@ message_parse_header_init(struct istream
return ctx;
}
+void
+message_parse_header_set_limit(struct message_header_parser_ctx *parser,
+ size_t header_block_max_size)
+{
+ parser->header_block_max_size = header_block_max_size;
+}
+
+void
+message_parse_header_lower_limit(struct message_header_parser_ctx *parser,
+ size_t header_block_max_size)
+{
+ if (header_block_max_size < parser->header_block_max_size)
+ message_parse_header_set_limit(parser, header_block_max_size);
+}
+
void message_parse_header_deinit(struct message_header_parser_ctx **_ctx)
{
struct message_header_parser_ctx *ctx = *_ctx;
@@ -73,6 +92,7 @@ int message_parse_header_next(struct mes
/* new header line */
line->name_offset = ctx->input->v_offset;
colon_pos = UINT_MAX;
+ ctx->header_block_total_size += ctx->value_buf->used;
buffer_set_used_size(ctx->value_buf, 0);
}
@@ -326,33 +346,39 @@ int message_parse_header_next(struct mes
line->middle = str_data(ctx->name) + line->name_len + 1;
}
+ line->value_len = I_MIN(line->value_len, ctx->header_block_max_size);
+ size_t line_value_size = line->value_len;
+ size_t header_total_used = ctx->header_block_total_size + ctx->value_buf->used;
+ size_t line_available = ctx->header_block_max_size <= header_total_used ? 0 :
+ ctx->header_block_max_size - header_total_used;
+ line_value_size = I_MIN(line_value_size, line_available);
+
if (!line->continued) {
/* first header line. make a copy of the line since we can't
really trust input stream not to lose it. */
- buffer_append(ctx->value_buf, line->value, line->value_len);
+ buffer_append(ctx->value_buf, line->value, line_value_size);
line->value = line->full_value = ctx->value_buf->data;
- line->full_value_len = line->value_len;
+ line->full_value_len = line->value_len = line_value_size;
} else if (line->use_full_value) {
/* continue saving the full value. */
if (last_no_newline) {
/* line is longer than fit into our buffer, so we
were forced to break it into multiple
message_header_lines */
- } else {
- if (last_crlf)
+ } else if (line_value_size > 1) {
+ if (last_crlf && line_value_size > 2)
buffer_append_c(ctx->value_buf, '\r');
buffer_append_c(ctx->value_buf, '\n');
}
if ((ctx->flags & MESSAGE_HEADER_PARSER_FLAG_CLEAN_ONELINE) != 0 &&
line->value_len > 0 && line->value[0] != ' ' &&
- IS_LWSP(line->value[0])) {
+ IS_LWSP(line->value[0]) &&
+ line_value_size > 0) {
buffer_append_c(ctx->value_buf, ' ');
- buffer_append(ctx->value_buf,
- line->value + 1, line->value_len - 1);
- } else {
- buffer_append(ctx->value_buf,
- line->value, line->value_len);
- }
+ buffer_append(ctx->value_buf, line->value + 1, line_value_size - 1);
+ } else
+ buffer_append(ctx->value_buf, line->value, line_value_size);
+
line->full_value = ctx->value_buf->data;
line->full_value_len = ctx->value_buf->used;
} else {
diff -up dovecot-2.3.16/src/lib-mail/message-header-parser.h.CVE-2024-23185 dovecot-2.3.16/src/lib-mail/message-header-parser.h
--- dovecot-2.3.16/src/lib-mail/message-header-parser.h.CVE-2024-23185 2021-08-06 11:25:51.000000000 +0200
+++ dovecot-2.3.16/src/lib-mail/message-header-parser.h 2024-08-20 22:55:36.530652449 +0200
@@ -1,6 +1,9 @@
#ifndef MESSAGE_HEADER_PARSER_H
#define MESSAGE_HEADER_PARSER_H
+/* This can be overridden by message_parse_header_set_limit() */
+#define MESSAGE_HEADER_BLOCK_DEFAULT_MAX_SIZE ((size_t) 10 * 1024*1024)
+
#define IS_LWSP(c) \
((c) == ' ' || (c) == '\t')
@@ -48,6 +51,13 @@ message_parse_header_init(struct istream
enum message_header_parser_flags flags) ATTR_NULL(2);
void message_parse_header_deinit(struct message_header_parser_ctx **ctx);
+void
+message_parse_header_set_limit(struct message_header_parser_ctx *parser,
+ size_t header_block_max_size);
+void
+message_parse_header_lower_limit(struct message_header_parser_ctx *parser,
+ size_t header_block_max_size);
+
/* Read and return next header line. Returns 1 if header is returned, 0 if
input stream is non-blocking and more data needs to be read, -1 when all is
done or error occurred (see stream's error status). */
diff -up dovecot-2.3.16/src/lib-mail/message-parser.c.CVE-2024-23185 dovecot-2.3.16/src/lib-mail/message-parser.c
--- dovecot-2.3.16/src/lib-mail/message-parser.c.CVE-2024-23185 2021-08-06 11:25:51.000000000 +0200
+++ dovecot-2.3.16/src/lib-mail/message-parser.c 2024-08-20 22:55:36.531652458 +0200
@@ -617,7 +617,18 @@ static int parse_next_header(struct mess
}
if (ret < 0) {
/* no boundary */
+ size_t headers_available =
+ ctx->all_headers_max_size > ctx->all_headers_total_size ?
+ ctx->all_headers_max_size - ctx->all_headers_total_size : 0;
+ message_parse_header_lower_limit(ctx->hdr_parser_ctx, headers_available);
ret = message_parse_header_next(ctx->hdr_parser_ctx, &hdr);
+ if (ret > 0) {
+ if (!hdr->continues) {
+ ctx->all_headers_total_size += hdr->name_len;
+ ctx->all_headers_total_size += hdr->middle_len;
+ }
+ ctx->all_headers_total_size += hdr->value_len;
+ }
if (ret == 0 || (ret < 0 && ctx->input->stream_errno != 0)) {
ctx->want_count = i_stream_get_data_size(ctx->input) + 1;
return ret;
@@ -762,6 +773,9 @@ message_parser_init_int(struct istream *
ctx->max_total_mime_parts = set->max_total_mime_parts != 0 ?
set->max_total_mime_parts :
MESSAGE_PARSER_DEFAULT_MAX_TOTAL_MIME_PARTS;
+ ctx->all_headers_max_size = set->all_headers_max_size != 0 ?
+ set->all_headers_max_size :
+ MESSAGE_PARSER_DEFAULT_ALL_HEADERS_MAX_SIZE;
ctx->input = input;
i_stream_ref(input);
return ctx;
@@ -779,6 +793,7 @@ message_parser_init(pool_t part_pool, st
ctx->next_part = &ctx->part->children;
ctx->parse_next_block = parse_next_header_init;
ctx->total_parts_count = 1;
+ ctx->all_headers_total_size = 0;
i_array_init(&ctx->next_part_stack, 4);
return ctx;
}
diff -up dovecot-2.3.16/src/lib-mail/message-parser.h.CVE-2024-23185 dovecot-2.3.16/src/lib-mail/message-parser.h
--- dovecot-2.3.16/src/lib-mail/message-parser.h.CVE-2024-23185 2021-08-06 11:25:51.000000000 +0200
+++ dovecot-2.3.16/src/lib-mail/message-parser.h 2024-08-20 22:55:36.531652458 +0200
@@ -19,6 +19,7 @@ enum message_parser_flags {
#define MESSAGE_PARSER_DEFAULT_MAX_NESTED_MIME_PARTS 100
#define MESSAGE_PARSER_DEFAULT_MAX_TOTAL_MIME_PARTS 10000
+#define MESSAGE_PARSER_DEFAULT_ALL_HEADERS_MAX_SIZE ((size_t) 50 * 1024*1024)
struct message_parser_settings {
enum message_header_parser_flags hdr_flags;
@@ -30,6 +31,11 @@ struct message_parser_settings {
/* Maximum MIME parts in total.
0 = MESSAGE_PARSER_DEFAULT_MAX_TOTAL_MIME_PARTS. */
unsigned int max_total_mime_parts;
+
+ /* Maximum bytes fore headers in top header plus all
+ MIME sections headers
+ 0 = MESSAGE_PARSER_DEFAULT_ALL_HEADERS_MAX_SIZE */
+ size_t all_headers_max_size;
};
struct message_parser_ctx;
diff -up dovecot-2.3.16/src/lib-mail/message-parser-private.h.CVE-2024-23185 dovecot-2.3.16/src/lib-mail/message-parser-private.h
--- dovecot-2.3.16/src/lib-mail/message-parser-private.h.CVE-2024-23185 2021-08-06 11:25:51.000000000 +0200
+++ dovecot-2.3.16/src/lib-mail/message-parser-private.h 2024-08-20 22:55:36.531652458 +0200
@@ -30,6 +30,8 @@ struct message_parser_ctx {
enum message_parser_flags flags;
unsigned int max_nested_mime_parts;
unsigned int max_total_mime_parts;
+ size_t all_headers_max_size;
+ size_t all_headers_total_size;
char *last_boundary;
struct message_boundary *boundaries;
diff -up dovecot-2.3.16/src/lib-mail/test-message-header-parser.c.CVE-2024-23185 dovecot-2.3.16/src/lib-mail/test-message-header-parser.c
--- dovecot-2.3.16/src/lib-mail/test-message-header-parser.c.CVE-2024-23185 2021-08-06 11:25:51.000000000 +0200
+++ dovecot-2.3.16/src/lib-mail/test-message-header-parser.c 2024-08-20 23:23:18.169196280 +0200
@@ -332,6 +332,71 @@ static void test_message_header_parser_n
test_end();
}
+#define assert_parsed_field(line, expected, actual, len) STMT_START { \
+ test_assert_idx(memcmp(expected, actual, strlen(expected)) == 0, line); \
+ test_assert_cmp_idx(strlen(expected), ==, len, line); \
+} STMT_END
+
+/* NOTE: implicit variables: (parser, hdr) */
+#define assert_parse_line(line, exp_name, exp_value, exp_full) STMT_START { \
+ test_assert_idx(message_parse_header_next(parser, &hdr) > 0, line); \
+ assert_parsed_field(line, exp_name, hdr->name, hdr->name_len); \
+ assert_parsed_field(line, exp_value, hdr->value, hdr->value_len); \
+ assert_parsed_field(line, exp_full, hdr->full_value, hdr->full_value_len); \
+ if (hdr->continues) hdr->use_full_value = TRUE; \
+} STMT_END
+
+static const unsigned char test_message_header_truncation_input[] =
+ /*01*/ "header1: this is short\n"
+ /*02*/ "header2: this is multiline\n"
+ /*03*/ " and long 343638404244464850525456586062\n"
+ /*04*/ " 64666870727476788082848688909294969800\n"
+ /*05*/ " 02040608101214161820222426283032343638\n"
+ /*06*/ "header3: I should not appear at all\n"
+ /*07*/ "\n";
+
+static void test_message_header_truncation_clean_oneline(void)
+{
+ test_begin("message header parser truncate + CLEAN_ONELINE flag");
+ struct message_header_line *hdr = NULL;
+ struct istream *input = test_istream_create_data(test_message_header_truncation_input, sizeof(test_message_header_truncation_input));
+ struct message_header_parser_ctx *parser = message_parse_header_init(input, NULL, MESSAGE_HEADER_PARSER_FLAG_CLEAN_ONELINE);
+ message_parse_header_set_limit(parser, 96);
+
+ assert_parse_line( 1, "header1", "this is short", "this is short");
+ assert_parse_line( 2, "header2", "this is multiline", "this is multiline");
+ assert_parse_line( 3, "header2", " and long 343638404244464850525456586062", "this is multiline and long 343638404244464850525456586062");
+ assert_parse_line( 4, "header2", " 64666870727476788082848688909294969800", "this is multiline and long 343638404244464850525456586062 6466687072747678808284868");
+ assert_parse_line( 5, "header2", " 02040608101214161820222426283032343638", "this is multiline and long 343638404244464850525456586062 6466687072747678808284868");
+ assert_parse_line( 6, "header3", "", "");
+ test_assert(message_parse_header_next(parser, &hdr) > 0 && hdr->eoh);
+
+ message_parse_header_deinit(&parser);
+ i_stream_unref(&input);
+ test_end();
+}
+
+static void test_message_header_truncation_flag0(void)
+{
+ test_begin("message header parser truncate + NO flags");
+ struct message_header_line *hdr = NULL;
+ struct istream *input = test_istream_create_data(test_message_header_truncation_input, sizeof(test_message_header_truncation_input));
+ struct message_header_parser_ctx *parser = message_parse_header_init(input, NULL, 0);
+ message_parse_header_set_limit(parser, 96);
+
+ assert_parse_line( 1, "header1", "this is short", "this is short");
+ assert_parse_line( 2, "header2", "this is multiline", "this is multiline");
+ assert_parse_line( 3, "header2", " and long 343638404244464850525456586062", "this is multiline\n and long 343638404244464850525456586062");
+ assert_parse_line( 4, "header2", " 64666870727476788082848688909294969800", "this is multiline\n and long 343638404244464850525456586062\n 646668707274767880828486");
+ assert_parse_line( 5, "header2", " 02040608101214161820222426283032343638", "this is multiline\n and long 343638404244464850525456586062\n 646668707274767880828486");
+ assert_parse_line( 6, "header3", "", "");
+ test_assert(message_parse_header_next(parser, &hdr) > 0 && hdr->eoh);
+
+ message_parse_header_deinit(&parser);
+ i_stream_unref(&input);
+ test_end();
+}
+
int main(void)
{
static void (*const test_functions[])(void) = {
@@ -341,6 +406,8 @@ int main(void)
test_message_header_parser_extra_cr_in_eoh,
test_message_header_parser_no_eoh,
test_message_header_parser_nul,
+ test_message_header_truncation_flag0,
+ test_message_header_truncation_clean_oneline,
NULL
};
return test_run(test_functions);
diff -up dovecot-2.3.16/src/lib-mail/test-message-parser.c.CVE-2024-23185 dovecot-2.3.16/src/lib-mail/test-message-parser.c
--- dovecot-2.3.16/src/lib-mail/test-message-parser.c.CVE-2024-23185 2021-08-06 11:25:51.000000000 +0200
+++ dovecot-2.3.16/src/lib-mail/test-message-parser.c 2024-08-20 22:55:36.531652458 +0200
@@ -1369,6 +1369,158 @@ static const char input_msg[] =
test_end();
}
+#define test_assert_virtual_size(part) \
+ test_assert((part).virtual_size == (part).lines + (part).physical_size)
+
+#define test_assert_part(part, flags_, children, h_lines, h_size, b_lines, b_size ) \
+STMT_START { \
+ test_assert((part)->flags == (flags_)); \
+ test_assert((part)->children_count == children); \
+ test_assert((part)->header_size.lines == h_lines); \
+ test_assert((part)->header_size.physical_size == h_size); \
+ test_assert((part)->body_size.lines == b_lines); \
+ test_assert((part)->body_size.physical_size == b_size); \
+ test_assert_virtual_size((part)->header_size); \
+ test_assert_virtual_size((part)->body_size); \
+} STMT_END
+
+static const enum message_part_flags FLAGS_MULTIPART =
+ MESSAGE_PART_FLAG_IS_MIME | MESSAGE_PART_FLAG_MULTIPART;
+static const enum message_part_flags FLAGS_RFC822 =
+ MESSAGE_PART_FLAG_IS_MIME | MESSAGE_PART_FLAG_MESSAGE_RFC822;
+static const enum message_part_flags FLAGS_TEXT =
+ MESSAGE_PART_FLAG_IS_MIME | MESSAGE_PART_FLAG_TEXT;
+
+static const char too_many_header_bytes_input_msg[] =
+ "Content-Type: multipart/mixed; boundary=\"1\"\n\n"
+ "--1\n"
+ "Content-Type: multipart/mixed; boundary=\"2\"\n\n"
+ "--2\n"
+ "Content-Type: message/rfc822\n\n"
+ "Content-Type: text/plain\n\n1-rfc822\n"
+ "--2\n"
+ "Content-Type: message/rfc822\n\n"
+ "Content-Type: text/plain\n\n2-rfc822\n"
+ "--1\n"
+ "Content-Type: message/rfc822\n\n"
+ "Content-Type: text/plain\n\n3-rfc822\n";
+
+static void test_message_parser_too_many_header_bytes_run(
+ const struct message_parser_settings *parser_set,
+ pool_t *pool_r, struct istream **input_r,
+ struct message_part **parts_r)
+{
+ *pool_r = pool_alloconly_create("message parser", 10240);
+ *input_r = test_istream_create(too_many_header_bytes_input_msg);
+ struct message_parser_ctx *parser = message_parser_init(*pool_r, *input_r, parser_set);
+
+ int ret;
+ struct message_block block ATTR_UNUSED;
+ while ((ret = message_parser_parse_next_block(parser, &block)) > 0);
+ test_assert(ret < 0);
+
+ message_parser_deinit(&parser, parts_r);
+}
+
+static void test_message_parser_too_many_header_bytes_default(void)
+{
+ test_begin("message parser too many header bytes default");
+
+ pool_t pool;
+ struct istream *input;
+ struct message_part *part_root;
+ const struct message_parser_settings parser_set = { .all_headers_max_size = 0 };
+
+ test_message_parser_too_many_header_bytes_run(&parser_set, &pool, &input, &part_root);
+
+ // test_assert_part(part, flags_, children, h_lines, h_size, b_lines, b_size )
+
+ test_assert_part(part_root, FLAGS_MULTIPART, 7, 2, 45, 21, 256);
+ test_assert(part_root->parent == NULL);
+
+ struct message_part *part_1 = part_root->children;
+ test_assert_part(part_1, FLAGS_MULTIPART, 4, 2, 45, 11, 137);
+
+ struct message_part *part_1_1 = part_1->children;
+ test_assert_part(part_1_1, FLAGS_RFC822, 1, 2, 30, 2, 34);
+
+ struct message_part *part_1_1_1 = part_1_1->children;
+ test_assert_part(part_1_1_1, FLAGS_TEXT, 0, 2, 26, 0, 8);
+
+ test_assert(part_1_1_1->next == NULL);
+
+ struct message_part *part_1_2 = part_1_1->next;
+ test_assert_part(part_1_2, FLAGS_RFC822, 1, 2, 30, 2, 34);
+
+ struct message_part *part_1_2_1 = part_1_2->children;
+ test_assert_part(part_1_2_1, FLAGS_TEXT, 0, 2, 26, 0, 8);
+
+ test_assert(part_1_2_1->next == NULL);
+
+ test_assert(part_1_2->next == NULL);
+
+ struct message_part *part_2 = part_1->next;
+ test_assert_part(part_2, FLAGS_RFC822, 1, 2, 30, 3, 35);
+
+ struct message_part *part_2_1 = part_2->children;
+ test_assert_part(part_2_1, FLAGS_TEXT, 0, 2, 26, 1, 9);
+ test_assert(part_2_1->next == NULL);
+
+ test_assert(part_2->next == NULL);
+
+ test_assert(part_root->next == NULL);
+
+ test_parsed_parts(input, part_root);
+ i_stream_unref(&input);
+ pool_unref(&pool);
+ test_end();
+}
+
+static void test_message_parser_too_many_header_bytes_100(void)
+{
+ test_begin("message parser too many header bytes 100");
+
+ pool_t pool;
+ struct istream *input;
+ struct message_part *part_root;
+ const struct message_parser_settings parser_set = { .all_headers_max_size = 100 };
+
+ test_message_parser_too_many_header_bytes_run(&parser_set, &pool, &input, &part_root);
+
+ // test_assert_part(part, flags_, children, h_lines, h_size, b_lines, b_size )
+
+ test_assert_part(part_root, FLAGS_MULTIPART, 5, 2, 45, 21, 256);
+ test_assert(part_root->parent == NULL);
+
+ struct message_part *part_1 = part_root->children;
+ test_assert_part(part_1, FLAGS_MULTIPART, 3, 2, 45, 11, 137);
+
+ struct message_part *part_1_1 = part_1->children;
+ test_assert_part(part_1_1, FLAGS_RFC822, 1, 2, 30, 2, 34);
+
+ struct message_part *part_1_1_1 = part_1_1->children;
+ test_assert_part(part_1_1_1, MESSAGE_PART_FLAG_IS_MIME, 0, 2, 26, 0, 8);
+
+ test_assert(part_1_1_1->next == NULL);
+
+ struct message_part *part_1_2 = part_1_1->next;
+ test_assert_part(part_1_2, MESSAGE_PART_FLAG_IS_MIME, 0, 2, 30, 2, 34);
+
+ test_assert(part_1_2->next == NULL);
+
+ struct message_part *part_2 = part_1->next;
+ test_assert_part(part_2, MESSAGE_PART_FLAG_IS_MIME, 0, 2, 30, 3, 35);
+
+ test_assert(part_2->next == NULL);
+
+ test_assert(part_root->next == NULL);
+
+ test_parsed_parts(input, part_root);
+ i_stream_unref(&input);
+ pool_unref(&pool);
+ test_end();
+}
+
int main(void)
{
static void (*const test_functions[])(void) = {
@@ -1392,6 +1544,8 @@ int main(void)
test_message_parser_mime_part_limit_rfc822,
test_message_parser_mime_version,
test_message_parser_mime_version_missing,
+ test_message_parser_too_many_header_bytes_default,
+ test_message_parser_too_many_header_bytes_100,
NULL
};
return test_run(test_functions);

@ -1,9 +0,0 @@
#Type Name ID GECOS Home directory Shell
g dovecot 97
u dovecot 97 "Dovecot IMAP server" /usr/libexec/dovecot /sbin/nologin
m dovecot dovecot
g dovenull -
u dovenull - "Dovecot - unauthorized user" /usr/libexec/dovecot /sbin/nologin
m dovenull dovenull

@ -1,28 +1,26 @@
%global __provides_exclude_from %{_docdir}
%global __requires_exclude_from %{_docdir}
Summary: Secure imap and pop3 server
Name: dovecot
Epoch: 1
Version: 2.3.16
%global prever %{nil}
Release: 11%{?dist}.1
Release: 5%{?dist}
#dovecot itself is MIT, a few sources are PD, pigeonhole is LGPLv2
License: MIT and LGPLv2
Group: System Environment/Daemons
URL: https://www.dovecot.org/
Source: https://www.dovecot.org/releases/2.3/%{name}-%{version}%{?prever}.tar.gz
URL: http://www.dovecot.org/
Source: http://www.dovecot.org/releases/2.3/%{name}-%{version}%{?prever}.tar.gz
Source1: dovecot.init
Source2: dovecot.pam
%global pigeonholever 0.5.16
Source8: https://pigeonhole.dovecot.org/releases/2.3/dovecot-2.3-pigeonhole-%{pigeonholever}.tar.gz
Source8: http://pigeonhole.dovecot.org/releases/2.3/dovecot-2.3-pigeonhole-%{pigeonholever}.tar.gz
Source9: dovecot.sysconfig
Source10: dovecot.tmpfilesd
#our own
Source14: dovecot.conf.5
Source15: prestartscript
Source16: dovecot.sysusers
# 3x Fedora/RHEL specific
Patch1: dovecot-2.0-defaultconfig.patch
@ -34,65 +32,50 @@ Patch6: dovecot-2.1.10-waitonline.patch
Patch8: dovecot-2.2.20-initbysystemd.patch
Patch9: dovecot-2.2.22-systemd_w_protectsystem.patch
Patch15: dovecot-2.3.11-bigkey.patch
# sent upstream, rhbz#1630380
Patch11: dovecot-2.2.36-aclfix.patch
Patch13: dovecot-2.2.36-bigkey.patch
# do not use own implementation of HMAC, use OpenSSL for certification purposes
# not sent upstream as proper fix would use dovecot's lib-dcrypt but it introduces
# hard to break circular dependency between lib and lib-dcrypt
Patch16: dovecot-2.3.6-opensslhmac.patch
Patch17: dovecot-2.3.14-opensslv3.patch
Patch14: dovecot-2.3.6-opensslhmac.patch
# FTBFS
Patch18: dovecot-2.3.15-fixvalcond.patch
Patch19: dovecot-2.3.15-valbasherr.patch
Patch20: dovecot-2.3.16-ftbfsbigend.patch
# from upstream, for dovecot < 2.3.17, s390x FTBFS fix
Patch15: dovecot-2.3.16-ftbfsbigend.patch
Patch16: dovecot-2.3.16-keeplzma.patch
# from upstream, for <= 2.3.19.1, rhbz#2106232
Patch21: dovecot-2.3.19.1-7bad6a24.patch
Patch17: dovecot-2.3.19.1-7bad6a24.patch
# from upstream, for < 2.3.19.1, rhbz#2128857
Patch22: dovecot-2.3.18-bdf447e4.patch
Patch23: dovecot-2.3.18-9f300239..4596d399.patch
# from upstream, for < 2.3.21, RHEL-25434
Patch24: dovecot-2.3.16-d7705bc6.patch
Patch18: dovecot-2.3.18-9f300239..4596d399.patch
Patch19: dovecot-2.3.18-bdf447e4.patch
# fix test failing due to too long path with all the mock path prefixes
Patch27: dovecot-2.3.21-test-socket-path.patch
# from upstream, for < 2.3.21, RHEL-22854
Patch20: dovecot-2.3.16-d7705bc6.patch
# from upstream for < 2.3.21.1, RHEL-55211
# https://github.com/dovecot/core/compare/8e4c42d%5E...1481c04.patch
Patch28: dovecot-2.3.21.1-CVE-2024-23184.patch
# from upstream for < 2.3.21.1, RHEL-55225
# https://github.com/dovecot/core/compare/f020e13%5E...ce88c33.patch
Patch29: dovecot-2.3.21.1-CVE-2024-23185.patch
Source15: prestartscript
BuildRequires: gcc, gcc-c++, openssl-devel, pam-devel, zlib-devel, bzip2-devel, libcap-devel
BuildRequires: openssl-devel, pam-devel, zlib-devel, bzip2-devel, libcap-devel
BuildRequires: libtool, autoconf, automake, pkgconfig
BuildRequires: sqlite-devel
BuildRequires: libpq-devel
BuildRequires: postgresql-devel
#BuildRequires: libpq-devel
BuildRequires: mariadb-connector-c-devel
BuildRequires: libxcrypt-devel
#BuildRequires: libxcrypt-devel
BuildRequires: openldap-devel
BuildRequires: krb5-devel
BuildRequires: quota-devel
BuildRequires: rpcgen
BuildRequires: xz-devel
BuildRequires: lz4-devel
BuildRequires: libzstd-devel
%if %{?rhel}0 == 0
BuildRequires: libsodium-devel
%endif
BuildRequires: libicu-devel
BuildRequires: libexttextcat-devel
BuildRequires: libstemmer-devel
BuildRequires: multilib-rpm-config
BuildRequires: flex, bison
BuildRequires: systemd-devel
# for dovecot.sysusers
BuildRequires: systemd-rpm-macros
#BuildRequires: libsodium-devel
#BuildRequires: libexttextcat-devel
#BuildRequires: libstemmer-devel
# gettext-devel is needed for running autoconf because of the
# presence of AM_ICONV
@ -103,19 +86,33 @@ Requires: openssl >= 0.9.7f-4
# Package includes an initscript service file, needs to require initscripts package
Requires(pre): shadow-utils
%if %{?fedora}0 > 140 || %{?rhel}0 > 60
Requires: systemd
Requires(post): systemd-units
Requires(preun): systemd-units
Requires(postun): systemd-units
%else
Requires: initscripts
Requires(post): chkconfig
Requires(preun): chkconfig initscripts
Requires(postun): initscripts
%endif
%if %{?fedora}0 > 150 || %{?rhel}0 >60
#clucene in fedora <=15 and rhel<=6 is too old
BuildRequires: clucene-core-devel
%endif
%global ssldir %{_sysconfdir}/pki/%{name}
%if %{?fedora}00%{?rhel} < 6
%global _initddir %{_initrddir}
BuildRequires: curl-devel expat-devel
%else
BuildRequires: libcurl-devel expat-devel
BuildRequires: make
%endif
%global restart_flag /run/%{name}/%{name}-restart-after-rpm-install
%global restart_flag /var/run/%{name}/%{name}-restart-after-rpm-install
%description
Dovecot is an IMAP server for Linux/UNIX-like systems, written with security
@ -127,6 +124,7 @@ The SQL drivers and authentication plug-ins are in their subpackages.
%package pigeonhole
Requires: %{name} = %{epoch}:%{version}-%{release}
Summary: Sieve and managesieve plug-in for dovecot
Group: System Environment/Daemons
License: MIT and LGPLv2
%description pigeonhole
@ -135,18 +133,21 @@ This package provides sieve and managesieve plug-in for dovecot LDA.
%package pgsql
Requires: %{name} = %{epoch}:%{version}-%{release}
Summary: Postgres SQL back end for dovecot
Group: System Environment/Daemons
%description pgsql
This package provides the Postgres SQL back end for dovecot-auth etc.
%package mysql
Requires: %{name} = %{epoch}:%{version}-%{release}
Summary: MySQL back end for dovecot
Group: System Environment/Daemons
%description mysql
This package provides the MySQL back end for dovecot-auth etc.
%package devel
Requires: %{name} = %{epoch}:%{version}-%{release}
Summary: Development files for dovecot
Group: Development/Libraries
%description devel
This package provides the development files for dovecot.
@ -158,26 +159,19 @@ This package provides the development files for dovecot.
%patch -P 6 -p1 -b .waitonline
%patch -P 8 -p1 -b .initbysystemd
%patch -P 9 -p1 -b .systemd_w_protectsystem
%patch -P 15 -p1 -b .bigkey
%patch -P 16 -p1 -b .opensslhmac
%patch -P 17 -p1 -b .opensslv3
%patch -P 18 -p1 -b .fixvalcond
%patch -P 19 -p1 -b .valbasherr
%patch -P 20 -p1 -b .ftbfsbigend
%patch -P 21 -p1 -b .7bad6a24
%patch -P 22 -p1 -b .bdf447e4
%patch -P 24 -p1 -b .d7705bc6
%patch -P 27 -p1 -b .test-socket-path
%patch -P 28 -p1 -b .CVE-2024-23184
%patch -P 29 -p1 -b .CVE-2024-23185
cp run-test-valgrind.supp dovecot-2.3-pigeonhole-%{pigeonholever}/
# valgrind would fail with shell wrapper
echo "testsuite" >dovecot-2.3-pigeonhole-%{pigeonholever}/run-test-valgrind.exclude
%patch -P 11 -p1 -b .aclfix
%patch -P 13 -p1 -b .bigkey
%patch -P 14 -p1 -b .opensslhmac
%patch -P 15 -p1 -b .ftbfsbigend
%patch -P 16 -p1 -b .keeplzma
%patch -P 17 -p1 -b .7bad6a24
%patch -P 19 -p1 -b .bdf447e4
%patch -P 20 -p1 -b .d7705bc6
pushd dovecot-2*3-pigeonhole-%{pigeonholever}
%patch -P 23 -p1 -b .9f300239..4596d399
%patch -P 18 -p1 -b .9f300239..4596d399
popd
sed -i '/DEFAULT_INCLUDES *=/s|$| '"$(pkg-config --cflags libclucene-core)|" src/plugins/fts-lucene/Makefile.in
%build
@ -185,8 +179,11 @@ sed -i '/DEFAULT_INCLUDES *=/s|$| '"$(pkg-config --cflags libclucene-core)|" src
%global _hardened_build 1
export CFLAGS="%{__global_cflags} -fno-strict-aliasing -fstack-reuse=none"
export LDFLAGS="-Wl,-z,now -Wl,-z,relro %{?__global_ldflags}"
# el6 autoconf too old to regen; use packaged files (#1082384)
%if %{?fedora}00%{?rhel} > 6
mkdir -p m4
autoreconf -I . -fiv #required for aarch64 support
%endif
%configure \
INSTALL_DATA="install -c -p -m644" \
--with-rundir=%{_rundir}/%{name} \
@ -204,18 +201,17 @@ autoreconf -I . -fiv #required for aarch64 support
--with-mysql \
--with-sqlite \
--with-zlib \
--with-zstd \
--with-libcap \
--with-icu \
--with-lucene \
--with-ssl=openssl \
--with-ssldir=%{ssldir} \
--with-solr \
--with-systemdsystemunitdir=%{_unitdir} \
--with-docs
sed -i 's|/etc/ssl|/etc/pki/dovecot|' doc/mkcert.sh doc/example-config/conf.d/10-ssl.conf
%make_build
make %{?_smp_mflags}
#pigeonhole
pushd dovecot-2*3-pigeonhole-%{pigeonholever}
@ -230,13 +226,13 @@ pushd dovecot-2*3-pigeonhole-%{pigeonholever}
--with-dovecot=../ \
--without-unfinished-features
%make_build
make %{?_smp_mflags}
popd
%install
rm -rf $RPM_BUILD_ROOT
%make_install
make install DESTDIR=$RPM_BUILD_ROOT
# move doc dir back to build dir so doc macro in files section can use it
mv $RPM_BUILD_ROOT/%{_docdir}/%{name} %{_builddir}/%{name}-%{version}%{?prever}/docinstall
@ -245,13 +241,17 @@ mv $RPM_BUILD_ROOT/%{_docdir}/%{name} %{_builddir}/%{name}-%{version}%{?prever}/
%multilib_fix_c_header --file %{_includedir}/dovecot/config.h
pushd dovecot-2*3-pigeonhole-%{pigeonholever}
%make_install
make install DESTDIR=$RPM_BUILD_ROOT
mv $RPM_BUILD_ROOT/%{_docdir}/%{name} $RPM_BUILD_ROOT/%{_docdir}/%{name}-pigeonhole
install -m 644 AUTHORS ChangeLog COPYING COPYING.LGPL INSTALL NEWS README $RPM_BUILD_ROOT/%{_docdir}/%{name}-pigeonhole
popd
%if %{?fedora}00%{?rhel} < 6
sed -i 's|password-auth|system-auth|' %{SOURCE2}
%endif
install -p -D -m 644 %{SOURCE2} $RPM_BUILD_ROOT%{_sysconfdir}/pam.d/dovecot
#install man pages
@ -260,8 +260,6 @@ install -p -D -m 644 %{SOURCE14} $RPM_BUILD_ROOT%{_mandir}/man5/dovecot.conf.5
#install waitonline script
install -p -D -m 755 %{SOURCE15} $RPM_BUILD_ROOT%{_libexecdir}/dovecot/prestartscript
install -p -D -m 0644 %{SOURCE16} $RPM_BUILD_ROOT%{_sysusersdir}/dovecot.sysusers
# generate ghost .pem files
mkdir -p $RPM_BUILD_ROOT%{ssldir}/certs
mkdir -p $RPM_BUILD_ROOT%{ssldir}/private
@ -270,9 +268,14 @@ chmod 600 $RPM_BUILD_ROOT%{ssldir}/certs/dovecot.pem
touch $RPM_BUILD_ROOT%{ssldir}/private/dovecot.pem
chmod 600 $RPM_BUILD_ROOT%{ssldir}/private/dovecot.pem
%if %{?fedora}0 > 140 || %{?rhel}0 > 60
install -p -D -m 644 %{SOURCE10} $RPM_BUILD_ROOT%{_tmpfilesdir}/dovecot.conf
%else
install -p -D -m 755 %{SOURCE1} $RPM_BUILD_ROOT%{_initddir}/dovecot
install -p -D -m 600 %{SOURCE9} $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig/dovecot
%endif
mkdir -p $RPM_BUILD_ROOT/run/dovecot/{login,empty,token-login}
mkdir -p $RPM_BUILD_ROOT/var/run/dovecot/{login,empty,token-login}
# Install dovecot configuration and dovecot-openssl.cnf
mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/dovecot/conf.d
@ -299,64 +302,79 @@ popd
%pre
#dovecot uid and gid are reserved, see /usr/share/doc/setup-*/uidgid
%sysusers_create_compat %{SOURCE16}
getent group dovecot >/dev/null || groupadd -r --gid 97 dovecot
getent passwd dovecot >/dev/null || \
useradd -r --uid 97 -g dovecot -d /usr/libexec/dovecot -s /sbin/nologin -c "Dovecot IMAP server" dovecot
if [ -z "$LEAPP_IPU_IN_PROGRESS" ]
then
# during LEAPP upgrade, services are not running anyway
getent group dovenull >/dev/null || groupadd -r dovenull
getent passwd dovenull >/dev/null || \
useradd -r -g dovenull -d /usr/libexec/dovecot -s /sbin/nologin -c "Dovecot's unauthorized user" dovenull
# do not let dovecot run during upgrade rhbz#134325
if [ "$1" = "2" ]; then
rm -f %restart_flag
%if %{?fedora}0 > 140 || %{?rhel}0 > 60
/bin/systemctl is-active %{name}.service >/dev/null 2>&1 && touch %restart_flag ||:
/bin/systemctl stop %{name}.service >/dev/null 2>&1
fi
%else
/sbin/service %{name} status >/dev/null 2>&1 && touch %restart_flag ||:
/sbin/service %{name} stop >/dev/null 2>&1
%endif
fi
%post
if [ $1 -eq 1 ]
then
%if %{?fedora}0 > 140 || %{?rhel}0 > 60
%systemd_post dovecot.service
%else
/sbin/chkconfig --add %{name}
%endif
fi
install -d -m 0755 -g dovecot -d /run/dovecot
install -d -m 0755 -d /run/dovecot/empty
install -d -m 0750 -g dovenull -d /run/dovecot/login
install -d -m 0750 -g dovenull -d /run/dovecot/token-login
[ -x /sbin/restorecon ] && /sbin/restorecon -R /run/dovecot ||:
install -d -m 0755 -g dovecot -d /var/run/dovecot
install -d -m 0755 -d /var/run/dovecot/empty
install -d -m 0750 -g dovenull -d /var/run/dovecot/login
install -d -m 0750 -g dovenull -d /var/run/dovecot/token-login
[ -x /sbin/restorecon ] && /sbin/restorecon -R /var/run/dovecot ||:
%preun
if [ $1 = 0 ]; then
%if %{?fedora}0 > 140 || %{?rhel}0 > 60
/bin/systemctl disable dovecot.service dovecot.socket >/dev/null 2>&1 || :
/bin/systemctl stop dovecot.service dovecot.socket >/dev/null 2>&1 || :
rm -rf /run/dovecot
%else
/sbin/service %{name} stop > /dev/null 2>&1
/sbin/chkconfig --del %{name}
%endif
rm -rf /var/run/dovecot
fi
%postun
if [ -z "$LEAPP_IPU_IN_PROGRESS" ]
then
# during LEAPP upgrade, services are not running anyway
%if %{?fedora}0 > 140 || %{?rhel}0 > 60
/bin/systemctl daemon-reload >/dev/null 2>&1 || :
%endif
if [ "$1" -ge "1" -a -e %restart_flag ]; then
%if %{?fedora}0 > 140 || %{?rhel}0 > 60
/bin/systemctl start dovecot.service >/dev/null 2>&1 || :
%else
/sbin/service %{name} start >/dev/null 2>&1 || :
%endif
rm -f %restart_flag
fi
fi
%posttrans
if [ -z "$LEAPP_IPU_IN_PROGRESS" ]
then
# during LEAPP upgrade, services are not running anyway
# dovecot should be started again in %%postun, but it's not executed on reinstall
# if it was already started, restart_flag won't be here, so it's ok to test it again
if [ -e %restart_flag ]; then
%if %{?fedora}0 > 140 || %{?rhel}0 > 60
/bin/systemctl start dovecot.service >/dev/null 2>&1 || :
%else
/sbin/service %{name} start >/dev/null 2>&1 || :
%endif
rm -f %restart_flag
fi
fi
%check
make check
@ -373,11 +391,15 @@ make check
%{_bindir}/dovecot-sysreport
%if %{?fedora}0 > 140 || %{?rhel}0 > 60
%_tmpfilesdir/dovecot.conf
%{_sysusersdir}/dovecot.sysusers
%{_unitdir}/dovecot.service
%{_unitdir}/dovecot-init.service
%{_unitdir}/dovecot.socket
%else
%{_initddir}/dovecot
%attr(0600,root,root) %config(noreplace) %{_sysconfdir}/sysconfig/dovecot
%endif
%dir %{_sysconfdir}/dovecot
%dir %{_sysconfdir}/dovecot/conf.d
@ -448,10 +470,10 @@ make check
%{_libexecdir}/%{name}
%exclude %{_libexecdir}/%{name}/managesieve*
%dir %attr(0755,root,dovecot) %ghost /run/dovecot
%attr(0750,root,dovenull) %ghost /run/dovecot/login
%attr(0750,root,dovenull) %ghost /run/dovecot/token-login
%attr(0755,root,root) %ghost /run/dovecot/empty
%dir %attr(0755,root,dovecot) %ghost /var/run/dovecot
%attr(0750,root,dovenull) %ghost /var/run/dovecot/login
%attr(0750,root,dovenull) %ghost /var/run/dovecot/token-login
%attr(0755,root,root) %ghost /var/run/dovecot/empty
%attr(0750,dovecot,dovecot) /var/lib/dovecot
@ -509,257 +531,116 @@ make check
%{_libdir}/%{name}/dict/libdriver_pgsql.so
%changelog
* Mon Sep 02 2024 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.16-11.1
- fix CVE-2024-23184: using a large number of address headers may trigger a denial of service (RHEL-55211)
- fix CVE-2024-23185: very large headers can cause resource exhaustion when parsing message (RHEL-55225)
* Fri Feb 16 2024 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.16-11
- fixes assert-crash when IMAP client uses QRESYNC (#RHEL-25434)
* Tue Aug 15 2023 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.16-10
- fix leaking mailboxes if virtual mailbox can't be opened (#2231408)
* Sat May 27 2023 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.16-9
- add buildrequire of rpcgen to enable rquota support(#2157045)
* Tue Sep 13 2022 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.16-8
- do not run systemd commands during leapp upgrade (#2119385)
* Tue Jul 12 2022 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.16-7
- fix possible privilege escalation when similar master and non-master passdbs are used (#2106232)
* Fri Mar 29 2024 MSVSphere Packaging Team <packager@msvsphere-os.ru> - 1:2.3.16-5
- Rebuilt for MSVSphere 8.10 beta
* Wed Jul 06 2022 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.16-6
- fix possible nonzero return value of postinst script(#2053368)
* Fri Feb 16 2024 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.16-5
- fixes assert-crash when IMAP client uses QRESYNC (#RHEL-22854)
* Tue Jul 05 2022 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.16-5
- workaround sysuers macro defficiency (#2095399)
* Fri Aug 04 2023 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.16-4
- fix leaking mailboxes if virtual mailbox can't be opened (#2128857)
* Tue Jul 05 2022 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.16-4
- use systemd-sysusers for user creation (#2095399)
* Tue Jul 19 2022 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.16-3
- fix possible privilege escalation when similar master and non-master passdbs are used (#2106231)
* Wed Nov 03 2021 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.16-3
- re-enable LTO build (#1990080)
* Wed Dec 08 2021 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.16-2
- do not disable xz/lzma for now despite being deprecated
* Wed Oct 27 2021 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.16-2
- set first_valid_uid to 1000 to match system default (#2009716)
* Fri Aug 20 2021 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.16-1
* Wed Dec 08 2021 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.16-1
- dovecot updated to 2.3.16, pigeonhole to 0.5.16
- fixes several regressions (#1997583)
* Mon Aug 09 2021 Mohan Boddu <mboddu@redhat.com> - 1:2.3.15-2
- Rebuilt for IMA sigs, glibc 2.34, aarch64 flags
Related: rhbz#1991688
* Wed Jul 21 2021 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.15-1
- dovecot updated to 2.3.15, pigeonhole updated to 0.5.15
- CVE-2021-29157: Dovecot does not correctly escape kid and azp fields in
JWT tokens. This may be used to supply attacker controlled keys to
validate tokens, if attacker has local access (#1979833)
- CVE-2021-33515: On-path attacker could have injected plaintext commands
before STARTTLS negotiation that would be executed after STARTTLS
finished with the client
- Add TSLv1.3 support to min_protocols.
* Wed Jul 14 2021 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.14-5
- fix mail storage block count parsing (#1974281)
* Wed Jun 16 2021 Mohan Boddu <mboddu@redhat.com> - 1:2.3.14-4
- Rebuilt for RHEL 9 BETA for openssl 3.0
Related: rhbz#1971065
* Fri Jun 04 2021 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.14-3
- compatibility with openssl 3.0 (#1962035)
* Thu Apr 15 2021 Mohan Boddu <mboddu@redhat.com> - 1:2.3.14-2
- Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937
* Mon Mar 22 2021 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.14-1
- dovecot updated to 2.3.14, pigeonhole to 0.5.14
- use OpenSSL's implementation of HMAC
- Remove autocreate, expire, snarf and mail-filter plugins.
- Remove cydir storage driver.
- Remove XZ/LZMA write support. Read support will be removed in future release.
* Mon Feb 08 2021 Pavel Raiskup <praiskup@redhat.com> - 1:2.3.13-7
- rebuild for libpq ABI fix rhbz#1908268
* Mon Feb 01 2021 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.13-6
- use make macros
* Tue Jan 26 2021 Fedora Release Engineering <releng@fedoraproject.org> - 1:2.3.13-5
- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild
* Mon Jan 18 2021 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.13-4
- fix multilib issues
* Mon Jan 18 2021 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.13-3
- bump release and rebuild
* Thu Jan 07 2021 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.13-2
- fix rundir location
* Wed Jan 06 2021 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.13-1
- fix release number
* Mon Jan 04 2021 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.13-0
- dovecot updated to 2.3.13, pigeonhole to 0.5.13
- CVE-2020-24386: Specially crafted command can cause IMAP hibernate to
allow logged in user to access other people's emails and filesystem
information.
- Metric filter and global event filter variable syntax changed to a
SQL-like format.
- auth: Added new aliases for %{variables}. Usage of the old ones is
possible, but discouraged.
- auth: Removed RPA auth mechanism, SKEY auth mechanism, NTLM auth
mechanism and related password schemes.
- auth: Removed passdb-sia, passdb-vpopmail and userdb-vpopmail.
- auth: Removed postfix postmap socket
* Wed Oct 21 2020 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.11.3-7
- change run directory from /var/run to /run (#1777922)
* Wed Oct 21 2020 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.11.3-6
- use bigger default key size (#1882939)
* Wed Sep 02 2020 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.11.3-5
- fix gssapi issue
* Wed Aug 26 2020 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.11.3-4
- fix FTBFS on 32bit systems
* Mon Aug 17 2020 Jeff Law <law@redhat.com> - 1:2.3.11.3-2
- Disable LTO
* Sat Aug 15 2020 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.11.3-1
- CVE-2020-12100: Parsing mails with a large number of MIME parts could
have resulted in excessive CPU usage or a crash due to running out of
stack memory.
- CVE-2020-12673: Dovecot's NTLM implementation does not correctly check
message buffer size, which leads to reading past allocation which can
lead to crash.
- CVE-2020-10967: lmtp/submission: Issuing the RCPT command with an
address that has the empty quoted string as local-part causes the lmtp
service to crash.
- CVE-2020-12674: Dovecot's RPA mechanism implementation accepts
zero-length message, which leads to assert-crash later on.
* Sat Aug 01 2020 Fedora Release Engineering <releng@fedoraproject.org> - 1:2.3.10.1-3
- Second attempt - Rebuilt for
https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
* Mon Jul 27 2020 Fedora Release Engineering <releng@fedoraproject.org> - 1:2.3.10.1-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
* Mon May 18 2020 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.10.1-1
- dovecot updated to 2.3.10.1
- fixes CVE-2020-10967, CVE-2020-10958, CVE-2020-10957
* Tue Apr 21 2020 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.10-1
- dovecot updated to 2.3.10, pigeonhole updated to 0.5.10
* Wed Feb 12 2020 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.9.3-1
- dovecot updated to 2.3.9.3
- fixes CVE-2020-7046: Truncated UTF-8 can be used to DoS
submission-login and lmtp processes.
- fixes CVE-2020-7957: Specially crafted mail can crash snippet generation.
* Tue Jan 28 2020 Fedora Release Engineering <releng@fedoraproject.org> - 1:2.3.9.2-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild
- fix CVE-2021-33515 plaintext commands injection (#1980014)
* Thu Dec 19 2019 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.9.2-1
- CVE-2019-19722: Mails with group addresses in From or To fields
caused crash in push notification drivers.
* Wed Dec 04 2019 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.9-1
- dovecot updated to 2.3.9, pigeonhole updated to 0.5.9
* Thu Oct 10 2019 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.8-1
- dovecot updated to 2.3.8, pigeonhole 0.5.8
* Thu Aug 29 2019 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.7.2-1
- dovecot updated to 2.3.7.2, pigeonhole 0.5.7.2
- fixes CVE-2019-11500: IMAP protocol parser does not properly handle NUL byte
when scanning data in quoted strings, leading to out of bounds heap
memory writes
* Wed Feb 03 2021 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.8-9
- fix CVE-2020-24386 IMAP hibernation function allows mail access (#1913534)
* Mon Aug 19 2019 Michal Hlavinka <mhlavink@redhat.com> - 1:1-2.3.7.1
- dovecot updated to 2.3.7.1, pigeonhole updated to 0.5.7.1
* Tue Jan 12 2021 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.8-8
- fix CVE-2020-25275 denial of service via mail MIME parsing (#1914019)
* Wed Jul 24 2019 Fedora Release Engineering <releng@fedoraproject.org> - 1:2.3.6-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild
* Thu Jan 07 2021 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.8-7
- change run directory from /var/run to /run (#1805947)
* Fri May 31 2019 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.6-3
- disable gcc 9 stack reuse temporarily
* Wed Dec 02 2020 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.8-6
- fix mail storage block count parsing (#1894418)
- MIME parser crashed when boundaries were wrong (#1888111)
* Mon May 13 2019 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.6-2
- use /run instead of /var/run (#1706372)
* Mon Nov 02 2020 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.8-5
- multilib compatibility (#1853137)
* Thu May 02 2019 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.6-1
- dovecot updated to 2.3.6, pigeonhole updated to 0.5.6
* Fri Aug 07 2020 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.8-4
- fix CVE-2020-12100 resource exhaustion via deeply nested MIME parts (#1866756)
- fix CVE-2020-12673 out of bound reads in dovecot NTLM implementation (#1866761)
- fix CVE-2020-12674 crash due to assert in RPA implementation (#1866768)
* Thu Apr 18 2019 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.5.2-1
- dovecot updated to 2.3.5.2
- fixes CVE-2019-10691: Trying to login with 8bit username containing
invalid UTF8 input causes auth process to crash if auth policy is enabled.
* Mon Jun 01 2020 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.8-3
- fix CVE-2020-10957 dovecot: malformed NOOP commands leads to DoS (#1840354)
- fix CVE-2020-10958 dovecot: command followed by sufficient number of newlines
leads to use-after-free (#1840357)
- fix CVE-2020-10967 dovecot: sending mail with empty quoted localpart
leads to DoS (#1840356)
* Thu Mar 28 2019 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.5.1-1
- dovecot updated to 2.3.5.1
- CVE-2019-7524: Missing input buffer size validation leads into
arbitrary buffer overflow when reading fts or pop3 uidl header
from Dovecot index.
* Thu Jan 09 2020 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.8-2
- fix default attributes for ghost files
* Wed Mar 06 2019 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.5-1
- dovecot updated to 2.3.5, pigeonhole updated to 0.5.5
* Tue Nov 19 2019 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.8-1
- dovecot updated to 2.3.8 with pigeonhole updated to 0.5.8 (#1653117)
* Thu Jan 31 2019 Fedora Release Engineering <releng@fedoraproject.org> - 1:2.3.4-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild
* Mon Jan 14 2019 Björn Esser <besser82@fedoraproject.org> - 1:2.3.4-2
- Rebuilt for libcrypt.so.2 (#1666033)
* Thu Aug 29 2019 Michal Hlavinka <mhlavink@redhat.com> - 1:2.2.36-10
- fix CVE-2019-11500: IMAP protocol parser does not properly handle NUL byte
when scanning data in quoted strings, leading to out of bounds heap
memory writes (#1741788)
* Wed Jan 09 2019 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.4-1
- dovecot updated to 2.3.4, pigeonhole updated to 0.5.4
* Fri Aug 23 2019 Michal Hlavinka <mhlavink@redhat.com> - 1:2.2.36-9
- reset errno before iterating through users (#1630410)
* Tue Oct 02 2018 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.3-1
- dovecot updated to 2.3.3, pigeonhole pdated to 0.5.3
- doveconf hides more secrets now in the default output
- NUL bytes in mail headers can cause truncated replies when fetched.
- virtual plugin: Some searches used 100% CPU for many seconds
- dsync assert-crashed with acl plugin in some situations.
- imapc: Fixed various assert-crashes when reconnecting to server.
* Mon Jun 17 2019 Michal Hlavinka <mhlavink@redhat.com> - 1:2.2.36-8
- fix CVE-2019-3814: improper certificate validation (#1674370)
* Fri Jun 14 2019 Michal Hlavinka <mhlavink@redhat.com> - 1:2.2.36-7
- do not print error message when restorecon is not present
during install (#1626395)
- change default config to use minimal UID = 1000 (#1630410)
* Tue Oct 02 2018 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.2.1-4
- fix dovecot-init service syntax error (#1635017)
* Mon Jun 10 2019 Michal Hlavinka <mhlavink@redhat.com> - 1:2.2.36-6
- use OpenSSl implementation of HMAC, disable CRAM-MD5 when FIPS is enabled (#1618749)
* Mon Aug 13 2018 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.2.1-3
- do not try to generate ssl-params as its obsolete (#1614640)
* Tue Oct 16 2018 Michal Hlavinka <mhlavink@redhat.com> - 1:2.2.36-5
- make key not that bigger (#1618714)
* Thu Jul 12 2018 Fedora Release Engineering <releng@fedoraproject.org> - 1:2.3.2.1-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild
* Tue Oct 16 2018 Michal Hlavinka <mhlavink@redhat.com> - 1:2.2.36-4
- generated key was too small (#1618714)
* Tue Jul 10 2018 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.2.1-1
- SSL/TLS servers may have crashed during client disconnection
* Wed Sep 19 2018 Michal Hlavinka <mhlavink@redhat.com> - 1:2.2.36-3
- fix global ACL directory configuration search path (#1630383)
- update first/last_valid_gid range patch (#1630410)
* Mon Jul 09 2018 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.2-1
- dovecot updated to 2.3.2, pigeonhole to 0.5.2
* Mon Jul 30 2018 Michal Hlavinka <mhlavink@redhat.com> - 1:2.2.36-2
- fix defaut permissions of gost run files
* Wed Mar 28 2018 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.1-2
- fix ftbfs - murmurhash3 check fail
* Thu Jun 28 2018 Michal Hlavinka <mhlavink@redhat.com> - 1:2.2.36-1
- dovecot updated to 2.2.36, pigeonhole to 0.4.24
* Wed Mar 28 2018 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.1-1
- dovecot updated to 2.3.1, pigeonhole updated to 0.5.1
* Thu May 24 2018 Michal Hlavinka <mhlavink@redhat.com> - 1:2.2.35-3
- disable tcp_wrappers as it's not available in rhel8
* Tue Mar 27 2018 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.0.1-3
- use libxcrypt for Fedora >= 28, part of ftbfs fix (#1548520)
* Thu Apr 19 2018 Michal Hlavinka <mhlavink@redhat.com> - 1:2.2.35-2
- include crypt.h explicitely
* Wed Mar 07 2018 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.0.1-2
- add gcc buildrequire
* Wed Mar 21 2018 Michal Hlavinka <mhlavink@redhat.com> - 1:2.2.35-1
- dovecot updated to 2.2.35, pigeonhole updated to 0.4.23
* Thu Mar 01 2018 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.0.1-1
- dovecot updated to 2.3.0.1, pigeonhole updated to 0.5.0.1
* Thu Mar 01 2018 Michal Hlavinka <mhlavink@redhat.com> - 1:2.2.34-1
- dovecot updated to 2.2.34, pigeonhole updated to 0.4.22
- fixes CVE-2017-15130: TLS SNI config lookups may lead to excessive
memory usage, causing imap-login/pop3-login VSZ limit to be reached
and the process restarted. This happens only if Dovecot config has
local_name { } or local { } configuration blocks and attacker uses
randomly generated SNI servernames.
- fixes CVE-2017-14461: Parsing invalid email addresses may cause a crash or
leak memory contents to attacker. For example, these memory contents
might contain parts of an email from another user if the same imap
process is reused for multiple users.
- fixes CVE-2017-15132: Aborted SASL authentication leaks memory in login
process.
* Fri Feb 09 2018 Igor Gnatenko <ignatenkobrain@fedoraproject.org> - 1:2.2.33.2-5
- Escape macros in %%changelog

Loading…
Cancel
Save