Blame SOURCES/dovecot-2.3.8-CVE_2020_12674prereq.patch

5be1f1
diff -up dovecot-2.2.36/src/auth/auth-request.c.CVE_2020_12674prereq dovecot-2.2.36/src/auth/auth-request.c
5be1f1
--- dovecot-2.2.36/src/auth/auth-request.c.CVE_2020_12674prereq	2020-08-09 14:37:53.468591087 +0200
5be1f1
+++ dovecot-2.2.36/src/auth/auth-request.c	2020-08-09 14:37:53.482591165 +0200
5be1f1
@@ -16,6 +16,7 @@
5be1f1
 #include "auth-cache.h"
5be1f1
 #include "auth-request.h"
5be1f1
 #include "auth-request-handler.h"
5be1f1
+#include "auth-request-handler-private.h"
5be1f1
 #include "auth-request-stats.h"
5be1f1
 #include "auth-client-connection.h"
5be1f1
 #include "auth-master-connection.h"
5be1f1
@@ -68,9 +69,6 @@ static void
5be1f1
 auth_request_userdb_import(struct auth_request *request, const char *args);
5be1f1
 
5be1f1
 static
5be1f1
-void auth_request_verify_plain_continue(struct auth_request *request,
5be1f1
-					verify_plain_callback_t *callback);
5be1f1
-static
5be1f1
 void auth_request_lookup_credentials_policy_continue(struct auth_request *request,
5be1f1
 						     lookup_credentials_callback_t *callback);
5be1f1
 static
5be1f1
@@ -211,10 +209,12 @@ void auth_request_success_continue(struc
5be1f1
 		return;
5be1f1
 	}
5be1f1
 
5be1f1
-	stats = auth_request_stats_get(request);
5be1f1
-	stats->auth_success_count++;
5be1f1
-	if (request->master_user != NULL)
5be1f1
-		stats->auth_master_success_count++;
5be1f1
+	if (request->set->stats) {
5be1f1
+		stats = auth_request_stats_get(request);
5be1f1
+		stats->auth_success_count++;
5be1f1
+		if (request->master_user != NULL)
5be1f1
+			stats->auth_master_success_count++;
5be1f1
+	}
5be1f1
 
5be1f1
 	auth_request_set_state(request, AUTH_REQUEST_STATE_FINISHED);
5be1f1
 	auth_request_refresh_last_access(request);
