File 5021-ssh-tolerate-extra-ssh_msg_service_request.patch of Package erlang
From 63aec63750c8aeeded82dc1b7a1318d7ef44b630 Mon Sep 17 00:00:00 2001
From: Jakub Witczak <kuba@erlang.org>
Date: Wed, 14 May 2025 11:43:25 +0200
Subject: [PATCH] ssh: tolerate extra ssh_msg_service_request
{userauth,server} guard added due to interoperability with clients
sending extra ssh_msg_service_request (e.g. Paramiko for Python,see
GH-6463)
---
lib/ssh/src/ssh_connection_handler.erl | 9 ++++--
lib/ssh/test/ssh_protocol_SUITE.erl | 44 ++++++++++++++++++++++++--
2 files changed, 48 insertions(+), 5 deletions(-)
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 2648c5256b..3eb8266a95 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -661,9 +661,12 @@ handle_event(state_timeout, no_hello_received, {hello,_Role}=StateName, D0 = #da
{stop, Shutdown, D};
-%%% ######## {service_request, client|server} ####
-
-handle_event(internal, Msg = #ssh_msg_service_request{name=ServiceName}, StateName = {service_request,server}, D0) ->
+%%% ######## {service_request, client|server} #### StateName ==
+%% {userauth,server} guard added due to interoperability with clients
+%% sending extra ssh_msg_service_request (e.g. Paramiko for Python,
+%% see GH-6463)
+handle_event(internal, Msg = #ssh_msg_service_request{name=ServiceName}, StateName, D0)
+ when StateName == {service_request,server}; StateName == {userauth,server} ->
case ServiceName of
"ssh-userauth" ->
Ssh0 = #ssh{session_id=SessionId} = D0#data.ssh_params,
diff --git a/lib/ssh/test/ssh_protocol_SUITE.erl b/lib/ssh/test/ssh_protocol_SUITE.erl
index b2a3fc4172..29254dd5f9 100644
--- a/lib/ssh/test/ssh_protocol_SUITE.erl
+++ b/lib/ssh/test/ssh_protocol_SUITE.erl
@@ -80,7 +80,8 @@
preferred_algorithms/1,
service_name_length_too_large/1,
service_name_length_too_short/1,
- client_close_after_hello/1
+ client_close_after_hello/1,
+ extra_ssh_msg_service_request/1
]).
-define(NEWLINE, <<"\r\n">>).
@@ -148,7 +149,8 @@ groups() ->
bad_long_service_name,
bad_very_long_service_name,
empty_service_name,
- bad_service_name_then_correct
+ bad_service_name_then_correct,
+ extra_ssh_msg_service_request
]},
{authentication, [], [client_handles_keyboard_interactive_0_pwds,
client_handles_banner_keyboard_interactive,
@@ -1055,6 +1057,44 @@ client_close_after_hello(Config0) ->
{fail, no_handshakers}
end.
+%%% Connect to an erlang server and pretend client sending extra
+%%% ssh_msg_service_request (Paramiko client behavior)
+extra_ssh_msg_service_request(Config) ->
+ %% Connect and negotiate keys
+ {ok,InitialState} = ssh_trpt_test_lib:exec(
+ [{set_options, [print_ops, print_seqnums, print_messages]}]
+ ),
+ {ok,AfterKexState} = connect_and_kex(Config, InitialState),
+ %% Do the authentcation
+ {User,Pwd} = server_user_password(Config),
+ UserAuthFlow =
+ fun(P) ->
+ [{send, #ssh_msg_service_request{name = "ssh-userauth"}},
+ {match, #ssh_msg_service_accept{name = "ssh-userauth"}, receive_msg},
+ {send, #ssh_msg_userauth_request{user = User,
+ service = "ssh-connection",
+ method = "password",
+ data = <<?BOOLEAN(?FALSE),
+ ?STRING(unicode:characters_to_binary(P))>>
+ }}]
+ end,
+ {ok,EndState} =
+ ssh_trpt_test_lib:exec(
+ UserAuthFlow("WRONG") ++
+ [{match, #ssh_msg_userauth_failure{_='_'}, receive_msg}] ++
+ UserAuthFlow(Pwd) ++
+ [{match, #ssh_msg_userauth_success{_='_'}, receive_msg}],
+ AfterKexState),
+ %% Disconnect
+ {ok,_} =
+ ssh_trpt_test_lib:exec(
+ [{send, #ssh_msg_disconnect{code = ?SSH_DISCONNECT_BY_APPLICATION,
+ description = "End of the fun",
+ language = ""
+ }},
+ close_socket
+ ], EndState),
+ ok.
%%%================================================================
%%%==== Internal functions ========================================
--
2.43.0