From: Timo Sirainen Date: Fri, 19 Dec 2008 07:31:18 +0000 (+0200) Subject: Increase failed login's reply delay by 5 seconds for each failure. X-Git-Tag: 1.2.beta1~169 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e5dec382163b476bed16dbf7eb470913a9bbdbe1;p=thirdparty%2Fdovecot%2Fcore.git Increase failed login's reply delay by 5 seconds for each failure. Don't add any delays if passdb returned nodelay extra field. Based on patch by Apple. --HG-- branch : HEAD --- diff --git a/src/auth/auth-request-handler.c b/src/auth/auth-request-handler.c index 66cc7c7b86..2f1aa7a54c 100644 --- a/src/auth/auth-request-handler.c +++ b/src/auth/auth-request-handler.c @@ -254,6 +254,8 @@ static void auth_callback(struct auth_request *request, as the wanted user */ auth_stream_reply_add(reply, "authz", NULL); } + if (request->no_failure_delay) + auth_stream_reply_add(reply, "nodelay", NULL); get_client_extra_fields(request, reply); auth_request_handle_failure(request, reply); diff --git a/src/imap-login/client-authenticate.c b/src/imap-login/client-authenticate.c index 03853f7dd0..11f95ebb86 100644 --- a/src/imap-login/client-authenticate.c +++ b/src/imap-login/client-authenticate.c @@ -18,6 +18,8 @@ #include +#define AUTH_FAILURE_DELAY_INCREASE_MSECS 5000 + #define IMAP_SERVICE_NAME "imap" #define IMAP_AUTH_FAILED_MSG "["IMAP_RESP_CODE_AUTHFAILED"] "AUTH_FAILED_MSG #define IMAP_AUTHZ_FAILED_MSG \ @@ -79,23 +81,50 @@ static void client_auth_input(struct imap_client *client) } } -static void client_auth_failed(struct imap_client *client) +static void client_authfail_delay_timeout(struct imap_client *client) +{ + timeout_remove(&client->to_authfail_delay); + + /* get back to normal client input. */ + i_assert(client->io == NULL); + client->io = io_add(client->common.fd, IO_READ, client_input, client); + client_input(client); +} + +static void client_auth_failed(struct imap_client *client, bool nodelay) { + unsigned int delay_msecs; + client->common.auth_command_tag = NULL; if (client->auth_initializing) return; - /* get back to normal client input. */ if (client->io != NULL) io_remove(&client->io); - client->io = io_add(client->common.fd, IO_READ, - client_input, client); - client_input(client); + if (nodelay) { + client->io = io_add(client->common.fd, IO_READ, + client_input, client); + client_input(client); + return; + } + + /* increase the timeout after each unsuccessful attempt, but don't + increase it so high that the idle timeout would be triggered */ + delay_msecs = client->common.auth_attempts * + AUTH_FAILURE_DELAY_INCREASE_MSECS; + if (delay_msecs > CLIENT_LOGIN_IDLE_TIMEOUT_MSECS) + delay_msecs = CLIENT_LOGIN_IDLE_TIMEOUT_MSECS - 1000; + timeout_reset(client->to_idle_disconnect); + + i_assert(client->to_authfail_delay == NULL); + client->to_authfail_delay = + timeout_add(delay_msecs, client_authfail_delay_timeout, client); } static bool client_handle_args(struct imap_client *client, - const char *const *args, bool success) + const char *const *args, bool success, + bool *nodelay_r) { const char *reason = NULL, *host = NULL, *destuser = NULL, *pass = NULL; const char *master_user = NULL; @@ -104,9 +133,12 @@ static bool client_handle_args(struct imap_client *client, bool proxy = FALSE, temp = FALSE, nologin = !success, proxy_self; bool authz_failure = FALSE; + *nodelay_r = FALSE; for (; *args != NULL; args++) { if (strcmp(*args, "nologin") == 0) nologin = TRUE; + else if (strcmp(*args, "nodelay") == 0) + *nodelay_r = TRUE; else if (strcmp(*args, "proxy") == 0) proxy = TRUE; else if (strcmp(*args, "temp") == 0) @@ -210,7 +242,7 @@ static bool client_handle_args(struct imap_client *client, i_assert(nologin || proxy_self); if (!client->destroyed) - client_auth_failed(client); + client_auth_failed(client, *nodelay_r); return TRUE; } @@ -221,6 +253,7 @@ static void sasl_callback(struct client *_client, enum sasl_server_reply reply, struct const_iovec iov[3]; const char *msg; size_t data_len; + bool nodelay; i_assert(!client->destroyed || reply == SASL_SERVER_REPLY_CLIENT_ERROR || @@ -231,7 +264,7 @@ static void sasl_callback(struct client *_client, enum sasl_server_reply reply, if (client->to_auth_waiting != NULL) timeout_remove(&client->to_auth_waiting); if (args != NULL) { - if (client_handle_args(client, args, TRUE)) + if (client_handle_args(client, args, TRUE, &nodelay)) break; } client_destroy_success(client, "Login"); @@ -241,7 +274,7 @@ static void sasl_callback(struct client *_client, enum sasl_server_reply reply, if (client->to_auth_waiting != NULL) timeout_remove(&client->to_auth_waiting); if (args != NULL) { - if (client_handle_args(client, args, FALSE)) + if (client_handle_args(client, args, FALSE, &nodelay)) break; } @@ -251,7 +284,7 @@ static void sasl_callback(struct client *_client, enum sasl_server_reply reply, client_send_tagline(client, msg); if (!client->destroyed) - client_auth_failed(client); + client_auth_failed(client, nodelay); break; case SASL_SERVER_REPLY_MASTER_FAILED: if (data == NULL) diff --git a/src/imap-login/client.c b/src/imap-login/client.c index 0a554382cf..d1e2ae7700 100644 --- a/src/imap-login/client.c +++ b/src/imap-login/client.c @@ -26,9 +26,6 @@ /* maximum length for IMAP command line. */ #define MAX_IMAP_LINE 8192 -/* Disconnect client after idling this many milliseconds */ -#define CLIENT_LOGIN_IDLE_TIMEOUT_MSECS (3*60*1000) - /* Disconnect client when it sends too many bad commands */ #define CLIENT_MAX_BAD_COMMANDS 10 @@ -572,6 +569,8 @@ void client_destroy(struct imap_client *client, const char *reason) timeout_remove(&client->to_idle_disconnect); if (client->to_auth_waiting != NULL) timeout_remove(&client->to_auth_waiting); + if (client->to_authfail_delay != NULL) + timeout_remove(&client->to_authfail_delay); if (client->common.fd != -1) { net_disconnect(client->common.fd); diff --git a/src/imap-login/client.h b/src/imap-login/client.h index ad655a7e12..e2f680b2c7 100644 --- a/src/imap-login/client.h +++ b/src/imap-login/client.h @@ -5,6 +5,9 @@ #include "master.h" #include "client-common.h" +/* Disconnect client after idling this many milliseconds */ +#define CLIENT_LOGIN_IDLE_TIMEOUT_MSECS (3*60*1000) + struct imap_client { struct client common; @@ -15,6 +18,7 @@ struct imap_client { struct ostream *output; struct imap_parser *parser; struct timeout *to_idle_disconnect, *to_auth_waiting; + struct timeout *to_authfail_delay; struct login_proxy *proxy; char *proxy_user, *proxy_master_user, *proxy_password; diff --git a/src/pop3-login/client-authenticate.c b/src/pop3-login/client-authenticate.c index 0eab44185f..4f2e10efde 100644 --- a/src/pop3-login/client-authenticate.c +++ b/src/pop3-login/client-authenticate.c @@ -20,6 +20,7 @@ #include #define POP3_SERVICE_NAME "pop3" +#define AUTH_FAILURE_DELAY_INCREASE_MSECS 5000 const char *capability_string = POP3_CAPABILITY_REPLY; @@ -82,8 +83,48 @@ static void client_auth_input(struct pop3_client *client) } } +static void client_authfail_delay_timeout(struct pop3_client *client) +{ + timeout_remove(&client->to_authfail_delay); + + /* get back to normal client input. */ + i_assert(client->io == NULL); + client->io = io_add(client->common.fd, IO_READ, client_input, client); + client_input(client); +} + +static void client_auth_failed(struct pop3_client *client, bool nodelay) +{ + unsigned int delay_msecs; + + if (client->auth_initializing) + return; + + if (client->io != NULL) + io_remove(&client->io); + if (nodelay) { + client->io = io_add(client->common.fd, IO_READ, + client_input, client); + client_input(client); + return; + } + + /* increase the timeout after each unsuccessful attempt, but don't + increase it so high that the idle timeout would be triggered */ + delay_msecs = client->common.auth_attempts * + AUTH_FAILURE_DELAY_INCREASE_MSECS; + if (delay_msecs > CLIENT_LOGIN_IDLE_TIMEOUT_MSECS) + delay_msecs = CLIENT_LOGIN_IDLE_TIMEOUT_MSECS - 1000; + timeout_reset(client->to_idle_disconnect); + + i_assert(client->to_authfail_delay == NULL); + client->to_authfail_delay = + timeout_add(delay_msecs, client_authfail_delay_timeout, client); +} + static bool client_handle_args(struct pop3_client *client, - const char *const *args, bool success) + const char *const *args, bool success, + bool *nodelay_r) { const char *reason = NULL, *host = NULL, *destuser = NULL, *pass = NULL; const char *master_user = NULL; @@ -91,9 +132,12 @@ static bool client_handle_args(struct pop3_client *client, unsigned int port = 110; bool proxy = FALSE, temp = FALSE, nologin = !success; + *nodelay_r = FALSE; for (; *args != NULL; args++) { if (strcmp(*args, "nologin") == 0) nologin = TRUE; + else if (strcmp(*args, "nodelay") == 0) + *nodelay_r = TRUE; else if (strcmp(*args, "proxy") == 0) proxy = TRUE; else if (strcmp(*args, "temp") == 0) @@ -150,14 +194,8 @@ static bool client_handle_args(struct pop3_client *client, client_send_line(client, str_c(reply)); - if (!client->destroyed) { - /* get back to normal client input. */ - if (client->io != NULL) - io_remove(&client->io); - client->io = io_add(client->common.fd, IO_READ, - client_input, client); - client_input(client); - } + if (!client->destroyed) + client_auth_failed(client, *nodelay_r); return TRUE; } @@ -168,6 +206,7 @@ static void sasl_callback(struct client *_client, enum sasl_server_reply reply, struct const_iovec iov[3]; const char *msg; size_t data_len; + bool nodelay; i_assert(!client->destroyed || reply == SASL_SERVER_REPLY_CLIENT_ERROR || @@ -176,7 +215,7 @@ static void sasl_callback(struct client *_client, enum sasl_server_reply reply, switch (reply) { case SASL_SERVER_REPLY_SUCCESS: if (args != NULL) { - if (client_handle_args(client, args, TRUE)) + if (client_handle_args(client, args, TRUE, &nodelay)) break; } @@ -185,7 +224,7 @@ static void sasl_callback(struct client *_client, enum sasl_server_reply reply, case SASL_SERVER_REPLY_AUTH_FAILED: case SASL_SERVER_REPLY_CLIENT_ERROR: if (args != NULL) { - if (client_handle_args(client, args, FALSE)) + if (client_handle_args(client, args, FALSE, &nodelay)) break; } @@ -193,14 +232,8 @@ static void sasl_callback(struct client *_client, enum sasl_server_reply reply, data : AUTH_FAILED_MSG, NULL); client_send_line(client, msg); - if (!client->destroyed && !client->auth_initializing) { - /* get back to normal client input. */ - if (client->io != NULL) - io_remove(&client->io); - client->io = io_add(client->common.fd, IO_READ, - client_input, client); - client_input(client); - } + if (!client->destroyed) + client_auth_failed(client, nodelay); break; case SASL_SERVER_REPLY_MASTER_FAILED: if (data == NULL) diff --git a/src/pop3-login/client.c b/src/pop3-login/client.c index 1851d7df36..594b645183 100644 --- a/src/pop3-login/client.c +++ b/src/pop3-login/client.c @@ -21,9 +21,6 @@ SASL authentication gives the largest output. */ #define MAX_OUTBUF_SIZE 4096 -/* Disconnect client after idling this many milliseconds */ -#define CLIENT_LOGIN_IDLE_TIMEOUT_MSECS (3*60*1000) - /* Disconnect client when it sends too many bad commands */ #define CLIENT_MAX_BAD_COMMANDS 10 @@ -378,6 +375,8 @@ void client_destroy(struct pop3_client *client, const char *reason) io_remove(&client->io); if (client->to_idle_disconnect != NULL) timeout_remove(&client->to_idle_disconnect); + if (client->to_authfail_delay != NULL) + timeout_remove(&client->to_authfail_delay); if (client->common.fd != -1) { net_disconnect(client->common.fd); diff --git a/src/pop3-login/client.h b/src/pop3-login/client.h index f4da65e722..2826b84b85 100644 --- a/src/pop3-login/client.h +++ b/src/pop3-login/client.h @@ -6,6 +6,9 @@ #include "client-common.h" #include "auth-client.h" +/* Disconnect client after idling this many milliseconds */ +#define CLIENT_LOGIN_IDLE_TIMEOUT_MSECS (3*60*1000) + struct pop3_client { struct client common; @@ -14,7 +17,7 @@ struct pop3_client { struct io *io; struct ostream *output; - struct timeout *to_idle_disconnect; + struct timeout *to_idle_disconnect, *to_authfail_delay; struct login_proxy *proxy; char *proxy_user, *proxy_master_user, *proxy_password;