dovecot: Make sure failed auth requests stay in failure buffer f...

dovecot at dovecot.org dovecot at dovecot.org
Tue Jan 1 23:53:33 EET 2008


details:   http://hg.dovecot.org/dovecot/rev/958500009336
changeset: 7088:958500009336
user:      Timo Sirainen <tss at iki.fi>
date:      Tue Jan 01 23:53:29 2008 +0200
description:
Make sure failed auth requests stay in failure buffer for at least a second.

diffstat:

3 files changed, 83 insertions(+), 44 deletions(-)
src/auth/auth-request-handler.c |  123 +++++++++++++++++++++++++--------------
src/auth/auth-request-handler.h |    2 
src/auth/main.c                 |    2 

diffs (204 lines):

diff -r a281705a2360 -r 958500009336 src/auth/auth-request-handler.c
--- a/src/auth/auth-request-handler.c	Tue Jan 01 23:34:32 2008 +0200
+++ b/src/auth/auth-request-handler.c	Tue Jan 01 23:53:29 2008 +0200
@@ -3,6 +3,7 @@
 #include "common.h"
 #include "ioloop.h"
 #include "array.h"
+#include "aqueue.h"
 #include "base64.h"
 #include "hash.h"
 #include "str.h"
@@ -13,6 +14,9 @@
 
 #include <stdlib.h>
 
+#define AUTH_FAILURE_DELAY_SECS 2
+#define AUTH_FAILURE_DELAY_CHECK_MSECS (1000*AUTH_FAILURE_DELAY_SECS/2)
+
 struct auth_request_handler {
 	int refcount;
 	pool_t pool;
@@ -27,8 +31,11 @@ struct auth_request_handler {
 	auth_request_callback_t *master_callback;
 };
 
-static ARRAY_DEFINE(auth_failures, struct auth_request *);
+static ARRAY_DEFINE(auth_failures_arr, struct auth_request *);
+static struct aqueue *auth_failures;
 static struct timeout *to_auth_failures;
+
+static void auth_failure_timeout(void *context);
 
 #undef auth_request_handler_create
 struct auth_request_handler *
@@ -145,6 +152,43 @@ static const char *get_client_extra_fiel
 	}
 
 	return str_len(str) == 0 ? NULL : str_c(str);
+}
+
+static void
+auth_request_handle_failure(struct auth_request *request, const char *str)
+{
+        struct auth_request_handler *handler = request->context;
+
+	if (request->delayed_failure) {
+		/* we came here from flush_failures() */
+		handler->callback(str, handler->context);
+		return;
+	}
+
+	/* remove the request from requests-list */
+	auth_request_ref(request);
+	auth_request_handler_remove(handler, request);
+
+	if (request->no_failure_delay) {
+		/* passdb specifically requested not to delay the
+		   reply. */
+		handler->callback(str, handler->context);
+		auth_request_unref(&request);
+		return;
+	}
+
+	/* failure. don't announce it immediately to avoid
+	   a) timing attacks, b) flooding */
+	request->delayed_failure = TRUE;
+	handler->refcount++;
+
+	request->last_access = ioloop_time;
+	aqueue_append(auth_failures, &request);
+	if (to_auth_failures == NULL) {
+		to_auth_failures =
+			timeout_add(AUTH_FAILURE_DELAY_CHECK_MSECS,
+				    auth_failure_timeout, NULL);
+	}
 }
 
 static void auth_callback(struct auth_request *request,
@@ -194,28 +238,7 @@ static void auth_callback(struct auth_re
 			str_append(str, fields);
 		}
 
-		if (request->delayed_failure) {
-			/* we came here from flush_failures() */
-			handler->callback(str_c(str), handler->context);
-			break;
-		}
-
-		/* remove the request from requests-list */
-		auth_request_ref(request);
-		auth_request_handler_remove(handler, request);
-
-		if (request->no_failure_delay) {
-			/* passdb specifically requested not to delay the
-			   reply. */
-			handler->callback(str_c(str), handler->context);
-			auth_request_unref(&request);
-		} else {
-			/* failure. don't announce it immediately to avoid
-			   a) timing attacks, b) flooding */
-			request->delayed_failure = TRUE;
-			handler->refcount++;
-			array_append(&auth_failures, &request, 1);
-		}
+		auth_request_handle_failure(request, str_c(str));
 		break;
 	}
 	/* NOTE: request may be destroyed now */
