aboutsummaryrefslogblamecommitdiffstats
path: root/lib/ssh/test/ssh_basic_SUITE.erl
blob: b09c95d6cb81558204bd962f35e3b85566002b8a (plain) (tree)
1
2
3
4


                   
                                                        


















                                                                         
                                           
















                                                                       

                                














                                                                                     



                                                  







                                                                      
                  















                                                                       










                                                                      








                                                                                 
               









                                                                      
         

                                                                      









                                     

                                                                      









                                                                                      









                                              

                                        
                                                                     
                                                                 


                                                                                     
                                                              
                                                                      




































                                                                               


                                                                                         




                                                                                     
                                                              
                                                                      























                                                                              


                                                                                           
                                                                                       


                                        
                                                        





















































                                                                           
                              
                                                                        
                                                                  
 
                                

       
                                                      
                                          




                                                                                      







                                                                      


                                                                                                             








                                                                        
                     






                                                                             










                                                                      


                                                                                                             








                                                                                     


                             





                                                                        



                                                               





                                                                        
                                                      
    







                                                                      
                                        
                                        

                                                                                       
                                                                                     



                                                       



                                                                    




                                                                             
                                                          
                                                





                                                                      
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
%%
%% %CopyrightEnd%
%%

%%

-module(ssh_basic_SUITE).

-include_lib("common_test/include/ct.hrl").
-include("test_server_line.hrl").

%% Note: This directive should only be used in test suites.
-compile(export_all).

-define(NEWLINE, <<"\r\n">>).

%%--------------------------------------------------------------------
%% Function: init_per_suite(Config) -> Config
%% Config - [tuple()]
%%   A list of key/value pairs, holding the test case configuration.
%% Description: Initialization before the whole suite
%%
%% Note: This function is free to add any key/value pairs to the Config
%% variable, but should NOT alter/remove any existing entries.
%%--------------------------------------------------------------------
init_per_suite(Config) ->
    case catch crypto:start() of
	ok ->
	    DataDir = ?config(data_dir, Config),
	    UserDir = ?config(priv_dir, Config),
	    ssh_test_lib:copyfile(DataDir, UserDir, "id_rsa"), 
	    ssh_test_lib:copyfile(DataDir, UserDir, "id_dsa"),
	    RSAFile = filename:join(DataDir, "id_rsa.pub"),
	    DSAFile = filename:join(DataDir, "id_dsa.pub"),
	    {ok, Ssh1} = file:read_file(RSAFile),
	    {ok, Ssh2} = file:read_file(DSAFile),
	    [{RSA, _}] = public_key:ssh_decode(Ssh1,public_key), 
	    [{DSA, _}] = public_key:ssh_decode(Ssh2,public_key), 
	    AuthKeys = public_key:ssh_encode([{RSA, [{comment, "Test"}]}, 
					      {DSA,[{comment, "Test"}]}], auth_keys),
	    AuthKeysFile = filename:join(UserDir, "authorized_keys"),
	    file:write_file(AuthKeysFile, AuthKeys),
	    %%ssh_test_lib:make_dsa_files(Config),
	    Config;
	_Else ->
	    {skip, "Crypto could not be started!"}
    end.

%%--------------------------------------------------------------------
%% Function: end_per_suite(Config) -> _
%% Config - [tuple()]
%%   A list of key/value pairs, holding the test case configuration.
%% Description: Cleanup after the whole suite
%%--------------------------------------------------------------------
end_per_suite(Config) ->
    crypto:stop(),
    ok.

%%--------------------------------------------------------------------
%% Function: init_per_testcase(TestCase, Config) -> Config
%% Case - atom()
%%   Name of the test case that is about to be run.
%% Config - [tuple()]
%%   A list of key/value pairs, holding the test case configuration.
%%
%% Description: Initialization before each test case
%%
%% Note: This function is free to add any key/value pairs to the Config
%% variable, but should NOT alter/remove any existing entries.
%% Description: Initialization before each test case
%%--------------------------------------------------------------------
init_per_testcase(_TestCase, Config) ->
    ssh:start(),
    Config.

%%--------------------------------------------------------------------
%% Function: end_per_testcase(TestCase, Config) -> _
%% Case - atom()
%%   Name of the test case that is about to be run.
%% Config - [tuple()]
%%   A list of key/value pairs, holding the test case configuration.
%% Description: Cleanup after each test case
%%--------------------------------------------------------------------

end_per_testcase(TestCase, Config) when TestCase == server_password_option;
					TestCase == server_userpassword_option ->
    UserDir = filename:join(?config(priv_dir, Config), nopubkey),
    file:del_dir(UserDir),
    end_per_testcase(Config);
end_per_testcase(_TestCase, Config) ->
    end_per_testcase(Config).
end_per_testcase(Config) ->    
    ssh:stop(),
    ok.

