webbuilder_pel7ppc64lebuilder0
3 years ago
29 changed files with 4191 additions and 82 deletions
@ -0,0 +1,10 @@ |
|||||||
|
diff -up dovecot-2.2.36/doc/dovecot-openssl.cnf.bigkey dovecot-2.2.36/doc/dovecot-openssl.cnf |
||||||
|
--- dovecot-2.2.36/doc/dovecot-openssl.cnf.bigkey 2017-06-23 13:18:28.000000000 +0200 |
||||||
|
+++ dovecot-2.2.36/doc/dovecot-openssl.cnf 2018-10-16 17:15:35.836205498 +0200 |
||||||
|
@@ -1,5 +1,5 @@ |
||||||
|
[ req ] |
||||||
|
-default_bits = 1024 |
||||||
|
+default_bits = 3072 |
||||||
|
encrypt_key = yes |
||||||
|
distinguished_name = req_dn |
||||||
|
x509_extensions = cert_type |
@ -0,0 +1,37 @@ |
|||||||
|
From 58ffd3e8a02e54fc98b6be78e02b0511ee9263eb Mon Sep 17 00:00:00 2001 |
||||||
|
From: Timo Sirainen <timo.sirainen@open-xchange.com> |
||||||
|
Date: Fri, 10 May 2019 19:24:51 +0300 |
||||||
|
Subject: [PATCH 1/2] lib-imap: Don't accept strings with NULs |
||||||
|
|
||||||
|
IMAP doesn't allow NULs except in binary literals. We'll still allow them |
||||||
|
in regular literals as well, but just not in strings. |
||||||
|
|
||||||
|
This fixes a bug with unescaping a string with NULs: str_unescape() could |
||||||
|
have been called for memory that points outside the allocated string, |
||||||
|
causing heap corruption. This could cause crashes or theoretically even |
||||||
|
result in remote code execution exploit. |
||||||
|
|
||||||
|
Found by Nick Roessler and Rafi Rubin |
||||||
|
--- |
||||||
|
src/lib-imap/imap-parser.c | 6 ++++++ |
||||||
|
1 file changed, 6 insertions(+) |
||||||
|
|
||||||
|
diff --git a/src/lib-imap/imap-parser.c b/src/lib-imap/imap-parser.c |
||||||
|
index dddf55189..f41668d7a 100644 |
||||||
|
--- a/src/lib-imap/imap-parser.c |
||||||
|
+++ b/src/lib-imap/imap-parser.c |
||||||
|
@@ -363,6 +363,11 @@ static bool imap_parser_read_string(struct imap_parser *parser, |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
+ if (data[i] == '\0') { |
||||||
|
+ parser->error = "NULs not allowed in strings"; |
||||||
|
+ return FALSE; |
||||||
|
+ } |
||||||
|
+ |
||||||
|
if (data[i] == '\\') { |
||||||
|
if (i+1 == data_size) { |
||||||
|
/* known data ends with '\' - leave it to |
||||||
|
-- |
||||||
|
2.11.0 |
||||||
|
|
@ -0,0 +1,33 @@ |
|||||||
|
From a56b0636b1bf9c7677c6fca9681f48752af700a1 Mon Sep 17 00:00:00 2001 |
||||||
|
From: Timo Sirainen <timo.sirainen@open-xchange.com> |
||||||
|
Date: Fri, 17 May 2019 10:33:53 +0300 |
||||||
|
Subject: [PATCH 2/2] lib-imap: Make sure str_unescape() won't be writing past |
||||||
|
allocated memory |
||||||
|
|
||||||
|
The previous commit should already prevent this, but this makes sure it |
||||||
|
can't become broken in the future either. It makes the performance a tiny |
||||||
|
bit worse, but that's not practically noticeable. |
||||||
|
--- |
||||||
|
src/lib-imap/imap-parser.c | 6 ++---- |
||||||
|
1 file changed, 2 insertions(+), 4 deletions(-) |
||||||
|
|
||||||
|
diff --git a/src/lib-imap/imap-parser.c b/src/lib-imap/imap-parser.c |
||||||
|
index f41668d7a..7f58d99e2 100644 |
||||||
|
--- a/src/lib-imap/imap-parser.c |
||||||
|
+++ b/src/lib-imap/imap-parser.c |
||||||
|
@@ -267,10 +267,8 @@ static void imap_parser_save_arg(struct imap_parser *parser, |
||||||
|
|
||||||
|
/* remove the escapes */ |
||||||
|
if (parser->str_first_escape >= 0 && |
||||||
|
- (parser->flags & IMAP_PARSE_FLAG_NO_UNESCAPE) == 0) { |
||||||
|
- /* -1 because we skipped the '"' prefix */ |
||||||
|
- (void)str_unescape(str + parser->str_first_escape-1); |
||||||
|
- } |
||||||
|
+ (parser->flags & IMAP_PARSE_FLAG_NO_UNESCAPE) == 0) |
||||||
|
+ (void)str_unescape(str); |
||||||
|
arg->_data.str = str; |
||||||
|
arg->str_len = strlen(str); |
||||||
|
break; |
||||||
|
-- |
||||||
|
2.11.0 |
||||||
|
|
@ -0,0 +1,36 @@ |
|||||||
|
From 7ce9990a5e6ba59e89b7fe1c07f574279aed922c Mon Sep 17 00:00:00 2001 |
||||||
|
From: Timo Sirainen <timo.sirainen@open-xchange.com> |
||||||
|
Date: Fri, 10 May 2019 19:43:55 +0300 |
||||||
|
Subject: [PATCH 1/2] lib-managesieve: Don't accept strings with NULs |
||||||
|
|
||||||
|
ManageSieve doesn't allow NULs in strings. |
||||||
|
|
||||||
|
This fixes a bug with unescaping a string with NULs: str_unescape() could |
||||||
|
have been called for memory that points outside the allocated string, |
||||||
|
causing heap corruption. This could cause crashes or theoretically even |
||||||
|
result in remote code execution exploit. |
||||||
|
|
||||||
|
Found by Nick Roessler and Rafi Rubin |
||||||
|
--- |
||||||
|
src/lib-managesieve/managesieve-parser.c | 5 +++++ |
||||||
|
1 file changed, 5 insertions(+) |
||||||
|
|
||||||
|
diff --git a/src/lib-managesieve/managesieve-parser.c b/src/lib-managesieve/managesieve-parser.c |
||||||
|
index d3eb2101..f5f9d323 100644 |
||||||
|
--- a/src/lib-managesieve/managesieve-parser.c |
||||||
|
+++ b/src/lib-managesieve/managesieve-parser.c |
||||||
|
@@ -258,6 +258,11 @@ managesieve_parser_read_string(struct managesieve_parser *parser, |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
+ if (data[i] == '\0') { |
||||||
|
+ parser->error = "NULs not allowed in strings"; |
||||||
|
+ return FALSE; |
||||||
|
+ } |
||||||
|
+ |
||||||
|
if (data[i] == '\\') { |
||||||
|
if (i+1 == data_size) { |
||||||
|
/* known data ends with '\' - leave it to |
||||||
|
-- |
||||||
|
2.11.0 |
||||||
|
|
@ -0,0 +1,33 @@ |
|||||||
|
From 4a299840cdb51f61f8d1ebc0210b19c40dfbc1cc Mon Sep 17 00:00:00 2001 |
||||||
|
From: Timo Sirainen <timo.sirainen@open-xchange.com> |
||||||
|
Date: Fri, 17 May 2019 10:39:25 +0300 |
||||||
|
Subject: [PATCH 2/2] lib-managesieve: Make sure str_unescape() won't be |
||||||
|
writing past allocated memory |
||||||
|
|
||||||
|
The previous commit should already prevent this, but this makes sure it |
||||||
|
can't become broken in the future either. It makes the performance a tiny |
||||||
|
bit worse, but that's not practically noticeable. |
||||||
|
--- |
||||||
|
src/lib-managesieve/managesieve-parser.c | 6 ++---- |
||||||
|
1 file changed, 2 insertions(+), 4 deletions(-) |
||||||
|
|
||||||
|
diff --git a/src/lib-managesieve/managesieve-parser.c b/src/lib-managesieve/managesieve-parser.c |
||||||
|
index f5f9d323..dc7d1fa9 100644 |
||||||
|
--- a/src/lib-managesieve/managesieve-parser.c |
||||||
|
+++ b/src/lib-managesieve/managesieve-parser.c |
||||||
|
@@ -169,10 +169,8 @@ static void managesieve_parser_save_arg(struct managesieve_parser *parser, |
||||||
|
|
||||||
|
/* remove the escapes */ |
||||||
|
if (parser->str_first_escape >= 0 && |
||||||
|
- (parser->flags & MANAGESIEVE_PARSE_FLAG_NO_UNESCAPE) == 0) { |
||||||
|
- /* -1 because we skipped the '"' prefix */ |
||||||
|
- str_unescape(str + parser->str_first_escape-1); |
||||||
|
- } |
||||||
|
+ (parser->flags & MANAGESIEVE_PARSE_FLAG_NO_UNESCAPE) == 0) |
||||||
|
+ (void)str_unescape(str); |
||||||
|
|
||||||
|
arg->_data.str = str; |
||||||
|
arg->str_len = strlen(str); |
||||||
|
-- |
||||||
|
2.11.0 |
||||||
|
|
@ -0,0 +1,69 @@ |
|||||||
|
From eb5ffe2641febe0fa5e9038f2e216c130e1e7519 Mon Sep 17 00:00:00 2001 |
||||||
|
From: Aki Tuomi <aki.tuomi@open-xchange.com> |
||||||
|
Date: Mon, 21 Jan 2019 11:36:30 +0200 |
||||||
|
Subject: [PATCH] login-common: Ensure we get username from certificate |
||||||
|
|
||||||
|
--- |
||||||
|
src/login-common/sasl-server.c | 42 ++++++++++++++++++++++++++++++++-- |
||||||
|
1 file changed, 40 insertions(+), 2 deletions(-) |
||||||
|
|
||||||
|
diff --git a/src/login-common/sasl-server.c b/src/login-common/sasl-server.c |
||||||
|
index a833c9a6d4..9465da9657 100644 |
||||||
|
--- a/src/login-common/sasl-server.c |
||||||
|
+++ b/src/login-common/sasl-server.c |
||||||
|
@@ -321,6 +321,37 @@ authenticate_callback(struct auth_client_request *request, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
+static bool get_cert_username(struct client *client, const char **username_r, |
||||||
|
+ const char **error_r) |
||||||
|
+{ |
||||||
|
+ /* no SSL */ |
||||||
|
+ if (client->ssl_proxy == NULL) { |
||||||
|
+ *username_r = NULL; |
||||||
|
+ return TRUE; |
||||||
|
+ } |
||||||
|
+ |
||||||
|
+ /* no client certificate */ |
||||||
|
+ if (!ssl_proxy_has_valid_client_cert(client->ssl_proxy)) { |
||||||
|
+ *username_r = NULL; |
||||||
|
+ return TRUE; |
||||||
|
+ } |
||||||
|
+ |
||||||
|
+ /* get peer name */ |
||||||
|
+ const char *username = ssl_proxy_get_peer_name(client->ssl_proxy); |
||||||
|
+ |
||||||
|
+ /* if we wanted peer name, but it was not there, fail */ |
||||||
|
+ if (client->set->auth_ssl_username_from_cert && |
||||||
|
+ (username == NULL || *username == '\0')) { |
||||||
|
+ if (client->set->auth_ssl_require_client_cert) { |
||||||
|
+ *error_r = "Missing username in certificate"; |
||||||
|
+ return FALSE; |
||||||
|
+ } |
||||||
|
+ } |
||||||
|
+ |
||||||
|
+ *username_r = username; |
||||||
|
+ return TRUE; |
||||||
|
+} |
||||||
|
+ |
||||||
|
void sasl_server_auth_begin(struct client *client, |
||||||
|
const char *service, const char *mech_name, |
||||||
|
const char *initial_resp_base64, |
||||||
|
@@ -359,8 +390,15 @@ void sasl_server_auth_begin(struct client *client, |
||||||
|
info.mech = mech->name; |
||||||
|
info.service = service; |
||||||
|
info.session_id = client_get_session_id(client); |
||||||
|
- info.cert_username = client->ssl_proxy == NULL ? NULL : |
||||||
|
- ssl_proxy_get_peer_name(client->ssl_proxy); |
||||||
|
+ if (client->set->auth_ssl_username_from_cert) { |
||||||
|
+ const char *error; |
||||||
|
+ if (!get_cert_username(client, &info.cert_username, &error)) { |
||||||
|
+ client_log_err(client, t_strdup_printf("Cannot get username " |
||||||
|
+ "from certificate: %s", error)); |
||||||
|
+ sasl_server_auth_failed(client, "Unable to validate certificate"); |
||||||
|
+ return; |
||||||
|
+ } |
||||||
|
+ } |
||||||
|
info.flags = client_get_auth_flags(client); |
||||||
|
info.local_ip = client->local_ip; |
||||||
|
info.remote_ip = client->ip; |
@ -0,0 +1,29 @@ |
|||||||
|
From 7525fece60f01b52deb13df3620976ee1d616837 Mon Sep 17 00:00:00 2001 |
||||||
|
From: Aki Tuomi <aki.tuomi@open-xchange.com> |
||||||
|
Date: Mon, 21 Jan 2019 10:54:06 +0200 |
||||||
|
Subject: [PATCH] auth: Fail authentication if certificate username was |
||||||
|
unexpectedly missing |
||||||
|
|
||||||
|
--- |
||||||
|
src/auth/auth-request-handler.c | 8 ++++++++ |
||||||
|
1 file changed, 8 insertions(+) |
||||||
|
|
||||||
|
diff --git a/src/auth/auth-request-handler.c b/src/auth/auth-request-handler.c |
||||||
|
index 617dc1883d..3044e94f91 100644 |
||||||
|
--- a/src/auth/auth-request-handler.c |
||||||
|
+++ b/src/auth/auth-request-handler.c |
||||||
|
@@ -560,6 +560,14 @@ bool auth_request_handler_auth_begin(struct auth_request_handler *handler, |
||||||
|
return TRUE; |
||||||
|
} |
||||||
|
|
||||||
|
+ if (request->set->ssl_require_client_cert && |
||||||
|
+ request->set->ssl_username_from_cert && |
||||||
|
+ !request->cert_username) { |
||||||
|
+ auth_request_handler_auth_fail(handler, request, |
||||||
|
+ "SSL certificate didn't contain username"); |
||||||
|
+ return TRUE; |
||||||
|
+ } |
||||||
|
+ |
||||||
|
/* Empty initial response is a "=" base64 string. Completely empty |
||||||
|
string shouldn't really be sent, but at least Exim does it, |
||||||
|
so just allow it for backwards compatibility.. */ |
@ -0,0 +1,22 @@ |
|||||||
|
From e5d428297d70e3ac8b6dfce7e0de182b86825082 Mon Sep 17 00:00:00 2001 |
||||||
|
From: Aki Tuomi <aki.tuomi@open-xchange.com> |
||||||
|
Date: Wed, 16 Jan 2019 18:28:57 +0200 |
||||||
|
Subject: [PATCH] auth: Do not import empty certificate username |
||||||
|
|
||||||
|
--- |
||||||
|
src/auth/auth-request.c | 2 +- |
||||||
|
1 file changed, 1 insertion(+), 1 deletion(-) |
||||||
|
|
||||||
|
diff --git a/src/auth/auth-request.c b/src/auth/auth-request.c |
||||||
|
index dd288b6d23..1cb665ec8c 100644 |
||||||
|
--- a/src/auth/auth-request.c |
||||||
|
+++ b/src/auth/auth-request.c |
||||||
|
@@ -445,7 +445,7 @@ bool auth_request_import_auth(struct auth_request *request, |
||||||
|
else if (strcmp(key, "valid-client-cert") == 0) |
||||||
|
request->valid_client_cert = TRUE; |
||||||
|
else if (strcmp(key, "cert_username") == 0) { |
||||||
|
- if (request->set->ssl_username_from_cert) { |
||||||
|
+ if (request->set->ssl_username_from_cert && *value != '\0') { |
||||||
|
/* get username from SSL certificate. it overrides |
||||||
|
the username given by the auth mechanism. */ |
||||||
|
request->user = p_strdup(request->pool, value); |
@ -0,0 +1,32 @@ |
|||||||
|
From fcd786753b2ba6b4fb82cc2affea8e0d61889c95 Mon Sep 17 00:00:00 2001 |
||||||
|
From: Timo Sirainen <timo.sirainen@open-xchange.com> |
||||||
|
Date: Mon, 4 Feb 2019 19:23:02 -0800 |
||||||
|
Subject: [PATCH] lib-storage: Fix buffer overflow when reading oversized |
||||||
|
hdr-pop3-uidl header |
||||||
|
|
||||||
|
--- |
||||||
|
src/lib-storage/index/index-pop3-uidl.c | 4 ++-- |
||||||
|
1 file changed, 2 insertions(+), 2 deletions(-) |
||||||
|
|
||||||
|
diff --git a/src/lib-storage/index/index-pop3-uidl.c b/src/lib-storage/index/index-pop3-uidl.c |
||||||
|
index 13b7363ef6..e537e9ff51 100644 |
||||||
|
--- a/src/lib-storage/index/index-pop3-uidl.c |
||||||
|
+++ b/src/lib-storage/index/index-pop3-uidl.c |
||||||
|
@@ -37,7 +37,7 @@ bool index_pop3_uidl_can_exist(struct mail *mail) |
||||||
|
/* this header isn't set yet */ |
||||||
|
return TRUE; |
||||||
|
} |
||||||
|
- memcpy(&uidl, data, size); |
||||||
|
+ memcpy(&uidl, data, sizeof(uidl)); |
||||||
|
return mail->uid <= uidl.max_uid_with_pop3_uidl; |
||||||
|
} |
||||||
|
|
||||||
|
@@ -95,7 +95,7 @@ void index_pop3_uidl_update_exists_finish(struct mailbox_transaction_context *tr |
||||||
|
|
||||||
|
/* check if we have already the same header */ |
||||||
|
if (size >= sizeof(uidl)) { |
||||||
|
- memcpy(&uidl, data, size); |
||||||
|
+ memcpy(&uidl, data, sizeof(uidl)); |
||||||
|
if (trans->highest_pop3_uidl_uid == uidl.max_uid_with_pop3_uidl) |
||||||
|
return; |
||||||
|
} |
@ -0,0 +1,22 @@ |
|||||||
|
From df17cee615377f2474c86eb6a5b3fe5caa8b70fe Mon Sep 17 00:00:00 2001 |
||||||
|
From: Timo Sirainen <timo.sirainen@open-xchange.com> |
||||||
|
Date: Mon, 4 Feb 2019 19:25:13 -0800 |
||||||
|
Subject: [PATCH] fts: Fix buffer overflow when reading oversized fts header |
||||||
|
|
||||||
|
--- |
||||||
|
src/plugins/fts/fts-api.c | 2 +- |
||||||
|
1 file changed, 1 insertion(+), 1 deletion(-) |
||||||
|
|
||||||
|
diff --git a/src/plugins/fts/fts-api.c b/src/plugins/fts/fts-api.c |
||||||
|
index 5a5b2a919e..4f8a1c125d 100644 |
||||||
|
--- a/src/plugins/fts/fts-api.c |
||||||
|
+++ b/src/plugins/fts/fts-api.c |
||||||
|
@@ -425,7 +425,7 @@ bool fts_index_get_header(struct mailbox *box, struct fts_index_header *hdr_r) |
||||||
|
i_zero(hdr_r); |
||||||
|
ret = FALSE; |
||||||
|
} else { |
||||||
|
- memcpy(hdr_r, data, data_size); |
||||||
|
+ memcpy(hdr_r, data, sizeof(*hdr_r)); |
||||||
|
ret = TRUE; |
||||||
|
} |
||||||
|
mail_index_view_close(&view); |
@ -0,0 +1,11 @@ |
|||||||
|
diff -up dovecot-2.2.36/dovecot.service.in.portreserve dovecot-2.2.36/dovecot.service.in |
||||||
|
--- dovecot-2.2.36/dovecot.service.in.portreserve 2019-08-13 13:16:17.660982741 +0200 |
||||||
|
+++ dovecot-2.2.36/dovecot.service.in 2019-08-13 13:16:17.664982728 +0200 |
||||||
|
@@ -13,6 +13,7 @@ After=local-fs.target network.target net |
||||||
|
[Service] |
||||||
|
Type=forking |
||||||
|
ExecStartPre=/usr/libexec/dovecot/prestartscript |
||||||
|
+ExecStartPre=-/usr/sbin/portrelease dovecot |
||||||
|
ExecStart=@sbindir@/dovecot |
||||||
|
PIDFile=@rundir@/master.pid |
||||||
|
ExecReload=@bindir@/doveadm reload |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,56 @@ |
|||||||
|
diff -up dovecot-2.3.8/dovecot-2.3-pigeonhole-0.5.8/src/lib-sieve/plugins/notify/ext-notify-common.c.CVE_2020_12100ph dovecot-2.3.8/dovecot-2.3-pigeonhole-0.5.8/src/lib-sieve/plugins/notify/ext-notify-common.c |
||||||
|
--- dovecot-2.3.8/dovecot-2.3-pigeonhole-0.5.8/src/lib-sieve/plugins/notify/ext-notify-common.c.CVE_2020_12100ph 2019-10-08 10:48:14.000000000 +0200 |
||||||
|
+++ dovecot-2.3.8/dovecot-2.3-pigeonhole-0.5.8/src/lib-sieve/plugins/notify/ext-notify-common.c 2020-08-07 16:42:56.515389867 +0200 |
||||||
|
@@ -148,6 +148,7 @@ static int cmd_notify_extract_body_text |
||||||
|
const char **body_text_r, size_t *body_size_r) |
||||||
|
{ |
||||||
|
const struct sieve_extension *this_ext = renv->oprtn->ext; |
||||||
|
+ const struct message_parser_settings parser_set = { .flags = 0 }; |
||||||
|
struct ext_notify_message_context *mctx; |
||||||
|
struct mail *mail = renv->msgdata->mail; |
||||||
|
struct message_parser_ctx *parser; |
||||||
|
@@ -181,7 +182,7 @@ static int cmd_notify_extract_body_text |
||||||
|
/* Initialize body decoder */ |
||||||
|
decoder = message_decoder_init(NULL, 0); |
||||||
|
|
||||||
|
- parser = message_parser_init(mctx->pool, input, 0, 0); |
||||||
|
+ parser = message_parser_init(mctx->pool, input, &parser_set); |
||||||
|
is_text = TRUE; |
||||||
|
save_body = FALSE; |
||||||
|
while ( (ret=message_parser_parse_next_block(parser, &block)) > 0 ) { |
||||||
|
diff -up dovecot-2.3.8/dovecot-2.3-pigeonhole-0.5.8/src/lib-sieve/sieve-message.c.CVE_2020_12100ph dovecot-2.3.8/dovecot-2.3-pigeonhole-0.5.8/src/lib-sieve/sieve-message.c |
||||||
|
--- dovecot-2.3.8/dovecot-2.3-pigeonhole-0.5.8/src/lib-sieve/sieve-message.c.CVE_2020_12100ph 2019-10-08 10:48:14.000000000 +0200 |
||||||
|
+++ dovecot-2.3.8/dovecot-2.3-pigeonhole-0.5.8/src/lib-sieve/sieve-message.c 2020-08-07 16:42:56.516389854 +0200 |
||||||
|
@@ -1077,10 +1077,10 @@ static int sieve_message_parts_add_missi |
||||||
|
struct sieve_message_context *msgctx = renv->msgctx; |
||||||
|
pool_t pool = msgctx->context_pool; |
||||||
|
struct mail *mail = sieve_message_get_mail(renv->msgctx); |
||||||
|
- enum message_parser_flags mparser_flags = |
||||||
|
- MESSAGE_PARSER_FLAG_INCLUDE_MULTIPART_BLOCKS; |
||||||
|
- enum message_header_parser_flags hparser_flags = |
||||||
|
- MESSAGE_HEADER_PARSER_FLAG_SKIP_INITIAL_LWSP; |
||||||
|
+ struct message_parser_settings parser_set = { |
||||||
|
+ .hdr_flags = MESSAGE_HEADER_PARSER_FLAG_SKIP_INITIAL_LWSP, |
||||||
|
+ .flags = MESSAGE_PARSER_FLAG_INCLUDE_MULTIPART_BLOCKS, |
||||||
|
+ }; |
||||||
|
ARRAY(struct sieve_message_header) headers; |
||||||
|
struct sieve_message_part *body_part, *header_part, *last_part; |
||||||
|
struct message_parser_ctx *parser; |
||||||
|
@@ -1117,7 +1117,7 @@ static int sieve_message_parts_add_missi |
||||||
|
if (iter_all) { |
||||||
|
t_array_init(&headers, 64); |
||||||
|
hdr_content = t_str_new(512); |
||||||
|
- hparser_flags |= MESSAGE_HEADER_PARSER_FLAG_CLEAN_ONELINE; |
||||||
|
+ parser_set.hdr_flags |= MESSAGE_HEADER_PARSER_FLAG_CLEAN_ONELINE; |
||||||
|
} else { |
||||||
|
i_zero(&headers); |
||||||
|
} |
||||||
|
@@ -1129,7 +1129,7 @@ static int sieve_message_parts_add_missi |
||||||
|
//parser = message_parser_init_from_parts(parts, input, |
||||||
|
// hparser_flags, mparser_flags); |
||||||
|
parser = message_parser_init(pool_datastack_create(), |
||||||
|
- input, hparser_flags, mparser_flags); |
||||||
|
+ input, &parser_set); |
||||||
|
while ( (ret=message_parser_parse_next_block |
||||||
|
(parser, &block)) > 0 ) { |
||||||
|
struct sieve_message_part **body_part_idx; |
@ -0,0 +1,121 @@ |
|||||||
|
diff -up dovecot-2.2.36/src/lib/array.h.CVE_2020_12100prereq dovecot-2.2.36/src/lib/array.h |
||||||
|
--- dovecot-2.2.36/src/lib/array.h.CVE_2020_12100prereq 2018-04-30 15:52:05.000000000 +0200 |
||||||
|
+++ dovecot-2.2.36/src/lib/array.h 2020-08-09 20:22:36.326347911 +0200 |
||||||
|
@@ -219,6 +219,15 @@ array_idx_i(const struct array *array, u |
||||||
|
i_assert(idx * array->element_size < array->buffer->used); |
||||||
|
return CONST_PTR_OFFSET(array->buffer->data, idx * array->element_size); |
||||||
|
} |
||||||
|
+ |
||||||
|
+#define array_front(array) array_idx(array, 0) |
||||||
|
+#define array_front_modifiable(array) array_idx_modifiable(array, 0) |
||||||
|
+#define array_back(array) array_idx(array, array_count(array)-1) |
||||||
|
+#define array_back_modifiable(array) array_idx_modifiable(array, array_count(array)-1) |
||||||
|
+#define array_pop_back(array) array_delete(array, array_count(array)-1, 1); |
||||||
|
+#define array_push_back(array, item) array_append(array, (item), 1) |
||||||
|
+#define array_pop_front(array) array_delete(array, 0, 1) |
||||||
|
+#define array_push_front(array, item) array_insert(array, 0, (item), 1) |
||||||
|
#define array_idx(array, idx) \ |
||||||
|
ARRAY_TYPE_CAST_CONST(array)array_idx_i(&(array)->arr, idx) |
||||||
|
|
||||||
|
diff -up dovecot-2.2.36/src/lib/buffer.c.CVE_2020_12100prereq dovecot-2.2.36/src/lib/buffer.c |
||||||
|
--- dovecot-2.2.36/src/lib/buffer.c.CVE_2020_12100prereq 2020-08-09 20:22:57.566465762 +0200 |
||||||
|
+++ dovecot-2.2.36/src/lib/buffer.c 2020-08-09 20:22:57.580465840 +0200 |
||||||
|
@@ -148,6 +148,10 @@ void buffer_free(buffer_t **_buf) |
||||||
|
{ |
||||||
|
struct real_buffer *buf = (struct real_buffer *)*_buf; |
||||||
|
|
||||||
|
+ |
||||||
|
+ if (buf == NULL) |
||||||
|
+ return; |
||||||
|
+ |
||||||
|
*_buf = NULL; |
||||||
|
if (buf->alloced) |
||||||
|
p_free(buf->pool, buf->w_buffer); |
||||||
|
diff -up dovecot-2.2.36/src/lib-mail/test-message-decoder.c.CVE_2020_12100prereq dovecot-2.2.36/src/lib-mail/test-message-decoder.c |
||||||
|
--- dovecot-2.2.36/src/lib-mail/test-message-decoder.c.CVE_2020_12100prereq 2018-04-30 15:52:05.000000000 +0200 |
||||||
|
+++ dovecot-2.2.36/src/lib-mail/test-message-decoder.c 2020-08-09 20:22:36.326347911 +0200 |
||||||
|
@@ -1,7 +1,8 @@ |
||||||
|
/* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */ |
||||||
|
|
||||||
|
#include "lib.h" |
||||||
|
-#include "buffer.h" |
||||||
|
+#include "str.h" |
||||||
|
+#include "istream.h" |
||||||
|
#include "charset-utf8.h" |
||||||
|
#include "message-parser.h" |
||||||
|
#include "message-header-decode.h" |
||||||
|
@@ -82,6 +83,66 @@ static void test_message_decoder(void) |
||||||
|
test_end(); |
||||||
|
} |
||||||
|
|
||||||
|
+static void test_message_decoder_multipart(void) |
||||||
|
+{ |
||||||
|
+ static const char test_message_input[] = |
||||||
|
+ "Content-Type: multipart/mixed; boundary=foo\n" |
||||||
|
+ "\n" |
||||||
|
+ "--foo\n" |
||||||
|
+ "Content-Transfer-Encoding: quoted-printable\n" |
||||||
|
+ "Content-Type: text/plain; charset=utf-8\n" |
||||||
|
+ "\n" |
||||||
|
+ "p=C3=A4iv=C3=A4=C3=A4\n" |
||||||
|
+ "\n" |
||||||
|
+ "--foo\n" |
||||||
|
+ "Content-Transfer-Encoding: base64\n" |
||||||
|
+ "Content-Type: text/plain; charset=utf-8\n" |
||||||
|
+ "\n" |
||||||
|
+ "ecO2dMOkIHZhYW4uCg== ignored\n" |
||||||
|
+ "--foo\n" |
||||||
|
+ "Content-Transfer-Encoding: base64\n" |
||||||
|
+ "Content-Type: text/plain; charset=utf-8\n" |
||||||
|
+ "\n" |
||||||
|
+ "?garbage\n" |
||||||
|
+ "--foo--\n"; |
||||||
|
+ struct message_parser_ctx *parser; |
||||||
|
+ struct message_decoder_context *decoder; |
||||||
|
+ struct message_part *parts; |
||||||
|
+ struct message_block input, output; |
||||||
|
+ struct istream *istream; |
||||||
|
+ string_t *str_out = t_str_new(20); |
||||||
|
+ int ret; |
||||||
|
+ |
||||||
|
+ test_begin("message decoder multipart"); |
||||||
|
+ |
||||||
|
+ istream = test_istream_create(test_message_input); |
||||||
|
+ parser = message_parser_init(pool_datastack_create(), istream, 0, 0); |
||||||
|
+ decoder = message_decoder_init(NULL, 0); |
||||||
|
+ |
||||||
|
+ test_istream_set_allow_eof(istream, FALSE); |
||||||
|
+ for (size_t i = 0; i < sizeof(test_message_input); i++) { |
||||||
|
+ if (i == sizeof(test_message_input)-1) |
||||||
|
+ test_istream_set_allow_eof(istream, TRUE); |
||||||
|
+ test_istream_set_size(istream, i); |
||||||
|
+ while ((ret = message_parser_parse_next_block(parser, &input)) > 0) { |
||||||
|
+ if (message_decoder_decode_next_block(decoder, &input, &output) && |
||||||
|
+ output.hdr == NULL && output.size > 0) |
||||||
|
+ str_append_data(str_out, output.data, output.size); |
||||||
|
+ } |
||||||
|
+ if (i == sizeof(test_message_input)-1) |
||||||
|
+ test_assert(ret == -1); |
||||||
|
+ else |
||||||
|
+ test_assert(ret == 0); |
||||||
|
+ } |
||||||
|
+ /* NOTE: qp-decoder decoder changes \n into \r\n */ |
||||||
|
+ test_assert_strcmp(str_c(str_out), "p\xC3\xA4iv\xC3\xA4\xC3\xA4\r\ny\xC3\xB6t\xC3\xA4 vaan.\n"); |
||||||
|
+ |
||||||
|
+ message_decoder_deinit(&decoder); |
||||||
|
+ message_parser_deinit(&parser, &parts); |
||||||
|
+ i_stream_unref(&istream); |
||||||
|
+ test_end(); |
||||||
|
+} |
||||||
|
+ |
||||||
|
static void test_message_decoder_current_content_type(void) |
||||||
|
{ |
||||||
|
struct message_decoder_context *ctx; |
||||||
|
@@ -149,6 +210,7 @@ int main(void) |
||||||
|
{ |
||||||
|
static void (*test_functions[])(void) = { |
||||||
|
test_message_decoder, |
||||||
|
+ //test_message_decoder_multipart, |
||||||
|
test_message_decoder_current_content_type, |
||||||
|
NULL |
||||||
|
}; |
@ -0,0 +1,34 @@ |
|||||||
|
From 1c6405d3026e5ceae3d214d63945bba85251af4c Mon Sep 17 00:00:00 2001 |
||||||
|
From: Aki Tuomi <aki.tuomi@open-xchange.com> |
||||||
|
Date: Mon, 18 May 2020 12:33:39 +0300 |
||||||
|
Subject: [PATCH 2/3] lib-ntlm: Check buffer length on responses |
||||||
|
|
||||||
|
Add missing check for buffer length. |
||||||
|
|
||||||
|
If this is not checked, it is possible to send message which |
||||||
|
causes read past buffer bug. |
||||||
|
|
||||||
|
Broken in c7480644202e5451fbed448508ea29a25cffc99c |
||||||
|
--- |
||||||
|
src/lib-ntlm/ntlm-message.c | 5 +++++ |
||||||
|
1 file changed, 5 insertions(+) |
||||||
|
|
||||||
|
diff --git a/src/lib-ntlm/ntlm-message.c b/src/lib-ntlm/ntlm-message.c |
||||||
|
index 160b9f918c..a29413b47e 100644 |
||||||
|
--- a/src/lib-ntlm/ntlm-message.c |
||||||
|
+++ b/src/lib-ntlm/ntlm-message.c |
||||||
|
@@ -184,6 +184,11 @@ static bool ntlmssp_check_buffer(const struct ntlmssp_buffer *buffer, |
||||||
|
if (length == 0 && space == 0) |
||||||
|
return 1; |
||||||
|
|
||||||
|
+ if (length > data_size) { |
||||||
|
+ *error = "buffer length out of bounds"; |
||||||
|
+ return 0; |
||||||
|
+ } |
||||||
|
+ |
||||||
|
if (offset >= data_size) { |
||||||
|
*error = "buffer offset out of bounds"; |
||||||
|
return 0; |
||||||
|
-- |
||||||
|
2.11.0 |
||||||
|
|
@ -0,0 +1,237 @@ |
|||||||
|
From bd9d2fe7da833f0e4705a8280efc56930371806b Mon Sep 17 00:00:00 2001 |
||||||
|
From: Aki Tuomi <aki.tuomi@open-xchange.com> |
||||||
|
Date: Wed, 6 May 2020 13:40:36 +0300 |
||||||
|
Subject: [PATCH 1/3] auth: mech-rpa - Fail on zero len buffer |
||||||
|
|
||||||
|
--- |
||||||
|
src/auth/mech-rpa.c | 2 +- |
||||||
|
1 file changed, 1 insertion(+), 1 deletion(-) |
||||||
|
|
||||||
|
diff --git a/src/auth/mech-rpa.c b/src/auth/mech-rpa.c |
||||||
|
index 08298ebdd6..2de8705b4f 100644 |
||||||
|
--- a/src/auth/mech-rpa.c |
||||||
|
+++ b/src/auth/mech-rpa.c |
||||||
|
@@ -224,7 +224,7 @@ rpa_read_buffer(pool_t pool, const unsigned char **data, |
||||||
|
return 0; |
||||||
|
|
||||||
|
len = *p++; |
||||||
|
- if (p + len > end) |
||||||
|
+ if (p + len > end || len == 0) |
||||||
|
return 0; |
||||||
|
|
||||||
|
*buffer = p_malloc(pool, len); |
||||||
|
-- |
||||||
|
2.11.0 |
||||||
|
|
||||||
|
From 98c39fd633adf9b1d11a7bad58ef0784a25042e6 Mon Sep 17 00:00:00 2001 |
||||||
|
From: Aki Tuomi <aki.tuomi@open-xchange.com> |
||||||
|
Date: Mon, 18 May 2020 13:08:45 +0300 |
||||||
|
Subject: [PATCH 3/3] auth: test-mech - Add tests for RPA and NTLM bug |
||||||
|
|
||||||
|
--- |
||||||
|
src/auth/test-mech.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++ |
||||||
|
1 file changed, 66 insertions(+) |
||||||
|
|
||||||
|
diff -up dovecot-2.3.8/src/auth/test-mech.c.CVE_2020_12674prereq dovecot-2.3.8/src/auth/test-mech.c |
||||||
|
--- dovecot-2.3.8/src/auth/test-mech.c.CVE_2020_12674prereq 2020-08-07 20:46:56.095295825 +0200 |
||||||
|
+++ dovecot-2.3.8/src/auth/test-mech.c 2020-08-07 20:47:08.742124304 +0200 |
||||||
|
@@ -0,0 +1,199 @@ |
||||||
|
+/* Copyright (c) 2020 Dovecot authors, see the included COPYING file */ |
||||||
|
+ |
||||||
|
+#include "lib.h" |
||||||
|
+#include "auth.h" |
||||||
|
+#include "array.h" |
||||||
|
+#include "str.h" |
||||||
|
+#include "auth-common.h" |
||||||
|
+#include "auth-request.h" |
||||||
|
+#include "auth-request-handler-private.h" |
||||||
|
+#include "auth-settings.h" |
||||||
|
+#include "otp.h" |
||||||
|
+#include "mech-otp-skey-common.h" |
||||||
|
+#include "settings-parser.h" |
||||||
|
+#include "password-scheme.h" |
||||||
|
+#include "test-common.h" |
||||||
|
+#include "test-auth.h" |
||||||
|
+#include "auth-token.h" |
||||||
|
+ |
||||||
|
+#include <unistd.h> |
||||||
|
+#include <time.h> |
||||||
|
+ |
||||||
|
+#define UCHAR_LEN(str) (const unsigned char *)(str), sizeof(str)-1 |
||||||
|
+ |
||||||
|
+extern const struct mech_module mech_oauthbearer; |
||||||
|
+extern const struct mech_module mech_otp; |
||||||
|
+extern const struct mech_module mech_ntlm; |
||||||
|
+extern const struct mech_module mech_rpa; |
||||||
|
+ |
||||||
|
+static struct auth_settings set; |
||||||
|
+static struct mechanisms_register *mech_reg; |
||||||
|
+ |
||||||
|
+struct test_case { |
||||||
|
+ const struct mech_module *mech; |
||||||
|
+ const unsigned char *in; |
||||||
|
+ size_t len; |
||||||
|
+ const char *username; |
||||||
|
+ const char *expect_error; |
||||||
|
+ bool success; |
||||||
|
+ bool set_username_before_test; |
||||||
|
+ bool set_cert_username; |
||||||
|
+}; |
||||||
|
+ |
||||||
|
+static void |
||||||
|
+verify_plain_continue_mock_callback(struct auth_request *request, |
||||||
|
+ verify_plain_callback_t *callback) |
||||||
|
+{ |
||||||
|
+ request->passdb_success = TRUE; |
||||||
|
+ callback(PASSDB_RESULT_OK, request); |
||||||
|
+} |
||||||
|
+ |
||||||
|
+static void |
||||||
|
+request_handler_reply_mock_callback(struct auth_request *request, |
||||||
|
+ enum auth_client_result result, |
||||||
|
+ const void *auth_reply ATTR_UNUSED, |
||||||
|
+ size_t reply_size ATTR_UNUSED) |
||||||
|
+{ |
||||||
|
+ request->failed = result != AUTH_CLIENT_RESULT_SUCCESS; |
||||||
|
+ |
||||||
|
+ if (request->passdb_result == PASSDB_RESULT_OK) |
||||||
|
+ request->failed = FALSE; |
||||||
|
+ else if (request->mech == &mech_otp) { |
||||||
|
+ if (null_strcmp(request->user, "otp_phase_2") == 0) |
||||||
|
+ request->failed = FALSE; |
||||||
|
+ } else if (request->mech == &mech_oauthbearer) { |
||||||
|
+ } |
||||||
|
+}; |
||||||
|
+ |
||||||
|
+static void |
||||||
|
+request_handler_reply_continue_mock_callback(struct auth_request *request, |
||||||
|
+ const void *reply, |
||||||
|
+ size_t reply_size) |
||||||
|
+{ |
||||||
|
+ request->context = p_strndup(request->pool, reply, reply_size); |
||||||
|
+} |
||||||
|
+ |
||||||
|
+static void |
||||||
|
+auth_client_request_mock_callback(const char *reply ATTR_UNUSED, |
||||||
|
+ struct auth_client_connection *conn ATTR_UNUSED) |
||||||
|
+{ |
||||||
|
+} |
||||||
|
+ |
||||||
|
+static void test_mechs_init(void) |
||||||
|
+{ |
||||||
|
+ const char *const services[] = {NULL}; |
||||||
|
+ process_start_time = time(NULL); |
||||||
|
+ |
||||||
|
+ /* Copy default settings */ |
||||||
|
+ set = *(struct auth_settings *) auth_setting_parser_info.defaults; |
||||||
|
+ global_auth_settings = &set; |
||||||
|
+ global_auth_settings->base_dir = "."; |
||||||
|
+ memset((&set)->username_chars_map, 1, sizeof((&set)->username_chars_map)); |
||||||
|
+ set.username_format = ""; |
||||||
|
+ |
||||||
|
+ t_array_init(&set.passdbs, 2); |
||||||
|
+ struct auth_passdb_settings *mock_set = t_new(struct auth_passdb_settings, 1); |
||||||
|
+ *mock_set = mock_passdb_set; |
||||||
|
+ array_push_back(&set.passdbs, &mock_set); |
||||||
|
+ mock_set = t_new(struct auth_passdb_settings, 1); |
||||||
|
+ *mock_set = mock_passdb_set; |
||||||
|
+ mock_set->master = TRUE; |
||||||
|
+ array_push_back(&set.passdbs, &mock_set); |
||||||
|
+ t_array_init(&set.userdbs, 1); |
||||||
|
+ |
||||||
|
+ /* Disable stats */ |
||||||
|
+ set.stats = FALSE; |
||||||
|
+ |
||||||
|
+ /* For tests of digest-md5. */ |
||||||
|
+ set.realms_arr = t_strsplit_spaces("example.com ", " "); |
||||||
|
+ /* For tests of mech-anonymous. */ |
||||||
|
+ set.anonymous_username = "anonuser"; |
||||||
|
+ |
||||||
|
+ mech_init(global_auth_settings); |
||||||
|
+ mech_reg = mech_register_init(global_auth_settings); |
||||||
|
+ passdbs_init(); |
||||||
|
+ userdbs_init(); |
||||||
|
+ passdb_mock_mod_init(); |
||||||
|
+ password_schemes_init(); |
||||||
|
+ |
||||||
|
+ auths_preinit(&set, pool_datastack_create(), mech_reg, services); |
||||||
|
+ auths_init(); |
||||||
|
+ auth_token_init(); |
||||||
|
+} |
||||||
|
+ |
||||||
|
+ |
||||||
|
+static void test_rpa(void) |
||||||
|
+{ |
||||||
|
+ static struct auth_request_handler handler = { |
||||||
|
+ .callback = auth_client_request_mock_callback, |
||||||
|
+ .reply_callback = request_handler_reply_mock_callback, |
||||||
|
+ .reply_continue_callback = request_handler_reply_continue_mock_callback, |
||||||
|
+ .verify_plain_continue_callback = verify_plain_continue_mock_callback, |
||||||
|
+ }; |
||||||
|
+ |
||||||
|
+ const struct mech_module *mech = &mech_rpa; |
||||||
|
+ test_begin("test rpa"); |
||||||
|
+ struct auth_request *req = mech->auth_new(); |
||||||
|
+ global_auth_settings->realms_arr = t_strsplit("example.com", " "); |
||||||
|
+ req->set = global_auth_settings; |
||||||
|
+ req->service = "login"; |
||||||
|
+ req->handler = &handler; |
||||||
|
+ //req->mech_event = event_create(NULL); |
||||||
|
+ //req->event = event_create(NULL); |
||||||
|
+ req->mech = mech; |
||||||
|
+ req->state = AUTH_REQUEST_STATE_MECH_CONTINUE; |
||||||
|
+ auth_request_state_count[AUTH_REQUEST_STATE_MECH_CONTINUE] = 1; |
||||||
|
+ mech->auth_initial(req, UCHAR_LEN("\x60\x11\x06\x09\x60\x86\x48\x01\x86\xf8\x73\x01\x01\x01\x00\x04\x00\x00\x01")); |
||||||
|
+ mech->auth_continue(req, UCHAR_LEN("\x60\x11\x06\x09\x60\x86\x48\x01\x86\xf8\x73\x01\x01\x00\x03A@A\x00")); |
||||||
|
+ test_assert(req->failed == TRUE); |
||||||
|
+ test_assert(req->passdb_success == FALSE); |
||||||
|
+ //event_unref(&req->mech_event); |
||||||
|
+ //event_unref(&req->event); |
||||||
|
+ mech->auth_free(req); |
||||||
|
+ test_end(); |
||||||
|
+} |
||||||
|
+ |
||||||
|
+static void test_ntlm(void) |
||||||
|
+{ |
||||||
|
+ static struct auth_request_handler handler = { |
||||||
|
+ .callback = auth_client_request_mock_callback, |
||||||
|
+ .reply_callback = request_handler_reply_mock_callback, |
||||||
|
+ .reply_continue_callback = request_handler_reply_continue_mock_callback, |
||||||
|
+ .verify_plain_continue_callback = verify_plain_continue_mock_callback, |
||||||
|
+ }; |
||||||
|
+ |
||||||
|
+ const struct mech_module *mech = &mech_ntlm; |
||||||
|
+ test_begin("test ntlm"); |
||||||
|
+ struct auth_request *req = mech->auth_new(); |
||||||
|
+ global_auth_settings->realms_arr = t_strsplit("example.com", " "); |
||||||
|
+ req->set = global_auth_settings; |
||||||
|
+ req->service = "login"; |
||||||
|
+ req->handler = &handler; |
||||||
|
+ //req->mech_event = event_create(NULL); |
||||||
|
+ //req->event = event_create(NULL); |
||||||
|
+ req->mech = mech; |
||||||
|
+ req->state = AUTH_REQUEST_STATE_MECH_CONTINUE; |
||||||
|
+ auth_request_state_count[AUTH_REQUEST_STATE_MECH_CONTINUE] = 1; |
||||||
|
+ mech->auth_initial(req, UCHAR_LEN("NTLMSSP\x00\x01\x00\x00\x00\x00\x02\x00\x00""AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")); |
||||||
|
+ mech->auth_continue(req, UCHAR_LEN("NTLMSSP\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00""AA\x00\x00\x41\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00""orange""\x00")); |
||||||
|
+ test_assert(req->failed == TRUE); |
||||||
|
+ test_assert(req->passdb_success == FALSE); |
||||||
|
+ //event_unref(&req->mech_event); |
||||||
|
+ //event_unref(&req->event); |
||||||
|
+ mech->auth_free(req); |
||||||
|
+ test_end(); |
||||||
|
+} |
||||||
|
+ |
||||||
|
+int main(void) |
||||||
|
+{ |
||||||
|
+ static void (*const test_functions[])(void) = { |
||||||
|
+ test_rpa, |
||||||
|
+ test_ntlm, |
||||||
|
+ NULL |
||||||
|
+ }; |
||||||
|
+ lib_init(); |
||||||
|
+ test_mechs_init(); |
||||||
|
+ int ret = test_run(test_functions); |
||||||
|
+ mech_register_deinit(&mech_reg); |
||||||
|
+ return ret; |
||||||
|
+} |
@ -0,0 +1,818 @@ |
|||||||
|
diff -up dovecot-2.2.36/src/auth/auth-request.c.CVE_2020_12674prereq dovecot-2.2.36/src/auth/auth-request.c |
||||||
|
--- dovecot-2.2.36/src/auth/auth-request.c.CVE_2020_12674prereq 2020-08-09 14:37:53.468591087 +0200 |
||||||
|
+++ dovecot-2.2.36/src/auth/auth-request.c 2020-08-09 14:37:53.482591165 +0200 |
||||||
|
@@ -16,6 +16,7 @@ |
||||||
|
#include "auth-cache.h" |
||||||
|
#include "auth-request.h" |
||||||
|
#include "auth-request-handler.h" |
||||||
|
+#include "auth-request-handler-private.h" |
||||||
|
#include "auth-request-stats.h" |
||||||
|
#include "auth-client-connection.h" |
||||||
|
#include "auth-master-connection.h" |
||||||
|
@@ -68,9 +69,6 @@ static void |
||||||
|
auth_request_userdb_import(struct auth_request *request, const char *args); |
||||||
|
|
||||||
|
static |
||||||
|
-void auth_request_verify_plain_continue(struct auth_request *request, |
||||||
|
- verify_plain_callback_t *callback); |
||||||
|
-static |
||||||
|
void auth_request_lookup_credentials_policy_continue(struct auth_request *request, |
||||||
|
lookup_credentials_callback_t *callback); |
||||||
|
static |
||||||
|
@@ -211,10 +209,12 @@ void auth_request_success_continue(struc |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
- stats = auth_request_stats_get(request); |
||||||
|
- stats->auth_success_count++; |
||||||
|
- if (request->master_user != NULL) |
||||||
|
- stats->auth_master_success_count++; |
||||||
|
+ if (request->set->stats) { |
||||||
|
+ stats = auth_request_stats_get(request); |
||||||
|
+ stats->auth_success_count++; |
||||||
|
+ if (request->master_user != NULL) |
||||||
|
+ stats->auth_master_success_count++; |
||||||
|
+ } |
||||||
|
|
||||||
|
auth_request_set_state(request, AUTH_REQUEST_STATE_FINISHED); |
||||||
|
auth_request_refresh_last_access(request); |
||||||
|
@@ -228,8 +228,10 @@ void auth_request_fail(struct auth_reque |
||||||
|
|
||||||
|
i_assert(request->state == AUTH_REQUEST_STATE_MECH_CONTINUE); |
||||||
|
|
||||||
|
- stats = auth_request_stats_get(request); |
||||||
|
- stats->auth_failure_count++; |
||||||
|
+ if (request->set->stats) { |
||||||
|
+ stats = auth_request_stats_get(request); |
||||||
|
+ stats->auth_failure_count++; |
||||||
|
+ } |
||||||
|
|
||||||
|
auth_request_set_state(request, AUTH_REQUEST_STATE_FINISHED); |
||||||
|
auth_request_refresh_last_access(request); |
||||||
|
@@ -989,7 +991,7 @@ void auth_request_policy_penalty_finish( |
||||||
|
|
||||||
|
switch(ctx->type) { |
||||||
|
case AUTH_POLICY_CHECK_TYPE_PLAIN: |
||||||
|
- auth_request_verify_plain_continue(ctx->request, ctx->callback_plain); |
||||||
|
+ ctx->request->handler->verify_plain_continue_callback(ctx->request, ctx->callback_plain); |
||||||
|
return; |
||||||
|
case AUTH_POLICY_CHECK_TYPE_LOOKUP: |
||||||
|
auth_request_lookup_credentials_policy_continue(ctx->request, ctx->callback_lookup); |
||||||
|
@@ -1036,7 +1038,8 @@ void auth_request_verify_plain(struct au |
||||||
|
request->user_changed_by_lookup = FALSE; |
||||||
|
|
||||||
|
if (request->policy_processed || !request->set->policy_check_before_auth) { |
||||||
|
- auth_request_verify_plain_continue(request, callback); |
||||||
|
+ request->handler->verify_plain_continue_callback(request, |
||||||
|
+ callback); |
||||||
|
} else { |
||||||
|
ctx = p_new(request->pool, struct auth_policy_check_ctx, 1); |
||||||
|
ctx->request = request; |
||||||
|
@@ -1046,9 +1049,9 @@ void auth_request_verify_plain(struct au |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
-static |
||||||
|
-void auth_request_verify_plain_continue(struct auth_request *request, |
||||||
|
- verify_plain_callback_t *callback) { |
||||||
|
+void auth_request_default_verify_plain_continue(struct auth_request *request, |
||||||
|
+ verify_plain_callback_t *callback) |
||||||
|
+{ |
||||||
|
|
||||||
|
struct auth_passdb *passdb; |
||||||
|
enum passdb_result result; |
||||||
|
diff -up dovecot-2.2.36/src/auth/auth-request-handler.c.CVE_2020_12674prereq dovecot-2.2.36/src/auth/auth-request-handler.c |
||||||
|
--- dovecot-2.2.36/src/auth/auth-request-handler.c.CVE_2020_12674prereq 2020-08-09 14:37:53.467591082 +0200 |
||||||
|
+++ dovecot-2.2.36/src/auth/auth-request-handler.c 2020-08-09 14:37:53.482591165 +0200 |
||||||
|
@@ -16,32 +16,29 @@ |
||||||
|
#include "auth-token.h" |
||||||
|
#include "auth-master-connection.h" |
||||||
|
#include "auth-request-handler.h" |
||||||
|
+#include "auth-request-handler-private.h" |
||||||
|
#include "auth-policy.h" |
||||||
|
|
||||||
|
#define AUTH_FAILURE_DELAY_CHECK_MSECS 500 |
||||||
|
|
||||||
|
-struct auth_request_handler { |
||||||
|
- int refcount; |
||||||
|
- pool_t pool; |
||||||
|
- HASH_TABLE(void *, struct auth_request *) requests; |
||||||
|
- |
||||||
|
- unsigned int connect_uid, client_pid; |
||||||
|
- |
||||||
|
- auth_client_request_callback_t *callback; |
||||||
|
- struct auth_client_connection *conn; |
||||||
|
- |
||||||
|
- auth_master_request_callback_t *master_callback; |
||||||
|
- |
||||||
|
- unsigned int destroyed:1; |
||||||
|
- unsigned int token_auth:1; |
||||||
|
-}; |
||||||
|
- |
||||||
|
static ARRAY(struct auth_request *) auth_failures_arr; |
||||||
|
static struct aqueue *auth_failures; |
||||||
|
static struct timeout *to_auth_failures; |
||||||
|
|
||||||
|
static void auth_failure_timeout(void *context) ATTR_NULL(1); |
||||||
|
|
||||||
|
+static void |
||||||
|
+auth_request_handler_default_reply_callback(struct auth_request *request, |
||||||
|
+ enum auth_client_result result, |
||||||
|
+ const void *auth_reply, |
||||||
|
+ size_t reply_size); |
||||||
|
+ |
||||||
|
+static void |
||||||
|
+auth_request_handler_default_reply_continue(struct auth_request *request, |
||||||
|
+ const void *reply, |
||||||
|
+ size_t reply_size); |
||||||
|
+ |
||||||
|
+ |
||||||
|
struct auth_request_handler * |
||||||
|
auth_request_handler_create(bool token_auth, auth_client_request_callback_t *callback, |
||||||
|
struct auth_client_connection *conn, |
||||||
|
@@ -60,6 +57,12 @@ auth_request_handler_create(bool token_a |
||||||
|
handler->conn = conn; |
||||||
|
handler->master_callback = master_callback; |
||||||
|
handler->token_auth = token_auth; |
||||||
|
+ handler->reply_callback = |
||||||
|
+ auth_request_handler_default_reply_callback; |
||||||
|
+ handler->reply_continue_callback = |
||||||
|
+ auth_request_handler_default_reply_continue; |
||||||
|
+ handler->verify_plain_continue_callback = |
||||||
|
+ auth_request_default_verify_plain_continue; |
||||||
|
return handler; |
||||||
|
} |
||||||
|
|
||||||
|
@@ -342,6 +345,16 @@ void auth_request_handler_reply(struct a |
||||||
|
enum auth_client_result result, |
||||||
|
const void *auth_reply, size_t reply_size) |
||||||
|
{ |
||||||
|
+ struct auth_request_handler *handler = request->handler; |
||||||
|
+ handler->reply_callback(request, result, auth_reply, reply_size); |
||||||
|
+} |
||||||
|
+ |
||||||
|
+static void |
||||||
|
+auth_request_handler_default_reply_callback(struct auth_request *request, |
||||||
|
+ enum auth_client_result result, |
||||||
|
+ const void *auth_reply, |
||||||
|
+ size_t reply_size) |
||||||
|
+{ |
||||||
|
struct auth_request_handler *handler = request->handler; |
||||||
|
string_t *str; |
||||||
|
int ret; |
||||||
|
@@ -394,6 +407,14 @@ void auth_request_handler_reply(struct a |
||||||
|
void auth_request_handler_reply_continue(struct auth_request *request, |
||||||
|
const void *reply, size_t reply_size) |
||||||
|
{ |
||||||
|
+ request->handler->reply_continue_callback(request, reply, reply_size); |
||||||
|
+} |
||||||
|
+ |
||||||
|
+static void |
||||||
|
+auth_request_handler_default_reply_continue(struct auth_request *request, |
||||||
|
+ const void *reply, |
||||||
|
+ size_t reply_size) |
||||||
|
+{ |
||||||
|
auth_request_handler_reply(request, AUTH_CLIENT_RESULT_CONTINUE, |
||||||
|
reply, reply_size); |
||||||
|
} |
||||||
|
@@ -657,6 +678,7 @@ static void auth_str_append_userdb_extra |
||||||
|
auth_str_add_keyvalue(dest, "master_user", |
||||||
|
request->master_user); |
||||||
|
} |
||||||
|
+ auth_str_add_keyvalue(dest, "auth_mech", request->mech->mech_name); |
||||||
|
if (*request->set->anonymous_username != '\0' && |
||||||
|
strcmp(request->user, request->set->anonymous_username) == 0) { |
||||||
|
/* this is an anonymous login, either via ANONYMOUS |
||||||
|
diff -up dovecot-2.2.36/src/auth/auth-request-handler.h.CVE_2020_12674prereq dovecot-2.2.36/src/auth/auth-request-handler.h |
||||||
|
--- dovecot-2.2.36/src/auth/auth-request-handler.h.CVE_2020_12674prereq 2017-06-23 13:18:28.000000000 +0200 |
||||||
|
+++ dovecot-2.2.36/src/auth/auth-request-handler.h 2020-08-09 14:37:53.482591165 +0200 |
||||||
|
@@ -17,6 +17,17 @@ auth_client_request_callback_t(const cha |
||||||
|
typedef void |
||||||
|
auth_master_request_callback_t(const char *reply, struct auth_master_connection *conn); |
||||||
|
|
||||||
|
+typedef void |
||||||
|
+auth_request_handler_reply_callback_t(struct auth_request *request, |
||||||
|
+ enum auth_client_result result, |
||||||
|
+ const void *auth_reply, |
||||||
|
+ size_t reply_size); |
||||||
|
+typedef void |
||||||
|
+auth_request_handler_reply_continue_callback_t(struct auth_request *request, |
||||||
|
+ const void *reply, |
||||||
|
+ size_t reply_size); |
||||||
|
+ |
||||||
|
+ |
||||||
|
struct auth_request_handler * |
||||||
|
auth_request_handler_create(bool token_auth, auth_client_request_callback_t *callback, |
||||||
|
struct auth_client_connection *conn, |
||||||
|
diff -up dovecot-2.2.36/src/auth/auth-request-handler-private.h.CVE_2020_12674prereq dovecot-2.2.36/src/auth/auth-request-handler-private.h |
||||||
|
--- dovecot-2.2.36/src/auth/auth-request-handler-private.h.CVE_2020_12674prereq 2020-08-09 14:37:53.482591165 +0200 |
||||||
|
+++ dovecot-2.2.36/src/auth/auth-request-handler-private.h 2020-08-09 14:37:53.482591165 +0200 |
||||||
|
@@ -0,0 +1,27 @@ |
||||||
|
+#ifndef AUTH_REQUEST_HANDLER_PRIVATE_H |
||||||
|
+#define AUTH_REQUEST_HANDLER_PRIVATE_H |
||||||
|
+ |
||||||
|
+struct auth_request; |
||||||
|
+struct auth_client_connection; |
||||||
|
+ |
||||||
|
+struct auth_request_handler { |
||||||
|
+ int refcount; |
||||||
|
+ pool_t pool; |
||||||
|
+ HASH_TABLE(void *, struct auth_request *) requests; |
||||||
|
+ |
||||||
|
+ unsigned int connect_uid, client_pid; |
||||||
|
+ |
||||||
|
+ auth_client_request_callback_t *callback; |
||||||
|
+ struct auth_client_connection *conn; |
||||||
|
+ |
||||||
|
+ auth_master_request_callback_t *master_callback; |
||||||
|
+ auth_request_handler_reply_callback_t *reply_callback; |
||||||
|
+ auth_request_handler_reply_continue_callback_t *reply_continue_callback; |
||||||
|
+ verify_plain_continue_callback_t *verify_plain_continue_callback; |
||||||
|
+ |
||||||
|
+ bool destroyed:1; |
||||||
|
+ bool token_auth:1; |
||||||
|
+}; |
||||||
|
+ |
||||||
|
+ |
||||||
|
+#endif |
||||||
|
diff -up dovecot-2.2.36/src/auth/auth-request.h.CVE_2020_12674prereq dovecot-2.2.36/src/auth/auth-request.h |
||||||
|
--- dovecot-2.2.36/src/auth/auth-request.h.CVE_2020_12674prereq 2018-04-30 15:52:05.000000000 +0200 |
||||||
|
+++ dovecot-2.2.36/src/auth/auth-request.h 2020-08-09 14:37:53.482591165 +0200 |
||||||
|
@@ -269,6 +269,8 @@ void auth_request_set_credentials(struct |
||||||
|
set_credentials_callback_t *callback); |
||||||
|
void auth_request_userdb_callback(enum userdb_result result, |
||||||
|
struct auth_request *request); |
||||||
|
+void auth_request_default_verify_plain_continue(struct auth_request *request, |
||||||
|
+ verify_plain_callback_t *callback); |
||||||
|
|
||||||
|
void auth_request_refresh_last_access(struct auth_request *request); |
||||||
|
void auth_str_append(string_t *dest, const char *key, const char *value); |
||||||
|
diff -up dovecot-2.2.36/src/auth/Makefile.am.CVE_2020_12674prereq dovecot-2.2.36/src/auth/Makefile.am |
||||||
|
--- dovecot-2.2.36/src/auth/Makefile.am.CVE_2020_12674prereq 2018-04-30 15:52:05.000000000 +0200 |
||||||
|
+++ dovecot-2.2.36/src/auth/Makefile.am 2020-08-09 14:37:53.482591165 +0200 |
||||||
|
@@ -227,7 +227,8 @@ test_programs = \ |
||||||
|
test-auth-cache \ |
||||||
|
test-auth-request-var-expand \ |
||||||
|
test-username-filter \ |
||||||
|
- test-db-dict |
||||||
|
+ test-db-dict \ |
||||||
|
+ test-mech |
||||||
|
|
||||||
|
noinst_PROGRAMS = $(test_programs) |
||||||
|
|
||||||
|
@@ -253,6 +254,13 @@ test_db_dict_SOURCES = test-db-dict.c |
||||||
|
test_db_dict_LDADD = $(test_libs) libauth.la |
||||||
|
test_db_dict_DEPENDENCIES = $(pkglibexec_PROGRAMS) $(test_libs) |
||||||
|
|
||||||
|
+test_mech_SOURCES = \ |
||||||
|
+ test-mock.c \ |
||||||
|
+ test-mech.c |
||||||
|
+ |
||||||
|
+test_mech_LDADD = $(test_libs) $(auth_libs) $(AUTH_LIBS) |
||||||
|
+test_mech_DEPENDENCIES = $(pkglibexec_PROGRAMS) $(test_libs) |
||||||
|
+ |
||||||
|
check: check-am check-test |
||||||
|
check-test: all-am |
||||||
|
for bin in $(test_programs); do \ |
||||||
|
diff -up dovecot-2.2.36/src/auth/passdb.h.CVE_2020_12674prereq dovecot-2.2.36/src/auth/passdb.h |
||||||
|
--- dovecot-2.2.36/src/auth/passdb.h.CVE_2020_12674prereq 2018-04-30 15:52:05.000000000 +0200 |
||||||
|
+++ dovecot-2.2.36/src/auth/passdb.h 2020-08-09 14:37:53.482591165 +0200 |
||||||
|
@@ -24,6 +24,8 @@ enum passdb_result { |
||||||
|
|
||||||
|
typedef void verify_plain_callback_t(enum passdb_result result, |
||||||
|
struct auth_request *request); |
||||||
|
+typedef void verify_plain_continue_callback_t(struct auth_request *request, |
||||||
|
+ verify_plain_callback_t *callback); |
||||||
|
typedef void lookup_credentials_callback_t(enum passdb_result result, |
||||||
|
const unsigned char *credentials, |
||||||
|
size_t size, |
||||||
|
diff -up dovecot-2.2.36/src/auth/test-auth.h.CVE_2020_12674prereq dovecot-2.2.36/src/auth/test-auth.h |
||||||
|
--- dovecot-2.2.36/src/auth/test-auth.h.CVE_2020_12674prereq 2020-08-09 14:38:24.950765769 +0200 |
||||||
|
+++ dovecot-2.2.36/src/auth/test-auth.h 2020-08-09 14:38:06.304662311 +0200 |
||||||
|
@@ -0,0 +1,21 @@ |
||||||
|
+/* Copyright (c) 2017-2018 Dovecot authors, see the included COPYING file */ |
||||||
|
+ |
||||||
|
+#ifndef TEST_AUTH_H |
||||||
|
+#define TEST_AUTH_H 1 |
||||||
|
+ |
||||||
|
+#include "lib.h" |
||||||
|
+#include "test-common.h" |
||||||
|
+ |
||||||
|
+struct auth_passdb; |
||||||
|
+struct auth_passdb_settings mock_passdb_set; |
||||||
|
+ |
||||||
|
+void test_auth_request_var_expand(void); |
||||||
|
+void test_db_dict_parse_cache_key(void); |
||||||
|
+void test_username_filter(void); |
||||||
|
+void test_db_lua(void); |
||||||
|
+struct auth_passdb *passdb_mock(void); |
||||||
|
+void passdb_mock_mod_init(void); |
||||||
|
+void passdb_mock_mod_deinit(void); |
||||||
|
+ |
||||||
|
+#endif |
||||||
|
+ |
||||||
|
diff -up dovecot-2.2.36/src/auth/test-mock.c.CVE_2020_12674prereq dovecot-2.2.36/src/auth/test-mock.c |
||||||
|
--- dovecot-2.2.36/src/auth/test-mock.c.CVE_2020_12674prereq 2020-08-09 14:37:53.483591170 +0200 |
||||||
|
+++ dovecot-2.2.36/src/auth/test-mock.c 2020-08-09 14:37:53.483591170 +0200 |
||||||
|
@@ -0,0 +1,109 @@ |
||||||
|
+/* Copyright (c) 2017-2018 Dovecot authors, see the included COPYING file */ |
||||||
|
+ |
||||||
|
+#include "test-auth.h" |
||||||
|
+#include "auth-common.h" |
||||||
|
+#include "passdb.h" |
||||||
|
+ |
||||||
|
+struct auth_penalty *auth_penalty; |
||||||
|
+time_t process_start_time; |
||||||
|
+bool worker, worker_restart_request; |
||||||
|
+static struct passdb_module *mock_passdb_mod = NULL; |
||||||
|
+static pool_t mock_pool; |
||||||
|
+ |
||||||
|
+void auth_module_load(const char *names ATTR_UNUSED) |
||||||
|
+{ |
||||||
|
+} |
||||||
|
+void auth_refresh_proctitle(void) { |
||||||
|
+} |
||||||
|
+ |
||||||
|
+static void passdb_mock_init(struct passdb_module *module ATTR_UNUSED) |
||||||
|
+{ |
||||||
|
+} |
||||||
|
+static void passdb_mock_deinit(struct passdb_module *module ATTR_UNUSED) |
||||||
|
+{ |
||||||
|
+} |
||||||
|
+static void passdb_mock_verify_plain(struct auth_request *request, const char *password ATTR_UNUSED, |
||||||
|
+ verify_plain_callback_t *callback) |
||||||
|
+{ |
||||||
|
+ callback(PASSDB_RESULT_OK, request); |
||||||
|
+} |
||||||
|
+ |
||||||
|
+static void passdb_mock_lookup_credentials(struct auth_request *request, |
||||||
|
+ lookup_credentials_callback_t *callback) |
||||||
|
+{ |
||||||
|
+ passdb_handle_credentials(PASSDB_RESULT_OK, "password", "PLAIN", |
||||||
|
+ callback, request); |
||||||
|
+} |
||||||
|
+ |
||||||
|
+static struct passdb_module_interface mock_interface = { |
||||||
|
+ .name = "mock", |
||||||
|
+ .init = passdb_mock_init, |
||||||
|
+ .deinit = passdb_mock_deinit, |
||||||
|
+ .verify_plain = passdb_mock_verify_plain, |
||||||
|
+ .lookup_credentials = passdb_mock_lookup_credentials, |
||||||
|
+}; |
||||||
|
+ |
||||||
|
+struct auth_passdb_settings mock_passdb_set = { |
||||||
|
+ .name = "mock", |
||||||
|
+ .driver = "mock", |
||||||
|
+ .args = "", |
||||||
|
+ .default_fields = "", |
||||||
|
+ .override_fields = "", |
||||||
|
+ .mechanisms = "", |
||||||
|
+ .username_filter = "", |
||||||
|
+ .skip = "never", |
||||||
|
+ .result_success = "return-ok", |
||||||
|
+ .result_failure = "continue", |
||||||
|
+ .result_internalfail = "continue", |
||||||
|
+ .deny = FALSE, |
||||||
|
+ .pass = FALSE, |
||||||
|
+ .master = FALSE, |
||||||
|
+ .auth_verbose = "default" |
||||||
|
+}; |
||||||
|
+ |
||||||
|
+void passdb_mock_mod_init(void) |
||||||
|
+{ |
||||||
|
+ if (mock_passdb_mod != NULL) |
||||||
|
+ return; |
||||||
|
+ |
||||||
|
+ mock_pool = pool_allocfree_create("auth mock"); |
||||||
|
+ |
||||||
|
+ passdb_register_module(&mock_interface); |
||||||
|
+ |
||||||
|
+ struct auth_passdb_settings set = { |
||||||
|
+ .name = "mock", |
||||||
|
+ .driver = "mock", |
||||||
|
+ .args = "", |
||||||
|
+ .default_fields = "", |
||||||
|
+ .override_fields = "", |
||||||
|
+ .mechanisms = "", |
||||||
|
+ .username_filter = "", |
||||||
|
+ |
||||||
|
+ .skip = "never", |
||||||
|
+ .result_success = "return-ok", |
||||||
|
+ .result_failure = "continue", |
||||||
|
+ .result_internalfail = "continue", |
||||||
|
+ |
||||||
|
+ .deny = FALSE, |
||||||
|
+ .pass = FALSE, |
||||||
|
+ .master = FALSE, |
||||||
|
+ .auth_verbose = "default" |
||||||
|
+ }; |
||||||
|
+ mock_passdb_mod = passdb_preinit(mock_pool, &set); |
||||||
|
+ passdb_init(mock_passdb_mod); |
||||||
|
+} |
||||||
|
+ |
||||||
|
+void passdb_mock_mod_deinit(void) |
||||||
|
+{ |
||||||
|
+ passdb_deinit(mock_passdb_mod); |
||||||
|
+ passdb_unregister_module(&mock_interface); |
||||||
|
+ pool_unref(&mock_pool); |
||||||
|
+} |
||||||
|
+ |
||||||
|
+struct auth_passdb *passdb_mock(void) |
||||||
|
+{ |
||||||
|
+ struct auth_passdb *ret = i_new(struct auth_passdb, 1); |
||||||
|
+ ret->set = &mock_passdb_set; |
||||||
|
+ ret->passdb = mock_passdb_mod; |
||||||
|
+ return ret; |
||||||
|
+} |
||||||
|
diff -up dovecot-2.2.36/src/lib/lib.c.CVE_2020_12674prereq dovecot-2.2.36/src/lib/lib.c |
||||||
|
--- dovecot-2.2.36/src/lib/lib.c.CVE_2020_12674prereq 2018-04-30 15:52:05.000000000 +0200 |
||||||
|
+++ dovecot-2.2.36/src/lib/lib.c 2020-08-09 14:37:53.483591170 +0200 |
||||||
|
@@ -175,7 +175,7 @@ void lib_init(void) |
||||||
|
hostpid_init(); |
||||||
|
lib_open_non_stdio_dev_null(); |
||||||
|
var_expand_extensions_init(); |
||||||
|
- |
||||||
|
+ random_init(); |
||||||
|
lib_initialized = TRUE; |
||||||
|
} |
||||||
|
|
||||||
|
diff -up dovecot-2.2.36/src/lib/lib.h.CVE_2020_12674prereq dovecot-2.2.36/src/lib/lib.h |
||||||
|
--- dovecot-2.2.36/src/lib/lib.h.CVE_2020_12674prereq 2020-08-24 14:42:44.084069002 +0200 |
||||||
|
+++ dovecot-2.2.36/src/lib/lib.h 2020-08-24 14:42:44.108068770 +0200 |
||||||
|
@@ -33,6 +33,7 @@ |
||||||
|
#include "imem.h" |
||||||
|
#include "byteorder.h" |
||||||
|
#include "rand.h" |
||||||
|
+#include "randgen.h" |
||||||
|
|
||||||
|
typedef struct buffer buffer_t; |
||||||
|
typedef struct buffer string_t; |
||||||
|
diff -up dovecot-2.2.36/src/lib/Makefile.am.CVE_2020_12674prereq dovecot-2.2.36/src/lib/Makefile.am |
||||||
|
--- dovecot-2.2.36/src/lib/Makefile.am.CVE_2020_12674prereq 2020-08-09 14:37:53.464591065 +0200 |
||||||
|
+++ dovecot-2.2.36/src/lib/Makefile.am 2020-08-09 14:37:53.483591170 +0200 |
||||||
|
@@ -98,6 +98,7 @@ liblib_la_SOURCES = \ |
||||||
|
md4.c \ |
||||||
|
md5.c \ |
||||||
|
mempool.c \ |
||||||
|
+ mempool-allocfree.c \ |
||||||
|
mempool-alloconly.c \ |
||||||
|
mempool-datastack.c \ |
||||||
|
mempool-system.c \ |
||||||
|
diff -up dovecot-2.2.36/src/lib/mempool-allocfree.c.CVE_2020_12674prereq dovecot-2.2.36/src/lib/mempool-allocfree.c |
||||||
|
--- dovecot-2.2.36/src/lib/mempool-allocfree.c.CVE_2020_12674prereq 2020-08-09 14:37:53.483591170 +0200 |
||||||
|
+++ dovecot-2.2.36/src/lib/mempool-allocfree.c 2020-08-09 14:37:53.483591170 +0200 |
||||||
|
@@ -0,0 +1,328 @@ |
||||||
|
+/* Copyright (c) 2017-2018 Dovecot authors, see the included COPYING file */ |
||||||
|
+ |
||||||
|
+/* @UNSAFE: whole file */ |
||||||
|
+#include "lib.h" |
||||||
|
+#include "safe-memset.h" |
||||||
|
+#include "mempool.h" |
||||||
|
+#include "llist.h" |
||||||
|
+ |
||||||
|
+/* |
||||||
|
+ * As the name implies, allocfree pools support both allocating and freeing |
||||||
|
+ * memory. |
||||||
|
+ * |
||||||
|
+ * Implementation |
||||||
|
+ * ============== |
||||||
|
+ * |
||||||
|
+ * Each allocfree pool contains a pool structure (struct allocfree_pool) to |
||||||
|
+ * keep track of allocfree-specific pool information and zero or more blocks |
||||||
|
+ * (struct pool_block) that keep track of ranges of memory used to back the |
||||||
|
+ * allocations. The blocks are kept in a doubly-linked list used to keep |
||||||
|
+ * track of all allocations that belong to the pool. |
||||||
|
+ * |
||||||
|
+ * +-----------+ |
||||||
|
+ * | allocfree | |
||||||
|
+ * | pool | |
||||||
|
+ * +-----+-----+ |
||||||
|
+ * | |
||||||
|
+ * | blocks +------------+ next +------------+ next |
||||||
|
+ * \------->| pool block |<=====>| pool block |<=====>...<====> NULL |
||||||
|
+ * +------------+ prev +------------+ prev |
||||||
|
+ * | <data> | | <data> | |
||||||
|
+ * . . |
||||||
|
+ * . . |
||||||
|
+ * . | <data> | |
||||||
|
+ * . +------------+ |
||||||
|
+ * | <data> | |
||||||
|
+ * +------------+ |
||||||
|
+ * |
||||||
|
+ * Creation |
||||||
|
+ * -------- |
||||||
|
+ * |
||||||
|
+ * When an allocfree pool is created the linked list of allocated blocks is |
||||||
|
+ * initialized to be empty. |
||||||
|
+ * |
||||||
|
+ * Allocation & Freeing |
||||||
|
+ * -------------------- |
||||||
|
+ * |
||||||
|
+ * Since each allocation (via p_malloc()) corresponds to one block, |
||||||
|
+ * allocations are simply a matter of: |
||||||
|
+ * |
||||||
|
+ * - allocating enough memory from the system heap (via calloc()) to hold |
||||||
|
+ * the block header and the requested number of bytes, |
||||||
|
+ * - making a note of the user-requested size in the block header, |
||||||
|
+ * - adding the new block to the pool's linked list of blocks, and |
||||||
|
+ * - returning a pointer to the payload area of the block to the caller. |
||||||
|
+ * |
||||||
|
+ * Freeing memory is simpler. The passed in pointer is converted to a |
||||||
|
+ * struct pool_block pointer. Then the block is removed from the pool's |
||||||
|
+ * linked list and free()d. |
||||||
|
+ * |
||||||
|
+ * If the pool was created via pool_allocfree_create_clean(), all blocks are |
||||||
|
+ * safe_memset() to zero just before being free()d. |
||||||
|
+ * |
||||||
|
+ * Reallocation |
||||||
|
+ * ------------ |
||||||
|
+ * |
||||||
|
+ * Reallocation is done by calling realloc() with a new size that is large |
||||||
|
+ * enough to cover the requested number of bytes plus the block header |
||||||
|
+ * overhead. |
||||||
|
+ * |
||||||
|
+ * Clearing |
||||||
|
+ * -------- |
||||||
|
+ * |
||||||
|
+ * Clearing the pool is supposed to return the pool to the same state it was |
||||||
|
+ * in when it was first created. To that end, the allocfree pool frees all |
||||||
|
+ * the blocks allocated since the pool's creation. In other words, clearing |
||||||
|
+ * is equivalent to (but faster than) calling p_free() for each allocation |
||||||
|
+ * in the pool. |
||||||
|
+ * |
||||||
|
+ * Finally, if the pool was created via pool_allocfree_create_clean(), all |
||||||
|
+ * blocks are safe_memset() to zero before being free()d. |
||||||
|
+ * |
||||||
|
+ * Destruction |
||||||
|
+ * ----------- |
||||||
|
+ * |
||||||
|
+ * Destroying a pool first clears it (see above) and then the pool structure |
||||||
|
+ * itself is safe_memset() to zero (if pool_allocfree_create_clean() was |
||||||
|
+ * used) and free()d. (The clearing leaves the pool in a minimal state |
||||||
|
+ * with no blocks allocated.) |
||||||
|
+ */ |
||||||
|
+ |
||||||
|
+struct allocfree_pool { |
||||||
|
+ struct pool pool; |
||||||
|
+ int refcount; |
||||||
|
+ size_t total_alloc_count; |
||||||
|
+ size_t total_alloc_used; |
||||||
|
+ |
||||||
|
+ struct pool_block *blocks; |
||||||
|
+#ifdef DEBUG |
||||||
|
+ char *name; |
||||||
|
+#endif |
||||||
|
+ bool clean_frees; |
||||||
|
+}; |
||||||
|
+ |
||||||
|
+struct pool_block { |
||||||
|
+ struct pool_block *prev,*next; |
||||||
|
+ |
||||||
|
+ size_t size; |
||||||
|
+ unsigned char *block; |
||||||
|
+}; |
||||||
|
+ |
||||||
|
+#define SIZEOF_ALLOCFREE_POOL MEM_ALIGN(sizeof(struct allocfree_pool)) |
||||||
|
+#define SIZEOF_POOLBLOCK (MEM_ALIGN(sizeof(struct pool_block))) |
||||||
|
+ |
||||||
|
+static const char *pool_allocfree_get_name(pool_t pool); |
||||||
|
+static void pool_allocfree_ref(pool_t pool); |
||||||
|
+static void pool_allocfree_unref(pool_t *pool); |
||||||
|
+static void *pool_allocfree_malloc(pool_t pool, size_t size); |
||||||
|
+static void pool_allocfree_free(pool_t pool, void *mem); |
||||||
|
+static void *pool_allocfree_realloc(pool_t pool, void *mem, |
||||||
|
+ size_t old_size, size_t new_size); |
||||||
|
+static void pool_allocfree_clear(pool_t pool); |
||||||
|
+static size_t pool_allocfree_get_max_easy_alloc_size(pool_t pool); |
||||||
|
+ |
||||||
|
+static const struct pool_vfuncs static_allocfree_pool_vfuncs = { |
||||||
|
+ pool_allocfree_get_name, |
||||||
|
+ |
||||||
|
+ pool_allocfree_ref, |
||||||
|
+ pool_allocfree_unref, |
||||||
|
+ |
||||||
|
+ pool_allocfree_malloc, |
||||||
|
+ pool_allocfree_free, |
||||||
|
+ |
||||||
|
+ pool_allocfree_realloc, |
||||||
|
+ |
||||||
|
+ pool_allocfree_clear, |
||||||
|
+ pool_allocfree_get_max_easy_alloc_size |
||||||
|
+}; |
||||||
|
+ |
||||||
|
+static const struct pool static_allocfree_pool = { |
||||||
|
+ .v = &static_allocfree_pool_vfuncs, |
||||||
|
+ |
||||||
|
+ .alloconly_pool = FALSE, |
||||||
|
+ .datastack_pool = FALSE |
||||||
|
+}; |
||||||
|
+ |
||||||
|
+pool_t pool_allocfree_create(const char *name ATTR_UNUSED) |
||||||
|
+{ |
||||||
|
+ struct allocfree_pool *pool; |
||||||
|
+ |
||||||
|
+ if (SIZEOF_POOLBLOCK > (SSIZE_T_MAX - POOL_MAX_ALLOC_SIZE)) |
||||||
|
+ i_panic("POOL_MAX_ALLOC_SIZE is too large"); |
||||||
|
+ |
||||||
|
+ pool = calloc(1, SIZEOF_ALLOCFREE_POOL); |
||||||
|
+ if (pool == NULL) |
||||||
|
+ i_fatal_status(FATAL_OUTOFMEM, "calloc(1, %"PRIuSIZE_T"): Out of memory", |
||||||
|
+ SIZEOF_ALLOCFREE_POOL); |
||||||
|
+#ifdef DEBUG |
||||||
|
+ pool->name = strdup(name); |
||||||
|
+#endif |
||||||
|
+ pool->pool = static_allocfree_pool; |
||||||
|
+ pool->refcount = 1; |
||||||
|
+ return &pool->pool; |
||||||
|
+} |
||||||
|
+ |
||||||
|
+pool_t pool_allocfree_create_clean(const char *name) |
||||||
|
+{ |
||||||
|
+ struct allocfree_pool *apool; |
||||||
|
+ pool_t pool; |
||||||
|
+ |
||||||
|
+ pool = pool_allocfree_create(name); |
||||||
|
+ apool = (struct allocfree_pool *)pool; |
||||||
|
+ apool->clean_frees = TRUE; |
||||||
|
+ return pool; |
||||||
|
+} |
||||||
|
+ |
||||||
|
+static void pool_allocfree_destroy(struct allocfree_pool *apool) |
||||||
|
+{ |
||||||
|
+ pool_allocfree_clear(&apool->pool); |
||||||
|
+ if (apool->clean_frees) |
||||||
|
+ safe_memset(apool, 0, SIZEOF_ALLOCFREE_POOL); |
||||||
|
+#ifdef DEBUG |
||||||
|
+ free(apool->name); |
||||||
|
+#endif |
||||||
|
+ free(apool); |
||||||
|
+} |
||||||
|
+ |
||||||
|
+static const char *pool_allocfree_get_name(pool_t pool ATTR_UNUSED) |
||||||
|
+{ |
||||||
|
+#ifdef DEBUG |
||||||
|
+ struct allocfree_pool *apool = |
||||||
|
+ container_of(pool, struct allocfree_pool, pool); |
||||||
|
+ return apool->name; |
||||||
|
+#else |
||||||
|
+ return "alloc"; |
||||||
|
+#endif |
||||||
|
+} |
||||||
|
+ |
||||||
|
+static void pool_allocfree_ref(pool_t pool) |
||||||
|
+{ |
||||||
|
+ struct allocfree_pool *apool = |
||||||
|
+ container_of(pool, struct allocfree_pool, pool); |
||||||
|
+ i_assert(apool->refcount > 0); |
||||||
|
+ |
||||||
|
+ apool->refcount++; |
||||||
|
+} |
||||||
|
+ |
||||||
|
+static void pool_allocfree_unref(pool_t *_pool) |
||||||
|
+{ |
||||||
|
+ pool_t pool = *_pool; |
||||||
|
+ struct allocfree_pool *apool = |
||||||
|
+ container_of(pool, struct allocfree_pool, pool); |
||||||
|
+ i_assert(apool->refcount > 0); |
||||||
|
+ |
||||||
|
+ /* erase the pointer before freeing anything, as the pointer may |
||||||
|
+ exist inside the pool's memory area */ |
||||||
|
+ *_pool = NULL; |
||||||
|
+ |
||||||
|
+ if (--apool->refcount > 0) |
||||||
|
+ return; |
||||||
|
+ |
||||||
|
+ pool_allocfree_destroy(apool); |
||||||
|
+} |
||||||
|
+ |
||||||
|
+static void *pool_block_attach(struct allocfree_pool *apool, struct pool_block *block) |
||||||
|
+{ |
||||||
|
+ i_assert(block->size > 0); |
||||||
|
+ DLLIST_PREPEND(&apool->blocks, block); |
||||||
|
+ block->block = PTR_OFFSET(block,SIZEOF_POOLBLOCK); |
||||||
|
+ apool->total_alloc_used += block->size; |
||||||
|
+ apool->total_alloc_count++; |
||||||
|
+ return block->block; |
||||||
|
+} |
||||||
|
+ |
||||||
|
+static struct pool_block * |
||||||
|
+pool_block_detach(struct allocfree_pool *apool, unsigned char *mem) |
||||||
|
+{ |
||||||
|
+ struct pool_block *block = PTR_OFFSET(mem, -SIZEOF_POOLBLOCK); |
||||||
|
+ |
||||||
|
+ /* make sure the block we are dealing with is correct */ |
||||||
|
+ i_assert(block->block == mem); |
||||||
|
+ i_assert((block->prev == NULL || block->prev->next == block) && |
||||||
|
+ (block->next == NULL || block->next->prev == block)); |
||||||
|
+ |
||||||
|
+ i_assert(apool->total_alloc_used >= block->size); |
||||||
|
+ i_assert(apool->total_alloc_count > 0); |
||||||
|
+ DLLIST_REMOVE(&apool->blocks, block); |
||||||
|
+ apool->total_alloc_used -= block->size; |
||||||
|
+ apool->total_alloc_count--; |
||||||
|
+ |
||||||
|
+ return block; |
||||||
|
+} |
||||||
|
+ |
||||||
|
+static void *pool_allocfree_malloc(pool_t pool, size_t size) |
||||||
|
+{ |
||||||
|
+ struct allocfree_pool *apool = |
||||||
|
+ container_of(pool, struct allocfree_pool, pool); |
||||||
|
+ |
||||||
|
+ struct pool_block *block = calloc(1, SIZEOF_POOLBLOCK + size); |
||||||
|
+ if (block == NULL) |
||||||
|
+ i_fatal_status(FATAL_OUTOFMEM, "calloc(1, %"PRIuSIZE_T"): Out of memory", |
||||||
|
+ SIZEOF_POOLBLOCK + size); |
||||||
|
+ block->size = size; |
||||||
|
+ return pool_block_attach(apool, block); |
||||||
|
+} |
||||||
|
+ |
||||||
|
+static void pool_allocfree_free(pool_t pool, void *mem) |
||||||
|
+{ |
||||||
|
+ struct allocfree_pool *apool = |
||||||
|
+ container_of(pool, struct allocfree_pool, pool); |
||||||
|
+ struct pool_block *block = pool_block_detach(apool, mem); |
||||||
|
+ if (apool->clean_frees) |
||||||
|
+ safe_memset(block, 0, SIZEOF_POOLBLOCK+block->size); |
||||||
|
+ free(block); |
||||||
|
+} |
||||||
|
+ |
||||||
|
+static void *pool_allocfree_realloc(pool_t pool, void *mem, |
||||||
|
+ size_t old_size, size_t new_size) |
||||||
|
+{ |
||||||
|
+ struct allocfree_pool *apool = |
||||||
|
+ container_of(pool, struct allocfree_pool, pool); |
||||||
|
+ unsigned char *new_mem; |
||||||
|
+ |
||||||
|
+ struct pool_block *block = pool_block_detach(apool, mem); |
||||||
|
+ if ((new_mem = realloc(block, SIZEOF_POOLBLOCK+new_size)) == NULL) |
||||||
|
+ i_fatal_status(FATAL_OUTOFMEM, "realloc(block, %"PRIuSIZE_T")", |
||||||
|
+ SIZEOF_POOLBLOCK+new_size); |
||||||
|
+ |
||||||
|
+ /* zero out new memory */ |
||||||
|
+ if (new_size > old_size) |
||||||
|
+ memset(new_mem + SIZEOF_POOLBLOCK + old_size, 0, |
||||||
|
+ new_size - old_size); |
||||||
|
+ block = (struct pool_block*)new_mem; |
||||||
|
+ block->size = new_size; |
||||||
|
+ return pool_block_attach(apool, block); |
||||||
|
+} |
||||||
|
+ |
||||||
|
+static void pool_allocfree_clear(pool_t pool) |
||||||
|
+{ |
||||||
|
+ struct allocfree_pool *apool = |
||||||
|
+ container_of(pool, struct allocfree_pool, pool); |
||||||
|
+ struct pool_block *block, *next; |
||||||
|
+ |
||||||
|
+ for (block = apool->blocks; block != NULL; block = next) { |
||||||
|
+ next = block->next; |
||||||
|
+ pool_allocfree_free(pool, block->block); |
||||||
|
+ } |
||||||
|
+ i_assert(apool->total_alloc_used == 0 && apool->total_alloc_count == 0); |
||||||
|
+} |
||||||
|
+ |
||||||
|
+static size_t pool_allocfree_get_max_easy_alloc_size(pool_t pool ATTR_UNUSED) |
||||||
|
+{ |
||||||
|
+ return 0; |
||||||
|
+} |
||||||
|
+ |
||||||
|
+size_t pool_allocfree_get_total_used_size(pool_t pool) |
||||||
|
+{ |
||||||
|
+ struct allocfree_pool *apool = |
||||||
|
+ container_of(pool, struct allocfree_pool, pool); |
||||||
|
+ return apool->total_alloc_used; |
||||||
|
+} |
||||||
|
+ |
||||||
|
+size_t pool_allocfree_get_total_alloc_size(pool_t pool) |
||||||
|
+{ |
||||||
|
+ struct allocfree_pool *apool = |
||||||
|
+ container_of(pool, struct allocfree_pool, pool); |
||||||
|
+ return apool->total_alloc_used + |
||||||
|
+ SIZEOF_POOLBLOCK*apool->total_alloc_count + sizeof(*apool); |
||||||
|
+} |
||||||
|
diff -up dovecot-2.2.36/src/lib/mempool.h.CVE_2020_12674prereq dovecot-2.2.36/src/lib/mempool.h |
||||||
|
--- dovecot-2.2.36/src/lib/mempool.h.CVE_2020_12674prereq 2018-04-30 15:52:05.000000000 +0200 |
||||||
|
+++ dovecot-2.2.36/src/lib/mempool.h 2020-08-09 14:37:53.483591170 +0200 |
||||||
|
@@ -10,6 +10,11 @@ |
||||||
|
pools to disable the warning. */ |
||||||
|
#define MEMPOOL_GROWING "GROWING-" |
||||||
|
|
||||||
|
+/* The maximum allocation size that's allowed. Anything larger than that |
||||||
|
+ will panic. No pool ever should need more than 4kB of overhead per |
||||||
|
+ allocation. */ |
||||||
|
+#define POOL_MAX_ALLOC_SIZE (SSIZE_T_MAX - 4096) |
||||||
|
+ |
||||||
|
/* Memory allocated and reallocated (the new data in it) in pools is always |
||||||
|
zeroed, it will cost only a few CPU cycles and may well save some debug |
||||||
|
time. */ |
||||||
|
@@ -63,6 +68,10 @@ pool_t pool_alloconly_create(const char |
||||||
|
needed. */ |
||||||
|
pool_t pool_alloconly_create_clean(const char *name, size_t size); |
||||||
|
|
||||||
|
+/* Create new alloc pool. This is very similar to system pool, but it |
||||||
|
+ will deallocate all memory on deinit. */ |
||||||
|
+pool_t pool_allocfree_create(const char *name); |
||||||
|
+ |
||||||
|
/* When allocating memory from returned pool, the data stack frame must be |
||||||
|
the same as it was when calling this function. pool_unref() also checks |
||||||
|
that the stack frame is the same. This should make it quite safe to use. */ |
@ -0,0 +1,5 @@ |
|||||||
|
imap/tcp |
||||||
|
imaps/tcp |
||||||
|
pop3/tcp |
||||||
|
pop3s/tcp |
||||||
|
sieve/tcp |
@ -1 +1,2 @@ |
|||||||
d /var/run/dovecot 0755 root dovecot - |
d /var/run/dovecot 0755 root dovecot - |
||||||
|
|
||||||
|
@ -0,0 +1,3 @@ |
|||||||
|
#!/bin/sh |
||||||
|
/bin/systemctl -q is-enabled NetworkManager.service >/dev/null 2>&1 && /usr/bin/nm-online -q --timeout 30 ||: |
||||||
|
|
Loading…
Reference in new issue