diff options
Diffstat (limited to 'lib/ssh/test/ssh_test_lib.erl')
-rw-r--r-- | lib/ssh/test/ssh_test_lib.erl | 653 |
1 files changed, 352 insertions, 301 deletions
diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl index bf533fc553..ae8f7abb70 100644 --- a/lib/ssh/test/ssh_test_lib.erl +++ b/lib/ssh/test/ssh_test_lib.erl @@ -22,12 +22,109 @@ %%---------------------------------------------------------------------- -module(ssh_test_lib). -%% Note: This directive should only be used in test suites. --compile(export_all). +-export([ +connect/2, +connect/3, +daemon/1, +daemon/2, +daemon/3, +daemon_port/1, +daemon_port/2, +gen_tcp_connect/3, +open_sshc/3, +open_sshc/4, +open_sshc_cmd/3, +open_sshc_cmd/4, +std_daemon/2, +std_daemon1/2, +std_connect/4, +std_simple_sftp/3, +std_simple_sftp/4, +std_simple_exec/3, +std_simple_exec/4, +start_shell/2, +start_shell/3, +start_io_server/0, +init_io_server/1, +loop_io_server/2, +io_request/5, +io_reply/3, +reply/2, +rcv_expected/3, +rcv_lingering/1, +receive_exec_result/1, +receive_exec_result_or_fail/1, +receive_exec_end/2, +receive_exec_end/3, +receive_exec_result/3, +failfun/2, +hostname/0, +del_dirs/1, +del_dir_contents/1, +do_del_files/2, +openssh_sanity_check/1, +default_algorithms/1, +default_algorithms/3, +default_algorithms/2, +run_fake_ssh/1, +extract_algos/1, +get_atoms/1, +intersection/2, +intersect/2, +intersect_bi_dir/1, +some_empty/1, +sort_spec/1, +sshc/1, +ssh_type/0, +ssh_type1/0, +installed_ssh_version/1, +algo_intersection/2, +to_atoms/1, +ssh_supports/2, +has_inet6_address/0, +open_port/1, +open_port/2, +sleep_millisec/1, +sleep_microsec/1, +busy_wait/2, +get_kex_init/1, +get_kex_init/3, +expected_state/1, +random_chars/1, +create_random_dir/1, +match_ip/2, +match_ip0/2, +match_ip1/2, +mangle_connect_address/1, +mangle_connect_address/2, +loopback/1, +mangle_connect_address1/2, +ntoa/1, +try_enable_fips_mode/0, +is_cryptolib_fips_capable/0, +report/2, +lc_name_in/1, +ptty_supported/0, +has_WSL/0, +winpath_to_linuxpath/1, +copy_recursive/2, +mk_dir_path/1, +setup_all_user_host_keys/1, +setup_all_user_host_keys/2, +setup_all_user_host_keys/3, +setup_all_host_keys/1, +setup_all_host_keys/2, +setup_all_user_keys/2, +setup_user_key/3, +setup_host_key_create_dir/3, +setup_host_key/3, +setup_known_host/3, +get_addr_str/0, +file_base_name/2 + ]). --include_lib("public_key/include/public_key.hrl"). -include_lib("common_test/include/ct.hrl"). --include_lib("ssh/src/ssh_transport.hrl"). +-include("ssh_transport.hrl"). -include_lib("kernel/include/file.hrl"). -include("ssh_test_lib.hrl"). @@ -184,11 +281,44 @@ start_shell(Port, IOServer) -> start_shell(Port, IOServer, ExtraOptions) -> spawn_link( fun() -> - Host = hostname(), + ct:log("~p:~p:~p ssh_test_lib:start_shell(~p, ~p, ~p)", + [?MODULE,?LINE,self(), Port, IOServer, ExtraOptions]), Options = [{user_interaction, false}, {silently_accept_hosts,true} | ExtraOptions], - group_leader(IOServer, self()), - ssh:shell(Host, Port, Options) + try + group_leader(IOServer, self()), + case Port of + 22 -> + Host = hostname(), + ct:log("Port==22 Call ssh:shell(~p, ~p)", + [Host, Options]), + ssh:shell(Host, Options); + _ when is_integer(Port) -> + Host = hostname(), + ct:log("is_integer(Port) Call ssh:shell(~p, ~p, ~p)", + [Host, Port, Options]), + ssh:shell(Host, Port, Options); + Socket when is_port(Socket) -> + receive + start -> ok + end, + ct:log("is_port(Socket) Call ssh:shell(~p, ~p)", + [Socket, Options]), + ssh:shell(Socket, Options); + ConnRef when is_pid(ConnRef) -> + ct:log("is_pid(ConnRef) Call ssh:shell(~p)", + [ConnRef]), + ssh:shell(ConnRef) % Options were given in ssh:connect + end + of + R -> + ct:log("~p:~p ssh_test_lib:start_shell(~p, ~p, ~p) -> ~p", + [?MODULE,?LINE,Port, IOServer, ExtraOptions, R]) + catch + C:E:S -> + ct:log("Exception ~p:~p~n~p", [C,E,S]), + ct:fail("Exception",[]) + end end). @@ -209,6 +339,7 @@ loop_io_server(TestCase, Buff0) -> %%ct:log("io_server ~p:~p ~p got ~p",[?MODULE,?LINE,self(),_REQ]), {ok, Reply, Buff} = io_request(Request, TestCase, From, ReplyAs, Buff0), + %%ct:log("io_server ~p:~p ~p going to reply ~p",[?MODULE,?LINE,self(),Reply]), io_reply(From, ReplyAs, Reply), loop_io_server(TestCase, Buff); {'EXIT',_, _} = _Exit -> @@ -218,6 +349,12 @@ loop_io_server(TestCase, Buff0) -> 30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) end. +io_request(getopts,_TestCase, _, _, Buff) -> + {ok, [], Buff}; +io_request({get_geometry,columns},_TestCase, _, _, Buff) -> + {ok, 80, Buff}; +io_request({get_geometry,rows},_TestCase, _, _, Buff) -> + {ok, 24, Buff}; io_request({put_chars, Chars}, TestCase, _, _, Buff) -> reply(TestCase, Chars), {ok, ok, Buff}; @@ -225,7 +362,7 @@ io_request({put_chars, unicode, Chars}, TestCase, _, _, Buff) when is_binary(Cha reply(TestCase, Chars), {ok, ok, Buff}; io_request({put_chars, unicode, io_lib, format, [Fmt,Args]}, TestCase, _, _, Buff) -> - reply(TestCase, io_lib:format(Fmt,Args)), + reply(TestCase, unicode:characters_to_binary(io_lib:format(Fmt,Args))), {ok, ok, Buff}; io_request({put_chars, Enc, Chars}, TestCase, _, _, Buff) -> reply(TestCase, unicode:characters_to_binary(Chars,Enc,latin1)), @@ -241,6 +378,7 @@ io_request({get_line, _Enc, _Prompt} = Request, _, From, ReplyAs, [] = Buff) -> io_request({get_line, _Enc,_}, _, _, _, [Line | Buff]) -> {ok, Line, Buff}. + io_reply(_, _, []) -> ok; io_reply(From, ReplyAs, Reply) -> @@ -294,25 +432,37 @@ rcv_lingering(Timeout) -> receive_exec_result([]) -> expected; receive_exec_result(Msgs) when is_list(Msgs) -> - ct:log("Expect data! ~p", [Msgs]), + ct:log("~p:~p Expect data! ~p", [?MODULE,?FUNCTION_NAME,Msgs]), receive Msg -> - case lists:member(Msg, Msgs) of + case lists:member(Msg, Msgs) + orelse lists:member({optional,Msg}, Msgs) + of true -> - ct:log("Collected data ~p", [Msg]), - receive_exec_result(Msgs--[Msg]); + ct:log("~p:~p Collected data ~p", [?MODULE,?FUNCTION_NAME,Msg]), + receive_exec_result(Msgs--[Msg,{optional,Msg}]); false -> case Msg of {ssh_cm,_,{data,_,1, Data}} -> - ct:log("StdErr: ~p~n", [Data]), + ct:log("~p:~p unexpected StdErr: ~p~n~p~n", [?MODULE,?FUNCTION_NAME,Data,Msg]), receive_exec_result(Msgs); Other -> - ct:log("Other ~p", [Other]), + ct:log("~p:~p unexpected Other ~p", [?MODULE,?FUNCTION_NAME,Other]), {unexpected_msg, Other} end end after - 30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) + 30000 -> + case lists:all(fun(M) -> + is_tuple(M) andalso (element(1,M) == optional) + end, Msgs) + of + false -> + ct:fail("timeout ~p:~p",[?MODULE,?FUNCTION_NAME]); + true -> + ct:log("~p:~p Only optional messages expected!~n ~p", [?MODULE,?FUNCTION_NAME,Msgs]), + expected + end end; receive_exec_result(Msg) -> receive_exec_result([Msg]). @@ -325,26 +475,14 @@ receive_exec_result_or_fail(Msg) -> end. receive_exec_end(ConnectionRef, ChannelId) -> - Eof = {ssh_cm, ConnectionRef, {eof, ChannelId}}, - ExitStatus = {ssh_cm, ConnectionRef, {exit_status, ChannelId, 0}}, - Closed = {ssh_cm, ConnectionRef,{closed, ChannelId}}, - case receive_exec_result(ExitStatus) of - {unexpected_msg, Eof} -> %% Open ssh seems to not allways send these messages - %% in the same order! - ct:log("2: Collected data ~p", [Eof]), - case receive_exec_result(ExitStatus) of - expected -> - expected = receive_exec_result(Closed); - {unexpected_msg, Closed} -> - ct:log("3: Collected data ~p", [Closed]) - end; - expected -> - ct:log("4: Collected data ~p", [ExitStatus]), - expected = receive_exec_result(Eof), - expected = receive_exec_result(Closed); - Other -> - ct:fail({unexpected_msg, Other}) - end. + receive_exec_end(ConnectionRef, ChannelId, 0). + +receive_exec_end(ConnectionRef, ChannelId, ExitStatus) -> + receive_exec_result( + [{ssh_cm, ConnectionRef, {eof, ChannelId}}, + {optional, {ssh_cm, ConnectionRef, {exit_status, ChannelId, ExitStatus}}}, + {ssh_cm, ConnectionRef, {closed, ChannelId}} + ]). receive_exec_result(Data, ConnectionRef, ChannelId) -> Eof = {ssh_cm, ConnectionRef, {eof, ChannelId}}, @@ -354,21 +492,6 @@ receive_exec_result(Data, ConnectionRef, ChannelId) -> expected = receive_exec_result(Closed). -setup_ssh_auth_keys(RSAFile, DSAFile, Dir) -> - Entries = ssh_file_entry(RSAFile) ++ ssh_file_entry(DSAFile), - AuthKeys = public_key:ssh_encode(Entries , auth_keys), - AuthKeysFile = filename:join(Dir, "authorized_keys"), - file:write_file(AuthKeysFile, AuthKeys). - -ssh_file_entry(PubFile) -> - case file:read_file(PubFile) of - {ok, Ssh} -> - [{Key, _}] = public_key:ssh_decode(Ssh, public_key), - [{Key, [{comment, "Test"}]}]; - _ -> - [] - end. - failfun(_User, {authmethod,none}) -> ok; failfun(User, Reason) -> @@ -378,233 +501,31 @@ hostname() -> {ok,Host} = inet:gethostname(), Host. -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. +del_dirs(Dir) -> + del_dir_contents(Dir), + file:del_dir(Dir), + ok. -setup_dsa(DataDir, UserDir) -> - file:copy(filename:join(DataDir, "id_dsa"), filename:join(UserDir, "id_dsa")), - System = filename:join(UserDir, "system"), - file:make_dir(System), - file:copy(filename:join(DataDir, "ssh_host_dsa_key"), filename:join(System, "ssh_host_dsa_key")), - file:copy(filename:join(DataDir, "ssh_host_dsa_key.pub"), filename:join(System, "ssh_host_dsa_key.pub")), -ct:log("DataDir ~p:~n ~p~n~nSystDir ~p:~n ~p~n~nUserDir ~p:~n ~p",[DataDir, file:list_dir(DataDir), System, file:list_dir(System), UserDir, file:list_dir(UserDir)]), - setup_dsa_known_host(DataDir, UserDir), - setup_dsa_auth_keys(DataDir, UserDir). - -setup_rsa(DataDir, UserDir) -> - file:copy(filename:join(DataDir, "id_rsa"), filename:join(UserDir, "id_rsa")), - System = filename:join(UserDir, "system"), - file:make_dir(System), - file:copy(filename:join(DataDir, "ssh_host_rsa_key"), filename:join(System, "ssh_host_rsa_key")), - file:copy(filename:join(DataDir, "ssh_host_rsa_key.pub"), filename:join(System, "ssh_host_rsa_key.pub")), -ct:log("DataDir ~p:~n ~p~n~nSystDir ~p:~n ~p~n~nUserDir ~p:~n ~p",[DataDir, file:list_dir(DataDir), System, file:list_dir(System), UserDir, file:list_dir(UserDir)]), - setup_rsa_known_host(DataDir, UserDir), - setup_rsa_auth_keys(DataDir, UserDir). - -setup_ecdsa(Size, DataDir, UserDir) -> - file:copy(filename:join(DataDir, "id_ecdsa"++Size), filename:join(UserDir, "id_ecdsa")), - System = filename:join(UserDir, "system"), - file:make_dir(System), - file:copy(filename:join(DataDir, "ssh_host_ecdsa_key"++Size), filename:join(System, "ssh_host_ecdsa_key")), - file:copy(filename:join(DataDir, "ssh_host_ecdsa_key"++Size++".pub"), filename:join(System, "ssh_host_ecdsa_key.pub")), -ct:log("DataDir ~p:~n ~p~n~nSystDir ~p:~n ~p~n~nUserDir ~p:~n ~p",[DataDir, file:list_dir(DataDir), System, file:list_dir(System), UserDir, file:list_dir(UserDir)]), - setup_ecdsa_known_host(Size, System, UserDir), - setup_ecdsa_auth_keys(Size, DataDir, UserDir). - -setup_eddsa(Alg, DataDir, UserDir) -> - {IdPriv, _IdPub, HostPriv, HostPub} = - case Alg of - ed25519 -> {"id_ed25519", "id_ed25519.pub", "ssh_host_ed25519_key", "ssh_host_ed25519_key.pub"}; - ed448 -> {"id_ed448", "id_ed448.pub", "ssh_host_ed448_key", "ssh_host_ed448_key.pub"} - end, - file:copy(filename:join(DataDir, IdPriv), filename:join(UserDir, IdPriv)), - System = filename:join(UserDir, "system"), - file:make_dir(System), - file:copy(filename:join(DataDir, HostPriv), filename:join(System, HostPriv)), - file:copy(filename:join(DataDir, HostPub), filename:join(System, HostPub)), -ct:log("DataDir ~p:~n ~p~n~nSystDir ~p:~n ~p~n~nUserDir ~p:~n ~p",[DataDir, file:list_dir(DataDir), System, file:list_dir(System), UserDir, file:list_dir(UserDir)]), - setup_eddsa_known_host(HostPub, DataDir, UserDir), - setup_eddsa_auth_keys(IdPriv, DataDir, UserDir). - -clean_dsa(UserDir) -> - del_dirs(filename:join(UserDir, "system")), - file:delete(filename:join(UserDir,"id_dsa")), - file:delete(filename:join(UserDir,"known_hosts")), - file:delete(filename:join(UserDir,"authorized_keys")). - -clean_rsa(UserDir) -> - del_dirs(filename:join(UserDir, "system")), - file:delete(filename:join(UserDir,"id_rsa")), - file:delete(filename:join(UserDir,"known_hosts")), - file:delete(filename:join(UserDir,"authorized_keys")). - -setup_dsa_pass_phrase(DataDir, UserDir, Phrase) -> - try - {ok, KeyBin} = file:read_file(filename:join(DataDir, "id_dsa")), - setup_pass_phrase(KeyBin, filename:join(UserDir, "id_dsa"), Phrase), - System = filename:join(UserDir, "system"), - file:make_dir(System), - file:copy(filename:join(DataDir, "ssh_host_dsa_key"), filename:join(System, "ssh_host_dsa_key")), - file:copy(filename:join(DataDir, "ssh_host_dsa_key.pub"), filename:join(System, "ssh_host_dsa_key.pub")), - setup_dsa_known_host(DataDir, UserDir), - setup_dsa_auth_keys(DataDir, UserDir) - of - _ -> true - catch - _:_ -> false - end. -setup_rsa_pass_phrase(DataDir, UserDir, Phrase) -> - try - {ok, KeyBin} = file:read_file(filename:join(DataDir, "id_rsa")), - setup_pass_phrase(KeyBin, filename:join(UserDir, "id_rsa"), Phrase), - System = filename:join(UserDir, "system"), - file:make_dir(System), - file:copy(filename:join(DataDir, "ssh_host_rsa_key"), filename:join(System, "ssh_host_rsa_key")), - file:copy(filename:join(DataDir, "ssh_host_rsa_key.pub"), filename:join(System, "ssh_host_rsa_key.pub")), - setup_rsa_known_host(DataDir, UserDir), - setup_rsa_auth_keys(DataDir, UserDir) - of - _ -> true - catch - _:_ -> false +del_dir_contents(Dir) -> + case file:list_dir(Dir) of + {ok, Files} -> + do_del_files(Dir, Files); + _ -> + ok end. -setup_ecdsa_pass_phrase(Size, DataDir, UserDir, Phrase) -> - try - {ok, KeyBin} = - case file:read_file(F=filename:join(DataDir, "id_ecdsa"++Size)) of - {error,E} -> - ct:log("Failed (~p) to read ~p~nFiles: ~p", [E,F,file:list_dir(DataDir)]), - file:read_file(filename:join(DataDir, "id_ecdsa")); - Other -> - Other - end, - setup_pass_phrase(KeyBin, filename:join(UserDir, "id_ecdsa"), Phrase), - System = filename:join(UserDir, "system"), - file:make_dir(System), - file:copy(filename:join(DataDir, "ssh_host_ecdsa_key"++Size), filename:join(System, "ssh_host_ecdsa_key")), - file:copy(filename:join(DataDir, "ssh_host_ecdsa_key"++Size++".pub"), filename:join(System, "ssh_host_ecdsa_key.pub")), - setup_ecdsa_known_host(Size, System, UserDir), - setup_ecdsa_auth_keys(Size, DataDir, UserDir) - of - _ -> true - catch - _:_ -> false - end. +do_del_files(Dir, Files) -> + lists:foreach(fun(File) -> + FullPath = filename:join(Dir,File), + case filelib:is_dir(FullPath) of + true -> + del_dirs(FullPath); + false -> + file:delete(FullPath) + end + end, Files). -setup_pass_phrase(KeyBin, OutFile, Phrase) -> - [{KeyType, _,_} = Entry0] = public_key:pem_decode(KeyBin), - Key = public_key:pem_entry_decode(Entry0), - Salt = crypto:strong_rand_bytes(8), - Entry = public_key:pem_entry_encode(KeyType, Key, - {{"DES-CBC", Salt}, Phrase}), - Pem = public_key:pem_encode([Entry]), - file:write_file(OutFile, Pem). - -setup_dsa_known_host(SystemDir, UserDir) -> - {ok, SshBin} = file:read_file(filename:join(SystemDir, "ssh_host_dsa_key.pub")), - [{Key, _}] = public_key:ssh_decode(SshBin, public_key), - setup_known_hosts(Key, UserDir). - -setup_rsa_known_host(SystemDir, UserDir) -> - {ok, SshBin} = file:read_file(filename:join(SystemDir, "ssh_host_rsa_key.pub")), - [{Key, _}] = public_key:ssh_decode(SshBin, public_key), - setup_known_hosts(Key, UserDir). - -setup_ecdsa_known_host(_Size, SystemDir, UserDir) -> - {ok, SshBin} = file:read_file(filename:join(SystemDir, "ssh_host_ecdsa_key.pub")), - [{Key, _}] = public_key:ssh_decode(SshBin, public_key), - setup_known_hosts(Key, UserDir). - -setup_eddsa_known_host(HostPub, SystemDir, UserDir) -> - {ok, SshBin} = file:read_file(filename:join(SystemDir, HostPub)), - [{Key, _}] = public_key:ssh_decode(SshBin, public_key), - setup_known_hosts(Key, UserDir). - -setup_known_hosts(Key, UserDir) -> - {ok, Hostname} = inet:gethostname(), - {ok, {A, B, C, D}} = inet:getaddr(Hostname, inet), - IP = lists:concat([A, ".", B, ".", C, ".", D]), - HostNames = [{hostnames,[Hostname, IP]}], - KnownHosts = [{Key, HostNames}], - KnownHostsEnc = public_key:ssh_encode(KnownHosts, known_hosts), - KHFile = filename:join(UserDir, "known_hosts"), - file:write_file(KHFile, KnownHostsEnc). - -setup_dsa_auth_keys(Dir, UserDir) -> - {ok, Pem} = file:read_file(filename:join(Dir, "id_dsa")), - DSA = public_key:pem_entry_decode(hd(public_key:pem_decode(Pem))), - PKey = DSA#'DSAPrivateKey'.y, - P = DSA#'DSAPrivateKey'.p, - Q = DSA#'DSAPrivateKey'.q, - G = DSA#'DSAPrivateKey'.g, - Dss = #'Dss-Parms'{p=P, q=Q, g=G}, - setup_auth_keys([{{PKey, Dss}, [{comment, "Test"}]}], UserDir). - -setup_rsa_auth_keys(Dir, UserDir) -> - {ok, Pem} = file:read_file(filename:join(Dir, "id_rsa")), - RSA = public_key:pem_entry_decode(hd(public_key:pem_decode(Pem))), - #'RSAPrivateKey'{publicExponent = E, modulus = N} = RSA, - PKey = #'RSAPublicKey'{publicExponent = E, modulus = N}, - setup_auth_keys([{ PKey, [{comment, "Test"}]}], UserDir). - -setup_ecdsa_auth_keys(Size, Dir, UserDir) -> - {ok, Pem} = - case file:read_file(F=filename:join(Dir, "id_ecdsa"++Size)) of - {error,E} -> - ct:log("Failed (~p) to read ~p~nFiles: ~p", [E,F,file:list_dir(Dir)]), - file:read_file(filename:join(Dir, "id_ecdsa")); - Other -> - Other - end, - ECDSA = public_key:pem_entry_decode(hd(public_key:pem_decode(Pem))), - #'ECPrivateKey'{publicKey = Q, - parameters = Param = {namedCurve,_Id0}} = ECDSA, - PKey = #'ECPoint'{point = Q}, - setup_auth_keys([{ {PKey,Param}, [{comment, "Test"}]}], UserDir). - -setup_eddsa_auth_keys(IdPriv, Dir, UserDir) -> - {ok, Pem} = file:read_file(filename:join(Dir, IdPriv)), - {ed_pri, Alg, Pub, _} = public_key:pem_entry_decode(hd(public_key:pem_decode(Pem))), - setup_auth_keys([{{ed_pub,Alg,Pub}, [{comment, "Test"}]}], UserDir). - -setup_auth_keys(Keys, Dir) -> - AuthKeys = public_key:ssh_encode(Keys, auth_keys), - AuthKeysFile = filename:join(Dir, "authorized_keys"), - ok = file:write_file(AuthKeysFile, AuthKeys), - AuthKeys. - -write_auth_keys(Keys, Dir) -> - AuthKeysFile = filename:join(Dir, "authorized_keys"), - file:write_file(AuthKeysFile, Keys). - -del_dirs(Dir) -> - case file:list_dir(Dir) of - {ok, []} -> - file:del_dir(Dir); - {ok, Files} -> - lists:foreach(fun(File) -> - FullPath = filename:join(Dir,File), - case filelib:is_dir(FullPath) of - true -> - del_dirs(FullPath), - file:del_dir(FullPath); - false -> - file:delete(FullPath) - end - end, Files); - _ -> - ok - end. openssh_sanity_check(Config) -> ssh:start(), @@ -622,34 +543,6 @@ openssh_sanity_check(Config) -> {skip, Str} end. -openssh_supports(ClientOrServer, Tag, Alg) when ClientOrServer == sshc ; - ClientOrServer == sshd -> - SSH_algos = ssh_test_lib:default_algorithms(ClientOrServer), - L = proplists:get_value(Tag, SSH_algos, []), - lists:member(Alg, L) orelse - lists:member(Alg, proplists:get_value(client2server, L, [])) orelse - lists:member(Alg, proplists:get_value(server2client, L, [])). - -%%-------------------------------------------------------------------- -%% Check if we have a "newer" ssh client that supports these test cases - -ssh_client_supports_Q() -> - 0 == check_ssh_client_support2( - ?MODULE:open_port({spawn, "ssh -Q cipher"}) - ). - -check_ssh_client_support2(P) -> - receive - {P, {data, _A}} -> - check_ssh_client_support2(P); - {P, {exit_status, E}} -> - ct:log("~p:~p exit_status:~n~p",[?MODULE,?LINE,E]), - E - after 5000 -> - ct:log("Openssh command timed out ~n"), - -1 - end. - %%%-------------------------------------------------------------------- %%% Probe a server or a client about algorithm support @@ -776,6 +669,15 @@ intersect_bi_dir([H={_,[A|_]}|T]) when is_atom(A) -> intersect_bi_dir([]) -> []. +some_empty([]) -> + false; +some_empty([{_,[]}|_]) -> + true; +some_empty([{_,L}|T]) when is_atom(hd(L)) -> + some_empty(T); +some_empty([{_,L}|T]) when is_tuple(hd(L)) -> + some_empty(L) orelse some_empty(T). + sort_spec(L = [{_,_}|_] ) -> [{Tag,sort_spec(Es)} || {Tag,Es} <- L]; sort_spec(L) -> lists:usort(L). @@ -967,12 +869,14 @@ get_kex_init(Conn, Ref, TRef) -> end; false -> - ct:log("~p:~p Not in 'connected' state: ~p",[?MODULE,?LINE,State]), receive {reneg_timeout,Ref} -> + ct:log("~p:~p Not in 'connected' state: ~p but reneg_timeout received. Fail.", + [?MODULE,?LINE,State]), ct:log("S = ~p", [S]), ct:fail(reneg_timeout) after 0 -> + ct:log("~p:~p Not in 'connected' state: ~p, Will try again after 100ms",[?MODULE,?LINE,State]), timer:sleep(100), % If renegotiation is complete we do not % want to exit on the reneg_timeout get_kex_init(Conn, Ref, TRef) @@ -1177,3 +1081,150 @@ mk_dir_path(DirPath) -> %%ct:log("~p:~p return Other ~p ~ts", [?MODULE,?LINE,Other,DirPath]), Other end. + +%%%---------------------------------------------------------------- +%%% New + +setup_all_user_host_keys(Config) -> + DataDir = proplists:get_value(data_dir, Config), + PrivDir = proplists:get_value(priv_dir, Config), + setup_all_user_host_keys(DataDir, PrivDir). + +setup_all_user_host_keys(DataDir, PrivDir) -> + setup_all_user_host_keys(DataDir, PrivDir, filename:join(PrivDir,"system")). + +setup_all_user_host_keys(DataDir, UserDir, SysDir) -> + lists:foldl(fun(Alg, OkAlgs) -> + try + ok = ssh_test_lib:setup_user_key(Alg, DataDir, UserDir), + ok = ssh_test_lib:setup_host_key(Alg, DataDir, SysDir) + of + ok -> [Alg|OkAlgs] + catch + error:{badmatch, {error,enoent}} -> + OkAlgs; + C:E:S -> + ct:log("Exception in ~p:~p for alg ~p: ~p:~p~n~p", + [?MODULE,?FUNCTION_NAME,Alg,C,E,S]), + OkAlgs + end + end, [], ssh_transport:supported_algorithms(public_key)). + + +setup_all_host_keys(Config) -> + DataDir = proplists:get_value(data_dir, Config), + PrivDir = proplists:get_value(priv_dir, Config), + setup_all_host_keys(DataDir, filename:join(PrivDir,"system")). + +setup_all_host_keys(DataDir, SysDir) -> + lists:foldl(fun(Alg, OkAlgs) -> + try + ok = ssh_test_lib:setup_host_key(Alg, DataDir, SysDir) + of + ok -> [Alg|OkAlgs] + catch + error:{badmatch, {error,enoent}} -> + OkAlgs; + C:E:S -> + ct:log("Exception in ~p:~p for alg ~p: ~p:~p~n~p", + [?MODULE,?FUNCTION_NAME,Alg,C,E,S]), + OkAlgs + end + end, [], ssh_transport:supported_algorithms(public_key)). + + +setup_all_user_keys(DataDir, UserDir) -> + lists:foldl(fun(Alg, OkAlgs) -> + try + ok = ssh_test_lib:setup_user_key(Alg, DataDir, UserDir) + of + ok -> [Alg|OkAlgs] + catch + error:{badmatch, {error,enoent}} -> + OkAlgs; + C:E:S -> + ct:log("Exception in ~p:~p for alg ~p: ~p:~p~n~p", + [?MODULE,?FUNCTION_NAME,Alg,C,E,S]), + OkAlgs + end + end, [], ssh_transport:supported_algorithms(public_key)). + + +setup_user_key(SshAlg, DataDir, UserDir) -> + file:make_dir(UserDir), + %% Copy private user key to user's dir + {ok,_} = file:copy(filename:join(DataDir, file_base_name(user_src,SshAlg)), + filename:join(UserDir, file_base_name(user,SshAlg))), + %% Setup authorized_keys in user's dir + {ok,Pub} = file:read_file(filename:join(DataDir, file_base_name(user_src,SshAlg)++".pub")), + ok = file:write_file(filename:join(UserDir, "authorized_keys"), + io_lib:format("~n~s~n",[Pub]), + [append]), + ?ct_log_show_file( filename:join(DataDir, file_base_name(user_src,SshAlg)++".pub") ), + ?ct_log_show_file( filename:join(UserDir, "authorized_keys") ), + ok. + +setup_host_key_create_dir(SshAlg, DataDir, BaseDir) -> + SysDir = filename:join(BaseDir,"system"), + ct:log("~p:~p SshAlg=~p~nDataDir = ~p~nBaseDir = ~p~nSysDir = ~p",[?MODULE,?LINE,SshAlg, DataDir, BaseDir,SysDir]), + file:make_dir(SysDir), + setup_host_key(SshAlg, DataDir, SysDir), + SysDir. + +setup_host_key(SshAlg, DataDir, SysDir) -> + mk_dir_path(SysDir), + %% Copy private host key to system's dir + {ok,_} = file:copy(filename:join(DataDir, file_base_name(system_src,SshAlg)), + filename:join(SysDir, file_base_name(system,SshAlg))), + ?ct_log_show_file( filename:join(SysDir, file_base_name(system,SshAlg)) ), + ok. + +setup_known_host(SshAlg, DataDir, UserDir) -> + {ok,Pub} = file:read_file(filename:join(DataDir, file_base_name(system_src,SshAlg)++".pub")), + S = lists:join(" ", lists:reverse(tl(lists:reverse(string:tokens(binary_to_list(Pub), " "))))), + ok = file:write_file(filename:join(UserDir, "known_hosts"), + io_lib:format("~p~n",[S])), + ?ct_log_show_file( filename:join(UserDir, "known_hosts") ), + ok. + + +get_addr_str() -> + {ok, Hostname} = inet:gethostname(), + {ok, {A, B, C, D}} = inet:getaddr(Hostname, inet), + IP = lists:concat([A, ".", B, ".", C, ".", D]), + lists:concat([Hostname,",",IP]). + + +file_base_name(user, 'ecdsa-sha2-nistp256') -> "id_ecdsa"; +file_base_name(user, 'ecdsa-sha2-nistp384') -> "id_ecdsa"; +file_base_name(user, 'ecdsa-sha2-nistp521') -> "id_ecdsa"; +file_base_name(user, 'rsa-sha2-256' ) -> "id_rsa"; +file_base_name(user, 'rsa-sha2-384' ) -> "id_rsa"; +file_base_name(user, 'rsa-sha2-512' ) -> "id_rsa"; +file_base_name(user, 'ssh-dss' ) -> "id_dsa"; +file_base_name(user, 'ssh-ed25519' ) -> "id_ed25519"; +file_base_name(user, 'ssh-ed448' ) -> "id_ed448"; +file_base_name(user, 'ssh-rsa' ) -> "id_rsa"; + +file_base_name(user_src, 'ecdsa-sha2-nistp256') -> "id_ecdsa256"; +file_base_name(user_src, 'ecdsa-sha2-nistp384') -> "id_ecdsa384"; +file_base_name(user_src, 'ecdsa-sha2-nistp521') -> "id_ecdsa521"; +file_base_name(user_src, Alg) -> file_base_name(user, Alg); + +file_base_name(system, 'ecdsa-sha2-nistp256') -> "ssh_host_ecdsa_key"; +file_base_name(system, 'ecdsa-sha2-nistp384') -> "ssh_host_ecdsa_key"; +file_base_name(system, 'ecdsa-sha2-nistp521') -> "ssh_host_ecdsa_key"; +file_base_name(system, 'rsa-sha2-256' ) -> "ssh_host_rsa_key"; +file_base_name(system, 'rsa-sha2-384' ) -> "ssh_host_rsa_key"; +file_base_name(system, 'rsa-sha2-512' ) -> "ssh_host_rsa_key"; +file_base_name(system, 'ssh-dss' ) -> "ssh_host_dsa_key"; +file_base_name(system, 'ssh-ed25519' ) -> "ssh_host_ed25519_key"; +file_base_name(system, 'ssh-ed448' ) -> "ssh_host_ed448_key"; +file_base_name(system, 'ssh-rsa' ) -> "ssh_host_rsa_key"; + +file_base_name(system_src, 'ecdsa-sha2-nistp256') -> "ssh_host_ecdsa_key256"; +file_base_name(system_src, 'ecdsa-sha2-nistp384') -> "ssh_host_ecdsa_key384"; +file_base_name(system_src, 'ecdsa-sha2-nistp521') -> "ssh_host_ecdsa_key521"; +file_base_name(system_src, Alg) -> file_base_name(system, Alg). + +%%%---------------------------------------------------------------- |