]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
login-common, *-login: Add proxy_dest_connection_limit error_code to proxy_session_fi...
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Wed, 3 Dec 2025 10:06:42 +0000 (12:06 +0200)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Thu, 27 Nov 2025 07:53:37 +0000 (07:53 +0000)
If IMAP backend returns with [LIMIT] or POP3 backend returns with [IN-USE],
use this error code rather than the generic proxy_dest_auth_failed.
Error messages are also updated.

src/imap-login/imap-proxy.c
src/login-common/client-common.c
src/login-common/login-proxy.c
src/login-common/login-proxy.h
src/pop3-login/pop3-proxy.c
src/submission-login/submission-proxy.c

index b4cdc8b924bdc2259903acf77c1f9ffeab9a1ce2..3156a4bbf4ebe5c7f646609c9d9b622377cb850b 100644 (file)
@@ -289,6 +289,12 @@ static bool auth_resp_code_is_serverbug(const char *resp)
                           strlen(IMAP_RESP_CODE_SERVERBUG"]")) == 0;
 }
 
+static bool auth_resp_code_is_limit(const char *resp)
+{
+       return strncasecmp(resp, IMAP_RESP_CODE_LIMIT"]",
+                          strlen(IMAP_RESP_CODE_LIMIT"]")) == 0;
+}
+
 static bool
 auth_resp_code_parse_referral(struct client *client, const char *resp,
                              const char **userhostport_r)
@@ -435,6 +441,8 @@ int imap_proxy_parse_line(struct client *client, const char *line)
                        else if (auth_resp_code_is_serverbug(line + 4))
                                failure_type = LOGIN_PROXY_FAILURE_TYPE_REMOTE;
                        else {
+                               if (auth_resp_code_is_limit(line + 4))
+                                       failure_type = LOGIN_PROXY_FAILURE_TYPE_AUTH_LIMIT_REACHED_REPLIED;
                                client_send_raw(client, t_strconcat(
                                        imap_client->cmd_tag, " ", line, "\r\n", NULL));
                        }
@@ -575,6 +583,7 @@ imap_proxy_send_failure_reply(struct imap_client *imap_client,
                        imap_client->cmd_tag, " NO ", reason, "\r\n", NULL));
                break;
        case LOGIN_PROXY_FAILURE_TYPE_AUTH_REPLIED:
+       case LOGIN_PROXY_FAILURE_TYPE_AUTH_LIMIT_REACHED_REPLIED:
                /* reply was already sent */
                break;
        }
index f57e99e02350be0e95be8e9ebbb74d15e36d7014..0d0135f67b6cdd85651a9f29fcf05bb156fa9e03 100644 (file)
@@ -1467,6 +1467,10 @@ bool client_get_extra_disconnect_reason(struct client *client,
                        event_reason = "redirected";
                        last_reason = "redirected";
                        break;
+               case LOGIN_PROXY_FAILURE_TYPE_AUTH_LIMIT_REACHED_REPLIED:
+                       event_reason = "connection_limit";
+                       last_reason = "connection limit reached";
+                       break;
                default:
                        i_unreached();
                }
index 2df51eb4026bc8d99b00ab0fa05c151fa3caa189..278142e8c7bcd5cd94bc36664e0bc84e48434f2c 100644 (file)
@@ -859,6 +859,7 @@ bool login_proxy_failed(struct login_proxy *proxy, struct event *event,
                break;
        case LOGIN_PROXY_FAILURE_TYPE_AUTH_REPLIED:
        case LOGIN_PROXY_FAILURE_TYPE_AUTH_NOT_REPLIED:
+       case LOGIN_PROXY_FAILURE_TYPE_AUTH_LIMIT_REACHED_REPLIED:
                log_prefix = "";
                try_reconnect = FALSE;
                break;
@@ -888,6 +889,7 @@ bool login_proxy_failed(struct login_proxy *proxy, struct event *event,
                i_strdup_printf("%s%s", log_prefix, reason);
 
        if (type != LOGIN_PROXY_FAILURE_TYPE_AUTH_REPLIED &&
+           type != LOGIN_PROXY_FAILURE_TYPE_AUTH_LIMIT_REACHED_REPLIED &&
            type != LOGIN_PROXY_FAILURE_TYPE_AUTH_NOT_REPLIED &&
            type != LOGIN_PROXY_FAILURE_TYPE_AUTH_TEMPFAIL)
                e_error(event, "%s%s", log_prefix, reason);
index 0064b81258578077de15cbf8bbad121fdfaf956f..cc554486e19249842e879ec2e1f152b938806e19 100644 (file)
@@ -44,6 +44,9 @@ enum login_proxy_failure_type {
        /* Authentication requests connecting to another host. The reason
           string contains the host (and optionally :port). */
        LOGIN_PROXY_FAILURE_TYPE_AUTH_REDIRECT,
+       /* Authentication failed because user has reached some limit.
+          The LOGIN/AUTH command reply was already sent to the client. */
+       LOGIN_PROXY_FAILURE_TYPE_AUTH_LIMIT_REACHED_REPLIED,
 };
 
 struct login_proxy_settings {
index c8cf43d918f12bdd1c1b0cbae774ca7728296a46..2389dc6f09afd929b925521a4efa47d11dc621ef 100644 (file)
@@ -316,6 +316,8 @@ int pop3_proxy_parse_line(struct client *client, const char *line)
        } else if (pop3_proxy_parse_referral(client, line + 5, &line)) {
                failure_type = LOGIN_PROXY_FAILURE_TYPE_AUTH_REDIRECT;
        } else {
+               if (str_begins_with(line, "-ERR [IN-USE]"))
+                       failure_type = LOGIN_PROXY_FAILURE_TYPE_AUTH_LIMIT_REACHED_REPLIED;
                client_send_raw(client, t_strconcat(line, "\r\n", NULL));
                line += 5;
        }
@@ -358,6 +360,7 @@ pop3_proxy_send_failure_reply(struct client *client,
                client_send_reply(client, POP3_CMD_REPLY_ERROR, reason);
                break;
        case LOGIN_PROXY_FAILURE_TYPE_AUTH_REPLIED:
+       case LOGIN_PROXY_FAILURE_TYPE_AUTH_LIMIT_REACHED_REPLIED:
                /* reply was already sent */
                break;
        }
index aa5534b9c843fbcd9bd9aecff539bab67938d6a9..a23a8c02b5efe1c2bec8aa706709c61d72933ecd 100644 (file)
@@ -733,6 +733,7 @@ submission_proxy_send_failure_reply(struct submission_client *subm_client,
                smtp_server_reply_submit(subm_client->proxy_reply);
                break;
        case LOGIN_PROXY_FAILURE_TYPE_AUTH_REPLIED:
+       case LOGIN_PROXY_FAILURE_TYPE_AUTH_LIMIT_REACHED_REPLIED:
                /* reply was already sent */
                i_assert(cmd == NULL);
                break;