]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
auth: auth-request - Handle final failure response
authorStephan Bosch <stephan.bosch@open-xchange.com>
Wed, 1 Nov 2023 23:07:25 +0000 (00:07 +0100)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Fri, 17 Nov 2023 10:49:10 +0000 (10:49 +0000)
src/auth/auth-request.c
src/auth/auth-request.h

index 3c563afa03c58e4dfdcd8f5d9231968d5b572c11..d1d52948f41600ee20150cb6396e095f757652ba 100644 (file)
@@ -273,6 +273,8 @@ static void auth_request_success_continue(struct auth_policy_check_ctx *ctx)
        if (ctx->success_data->used > 0 && !request->fields.final_resp_ok) {
                /* we'll need one more SASL round, since client doesn't support
                   the final SASL response */
+               i_assert(!request->final_resp_sent);
+               request->final_resp_sent = TRUE;
                auth_request_handler_reply_continue(request,
                        ctx->success_data->data, ctx->success_data->used);
                return;
@@ -289,6 +291,21 @@ void auth_request_fail_with_reply(struct auth_request *request,
 {
        i_assert(request->state == AUTH_REQUEST_STATE_MECH_CONTINUE);
 
+       /* Sending challenge data (final_data_size > 0) as part of the final
+          authentication command response is never an option in SASL, but when
+          the authentication client sets the "final-resp-ok" field it indicates
+          that it will handle the final protocol sequence, avoiding the need to
+          do that here. */
+       if (final_data_size > 0 && !request->fields.final_resp_ok) {
+               /* Otherwise, we need to send the data as part of a normal
+                  challenge and wait for a dummy client response. */
+               i_assert(!request->final_resp_sent);
+               request->final_resp_sent = TRUE;
+               auth_request_handler_reply_continue(request, final_data,
+                                                   final_data_size);
+               return;
+       }
+
        auth_request_set_state(request, AUTH_REQUEST_STATE_FINISHED);
        auth_request_refresh_last_access(request);
        auth_request_log_finished(request);
@@ -398,7 +415,11 @@ void auth_request_continue(struct auth_request *request,
 {
        i_assert(request->state == AUTH_REQUEST_STATE_MECH_CONTINUE);
 
-       if (request->fields.successful) {
+       if (request->final_resp_sent) {
+               if (!request->fields.successful) {
+                       auth_request_fail(request);
+                       return;
+               }
                auth_request_success(request, "", 0);
                return;
        }
index f289666660d9cd32cfa32d41b838e3aee83a76f8..636b9146a6df3352a2bf20786e1bf8273dcbb168 100644 (file)
@@ -231,6 +231,9 @@ struct auth_request {
           needs to be tracked outside regular extra fields, because they get
           rolled back on passdb failure. */
        bool failure_nodelay:1;
+       /* Sent final response (challenge). Waiting for dummy client response.
+        */
+       bool final_resp_sent:1;
 
        bool event_finished_sent:1;