]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Increase failed login's reply delay by 5 seconds for each failure.
authorTimo Sirainen <tss@iki.fi>
Fri, 19 Dec 2008 07:31:18 +0000 (09:31 +0200)
committerTimo Sirainen <tss@iki.fi>
Fri, 19 Dec 2008 07:31:18 +0000 (09:31 +0200)
Don't add any delays if passdb returned nodelay extra field.
Based on patch by Apple.

--HG--
branch : HEAD

src/auth/auth-request-handler.c
src/imap-login/client-authenticate.c
src/imap-login/client.c
src/imap-login/client.h
src/pop3-login/client-authenticate.c
src/pop3-login/client.c
src/pop3-login/client.h

index 66cc7c7b864512c44e8e5c69a58b674f5ee16d4d..2f1aa7a54c85d418f7a5f82182b15d2ac07faf7c 100644 (file)
@@ -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);
index 03853f7dd01ed970af44483bbfb1951d199da584..11f95ebb866a8a9b8781532313f5286ed442ffef 100644 (file)
@@ -18,6 +18,8 @@
 
 #include <stdlib.h>
 
+#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)
index 0a554382cf8aaf7eeac432f55aaa206c513b4f87..d1e2ae77004ed83cad9f453d012893de3cfc66c1 100644 (file)
@@ -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);
index ad655a7e124acc6595b5e25aa6ea79a6342bfec7..e2f680b2c7903a082355404aa18c4da23109da1e 100644 (file)
@@ -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;
index 0eab44185ff33b317fa387d3beadc276cca7ea1f..4f2e10efde6a3a40266230d18005012fb7d30aba 100644 (file)
@@ -20,6 +20,7 @@
 #include <stdlib.h>
 
 #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)
index 1851d7df3682682a361dbc7d4c7379012b857fd3..594b645183b68179ac7cc7c8d89b561414edfada 100644 (file)
@@ -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);
index f4da65e7225fbf13ded7e9f2723088bedfa4ca4d..2826b84b855d0d70821fc7cb49749402655afa66 100644 (file)
@@ -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;