@@ -477,36 +500,52 @@ void auth_request_handler_master_request
 	}
 }
 
-void auth_request_handler_flush_failures(void)
-{
-	struct auth_request **auth_request;
+void auth_request_handler_flush_failures(bool flush_all)
+{
+	struct auth_request **auth_requests, *auth_request;
 	unsigned int i, count;
-
-	auth_request = array_get_modifiable(&auth_failures, &count);
-
+	time_t diff;
+
+	count = aqueue_count(auth_failures);
+	if (count == 0) {
+		timeout_remove(&to_auth_failures);
+		return;
+	}
+
+	auth_requests = array_idx_modifiable(&auth_failures_arr, 0);
 	for (i = 0; i < count; i++) {
-		i_assert(auth_request[i]->state == AUTH_REQUEST_STATE_FINISHED);
-		auth_request[i]->callback(auth_request[i],
-					  AUTH_CLIENT_RESULT_FAILURE, NULL, 0);
-		auth_request_unref(&auth_request[i]);
-	}
-	array_clear(&auth_failures);
+		auth_request = auth_requests[aqueue_idx(auth_failures, 0)];
+
+		diff = ioloop_time - auth_request->last_access;
+		if (diff < AUTH_FAILURE_DELAY_SECS && !flush_all)
+			break;
+
+		aqueue_delete_tail(auth_failures);
+
+		i_assert(auth_request->state == AUTH_REQUEST_STATE_FINISHED);
+		auth_request->callback(auth_request,
+				       AUTH_CLIENT_RESULT_FAILURE, NULL, 0);
+		auth_request_unref(&auth_request);
+	}
 }
 
 static void auth_failure_timeout(void *context ATTR_UNUSED)
 {
-	auth_request_handler_flush_failures();
+	auth_request_handler_flush_failures(FALSE);
 }
 
 void auth_request_handler_init(void)
 {
-	i_array_init(&auth_failures, 128);
-        to_auth_failures = timeout_add(2000, auth_failure_timeout, NULL);
+	i_array_init(&auth_failures_arr, 128);
+	auth_failures = aqueue_init(&auth_failures_arr.arr);
 }
 
 void auth_request_handler_deinit(void)
 {
-	auth_request_handler_flush_failures();
-	array_free(&auth_failures);
-	timeout_remove(&to_auth_failures);
-}
+	auth_request_handler_flush_failures(TRUE);
+	array_free(&auth_failures_arr);
+	aqueue_deinit(&auth_failures);
+
+	if (to_auth_failures != NULL)
+		timeout_remove(&to_auth_failures);
+}
diff -r a281705a2360 -r 958500009336 src/auth/auth-request-handler.h
--- a/src/auth/auth-request-handler.h	Tue Jan 01 23:34:32 2008 +0200
+++ b/src/auth/auth-request-handler.h	Tue Jan 01 23:53:29 2008 +0200
@@ -39,7 +39,7 @@ void auth_request_handler_master_request
 					 unsigned int id,
 					 unsigned int client_id);
 
-void auth_request_handler_flush_failures(void);
+void auth_request_handler_flush_failures(bool flush_all);
 
 void auth_request_handler_init(void);
 void auth_request_handler_deinit(void);
diff -r a281705a2360 -r 958500009336 src/auth/main.c
--- a/src/auth/main.c	Tue Jan 01 23:34:32 2008 +0200
+++ b/src/auth/main.c	Tue Jan 01 23:53:29 2008 +0200
@@ -281,7 +281,7 @@ static void main_deinit(void)
 	if (worker_client != NULL)
 		auth_worker_client_unref(&worker_client);
 	else
-		auth_request_handler_flush_failures();
+		auth_request_handler_flush_failures(TRUE);
 
         auth_worker_server_deinit();
 	auth_master_listeners_deinit();


More information about the dovecot-cvs mailing list