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


                   
                                                        


















                                                                         
                                           
















                                                                       








                                                     




















































                                                                       
         
                                                           











                                                        
































































































































































































































































































                                                                               
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2008-2011. 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 ->
	    Dir = ?config(priv_dir, Config),
	    ssh_test_lib:save_known_hosts(Dir),
	    {ok, _} =  ssh_test_lib:get_id_keys(Dir),
	    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) ->
    Dir = ?config(priv_dir, Config),
    crypto:stop(),
    ssh_test_lib:remove_id_keys(Dir),
    ssh_test_lib:restore_known_hosts(Dir),
    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) ->
    rename_known_hosts(backup),
    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) ->
    ssh:stop(),
    rename_known_hosts(restore),
    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_allready_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.
%%--------------------------------------------------------------------

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),
    Host = ssh_test_lib:hostname(),
    Port = ssh_test_lib:inet_port(),
    {ok, Pid} = ssh:daemon(Port, [{system_dir, SystemDir},
				   {failfun, fun ssh_test_lib:failfun/2}]),
    {ok, ConnectionRef} =
	ssh:connect(Host, Port, [{silently_accept_hosts, true},
				 {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),
    Host = ssh_test_lib:hostname(),
    Port = ssh_test_lib:inet_port(),
    {ok, Pid} = ssh:daemon(Port, [{system_dir, SystemDir},
				  {compression, zlib},
				  {failfun, fun ssh_test_lib:failfun/2}]),

    {ok, ConnectionRef} =
	ssh:connect(Host, Port, [{silently_accept_hosts, true},
				 {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),
    Port = ssh_test_lib:inet_port(),
    {ok, _Pid} = ssh:daemon(Port, [{system_dir, SystemDir},
				  {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),
    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_allready_started(doc) ->
    ["Test that get correct error message if you try to start a daemon",
    "on an adress that allready runs a daemon see also seq10667" ];

daemon_allready_started(suite) ->
    [];

daemon_allready_started(Config) when is_list(Config) ->
    SystemDir = ?config(data_dir, Config),
    Port = ssh_test_lib:inet_port(),
    {ok, Pid} = ssh:daemon(Port, [{system_dir, SystemDir},
				  {failfun, fun ssh_test_lib:failfun/2}]),
   {error, eaddrinuse} = ssh: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 = ?config(data_dir, Config), % to make sure we don't use
    SysDir = ?config(data_dir, Config),	 % public-key-auth
    Port = ssh_test_lib:inet_port(),
    {ok, Pid} =
	ssh:daemon(Port, [{system_dir, SysDir},
			  {password, "morot"}]),
    Host = ssh_test_lib:hostname(),

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

    test_server:format("Test of wrong pasword: 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 = ?config(data_dir, Config),  % to make sure we don't use
    SysDir = ?config(data_dir, Config),	  % public-key-auth
    Port = ssh_test_lib:inet_port(),
    {ok, Pid} =
	ssh:daemon(Port, [{system_dir, SysDir},
			  {user_passwords, [{"vego", "morot"}]}]),
    Host = ssh_test_lib:hostname(),

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

    {error, Reason0} =
	ssh: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:connect(Host, Port, [{silently_accept_hosts, true},
				 {user, "vego"},
				 {password, "foo"},
				 {user_interaction, false},
				 {user_dir, UserDir}]),
    test_server:format("Test of wrong Pasword. "
		       "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) ->
    SystemDir = ?config(data_dir, Config),
    UserDir = ?config(priv_dir, Config),
    Port = ssh_test_lib:inet_port(),

    {ok, Pid} = ssh:daemon(Port, [{system_dir, SystemDir},
				  {failfun, fun ssh_test_lib:failfun/2}]),

    KnownHosts = filename:join(UserDir, "known_hosts"),
    file:delete(KnownHosts),
    {error, enoent} = file:read_file(KnownHosts),
    Host = ssh_test_lib:hostname(),
    {ok, ConnectionRef} =
	ssh: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,
    {ok, Hostname} = inet:gethostname(),
    [HostAndIp, Alg, _KeyData] = string:tokens(Line, " "),
    [Hostname, _Ip] = string:tokens(HostAndIp, ","),
    "ssh-" ++ _ = Alg,
     ssh:stop_daemon(Pid).

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

rename_known_hosts(BR) ->
    KnownHosts = ssh_file:file_name(user, "known_hosts", []),
    B = KnownHosts ++ "xxx",
    case BR of
	backup ->
	    file:rename(KnownHosts, B);
	restore ->
	    file:delete(KnownHosts),
	    file:rename(B, KnownHosts)
    end.