Mercurial > dovecot > original-hg > dovecot-1.2
changeset 7088:958500009336 HEAD
Make sure failed auth requests stay in failure buffer for at least a second.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Tue, 01 Jan 2008 23:53:29 +0200 |
parents | a281705a2360 |
children | 10d49a20b04e |
files | src/auth/auth-request-handler.c src/auth/auth-request-handler.h src/auth/main.c |
diffstat | 3 files changed, 78 insertions(+), 39 deletions(-) [+] |
line wrap: on
line diff
--- 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,9 +31,12 @@ 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 * auth_request_handler_create(struct auth *auth, @@ -147,6 +154,43 @@ 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, enum auth_client_result result, const void *reply, size_t reply_size) @@ -194,28 +238,7 @@ 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_flush_failures(void) +void auth_request_handler_flush_failures(bool flush_all) { - struct auth_request **auth_request; + struct auth_request **auth_requests, *auth_request; unsigned int i, count; + time_t diff; - auth_request = array_get_modifiable(&auth_failures, &count); + 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]); + 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); } - array_clear(&auth_failures); } 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); }
--- 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 @@ 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);
--- 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 @@ 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();