]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
auth: sasl-server - Add PASSWORD_MISMATCH output status
authorStephan Bosch <stephan.bosch@open-xchange.com>
Sat, 4 Oct 2025 20:02:18 +0000 (22:02 +0200)
committertimo.sirainen <timo.sirainen@open-xchange.com>
Thu, 9 Oct 2025 08:41:22 +0000 (08:41 +0000)
This allows more precise handling of password mismatch errors from looked up
credentials.

src/auth/auth-sasl.c
src/auth/sasl-server-mech-cram-md5.c
src/auth/sasl-server-mech-digest-md5.c
src/auth/sasl-server-mech-otp.c
src/auth/sasl-server-mech-scram.c
src/auth/sasl-server-protected.h
src/auth/sasl-server-request.c
src/auth/sasl-server.h

index e098402f71c9fe9d7677cb13b099112cd8d20217..a90581923d548631eb38d9d1b39d3b0c82be7e66 100644 (file)
@@ -146,6 +146,11 @@ auth_sasl_request_output(struct sasl_server_req_ctx *rctx,
        case SASL_SERVER_OUTPUT_INTERNAL_FAILURE:
                auth_request_internal_failure(request);
                break;
+       case SASL_SERVER_OUTPUT_PASSWORD_MISMATCH:
+               e_info(request->event, "%s", AUTH_LOG_MSG_PASSWORD_MISMATCH);
+               auth_request_fail_with_reply(
+                       request, output->data, output->data_size);
+               break;
        case SASL_SERVER_OUTPUT_FAILURE:
                auth_request_fail_with_reply(
                        request, output->data, output->data_size);
index f1ce8b4cbfba8faaa07e2f75238730241c94ed23..ef03e215ef92e80490916b3d89527b8c6a89d64b 100644 (file)
@@ -71,8 +71,7 @@ verify_credentials(struct sasl_server_mech_request *auth_request,
 
        if (!mem_equals_timing_safe(response_hex, request->response,
                                    sizeof(digest) * 2)) {
-               e_info(auth_request->event, AUTH_LOG_MSG_PASSWORD_MISMATCH);
-               sasl_server_request_failure(auth_request);
+               sasl_server_request_password_mismatch(auth_request);
                return;
        }
 
index 8f5ad5dfba49f0df9f899dd092714b2c1fa1900a..35441fd72f5cb8f0be0b43afd23ea75d659ff32f 100644 (file)
@@ -213,9 +213,8 @@ verify_credentials(struct sasl_server_mech_request *auth_request,
                        /* verify response */
                        if (!mem_equals_timing_safe(response_hex,
                                                    request->response, 32)) {
-                               e_info(auth_request->event,
-                                      AUTH_LOG_MSG_PASSWORD_MISMATCH);
-                               sasl_server_request_failure(auth_request);
+                               sasl_server_request_password_mismatch(
+                                       auth_request);
                                return;
                        }
                } else {
@@ -559,7 +558,6 @@ mech_digest_md5_auth_continue(struct sasl_server_mech_request *auth_request,
                sasl_server_request_failure(auth_request);
                return;
        }
-
        if (!sasl_server_request_set_authid(auth_request,
                                            SASL_SERVER_AUTHID_TYPE_USERNAME,
                                            request->username)) {
index 6582af98fde3e5cb0a00f721354d33e33bc20512..7291adf8f0b3178b6fc4a8b3647f4937ae86cace 100644 (file)
@@ -196,7 +196,7 @@ mech_otp_verify(struct otp_auth_request *request, const char *data, bool hex)
 
        ret = memcmp(cur_hash, state->hash, OTP_HASH_SIZE);
        if (ret != 0) {
-               sasl_server_request_failure(auth_request);
+               sasl_server_request_password_mismatch(auth_request);
                otp_unlock(request);
                return;
        }
@@ -230,7 +230,7 @@ mech_otp_verify_init(struct otp_auth_request *request, const char *data,
 
        ret = memcmp(hash, request->state.hash, OTP_HASH_SIZE);
        if (ret != 0) {
-               sasl_server_request_failure(auth_request);
+               sasl_server_request_password_mismatch(auth_request);
                otp_unlock(request);
                return;
        }
index f0e2733910b0e5fc3d86779a96d7c6e2ee1a8e09..5dbef6832bcc8bfdb9e5ec25e109add93c9087be 100644 (file)
@@ -166,17 +166,17 @@ mech_scram_auth_continue(struct sasl_server_mech_request *auth_request,
                        i_unreached();
                case AUTH_SCRAM_SERVER_ERROR_PROTOCOL_VIOLATION:
                        e_info(auth_request->event, "%s", error);
+                       sasl_server_request_failure(auth_request);
                        break;
                case AUTH_SCRAM_SERVER_ERROR_BAD_USERNAME:
                case AUTH_SCRAM_SERVER_ERROR_BAD_LOGIN_USERNAME:
                case AUTH_SCRAM_SERVER_ERROR_LOOKUP_FAILED:
+                       sasl_server_request_failure(auth_request);
                        break;
                case AUTH_SCRAM_SERVER_ERROR_VERIFICATION_FAILED:
-                       e_info(auth_request->event,
-                              AUTH_LOG_MSG_PASSWORD_MISMATCH);
+                       sasl_server_request_password_mismatch(auth_request);
                        break;
                }
-               sasl_server_request_failure(auth_request);
                return;
        }
        if (ret == 0)
index f654b7398c5e554e943d944591a3f40eb90fc351..f91a9de706a7e1eb9f185d8e5bb2fe34dfa716d5 100644 (file)
@@ -123,6 +123,8 @@ void sasl_server_request_failure_with_reply(
        struct sasl_server_mech_request *mreq,
        const void *data, size_t data_size);
 void sasl_server_request_failure(struct sasl_server_mech_request *mreq);
+void sasl_server_request_password_mismatch(
+       struct sasl_server_mech_request *mreq);
 void sasl_server_request_internal_failure(
        struct sasl_server_mech_request *mreq);
 
index 558702dc17b163ec263d8ba5616fd6566e8ae7d3..da65b86df3a3a6202ab4e3410da13e7a2034f3d1 100644 (file)
@@ -428,11 +428,14 @@ sasl_server_request_failure_common(struct sasl_server_mech_request *mreq,
        req->failed = TRUE;
        if (data_size > 0) {
                i_assert(status != SASL_SERVER_OUTPUT_INTERNAL_FAILURE);
+               i_assert(status != SASL_SERVER_OUTPUT_PASSWORD_MISMATCH);
                i_assert(!req->finished_with_data);
                req->finished_with_data = TRUE;
                e_debug(req->event,
                        "Interaction failed with final data (size=%zu)",
                        data_size);
+       } else if (status == SASL_SERVER_OUTPUT_PASSWORD_MISMATCH) {
+               e_debug(req->event, "Interaction failed: Password mismatch");
        } else if (status == SASL_SERVER_OUTPUT_INTERNAL_FAILURE) {
                e_debug(req->event, "Interaction failed (internal failure)");
        } else {
@@ -462,6 +465,13 @@ void sasl_server_request_failure(struct sasl_server_mech_request *mreq)
                                           "", 0);
 }
 
+void sasl_server_request_password_mismatch(
+       struct sasl_server_mech_request *mreq)
+{
+       sasl_server_request_failure_common(
+               mreq, SASL_SERVER_OUTPUT_PASSWORD_MISMATCH, "", 0);
+}
+
 void sasl_server_request_internal_failure(
        struct sasl_server_mech_request *mreq)
 {
index 0efb15407e469b5a37b72697d935900fdee07bae..46d5d552268d084ae047a6fd050f4094c4fcc99e 100644 (file)
@@ -39,7 +39,9 @@ enum sasl_mech_passdb_need {
 
 enum sasl_server_output_status {
        /* Internal failure */
-       SASL_SERVER_OUTPUT_INTERNAL_FAILURE = -2,
+       SASL_SERVER_OUTPUT_INTERNAL_FAILURE = -3,
+       /* Password mismatch */
+       SASL_SERVER_OUTPUT_PASSWORD_MISMATCH = -2,
        /* Authentication failed */
        SASL_SERVER_OUTPUT_FAILURE = -1,
        /* Client is challlenged to continue authentication */