aboutsummaryrefslogblamecommitdiffstats
path: root/lib/ssh/test/ssh_to_openssh_SUITE.erl
blob: 334281f53ba0fe55f835da835b25d1e65c7b294e (plain) (tree)
1
2
3
4
5


                   
                                                        
  










                                                                           






                              
                                           
                             



                                                           
                              
                               
 
                                                                      
                                                                      
                                                                      
 
          
                              
 
         
                                     

                                                    
            


                                    

        
            
                                                            
                            
                                                                  
                           

      
                         


                                                   
                                                         



                                                        

                         

       
                                        

                                                    
                                                        
                                                        
           


                                                
                                                          
                                        
                            
           
 
                                       
                                                    
                                    
                                    

                           
           
 
 


                                                                      
                                                                      
        









                                                                      
                                                                      
 

                                           
 


                                                                  
                                                            
                                       
                                   
                                   
                     

                               
                                                                      

                                                               
                         


                                                       
 
                                                                     
                                                                                     

                  
                    
                                                                         
                                                             

                                         






                                                                                           

                              





                                                                                    
                                                                                           
                                         


                                     




                                                  


                          




                                                            
                                                                                                    



                                  

                                                                      
                                                                      
                                                                      
                           




                                                                 
                                                                                    


                                                       
                                            


                                             








                                                                                      

                


                       
                           


                                          

                                                                 
                
               
                                                                
                            


                                                         
 







                                            

                                                         
        
 







                       
                                                                      
                                                                       
                                   

                                                





                                                           



                                                                 
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%%     http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% %CopyrightEnd%
%%

%%
-module(ssh_to_openssh_SUITE).

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

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

-define(SSH_DEFAULT_PORT, 22).
-define(REKEY_DATA_TMO, 65000).

%%--------------------------------------------------------------------
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------

suite() ->
    [{timetrap,{seconds,60}}].

all() -> 
    case os:find_executable("ssh") of
	false -> 
	    {skip, "openSSH not installed on host"};
	_ ->
	    [{group, erlang_client},
	     {group, erlang_server}
	     ]
    end.

groups() -> 
    [{erlang_client, [], [erlang_shell_client_openssh_server
			 ]},
     {erlang_server, [], [erlang_server_openssh_client_renegotiate
			 ]}
    ].

init_per_suite(Config) ->
    ?CHECK_CRYPTO(
       case gen_tcp:connect("localhost", 22, []) of
	   {error,econnrefused} ->
	       {skip,"No openssh deamon (econnrefused)"};
	   _ ->
	       ssh_test_lib:openssh_sanity_check(Config)
       end
      ).

end_per_suite(_Config) ->
    ok.

init_per_group(erlang_server, Config) ->
    DataDir = proplists:get_value(data_dir, Config),
    UserDir = proplists:get_value(priv_dir, Config),
    ssh_test_lib:setup_dsa_known_host(DataDir, UserDir),
    ssh_test_lib:setup_rsa_known_host(DataDir, UserDir),
    Config;
init_per_group(erlang_client, Config) ->
    CommonAlgs = ssh_test_lib:algo_intersection(
		   ssh:default_algorithms(),
		   ssh_test_lib:default_algorithms(sshd)),
    [{common_algs,CommonAlgs} | Config];
init_per_group(_, Config) ->
    Config.

end_per_group(erlang_server, Config) ->
    UserDir = proplists:get_value(priv_dir, Config),
    ssh_test_lib:clean_dsa(UserDir),
    ssh_test_lib:clean_rsa(UserDir),
    Config;
end_per_group(_, Config) ->
    Config.


init_per_testcase(erlang_server_openssh_client_renegotiate, Config) ->
    case os:type() of
	{unix,_} -> ssh:start(), Config;
	Type -> {skip, io_lib:format("Unsupported test on ~p",[Type])}
    end;
init_per_testcase(_TestCase, Config) ->
    ssh:start(),
    Config.

end_per_testcase(_TestCase, _Config) ->
    ssh:stop(),
    ok.

%%--------------------------------------------------------------------
%% Test Cases --------------------------------------------------------
%%--------------------------------------------------------------------

erlang_shell_client_openssh_server() ->
    [{doc, "Test that ssh:shell/2 works"}].

erlang_shell_client_openssh_server(Config) when is_list(Config) ->
    process_flag(trap_exit, true),
    IO = ssh_test_lib:start_io_server(),
    Shell = ssh_test_lib:start_shell(?SSH_DEFAULT_PORT, IO),
    IO ! {input, self(), "echo Hej\n"},
    receive_data("Hej", undefined),
    IO ! {input, self(), "exit\n"},
    receive_logout(),
    receive_normal_exit(Shell).
   
