diff options
Diffstat (limited to 'lib/ssh')
-rw-r--r-- | lib/ssh/doc/src/ssh.xml | 9 | ||||
-rw-r--r-- | lib/ssh/doc/src/ssh_sftpd.xml | 7 | ||||
-rw-r--r-- | lib/ssh/doc/src/using_ssh.xml | 12 | ||||
-rw-r--r-- | lib/ssh/src/ssh.appup.src | 22 | ||||
-rw-r--r-- | lib/ssh/src/ssh.erl | 4 | ||||
-rw-r--r-- | lib/ssh/src/ssh_connection_handler.erl | 22 | ||||
-rw-r--r-- | lib/ssh/src/ssh_connection_manager.erl | 22 | ||||
-rw-r--r-- | lib/ssh/src/ssh_sftpd.erl | 77 | ||||
-rw-r--r-- | lib/ssh/src/ssh_xfer.erl | 5 | ||||
-rw-r--r-- | lib/ssh/src/ssh_xfer.hrl | 12 | ||||
-rw-r--r-- | lib/ssh/test/ssh_basic_SUITE.erl | 30 | ||||
-rw-r--r-- | lib/ssh/test/ssh_sftpd_SUITE.erl | 36 | ||||
-rw-r--r-- | lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl | 21 | ||||
-rw-r--r-- | lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_sftpd_file_alt.erl | 2 |
14 files changed, 195 insertions, 86 deletions
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml index 517cbf1ef9..a0afb5056e 100644 --- a/lib/ssh/doc/src/ssh.xml +++ b/lib/ssh/doc/src/ssh.xml @@ -181,10 +181,13 @@ (simply passed on to the transport protocol).</p></item> <tag><c><![CDATA[{ipv6_disabled, boolean()}]]></c></tag> <item> - <p>Determines if SSH shall use IPv6 or not.</p></item> - <tag><c><![CDATA[{idle_time, timeout()}]]></c></tag> + <p>Determines if SSH shall use IPv6 or not.</p> + </item> + <tag><c><![CDATA[{rekey_limit, integer()}]]></c></tag> <item> - <p>Sets a timeout on connection when no channels are active, default is infinity</p></item> + <p>Provide, in bytes, when rekeying should be initiated, + defaults to one time each GB and one time per hour.</p> + </item> </taglist> </desc> </func> diff --git a/lib/ssh/doc/src/ssh_sftpd.xml b/lib/ssh/doc/src/ssh_sftpd.xml index a4273195b5..3666bc7692 100644 --- a/lib/ssh/doc/src/ssh_sftpd.xml +++ b/lib/ssh/doc/src/ssh_sftpd.xml @@ -80,7 +80,12 @@ the user will end up in <c>/tmp/etc</c>. </p> </item> - </taglist> + <tag><c><![CDATA[{sftpd_vsn, integer()}]]></c></tag> + <item> + <p>Sets the sftp version to use, defaults to 5. Version 6 is under + development and limited.</p> + </item> + </taglist> </desc> </func> </funcs> diff --git a/lib/ssh/doc/src/using_ssh.xml b/lib/ssh/doc/src/using_ssh.xml index 1a54f3f964..87b811d591 100644 --- a/lib/ssh/doc/src/using_ssh.xml +++ b/lib/ssh/doc/src/using_ssh.xml @@ -5,6 +5,7 @@ <header> <copyright> <year>2012</year> + <year>2013</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -102,7 +103,8 @@ <p>Use the openssh client from a shell to connect to the Erlang ssh daemon.</p> <code> - $bash> ssh tarlop -p 8989 -i /tmp/otptest_user/.ssh/id_rsa -o UserKnownHostsFile=/tmp/otptest_user/.ssh/known_hosts + $bash> ssh tarlop -p 8989 -i /tmp/otptest_user/.ssh/id_rsa\ + -o UserKnownHostsFile=/tmp/otptest_user/.ssh/known_hosts The authenticity of host 'tarlop' can't be established. RSA key fingerprint is 14:81:80:50:b1:1f:57:dd:93:a8:2d:2f:dd:90:ae:a8. Are you sure you want to continue connecting (yes/no)? yes @@ -174,8 +176,9 @@ <code type="erl" > 1> ssh:start(). ok - 2> ssh:daemon(8989, [{system_dir, "/tmp/ssh_daemon"}, {user_dir, "/tmp/otptest_user/.ssh"}, - {subsystems, [ssh_sftpd:subsystem_spec([{cwd, "/tmp/sftp/example"}])]}]). + 2> ssh:daemon(8989, [{system_dir, "/tmp/ssh_daemon"}, + {user_dir, "/tmp/otptest_user/.ssh"}, + {subsystems, [ssh_sftpd:subsystem_spec([{cwd, "/tmp/sftp/example"}])]}]). {ok,<0.54.0>} 3> </code> @@ -183,7 +186,8 @@ <p> Run the openssh sftp client</p> <code type="erl"> - $bash> sftp -oPort=8989 -o IdentityFile=/tmp/otptest_user/.ssh/id_rsa -o UserKnownHostsFile=/tmp/otptest_user/.ssh/known_hosts tarlop + $bash> sftp -oPort=8989 -o IdentityFile=/tmp/otptest_user/.ssh/id_rsa\ + -o UserKnownHostsFile=/tmp/otptest_user/.ssh/known_hosts tarlop Connecting to tarlop... sftp> pwd Remote working directory: /tmp/sftp/example diff --git a/lib/ssh/src/ssh.appup.src b/lib/ssh/src/ssh.appup.src index 6ba32e018f..826a11f1f4 100644 --- a/lib/ssh/src/ssh.appup.src +++ b/lib/ssh/src/ssh.appup.src @@ -19,29 +19,15 @@ {"%VSN%", [ - {<<"2.1.1">>, [{restart_application, ssh}]}, - {<<"2.1">>, [{load_module, ssh_sftpd_file_api, soft_purge, soft_purge, []}, - {load_module, ssh_connection, soft_purge, soft_purge, []}, - {load_module, ssh_connection_manager, soft_purge, soft_purge, []}, - {load_module, ssh_auth, soft_purge, soft_purge, []}, - {load_module, ssh_connection_handler, soft_purge, soft_purge, []}, - {load_module, ssh_channel, soft_purge, soft_purge, []}, - {load_module, ssh_file, soft_purge, soft_purge, []}]}, - {load_module, ssh, soft_purge, soft_purge, []}]}, + {<<"2.1.1">>, [{restart_application, ssh}]}, + {<<"2.1">>, [{restart_application, ssh}]}, {<<"2.0\\.*">>, [{restart_application, ssh}]}, {<<"1\\.*">>, [{restart_application, ssh}]} ], [ {<<"2.1.1">>, [{restart_application, ssh}]}, - {<<"2.1">>,[{load_module, ssh_sftpd_file_api, soft_purge, soft_purge, []}, - {load_module, ssh_connection, soft_purge, soft_purge, []}, - {load_module, ssh_connection_manager, soft_purge, soft_purge, []}, - {load_module, ssh_auth, soft_purge, soft_purge, []}, - {load_module, ssh_connection_handler, soft_purge, soft_purge, []}, - {load_module, ssh_channel, soft_purge, soft_purge, []}, - {load_module, ssh_file, soft_purge, soft_purge, []}]}, - {load_module, ssh, soft_purge, soft_purge, []}]}, + {<<"2.1">>,[{restart_application, ssh}]}, {<<"2.0\\.*">>, [{restart_application, ssh}]}, {<<"1\\.*">>, [{restart_application, ssh}]} ] -}.
\ No newline at end of file +}. diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl index a3ba8148eb..3ef26b1678 100644 --- a/lib/ssh/src/ssh.erl +++ b/lib/ssh/src/ssh.erl @@ -369,6 +369,8 @@ handle_option([{quiet_mode, _} = Opt|Rest], SocketOptions, SshOptions) -> handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); handle_option([{idle_time, _} = Opt | Rest], SocketOptions, SshOptions) -> handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); +handle_option([{rekey_limit, _} = Opt|Rest], SocketOptions, SshOptions) -> + handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); handle_option([Opt | Rest], SocketOptions, SshOptions) -> handle_option(Rest, [handle_inet_option(Opt) | SocketOptions], SshOptions). @@ -449,6 +451,8 @@ handle_ssh_option({quiet_mode, Value} = Opt) when Value == true; Opt; handle_ssh_option({idle_time, Value} = Opt) when is_integer(Value), Value > 0 -> Opt; +handle_ssh_option({rekey_limit, Value} = Opt) when is_integer(Value) -> + Opt; handle_ssh_option(Opt) -> throw({error, {eoptions, Opt}}). diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl index b79e8530b7..88b45111ff 100644 --- a/lib/ssh/src/ssh_connection_handler.erl +++ b/lib/ssh/src/ssh_connection_handler.erl @@ -35,7 +35,8 @@ -export([start_link/4, send/2, renegotiate/1, send_event/2, connection_info/3, - peer_address/1]). + peer_address/1, + renegotiate_data/1]). %% gen_fsm callbacks -export([hello/2, kexinit/2, key_exchange/2, new_keys/2, @@ -85,6 +86,8 @@ send(ConnectionHandler, Data) -> renegotiate(ConnectionHandler) -> send_all_state_event(ConnectionHandler, renegotiate). +renegotiate_data(ConnectionHandler) -> + send_all_state_event(ConnectionHandler, data_size). connection_info(ConnectionHandler, From, Options) -> send_all_state_event(ConnectionHandler, {info, From, Options}). @@ -500,7 +503,22 @@ handle_event(renegotiate, StateName, State) -> handle_event({info, From, Options}, StateName, #state{ssh_params = Ssh} = State) -> spawn(?MODULE, ssh_info_handler, [Options, Ssh, From]), {next_state, StateName, State}; - +handle_event(data_size, connected, #state{ssh_params = Ssh0} = State) -> + Sent = inet:getstat(State#state.socket, [send_oct]), + MaxSent = proplists:get_value(rekey_limit, State#state.opts, 1024000000), + case Sent >= MaxSent of + true -> + {KeyInitMsg, SshPacket, Ssh} = ssh_transport:key_exchange_init_msg(Ssh0), + send_msg(SshPacket, State), + {next_state, connected, + next_packet(State#state{ssh_params = Ssh, + key_exchange_init_msg = KeyInitMsg, + renegotiate = true})}; + _ -> + {next_state, connected, next_packet(State)} + end; +handle_event(data_size, StateName, State) -> + {next_state, StateName, State}; handle_event({unknown, Data}, StateName, State) -> Msg = #ssh_msg_unimplemented{sequence = Data}, send_msg(Msg, State), diff --git a/lib/ssh/src/ssh_connection_manager.erl b/lib/ssh/src/ssh_connection_manager.erl index 0c1eee5186..94a9ed505f 100644 --- a/lib/ssh/src/ssh_connection_manager.erl +++ b/lib/ssh/src/ssh_connection_manager.erl @@ -125,7 +125,8 @@ info(ConnectionManager, ChannelProcess) -> %% or amount of data sent counter! renegotiate(ConnectionManager) -> cast(ConnectionManager, renegotiate). - +renegotiate_data(ConnectionManager) -> + cast(ConnectionManager, renegotiate_data). connection_info(ConnectionManager, Options) -> call(ConnectionManager, {connection_info, Options}). @@ -481,7 +482,9 @@ handle_cast({global_request, _, _, _, _} = Request, State0) -> handle_cast(renegotiate, #state{connection = Pid} = State) -> ssh_connection_handler:renegotiate(Pid), {noreply, State}; - +handle_cast(renegotiate_data, #state{connection = Pid} = State) -> + ssh_connection_handler:renegotiate_data(Pid), + {noreply, State}; handle_cast({adjust_window, ChannelId, Bytes}, #state{connection = Pid, connection_state = #connection{channel_cache = Cache}} = State) -> @@ -520,6 +523,8 @@ handle_info({start_connection, server, Exec = proplists:get_value(exec, Options), CliSpec = proplists:get_value(ssh_cli, Options, {ssh_cli, [Shell]}), ssh_connection_handler:send_event(Connection, socket_control), + erlang:send_after(3600000, self(), rekey), + erlang:send_after(60000, self(), rekey_data), {noreply, State#state{connection = Connection, connection_state = CState#connection{address = Address, @@ -536,6 +541,8 @@ handle_info({start_connection, client, case (catch ssh_transport:connect(Parent, Address, Port, SocketOpts, Options)) of {ok, Connection} -> + erlang:send_after(60000, self(), rekey_data), + erlang:send_after(3600000, self(), rekey), {noreply, State#state{connection = Connection}}; Reason -> Pid ! {self(), not_connected, Reason}, @@ -568,8 +575,15 @@ handle_info({'DOWN', _Ref, process, ChannelPid, _Reason}, State) -> %%% So that terminate will be run when supervisor is shutdown handle_info({'EXIT', _Sup, Reason}, State) -> - {stop, Reason, State}. - + {stop, Reason, State}; +handle_info(rekey, State) -> + renegotiate(self()), + erlang:send_after(3600000, self(), rekey), + {noreply, State}; +handle_info(rekey_data, State) -> + renegotiate_data(self()), + erlang:send_after(60000, self(), rekey_data), + {noreply, State}. handle_password(Opts) -> handle_rsa_password(handle_dsa_password(handle_normal_password(Opts))). handle_normal_password(Opts) -> diff --git a/lib/ssh/src/ssh_sftpd.erl b/lib/ssh/src/ssh_sftpd.erl index 6d6f4a0121..c7e8373840 100644 --- a/lib/ssh/src/ssh_sftpd.erl +++ b/lib/ssh/src/ssh_sftpd.erl @@ -119,9 +119,7 @@ init(Options) -> {Root0, State0} end, MaxLength = proplists:get_value(max_files, Options, 0), - - Vsn = proplists:get_value(vsn, Options, 5), - + Vsn = proplists:get_value(sftpd_vsn, Options, 5), {ok, State#state{cwd = CWD, root = Root, max_files = MaxLength, handles = [], pending = <<>>, xf = #ssh_xfer{vsn = Vsn, ext = []}}}. @@ -361,17 +359,21 @@ handle_op(?SSH_FXP_FSETSTAT, ReqId, <<?UINT32(HLen), BinHandle:HLen/binary, State0 end; handle_op(?SSH_FXP_REMOVE, ReqId, <<?UINT32(PLen), BPath:PLen/binary>>, - State0 = #state{file_handler = FileMod, file_state = FS0}) -> + State0 = #state{file_handler = FileMod, file_state = FS0, xf = #ssh_xfer{vsn = Vsn}}) -> Path = relate_file_name(BPath, State0), - %% case FileMod:is_dir(Path) of %% This version 6 we still have ver 5 - %% true -> - %% ssh_xfer:xf_send_status(State#state.xf, ReqId, - %% ?SSH_FX_FILE_IS_A_DIRECTORY); - %% false -> - {Status, FS1} = FileMod:delete(Path, FS0), - State1 = State0#state{file_state = FS1}, - send_status(Status, ReqId, State1); - %%end; + {IsDir, _FS1} = FileMod:is_dir(Path, FS0), + case IsDir of %% This version 6 we still have ver 5 + true when Vsn > 5 -> + ssh_xfer:xf_send_status(State0#state.xf, ReqId, + ?SSH_FX_FILE_IS_A_DIRECTORY, "File is a directory"); + true -> + ssh_xfer:xf_send_status(State0#state.xf, ReqId, + ?SSH_FX_FAILURE, "File is a directory"); + false -> + {Status, FS1} = FileMod:delete(Path, FS0), + State1 = State0#state{file_state = FS1}, + send_status(Status, ReqId, State1) + end; handle_op(?SSH_FXP_RMDIR, ReqId, <<?UINT32(PLen), BPath:PLen/binary>>, State0 = #state{file_handler = FileMod, file_state = FS0}) -> Path = relate_file_name(BPath, State0), @@ -629,31 +631,34 @@ open(Vsn, ReqId, Data, State) when Vsn >= 4 -> do_open(ReqId, State, Path, Flags). do_open(ReqId, State0, Path, Flags) -> - #state{file_handler = FileMod, file_state = FS0, root = Root} = State0, + #state{file_handler = FileMod, file_state = FS0, root = Root, xf = #ssh_xfer{vsn = Vsn}} = State0, XF = State0#state.xf, F = [binary | Flags], - %% case FileMod:is_dir(Path) of %% This is version 6 we still have 5 - %% true -> - %% ssh_xfer:xf_send_status(State#state.xf, ReqId, - %% ?SSH_FX_FILE_IS_A_DIRECTORY); - %% false -> - - AbsPath = case Root of - "" -> - Path; - _ -> - relate_file_name(Path, State0) - end, - - {Res, FS1} = FileMod:open(AbsPath, F, FS0), - State1 = State0#state{file_state = FS1}, - case Res of - {ok, IoDevice} -> - add_handle(State1, XF, ReqId, file, {Path,IoDevice}); - {error, Error} -> - ssh_xfer:xf_send_status(State1#state.xf, ReqId, - ssh_xfer:encode_erlang_status(Error)), - State1 + {IsDir, _FS1} = FileMod:is_dir(Path, FS0), + case IsDir of + true when Vsn > 5 -> + ssh_xfer:xf_send_status(State0#state.xf, ReqId, + ?SSH_FX_FILE_IS_A_DIRECTORY, "File is a directory"); + true -> + ssh_xfer:xf_send_status(State0#state.xf, ReqId, + ?SSH_FX_FAILURE, "File is a directory"); + false -> + AbsPath = case Root of + "" -> + Path; + _ -> + relate_file_name(Path, State0) + end, + {Res, FS1} = FileMod:open(AbsPath, F, FS0), + State1 = State0#state{file_state = FS1}, + case Res of + {ok, IoDevice} -> + add_handle(State1, XF, ReqId, file, {Path,IoDevice}); + {error, Error} -> + ssh_xfer:xf_send_status(State1#state.xf, ReqId, + ssh_xfer:encode_erlang_status(Error)), + State1 + end end. %% resolve all symlinks in a path diff --git a/lib/ssh/src/ssh_xfer.erl b/lib/ssh/src/ssh_xfer.erl index d5b6dd03d1..4dfd9ed8b0 100644 --- a/lib/ssh/src/ssh_xfer.erl +++ b/lib/ssh/src/ssh_xfer.erl @@ -383,6 +383,8 @@ decode_status(Status) -> ?SSH_FX_UNKNOWN_PRINCIPLE -> unknown_principle; ?SSH_FX_LOCK_CONFlICT -> lock_conflict; ?SSH_FX_NOT_A_DIRECTORY -> not_a_directory; + ?SSH_FX_FILE_IS_A_DIRECTORY -> file_is_a_directory; + ?SSH_FX_CANNOT_DELETE -> cannot_delete; _ -> {error,Status} end. @@ -392,6 +394,9 @@ encode_erlang_status(Status) -> eof -> ?SSH_FX_EOF; enoent -> ?SSH_FX_NO_SUCH_FILE; eacces -> ?SSH_FX_PERMISSION_DENIED; + eisdir -> ?SSH_FX_FILE_IS_A_DIRECTORY; + eperm -> ?SSH_FX_CANNOT_DELETE; + eexist -> ?SSH_FX_FILE_ALREADY_EXISTS; _ -> ?SSH_FX_FAILURE end. diff --git a/lib/ssh/src/ssh_xfer.hrl b/lib/ssh/src/ssh_xfer.hrl index c13950eb6e..0d85cf2094 100644 --- a/lib/ssh/src/ssh_xfer.hrl +++ b/lib/ssh/src/ssh_xfer.hrl @@ -58,7 +58,6 @@ %%% # SSH_FX_xxx %%% Description: Response packet types for file transfer protocol. %%%---------------------------------------------------------------------- - -define(SSH_FX_OK, 0). -define(SSH_FX_EOF, 1). -define(SSH_FX_NO_SUCH_FILE, 2). @@ -79,7 +78,18 @@ -define(SSH_FX_LOCK_CONFlICT, 17). -define(SSH_FX_DIR_NOT_EMPTY, 18). -define(SSH_FX_NOT_A_DIRECTORY, 19). +-define(SSH_FX_INVALID_FILENAME, 20). +-define(SSH_FX_LINK_LOOP, 21). +-define(SSH_FX_CANNOT_DELETE, 22). +-define(SSH_FX_INVALID_PARAMETER, 23). -define(SSH_FX_FILE_IS_A_DIRECTORY, 24). +-define(SSH_FX_BYTE_RANGE_LOCK_CONFLICT,25). +-define(SSH_FX_BYTE_RANGE_LOCK_REFUSED, 26). +-define(SSH_FX_DELETE_PENDING, 27). +-define(SSH_FX_FILE_CORRUPT, 28). +-define(SSH_FX_OWNER_INVALID, 29). +-define(SSH_FX_GROUP_INVALID, 30). +-define(SSH_FX_NO_MATCHING_BYTE_RANGE_LOCK,31). %%%---------------------------------------------------------------------- %%% # SSH_FILEXFER_xxx diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl index 5fec7f0cd7..efcb11f88f 100644 --- a/lib/ssh/test/ssh_basic_SUITE.erl +++ b/lib/ssh/test/ssh_basic_SUITE.erl @@ -42,15 +42,14 @@ all() -> {group, dsa_pass_key}, {group, rsa_pass_key}, {group, internal_error}, - {group, idle_time}, daemon_already_started, server_password_option, server_userpassword_option, close]. groups() -> - [{dsa_key, [], [send, exec, exec_compressed, shell, known_hosts, idle_time]}, - {rsa_key, [], [send, exec, exec_compressed, shell, known_hosts, idle_time]}, + [{dsa_key, [], [send, exec, exec_compressed, shell, known_hosts, idle_time, rekey]}, + {rsa_key, [], [send, exec, exec_compressed, shell, known_hosts, idle_time, rekey]}, {dsa_pass_key, [], [pass_phrase]}, {rsa_pass_key, [], [pass_phrase]}, {internal_error, [], [internal_error]} @@ -247,7 +246,8 @@ idle_time(Config) -> ConnectionRef = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, {user_dir, UserDir}, - {user_interaction, false}]), + {user_interaction, false}, + {idle_time, 2000}]), {ok, Id} = ssh_connection:session_channel(ConnectionRef, 1000), ssh_connection:close(ConnectionRef, Id), receive @@ -256,6 +256,28 @@ idle_time(Config) -> end, ssh:stop_daemon(Pid). %%-------------------------------------------------------------------- +rekey(doc) -> + ["Idle timeout test"]; +rekey(Config) -> + SystemDir = filename:join(?config(priv_dir, Config), system), + UserDir = ?config(priv_dir, Config), + + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, + {user_dir, UserDir}, + {failfun, fun ssh_test_lib:failfun/2}, + {rekey_limit, 0}]), + ConnectionRef = + ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user_dir, UserDir}, + {user_interaction, false}, + {rekey_limit, 0}]), + receive + after 15000 -> + %%By this time rekeying would have been done + ssh:close(ConnectionRef), + ssh:stop_daemon(Pid) + end. +%%-------------------------------------------------------------------- shell(doc) -> ["Test that ssh:shell/2 works"]; shell(Config) when is_list(Config) -> diff --git a/lib/ssh/test/ssh_sftpd_SUITE.erl b/lib/ssh/test/ssh_sftpd_SUITE.erl index b995eb9f0e..5aa46872ee 100644 --- a/lib/ssh/test/ssh_sftpd_SUITE.erl +++ b/lib/ssh/test/ssh_sftpd_SUITE.erl @@ -58,7 +58,8 @@ all() -> links, ver3_rename, relpath, - sshd_read_file]. + sshd_read_file, + ver6_basic]. groups() -> []. @@ -106,12 +107,18 @@ init_per_testcase(TestCase, Config) -> SystemDir = filename:join(?config(priv_dir, Config), system), Port = ssh_test_lib:inet_port(node()), - - {ok, Sftpd} = - ssh_sftpd:listen(Port, [{system_dir, SystemDir}, - {user_dir, PrivDir}, - {user_passwords,[{?USER, ?PASSWD}]}, - {pwdfun, fun(_,_) -> true end}]), + Options = [{system_dir, SystemDir}, + {user_dir, PrivDir}, + {user_passwords,[{?USER, ?PASSWD}]}, + {pwdfun, fun(_,_) -> true end}], + {ok, Sftpd} = case TestCase of + ver6_basic -> + SubSystems = [ssh_sftpd:subsystem_spec([{sftpd_vsn, 6}])], + ssh:daemon(Port, [{subsystems, SubSystems}|Options]); + _ -> + SubSystems = [ssh_sftpd:subsystem_spec([])], + ssh:daemon(Port, [{subsystems, SubSystems}|Options]) + end, Cm = ssh_test_lib:connect(Port, [{user_dir, ClientUserDir}, @@ -341,7 +348,7 @@ mk_rm_dir(Config) when is_list(Config) -> _/binary>>, _} = mkdir(DirName, Cm, Channel, ReqId), NewReqId = 1, - {ok, <<?SSH_FXP_STATUS, ?UINT32(NewReqId), ?UINT32(?SSH_FX_FAILURE), + {ok, <<?SSH_FXP_STATUS, ?UINT32(NewReqId), ?UINT32(?SSH_FX_FILE_ALREADY_EXISTS), _/binary>>, _} = mkdir(DirName, Cm, Channel, NewReqId), NewReqId1 = 2, @@ -591,7 +598,18 @@ sshd_read_file(Config) when is_list(Config) -> read_file(Handle, 100, 0, Cm, Channel, NewReqId), {ok, Data} = file:read_file(FileName). - +ver6_basic(doc) -> + ["Test SFTP Version 6"]; +ver6_basic(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + %FileName = filename:join(PrivDir, "test.txt"), + {Cm, Channel} = ?config(sftp, Config), + ReqId = 0, + {ok, <<?SSH_FXP_STATUS, ?UINT32(ReqId), % Ver 6 we have 5 + ?UINT32(?SSH_FX_FILE_IS_A_DIRECTORY), _/binary>>, _} = + open_file(PrivDir, Cm, Channel, ReqId, + ?ACE4_READ_DATA bor ?ACE4_READ_ATTRIBUTES, + ?SSH_FXF_OPEN_EXISTING). %%-------------------------------------------------------------------- %% Internal functions ------------------------------------------------ %%-------------------------------------------------------------------- diff --git a/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl b/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl index 7fc2312661..8f722941d4 100644 --- a/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl +++ b/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl @@ -42,7 +42,8 @@ all() -> quit, file_cb, root_dir, - list_dir_limited]. + list_dir_limited, + ver6_basic]. groups() -> []. @@ -112,7 +113,12 @@ init_per_testcase(TestCase, Config) -> [{system_dir, SystemDir}, {user_dir, PrivDir}, {subsystems, [Spec]}]; - + "ver6_basic" -> + Spec = + ssh_sftpd:subsystem_spec([{sftpd_vsn, 6}]), + [{system_dir, SystemDir}, + {user_dir, PrivDir}, + {subsystems, [Spec]}]; _ -> [{user_dir, PrivDir}, {system_dir, SystemDir}] @@ -232,7 +238,7 @@ file_cb(Config) when is_list(Config) -> NewDir = filename:join(PrivDir, "testdir"), ok = ssh_sftp:make_dir(Sftp, NewDir), alt_file_handler_check(alt_make_dir), - + ok = ssh_sftp:del_dir(Sftp, NewDir), alt_file_handler_check(alt_read_link_info), alt_file_handler_check(alt_write_file_info), @@ -260,6 +266,15 @@ list_dir_limited(Config) when is_list(Config) -> ssh_sftp:list_dir(Sftp, "."), ct:pal("Listing: ~p~n", [Listing]). +ver6_basic(doc) -> + ["Test some version 6 features"]; +ver6_basic(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + NewDir = filename:join(PrivDir, "testdir2"), + {Sftp, _} = ?config(sftp, Config), + ok = ssh_sftp:make_dir(Sftp, NewDir), + %%Test file_is_a_directory + {error, file_is_a_directory} = ssh_sftp:delete(Sftp, NewDir). %%-------------------------------------------------------------------- %% Internal functions ------------------------------------------------ %%-------------------------------------------------------------------- diff --git a/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_sftpd_file_alt.erl b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_sftpd_file_alt.erl index 9e119c4929..9f8a7c496c 100644 --- a/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_sftpd_file_alt.erl +++ b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_sftpd_file_alt.erl @@ -48,7 +48,7 @@ get_cwd(State) -> {file:get_cwd(), State}. is_dir(AbsPath, State) -> - sftpd_file_alt_tester ! alt_is_dir, + %sftpd_file_alt_tester ! alt_is_dir, {filelib:is_dir(AbsPath), State}. list_dir(AbsPath, State) -> |