aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssh/test/ssh_basic_SUITE.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssh/test/ssh_basic_SUITE.erl')
-rw-r--r--lib/ssh/test/ssh_basic_SUITE.erl247
1 files changed, 225 insertions, 22 deletions
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index 2b3fadbbf4..f30e86f193 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -42,6 +42,7 @@ suite() ->
all() ->
[app_test,
appup_test,
+ {group, key_exchange},
{group, dsa_key},
{group, rsa_key},
{group, dsa_pass_key},
@@ -92,6 +93,11 @@ groups() ->
max_sessions_sftp_start_channel_parallel,
max_sessions_sftp_start_channel_sequential
]},
+ {key_exchange, [], ['diffie-hellman-group-exchange-sha1',
+ 'diffie-hellman-group-exchange-sha256',
+ 'diffie-hellman-group1-sha1',
+ 'diffie-hellman-group14-sha1'
+ ]},
{dir_options, [], [user_dir_option,
system_dir_option]}
].
@@ -99,7 +105,9 @@ groups() ->
basic_tests() ->
[send, close, peername_sockname,
- exec, exec_compressed, shell, cli, known_hosts,
+ exec, exec_compressed,
+ shell, shell_no_unicode, shell_unicode_string,
+ cli, known_hosts,
idle_time, openssh_zlib_basic_test, misc_ssh_options, inet_option].
@@ -144,6 +152,11 @@ init_per_group(internal_error, Config) ->
ssh_test_lib:setup_dsa(DataDir, PrivDir),
file:delete(filename:join(PrivDir, "system/ssh_host_dsa_key")),
Config;
+init_per_group(key_exchange, Config) ->
+ DataDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
+ ssh_test_lib:setup_rsa(DataDir, PrivDir),
+ Config;
init_per_group(dir_options, Config) ->
PrivDir = ?config(priv_dir, Config),
%% Make unreadable dir:
@@ -191,6 +204,8 @@ init_per_group(_, Config) ->
end_per_group(hardening_tests, Config) ->
end_per_group(dsa_key, Config);
+end_per_group(key_exchange, Config) ->
+ end_per_group(rsa_key, Config);
end_per_group(dsa_key, Config) ->
PrivDir = ?config(priv_dir, Config),
ssh_test_lib:clean_dsa(PrivDir),
@@ -215,6 +230,25 @@ end_per_group(internal_error, Config) ->
end_per_group(_, Config) ->
Config.
%%--------------------------------------------------------------------
+init_per_testcase(TC, Config) when TC==shell_no_unicode ;
+ TC==shell_unicode_string ->
+ PrivDir = ?config(priv_dir, Config),
+ UserDir = ?config(priv_dir, Config),
+ SysDir = ?config(data_dir, Config),
+ ssh:start(),
+ Sftpd = {_Pid, _Host, Port} =
+ ssh_test_lib:daemon([{system_dir, SysDir},
+ {user_dir, PrivDir},
+ {user_passwords, [{"foo", "bar"}]}]),
+ ct:sleep(500),
+ IO = ssh_test_lib:start_io_server(),
+ Shell = ssh_test_lib:start_shell(Port, IO, UserDir,
+ [{silently_accept_hosts, true},
+ {user,"foo"},{password,"bar"}]),
+ ct:log("IO=~p, Shell=~p, self()=~p",[IO,Shell,self()]),
+ ct:log("file:native_name_encoding() = ~p,~nio:getopts() = ~p",
+ [file:native_name_encoding(),io:getopts()]),
+ wait_for_erlang_first_line([{io,IO}, {shell,Shell}, {sftpd, Sftpd} | Config]);
init_per_testcase(_TestCase, Config) ->
ssh:start(),
Config.
@@ -224,6 +258,15 @@ end_per_testcase(TestCase, Config) when TestCase == server_password_option;
UserDir = filename:join(?config(priv_dir, Config), nopubkey),
ssh_test_lib:del_dirs(UserDir),
end_per_testcase(Config);
+end_per_testcase(TC, Config) when TC==shell_no_unicode ;
+ TC==shell_unicode_string ->
+ case ?config(sftpd, Config) of
+ {Pid, _, _} ->
+ ssh:stop_daemon(Pid),
+ ssh:stop();
+ _ ->
+ ssh:stop()
+ end;
end_per_testcase(_TestCase, Config) ->
end_per_testcase(Config).
end_per_testcase(_Config) ->
@@ -577,7 +620,7 @@ shell(Config) when is_list(Config) ->
{'EXIT', _, _} ->
ct:fail(no_ssh_connection);
ErlShellStart ->
- ct:pal("Erlang shell start: ~p~n", [ErlShellStart]),
+ ct:log("Erlang shell start: ~p~n", [ErlShellStart]),
do_shell(IO, Shell)
end.
@@ -661,7 +704,7 @@ server_password_option(Config) when is_list(Config) ->
{user_interaction, false},
{user_dir, UserDir}]),
- ct:pal("Test of wrong password: Error msg: ~p ~n", [Reason]),
+ ct:log("Test of wrong password: Error msg: ~p ~n", [Reason]),
ssh:close(ConnectionRef),
ssh:stop_daemon(Pid).
@@ -788,6 +831,59 @@ ssh_msg_debug_fun_option_client(Config) ->
end.
%%--------------------------------------------------------------------
+'diffie-hellman-group-exchange-sha1'(Config) ->
+ kextest('diffie-hellman-group-exchange-sha1',Config).
+
+'diffie-hellman-group-exchange-sha256'(Config) ->
+ kextest('diffie-hellman-group-exchange-sha256',Config).
+
+'diffie-hellman-group1-sha1'(Config) ->
+ kextest('diffie-hellman-group1-sha1',Config).
+
+'diffie-hellman-group14-sha1'(Config) ->
+ kextest('diffie-hellman-group14-sha1',Config).
+
+
+kextest(Kex, Config) ->
+ case lists:member(Kex, ssh_transport:supported_algorithms(kex)) of
+ true ->
+ process_flag(trap_exit, true),
+ SystemDir = filename:join(?config(priv_dir, Config), system),
+ UserDir = ?config(priv_dir, Config),
+
+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ {user_dir, UserDir},
+ {user_passwords, [{"foo", "bar"}]},
+ {preferred_algorithms,
+ [{kex, [Kex]}]},
+ {failfun, fun ssh_test_lib:failfun/2}]),
+
+ ConnectionRef =
+ ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
+ {user, "foo"},
+ {password, "bar"},
+ {user_dir, UserDir},
+ {preferred_algorithms,
+ [{kex, [Kex]}]},
+ {user_interaction, false}]),
+
+ {ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity),
+ success = ssh_connection:exec(ConnectionRef, ChannelId,
+ "1+1.", infinity),
+ Data = {ssh_cm, ConnectionRef, {data, ChannelId, 0, <<"2\n">>}},
+ case ssh_test_lib:receive_exec_result(Data) of
+ expected ->
+ ok;
+ Other ->
+ ct:fail(Other)
+ end,
+ ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId),
+ ssh:stop_daemon(Pid);
+ false ->
+ {skip, lists:concat([Kex, " is not supported"])}
+ end.
+
+%%--------------------------------------------------------------------
connectfun_disconnectfun_server(Config) ->
PrivDir = ?config(priv_dir, Config),
UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth
@@ -1163,13 +1259,13 @@ peername_sockname(Config) when is_list(Config) ->
ssh:connection_info(ConnectionRef, [peer]),
[{sockname, {HostSockClient,PortSockClient} = ClientSock}] =
ssh:connection_info(ConnectionRef, [sockname]),
- ct:pal("Client: ~p ~p", [ClientPeer, ClientSock]),
+ ct:log("Client: ~p ~p", [ClientPeer, ClientSock]),
receive
{ssh_cm, ConnectionRef, {data, ChannelId, _, Response}} ->
{PeerNameSrv,SockNameSrv} = binary_to_term(Response),
{HostPeerSrv,PortPeerSrv} = PeerNameSrv,
{HostSockSrv,PortSockSrv} = SockNameSrv,
- ct:pal("Server: ~p ~p", [PeerNameSrv, SockNameSrv]),
+ ct:log("Server: ~p ~p", [PeerNameSrv, SockNameSrv]),
host_equal(HostPeerSrv, HostSockClient),
PortPeerSrv = PortSockClient,
host_equal(HostSockSrv, HostPeerClient),
@@ -1347,7 +1443,7 @@ packet_size_zero(Config) ->
receive
{ssh_cm,Conn,{data,Chan,_Type,_Msg1}} = M ->
- ct:pal("Got ~p",[M]),
+ ct:log("Got ~p",[M]),
ct:fail(doesnt_obey_max_packet_size_0)
after 5000 ->
ok
@@ -1424,7 +1520,7 @@ chan_exec(ConnectionRef, Cmnd, Expected) ->
ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId0);
{unexpected_msg,{ssh_cm, ConnectionRef, {exit_status, ChannelId0, 0}}
= ExitStatus0} ->
- ct:pal("0: Collected data ~p", [ExitStatus0]),
+ ct:log("0: Collected data ~p", [ExitStatus0]),
ssh_test_lib:receive_exec_result(Data0,
ConnectionRef, ChannelId0);
Other0 ->
@@ -1516,7 +1612,7 @@ ssh_connect_negtimeout(Config, Parallel) ->
{ok,Socket} = gen_tcp:connect(Host, Port, []),
Factor = 2,
- ct:pal("And now sleeping ~p*NegTimeOut (~p ms)...", [Factor, round(Factor * NegTimeOut)]),
+ ct:log("And now sleeping ~p*NegTimeOut (~p ms)...", [Factor, round(Factor * NegTimeOut)]),
ct:sleep(round(Factor * NegTimeOut)),
case inet:sockname(Socket) of
@@ -1547,22 +1643,22 @@ ssh_connect_nonegtimeout_connected(Config, Parallel) ->
{parallel_login, Parallel},
{negotiation_timeout, NegTimeOut},
{failfun, fun ssh_test_lib:failfun/2}]),
- ct:pal("~p Listen ~p:~p",[_Pid,_Host,Port]),
+ ct:log("~p Listen ~p:~p",[_Pid,_Host,Port]),
ct:sleep(500),
IO = ssh_test_lib:start_io_server(),
Shell = ssh_test_lib:start_shell(Port, IO, UserDir),
receive
Error = {'EXIT', _, _} ->
- ct:pal("~p",[Error]),
+ ct:log("~p",[Error]),
ct:fail(no_ssh_connection);
ErlShellStart ->
- ct:pal("---Erlang shell start: ~p~n", [ErlShellStart]),
+ ct:log("---Erlang shell start: ~p~n", [ErlShellStart]),
one_shell_op(IO, NegTimeOut),
one_shell_op(IO, NegTimeOut),
Factor = 2,
- ct:pal("And now sleeping ~p*NegTimeOut (~p ms)...", [Factor, round(Factor * NegTimeOut)]),
+ ct:log("And now sleeping ~p*NegTimeOut (~p ms)...", [Factor, round(Factor * NegTimeOut)]),
ct:sleep(round(Factor * NegTimeOut)),
one_shell_op(IO, NegTimeOut)
@@ -1571,7 +1667,7 @@ ssh_connect_nonegtimeout_connected(Config, Parallel) ->
one_shell_op(IO, TimeOut) ->
- ct:pal("One shell op: Waiting for prompter"),
+ ct:log("One shell op: Waiting for prompter"),
receive
ErlPrompt0 -> ct:log("Erlang prompt: ~p~n", [ErlPrompt0])
after TimeOut -> ct:fail("Timeout waiting for promter")
@@ -1597,7 +1693,23 @@ one_shell_op(IO, TimeOut) ->
end.
%%--------------------------------------------------------------------
+shell_no_unicode(Config) ->
+ new_do_shell(?config(io,Config),
+ [new_prompt,
+ {type,"io:format(\"hej ~p~n\",[42])."},
+ {expect,"hej 42"}
+ ]).
+
+%%--------------------------------------------------------------------
+shell_unicode_string(Config) ->
+ new_do_shell(?config(io,Config),
+ [new_prompt,
+ {type,"io:format(\"こにちわ~ts~n\",[\"四二\"])."},
+ {expect,"こにちわ四二"},
+ {expect,"ok"}
+ ]).
+%%--------------------------------------------------------------------
openssh_zlib_basic_test() ->
[{doc, "Test basic connection with openssh_zlib"}].
openssh_zlib_basic_test(Config) ->
@@ -1658,7 +1770,7 @@ connect_fun(ssh_sftp__start_channel, _Config) ->
max_sessions(Config, ParallelLogin, Connect0) when is_function(Connect0,2) ->
Connect = fun(Host,Port) ->
R = Connect0(Host,Port),
- ct:pal("Connect(~p,~p) -> ~p",[Host,Port,R]),
+ ct:log("Connect(~p,~p) -> ~p",[Host,Port,R]),
R
end,
SystemDir = filename:join(?config(priv_dir, Config), system),
@@ -1671,7 +1783,7 @@ max_sessions(Config, ParallelLogin, Connect0) when is_function(Connect0,2) ->
{parallel_login, ParallelLogin},
{max_sessions, MaxSessions}
]),
- ct:pal("~p Listen ~p:~p for max ~p sessions",[Pid,Host,Port,MaxSessions]),
+ ct:log("~p Listen ~p:~p for max ~p sessions",[Pid,Host,Port,MaxSessions]),
try [Connect(Host,Port) || _ <- lists:seq(1,MaxSessions)]
of
Connections ->
@@ -1680,7 +1792,7 @@ max_sessions(Config, ParallelLogin, Connect0) when is_function(Connect0,2) ->
[_|_] = Connections,
%% Now try one more than alowed:
- ct:pal("Info Report might come here...",[]),
+ ct:log("Info Report might come here...",[]),
try Connect(Host,Port)
of
_ConnectionRef1 ->
@@ -1792,6 +1904,8 @@ check_error("Invalid state") ->
ok;
check_error("Connection closed") ->
ok;
+check_error("Selection of key exchange algorithm failed") ->
+ ok;
check_error(Error) ->
ct:fail(Error).
@@ -1807,12 +1921,12 @@ basic_test(Config) ->
do_shell(IO, Shell) ->
receive
ErlPrompt0 ->
- ct:pal("Erlang prompt: ~p~n", [ErlPrompt0])
+ ct:log("Erlang prompt: ~p~n", [ErlPrompt0])
end,
IO ! {input, self(), "1+1.\r\n"},
receive
Echo0 ->
- ct:pal("Echo: ~p ~n", [Echo0])
+ ct:log("Echo: ~p ~n", [Echo0])
end,
receive
?NEWLINE ->
@@ -1820,7 +1934,7 @@ do_shell(IO, Shell) ->
end,
receive
Result0 = <<"2">> ->
- ct:pal("Result: ~p~n", [Result0])
+ ct:log("Result: ~p~n", [Result0])
end,
receive
?NEWLINE ->
@@ -1828,7 +1942,7 @@ do_shell(IO, Shell) ->
end,
receive
ErlPrompt1 ->
- ct:pal("Erlang prompt: ~p~n", [ErlPrompt1])
+ ct:log("Erlang prompt: ~p~n", [ErlPrompt1])
end,
exit(Shell, kill).
%%Does not seem to work in the testserver!
@@ -1839,7 +1953,7 @@ do_shell(IO, Shell) ->
%% end,
%% receive
%% Echo1 ->
- %% ct:pal("Echo: ~p ~n", [Echo1])
+ %% ct:log("Echo: ~p ~n", [Echo1])
%% end,
%% receive
%% ?NEWLINE ->
@@ -1847,7 +1961,7 @@ do_shell(IO, Shell) ->
%% end,
%% receive
%% Result1 ->
- %% ct:pal("Result: ~p~n", [Result1])
+ %% ct:log("Result: ~p~n", [Result1])
%% end,
%% receive
%% {'EXIT', Shell, killed} ->
@@ -1855,6 +1969,95 @@ do_shell(IO, Shell) ->
%% end.
+%%--------------------------------------------------------------------
+wait_for_erlang_first_line(Config) ->
+ receive
+ {'EXIT', _, _} ->
+ {fail,no_ssh_connection};
+ <<"Eshell ",_/binary>> = _ErlShellStart ->
+ ct:log("Erlang shell start: ~p~n", [_ErlShellStart]),
+ Config;
+ Other ->
+ ct:log("Unexpected answer from ssh server: ~p",[Other]),
+ {fail,unexpected_answer}
+ after 10000 ->
+ ct:log("No answer from ssh-server"),
+ {fail,timeout}
+ end.
+
+
+
+new_do_shell(IO, List) -> new_do_shell(IO, 0, List).
+
+new_do_shell(IO, N, [new_prompt|More]) ->
+ new_do_shell(IO, N+1, More);
+
+new_do_shell(IO, N, Ops=[{Order,Arg}|More]) ->
+ Pfx = prompt_prefix(),
+ PfxSize = size(Pfx),
+ receive
+ _X = <<"\r\n">> ->
+ ct:log("Skip newline ~p",[_X]),
+ new_do_shell(IO, N, Ops);
+
+ <<Pfx:PfxSize/binary,P1,"> ">> when (P1-$0)==N ->
+ new_do_shell_prompt(IO, N, Order, Arg, More);
+
+ <<Pfx:PfxSize/binary,P1,P2,"> ">> when (P1-$0)*10 + (P2-$0) == N ->
+ new_do_shell_prompt(IO, N, Order, Arg, More);
+
+ <<Pfx:PfxSize/binary,P1,P2,P3,"> ">> when (P1-$0)*100 + (P2-$0)*10 + (P3-$0) == N ->
+ new_do_shell_prompt(IO, N, Order, Arg, More);
+
+ Err when element(1,Err)==error ->
+ ct:fail("new_do_shell error: ~p~n",[Err]);
+
+ RecBin when Order==expect ; Order==expect_echo ->
+ ct:log("received ~p",[RecBin]),
+ RecStr = string:strip(unicode:characters_to_list(RecBin)),
+ ExpStr = string:strip(Arg),
+ case lists:prefix(ExpStr, RecStr) of
+ true when Order==expect ->
+ ct:log("Matched ~ts",[RecStr]),
+ new_do_shell(IO, N, More);
+ true when Order==expect_echo ->
+ ct:log("Matched echo ~ts",[RecStr]),
+ new_do_shell(IO, N, More);
+ false ->
+ ct:fail("*** Expected ~p, but got ~p",[string:strip(ExpStr),RecStr])
+ end
+ after 30000 ->
+ ct:log("Meassage queue of ~p:~n~p",
+ [self(), erlang:process_info(self(), messages)]),
+ case Order of
+ expect -> ct:fail("timeout, expected ~p",[string:strip(Arg)]);
+ type -> ct:fail("timeout, no prompt")
+ end
+ end;
+
+new_do_shell(_, _, []) ->
+ ok.
+
+prompt_prefix() ->
+ case node() of
+ nonode@nohost -> <<>>;
+ Node -> list_to_binary(
+ lists:concat(["(",Node,")"]))
+ end.
+
+
+new_do_shell_prompt(IO, N, type, Str, More) ->
+ ct:log("Matched prompt ~p to trigger sending of next line to server",[N]),
+ IO ! {input, self(), Str++"\r\n"},
+ ct:log("Promt '~p> ', Sent ~ts",[N,Str++"\r\n"]),
+ new_do_shell(IO, N, [{expect_echo,Str}|More]); % expect echo of the sent line
+new_do_shell_prompt(IO, N, Op, Str, More) ->
+ ct:log("Matched prompt ~p",[N]),
+ new_do_shell(IO, N, [{Op,Str}|More]).
+
+%%--------------------------------------------------------------------
+
+
std_daemon(Config, ExtraOpts) ->
SystemDir = ?config(data_dir, Config),
PrivDir = ?config(priv_dir, Config),