From: Stephan Bosch Date: Sat, 4 Oct 2025 20:02:18 +0000 (+0200) Subject: auth: sasl-server - Add PASSWORD_MISMATCH output status X-Git-Tag: 2.4.2~166 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0354168f9a520d7c16f2f5817843e48a2928d097;p=thirdparty%2Fdovecot%2Fcore.git auth: sasl-server - Add PASSWORD_MISMATCH output status This allows more precise handling of password mismatch errors from looked up credentials. --- diff --git a/src/auth/auth-sasl.c b/src/auth/auth-sasl.c index e098402f71..a90581923d 100644 --- a/src/auth/auth-sasl.c +++ b/src/auth/auth-sasl.c @@ -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); diff --git a/src/auth/sasl-server-mech-cram-md5.c b/src/auth/sasl-server-mech-cram-md5.c index f1ce8b4cbf..ef03e215ef 100644 --- a/src/auth/sasl-server-mech-cram-md5.c +++ b/src/auth/sasl-server-mech-cram-md5.c @@ -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; } diff --git a/src/auth/sasl-server-mech-digest-md5.c b/src/auth/sasl-server-mech-digest-md5.c index 8f5ad5dfba..35441fd72f 100644 --- a/src/auth/sasl-server-mech-digest-md5.c +++ b/src/auth/sasl-server-mech-digest-md5.c @@ -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)) { diff --git a/src/auth/sasl-server-mech-otp.c b/src/auth/sasl-server-mech-otp.c index 6582af98fd..7291adf8f0 100644 --- a/src/auth/sasl-server-mech-otp.c +++ b/src/auth/sasl-server-mech-otp.c @@ -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; } diff --git a/src/auth/sasl-server-mech-scram.c b/src/auth/sasl-server-mech-scram.c index f0e2733910..5dbef6832b 100644 --- a/src/auth/sasl-server-mech-scram.c +++ b/src/auth/sasl-server-mech-scram.c @@ -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) diff --git a/src/auth/sasl-server-protected.h b/src/auth/sasl-server-protected.h index f654b7398c..f91a9de706 100644 --- a/src/auth/sasl-server-protected.h +++ b/src/auth/sasl-server-protected.h @@ -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); diff --git a/src/auth/sasl-server-request.c b/src/auth/sasl-server-request.c index 558702dc17..da65b86df3 100644 --- a/src/auth/sasl-server-request.c +++ b/src/auth/sasl-server-request.c @@ -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) { diff --git a/src/auth/sasl-server.h b/src/auth/sasl-server.h index 0efb15407e..46d5d55226 100644 --- a/src/auth/sasl-server.h +++ b/src/auth/sasl-server.h @@ -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 */