%%--------------------------------------------------------------------
%% Test that the Erlang/OTP server can renegotiate with openSSH
erlang_server_openssh_client_renegotiate(Config) ->
    _PubKeyAlg = ssh_rsa,
    SystemDir = proplists:get_value(data_dir, Config),
    PrivDir = proplists:get_value(priv_dir, Config),
    KnownHosts = filename:join(PrivDir, "known_hosts"),

    {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
                                             {failfun, fun ssh_test_lib:failfun/2}]),
    ct:sleep(500),

    RenegLimitK = 3,
    DataFile = filename:join(PrivDir, "renegotiate_openssh_client.data"),
    Data =  lists:duplicate(trunc(1.1*RenegLimitK*1024), $a),
    ok = file:write_file(DataFile, Data),

    Cmd = ssh_test_lib:open_sshc_cmd(Host, Port,
                                     [" -o UserKnownHostsFile=", KnownHosts,
                                      " -o StrictHostKeyChecking=no",
                                      " -o RekeyLimit=",integer_to_list(RenegLimitK),"K"]),


    OpenSsh = ssh_test_lib:open_port({spawn, Cmd++" < "++DataFile}),

    Expect = fun({data,R}) -> 
		     try
			 NonAlphaChars = [C || C<-lists:seq(1,255), 
					       not lists:member(C,lists:seq($a,$z)),
					       not lists:member(C,lists:seq($A,$Z))
					 ],
			 Lines = string:tokens(binary_to_list(R), NonAlphaChars),
			 lists:any(fun(L) -> length(L)>1 andalso lists:prefix(L, Data) end,
				   Lines)
		     catch
			 _:_ -> false
		     end;

		({exit_status,E}) when E=/=0 ->
		     ct:log("exit_status ~p",[E]),
		     throw({skip,"exit status"});

		(_) ->
		     false
	     end,
    
    try 
	ssh_test_lib:rcv_expected(Expect, OpenSsh, ?TIMEOUT)
    of
	_ ->
	    %% Unfortunately we can't check that there has been a renegotiation, just trust OpenSSH.
	    ssh:stop_daemon(Pid)
    catch
	throw:{skip,R} -> {skip,R}
    end.

%%--------------------------------------------------------------------
%%% Internal functions -----------------------------------------------
%%--------------------------------------------------------------------
receive_data(Data, Conn) ->
    receive
	Info when is_binary(Info) ->
	    Lines = string:tokens(binary_to_list(Info), "\r\n "),
	    case lists:member(Data, Lines) of
		true ->
		    ct:log("Expected result ~p found in lines: ~p~n", [Data,Lines]),
		    ok;
		false ->
		    ct:log("Extra info: ~p~n", [Info]),
		    receive_data(Data, Conn)
	    end;
	Other ->
	    ct:log("Unexpected: ~p",[Other]),
	    receive_data(Data, Conn)
    after
	30000 ->
             {State, _} = case Conn of
                              undefined -> {'??','??'};
                              _ -> sys:get_state(Conn)
                          end,
            ct:log("timeout ~p:~p~nExpect ~p~nState = ~p",[?MODULE,?LINE,Data,State]),
            ct:fail("timeout ~p:~p",[?MODULE,?LINE])
    end.	

receive_logout() ->
    receive
	<<"logout">> ->
	    extra_logout(),
	    receive
		<<"Connection closed">> ->
		    ok
	    after 
		30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE])
	    end;
	Info ->
	    ct:log("Extra info when logging out: ~p~n", [Info]),
	    receive_logout()
    after 
	30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE])
    end.

receive_normal_exit(Shell) ->
    receive
	{'EXIT', Shell, normal} ->
	    ok;
	<<"\r\n">> ->
	    receive_normal_exit(Shell);
	Other ->
	    ct:fail({unexpected_msg, Other})
    after 
	30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE])
    end.

extra_logout() ->
    receive 	
	<<"logout">> ->
	    ok
    after 500 -> 
	    ok
    end.

%%--------------------------------------------------------------------
%% Check if we have a "newer" ssh client that supports these test cases
check_ssh_client_support(Config) ->
    case ssh_test_lib:ssh_client_supports_Q() of
	true ->
	    ssh:start(),
	    Config;
	_ ->
	    {skip, "test case not supported by ssh client"}
    end.

comment(AtomList) ->
    ct:comment(
      string:join(lists:map(fun erlang:atom_to_list/1, AtomList),
		", ")).