Compare commits

...

No commits in common. "imports/c8-beta/dovecot-2.3.16-3.el8" and "c8" have entirely different histories.

7 changed files with 2130 additions and 13 deletions

View File

@ -0,0 +1,17 @@
diff --git a/src/lib-index/mail-index-sync.c b/src/lib-index/mail-index-sync.c
index 6322ee1869..c847f1cc01 100644
--- a/src/lib-index/mail-index-sync.c
+++ b/src/lib-index/mail-index-sync.c
@@ -544,6 +544,12 @@ static bool mail_index_sync_view_have_any(struct mail_index_view *view,
return TRUE;
mail_transaction_log_get_head(view->index->log, &log_seq, &log_offset);
+ if (log_seq < view->map->hdr.log_file_seq ||
+ ((log_seq == view->map->hdr.log_file_seq &&
+ log_offset < view->map->hdr.log_file_tail_offset))) {
+ /* invalid offsets - let the syncing handle the error */
+ return TRUE;
+ }
if (mail_transaction_log_view_set(view->log_view,
view->map->hdr.log_file_seq,
view->map->hdr.log_file_tail_offset,

View File

@ -0,0 +1,578 @@
From 9f3002393fe1c1fe317121d03591569dac120739 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan.bosch@open-xchange.com>
Date: Tue, 17 Aug 2021 19:09:13 +0200
Subject: [PATCH 01/12] lib-sieve: sieve-interpreter - Fix field mixup in debug
message.
---
src/lib-sieve/sieve-interpreter.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/lib-sieve/sieve-interpreter.c b/src/lib-sieve/sieve-interpreter.c
index 9ee6c659..274e142d 100644
--- a/src/lib-sieve/sieve-interpreter.c
+++ b/src/lib-sieve/sieve-interpreter.c
@@ -1003,8 +1003,8 @@ int sieve_interpreter_continue(struct sieve_interpreter *interp,
}
e_debug(e->event(), "Finished running script `%s' "
"(status=%s, resource usage: %s)",
- sieve_execution_exitcode_to_str(ret),
sieve_binary_source(interp->runenv.sbin),
+ sieve_execution_exitcode_to_str(ret),
sieve_resource_usage_get_summary(&interp->rusage));
interp->running = FALSE;
}
From 54e020c1212f626049bffc6c6fea8e606a893af2 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan.bosch@open-xchange.com>
Date: Wed, 18 Aug 2021 01:44:23 +0200
Subject: [PATCH 02/12] lib-sieve: sieve-result - Remove success parameter from
sieve_result_implicit_keep_execute().
---
src/lib-sieve/sieve-result.c | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)
diff --git a/src/lib-sieve/sieve-result.c b/src/lib-sieve/sieve-result.c
index 55eb9f54..d3f2f925 100644
--- a/src/lib-sieve/sieve-result.c
+++ b/src/lib-sieve/sieve-result.c
@@ -1475,8 +1475,7 @@ void sieve_result_execution_destroy(struct sieve_result_execution **_rexec)
}
static void
-sieve_result_implicit_keep_execute(struct sieve_result_execution *rexec,
- bool success)
+sieve_result_implicit_keep_execute(struct sieve_result_execution *rexec)
{
const struct sieve_action_exec_env *aenv = &rexec->action_env;
struct sieve_result *result = aenv->result;
@@ -1486,6 +1485,7 @@ sieve_result_implicit_keep_execute(struct sieve_result_execution *rexec,
struct sieve_action_execution *aexec_keep = &rexec->keep;
struct sieve_result_action *ract_keep = &rexec->keep_action;
struct sieve_action *act_keep = &ract_keep->action;
+ bool success = (rexec->status == SIEVE_EXEC_OK);
if (rexec->keep_equiv_action != NULL) {
e_debug(rexec->event, "No implicit keep needed "
@@ -1579,8 +1579,8 @@ sieve_result_implicit_keep_execute(struct sieve_result_execution *rexec,
}
}
- e_debug(rexec->event, "Execute implicit keep (failure=%s)",
- (!success ? "yes" : "no"));
+ e_debug(rexec->event, "Execute implicit keep (status=%s)",
+ sieve_execution_exitcode_to_str(rexec->status));
/* Initialize side effects */
sieve_action_execution_add_side_effects(rexec, aexec_keep, ract_keep);
@@ -1633,7 +1633,7 @@ sieve_result_implicit_keep_finalize(struct sieve_result_execution *rexec,
/* Start keep if necessary */
if (act_keep->def == NULL ||
aexec_keep->state != SIEVE_ACTION_EXECUTION_STATE_EXECUTED) {
- sieve_result_implicit_keep_execute(rexec, success);
+ sieve_result_implicit_keep_execute(rexec);
/* Switch to failure keep if necessary. */
} else if (rexec->keep_success && !success){
e_debug(rexec->event, "Switch to failure implicit keep");
@@ -1645,7 +1645,7 @@ sieve_result_implicit_keep_finalize(struct sieve_result_execution *rexec,
i_zero(aexec_keep);
/* Start failure keep action. */
- sieve_result_implicit_keep_execute(rexec, success);
+ sieve_result_implicit_keep_execute(rexec);
}
if (act_keep->def == NULL)
return rexec->keep_status;
@@ -1931,10 +1931,8 @@ int sieve_result_execute(struct sieve_result_execution *rexec, int status,
/* Execute implicit keep if the transaction failed or when the
implicit keep was not canceled during transaction.
*/
- if (rexec->status != SIEVE_EXEC_OK || rexec->keep_implicit) {
- sieve_result_implicit_keep_execute(
- rexec, (rexec->status == SIEVE_EXEC_OK));
- }
+ if (rexec->status != SIEVE_EXEC_OK || rexec->keep_implicit)
+ sieve_result_implicit_keep_execute(rexec);
}
/* Transaction commit/rollback */
From 291f2fdb77b86db566dca7c028dd93fc741f6b31 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan.bosch@open-xchange.com>
Date: Wed, 18 Aug 2021 01:40:57 +0200
Subject: [PATCH 03/12] lib-sieve: sieve-result - Remove success parameter from
sieve_result_implicit_keep_finalize().
---
src/lib-sieve/sieve-result.c | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/src/lib-sieve/sieve-result.c b/src/lib-sieve/sieve-result.c
index d3f2f925..3cf2c02a 100644
--- a/src/lib-sieve/sieve-result.c
+++ b/src/lib-sieve/sieve-result.c
@@ -1603,8 +1603,7 @@ sieve_result_implicit_keep_execute(struct sieve_result_execution *rexec)
}
static int
-sieve_result_implicit_keep_finalize(struct sieve_result_execution *rexec,
- bool success)
+sieve_result_implicit_keep_finalize(struct sieve_result_execution *rexec)
{
const struct sieve_action_exec_env *aenv = &rexec->action_env;
const struct sieve_execute_env *eenv = aenv->exec_env;
@@ -1612,6 +1611,7 @@ sieve_result_implicit_keep_finalize(struct sieve_result_execution *rexec,
struct sieve_result_action *ract_keep = &rexec->keep_action;
struct sieve_action *act_keep = &ract_keep->action;
int commit_status = SIEVE_EXEC_OK;
+ bool success = (rexec->status == SIEVE_EXEC_OK);
if (rexec->keep_equiv_action != NULL) {
struct sieve_action_execution *ke_aexec =
@@ -1627,8 +1627,8 @@ sieve_result_implicit_keep_finalize(struct sieve_result_execution *rexec,
return rexec->keep_status;
}
- e_debug(rexec->event, "Finalize implicit keep (failure=%s)",
- (!success ? "yes" : "no"));
+ e_debug(rexec->event, "Finalize implicit keep (status=%s)",
+ sieve_execution_exitcode_to_str(rexec->status));
/* Start keep if necessary */
if (act_keep->def == NULL ||
@@ -1950,8 +1950,7 @@ int sieve_result_execute(struct sieve_result_execution *rexec, int status,
implicit keep was not canceled during transaction.
*/
if (rexec->status != SIEVE_EXEC_OK || rexec->keep_implicit) {
- ret = sieve_result_implicit_keep_finalize(
- rexec, (rexec->status == SIEVE_EXEC_OK));
+ ret = sieve_result_implicit_keep_finalize(rexec);
switch (ret) {
case SIEVE_EXEC_OK:
if (result_status == SIEVE_EXEC_TEMP_FAILURE)
From 10e347e3c9eb5e7bf5bc6f178389005357f527fe Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan.bosch@open-xchange.com>
Date: Wed, 18 Aug 2021 02:07:01 +0200
Subject: [PATCH 04/12] lib-sieve: sieve-result - Move temp failure status
checks into sieve_result_implicit_keep_execute().
---
src/lib-sieve/sieve-result.c | 38 ++++++++++++++++++++++++------------
1 file changed, 26 insertions(+), 12 deletions(-)
diff --git a/src/lib-sieve/sieve-result.c b/src/lib-sieve/sieve-result.c
index 3cf2c02a..44afeef7 100644
--- a/src/lib-sieve/sieve-result.c
+++ b/src/lib-sieve/sieve-result.c
@@ -934,6 +934,7 @@ struct sieve_result_execution {
bool keep_success:1;
bool keep_explicit:1;
bool keep_implicit:1;
+ bool keep_finalizing:1;
bool seen_delivery:1;
bool executed:1;
bool executed_delivery:1;
@@ -1485,7 +1486,24 @@ sieve_result_implicit_keep_execute(struct sieve_result_execution *rexec)
struct sieve_action_execution *aexec_keep = &rexec->keep;
struct sieve_result_action *ract_keep = &rexec->keep_action;
struct sieve_action *act_keep = &ract_keep->action;
- bool success = (rexec->status == SIEVE_EXEC_OK);
+ bool success = FALSE;
+
+ switch (rexec->status) {
+ case SIEVE_EXEC_OK:
+ success = TRUE;
+ break;
+ case SIEVE_EXEC_TEMP_FAILURE:
+ case SIEVE_EXEC_RESOURCE_LIMIT:
+ if (rexec->executed)
+ break;
+ if (rexec->committed)
+ break;
+ if (rexec->keep_finalizing)
+ break;
+ return;
+ default:
+ break;
+ }
if (rexec->keep_equiv_action != NULL) {
e_debug(rexec->event, "No implicit keep needed "
@@ -1630,6 +1648,8 @@ sieve_result_implicit_keep_finalize(struct sieve_result_execution *rexec)
e_debug(rexec->event, "Finalize implicit keep (status=%s)",
sieve_execution_exitcode_to_str(rexec->status));
+ rexec->keep_finalizing = TRUE;
+
/* Start keep if necessary */
if (act_keep->def == NULL ||
aexec_keep->state != SIEVE_ACTION_EXECUTION_STATE_EXECUTED) {
@@ -1923,17 +1943,11 @@ int sieve_result_execute(struct sieve_result_execution *rexec, int status,
return rexec->status;
}
- /* Execute implicit keep if necessary */
-
- if (rexec->executed ||
- (rexec->status != SIEVE_EXEC_TEMP_FAILURE &&
- rexec->status != SIEVE_EXEC_RESOURCE_LIMIT)) {
- /* Execute implicit keep if the transaction failed or when the
- implicit keep was not canceled during transaction.
- */
- if (rexec->status != SIEVE_EXEC_OK || rexec->keep_implicit)
- sieve_result_implicit_keep_execute(rexec);
- }
+ /* Execute implicit keep if the transaction failed or when the
+ implicit keep was not canceled during transaction.
+ */
+ if (rexec->status != SIEVE_EXEC_OK || rexec->keep_implicit)
+ sieve_result_implicit_keep_execute(rexec);
/* Transaction commit/rollback */
From c84e6e5d8d1d8b03a0ba5958804d200c6e1916d8 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan.bosch@open-xchange.com>
Date: Wed, 18 Aug 2021 02:26:32 +0200
Subject: [PATCH 05/12] lib-sieve: sieve-result - Move temp failure status
checks into sieve_result_implicit_keep_finalize().
---
src/lib-sieve/sieve-result.c | 56 +++++++++++++++++++++---------------
1 file changed, 33 insertions(+), 23 deletions(-)
diff --git a/src/lib-sieve/sieve-result.c b/src/lib-sieve/sieve-result.c
index 44afeef7..10cc3b95 100644
--- a/src/lib-sieve/sieve-result.c
+++ b/src/lib-sieve/sieve-result.c
@@ -1629,7 +1629,20 @@ sieve_result_implicit_keep_finalize(struct sieve_result_execution *rexec)
struct sieve_result_action *ract_keep = &rexec->keep_action;
struct sieve_action *act_keep = &ract_keep->action;
int commit_status = SIEVE_EXEC_OK;
- bool success = (rexec->status == SIEVE_EXEC_OK);
+ bool success = FALSE;
+
+ switch (rexec->status) {
+ case SIEVE_EXEC_OK:
+ success = TRUE;
+ break;
+ case SIEVE_EXEC_TEMP_FAILURE:
+ case SIEVE_EXEC_RESOURCE_LIMIT:
+ if (rexec->committed)
+ break;
+ return rexec->status;
+ default:
+ break;
+ }
if (rexec->keep_equiv_action != NULL) {
struct sieve_action_execution *ke_aexec =
@@ -1957,32 +1970,29 @@ int sieve_result_execute(struct sieve_result_execution *rexec, int status,
/* Commit implicit keep if necessary */
result_status = rexec->status;
- if (rexec->committed ||
- (rexec->status != SIEVE_EXEC_TEMP_FAILURE &&
- rexec->status != SIEVE_EXEC_RESOURCE_LIMIT)) {
- /* Commit implicit keep if the transaction failed or when the
- implicit keep was not canceled during transaction.
- */
- if (rexec->status != SIEVE_EXEC_OK || rexec->keep_implicit) {
- ret = sieve_result_implicit_keep_finalize(rexec);
- switch (ret) {
- case SIEVE_EXEC_OK:
- if (result_status == SIEVE_EXEC_TEMP_FAILURE)
- result_status = SIEVE_EXEC_FAILURE;
+
+ /* Commit implicit keep if the transaction failed or when the
+ implicit keep was not canceled during transaction.
+ */
+ if (rexec->status != SIEVE_EXEC_OK || rexec->keep_implicit) {
+ ret = sieve_result_implicit_keep_finalize(rexec);
+ switch (ret) {
+ case SIEVE_EXEC_OK:
+ if (result_status == SIEVE_EXEC_TEMP_FAILURE)
+ result_status = SIEVE_EXEC_FAILURE;
+ break;
+ case SIEVE_EXEC_TEMP_FAILURE:
+ if (!rexec->committed) {
+ result_status = ret;
break;
- case SIEVE_EXEC_TEMP_FAILURE:
- if (!rexec->committed) {
- result_status = ret;
- break;
- }
- /* fall through */
- default:
- result_status = SIEVE_EXEC_KEEP_FAILED;
}
+ /* fall through */
+ default:
+ result_status = SIEVE_EXEC_KEEP_FAILED;
}
- if (rexec->status == SIEVE_EXEC_OK)
- rexec->status = result_status;
}
+ if (rexec->status == SIEVE_EXEC_OK)
+ rexec->status = result_status;
/* Finish execution */
From 92b4b06d5d8deeefdd17d5fb18d7f0d23e8e414b Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan.bosch@open-xchange.com>
Date: Wed, 18 Aug 2021 02:46:18 +0200
Subject: [PATCH 06/12] lib-sieve: sieve-result - Skip implicit keep in
execution stage upon temp failure.
It will be executed in the commit phase if necessary; don't do it early; it will
only be rolled back.
---
src/lib-sieve/sieve-result.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/lib-sieve/sieve-result.c b/src/lib-sieve/sieve-result.c
index 10cc3b95..82354831 100644
--- a/src/lib-sieve/sieve-result.c
+++ b/src/lib-sieve/sieve-result.c
@@ -1494,8 +1494,6 @@ sieve_result_implicit_keep_execute(struct sieve_result_execution *rexec)
break;
case SIEVE_EXEC_TEMP_FAILURE:
case SIEVE_EXEC_RESOURCE_LIMIT:
- if (rexec->executed)
- break;
if (rexec->committed)
break;
if (rexec->keep_finalizing)
From f2b81cc6ebaa3001bde693f7abdb990f467f7831 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan.bosch@open-xchange.com>
Date: Wed, 18 Aug 2021 02:56:32 +0200
Subject: [PATCH 07/12] lib-sieve: sieve-result - Fix handling of resource
limit status after implicit keep commit.
---
src/lib-sieve/sieve-result.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/lib-sieve/sieve-result.c b/src/lib-sieve/sieve-result.c
index 82354831..96582075 100644
--- a/src/lib-sieve/sieve-result.c
+++ b/src/lib-sieve/sieve-result.c
@@ -1980,6 +1980,7 @@ int sieve_result_execute(struct sieve_result_execution *rexec, int status,
result_status = SIEVE_EXEC_FAILURE;
break;
case SIEVE_EXEC_TEMP_FAILURE:
+ case SIEVE_EXEC_RESOURCE_LIMIT:
if (!rexec->committed) {
result_status = ret;
break;
From 293f0027106a725e4cbcf56b673f1eedda00c317 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan.bosch@open-xchange.com>
Date: Wed, 18 Aug 2021 02:54:25 +0200
Subject: [PATCH 08/12] lib-sieve: sieve-result - Fix resource leak occurring
when implicit keep is executed before temporary failure at commit.
In the commit phase the implicit keep was never finalized, meaning that it was
not rolled back and thus not cleaned up properly. This leads to a memory leak
and a mailbox reference leak. This in turn causes an assert crash at the end
of delivery when the mail user is destroyed.
---
src/lib-sieve/sieve-result.c | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/src/lib-sieve/sieve-result.c b/src/lib-sieve/sieve-result.c
index 96582075..10ea349c 100644
--- a/src/lib-sieve/sieve-result.c
+++ b/src/lib-sieve/sieve-result.c
@@ -1627,7 +1627,7 @@ sieve_result_implicit_keep_finalize(struct sieve_result_execution *rexec)
struct sieve_result_action *ract_keep = &rexec->keep_action;
struct sieve_action *act_keep = &ract_keep->action;
int commit_status = SIEVE_EXEC_OK;
- bool success = FALSE;
+ bool success = FALSE, temp_failure = FALSE;
switch (rexec->status) {
case SIEVE_EXEC_OK:
@@ -1637,7 +1637,15 @@ sieve_result_implicit_keep_finalize(struct sieve_result_execution *rexec)
case SIEVE_EXEC_RESOURCE_LIMIT:
if (rexec->committed)
break;
- return rexec->status;
+
+ if (aexec_keep->state !=
+ SIEVE_ACTION_EXECUTION_STATE_EXECUTED)
+ return rexec->status;
+ /* Roll back for temporary failure when no other action
+ is committed. */
+ commit_status = rexec->status;
+ temp_failure = TRUE;
+ break;
default:
break;
}
@@ -1662,8 +1670,10 @@ sieve_result_implicit_keep_finalize(struct sieve_result_execution *rexec)
rexec->keep_finalizing = TRUE;
/* Start keep if necessary */
- if (act_keep->def == NULL ||
- aexec_keep->state != SIEVE_ACTION_EXECUTION_STATE_EXECUTED) {
+ if (temp_failure) {
+ rexec->keep_status = rexec->status;
+ } else if (act_keep->def == NULL ||
+ aexec_keep->state != SIEVE_ACTION_EXECUTION_STATE_EXECUTED) {
sieve_result_implicit_keep_execute(rexec);
/* Switch to failure keep if necessary. */
} else if (rexec->keep_success && !success){
From 81bd53d6c9fa14fc6b32304e49dddb8fd022de91 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan.bosch@open-xchange.com>
Date: Wed, 18 Aug 2021 13:29:41 +0200
Subject: [PATCH 09/12] lib-sieve: sieve-result - Assert that implicit keep is
executed in sieve_result_implicit_keep_finalize().
---
src/lib-sieve/sieve-result.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/lib-sieve/sieve-result.c b/src/lib-sieve/sieve-result.c
index 10ea349c..de97d6ae 100644
--- a/src/lib-sieve/sieve-result.c
+++ b/src/lib-sieve/sieve-result.c
@@ -1691,6 +1691,8 @@ sieve_result_implicit_keep_finalize(struct sieve_result_execution *rexec)
if (act_keep->def == NULL)
return rexec->keep_status;
+ i_assert(aexec_keep->state == SIEVE_ACTION_EXECUTION_STATE_EXECUTED);
+
/* Finalize keep action */
rexec->keep_status = sieve_result_action_commit_or_rollback(
rexec, aexec_keep, rexec->keep_status, &commit_status);
From dbf5b62ba82766a7d824e81005b2517d96984ef0 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan.bosch@open-xchange.com>
Date: Wed, 18 Aug 2021 02:43:05 +0200
Subject: [PATCH 10/12] lib-sieve: sieve-result - Add debug messages for temp
failure handling.
---
src/lib-sieve/sieve-result.c | 28 +++++++++++++++++++++++++---
1 file changed, 25 insertions(+), 3 deletions(-)
diff --git a/src/lib-sieve/sieve-result.c b/src/lib-sieve/sieve-result.c
index de97d6ae..c21c8017 100644
--- a/src/lib-sieve/sieve-result.c
+++ b/src/lib-sieve/sieve-result.c
@@ -1494,10 +1494,21 @@ sieve_result_implicit_keep_execute(struct sieve_result_execution *rexec)
break;
case SIEVE_EXEC_TEMP_FAILURE:
case SIEVE_EXEC_RESOURCE_LIMIT:
- if (rexec->committed)
+ if (rexec->committed) {
+ e_debug(rexec->event,
+ "Temporary failure occurred (status=%s), "
+ "but other actions were already committed: "
+ "execute failure implicit keep",
+ sieve_execution_exitcode_to_str(rexec->status));
break;
+ }
if (rexec->keep_finalizing)
break;
+
+ e_debug(rexec->event,
+ "Skip implicit keep for temporary failure "
+ "(state=execute, status=%s)",
+ sieve_execution_exitcode_to_str(rexec->status));
return;
default:
break;
@@ -1635,12 +1646,23 @@ sieve_result_implicit_keep_finalize(struct sieve_result_execution *rexec)
break;
case SIEVE_EXEC_TEMP_FAILURE:
case SIEVE_EXEC_RESOURCE_LIMIT:
- if (rexec->committed)
+ if (rexec->committed) {
+ e_debug(rexec->event,
+ "Temporary failure occurred (status=%s), "
+ "but other actions were already committed: "
+ "commit failure implicit keep",
+ sieve_execution_exitcode_to_str(rexec->status));
break;
+ }
if (aexec_keep->state !=
- SIEVE_ACTION_EXECUTION_STATE_EXECUTED)
+ SIEVE_ACTION_EXECUTION_STATE_EXECUTED) {
+ e_debug(rexec->event,
+ "Skip implicit keep for temporary failure "
+ "(state=commit, status=%s)",
+ sieve_execution_exitcode_to_str(rexec->status));
return rexec->status;
+ }
/* Roll back for temporary failure when no other action
is committed. */
commit_status = rexec->status;
From 65d771c15bf443690580dbb0643556794106522b Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan.bosch@open-xchange.com>
Date: Wed, 18 Aug 2021 13:26:26 +0200
Subject: [PATCH 11/12] lib-sieve: sieve-result - Indicate in
sieve_result_transaction_execute() debug message whether actions were
executed.
---
src/lib-sieve/sieve-result.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/lib-sieve/sieve-result.c b/src/lib-sieve/sieve-result.c
index c21c8017..6f3cb954 100644
--- a/src/lib-sieve/sieve-result.c
+++ b/src/lib-sieve/sieve-result.c
@@ -1796,10 +1796,11 @@ sieve_result_transaction_execute(struct sieve_result_execution *rexec,
}
e_debug(rexec->event, "Finished executing actions "
- "(status=%s, keep=%s)",
+ "(status=%s, keep=%s, executed=%s)",
sieve_execution_exitcode_to_str(status),
(rexec->keep_explicit ? "explicit" :
- (rexec->keep_implicit ? "implicit" : "none")));
+ (rexec->keep_implicit ? "implicit" : "none")),
+ (rexec->executed ? "yes" : "no"));
return status;
}
From 4596d39908a868783fae9a0c2fd264409c0aaa96 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan.bosch@open-xchange.com>
Date: Wed, 18 Aug 2021 13:27:50 +0200
Subject: [PATCH 12/12] lib-sieve: sieve-result - Indicate in
sieve_result_transaction_finalize() debug message whether actions were
committed.
---
src/lib-sieve/sieve-result.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/lib-sieve/sieve-result.c b/src/lib-sieve/sieve-result.c
index 6f3cb954..effd6f28 100644
--- a/src/lib-sieve/sieve-result.c
+++ b/src/lib-sieve/sieve-result.c
@@ -1859,10 +1859,11 @@ sieve_result_transaction_commit_or_rollback(
}
e_debug(rexec->event, "Finished finalizing actions "
- "(status=%s, keep=%s)",
+ "(status=%s, keep=%s, committed=%s)",
sieve_execution_exitcode_to_str(status),
(rexec->keep_explicit ? "explicit" :
- (rexec->keep_implicit ? "implicit" : "none")));
+ (rexec->keep_implicit ? "implicit" : "none")),
+ (rexec->committed ? "yes" : "no"));
return commit_status;
}

View File

@ -0,0 +1,31 @@
From bdf4474ed82aaf964e7d94e72ca56b496e3815f9 Mon Sep 17 00:00:00 2001
From: Timo Sirainen <timo.sirainen@open-xchange.com>
Date: Fri, 1 Oct 2021 15:08:45 +0300
Subject: [PATCH] virtual: Fix leaking mailboxes if virtual mailbox can't be
opened
Fixes also a crash at deinit:
Panic: file mail-user.c: line 232 (mail_user_deinit): assertion failed: ((*user)->refcount == 1)
---
src/plugins/virtual/virtual-storage.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/plugins/virtual/virtual-storage.c b/src/plugins/virtual/virtual-storage.c
index 2f31503d53..a0779cc186 100644
--- a/src/plugins/virtual/virtual-storage.c
+++ b/src/plugins/virtual/virtual-storage.c
@@ -495,12 +495,12 @@ static int virtual_mailbox_open(struct mailbox *box)
ret = virtual_mailboxes_open(mbox, box->flags);
array_pop_back(&mbox->storage->open_stack);
}
+ if (ret == 0)
+ ret = index_storage_mailbox_open(box, FALSE);
if (ret < 0) {
virtual_mailbox_close_internal(mbox);
return -1;
}
- if (index_storage_mailbox_open(box, FALSE) < 0)
- return -1;
mbox->virtual_ext_id =
mail_index_ext_register(mbox->box.index, "virtual", 0,

View File

@ -0,0 +1,22 @@
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"

View File

@ -0,0 +1,976 @@
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);
}

View File

@ -0,0 +1,459 @@
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);

View File

@ -5,7 +5,7 @@ Name: dovecot
Epoch: 1 Epoch: 1
Version: 2.3.16 Version: 2.3.16
%global prever %{nil} %global prever %{nil}
Release: 3%{?dist} Release: 6%{?dist}
#dovecot itself is MIT, a few sources are PD, pigeonhole is LGPLv2 #dovecot itself is MIT, a few sources are PD, pigeonhole is LGPLv2
License: MIT and LGPLv2 License: MIT and LGPLv2
Group: System Environment/Daemons Group: System Environment/Daemons
@ -50,6 +50,24 @@ Patch16: dovecot-2.3.16-keeplzma.patch
# from upstream, for <= 2.3.19.1, rhbz#2106232 # from upstream, for <= 2.3.19.1, rhbz#2106232
Patch17: dovecot-2.3.19.1-7bad6a24.patch Patch17: dovecot-2.3.19.1-7bad6a24.patch
# from upstream, for < 2.3.19.1, rhbz#2128857
Patch18: dovecot-2.3.18-9f300239..4596d399.patch
Patch19: dovecot-2.3.18-bdf447e4.patch
# from upstream, for < 2.3.21, RHEL-22854
Patch20: dovecot-2.3.16-d7705bc6.patch
# from upstream for < 2.3.21.1, RHEL-55206
# https://github.com/dovecot/core/compare/8e4c42d%5E...1481c04.patch
Patch21: dovecot-2.3.21.1-CVE-2024-23184.patch
# from upstream for < 2.3.21.1, RHEL-55219
# https://github.com/dovecot/core/compare/f020e13%5E...ce88c33.patch
Patch22: dovecot-2.3.21.1-CVE-2024-23185.patch
# fix test failing due to too long path with all the mock path prefixes
Patch23: dovecot-2.3.21-test-socket-path.patch
Source15: prestartscript Source15: prestartscript
BuildRequires: openssl-devel, pam-devel, zlib-devel, bzip2-devel, libcap-devel BuildRequires: openssl-devel, pam-devel, zlib-devel, bzip2-devel, libcap-devel
@ -145,19 +163,25 @@ This package provides the development files for dovecot.
%prep %prep
%setup -q -n %{name}-%{version}%{?prever} -a 8 %setup -q -n %{name}-%{version}%{?prever} -a 8
%patch1 -p1 -b .default-settings %patch -P 1 -p1 -b .default-settings
%patch2 -p1 -b .mkcert-permissions %patch -P 2 -p1 -b .mkcert-permissions
%patch3 -p1 -b .mkcert-paths %patch -P 3 -p1 -b .mkcert-paths
%patch6 -p1 -b .waitonline %patch -P 6 -p1 -b .waitonline
%patch8 -p1 -b .initbysystemd %patch -P 8 -p1 -b .initbysystemd
%patch9 -p1 -b .systemd_w_protectsystem %patch -P 9 -p1 -b .systemd_w_protectsystem
%patch11 -p1 -b .aclfix %patch -P 11 -p1 -b .aclfix
%patch13 -p1 -b .bigkey %patch -P 13 -p1 -b .bigkey
%patch14 -p1 -b .opensslhmac %patch -P 14 -p1 -b .opensslhmac
%patch15 -p1 -b .ftbfsbigend %patch -P 15 -p1 -b .ftbfsbigend
%patch16 -p1 -b .keeplzma %patch -P 16 -p1 -b .keeplzma
%patch17 -p1 -b .7bad6a24 %patch -P 17 -p1 -b .7bad6a24
%patch -P 19 -p1 -b .bdf447e4
%patch -P 20 -p1 -b .d7705bc6
%patch -P 21 -p1 -b .CVE-2024-23184
%patch -P 22 -p1 -b .CVE-2024-23185
%patch -P 23 -p1 -b .test-socket-path
pushd dovecot-2*3-pigeonhole-%{pigeonholever} pushd dovecot-2*3-pigeonhole-%{pigeonholever}
%patch -P 18 -p1 -b .9f300239..4596d399
popd popd
@ -520,6 +544,16 @@ make check
%{_libdir}/%{name}/dict/libdriver_pgsql.so %{_libdir}/%{name}/dict/libdriver_pgsql.so
%changelog %changelog
* Tue Aug 20 2024 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.16-6
- fix CVE-2024-23185: very large headers can cause resource exhaustion when parsing message (RHEL-55219)
- fix CVE-2024-23184: using a large number of address headers may trigger a denial of service (RHEL-55206)
* Fri Feb 16 2024 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.16-5
- fixes assert-crash when IMAP client uses QRESYNC (#RHEL-22854)
* 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 19 2022 Michal Hlavinka <mhlavink@redhat.com> - 1:2.3.16-3 * 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) - fix possible privilege escalation when similar master and non-master passdbs are used (#2106231)