%%--------------------------------------------------------------------
%% Function: all(Clause) -> TestCases
%% Clause - atom() - suite | doc
%% TestCases - [Case]
%% Case - atom()
%%   Name of a test case.
%% Description: Returns a list of all test cases in this test suite
%%--------------------------------------------------------------------
all() -> 
    [exec, exec_compressed, shell, daemon_already_started, 
     server_password_option, server_userpassword_option, known_hosts].

groups() -> 
    [].

init_per_group(_GroupName, Config) ->
	Config.

end_per_group(_GroupName, Config) ->
	Config.

%% Test cases starts here.
%%--------------------------------------------------------------------
sign_and_verify_rsa(doc) ->
    ["Test api function ssh:sign_data and ssh:verify_data"];

sign_and_verify_rsa(suite) ->
    [];
sign_and_verify_rsa(Config) when is_list(Config) ->
    Data = ssh:sign_data(<<"correct data">>, "ssh-rsa"),
    ok = ssh:verify_data(<<"correct data">>, Data, "ssh-rsa"),
    {error,invalid_signature} = ssh:verify_data(<<"incorrect data">>, Data,"ssh-rsa").


exec(doc) ->
    ["Test api function ssh_connection:exec"];

exec(suite) ->
    [];

exec(Config) when is_list(Config) ->
    process_flag(trap_exit, true),
    SystemDir = ?config(data_dir, Config),
    UserDir = ?config(priv_dir, Config),
    
    {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
					     {user_dir, UserDir},
					     {failfun, fun ssh_test_lib:failfun/2}]),
    ConnectionRef =
	ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
					  {user_dir, UserDir},
					  {user_interaction, false}]),
    {ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity),
    success = ssh_connection:exec(ConnectionRef, ChannelId0,
				  "1+1.", infinity),
    Data0 = {ssh_cm, ConnectionRef, {data, ChannelId0, 0, <<"2\n">>}},
    case ssh_test_lib:receive_exec_result(Data0) of
	expected ->
	    ok;
	Other0 ->
	    test_server:fail(Other0)
    end,
    ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId0),

    %% Test that it is possible to start a new channel and
    %% run an other exec on the same connection.
    {ok, ChannelId1} = ssh_connection:session_channel(ConnectionRef, infinity),
    success = ssh_connection:exec(ConnectionRef, ChannelId1,
				  "2+2.", infinity),
    Data1 = {ssh_cm, ConnectionRef, {data, ChannelId1, 0, <<"4\n">>}},
    case ssh_test_lib:receive_exec_result(Data1) of
	expected ->
	    ok;
	Other1 ->
	    test_server:fail(Other1)
    end,
    ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId1),
    ssh:stop_daemon(Pid).

%%--------------------------------------------------------------------
exec_compressed(doc) ->
    ["Test that compression option works"];

exec_compressed(suite) ->
    [];

exec_compressed(Config) when is_list(Config) ->
    process_flag(trap_exit, true),
    SystemDir = ?config(data_dir, Config),
    UserDir = ?config(priv_dir, Config),

    {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},{user_dir, UserDir},
					     {compression, zlib},
					     {failfun, fun ssh_test_lib:failfun/2}]),
    
    ConnectionRef =
	ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
					  {user_dir, UserDir},
					  {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 ->
	    test_server:fail(Other)
    end,
    ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId),
    ssh:stop_daemon(Pid).

%%--------------------------------------------------------------------

shell(doc) ->
    ["Test that ssh:shell/2 works"];

shell(suite) ->
    [];

shell(Config) when is_list(Config) ->
    process_flag(trap_exit, true),
    SystemDir = ?config(data_dir, Config),
    UserDir = ?config(priv_dir, Config),

    {_Pid, _Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},{user_dir, UserDir},
					       {failfun, fun ssh_test_lib:failfun/2}]),
    test_server:sleep(500),

    IO = ssh_test_lib:start_io_server(),
    Shell = ssh_test_lib:start_shell(Port, IO, UserDir),
    receive
	ErlShellStart ->
	    test_server:format("Erlang shell start: ~p~n", [ErlShellStart])
    end,
    receive
	ErlPrompt0 ->
	    test_server:format("Erlang prompt: ~p~n", [ErlPrompt0])
    end,
    IO ! {input, self(), "1+1.\r\n"},
     receive
	Echo0 ->
	     test_server:format("Echo: ~p ~n", [Echo0])
    end,
    receive
	?NEWLINE ->
	    ok
    end,
    receive
	Result0 = <<"2">> ->
	    test_server:format("Result: ~p~n", [Result0])
    end,
    receive
	?NEWLINE ->
	    ok
    end,
    receive
	ErlPrompt1 ->
	    test_server:format("Erlang prompt: ~p~n", [ErlPrompt1])
    end,
    exit(Shell, kill),
    %% Does not seem to work in the testserver!
    %%   IO ! {input, self(), "q().\r\n"},
    %%     receive
    %% 	?NEWLINE ->
    %% 	    ok
    %%     end,
    %%     receive
    %% 	Echo1 ->
    %% 	     test_server:format("Echo: ~p ~n", [Echo1])
    %%     end,
    %%     receive
    %% 	?NEWLINE ->
    %% 	    ok
    %%     end,
    %%     receive
    %% 	Result1 ->
    %% 	    test_server:format("Result: ~p~n", [Result1])
    %%     end,
    receive
	{'EXIT', Shell, killed} ->
	    ok
    end.