5be1f1
@@ -228,8 +228,10 @@ void auth_request_fail(struct auth_reque
5be1f1
 
5be1f1
 	i_assert(request->state == AUTH_REQUEST_STATE_MECH_CONTINUE);
5be1f1
 
5be1f1
-	stats = auth_request_stats_get(request);
5be1f1
-	stats->auth_failure_count++;
5be1f1
+	if (request->set->stats) {
5be1f1
+		stats = auth_request_stats_get(request);
5be1f1
+		stats->auth_failure_count++;
5be1f1
+	}
5be1f1
 
5be1f1
 	auth_request_set_state(request, AUTH_REQUEST_STATE_FINISHED);
5be1f1
 	auth_request_refresh_last_access(request);
5be1f1
@@ -989,7 +991,7 @@ void auth_request_policy_penalty_finish(
5be1f1
 
5be1f1
 	switch(ctx->type) {
5be1f1
 	case AUTH_POLICY_CHECK_TYPE_PLAIN:
5be1f1
-		auth_request_verify_plain_continue(ctx->request, ctx->callback_plain);
5be1f1
+		ctx->request->handler->verify_plain_continue_callback(ctx->request, ctx->callback_plain);
5be1f1
 		return;
5be1f1
 	case AUTH_POLICY_CHECK_TYPE_LOOKUP:
5be1f1
 		auth_request_lookup_credentials_policy_continue(ctx->request, ctx->callback_lookup);
5be1f1
@@ -1036,7 +1038,8 @@ void auth_request_verify_plain(struct au
5be1f1
 	request->user_changed_by_lookup = FALSE;
5be1f1
 
5be1f1
 	if (request->policy_processed || !request->set->policy_check_before_auth) {
5be1f1
-		auth_request_verify_plain_continue(request, callback);
5be1f1
+		request->handler->verify_plain_continue_callback(request,
5be1f1
+								 callback);
5be1f1
 	} else {
5be1f1
 		ctx = p_new(request->pool, struct auth_policy_check_ctx, 1);
5be1f1
 		ctx->request = request;
5be1f1
@@ -1046,9 +1049,9 @@ void auth_request_verify_plain(struct au
5be1f1
 	}
5be1f1
 }
5be1f1
 
5be1f1
-static
5be1f1
-void auth_request_verify_plain_continue(struct auth_request *request,
5be1f1
-					verify_plain_callback_t *callback) {
5be1f1
+void auth_request_default_verify_plain_continue(struct auth_request *request,
5be1f1
+						verify_plain_callback_t *callback)
5be1f1
+{
5be1f1
 
5be1f1
 	struct auth_passdb *passdb;
5be1f1
 	enum passdb_result result;
5be1f1
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
5be1f1
--- dovecot-2.2.36/src/auth/auth-request-handler.c.CVE_2020_12674prereq	2020-08-09 14:37:53.467591082 +0200
5be1f1
+++ dovecot-2.2.36/src/auth/auth-request-handler.c	2020-08-09 14:37:53.482591165 +0200
5be1f1
@@ -16,32 +16,29 @@
5be1f1
 #include "auth-token.h"
5be1f1
 #include "auth-master-connection.h"
5be1f1
 #include "auth-request-handler.h"
5be1f1
+#include "auth-request-handler-private.h"
5be1f1
 #include "auth-policy.h"
5be1f1
 
5be1f1
 #define AUTH_FAILURE_DELAY_CHECK_MSECS 500
5be1f1
 
5be1f1
-struct auth_request_handler {
5be1f1
-	int refcount;
5be1f1
-	pool_t pool;
5be1f1
-	HASH_TABLE(void *, struct auth_request *) requests;
5be1f1
-
5be1f1
-        unsigned int connect_uid, client_pid;
5be1f1
-
5be1f1
-	auth_client_request_callback_t *callback;
5be1f1
-	struct auth_client_connection *conn;
5be1f1
-
5be1f1
-	auth_master_request_callback_t *master_callback;
5be1f1
-
5be1f1
-	unsigned int destroyed:1;
5be1f1
-	unsigned int token_auth:1;
5be1f1
-};
5be1f1
-
5be1f1
 static ARRAY(struct auth_request *) auth_failures_arr;
5be1f1
 static struct aqueue *auth_failures;
5be1f1
 static struct timeout *to_auth_failures;
5be1f1
 
5be1f1
 static void auth_failure_timeout(void *context) ATTR_NULL(1);
5be1f1
 
5be1f1
+static void
5be1f1
+auth_request_handler_default_reply_callback(struct auth_request *request,
5be1f1
+					    enum auth_client_result result,
5be1f1
+					    const void *auth_reply,
5be1f1
+					    size_t reply_size);
5be1f1
+
5be1f1
+static void
5be1f1
+auth_request_handler_default_reply_continue(struct auth_request *request,
5be1f1
+					    const void *reply,
5be1f1
+					    size_t reply_size);
5be1f1
+
5be1f1
+
5be1f1
 struct auth_request_handler *
5be1f1
 auth_request_handler_create(bool token_auth, auth_client_request_callback_t *callback,
5be1f1
 			    struct auth_client_connection *conn,
5be1f1
@@ -60,6 +57,12 @@ auth_request_handler_create(bool token_a
5be1f1
 	handler->conn = conn;
5be1f1
 	handler->master_callback = master_callback;
5be1f1
 	handler->token_auth = token_auth;
5be1f1
+	handler->reply_callback =
5be1f1
+		auth_request_handler_default_reply_callback;
5be1f1
+	handler->reply_continue_callback =
5be1f1
+		auth_request_handler_default_reply_continue;
5be1f1
+	handler->verify_plain_continue_callback =
5be1f1
+		auth_request_default_verify_plain_continue;
5be1f1
 	return handler;
5be1f1
 }
5be1f1
 
5be1f1
@@ -342,6 +345,16 @@ void auth_request_handler_reply(struct a
5be1f1
 				enum auth_client_result result,
5be1f1
 				const void *auth_reply, size_t reply_size)
5be1f1
 {
5be1f1
+	struct auth_request_handler *handler = request->handler;
5be1f1
+	handler->reply_callback(request, result, auth_reply, reply_size);
5be1f1
+}
5be1f1
+
5be1f1
+static void
5be1f1
+auth_request_handler_default_reply_callback(struct auth_request *request,
5be1f1
+					    enum auth_client_result result,
5be1f1
+					    const void *auth_reply,
5be1f1
+					    size_t reply_size)
5be1f1
+{
5be1f1
         struct auth_request_handler *handler = request->handler;
5be1f1
 	string_t *str;
5be1f1
 	int ret;
5be1f1
@@ -394,6 +407,14 @@ void auth_request_handler_reply(struct a
5be1f1
 void auth_request_handler_reply_continue(struct auth_request *request,
5be1f1
 					 const void *reply, size_t reply_size)
5be1f1
 {
5be1f1
+	request->handler->reply_continue_callback(request, reply, reply_size);
5be1f1
+}
5be1f1
+
5be1f1
+static void
5be1f1
+auth_request_handler_default_reply_continue(struct auth_request *request,
5be1f1
+					    const void *reply,
5be1f1
+					    size_t reply_size)
5be1f1
+{
5be1f1
 	auth_request_handler_reply(request, AUTH_CLIENT_RESULT_CONTINUE,
5be1f1
 				   reply, reply_size);
5be1f1
 }
5be1f1
@@ -657,6 +678,7 @@ static void auth_str_append_userdb_extra
5be1f1
 		auth_str_add_keyvalue(dest, "master_user",
5be1f1
 				      request->master_user);
5be1f1
 	}
5be1f1
+	auth_str_add_keyvalue(dest, "auth_mech", request->mech->mech_name);
5be1f1
 	if (*request->set->anonymous_username != '\0' &&
5be1f1
 	    strcmp(request->user, request->set->anonymous_username) == 0) {
5be1f1
 		/* this is an anonymous login, either via ANONYMOUS
5be1f1
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
5be1f1
--- dovecot-2.2.36/src/auth/auth-request-handler.h.CVE_2020_12674prereq	2017-06-23 13:18:28.000000000 +0200
5be1f1
+++ dovecot-2.2.36/src/auth/auth-request-handler.h	2020-08-09 14:37:53.482591165 +0200
5be1f1
@@ -17,6 +17,17 @@ auth_client_request_callback_t(const cha
5be1f1
 typedef void
5be1f1
 auth_master_request_callback_t(const char *reply, struct auth_master_connection *conn);
5be1f1
 
5be1f1
+typedef void
5be1f1
+auth_request_handler_reply_callback_t(struct auth_request *request,
5be1f1
+				      enum auth_client_result result,
5be1f1
+				      const void *auth_reply,
5be1f1
+				      size_t reply_size);
5be1f1
+typedef void
5be1f1
+auth_request_handler_reply_continue_callback_t(struct auth_request *request,
5be1f1
+					       const void *reply,
5be1f1
+					       size_t reply_size);
5be1f1
+
5be1f1
+
5be1f1
 struct auth_request_handler *
5be1f1
 auth_request_handler_create(bool token_auth, auth_client_request_callback_t *callback,
5be1f1
 			    struct auth_client_connection *conn,
5be1f1
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
5be1f1
--- dovecot-2.2.36/src/auth/auth-request-handler-private.h.CVE_2020_12674prereq	2020-08-09 14:37:53.482591165 +0200
5be1f1
+++ dovecot-2.2.36/src/auth/auth-request-handler-private.h	2020-08-09 14:37:53.482591165 +0200
5be1f1
@@ -0,0 +1,27 @@
5be1f1
+#ifndef AUTH_REQUEST_HANDLER_PRIVATE_H
5be1f1
+#define AUTH_REQUEST_HANDLER_PRIVATE_H
5be1f1
+
5be1f1
+struct auth_request;
5be1f1
+struct auth_client_connection;
5be1f1
+
5be1f1
+struct auth_request_handler {
5be1f1
+	int refcount;
5be1f1
+	pool_t pool;
5be1f1
+	HASH_TABLE(void *, struct auth_request *) requests;
5be1f1
+
5be1f1
+        unsigned int connect_uid, client_pid;
5be1f1
+
5be1f1
+	auth_client_request_callback_t *callback;
5be1f1
+	struct auth_client_connection *conn;
5be1f1
+
5be1f1
+	auth_master_request_callback_t *master_callback;
5be1f1
+	auth_request_handler_reply_callback_t *reply_callback;
5be1f1
+	auth_request_handler_reply_continue_callback_t *reply_continue_callback;
5be1f1
+	verify_plain_continue_callback_t *verify_plain_continue_callback;
5be1f1
+
5be1f1
+	bool destroyed:1;
5be1f1
+	bool token_auth:1;
5be1f1
+};
5be1f1
+
5be1f1
+
5be1f1
+#endif
5be1f1
diff -up dovecot-2.2.36/src/auth/auth-request.h.CVE_2020_12674prereq dovecot-2.2.36/src/auth/auth-request.h
5be1f1
--- dovecot-2.2.36/src/auth/auth-request.h.CVE_2020_12674prereq	2018-04-30 15:52:05.000000000 +0200
5be1f1
+++ dovecot-2.2.36/src/auth/auth-request.h	2020-08-09 14:37:53.482591165 +0200
5be1f1
@@ -269,6 +269,8 @@ void auth_request_set_credentials(struct
5be1f1
 				  set_credentials_callback_t *callback);
5be1f1
 void auth_request_userdb_callback(enum userdb_result result,
5be1f1
 				  struct auth_request *request);
5be1f1
+void auth_request_default_verify_plain_continue(struct auth_request *request,
5be1f1
+						verify_plain_callback_t *callback);
5be1f1
 
5be1f1
 void auth_request_refresh_last_access(struct auth_request *request);
5be1f1
 void auth_str_append(string_t *dest, const char *key, const char *value);
5be1f1
diff -up dovecot-2.2.36/src/auth/Makefile.am.CVE_2020_12674prereq dovecot-2.2.36/src/auth/Makefile.am
5be1f1
--- dovecot-2.2.36/src/auth/Makefile.am.CVE_2020_12674prereq	2018-04-30 15:52:05.000000000 +0200
5be1f1
+++ dovecot-2.2.36/src/auth/Makefile.am	2020-08-09 14:37:53.482591165 +0200
5be1f1
@@ -227,7 +227,8 @@ test_programs = \
5be1f1
 	test-auth-cache \
5be1f1
 	test-auth-request-var-expand \
5be1f1
 	test-username-filter \
5be1f1
-	test-db-dict
5be1f1
+	test-db-dict \
5be1f1
+	test-mech
5be1f1
 
5be1f1
 noinst_PROGRAMS = $(test_programs)
5be1f1
 
5be1f1
@@ -253,6 +254,13 @@ test_db_dict_SOURCES = test-db-dict.c
5be1f1
 test_db_dict_LDADD = $(test_libs) libauth.la
5be1f1
 test_db_dict_DEPENDENCIES = $(pkglibexec_PROGRAMS) $(test_libs)
5be1f1
 
5be1f1
+test_mech_SOURCES = \
5be1f1
+	test-mock.c \
5be1f1
+	test-mech.c
5be1f1
+
5be1f1
+test_mech_LDADD = $(test_libs) $(auth_libs) $(AUTH_LIBS)
5be1f1
+test_mech_DEPENDENCIES = $(pkglibexec_PROGRAMS) $(test_libs)
5be1f1
+
5be1f1
 check: check-am check-test
5be1f1
 check-test: all-am
5be1f1
 	for bin in $(test_programs); do \
5be1f1
diff -up dovecot-2.2.36/src/auth/passdb.h.CVE_2020_12674prereq dovecot-2.2.36/src/auth/passdb.h
5be1f1
--- dovecot-2.2.36/src/auth/passdb.h.CVE_2020_12674prereq	2018-04-30 15:52:05.000000000 +0200
5be1f1
+++ dovecot-2.2.36/src/auth/passdb.h	2020-08-09 14:37:53.482591165 +0200
5be1f1
@@ -24,6 +24,8 @@ enum passdb_result {
5be1f1
 
5be1f1
 typedef void verify_plain_callback_t(enum passdb_result result,
5be1f1
 				     struct auth_request *request);
5be1f1
+typedef void verify_plain_continue_callback_t(struct auth_request *request,
5be1f1
+					      verify_plain_callback_t *callback);
5be1f1
 typedef void lookup_credentials_callback_t(enum passdb_result result,
5be1f1
 					   const unsigned char *credentials,
5be1f1
 					   size_t size,
5be1f1
diff -up dovecot-2.2.36/src/auth/test-auth.h.CVE_2020_12674prereq dovecot-2.2.36/src/auth/test-auth.h
5be1f1
--- dovecot-2.2.36/src/auth/test-auth.h.CVE_2020_12674prereq	2020-08-09 14:38:24.950765769 +0200
5be1f1
+++ dovecot-2.2.36/src/auth/test-auth.h	2020-08-09 14:38:06.304662311 +0200
5be1f1
@@ -0,0 +1,21 @@
5be1f1
+/* Copyright (c) 2017-2018 Dovecot authors, see the included COPYING file */
5be1f1
+
5be1f1
+#ifndef TEST_AUTH_H
5be1f1
+#define TEST_AUTH_H 1
5be1f1
+
5be1f1
+#include "lib.h"
5be1f1
+#include "test-common.h"
5be1f1
+
5be1f1
+struct auth_passdb;
5be1f1
+struct auth_passdb_settings mock_passdb_set;
5be1f1
+
5be1f1
+void test_auth_request_var_expand(void);
5be1f1
+void test_db_dict_parse_cache_key(void);
5be1f1
+void test_username_filter(void);
5be1f1
+void test_db_lua(void);
5be1f1
+struct auth_passdb *passdb_mock(void);
5be1f1
+void passdb_mock_mod_init(void);
5be1f1
+void passdb_mock_mod_deinit(void);
5be1f1
+
5be1f1
+#endif
5be1f1
+
5be1f1
diff -up dovecot-2.2.36/src/auth/test-mock.c.CVE_2020_12674prereq dovecot-2.2.36/src/auth/test-mock.c
5be1f1
--- dovecot-2.2.36/src/auth/test-mock.c.CVE_2020_12674prereq	2020-08-09 14:37:53.483591170 +0200
5be1f1
+++ dovecot-2.2.36/src/auth/test-mock.c	2020-08-09 14:37:53.483591170 +0200
5be1f1
@@ -0,0 +1,109 @@
5be1f1
+/* Copyright (c) 2017-2018 Dovecot authors, see the included COPYING file */
5be1f1
+
5be1f1
+#include "test-auth.h"
5be1f1
+#include "auth-common.h"
5be1f1
+#include "passdb.h"
5be1f1
+
5be1f1
+struct auth_penalty *auth_penalty;
5be1f1
+time_t process_start_time;
5be1f1
+bool worker, worker_restart_request;
5be1f1
+static struct passdb_module *mock_passdb_mod = NULL;
5be1f1
+static pool_t mock_pool;
5be1f1
+
5be1f1
+void auth_module_load(const char *names ATTR_UNUSED)
5be1f1
+{
5be1f1
+}
5be1f1
+void auth_refresh_proctitle(void) {
5be1f1
+}
5be1f1
+
5be1f1
+static void passdb_mock_init(struct passdb_module *module ATTR_UNUSED)
5be1f1
+{
5be1f1
+}
5be1f1
+static void passdb_mock_deinit(struct passdb_module *module ATTR_UNUSED)
5be1f1
+{
5be1f1
+}
5be1f1
+static void passdb_mock_verify_plain(struct auth_request *request, const char *password ATTR_UNUSED,
5be1f1
+				     verify_plain_callback_t *callback)
5be1f1
+{
5be1f1
+	callback(PASSDB_RESULT_OK, request);
5be1f1
+}
5be1f1
+
5be1f1
+static void passdb_mock_lookup_credentials(struct auth_request *request,
5be1f1
+					   lookup_credentials_callback_t *callback)
5be1f1
+{
5be1f1
+	passdb_handle_credentials(PASSDB_RESULT_OK, "password", "PLAIN",
5be1f1
+				  callback, request);
5be1f1
+}
5be1f1
+
5be1f1
+static struct passdb_module_interface mock_interface = {
5be1f1
+	.name = "mock",
5be1f1
+	.init = passdb_mock_init,
5be1f1
+	.deinit = passdb_mock_deinit,
5be1f1
+	.verify_plain = passdb_mock_verify_plain,
5be1f1
+	.lookup_credentials = passdb_mock_lookup_credentials,
5be1f1
+};
5be1f1
+
5be1f1
+struct auth_passdb_settings mock_passdb_set = {
5be1f1
+	.name = "mock",
5be1f1
+	.driver = "mock",
5be1f1
+	.args = "",
5be1f1
+	.default_fields = "",
5be1f1
+	.override_fields = "",
5be1f1
+	.mechanisms = "",
5be1f1
+	.username_filter = "",
5be1f1
+	.skip = "never",
5be1f1
+	.result_success = "return-ok",
5be1f1
+	.result_failure = "continue",
5be1f1
+	.result_internalfail = "continue",
5be1f1
+	.deny = FALSE,
5be1f1
+	.pass = FALSE,
5be1f1
+	.master = FALSE,
5be1f1
+	.auth_verbose = "default"
5be1f1
+};
5be1f1
+
5be1f1
+void passdb_mock_mod_init(void)
5be1f1
+{
5be1f1
+	if (mock_passdb_mod != NULL)
5be1f1
+		return;
5be1f1
+
5be1f1
+	mock_pool = pool_allocfree_create("auth mock");
5be1f1
+
5be1f1
+	passdb_register_module(&mock_interface);
5be1f1
+
5be1f1
+	struct auth_passdb_settings set = {
5be1f1
+		.name = "mock",
5be1f1
+		.driver = "mock",
5be1f1
+		.args = "",
5be1f1
+		.default_fields = "",
5be1f1
+		.override_fields = "",
5be1f1
+		.mechanisms = "",
5be1f1
+		.username_filter = "",
5be1f1
+
5be1f1
+		.skip = "never",
5be1f1
+		.result_success = "return-ok",
5be1f1
+		.result_failure = "continue",
5be1f1
+		.result_internalfail = "continue",
5be1f1
+
5be1f1
+		.deny = FALSE,
5be1f1
+		.pass = FALSE,
5be1f1
+		.master = FALSE,
5be1f1
+		.auth_verbose = "default"
5be1f1
+	};
5be1f1
+	mock_passdb_mod = passdb_preinit(mock_pool, &set);
5be1f1
+	passdb_init(mock_passdb_mod);
5be1f1
+}
5be1f1
+
5be1f1
+void passdb_mock_mod_deinit(void)
5be1f1
+{
5be1f1
+	passdb_deinit(mock_passdb_mod);
5be1f1
+	passdb_unregister_module(&mock_interface);
5be1f1
+	pool_unref(&mock_pool);
5be1f1
+}
5be1f1
+
5be1f1
+struct auth_passdb *passdb_mock(void)
5be1f1
+{
5be1f1
+	struct auth_passdb *ret = i_new(struct auth_passdb, 1);
5be1f1
+	ret->set = &mock_passdb_set;
5be1f1
+	ret->passdb = mock_passdb_mod;
5be1f1
+	return ret;
5be1f1
+}
5be1f1
diff -up dovecot-2.2.36/src/lib/lib.c.CVE_2020_12674prereq dovecot-2.2.36/src/lib/lib.c
5be1f1
--- dovecot-2.2.36/src/lib/lib.c.CVE_2020_12674prereq	2018-04-30 15:52:05.000000000 +0200
5be1f1
+++ dovecot-2.2.36/src/lib/lib.c	2020-08-09 14:37:53.483591170 +0200
5be1f1
@@ -175,7 +175,7 @@ void lib_init(void)
5be1f1
 	hostpid_init();
5be1f1
 	lib_open_non_stdio_dev_null();
5be1f1
 	var_expand_extensions_init();
5be1f1
-
5be1f1
+	random_init();
5be1f1
 	lib_initialized = TRUE;
5be1f1
 }
5be1f1
 
5be1f1
diff -up dovecot-2.2.36/src/lib/lib.h.CVE_2020_12674prereq dovecot-2.2.36/src/lib/lib.h
5be1f1
--- dovecot-2.2.36/src/lib/lib.h.CVE_2020_12674prereq   2020-08-24 14:42:44.084069002 +0200
5be1f1
+++ dovecot-2.2.36/src/lib/lib.h        2020-08-24 14:42:44.108068770 +0200
5be1f1
@@ -33,6 +33,7 @@
5be1f1
 #include "imem.h"
5be1f1
 #include "byteorder.h"
5be1f1
 #include "rand.h"
5be1f1
+#include "randgen.h"
5be1f1
 
5be1f1
 typedef struct buffer buffer_t;
5be1f1
 typedef struct buffer string_t;
5be1f1
diff -up dovecot-2.2.36/src/lib/Makefile.am.CVE_2020_12674prereq dovecot-2.2.36/src/lib/Makefile.am
5be1f1
--- dovecot-2.2.36/src/lib/Makefile.am.CVE_2020_12674prereq	2020-08-09 14:37:53.464591065 +0200
5be1f1
+++ dovecot-2.2.36/src/lib/Makefile.am	2020-08-09 14:37:53.483591170 +0200
5be1f1
@@ -98,6 +98,7 @@ liblib_la_SOURCES = \
5be1f1
 	md4.c \
5be1f1
 	md5.c \
5be1f1
 	mempool.c \
5be1f1
+	mempool-allocfree.c \
5be1f1
 	mempool-alloconly.c \
5be1f1
 	mempool-datastack.c \
5be1f1
 	mempool-system.c \
5be1f1
diff -up dovecot-2.2.36/src/lib/mempool-allocfree.c.CVE_2020_12674prereq dovecot-2.2.36/src/lib/mempool-allocfree.c
5be1f1
--- dovecot-2.2.36/src/lib/mempool-allocfree.c.CVE_2020_12674prereq	2020-08-09 14:37:53.483591170 +0200
5be1f1
+++ dovecot-2.2.36/src/lib/mempool-allocfree.c	2020-08-09 14:37:53.483591170 +0200
5be1f1
@@ -0,0 +1,328 @@
5be1f1
+/* Copyright (c) 2017-2018 Dovecot authors, see the included COPYING file */
5be1f1
+
5be1f1
+/* @UNSAFE: whole file */
5be1f1
+#include "lib.h"
5be1f1
+#include "safe-memset.h"
5be1f1
+#include "mempool.h"
5be1f1
+#include "llist.h"
5be1f1
+
5be1f1
+/*
5be1f1
+ * As the name implies, allocfree pools support both allocating and freeing
5be1f1
+ * memory.
5be1f1
+ *
5be1f1
+ * Implementation
5be1f1
+ * ==============
5be1f1
+ *
5be1f1
+ * Each allocfree pool contains a pool structure (struct allocfree_pool) to
5be1f1
+ * keep track of allocfree-specific pool information and zero or more blocks
5be1f1
+ * (struct pool_block) that keep track of ranges of memory used to back the
5be1f1
+ * allocations.  The blocks are kept in a doubly-linked list used to keep
5be1f1
+ * track of all allocations that belong to the pool.
5be1f1
+ *
5be1f1
+ * +-----------+
5be1f1
+ * | allocfree |
5be1f1
+ * |    pool   |
5be1f1
+ * +-----+-----+
5be1f1
+ *       |
5be1f1
+ *       | blocks +------------+ next  +------------+ next
5be1f1
+ *       \------->| pool block |<=====>| pool block |<=====>...<====> NULL
5be1f1
+ *                +------------+  prev +------------+  prev
5be1f1
+ *                |   <data>   |       |   <data>   |
5be1f1
+ *                      .                    .
5be1f1
+ *                      .                    .
5be1f1
+ *                      .              |   <data>   |
5be1f1
+ *                      .              +------------+
5be1f1
+ *                |   <data>   |
5be1f1
+ *                +------------+
5be1f1
+ *
5be1f1
+ * Creation
5be1f1
+ * --------
5be1f1
+ *
5be1f1
+ * When an allocfree pool is created the linked list of allocated blocks is
5be1f1
+ * initialized to be empty.
5be1f1
+ *
5be1f1
+ * Allocation & Freeing
5be1f1
+ * --------------------
5be1f1
+ *
5be1f1
+ * Since each allocation (via p_malloc()) corresponds to one block,
5be1f1
+ * allocations are simply a matter of:
5be1f1
+ *
5be1f1
+ *  - allocating enough memory from the system heap (via calloc()) to hold
5be1f1
+ *    the block header and the requested number of bytes,
5be1f1
+ *  - making a note of the user-requested size in the block header,
5be1f1
+ *  - adding the new block to the pool's linked list of blocks, and
5be1f1
+ *  - returning a pointer to the payload area of the block to the caller.
5be1f1
+ *
5be1f1
+ * Freeing memory is simpler.  The passed in pointer is converted to a
5be1f1
+ * struct pool_block pointer.  Then the block is removed from the pool's
5be1f1
+ * linked list and free()d.
5be1f1
+ *
5be1f1
+ * If the pool was created via pool_allocfree_create_clean(), all blocks are
5be1f1
+ * safe_memset() to zero just before being free()d.
5be1f1
+ *
5be1f1
+ * Reallocation
5be1f1
+ * ------------
5be1f1
+ *
5be1f1
+ * Reallocation is done by calling realloc() with a new size that is large
5be1f1
+ * enough to cover the requested number of bytes plus the block header
5be1f1
+ * overhead.
5be1f1
+ *
5be1f1
+ * Clearing
5be1f1
+ * --------
5be1f1
+ *
5be1f1
+ * Clearing the pool is supposed to return the pool to the same state it was
5be1f1
+ * in when it was first created.  To that end, the allocfree pool frees all
5be1f1
+ * the blocks allocated since the pool's creation.  In other words, clearing
5be1f1
+ * is equivalent to (but faster than) calling p_free() for each allocation
5be1f1
+ * in the pool.
5be1f1
+ *
5be1f1
+ * Finally, if the pool was created via pool_allocfree_create_clean(), all
5be1f1
+ * blocks are safe_memset() to zero before being free()d.
5be1f1
+ *
5be1f1
+ * Destruction
5be1f1
+ * -----------
5be1f1
+ *
5be1f1
+ * Destroying a pool first clears it (see above) and then the pool structure
5be1f1
+ * itself is safe_memset() to zero (if pool_allocfree_create_clean() was
5be1f1
+ * used) and free()d.  (The clearing leaves the pool in a minimal state
5be1f1
+ * with no blocks allocated.)
5be1f1
+ */
5be1f1
+
5be1f1
+struct allocfree_pool {
5be1f1
+	struct pool pool;
5be1f1
+	int refcount;
5be1f1
+	size_t total_alloc_count;
5be1f1
+	size_t total_alloc_used;
5be1f1
+
5be1f1
+	struct pool_block *blocks;
5be1f1
+#ifdef DEBUG
5be1f1
+	char *name;
5be1f1
+#endif
5be1f1
+	bool clean_frees;
5be1f1
+};
5be1f1
+
5be1f1
+struct pool_block {
5be1f1
+	struct pool_block *prev,*next;
5be1f1
+
5be1f1
+	size_t size;
5be1f1
+	unsigned char *block;
5be1f1
+};
5be1f1
+
5be1f1
+#define SIZEOF_ALLOCFREE_POOL MEM_ALIGN(sizeof(struct allocfree_pool))
5be1f1
+#define SIZEOF_POOLBLOCK (MEM_ALIGN(sizeof(struct pool_block)))
5be1f1
+
5be1f1
+static const char *pool_allocfree_get_name(pool_t pool);
5be1f1
+static void pool_allocfree_ref(pool_t pool);
5be1f1
+static void pool_allocfree_unref(pool_t *pool);
5be1f1
+static void *pool_allocfree_malloc(pool_t pool, size_t size);
5be1f1
+static void pool_allocfree_free(pool_t pool, void *mem);
5be1f1
+static void *pool_allocfree_realloc(pool_t pool, void *mem,
5be1f1
+				    size_t old_size, size_t new_size);
5be1f1
+static void pool_allocfree_clear(pool_t pool);
5be1f1
+static size_t pool_allocfree_get_max_easy_alloc_size(pool_t pool);
5be1f1
+
5be1f1
+static const struct pool_vfuncs static_allocfree_pool_vfuncs = {
5be1f1
+	pool_allocfree_get_name,
5be1f1
+
5be1f1
+	pool_allocfree_ref,
5be1f1
+	pool_allocfree_unref,
5be1f1
+
5be1f1
+	pool_allocfree_malloc,
5be1f1
+	pool_allocfree_free,
5be1f1
+
5be1f1
+	pool_allocfree_realloc,
5be1f1
+
5be1f1
+	pool_allocfree_clear,
5be1f1
+	pool_allocfree_get_max_easy_alloc_size
5be1f1
+};
5be1f1
+
5be1f1
+static const struct pool static_allocfree_pool = {
5be1f1
+	.v = &static_allocfree_pool_vfuncs,
5be1f1
+
5be1f1
+	.alloconly_pool = FALSE,
5be1f1
+	.datastack_pool = FALSE
5be1f1
+};
5be1f1
+
5be1f1
+pool_t pool_allocfree_create(const char *name ATTR_UNUSED)
5be1f1
+{
5be1f1
+	struct allocfree_pool *pool;
5be1f1
+
5be1f1
+	if (SIZEOF_POOLBLOCK > (SSIZE_T_MAX - POOL_MAX_ALLOC_SIZE))
5be1f1
+		i_panic("POOL_MAX_ALLOC_SIZE is too large");
5be1f1
+
5be1f1
+	pool = calloc(1, SIZEOF_ALLOCFREE_POOL);
5be1f1
+	if (pool == NULL)
5be1f1
+		i_fatal_status(FATAL_OUTOFMEM, "calloc(1, %"PRIuSIZE_T"): Out of memory",
5be1f1
+			       SIZEOF_ALLOCFREE_POOL);
5be1f1
+#ifdef DEBUG
5be1f1
+	pool->name = strdup(name);
5be1f1
+#endif
5be1f1
+	pool->pool = static_allocfree_pool;
5be1f1
+	pool->refcount = 1;
5be1f1
+	return &pool->pool;
5be1f1
+}
5be1f1
+
5be1f1
+pool_t pool_allocfree_create_clean(const char *name)
5be1f1
+{
5be1f1
+	struct allocfree_pool *apool;
5be1f1
+	pool_t pool;
5be1f1
+
5be1f1
+	pool = pool_allocfree_create(name);
5be1f1
+	apool = (struct allocfree_pool *)pool;
5be1f1
+	apool->clean_frees = TRUE;
5be1f1
+	return pool;
5be1f1
+}
5be1f1
+
5be1f1
+static void pool_allocfree_destroy(struct allocfree_pool *apool)
5be1f1
+{
5be1f1
+	pool_allocfree_clear(&apool->pool);
5be1f1
+	if (apool->clean_frees)
5be1f1
+		safe_memset(apool, 0, SIZEOF_ALLOCFREE_POOL);
5be1f1
+#ifdef DEBUG
5be1f1
+	free(apool->name);
5be1f1
+#endif
5be1f1
+	free(apool);
5be1f1
+}
5be1f1
+
5be1f1
+static const char *pool_allocfree_get_name(pool_t pool ATTR_UNUSED)
5be1f1
+{
5be1f1
+#ifdef DEBUG
5be1f1
+	struct allocfree_pool *apool =
5be1f1
+		container_of(pool, struct allocfree_pool, pool);
5be1f1
+	return apool->name;
5be1f1
+#else
5be1f1
+	return "alloc";
5be1f1
+#endif
5be1f1
+}
5be1f1
+
5be1f1
+static void pool_allocfree_ref(pool_t pool)
5be1f1
+{
5be1f1
+	struct allocfree_pool *apool =
5be1f1
+		container_of(pool, struct allocfree_pool, pool);
5be1f1
+	i_assert(apool->refcount > 0);
5be1f1
+
5be1f1
+	apool->refcount++;
5be1f1
+}
5be1f1
+
5be1f1
+static void pool_allocfree_unref(pool_t *_pool)
5be1f1
+{
5be1f1
+	pool_t pool = *_pool;
5be1f1
+	struct allocfree_pool *apool =
5be1f1
+		container_of(pool, struct allocfree_pool, pool);
5be1f1
+	i_assert(apool->refcount > 0);
5be1f1
+
5be1f1
+	/* erase the pointer before freeing anything, as the pointer may
5be1f1
+	   exist inside the pool's memory area */
5be1f1
+	*_pool = NULL;
5be1f1
+
5be1f1
+	if (--apool->refcount > 0)
5be1f1
+		return;
5be1f1
+
5be1f1
+	pool_allocfree_destroy(apool);
5be1f1
+}
5be1f1
+
5be1f1
+static void *pool_block_attach(struct allocfree_pool *apool, struct pool_block *block)
5be1f1
+{
5be1f1
+	i_assert(block->size > 0);
5be1f1
+	DLLIST_PREPEND(&apool->blocks, block);
5be1f1
+	block->block = PTR_OFFSET(block,SIZEOF_POOLBLOCK);
5be1f1
+	apool->total_alloc_used += block->size;
5be1f1
+	apool->total_alloc_count++;
5be1f1
+	return block->block;
5be1f1
+}
5be1f1
+
5be1f1
+static struct pool_block *
5be1f1
+pool_block_detach(struct allocfree_pool *apool, unsigned char *mem)
5be1f1
+{
5be1f1
+	struct pool_block *block = PTR_OFFSET(mem, -SIZEOF_POOLBLOCK);
5be1f1
+
5be1f1
+	/* make sure the block we are dealing with is correct */
5be1f1
+	i_assert(block->block == mem);
5be1f1
+	i_assert((block->prev == NULL || block->prev->next == block) &&
5be1f1
+		 (block->next == NULL || block->next->prev == block));
5be1f1
+
5be1f1
+	i_assert(apool->total_alloc_used >= block->size);
5be1f1
+	i_assert(apool->total_alloc_count > 0);
5be1f1
+	DLLIST_REMOVE(&apool->blocks, block);
5be1f1
+	apool->total_alloc_used -= block->size;
5be1f1
+	apool->total_alloc_count--;
5be1f1
+
5be1f1
+	return block;
5be1f1
+}
5be1f1
+
5be1f1
+static void *pool_allocfree_malloc(pool_t pool, size_t size)
5be1f1
+{
5be1f1
+	struct allocfree_pool *apool =
5be1f1
+		container_of(pool, struct allocfree_pool, pool);
5be1f1
+
5be1f1
+	struct pool_block *block = calloc(1, SIZEOF_POOLBLOCK + size);
5be1f1
+	if (block == NULL)
5be1f1
+		i_fatal_status(FATAL_OUTOFMEM, "calloc(1, %"PRIuSIZE_T"): Out of memory",
5be1f1
+			       SIZEOF_POOLBLOCK + size);
5be1f1
+	block->size = size;
5be1f1
+	return pool_block_attach(apool, block);
5be1f1
+}
5be1f1
+
5be1f1
+static void pool_allocfree_free(pool_t pool, void *mem)
5be1f1
+{
5be1f1
+	struct allocfree_pool *apool =
5be1f1
+		container_of(pool, struct allocfree_pool, pool);
5be1f1
+	struct pool_block *block = pool_block_detach(apool, mem);
5be1f1
+	if (apool->clean_frees)
5be1f1
+		safe_memset(block, 0, SIZEOF_POOLBLOCK+block->size);
5be1f1
+	free(block);
5be1f1
+}
5be1f1
+
5be1f1
+static void *pool_allocfree_realloc(pool_t pool, void *mem,
5be1f1
+				    size_t old_size, size_t new_size)
5be1f1
+{
5be1f1
+	struct allocfree_pool *apool =
5be1f1
+		container_of(pool, struct allocfree_pool, pool);
5be1f1
+	unsigned char *new_mem;
5be1f1
+
5be1f1
+	struct pool_block *block = pool_block_detach(apool, mem);
5be1f1
+	if ((new_mem = realloc(block, SIZEOF_POOLBLOCK+new_size)) == NULL)
5be1f1
+		i_fatal_status(FATAL_OUTOFMEM, "realloc(block, %"PRIuSIZE_T")",
5be1f1
+			       SIZEOF_POOLBLOCK+new_size);
5be1f1
+
5be1f1
+	/* zero out new memory */
5be1f1
+	if (new_size > old_size)
5be1f1
+		memset(new_mem + SIZEOF_POOLBLOCK + old_size, 0,
5be1f1
+		       new_size - old_size);
5be1f1
+	block = (struct pool_block*)new_mem;
5be1f1
+	block->size = new_size;
5be1f1
+	return pool_block_attach(apool, block);
5be1f1
+}
5be1f1
+
5be1f1
+static void pool_allocfree_clear(pool_t pool)
5be1f1
+{
5be1f1
+	struct allocfree_pool *apool =
5be1f1
+		container_of(pool, struct allocfree_pool, pool);
5be1f1
+	struct pool_block *block, *next;
5be1f1
+
5be1f1
+	for (block = apool->blocks; block != NULL; block = next) {
5be1f1
+		next = block->next;
5be1f1
+		pool_allocfree_free(pool, block->block);
5be1f1
+	}
5be1f1
+	i_assert(apool->total_alloc_used == 0 && apool->total_alloc_count == 0);
5be1f1
+}
5be1f1
+
5be1f1
+static size_t pool_allocfree_get_max_easy_alloc_size(pool_t pool ATTR_UNUSED)
5be1f1
+{
5be1f1
+	return 0;
5be1f1
+}
5be1f1
+
5be1f1
+size_t pool_allocfree_get_total_used_size(pool_t pool)
5be1f1
+{
5be1f1
+	struct allocfree_pool *apool =
5be1f1
+		container_of(pool, struct allocfree_pool, pool);
5be1f1
+	return apool->total_alloc_used;
5be1f1
+}
5be1f1
+
5be1f1
+size_t pool_allocfree_get_total_alloc_size(pool_t pool)
5be1f1
+{
5be1f1
+	struct allocfree_pool *apool =
5be1f1
+		container_of(pool, struct allocfree_pool, pool);
5be1f1
+	return apool->total_alloc_used +
5be1f1
+	       SIZEOF_POOLBLOCK*apool->total_alloc_count + sizeof(*apool);
5be1f1
+}
5be1f1
diff -up dovecot-2.2.36/src/lib/mempool.h.CVE_2020_12674prereq dovecot-2.2.36/src/lib/mempool.h
5be1f1
--- dovecot-2.2.36/src/lib/mempool.h.CVE_2020_12674prereq	2018-04-30 15:52:05.000000000 +0200
5be1f1
+++ dovecot-2.2.36/src/lib/mempool.h	2020-08-09 14:37:53.483591170 +0200
5be1f1
@@ -10,6 +10,11 @@
5be1f1
    pools to disable the warning. */
5be1f1
 #define MEMPOOL_GROWING "GROWING-"
5be1f1
 
5be1f1
+/* The maximum allocation size that's allowed.  Anything larger than that
5be1f1
+   will panic.  No pool ever should need more than 4kB of overhead per
5be1f1
+   allocation. */
5be1f1
+#define POOL_MAX_ALLOC_SIZE	(SSIZE_T_MAX - 4096)
5be1f1
+
5be1f1
 /* Memory allocated and reallocated (the new data in it) in pools is always
5be1f1
    zeroed, it will cost only a few CPU cycles and may well save some debug
5be1f1
    time. */
5be1f1
@@ -63,6 +68,10 @@ pool_t pool_alloconly_create(const char
5be1f1
    needed. */
5be1f1
 pool_t pool_alloconly_create_clean(const char *name, size_t size);
5be1f1
 
5be1f1
+/* Create new alloc pool. This is very similar to system pool, but it
5be1f1
+   will deallocate all memory on deinit. */
5be1f1
+pool_t pool_allocfree_create(const char *name);
5be1f1
+
5be1f1
 /* When allocating memory from returned pool, the data stack frame must be
5be1f1
    the same as it was when calling this function. pool_unref() also checks
5be1f1
    that the stack frame is the same. This should make it quite safe to use. */