aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssh
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssh')
-rw-r--r--lib/ssh/doc/src/ssh.xml9
-rw-r--r--lib/ssh/doc/src/ssh_sftpd.xml7
-rw-r--r--lib/ssh/doc/src/using_ssh.xml12
-rw-r--r--lib/ssh/src/ssh.appup.src22
-rw-r--r--lib/ssh/src/ssh.erl4
-rw-r--r--lib/ssh/src/ssh_connection_handler.erl22
-rw-r--r--lib/ssh/src/ssh_connection_manager.erl22
-rw-r--r--lib/ssh/src/ssh_sftpd.erl77
-rw-r--r--lib/ssh/src/ssh_xfer.erl5
-rw-r--r--lib/ssh/src/ssh_xfer.hrl12
-rw-r--r--lib/ssh/test/ssh_basic_SUITE.erl30
-rw-r--r--lib/ssh/test/ssh_sftpd_SUITE.erl36
-rw-r--r--lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl21
-rw-r--r--lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_sftpd_file_alt.erl2
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,&lt;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) ->