diff options
Diffstat (limited to 'lib/ssh/src')
-rw-r--r-- | lib/ssh/src/ssh.erl | 59 | ||||
-rw-r--r-- | lib/ssh/src/ssh.hrl | 10 | ||||
-rw-r--r-- | lib/ssh/src/ssh_cli.erl | 177 | ||||
-rw-r--r-- | lib/ssh/src/ssh_options.erl | 2 | ||||
-rw-r--r-- | lib/ssh/src/ssh_sftp.erl | 41 | ||||
-rw-r--r-- | lib/ssh/src/ssh_transport.erl | 19 | ||||
-rw-r--r-- | lib/ssh/src/ssh_xfer.erl | 39 | ||||
-rw-r--r-- | lib/ssh/src/ssh_xfer.hrl | 4 |
8 files changed, 186 insertions, 165 deletions
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl index 28f8e0ac18..c93b796078 100644 --- a/lib/ssh/src/ssh.erl +++ b/lib/ssh/src/ssh.erl @@ -477,33 +477,12 @@ stop_daemon(Address, Port, Profile) -> %% and will not return until the remote shell is ended.(e.g. on %% exit from the shell) %%-------------------------------------------------------------------- --spec shell(open_socket() | host()) -> _. +-spec shell(open_socket() | host() | connection_ref()) -> _. shell(Socket) when is_port(Socket) -> shell(Socket, []); -shell(Host) -> - shell(Host, ?SSH_DEFAULT_PORT, []). - - --spec shell(open_socket() | host(), client_options()) -> _. - -shell(Socket, Options) when is_port(Socket) -> - start_shell( connect(Socket, Options) ); -shell(Host, Options) -> - shell(Host, ?SSH_DEFAULT_PORT, Options). - --spec shell(Host, Port, Options) -> _ when - Host :: host(), - Port :: inet:port_number(), - Options :: client_options() . - -shell(Host, Port, Options) -> - start_shell( connect(Host, Port, Options) ). - - - -start_shell({ok, ConnectionRef}) -> +shell(ConnectionRef) when is_pid(ConnectionRef) -> case ssh_connection:session_channel(ConnectionRef, infinity) of {ok,ChannelId} -> success = ssh_connection:ptty_alloc(ConnectionRef, ChannelId, []), @@ -521,8 +500,38 @@ start_shell({ok, ConnectionRef}) -> Error end; -start_shell(Error) -> - Error. +shell(Host) -> + shell(Host, ?SSH_DEFAULT_PORT, []). + + +-spec shell(open_socket() | host(), client_options()) -> _. + +shell(Socket, Options) when is_port(Socket) -> + case connect(Socket, Options) of + {ok,ConnectionRef} -> + shell(ConnectionRef), + close(ConnectionRef); + Error -> + Error + end; + +shell(Host, Options) -> + shell(Host, ?SSH_DEFAULT_PORT, Options). + + +-spec shell(Host, Port, Options) -> _ when + Host :: host(), + Port :: inet:port_number(), + Options :: client_options() . + +shell(Host, Port, Options) -> + case connect(Host, Port, Options) of + {ok,ConnectionRef} -> + shell(ConnectionRef), + close(ConnectionRef); + Error -> + Error + end. %%-------------------------------------------------------------------- -spec default_algorithms() -> algs_list() . diff --git a/lib/ssh/src/ssh.hrl b/lib/ssh/src/ssh.hrl index a991f72cf2..86c447f695 100644 --- a/lib/ssh/src/ssh.hrl +++ b/lib/ssh/src/ssh.hrl @@ -163,6 +163,8 @@ 'aes128-ctr' | 'aes128-gcm@openssh.com' | 'aes192-ctr' | + 'aes192-cbc' | + 'aes256-cbc' | 'aes256-ctr' | 'aes256-gcm@openssh.com' | 'chacha20-poly1305@openssh.com' @@ -171,6 +173,7 @@ -type mac_alg() :: 'AEAD_AES_128_GCM' | 'AEAD_AES_256_GCM' | 'hmac-sha1' | + 'hmac-sha1-96' | 'hmac-sha2-256' | 'hmac-sha2-512' . @@ -315,17 +318,20 @@ -type subsystem_daemon_option() :: {subsystems, subsystem_specs()}. -type subsystem_specs() :: [ subsystem_spec() ]. --type shell_daemon_option() :: {shell, mod_fun_args() | 'shell_fun/1'() | 'shell_fun/2'() }. +-type shell_daemon_option() :: {shell, shell_spec()} . +-type shell_spec() :: mod_fun_args() | shell_fun() | disabled . +-type shell_fun() :: 'shell_fun/1'() | 'shell_fun/2'() . -type 'shell_fun/1'() :: fun((User::string()) -> pid()) . -type 'shell_fun/2'() :: fun((User::string(), PeerAddr::inet:ip_address()) -> pid()). -type exec_daemon_option() :: {exec, exec_spec()} . --type exec_spec() :: {direct, exec_fun()} . +-type exec_spec() :: {direct, exec_fun()} | disabled | deprecated_exec_opt(). -type exec_fun() :: 'exec_fun/1'() | 'exec_fun/2'() | 'exec_fun/3'(). -type 'exec_fun/1'() :: fun((Cmd::string()) -> exec_result()) . -type 'exec_fun/2'() :: fun((Cmd::string(), User::string()) -> exec_result()) . -type 'exec_fun/3'() :: fun((Cmd::string(), User::string(), ClientAddr::ip_port()) -> exec_result()) . -type exec_result() :: {ok,Result::term()} | {error,Reason::term()} . +-type deprecated_exec_opt() :: fun() | mod_fun_args() . -type ssh_cli_daemon_option() :: {ssh_cli, mod_args() | no_cli }. diff --git a/lib/ssh/src/ssh_cli.erl b/lib/ssh/src/ssh_cli.erl index af51356355..7f04fcb804 100644 --- a/lib/ssh/src/ssh_cli.erl +++ b/lib/ssh/src/ssh_cli.erl @@ -46,6 +46,8 @@ exec }). +-define(EXEC_ERROR_STATUS, 255). + %%==================================================================== %% ssh_server_channel callbacks %%==================================================================== @@ -105,6 +107,12 @@ handle_ssh_msg({ssh_cm, ConnectionHandler, write_chars(ConnectionHandler, ChannelId, Chars), {ok, State#state{pty = Pty, buf = NewBuf}}; +handle_ssh_msg({ssh_cm, ConnectionHandler, {shell, ChannelId, WantReply}}, #state{shell=disabled} = State) -> + write_chars(ConnectionHandler, ChannelId, 1, "Prohibited."), + ssh_connection:reply_request(ConnectionHandler, WantReply, success, ChannelId), + ssh_connection:exit_status(ConnectionHandler, ChannelId, ?EXEC_ERROR_STATUS), + ssh_connection:send_eof(ConnectionHandler, ChannelId), + {stop, ChannelId, State#state{channel = ChannelId, cm = ConnectionHandler}}; handle_ssh_msg({ssh_cm, ConnectionHandler, {shell, ChannelId, WantReply}}, State) -> NewState = start_shell(ConnectionHandler, State), ssh_connection:reply_request(ConnectionHandler, WantReply, success, ChannelId), @@ -114,22 +122,28 @@ handle_ssh_msg({ssh_cm, ConnectionHandler, {shell, ChannelId, WantReply}}, Stat handle_ssh_msg({ssh_cm, ConnectionHandler, {exec, ChannelId, WantReply, Cmd}}, S0) -> case case S0#state.exec of + disabled -> + {"Prohibited.", ?EXEC_ERROR_STATUS, 1}; + {direct,F} -> %% Exec called and a Fun or MFA is defined to use. The F returns the %% value to return. - exec_direct(ConnectionHandler, F, Cmd); + %% The standard I/O is directed from/to the channel ChannelId. + exec_direct(ConnectionHandler, ChannelId, Cmd, F, WantReply, S0); - undefined when S0#state.shell == ?DEFAULT_SHELL -> + undefined when S0#state.shell == ?DEFAULT_SHELL ; + S0#state.shell == disabled -> %% Exec called and the shell is the default shell (= Erlang shell). %% To be exact, eval the term as an Erlang term (but not using the %% ?DEFAULT_SHELL directly). This disables banner, prompts and such. - exec_in_erlang_default_shell(Cmd); + %% The standard I/O is directed from/to the channel ChannelId. + exec_in_erlang_default_shell(ConnectionHandler, ChannelId, Cmd, WantReply, S0); undefined -> %% Exec called, but the a shell other than the default shell is defined. %% No new exec shell is defined, so don't execute! %% We don't know if it is intended to use the new shell or not. - {"Prohibited.", 255, 1}; + {"Prohibited.", ?EXEC_ERROR_STATUS, 1}; _ -> %% Exec called and a Fun or MFA is defined to use. The F communicates via @@ -216,14 +230,9 @@ handle_msg({Group, Req}, #state{group = Group, buf = Buf, pty = Pty, write_chars(ConnectionHandler, ChannelId, Chars), {ok, State#state{buf = NewBuf}}; -handle_msg({'EXIT', Group, Reason}, #state{group = Group, +handle_msg({'EXIT', Group, _Reason}, #state{group = Group, cm = ConnectionHandler, channel = ChannelId} = State) -> - Status = case Reason of - normal -> 0; - _ -> -1 - end, - ssh_connection:exit_status(ConnectionHandler, ChannelId, Status), ssh_connection:send_eof(ConnectionHandler, ChannelId), {stop, ChannelId, State}; @@ -357,7 +366,7 @@ insert_chars([], {Buf, BufTail, Col}, _Tty) -> insert_chars(Chars, {Buf, BufTail, Col}, Tty) -> {NewBuf, _NewBufTail, WriteBuf, NewCol} = conv_buf(Chars, Buf, [], [], Col), - M = move_cursor(NewCol + length(BufTail), NewCol, Tty), + M = move_cursor(special_at_width(NewCol+length(BufTail), Tty), NewCol, Tty), {[WriteBuf, BufTail | M], {NewBuf, BufTail, NewCol}}. %%% delete characters at current position, (backwards if negative argument) @@ -372,7 +381,7 @@ delete_chars(N, {Buf, BufTail, Col}, Tty) -> % N < 0 NewBuf = nthtail(-N, Buf), 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), + M2 = move_cursor(special_at_width(NewCol+length(BufTail)-N, Tty), NewCol, Tty), {[M1, BufTail, lists:duplicate(-N, $ ) | M2], {NewBuf, BufTail, NewCol}}. @@ -429,6 +438,10 @@ move_cursor(From, To, #ssh_pty{width=Width, term=Type}) -> end, [Tcol | Trow]. +%%% Caution for line "breaks" +special_at_width(From0, #ssh_pty{width=Width}) when (From0 rem Width) == 0 -> From0 - 1; +special_at_width(From0, _) -> From0. + %% %%% write out characters %% %%% make sure that there is data to send %% %%% before calling ssh_connection:send @@ -518,86 +531,94 @@ start_exec_shell(ConnectionHandler, Cmd, State) -> buf = empty_buf()}. %%-------------------------------------------------------------------- -exec_in_erlang_default_shell(Cmd) -> - case eval(parse(scan(Cmd))) of - {ok, Term} -> - {io_lib:format("~p\n", [Term]), 0, 0}; - {error, Error} when is_atom(Error) -> - {io_lib:format("Error in ~p: ~p\n", [Cmd,Error]), -1, 1}; - _ -> - {io_lib:format("Error: ~p\n", [Cmd]), -1, 1} - end. +exec_in_erlang_default_shell(ConnectionHandler, ChannelId, Cmd, WantReply, State) -> + exec_in_self_group(ConnectionHandler, ChannelId, WantReply, State, + fun() -> + eval(parse(scan(Cmd))) + end). + scan(Cmd) -> erl_scan:string(Cmd). parse({ok, Tokens, _}) -> erl_parse:parse_exprs(Tokens); -parse(Error) -> - Error. +parse({error, {_,erl_scan,Cause}, _}) -> + {error, erl_scan:format_error(Cause)}. eval({ok, Expr_list}) -> - case (catch erl_eval:exprs(Expr_list, - erl_eval:new_bindings())) of - {value, Value, _NewBindings} -> - {ok, Value}; - {'EXIT', {Error, _}} -> - {error, Error}; - {error, Error} -> - {error, Error}; - Error -> - {error, Error} - end; + {value, Value, _NewBindings} = erl_eval:exprs(Expr_list, erl_eval:new_bindings()), + {ok, Value}; +eval({error, {_,erl_parse,Cause}}) -> + {error, erl_parse:format_error(Cause)}; eval({error,Error}) -> - {error, Error}; -eval(Error) -> {error, Error}. %%-------------------------------------------------------------------- -exec_direct(ConnectionHandler, ExecSpec, Cmd) -> - try - case ExecSpec of - _ when is_function(ExecSpec, 1) -> - ExecSpec(Cmd); - _ when is_function(ExecSpec, 2) -> - [{user,User}] = ssh_connection_handler:connection_info(ConnectionHandler, [user]), - ExecSpec(Cmd, User); - _ when is_function(ExecSpec, 3) -> - ConnectionInfo = - ssh_connection_handler:connection_info(ConnectionHandler, [peer, user]), - User = proplists:get_value(user, ConnectionInfo), - {_, PeerAddr} = proplists:get_value(peer, ConnectionInfo), - ExecSpec(Cmd, User, PeerAddr) - end - of - Reply -> - return_direct_exec_reply(Reply, Cmd) - catch - C:Error -> - {io_lib:format("Error in \"~s\": ~p ~p~n", [Cmd,C,Error]), -1, 1} - end. - - +exec_direct(ConnectionHandler, ChannelId, Cmd, ExecSpec, WantReply, State) -> + Fun = + fun() -> + if + is_function(ExecSpec, 1) -> + ExecSpec(Cmd); + + is_function(ExecSpec, 2) -> + [{user,User}] = ssh_connection_handler:connection_info(ConnectionHandler, [user]), + ExecSpec(Cmd, User); + + is_function(ExecSpec, 3) -> + ConnectionInfo = + ssh_connection_handler:connection_info(ConnectionHandler, [peer, user]), + User = proplists:get_value(user, ConnectionInfo), + {_, PeerAddr} = proplists:get_value(peer, ConnectionInfo), + ExecSpec(Cmd, User, PeerAddr); + + true -> + {error, "Bad exec fun in server"} + end + end, + exec_in_self_group(ConnectionHandler, ChannelId, WantReply, State, Fun). -return_direct_exec_reply(Reply, Cmd) -> - case fmt_exec_repl(Reply) of - {ok,S} -> - {S, 0, 0}; - {error,S} -> - {io_lib:format("Error in \"~s\": ~s~n", [Cmd,S]), -1, 1} - end. +%%-------------------------------------------------------------------- +%% Help for directing stdin and stdout from and to the channel from/to the client +%% +exec_in_self_group(ConnectionHandler, ChannelId, WantReply, State, Fun) -> + Exec = + fun() -> + spawn( + fun() -> + case try + ssh_connection:reply_request(ConnectionHandler, WantReply, success, ChannelId), + Fun() + of + {ok, Result} -> + {ok, Result}; + {error, Error} -> + {error, Error}; + X -> + {error, "Bad exec fun in server. Invalid return value: "++t2str(X)} + catch error:Err -> + {error,Err}; + Cls:Exp -> + {error,{Cls,Exp}} + end + of + {ok,Str} -> + write_chars(ConnectionHandler, ChannelId, t2str(Str)), + ssh_connection:exit_status(ConnectionHandler, ChannelId, 0); + {error, Str} -> + write_chars(ConnectionHandler, ChannelId, 1, "**Error** "++t2str(Str)), + ssh_connection:exit_status(ConnectionHandler, ChannelId, ?EXEC_ERROR_STATUS) + end + end) + end, + {ok, State#state{group = group:start(self(), Exec, [{echo,false}]), + buf = empty_buf()}}. + -fmt_exec_repl({T,A}) when T==ok ; T==error -> - try - {T, io_lib:format("~s",[A])} - catch - error:badarg -> - {T, io_lib:format("~p", [A])}; - C:Err -> - {error, io_lib:format("~p:~p~n",[C,Err])} - end; -fmt_exec_repl(Other) -> - {error, io_lib:format("Bad exec-plugin return: ~p",[Other])}. +t2str(T) -> try io_lib:format("~s",[T]) + catch _:_ -> io_lib:format("~p",[T]) + end. %%-------------------------------------------------------------------- % Pty can be undefined if the client never sets any pty options before diff --git a/lib/ssh/src/ssh_options.erl b/lib/ssh/src/ssh_options.erl index 39f23a8b8a..e2a18edc0d 100644 --- a/lib/ssh/src/ssh_options.erl +++ b/lib/ssh/src/ssh_options.erl @@ -306,6 +306,7 @@ default(server) -> shell => #{default => ?DEFAULT_SHELL, chk => fun({M,F,A}) -> is_atom(M) andalso is_atom(F) andalso is_list(A); + (disabled) -> true; (V) -> check_function1(V) orelse check_function2(V) end, class => user_option @@ -314,6 +315,7 @@ default(server) -> exec => #{default => undefined, chk => fun({direct, V}) -> check_function1(V) orelse check_function2(V) orelse check_function3(V); + (disabled) -> true; %% Compatibility (undocumented): ({M,F,A}) -> is_atom(M) andalso is_atom(F) andalso is_list(A); (V) -> check_function1(V) orelse check_function2(V) orelse check_function3(V) diff --git a/lib/ssh/src/ssh_sftp.erl b/lib/ssh/src/ssh_sftp.erl index 4b6e187c3a..28df85dfa4 100644 --- a/lib/ssh/src/ssh_sftp.erl +++ b/lib/ssh/src/ssh_sftp.erl @@ -160,8 +160,10 @@ start_channel(Socket, UserOptions) when is_port(Socket) -> start_channel(Cm, UserOptions) when is_pid(Cm) -> Timeout = proplists:get_value(timeout, UserOptions, infinity), {_SshOpts, ChanOpts, SftpOpts} = handle_options(UserOptions), - case ssh_xfer:attach(Cm, [], ChanOpts) of - {ok, ChannelId, Cm} -> + WindowSize = proplists:get_value(window_size, ChanOpts, ?XFER_WINDOW_SIZE), + PacketSize = proplists:get_value(packet_size, ChanOpts, ?XFER_PACKET_SIZE), + case ssh_connection:session_channel(Cm, WindowSize, PacketSize, Timeout) of + {ok, ChannelId} -> case ssh_client_channel:start(Cm, ChannelId, ?MODULE, [Cm, ChannelId, SftpOpts]) of {ok, Pid} -> @@ -194,25 +196,24 @@ start_channel(Host, UserOptions) -> -> {ok,pid(),ssh:connection_ref()} | {error,reason()}. start_channel(Host, Port, UserOptions) -> - {SshOpts, ChanOpts, SftpOpts} = handle_options(UserOptions), + {SshOpts, _ChanOpts, _SftpOpts} = handle_options(UserOptions), Timeout = % A mixture of ssh:connect and ssh_sftp:start_channel: - proplists:get_value(connect_timeout, SshOpts, - proplists:get_value(timeout, SftpOpts, infinity)), - case ssh_xfer:connect(Host, Port, SshOpts, ChanOpts, Timeout) of - {ok, ChannelId, Cm} -> - case ssh_client_channel:start(Cm, ChannelId, ?MODULE, [Cm,ChannelId,SftpOpts]) of - {ok, Pid} -> - case wait_for_version_negotiation(Pid, Timeout) of - ok -> - {ok, Pid, Cm}; - TimeOut -> - TimeOut - end; - {error, Reason} -> - {error, format_channel_start_error(Reason)}; - ignore -> - {error, ignore} - end; + case proplists:get_value(connect_timeout, UserOptions) of + undefined -> + proplists:get_value(timeout, UserOptions, infinity); + TO -> + TO + end, + case ssh:connect(Host, Port, SshOpts, Timeout) of + {ok, Cm} -> + case start_channel(Cm, UserOptions) of + {ok, Pid} -> + {ok, Pid, Cm}; + Error -> + Error + end; + {error, Timeout} -> + {error, timeout}; Error -> Error end. diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl index a85926354e..d1a3d513d1 100644 --- a/lib/ssh/src/ssh_transport.erl +++ b/lib/ssh/src/ssh_transport.erl @@ -108,7 +108,9 @@ default_algorithms(cipher) -> ])); default_algorithms(mac) -> supported_algorithms(mac, same(['AEAD_AES_128_GCM', - 'AEAD_AES_256_GCM'])); + 'AEAD_AES_256_GCM', + 'hmac-sha1-96' + ])); default_algorithms(Alg) -> supported_algorithms(Alg, []). @@ -161,6 +163,8 @@ supported_algorithms(cipher) -> {'aes128-ctr', [{ciphers,aes_128_ctr}]}, {'AEAD_AES_256_GCM', [{ciphers,aes_256_gcm}]}, {'AEAD_AES_128_GCM', [{ciphers,aes_128_gcm}]}, + {'aes256-cbc', [{ciphers,aes_256_cbc}]}, + {'aes192-cbc', [{ciphers,aes_192_cbc}]}, {'aes128-cbc', [{ciphers,aes_128_cbc}]}, {'3des-cbc', [{ciphers,des_ede3_cbc}]} ] @@ -171,6 +175,7 @@ supported_algorithms(mac) -> [{'hmac-sha2-256', [{macs,hmac}, {hashs,sha256}]}, {'hmac-sha2-512', [{macs,hmac}, {hashs,sha512}]}, {'hmac-sha1', [{macs,hmac}, {hashs,sha}]}, + {'hmac-sha1-96', [{macs,hmac}, {hashs,sha}]}, {'AEAD_AES_128_GCM', [{ciphers,aes_128_gcm}]}, {'AEAD_AES_256_GCM', [{ciphers,aes_256_gcm}]} ] @@ -1345,6 +1350,18 @@ cipher('aes128-cbc') -> iv_bytes = 16, block_bytes = 16}; +cipher('aes192-cbc') -> + #cipher{impl = aes_192_cbc, + key_bytes = 24, + iv_bytes = 16, + block_bytes = 16}; + +cipher('aes256-cbc') -> + #cipher{impl = aes_256_cbc, + key_bytes = 32, + iv_bytes = 16, + block_bytes = 16}; + cipher('aes128-ctr') -> #cipher{impl = aes_128_ctr, key_bytes = 16, diff --git a/lib/ssh/src/ssh_xfer.erl b/lib/ssh/src/ssh_xfer.erl index 1d77ccb311..b071b38be2 100644 --- a/lib/ssh/src/ssh_xfer.erl +++ b/lib/ssh/src/ssh_xfer.erl @@ -24,7 +24,6 @@ -module(ssh_xfer). --export([attach/2, attach/3, connect/3, connect/4, connect/5]). -export([open/6, opendir/3, readdir/3, close/3, read/5, write/5, rename/5, remove/3, mkdir/4, rmdir/3, realpath/3, extended/4, stat/4, fstat/4, lstat/4, setstat/4, @@ -47,44 +46,6 @@ -define(is_set(F, Bits), ((F) band (Bits)) == (F)). --define(XFER_PACKET_SIZE, 65536). --define(XFER_WINDOW_SIZE, 20*?XFER_PACKET_SIZE). - -attach(CM, Opts) -> - open_xfer(CM, Opts, []). - -attach(CM, Opts, ChanOpts) -> - open_xfer(CM, Opts, ChanOpts). - - -connect(Host, Port, Opts) -> - case ssh:connect(Host, Port, Opts) of - {ok, CM} -> open_xfer(CM, Opts, []); - Error -> Error - end. - -connect(Host, Port, Opts, Timeout) -> - connect(Host, Port, Opts, [], Timeout). - -connect(Host, Port, Opts, ChanOpts, Timeout) -> - case ssh:connect(Host, Port, Opts, Timeout) of - {ok, CM} -> open_xfer(CM, [{timeout, Timeout}|Opts], ChanOpts); - {error, Timeout} -> {error, timeout}; - Error -> Error - end. - - -open_xfer(CM, Opts, ChanOpts) -> - TMO = proplists:get_value(timeout, Opts, infinity), - WindowSize = proplists:get_value(window_size, ChanOpts, ?XFER_WINDOW_SIZE), - PacketSize = proplists:get_value(packet_size, ChanOpts, ?XFER_PACKET_SIZE), - case ssh_connection:session_channel(CM, WindowSize, PacketSize, TMO) of - {ok, ChannelId} -> - {ok, ChannelId, CM}; - Error -> - Error - end. - protocol_version_request(XF, Version) -> xf_request(XF, ?SSH_FXP_INIT, <<?UINT32(Version)>>). diff --git a/lib/ssh/src/ssh_xfer.hrl b/lib/ssh/src/ssh_xfer.hrl index a76e9151db..aaf2c16d10 100644 --- a/lib/ssh/src/ssh_xfer.hrl +++ b/lib/ssh/src/ssh_xfer.hrl @@ -20,6 +20,10 @@ %% + +-define(XFER_PACKET_SIZE, 65536). +-define(XFER_WINDOW_SIZE, 20*?XFER_PACKET_SIZE). + %%% Description: SFTP defines -define(SSH_SFTP_PROTOCOL_VERSION, 6). %%%---------------------------------------------------------------------- |