%%--------------------------------------------------------------------
daemon_already_started(doc) ->
    ["Test that get correct error message if you try to start a daemon",
    "on an adress that already runs a daemon see also seq10667" ];

daemon_already_started(suite) ->
    [];

daemon_already_started(Config) when is_list(Config) ->
    SystemDir = ?config(data_dir, Config),
    {Pid, _Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
					      {failfun, fun ssh_test_lib:failfun/2}]),
    {error, eaddrinuse} = ssh_test_lib:daemon(Port, [{system_dir, SystemDir},
						     {failfun,
						      fun ssh_test_lib:failfun/2}]),
    ssh:stop_daemon(Pid).

%%--------------------------------------------------------------------
server_password_option(doc) ->
    ["validate to server that uses the 'password' option"];
server_password_option(suite) ->
    [];
server_password_option(Config) when is_list(Config) ->
    UserDir = filename:join(?config(priv_dir, Config), nopubkey), % to make sure we don't use public-key-auth
    file:make_dir(UserDir),
    SysDir = ?config(data_dir, Config),	 
    {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir},
					     {password, "morot"}]),

    ConnectionRef =
	ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
					  {user, "foo"},
					  {password, "morot"},
					  {user_interaction, false},
					  {user_dir, UserDir}]),
    {error, Reason} =
	ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
					  {user, "vego"},
					  {password, "foo"},
					  {user_interaction, false},
					  {user_dir, UserDir}]),
    
    test_server:format("Test of wrong password: Error msg: ~p ~n", [Reason]),

    ssh:close(ConnectionRef),
    ssh:stop_daemon(Pid).

%%--------------------------------------------------------------------

server_userpassword_option(doc) ->
    ["validate to server that uses the 'password' option"];
server_userpassword_option(suite) ->
    [];
server_userpassword_option(Config) when is_list(Config) ->
    UserDir = filename:join(?config(priv_dir, Config), nopubkey), % to make sure we don't use public-key-auth
    file:make_dir(UserDir),
    SysDir = ?config(data_dir, Config),	  
    {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir},
					     {user_passwords, [{"vego", "morot"}]}]),

    ConnectionRef =
	ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
					  {user, "vego"},
					  {password, "morot"},
					  {user_interaction, false},
					  {user_dir, UserDir}]),
    ssh:close(ConnectionRef),

    {error, Reason0} =
	ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
					  {user, "foo"},
					  {password, "morot"},
					  {user_interaction, false},
					  {user_dir, UserDir}]),
    
    test_server:format("Test of user foo that does not exist. "
		       "Error msg: ~p ~n", [Reason0]),

    {error, Reason1} =
	ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
					  {user, "vego"},
					  {password, "foo"},
					  {user_interaction, false},
					  {user_dir, UserDir}]),
    test_server:format("Test of wrong Password. "
		       "Error msg: ~p ~n", [Reason1]),
    
    ssh:stop_daemon(Pid).

%%--------------------------------------------------------------------
known_hosts(doc) ->
    ["check that known_hosts is updated correctly"];
known_hosts(suite) ->
    [];
known_hosts(Config) when is_list(Config) ->
    DataDir = ?config(data_dir, Config),
    UserDir = ?config(priv_dir, Config),
    
    {Pid, Host, Port} = ssh_test_lib:daemon([{user_dir, UserDir},{system_dir, DataDir},
					     {failfun, fun ssh_test_lib:failfun/2}]),

    KnownHosts = filename:join(UserDir, "known_hosts"),
    file:delete(KnownHosts),
    {error, enoent} = file:read_file(KnownHosts),
    ConnectionRef =
	ssh_test_lib:connect(Host, Port, [{user_dir, UserDir},
					  {user_interaction, false},
					  silently_accept_hosts]),
    {ok, _Channel} = ssh_connection:session_channel(ConnectionRef, infinity),
    ok = ssh:close(ConnectionRef),
    {ok, Binary} = file:read_file(KnownHosts),
    Lines = string:tokens(binary_to_list(Binary), "\n"),
    [Line] = Lines,
    [HostAndIp, Alg, _KeyData] = string:tokens(Line, " "),
    [Host, _Ip] = string:tokens(HostAndIp, ","),
    "ssh-" ++ _ = Alg,
     ssh:stop_daemon(Pid).

%%--------------------------------------------------------------------
%% Internal functions
%%--------------------------------------------------------------------