diff options
Diffstat (limited to 'lib/ssh')
40 files changed, 892 insertions, 118 deletions
diff --git a/lib/ssh/doc/src/book.xml b/lib/ssh/doc/src/book.xml index 3c2375f96d..c031d872d7 100644 --- a/lib/ssh/doc/src/book.xml +++ b/lib/ssh/doc/src/book.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="iso-8859-1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE book SYSTEM "book.dtd"> <book xmlns:xi="http://www.w3.org/2001/XInclude"> <header titlestyle="normal"> <copyright> - <year>2005</year><year>2012</year> + <year>2005</year><year>2013</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> diff --git a/lib/ssh/doc/src/fascicules.xml b/lib/ssh/doc/src/fascicules.xml index 069d9002e0..7e99398c16 100644 --- a/lib/ssh/doc/src/fascicules.xml +++ b/lib/ssh/doc/src/fascicules.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="iso-8859-1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE fascicules SYSTEM "fascicules.dtd"> <fascicules> diff --git a/lib/ssh/doc/src/introduction.xml b/lib/ssh/doc/src/introduction.xml index e76aa20d64..b42910cb34 100644 --- a/lib/ssh/doc/src/introduction.xml +++ b/lib/ssh/doc/src/introduction.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="iso-8859-1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml index 041f5e54af..0d88cbda7a 100644 --- a/lib/ssh/doc/src/notes.xml +++ b/lib/ssh/doc/src/notes.xml @@ -29,6 +29,78 @@ <file>notes.xml</file> </header> +<section><title>Ssh 3.0</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + The ssh cli is now faster at close and before new prompt.</p> + <p> + Own Id: OTP-11339 Aux Id: seq12423 </p> + </item> + <item> + <p> + Ssh process structure was redesigned to better map to + what is truly parallel this has solved a lot of strange + timing issues that sometimes would occur, for instance a + process leak could happen when a lot of connections where + taken up and down in parallel in a short period of time. + Also backwards compatible clauses to "original" but never + supported features has been removed.</p> + <p> + Impact: Increases flow efficiency</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-11363</p> + </item> + <item> + <p> + Fix various typos in erts, kernel and ssh. Thanks to + Martin Hässler.</p> + <p> + Own Id: OTP-11414</p> + </item> + <item> + <p> + Correct private_key type documentation in + ssh_server_key_api. Thanks to Tristan Sloughter.</p> + <p> + Own Id: OTP-11449</p> + </item> + <item> + <p> + The functions in ssh_no_io.erl did not mimic the + functions in ssh_io.erl correctly, the arity was + incorrect for some functions which caused ssh to fail in + the wrong way.</p> + <p> + Own Id: OTP-11490</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Add option to disallow CLI</p> + <p> + Own Id: OTP-10976</p> + </item> + <item> + <p> + Add sockname and user to ssh:connection_info/2</p> + <p> + Own Id: OTP-11296</p> + </item> + </list> + </section> + +</section> + <section><title>Ssh 2.1.8</title> <section><title>Improvements and New Features</title> diff --git a/lib/ssh/doc/src/part_notes.xml b/lib/ssh/doc/src/part_notes.xml index 1b47a12021..c5cc163717 100644 --- a/lib/ssh/doc/src/part_notes.xml +++ b/lib/ssh/doc/src/part_notes.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE part SYSTEM "part.dtd"> <part xmlns:xi="http://www.w3.org/2001/XInclude"> <header> <copyright> - <year>2004</year><year>2010</year> + <year>2004</year><year>2013</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> diff --git a/lib/ssh/doc/src/ref_man.xml b/lib/ssh/doc/src/ref_man.xml index 88203b5034..55339298e8 100644 --- a/lib/ssh/doc/src/ref_man.xml +++ b/lib/ssh/doc/src/ref_man.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="iso-8859-1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE application SYSTEM "application.dtd"> <application xmlns:xi="http://www.w3.org/2001/XInclude"> <header> <copyright> - <year>2004</year><year>2012</year> + <year>2004</year><year>2013</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml index c1a51d57fc..89d8be850e 100644 --- a/lib/ssh/doc/src/ssh.xml +++ b/lib/ssh/doc/src/ssh.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="iso-8859-1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE erlref SYSTEM "erlref.dtd"> <erlref> @@ -38,6 +38,8 @@ <item>Supported SSH version is 2.0 </item> <item>Supported MAC algorithms: hmac-sha1</item> <item>Supported encryption algorithms: aes128-cb and 3des-cbc</item> + <item>Supports unicode filenames if the emulator and the underlaying OS supports it. See the DESCRIPTION section in <seealso marker="file">file</seealso> for information about this subject</item> + <item>Supports unicode in shell and cli</item> </list> </section> diff --git a/lib/ssh/doc/src/ssh_app.xml b/lib/ssh/doc/src/ssh_app.xml index c01f44936a..a1d2402790 100644 --- a/lib/ssh/doc/src/ssh_app.xml +++ b/lib/ssh/doc/src/ssh_app.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="iso-8859-1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE appref SYSTEM "appref.dtd"> <appref> <header> <copyright> - <year>2012</year> + <year>2012</year><year>2013</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> diff --git a/lib/ssh/doc/src/ssh_channel.xml b/lib/ssh/doc/src/ssh_channel.xml index 66b3b8b656..a52a6a115e 100644 --- a/lib/ssh/doc/src/ssh_channel.xml +++ b/lib/ssh/doc/src/ssh_channel.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="iso-8859-1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE erlref SYSTEM "erlref.dtd"> <erlref> diff --git a/lib/ssh/doc/src/ssh_client_key_api.xml b/lib/ssh/doc/src/ssh_client_key_api.xml index 2fa06f8bf1..f3d05a8980 100644 --- a/lib/ssh/doc/src/ssh_client_key_api.xml +++ b/lib/ssh/doc/src/ssh_client_key_api.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="iso-8859-1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE erlref SYSTEM "erlref.dtd"> <erlref> diff --git a/lib/ssh/doc/src/ssh_connection.xml b/lib/ssh/doc/src/ssh_connection.xml index efd4865a6f..72e7252536 100644 --- a/lib/ssh/doc/src/ssh_connection.xml +++ b/lib/ssh/doc/src/ssh_connection.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="iso-8859-1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE erlref SYSTEM "erlref.dtd"> <erlref> diff --git a/lib/ssh/doc/src/ssh_protocol.xml b/lib/ssh/doc/src/ssh_protocol.xml index 28f42f5707..7288266cf7 100644 --- a/lib/ssh/doc/src/ssh_protocol.xml +++ b/lib/ssh/doc/src/ssh_protocol.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="iso-8859-1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <!-- %EricssonCopyright% --> <chapter> <header> <copyright> - <year>2013</year> + <year>2013</year><year>2013</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> diff --git a/lib/ssh/doc/src/ssh_server_key_api.xml b/lib/ssh/doc/src/ssh_server_key_api.xml index ee537f2f60..f7133e4ba5 100644 --- a/lib/ssh/doc/src/ssh_server_key_api.xml +++ b/lib/ssh/doc/src/ssh_server_key_api.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="iso-8859-1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE erlref SYSTEM "erlref.dtd"> <erlref> diff --git a/lib/ssh/doc/src/ssh_sftp.xml b/lib/ssh/doc/src/ssh_sftp.xml index 0d61e57edb..e55d092fe2 100644 --- a/lib/ssh/doc/src/ssh_sftp.xml +++ b/lib/ssh/doc/src/ssh_sftp.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="iso-8859-1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE erlref SYSTEM "erlref.dtd"> <erlref> <header> <copyright> - <year>2005</year><year>2012</year> + <year>2005</year><year>2013</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> diff --git a/lib/ssh/doc/src/ssh_sftpd.xml b/lib/ssh/doc/src/ssh_sftpd.xml index a73d6e52d4..81c2acc575 100644 --- a/lib/ssh/doc/src/ssh_sftpd.xml +++ b/lib/ssh/doc/src/ssh_sftpd.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="iso-8859-1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE erlref SYSTEM "erlref.dtd"> <erlref> diff --git a/lib/ssh/doc/src/usersguide.xml b/lib/ssh/doc/src/usersguide.xml index c818003090..8ab14c2945 100644 --- a/lib/ssh/doc/src/usersguide.xml +++ b/lib/ssh/doc/src/usersguide.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="iso-8859-1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE part SYSTEM "part.dtd"> <part xmlns:xi="http://www.w3.org/2001/XInclude"> <header> <copyright> - <year>2012</year> + <year>2012</year><year>2013</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> diff --git a/lib/ssh/doc/src/using_ssh.xml b/lib/ssh/doc/src/using_ssh.xml index c994c1c56c..4d73366f5e 100644 --- a/lib/ssh/doc/src/using_ssh.xml +++ b/lib/ssh/doc/src/using_ssh.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="iso-8859-1" ?> +<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> diff --git a/lib/ssh/src/ssh.hrl b/lib/ssh/src/ssh.hrl index 94ced9da6f..0c4d34f89c 100644 --- a/lib/ssh/src/ssh.hrl +++ b/lib/ssh/src/ssh.hrl @@ -54,6 +54,7 @@ -define(uint32(X), << ?UINT32(X) >> ). -define(uint64(X), << ?UINT64(X) >> ). -define(string(X), << ?STRING(list_to_binary(X)) >> ). +-define(string_utf8(X), << ?STRING(unicode:characters_to_binary(X)) >> ). -define(binary(X), << ?STRING(X) >>). -define(SSH_CIPHER_NONE, 0). diff --git a/lib/ssh/src/ssh_acceptor_sup.erl b/lib/ssh/src/ssh_acceptor_sup.erl index f37e1fe4ff..2be729d305 100644 --- a/lib/ssh/src/ssh_acceptor_sup.erl +++ b/lib/ssh/src/ssh_acceptor_sup.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2013. 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 @@ -84,8 +84,8 @@ child_spec(ServerOpts) -> [{active, false}, {reuseaddr, true}] ++ SocketOpts, ServerOpts, Timeout]}, - Restart = permanent, - Shutdown = 3600, + Restart = transient, + Shutdown = brutal_kill, Modules = [ssh_acceptor], Type = worker, {Name, StartFunc, Restart, Shutdown, Type, Modules}. diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl index 1fa3df847f..409a1db6d5 100644 --- a/lib/ssh/src/ssh_auth.erl +++ b/lib/ssh/src/ssh_auth.erl @@ -83,7 +83,7 @@ password_msg([#ssh{opts = Opts, io_cb = IoCb, method = "password", data = <<?BOOLEAN(?FALSE), - ?STRING(list_to_binary(Password))>>}, + ?STRING(unicode:characters_to_binary(Password))>>}, Ssh) end. @@ -190,8 +190,7 @@ handle_userauth_request(#ssh_msg_userauth_request{user = User, data = Data}, _, #ssh{opts = Opts} = Ssh) -> <<_:8, ?UINT32(Sz), BinPwd:Sz/binary>> = Data, - Password = binary_to_list(BinPwd), - + Password = unicode:characters_to_list(BinPwd), case check_password(User, Password, Opts) of true -> {authorized, User, @@ -352,7 +351,7 @@ verify_sig(SessionId, User, Service, Alg, KeyBlob, SigWLen, Opts) -> build_sig_data(SessionId, User, Service, KeyBlob, Alg) -> Sig = [?binary(SessionId), ?SSH_MSG_USERAUTH_REQUEST, - ?string(User), + ?string_utf8(User), ?string(Service), ?binary(<<"publickey">>), ?TRUE, diff --git a/lib/ssh/src/ssh_bits.erl b/lib/ssh/src/ssh_bits.erl index 2b0241cb83..8aaff93b9f 100644 --- a/lib/ssh/src/ssh_bits.erl +++ b/lib/ssh/src/ssh_bits.erl @@ -116,6 +116,10 @@ enc(Xs, [string|Ts], Offset) -> X0 = hd(Xs), Y = ?string(X0), [Y | enc(tl(Xs),Ts,Offset+size(Y))]; +enc(Xs, [string_utf8|Ts], Offset) -> + X0 = hd(Xs), + Y = ?string_utf8(X0), + [Y | enc(tl(Xs),Ts,Offset+size(Y))]; enc(Xs, [binary|Ts], Offset) -> X0 = hd(Xs), Y = ?binary(X0), diff --git a/lib/ssh/src/ssh_cli.erl b/lib/ssh/src/ssh_cli.erl index 5cb1e133d3..41febf9707 100644 --- a/lib/ssh/src/ssh_cli.erl +++ b/lib/ssh/src/ssh_cli.erl @@ -161,6 +161,21 @@ handle_msg({ssh_channel_up, ChannelId, ConnectionHandler}, cm = ConnectionHandler} = State) -> {ok, State}; +handle_msg({Group, set_unicode_state, _Arg}, State) -> + Group ! {self(), set_unicode_state, false}, + {ok, State}; + +handle_msg({Group, get_unicode_state}, State) -> + Group ! {self(), get_unicode_state, false}, + {ok, State}; + +handle_msg({Group, tty_geometry}, #state{group = Group, + pty = #ssh_pty{width=Width, + height=Height} + } = State) -> + Group ! {self(),tty_geometry,{Width,Height}}, + {ok,State}; + handle_msg({Group, Req}, #state{group = Group, buf = Buf, pty = Pty, cm = ConnectionHandler, channel = ChannelId} = State) -> @@ -334,7 +349,7 @@ delete_chars(N, {Buf, BufTail, Col}, Tty) when N > 0 -> {Buf, NewBufTail, Col}}; delete_chars(N, {Buf, BufTail, Col}, Tty) -> % N < 0 NewBuf = nthtail(-N, Buf), - NewCol = Col + N, + NewCol = case Col + N of V when V >= 0 -> V; _ -> 0 end, M1 = move_cursor(Col, NewCol, Tty), M2 = move_cursor(NewCol + length(BufTail) - N, NewCol, Tty), {[M1, BufTail, lists:duplicate(-N, $ ) | M2], diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl index 7016f349e8..b377614949 100644 --- a/lib/ssh/src/ssh_connection.erl +++ b/lib/ssh/src/ssh_connection.erl @@ -271,10 +271,36 @@ cancel_tcpip_forward(ConnectionHandler, BindIP, Port) -> %%-------------------------------------------------------------------- %%% Internal API %%-------------------------------------------------------------------- +l2b(L) when is_integer(hd(L)) -> + try list_to_binary(L) + of + B -> B + catch + _:_ -> + unicode:characters_to_binary(L) + end; +l2b([H|T]) -> + << (l2b(H))/binary, (l2b(T))/binary >>; +l2b(B) when is_binary(B) -> + B; +l2b([]) -> + <<>>. + + + channel_data(ChannelId, DataType, Data, Connection, From) when is_list(Data)-> channel_data(ChannelId, DataType, - list_to_binary(Data), Connection, From); +%% list_to_binary(Data), Connection, From); + l2b(Data), Connection, From); + %% try list_to_binary(Data) + %% of + %% B -> B + %% catch + %% _:_ -> io:format('BAD BINARY: ~p~n',[Data]), + %% unicode:characters_to_binary(Data) + %% end, + %% Connection, From); channel_data(ChannelId, DataType, Data, #connection{channel_cache = Cache} = Connection, @@ -730,7 +756,6 @@ handle_msg(#ssh_msg_request_success{data = Data}, {{replies, [{channel_requst_reply, From, {success, Data}}]}, Connection#connection{requests = Rest}}; -%%% This transport message will also be handled at the connection level handle_msg(#ssh_msg_disconnect{code = Code, description = Description, language = _Lang }, diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl index 7ba2179a76..3462b98172 100644 --- a/lib/ssh/src/ssh_connection_handler.erl +++ b/lib/ssh/src/ssh_connection_handler.erl @@ -519,7 +519,8 @@ connected({#ssh_msg_kexinit{}, _Payload} = Event, State) -> #state{}) -> gen_fsm_state_return(). %%-------------------------------------------------------------------- -handle_event(#ssh_msg_disconnect{description = Desc}, _StateName, #state{} = State) -> +handle_event(#ssh_msg_disconnect{description = Desc} = DisconnectMsg, _StateName, #state{} = State) -> + handle_disconnect(DisconnectMsg, State), {stop, {shutdown, Desc}, State}; handle_event(#ssh_msg_ignore{}, StateName, State) -> @@ -850,7 +851,11 @@ handle_info({Protocol, Socket, Data}, Statename, handle_info({CloseTag, _Socket}, _StateName, #state{transport_close_tag = CloseTag, ssh_params = #ssh{role = _Role, opts = _Opts}} = State) -> - {stop, {shutdown, "Connection Lost"}, State}; + DisconnectMsg = + #ssh_msg_disconnect{code = ?SSH_DISCONNECT_BY_APPLICATION, + description = "Connection closed", + language = "en"}, + handle_disconnect(DisconnectMsg, State); handle_info({timeout, {_, From} = Request}, Statename, #state{connection_state = #connection{requests = Requests} = Connection} = State) -> @@ -1377,10 +1382,16 @@ handle_ssh_packet(Length, StateName, #state{decoded_data_buffer = DecData0, handle_disconnect(DisconnectMsg, State0) end. -handle_disconnect(#ssh_msg_disconnect{description = Desc}, State) -> - {stop, {shutdown, Desc}, State}. -handle_disconnect(#ssh_msg_disconnect{description = Desc}, State, ErrorMsg) -> - {stop, {shutdown, {Desc, ErrorMsg}}, State}. +handle_disconnect(#ssh_msg_disconnect{description = Desc} = Msg, #state{connection_state = Connection0, + role = Role} = State0) -> + {disconnect, _, {{replies, Replies}, Connection}} = ssh_connection:handle_msg(Msg, Connection0, Role), + State = send_replies(Replies, State0), + {stop, {shutdown, Desc}, State#state{connection_state = Connection}}. +handle_disconnect(#ssh_msg_disconnect{description = Desc} = Msg, #state{connection_state = Connection0, + role = Role} = State0, ErrorMsg) -> + {disconnect, _, {{replies, Replies}, Connection}} = ssh_connection:handle_msg(Msg, Connection0, Role), + State = send_replies(Replies, State0), + {stop, {shutdown, {Desc, ErrorMsg}}, State#state{connection_state = Connection}}. counterpart_versions(NumVsn, StrVsn, #ssh{role = server} = Ssh) -> Ssh#ssh{c_vsn = NumVsn , c_version = StrVsn}; @@ -1420,9 +1431,9 @@ retry_fun(User, PeerAddr, Reason, Opts) -> do_retry_fun(Fun, User, PeerAddr, Reason) -> case erlang:fun_info(Fun, arity) of - 2 -> %% Backwards compatible + {arity, 2} -> %% Backwards compatible catch Fun(User, Reason); - 3 -> + {arity, 3} -> catch Fun(User, PeerAddr, Reason) end. diff --git a/lib/ssh/src/ssh_io.erl b/lib/ssh/src/ssh_io.erl index 01fc713569..832b144db9 100644 --- a/lib/ssh/src/ssh_io.erl +++ b/lib/ssh/src/ssh_io.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2012. All Rights Reserved. +%% Copyright Ericsson AB 2005-2013. 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 @@ -24,7 +24,6 @@ -module(ssh_io). -export([yes_no/2, read_password/2, read_line/2, format/2]). --import(lists, [reverse/1]). -include("ssh.hrl"). read_line(Prompt, Ssh) -> @@ -81,7 +80,7 @@ format(Fmt, Args) -> trim(Line) when is_list(Line) -> - reverse(trim1(reverse(trim1(Line)))); + lists:reverse(trim1(lists:reverse(trim1(Line)))); trim(Other) -> Other. trim1([$\s|Cs]) -> trim(Cs); diff --git a/lib/ssh/src/ssh_message.erl b/lib/ssh/src/ssh_message.erl index 7bd0375521..01a0988718 100644 --- a/lib/ssh/src/ssh_message.erl +++ b/lib/ssh/src/ssh_message.erl @@ -120,7 +120,7 @@ encode(#ssh_msg_userauth_request{ data = Data }) -> ssh_bits:encode([?SSH_MSG_USERAUTH_REQUEST, User, Service, Method, Data], - [byte, string, string, string, '...']); + [byte, string_utf8, string, string, '...']); encode(#ssh_msg_userauth_failure{ authentications = Auths, partial_success = Bool @@ -135,7 +135,7 @@ encode(#ssh_msg_userauth_banner{ language = Lang }) -> ssh_bits:encode([?SSH_MSG_USERAUTH_BANNER, Banner, Lang], - [byte, string, string]); + [byte, string_utf8, string]); encode(#ssh_msg_userauth_pk_ok{ algorithm_name = Alg, diff --git a/lib/ssh/src/ssh_no_io.erl b/lib/ssh/src/ssh_no_io.erl index 9f83506cdd..825a0d4af5 100644 --- a/lib/ssh/src/ssh_no_io.erl +++ b/lib/ssh/src/ssh_no_io.erl @@ -24,27 +24,27 @@ -module(ssh_no_io). -include("ssh_transport.hrl"). --export([yes_no/1, read_password/1, read_line/1, format/2]). +-export([yes_no/2, read_password/2, read_line/2, format/2]). -yes_no(_Prompt) -> +yes_no(_, _) -> throw({{no_io_allowed, yes_no}, #ssh_msg_disconnect{code = ?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE, description = "User interaction is not allowed", language = "en"}}). -read_password(_Prompt) -> +read_password(_, _) -> throw({{no_io_allowed, read_password}, #ssh_msg_disconnect{code = ?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE, description = "User interaction is not allowed", language = "en"}}). -read_line(_Prompt) -> +read_line(_, _) -> throw({{no_io_allowed, read_line}, #ssh_msg_disconnect{code = ?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE, description = "User interaction is not allowed", language = "en"}} ). -format(_Fmt, _Args) -> +format(_, _) -> throw({{no_io_allowed, format}, #ssh_msg_disconnect{code = ?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE, description = "User interaction is not allowed", diff --git a/lib/ssh/src/ssh_sftp.erl b/lib/ssh/src/ssh_sftp.erl index 10167a9223..0ea2366ac7 100644 --- a/lib/ssh/src/ssh_sftp.erl +++ b/lib/ssh/src/ssh_sftp.erl @@ -352,7 +352,7 @@ write_file(Pid, Name, List) -> write_file(Pid, Name, List, ?FILEOP_TIMEOUT). write_file(Pid, Name, List, FileOpTimeout) when is_list(List) -> - write_file(Pid, Name, list_to_binary(List), FileOpTimeout); + write_file(Pid, Name, unicode:characters_to_binary(List), FileOpTimeout); write_file(Pid, Name, Bin, FileOpTimeout) -> case open(Pid, Name, [write, binary], FileOpTimeout) of {ok, Handle} -> @@ -514,7 +514,7 @@ do_handle_call({pread,Async,Handle,At,Length}, From, State) -> case get_mode(Handle, State2) of binary -> {{ok,Data}, State2}; text -> - {{ok,binary_to_list(Data)}, State2} + {{ok,unicode:characters_to_list(Data)}, State2} end; (Rep, State2) -> {Rep, State2} @@ -535,8 +535,7 @@ do_handle_call({read,Async,Handle,Length}, From, State) -> fun({ok,Data}, State2) -> case get_mode(Handle, State2) of binary -> {{ok,Data}, State2}; - text -> - {{ok,binary_to_list(Data)}, State2} + text -> {{ok,binary_to_list(Data)}, State2} end; (Rep, State2) -> {Rep, State2} end); diff --git a/lib/ssh/src/ssh_sftpd.erl b/lib/ssh/src/ssh_sftpd.erl index 174ca0126b..213b5c714d 100644 --- a/lib/ssh/src/ssh_sftpd.erl +++ b/lib/ssh/src/ssh_sftpd.erl @@ -214,8 +214,7 @@ handle_op(?SSH_FXP_INIT, Version, B, State) when is_binary(B) -> handle_op(?SSH_FXP_REALPATH, ReqId, <<?UINT32(Rlen), RPath:Rlen/binary>>, State0) -> - RelPath0 = binary_to_list(RPath), - RelPath = relate_file_name(RelPath0, State0, _Canonicalize=false), + RelPath = relate_file_name(RPath, State0, _Canonicalize=false), {Res, State} = resolve_symlinks(RelPath, State0), case Res of {ok, AbsPath} -> @@ -231,7 +230,7 @@ handle_op(?SSH_FXP_OPENDIR, ReqId, <<?UINT32(RLen), RPath:RLen/binary>>, State0 = #state{xf = #ssh_xfer{vsn = Vsn}, file_handler = FileMod, file_state = FS0}) -> - RelPath = binary_to_list(RPath), + RelPath = unicode:characters_to_list(RPath), AbsPath = relate_file_name(RelPath, State0), XF = State0#state.xf, @@ -312,9 +311,8 @@ handle_op(?SSH_FXP_WRITE, ReqId, ?SSH_FX_INVALID_HANDLE), State end; -handle_op(?SSH_FXP_READLINK, ReqId, <<?UINT32(PLen), BPath:PLen/binary>>, +handle_op(?SSH_FXP_READLINK, ReqId, <<?UINT32(PLen), RelPath:PLen/binary>>, State = #state{file_handler = FileMod, file_state = FS0}) -> - RelPath = binary_to_list(BPath), AbsPath = relate_file_name(RelPath, State), {Res, FS1} = FileMod:read_link(AbsPath, FS0), case Res of @@ -524,10 +522,10 @@ close_our_file({_,Fd}, FileMod, FS0) -> %%% stat: do the stat stat(Vsn, ReqId, Data, State, F) when Vsn =< 3-> <<?UINT32(BLen), BPath:BLen/binary>> = Data, - stat(ReqId, binary_to_list(BPath), State, F); + stat(ReqId, unicode:characters_to_list(BPath), State, F); stat(Vsn, ReqId, Data, State, F) when Vsn >= 4-> <<?UINT32(BLen), BPath:BLen/binary, ?UINT32(_Flags)>> = Data, - stat(ReqId, binary_to_list(BPath), State, F). + stat(ReqId, unicode:characters_to_list(BPath), State, F). fstat(Vsn, ReqId, Data, State) when Vsn =< 3-> <<?UINT32(HLen), Handle:HLen/binary>> = Data, @@ -609,13 +607,13 @@ decode_4_acess([]) -> open(Vsn, ReqId, Data, State) when Vsn =< 3 -> <<?UINT32(BLen), BPath:BLen/binary, ?UINT32(PFlags), _Attrs/binary>> = Data, - Path = binary_to_list(BPath), + Path = unicode:characters_to_list(BPath), Flags = ssh_xfer:decode_open_flags(Vsn, PFlags), do_open(ReqId, State, Path, Flags); open(Vsn, ReqId, Data, State) when Vsn >= 4 -> <<?UINT32(BLen), BPath:BLen/binary, ?UINT32(Access), ?UINT32(PFlags), _Attrs/binary>> = Data, - Path = binary_to_list(BPath), + Path = unicode:characters_to_list(BPath), FlagBits = ssh_xfer:decode_open_flags(Vsn, PFlags), AcessBits = ssh_xfer:decode_ace_mask(Access), %% TODO: This is to make sure the Access flags are not ignored @@ -712,7 +710,7 @@ relate_file_name(File, State) -> relate_file_name(File, State, _Canonicalize=true). relate_file_name(File, State, Canonicalize) when is_binary(File) -> - relate_file_name(binary_to_list(File), State, Canonicalize); + relate_file_name(unicode:characters_to_list(File), State, Canonicalize); relate_file_name(File, #state{cwd = CWD, root = ""}, Canonicalize) -> relate_filename_to_path(File, CWD, Canonicalize); relate_file_name(File, #state{root = Root}, Canonicalize) -> diff --git a/lib/ssh/src/ssh_system_sup.erl b/lib/ssh/src/ssh_system_sup.erl index bf3c12a988..848133f838 100644 --- a/lib/ssh/src/ssh_system_sup.erl +++ b/lib/ssh/src/ssh_system_sup.erl @@ -54,13 +54,16 @@ stop_listener(SysSup) -> stop_listener(Address, Port) -> Name = make_name(Address, Port), stop_acceptor(whereis(Name)). - -stop_system(SysSup) when is_pid(SysSup)-> - exit(SysSup, shutdown). + +stop_system(SysSup) -> + Name = sshd_sup:system_name(SysSup), + spawn(fun() -> sshd_sup:stop_child(Name) end), + ok. stop_system(Address, Port) -> - stop_system(system_supervisor(Address, Port)). - + spawn(fun() -> sshd_sup:stop_child(Address, Port) end), + ok. + system_supervisor(Address, Port) -> Name = make_name(Address, Port), whereis(Name). @@ -136,7 +139,7 @@ ssh_acceptor_child_spec(ServerOpts) -> Port = proplists:get_value(port, ServerOpts), Name = id(ssh_acceptor_sup, Address, Port), StartFunc = {ssh_acceptor_sup, start_link, [ServerOpts]}, - Restart = permanent, + Restart = transient, Shutdown = infinity, Modules = [ssh_acceptor_sup], Type = supervisor, diff --git a/lib/ssh/src/ssh_xfer.erl b/lib/ssh/src/ssh_xfer.erl index e18e18a9a9..63d01fd9de 100644 --- a/lib/ssh/src/ssh_xfer.erl +++ b/lib/ssh/src/ssh_xfer.erl @@ -72,7 +72,6 @@ protocol_version_request(XF) -> open(XF, ReqID, FileName, Access, Flags, Attrs) -> Vsn = XF#ssh_xfer.vsn, - FileName1 = unicode:characters_to_binary(FileName), MBits = if Vsn >= 5 -> M = encode_ace_mask(Access), ?uint32(M); @@ -82,7 +81,7 @@ open(XF, ReqID, FileName, Access, Flags, Attrs) -> F = encode_open_flags(Flags), xf_request(XF,?SSH_FXP_OPEN, [?uint32(ReqID), - ?binary(FileName1), + ?string_utf8(FileName), MBits, ?uint32(F), encode_ATTR(Vsn,Attrs)]). @@ -90,7 +89,7 @@ open(XF, ReqID, FileName, Access, Flags, Attrs) -> opendir(XF, ReqID, DirName) -> xf_request(XF, ?SSH_FXP_OPENDIR, [?uint32(ReqID), - ?string(DirName)]). + ?string_utf8(DirName)]). close(XF, ReqID, Handle) -> @@ -127,13 +126,11 @@ write(XF,ReqID, Handle, Offset, Data) -> remove(XF, ReqID, File) -> xf_request(XF, ?SSH_FXP_REMOVE, [?uint32(ReqID), - ?string(File)]). + ?string_utf8(File)]). %% Rename a file/directory -rename(XF, ReqID, Old, New, Flags) -> +rename(XF, ReqID, OldPath, NewPath, Flags) -> Vsn = XF#ssh_xfer.vsn, - OldPath = unicode:characters_to_binary(Old), - NewPath = unicode:characters_to_binary(New), FlagBits = if Vsn >= 5 -> F0 = encode_rename_flags(Flags), @@ -143,30 +140,27 @@ rename(XF, ReqID, Old, New, Flags) -> end, xf_request(XF, ?SSH_FXP_RENAME, [?uint32(ReqID), - ?binary(OldPath), - ?binary(NewPath), + ?string_utf8(OldPath), + ?string_utf8(NewPath), FlagBits]). %% Create directory mkdir(XF, ReqID, Path, Attrs) -> - Path1 = unicode:characters_to_binary(Path), xf_request(XF, ?SSH_FXP_MKDIR, [?uint32(ReqID), - ?binary(Path1), + ?string_utf8(Path), encode_ATTR(XF#ssh_xfer.vsn, Attrs)]). %% Remove a directory rmdir(XF, ReqID, Dir) -> - Dir1 = unicode:characters_to_binary(Dir), xf_request(XF, ?SSH_FXP_RMDIR, [?uint32(ReqID), - ?binary(Dir1)]). + ?string_utf8(Dir)]). %% Stat file stat(XF, ReqID, Path, Flags) -> - Path1 = unicode:characters_to_binary(Path), Vsn = XF#ssh_xfer.vsn, AttrFlags = if Vsn >= 5 -> F = encode_attr_flags(Vsn, Flags), @@ -176,13 +170,12 @@ stat(XF, ReqID, Path, Flags) -> end, xf_request(XF, ?SSH_FXP_STAT, [?uint32(ReqID), - ?binary(Path1), + ?string_utf8(Path), AttrFlags]). %% Stat file - follow symbolic links lstat(XF, ReqID, Path, Flags) -> - Path1 = unicode:characters_to_binary(Path), Vsn = XF#ssh_xfer.vsn, AttrFlags = if Vsn >= 5 -> F = encode_attr_flags(Vsn, Flags), @@ -192,7 +185,7 @@ lstat(XF, ReqID, Path, Flags) -> end, xf_request(XF, ?SSH_FXP_LSTAT, [?uint32(ReqID), - ?binary(Path1), + ?string_utf8(Path), AttrFlags]). %% Stat open file @@ -211,10 +204,9 @@ fstat(XF, ReqID, Handle, Flags) -> %% Modify file attributes setstat(XF, ReqID, Path, Attrs) -> - Path1 = unicode:characters_to_binary(Path), xf_request(XF, ?SSH_FXP_SETSTAT, [?uint32(ReqID), - ?binary(Path1), + ?string_utf8(Path), encode_ATTR(XF#ssh_xfer.vsn, Attrs)]). @@ -227,10 +219,9 @@ fsetstat(XF, ReqID, Handle, Attrs) -> %% Read a symbolic link readlink(XF, ReqID, Path) -> - Path1 = unicode:characters_to_binary(Path), xf_request(XF, ?SSH_FXP_READLINK, [?uint32(ReqID), - ?binary(Path1)]). + ?string_utf8(Path)]). %% Create a symbolic link @@ -244,10 +235,9 @@ symlink(XF, ReqID, LinkPath, TargetPath) -> %% Convert a path into a 'canonical' form realpath(XF, ReqID, Path) -> - Path1 = unicode:characters_to_binary(Path), xf_request(XF, ?SSH_FXP_REALPATH, [?uint32(ReqID), - ?binary(Path1)]). + ?string_utf8(Path)]). extended(XF, ReqID, Request, Data) -> xf_request(XF, ?SSH_FXP_EXTENDED, @@ -296,7 +286,10 @@ xf_send_names(#ssh_xfer{cm = CM, channel = Channel, vsn = Vsn}, Count = length(NamesAndAttrs), {Data, Len} = encode_names(Vsn, NamesAndAttrs), Size = 1 + 4 + 4 + Len, - ToSend = [<<?UINT32(Size), ?SSH_FXP_NAME, ?UINT32(ReqId), ?UINT32(Count)>>, + ToSend = [<<?UINT32(Size), + ?SSH_FXP_NAME, + ?UINT32(ReqId), + ?UINT32(Count)>>, Data], ssh_connection:send(CM, Channel, ToSend). @@ -818,25 +811,27 @@ decode_names(_Vsn, 0, _Data) -> decode_names(Vsn, I, <<?UINT32(Len), FileName:Len/binary, ?UINT32(LLen), _LongName:LLen/binary, Tail/binary>>) when Vsn =< 3 -> - Name = binary_to_list(FileName), + Name = unicode:characters_to_list(FileName), {A, Tail2} = decode_ATTR(Vsn, Tail), [{Name, A} | decode_names(Vsn, I-1, Tail2)]; decode_names(Vsn, I, <<?UINT32(Len), FileName:Len/binary, Tail/binary>>) when Vsn >= 4 -> - Name = binary_to_list(FileName), + Name = unicode:characters_to_list(FileName), {A, Tail2} = decode_ATTR(Vsn, Tail), [{Name, A} | decode_names(Vsn, I-1, Tail2)]. encode_names(Vsn, NamesAndAttrs) -> lists:mapfoldl(fun(N, L) -> encode_name(Vsn, N, L) end, 0, NamesAndAttrs). -encode_name(Vsn, {Name,Attr}, Len) when Vsn =< 3 -> +encode_name(Vsn, {NameUC,Attr}, Len) when Vsn =< 3 -> + Name = binary_to_list(unicode:characters_to_binary(NameUC)), NLen = length(Name), EncAttr = encode_ATTR(Vsn, Attr), ALen = size(EncAttr), NewLen = Len + NLen*2 + 4 + 4 + ALen, {[<<?UINT32(NLen)>>, Name, <<?UINT32(NLen)>>, Name, EncAttr], NewLen}; -encode_name(Vsn, {Name,Attr}, Len) when Vsn >= 4 -> +encode_name(Vsn, {NameUC,Attr}, Len) when Vsn >= 4 -> + Name = binary_to_list(unicode:characters_to_binary(NameUC)), NLen = length(Name), EncAttr = encode_ATTR(Vsn, Attr), ALen = size(EncAttr), @@ -851,9 +846,9 @@ encode_acl_items([ACE|As]) -> Type = encode_ace_type(ACE#ssh_xfer_ace.type), Flag = encode_ace_flag(ACE#ssh_xfer_ace.flag), Mask = encode_ace_mask(ACE#ssh_xfer_ace.mask), - Who = list_to_binary(ACE#ssh_xfer_ace.who), + Who = ACE#ssh_xfer_ace.who, [?uint32(Type), ?uint32(Flag), ?uint32(Mask), - ?binary(Who) | encode_acl_items(As)]; + ?string_utf8(Who) | encode_acl_items(As)]; encode_acl_items([]) -> []. @@ -872,7 +867,7 @@ decode_acl_items(I, <<?UINT32(Type), [#ssh_xfer_ace { type = decode_ace_type(Type), flag = decode_ace_flag(Flag), mask = decode_ace_mask(Mask), - who = binary_to_list(BWho)} | Acc]). + who = unicode:characters_to_list(BWho)} | Acc]). encode_extensions(Exts) -> Count = length(Exts), diff --git a/lib/ssh/src/sshd_sup.erl b/lib/ssh/src/sshd_sup.erl index 747906b2cf..60222f5172 100644 --- a/lib/ssh/src/sshd_sup.erl +++ b/lib/ssh/src/sshd_sup.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2013. 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 @@ -58,12 +58,7 @@ start_child(ServerOpts) -> end. stop_child(Name) -> - case supervisor:terminate_child(?MODULE, Name) of - ok -> - supervisor:delete_child(?MODULE, Name); - Error -> - Error - end. + supervisor:terminate_child(?MODULE, Name). stop_child(Address, Port) -> Name = id(Address, Port), @@ -94,7 +89,7 @@ init([Servers]) -> child_spec(Address, Port, ServerOpts) -> Name = id(Address, Port), StartFunc = {ssh_system_sup, start_link, [ServerOpts]}, - Restart = transient, + Restart = temporary, Shutdown = infinity, Modules = [ssh_system_sup], Type = supervisor, diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl index b3281e433e..b4e3871efd 100644 --- a/lib/ssh/test/ssh_basic_SUITE.erl +++ b/lib/ssh/test/ssh_basic_SUITE.erl @@ -46,7 +46,7 @@ all() -> daemon_already_started, server_password_option, server_userpassword_option, - close]. + double_close]. groups() -> [{dsa_key, [], basic_tests()}, @@ -57,7 +57,7 @@ groups() -> ]. basic_tests() -> - [send, peername_sockname, + [send, close, peername_sockname, exec, exec_compressed, shell, cli, known_hosts, idle_time, rekey, openssh_zlib_basic_test]. @@ -487,7 +487,7 @@ internal_error(Config) when is_list(Config) -> {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, {user_dir, UserDir}, {failfun, fun ssh_test_lib:failfun/2}]), - {error,Error} = + {error, Error} = ssh:connect(Host, Port, [{silently_accept_hosts, true}, {user_dir, UserDir}, {user_interaction, false}]), @@ -566,9 +566,35 @@ ips(Name) when is_list(Name) -> ordsets:from_list(IPs4++IPs6). %%-------------------------------------------------------------------- + close() -> - [{doc, "Simulate that we try to close an already closed connection"}]. + [{doc, "Client receives close when server closes"}]. close(Config) when is_list(Config) -> + process_flag(trap_exit, true), + SystemDir = filename:join(?config(priv_dir, Config), system), + UserDir = ?config(priv_dir, Config), + + {Server, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, + {user_dir, UserDir}, + {failfun, fun ssh_test_lib:failfun/2}]), + Client = + ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user_dir, UserDir}, + {user_interaction, false}]), + {ok, ChannelId} = ssh_connection:session_channel(Client, infinity), + + ssh:stop_daemon(Server), + receive + {ssh_cm, Client,{closed, ChannelId}} -> + ok + after 5000 -> + ct:fail(timeout) + end. + +%%-------------------------------------------------------------------- +double_close() -> + [{doc, "Simulate that we try to close an already closed connection"}]. +double_close(Config) when is_list(Config) -> SystemDir = ?config(data_dir, Config), PrivDir = ?config(priv_dir, Config), UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth @@ -587,6 +613,8 @@ close(Config) when is_list(Config) -> exit(CM, {shutdown, normal}), ok = ssh:close(CM). +%%-------------------------------------------------------------------- + openssh_zlib_basic_test() -> [{doc, "Test basic connection with openssh_zlib"}]. openssh_zlib_basic_test(Config) -> @@ -612,7 +640,7 @@ openssh_zlib_basic_test(Config) -> %% the "tcp-application" before the socket closed message is recived check_error("Internal error") -> ok; -check_error("Connection Lost") -> +check_error("Connection closed") -> ok; check_error(Error) -> ct:fail(Error). diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl index 6ed3dfa68c..00c25bf394 100644 --- a/lib/ssh/test/ssh_test_lib.erl +++ b/lib/ssh/test/ssh_test_lib.erl @@ -63,8 +63,13 @@ daemon(Host, Port, Options) -> Error end. + + start_shell(Port, IOServer, UserDir) -> - spawn_link(?MODULE, init_shell, [Port, IOServer, [{user_dir, UserDir}]]). + start_shell(Port, IOServer, UserDir, []). + +start_shell(Port, IOServer, UserDir, Options) -> + spawn_link(?MODULE, init_shell, [Port, IOServer, [{user_dir, UserDir}|Options]]). start_shell(Port, IOServer) -> spawn_link(?MODULE, init_shell, [Port, IOServer, []]). @@ -91,18 +96,23 @@ loop_io_server(TestCase, Buff0) -> {input, TestCase, Line} -> loop_io_server(TestCase, Buff0 ++ [Line]); {io_request, From, ReplyAs, Request} -> +%%ct:pal("~p",[{io_request, From, ReplyAs, Request}]), {ok, Reply, Buff} = io_request(Request, TestCase, From, ReplyAs, Buff0), +%%ct:pal("io_request(~p)-->~p",[Request,{ok, Reply, Buff}]), io_reply(From, ReplyAs, Reply), loop_io_server(TestCase, Buff); {'EXIT',_, _} -> - erlang:display('EXIT'), + erlang:display('ssh_test_lib:loop_io_server/2 EXIT'), ok end. io_request({put_chars, Chars}, TestCase, _, _, Buff) -> reply(TestCase, Chars), {ok, ok, Buff}; +io_request({put_chars, unicode, Chars}, TestCase, _, _, Buff) when is_binary(Chars) -> + reply(TestCase, Chars), + {ok, ok, Buff}; io_request({put_chars, Enc, Chars}, TestCase, _, _, Buff) -> reply(TestCase, unicode:characters_to_binary(Chars,Enc,latin1)), {ok, ok, Buff}; @@ -120,11 +130,13 @@ io_request({get_line, _Enc,_}, _, _, _, [Line | Buff]) -> io_reply(_, _, []) -> ok; io_reply(From, ReplyAs, Reply) -> +%%ct:pal("io_reply ~p sending ~p ! ~p",[self(),From, {io_reply, ReplyAs, Reply}]), From ! {io_reply, ReplyAs, Reply}. reply(_, []) -> ok; reply(TestCase, Result) -> +%%ct:pal("reply ~p sending ~p ! ~p",[self(), TestCase, Result]), TestCase ! Result. receive_exec_result(Msg) -> diff --git a/lib/ssh/test/ssh_unicode_SUITE.erl b/lib/ssh/test/ssh_unicode_SUITE.erl new file mode 100644 index 0000000000..a896a425b9 --- /dev/null +++ b/lib/ssh/test/ssh_unicode_SUITE.erl @@ -0,0 +1,590 @@ +%% Next line needed to enable utf8-strings in Erlang: +%% -*- coding: utf-8 -*- + +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-2013. 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% +%% + +%% gerl +fnu +%% ct:run_test([{suite,"ssh_unicode_SUITE"}, {logdir,"LOG"}]). + +-module(ssh_unicode_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("kernel/include/file.hrl"). + +% Default timetrap timeout +-define(default_timeout, ?t:minutes(1)). + +-define(USER, "åke高兴"). +-define(PASSWD, "ärlig日本じん"). +-define('sftp.txt', "sftp瑞点.txt"). +-define('test.txt', "testハンス.txt"). +-define('link_test.txt', "link_test語.txt"). + +-define(bindata, unicode:characters_to_binary("foobar å 一二三四いちにさんち") ). + +-define(NEWLINE, <<"\r\n">>). + +%%-------------------------------------------------------------------- +%% Common Test interface functions ----------------------------------- +%%-------------------------------------------------------------------- + +%% suite() -> +%% [{ct_hooks,[ts_install_cth]}]. + +all() -> + [{group, sftp}, + {group, shell} + ]. + + +init_per_suite(Config) -> + case {file:native_name_encoding(), (catch crypto:start())} of + {utf8, ok} -> + ssh:start(), + Config; + {utf8, _} -> + {skip,"Could not start crypto!"}; + _ -> + {skip,"Not unicode filename enabled emulator"} + end. + +end_per_suite(Config) -> + ssh:stop(), + crypto:stop(), + Config. + +%%-------------------------------------------------------------------- +groups() -> + [{shell, [], [shell_no_unicode, shell_unicode_string]}, + {sftp, [], [open_close_file, open_close_dir, read_file, read_dir, + write_file, rename_file, mk_rm_dir, remove_file, links, + retrieve_attributes, set_attributes, async_read, async_read_bin, + async_write + %% , position, pos_read, pos_write + ]}]. + +init_per_group(Group, Config) when Group==sftp + ; Group==shell -> + PrivDir = ?config(priv_dir, Config), + SysDir = ?config(data_dir, Config), + Sftpd = + ssh_test_lib:daemon([{system_dir, SysDir}, + {user_dir, PrivDir}, + {user_passwords, [{?USER, ?PASSWD}]}]), + [{group,Group}, {sftpd, Sftpd} | Config]; + +init_per_group(Group, Config) -> + [{group,Group} | Config]. + + +end_per_group(erlang_server, Config) -> + Config; +end_per_group(_, Config) -> + Config. + +%%-------------------------------------------------------------------- +init_per_testcase(_Case, Config) -> + prep(Config), + TmpConfig0 = lists:keydelete(watchdog, 1, Config), + TmpConfig = lists:keydelete(sftp, 1, TmpConfig0), + Dog = ct:timetrap(?default_timeout), + + case ?config(group, Config) of + sftp -> + {_Pid, Host, Port} = ?config(sftpd, Config), + {ok, ChannelPid, Connection} = + ssh_sftp:start_channel(Host, Port, + [{user, ?USER}, + {password, ?PASSWD}, + {user_interaction, false}, + {silently_accept_hosts, true}]), + Sftp = {ChannelPid, Connection}, + [{sftp, Sftp}, {watchdog, Dog} | TmpConfig]; + shell -> + UserDir = ?config(priv_dir, Config), + process_flag(trap_exit, true), + {_Pid, _Host, Port} = ?config(sftpd, Config), + ct:sleep(500), + IO = ssh_test_lib:start_io_server(), + Shell = ssh_test_lib:start_shell(Port, IO, UserDir, + [{silently_accept_hosts, true}, + {user,?USER},{password,?PASSWD}]), +%%ct:pal("IO=~p, Shell=~p, self()=~p",[IO,Shell,self()]), + wait_for_erlang_first_line([{io,IO}, {shell,Shell} | Config]) + end. + + +wait_for_erlang_first_line(Config) -> + receive + {'EXIT', _, _} -> + {fail,no_ssh_connection}; + <<"Eshell ",_/binary>> = ErlShellStart -> +%% ct:pal("Erlang shell start: ~p~n", [ErlShellStart]), + Config; + Other -> + ct:pal("Unexpected answer from ssh server: ~p",[Other]), + {fail,unexpected_answer} + after 10000 -> + ct:pal("No answer from ssh-server"), + {fail,timeout} + end. + + + +end_per_testcase(rename_file, Config) -> + PrivDir = ?config(priv_dir, Config), + NewFileName = filename:join(PrivDir, ?'test.txt'), + file:delete(NewFileName), + end_per_testcase(Config); +end_per_testcase(_TC, Config) -> + end_per_testcase(Config). + +end_per_testcase(Config) -> + catch exit(?config(shell,Config), kill), + case ?config(sftp, Config) of + {Sftp, Connection} -> + ssh_sftp:stop_channel(Sftp), + ssh:close(Connection); + _ -> + ok + end. + +%%-------------------------------------------------------------------- +%% Test Cases -------------------------------------------------------- + +-define(chk_expected(Received,Expected), + (fun(R_,E_) when R_==E_ -> ok; + (R_,E_) -> ct:pal("Expected: ~p~nReceived: ~p~n", [E_,R_]), + E_ = R_ + end)(Received,Expected)). + +-define(receive_chk(Ref,Expected), + (fun(E__) -> + receive + {async_reply, Ref, Received} when Received==E__ -> + ?chk_expected(Received, E__); + {async_reply, Ref, Received} when Received=/=E__ -> + ct:pal("Expected: ~p~nReceived: ~p~n", [E__,Received]), + E__ = Received; + Msg -> + ct:pal("Expected (Ref=~p): ~p", [Ref,E__]), + ct:fail(Msg) + end + end)(Expected)). + +%%-------------------------------------------------------------------- + + +open_close_file() -> + [{doc, "Test API functions open/3 and close/2"}]. +open_close_file(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, ?'sftp.txt'), + {Sftp, _} = ?config(sftp, Config), + + lists:foreach( + fun(Mode) -> + ct:log("Mode: ~p",[Mode]), + %% list_dir(PrivDir), + ok = open_close_file(Sftp, FileName, Mode) + end, + [ + [read], + [write], + [write, creat], + [write, trunc], + [append], + [read, binary] + ]). + +open_close_file(Server, File, Mode) -> + {ok, Handle} = ssh_sftp:open(Server, File, Mode), + ok = ssh_sftp:close(Server, Handle). + +%%-------------------------------------------------------------------- +open_close_dir() -> + [{doc, "Test API functions opendir/2 and close/2"}]. +open_close_dir(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + {Sftp, _} = ?config(sftp, Config), + FileName = filename:join(PrivDir, ?'sftp.txt'), + + {ok, Handle} = ssh_sftp:opendir(Sftp, PrivDir), + ok = ssh_sftp:close(Sftp, Handle), + {error, _} = ssh_sftp:opendir(Sftp, FileName). + +%%-------------------------------------------------------------------- +read_file() -> + [{doc, "Test API funtion read_file/2"}]. +read_file(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, ?'sftp.txt'), + {Sftp, _} = ?config(sftp, Config), + ?chk_expected(ssh_sftp:read_file(Sftp,FileName), file:read_file(FileName)). + +%%-------------------------------------------------------------------- +read_dir() -> + [{doc,"Test API function list_dir/2"}]. +read_dir(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + {Sftp, _} = ?config(sftp, Config), + {ok, Files} = ssh_sftp:list_dir(Sftp, PrivDir), + ct:pal("sftp list dir: ~ts~n", [Files]). + +%%-------------------------------------------------------------------- +write_file() -> + [{doc, "Test API function write_file/2"}]. +write_file(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, ?'sftp.txt'), + {Sftp, _} = ?config(sftp, Config), + ok = ssh_sftp:write_file(Sftp, FileName, [?bindata]), + ?chk_expected(file:read_file(FileName), {ok,?bindata}). + +%%-------------------------------------------------------------------- +remove_file() -> + [{doc,"Test API function delete/2"}]. +remove_file(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, ?'sftp.txt'), + {Sftp, _} = ?config(sftp, Config), + + {ok, Files} = ssh_sftp:list_dir(Sftp, PrivDir), + true = lists:member(filename:basename(FileName), Files), + ok = ssh_sftp:delete(Sftp, FileName), + {ok, NewFiles} = ssh_sftp:list_dir(Sftp, PrivDir), + false = lists:member(filename:basename(FileName), NewFiles), + {error, _} = ssh_sftp:delete(Sftp, FileName). +%%-------------------------------------------------------------------- +rename_file() -> + [{doc, "Test API function rename_file/2"}]. +rename_file(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, ?'sftp.txt'), + NewFileName = filename:join(PrivDir, ?'test.txt'), + + {Sftp, _} = ?config(sftp, Config), + {ok, Files} = ssh_sftp:list_dir(Sftp, PrivDir), + ct:pal("FileName: ~ts~nFiles: ~ts~n", [FileName, [[$\n,$ ,F]||F<-Files] ]), + true = lists:member(filename:basename(FileName), Files), + false = lists:member(filename:basename(NewFileName), Files), + ok = ssh_sftp:rename(Sftp, FileName, NewFileName), + {ok, NewFiles} = ssh_sftp:list_dir(Sftp, PrivDir), + ct:pal("FileName: ~ts, Files: ~ts~n", [FileName, [[$\n,F]||F<-NewFiles] ]), + + false = lists:member(filename:basename(FileName), NewFiles), + true = lists:member(filename:basename(NewFileName), NewFiles). + +%%-------------------------------------------------------------------- +mk_rm_dir() -> + [{doc,"Test API functions make_dir/2, del_dir/2"}]. +mk_rm_dir(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + {Sftp, _} = ?config(sftp, Config), + + DirName = filename:join(PrivDir, "test"), + ok = ssh_sftp:make_dir(Sftp, DirName), + ok = ssh_sftp:del_dir(Sftp, DirName), + NewDirName = filename:join(PrivDir, "foo/bar"), + {error, _} = ssh_sftp:make_dir(Sftp, NewDirName), + {error, _} = ssh_sftp:del_dir(Sftp, PrivDir). + +%%-------------------------------------------------------------------- +links() -> + [{doc,"Tests API function make_symlink/3"}]. +links(Config) when is_list(Config) -> + case os:type() of + {win32, _} -> + {skip, "Links are not fully supported by windows"}; + _ -> + {Sftp, _} = ?config(sftp, Config), + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, ?'sftp.txt'), + LinkFileName = filename:join(PrivDir, ?'link_test.txt'), + + ok = ssh_sftp:make_symlink(Sftp, LinkFileName, FileName), + {ok, FileName} = ssh_sftp:read_link(Sftp, LinkFileName) + end. + +%%-------------------------------------------------------------------- +retrieve_attributes() -> + [{doc, "Test API function read_file_info/3"}]. +retrieve_attributes(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, ?'sftp.txt'), + + {Sftp, _} = ?config(sftp, Config), + {ok, FileInfo} = ssh_sftp:read_file_info(Sftp, FileName), + {ok, NewFileInfo} = file:read_file_info(FileName), + + %% TODO comparison. There are some differences now is that ok? + ct:pal("SFTP: ~p~nFILE: ~p~n", [FileInfo, NewFileInfo]). + +%%-------------------------------------------------------------------- +set_attributes() -> + [{doc,"Test API function write_file_info/3"}]. +set_attributes(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, ?'test.txt'), + + {Sftp, _} = ?config(sftp, Config), + {ok,Fd} = file:open(FileName, write), + io:put_chars(Fd,"foo"), + ok = ssh_sftp:write_file_info(Sftp, FileName, #file_info{mode=8#400}), + {error, eacces} = file:write_file(FileName, "hello again"), + ssh_sftp:write_file_info(Sftp, FileName, #file_info{mode=8#600}), + ok = file:write_file(FileName, "hello again"). + +%%-------------------------------------------------------------------- + +async_read() -> + [{doc,"Test API aread/3"}]. +async_read(Config) when is_list(Config) -> + do_async_read(Config, false). + +async_read_bin() -> + [{doc,"Test API aread/3"}]. +async_read_bin(Config) when is_list(Config) -> + do_async_read(Config, true). + +do_async_read(Config, BinaryFlag) -> + {Sftp, _} = ?config(sftp, Config), + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, ?'sftp.txt'), + {ok,ExpDataBin} = file:read_file(FileName), + ExpData = case BinaryFlag of + true -> ExpDataBin; + false -> binary_to_list(ExpDataBin) + end, + {ok, Handle} = ssh_sftp:open(Sftp, FileName, [read|case BinaryFlag of + true -> [binary]; + false -> [] + end]), + {async, Ref} = ssh_sftp:aread(Sftp, Handle, 20), + ?receive_chk(Ref, {ok,ExpData}). + +%%-------------------------------------------------------------------- +async_write() -> + [{doc,"Test API awrite/3"}]. +async_write(Config) when is_list(Config) -> + {Sftp, _} = ?config(sftp, Config), + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, ?'test.txt'), + {ok, Handle} = ssh_sftp:open(Sftp, FileName, [write]), + Expected = ?bindata, + {async, Ref} = ssh_sftp:awrite(Sftp, Handle, Expected), + + receive + {async_reply, Ref, ok} -> + {ok, Data} = file:read_file(FileName), + ?chk_expected(Data, Expected); + Msg -> + ct:fail(Msg) + end. + +%%-------------------------------------------------------------------- + +position() -> + [{doc, "Test API functions position/3"}]. +position(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, ?'test.txt'), + {Sftp, _} = ?config(sftp, Config), + + Data = list_to_binary("1234567890"), + ssh_sftp:write_file(Sftp, FileName, [Data]), + {ok, Handle} = ssh_sftp:open(Sftp, FileName, [read]), + + {ok, 3} = ssh_sftp:position(Sftp, Handle, {bof, 3}), + {ok, "4"} = ssh_sftp:read(Sftp, Handle, 1), + + {ok, 10} = ssh_sftp:position(Sftp, Handle, eof), + eof = ssh_sftp:read(Sftp, Handle, 1), + + {ok, 6} = ssh_sftp:position(Sftp, Handle, {bof, 6}), + {ok, "7"} = ssh_sftp:read(Sftp, Handle, 1), + + {ok, 9} = ssh_sftp:position(Sftp, Handle, {cur, 2}), + {ok, "0"} = ssh_sftp:read(Sftp, Handle, 1), + + {ok, 0} = ssh_sftp:position(Sftp, Handle, bof), + {ok, "1"} = ssh_sftp:read(Sftp, Handle, 1), + + {ok, 1} = ssh_sftp:position(Sftp, Handle, cur), + {ok, "2"} = ssh_sftp:read(Sftp, Handle, 1). + +%%-------------------------------------------------------------------- +pos_read() -> + [{doc,"Test API functions pread/3 and apread/3"}]. +pos_read(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, ?'test.txt'), + {Sftp, _} = ?config(sftp, Config), + Data = ?bindata, + ssh_sftp:write_file(Sftp, FileName, [Data]), + + {ok, Handle} = ssh_sftp:open(Sftp, FileName, [read]), + {async, Ref} = ssh_sftp:apread(Sftp, Handle, {bof,5}, 4), + + ?receive_chk(Ref, {ok,binary_part(Data,5,4)}), + ?chk_expected(ssh_sftp:pread(Sftp,Handle,{bof,4},4), {ok,binary_part(Data,4,4)}). + + +%%-------------------------------------------------------------------- +pos_write() -> + [{doc,"Test API functions pwrite/4 and apwrite/4"}]. +pos_write(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, ?'test.txt'), + {Sftp, _} = ?config(sftp, Config), + + {ok, Handle} = ssh_sftp:open(Sftp, FileName, [write]), + + Data = unicode:characters_to_list("再见"), + ssh_sftp:write_file(Sftp, FileName, [Data]), + + NewData = unicode:characters_to_list(" さようなら"), + {async, Ref} = ssh_sftp:apwrite(Sftp, Handle, {bof, 2}, NewData), + ?receive_chk(Ref, ok), + + ok = ssh_sftp:pwrite(Sftp, Handle, eof, unicode:characters_to_list(" adjö ")), + + ?chk_expected(ssh_sftp:read_file(Sftp,FileName), + {ok,unicode:characters_to_binary("再见 さようなら adjö ")}). + +%%-------------------------------------------------------------------- +sftp_nonexistent_subsystem() -> + [{doc, "Try to execute sftp subsystem on a server that does not support it"}]. +sftp_nonexistent_subsystem(Config) when is_list(Config) -> + {_,Host, Port} = ?config(sftpd, Config), + {error,"server failed to start sftp subsystem"} = + ssh_sftp:start_channel(Host, Port, + [{user_interaction, false}, + {user, ?USER}, + {password, ?PASSWD}, + {silently_accept_hosts, true}]). + +%%-------------------------------------------------------------------- +shell_no_unicode(Config) -> + do_shell(?config(io,Config), + [new_prompt, + {type,"io:format(\"hej ~p~n\",[42])."}, + {expect,"hej 42"} + ]). + +%%-------------------------------------------------------------------- +shell_unicode_string(Config) -> + do_shell(?config(io,Config), + [new_prompt, + {type,"io:format(\"こにちわ~ts~n\",[\"四二\"])."}, + {expect,"こにちわ四二"}, + {expect,"ok"} + ]). + +%%-------------------------------------------------------------------- +%% Internal functions ------------------------------------------------ +%%-------------------------------------------------------------------- +prep(Config) -> + PrivDir = ?config(priv_dir, Config), + TestFile = filename:join(PrivDir, ?'sftp.txt'), + TestFile1 = filename:join(PrivDir, ?'test.txt'), + TestLink = filename:join(PrivDir, ?'link_test.txt'), + + file:delete(TestFile), + file:delete(TestFile1), + file:delete(TestLink), + + %% Initial config + DataDir = ?config(data_dir, Config), + FileName = filename:join(DataDir, ?'sftp.txt'), + {ok,_BytesCopied} = file:copy(FileName, TestFile), + Mode = 8#00400 bor 8#00200 bor 8#00040, % read & write owner, read group + {ok, FileInfo} = file:read_file_info(TestFile), + ok = file:write_file_info(TestFile, + FileInfo#file_info{mode = Mode}). + + +%% list_dir(Dir) -> +%% ct:pal("prep/1: ls(~p):~n~p~n~ts",[Dir, file:list_dir(Dir), +%% begin +%% {ok,DL} = file:list_dir(Dir), +%% [[$\n|FN] || FN <- DL] +%% end]). + + +%%-------------------------------------------------------------------- +do_shell(IO, List) -> do_shell(IO, 0, List). + +do_shell(IO, N, [new_prompt|More]) -> + do_shell(IO, N+1, More); + +do_shell(IO, N, Ops=[{Order,Arg}|More]) -> + receive + X = <<"\r\n">> -> +%% ct:pal("Skip newline ~p",[X]), + do_shell(IO, N, Ops); + + <<P1,"> ">> when (P1-$0)==N -> + do_shell_prompt(IO, N, Order, Arg, More); + + <<P1,P2,"> ">> when (P1-$0)*10 + (P2-$0) == N -> + do_shell_prompt(IO, N, Order, Arg, More); + + Err when element(1,Err)==error -> + ct:fail("do_shell error: ~p~n",[Err]); + + RecBin when Order==expect ; Order==expect_echo -> +%% ct:pal("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:pal("Matched ~ts",[RecStr]), + do_shell(IO, N, More); + true when Order==expect_echo -> + ct:pal("Matched echo ~ts",[RecStr]), + do_shell(IO, N, More); + false -> + ct:fail("*** Expected ~p, but got ~p",[string:strip(ExpStr),RecStr]) + end + after 10000 -> + case Order of + expect -> ct:fail("timeout, expected ~p",[string:strip(Arg)]); + type -> ct:fail("timeout, no prompt") + end + end; + +do_shell(_, _, []) -> + ok. + + +do_shell_prompt(IO, N, type, Str, More) -> +%% ct:pal("Matched prompt ~p to trigger sending of next line to server",[N]), + IO ! {input, self(), Str++"\r\n"}, + ct:pal("Promt '~p> ', Sent ~ts",[N,Str++"\r\n"]), + do_shell(IO, N, [{expect_echo,Str}|More]); % expect echo of the sent line +do_shell_prompt(IO, N, Op, Str, More) -> +%% ct:pal("Matched prompt ~p",[N]), + do_shell(IO, N, [{Op,Str}|More]). + +%%-------------------------------------------------------------------- diff --git a/lib/ssh/test/ssh_unicode_SUITE_data/sftp.txt b/lib/ssh/test/ssh_unicode_SUITE_data/sftp.txt new file mode 100644 index 0000000000..3eaaddca21 --- /dev/null +++ b/lib/ssh/test/ssh_unicode_SUITE_data/sftp.txt @@ -0,0 +1 @@ +åäöÅÄÖ瑞語 diff --git a/lib/ssh/test/ssh_unicode_SUITE_data/sftp瑞点.txt b/lib/ssh/test/ssh_unicode_SUITE_data/sftp瑞点.txt new file mode 100644 index 0000000000..3eaaddca21 --- /dev/null +++ b/lib/ssh/test/ssh_unicode_SUITE_data/sftp瑞点.txt @@ -0,0 +1 @@ +åäöÅÄÖ瑞語 diff --git a/lib/ssh/test/ssh_unicode_SUITE_data/ssh_host_dsa_key b/lib/ssh/test/ssh_unicode_SUITE_data/ssh_host_dsa_key new file mode 100644 index 0000000000..51ab6fbd88 --- /dev/null +++ b/lib/ssh/test/ssh_unicode_SUITE_data/ssh_host_dsa_key @@ -0,0 +1,13 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBuwIBAAKBgQCClaHzE2ul0gKSUxah5W0W8UiJLy4hXngKEqpaUq9SSdVdY2LK +wVfKH1gt5iuaf1FfzOhsIC9G/GLnjYttXZc92cv/Gfe3gR+s0ni2++MX+T++mE/Q +diltXv/Hp27PybS67SmiFW7I+RWnT2OKlMPtw2oUuKeztCe5UWjaj/y5FQIVAPLA +l9RpiU30Z87NRAHY3NTRaqtrAoGANMRxw8UfdtNVR0CrQj3AgPaXOGE4d+G4Gp4X +skvnCHycSVAjtYxebUkzUzt5Q6f/IabuLUdge3gXrc8BetvrcKbp+XZgM0/Vj2CF +Ymmy3in6kzGZq7Fw1sZaku6AOU8vLa5woBT2vAcHLLT1bLAzj7viL048T6MfjrOP +ef8nHvACgYBhDWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah +/XcF3DeRF+eEoz48wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+U +ykSTXYUbtsfTNRFQGBW2/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0CgIVAN4wtL5W +Lv62jKcdskxNyz2NQoBx +-----END DSA PRIVATE KEY----- + diff --git a/lib/ssh/test/ssh_unicode_SUITE_data/ssh_host_dsa_key.pub b/lib/ssh/test/ssh_unicode_SUITE_data/ssh_host_dsa_key.pub new file mode 100644 index 0000000000..4dbb1305b0 --- /dev/null +++ b/lib/ssh/test/ssh_unicode_SUITE_data/ssh_host_dsa_key.pub @@ -0,0 +1,11 @@ +---- BEGIN SSH2 PUBLIC KEY ---- +AAAAB3NzaC1kc3MAAACBAIKVofMTa6XSApJTFqHlbRbxSIkvLiFeeAoSqlpSr1JJ1V1j +YsrBV8ofWC3mK5p/UV/M6GwgL0b8YueNi21dlz3Zy/8Z97eBH6zSeLb74xf5P76YT9B2 +KW1e/8enbs/JtLrtKaIVbsj5FadPY4qUw+3DahS4p7O0J7lRaNqP/LkVAAAAFQDywJfU +aYlN9GfOzUQB2NzU0WqrawAAAIA0xHHDxR9201VHQKtCPcCA9pc4YTh34bganheyS+cI +fJxJUCO1jF5tSTNTO3lDp/8hpu4tR2B7eBetzwF62+twpun5dmAzT9WPYIViabLeKfqT +MZmrsXDWxlqS7oA5Ty8trnCgFPa8BwcstPVssDOPu+IvTjxPox+Os495/yce8AAAAIBh +DWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah/XcF3DeRF+eEoz48 +wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+UykSTXYUbtsfTNRFQGBW2 +/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0Cg== +---- END SSH2 PUBLIC KEY ---- diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk index 90f09471c9..9ffc59dbaf 100644 --- a/lib/ssh/vsn.mk +++ b/lib/ssh/vsn.mk @@ -1,5 +1,5 @@ #-*-makefile-*- ; force emacs to enter makefile-mode -SSH_VSN = 2.1.8 +SSH_VSN = 3.0.1 APP_VSN = "ssh-$(SSH_VSN)" |