From: Stephan Bosch Date: Fri, 27 Oct 2023 02:42:09 +0000 (+0200) Subject: lib-auth-client: auth-client - Implement implicit handling of final SASL reply X-Git-Tag: 2.4.0~2418 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=694fcf6d0d68ccf768e10107f7c145a2731afa45;p=thirdparty%2Fdovecot%2Fcore.git lib-auth-client: auth-client - Implement implicit handling of final SASL reply Turn it into a additional SASL interaction cycle if the client does not support handing a final reply/challenge. --- diff --git a/src/lib-auth-client/auth-client-private.h b/src/lib-auth-client/auth-client-private.h index d5c99e2fc3..b87bf9339d 100644 --- a/src/lib-auth-client/auth-client-private.h +++ b/src/lib-auth-client/auth-client-private.h @@ -9,13 +9,17 @@ struct auth_client_request { pool_t pool; + enum auth_request_flags flags; struct event *event; struct auth_client_connection *conn; - struct timeout *to_fail; + struct timeout *to_fail, *to_final; unsigned int id; time_t created; + enum auth_request_status final_status; + const char *const *final_args; + auth_request_callback_t *callback; void *context; diff --git a/src/lib-auth-client/auth-client-request.c b/src/lib-auth-client/auth-client-request.c index 472e3c05ea..bda7e2bcd6 100644 --- a/src/lib-auth-client/auth-client-request.c +++ b/src/lib-auth-client/auth-client-request.c @@ -10,6 +10,11 @@ static void auth_client_request_fail_conn_lost(struct auth_client_request *request); +static void +auth_client_request_handle_input(struct auth_client_request **_request, + enum auth_request_status status, + const char *base64_data, + const char *const *args, bool final); static void auth_server_send_new_request(struct auth_client_connection *conn, @@ -190,6 +195,8 @@ auth_client_request_new(struct auth_client *client, request = p_new(pool, struct auth_client_request, 1); request->pool = pool; request->conn = client->conn; + request->flags = request_info->flags; + request->final_status = AUTH_REQUEST_STATUS_CONTINUE; request->callback = callback; request->context = context; @@ -250,6 +257,7 @@ static void auth_client_request_free(struct auth_client_request **_request) auth_client_connection_remove_request(request->conn, request); timeout_remove(&request->to_fail); + timeout_remove(&request->to_final); event_unref(&request->event); pool_unref(&request->pool); } @@ -310,12 +318,26 @@ args_parse_user(struct auth_client_request *request, const char *key, event_add_str(request->event, "auth_user", value); } +static void auth_client_request_final(struct auth_client_request *request) +{ + timeout_remove(&request->to_final); + i_assert(request->final_status != AUTH_REQUEST_STATUS_CONTINUE); + auth_client_request_handle_input(&request, request->final_status, NULL, + request->final_args, FALSE); +} + void auth_client_request_continue(struct auth_client_request *request, const char *data_base64) { struct const_iovec iov[3]; const char *prefix; + if (request->final_status != AUTH_REQUEST_STATUS_CONTINUE) { + request->to_final = timeout_add_short( + 0, auth_client_request_final, request); + return; + } + if (!request->conn->connected) { e_error(request->event, "Error sending continue request to auth server: " @@ -343,18 +365,20 @@ void auth_client_request_continue(struct auth_client_request *request, } } -void auth_client_request_server_input(struct auth_client_request **_request, - enum auth_request_status status, - const char *const *args) +static void +auth_client_request_handle_input(struct auth_client_request **_request, + enum auth_request_status status, + const char *base64_data, + const char *const *args, bool final) { struct auth_client_request *request = *_request; - const char *const *tmp, *base64_data = NULL; + const char *const *tmp; struct event_passthrough *e; if (auth_client_request_is_aborted(request)) { /* aborted already */ auth_client_request_free(_request); - return TRUE; + return; } switch (status) { @@ -368,17 +392,14 @@ void auth_client_request_server_input(struct auth_client_request **_request, break; } - for (tmp = args; *tmp != NULL; tmp++) { + for (tmp = args; tmp != NULL && *tmp != NULL; tmp++) { const char *key; const char *value; t_split_key_value_eq(*tmp, &key, &value); - if (str_begins(key, "event_", &key)) { + if (str_begins(key, "event_", &key)) event_add_str(request->event, key, value); - } else if (strcmp(key, "resp") == 0) { - base64_data = value; - } else { + else args_parse_user(request, key, value); - } } switch (status) { @@ -386,9 +407,10 @@ void auth_client_request_server_input(struct auth_client_request **_request, e_debug(e->event(), "Finished"); break; case AUTH_REQUEST_STATUS_CONTINUE: - base64_data = args[0]; - args = NULL; - e_debug(e->event(), "Got challenge"); + if (!final) + e_debug(e->event(), "Got challenge"); + else + e_debug(e->event(), "Created final challenge"); break; case AUTH_REQUEST_STATUS_FAIL: e->add_str("error", "Authentication failed"); @@ -407,6 +429,54 @@ void auth_client_request_server_input(struct auth_client_request **_request, auth_client_request_free(_request); } +void auth_client_request_server_input(struct auth_client_request **_request, + enum auth_request_status status, + const char *const *args) +{ + struct auth_client_request *request = *_request; + const char *const *tmp, *base64_data = NULL; + bool final = FALSE; + + if (auth_client_request_is_aborted(request)) { + /* aborted already */ + auth_client_request_free(_request); + return; + } + + switch (status) { + case AUTH_REQUEST_STATUS_FAIL: + case AUTH_REQUEST_STATUS_OK: + case AUTH_REQUEST_STATUS_INTERNAL_FAIL: + for (tmp = args; *tmp != NULL; tmp++) { + const char *key; + const char *value; + t_split_key_value_eq(*tmp, &key, &value); + if (strcmp(key, "resp") == 0) + base64_data = value; + } + if (base64_data == NULL || + (status == AUTH_REQUEST_STATUS_OK && + HAS_ALL_BITS(request->flags, + AUTH_REQUEST_FLAG_SUPPORT_FINAL_RESP))) + break; + request->final_status = status; + request->final_args = p_strarray_dup(request->pool, args); + status = AUTH_REQUEST_STATUS_CONTINUE; + args = NULL; + final = TRUE; + break; + case AUTH_REQUEST_STATUS_CONTINUE: + base64_data = args[0]; + args = NULL; + break; + case AUTH_REQUEST_STATUS_ABORT: + i_unreached(); + } + + auth_client_request_handle_input(_request, status, + base64_data, args, final); +} + void auth_client_send_cancel(struct auth_client *client, unsigned int id) { if (!client->conn->connected) { diff --git a/src/lib-auth-client/auth-client.h b/src/lib-auth-client/auth-client.h index 79b23bd848..236e97648d 100644 --- a/src/lib-auth-client/auth-client.h +++ b/src/lib-auth-client/auth-client.h @@ -17,6 +17,8 @@ enum auth_request_flags { AUTH_REQUEST_FLAG_VALID_CLIENT_CERT = 0x02, /* Skip penalty checks for this request */ AUTH_REQUEST_FLAG_NO_PENALTY = 0x04, + /* Support final SASL response (handled locally) */ + AUTH_REQUEST_FLAG_SUPPORT_FINAL_RESP = 0x08, /* Enable auth_debug=yes logging for this request */ AUTH_REQUEST_FLAG_DEBUG = 0x10, /* Connection from the previous hop is secured by TLS. */ diff --git a/src/login-common/sasl-server.c b/src/login-common/sasl-server.c index 99c4c8ab51..6f88a6aea2 100644 --- a/src/login-common/sasl-server.c +++ b/src/login-common/sasl-server.c @@ -113,6 +113,8 @@ client_get_auth_flags(struct client *client) auth_flags |= AUTH_REQUEST_FLAG_CONN_SECURED_TLS; if (client->connection_secured) auth_flags |= AUTH_REQUEST_FLAG_CONN_SECURED; + if (login_binary->sasl_support_final_reply) + auth_flags |= AUTH_REQUEST_FLAG_SUPPORT_FINAL_RESP; return auth_flags; }